|
@@ -0,0 +1,77 @@
|
|
|
|
|
+def generate_line(root, node_type):
|
|
|
|
|
+ """
|
|
|
|
|
+ Print an expression tree in a single text line. Where needed, add
|
|
|
|
|
+ parentheses.
|
|
|
|
|
+
|
|
|
|
|
+ >>> from node import Node, Leaf
|
|
|
|
|
+ >>> #from graph import generate_graph
|
|
|
|
|
+ >>> l0, l1 = Leaf(1), Leaf(2)
|
|
|
|
|
+ >>> n0 = Node('+', l0, l1)
|
|
|
|
|
+ >>> print generate_line(n0, Node)
|
|
|
|
|
+ 1 + 2
|
|
|
|
|
+ >>> n1 = Node('+', l0, l1)
|
|
|
|
|
+ >>> n2 = Node('*', n0, n1)
|
|
|
|
|
+ >>> print generate_line(n2, Node)
|
|
|
|
|
+ (1 + 2) * (1 + 2)
|
|
|
|
|
+ >>> l2 = Leaf(3)
|
|
|
|
|
+ >>> n3 = Node('-', l2)
|
|
|
|
|
+ >>> n4 = Node('*', n1, n3)
|
|
|
|
|
+ >>> print generate_line(n4, Node)
|
|
|
|
|
+ (1 + 2) * -3
|
|
|
|
|
+ >>> #integral = Node('int', n0, n1)
|
|
|
|
|
+ """
|
|
|
|
|
+
|
|
|
|
|
+ operators = [
|
|
|
|
|
+ ('+', '-'),
|
|
|
|
|
+ ('*', '/'),
|
|
|
|
|
+ ('^', )
|
|
|
|
|
+ ]
|
|
|
|
|
+ max_assoc = len(operators)
|
|
|
|
|
+
|
|
|
|
|
+ def assoc(node):
|
|
|
|
|
+ """
|
|
|
|
|
+ Get the associativity of an operator node.
|
|
|
|
|
+ """
|
|
|
|
|
+ if isinstance(node, node_type) and len(node) > 1:
|
|
|
|
|
+ op = node.title()
|
|
|
|
|
+
|
|
|
|
|
+ for i, group in enumerate(operators):
|
|
|
|
|
+ if op in group:
|
|
|
|
|
+ return i
|
|
|
|
|
+
|
|
|
|
|
+ return max_assoc
|
|
|
|
|
+
|
|
|
|
|
+ def traverse(node):
|
|
|
|
|
+ """
|
|
|
|
|
+ The expression tree is traversed using preorder traversal:
|
|
|
|
|
+ 1. Visit the root
|
|
|
|
|
+ 2. Traverse the left subtree
|
|
|
|
|
+ 3. Traverse the right subtree
|
|
|
|
|
+ """
|
|
|
|
|
+ s = node.title()
|
|
|
|
|
+
|
|
|
|
|
+ if not isinstance(node, node_type):
|
|
|
|
|
+ return s
|
|
|
|
|
+
|
|
|
|
|
+ arity = len(node)
|
|
|
|
|
+
|
|
|
|
|
+ if arity == 1:
|
|
|
|
|
+ # Unary expression
|
|
|
|
|
+ s += traverse(node[0])
|
|
|
|
|
+ elif arity == 2:
|
|
|
|
|
+ # Binary expression
|
|
|
|
|
+ left, right = map(traverse, node)
|
|
|
|
|
+
|
|
|
|
|
+ # Check if there is an assiociativity conflict on either side. If
|
|
|
|
|
+ # so, add parentheses
|
|
|
|
|
+ if assoc(node[0]) < assoc(node):
|
|
|
|
|
+ left = '(' + left + ')'
|
|
|
|
|
+
|
|
|
|
|
+ if assoc(node[1]) < assoc(node):
|
|
|
|
|
+ right = '(' + right + ')'
|
|
|
|
|
+
|
|
|
|
|
+ s = left + ' ' + s + ' ' + right
|
|
|
|
|
+
|
|
|
|
|
+ return s
|
|
|
|
|
+
|
|
|
|
|
+ return traverse(root)
|