| # Coroutine example:  general coroutine transfers | 
 | # | 
 | # The program is a variation of a Simula 67 program due to Dahl & Hoare, | 
 | # (Dahl/Dijkstra/Hoare, Structured Programming; Academic Press, 1972) | 
 | # who in turn credit the original example to Conway. | 
 | # | 
 | # We have a number of input lines, terminated by a 0 byte.  The problem | 
 | # is to squash them together into output lines containing 72 characters | 
 | # each.  A semicolon must be added between input lines.  Runs of blanks | 
 | # and tabs in input lines must be squashed into single blanks. | 
 | # Occurrences of "**" in input lines must be replaced by "^". | 
 | # | 
 | # Here's a test case: | 
 |  | 
 | test = """\ | 
 |    d    =   sqrt(b**2  -  4*a*c) | 
 | twoa    =   2*a | 
 |    L    =   -b/twoa | 
 |    R    =   d/twoa | 
 |   A1    =   L + R | 
 |   A2    =   L - R\0 | 
 | """ | 
 |  | 
 | # The program should print: | 
 |  | 
 | # d = sqrt(b^2 - 4*a*c);twoa = 2*a; L = -b/twoa; R = d/twoa; A1 = L + R; | 
 | #A2 = L - R | 
 | #done | 
 |  | 
 | # getline: delivers the next input line to its invoker | 
 | # disassembler: grabs input lines from getline, and delivers them one | 
 | #    character at a time to squasher, also inserting a semicolon into | 
 | #    the stream between lines | 
 | # squasher:  grabs characters from disassembler and passes them on to | 
 | #    assembler, first replacing "**" with "^" and squashing runs of | 
 | #    whitespace | 
 | # assembler: grabs characters from squasher and packs them into lines | 
 | #    with 72 character each, delivering each such line to putline; | 
 | #    when it sees a null byte, passes the last line to putline and | 
 | #    then kills all the coroutines | 
 | # putline: grabs lines from assembler, and just prints them | 
 |  | 
 | from Coroutine import * | 
 |  | 
 | def getline(text): | 
 |     for line in string.splitfields(text, '\n'): | 
 |         co.tran(codisassembler, line) | 
 |  | 
 | def disassembler(): | 
 |     while 1: | 
 |         card = co.tran(cogetline) | 
 |         for i in range(len(card)): | 
 |             co.tran(cosquasher, card[i]) | 
 |         co.tran(cosquasher, ';') | 
 |  | 
 | def squasher(): | 
 |     while 1: | 
 |         ch = co.tran(codisassembler) | 
 |         if ch == '*': | 
 |             ch2 = co.tran(codisassembler) | 
 |             if ch2 == '*': | 
 |                 ch = '^' | 
 |             else: | 
 |                 co.tran(coassembler, ch) | 
 |                 ch = ch2 | 
 |         if ch in ' \t': | 
 |             while 1: | 
 |                 ch2 = co.tran(codisassembler) | 
 |                 if ch2 not in ' \t': | 
 |                     break | 
 |             co.tran(coassembler, ' ') | 
 |             ch = ch2 | 
 |         co.tran(coassembler, ch) | 
 |  | 
 | def assembler(): | 
 |     line = '' | 
 |     while 1: | 
 |         ch = co.tran(cosquasher) | 
 |         if ch == '\0': | 
 |             break | 
 |         if len(line) == 72: | 
 |             co.tran(coputline, line) | 
 |             line = '' | 
 |         line = line + ch | 
 |     line = line + ' ' * (72 - len(line)) | 
 |     co.tran(coputline, line) | 
 |     co.kill() | 
 |  | 
 | def putline(): | 
 |     while 1: | 
 |         line = co.tran(coassembler) | 
 |         print line | 
 |  | 
 | import string | 
 | co = Coroutine() | 
 | cogetline = co.create(getline, test) | 
 | coputline = co.create(putline) | 
 | coassembler = co.create(assembler) | 
 | codisassembler = co.create(disassembler) | 
 | cosquasher = co.create(squasher) | 
 |  | 
 | co.tran(coputline) | 
 | print 'done' | 
 |  | 
 | # end of example |