code: def build_ast(expression, debug = False):
      
      #use a directed graph to store the tree
      G = DiGraph()
      stack = []
  
  
      for n in expression:
          # Since the graph does not maintain the order of adding nodes/edges
          # add an extra attribute 'pos' so we can always sort to the correct order
          if isinstance(n,OperatorNode):
              if n.ttype == "operator-infix":
                  arg2 = stack.pop()
                  arg1 = stack.pop()
                  # Hack to write the name of sheet in 2argument address
                  if(n.tvalue == ':'):
                      if '!' in arg1.tvalue and arg2.ttype == 'operand' and '!' not in arg2.tvalue:
                          arg2.tvalue = arg1.tvalue.split('!')[0] + '!' + arg2.tvalue
  
                  G.add_node(arg1,pos = 1)
                  G.add_node(arg2,pos = 2)
                  G.add_edge(arg1, n)
                  G.add_edge(arg2, n)
              else:
                  arg1 = stack.pop()
                  G.add_node(arg1,pos = 1)
                  G.add_edge(arg1, n)
  
          elif isinstance(n,FunctionNode):
              args = []
              for _ in range(n.num_args):
                  try:
                      args.append(stack.pop())
                  except:
                      raise Exception()
              #try:
                  # args = [stack.pop() for _ in range(n.num_args)]
              #except:
              #        print 'STACK', stack, type(n)
              #        raise Exception('prut')
              args.reverse()
              for i,a in enumerate(args):
                  G.add_node(a,pos = i)
                  G.add_edge(a,n)
          else:
              G.add_node(n,pos=0)
  
          stack.append(n)
  
      return G,stack.pop()
docs: build an AST from an Excel formula expression in reverse polish notation