summaryrefslogtreecommitdiff
path: root/ipl/packs/tcll1/ll1.icn
diff options
context:
space:
mode:
Diffstat (limited to 'ipl/packs/tcll1/ll1.icn')
-rw-r--r--ipl/packs/tcll1/ll1.icn279
1 files changed, 279 insertions, 0 deletions
diff --git a/ipl/packs/tcll1/ll1.icn b/ipl/packs/tcll1/ll1.icn
new file mode 100644
index 0000000..65f97e9
--- /dev/null
+++ b/ipl/packs/tcll1/ll1.icn
@@ -0,0 +1,279 @@
+
+link gramanal
+link xcode
+
+global outFile
+
+global fiducials #set(Symbol)
+global selectionSet #table:Production->Set(Symbol)
+ # set of symbols that choose this production
+ # if lhs is atop the stack
+
+#
+#
+#
+procedure analyzeGrammar()
+
+findMinLeng()
+checkMinLeng()
+checkAccessibility()
+findFirstSets()
+findLastSets()
+checkLnRRecursive()
+findFollowSets()
+
+end
+
+procedure declareFiducial(s)
+local t
+/symbol[s] := Symbol(s)
+t := symbol[s]
+/t.kind := "Terminal"
+if t.kind ~== "Terminal" then {
+ error(t.kind," ",s," being declared a fiducial")
+ fail
+}
+insert(fiducials,t)
+return
+end
+
+procedure findSelectionSets()
+local p,r,s,t
+every p:=!!productions do {
+ s:= set()
+ every r := exposedLeft(p) do {
+ if isNonterminal(r) then {
+ s ++:= first[r]
+ } else if isTerminal(r) then {
+ insert(s,r)
+ }
+ }
+ if p.minLeng=0 then s ++:= follow[p.lhs]
+ every t := !s & not isTerminal(t) do delete(s,t)
+ selectionSet[p] := s
+}
+return
+end
+
+procedure ll1(outFileName)
+local t,g
+
+analyzeGrammar()
+findSelectionSets()
+
+testLL1()
+
+if errorCount>0 then fail
+
+outFile := open(outFileName,"w") |
+ {error( "unable to open output file ",outFileName)
+ return}
+
+t:=genLL1()
+#g:=encode(t)
+#write(outFile,g)
+xencode(t,outFile)
+#
+close(outFile)
+return
+
+end
+
+procedure testLL1()
+
+local n, plist, p1, p2, px, py, m, i, s
+
+#check for left recursion
+
+every n := !nonterminals do
+ if member(first[n],n) then
+ error(n.name," is left recursive, the grammar is not LL(1)")
+
+#check for overlapping selection sets
+
+every n := !nonterminals do {
+ plist := productions[n]
+ m := *plist
+ every p1 := plist[i:=1 to m-1] &
+ p2 := plist[i+1 to m] do {
+ if p1.minLeng = p2.minLeng = 0 then {
+ error("productions\n1.\t",
+ productionToString(p1),"\n2.\t",
+ productionToString(p2),
+ "\nboth derive the empty string" )
+ } else if *(s:=selectionSet[p1]**selectionSet[p2]) > 0 then {
+ if (p1.minLeng = 0) | (p2.minLeng = 0) then {
+ px:=p1; py:=p2; if px.minLeng=0 then px:=:py
+ warning("overlapping selection sets for\n\t",
+ productionToString(px),
+ "\nand empty-deriving production\n\t",
+ productionToString(py) )
+ } else {
+ error("overlapping selection sets for\n1.\t",
+ productionToString(p1),"\n2.\t",
+ productionToString(p2) )
+ }
+ showSymbolSet(" overlap: ",s)
+ }
+ }
+}
+return
+end
+
+procedure genLL1()
+local mapSymbol,
+ rhsList,
+ mapRHS,
+ emptyRHS,
+ sel,
+ deflt,
+ firstFiduc,
+ fiducList,
+ actionList,
+ termList,
+ minLengRHS
+local s,p,r,L,n,m,mr,ml,ms,nullrhs,t,i
+# build encapsulated symbols, [ name ], so that all references
+# to the symbol can share the same string
+mapSymbol := table()
+every s := !symbol do {
+ mapSymbol[s] := [s.name]
+}
+# map productions into right hand side lists with encapsulated symbols
+emptyRHS:=list()
+mapRHS := table()
+every p := !!productions do {
+ L:=list()
+ every s:= !p.rhs do put(L,mapSymbol[s])
+ mapRHS[p] := if *L = 0 then emptyRHS else L
+}
+#make a list of all right hand sides
+# the list will be used after input to remove the symbols
+# from their encapsulating lists
+rhsList:=[]
+every L:=!mapRHS do put(rhsList,L)
+
+#create selection and default tables
+sel:=table()
+deflt:=table()
+every n:=!nonterminals do {
+
+ # Build a list of productions for the nonterminal sorted by
+ # cardinality of selection set. Reserve a production with an
+ # empty-string-deriving RHS for special treatment. Put the
+ # productions into the sel table, but reserve the empty-deriving
+ # RHS or, if none, then the RHS with the largest selection set to
+ # be the default. If there is an overlap in selection sets between
+ # a non-empty-deriving and the empty-deriving RHS, then this will
+ # give precedence to the non-empty-deriving RHS, as is required to
+ # solve the "dangling else problem."
+
+ nullrhs:=&null
+ t:=table() #map productions into cardinality of selection set
+ every p:=!productions[n] do
+ if p.minLeng=0
+ then nullrhs:=p
+ else t[p] := *selectionSet[p]
+ L:=sort(t,2)
+ put(L,[\nullrhs,*selectionSet[nullrhs]])
+ if *L = 1 then {
+ deflt[mapSymbol[n]] := mapRHS[L[1][1]]
+ } else {
+ /sel[mapSymbol[n]] := table()
+ # if there is an empty-deriving RHS then put all other
+ # RHS's into sel table--the empty-deriving one will be
+ # the default. Or, if the largest selection set
+ # for any RHS is small enough, then put all RHS's into
+ # selection table. Otherwise, reserve the RHS with the
+ # largest selection set to be the default.
+ m := if /nullrhs & L[*L][2] < 5 then *L else *L-1
+ every i := 1 to m &
+ p := L[i][1] &
+ mr := mapRHS[p] &
+ ml := mapSymbol[p.lhs] &
+ ms := mapSymbol[!selectionSet[p]] do {
+ sel[ml][ms] := mr
+ }
+ # If not included already, handle the last.
+ if m~=*L then deflt[mapSymbol[n]]:=mapRHS[L[*L][1]]
+ }
+}
+
+termList := list()
+every s:=!terminals do put(termList,mapSymbol[s])
+
+actionList := list()
+every put(actionList,mapSymbol[!actions])
+
+fiducList := list()
+insert(fiducials,eoiSymbol)
+every put(fiducList,mapSymbol[!fiducials])
+
+firstFiduc := table()
+every n:=!nonterminals & *(s:=first[n]**fiducials)>0 do {
+ firstFiduc[mapSymbol[n]] := list()
+ every put(firstFiduc[mapSymbol[n]],
+ mapSymbol[!s])
+}
+
+minLengRHS := table()
+every n := !nonterminals do {
+ p := productions[n][1]
+ every r := !productions[n] &
+ p.minLeng > r.minLeng do p:=r
+ minLengRHS[mapSymbol[n]] := mapRHS[p]
+}
+
+return [
+ rhsList,
+ sel,
+ deflt,
+ termList,
+ actionList,
+ fiducList,
+ firstFiduc,
+ minLengRHS,
+ mapSymbol[startSymbol],
+ mapSymbol[eoiSymbol]
+ ]
+end
+
+
+#######################################################################
+#
+# printing the grammar
+#
+procedure printGrammar()
+local n,p,st,s
+write("start symbol:\t",startSymbol.name)
+write("EOI symbol:\t",eoiSymbol.name)
+write()
+showSymbolSet("terminal symbols: ",terminals)
+
+write()
+showSymbolSet("fiducial symbols: ",fiducials)
+
+write()
+showSymbolSet("action symbols: ",actions)
+
+write()
+write("nonterminal symbols:")
+st := set()
+every insert(st,(!nonterminals).name)
+st := sort(st)
+every n := !st do {
+ s := symbol[n]
+ write(" ",n,":")
+ showSymbolSet(" first set: ",first[s])
+ showSymbolSet(" follow set: ",follow[s])
+ write()
+}
+
+write("productions:")
+every p := !productions[symbol[!st]] do {
+ writeIndented(productionToString(p))
+ showSymbolSet(" : ",selectionSet[p])
+}
+return
+end
+