|
@@ -0,0 +1,1435 @@
|
|
|
|
|
+IMPLEMENTATION MODULE CRT;
|
|
|
|
|
+
|
|
|
|
|
+(* CRT Table Handler
|
|
|
|
|
+ === =============
|
|
|
|
|
+
|
|
|
|
|
+ (1) handles a symbol table for terminals, pragmas and nonterminals
|
|
|
|
|
+ (2) handles a table for character classes (for scanner generation)
|
|
|
|
|
+ (3) handles a top-down graph for productions
|
|
|
|
|
+ (4) computes various sets (start symbols, followers, any sets)
|
|
|
|
|
+ (5) contains procedures for grammar tests
|
|
|
|
|
+
|
|
|
|
|
+ --------------------------------------------------------------------*)
|
|
|
|
|
+
|
|
|
|
|
+IMPORT CRS, FileIO, Sets, Storage;
|
|
|
|
|
+IMPORT SYSTEM (* for TSIZE only *);
|
|
|
|
|
+
|
|
|
|
|
+CONST
|
|
|
|
|
+ maxSetNr = 256; (* max. number of symbol sets *)
|
|
|
|
|
+(* moved next declaration to def module Fri 08-20-1993, and was 150
|
|
|
|
|
+ maxClasses = 250; (* max. number of character classes *) *)
|
|
|
|
|
+ maxNames = 100; (* max. number of declared token names *)
|
|
|
|
|
+
|
|
|
|
|
+TYPE
|
|
|
|
|
+ FirstSets = ARRAY [0 .. maxNt] OF RECORD
|
|
|
|
|
+ ts: Set; (* terminal symbols *)
|
|
|
|
|
+ ready: BOOLEAN; (* TRUE = ts is complete *)
|
|
|
|
|
+ END;
|
|
|
|
|
+ FollowSets = ARRAY [0 .. maxNt] OF RECORD
|
|
|
|
|
+ ts: Set; (* terminal symbols *)
|
|
|
|
|
+ nts: Set; (* nts whose start set is to be included in ts *)
|
|
|
|
|
+ END;
|
|
|
|
|
+ CharClass = RECORD
|
|
|
|
|
+ name: Name; (* class name *)
|
|
|
|
|
+ set: INTEGER (* ptr to set representing the class *)
|
|
|
|
|
+ END;
|
|
|
|
|
+ SymbolTable = ARRAY [0 .. maxSymbols] OF SymbolNode;
|
|
|
|
|
+ ClassTable = ARRAY [0 .. maxClasses] OF CharClass;
|
|
|
|
|
+ GraphList = ARRAY [0 .. maxNodes] OF GraphNode;
|
|
|
|
|
+ SymbolSet = ARRAY [0 .. maxSetNr] OF Set;
|
|
|
|
|
+ NameTable = ARRAY [1 .. maxNames] OF RECORD name, definition: Name END;
|
|
|
|
|
+
|
|
|
|
|
+VAR
|
|
|
|
|
+ (* moved symbol table to the heap Fri 08-20-1993 to allow larger one *)
|
|
|
|
|
+ st: POINTER TO SymbolTable; (* symbol table for terminals,
|
|
|
|
|
+ pragmas, and nonterminals *)
|
|
|
|
|
+ gn: POINTER TO GraphList; (* top-down graph *)
|
|
|
|
|
+ tt: NameTable; (* table of token name declarations *)
|
|
|
|
|
+ first: FirstSets; (* first[i] = first symbols of st[i+firstNt] *)
|
|
|
|
|
+ follow: FollowSets; (* follow[i] = followers of st[i+firstNt] *)
|
|
|
|
|
+ chClass: ClassTable; (* character classes *)
|
|
|
|
|
+ set: SymbolSet; (* set[0] = all SYNC symbols *)
|
|
|
|
|
+ maxSet: INTEGER; (* index of last symbol set *)
|
|
|
|
|
+ lastName,
|
|
|
|
|
+ dummyName: CARDINAL; (* for unnamed character classes *)
|
|
|
|
|
+ ch: CHAR;
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+(* Restriction Implementation restriction
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+PROCEDURE Restriction (n, limit: INTEGER);
|
|
|
|
|
+(* Fri 08-20-1993 extended *)
|
|
|
|
|
+ BEGIN
|
|
|
|
|
+ FileIO.WriteLn(FileIO.StdOut);
|
|
|
|
|
+ FileIO.WriteString(FileIO.StdOut, "Restriction ");
|
|
|
|
|
+ FileIO.WriteInt(FileIO.StdOut, n, 1); FileIO.WriteLn(FileIO.StdOut);
|
|
|
|
|
+ CASE n OF
|
|
|
|
|
+ 1 : FileIO.WriteString(FileIO.StdOut, "Too many graph nodes")
|
|
|
|
|
+ | 2 : FileIO.WriteString(FileIO.StdOut, "Too many symbols")
|
|
|
|
|
+ | 3 : FileIO.WriteString(FileIO.StdOut, "Too many sets")
|
|
|
|
|
+ | 4 : FileIO.WriteString(FileIO.StdOut, "Too many character classes")
|
|
|
|
|
+ | 5 : FileIO.WriteString(FileIO.StdOut, "Too many symbol sets")
|
|
|
|
|
+ | 6 : FileIO.WriteString(FileIO.StdOut, "Too many token names")
|
|
|
|
|
+ | 7 : FileIO.WriteString(FileIO.StdOut, "Too many states")
|
|
|
|
|
+ | 8 : FileIO.WriteString(FileIO.StdOut, "Semantic text buffer overflow")
|
|
|
|
|
+ | 9 : FileIO.WriteString(FileIO.StdOut, "Circular check buffer overflow")
|
|
|
|
|
+ | 10 : FileIO.WriteString(FileIO.StdOut, "Too many literal terminals")
|
|
|
|
|
+ | 11 : FileIO.WriteString(FileIO.StdOut, "Too many non-terminals")
|
|
|
|
|
+ | -1 : FileIO.WriteString(FileIO.StdOut, "Compiler error")
|
|
|
|
|
+ END;
|
|
|
|
|
+ IF n > 0 THEN
|
|
|
|
|
+ FileIO.WriteString(FileIO.StdOut, " (limited to ");
|
|
|
|
|
+ FileIO.WriteInt(FileIO.StdOut, limit, 1);
|
|
|
|
|
+ FileIO.Write(FileIO.StdOut, ")");
|
|
|
|
|
+ END;
|
|
|
|
|
+(* maybe we want CRX.WriteStatistics; *)
|
|
|
|
|
+ FileIO.QuitExecution
|
|
|
|
|
+ END Restriction;
|
|
|
|
|
+
|
|
|
|
|
+(* MovePragmas Move pragmas after terminals
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+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(2, maxSymbols) END;
|
|
|
|
|
+ st^[maxP] := st^[i]; DEC(i)
|
|
|
|
|
+ END;
|
|
|
|
|
+ END
|
|
|
|
|
+ END MovePragmas;
|
|
|
|
|
+
|
|
|
|
|
+(* ClearMarkList Clear mark list m
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+PROCEDURE ClearMarkList (VAR m: MarkList);
|
|
|
|
|
+ VAR
|
|
|
|
|
+ i: INTEGER;
|
|
|
|
|
+ BEGIN
|
|
|
|
|
+ i := 0;
|
|
|
|
|
+ WHILE i < maxNodes DIV Sets.size DO m[i] := BITSET{}; INC(i) END;
|
|
|
|
|
+ END ClearMarkList;
|
|
|
|
|
+
|
|
|
|
|
+(* GetNode Get node with index gp in n
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+PROCEDURE GetNode (gp: INTEGER; VAR n: GraphNode);
|
|
|
|
|
+ BEGIN
|
|
|
|
|
+ n := gn^[gp]
|
|
|
|
|
+ END GetNode;
|
|
|
|
|
+
|
|
|
|
|
+(* PutNode Replace node with index gp by n
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+PROCEDURE PutNode (gp: INTEGER; n: GraphNode);
|
|
|
|
|
+ BEGIN
|
|
|
|
|
+ gn^[gp] := n
|
|
|
|
|
+ END PutNode;
|
|
|
|
|
+
|
|
|
|
|
+(* NewName Collects a user defined token name
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+PROCEDURE NewName (n: Name; s: ARRAY OF CHAR);
|
|
|
|
|
+ BEGIN
|
|
|
|
|
+ IF lastName = maxNames THEN Restriction(6, maxNames)
|
|
|
|
|
+ ELSE
|
|
|
|
|
+ INC(lastName); symNames := TRUE;
|
|
|
|
|
+ tt[lastName].name := n; FileIO.Assign(s, tt[lastName].definition);
|
|
|
|
|
+ END;
|
|
|
|
|
+ END NewName;
|
|
|
|
|
+
|
|
|
|
|
+(* NewSym Generate a new symbol and return its index
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+PROCEDURE NewSym (typ: INTEGER; name: Name; line: INTEGER): INTEGER;
|
|
|
|
|
+ VAR
|
|
|
|
|
+ i: INTEGER;
|
|
|
|
|
+ BEGIN
|
|
|
|
|
+ IF maxT + 1 = firstNt THEN Restriction(2, maxSymbols)
|
|
|
|
|
+ ELSE
|
|
|
|
|
+ CASE typ OF
|
|
|
|
|
+ t: INC(maxT); i := maxT;
|
|
|
|
|
+ | pr: DEC(maxP); DEC(firstNt); DEC(lastNt); i := maxP;
|
|
|
|
|
+ | nt, unknown: DEC(firstNt); i := firstNt;
|
|
|
|
|
+ END;
|
|
|
|
|
+ IF maxT + 1 >= firstNt THEN Restriction(2, maxSymbols) END;
|
|
|
|
|
+ st^[i].typ := typ; st^[i].name := name;
|
|
|
|
|
+ st^[i].constant := ""; (* Bug fix - PDT *)
|
|
|
|
|
+ st^[i].struct := 0; st^[i].deletable := FALSE;
|
|
|
|
|
+ st^[i].attrPos.beg := - FileIO.Long1;
|
|
|
|
|
+ st^[i].semPos.beg := - FileIO.Long1;
|
|
|
|
|
+ st^[i].line := line;
|
|
|
|
|
+ END;
|
|
|
|
|
+ RETURN i;
|
|
|
|
|
+ END NewSym;
|
|
|
|
|
+
|
|
|
|
|
+(* GetSym Get symbol sp in sn
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+PROCEDURE GetSym (sp: INTEGER; VAR sn: SymbolNode);
|
|
|
|
|
+ BEGIN
|
|
|
|
|
+ sn := st^[sp]
|
|
|
|
|
+ END GetSym;
|
|
|
|
|
+
|
|
|
|
|
+(* PutSym Replace symbol with index snix by sn
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+PROCEDURE PutSym (sp: INTEGER; sn: SymbolNode);
|
|
|
|
|
+ BEGIN
|
|
|
|
|
+ st^[sp] := sn
|
|
|
|
|
+ END PutSym;
|
|
|
|
|
+
|
|
|
|
|
+(* FindSym Find index of symbol with name n
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+PROCEDURE FindSym (n: Name): INTEGER;
|
|
|
|
|
+ VAR
|
|
|
|
|
+ i: INTEGER;
|
|
|
|
|
+ BEGIN
|
|
|
|
|
+ i := 0; (*search in terminal list*)
|
|
|
|
|
+ WHILE (i <= maxT) & (FileIO.Compare(st^[i].name, n) # 0) DO
|
|
|
|
|
+ INC(i)
|
|
|
|
|
+ END;
|
|
|
|
|
+ IF i <= maxT THEN RETURN i END;
|
|
|
|
|
+ i := firstNt; (*search in nonterminal/pragma list*)
|
|
|
|
|
+ WHILE (i < maxSymbols) & (FileIO.Compare(st^[i].name, n) # 0) DO
|
|
|
|
|
+ INC(i)
|
|
|
|
|
+ END;
|
|
|
|
|
+ IF i < maxSymbols THEN RETURN i ELSE RETURN noSym END
|
|
|
|
|
+ END FindSym;
|
|
|
|
|
+
|
|
|
|
|
+(* PrintSet Print set s
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+PROCEDURE PrintSet (f: FileIO.File; s: ARRAY OF BITSET; 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 := FileIO.SLENGTH(sn.name);
|
|
|
|
|
+ IF col + len + 2 > maxLineLen THEN
|
|
|
|
|
+ FileIO.WriteLn(f); col := 1;
|
|
|
|
|
+ WHILE col < indent DO FileIO.Write(f, " "); INC(col) END
|
|
|
|
|
+ END;
|
|
|
|
|
+ FileIO.WriteString(f, sn.name);
|
|
|
|
|
+ FileIO.WriteString(f, " ");
|
|
|
|
|
+ INC(col, len + 2)
|
|
|
|
|
+ END;
|
|
|
|
|
+ INC(i)
|
|
|
|
|
+ END;
|
|
|
|
|
+ IF empty THEN FileIO.WriteString(f, "-- empty set --") END;
|
|
|
|
|
+ FileIO.WriteLn(f)
|
|
|
|
|
+ END PrintSet;
|
|
|
|
|
+
|
|
|
|
|
+(* NewSet Stores s as a new set and return its index
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+PROCEDURE NewSet (s: Set): INTEGER;
|
|
|
|
|
+(*any-set computation requires not to search if s is already in set*)
|
|
|
|
|
+ BEGIN
|
|
|
|
|
+ INC(maxSet); IF maxSet > maxSetNr THEN Restriction(3, maxSetNr) END;
|
|
|
|
|
+ set[maxSet] := s; RETURN maxSet
|
|
|
|
|
+ END NewSet;
|
|
|
|
|
+
|
|
|
|
|
+(* CompFirstSet Compute first symbols of (sub) graph at gp
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+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, ind: nothing *)
|
|
|
|
|
+ END;
|
|
|
|
|
+ IF ~ DelNode(gn) THEN RETURN END;
|
|
|
|
|
+ gp := ABS(gn.next)
|
|
|
|
|
+ END
|
|
|
|
|
+ END CompFirst;
|
|
|
|
|
+
|
|
|
|
|
+ BEGIN (* ComputeFirstSet *)
|
|
|
|
|
+ ClearMarkList(visited);
|
|
|
|
|
+ CompFirst(gp, fs);
|
|
|
|
|
+ IF ddt["I"] THEN
|
|
|
|
|
+ FileIO.WriteLn(FileIO.StdOut);
|
|
|
|
|
+ FileIO.WriteString(FileIO.StdOut, "ComputeFirstSet: gp = ");
|
|
|
|
|
+ FileIO.WriteInt(FileIO.StdOut, gp, 1);
|
|
|
|
|
+ FileIO.WriteLn(FileIO.StdOut);
|
|
|
|
|
+ PrintSet(FileIO.StdOut, fs, 0);
|
|
|
|
|
+ END;
|
|
|
|
|
+ END CompFirstSet;
|
|
|
|
|
+
|
|
|
|
|
+(* CompFirstSets Compute first symbols of nonterminals
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+PROCEDURE CompFirstSets;
|
|
|
|
|
+ VAR
|
|
|
|
|
+ i: INTEGER;
|
|
|
|
|
+ sn: SymbolNode;
|
|
|
|
|
+ BEGIN
|
|
|
|
|
+ i := firstNt;
|
|
|
|
|
+ IF lastNt-firstNt > maxNt THEN Restriction(11, maxNt) END;;
|
|
|
|
|
+ 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;
|
|
|
|
|
+
|
|
|
|
|
+(* CompExpected Compute symbols expected at location gp in Symbol sp
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+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;
|
|
|
|
|
+
|
|
|
|
|
+(* CompFollowSets Get follow symbols of nonterminals
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+PROCEDURE CompFollowSets;
|
|
|
|
|
+ VAR
|
|
|
|
|
+ sn: SymbolNode;
|
|
|
|
|
+ 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=opt) OR (gn.typ=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);
|
|
|
|
|
+ (* fix 1.42 *) IF i = curSy THEN Sets.Excl(follow[i].nts, j) END
|
|
|
|
|
+ END;
|
|
|
|
|
+ INC(j)
|
|
|
|
|
+ END;
|
|
|
|
|
+ END Complete;
|
|
|
|
|
+
|
|
|
|
|
+ BEGIN (* GetFollowSets *)
|
|
|
|
|
+ size := (lastNt - firstNt + 2) DIV Sets.size;
|
|
|
|
|
+ curSy := firstNt;
|
|
|
|
|
+ WHILE curSy <= lastNt DO
|
|
|
|
|
+ Sets.Clear(follow[curSy - firstNt].ts);
|
|
|
|
|
+ i := 0;
|
|
|
|
|
+ WHILE i <= size DO
|
|
|
|
|
+ follow[curSy - firstNt].nts[i] := BITSET{}; INC(i)
|
|
|
|
|
+ END;
|
|
|
|
|
+ INC(curSy)
|
|
|
|
|
+ END;
|
|
|
|
|
+
|
|
|
|
|
+ ClearMarkList(visited);
|
|
|
|
|
+ curSy := firstNt; (*get direct successors of nonterminals*)
|
|
|
|
|
+ WHILE curSy <= lastNt DO
|
|
|
|
|
+ GetSym(curSy, sn); CompFol(sn.struct);
|
|
|
|
|
+ INC(curSy)
|
|
|
|
|
+ END;
|
|
|
|
|
+
|
|
|
|
|
+ curSy := 0; (*add indirect successors to follow.ts*)
|
|
|
|
|
+ WHILE curSy <= lastNt - firstNt DO
|
|
|
|
|
+ ClearMarkList(visited); Complete(curSy);
|
|
|
|
|
+ INC(curSy);
|
|
|
|
|
+ END;
|
|
|
|
|
+ END CompFollowSets;
|
|
|
|
|
+
|
|
|
|
|
+(* CompAnySets Compute all any-sets
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+PROCEDURE CompAnySets;
|
|
|
|
|
+ VAR
|
|
|
|
|
+ curSy: 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=opt) OR (gn.typ=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=opt) OR (gn.typ=iter) THEN
|
|
|
|
|
+ FindAS(gn.p1);
|
|
|
|
|
+ IF LeadingAny(gn.p1, a) THEN
|
|
|
|
|
+ CompExpected(ABS(gn.next), curSy, 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
|
|
|
|
|
+ CompExpected(gn2.p2, curSy, 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;
|
|
|
|
|
+
|
|
|
|
|
+(* CompSyncSets Compute follow symbols of sync-nodes
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+PROCEDURE CompSyncSets;
|
|
|
|
|
+ VAR
|
|
|
|
|
+ curSy: 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=opt) OR (gn.typ=iter) 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;
|
|
|
|
|
+
|
|
|
|
|
+(* CompDeletableSymbols Compute all deletable symbols and print them
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+PROCEDURE CompDeletableSymbols;
|
|
|
|
|
+ VAR
|
|
|
|
|
+ changed, none: BOOLEAN;
|
|
|
|
|
+ i: INTEGER;
|
|
|
|
|
+ sn: SymbolNode;
|
|
|
|
|
+ BEGIN
|
|
|
|
|
+ REPEAT
|
|
|
|
|
+ changed := FALSE;
|
|
|
|
|
+ i := firstNt;
|
|
|
|
|
+ WHILE i <= lastNt DO (*for all nonterminals*)
|
|
|
|
|
+ GetSym(i, sn);
|
|
|
|
|
+ IF ~ sn.deletable & (sn.struct # 0) & DelGraph(sn.struct) THEN
|
|
|
|
|
+ sn.deletable := TRUE; PutSym(i, sn); changed := TRUE
|
|
|
|
|
+ END;
|
|
|
|
|
+ INC(i)
|
|
|
|
|
+ END;
|
|
|
|
|
+ UNTIL ~ changed;
|
|
|
|
|
+
|
|
|
|
|
+ FileIO.WriteString(CRS.lst, "Deletable symbols:");
|
|
|
|
|
+ i := firstNt; none := TRUE;
|
|
|
|
|
+ WHILE i <= lastNt DO
|
|
|
|
|
+ GetSym(i, sn);
|
|
|
|
|
+ IF sn.deletable THEN
|
|
|
|
|
+ none := FALSE;
|
|
|
|
|
+ FileIO.WriteLn(CRS.lst); FileIO.WriteString(CRS.lst, " ");
|
|
|
|
|
+ FileIO.WriteString(CRS.lst, sn.name)
|
|
|
|
|
+ END;
|
|
|
|
|
+ INC(i);
|
|
|
|
|
+ END;
|
|
|
|
|
+ IF none THEN FileIO.WriteString(CRS.lst, " -- none --") END;
|
|
|
|
|
+ FileIO.WriteLn(CRS.lst);
|
|
|
|
|
+ END CompDeletableSymbols;
|
|
|
|
|
+
|
|
|
|
|
+(* CompSymbolSets Get first-sets, follow-sets, and sync-set
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+PROCEDURE CompSymbolSets;
|
|
|
|
|
+ VAR
|
|
|
|
|
+ i: INTEGER;
|
|
|
|
|
+ sn: SymbolNode;
|
|
|
|
|
+ BEGIN
|
|
|
|
|
+ MovePragmas;
|
|
|
|
|
+ CompDeletableSymbols;
|
|
|
|
|
+ CompFirstSets;
|
|
|
|
|
+ CompFollowSets;
|
|
|
|
|
+ CompAnySets;
|
|
|
|
|
+ CompSyncSets;
|
|
|
|
|
+ IF ddt["F"] THEN
|
|
|
|
|
+ i := firstNt;
|
|
|
|
|
+ FileIO.WriteString(CRS.lst, "List of first & follow symbols:");
|
|
|
|
|
+ FileIO.WriteLn(CRS.lst); FileIO.WriteLn(CRS.lst);
|
|
|
|
|
+ WHILE i <= lastNt DO (* for all nonterminals *)
|
|
|
|
|
+ GetSym(i, sn);
|
|
|
|
|
+ FileIO.WriteString(CRS.lst, sn.name); FileIO.WriteLn(CRS.lst);
|
|
|
|
|
+ FileIO.WriteString(CRS.lst, "first: ");
|
|
|
|
|
+ PrintSet(CRS.lst, first[i - firstNt].ts, 10);
|
|
|
|
|
+ FileIO.WriteString(CRS.lst, "follow: ");
|
|
|
|
|
+ PrintSet(CRS.lst, follow[i - firstNt].ts, 10);
|
|
|
|
|
+ FileIO.WriteLn(CRS.lst);
|
|
|
|
|
+ INC(i);
|
|
|
|
|
+ END;
|
|
|
|
|
+
|
|
|
|
|
+ i := 0;
|
|
|
|
|
+ FileIO.WriteLn(CRS.lst); FileIO.WriteLn(CRS.lst);
|
|
|
|
|
+ FileIO.WriteString(CRS.lst, "List of sets (ANY, SYNC): ");
|
|
|
|
|
+ IF maxSet < 0 THEN FileIO.WriteString(CRS.lst, " -- none --");
|
|
|
|
|
+ ELSE FileIO.WriteLn(CRS.lst);
|
|
|
|
|
+ END;
|
|
|
|
|
+ WHILE i <= maxSet DO
|
|
|
|
|
+ FileIO.WriteString(CRS.lst, " set[");
|
|
|
|
|
+ FileIO.WriteInt(CRS.lst, i, 2);
|
|
|
|
|
+ FileIO.WriteString(CRS.lst, "] = ");
|
|
|
|
|
+ PrintSet(CRS.lst, set[i], 16);
|
|
|
|
|
+ INC(i)
|
|
|
|
|
+ END;
|
|
|
|
|
+ FileIO.WriteLn(CRS.lst);
|
|
|
|
|
+ END;
|
|
|
|
|
+ END CompSymbolSets;
|
|
|
|
|
+
|
|
|
|
|
+(* GetFirstSet Get precomputed first-set for nonterminal sp
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+PROCEDURE GetFirstSet (sp: INTEGER; VAR s: Set);
|
|
|
|
|
+ BEGIN
|
|
|
|
|
+ s := first[sp - firstNt].ts
|
|
|
|
|
+ END GetFirstSet;
|
|
|
|
|
+
|
|
|
|
|
+(* GetFollowSet Get precomputed follow-set for nonterminal snix
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+PROCEDURE GetFollowSet (sp: INTEGER; VAR s: Set);
|
|
|
|
|
+ BEGIN
|
|
|
|
|
+ s := follow[sp - firstNt].ts
|
|
|
|
|
+ END GetFollowSet;
|
|
|
|
|
+
|
|
|
|
|
+(* GetSet Get set with index nr
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+PROCEDURE GetSet (nr: INTEGER; VAR s: Set);
|
|
|
|
|
+ BEGIN
|
|
|
|
|
+ s := set[nr]
|
|
|
|
|
+ END GetSet;
|
|
|
|
|
+
|
|
|
|
|
+(* PrintSymbolTable Print symbol table
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+PROCEDURE PrintSymbolTable;
|
|
|
|
|
+ VAR
|
|
|
|
|
+ i: INTEGER;
|
|
|
|
|
+
|
|
|
|
|
+ PROCEDURE WriteBool (b: BOOLEAN);
|
|
|
|
|
+ BEGIN
|
|
|
|
|
+ IF b THEN FileIO.WriteString(CRS.lst, " TRUE ");
|
|
|
|
|
+ ELSE FileIO.WriteString(CRS.lst, " FALSE");
|
|
|
|
|
+ END;
|
|
|
|
|
+ END WriteBool;
|
|
|
|
|
+
|
|
|
|
|
+ PROCEDURE WriteTyp1 (typ: INTEGER);
|
|
|
|
|
+ BEGIN
|
|
|
|
|
+ CASE typ OF
|
|
|
|
|
+ unknown: FileIO.WriteString(CRS.lst, " unknown");
|
|
|
|
|
+ | t : FileIO.WriteString(CRS.lst, " t ");
|
|
|
|
|
+ | pr : FileIO.WriteString(CRS.lst, " pr ");
|
|
|
|
|
+ | nt : FileIO.WriteString(CRS.lst, " nt ");
|
|
|
|
|
+ END;
|
|
|
|
|
+ END WriteTyp1;
|
|
|
|
|
+
|
|
|
|
|
+ BEGIN (* PrintSymbolTable *)
|
|
|
|
|
+ FileIO.WriteString(CRS.lst, "SymbolTable:");
|
|
|
|
|
+ FileIO.WriteLn(CRS.lst); FileIO.WriteLn(CRS.lst);
|
|
|
|
|
+ FileIO.WriteString(CRS.lst, "nr definition ");
|
|
|
|
|
+ IF (*CRT.*) ddt["N"] OR (*CRT.*) symNames THEN
|
|
|
|
|
+ FileIO.WriteString(CRS.lst, "constant ")
|
|
|
|
|
+ END;
|
|
|
|
|
+ FileIO.WriteString(CRS.lst, "typ hasAttrs struct del line");
|
|
|
|
|
+ FileIO.WriteLn(CRS.lst); FileIO.WriteLn(CRS.lst);
|
|
|
|
|
+ i := 0;
|
|
|
|
|
+ WHILE i < maxSymbols DO
|
|
|
|
|
+ FileIO.WriteInt(CRS.lst, i, 3); FileIO.WriteText(CRS.lst, "", 3);
|
|
|
|
|
+ FileIO.WriteText(CRS.lst, st^[i].name, 26);
|
|
|
|
|
+ IF (*CRT.*) ddt["N"] OR (*CRT.*) symNames THEN
|
|
|
|
|
+ IF i <= maxT THEN
|
|
|
|
|
+ FileIO.WriteText(CRS.lst, st^[i].constant, 16);
|
|
|
|
|
+ ELSE
|
|
|
|
|
+ FileIO.WriteText(CRS.lst, "", 16);
|
|
|
|
|
+ END;
|
|
|
|
|
+ END;
|
|
|
|
|
+ WriteTyp1(st^[i].typ);
|
|
|
|
|
+ WriteBool(st^[i].attrPos.beg >= FileIO.Long0);
|
|
|
|
|
+ FileIO.WriteInt(CRS.lst, st^[i].struct, 5);
|
|
|
|
|
+ WriteBool(st^[i].deletable);
|
|
|
|
|
+ FileIO.WriteInt(CRS.lst, st^[i].line, 5);
|
|
|
|
|
+ FileIO.WriteLn(CRS.lst);
|
|
|
|
|
+ IF i = maxT THEN i := firstNt ELSE INC(i) END
|
|
|
|
|
+ END;
|
|
|
|
|
+ FileIO.WriteLn(CRS.lst); FileIO.WriteLn(CRS.lst);
|
|
|
|
|
+ END PrintSymbolTable;
|
|
|
|
|
+
|
|
|
|
|
+(* NewClass Define a new character class
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+PROCEDURE NewClass (name: Name; set: Set): INTEGER;
|
|
|
|
|
+ BEGIN
|
|
|
|
|
+ INC(maxC); IF maxC > maxClasses THEN Restriction(4, maxClasses) 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;
|
|
|
|
|
+
|
|
|
|
|
+(* ClassWithName Return index of class with name n
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+PROCEDURE ClassWithName (n: Name): INTEGER;
|
|
|
|
|
+ VAR
|
|
|
|
|
+ i: INTEGER;
|
|
|
|
|
+ BEGIN
|
|
|
|
|
+ i := maxC;
|
|
|
|
|
+ WHILE (i >= 0) & (FileIO.Compare(chClass[i].name, n) # 0) DO
|
|
|
|
|
+ DEC(i)
|
|
|
|
|
+ END;
|
|
|
|
|
+ RETURN i
|
|
|
|
|
+ END ClassWithName;
|
|
|
|
|
+
|
|
|
|
|
+(* ClassWithSet Return index of class with the specified set
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+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;
|
|
|
|
|
+
|
|
|
|
|
+(* GetClass Return character class n
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+PROCEDURE GetClass (n: INTEGER; VAR s: Set);
|
|
|
|
|
+ BEGIN
|
|
|
|
|
+ GetSet(chClass[n].set, s);
|
|
|
|
|
+ END GetClass;
|
|
|
|
|
+
|
|
|
|
|
+(* GetClassName Get the name of class n
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+PROCEDURE GetClassName (n: INTEGER; VAR name: Name);
|
|
|
|
|
+ BEGIN
|
|
|
|
|
+ name := chClass[n].name
|
|
|
|
|
+ END GetClassName;
|
|
|
|
|
+
|
|
|
|
|
+(* XRef Produce a cross reference listing of all symbols
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+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: INTEGER;
|
|
|
|
|
+ l, p, q: ListPtr;
|
|
|
|
|
+ sn: SymbolNode;
|
|
|
|
|
+ xList: ARRAY [0 .. maxSymbols] OF ListHdr;
|
|
|
|
|
+
|
|
|
|
|
+ BEGIN (* XRef *)
|
|
|
|
|
+ IF maxT <= 0 THEN RETURN END;
|
|
|
|
|
+ MovePragmas;
|
|
|
|
|
+ (* initialize 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 = t) OR (gn.typ = wt) OR (gn.typ = nt) THEN
|
|
|
|
|
+ Storage.ALLOCATE(l, SYSTEM.TSIZE(ListNode));
|
|
|
|
|
+ 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;
|
|
|
|
|
+ Storage.ALLOCATE(l, SYSTEM.TSIZE(ListNode)); 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 *)
|
|
|
|
|
+ FileIO.WriteString(CRS.lst, "Cross reference list:");
|
|
|
|
|
+ FileIO.WriteLn(CRS.lst); FileIO.WriteLn(CRS.lst);
|
|
|
|
|
+ FileIO.WriteString(CRS.lst, "Terminals:"); FileIO.WriteLn(CRS.lst);
|
|
|
|
|
+ FileIO.WriteString(CRS.lst, " 0 EOF"); FileIO.WriteLn(CRS.lst);
|
|
|
|
|
+ i := 1;
|
|
|
|
|
+ WHILE i <= lastNt DO (* for all symbols *)
|
|
|
|
|
+ IF i = maxT THEN
|
|
|
|
|
+ FileIO.WriteLn(CRS.lst);
|
|
|
|
|
+ FileIO.WriteString(CRS.lst, "Pragmas:"); FileIO.WriteLn(CRS.lst);
|
|
|
|
|
+ ELSE
|
|
|
|
|
+ FileIO.WriteInt(CRS.lst, i, 3); FileIO.WriteString(CRS.lst, " ");
|
|
|
|
|
+ FileIO.WriteText(CRS.lst, xList[i].name, 25);
|
|
|
|
|
+ l := xList[i].lptr; col := 35;
|
|
|
|
|
+ WHILE l # NIL DO
|
|
|
|
|
+ IF col + 5 > maxLineLen THEN
|
|
|
|
|
+ FileIO.WriteLn(CRS.lst); FileIO.WriteText(CRS.lst, "", 30);
|
|
|
|
|
+ col := 35
|
|
|
|
|
+ END;
|
|
|
|
|
+ IF l^.line = 0 THEN FileIO.WriteString(CRS.lst, "undef")
|
|
|
|
|
+ ELSE FileIO.WriteInt(CRS.lst, l^.line, 5)
|
|
|
|
|
+ END;
|
|
|
|
|
+ INC(col, 5);
|
|
|
|
|
+ l := l^.next
|
|
|
|
|
+ END;
|
|
|
|
|
+ FileIO.WriteLn(CRS.lst);
|
|
|
|
|
+ END;
|
|
|
|
|
+ IF i = maxP THEN
|
|
|
|
|
+ FileIO.WriteLn(CRS.lst);
|
|
|
|
|
+ FileIO.WriteString(CRS.lst, "Nonterminals:");
|
|
|
|
|
+ FileIO.WriteLn(CRS.lst);
|
|
|
|
|
+ i := firstNt
|
|
|
|
|
+ ELSE INC(i)
|
|
|
|
|
+ END
|
|
|
|
|
+ END;
|
|
|
|
|
+ FileIO.WriteLn(CRS.lst); FileIO.WriteLn(CRS.lst);
|
|
|
|
|
+ END XRef;
|
|
|
|
|
+
|
|
|
|
|
+(* NewNode Generate a new graph node and return its index gp
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+PROCEDURE NewNode (typ, p1, line: INTEGER): INTEGER;
|
|
|
|
|
+ BEGIN
|
|
|
|
|
+ INC(nNodes); IF nNodes > maxNodes THEN Restriction(1, maxNodes) END;
|
|
|
|
|
+ gn^[nNodes].typ := typ; gn^[nNodes].next := 0;
|
|
|
|
|
+ gn^[nNodes].p1 := p1; gn^[nNodes].p2 := 0;
|
|
|
|
|
+ gn^[nNodes].pos.beg := - FileIO.Long1; (* Bugfix - PDT *)
|
|
|
|
|
+ gn^[nNodes].pos.len := 0; gn^[nNodes].pos.col := 0;
|
|
|
|
|
+ gn^[nNodes].line := line;
|
|
|
|
|
+ RETURN nNodes;
|
|
|
|
|
+ END NewNode;
|
|
|
|
|
+
|
|
|
|
|
+(* CompleteGraph Set right ends of graph gp to 0
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+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;
|
|
|
|
|
+
|
|
|
|
|
+(* ConcatAlt Make (gL2, gR2) an alternative of (gL1, gR1)
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+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;
|
|
|
|
|
+
|
|
|
|
|
+(* ConcatSeq Make (gL2, gR2) a successor of (gL1, gR1)
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+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;
|
|
|
|
|
+
|
|
|
|
|
+(* MakeFirstAlt Generate alt-node with (gL,gR) as only alternative
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+PROCEDURE MakeFirstAlt (VAR gL, gR: INTEGER);
|
|
|
|
|
+ BEGIN
|
|
|
|
|
+ gL := NewNode(alt, gL, 0); gn^[gL].next := gR; gR := gL
|
|
|
|
|
+ END MakeFirstAlt;
|
|
|
|
|
+
|
|
|
|
|
+(* MakeIteration Enclose (gL, gR) into iteration node
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+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;
|
|
|
|
|
+
|
|
|
|
|
+(* MakeOption Enclose (gL, gR) into option node
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+PROCEDURE MakeOption (VAR gL, gR: INTEGER);
|
|
|
|
|
+ BEGIN
|
|
|
|
|
+ gL := NewNode(opt, gL, 0); gn^[gL].next := gR; gR := gL
|
|
|
|
|
+ END MakeOption;
|
|
|
|
|
+
|
|
|
|
|
+(* StrToGraph Generate node chain from characters in s
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+PROCEDURE StrToGraph (s: ARRAY OF CHAR; VAR gL, gR: INTEGER);
|
|
|
|
|
+ VAR
|
|
|
|
|
+ i, len: CARDINAL;
|
|
|
|
|
+ BEGIN
|
|
|
|
|
+ gR := 0; i := 1; len := FileIO.SLENGTH(s) - 1; (*strip quotes*)
|
|
|
|
|
+ WHILE i < len DO
|
|
|
|
|
+ gn^[gR].next := NewNode(char, ORD(s[i]), 0); gR := gn^[gR].next;
|
|
|
|
|
+ INC(i)
|
|
|
|
|
+ END;
|
|
|
|
|
+ gL := gn^[0].next; gn^[0].next := 0
|
|
|
|
|
+ END StrToGraph;
|
|
|
|
|
+
|
|
|
|
|
+(* DelGraph Check if graph starting with index gp is deletable
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+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;
|
|
|
|
|
+
|
|
|
|
|
+(* DelNode Check if graph node gn is deletable
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+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 = eps) OR (gn.typ = iter)
|
|
|
|
|
+ OR (gn.typ = opt) OR (gn.typ = sem) OR (gn.typ = sync)
|
|
|
|
|
+ END
|
|
|
|
|
+ END DelNode;
|
|
|
|
|
+
|
|
|
|
|
+(* PrintGraph Print the graph
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+PROCEDURE PrintGraph;
|
|
|
|
|
+ VAR
|
|
|
|
|
+ i: INTEGER;
|
|
|
|
|
+
|
|
|
|
|
+ PROCEDURE WriteTyp2 (typ: INTEGER);
|
|
|
|
|
+ BEGIN
|
|
|
|
|
+ CASE typ OF
|
|
|
|
|
+ nt : FileIO.WriteString(CRS.lst, "nt ")
|
|
|
|
|
+ | t : FileIO.WriteString(CRS.lst, "t ")
|
|
|
|
|
+ | wt : FileIO.WriteString(CRS.lst, "wt ")
|
|
|
|
|
+ | any : FileIO.WriteString(CRS.lst, "any ")
|
|
|
|
|
+ | eps : FileIO.WriteString(CRS.lst, "eps ")
|
|
|
|
|
+ | sem : FileIO.WriteString(CRS.lst, "sem ")
|
|
|
|
|
+ | sync: FileIO.WriteString(CRS.lst, "sync")
|
|
|
|
|
+ | alt : FileIO.WriteString(CRS.lst, "alt ")
|
|
|
|
|
+ | iter: FileIO.WriteString(CRS.lst, "iter")
|
|
|
|
|
+ | opt : FileIO.WriteString(CRS.lst, "opt ")
|
|
|
|
|
+ ELSE FileIO.WriteString(CRS.lst, "--- ")
|
|
|
|
|
+ END;
|
|
|
|
|
+ END WriteTyp2;
|
|
|
|
|
+
|
|
|
|
|
+ BEGIN (* PrintGraph *)
|
|
|
|
|
+ FileIO.WriteString(CRS.lst, "GraphList:");
|
|
|
|
|
+ FileIO.WriteLn(CRS.lst); FileIO.WriteLn(CRS.lst);
|
|
|
|
|
+ FileIO.WriteString(CRS.lst, " nr typ next p1 p2 line");
|
|
|
|
|
+(* useful for debugging - PDT *)
|
|
|
|
|
+ FileIO.WriteString(CRS.lst, " posbeg poslen poscol");
|
|
|
|
|
+(* *)
|
|
|
|
|
+ FileIO.WriteLn(CRS.lst); FileIO.WriteLn(CRS.lst);
|
|
|
|
|
+ i := 0;
|
|
|
|
|
+ WHILE i <= nNodes DO
|
|
|
|
|
+ FileIO.WriteInt(CRS.lst, i, 3); FileIO.WriteString(CRS.lst, " ");
|
|
|
|
|
+ WriteTyp2(gn^[i].typ); FileIO.WriteInt(CRS.lst, gn^[i].next, 7);
|
|
|
|
|
+ FileIO.WriteInt(CRS.lst, gn^[i].p1, 7);
|
|
|
|
|
+ FileIO.WriteInt(CRS.lst, gn^[i].p2, 7);
|
|
|
|
|
+ FileIO.WriteInt(CRS.lst, gn^[i].line, 7);
|
|
|
|
|
+(* useful for debugging - PDT *)
|
|
|
|
|
+ FileIO.WriteInt(CRS.lst, FileIO.INTL(gn^[i].pos.beg), 7);
|
|
|
|
|
+ FileIO.WriteCard(CRS.lst, gn^[i].pos.len, 7);
|
|
|
|
|
+ FileIO.WriteInt(CRS.lst, gn^[i].pos.col, 7);
|
|
|
|
|
+(* *)
|
|
|
|
|
+ FileIO.WriteLn(CRS.lst);
|
|
|
|
|
+ INC(i);
|
|
|
|
|
+ END;
|
|
|
|
|
+ FileIO.WriteLn(CRS.lst); FileIO.WriteLn(CRS.lst);
|
|
|
|
|
+ END PrintGraph;
|
|
|
|
|
+
|
|
|
|
|
+(* FindCircularProductions Test grammar for circular derivations
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+PROCEDURE FindCircularProductions (VAR ok: BOOLEAN);
|
|
|
|
|
+ TYPE
|
|
|
|
|
+ ListEntry = RECORD
|
|
|
|
|
+ left: INTEGER;
|
|
|
|
|
+ right: INTEGER;
|
|
|
|
|
+ deleted: BOOLEAN;
|
|
|
|
|
+ END;
|
|
|
|
|
+ VAR
|
|
|
|
|
+ changed, onLeftSide,
|
|
|
|
|
+ onRightSide: BOOLEAN;
|
|
|
|
|
+ i, j, listLength: INTEGER;
|
|
|
|
|
+ list: ARRAY [0 .. 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 = alt) OR (gn.typ = iter) OR (gn.typ = 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);
|
|
|
|
|
+ IF listLength > maxList THEN Restriction(9, maxList) END
|
|
|
|
|
+ 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;
|
|
|
|
|
+
|
|
|
|
|
+ FileIO.WriteString(CRS.lst, "Circular derivations: ");
|
|
|
|
|
+ i := 0; ok := TRUE;
|
|
|
|
|
+ WHILE i < listLength DO
|
|
|
|
|
+ IF ~ list[i].deleted THEN
|
|
|
|
|
+ ok := FALSE;
|
|
|
|
|
+ FileIO.WriteLn(CRS.lst); FileIO.WriteString(CRS.lst, " ");
|
|
|
|
|
+ GetSym(list[i].left, sn); FileIO.WriteText(CRS.lst, sn.name, 20);
|
|
|
|
|
+ FileIO.WriteString(CRS.lst, " --> ");
|
|
|
|
|
+ GetSym(list[i].right, sn); FileIO.WriteText(CRS.lst, sn.name, 20);
|
|
|
|
|
+ END;
|
|
|
|
|
+ INC(i)
|
|
|
|
|
+ END;
|
|
|
|
|
+ IF ok THEN FileIO.WriteString(CRS.lst, " -- none --") END;
|
|
|
|
|
+ FileIO.WriteLn(CRS.lst);
|
|
|
|
|
+ END FindCircularProductions;
|
|
|
|
|
+
|
|
|
|
|
+(* LL1Test Collect terminal sets and checks LL(1) conditions
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+PROCEDURE LL1Test (VAR ll1: BOOLEAN);
|
|
|
|
|
+ VAR
|
|
|
|
|
+ sn: SymbolNode;
|
|
|
|
|
+ curSy: INTEGER;
|
|
|
|
|
+
|
|
|
|
|
+ PROCEDURE LL1Error (cond, ts: INTEGER);
|
|
|
|
|
+ VAR
|
|
|
|
|
+ sn: SymbolNode;
|
|
|
|
|
+ BEGIN
|
|
|
|
|
+ ll1 := FALSE;
|
|
|
|
|
+ FileIO.WriteLn(CRS.lst);
|
|
|
|
|
+ FileIO.WriteString(CRS.lst, " LL(1) error in ");
|
|
|
|
|
+ GetSym(curSy, sn); FileIO.WriteString(CRS.lst, sn.name);
|
|
|
|
|
+ FileIO.WriteString(CRS.lst, ": ");
|
|
|
|
|
+ IF ts > 0 THEN
|
|
|
|
|
+ GetSym(ts, sn); FileIO.WriteString(CRS.lst, sn.name);
|
|
|
|
|
+ FileIO.WriteString(CRS.lst, " is ");
|
|
|
|
|
+ END;
|
|
|
|
|
+ CASE cond OF
|
|
|
|
|
+ 1: FileIO.WriteString(CRS.lst,
|
|
|
|
|
+ "the start of several alternatives.")
|
|
|
|
|
+ | 2: FileIO.WriteString(CRS.lst,
|
|
|
|
|
+ "the start & successor of a deletable structure")
|
|
|
|
|
+ | 3: FileIO.WriteString(CRS.lst,
|
|
|
|
|
+ "an ANY node that matches no symbol")
|
|
|
|
|
+ END;
|
|
|
|
|
+ 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 = opt) OR (gn.typ = 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 *)
|
|
|
|
|
+ FileIO.WriteString(CRS.lst, "LL(1) conditions:");
|
|
|
|
|
+ curSy := firstNt; ll1 := TRUE;
|
|
|
|
|
+ WHILE curSy <= lastNt DO (*for all nonterminals*)
|
|
|
|
|
+ GetSym(curSy, sn); CheckAlternatives(sn.struct);
|
|
|
|
|
+ INC(curSy)
|
|
|
|
|
+ END;
|
|
|
|
|
+ IF ll1 THEN FileIO.WriteString(CRS.lst, " -- ok --") END;
|
|
|
|
|
+ FileIO.WriteLn(CRS.lst);
|
|
|
|
|
+ END LL1Test;
|
|
|
|
|
+
|
|
|
|
|
+(* TestCompleteness Test if all nonterminals have productions
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+PROCEDURE TestCompleteness (VAR ok: BOOLEAN);
|
|
|
|
|
+ VAR
|
|
|
|
|
+ sp: INTEGER;
|
|
|
|
|
+ sn: SymbolNode;
|
|
|
|
|
+ BEGIN
|
|
|
|
|
+ FileIO.WriteString(CRS.lst, "Undefined nonterminals: ");
|
|
|
|
|
+ sp := firstNt; ok := TRUE;
|
|
|
|
|
+ WHILE sp <= lastNt DO (*for all nonterminals*)
|
|
|
|
|
+ GetSym(sp, sn);
|
|
|
|
|
+ IF sn.struct = 0 THEN
|
|
|
|
|
+ ok := FALSE;
|
|
|
|
|
+ FileIO.WriteLn(CRS.lst); FileIO.WriteString(CRS.lst, " ");
|
|
|
|
|
+ FileIO.WriteString(CRS.lst, sn.name);
|
|
|
|
|
+ END;
|
|
|
|
|
+ INC(sp)
|
|
|
|
|
+ END;
|
|
|
|
|
+ IF ok THEN FileIO.WriteString(CRS.lst, " -- none --") END;
|
|
|
|
|
+ FileIO.WriteLn(CRS.lst);
|
|
|
|
|
+ END TestCompleteness;
|
|
|
|
|
+
|
|
|
|
|
+(* TestIfAllNtReached Test if all nonterminals can be reached
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+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 = alt) OR (gn.typ = iter) OR (gn.typ = 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);
|
|
|
|
|
+
|
|
|
|
|
+ FileIO.WriteString(CRS.lst, "Unreachable nonterminals:");
|
|
|
|
|
+ sp := firstNt; ok := TRUE;
|
|
|
|
|
+ WHILE sp <= lastNt DO (*for all nonterminals*)
|
|
|
|
|
+ IF ~ Sets.In(reached, sp) THEN
|
|
|
|
|
+ ok := FALSE; GetSym(sp, sn);
|
|
|
|
|
+ FileIO.WriteLn(CRS.lst); FileIO.WriteString(CRS.lst, " ");
|
|
|
|
|
+ FileIO.WriteString(CRS.lst, sn.name)
|
|
|
|
|
+ END;
|
|
|
|
|
+ INC(sp)
|
|
|
|
|
+ END;
|
|
|
|
|
+ IF ok THEN FileIO.WriteString(CRS.lst, " -- none --") END;
|
|
|
|
|
+ FileIO.WriteLn(CRS.lst);
|
|
|
|
|
+ END TestIfAllNtReached;
|
|
|
|
|
+
|
|
|
|
|
+(* TestIfNtToTerm Test if all nonterminals can be derived to terminals
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+PROCEDURE TestIfNtToTerm (VAR ok: BOOLEAN);
|
|
|
|
|
+ VAR
|
|
|
|
|
+ changed: BOOLEAN;
|
|
|
|
|
+ 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)
|
|
|
|
|
+ & ((gn.p2 = 0) OR ~ 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;
|
|
|
|
|
+
|
|
|
|
|
+ FileIO.WriteString(CRS.lst, "Underivable nonterminals:");
|
|
|
|
|
+ sp := firstNt; ok := TRUE;
|
|
|
|
|
+ WHILE sp <= lastNt DO
|
|
|
|
|
+ IF ~ Sets.In(termList, sp) THEN
|
|
|
|
|
+ ok := FALSE; GetSym(sp, sn);
|
|
|
|
|
+ FileIO.WriteLn(CRS.lst); FileIO.WriteString(CRS.lst, " ");
|
|
|
|
|
+ FileIO.WriteString(CRS.lst, sn.name);
|
|
|
|
|
+ END;
|
|
|
|
|
+ INC(sp)
|
|
|
|
|
+ END;
|
|
|
|
|
+ IF ok THEN FileIO.WriteString(CRS.lst, " -- none --") END;
|
|
|
|
|
+ FileIO.WriteLn(CRS.lst);
|
|
|
|
|
+ END TestIfNtToTerm;
|
|
|
|
|
+
|
|
|
|
|
+(* ASCIIName Assigns the wellknown ASCII-Name in lowercase
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+PROCEDURE ASCIIName (ascii: CHAR; VAR asciiname: Name);
|
|
|
|
|
+ VAR
|
|
|
|
|
+ N : CARDINAL;
|
|
|
|
|
+ BEGIN
|
|
|
|
|
+ CASE ascii OF
|
|
|
|
|
+ 00C : asciiname := "nul"
|
|
|
|
|
+ | 01C : asciiname := "soh"
|
|
|
|
|
+ | 02C : asciiname := "stx"
|
|
|
|
|
+ | 03C : asciiname := "etx"
|
|
|
|
|
+ | 04C : asciiname := "eot"
|
|
|
|
|
+ | 05C : asciiname := "enq"
|
|
|
|
|
+ | 06C : asciiname := "ack"
|
|
|
|
|
+ | 07C : asciiname := "bel"
|
|
|
|
|
+ | 10C : asciiname := "bs"
|
|
|
|
|
+ | 11C : asciiname := "ht"
|
|
|
|
|
+ | 12C : asciiname := "lf"
|
|
|
|
|
+ | 13C : asciiname := "vt"
|
|
|
|
|
+ | 14C : asciiname := "ff"
|
|
|
|
|
+ | 15C : asciiname := "cr"
|
|
|
|
|
+ | 16C : asciiname := "so"
|
|
|
|
|
+ | 17C : asciiname := "si"
|
|
|
|
|
+ | 20C : asciiname := "dle"
|
|
|
|
|
+ | 21C : asciiname := "dc1"
|
|
|
|
|
+ | 22C : asciiname := "dc2"
|
|
|
|
|
+ | 23C : asciiname := "dc3"
|
|
|
|
|
+ | 24C : asciiname := "dc4"
|
|
|
|
|
+ | 25C : asciiname := "nak"
|
|
|
|
|
+ | 26C : asciiname := "syn"
|
|
|
|
|
+ | 27C : asciiname := "etb"
|
|
|
|
|
+ | 30C : asciiname := "can"
|
|
|
|
|
+ | 31C : asciiname := "em"
|
|
|
|
|
+ | 32C : asciiname := "sub"
|
|
|
|
|
+ | 33C : asciiname := "esc"
|
|
|
|
|
+ | 34C : asciiname := "fs"
|
|
|
|
|
+ | 35C : asciiname := "gs"
|
|
|
|
|
+ | 36C : asciiname := "rs"
|
|
|
|
|
+ | 37C : asciiname := "us"
|
|
|
|
|
+ | " " : asciiname := "sp"
|
|
|
|
|
+ | "!" : asciiname := "bang"
|
|
|
|
|
+ | '"' : asciiname := "dquote"
|
|
|
|
|
+ | "#" : asciiname := "hash"
|
|
|
|
|
+ | "$" : asciiname := "dollar"
|
|
|
|
|
+ | "%" : asciiname := "percent"
|
|
|
|
|
+ | "&" : asciiname := "and"
|
|
|
|
|
+ | "'" : asciiname := "squote"
|
|
|
|
|
+ | "(" : asciiname := "lparen"
|
|
|
|
|
+ | ")" : asciiname := "rparen"
|
|
|
|
|
+ | "*" : asciiname := "star"
|
|
|
|
|
+ | "+" : asciiname := "plus"
|
|
|
|
|
+ | "," : asciiname := "comma"
|
|
|
|
|
+ | "-" : asciiname := "minus"
|
|
|
|
|
+ | "." : asciiname := "point"
|
|
|
|
|
+ | "/" : asciiname := "slash"
|
|
|
|
|
+ | "0" : asciiname := "zero"
|
|
|
|
|
+ | "1" : asciiname := "one"
|
|
|
|
|
+ | "2" : asciiname := "two"
|
|
|
|
|
+ | "3" : asciiname := "three"
|
|
|
|
|
+ | "4" : asciiname := "four"
|
|
|
|
|
+ | "5" : asciiname := "five"
|
|
|
|
|
+ | "6" : asciiname := "six"
|
|
|
|
|
+ | "7" : asciiname := "seven"
|
|
|
|
|
+ | "8" : asciiname := "eight"
|
|
|
|
|
+ | "9" : asciiname := "nine"
|
|
|
|
|
+ | ":" : asciiname := "colon"
|
|
|
|
|
+ | ";" : asciiname := "semicolon"
|
|
|
|
|
+ | "<" : asciiname := "less"
|
|
|
|
|
+ | "=" : asciiname := "equal"
|
|
|
|
|
+ | ">" : asciiname := "greater"
|
|
|
|
|
+ | "?" : asciiname := "query"
|
|
|
|
|
+ | "@" : asciiname := "at"
|
|
|
|
|
+ | "A" .. "Z", "a" .. "z"
|
|
|
|
|
+ : asciiname := " "; asciiname[0] := ascii
|
|
|
|
|
+ | "[" : asciiname := "lbrack"
|
|
|
|
|
+ | "\" : asciiname := "backslash"
|
|
|
|
|
+ | "]" : asciiname := "rbrack"
|
|
|
|
|
+ | "^" : asciiname := "uparrow"
|
|
|
|
|
+ | "_" : asciiname := "underscore"
|
|
|
|
|
+ | "`" : asciiname := "accent"
|
|
|
|
|
+ | "{" : asciiname := "lbrace"
|
|
|
|
|
+ | "|" : asciiname := "bar"
|
|
|
|
|
+ | "}" : asciiname := "rbrace"
|
|
|
|
|
+ | "~" : asciiname := "tilde"
|
|
|
|
|
+ | 177C: asciiname := "delete"
|
|
|
|
|
+ ELSE
|
|
|
|
|
+ N := ORD(ascii);
|
|
|
|
|
+ asciiname := 'ascii ';
|
|
|
|
|
+ asciiname[6] := CHR(N MOD 10 + ORD('0'));
|
|
|
|
|
+ N := N DIV 10;
|
|
|
|
|
+ asciiname[5] := CHR(N MOD 10 + ORD('0'));
|
|
|
|
|
+ asciiname[4] := CHR(N DIV 10 + ORD('0'));
|
|
|
|
|
+ END
|
|
|
|
|
+ END ASCIIName;
|
|
|
|
|
+
|
|
|
|
|
+(* BuildName Build new Name to represent old string
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+PROCEDURE BuildName (VAR old, new: ARRAY OF CHAR);
|
|
|
|
|
+ VAR
|
|
|
|
|
+ ForLoop, I, TargetIndex: CARDINAL;
|
|
|
|
|
+ AsciiName: Name;
|
|
|
|
|
+ BEGIN
|
|
|
|
|
+ TargetIndex := 0;
|
|
|
|
|
+ FOR ForLoop := 1 TO FileIO.SLENGTH(old) - 2 DO
|
|
|
|
|
+ CASE old[ForLoop] OF
|
|
|
|
|
+ "A" .. "Z", "a" .. "z":
|
|
|
|
|
+ IF TargetIndex <= HIGH(new) THEN
|
|
|
|
|
+ new[TargetIndex] := old[ForLoop];
|
|
|
|
|
+ INC(TargetIndex);
|
|
|
|
|
+ END;
|
|
|
|
|
+ ELSE
|
|
|
|
|
+ ASCIIName(old[ForLoop], AsciiName);
|
|
|
|
|
+ FOR I := 0 TO FileIO.SLENGTH(AsciiName) - 1 DO
|
|
|
|
|
+ IF TargetIndex <= HIGH(new) THEN
|
|
|
|
|
+ new[TargetIndex] := AsciiName[I];
|
|
|
|
|
+ INC(TargetIndex);
|
|
|
|
|
+ END;
|
|
|
|
|
+ END;
|
|
|
|
|
+ END;
|
|
|
|
|
+ END;
|
|
|
|
|
+ IF TargetIndex <= HIGH(new) THEN new[TargetIndex] := 0C END;
|
|
|
|
|
+ END BuildName;
|
|
|
|
|
+
|
|
|
|
|
+(* SymName Generates a new name for a symbol constant
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+PROCEDURE SymName (symn: Name; VAR conn: Name);
|
|
|
|
|
+ BEGIN
|
|
|
|
|
+ IF (symn[0] = '"') OR (symn[0] = "'") THEN
|
|
|
|
|
+ IF FileIO.SLENGTH(symn) = 3 THEN
|
|
|
|
|
+ ASCIIName(symn[1], conn);
|
|
|
|
|
+ ELSE
|
|
|
|
|
+ BuildName(symn, conn);
|
|
|
|
|
+ END;
|
|
|
|
|
+ ELSE
|
|
|
|
|
+ conn := symn;
|
|
|
|
|
+ END;
|
|
|
|
|
+ FileIO.Concat(conn, "Sym", conn);
|
|
|
|
|
+ END SymName;
|
|
|
|
|
+
|
|
|
|
|
+(* AssignSymNames Assigns the user defined or generated token names
|
|
|
|
|
+----------------------------------------------------------------------*)
|
|
|
|
|
+PROCEDURE AssignSymNames (default: BOOLEAN; VAR thereExists: BOOLEAN);
|
|
|
|
|
+
|
|
|
|
|
+ PROCEDURE AssignDef (VAR n (*is not modified*), const: Name);
|
|
|
|
|
+ VAR
|
|
|
|
|
+ ForLoop: CARDINAL;
|
|
|
|
|
+ BEGIN
|
|
|
|
|
+ FOR ForLoop := 1 TO lastName DO
|
|
|
|
|
+ IF FileIO.Compare(n, tt[ForLoop].definition) = 0 THEN
|
|
|
|
|
+ const := tt[ForLoop].name; thereExists := TRUE; RETURN;
|
|
|
|
|
+ END;
|
|
|
|
|
+ END;
|
|
|
|
|
+ IF default THEN SymName(n, const); ELSE const := ""; END;
|
|
|
|
|
+ END AssignDef;
|
|
|
|
|
+
|
|
|
|
|
+ VAR
|
|
|
|
|
+ ForLoop: INTEGER;
|
|
|
|
|
+
|
|
|
|
|
+ BEGIN
|
|
|
|
|
+ thereExists := default;
|
|
|
|
|
+ st^[0].constant := "EOFSYM";
|
|
|
|
|
+ FOR ForLoop := 1 TO maxP DO
|
|
|
|
|
+ AssignDef(st^[ForLoop].name, st^[ForLoop].constant)
|
|
|
|
|
+ END;
|
|
|
|
|
+ st^[maxT].constant := "NOSYM";
|
|
|
|
|
+ END AssignSymNames;
|
|
|
|
|
+
|
|
|
|
|
+BEGIN (* CRT *)
|
|
|
|
|
+ ch := "A"; WHILE ch <= "Z" DO ddt[ch] := FALSE; INC(ch) END;
|
|
|
|
|
+ maxSet := 0; Sets.Clear(set[0]); Sets.Incl(set[0], eofSy);
|
|
|
|
|
+ firstNt := maxSymbols; maxP := maxSymbols; maxT := -1; maxC := -1;
|
|
|
|
|
+ lastNt := maxP - 1;
|
|
|
|
|
+ dummyName := 0; lastName := 0; symNames := FALSE;
|
|
|
|
|
+ (* The dummy node gn^[0] ensures that none of the procedures
|
|
|
|
|
+ above have to check for 0 indices. *)
|
|
|
|
|
+ Storage.ALLOCATE(gn, SYSTEM.TSIZE(GraphList));
|
|
|
|
|
+ Storage.ALLOCATE(st, SYSTEM.TSIZE(SymbolTable));
|
|
|
|
|
+ nNodes := 0;
|
|
|
|
|
+ gn^[0].typ := -1; gn^[0].p1 := 0; gn^[0].p2 := 0;
|
|
|
|
|
+ gn^[0].next := 0; gn^[0].line := 0;
|
|
|
|
|
+ gn^[0].pos.beg := - FileIO.Long1;
|
|
|
|
|
+ gn^[0].pos.len := 0; gn^[0].pos.col := 0;
|
|
|
|
|
+(* debug info when choosing constants - PDT
|
|
|
|
|
+ FileIO.WriteString(FileIO.StdOut, "Symbol table");
|
|
|
|
|
+ FileIO.WriteCard(FileIO.StdOut, SIZE(SymbolTable), 1);
|
|
|
|
|
+ FileIO.WriteLn(FileIO.StdOut);
|
|
|
|
|
+ FileIO.WriteString(FileIO.StdOut, "Class table ");
|
|
|
|
|
+ FileIO.WriteCard(FileIO.StdOut, SIZE(ClassTable), 1);
|
|
|
|
|
+ FileIO.WriteLn(FileIO.StdOut);
|
|
|
|
|
+ FileIO.WriteString(FileIO.StdOut, "Name table ");
|
|
|
|
|
+ FileIO.WriteCard(FileIO.StdOut, SIZE(NameTable), 1);
|
|
|
|
|
+ FileIO.WriteLn(FileIO.StdOut);
|
|
|
|
|
+ FileIO.WriteString(FileIO.StdOut, "Graph list ");
|
|
|
|
|
+ FileIO.WriteCard(FileIO.StdOut, SIZE(GraphList), 1);
|
|
|
|
|
+ FileIO.WriteLn(FileIO.StdOut);
|
|
|
|
|
+*)
|
|
|
|
|
+END CRT.
|