Ignore:
Timestamp:
10/22/16 10:21:15 (6 years ago)
Author:
gkronber
Message:

#2677: extended infix parser and infix formatter to support functions with multiple arguments

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/sources/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Importer/InfixExpressionParser.cs

    r14319 r14347  
    3737  /// </summary>
    3838  public sealed class InfixExpressionParser {
    39     private enum TokenType { Operator, Identifier, Number, LeftPar, RightPar, End, NA };
     39    private enum TokenType { Operator, Identifier, Number, LeftPar, RightPar, Comma, End, NA };
    4040    private class Token {
    4141      internal double doubleVal;
     
    102102        { "MEAN", new Average()},
    103103        { "IF", new IfThenElse()},
    104         { ">", new GreaterThan()},
    105         { "<", new LessThan()},
     104        { "GT", new GreaterThan()},
     105        { "LT", new LessThan()},
    106106        { "AND", new And()},
    107107        { "OR", new Or()},
     
    138138        }
    139139        if (char.IsDigit(str[pos])) {
    140           // read number (=> read until white space or operator)
     140          // read number (=> read until white space or operator or comma)
    141141          var sb = new StringBuilder();
    142142          sb.Append(str[pos]);
     
    147147            && str[pos] != '*'
    148148            && str[pos] != '/'
    149             && str[pos] != ')') {
     149            && str[pos] != ')'
     150            && str[pos] != ',') {
    150151            sb.Append(str[pos]);
    151152            pos++;
     
    211212          pos++;
    212213          yield return new Token { TokenType = TokenType.RightPar, strVal = ")" };
     214        } else if (str[pos] == ',') {
     215          pos++;
     216          yield return new Token { TokenType = TokenType.Comma, strVal = "," };
    213217        } else {
    214218          throw new ArgumentException("Invalid character: " + str[pos]);
     
    217221    }
    218222
    219     // S = Expr EOF
    220     // Expr = ['-' | '+'] Term { '+' Term | '-' Term }
    221     // Term = Fact { '*' Fact | '/' Fact }
    222     // Fact = '(' Expr ')' | funcId '(' Expr ')' | varId | number
     223    // S       = Expr EOF
     224    // Expr    = ['-' | '+'] Term { '+' Term | '-' Term }
     225    // Term    = Fact { '*' Fact | '/' Fact }
     226    // Fact    = '(' Expr ')' | funcId '(' ArgList ')' | varId | number
     227    // ArgList = Expr { ',' Expr }
    223228    private ISymbolicExpressionTreeNode ParseS(Queue<Token> tokens) {
    224229      var expr = ParseExpr(tokens);
     
    328333    }
    329334
    330     // Fact = '(' Expr ')' | funcId '(' Expr ')' | varId | number
     335    // Fact = '(' Expr ')' | funcId '(' ArgList ')' | varId | number
    331336    private ISymbolicExpressionTreeNode ParseFact(Queue<Token> tokens) {
    332337      var next = tokens.Peek();
     
    348353          if (lPar.TokenType != TokenType.LeftPar)
    349354            throw new ArgumentException("expected (");
    350           var expr = ParseExpr(tokens);
     355          var args = ParseArgList(tokens);
     356
     357          // check semantic constraints
     358          if (funcNode.Symbol.MinimumArity > args.Length || funcNode.Symbol.MaximumArity < args.Length)
     359            throw new ArgumentException(string.Format("Symbol {0} requires between {1} and  {2} arguments.", funcId,
     360              funcNode.Symbol.MinimumArity, funcNode.Symbol.MaximumArity));
     361          foreach (var arg in args) funcNode.AddSubtree(arg);
     362
    351363          var rPar = tokens.Dequeue();
    352364          if (rPar.TokenType != TokenType.RightPar)
    353365            throw new ArgumentException("expected )");
    354366
    355           funcNode.AddSubtree(expr);
    356367          return funcNode;
    357368        } else {
     
    371382      }
    372383    }
     384
     385    // ArgList = Expr { ',' Expr }
     386    private ISymbolicExpressionTreeNode[] ParseArgList(Queue<Token> tokens) {
     387      var exprList = new List<ISymbolicExpressionTreeNode>();
     388      exprList.Add(ParseExpr(tokens));
     389      while (tokens.Peek().TokenType != TokenType.RightPar) {
     390        var comma = tokens.Dequeue();
     391        if (comma.TokenType != TokenType.Comma) throw new ArgumentException("expected ',' ");
     392        exprList.Add(ParseExpr(tokens));
     393      }
     394      return exprList.ToArray();
     395    }
    373396  }
    374397}
Note: See TracChangeset for help on using the changeset viewer.