def build_balanced_tree(es, f, start=None, end=None):
    """Create a balanced syntax tree out of an associative binary operator.

    Many internal functions do not like deep, stick-shaped trees since those
    functions are recursive and Python has a small-ish maximum stack depth.

    Parameters:
        es    - a non-empty list of syntax trees
        f     - a function that takes two syntax trees and returns a new one
        start - if non-none, only use expressions in es[start:]
        end   - if non-none, only use expressions in es[:end]
    """
    if start is None:
        start = 0
    if end is None:
        end = len(es)
    n = end - start
    assert n > 0, "cannot create balanced tree out of empty list"
    if n == 1:
        return es[start]
    else:
        cut = start + (n // 2)
        return f(
            build_balanced_tree(es, f, start=start, end=cut),
            build_balanced_tree(es, f, start=cut, end=end))