summaryrefslogtreecommitdiff
path: root/ipl/packs/ibpag2/ibutil.icn
blob: d16e511968f99fee4dc3e0aaa98691a5b4058db3 (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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
############################################################################
#
#	Name:	 ibutil.icn
#
#	Title:	 utilities for Ibpag2
#
#	Author:	 Richard L. Goerwitz
#
#	Version: 1.21
#
############################################################################
#  
#  Contains:
#
#      production_2_string(p)	    makes production or item p human-
#				    readable 
#
#      print_item_list(C, i)        returns human-readable version of
#                                   item list C
#
#      print_grammar(grammar, f)    sends to file f (default &output)
#                                   a human-readable printout of a grammar,
#                                   as recorded in an ib_grammar structure
#
#      print_action_goto_tables(atbl, gtbl, ibtoktbl, f)
#                                   sends to file f (default (&output)
#                                   a human-readable printout of action
#                                   table atbl and goto table gtbl
#
#      print_follow_sets(FOLLOW_table)
#                                   returns a human-readable version
#                                   of a FOLLOW table (table of sets)
#
#      print_first_sets(FIRST_table)
#                                   returns a human-readable version
#                                   of a FIRST table (a table of sets)
#
#      ibreplace(s1, s2, s3)	    replaces s2 with s3 in s1
#
#      equivalent_items(i1, i2)     succeeds if item i1 is structurally
#				    identical to item i2
#
#      equivalent_item_lists(l1,l2) same as equivalent_items, but for
#                                   lists of items, not individual items
#
############################################################################
#
#  Links: none
#
############################################################################


record production(LHS, RHS, POS, LOOK, no, prec, assoc)

#
# production_2_string:  production record -> string
#                       p                 -> s
#
#     Stringizes an image of the LHS and RHS of production p in
#     human-readable form.
#
procedure production_2_string(p, ibtoktbl)

    local s, m, t

    s := image(p.LHS) || " -> "
    every m := !p.RHS do {
	if t := \ (\ibtoktbl)[m]
	then s ||:= t || " "
	else s ||:= image(m) || " "
    }
    # if the POS field is nonnull, print it
    s ||:= "(POS = " || image(\p.POS) || ") "
    # if the LOOK field is nonnull, print it, too
    s ||:= "lookahead = " || image(\p.LOOK)

    return trim(s)

end


#
# print_item_list:  makes item list human readable
#
procedure print_item_list(C, i)

    write(&errout, "Productions for item list ", i, ":")
    every write(&errout, "\t", production_2_string(!C[i]))
    write(&errout)
    return

end


#
# print_grammar:  makes entire grammar human readable
#
procedure print_grammar(grammar, f)

    local p, i, sl

    /f := &errout

    write(f, "Start symbol:")
    write(f, "\t", grammar.start)
    write(f)
    write(f, "Rules:")
    every p := !grammar.rules do {
	writes(f, "\tRule ", right(p.no, 3, " "), "  ")
	write(f, production_2_string(p, grammar.tbl))
    }
    write(f)
    write(f, "Tokens:")
    sl := sort(grammar.tbl, 3)
    every i := 1 to *sl-1 by 2 do
	write(f, "\t", left(sl[i], 5, "."), right(sl[i+1], 20, "."))
    write(f)
    return

end


#
# print_action_goto_tables
#
#     Makes action & goto tables human readable.  If a table mapping
#     integer (i.e. char) literals to token names is supplied, the
#     token names themselves are printed.
#
procedure print_action_goto_tables(atbl, gtbl, ibtoktbl, f)

    local TAB, tbl, key_set, size, i, column, k

    /f := &errout
    TAB := "\t"

    every tbl := atbl|gtbl do {

	key_set := set(); every insert(key_set, key(tbl))
	writes(f, TAB)
	every k := !key_set do
	    writes(f, \(\ibtoktbl)[k] | k, TAB)
	write(f)
	
	size := 0; every size <:= key(!tbl)
	every i := 1 to size do {
	    writes(f, i, TAB)
	    every column := tbl[!key_set] do {
		# action lists may have more than one element
		if /column[i] then
		    writes(f, "  ", TAB) & next
		\column[i] ? {
		    if any('asr') then {
			while any('asr') do {
			    writes(f, ="a") & next
			    writes(f, tab(upto('.<')))
			    if ="<" then tab(find(">")+1) else ="."
			    tab(many(&digits))
			}
			writes(f, TAB)
		    }
		    else writes(f, tab(many(&digits)), TAB)
		}
	    }
	    write(f)
	}
	write(f)
    }

    return

end


#
# print_follow_sets:  make FOLLOW table human readable
#
procedure print_follow_sets(FOLLOW_table)

    local FOLLOW_sets, i

    FOLLOW_sets := sort(FOLLOW_table, 3)
    write(&errout, "FOLLOW sets are as follows:")
    every i := 1 to *FOLLOW_sets-1 by 2 do {
	writes(&errout, "\tFOLLOW(", image(FOLLOW_sets[i]), ") = ")
	every writes(&errout, image(! FOLLOW_sets[i+1]), " ")
	write(&errout)
    }
    write(&errout)
    return

end


#
# print_first_sets:  make FIRST table human readable
#
procedure print_first_sets(FIRST_table)

    local FIRST_sets, i

    FIRST_sets := sort(FIRST_table, 3)
    write(&errout, "FIRST sets are as follows:")
    every i := 1 to *FIRST_sets-1 by 2 do {
	writes(&errout, "\tFIRST(", image(FIRST_sets[i]), ") = ")
	every writes(&errout, image(! FIRST_sets[i+1]), " ")
	write(&errout)
    }
    write(&errout)
    return

end


#
# ibreplace: string x string x string -> string
#            (s1,     s2,      s3)    -> s4
#
#     Where s4 is s1, with every instance of s2 stripped out and
#     replaced by s3.  E.g. replace("hello there; hello", "hello",
#     "hi") yields "hi there; hi".  Taken straight from the IPL.
#
procedure ibreplace(s1,s2,s3)

    local result, i

    result := ""
    i := *s2

    s1 ? {
	while result ||:= tab(find(s2)) do {
	    result ||:= s3
	    move(i)
	}
	return result || tab(0)
    }

end

    
#
# equivalent_items:  record x record -> record or failure
#                    (item1,  item2) -> item1  or failure
#
#     Where item1 and item2 are records having LHS, RHS, POS, & LOOK
#     fields (and possibly others, though they aren't used).  Returns
#     item1 if item1 and item2 are structurally identical as far as
#     their LHS, RHS, LOOK, and POS fields are concerned.  For SLR
#     table generators, LOOK will always be null.
#
procedure equivalent_items(item1, item2)

    local i

    item1 === item2 & (return item1)

    if item1.LHS == item2.LHS &
	item1.POS = item2.POS &
	#
	# This comparison doesn't have to be recursive, since I take
	# care never to alter RHS structures.  Identical RHSs should
	# always be *the same underlying structure*.
	#
	item1.RHS === item2.RHS &
	item1.LOOK === item2.LOOK
    then
	return item1

end


#
# equivalent_item_lists: list x list -> list or fail
#                        (il1,  il2) -> il1
#
#     Where il1 is one sorted list-of-items (as returned by goto() or
#     by closure()), where il2 is another such list.  Returns the
#     first list if the LHS, RHS, and POS fields of the constituent
#     items are all structurally identical, i.e. if the two lists
#     contain the structurally identical items.
#
procedure equivalent_item_lists(il1, il2)

    local i

    il1 === il2 & (return il1)
    if *il1 = *il2
    then {
	every i := 1 to *il1 do
            equivalent_items(il1[i], il2[i]) | fail
    }
    else fail

    return il1

end