Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2895_PushGP_GenealogyAnalysis/HeuristicLab.Problems.ProgramSynthesis/Push/Parser/PushParser.cs @ 18183

Last change on this file since 18183 was 15771, checked in by bburlacu, 7 years ago

#2895: Add solution skeleton for PushGP with genealogy analysis.

File size: 8.0 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Globalization;
4using System.Linq;
5using System.Text.RegularExpressions;
6
7namespace HeuristicLab.Problems.ProgramSynthesis {
8  public static class PushParser {
9    private const char delimiter = ' ';
10
11    private static readonly CultureInfo cultureInfo = CultureInfo.CreateSpecificCulture("en-US");
12
13    private static readonly char[] symbolTrim = { '\r', '\n' };
14
15    public static Expression Parse(string source, int startIndex = 0) {
16      bool error;
17      var symbols = GetSymbols(source, out error); // source.Split(delimiter);
18
19      int endIndex;
20      return Parse(symbols, startIndex, out endIndex);
21    }
22
23    public static PushProgram ParseProgram(string source, int startIndex = 0) {
24      var expression = Parse(source, startIndex);
25
26      return expression as PushProgram ?? new PushProgram(new[] { expression });
27    }
28
29    private static IReadOnlyList<string> GetSymbols(string source, out bool error) {
30      var chars = source.ToCharArray();
31      var symbols = new List<string>();
32
33      for (var i = 0; i < chars.Length; i++) {
34        var cur = chars[i];
35        int endIndex;
36        int length;
37        string str;
38
39        switch (cur) {
40          case delimiter: break;
41          case PushEnvironment.StringSymbol:
42            endIndex = source.IndexOf(PushEnvironment.StringSymbol, i + 1);
43            if (endIndex < i) {
44              error = true;
45              return symbols;
46            }
47
48            length = endIndex - i + 1;
49            str = source.Substring(i, length);
50            symbols.Add(str);
51            i += length; // skip following space
52
53            break;
54
55          case PushEnvironment.CharSymbol:
56            endIndex = source.IndexOf(PushEnvironment.CharSymbol, i + 1);
57            if (endIndex < i) {
58              error = true;
59              return symbols;
60            }
61
62            length = endIndex - i + 1;
63            str = source.Substring(i, length);
64            str = EscapeLikeALiteral(str);
65            symbols.Add(str);
66            i += length; // skip following space
67
68            break;
69
70          case PushEnvironment.VectorStartSymbol:
71            endIndex = source.IndexOf(PushEnvironment.VectorEndSymbol, i + 1);
72            if (endIndex < i) {
73              error = true;
74              return symbols;
75            }
76
77            length = endIndex - i + 1;
78            str = source.Substring(i, length);
79            symbols.Add(str);
80            i += length; // skip following space
81            break;
82
83          default:
84            endIndex = source.IndexOf(' ', i + 1);
85
86            length = endIndex < i
87              ? chars.Length - i
88              : endIndex - i;
89
90            str = source.Substring(i, length);
91            symbols.Add(str);
92            i += length; // skip following space
93
94            break;
95        }
96      }
97
98      error = true;
99      return symbols;
100    }
101
102    private static Expression Parse(IReadOnlyList<string> symbols, int startIndex, out int endIndex) {
103      var expressions = new List<Expression>();
104
105      for (var i = startIndex; i < symbols.Count; i++) {
106        var symbol = symbols[i].TrimEnd(symbolTrim);
107
108        if (string.IsNullOrWhiteSpace(symbol)) continue;
109
110        switch (symbol) {
111          case PushEnvironment.ProgramStartSymbolStr:
112            var subExpression = Parse(symbols, i + 1, out endIndex);
113            expressions.Insert(0, subExpression);
114            i = endIndex;
115            continue;
116          case PushEnvironment.ProgramEndSymbolStr:
117            endIndex = i;
118            return new PushProgram(expressions);
119        }
120
121        // literal
122        Expression expression;
123        if (TryParseLiteral(symbol, out expression)) {
124          expressions.Insert(0, expression);
125          continue;
126        }
127
128        // expression
129        if (ExpressionTable.TryGetStatelessExpression(symbol, out expression)
130         || ExpressionTable.TryGetStatefulExpression(symbol, out expression)) {
131          expressions.Insert(0, expression);
132          continue;
133        }
134
135        // identifier - custom expression or named literals
136        expressions.Insert(0, new NameDefineXExecExpression(symbol));
137      }
138
139      endIndex = symbols.Count - 1;
140
141      switch (expressions.Count) {
142        case 0:
143          return PushProgram.Empty;
144        case 1:
145          return expressions[0];
146        default:
147          return new PushProgram(expressions);
148      }
149    }
150
151    private static bool TryParseLiteral(string word, out Expression expression) {
152      if (word.StartsWith(PushEnvironment.CharSymbolStr) &&
153          word.EndsWith(PushEnvironment.CharSymbolStr) &&
154          word.Length == 3) {
155        expression = new CharPushExpression(word[1]);
156        return true;
157      }
158
159      if (word.StartsWith(PushEnvironment.StringSymbolStr) &&
160          word.EndsWith(PushEnvironment.StringSymbolStr)) {
161        var stringValue = word.Length == 0 ? string.Empty : word.Substring(1, word.Length - 2);
162        expression = new StringPushExpression(stringValue);
163        return true;
164      }
165
166      // "[]" has no values and can therefor not parsed correctly as vector of a specific type
167      if (word.StartsWith(PushEnvironment.VectorStartSymbolStr) &&
168          word.EndsWith(PushEnvironment.VectorEndSymbolStr) &&
169          word.Length > 2) {
170
171        var vectorEntries = word
172          .Substring(1, word.Length - 2)
173          .Split(PushEnvironment.VectorSeparatorSymbol)
174          .ToList();
175
176        if (vectorEntries.Count == 0) {
177          expression = null;
178          return false;
179        }
180
181        Expression e;
182        var first = vectorEntries.First();
183        if (!TryParseLiteral(first, out e)) {
184          expression = null;
185          return false;
186        }
187
188        if (e.GetType() == typeof(IntegerPushExpression)) {
189          var integerValues = vectorEntries.Select(long.Parse).ToList();
190          expression = new IntegerVectorPushExpression(integerValues);
191        } else if (e.GetType() == typeof(FloatPushExpression)) {
192          var doubleValues = vectorEntries.Select(x => double.Parse(x, NumberStyles.Float, cultureInfo)).ToList();
193          expression = new FloatVectorPushExpression(doubleValues);
194        } else if (e.GetType() == typeof(StringPushExpression)) {
195          var stringValues = vectorEntries.Select(str => str.Substring(1, str.Length - 2)).ToList();
196          expression = new StringVectorPushExpression(stringValues);
197        } else if (e.GetType() == typeof(BooleanPushExpression)) {
198          var booleanValues = vectorEntries.Select(bool.Parse).ToList();
199          expression = new BooleanVectorPushExpression(booleanValues);
200        } else {
201          expression = null;
202          return false;
203        }
204
205        return true;
206      }
207
208      long longValue;
209      if (long.TryParse(word, out longValue)) {
210        expression = new IntegerPushExpression(longValue);
211        return true;
212      }
213
214      double floatValue;
215      if (double.TryParse(word, NumberStyles.Float, cultureInfo, out floatValue)) {
216        expression = new FloatPushExpression(floatValue);
217        return true;
218      }
219
220      bool booleanValue;
221      if (bool.TryParse(word, out booleanValue)) {
222        expression = new BooleanPushExpression(booleanValue);
223        return true;
224      }
225
226      expression = null;
227      return false;
228    }
229
230    private static string EscapeLikeALiteral(string src) {
231      return Regex.Replace(src, @"\\(?<simple>['""\\0abfnrtv])", m => {
232        var s = m.Groups["simple"].Value;
233        switch (s) {
234          case "'": return "'";
235          case "\"": return "\"";
236          case "0": return "\0";
237          case "a": return "\a";
238          case "b": return "\b";
239          case "f": return "\f";
240          case "n": return "\n";
241          case "r": return "\r";
242          case "t": return "\t";
243          case "v": return "\v";
244          default:
245            throw new InvalidOperationException();
246        }
247      });
248    }
249  }
250}
Note: See TracBrowser for help on using the repository browser.