-- LR1ItemsImpl.mesa -- last edit September 11, 1984 3:11:25 pm PDT -- Sturgis, June 3, 1986 2:52:37 pm PDT DIRECTORY GrammarBasic USING[Grammar, Symbol, Production, GenProductions, GenProductionsForSymbol, GetAssociatedLR1Closure, NoteAssociatedLR1Closure, TestCanProduceEmpty], TerminalSequences USING[TerminalSeq, TerminalSeqSet, CreateEmptyTerminalSeqSet, GetEmptyTerminalSeq, GenFirstNonEmptyTerminalSeqs, GetSetOfExactlyTheEmptyTermSeq, GetWithEmptyTerminalSeqRemoved, InsertTerminalSeqInSet, InsertTermSeqSetInSet, TestIfEmptySeqInSet, TestIfTerminalSeqSetEmpty], LR0ItemSetsBasic USING[LR0Item], LR0Items USING[GetGrammarFromLR0Item, GetFirstSymbol, GetFirstLR0Item, GetNextLR0Item, GetProductionAndPosition, GetStartLR0Item, GenKernelGoTo0Items], LR1ItemSetsBasic USING[LR1Item, LR1ItemSet, LR1ItemSubset, CreateEmptyLR1ItemSet, InsertItemInLR1ItemSet, GenerateDirtySubsetsFromLR1ItemSet, GenerateSubsetsFromLR1ItemSet, FreezeLR1ItemSet, InsertSubsetInLR1ItemSet, NarrowLR1ItemSet], LR1Items USING[]; LR1ItemsImpl: CEDAR PROGRAM IMPORTS GrammarBasic, LR0Items, LR1ItemSetsBasic, TerminalSequences EXPORTS LR1Items = BEGIN OPEN GrammarBasic, TerminalSequences, LR0ItemSetsBasic, LR0Items, LR1ItemSetsBasic; GenKernelV1EpsilonItemSubsets: PUBLIC PROC[grammar: Grammar, for: PROC[LR1ItemSubset]] = BEGIN terminals: TerminalSeqSet _ CreateEmptyTerminalSeqSet[grammar]; [] _ InsertTerminalSeqInSet[terminals, GetEmptyTerminalSeq[grammar]]; for[[GetStartLR0Item[grammar], terminals]]; END; GenKernelGoTo1ItemSubsetsFromKernelItemSubset: PUBLIC PROC[from: LR1ItemSubset, for: PROC[Symbol, LR1ItemSubset]] = BEGIN GenPreCloseGoTo1ItemSubsets: PROC[innerSubset: LR1ItemSubset, innerFor: PROC[Symbol, LR1ItemSubset]] = BEGIN SeeOneLR0Item: PROC[s: Symbol, lr0Item: LR0Item] = {innerFor[s, [lr0Item, innerSubset.terminals]]}; GenKernelGoTo0Items[innerSubset.lr0Item, SeeOneLR0Item]; END; HandleOneCloseSubset: PROC[closeSubset: LR1ItemSubset] = {GenPreCloseGoTo1ItemSubsets[closeSubset, for]}; GenCloseOfLR1ItemSubset[from, HandleOneCloseSubset]; END; -- this procedure depends on some precomputed info GenCloseOfLR1ItemSubset: PUBLIC PROC[firstSubset: LR1ItemSubset, for: PROC[LR1ItemSubset]] = BEGIN grammar: Grammar _ GetGrammarFromLR0Item[firstSubset.lr0Item]; emptySeq: TerminalSeq _ GetEmptyTerminalSeq[grammar]; SecondStepOfClose: PROC[secondSubset: LR1ItemSubset] = BEGIN -- secondItem is always of the form [A _ .b, t], and it appears in the closure unless t = e. -- and we have pre computed closure([A _ .b, e]) maskedSecondTerms: TerminalSeqSet; ThirdStepOfClose: PROC[thirdSubset: LR1ItemSubset] = BEGIN maskedThirdTerms: TerminalSeqSet; maskedThirdTerms _ GetWithEmptyTerminalSeqRemoved[thirdSubset.terminals]; IF maskedThirdTerms # NIL THEN for[[thirdSubset.lr0Item, maskedThirdTerms]]; IF NOT TestIfEmptySeqInSet[thirdSubset.terminals] THEN RETURN; IF maskedSecondTerms # NIL THEN for[[thirdSubset.lr0Item, maskedSecondTerms]]; IF NOT TestIfEmptySeqInSet[secondSubset.terminals] THEN RETURN; for[[thirdSubset.lr0Item, firstSubset.terminals]]; END; production: Production _ GetProductionAndPosition[secondSubset.lr0Item].production; -- A _ b subClosure: LR1ItemSet _ NarrowLR1ItemSet[GetAssociatedLR1Closure[production]]; -- close([A _ .b, e]) IF subClosure = NIL THEN -- they havn't been built yet BEGIN PreComputeClosures[grammar]; subClosure _ NarrowLR1ItemSet[GetAssociatedLR1Closure[production]]; END; maskedSecondTerms _ GetWithEmptyTerminalSeqRemoved[secondSubset.terminals]; IF maskedSecondTerms # NIL THEN for[[secondSubset.lr0Item, maskedSecondTerms]]; GenerateSubsetsFromLR1ItemSet[subClosure, ThirdStepOfClose]; END; for[firstSubset]; -- the input ItemSubset itself is in the closure GenOneCloseStep[[firstSubset.lr0Item, GetSetOfExactlyTheEmptyTermSeq[grammar]], SecondStepOfClose]; -- here are the rest, with possible repetitions END; -- support code -- this procedure pre-computes the closures of certain items, and associates one such closure with each production. It associates close([A_.b, e]) with the production A_b. PreComputeClosures: PROC[grammar: Grammar] = BEGIN emptySeq: TerminalSeq _ GetEmptyTerminalSeq[grammar]; HandleOneProduction: PROC[production: Production] = BEGIN closure: LR1ItemSet _ ConstructFullClosure[[GetFirstLR0Item[production], emptySeq]]; NoteAssociatedLR1Closure[production, closure]; END; GenProductions[grammar, HandleOneProduction]; END; -- following procedure is used to generate a full closure using the basic close definition. The results are captured in an ItemSet. The caller will associated these item sets with the first position in each productions. ConstructFullClosure: PROC[lr1Item: LR1Item] RETURNS[LR1ItemSet] = BEGIN grammar: Grammar _ GetGrammarFromLR0Item[lr1Item.lr0Item]; tentative: LR1ItemSet _ CreateEmptyLR1ItemSet[grammar]; moreToDo: BOOLEAN _ TRUE; [] _ InsertItemInLR1ItemSet[tentative, lr1Item]; WHILE moreToDo DO InstallOneSubset: PROC[closureItems: LR1ItemSubset] = {IF InsertSubsetInLR1ItemSet[closureItems, tentative] THEN moreToDo _ TRUE}; HandleOneSubset: PROC[subsetToClose: LR1ItemSubset] = {GenOneCloseStep[subsetToClose, InstallOneSubset]}; moreToDo _ FALSE; GenerateDirtySubsetsFromLR1ItemSet[tentative, HandleOneSubset]; ENDLOOP; RETURN[FreezeLR1ItemSet[tentative, FALSE]]; END; -- this is the basic close definition, a closure is obtained by combining the input item with the result of the repeated application of this procedure. GenOneCloseStep: PROC[lr1ItemSubset: LR1ItemSubset, for: PROC[LR1ItemSubset]] = BEGIN leftSide: Symbol _ GetFirstSymbol[lr1ItemSubset.lr0Item]; -- the first symbol after the "dot" grammar: Grammar _ GetGrammarFromLR0Item[lr1ItemSubset.lr0Item]; emptySeq: TerminalSeq _ GetEmptyTerminalSeq[grammar]; terminalSet: TerminalSeqSet _ CreateEmptyTerminalSeqSet[grammar]; -- first check for obviously empty closure IF leftSide = NIL THEN RETURN; -- first, build the terminal set that will follow each LR0 Item in the closure BEGIN remainder: LR0Item _ GetNextLR0Item[lr1ItemSubset.lr0Item]; emptyInPrev: BOOLEAN _ TRUE; -- initial value, lets the loop go around once WHILE remainder.ref # NIL AND emptyInPrev DO firstOfRemainder: Symbol _ GetFirstSymbol[remainder]; IF firstOfRemainder # NIL THEN BEGIN noSeqsSeen: BOOLEAN _ TRUE; -- tentative; SeeOneTerminalSeq: PROC[seq: TerminalSeq] = BEGIN IF seq # emptySeq THEN [] _ InsertTerminalSeqInSet[terminalSet, seq] ELSE emptyInPrev _ TRUE; noSeqsSeen _ FALSE; END; emptyInPrev _ FALSE; -- tentative value GenFirstNonEmptyTerminalSeqs[firstOfRemainder, SeeOneTerminalSeq]; IF noSeqsSeen THEN emptyInPrev _ TRUE; IF TestCanProduceEmpty[firstOfRemainder] THEN emptyInPrev _ TRUE; END ELSE emptyInPrev _ TRUE; remainder _ GetNextLR0Item[remainder]; ENDLOOP; IF emptyInPrev THEN {[] _ InsertTermSeqSetInSet[add: lr1ItemSubset.terminals, to: terminalSet]}; END; -- again, check for empty closure IF TestIfTerminalSeqSetEmpty[terminalSet] THEN RETURN; -- now generate the lr0 items for the closure, and present the combined result to the caller. BEGIN HandleOneProduction: PROC[production: Production] = BEGIN lr0Item: LR0Item _ GetFirstLR0Item[production]; for[[lr0Item, terminalSet]]; END; GenProductionsForSymbol[leftSide, HandleOneProduction]; END; END; -- September 13, 1984 9:03:04 am PDT: this seems all wrong, and I am replacing it with new code. However, I am holding it around just in case I am confused at this time. OldGenOneCloseStep: PROC[lr1ItemSubset: LR1ItemSubset, for: PROC[LR1ItemSubset]] = BEGIN leftSide: Symbol _ GetFirstSymbol[lr1ItemSubset.lr0Item]; -- the first symbol after the "dot" grammar: Grammar _ GetGrammarFromLR0Item[lr1ItemSubset.lr0Item]; emptySeq: TerminalSeq _ GetEmptyTerminalSeq[grammar]; HandleOneProduction: PROC[production: Production] = BEGIN lr0Item: LR0Item _ GetFirstLR0Item[production]; remainder: LR0Item _ GetNextLR0Item[lr1ItemSubset.lr0Item]; emptyInPrev: BOOLEAN _ TRUE; -- initial value, lets the loop go around once WHILE remainder.ref # NIL AND emptyInPrev DO firstOfRemainder: Symbol _ GetFirstSymbol[remainder]; terminals: TerminalSeqSet _ CreateEmptyTerminalSeqSet[grammar]; SeeOneTerminalSeq: PROC[seq: TerminalSeq] = BEGIN IF seq # emptySeq THEN [] _ InsertTerminalSeqInSet[terminals, seq] ELSE emptyInPrev _ TRUE; END; IF firstOfRemainder # NIL THEN BEGIN maskedTerminals: TerminalSeqSet; emptyInPrev _ FALSE; -- tentative value GenFirstNonEmptyTerminalSeqs[firstOfRemainder, SeeOneTerminalSeq]; maskedTerminals _ GetWithEmptyTerminalSeqRemoved[terminals]; IF maskedTerminals # NIL THEN for[[lr0Item, maskedTerminals]]; END ELSE emptyInPrev _ TRUE; remainder _ GetNextLR0Item[remainder]; ENDLOOP; IF emptyInPrev THEN for[[lr0Item, lr1ItemSubset.terminals]]; END; IF leftSide # NIL THEN GenProductionsForSymbol[leftSide, HandleOneProduction]; END; END.. -- remark: September 14, 1984 11:02:33 am PDT: yet another bug in one close step. If a production has right side, then SeeOneTerminalSeq in the innermost loop never gets called. In this case, we must set emptyInPrev to TRUE, but we didn't. -- remark: September 21, 1984 5:33:06 pm PDT: yet another bug in one close step. We must set emptyInPrev true if first of remainder can be empty. (This is because GenFirstNonEmptySeqs will not generate the empty seq (by design)). ÊR˜Jšœ˜J˜2J˜'J˜˜ Jšœ¡˜¡Jšœ¢˜¢Jšœ ˜ Jšœ—˜—Jšœë˜ëJšœ˜—J˜J˜Jšœs˜s˜JšœY˜YJ˜J˜˜YJ˜J˜?J˜EJ˜+J˜—J˜šœs˜sJ˜˜gJ˜˜2J˜0—J˜8J˜—J˜˜8J˜0J˜—J˜4J˜—J˜J˜J˜J˜J˜2˜]J˜J˜>J˜5J˜˜6Jšœ˜Jšœ*Ïgœ/œ˜\Jšœ*œœ˜0J˜J˜"J˜˜4J˜J˜!J˜IJ˜LJ˜>J˜NJ˜?J˜2J˜J˜—Jšœ[˜\Jšœ_œœ˜eJ˜˜6J˜J˜JšœC˜CJ˜J˜—J˜KJ˜OJ˜J˜—J˜J˜&J˜—J˜