-- GrammarBasicImpl.mesa
-- last edit September 10, 1984 3:49:59 pm PDT
-- Sturgis, April 1, 1986 1:23:25 pm PST
DIRECTORY
GenOneCasabaParserPrivate USING[GetErrorInfo, KillParserGen],
GrammarBasic USING[TerminalVariety],
IO USING[int, PutF, rope, STREAM],
Rope USING[Equal, Fetch, Length, ROPE];
GrammarBasicImpl: CEDAR PROGRAM IMPORTS GenOneCasabaParserPrivate, IO, Rope EXPORTS GrammarBasic =
BEGIN OPEN GenOneCasabaParserPrivate, GrammarBasic, Rope, IO;
-- first the basic grammar stuff
Grammar: TYPE = REF GrammarBody;
GrammarBody: PUBLIC TYPE = RECORD[
startProduction: Production ← NIL,
productions: Production ← NIL,
symbols: Symbol ← NIL,
symbolHashTable: SymbolHashTable,
terminalCount: CARDINAL ← 0,
terminalList: SymbolCell,
-- following entries record info for clients
terminalSeqCollection: REF ANY,
lr0ItemSetCollection: REF ANY,
lr0ItemCollection: REF ANY,
lr1ItemSetCollection: REF ANY
];
Symbol: TYPE = REF SymbolBody;
SymbolBody: PUBLIC TYPE = RECORD[
text: ROPE,
terminalVariety: TerminalVariety ← unique, -- used for terminals
spellingOrClass: ROPE, -- used for terminals
terminal: BOOLEAN,
producesTerminals: BOOLEAN,
reachable: BOOLEAN,
next: Symbol,
-- following entries record info for clients
productionList: REF ANY,
terminalSeq: REF ANY,
canProduceEmpty: BOOLEAN,
canBeFirstList: REF ANY
];
Production: TYPE = REF ProductionBody;
ProductionBody: PUBLIC TYPE = RECORD[
leftSymbol: Symbol,
rightSide: RightSide,
index: CARDINAL,
next: Production ← NIL,
-- following entries record info for clients
firstLR0Item: REF ANY ← NIL,
associatedLR0Closure: REF ANY ← NIL,
associatedLR1Closure: REF ANY ← NIL
];
RightSide: TYPE = REF RightSideBody;
RightSideBody: TYPE = RECORD[
symbols: SEQUENCE nRightSymbols: CARDINAL OF Symbol];
SymbolCell: TYPE = REF SymbolCellBody;
SymbolCellBody: TYPE = RECORD[
symbol: Symbol,
next: SymbolCell];
BuildAGrammar: PUBLIC PROC[
genTheGrammar: PROC[
oneUniqueTerminal: PROC[name: ROPE, spelling: ROPE], -- spelling = NIL if the same spelling as name
oneGenericTerminal: PROC[name: ROPE, class: ROPE],
oneNonTerminal: PROC[name: ROPE],
oneLeftSide: PROC[ruleIndex: CARDINAL, symb: ROPE],
aRightSideSymb: PROC[ROPE]]]
RETURNS[Grammar] =
BEGIN
kill: BOOLEAN ← FALSE; -- tentative
grammar: Grammar ← NEW[GrammarBody];
lastSymbol: Symbol ← NIL;
lastTerminal: SymbolCell ← NIL;
nTerminals: CARDINAL ← 0;
firstProduction: Production ← NIL;
lastProduction: Production ← NIL;
currentIndex: CARDINAL;
currentLeftSide: Symbol ← NIL;
currentRightSideList: SymbolCell ← NIL;
lastRightSideCell: SymbolCell ← NIL;
currentRightSideSymbolCount: CARDINAL ← 0;
SeeOneUniqueTerminal: PROC[name: ROPE, spelling: ROPE] =
BEGIN
IF spelling = NIL OR Length[spelling] = 0 THEN spelling ← name;
HandleOneTerminal[name, unique, spelling];
END;
SeeOneGenericTerminal: PROC[name: ROPE, class: ROPE] =
{HandleOneTerminal[name, generic, class]};
HandleOneTerminal: PROC[name: ROPE, variety: TerminalVariety, spellingOrClass: ROPE] =
BEGIN
symbol: Symbol;
terminalCell: SymbolCell;
symbol ← EnterTerminalSymbol[grammar.symbolHashTable, name, variety, spellingOrClass];
IF lastSymbol # NIL THEN lastSymbol.next ← symbol
ELSE grammar.symbols ← symbol;
lastSymbol ← symbol;
nTerminals ← nTerminals + 1;
terminalCell ← NEW[SymbolCellBody ← [symbol, NIL]];
IF lastTerminal = NIL THEN grammar.terminalList ← terminalCell ELSE lastTerminal.next ← terminalCell;
lastTerminal ← terminalCell;
END;
SeeOneNonTerminal: PROC[name: ROPE] =
BEGIN
symbol: Symbol;
symbol ← EnterNonTerminalSymbol[grammar.symbolHashTable, name];
IF lastSymbol # NIL THEN lastSymbol.next ← symbol
ELSE grammar.symbols ← symbol;
lastSymbol ← symbol;
END;
CleanUpPrevious: PROC =
BEGIN
IF currentLeftSide # NIL THEN
BEGIN
rightSide: RightSide ← NEW[RightSideBody[currentRightSideSymbolCount]];
production: Production ← NEW[ProductionBody ← [currentLeftSide, rightSide, currentIndex]];
FOR I: CARDINAL IN [0..currentRightSideSymbolCount) DO
rightSide.symbols[I] ← currentRightSideList.symbol;
currentRightSideList ← currentRightSideList.next;
ENDLOOP;
IF lastProduction = NIL THEN firstProduction ← production
ELSE lastProduction.next ← production;
IF grammar.startProduction = NIL THEN grammar.startProduction ← production;
lastProduction ← production;
currentLeftSide ← NIL;
currentRightSideList ← lastRightSideCell ← NIL;
currentRightSideSymbolCount ← 0;
END;
END;
SeeLeftSide: PROC[ruleIndex: CARDINAL, symb: ROPE] =
BEGIN
CleanUpPrevious[];
currentIndex ← ruleIndex;
currentLeftSide ← LookUpSymbol[grammar.symbolHashTable, symb];
END;
SeeARightSideSymbol: PROC[symbolText: ROPE] =
BEGIN
symbol: Symbol;
cell: SymbolCell;
symbol ← LookUpSymbol[grammar.symbolHashTable, symbolText];
cell ← NEW[SymbolCellBody ← [symbol, NIL]];
IF lastRightSideCell = NIL THEN currentRightSideList ← cell ELSE lastRightSideCell.next ← cell;
lastRightSideCell ← cell;
currentRightSideSymbolCount ← currentRightSideSymbolCount + 1;
END;
grammar.symbolHashTable ← BuildSymbolHashTable[];
genTheGrammar[SeeOneUniqueTerminal, SeeOneGenericTerminal, SeeOneNonTerminal, SeeLeftSide, SeeARightSideSymbol
! GetErrorInfo =>
BEGIN
stream: IO.STREAM; position: INT;
[stream, position] ← GetErrorInfo[];
kill ← TRUE;
RESUME[stream, position]
END];
CleanUpPrevious[];
grammar.productions ← firstProduction;
grammar.terminalCount ← nTerminals;
IF kill THEN RETURN[NIL];
PrepareTheGrammar[grammar];
RETURN[grammar];
END;
GetLength: PUBLIC PROC[production: Production] RETURNS[CARDINAL] =
{RETURN[production.rightSide.nRightSymbols]};
GetStartProduction: PUBLIC PROC[grammar: Grammar] RETURNS[Production] =
{RETURN[grammar.startProduction]};
GetRightSideSymbol: PUBLIC PROC[production: Production, I: CARDINAL] RETURNS[Symbol] =
{RETURN[production.rightSide.symbols[I]]};
GetLeftSideSymbol: PUBLIC PROC[production: Production] RETURNS[Symbol] =
{RETURN[production.leftSymbol]};
GenProductions: PUBLIC PROC[grammar: Grammar, for: PROC[Production]] =
BEGIN
FOR production: Production ← grammar.productions, production.next WHILE production # NIL DO
for[production];
ENDLOOP;
END;
GenAllSymbols: PUBLIC PROC[grammar: Grammar, for: PROC[Symbol]] =
BEGIN
FOR symbol: Symbol ← grammar.symbols, symbol.next WHILE symbol # NIL DO
for[symbol];
ENDLOOP;
END;
GetSymbolText: PUBLIC PROC[symbol: Symbol] RETURNS[ROPE] =
{RETURN[symbol.text]};
GetTerminalVariety: PUBLIC PROC[symbol: Symbol] RETURNS[TerminalVariety] =
BEGIN
IF NOT symbol.terminal THEN ERROR;
RETURN[symbol.terminalVariety];
END;
GetTerminalSpelling: PUBLIC PROC[symbol: Symbol] RETURNS[ROPE] =
BEGIN
IF NOT symbol.terminal THEN SymbolError[symbol, "was expected to be a terminal"];
IF NOT symbol.terminalVariety = unique THEN SymbolError[symbol, "should not be generic"];
RETURN[symbol.spellingOrClass];
END;
GetTerminalClass: PUBLIC PROC[symbol: Symbol] RETURNS[ROPE] =
BEGIN
IF NOT symbol.terminal THEN SymbolError[symbol, "was expected to be a terminal"];
IF NOT symbol.terminalVariety = generic THEN SymbolError[symbol, "should be generic"];
RETURN[symbol.spellingOrClass];
END;
GetProductionIndex: PUBLIC PROC[production: Production] RETURNS[CARDINAL] =
{RETURN[production.index]};
GetGrammarStats: PUBLIC PROC[grammar: Grammar] RETURNS[
nProductions, nRightSideItems, nTerminals, nNonTerminals: INT] =
BEGIN
SeeOneProduction: PROC[p: Production] =
BEGIN
nProductions←nProductions+1;
nRightSideItems←nRightSideItems+GetLength[p];
END;
SeeOneSymbol: PROC[s: Symbol] =
BEGIN
IF TestIfTerminal[s] THEN nTerminals ← nTerminals+1
ELSE nNonTerminals ← nNonTerminals+1;
END;
nProductions ← nRightSideItems ← nTerminals ← nNonTerminals ← 0;
GenProductions[grammar, SeeOneProduction];
GenAllSymbols[grammar, SeeOneSymbol];
END;
-- then the recorded info to help higher level code
NoteTerminalSeqCollection: PUBLIC PROC[grammar: Grammar, ref: REF ANY] =
{grammar.terminalSeqCollection ← ref};
GetTerminalSeqCollection: PUBLIC PROC[grammar: Grammar] RETURNS[REF ANY] =
{RETURN[grammar.terminalSeqCollection]};
NoteTerminalSeq: PUBLIC PROC[s: Symbol, ref: REF ANY] =
{s.terminalSeq ← ref};
GetTerminalSeq: PUBLIC PROC[s: Symbol] RETURNS[REF ANY] =
{RETURN[s.terminalSeq]};
NoteLR0ItemSetCollection: PUBLIC PROC[grammar: Grammar, ref: REF ANY] =
{grammar.lr0ItemSetCollection ← ref};
GetLR0ItemSetCollection: PUBLIC PROC[grammar: Grammar] RETURNS[REF ANY] =
{RETURN[grammar.lr0ItemSetCollection]};
NoteFirstLR0Item: PUBLIC PROC[production: Production, ref: REF ANY] =
{production.firstLR0Item ← ref};
GetFirstLR0Item: PUBLIC PROC[production: Production] RETURNS[REF ANY] =
{RETURN[production.firstLR0Item]};
NoteLR0ItemCollection: PUBLIC PROC[grammar: Grammar, ref: REF ANY] =
{grammar.lr0ItemCollection ← ref};
GetLR0ItemCollection: PUBLIC PROC[grammar: Grammar] RETURNS[REF ANY] =
{RETURN[grammar.lr0ItemCollection]};
NoteAssociatedLR0Closure: PUBLIC PROC[production: Production, ref: REF ANY] =
{production.associatedLR0Closure ← ref};
GetAssociatedLR0Closure: PUBLIC PROC[production: Production] RETURNS[REF ANY] =
{RETURN[production.associatedLR0Closure]};
NoteLR1ItemSetCollection: PUBLIC PROC[grammar: Grammar, ref: REF ANY] =
{grammar.lr1ItemSetCollection ← ref};
GetLR1ItemSetCollection: PUBLIC PROC[grammar: Grammar] RETURNS[REF ANY] =
{RETURN[grammar.lr1ItemSetCollection]};
NoteAssociatedLR1Closure: PUBLIC PROC[production: Production, ref: REF ANY] =
{production.associatedLR1Closure ← ref};
GetAssociatedLR1Closure: PUBLIC PROC[production: Production] RETURNS[REF ANY] =
{RETURN[production.associatedLR1Closure]};
-- these procedures are used by the derivitive procedures and their support
NoteProductionList: PROC[s: Symbol, list: REF ANY] =
{s.productionList ← list};
GetProductionList: PROC[s: Symbol] RETURNS[REF ANY] =
{RETURN[s.productionList]};
GetNTerminals: PROC[grammar: Grammar] RETURNS[CARDINAL] =
{RETURN[grammar.terminalCount]};
GetTerminalFlag: PROC[s: Symbol] RETURNS[BOOLEAN] =
{RETURN[s.terminal]};
NoteCanProduceEmpty: PROC[s: Symbol, flag: BOOLEAN] =
{s.canProduceEmpty ← flag};
GetCanProduceEmpty: PROC[s: Symbol] RETURNS[BOOLEAN] =
{RETURN[s.canProduceEmpty]};
NoteCanBeFirstList: PROC[s: Symbol, ref: REF ANY] =
{s.canBeFirstList ← ref};
GetCanBeFirstList: PROC[s: Symbol] RETURNS[REF ANY] =
{RETURN[s.canBeFirstList]};
-- then the derivitive procedures
ProductionCell: TYPE = REF ProductionCellBody;
ProductionCellBody: TYPE = RECORD[production: Production, next: ProductionCell];
PrepareTheGrammar: PUBLIC PROC[grammar: Grammar] =
BEGIN
ConstructProductionLists[grammar];
CheckBasicRules[grammar];
ConstructCanProduceEmpty[grammar];
ConstructCanBeFirst[grammar];
END;
TestIfTerminal: PUBLIC PROC[symbol: Symbol] RETURNS[BOOLEAN] =
{RETURN[symbol.terminal]};
GetNTerminalSymbols: PUBLIC PROC[grammar: Grammar] RETURNS[CARDINAL] =
{RETURN[GetNTerminals[grammar]]};
GenTerminalSymbols: PUBLIC PROC[grammar: Grammar, for: PROC[Symbol]] =
BEGIN
FOR cell: SymbolCell ← NARROW[grammar.terminalList], cell.next WHILE cell # NIL DO
for[cell.symbol];
ENDLOOP;
END;
GenProductionsForSymbol: PUBLIC PROC[s: Symbol, for: PROC[Production]] =
BEGIN
FOR cell: ProductionCell ← NARROW[GetProductionList[s]], cell.next WHILE cell # NIL DO
for[cell.production];
ENDLOOP;
END;
TestCanProduceEmpty: PUBLIC PROC[s: Symbol] RETURNS[BOOLEAN] =
{RETURN[GetCanProduceEmpty[s]]};
GenCanBeFirst: PUBLIC PROC[s: Symbol, for: PROC[Symbol]] =
BEGIN
FOR cell: SymbolCell ← NARROW[GetCanBeFirstList[s]], cell.next WHILE cell # NIL DO
for[cell.symbol];
ENDLOOP;
END;
-- support code for the derivitive procedures
-- This code includes several calculations that ultimately support the computation of First1(A). These are particularly inefficient routines, if they show up significantly in a Spy run, they should be reworked.
CheckBasicRules: PROC[grammar: Grammar] =
BEGIN
-- the grammar is augmented: the left side symbol of start production appears no where else
BEGIN
first: Production ← grammar.startProduction;
start: Symbol ← first.leftSymbol;
FOR production: Production ← grammar.productions, production.next WHILE production # NIL DO
IF production # grammar.startProduction AND production.leftSymbol = start THEN SymbolError[production.leftSymbol, "is the unique start symbol, hence should not occur on the left side of some production which is not the start production"];
FOR I: CARDINAL IN [0..production.rightSide.nRightSymbols) DO
IF production.rightSide.symbols[I] = start THEN SymbolError[production.rightSide.symbols[I], "is the unique start symbol, hence should not occur on the right side of any production"];
ENDLOOP;
ENDLOOP;
END;
-- no terminal appears on the left
BEGIN
FOR production: Production ← grammar.productions, production.next WHILE production # NIL DO
IF production.leftSymbol.terminal THEN SymbolError[production.leftSymbol, "should be a non terminal"];
ENDLOOP;
END;
-- all symbols lead to non terminal sequences.
BEGIN
changes: BOOLEAN ← TRUE;
FOR symbol: Symbol ← grammar.symbols, symbol.next WHILE symbol # NIL DO
symbol.producesTerminals ← symbol.terminal;
ENDLOOP;
WHILE changes DO
changes ← FALSE;
FOR production: Production ← grammar.productions, production.next WHILE production # NIL DO
producesTerminals: BOOLEAN ← TRUE;
IF Equal[production.leftSymbol.text, "product"] THEN {a: INT ← 5; a ← 10};
IF production.leftSymbol.producesTerminals THEN LOOP;
FOR I: CARDINAL IN [0..production.rightSide.nRightSymbols) DO
symbol: Symbol ← production.rightSide.symbols[I];
IF NOT symbol.producesTerminals THEN
{producesTerminals ← FALSE; EXIT};
ENDLOOP;
IF producesTerminals THEN
BEGIN
production.leftSymbol.producesTerminals ← TRUE;
changes ← TRUE;
END;
ENDLOOP;
ENDLOOP;
FOR symbol: Symbol ← grammar.symbols, symbol.next WHILE symbol # NIL DO
IF NOT symbol.producesTerminals THEN SymbolError[symbol, "is a non terminal, but does not generate any terminal strings"];
ENDLOOP;
END;
-- all symbols are reachable
BEGIN
changes: BOOLEAN ← TRUE;
FOR symbol: Symbol ← grammar.symbols, symbol.next WHILE symbol # NIL DO
symbol.reachable ← FALSE;
ENDLOOP;
grammar.startProduction.leftSymbol.reachable ← TRUE;
WHILE changes DO
changes ← FALSE;
FOR production: Production ← grammar.productions, production.next WHILE production # NIL DO
IF NOT production.leftSymbol.reachable THEN LOOP;
FOR I: CARDINAL IN [0..production.rightSide.nRightSymbols) DO
IF NOT production.rightSide.symbols[I].reachable THEN
BEGIN
production.rightSide.symbols[I].reachable ← TRUE;
changes ← TRUE;
END;
ENDLOOP;
ENDLOOP;
ENDLOOP;
FOR symbol: Symbol ← grammar.symbols, symbol.next WHILE symbol # NIL DO
IF NOT symbol.reachable THEN SymbolError[symbol, "is not reachable from the start symbol"];
ENDLOOP;
END;
END;
ConstructProductionLists: PROC[grammar: Grammar] =
BEGIN
SetListsEmpty: PROC[s: Symbol] =
{NoteProductionList[s, NIL]};
NoteOneProduction: PROC[production: Production] =
BEGIN
symbol: Symbol ← GetLeftSideSymbol[production];
newCell: ProductionCell ← NEW[ProductionCellBody ← [production, NARROW[GetProductionList[symbol]]]];
NoteProductionList[symbol, newCell];
END;
GenAllSymbols[grammar, SetListsEmpty];
GenProductions[grammar, NoteOneProduction];
END;
ConstructCanProduceEmpty: PROC[grammar: Grammar] =
BEGIN
someFlagsSet: BOOLEAN ← TRUE;
ClearTheFlags: PROC[s: Symbol] =
{NoteCanProduceEmpty[s, FALSE]};
ExploreOneProduction: PROC[production: Production] =
BEGIN
left: Symbol;
FOR I: CARDINAL IN[0..GetLength[production]) DO
currentSymbol: Symbol ← GetRightSideSymbol[production, I];
IF NOT GetCanProduceEmpty[currentSymbol] THEN RETURN;
ENDLOOP;
left ← GetLeftSideSymbol[production];
IF GetCanProduceEmpty[left] THEN RETURN;
someFlagsSet ← TRUE;
NoteCanProduceEmpty[left, TRUE];
END;
GenAllSymbols[grammar, ClearTheFlags];
WHILE someFlagsSet DO
someFlagsSet ← FALSE;
GenProductions[grammar, ExploreOneProduction];
ENDLOOP;
END;
ConstructCanBeFirst: PROC[grammar: Grammar] =
BEGIN
somethingAdded: BOOLEAN ← TRUE; -- initial
ClearTheSets: PROC[s: Symbol] =
{NoteCanBeFirstList[s, NIL]};
AddToCanBeFirst: PROC[to: Symbol, s: Symbol] =
BEGIN
found: BOOLEAN ← FALSE; -- initial value
FOR cell: SymbolCell ← NARROW[GetCanBeFirstList[to]], cell.next WHILE cell # NIL DO
IF cell.symbol = s THEN {found ← TRUE; EXIT};
ENDLOOP;
IF NOT found THEN
BEGIN
newCell: SymbolCell ← NEW[SymbolCellBody ← [s, NARROW[GetCanBeFirstList[to]]]];
NoteCanBeFirstList[to, newCell];
somethingAdded ← TRUE;
END;
END;
ExploreOneProduction: PROC[production: Production] =
BEGIN
left: Symbol ← GetLeftSideSymbol[production];
FOR I: CARDINAL IN[0..GetLength[production]) DO
currentSymbol: Symbol ← GetRightSideSymbol[production, I];
AddToCanBeFirst[left, currentSymbol];
FOR cell: SymbolCell ← NARROW[GetCanBeFirstList[currentSymbol]], cell.next WHILE cell # NIL DO
AddToCanBeFirst[left, cell.symbol];
ENDLOOP;
IF NOT GetCanProduceEmpty[currentSymbol] THEN EXIT;
ENDLOOP;
END;
GenAllSymbols[grammar, ClearTheSets];
WHILE somethingAdded DO
somethingAdded ← FALSE;
GenProductions[grammar, ExploreOneProduction];
ENDLOOP;
END;
-- symbol hashing
SymbolHashTable: TYPE = REF SymbolHashTableBody;
SymbolHashTableBody: TYPE = RECORD[
slots: SEQUENCE nSlots: CARDINAL OF SymbolHashCell];
SymbolHashCell: TYPE = REF SymbolHashCellBody;
SymbolHashCellBody: TYPE = RECORD[
symbol: Symbol,
next: SymbolHashCell];
BuildSymbolHashTable: PROCEDURE RETURNS[SymbolHashTable] =
BEGIN
table: SymbolHashTable ← NEW[SymbolHashTableBody[1024]];
FOR I: CARDINAL IN [0..table.nSlots) DO table.slots[I] ← NIL ENDLOOP;
RETURN[table];
END;
EnterTerminalSymbol: PROCEDURE[table: SymbolHashTable, name: ROPE, variety: TerminalVariety, spellingOrClass: ROPE] RETURNS[Symbol] =
BEGIN
symbol: Symbol; new: BOOLEAN;
[symbol, new] ← FetchSymbol[table, name];
IF NOT new THEN SymbolError[symbol, "is declared more than once"];
symbol.spellingOrClass ← spellingOrClass;
symbol.terminal ← TRUE;
symbol.terminalVariety ← variety;
RETURN[symbol];
END;
EnterNonTerminalSymbol: PROCEDURE[table: SymbolHashTable, name: ROPE] RETURNS[Symbol] =
BEGIN
symbol: Symbol; new: BOOLEAN;
[symbol, new] ← FetchSymbol[table, name];
IF NOT new THEN SymbolError[symbol, "is declared more than once"];
symbol.terminal ← FALSE;
RETURN[symbol];
END;
LookUpSymbol: PROCEDURE[table: SymbolHashTable, name: ROPE] RETURNS[Symbol] =
BEGIN
symbol: Symbol; new: BOOLEAN;
[symbol, new] ← FetchSymbol[table, name];
IF new THEN SymbolError[symbol, "is not declared"];
RETURN[symbol];
END;
FetchSymbol: PROCEDURE[table: SymbolHashTable, name: ROPE] RETURNS[Symbol, --new--BOOLEAN] =
BEGIN
hashCode: CARDINAL ← 0;
symbol: Symbol;
cell: SymbolHashCell;
FOR I: INT IN [0..Length[name]) DO
hashCode ← hashCode + LOOPHOLE[Fetch[name, I], CARDINAL];
ENDLOOP;
hashCode ← hashCode MOD table.nSlots;
FOR cell: SymbolHashCell ← table.slots[hashCode], cell.next WHILE cell # NIL DO
IF Equal[cell.symbol.text, name] THEN RETURN[cell.symbol, FALSE];
ENDLOOP;
symbol ← NEW[SymbolBody ← [
name,
generic,
NIL,
FALSE,
FALSE,
FALSE,
NIL,
NIL,
NIL,
FALSE,
NIL]];
cell ← NEW[SymbolHashCellBody ← [symbol, table.slots[hashCode]]];
table.slots[hashCode] ← cell;
RETURN[symbol, TRUE];
END;
SymbolError: PROC[symbol: Symbol, msgText: Rope.ROPE, fatal: BOOLEAN ← FALSE] =
BEGIN
stream: STREAM; position: INT;
[stream, position] ← GetErrorInfo[];
IO.PutF[stream, "\NError in Grammer definition"];
IF position >= 0 THEN IO.PutF[stream, " at position %g", IO.int[position]];
IO.PutF[stream, ", the symbol \"%g\" %g\N\N", IO.rope[symbol.text], IO.rope[msgText]];
IF fatal THEN KillParserGen[];
END;
END..
-- remark: September 10, 1984 3:48:44 pm PDT: code to produce canbefirst list had a very bad bug: when finding that S could be a first symbol for S', it did not attempt to include other symbols known to be on the can be first list for S.