Computer Science 112 Fundamentals of Programming II Expression Trees.
-
Upload
philip-garrison -
Category
Documents
-
view
232 -
download
1
Transcript of Computer Science 112 Fundamentals of Programming II Expression Trees.
A Parse (Expression) Tree
Evaluator
Source language program
Syntax error messages
Ok or not OKParser
The value of the expression
Semantic error messages
A parse tree
Trees for Binary Expressions
• An expression tree for a number is a node containing the number
• Otherwise, the tree is a node containing an operator and links to left and right subtrees
• The subtrees contain the operands of the expression
Example Expression Trees
23 23
3 + 5+
3 5
3 + 5 * 4 +
3 *
5 4
Root nodeRight subtreeLeft subtree
(3 + 5) * 4
+
3 5
*
4
Operator Precedence
3 + 5 * 4 +
3 *
5 4
(3 + 5) * 4
+
3 5
*
4
5 * 4 + 3 +
*
5 4
3
Operators with higher precedence appear lowerin the tree, unless overriddenby parentheses.
Operator Precedence
5 * 4 - 3 -
*
5 4
3
When operators have equalprecedence, the ones to theleft appear lower in the tree.
5 + 4 - 3 -
+
5 4
3
5 + 4 - 3 + 6 -
+
5 4
3
+
6
Properties of Expression Trees
• Numbers are in leaf nodes
• Operators are in interior nodes
• All interior nodes have exactly two children
• Both types of nodes implement the same interface
Things We Might Want from an Expression Tree
• Its value
• Its prefix form
• Its infix form
• Its postfix form
Resources# The interface to all expression tree classes
value() # Returns the int value of the expression prefix() # Returns a string in prefixinfix() # Returns a string in infix (fully parenthesized)postfix() # Returns a string in postfix
# Implementing classes
LeafNode(data)
InteriorNode(opToken, leftOperandNode, rightOperandNode)
Evaluating an Expression Tree
• A leaf node returns the number contained in it
• An interior node evaluates its left and right subtrees, applies its operator to these values, and returns the result
Evaluating a Leaf Nodeclass LeafNode(object):
def __init__(self, data): self.data = data
def value(self): return self.data
# Other methods go here
A LeafNode forms the base case for the recursive processing of expression trees
Evaluating an Interior Nodeclass InteriorNode(object):
def __init__(self, opToken, leftOperandNode, rightOperandNode): self.operator = opToken self.left = leftOperandNode self.right = rightOperandNode
def value(self): return self.computeValue(op, self.left.value() self.right.value()) # Other methods go here
The method computeValue is the same one we used in the stack-based evaluator
Tree Traversals
• An expression tree supports three types of traversals– preorder (visit the node, then go left, then go right)– inorder (go left, then visit the node, then go right)– postorder (go left, then go right, then the visit node
Tree Traversals
• An expression tree supports three types of traversals– preorder (visit the node, then go left, then go right)– inorder (go left, then visit the node, then go right)– postorder (go left, then go right, then visit the node
• These traversals can generate the prefix, infix, and postfix notations of an expression
Code for postfixclass LeafNode(object):
def __init__(self, data): self.data = data
def postfix(self): return str(self.data)
# Other methods go here
class InteriorNode(object):
def __init__(self, opToken, leftOperandNode, rightOperandNode): self.operator = opToken self.left = leftOperandNode self.right = rightOperandNode
def postfix(self): return self.left.postfix() + " " + self.right.postfix() \ + " " + str(self.operator)
Generate Postfix
3 + 5 * 4 +
3 *
5 4
Node an operator, so go left
def postfix(self): return str(self.data)
def postfix(self): return self.left.postfix() + " " + self.right.postfix() \ + " " + str(self.operator)
Generate Postfix
3 + 5 * 4 +
3 *
5 4
Node an operand, return "3"
def postfix(self): return str(self.data)
def postfix(self): return self.left.postfix() + " " + self.right.postfix() \ + " " + str(self.operator)
Generate Postfix
3 + 5 * 4 +
3 *
5 4
Now go right
3
def postfix(self): return str(self.data)
def postfix(self): return self.left.postfix() + " " + self.right.postfix() \ + " " + str(self.operator)
Generate Postfix
3 + 5 * 4 +
3 *
5 4
Node an operator, so go left
3
def postfix(self): return str(self.data)
def postfix(self): return self.left.postfix() + " " + self.right.postfix() \ + " " + str(self.operator)
Generate Postfix
3 + 5 * 4 +
3 *
5 4
Node an operand, return "5"
3 5
def postfix(self): return str(self.data)
def postfix(self): return self.left.postfix() + " " + self.right.postfix() \ + " " + str(self.operator)
Generate Postfix
3 + 5 * 4 +
3 *
5 4
Now go right
3 5
def postfix(self): return str(self.data)
def postfix(self): return self.left.postfix() + " " + self.right.postfix() \ + " " + str(self.operator)
Generate Postfix
3 + 5 * 4 +
3 *
5 4
Node an operand, return "4"
3 5 4
def postfix(self): return str(self.data)
def postfix(self): return self. left.postfix() + " " + self. right.postfix() \ + " " + str(self.operator)
Generate Postfix
3 + 5 * 4 +
3 *
5 4
Return "*"
3 5 4 *
def postfix(self): return str(self.data)
def postfix(self): return self.left.postfix() + " " + self.right.postfix() \ + " " + str(self.operator)
Generate Postfix
3 + 5 * 4 +
3 *
5 4
Return "+"
3 5 4 * +
def postfix(self): return str(self.data)
def postfix(self): return self.left.postfix() + " " + self.right.postfix() \ + " " + str(self.operator)
Building an Expression Tree
• Each parsing method builds a tree that represents the portion of the expression for which it is responsible
• Each parsing method returns its tree to the caller
Build a Tree for Primaries# primary = number | "(" expression ")"def primary(self): token = scanner.get() if token.getType() == Token.INT: tree = LeafNode(token.getValue()) scanner.next() elif token.getType() == Token.L_PAR: scanner.next() tree = self.expression() self._accept(scanner.get(), Token.R_PAR, "')' expected") scanner.next() else: tree = LeafNode(token.getValue()) fatalError (token, "unexpected token") return tree
Build a Tree for Expressions
# expression = term { addingOperator term }def expression(self): tree = self.term() token = scanner.get() while token.getType() in (Token.PLUS, Token.MINUS): scanner.next() tree = InteriorNode(token, tree, self.term()) token = scanner.get() return tree