line.py 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. def generate_line(root, node_type):
  2. """
  3. Print an expression tree in a single text line. Where needed, add
  4. parentheses.
  5. >>> from node import Node, Leaf
  6. >>> #from graph import generate_graph
  7. >>> l0, l1 = Leaf(1), Leaf(2)
  8. >>> n0 = Node('+', l0, l1)
  9. >>> print generate_line(n0, Node)
  10. 1 + 2
  11. >>> n1 = Node('+', l0, l1)
  12. >>> n2 = Node('*', n0, n1)
  13. >>> print generate_line(n2, Node)
  14. (1 + 2) * (1 + 2)
  15. >>> l2 = Leaf(3)
  16. >>> n3 = Node('-', l2)
  17. >>> n4 = Node('*', n1, n3)
  18. >>> print generate_line(n4, Node)
  19. (1 + 2) * -3
  20. >>> #integral = Node('int', n0, n1)
  21. """
  22. operators = [
  23. ('+', '-'),
  24. ('*', '/'),
  25. ('^', )
  26. ]
  27. max_assoc = len(operators)
  28. def assoc(node):
  29. """
  30. Get the associativity of an operator node.
  31. """
  32. if isinstance(node, node_type) and len(node) > 1:
  33. op = node.title()
  34. for i, group in enumerate(operators):
  35. if op in group:
  36. return i
  37. return max_assoc
  38. def traverse(node):
  39. """
  40. The expression tree is traversed using preorder traversal:
  41. 1. Visit the root
  42. 2. Traverse the left subtree
  43. 3. Traverse the right subtree
  44. """
  45. s = node.title()
  46. if not isinstance(node, node_type):
  47. return s
  48. arity = len(node)
  49. if arity == 1:
  50. # Unary expression
  51. s += traverse(node[0])
  52. elif arity == 2:
  53. # Binary expression
  54. left, right = map(traverse, node)
  55. # Check if there is an assiociativity conflict on either side. If
  56. # so, add parentheses
  57. if assoc(node[0]) < assoc(node):
  58. left = '(' + left + ')'
  59. if assoc(node[1]) < assoc(node):
  60. right = '(' + right + ')'
  61. s = left + ' ' + s + ' ' + right
  62. return s
  63. return traverse(root)