|
@@ -35,138 +35,6 @@ def pred(node):
|
|
|
return MAX_PRED
|
|
return MAX_PRED
|
|
|
|
|
|
|
|
|
|
|
|
|
-def generate_line_old(root):
|
|
|
|
|
- """
|
|
|
|
|
- Print an expression tree in a single text line. Where needed, add
|
|
|
|
|
- parentheses.
|
|
|
|
|
-
|
|
|
|
|
- >>> from node import Node, Leaf
|
|
|
|
|
- >>> l0, l1 = Leaf(1), Leaf(2)
|
|
|
|
|
- >>> plus = Node('+', l0, l1)
|
|
|
|
|
- >>> print generate_line_old(plus)
|
|
|
|
|
- 1 + 2
|
|
|
|
|
-
|
|
|
|
|
- >>> plus2 = Node('+', l0, l1)
|
|
|
|
|
- >>> times = Node('*', plus, plus2)
|
|
|
|
|
- >>> print generate_line_old(times)
|
|
|
|
|
- (1 + 2)(1 + 2)
|
|
|
|
|
-
|
|
|
|
|
- >>> l2 = Leaf(3)
|
|
|
|
|
- >>> uminus = Node('-', l2)
|
|
|
|
|
- >>> times = Node('*', plus, uminus)
|
|
|
|
|
- >>> print generate_line_old(times)
|
|
|
|
|
- (1 + 2) * -3
|
|
|
|
|
-
|
|
|
|
|
- >>> exp = Leaf('x')
|
|
|
|
|
- >>> inf = Leaf('oo')
|
|
|
|
|
- >>> minus_inf = Node('-', inf)
|
|
|
|
|
- >>> integral = Node('int', exp, minus_inf, inf)
|
|
|
|
|
- >>> print generate_line_old(integral)
|
|
|
|
|
- int(x, -oo, oo)
|
|
|
|
|
- """
|
|
|
|
|
-
|
|
|
|
|
- def traverse(node):
|
|
|
|
|
- """
|
|
|
|
|
- The expression tree is traversed using preorder traversal:
|
|
|
|
|
- 1. Visit the root
|
|
|
|
|
- 2. Traverse the subtrees in left-to-right order
|
|
|
|
|
- """
|
|
|
|
|
- if not node:
|
|
|
|
|
- return '<empty expression>'
|
|
|
|
|
-
|
|
|
|
|
- op = node.title()
|
|
|
|
|
-
|
|
|
|
|
- if not node.nodes:
|
|
|
|
|
- return op
|
|
|
|
|
-
|
|
|
|
|
- arity = len(node)
|
|
|
|
|
-
|
|
|
|
|
- if is_operator(node):
|
|
|
|
|
- if arity == 1:
|
|
|
|
|
- # Unary operator
|
|
|
|
|
- sub = node[0]
|
|
|
|
|
- sub_exp = traverse(sub)
|
|
|
|
|
-
|
|
|
|
|
- # Negated sub-expressions with spaces in them should be
|
|
|
|
|
- # enclosed in parentheses, unless they have a higher precedence
|
|
|
|
|
- # than subtraction are rewritten to a factor of a subtraction:
|
|
|
|
|
- # -(1 + 2)
|
|
|
|
|
- # -(1 - 2)
|
|
|
|
|
- # -4a
|
|
|
|
|
- # -(4 * 5)
|
|
|
|
|
- # 1 - 4 * 5
|
|
|
|
|
- # 1 + -(4 * 5) -> 1 - 4 * 5
|
|
|
|
|
- if ' ' in sub_exp and sub.is_Leaf \
|
|
|
|
|
- and hasattr(node, 'marked_negation') \
|
|
|
|
|
- and pred(sub) > 0:
|
|
|
|
|
- sub_exp = '(' + sub_exp + ')'
|
|
|
|
|
-
|
|
|
|
|
- result = op + sub_exp
|
|
|
|
|
- else:
|
|
|
|
|
- # N-ary operator
|
|
|
|
|
- node_pred = pred(node)
|
|
|
|
|
- result = ''
|
|
|
|
|
- sep = ' ' + op + ' '
|
|
|
|
|
- e = []
|
|
|
|
|
-
|
|
|
|
|
- # Mark added and subtracted negations for later use when adding
|
|
|
|
|
- # parentheses
|
|
|
|
|
- if op in ('+', '-'):
|
|
|
|
|
- for child in node:
|
|
|
|
|
- if child.title() == '-' and len(child) == 1:
|
|
|
|
|
- child.marked_negation = True
|
|
|
|
|
-
|
|
|
|
|
- for i, child in enumerate(node):
|
|
|
|
|
- exp = traverse(child)
|
|
|
|
|
-
|
|
|
|
|
- # Check if there is a precedence conflict
|
|
|
|
|
- # If so, add parentheses
|
|
|
|
|
- child_pred = pred(child)
|
|
|
|
|
-
|
|
|
|
|
- if child_pred < node_pred or \
|
|
|
|
|
- (i and child_pred == node_pred \
|
|
|
|
|
- and op != child.title()):
|
|
|
|
|
- exp = '(' + exp + ')'
|
|
|
|
|
-
|
|
|
|
|
- e.append(exp)
|
|
|
|
|
-
|
|
|
|
|
- if op == '*':
|
|
|
|
|
- # Check if an explicit multiplication sign is nessecary
|
|
|
|
|
- left, right = node
|
|
|
|
|
-
|
|
|
|
|
- # Get the previous multiplication element if the arity is
|
|
|
|
|
- # greater than 2
|
|
|
|
|
- if left.title() == '*':
|
|
|
|
|
- left = left[1]
|
|
|
|
|
-
|
|
|
|
|
- # a * b -> ab
|
|
|
|
|
- # a * 2 -> a * 2
|
|
|
|
|
- # a * (b) -> a(b)
|
|
|
|
|
- # (a) * b -> (a)b
|
|
|
|
|
- # (a) * (b) -> (a)(b)
|
|
|
|
|
- # 2 * a -> 2a
|
|
|
|
|
- left_id = is_id(left)
|
|
|
|
|
- right_id = is_id(right)
|
|
|
|
|
- left_paren = e[0][-1] == ')'
|
|
|
|
|
- right_paren = e[1][0] == '('
|
|
|
|
|
- left_int = is_int(left)
|
|
|
|
|
-
|
|
|
|
|
- if (left_id or left_paren or left_int) \
|
|
|
|
|
- and (right_id or right_paren):
|
|
|
|
|
- sep = ''
|
|
|
|
|
-
|
|
|
|
|
- result += sep.join(e)
|
|
|
|
|
- else:
|
|
|
|
|
- # Function call
|
|
|
|
|
- result = op + '(' + ', '.join(map(traverse, node)) + ')'
|
|
|
|
|
-
|
|
|
|
|
- return result
|
|
|
|
|
-
|
|
|
|
|
- # An addition with negation can be written as a subtraction, e.g.:
|
|
|
|
|
- # 1 + -2 -> 1 - 2
|
|
|
|
|
- return traverse(root).replace('+ -', '- ')
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
def is_id(node):
|
|
def is_id(node):
|
|
|
return node.is_leaf and not node.title().isdigit()
|
|
return node.is_leaf and not node.title().isdigit()
|
|
|
|
|
|
|
@@ -231,17 +99,18 @@ def generate_line(root):
|
|
|
content = {}
|
|
content = {}
|
|
|
|
|
|
|
|
def construct_unary(node):
|
|
def construct_unary(node):
|
|
|
- result = node.title()
|
|
|
|
|
|
|
+ op = node.title()
|
|
|
value = node[0]
|
|
value = node[0]
|
|
|
|
|
|
|
|
# -a
|
|
# -a
|
|
|
- # -3*4
|
|
|
|
|
|
|
+ # -3 * 4
|
|
|
# --a
|
|
# --a
|
|
|
if value.is_leaf \
|
|
if value.is_leaf \
|
|
|
or not ' ' in content[value] or pred(value) > 0:
|
|
or not ' ' in content[value] or pred(value) > 0:
|
|
|
- return result + content[value]
|
|
|
|
|
|
|
+ return op + content[value]
|
|
|
|
|
|
|
|
- return '%s(%s)' % (result, content[value])
|
|
|
|
|
|
|
+ # -(a + b)
|
|
|
|
|
+ return '%s(%s)' % (op, content[value])
|
|
|
|
|
|
|
|
|
|
|
|
|
def construct_nary(node):
|
|
def construct_nary(node):
|