Free cookie consent management tool by TermsFeed Policy Generator

source: branches/PushGP/HeuristicLab.PushGP/HeuristicLab.Problems.ProgramSynthesis/Push/Parser/PushParser.cs @ 15033

Last change on this file since 15033 was 15017, checked in by pkimmesw, 7 years ago

#2665 Fixed Benchmark Problem Definition, Converted LoopExpressions to stateless expressions, Added several unit test to ensure funcionality, Fixed UI bugs

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