1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
############################################################################
#
# File: parse.icn
#
# Subject: Program to parse simple statements
#
# Author: Kenneth Walker
#
# Date: February 18, 1996
#
############################################################################
#
# This file is in the public domain.
#
############################################################################
#
# This program parses simple statements.
#
# It provides an interesting example of the use of co-expressions.
#
############################################################################
global lex # co-expression for lexical analyzer
global next_tok # next token from input
record token(type, string)
procedure main()
lex := create ((!&input ? get_tok()) | |token("eof", "eof"))
prog()
end
#
# get_tok is the main body of lexical analyzer
#
procedure get_tok()
local tok
repeat { # skip white space and comments
tab(many(' '))
if ="#" | pos(0) then fail
if any(&letters) then # determine token type
tok := token("id", tab(many(&letters ++ '_')))
else if any(&digits) then
tok := token("integer", tab(many(&digits)))
else case move(1) of {
";" : tok := token("semi", ";")
"(" : tok := token("lparen", "(")
")" : tok := token("rparen", ")")
":" : if ="=" then tok := token("assign", ":=")
else tok := token("colon", ":")
"+" : tok := token("add_op", "+")
"-" : tok := token("add_op", "-")
"*" : tok := token("mult_op", "*")
"/" : tok := token("mult_op", "/")
default : err("invalid character in input")
}
suspend tok
}
end
#
# The procedures that follow make up the parser
#
procedure prog()
next_tok := @lex
stmt()
while next_tok.type == "semi" do {
next_tok := @lex
stmt()
}
if next_tok.type ~== "eof" then
err("eof expected")
end
procedure stmt()
if next_tok.type ~== "id" then
err("id expected")
write(next_tok.string)
if (@lex).type ~== "assign" then
err(":= expected")
next_tok := @lex
expr()
write(":=")
end
procedure expr()
local op
term()
while next_tok.type == "add_op" do {
op := next_tok.string
next_tok := @lex
term()
write(op)
}
end
procedure term()
local op
factor()
while next_tok.type == "mult_op" do {
op := next_tok.string
next_tok := @lex
factor()
write(op)
}
end
procedure factor()
case next_tok.type of {
"id" | "integer": {
write(next_tok.string)
next_tok := @lex
}
"lparen": {
next_tok := @lex
expr()
if next_tok.type ~== "rparen" then
err(") expected")
else
next_tok := @lex
}
default:
err("id or integer expected")
}
end
procedure err(s)
stop(" ** error ** ", s)
end
|