Advertisement
Guest User

Untitled

a guest
Feb 10th, 2021
59
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 7.57 KB | None | 0 0
  1.         public static TreeNode BuildAST(List<Token> infix)
  2.         /*
  3.          *
  4.          *
  5.          * This is an implementation of Djikstra's Shunting-yard algorithm
  6.          * It is not 100% true to the original, but quite close
  7.          *
  8.          * We use two stacks: one for operators (e.g +, -, /) and one for the numbers (integers only supported)
  9.          * The numstack is not actually storing Integer types, but TreeNodes that represent Integers
  10.          *      The numstack TreeNodes could just be of value '1' or could ALSO be a 'leaf' of the tree
  11.          *      A 'leaf' is a calculation that represents an Integer to be calculated
  12.          *      An example leaf could be:
  13.          *                  +
  14.          *                1   2
  15.          *      Programatically, this will just be given as the '+' root node with .Left and .Right being nodes '1' & '2'
  16.          *
  17.          *
  18.          *
  19.          * INPUT: List of Token objects that represent a mathematical expression, e.g ['1', '+', '2']
  20.          * (just showing Token.Value() as list elements for demo)
  21.          *
  22.          * OUTPUT: The ROOT node of the Abstract Syntax Tree (AST) as a TreeNode object.
  23.          * The parents of any nodes in this AST could be a Num or BinOp (both inherit from TreeNode)
  24.          * Num: Represents just an Integer itself
  25.          * BinOp: Represents an Operator. Left & Right nodes of a BinOp are to be the operands.
  26.          */
  27.         {
  28.             Stack<BinOp> operatorStack = new Stack<BinOp>();
  29.             Stack<TreeNode> numStack = new Stack<TreeNode>();
  30.  
  31.             infix = findUnaryMinus(infix); // Replace unary minus with "_" to distinguish
  32.  
  33.             foreach (Token token in infix)
  34.             {
  35.  
  36.                 if (token.Value().Equals("(")) operatorStack.Push(new BinOp("("));
  37.                 // If it is the opening of a nested expression, just add it to the opstack - precedences values will be dealt with later
  38.  
  39.  
  40.                 else if (token.Type().Equals("number")) // If it is a number (Integers only supported), add to numStack
  41.                 {
  42.                     numStack.Push(
  43.                         new Num(
  44.                             int.Parse(token.Value()
  45.                         )));
  46.                     // Simply create a new Num (child class of TreeNode) node with the number in the character, converted to Integer type.
  47.                 }
  48.  
  49.  
  50.                 else if (BinOp.precedences.ContainsKey(token.Value()) && !token.Value().Equals(")"))
  51.                     // BinOp.precedences is a DICTIONARY of all operators & their precedence (represented in Integers)
  52.                     // If token.Value() IS an OPERATOR and is NOT ")"
  53.                 {
  54.                     // We have found an operator, e.g '+'
  55.                     // We need to resolve the operands into leaves of the tree first
  56.                     while (operatorStack.Count > 0 && BinOp.precedences[operatorStack.Peek().value] >= BinOp.precedences[token.Value()])
  57.                         // While the precedence of the top of the operatorStack is bigger than or equal to the precedence of the char
  58.                         // Remember that precedences of operators are stored as Integers in the dictionary, so we can compare them easily like this
  59.                     {
  60.                         BinOp binOperator = operatorStack.Pop();
  61.                         // This will be the parent node of our 'leaf'
  62.                         // the '+' in the example in the topmost comment
  63.  
  64.                         if (binOperator.value.Equals("_")) // unary minus
  65.                         {
  66.                             binOperator.left = numStack.Pop(); // only needs one operand as unary minus only takes one
  67.                         }
  68.  
  69.                         else
  70.                         {
  71.                             // Reversed as the second op was pushed at the end
  72.                             binOperator.right = numStack.Pop();
  73.                             binOperator.left = numStack.Pop();
  74.                             // child nodes '1' and '2' added (following example in top comment)
  75.                             // The numstack does not just contain raw Integer nodes, it could have another leaf (a leaf resolves to an Integer)
  76.                         }
  77.  
  78.                         numStack.Push(binOperator); // Leaf created! Now push parent node of leaf back onto numStack
  79.                     }
  80.                     // Now that our loop has iteratively created leaves and connected them for our tree, we have finished
  81.  
  82.                     // Now push operator at the end - we have not calculated anything with this one yet
  83.                     operatorStack.Push(new BinOp(token.Value()));
  84.                 }
  85.  
  86.                 else if (token.Value().Equals(")")) // End of nested () expression
  87.                 {
  88.                     while (operatorStack.Count > 0 && !operatorStack.Peek().value.Equals("("))
  89.                     {
  90.                         BinOp binOperator = operatorStack.Pop();
  91.  
  92.                         if (binOperator.value.Equals("_")) // unary minus
  93.                         {
  94.                             binOperator.left = numStack.Pop();
  95.                         }
  96.  
  97.                         else
  98.                         {
  99.                             // Reversed as the second op was pushed at the end
  100.                             binOperator.right = numStack.Pop();
  101.                             binOperator.left = numStack.Pop();
  102.                             // child nodes '1' and '2' added (following example in top comment)
  103.                             // The numstack does not just contain raw Integer nodes, it could have another leaf (a leaf resolves to an Integer)
  104.                         }
  105.  
  106.                         numStack.Push(binOperator);
  107.                     }
  108.                     // Similar loop to previously used - this time to resolve everything that we have collected inside the brackets.
  109.                     // the minute we run into another nest, '(', we can leave it for later.
  110.  
  111.                     operatorStack.Pop(); // We still have the '(' operator that started this expr in brackets left, let's get rid of it.
  112.                 }
  113.  
  114.                 else
  115.                 {
  116.                     throw new SyntaxError(); // Don't recognise what kind of Token is in our expression.
  117.                 }
  118.             }
  119.  
  120.             while (operatorStack.Count > 0) // Same leaf-making loop as before but with slightly different condition
  121.             {
  122.                 BinOp binOperator = operatorStack.Pop();
  123.  
  124.                 if (binOperator.value.Equals("_")) // unary minus
  125.                 {
  126.                     binOperator.left = numStack.Pop();
  127.                 }
  128.  
  129.                 else
  130.                 {
  131.                     // Reversed as the second op was pushed at the end
  132.                     binOperator.right = numStack.Pop();
  133.                     binOperator.left = numStack.Pop();
  134.                     // child nodes '1' and '2' added (following example in top comment)
  135.                     // The numstack does not just contain raw Integer nodes, it could have another leaf (a leaf resolves to an Integer)
  136.                 }
  137.  
  138.                 numStack.Push(binOperator);
  139.             } // While there are still operators left, make leaves of the remaining with their operands until no more to make
  140.  
  141.             // At this point, the root node should be left at the top of the numStack (and the only thing in it)
  142.             return numStack.Pop();
  143.             // we have NOT calculated anything - just built a tree of the expression and returned its root as a TreeNode.
  144.         }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement