from itertools import count def numbers(): for n in count(): yield str(n) def terms(): def parens(): for exp in expressions(): yield "(" + exp + ")" return alternate(numbers, parens) def mul(): def mul2(): for a, b in combine(mul, terms): yield a + "*" + b return alternate(terms, mul2) def add(): def add2(): for a, b in combine(add, mul): yield a + "+" + b return alternate(mul, add2) expressions = add def alternate(s, t): x = s() y = t() while True: yield x.next() yield y.next() def combine(s, t): for n in count(1): comb = [x for x in partial_combination(s, t, n)] #print "comb", n, comb if len(comb) == 0: return else: for p in comb: yield p def take_first(s, n): x = s() for i in range(0, n): yield x.next() def partial_combination(s, t, n): vals = [val for val in take_first(s, n)] for i in range(len(vals), n): vals.append(None) vals.reverse() ygen = t() for x in vals: try: y = ygen.next() if x is not None: yield (x, y) except: if x is None: return for e in expressions(): print e