summaryrefslogtreecommitdiff
path: root/ipl/packs/ibpag2/slrtbls.icn
diff options
context:
space:
mode:
Diffstat (limited to 'ipl/packs/ibpag2/slrtbls.icn')
-rw-r--r--ipl/packs/ibpag2/slrtbls.icn370
1 files changed, 370 insertions, 0 deletions
diff --git a/ipl/packs/ibpag2/slrtbls.icn b/ipl/packs/ibpag2/slrtbls.icn
new file mode 100644
index 0000000..8d00f12
--- /dev/null
+++ b/ipl/packs/ibpag2/slrtbls.icn
@@ -0,0 +1,370 @@
+############################################################################
+#
+# Name: slrtbls.icn
+#
+# Title: slr table generation routines
+#
+# Author: Richard L. Goerwitz
+#
+# Version: 1.20
+#
+############################################################################
+#
+# Contains make_slr_tables(grammar, atbl, gtbl, noconflict,
+# like_yacc), where grammar is an ib_grammar record (as returned by
+# ibreader), where atbl and gtbl are initialized (default &null) hash
+# tables, and where noconflict is a switch that, if nonnull, directs
+# the resolver to abort on unresolvable conflicts. Returns &null if
+# successful in filling out atbl and gtbl. If likeyacc is nonnull,
+# make_slr_tables will resolve reduce/reduce conflicts by order of
+# occurrence in the grammar, just like YACC. Shift/reduce conflicts
+# will be resolved in favor of shift.
+#
+# The reason for the noconflict switch is that there are parsers that
+# can accept tables with multiple action entries, i.e. parsers that
+# can use tables generated by ambiguous grammars.
+#
+# In this routine's case, success is identified with creating a
+# standard SLR action and goto table. Note that both tables end up
+# as tables of tables, with symbols being the primary or first key,
+# and state numbers being the second. This is the reverse of the
+# usual arrangement, but turns out to save a lot of space. Atbl
+# values are of the form "s2.3", "r4<A>10", "a", etc. The string
+# "s2.3" means "shift the current lookahead token, and enter state 2
+# via rule 3." By way of contrast, "r4<A>10" means "reduce by rule
+# number 4, which has A as its LHS symbol and 10 RHS symbols." A
+# single "a" means "accept."
+
+# Atbl entries may contain more than one action. The actions are
+# simply concatenated: "s2.3r4<A>10a". Conflicts may be resolved
+# later by associativity or precedence, if available. Unresolvable
+# conflicts only cause error termination if the 5th and final
+# argument is nonnull (see above on "noconflict").
+#
+# Gtbl entries are simpler than atble entries, consisting of a single
+# integer.
+#
+############################################################################
+#
+# Links: follow, slritems, iohno
+#
+############################################################################
+
+# declared in ibreader.icn
+# record ib_grammar(start, rules, tbl)
+
+#link follow, slritems, iohno#, ximage
+
+#
+# make_slr_tables
+#
+procedure make_slr_tables(grammar, atbl, gtbl, noconflict, like_yacc)
+
+ local start_symbol, st, C, i, augmented_start_symbol, item,
+ symbol, new_item_list, j, action
+
+ # Initialize start symbol and rule list/set (either is okay).
+ start_symbol := grammar.start
+ st := grammar.rules
+
+ # Number the rules, and then construct the canonical LR(0) item sets.
+ every i := 1 to *st do st[i].no := i
+ C := make_slr_item_sets(start_symbol, st)
+
+ # Now, go through each item in each item set in C filling out the
+ # action (atbl) and goto table (gtbl) as we go.
+ #
+ augmented_start_symbol := "`_" || start_symbol || "_'"
+ every i := 1 to *C do {
+ every item := !C[i] do {
+ # if the dot's *not* at the end of the production...
+ if symbol := item.RHS[item.POS] then {
+ # if were looking at a terminal, enter a shift action
+ if type(symbol) == "integer" then {
+ if symbol = -2 then next # Never shift epsilon!
+ new_item_list := slr_goto(C[i], symbol, st)
+ every j := 1 to *C do {
+ if equivalent_item_lists(new_item_list, C[j]) then {
+ action := "s" || j || "." || item.no
+ resolve(st, atbl, symbol, i, action,
+ noconflict, like_yacc)
+ break next
+ }
+ }
+ # if we're looking at a nonterminal, add action to gtbl
+ } else {
+ new_item_list := slr_goto(C[i], symbol, st)
+ every j := 1 to *C do {
+ if equivalent_item_lists(new_item_list, C[j]) then {
+ /gtbl[symbol] := table()
+ /gtbl[symbol][i] := j |
+ gtbl[symbol][i] =:= j |
+ iohno(80, image(symbol), ".", image(i), ":", j)
+ break next
+ }
+ }
+ }
+ # ...else if the dot *is* at the end of the production
+ } else {
+ if item.LHS == augmented_start_symbol then {
+ action := "a"
+ # 0 = EOF
+ resolve(st, atbl, 0, i, action, noconflict, like_yacc)
+ } else {
+ # add a reduce for every symbol in FOLLOW(item.LHS)
+ every symbol := !FOLLOW(start_symbol, st, item.LHS) do {
+ # RHS size is 0 for epsilon.
+ if item.RHS[1] === -2 then {
+ action := "r" || item.no || "<" || item.LHS ||
+ ">0"
+ } else
+ action := "r" || item.no || "<" || item.LHS ||
+ ">" || *item.RHS
+ resolve(st, atbl, symbol, i, action,
+ noconflict, like_yacc)
+ }
+ }
+ }
+ }
+ }
+
+ return
+
+end
+
+
+#
+# resolve: list|set x table x string|integer, integer, anything, anything
+# -> string
+# (st, tbl, symbol, state, action, noconflict, like_yacc)
+# -> new_action_list
+#
+# Add action to action table, resolving conflicts by precedence
+# and associativity, if need be. If noconflict is nonnull, abort
+# on unresolvable conflicts. Fails on shift/shift "conflicts," or
+# if an identical action is already present in the table entry to
+# be modified. If like_yacc is nonnull, resolve reduce/reduce
+# conflicts by their order of occurrence in the grammar; resolve
+# shift/reduce conflicts in favor of shift.
+#
+procedure resolve(st, tbl, symbol, state, action, noconflict, like_yacc)
+
+ local actions, chr, a, ruleno, p, newp
+
+ /tbl[symbol] := table()
+ /tbl[symbol][state] := ""
+
+ # If this action is already present, then don't re-enter it. Just
+ # fail.
+ #
+ tbl[symbol][state] ? {
+ while a := tab(any('sra')) do {
+ a ||:= tab(upto('.<'))
+ a ||:= { (="<" || tab(find(">")+1)) | ="." }
+ a ||:= tab(many(&digits))
+ if a == action then fail
+ }
+ }
+
+ # Get rule number for the new action specified as arg 5, and
+ # fetch its source production.
+ action ? {
+ case move(1) of {
+ "s": ruleno := (tab(find(".")+1), tab(many(&digits)))
+ "r": ruleno := 1(tab(find("<")), move(1))
+ "a": return tbl[symbol][state] := action || tbl[symbol][state]
+ } | iohno(70, tbl[symbol][state])
+ (newp := !st).no = ruleno |
+ iohno(72, tbl[symbol][state])
+ }
+
+ # Resolve any conflicts that might be present.
+ #
+ actions := ""
+ tbl[symbol][state] ? {
+ while a := tab(any('sra')) do {
+ # Snip out the old action, and put it into a.
+ a ||:= tab(upto('.<'))
+ a ||:= { (="<" || tab(find(">")+1)) | ="." }
+ a ||:= tab(many(&digits))
+ #
+ # Get the old action's rule number, and use it to fetch
+ # the full production that it is keyed to.
+ #
+ a ? {
+ case move(1) of {
+ "s": ruleno := (tab(find(".")+1), tab(many(&digits)))
+ "r": ruleno := 1(tab(find("<")), move(1))
+ "a": return tbl[symbol][state] := a || actions || action
+ } | iohno(70, tbl[symbol][state])
+ # Go through rule list; find the one whose number is ruleno.
+ (p := !st).no = ruleno |
+ iohno(71, tbl[symbol][state])
+ }
+
+ # Check precedences to see if we can resolve the conflict
+ # this way.
+ #
+ if \newp.prec > \p.prec then
+ # discard the old action, a
+ return tbl[symbol][state] := actions || action || tab(0)
+ else if \newp.prec < \p.prec then
+ # discard the new action, action
+ return tbl[symbol][state] := actions || a || tab(0)
+ else {
+ #
+ # If, however, both precedences are the same (i.e.
+ # newp.prec === p.prec), then we must check the
+ # associativities. Right implies shift; left, reduce.
+ # If there is no associativity, then we have a
+ # conflict. Nonassociative ("n") implies error.
+ #
+ case action[1] of {
+ default: iohno(70, tbl[symbol][state])
+ # case "a" is handled above; look for "s" & "r"
+ "s" : {
+ if a[1] == "s" then fail # no shift/shift "conflict"
+ else if a[1] == "r" then {
+ newp.assoc === p.assoc | {
+ iohno(40, "state " || state || "; token " ||
+ symbol || "; rules " || newp.no ||
+ "," || p.no)
+ }
+ case newp.assoc of {
+ "n" : iohno(41, production_2_string(newp))
+ &null: { # no associativity given
+ if \noconflict & /like_yacc then
+ iohno(46, "state " || state ||
+ "; token " || symbol ||
+ "; rules " || newp.no ||
+ "," || p.no)
+ else {
+ write(&errout, "warning: shift/reduce",
+ " conflict in state " || state ||
+ "; token " || symbol ||
+ "; rules " || newp.no ||
+ "," || p.no)
+ if \like_yacc then {
+ write(&errout, "resolving in _
+ favor of shift.")
+ return tbl[symbol][state] :=
+ actions || action || tab(0)
+ } else {
+ write(&errout, "creating multi-_
+ action table entry")
+ return tbl[symbol][state] :=
+ actions || action || a || tab(0)
+ }
+ }
+ }
+ "l" : { # left associative
+ # discard new action, action
+ return tbl[symbol][state] :=
+ actions || a || tab(0)
+ }
+ "r" : { # right associative
+ # remove old action, a
+ return tbl[symbol][state] :=
+ actions || action || tab(0)
+ }
+ }
+ }
+ }
+ "r" : {
+ if a[1] == "r" then {
+ #
+ # If conflicts in general, and reduce-reduce
+ # conflicts in specific are not okay...
+ #
+ if \noconflict & /like_yacc then {
+ # ...abort, otherwise...
+ iohno(42, "state " || state || "; token " ||
+ symbol || "; " || "; rules " ||
+ newp.no || "," || p.no)
+ } else {
+ #
+ # ...flag reduce-reduce conficts, and
+ # then resolve them by their order of
+ # occurrence in the grammar.
+ #
+ write(&errout, "warning: reduce/reduce",
+ " conflict in state ", state,
+ "; token ", symbol, "; rules ",
+ newp.no, ",", p.no)
+ if \like_yacc then {
+ write(&errout, "resolving by order of _
+ occurrence in the grammar")
+ if newp.no > p.no
+ # discard later production (newp)
+ then return return tbl[symbol][state] :=
+ actions || a || tab(0)
+ # discard later production (old p)
+ else return tbl[symbol][state] :=
+ actions || action || tab(0)
+ } else {
+ #
+ # If conflicts ok, but we aren't supposed
+ # to resolve reduce-reduce conflicts by
+ # order of rule occurrence:
+ #
+ write(&errout, "creating multi-action _
+ table entry")
+ return tbl[symbol][state] :=
+ actions || action || a || tab(0)
+ }
+ }
+ } else {
+ # associativities must be the same for both rules:
+ newp.assoc === p.assoc | {
+ iohno(40, "state " || state || "; token " ||
+ symbol || "; rules " || newp.no ||
+ "," || p.no)
+ }
+ case newp.assoc of {
+ "n" : iohno(41, production_2_string(newp))
+ &null: {
+ if \noconflict & /like_yacc then
+ iohno(46, "state " || state ||
+ "; token " || symbol ||
+ "; rules " || newp.no ||
+ "," || p.no)
+ else {
+ write(&errout, "warning: shift/reduce",
+ " conflict in state " || state ||
+ "; token " || symbol ||
+ "; rules " || newp.no ||
+ "," || p.no)
+ if \like_yacc then {
+ write(&errout, "resolving in _
+ favor of shift.")
+ return tbl[symbol][state] :=
+ actions || a || tab(0)
+ } else {
+ write(&errout, "creating multi-_
+ action table entry")
+ return tbl[symbol][state] :=
+ actions || action || a || tab(0)
+ }
+ }
+ }
+ "r" : {
+ # discard new action, action
+ return tbl[symbol][state] :=
+ actions || a || tab(0)
+ }
+ "l" : {
+ # remove old action, a
+ return tbl[symbol][state] :=
+ actions || action || tab(0)
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return tbl[symbol][state] ||:= action
+
+end