| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435 |
- 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.
|