home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume44
/
ibpag2
/
part03
/
slrtbls.icn
< prev
Wrap
Text File
|
1994-09-25
|
12KB
|
371 lines
############################################################################
#
# Name: slrtbls.icn
#
# Title: slr table generation routines
#
# Author: Richard L. Goerwitz
#
# $Revision: 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