Changeset 14823
- Timestamp:
- 04/04/17 16:53:00 (8 years ago)
- Location:
- branches/symbreg-factors-2650/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/symbreg-factors-2650/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Formatters/InfixExpressionFormatter.cs
r14761 r14823 60 60 61 61 private void FormatRecursively(ISymbolicExpressionTreeNode node, StringBuilder strBuilder) { 62 if (node.SubtreeCount > 1) {62 if (node.SubtreeCount > 1) { 63 63 var token = GetToken(node.Symbol); 64 if (token == "+" || token == "-" || token == "OR" || token == "XOR") {64 if (token == "+" || token == "-" || token == "OR" || token == "XOR") { 65 65 strBuilder.Append("("); 66 66 FormatRecursively(node.Subtrees.First(), strBuilder); 67 67 68 foreach (var subtree in node.Subtrees.Skip(1)) {68 foreach (var subtree in node.Subtrees.Skip(1)) { 69 69 strBuilder.Append(" ").Append(token).Append(" "); 70 70 FormatRecursively(subtree, strBuilder); … … 72 72 strBuilder.Append(")"); 73 73 74 } else if (token == "*" || token == "/" || token == "AND") {74 } else if (token == "*" || token == "/" || token == "AND") { 75 75 strBuilder.Append("("); 76 76 FormatRecursively(node.Subtrees.First(), strBuilder); 77 77 78 foreach (var subtree in node.Subtrees.Skip(1)) {78 foreach (var subtree in node.Subtrees.Skip(1)) { 79 79 strBuilder.Append(" ").Append(token).Append(" "); 80 80 FormatRecursively(subtree, strBuilder); … … 85 85 strBuilder.Append(token).Append("("); 86 86 FormatRecursively(node.Subtrees.First(), strBuilder); 87 foreach (var subtree in node.Subtrees.Skip(1)) {87 foreach (var subtree in node.Subtrees.Skip(1)) { 88 88 strBuilder.Append(", "); 89 89 FormatRecursively(subtree, strBuilder); … … 91 91 strBuilder.Append(")"); 92 92 } 93 } else if (node.SubtreeCount == 1) {93 } else if (node.SubtreeCount == 1) { 94 94 var token = GetToken(node.Symbol); 95 if (token == "-" || token == "NOT") {95 if (token == "-" || token == "NOT") { 96 96 strBuilder.Append("(").Append(token).Append("("); 97 97 FormatRecursively(node.GetSubtree(0), strBuilder); 98 98 strBuilder.Append("))"); 99 } else if (token == "/") {99 } else if (token == "/") { 100 100 strBuilder.Append("1/"); 101 101 FormatRecursively(node.GetSubtree(0), strBuilder); 102 } else if (token == "+" || token == "*") {102 } else if (token == "+" || token == "*") { 103 103 FormatRecursively(node.GetSubtree(0), strBuilder); 104 104 } else { … … 110 110 } else { 111 111 // no subtrees 112 if (node.Symbol is LaggedVariable) {112 if (node.Symbol is LaggedVariable) { 113 113 var varNode = node as LaggedVariableTreeNode; 114 if (!varNode.Weight.IsAlmost(1.0)) {114 if (!varNode.Weight.IsAlmost(1.0)) { 115 115 strBuilder.Append("("); 116 116 strBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}", varNode.Weight); … … 118 118 } 119 119 strBuilder.Append("LAG("); 120 if (varNode.VariableName.Contains("'")) {120 if (varNode.VariableName.Contains("'")) { 121 121 strBuilder.AppendFormat("\"{0}\"", varNode.VariableName); 122 122 } else { … … 126 126 .AppendFormat(CultureInfo.InvariantCulture, "{0}", varNode.Lag) 127 127 .Append(")"); 128 } else if (node.Symbol is Variable) {128 } else if (node.Symbol is Variable) { 129 129 var varNode = node as VariableTreeNode; 130 if (!varNode.Weight.IsAlmost(1.0)) {130 if (!varNode.Weight.IsAlmost(1.0)) { 131 131 strBuilder.Append("("); 132 132 strBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}", varNode.Weight); 133 133 strBuilder.Append("*"); 134 134 } 135 if (varNode.VariableName.Contains("'")) {135 if (varNode.VariableName.Contains("'")) { 136 136 strBuilder.AppendFormat("\"{0}\"", varNode.VariableName); 137 137 } else { 138 138 strBuilder.AppendFormat("'{0}'", varNode.VariableName); 139 139 } 140 if (!varNode.Weight.IsAlmost(1.0)) {140 if (!varNode.Weight.IsAlmost(1.0)) { 141 141 strBuilder.Append(")"); 142 142 } 143 } else if (node.Symbol is FactorVariable) {143 } else if (node.Symbol is FactorVariable) { 144 144 var factorNode = node as FactorVariableTreeNode; 145 if (factorNode.VariableName.Contains("'")) {145 if (factorNode.VariableName.Contains("'")) { 146 146 strBuilder.AppendFormat("\"{0}\"", factorNode.VariableName); 147 147 } else { … … 150 150 strBuilder.AppendFormat("[{0}]", 151 151 string.Join(", ", factorNode.Weights.Select(w => w.ToString(CultureInfo.InvariantCulture)))); 152 } else if (node.Symbol is BinaryFactorVariable) {152 } else if (node.Symbol is BinaryFactorVariable) { 153 153 var factorNode = node as BinaryFactorVariableTreeNode; 154 if (!factorNode.Weight.IsAlmost(1.0)) {154 if (!factorNode.Weight.IsAlmost(1.0)) { 155 155 strBuilder.Append("("); 156 156 strBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}", factorNode.Weight); 157 157 strBuilder.Append("*"); 158 158 } 159 if (factorNode.VariableName.Contains("'")) {160 strBuilder.AppendFormat("\"{0} ={1}\"", factorNode.VariableName, factorNode.VariableValue);159 if (factorNode.VariableName.Contains("'")) { 160 strBuilder.AppendFormat("\"{0}\"", factorNode.VariableName); 161 161 } else { 162 strBuilder.AppendFormat("'{0} ={1}'", factorNode.VariableName, factorNode.VariableValue);162 strBuilder.AppendFormat("'{0}'", factorNode.VariableName); 163 163 } 164 if(!factorNode.Weight.IsAlmost(1.0)) { 164 strBuilder.Append(" = "); 165 if (factorNode.VariableValue.Contains("'")) { 166 strBuilder.AppendFormat("\"{0}\"", factorNode.VariableValue); 167 } else { 168 strBuilder.AppendFormat("'{0}'", factorNode.VariableValue); 169 } 170 171 if (!factorNode.Weight.IsAlmost(1.0)) { 165 172 strBuilder.Append(")"); 166 173 } 167 174 168 } else if (node.Symbol is Constant) {175 } else if (node.Symbol is Constant) { 169 176 var constNode = node as ConstantTreeNode; 170 if (constNode.Value >= 0.0)177 if (constNode.Value >= 0.0) 171 178 strBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}", constNode.Value); 172 179 else … … 178 185 private string GetToken(ISymbol symbol) { 179 186 var tok = InfixExpressionParser.knownSymbols.GetBySecond(symbol).SingleOrDefault(); 180 if (tok == null)187 if (tok == null) 181 188 throw new ArgumentException(string.Format("Unknown symbol {0} found.", symbol.Name)); 182 189 return tok; -
branches/symbreg-factors-2650/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Importer/InfixExpressionParser.cs
r14765 r14823 132 132 133 133 134 foreach (var kvp in dict) {134 foreach (var kvp in dict) { 135 135 knownSymbols.Add(kvp.Key, kvp.Value); 136 136 } … … 151 151 private IEnumerable<Token> GetAllTokens(string str) { 152 152 int pos = 0; 153 while (true) {154 while (pos < str.Length && Char.IsWhiteSpace(str[pos])) pos++;155 if (pos >= str.Length) {153 while (true) { 154 while (pos < str.Length && Char.IsWhiteSpace(str[pos])) pos++; 155 if (pos >= str.Length) { 156 156 yield return new Token { TokenType = TokenType.End, strVal = "" }; 157 157 yield break; 158 158 } 159 if (char.IsDigit(str[pos])) {159 if (char.IsDigit(str[pos])) { 160 160 // read number (=> read until white space or operator or comma) 161 161 var sb = new StringBuilder(); 162 162 sb.Append(str[pos]); 163 163 pos++; 164 while (pos < str.Length && !char.IsWhiteSpace(str[pos])164 while (pos < str.Length && !char.IsWhiteSpace(str[pos]) 165 165 && (str[pos] != '+' || str[pos - 1] == 'e' || str[pos - 1] == 'E') // continue reading exponents 166 166 && (str[pos] != '-' || str[pos - 1] == 'e' || str[pos - 1] == 'E') … … 174 174 } 175 175 double dblVal; 176 if (double.TryParse(sb.ToString(), NumberStyles.Float, CultureInfo.InvariantCulture, out dblVal))176 if (double.TryParse(sb.ToString(), NumberStyles.Float, CultureInfo.InvariantCulture, out dblVal)) 177 177 yield return new Token { TokenType = TokenType.Number, strVal = sb.ToString(), doubleVal = dblVal }; 178 178 else yield return new Token { TokenType = TokenType.NA, strVal = sb.ToString() }; 179 } else if (char.IsLetter(str[pos]) || str[pos] == '_') {179 } else if (char.IsLetter(str[pos]) || str[pos] == '_') { 180 180 // read ident 181 181 var sb = new StringBuilder(); 182 182 sb.Append(str[pos]); 183 183 pos++; 184 while (pos < str.Length &&184 while (pos < str.Length && 185 185 (char.IsLetter(str[pos]) || str[pos] == '_' || char.IsDigit(str[pos]))) { 186 186 sb.Append(str[pos]); … … 188 188 } 189 189 yield return new Token { TokenType = TokenType.Identifier, strVal = sb.ToString() }; 190 } else if (str[pos] == '"') {190 } else if (str[pos] == '"') { 191 191 // read to next " 192 192 pos++; 193 193 var sb = new StringBuilder(); 194 while (pos < str.Length && str[pos] != '"') {194 while (pos < str.Length && str[pos] != '"') { 195 195 sb.Append(str[pos]); 196 196 pos++; 197 197 } 198 if (pos < str.Length && str[pos] == '"') {198 if (pos < str.Length && str[pos] == '"') { 199 199 pos++; // skip " 200 200 yield return new Token { TokenType = TokenType.Identifier, strVal = sb.ToString() }; … … 202 202 yield return new Token { TokenType = TokenType.NA }; 203 203 204 } else if (str[pos] == '\'') {204 } else if (str[pos] == '\'') { 205 205 // read to next ' 206 206 pos++; 207 207 var sb = new StringBuilder(); 208 while (pos < str.Length && str[pos] != '\'') {208 while (pos < str.Length && str[pos] != '\'') { 209 209 sb.Append(str[pos]); 210 210 pos++; 211 211 } 212 if (pos < str.Length && str[pos] == '\'') {212 if (pos < str.Length && str[pos] == '\'') { 213 213 pos++; // skip ' 214 214 yield return new Token { TokenType = TokenType.Identifier, strVal = sb.ToString() }; 215 215 } else 216 216 yield return new Token { TokenType = TokenType.NA }; 217 } else if (str[pos] == '+') {217 } else if (str[pos] == '+') { 218 218 pos++; 219 219 yield return new Token { TokenType = TokenType.Operator, strVal = "+" }; 220 } else if (str[pos] == '-') {220 } else if (str[pos] == '-') { 221 221 pos++; 222 222 yield return new Token { TokenType = TokenType.Operator, strVal = "-" }; 223 } else if (str[pos] == '/') {223 } else if (str[pos] == '/') { 224 224 pos++; 225 225 yield return new Token { TokenType = TokenType.Operator, strVal = "/" }; 226 } else if (str[pos] == '*') {226 } else if (str[pos] == '*') { 227 227 pos++; 228 228 yield return new Token { TokenType = TokenType.Operator, strVal = "*" }; 229 } else if (str[pos] == '(') {229 } else if (str[pos] == '(') { 230 230 pos++; 231 231 yield return new Token { TokenType = TokenType.LeftPar, strVal = "(" }; 232 } else if (str[pos] == ')') {232 } else if (str[pos] == ')') { 233 233 pos++; 234 234 yield return new Token { TokenType = TokenType.RightPar, strVal = ")" }; 235 } else if (str[pos] == '[') {235 } else if (str[pos] == '[') { 236 236 pos++; 237 237 yield return new Token { TokenType = TokenType.LeftBracket, strVal = "[" }; 238 } else if (str[pos] == ']') {238 } else if (str[pos] == ']') { 239 239 pos++; 240 240 yield return new Token { TokenType = TokenType.RightBracket, strVal = "]" }; 241 } else if (str[pos] == '=') {241 } else if (str[pos] == '=') { 242 242 pos++; 243 243 yield return new Token { TokenType = TokenType.Eq, strVal = "=" }; 244 } else if (str[pos] == ',') {244 } else if (str[pos] == ',') { 245 245 pos++; 246 246 yield return new Token { TokenType = TokenType.Comma, strVal = "," }; … … 255 255 256 256 var endTok = tokens.Dequeue(); 257 if (endTok.TokenType != TokenType.End)257 if (endTok.TokenType != TokenType.End) 258 258 throw new ArgumentException(string.Format("Expected end of expression (got {0})", endTok.strVal)); 259 259 … … 267 267 var negTerms = new List<ISymbolicExpressionTreeNode>(); 268 268 bool negateFirstTerm = false; 269 if (next.TokenType == TokenType.Operator && (next.strVal == "+" || next.strVal == "-")) {269 if (next.TokenType == TokenType.Operator && (next.strVal == "+" || next.strVal == "-")) { 270 270 tokens.Dequeue(); 271 if (next.strVal == "-")271 if (next.strVal == "-") 272 272 negateFirstTerm = true; 273 273 } 274 274 var t = ParseTerm(tokens); 275 if (negateFirstTerm) negTerms.Add(t);275 if (negateFirstTerm) negTerms.Add(t); 276 276 else posTerms.Add(t); 277 277 278 278 next = tokens.Peek(); 279 while (next.strVal == "+" || next.strVal == "-") {280 switch (next.strVal) {279 while (next.strVal == "+" || next.strVal == "-") { 280 switch (next.strVal) { 281 281 case "+": { 282 282 tokens.Dequeue(); … … 296 296 297 297 var sum = GetSymbol("+").CreateTreeNode(); 298 foreach (var posTerm in posTerms) sum.AddSubtree(posTerm);299 if (negTerms.Any()) {300 if (negTerms.Count == 1) {298 foreach (var posTerm in posTerms) sum.AddSubtree(posTerm); 299 if (negTerms.Any()) { 300 if (negTerms.Count == 1) { 301 301 var sub = GetSymbol("-").CreateTreeNode(); 302 302 sub.AddSubtree(negTerms.Single()); … … 304 304 } else { 305 305 var sumNeg = GetSymbol("+").CreateTreeNode(); 306 foreach (var negTerm in negTerms) sumNeg.AddSubtree(negTerm);306 foreach (var negTerm in negTerms) sumNeg.AddSubtree(negTerm); 307 307 308 308 var constNode = (ConstantTreeNode)constant.CreateTreeNode(); … … 315 315 } 316 316 } 317 if (sum.SubtreeCount == 1) return sum.Subtrees.First();317 if (sum.SubtreeCount == 1) return sum.Subtrees.First(); 318 318 else return sum; 319 319 } … … 321 321 private ISymbol GetSymbol(string tok) { 322 322 var symb = knownSymbols.GetByFirst(tok).FirstOrDefault(); 323 if (symb == null) throw new ArgumentException(string.Format("Unknown token {0} found.", tok));323 if (symb == null) throw new ArgumentException(string.Format("Unknown token {0} found.", tok)); 324 324 return symb; 325 325 } … … 332 332 333 333 var next = tokens.Peek(); 334 while (next.strVal == "*" || next.strVal == "/") {335 switch (next.strVal) {334 while (next.strVal == "*" || next.strVal == "/") { 335 switch (next.strVal) { 336 336 case "*": { 337 337 tokens.Dequeue(); … … 352 352 next = tokens.Peek(); 353 353 } 354 if (factors.Count == 1) return factors.First();354 if (factors.Count == 1) return factors.First(); 355 355 else { 356 356 var prod = GetSymbol("*").CreateTreeNode(); 357 foreach (var f in factors) prod.AddSubtree(f);357 foreach (var f in factors) prod.AddSubtree(f); 358 358 return prod; 359 359 } … … 372 372 private ISymbolicExpressionTreeNode ParseFact(Queue<Token> tokens) { 373 373 var next = tokens.Peek(); 374 if (next.TokenType == TokenType.LeftPar) {374 if (next.TokenType == TokenType.LeftPar) { 375 375 tokens.Dequeue(); 376 376 var expr = ParseExpr(tokens); 377 377 var rPar = tokens.Dequeue(); 378 if (rPar.TokenType != TokenType.RightPar)378 if (rPar.TokenType != TokenType.RightPar) 379 379 throw new ArgumentException("expected )"); 380 380 return expr; 381 } else if (next.TokenType == TokenType.Identifier) {381 } else if (next.TokenType == TokenType.Identifier) { 382 382 var idTok = tokens.Dequeue(); 383 if (tokens.Peek().TokenType == TokenType.LeftPar) {383 if (tokens.Peek().TokenType == TokenType.LeftPar) { 384 384 // function identifier or LAG 385 385 var funcId = idTok.strVal.ToUpperInvariant(); … … 387 387 var funcNode = GetSymbol(funcId).CreateTreeNode(); 388 388 var lPar = tokens.Dequeue(); 389 if (lPar.TokenType != TokenType.LeftPar)389 if (lPar.TokenType != TokenType.LeftPar) 390 390 throw new ArgumentException("expected ("); 391 391 392 392 // handle 'lag' specifically 393 if (funcNode.Symbol is LaggedVariable) {393 if (funcNode.Symbol is LaggedVariable) { 394 394 var varId = tokens.Dequeue(); 395 if (varId.TokenType != TokenType.Identifier) throw new ArgumentException("Identifier expected. Format for lagged variables: \"lag(x, -1)\"");395 if (varId.TokenType != TokenType.Identifier) throw new ArgumentException("Identifier expected. Format for lagged variables: \"lag(x, -1)\""); 396 396 var comma = tokens.Dequeue(); 397 if (comma.TokenType != TokenType.Comma) throw new ArgumentException("',' expected, Format for lagged variables: \"lag(x, -1)\"");397 if (comma.TokenType != TokenType.Comma) throw new ArgumentException("',' expected, Format for lagged variables: \"lag(x, -1)\""); 398 398 double sign = 1.0; 399 if (tokens.Peek().strVal == "+" || tokens.Peek().strVal == "-") {399 if (tokens.Peek().strVal == "+" || tokens.Peek().strVal == "-") { 400 400 // read sign 401 401 var signTok = tokens.Dequeue(); 402 if (signTok.strVal == "-") sign = -1.0;402 if (signTok.strVal == "-") sign = -1.0; 403 403 } 404 404 var lagToken = tokens.Dequeue(); 405 if (lagToken.TokenType != TokenType.Number) throw new ArgumentException("Number expected, Format for lagged variables: \"lag(x, -1)\"");406 if (!lagToken.doubleVal.IsAlmost(Math.Round(lagToken.doubleVal)))405 if (lagToken.TokenType != TokenType.Number) throw new ArgumentException("Number expected, Format for lagged variables: \"lag(x, -1)\""); 406 if (!lagToken.doubleVal.IsAlmost(Math.Round(lagToken.doubleVal))) 407 407 throw new ArgumentException("Time lags must be integer values"); 408 408 var laggedVarNode = funcNode as LaggedVariableTreeNode; … … 414 414 var args = ParseArgList(tokens); 415 415 // check number of arguments 416 if (funcNode.Symbol.MinimumArity > args.Length || funcNode.Symbol.MaximumArity < args.Length) {416 if (funcNode.Symbol.MinimumArity > args.Length || funcNode.Symbol.MaximumArity < args.Length) { 417 417 throw new ArgumentException(string.Format("Symbol {0} requires between {1} and {2} arguments.", funcId, 418 418 funcNode.Symbol.MinimumArity, funcNode.Symbol.MaximumArity)); 419 419 } 420 foreach (var arg in args) funcNode.AddSubtree(arg);420 foreach (var arg in args) funcNode.AddSubtree(arg); 421 421 } 422 422 423 423 var rPar = tokens.Dequeue(); 424 if (rPar.TokenType != TokenType.RightPar)424 if (rPar.TokenType != TokenType.RightPar) 425 425 throw new ArgumentException("expected )"); 426 426 … … 428 428 } else { 429 429 // variable 430 if (tokens.Peek().TokenType == TokenType.Eq) {430 if (tokens.Peek().TokenType == TokenType.Eq) { 431 431 // binary factor 432 432 tokens.Dequeue(); // skip Eq 433 433 var valTok = tokens.Dequeue(); 434 if (valTok.TokenType != TokenType.Identifier) throw new ArgumentException("expected identifier");434 if (valTok.TokenType != TokenType.Identifier) throw new ArgumentException("expected identifier"); 435 435 var binFactorNode = (BinaryFactorVariableTreeNode)binaryFactorVar.CreateTreeNode(); 436 436 binFactorNode.Weight = 1.0; … … 438 438 binFactorNode.VariableValue = valTok.strVal; 439 439 return binFactorNode; 440 } else if (tokens.Peek().TokenType == TokenType.LeftBracket) {440 } else if (tokens.Peek().TokenType == TokenType.LeftBracket) { 441 441 // factor variable 442 442 var factorVariableNode = (FactorVariableTreeNode)factorVar.CreateTreeNode(); … … 447 447 // at least one weight is necessary 448 448 var sign = 1.0; 449 if (tokens.Peek().TokenType == TokenType.Operator) {449 if (tokens.Peek().TokenType == TokenType.Operator) { 450 450 var opToken = tokens.Dequeue(); 451 if (opToken.strVal == "+") sign = 1.0;452 else if (opToken.strVal == "-") sign = -1.0;451 if (opToken.strVal == "+") sign = 1.0; 452 else if (opToken.strVal == "-") sign = -1.0; 453 453 else throw new ArgumentException(); 454 454 } 455 if (tokens.Peek().TokenType != TokenType.Number) throw new ArgumentException("number expected");455 if (tokens.Peek().TokenType != TokenType.Number) throw new ArgumentException("number expected"); 456 456 var weightTok = tokens.Dequeue(); 457 457 weights.Add(sign * weightTok.doubleVal); 458 while (tokens.Peek().TokenType == TokenType.Comma) {458 while (tokens.Peek().TokenType == TokenType.Comma) { 459 459 // skip comma 460 460 tokens.Dequeue(); 461 if (tokens.Peek().TokenType == TokenType.Operator) {461 if (tokens.Peek().TokenType == TokenType.Operator) { 462 462 var opToken = tokens.Dequeue(); 463 if (opToken.strVal == "+") sign = 1.0;464 else if (opToken.strVal == "-") sign = -1.0;463 if (opToken.strVal == "+") sign = 1.0; 464 else if (opToken.strVal == "-") sign = -1.0; 465 465 else throw new ArgumentException(); 466 466 } 467 467 weightTok = tokens.Dequeue(); 468 if (weightTok.TokenType != TokenType.Number) throw new ArgumentException("number expected");468 if (weightTok.TokenType != TokenType.Number) throw new ArgumentException("number expected"); 469 469 weights.Add(sign * weightTok.doubleVal); 470 470 } 471 471 var rightBracketToken = tokens.Dequeue(); 472 if (rightBracketToken.TokenType != TokenType.RightBracket) throw new ArgumentException("closing bracket ] expected");472 if (rightBracketToken.TokenType != TokenType.RightBracket) throw new ArgumentException("closing bracket ] expected"); 473 473 factorVariableNode.Weights = weights.ToArray(); 474 474 return factorVariableNode; … … 481 481 } 482 482 } 483 } else if (next.TokenType == TokenType.Number) {483 } else if (next.TokenType == TokenType.Number) { 484 484 var numTok = tokens.Dequeue(); 485 485 var constNode = (ConstantTreeNode)constant.CreateTreeNode(); … … 495 495 var exprList = new List<ISymbolicExpressionTreeNode>(); 496 496 exprList.Add(ParseExpr(tokens)); 497 while (tokens.Peek().TokenType != TokenType.RightPar) {497 while (tokens.Peek().TokenType != TokenType.RightPar) { 498 498 var comma = tokens.Dequeue(); 499 if (comma.TokenType != TokenType.Comma) throw new ArgumentException("expected ',' ");499 if (comma.TokenType != TokenType.Comma) throw new ArgumentException("expected ',' "); 500 500 exprList.Add(ParseExpr(tokens)); 501 501 }
Note: See TracChangeset
for help on using the changeset viewer.