1# Coroutine example:  general coroutine transfers
2#
3# The program is a variation of a Simula 67 program due to Dahl & Hoare,
4# (Dahl/Dijkstra/Hoare, Structured Programming; Academic Press, 1972)
5# who in turn credit the original example to Conway.
6#
7# We have a number of input lines, terminated by a 0 byte.  The problem
8# is to squash them together into output lines containing 72 characters
9# each.  A semicolon must be added between input lines.  Runs of blanks
10# and tabs in input lines must be squashed into single blanks.
11# Occurrences of "**" in input lines must be replaced by "^".
12#
13# Here's a test case:
14
15test = """\
16   d    =   sqrt(b**2  -  4*a*c)
17twoa    =   2*a
18   L    =   -b/twoa
19   R    =   d/twoa
20  A1    =   L + R
21  A2    =   L - R\0
22"""
23
24# The program should print:
25
26# d = sqrt(b^2 - 4*a*c);twoa = 2*a; L = -b/twoa; R = d/twoa; A1 = L + R;
27#A2 = L - R
28#done
29
30# getline: delivers the next input line to its invoker
31# disassembler: grabs input lines from getline, and delivers them one
32#    character at a time to squasher, also inserting a semicolon into
33#    the stream between lines
34# squasher:  grabs characters from disassembler and passes them on to
35#    assembler, first replacing "**" with "^" and squashing runs of
36#    whitespace
37# assembler: grabs characters from squasher and packs them into lines
38#    with 72 character each, delivering each such line to putline;
39#    when it sees a null byte, passes the last line to putline and
40#    then kills all the coroutines
41# putline: grabs lines from assembler, and just prints them
42
43from Coroutine import *
44
45def getline(text):
46    for line in string.splitfields(text, '\n'):
47        co.tran(codisassembler, line)
48
49def disassembler():
50    while 1:
51        card = co.tran(cogetline)
52        for i in range(len(card)):
53            co.tran(cosquasher, card[i])
54        co.tran(cosquasher, ';')
55
56def squasher():
57    while 1:
58        ch = co.tran(codisassembler)
59        if ch == '*':
60            ch2 = co.tran(codisassembler)
61            if ch2 == '*':
62                ch = '^'
63            else:
64                co.tran(coassembler, ch)
65                ch = ch2
66        if ch in ' \t':
67            while 1:
68                ch2 = co.tran(codisassembler)
69                if ch2 not in ' \t':
70                    break
71            co.tran(coassembler, ' ')
72            ch = ch2
73        co.tran(coassembler, ch)
74
75def assembler():
76    line = ''
77    while 1:
78        ch = co.tran(cosquasher)
79        if ch == '\0':
80            break
81        if len(line) == 72:
82            co.tran(coputline, line)
83            line = ''
84        line = line + ch
85    line = line + ' ' * (72 - len(line))
86    co.tran(coputline, line)
87    co.kill()
88
89def putline():
90    while 1:
91        line = co.tran(coassembler)
92        print line
93
94import string
95co = Coroutine()
96cogetline = co.create(getline, test)
97coputline = co.create(putline)
98coassembler = co.create(assembler)
99codisassembler = co.create(disassembler)
100cosquasher = co.create(squasher)
101
102co.tran(coputline)
103print 'done'
104
105# end of example
106