summaryrefslogtreecommitdiff
path: root/ipl/progs/parse.icn
blob: ee3c11c3973b87e867a87e58d01b5d5da40ac6e4 (plain)
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