Free cookie consent management tool by TermsFeed Policy Generator

Ignore:
Timestamp:
01/03/22 12:23:11 (2 years ago)
Author:
gkronber
Message:

#3136: merged r18165:18174 from trunk to branch (resolving conflicts in the parser)

Location:
branches/3136_Structural_GP
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • branches/3136_Structural_GP

  • branches/3136_Structural_GP/HeuristicLab.Problems.DataAnalysis.Symbolic

  • branches/3136_Structural_GP/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Importer/InfixExpressionParser.cs

    r18157 r18176  
    4040  ///
    4141  /// S             = Expr EOF
    42   /// Expr          = ['-' | '+'] Term { '+' Term | '-' Term }
     42  /// Expr          = Term { '+' Term | '-' Term }
    4343  /// Term          = Fact { '*' Fact | '/' Fact }
    4444  /// Fact          = SimpleFact [ '^' SimpleFact ]
     
    4949  ///                 | VarExpr
    5050  ///                 | number
     51  ///                 | ['+' | '-'] SimpleFact
    5152  /// ArgList       = Expr { ',' Expr }
    5253  /// VarExpr       = varId OptFactorPart
    53   /// OptFactorPart = [ ('=' varVal | '[' ['+' | '-' ] number {',' ['+' | '-' ] number } ']' ) ]
     54  /// OptFactorPart = [ ('=' varVal | '[' ['+' | '-' ]  number {',' ['+' | '-' ] number } ']' ) ]
    5455  /// varId         =  ident | ' ident ' | " ident "
    5556  /// varVal        =  ident | ' ident ' | " ident "
     
    8485
    8586    private Number number = new Number();
    86     private Constant constant = new Constant();
     87    private Constant minusOne = new Constant() { Value = -1 };
    8788    private Variable variable = new Variable();
    8889    private BinaryFactorVariable binaryFactorVar = new BinaryFactorVariable();
     
    139140        { "XOR", new Xor()},
    140141        { "DIFF", new Derivative()},
    141         { "LAG", new LaggedVariable() }
     142        { "LAG", new LaggedVariable() },
    142143      };
    143144
     
    163164      int pos = 0;
    164165      while (true) {
    165         while (pos < str.Length && Char.IsWhiteSpace(str[pos])) pos++;
     166        while (pos < str.Length && char.IsWhiteSpace(str[pos])) pos++;
    166167        if (pos >= str.Length) {
    167168          yield return new Token { TokenType = TokenType.End, strVal = "" };
     
    169170        }
    170171        if (char.IsDigit(str[pos])) {
    171           // read number (=> read until white space or operator or comma)
     172          // read number (=> read until white space or other symbol)
    172173          var sb = new StringBuilder();
    173174          sb.Append(str[pos]);
     
    270271        } else if (str[pos] == '<') {
    271272          pos++;
    272           yield return new Token {TokenType = TokenType.LeftAngleBracket, strVal = "<"};
     273          yield return new Token { TokenType = TokenType.LeftAngleBracket, strVal = "<" };
    273274        } else if (str[pos] == '>') {
    274275          pos++;
    275           yield return new Token {TokenType = TokenType.RightAngleBracket, strVal = ">"};
     276          yield return new Token { TokenType = TokenType.RightAngleBracket, strVal = ">" };
    276277        } else {
    277278          throw new ArgumentException("Invalid character: " + str[pos]);
     
    290291    }
    291292
    292     /// Expr          = ['-' | '+'] Term { '+' Term | '-' Term }
     293    /// Expr          = Term { '+' Term | '-' Term }
    293294    private ISymbolicExpressionTreeNode ParseExpr(Queue<Token> tokens) {
     295      // build tree from bottom to top and left to right
     296      // a + b - c => ((a + b) - c)
     297      // a - b - c => ((a - b) - c)
     298      // and then flatten as far as possible
     299      var left = ParseTerm(tokens);
     300
    294301      var next = tokens.Peek();
    295       var posTerms = new List<ISymbolicExpressionTreeNode>();
    296       var negTerms = new List<ISymbolicExpressionTreeNode>();
    297       bool negateFirstTerm = false;
    298       if (next.TokenType == TokenType.Operator && (next.strVal == "+" || next.strVal == "-")) {
    299         tokens.Dequeue();
    300         if (next.strVal == "-")
    301           negateFirstTerm = true;
    302       }
    303       var t = ParseTerm(tokens);
    304       if (negateFirstTerm) negTerms.Add(t);
    305       else posTerms.Add(t);
    306 
    307       next = tokens.Peek();
    308302      while (next.strVal == "+" || next.strVal == "-") {
    309303        switch (next.strVal) {
    310304          case "+": {
    311305              tokens.Dequeue();
    312               var term = ParseTerm(tokens);
    313               posTerms.Add(term);
     306              var right = ParseTerm(tokens);
     307              var op = GetSymbol("+").CreateTreeNode();
     308              op.AddSubtree(left);
     309              op.AddSubtree(right);
     310              left = op;
    314311              break;
    315312            }
    316313          case "-": {
    317314              tokens.Dequeue();
    318               var term = ParseTerm(tokens);
    319               negTerms.Add(term);
     315              var right = ParseTerm(tokens);
     316              var op = GetSymbol("-").CreateTreeNode();
     317              op.AddSubtree(left);
     318              op.AddSubtree(right);
     319              left = op;
    320320              break;
    321321            }
     
    324324      }
    325325
    326       var sum = GetSymbol("+").CreateTreeNode();
    327       foreach (var posTerm in posTerms) sum.AddSubtree(posTerm);
    328       if (negTerms.Any()) {
    329         if (negTerms.Count == 1) {
    330           var sub = GetSymbol("-").CreateTreeNode();
    331           sub.AddSubtree(negTerms.Single());
    332           sum.AddSubtree(sub);
    333         } else {
    334           var sumNeg = GetSymbol("+").CreateTreeNode();
    335           foreach (var negTerm in negTerms) sumNeg.AddSubtree(negTerm);
    336 
    337           var constNode = (NumberTreeNode)number.CreateTreeNode();
    338           constNode.Value = -1.0;
    339           var prod = GetSymbol("*").CreateTreeNode();
    340           prod.AddSubtree(constNode);
    341           prod.AddSubtree(sumNeg);
    342 
    343           sum.AddSubtree(prod);
    344         }
    345       }
    346       if (sum.SubtreeCount == 1) return sum.Subtrees.First();
    347       else return sum;
     326      FoldLeftRecursive(left);
     327      return left;
    348328    }
    349329
    350330    private ISymbol GetSymbol(string tok) {
    351       if(knownSymbols.ContainsFirst(tok))
     331      if (knownSymbols.ContainsFirst(tok))
    352332        return knownSymbols.GetByFirst(tok).FirstOrDefault();
    353333      else
     
    357337    /// Term          = Fact { '*' Fact | '/' Fact }
    358338    private ISymbolicExpressionTreeNode ParseTerm(Queue<Token> tokens) {
    359       var factors = new List<ISymbolicExpressionTreeNode>();
    360       var firstFactor = ParseFact(tokens);
    361       factors.Add(firstFactor);
     339      // build tree from bottom to top and left to right
     340      // a / b * c => ((a / b) * c)
     341      // a / b / c => ((a / b) / c)
     342      // and then flatten as far as possible
     343
     344      var left = ParseFact(tokens);
    362345
    363346      var next = tokens.Peek();
     
    366349          case "*": {
    367350              tokens.Dequeue();
    368               var fact = ParseFact(tokens);
    369               factors.Add(fact);
     351              var right = ParseFact(tokens);
     352
     353              var op = GetSymbol("*").CreateTreeNode();
     354              op.AddSubtree(left);
     355              op.AddSubtree(right);
     356              left = op;
    370357              break;
    371358            }
    372359          case "/": {
    373360              tokens.Dequeue();
    374               var invFact = ParseFact(tokens);
    375               var divNode = GetSymbol("/").CreateTreeNode(); // 1/x
    376               divNode.AddSubtree(invFact);
    377               factors.Add(divNode);
     361              var right = ParseFact(tokens);
     362              var op = GetSymbol("/").CreateTreeNode();
     363              op.AddSubtree(left);
     364              op.AddSubtree(right);
     365              left = op;
    378366              break;
    379367            }
     
    382370        next = tokens.Peek();
    383371      }
    384       if (factors.Count == 1) return factors.First();
    385       else {
    386         var prod = GetSymbol("*").CreateTreeNode();
    387         foreach (var f in factors) prod.AddSubtree(f);
    388         return prod;
     372      // remove all nodes where the child op is the same as the parent op
     373      // (a * b) * c) => (a * b * c)
     374      // (a / b) / c) => (a / b / c)
     375
     376      FoldLeftRecursive(left);
     377      return left;
     378    }
     379
     380    private void FoldLeftRecursive(ISymbolicExpressionTreeNode parent) {
     381      if (parent.SubtreeCount > 1) {
     382        var child = parent.GetSubtree(0);
     383        FoldLeftRecursive(child);
     384        if (parent.Symbol == child.Symbol && IsAssociative(parent.Symbol)) {
     385          parent.RemoveSubtree(0);
     386          for (int i = 0; i < child.SubtreeCount; i++) {
     387            parent.InsertSubtree(i, child.GetSubtree(i));
     388          }
     389        }
    389390      }
    390391    }
     
    411412    ///                 | funcId '(' ArgList ')
    412413    ///                 | VarExpr
     414    ///                 | '<' 'num' [ '=' [ '+' | '-' ] number ] '>'
    413415    ///                 | number
     416    ///                 | ['+' | '-' ] SimpleFact
    414417    /// ArgList       = Expr { ',' Expr }
    415418    /// VarExpr       = varId OptFactorPart
     
    435438        if (tokens.Peek().TokenType == TokenType.LeftPar) {
    436439          // function identifier or LAG
    437           var funcId = idTok.strVal.ToUpperInvariant();
    438 
    439           var funcNode = GetSymbol(funcId).CreateTreeNode();
    440           var lPar = tokens.Dequeue();
    441           if (lPar.TokenType != TokenType.LeftPar)
    442             throw new ArgumentException("expected (");
    443 
    444           // handle 'lag' specifically
    445           if (funcNode.Symbol is LaggedVariable) {
    446             var varId = tokens.Dequeue();
    447             if (varId.TokenType != TokenType.Identifier) throw new ArgumentException("Identifier expected. Format for lagged variables: \"lag(x, -1)\"");
    448             var comma = tokens.Dequeue();
    449             if (comma.TokenType != TokenType.Comma) throw new ArgumentException("',' expected, Format for lagged variables: \"lag(x, -1)\"");
    450             double sign = 1.0;
    451             if (tokens.Peek().strVal == "+" || tokens.Peek().strVal == "-") {
    452               // read sign
    453               var signTok = tokens.Dequeue();
    454               if (signTok.strVal == "-") sign = -1.0;
    455             }
    456             var lagToken = tokens.Dequeue();
    457             if (lagToken.TokenType != TokenType.Number) throw new ArgumentException("Number expected, Format for lagged variables: \"lag(x, -1)\"");
    458             if (!lagToken.doubleVal.IsAlmost(Math.Round(lagToken.doubleVal)))
    459               throw new ArgumentException("Time lags must be integer values");
    460             var laggedVarNode = funcNode as LaggedVariableTreeNode;
    461             laggedVarNode.VariableName = varId.strVal;
    462             laggedVarNode.Lag = (int)Math.Round(sign * lagToken.doubleVal);
    463             laggedVarNode.Weight = 1.0;
    464           } else if (funcNode.Symbol is SubFunctionSymbol) { // SubFunction
    465             var subFunction = funcNode as SubFunctionTreeNode;
    466             subFunction.Name = next.strVal;
    467             // input arguments
    468             var args = ParseArgList(tokens);
    469             IList<string> arguments = new List<string>();
    470             foreach (var arg in args)
    471               if(arg is VariableTreeNode varTreeNode)
    472                 arguments.Add(varTreeNode.VariableName);
    473             subFunction.Arguments = arguments;
     440          return ParseFunctionOrLaggedVariable(tokens, idTok);
     441        } else {
     442          return ParseVariable(tokens, idTok);
     443        }
     444      } else if (next.TokenType == TokenType.LeftAngleBracket) {
     445        // '<' 'num' [ '=' ['+'|'-'] number ] '>'
     446        return ParseNumber(tokens);
     447      } else if (next.TokenType == TokenType.Operator && (next.strVal == "-" || next.strVal == "+")) {
     448        // ['+' | '-' ] SimpleFact
     449        if (tokens.Dequeue().strVal == "-") {
     450          var arg = ParseSimpleFact(tokens);
     451          if (arg is NumberTreeNode numNode) {
     452            numNode.Value *= -1;
     453            return numNode;
     454          } else if (arg is ConstantTreeNode constNode) {
     455            var constSy = new Constant { Value = -constNode.Value };
     456            return constSy.CreateTreeNode();
     457          } else if (arg is VariableTreeNode varNode) {
     458            varNode.Weight *= -1;
     459            return varNode;
    474460          } else {
    475             // functions
    476             var args = ParseArgList(tokens);
    477             // check number of arguments
    478             if (funcNode.Symbol.MinimumArity > args.Length || funcNode.Symbol.MaximumArity < args.Length) {
    479               throw new ArgumentException(string.Format("Symbol {0} requires between {1} and {2} arguments.", funcId,
    480                 funcNode.Symbol.MinimumArity, funcNode.Symbol.MaximumArity));
    481             }
    482             foreach (var arg in args) funcNode.AddSubtree(arg);
     461            var mul = GetSymbol("*").CreateTreeNode();
     462            var neg = minusOne.CreateTreeNode();
     463            mul.AddSubtree(neg);
     464            mul.AddSubtree(arg);
     465            return mul;
    483466          }
    484 
    485           var rPar = tokens.Dequeue();
    486           if (rPar.TokenType != TokenType.RightPar)
    487             throw new ArgumentException("expected )");
    488 
    489 
    490           return funcNode;
    491467        } else {
    492           // variable
    493           if (tokens.Peek().TokenType == TokenType.Eq) {
    494             // binary factor
    495             tokens.Dequeue(); // skip Eq
    496             var valTok = tokens.Dequeue();
    497             if (valTok.TokenType != TokenType.Identifier) throw new ArgumentException("expected identifier");
    498             var binFactorNode = (BinaryFactorVariableTreeNode)binaryFactorVar.CreateTreeNode();
    499             binFactorNode.Weight = 1.0;
    500             binFactorNode.VariableName = idTok.strVal;
    501             binFactorNode.VariableValue = valTok.strVal;
    502             return binFactorNode;
    503           } else if (tokens.Peek().TokenType == TokenType.LeftBracket) {
    504             // factor variable
    505             var factorVariableNode = (FactorVariableTreeNode)factorVar.CreateTreeNode();
    506             factorVariableNode.VariableName = idTok.strVal;
    507 
    508             tokens.Dequeue(); // skip [
    509             var weights = new List<double>();
    510             // at least one weight is necessary
    511             var sign = 1.0;
    512             if (tokens.Peek().TokenType == TokenType.Operator) {
    513               var opToken = tokens.Dequeue();
    514               if (opToken.strVal == "+") sign = 1.0;
    515               else if (opToken.strVal == "-") sign = -1.0;
    516               else throw new ArgumentException();
    517             }
    518             if (tokens.Peek().TokenType != TokenType.Number) throw new ArgumentException("number expected");
    519             var weightTok = tokens.Dequeue();
    520             weights.Add(sign * weightTok.doubleVal);
    521             while (tokens.Peek().TokenType == TokenType.Comma) {
    522               // skip comma
    523               tokens.Dequeue();
    524               if (tokens.Peek().TokenType == TokenType.Operator) {
    525                 var opToken = tokens.Dequeue();
    526                 if (opToken.strVal == "+") sign = 1.0;
    527                 else if (opToken.strVal == "-") sign = -1.0;
    528                 else throw new ArgumentException();
    529               }
    530               weightTok = tokens.Dequeue();
    531               if (weightTok.TokenType != TokenType.Number) throw new ArgumentException("number expected");
    532               weights.Add(sign * weightTok.doubleVal);
    533             }
    534             var rightBracketToken = tokens.Dequeue();
    535             if (rightBracketToken.TokenType != TokenType.RightBracket) throw new ArgumentException("closing bracket ] expected");
    536             factorVariableNode.Weights = weights.ToArray();
    537             return factorVariableNode;
    538           } else {
    539             // variable
    540             var varNode = (VariableTreeNode)variable.CreateTreeNode();
    541             varNode.Weight = 1.0;
    542             varNode.VariableName = idTok.strVal;
    543             return varNode;
    544           }
    545         }
    546       } else if (next.TokenType == TokenType.LeftAngleBracket) {
    547         Token numberTok = null;
    548         var leftAngleBracket = tokens.Dequeue();
    549         if (leftAngleBracket.TokenType != TokenType.LeftAngleBracket)
    550           throw new ArgumentException("opening bracket < expected");
    551 
    552         var idTok = tokens.Dequeue();
    553         if (idTok.TokenType != TokenType.Identifier || idTok.strVal.ToLower() != "num")
    554           throw new ArgumentException("string 'num' expected");
    555 
    556         if (tokens.Peek().TokenType == TokenType.Eq) {
    557           var equalTok = tokens.Dequeue();
    558           if (tokens.Peek().TokenType != TokenType.Number)
    559             throw new ArgumentException("No value for number specified.");
    560 
    561           numberTok = tokens.Dequeue();
    562         }
    563 
    564         var rightAngleBracket = tokens.Dequeue();
    565         if (rightAngleBracket.TokenType != TokenType.RightAngleBracket)
    566           throw new ArgumentException("closing bracket > expected");
    567         var numNode = (NumberTreeNode)number.CreateTreeNode();
    568         if (numberTok != null) numNode.Value = numberTok.doubleVal;
    569         return numNode;
     468          return ParseSimpleFact(tokens);
     469        }
    570470      } else if (next.TokenType == TokenType.Number) {
     471        // number
    571472        var numTok = tokens.Dequeue();
    572         var constSy = new Constant {Value = numTok.doubleVal};
     473        var constSy = new Constant { Value = numTok.doubleVal };
    573474        return constSy.CreateTreeNode();
    574475      } else {
    575476        throw new ArgumentException(string.Format("unexpected token in expression {0}", next.strVal));
    576477      }
     478    }
     479
     480    private ISymbolicExpressionTreeNode ParseNumber(Queue<Token> tokens) {
     481      // we distinguish parameters and constants. The values of parameters can be changed.
     482      // a parameter is written as '<' 'num' [ '=' ['+'|'-'] number ] '>' with an optional initialization
     483      Token numberTok = null;
     484      var leftAngleBracket = tokens.Dequeue();
     485      if (leftAngleBracket.TokenType != TokenType.LeftAngleBracket)
     486        throw new ArgumentException("opening bracket < expected");
     487
     488      var idTok = tokens.Dequeue();
     489      if (idTok.TokenType != TokenType.Identifier || idTok.strVal.ToLower() != "num")
     490        throw new ArgumentException("string 'num' expected");
     491
     492      var numNode = (NumberTreeNode)number.CreateTreeNode();
     493
     494      if (tokens.Peek().TokenType == TokenType.Eq) {
     495        tokens.Dequeue(); // skip "="
     496        var next = tokens.Peek();
     497        if (next.strVal != "+" && next.strVal != "-" && next.TokenType != TokenType.Number)
     498          throw new ArgumentException("Expected '+', '-' or number.");
     499
     500        var sign = 1.0;
     501        if (next.strVal == "+" || next.strVal == "-") {
     502          if (tokens.Dequeue().strVal == "-") sign = -1.0;
     503        }
     504        if (tokens.Peek().TokenType != TokenType.Number) {
     505          throw new ArgumentException("Expected number.");
     506        }
     507        numberTok = tokens.Dequeue();
     508        numNode.Value = sign * numberTok.doubleVal;
     509      }
     510
     511      var rightAngleBracket = tokens.Dequeue();
     512      if (rightAngleBracket.TokenType != TokenType.RightAngleBracket)
     513        throw new ArgumentException("closing bracket > expected");
     514
     515      return numNode;
     516    }
     517
     518    private ISymbolicExpressionTreeNode ParseVariable(Queue<Token> tokens, Token idTok) {
     519      // variable
     520      if (tokens.Peek().TokenType == TokenType.Eq) {
     521        // binary factor
     522        tokens.Dequeue(); // skip Eq
     523        var valTok = tokens.Dequeue();
     524        if (valTok.TokenType != TokenType.Identifier) throw new ArgumentException("expected identifier");
     525        var binFactorNode = (BinaryFactorVariableTreeNode)binaryFactorVar.CreateTreeNode();
     526        binFactorNode.Weight = 1.0;
     527        binFactorNode.VariableName = idTok.strVal;
     528        binFactorNode.VariableValue = valTok.strVal;
     529        return binFactorNode;
     530      } else if (tokens.Peek().TokenType == TokenType.LeftBracket) {
     531        // factor variable
     532        var factorVariableNode = (FactorVariableTreeNode)factorVar.CreateTreeNode();
     533        factorVariableNode.VariableName = idTok.strVal;
     534
     535        tokens.Dequeue(); // skip [
     536        var weights = new List<double>();
     537        // at least one weight is necessary
     538        var sign = 1.0;
     539        if (tokens.Peek().TokenType == TokenType.Operator) {
     540          var opToken = tokens.Dequeue();
     541          if (opToken.strVal == "+") sign = 1.0;
     542          else if (opToken.strVal == "-") sign = -1.0;
     543          else throw new ArgumentException();
     544        }
     545        if (tokens.Peek().TokenType != TokenType.Number) throw new ArgumentException("number expected");
     546        var weightTok = tokens.Dequeue();
     547        weights.Add(sign * weightTok.doubleVal);
     548        while (tokens.Peek().TokenType == TokenType.Comma) {
     549          // skip comma
     550          tokens.Dequeue();
     551          if (tokens.Peek().TokenType == TokenType.Operator) {
     552            var opToken = tokens.Dequeue();
     553            if (opToken.strVal == "+") sign = 1.0;
     554            else if (opToken.strVal == "-") sign = -1.0;
     555            else throw new ArgumentException();
     556          }
     557          weightTok = tokens.Dequeue();
     558          if (weightTok.TokenType != TokenType.Number) throw new ArgumentException("number expected");
     559          weights.Add(sign * weightTok.doubleVal);
     560        }
     561        var rightBracketToken = tokens.Dequeue();
     562        if (rightBracketToken.TokenType != TokenType.RightBracket) throw new ArgumentException("closing bracket ] expected");
     563        factorVariableNode.Weights = weights.ToArray();
     564        return factorVariableNode;
     565      } else {
     566        // variable
     567        var varNode = (VariableTreeNode)variable.CreateTreeNode();
     568        varNode.Weight = 1.0;
     569        varNode.VariableName = idTok.strVal;
     570        return varNode;
     571      }
     572    }
     573
     574    private ISymbolicExpressionTreeNode ParseFunctionOrLaggedVariable(Queue<Token> tokens, Token idTok) {
     575      var funcId = idTok.strVal.ToUpperInvariant();
     576
     577      var funcNode = GetSymbol(funcId).CreateTreeNode();
     578      var lPar = tokens.Dequeue();
     579      if (lPar.TokenType != TokenType.LeftPar)
     580        throw new ArgumentException("expected (");
     581
     582      // handle 'lag' specifically
     583      if (funcNode.Symbol is LaggedVariable) {
     584        ParseLaggedVariable(tokens, funcNode);
     585      } else if (funcNode.Symbol is SubFunctionSymbol) { // SubFunction
     586        var subFunction = funcNode as SubFunctionTreeNode;
     587        subFunction.Name = idTok.strVal;
     588        // input arguments
     589        var args = ParseArgList(tokens);
     590        IList<string> arguments = new List<string>();
     591        foreach (var arg in args)
     592          if (arg is VariableTreeNode varTreeNode)
     593            arguments.Add(varTreeNode.VariableName);
     594        subFunction.Arguments = arguments;
     595      } else {
     596        // functions
     597        var args = ParseArgList(tokens);
     598        // check number of arguments
     599        if (funcNode.Symbol.MinimumArity > args.Length || funcNode.Symbol.MaximumArity < args.Length) {
     600          throw new ArgumentException(string.Format("Symbol {0} requires between {1} and  {2} arguments.", funcId,
     601            funcNode.Symbol.MinimumArity, funcNode.Symbol.MaximumArity));
     602        }
     603        foreach (var arg in args) funcNode.AddSubtree(arg);
     604      }
     605
     606      var rPar = tokens.Dequeue();
     607      if (rPar.TokenType != TokenType.RightPar)
     608        throw new ArgumentException("expected )");
     609
     610
     611      return funcNode;
     612    }
     613
     614    private static void ParseLaggedVariable(Queue<Token> tokens, ISymbolicExpressionTreeNode funcNode) {
     615      var varId = tokens.Dequeue();
     616      if (varId.TokenType != TokenType.Identifier) throw new ArgumentException("Identifier expected. Format for lagged variables: \"lag(x, -1)\"");
     617      var comma = tokens.Dequeue();
     618      if (comma.TokenType != TokenType.Comma) throw new ArgumentException("',' expected, Format for lagged variables: \"lag(x, -1)\"");
     619      double sign = 1.0;
     620      if (tokens.Peek().strVal == "+" || tokens.Peek().strVal == "-") {
     621        // read sign
     622        var signTok = tokens.Dequeue();
     623        if (signTok.strVal == "-") sign = -1.0;
     624      }
     625      var lagToken = tokens.Dequeue();
     626      if (lagToken.TokenType != TokenType.Number) throw new ArgumentException("Number expected, Format for lagged variables: \"lag(x, -1)\"");
     627      if (!lagToken.doubleVal.IsAlmost(Math.Round(lagToken.doubleVal)))
     628        throw new ArgumentException("Time lags must be integer values");
     629      var laggedVarNode = funcNode as LaggedVariableTreeNode;
     630      laggedVarNode.VariableName = varId.strVal;
     631      laggedVarNode.Lag = (int)Math.Round(sign * lagToken.doubleVal);
     632      laggedVarNode.Weight = 1.0;
    577633    }
    578634
     
    588644      return exprList.ToArray();
    589645    }
     646
     647    private bool IsAssociative(ISymbol sy) {
     648      return sy == GetSymbol("+") || sy == GetSymbol("-") ||
     649             sy == GetSymbol("*") || sy == GetSymbol("/") ||
     650             sy == GetSymbol("AND") || sy == GetSymbol("OR") || sy == GetSymbol("XOR");
     651    }
    590652  }
    591653}
Note: See TracChangeset for help on using the changeset viewer.