-- ParserDisplayImpl.mesa
-- last edit November 2, 1984 2:17:16 pm PST
-- Sturgis, April 1, 1986 2:54:05 pm PST
DIRECTORY
GrammarBasic USING[GenAllSymbols, GenCanBeFirst, GenProductions, GenTerminalSymbols, GetLeftSideSymbol, GetLength, GetNTerminalSymbols, GetProductionIndex, GetRightSideSymbol, GetSymbolText, Grammar, Production, Symbol, TestCanProduceEmpty, TestIfTerminal],
IO USING [card, CR, int, PutChar, PutF, PutRope, rope, STREAM],
LR0Items USING[GetProductionAndPosition],
LR0ItemSetsBasic USING[GenItemsInLR0ItemSet, LR0Item, LR0ItemSet, NarrowLR0ItemSet],
LR1ItemSetsBasic USING[GenerateSubsetsFromLR1ItemSet, LR1Item, LR1ItemSet, LR1ItemSubset, NarrowLR1ItemSet],
ParserDisplay USING[],
ParserGraphAlgorithms USING[TestConsistencyOfNode, GenerateParseActions],
ParserGraphs USING[GenerateAllNodes, GenerateArcs, GetAssociatedSet, GetBaseNode, GetClass, GetGraph, GetNodeIndex, GetRingNumber, GetStartNode, Graph, GraphClass, Node],
Rope USING[ROPE],
TerminalSequences USING[GenTerminalSeqsFromSet, GetSymbolFromTerminalSeq, TerminalSeq, TerminalSeqSet];
ParserDisplayImpl: CEDAR PROGRAM IMPORTS GrammarBasic, IO, LR0Items, LR0ItemSetsBasic, LR1ItemSetsBasic, ParserGraphAlgorithms, ParserGraphs, TerminalSequences EXPORTS ParserDisplay =
BEGIN OPEN GrammarBasic, IO, LR0Items, LR0ItemSetsBasic, LR1ItemSetsBasic, ParserGraphAlgorithms, ParserGraphs, Rope, TerminalSequences;
ShowGrammar: PUBLIC PROC[on: STREAM, grammar: Grammar] =
BEGIN
ShowOneProduction: PROC[production: Production] =
BEGIN
PutF[on, "(%g) ", card[GetProductionIndex[production]]];
PutRope[on, GetSymbolText[GetLeftSideSymbol[production]]];
PutRope[on, " ← "];
FOR I: CARDINAL IN [0..GetLength[production]) DO
PutRope[on, GetSymbolText[GetRightSideSymbol[production, I]]];
IF I+1 # GetLength[production] THEN PutRope[on, " "];
ENDLOOP;
PutChar[on, CR];
END;
ShowOneTerminal: PROC[s: Symbol] =
{PutF[on, " %g\N", rope[GetSymbolText[s]]]};
ShowOneNonTerminal: PROC[s: Symbol] =
BEGIN
ShowOneFirst: PROC[first: Symbol] =
{PutF[on, " %g\N", rope[GetSymbolText[first]]]};
IF NOT TestIfTerminal[s] THEN
BEGIN
PutF[on, " %g%g\N", rope[GetSymbolText[s]], rope[IF TestCanProduceEmpty[s] THEN " (can produce empty)" ELSE ""]];
GenCanBeFirst[s, ShowOneFirst];
END;
END;
PutChar[on, CR];
GenProductions[grammar, ShowOneProduction];
PutF[on, "\N\NnTerminals = %g\N", card[GetNTerminalSymbols[grammar]]];
GenTerminalSymbols[grammar, ShowOneTerminal];
PutF[on, "\N\NNon Terminals\N"];
GenAllSymbols[grammar, ShowOneNonTerminal];
END;
ShowTerminalSeqSet: PUBLIC PROC[on: STREAM, offset: CARDINAL, set: TerminalSeqSet] =
BEGIN
first: BOOLEAN ← TRUE;
ShowOneSeq: PROC[seq: TerminalSeq] =
BEGIN
IF NOT first THEN PutRope[on, ", "]; first ← FALSE;
ShowTerminalSeq[on, 0, seq];
END;
Offset[on, offset];
GenTerminalSeqsFromSet[set, ShowOneSeq];
END;
ShowLR0Item: PUBLIC PROC[on: STREAM, offset: CARDINAL, item: LR0Item] =
BEGIN
Offset[on, offset]; PutRope[on, "[ "];
ShowLR0ItemInner[on, item];
PutRope[on, " ]"];
END;
This is only good for viewer io streams (as it uses looks information)
ShowLR0ItemInner: PROC[on: STREAM, item: LR0Item] =
BEGIN
production: Production;
position: CARDINAL;
[production, position] ← GetProductionAndPosition[item];
PutRope[on, GetSymbolText[GetLeftSideSymbol[production]]];
PutRope[on, " ← "];
this is the old code, using dot notation
FOR I: CARDINAL IN [0..GetLength[production]) DO
IF I = position THEN PutRope[on, " . "] ELSE PutRope[on, " "];
PutRope[on, GetSymbolText[GetRightSideSymbol[production, I]]];
ENDLOOP
FOR I: CARDINAL IN [0..GetLength[production]) DO
IF I = position THEN
IO.PutF[on, " %l%g%l", IO.rope["i"], IO.rope[GetSymbolText[GetRightSideSymbol[production, I]]], IO.rope[" "]]
ELSE IO.PutF[on, " %g", IO.rope[GetSymbolText[GetRightSideSymbol[production, I]]]];
ENDLOOP;
IF position = GetLength[production] THEN PutRope[on, " . "];
END;
ShowLR1Item: PUBLIC PROC[on: STREAM, offset: CARDINAL, item: LR1Item] =
BEGIN
Offset[on, offset]; PutRope[on, "[ "];
ShowLR0ItemInner[on, item.lr0Item];
PutRope[on, " | "];
ShowTerminalSeq[on, 0, item.terminalSeq];
PutRope[on, " ]"];
END;
ShowLR0ItemSet: PUBLIC PROC[on: STREAM, offset: CARDINAL, set: REF ANY] =
BEGIN
lr0ItemSet: LR0ItemSet ← NarrowLR0ItemSet[set];
ShowOneItem: PROC[item: LR0Item] =
BEGIN
Offset[on, offset];
ShowLR0Item[on, offset, item];
PutRope[on, "\N"];
END;
GenItemsInLR0ItemSet[lr0ItemSet, ShowOneItem];
END;
ShowNode: PUBLIC PROC[on: STREAM, offset: CARDINAL, node: Node] =
BEGIN
ring: CARDINAL;
baseNodeIndex: CARDINAL;
consistent: BOOLEAN;
graph: Graph ← GetGraph[node];
startNode: Node ← GetStartNode[graph];
graphClass: GraphClass ← GetClass[graph];
showAssociatedSet: PROC[STREAM, CARDINAL, REF ANY];
ShowOneArc: PROC[s: Symbol, target: Node] RETURNS[BOOLEAN] =
BEGIN
Offset[on, offset+3];
PutF[on, "%g to %g\N", rope[GetSymbolText[s]], card[GetNodeIndex[target]]];
RETURN[TRUE];
END;
Offset[on, offset];
PutF[on, "node %g", card[GetNodeIndex[node]]];
IF node = startNode THEN PutRope[on, " (start node)"];
SELECT graphClass FROM
LR0 =>
BEGIN
ring ← GetRingNumber[node];
baseNodeIndex ← LAST[CARDINAL];
consistent ← TRUE;
END;
LALR1 =>
BEGIN
ring ← GetRingNumber[node];
baseNodeIndex ← GetNodeIndex[GetBaseNode[node]];
consistent ← (ring # 0);
END;
SplitNode =>
BEGIN
baseNode: Node ← GetBaseNode[node];
ring ← GetRingNumber[baseNode];
baseNodeIndex ← GetNodeIndex[baseNode];
consistent ← ring # 0 OR TestConsistencyOfNode[node];
END;
ENDCASE => ERROR;
IF ring # LAST[CARDINAL] THEN
PutF[on, " (ring = %g)", card[ring]];
IF baseNodeIndex # LAST[CARDINAL] THEN
PutF[on, " (base = %g)", card[baseNodeIndex]];
IF NOT consistent THEN
PutRope[on, " (This node is NOT consistent)"];
PutRope[on, "\N"];
Offset[on, offset]; PutRope[on, " associated set\N"];
SELECT graphClass FROM
LR0 => showAssociatedSet ← ShowLR0ItemSet;
LALR1, SplitNode => showAssociatedSet ← ShowLR1ItemSet;
ENDCASE => ERROR;
showAssociatedSet[on, offset+3, GetAssociatedSet[node]];
Offset[on, offset]; PutRope[on, " arcs\N"];
GenerateArcs[node, ShowOneArc];
PutRope[on, "\N"];
END;
ShowGraph: PUBLIC PROC[on: STREAM, ringsOnly: BOOLEAN, offset: CARDINAL, graph: Graph] =
BEGIN
index: CARDINAL ← 0;
startNode: Node ← GetStartNode[graph];
ShowOneNode: PROC[node: Node] RETURNS[BOOLEAN] =
BEGIN
IF (NOT ringsOnly) OR (GetRingNumber[node] # LAST[CARDINAL]) THEN
ShowNode[on, offset, node];
RETURN[TRUE];
END;
Offset[on, offset]; PutF[on, "(start node = %g)\N", card[GetNodeIndex[startNode]]];
GenerateAllNodes[graph, ShowOneNode];
PutRope[on, "\N"];
PutRope[on, "\N"];
END;
ShowGeneratedParser: PUBLIC PROC[on: STREAM, graph: Graph] =
BEGIN
ShowSymbol: PROC[text: ROPE] =
{PutF[on, "symbol: %g\N", rope[text]]};
ShowUniqueToken: PROC[name: ROPE, spelling: ROPE] =
{PutF[on, "uniqueToken: %g (spelled as: %g)\N", rope[name], rope[spelling]]};
ShowGenericToken: PROC[name: ROPE, class: ROPE] =
{PutF[on, "genericToken: %g (class: %g)\N", rope[name], rope[class]]};
ShowShift: PROC[state: CARDINAL, terminalSeq: ROPE, newState: CARDINAL] =
{PutF[on, "shift: %g <%g> %g\N", card[state], rope[terminalSeq], card[newState]]};
ShowReduction: PROC[state: CARDINAL, terminalSeq: ROPE, leftSide: ROPE, ruleNumber: CARDINAL, ruleSize: CARDINAL] =
{PutF[on, "reduction: %g <%g> <%g %g %g>\N", card[state], rope[terminalSeq], rope[leftSide], card[ruleNumber], card[ruleSize]]};
ShowAcceptance: PROC[state: CARDINAL, terminalSeq: ROPE] =
{PutF[on, "accept: %g <%g>\N", card[state], rope[terminalSeq]]};
ShowStart: PROC[state: CARDINAL] =
{PutF[on, "start: %g\N", card[state]]};
GenerateParseActions[graph, ShowSymbol, ShowUniqueToken, ShowGenericToken, ShowShift, ShowReduction, ShowAcceptance, ShowStart];
END;
ShowArcCounts: PUBLIC PROC[on: STREAM, g: Graph] =
BEGIN
h: Histogram ← MakeHistogram["node", "arc", 100];
SeeOneNode: PROC[n: Node] RETURNS[BOOLEAN] =
BEGIN
nArcs: CARDINAL ← 0;
SeeOneArc: PROC[s: Symbol, t: Node] RETURNS[BOOLEAN] =
{nArcs ← nArcs+1; RETURN[TRUE]};
GenerateArcs[n, SeeOneArc];
NoteNItemsInOneContainer[h, nArcs];
RETURN[TRUE];
END;
GenerateAllNodes[g, SeeOneNode];
PrintHistogram[on, h];
END;
ShowRingCounts: PUBLIC PROC[on: STREAM, g: Graph] =
BEGIN
h: Histogram ← MakeHistogram["node", "ring", 15];
SeeOneNode: PROC[n: Node] RETURNS[BOOLEAN] =
BEGIN
ring: CARDINAL ← SELECT GetClass[g] FROM
LR0, LALR1 => GetRingNumber[n],
SplitNode => GetRingNumber[GetBaseNode[n]],
ENDCASE => ERROR;
IF ring < LAST[CARDINAL] THEN NoteNItemsInOneContainer[h, ring];
RETURN[TRUE];
END;
GenerateAllNodes[g, SeeOneNode];
PrintRingHistogram[on, h];
END;
StartShowingSignals: PUBLIC SIGNAL[ROPE] = CODE;
SignalRope: PUBLIC SIGNAL[ROPE] = CODE;
SignalSymbol: PUBLIC SIGNAL[ROPE, Symbol] = CODE;
SignalTerminalSeq: PUBLIC SIGNAL[text: ROPE, seq: TerminalSeq] = CODE;
SignalTerminalSeqSet: PUBLIC SIGNAL[text: ROPE, set: TerminalSeqSet] = CODE;
SignalLR0Item: PUBLIC SIGNAL[ROPE, LR0Item] = CODE;
SignalLR1Item: PUBLIC SIGNAL[ROPE, LR1Item] = CODE;
SignalLR0ItemSet: PUBLIC SIGNAL[text: ROPE, set: LR0ItemSet] = CODE;
SignalLR1ItemSet: PUBLIC SIGNAL[text: ROPE, set: LR1ItemSet] = CODE;
SignalNode: PUBLIC SIGNAL[text: ROPE, node: Node] = CODE;
StopShowingSignals: PUBLIC SIGNAL[ROPE] = CODE;
-- histograms
Histogram: TYPE = REF HistogramBody;
HistogramBody: PUBLIC TYPE = RECORD[
nameForContainer: ROPE,
nameForItem: ROPE,
nContainers: INT,
nItems: INT,
overflow: INT,
counts: SEQUENCE limit: CARDINAL OF INT];
MakeHistogram: PUBLIC PROCEDURE[nameForContainer: ROPE, nameForItem: ROPE, maxSize: CARDINAL] RETURNS[Histogram] =
BEGIN
hist: Histogram ← NEW[HistogramBody[maxSize+1] ← [nameForContainer, nameForItem, 0, 0, 0, ]];
FOR I: CARDINAL IN [0..maxSize] DO hist.counts[I] ← 0 ENDLOOP;
RETURN[hist]
END;
NoteNItemsInOneContainer: PUBLIC PROCEDURE[hist: Histogram, size: CARDINAL] =
BEGIN
IF size >= hist.limit THEN hist.overflow ← hist.overflow + 1 ELSE hist.counts[size] ← hist.counts[size]+ 1;
hist.nContainers ← hist.nContainers + 1;
hist.nItems ← hist.nItems + size;
END;
PrintHistogram: PUBLIC PROCEDURE[s: STREAM, hist: Histogram] =
BEGIN
s.PutF["total number of %gs: %g\N", rope[hist.nameForContainer], int[hist.nContainers]];
s.PutF["total number of %gs: %g\N", rope[hist.nameForItem], int[hist.nItems]];
s.PutF["following is number of %gs with given number of %gs\N", rope[hist.nameForContainer], rope[hist.nameForItem]];
s.PutF["in form n %gs: n %gs\N", rope[hist.nameForItem], rope[hist.nameForContainer]];
s.PutF["entries with 0 %gs will be skipped\N", rope[hist.nameForContainer]];
FOR I: CARDINAL IN [0..hist.limit) DO
IF hist.counts[I] # 0 THEN
s.PutF[" %g: %g\N", card[I], int[hist.counts[I]]];
ENDLOOP;
IF hist.overflow # 0 THEN
s.PutF[" >= %g: %g\N", int[hist.limit], int[hist.overflow]]
END;
-- following is a special case
PrintRingHistogram: PROCEDURE[s: STREAM, hist: Histogram] =
BEGIN
s.PutF["total number of nodes: %g\N", int[hist.nContainers]];
s.PutF["following is number of nodes in each ring\N"];
s.PutF["in form ring: n nodes\N"];
FOR I: CARDINAL IN [0..hist.limit) DO
IF hist.counts[I] # 0 THEN
s.PutF[" %g: %g\N", card[I], int[hist.counts[I]]];
ENDLOOP;
IF hist.overflow # 0 THEN
s.PutF[" >= %g: %g\N", int[hist.limit], int[hist.overflow]]
END;
-- support code
Offset: PROC[on: STREAM, count: CARDINAL] =
{FOR I: CARDINAL IN [0..count) DO PutChar[on, ' ] ENDLOOP};
ShowLR1ItemSet: PUBLIC PROC[on: STREAM, offset: CARDINAL, set: REF ANY] =
BEGIN
lr1ItemSet: LR1ItemSet ← NarrowLR1ItemSet[set];
ShowOneSubset: PROC[subSet: LR1ItemSubset] =
BEGIN
Offset[on, offset]; PutRope[on, "[ "];
ShowLR0ItemInner[on, subSet.lr0Item];
PutRope[on, " : "];
ShowTerminalSeqSet[on, 0, subSet.terminals];
PutRope[on, "]\N"];
END;
GenerateSubsetsFromLR1ItemSet[lr1ItemSet, ShowOneSubset, TRUE];
END;
ShowTerminalSeq: PUBLIC PROC[on: STREAM, offset: CARDINAL, seq: TerminalSeq] =
BEGIN
symbol: Symbol ← GetSymbolFromTerminalSeq[seq];
Offset[on, offset];
PutChar[on, '<];
IF symbol # NIL THEN PutRope[on, GetSymbolText[symbol]];
PutChar[on, '>];
END;
END..