mirror of
https://github.com/vishapoberon/compiler.git
synced 2026-04-06 14:32:24 +00:00
voc compiler first commit
This commit is contained in:
parent
4a7dc4b549
commit
760d826948
119 changed files with 30394 additions and 0 deletions
994
src/tools/coco/CRT.Mod
Normal file
994
src/tools/coco/CRT.Mod
Normal file
|
|
@ -0,0 +1,994 @@
|
|||
MODULE CRT; (* H.Moessenboeck 17.11.93, Cocol-R Tables *)
|
||||
|
||||
IMPORT Texts := CmdlnTexts, Oberon, Sets;
|
||||
|
||||
CONST
|
||||
maxSymbols* = 300; (*max nr of t, nt, and pragmas*)
|
||||
maxTerminals* = 256; (*max nr of terminals*)
|
||||
maxNt* = 128; (*max nr of nonterminals*)
|
||||
maxNodes* = 1500; (*max nr of graph nodes*)
|
||||
normTrans* = 0; contextTrans* = 1; (*transition codes*)
|
||||
maxSetNr = 128; (* max. number of symbol sets *)
|
||||
maxClasses = 50; (* max. number of character classes *)
|
||||
|
||||
(* node types *)
|
||||
t* = 1; pr* = 2; nt* = 3; class* = 4; char* = 5; wt* = 6; any* = 7; eps* = 8; sync* = 9; sem* = 10;
|
||||
alt* = 11; iter* = 12; opt* = 13;
|
||||
|
||||
noSym* = -1;
|
||||
eofSy* = 0;
|
||||
|
||||
(* token kinds *)
|
||||
classToken* = 0; (*token class*)
|
||||
litToken* = 1; (*literal (e.g. keyword) not recognized by DFA*)
|
||||
classLitToken* = 2; (*token class that can also match a literal*)
|
||||
|
||||
TYPE
|
||||
Name* = ARRAY 16 OF CHAR; (*symbol name*)
|
||||
Position* = RECORD (*position of stretch of source text*)
|
||||
beg*: LONGINT; (*start relative to beginning of file*)
|
||||
len*: INTEGER; (*length*)
|
||||
col*: INTEGER; (*column number of start position*)
|
||||
END;
|
||||
|
||||
SymbolNode* = RECORD
|
||||
typ*: INTEGER; (*nt, t, pr, unknown*)
|
||||
name*: Name; (*symbol name*)
|
||||
struct*: INTEGER; (*typ = nt: index of 1st node of syntax graph*)
|
||||
(*typ = t: token kind: literal, class, ...*)
|
||||
deletable*: BOOLEAN; (*typ = nt: TRUE, if nonterminal is deletable*)
|
||||
attrPos*: Position; (*position of attributes in source text*)
|
||||
semPos*: Position; (*typ = pr: pos of sem action in source text*)
|
||||
(*typ = nt: pos of local decls in source text *)
|
||||
line*: INTEGER; (*source text line number of item in this node*)
|
||||
END;
|
||||
|
||||
Set* = ARRAY maxTerminals DIV Sets.size OF SET;
|
||||
|
||||
GraphNode* = RECORD
|
||||
typ* : INTEGER; (* nt,sts,wts,char,class,any,eps,sem,sync,alt,iter,opt*)
|
||||
next*: INTEGER; (* index of successor node *)
|
||||
(* next < 0: to successor in enclosing structure *)
|
||||
p1*: INTEGER; (* typ IN {nt, t, wt}: index to symbol list *)
|
||||
(* typ = any: index to anyset *)
|
||||
(* typ = sync: index to syncset *)
|
||||
(* typ = alt: index of 1st node of 1st alternative*)
|
||||
(* typ IN {iter, opt}: 1st node in subexpression *)
|
||||
(* typ = char: ordinal character value *)
|
||||
(* typ = class: index of character class *)
|
||||
p2*: INTEGER; (* typ = alt: index of 1st node of 2nd alternative*)
|
||||
(* typ IN {char, class}: transition code *)
|
||||
pos*: Position; (* typ IN {nt, t, wt}: pos of actual attribs *)
|
||||
(* typ = sem: pos of sem action in source text. *)
|
||||
line*: INTEGER; (* source text line number of item in this node *)
|
||||
END;
|
||||
|
||||
MarkList* = ARRAY maxNodes DIV Sets.size OF SET;
|
||||
|
||||
FirstSets = ARRAY maxNt OF RECORD
|
||||
ts: Set; (*terminal symbols*)
|
||||
ready: BOOLEAN; (*TRUE = ts is complete*)
|
||||
END;
|
||||
FollowSets = ARRAY maxNt OF RECORD
|
||||
ts: Set; (*terminal symbols*)
|
||||
nts: Set; (*nts whose start set is to be included*)
|
||||
END;
|
||||
CharClass = RECORD
|
||||
name: Name; (*class name*)
|
||||
set: INTEGER (* ptr to set representing the class*)
|
||||
END;
|
||||
SymbolTable = ARRAY maxSymbols OF SymbolNode;
|
||||
ClassTable = ARRAY maxClasses OF CharClass;
|
||||
GraphList = ARRAY maxNodes OF GraphNode;
|
||||
|
||||
VAR
|
||||
maxSet*: INTEGER; (* index of last set *)
|
||||
maxT*: INTEGER; (* terminals stored from 0 .. maxT *)
|
||||
maxP*: INTEGER; (* pragmas stored from maxT+1 .. maxP *)
|
||||
firstNt*: INTEGER; (* index of first nt: available after CompSymbolSets *)
|
||||
lastNt*: INTEGER; (* index of last nt: available after CompSymbolSets *)
|
||||
maxC*: INTEGER; (* index of last character class *)
|
||||
semDeclPos*: Position; (*position of global semantic declarations*)
|
||||
importPos*: Position; (*position of imported identifiers*)
|
||||
ignored*: Set; (* characters ignored by the scanner *)
|
||||
ignoreCase*: BOOLEAN; (* TRUE: scanner treats lower case as upper case*)
|
||||
ddt*: ARRAY 10 OF BOOLEAN; (* debug and test switches *)
|
||||
nNodes*: INTEGER; (* index of last graph node *)
|
||||
root*: INTEGER; (* index of root node, filled by ATG *)
|
||||
|
||||
w: Texts.Writer;
|
||||
st: SymbolTable;
|
||||
gn: GraphList;
|
||||
first: FirstSets; (*first[i] = first symbols of st[i+firstNt]*)
|
||||
follow: FollowSets; (*follow[i] = followers of st[i+firstNt]*)
|
||||
chClass: ClassTable; (*character classes*)
|
||||
set: ARRAY 128 OF Set; (*set[0] reserved for union of all synchronisation sets*)
|
||||
dummyName: INTEGER; (*for unnamed character classes*)
|
||||
|
||||
PROCEDURE ^MovePragmas;
|
||||
PROCEDURE ^DelNode*(gn: GraphNode): BOOLEAN;
|
||||
|
||||
PROCEDURE Str(s: ARRAY OF CHAR);
|
||||
BEGIN Texts.WriteString(w, s)
|
||||
END Str;
|
||||
|
||||
PROCEDURE NL;
|
||||
BEGIN Texts.WriteLn(w)
|
||||
END NL;
|
||||
|
||||
PROCEDURE Length(s: ARRAY OF CHAR): INTEGER;
|
||||
VAR i: INTEGER;
|
||||
BEGIN
|
||||
i:=0; WHILE (i < LEN(s)) & (s[i] # 0X) DO INC(i) END;
|
||||
RETURN i
|
||||
END Length;
|
||||
|
||||
PROCEDURE Restriction(n: INTEGER);
|
||||
BEGIN
|
||||
NL; Str("Restriction "); Texts.WriteInt(w, n, 0); NL; Texts.Append(Oberon.Log, w.buf);
|
||||
HALT(99)
|
||||
END Restriction;
|
||||
|
||||
PROCEDURE ClearMarkList(VAR m: MarkList);
|
||||
VAR i: INTEGER;
|
||||
BEGIN
|
||||
i := 0; WHILE i < maxNodes DIV Sets.size DO m[i] := {}; INC(i) END;
|
||||
END ClearMarkList;
|
||||
|
||||
PROCEDURE GetNode*(gp: INTEGER; VAR n: GraphNode);
|
||||
BEGIN
|
||||
n := gn[gp]
|
||||
END GetNode;
|
||||
|
||||
PROCEDURE PutNode*(gp: INTEGER; n: GraphNode);
|
||||
BEGIN gn[gp] := n
|
||||
END PutNode;
|
||||
|
||||
PROCEDURE DelGraph*(gp: INTEGER): BOOLEAN;
|
||||
VAR gn: GraphNode;
|
||||
BEGIN
|
||||
IF gp = 0 THEN RETURN TRUE END; (*end of graph found*)
|
||||
GetNode(gp, gn);
|
||||
RETURN DelNode(gn) & DelGraph(ABS(gn.next));
|
||||
END DelGraph;
|
||||
|
||||
PROCEDURE NewSym*(typ: INTEGER; name: Name; line: INTEGER): INTEGER;
|
||||
VAR i: INTEGER;
|
||||
BEGIN
|
||||
IF maxT + 1 = firstNt THEN Restriction(6)
|
||||
ELSE
|
||||
CASE typ OF
|
||||
| t: INC(maxT); i := maxT
|
||||
| pr: DEC(maxP); DEC(firstNt); DEC(lastNt); i := maxP
|
||||
| nt: DEC(firstNt); i := firstNt
|
||||
END;
|
||||
IF maxT >= maxTerminals THEN Restriction(6) END;
|
||||
st[i].typ := typ; st[i].name := name;
|
||||
st[i].struct := 0; st[i].deletable := FALSE;
|
||||
st[i].attrPos.beg := -1;
|
||||
st[i].semPos.beg := -1;
|
||||
st[i].line := line
|
||||
END;
|
||||
RETURN i
|
||||
END NewSym;
|
||||
|
||||
PROCEDURE GetSym*(sp: INTEGER; VAR sn: SymbolNode);
|
||||
BEGIN sn := st[sp]
|
||||
END GetSym;
|
||||
|
||||
PROCEDURE PutSym*(sp: INTEGER; sn: SymbolNode);
|
||||
BEGIN st[sp] := sn
|
||||
END PutSym;
|
||||
|
||||
PROCEDURE FindSym*(name: Name): INTEGER;
|
||||
VAR i: INTEGER;
|
||||
BEGIN
|
||||
i := 0; (*search in terminal list*)
|
||||
WHILE (i <= maxT) & (st[i].name # name) DO INC(i) END;
|
||||
IF i <= maxT THEN RETURN i END;
|
||||
i := firstNt; (*search in nonterminal/pragma list*)
|
||||
WHILE (i < maxSymbols) & (st[i].name # name) DO INC(i) END;
|
||||
IF i < maxSymbols THEN RETURN i ELSE RETURN noSym END
|
||||
END FindSym;
|
||||
|
||||
PROCEDURE NewSet*(s: Set): INTEGER;
|
||||
BEGIN
|
||||
INC(maxSet); IF maxSet > maxSetNr THEN Restriction(4) END;
|
||||
set[maxSet] := s;
|
||||
RETURN maxSet
|
||||
END NewSet;
|
||||
|
||||
PROCEDURE PrintSet(s: ARRAY OF SET; indent: INTEGER);
|
||||
CONST maxLineLen = 80;
|
||||
VAR col, i, len: INTEGER; empty: BOOLEAN; sn: SymbolNode;
|
||||
BEGIN
|
||||
i := 0; col := indent; empty := TRUE;
|
||||
WHILE i <= maxT DO
|
||||
IF Sets.In(s, i) THEN
|
||||
empty := FALSE; GetSym(i, sn); len := Length(sn.name);
|
||||
IF col + len + 2 > maxLineLen THEN
|
||||
NL; col := 1;
|
||||
WHILE col < indent DO Texts.Write(w, " "); INC(col) END
|
||||
END;
|
||||
Str(sn.name); Str(" ");
|
||||
INC(col, len + 2)
|
||||
END;
|
||||
INC(i)
|
||||
END;
|
||||
IF empty THEN Str("-- empty set --") END;
|
||||
NL; Texts.Append(Oberon.Log, w.buf)
|
||||
END PrintSet;
|
||||
|
||||
PROCEDURE CompFirstSet*(gp: INTEGER; VAR fs: Set);
|
||||
VAR visited: MarkList;
|
||||
|
||||
PROCEDURE CompFirst(gp: INTEGER; VAR fs: Set);
|
||||
VAR s: Set; gn: GraphNode; sn: SymbolNode;
|
||||
BEGIN
|
||||
Sets.Clear(fs);
|
||||
WHILE (gp # 0) & ~ Sets.In(visited, gp) DO
|
||||
GetNode(gp, gn); Sets.Incl(visited, gp);
|
||||
CASE gn.typ OF
|
||||
| nt:
|
||||
IF first[gn.p1 - firstNt].ready THEN
|
||||
Sets.Unite(fs, first[gn.p1 - firstNt].ts);
|
||||
ELSE
|
||||
GetSym(gn.p1, sn); CompFirst(sn.struct, s); Sets.Unite(fs, s);
|
||||
END;
|
||||
| t, wt: Sets.Incl(fs, gn.p1);
|
||||
| any: Sets.Unite(fs, set[gn.p1])
|
||||
| alt, iter, opt:
|
||||
CompFirst(gn.p1, s); Sets.Unite(fs, s);
|
||||
IF gn.typ = alt THEN CompFirst(gn.p2, s); Sets.Unite(fs, s) END
|
||||
ELSE (* eps, sem, sync: nothing *)
|
||||
END;
|
||||
IF ~ DelNode(gn) THEN RETURN END;
|
||||
gp := ABS(gn.next)
|
||||
END
|
||||
END CompFirst;
|
||||
|
||||
BEGIN (* ComputeFirstSet *)
|
||||
ClearMarkList(visited);
|
||||
CompFirst(gp, fs);
|
||||
IF ddt[3] THEN
|
||||
NL; Str("ComputeFirstSet: gp = "); Texts.WriteInt(w, gp, 0); NL;
|
||||
PrintSet(fs, 0);
|
||||
END;
|
||||
END CompFirstSet;
|
||||
|
||||
PROCEDURE CompFirstSets;
|
||||
VAR i: INTEGER; sn: SymbolNode;
|
||||
BEGIN
|
||||
i := firstNt; WHILE i <= lastNt DO first[i-firstNt].ready := FALSE; INC(i) END;
|
||||
i := firstNt;
|
||||
WHILE i <= lastNt DO (* for all nonterminals *)
|
||||
GetSym(i, sn); CompFirstSet(sn.struct, first[i - firstNt].ts);
|
||||
first[i - firstNt].ready := TRUE;
|
||||
INC(i)
|
||||
END;
|
||||
END CompFirstSets;
|
||||
|
||||
PROCEDURE CompExpected*(gp, sp: INTEGER; VAR exp: Set);
|
||||
BEGIN
|
||||
CompFirstSet(gp, exp);
|
||||
IF DelGraph(gp) THEN Sets.Unite(exp, follow[sp - firstNt].ts) END
|
||||
END CompExpected;
|
||||
|
||||
PROCEDURE CompFollowSets;
|
||||
VAR sn: SymbolNode; gn: GraphNode; curSy, i, size: INTEGER; visited: MarkList;
|
||||
|
||||
PROCEDURE CompFol(gp: INTEGER);
|
||||
VAR s: Set; gn: GraphNode;
|
||||
BEGIN
|
||||
WHILE (gp > 0) & ~ Sets.In(visited, gp) DO
|
||||
GetNode(gp, gn); Sets.Incl(visited, gp);
|
||||
IF gn.typ = nt THEN
|
||||
CompFirstSet(ABS(gn.next), s); Sets.Unite(follow[gn.p1 - firstNt].ts, s);
|
||||
IF DelGraph(ABS(gn.next)) THEN
|
||||
Sets.Incl(follow[gn.p1 - firstNt].nts, curSy - firstNt)
|
||||
END
|
||||
ELSIF gn.typ IN {opt, iter} THEN CompFol(gn.p1)
|
||||
ELSIF gn.typ = alt THEN CompFol(gn.p1); CompFol(gn.p2)
|
||||
END;
|
||||
gp := gn.next
|
||||
END
|
||||
END CompFol;
|
||||
|
||||
PROCEDURE Complete(i: INTEGER);
|
||||
VAR j: INTEGER;
|
||||
BEGIN
|
||||
IF Sets.In(visited, i) THEN RETURN END;
|
||||
Sets.Incl(visited, i);
|
||||
j := 0;
|
||||
WHILE j <= lastNt - firstNt DO (* for all nonterminals *)
|
||||
IF Sets.In(follow[i].nts, j) THEN
|
||||
Complete(j); Sets.Unite(follow[i].ts, follow[j].ts);
|
||||
Sets.Excl(follow[i].nts, j)
|
||||
END;
|
||||
INC(j)
|
||||
END;
|
||||
END Complete;
|
||||
|
||||
BEGIN (* CompFollowSets *)
|
||||
curSy := firstNt; size := (lastNt - firstNt + 2) DIV Sets.size;
|
||||
WHILE curSy <= lastNt + 1 DO (* also for dummy root nt*)
|
||||
Sets.Clear(follow[curSy - firstNt].ts);
|
||||
i := 0; WHILE i <= size DO follow[curSy - firstNt].nts[i] := {}; INC(i) END;
|
||||
INC(curSy)
|
||||
END;
|
||||
|
||||
curSy := firstNt; (*get direct successors of nonterminals*)
|
||||
WHILE curSy <= lastNt DO
|
||||
GetSym(curSy, sn); ClearMarkList(visited); CompFol(sn.struct);
|
||||
INC(curSy)
|
||||
END;
|
||||
CompFol(root); (*curSy=lastNt+1*)
|
||||
|
||||
curSy := 0; (*add indirect successors to follow.ts*)
|
||||
WHILE curSy <= lastNt - firstNt DO
|
||||
ClearMarkList(visited); Complete(curSy);
|
||||
INC(curSy);
|
||||
END;
|
||||
END CompFollowSets;
|
||||
|
||||
|
||||
PROCEDURE CompAnySets;
|
||||
VAR curSy, i: INTEGER; sn: SymbolNode;
|
||||
|
||||
PROCEDURE LeadingAny(gp: INTEGER; VAR a: GraphNode): BOOLEAN;
|
||||
VAR gn: GraphNode;
|
||||
BEGIN
|
||||
IF gp <= 0 THEN RETURN FALSE END;
|
||||
GetNode(gp, gn);
|
||||
IF (gn.typ = any) THEN a := gn; RETURN TRUE
|
||||
ELSE RETURN (gn.typ = alt) & (LeadingAny(gn.p1, a) OR LeadingAny(gn.p2, a))
|
||||
OR (gn.typ IN {opt, iter}) & LeadingAny(gn.p1, a)
|
||||
OR DelNode(gn) & LeadingAny(gn.next, a)
|
||||
END
|
||||
END LeadingAny;
|
||||
|
||||
PROCEDURE FindAS(gp: INTEGER);
|
||||
VAR gn, gn2, a: GraphNode; s1, s2: Set; p: INTEGER;
|
||||
BEGIN
|
||||
WHILE gp > 0 DO
|
||||
GetNode(gp, gn);
|
||||
IF gn.typ IN {opt, iter} THEN
|
||||
FindAS(gn.p1);
|
||||
IF LeadingAny(gn.p1, a) THEN
|
||||
CompFirstSet(ABS(gn.next), s1); Sets.Differ(set[a.p1], s1)
|
||||
END
|
||||
ELSIF gn.typ = alt THEN
|
||||
p := gp; Sets.Clear(s1);
|
||||
WHILE p # 0 DO
|
||||
GetNode(p, gn2); FindAS(gn2.p1);
|
||||
IF LeadingAny(gn2.p1, a) THEN
|
||||
CompFirstSet(gn2.p2, s2); Sets.Unite(s2, s1); Sets.Differ(set[a.p1], s2)
|
||||
ELSE
|
||||
CompFirstSet(gn2.p1, s2); Sets.Unite(s1, s2)
|
||||
END;
|
||||
p := gn2.p2
|
||||
END
|
||||
END;
|
||||
gp := gn.next
|
||||
END
|
||||
END FindAS;
|
||||
|
||||
BEGIN
|
||||
curSy := firstNt;
|
||||
WHILE curSy <= lastNt DO (* for all nonterminals *)
|
||||
GetSym(curSy, sn); FindAS(sn.struct);
|
||||
INC(curSy)
|
||||
END
|
||||
END CompAnySets;
|
||||
|
||||
|
||||
PROCEDURE CompSyncSets;
|
||||
VAR curSy, i: INTEGER; sn: SymbolNode; visited: MarkList;
|
||||
|
||||
PROCEDURE CompSync(gp: INTEGER);
|
||||
VAR s: Set; gn: GraphNode;
|
||||
BEGIN
|
||||
WHILE (gp > 0) & ~ Sets.In(visited, gp) DO
|
||||
GetNode(gp, gn); Sets.Incl(visited, gp);
|
||||
IF gn.typ = sync THEN
|
||||
CompExpected(ABS(gn.next), curSy, s);
|
||||
Sets.Incl(s, eofSy); Sets.Unite(set[0], s);
|
||||
gn.p1 := NewSet(s); PutNode(gp, gn)
|
||||
ELSIF gn.typ = alt THEN CompSync(gn.p1); CompSync(gn.p2)
|
||||
ELSIF gn.typ IN {iter, opt} THEN CompSync(gn.p1)
|
||||
END;
|
||||
gp := gn.next
|
||||
END
|
||||
END CompSync;
|
||||
|
||||
BEGIN
|
||||
curSy := firstNt; ClearMarkList(visited);
|
||||
WHILE curSy <= lastNt DO
|
||||
GetSym(curSy, sn); CompSync(sn.struct);
|
||||
INC(curSy);
|
||||
END
|
||||
END CompSyncSets;
|
||||
|
||||
|
||||
PROCEDURE CompDeletableSymbols*;
|
||||
VAR changed, del: BOOLEAN; i: INTEGER; sn: SymbolNode;
|
||||
BEGIN
|
||||
del := FALSE;
|
||||
REPEAT
|
||||
changed := FALSE;
|
||||
i := firstNt;
|
||||
WHILE i <= lastNt DO (*for all nonterminals*)
|
||||
GetSym(i, sn);
|
||||
IF ~sn.deletable & DelGraph(sn.struct) THEN
|
||||
sn.deletable := TRUE; PutSym(i, sn); changed := TRUE; del := TRUE
|
||||
END;
|
||||
INC(i)
|
||||
END;
|
||||
UNTIL ~changed;
|
||||
|
||||
i := firstNt; IF del THEN NL END;
|
||||
WHILE i <= lastNt DO
|
||||
GetSym(i, sn);
|
||||
IF sn.deletable THEN Str(" "); Str(sn.name); Str(" deletable"); NL END;
|
||||
INC(i);
|
||||
END;
|
||||
Texts.Append(Oberon.Log, w.buf)
|
||||
END CompDeletableSymbols;
|
||||
|
||||
|
||||
PROCEDURE CompSymbolSets*;
|
||||
VAR i: INTEGER; sn: SymbolNode;
|
||||
BEGIN
|
||||
i := NewSym(t, "???", 0); (*unknown symbols get code maxT*)
|
||||
MovePragmas;
|
||||
CompDeletableSymbols;
|
||||
CompFirstSets;
|
||||
CompFollowSets;
|
||||
CompAnySets;
|
||||
CompSyncSets;
|
||||
IF ddt[1] THEN
|
||||
i := firstNt; Str("First & follow symbols:"); NL;
|
||||
WHILE i <= lastNt DO (* for all nonterminals *)
|
||||
GetSym(i, sn); Str(sn.name); NL;
|
||||
Str("first: "); PrintSet(first[i - firstNt].ts, 10);
|
||||
Str("follow: "); PrintSet(follow[i - firstNt].ts, 10);
|
||||
NL;
|
||||
INC(i);
|
||||
END;
|
||||
|
||||
IF maxSet >= 0 THEN NL; NL; Str("List of sets (ANY, SYNC): "); NL END;
|
||||
i := 0;
|
||||
WHILE i <= maxSet DO
|
||||
Str(" set["); Texts.WriteInt (w, i, 2); Str("] = "); PrintSet(set[i], 16);
|
||||
INC (i)
|
||||
END;
|
||||
NL; NL; Texts.Append(Oberon.Log, w.buf)
|
||||
END;
|
||||
END CompSymbolSets;
|
||||
|
||||
|
||||
PROCEDURE GetFirstSet(sp: INTEGER; VAR s: Set);
|
||||
BEGIN s := first[sp - firstNt].ts
|
||||
END GetFirstSet;
|
||||
|
||||
PROCEDURE GetFollowSet(sp: INTEGER; VAR s: Set);
|
||||
BEGIN s := follow[sp - firstNt].ts
|
||||
END GetFollowSet;
|
||||
|
||||
PROCEDURE GetSet*(nr: INTEGER; VAR s: Set);
|
||||
BEGIN s := set[nr]
|
||||
END GetSet;
|
||||
|
||||
PROCEDURE MovePragmas;
|
||||
VAR i: INTEGER;
|
||||
BEGIN
|
||||
IF maxP > firstNt THEN
|
||||
i := maxSymbols - 1; maxP := maxT;
|
||||
WHILE i > lastNt DO
|
||||
INC(maxP); IF maxP >= firstNt THEN Restriction(6) END;
|
||||
st[maxP] := st[i]; DEC(i)
|
||||
END;
|
||||
END
|
||||
END MovePragmas;
|
||||
|
||||
PROCEDURE PrintSymbolTable*;
|
||||
VAR i, j: INTEGER;
|
||||
|
||||
PROCEDURE WriteTyp(typ: INTEGER);
|
||||
BEGIN
|
||||
CASE typ OF
|
||||
| t : Str(" t ");
|
||||
| pr : Str(" pr ");
|
||||
| nt : Str(" nt ");
|
||||
END;
|
||||
END WriteTyp;
|
||||
|
||||
BEGIN (* PrintSymbolTable *)
|
||||
Str("Symbol Table:"); NL; NL;
|
||||
Str("nr name typ hasAttribs struct del line"); NL; NL;
|
||||
|
||||
i := 0;
|
||||
WHILE i < maxSymbols DO
|
||||
Texts.WriteInt(w, i, 3); Str(" ");
|
||||
j := 0; WHILE (j < 8) & (st[i].name[j] # 0X) DO Texts.Write(w, st[i].name[j]); INC(j) END;
|
||||
WHILE j < 8 DO Texts.Write(w, " "); INC(j) END;
|
||||
WriteTyp(st[i].typ);
|
||||
IF st[i].attrPos.beg >= 0 THEN Str(" TRUE ") ELSE Str(" FALSE") END;
|
||||
Texts.WriteInt(w, st[i].struct, 10);
|
||||
IF st[i].deletable THEN Str(" TRUE ") ELSE Str(" FALSE") END;
|
||||
Texts.WriteInt(w, st[i].line, 6); NL;
|
||||
IF i = maxT THEN i := firstNt ELSE INC(i) END
|
||||
END;
|
||||
NL; NL; Texts.Append(Oberon.Log, w.buf)
|
||||
END PrintSymbolTable;
|
||||
|
||||
PROCEDURE NewClass*(name: Name; set: Set): INTEGER;
|
||||
BEGIN
|
||||
INC(maxC); IF maxC >= maxClasses THEN Restriction(7) END;
|
||||
IF name[0] = "#" THEN name[1] := CHR(ORD("A") + dummyName); INC(dummyName) END;
|
||||
chClass[maxC].name := name; chClass[maxC].set := NewSet(set);
|
||||
RETURN maxC
|
||||
END NewClass;
|
||||
|
||||
PROCEDURE ClassWithName*(name: Name): INTEGER;
|
||||
VAR i: INTEGER;
|
||||
BEGIN
|
||||
i := maxC; WHILE (i >= 0) & (chClass[i].name # name) DO DEC(i) END;
|
||||
RETURN i
|
||||
END ClassWithName;
|
||||
|
||||
PROCEDURE ClassWithSet*(s: Set): INTEGER;
|
||||
VAR i: INTEGER;
|
||||
BEGIN
|
||||
i := maxC; WHILE (i >= 0) & ~ Sets.Equal(set[chClass[i].set], s) DO DEC(i) END;
|
||||
RETURN i
|
||||
END ClassWithSet;
|
||||
|
||||
PROCEDURE GetClass*(n: INTEGER; VAR s: Set);
|
||||
BEGIN
|
||||
GetSet(chClass[n].set, s)
|
||||
END GetClass;
|
||||
|
||||
PROCEDURE GetClassName*(n: INTEGER; VAR name: Name);
|
||||
BEGIN
|
||||
name := chClass[n].name
|
||||
END GetClassName;
|
||||
|
||||
PROCEDURE XRef*;
|
||||
CONST maxLineLen = 80;
|
||||
TYPE ListPtr = POINTER TO ListNode;
|
||||
ListNode = RECORD
|
||||
next: ListPtr;
|
||||
line: INTEGER;
|
||||
END;
|
||||
ListHdr = RECORD
|
||||
name: Name;
|
||||
lptr: ListPtr;
|
||||
END;
|
||||
VAR gn: GraphNode; col, i, j: INTEGER; l, p, q: ListPtr;
|
||||
sn: SymbolNode;
|
||||
xList: ARRAY maxSymbols OF ListHdr;
|
||||
|
||||
BEGIN (* XRef *)
|
||||
IF maxT <= 0 THEN RETURN END;
|
||||
MovePragmas;
|
||||
(* initialise cross reference list *)
|
||||
i := 0;
|
||||
WHILE i <= lastNt DO (* for all symbols *)
|
||||
GetSym(i, sn); xList[i].name := sn.name; xList[i].lptr := NIL;
|
||||
IF i = maxP THEN i := firstNt ELSE INC(i) END
|
||||
END;
|
||||
|
||||
(* search lines where symbol has been referenced *)
|
||||
i := 1;
|
||||
WHILE i <= nNodes DO (* for all graph nodes *)
|
||||
GetNode(i, gn);
|
||||
IF gn.typ IN {t, wt, nt} THEN
|
||||
NEW(l); l^.next := xList[gn.p1].lptr; l^.line := gn.line;
|
||||
xList[gn.p1].lptr := l
|
||||
END;
|
||||
INC(i);
|
||||
END;
|
||||
|
||||
(* search lines where symbol has been defined and insert in order *)
|
||||
i := 1;
|
||||
WHILE i <= lastNt DO (*for all symbols*)
|
||||
GetSym(i, sn); p := xList[i].lptr; q := NIL;
|
||||
WHILE (p # NIL) & (p^.line > sn.line) DO q := p; p := p^.next END;
|
||||
NEW(l); l^.next := p;
|
||||
l^.line := -sn.line;
|
||||
IF q # NIL THEN q^.next := l ELSE xList[i].lptr := l END;
|
||||
IF i = maxP THEN i := firstNt ELSE INC(i) END
|
||||
END;
|
||||
|
||||
(* print cross reference listing *)
|
||||
NL; Str("Cross reference list:"); NL; NL; Str("Terminals:"); NL; Str(" 0 EOF"); NL;
|
||||
i := 1;
|
||||
WHILE i <= lastNt DO (*for all symbols*)
|
||||
Texts.WriteInt(w, i, 3); Str(" ");
|
||||
j := 0; WHILE (j < 15) & (xList[i].name[j] # 0X) DO Texts.Write(w, xList[i].name[j]); INC(j) END;
|
||||
l := xList[i].lptr; col := 25;
|
||||
WHILE l # NIL DO
|
||||
IF col + 5 > maxLineLen THEN
|
||||
NL; col := 0; WHILE col < 25 DO Texts.Write(w, " "); INC(col) END
|
||||
END;
|
||||
IF l^.line = 0 THEN Str("undef") ELSE Texts.WriteInt(w, l^.line, 5) END;
|
||||
INC(col, 5);
|
||||
l := l^.next
|
||||
END;
|
||||
NL;
|
||||
IF i = maxT THEN NL; Str("Pragmas:"); NL END;
|
||||
IF i = maxP THEN NL; Str("Nonterminals:"); NL; i := firstNt ELSE INC(i) END
|
||||
END;
|
||||
NL; NL; Texts.Append(Oberon.Log, w.buf)
|
||||
END XRef;
|
||||
|
||||
|
||||
PROCEDURE NewNode*(typ, p1, line: INTEGER): INTEGER;
|
||||
BEGIN
|
||||
INC(nNodes); IF nNodes > maxNodes THEN Restriction(3) END;
|
||||
gn[nNodes].typ := typ; gn[nNodes].next := 0;
|
||||
gn[nNodes].p1 := p1; gn[nNodes].p2 := 0;
|
||||
gn[nNodes].pos.beg := -1; gn[nNodes].line := line;
|
||||
RETURN nNodes;
|
||||
END NewNode;
|
||||
|
||||
PROCEDURE CompleteGraph*(gp: INTEGER);
|
||||
VAR p: INTEGER;
|
||||
BEGIN
|
||||
WHILE gp # 0 DO
|
||||
p := gn[gp].next; gn[gp].next := 0; gp := p
|
||||
END
|
||||
END CompleteGraph;
|
||||
|
||||
PROCEDURE ConcatAlt*(VAR gL1, gR1: INTEGER; gL2, gR2: INTEGER);
|
||||
VAR p: INTEGER;
|
||||
BEGIN
|
||||
gL2 := NewNode(alt, gL2, 0);
|
||||
p := gL1; WHILE gn[p].p2 # 0 DO p := gn[p].p2 END; gn[p].p2 := gL2;
|
||||
p := gR1; WHILE gn[p].next # 0 DO p := gn[p].next END; gn[p].next := gR2
|
||||
END ConcatAlt;
|
||||
|
||||
PROCEDURE ConcatSeq*(VAR gL1, gR1: INTEGER; gL2, gR2: INTEGER);
|
||||
VAR p, q: INTEGER;
|
||||
BEGIN
|
||||
p := gn[gR1].next; gn[gR1].next := gL2; (*head node*)
|
||||
WHILE p # 0 DO (*substructure*)
|
||||
q := gn[p].next; gn[p].next := -gL2; p := q
|
||||
END;
|
||||
gR1 := gR2
|
||||
END ConcatSeq;
|
||||
|
||||
PROCEDURE MakeFirstAlt*(VAR gL, gR: INTEGER);
|
||||
BEGIN
|
||||
gL := NewNode(alt, gL, 0); gn[gL].next := gR; gR := gL
|
||||
END MakeFirstAlt;
|
||||
|
||||
PROCEDURE MakeIteration*(VAR gL, gR: INTEGER);
|
||||
VAR p, q: INTEGER;
|
||||
BEGIN
|
||||
gL := NewNode(iter, gL, 0); p := gR; gR := gL;
|
||||
WHILE p # 0 DO
|
||||
q := gn[p].next; gn[p].next := - gL; p := q
|
||||
END
|
||||
END MakeIteration;
|
||||
|
||||
PROCEDURE MakeOption*(VAR gL, gR: INTEGER);
|
||||
BEGIN
|
||||
gL := NewNode(opt, gL, 0); gn[gL].next := gR; gR := gL
|
||||
END MakeOption;
|
||||
|
||||
PROCEDURE StrToGraph*(str: ARRAY OF CHAR; VAR gL, gR: INTEGER);
|
||||
VAR len, i: INTEGER;
|
||||
BEGIN
|
||||
gR := 0; i := 1; len := Length(str) - 1;
|
||||
WHILE i < len DO
|
||||
gn[gR].next := NewNode(char, ORD(str[i]), 0); gR := gn[gR].next;
|
||||
INC(i)
|
||||
END;
|
||||
gL := gn[0].next; gn[0].next := 0
|
||||
END StrToGraph;
|
||||
|
||||
PROCEDURE DelNode*(gn: GraphNode): BOOLEAN;
|
||||
VAR sn: SymbolNode;
|
||||
|
||||
PROCEDURE DelAlt(gp: INTEGER): BOOLEAN;
|
||||
VAR gn: GraphNode;
|
||||
BEGIN
|
||||
IF gp <= 0 THEN RETURN TRUE END; (*end of graph found*)
|
||||
GetNode(gp, gn);
|
||||
RETURN DelNode(gn) & DelAlt(gn.next);
|
||||
END DelAlt;
|
||||
|
||||
BEGIN
|
||||
IF gn.typ = nt THEN GetSym(gn.p1, sn); RETURN sn.deletable
|
||||
ELSIF gn.typ = alt THEN RETURN DelAlt(gn.p1) OR (gn.p2 # 0) & DelAlt(gn.p2)
|
||||
ELSE RETURN gn.typ IN {eps, iter, opt, sem, sync}
|
||||
END
|
||||
END DelNode;
|
||||
|
||||
PROCEDURE PrintGraph*;
|
||||
VAR i: INTEGER;
|
||||
|
||||
PROCEDURE WriteTyp(typ: INTEGER);
|
||||
BEGIN
|
||||
CASE typ OF
|
||||
| nt : Str("nt ")
|
||||
| t : Str("t ")
|
||||
| wt : Str("wt ")
|
||||
| any : Str("any ")
|
||||
| eps : Str("eps ")
|
||||
| sem : Str("sem ")
|
||||
| sync: Str("sync")
|
||||
| alt : Str("alt ")
|
||||
| iter: Str("iter")
|
||||
| opt : Str("opt ")
|
||||
ELSE Str("--- ")
|
||||
END;
|
||||
END WriteTyp;
|
||||
|
||||
BEGIN (* PrintGraph *)
|
||||
Str("GraphList:"); NL; NL;
|
||||
Str(" nr typ next p1 p2 line"); NL; NL;
|
||||
|
||||
i := 0;
|
||||
WHILE i <= nNodes DO
|
||||
Texts.WriteInt(w, i, 3); Str(" ");
|
||||
WriteTyp(gn[i].typ); Texts.WriteInt(w, gn[i].next, 7);
|
||||
Texts.WriteInt(w, gn[i].p1, 7);
|
||||
Texts.WriteInt(w, gn[i].p2, 7);
|
||||
Texts.WriteInt(w, gn[i].line, 7);
|
||||
NL;
|
||||
INC(i);
|
||||
END;
|
||||
NL; NL; Texts.Append(Oberon.Log, w.buf)
|
||||
END PrintGraph;
|
||||
|
||||
PROCEDURE FindCircularProductions* (VAR ok: BOOLEAN);
|
||||
CONST maxList = 150;
|
||||
TYPE ListEntry = RECORD
|
||||
left : INTEGER;
|
||||
right : INTEGER;
|
||||
deleted: BOOLEAN;
|
||||
END;
|
||||
VAR changed, onLeftSide, onRightSide: BOOLEAN; i, j, listLength: INTEGER;
|
||||
list: ARRAY maxList OF ListEntry;
|
||||
singles: MarkList;
|
||||
sn: SymbolNode;
|
||||
|
||||
PROCEDURE GetSingles (gp: INTEGER; VAR singles: MarkList);
|
||||
VAR gn: GraphNode;
|
||||
BEGIN
|
||||
IF gp <= 0 THEN RETURN END; (* end of graph found *)
|
||||
GetNode (gp, gn);
|
||||
IF gn.typ = nt THEN
|
||||
IF DelGraph(ABS(gn.next)) THEN Sets.Incl(singles, gn.p1) END
|
||||
ELSIF gn.typ IN {alt, iter, opt} THEN
|
||||
IF DelGraph(ABS(gn.next)) THEN
|
||||
GetSingles(gn.p1, singles);
|
||||
IF gn.typ = alt THEN GetSingles(gn.p2, singles) END
|
||||
END
|
||||
END;
|
||||
IF DelNode(gn) THEN GetSingles(gn.next, singles) END
|
||||
END GetSingles;
|
||||
|
||||
BEGIN (* FindCircularProductions *)
|
||||
i := firstNt; listLength := 0;
|
||||
WHILE i <= lastNt DO (* for all nonterminals i *)
|
||||
ClearMarkList (singles); GetSym (i, sn);
|
||||
GetSingles (sn.struct, singles); (* get nt's j such that i-->j *)
|
||||
j := firstNt;
|
||||
WHILE j <= lastNt DO (* for all nonterminals j *)
|
||||
IF Sets.In(singles, j) THEN
|
||||
list[listLength].left := i; list[listLength].right := j;
|
||||
list[listLength].deleted := FALSE;
|
||||
INC (listLength)
|
||||
END;
|
||||
INC(j)
|
||||
END;
|
||||
INC(i)
|
||||
END;
|
||||
|
||||
REPEAT
|
||||
i := 0; changed := FALSE;
|
||||
WHILE i < listLength DO
|
||||
IF ~ list[i].deleted THEN
|
||||
j := 0; onLeftSide := FALSE; onRightSide := FALSE;
|
||||
WHILE j < listLength DO
|
||||
IF ~ list[j].deleted THEN
|
||||
IF list[i].left = list[j].right THEN onRightSide := TRUE END;
|
||||
IF list[j].left = list[i].right THEN onLeftSide := TRUE END
|
||||
END;
|
||||
INC(j)
|
||||
END;
|
||||
IF ~ onRightSide OR ~ onLeftSide THEN
|
||||
list[i].deleted := TRUE; changed := TRUE
|
||||
END
|
||||
END;
|
||||
INC(i)
|
||||
END
|
||||
UNTIL ~ changed;
|
||||
|
||||
i := 0; ok := TRUE;
|
||||
WHILE i < listLength DO
|
||||
IF ~ list[i].deleted THEN
|
||||
ok := FALSE;
|
||||
GetSym(list[i].left, sn); NL; Str(" "); Str(sn.name); Str(" --> ");
|
||||
GetSym(list[i].right, sn); Str(sn.name)
|
||||
END;
|
||||
INC(i)
|
||||
END;
|
||||
Texts.Append(Oberon.Log, w.buf)
|
||||
END FindCircularProductions;
|
||||
|
||||
|
||||
PROCEDURE LL1Test* (VAR ll1: BOOLEAN);
|
||||
VAR sn: SymbolNode; curSy: INTEGER;
|
||||
|
||||
PROCEDURE LL1Error (cond, ts: INTEGER);
|
||||
VAR sn: SymbolNode;
|
||||
BEGIN
|
||||
ll1 := FALSE;
|
||||
GetSym (curSy, sn); Str(" LL1 error in "); Str(sn.name); Str(": ");
|
||||
IF ts > 0 THEN GetSym (ts, sn); Str(sn.name); Str(" is ") END;
|
||||
CASE cond OF
|
||||
1: Str(" start of several alternatives.")
|
||||
| 2: Str(" start & successor of deletable structure")
|
||||
| 3: Str(" an ANY node that matchs no symbol")
|
||||
END;
|
||||
NL; Texts.Append(Oberon.Log, w.buf)
|
||||
END LL1Error;
|
||||
|
||||
PROCEDURE Check (cond: INTEGER; VAR s1, s2: Set);
|
||||
VAR i: INTEGER;
|
||||
BEGIN
|
||||
i := 0;
|
||||
WHILE i <= maxT DO
|
||||
IF Sets.In(s1, i) & Sets.In(s2, i) THEN LL1Error(cond, i) END;
|
||||
INC(i)
|
||||
END
|
||||
END Check;
|
||||
|
||||
PROCEDURE CheckAlternatives (gp: INTEGER);
|
||||
VAR gn, gn1: GraphNode; s1, s2: Set; p: INTEGER;
|
||||
BEGIN
|
||||
WHILE gp > 0 DO
|
||||
GetNode(gp, gn);
|
||||
IF gn.typ = alt THEN
|
||||
p := gp; Sets.Clear(s1);
|
||||
WHILE p # 0 DO (*for all alternatives*)
|
||||
GetNode(p, gn1); CompExpected(gn1.p1, curSy, s2);
|
||||
Check(1, s1, s2); Sets.Unite(s1, s2);
|
||||
CheckAlternatives(gn1.p1);
|
||||
p := gn1.p2
|
||||
END
|
||||
ELSIF gn.typ IN {opt, iter} THEN
|
||||
CompExpected(gn.p1, curSy, s1);
|
||||
CompExpected(ABS(gn.next), curSy, s2);
|
||||
Check(2, s1, s2);
|
||||
CheckAlternatives(gn.p1)
|
||||
ELSIF gn.typ = any THEN
|
||||
GetSet(gn.p1, s1);
|
||||
IF Sets.Empty(s1) THEN LL1Error(3, 0) END (*e.g. {ANY} ANY or [ANY] ANY*)
|
||||
END;
|
||||
gp := gn.next
|
||||
END
|
||||
END CheckAlternatives;
|
||||
|
||||
BEGIN (* LL1Test *)
|
||||
curSy := firstNt; ll1 := TRUE;
|
||||
WHILE curSy <= lastNt DO (*for all nonterminals*)
|
||||
GetSym(curSy, sn); CheckAlternatives (sn.struct);
|
||||
INC (curSy)
|
||||
END;
|
||||
END LL1Test;
|
||||
|
||||
|
||||
PROCEDURE TestCompleteness* (VAR ok: BOOLEAN);
|
||||
VAR sp: INTEGER; sn: SymbolNode;
|
||||
BEGIN
|
||||
sp := firstNt; ok := TRUE;
|
||||
WHILE sp <= lastNt DO (*for all nonterminals*)
|
||||
GetSym (sp, sn);
|
||||
IF sn.struct = 0 THEN
|
||||
ok := FALSE; NL; Str(" No production for "); Str(sn.name); Texts.Append(Oberon.Log, w.buf)
|
||||
END;
|
||||
INC(sp)
|
||||
END
|
||||
END TestCompleteness;
|
||||
|
||||
|
||||
PROCEDURE TestIfAllNtReached* (VAR ok: BOOLEAN);
|
||||
VAR gn: GraphNode; sp: INTEGER; reached: MarkList; sn: SymbolNode;
|
||||
|
||||
PROCEDURE MarkReachedNts (gp: INTEGER);
|
||||
VAR gn: GraphNode; sn: SymbolNode;
|
||||
BEGIN
|
||||
WHILE gp > 0 DO
|
||||
GetNode(gp, gn);
|
||||
IF gn.typ = nt THEN
|
||||
IF ~ Sets.In(reached, gn.p1) THEN (*new nt reached*)
|
||||
Sets.Incl(reached, gn.p1);
|
||||
GetSym(gn.p1, sn); MarkReachedNts(sn.struct)
|
||||
END
|
||||
ELSIF gn.typ IN {alt, iter, opt} THEN
|
||||
MarkReachedNts(gn.p1);
|
||||
IF gn.typ = alt THEN MarkReachedNts(gn.p2) END
|
||||
END;
|
||||
gp := gn.next
|
||||
END
|
||||
END MarkReachedNts;
|
||||
|
||||
BEGIN (* TestIfAllNtReached *)
|
||||
ClearMarkList(reached);
|
||||
GetNode(root, gn); Sets.Incl(reached, gn.p1);
|
||||
GetSym(gn.p1, sn); MarkReachedNts(sn.struct);
|
||||
|
||||
sp := firstNt; ok := TRUE;
|
||||
WHILE sp <= lastNt DO (*for all nonterminals*)
|
||||
IF ~ Sets.In(reached, sp) THEN
|
||||
ok := FALSE; GetSym(sp, sn); NL; Str(" "); Str(sn.name); Str(" cannot be reached")
|
||||
END;
|
||||
INC(sp)
|
||||
END;
|
||||
Texts.Append(Oberon.Log, w.buf)
|
||||
END TestIfAllNtReached;
|
||||
|
||||
|
||||
PROCEDURE TestIfNtToTerm* (VAR ok: BOOLEAN);
|
||||
VAR changed: BOOLEAN; gn: GraphNode; sp: INTEGER;
|
||||
sn: SymbolNode;
|
||||
termList: MarkList;
|
||||
|
||||
PROCEDURE IsTerm (gp: INTEGER): BOOLEAN;
|
||||
VAR gn: GraphNode;
|
||||
BEGIN
|
||||
WHILE gp > 0 DO
|
||||
GetNode(gp, gn);
|
||||
IF (gn.typ = nt) & ~ Sets.In(termList, gn.p1)
|
||||
OR (gn.typ = alt) & ~ IsTerm(gn.p1) & ~ IsTerm(gn.p2) THEN RETURN FALSE
|
||||
END;
|
||||
gp := gn.next
|
||||
END;
|
||||
RETURN TRUE
|
||||
END IsTerm;
|
||||
|
||||
BEGIN (* TestIfNtToTerm *)
|
||||
ClearMarkList(termList);
|
||||
REPEAT
|
||||
sp := firstNt; changed := FALSE;
|
||||
WHILE sp <= lastNt DO
|
||||
IF ~ Sets.In(termList, sp) THEN
|
||||
GetSym(sp, sn);
|
||||
IF IsTerm(sn.struct) THEN Sets.Incl(termList, sp); changed := TRUE END
|
||||
END;
|
||||
INC(sp)
|
||||
END
|
||||
UNTIL ~changed;
|
||||
|
||||
sp := firstNt; ok := TRUE;
|
||||
WHILE sp <= lastNt DO
|
||||
IF ~ Sets.In(termList, sp) THEN
|
||||
ok := FALSE; GetSym(sp, sn); NL; Str(" "); Str(sn.name); Str(" cannot be derived to terminals")
|
||||
END;
|
||||
INC(sp)
|
||||
END;
|
||||
Texts.Append(Oberon.Log, w.buf)
|
||||
END TestIfNtToTerm;
|
||||
|
||||
PROCEDURE Init*;
|
||||
BEGIN
|
||||
maxSet := 0; Sets.Clear(set[0]); Sets.Incl(set[0], eofSy);
|
||||
firstNt := maxSymbols; maxP := maxSymbols; maxT := -1; maxC := -1;
|
||||
lastNt := maxP - 1;
|
||||
dummyName := 0;
|
||||
nNodes := 0
|
||||
END Init;
|
||||
|
||||
BEGIN (* CRT *)
|
||||
(* The dummy node gn[0] ensures that none of the procedures
|
||||
above have to check for 0 indices. *)
|
||||
nNodes := 0;
|
||||
gn[0].typ := -1; gn[0].p1 := 0; gn[0].p2 := 0; gn[0].next := 0; gn[0].line := 0;
|
||||
Texts.OpenWriter(w)
|
||||
END CRT.
|
||||
Loading…
Add table
Add a link
Reference in a new issue