'Call `handle_actions` recursively on `self.tree` and return result.
`handle_actions` is a dictionary of node names (e.g. \'product\', \'sum\',
etc&) to functions. These functions are of the following form:
-input: a list of processed child nodes. If it includes any terminal
nodes in the list, they will be given as their processed forms also.
-output: whatever to be passed to the level higher, and what to
return for the final node.
`terminal_converter` is a function that takes in a token and returns a
processed form. The default of `None` just leaves them as strings.'

def reduce_tree(self, handle_actions, terminal_converter=None):

    def handle_node(node):
        '\n                                                Return    the    result    representing    the    node,    using    recursion.\n\n                                                Call    the    appropriate    `handle_action`    for    this    node.    As    its    inputs,\n                                                feed    it    the    output    of    `handle_node`    for    each    child    node.\n                                                '
        if (not isinstance(node, ParseResults)):
            if (terminal_converter is None):
                return node
            else:
                return terminal_converter(node)
        node_name = node.getName()
        if (node_name not in handle_actions):
            raise Exception(u"Unknown    branch    name    '{}'".format(node_name))
        action = handle_actions[node_name]
        handled_kids = [handle_node(k) for k in node]
        return action(handled_kids)
    return handle_node(self.tree)
