CRT.mod 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435
  1. IMPLEMENTATION MODULE CRT;
  2. (* CRT Table Handler
  3. === =============
  4. (1) handles a symbol table for terminals, pragmas and nonterminals
  5. (2) handles a table for character classes (for scanner generation)
  6. (3) handles a top-down graph for productions
  7. (4) computes various sets (start symbols, followers, any sets)
  8. (5) contains procedures for grammar tests
  9. --------------------------------------------------------------------*)
  10. IMPORT CRS, FileIO, Sets, Storage;
  11. IMPORT SYSTEM (* for TSIZE only *);
  12. CONST
  13. maxSetNr = 256; (* max. number of symbol sets *)
  14. (* moved next declaration to def module Fri 08-20-1993, and was 150
  15. maxClasses = 250; (* max. number of character classes *) *)
  16. maxNames = 100; (* max. number of declared token names *)
  17. TYPE
  18. FirstSets = ARRAY [0 .. maxNt] OF RECORD
  19. ts: Set; (* terminal symbols *)
  20. ready: BOOLEAN; (* TRUE = ts is complete *)
  21. END;
  22. FollowSets = ARRAY [0 .. maxNt] OF RECORD
  23. ts: Set; (* terminal symbols *)
  24. nts: Set; (* nts whose start set is to be included in ts *)
  25. END;
  26. CharClass = RECORD
  27. name: Name; (* class name *)
  28. set: INTEGER (* ptr to set representing the class *)
  29. END;
  30. SymbolTable = ARRAY [0 .. maxSymbols] OF SymbolNode;
  31. ClassTable = ARRAY [0 .. maxClasses] OF CharClass;
  32. GraphList = ARRAY [0 .. maxNodes] OF GraphNode;
  33. SymbolSet = ARRAY [0 .. maxSetNr] OF Set;
  34. NameTable = ARRAY [1 .. maxNames] OF RECORD name, definition: Name END;
  35. VAR
  36. (* moved symbol table to the heap Fri 08-20-1993 to allow larger one *)
  37. st: POINTER TO SymbolTable; (* symbol table for terminals,
  38. pragmas, and nonterminals *)
  39. gn: POINTER TO GraphList; (* top-down graph *)
  40. tt: NameTable; (* table of token name declarations *)
  41. first: FirstSets; (* first[i] = first symbols of st[i+firstNt] *)
  42. follow: FollowSets; (* follow[i] = followers of st[i+firstNt] *)
  43. chClass: ClassTable; (* character classes *)
  44. set: SymbolSet; (* set[0] = all SYNC symbols *)
  45. maxSet: INTEGER; (* index of last symbol set *)
  46. lastName,
  47. dummyName: CARDINAL; (* for unnamed character classes *)
  48. ch: CHAR;
  49. (* Restriction Implementation restriction
  50. ----------------------------------------------------------------------*)
  51. PROCEDURE Restriction (n, limit: INTEGER);
  52. (* Fri 08-20-1993 extended *)
  53. BEGIN
  54. FileIO.WriteLn(FileIO.StdOut);
  55. FileIO.WriteString(FileIO.StdOut, "Restriction ");
  56. FileIO.WriteInt(FileIO.StdOut, n, 1); FileIO.WriteLn(FileIO.StdOut);
  57. CASE n OF
  58. 1 : FileIO.WriteString(FileIO.StdOut, "Too many graph nodes")
  59. | 2 : FileIO.WriteString(FileIO.StdOut, "Too many symbols")
  60. | 3 : FileIO.WriteString(FileIO.StdOut, "Too many sets")
  61. | 4 : FileIO.WriteString(FileIO.StdOut, "Too many character classes")
  62. | 5 : FileIO.WriteString(FileIO.StdOut, "Too many symbol sets")
  63. | 6 : FileIO.WriteString(FileIO.StdOut, "Too many token names")
  64. | 7 : FileIO.WriteString(FileIO.StdOut, "Too many states")
  65. | 8 : FileIO.WriteString(FileIO.StdOut, "Semantic text buffer overflow")
  66. | 9 : FileIO.WriteString(FileIO.StdOut, "Circular check buffer overflow")
  67. | 10 : FileIO.WriteString(FileIO.StdOut, "Too many literal terminals")
  68. | 11 : FileIO.WriteString(FileIO.StdOut, "Too many non-terminals")
  69. | -1 : FileIO.WriteString(FileIO.StdOut, "Compiler error")
  70. END;
  71. IF n > 0 THEN
  72. FileIO.WriteString(FileIO.StdOut, " (limited to ");
  73. FileIO.WriteInt(FileIO.StdOut, limit, 1);
  74. FileIO.Write(FileIO.StdOut, ")");
  75. END;
  76. (* maybe we want CRX.WriteStatistics; *)
  77. FileIO.QuitExecution
  78. END Restriction;
  79. (* MovePragmas Move pragmas after terminals
  80. ----------------------------------------------------------------------*)
  81. PROCEDURE MovePragmas;
  82. VAR
  83. i: INTEGER;
  84. BEGIN
  85. IF maxP > firstNt THEN
  86. i := maxSymbols - 1; maxP := maxT;
  87. WHILE i > lastNt DO
  88. INC(maxP); IF maxP >= firstNt THEN Restriction(2, maxSymbols) END;
  89. st^[maxP] := st^[i]; DEC(i)
  90. END;
  91. END
  92. END MovePragmas;
  93. (* ClearMarkList Clear mark list m
  94. ----------------------------------------------------------------------*)
  95. PROCEDURE ClearMarkList (VAR m: MarkList);
  96. VAR
  97. i: INTEGER;
  98. BEGIN
  99. i := 0;
  100. WHILE i < maxNodes DIV Sets.size DO m[i] := BITSET{}; INC(i) END;
  101. END ClearMarkList;
  102. (* GetNode Get node with index gp in n
  103. ----------------------------------------------------------------------*)
  104. PROCEDURE GetNode (gp: INTEGER; VAR n: GraphNode);
  105. BEGIN
  106. n := gn^[gp]
  107. END GetNode;
  108. (* PutNode Replace node with index gp by n
  109. ----------------------------------------------------------------------*)
  110. PROCEDURE PutNode (gp: INTEGER; n: GraphNode);
  111. BEGIN
  112. gn^[gp] := n
  113. END PutNode;
  114. (* NewName Collects a user defined token name
  115. ----------------------------------------------------------------------*)
  116. PROCEDURE NewName (n: Name; s: ARRAY OF CHAR);
  117. BEGIN
  118. IF lastName = maxNames THEN Restriction(6, maxNames)
  119. ELSE
  120. INC(lastName); symNames := TRUE;
  121. tt[lastName].name := n; FileIO.Assign(s, tt[lastName].definition);
  122. END;
  123. END NewName;
  124. (* NewSym Generate a new symbol and return its index
  125. ----------------------------------------------------------------------*)
  126. PROCEDURE NewSym (typ: INTEGER; name: Name; line: INTEGER): INTEGER;
  127. VAR
  128. i: INTEGER;
  129. BEGIN
  130. IF maxT + 1 = firstNt THEN Restriction(2, maxSymbols)
  131. ELSE
  132. CASE typ OF
  133. t: INC(maxT); i := maxT;
  134. | pr: DEC(maxP); DEC(firstNt); DEC(lastNt); i := maxP;
  135. | nt, unknown: DEC(firstNt); i := firstNt;
  136. END;
  137. IF maxT + 1 >= firstNt THEN Restriction(2, maxSymbols) END;
  138. st^[i].typ := typ; st^[i].name := name;
  139. st^[i].constant := ""; (* Bug fix - PDT *)
  140. st^[i].struct := 0; st^[i].deletable := FALSE;
  141. st^[i].attrPos.beg := - FileIO.Long1;
  142. st^[i].semPos.beg := - FileIO.Long1;
  143. st^[i].line := line;
  144. END;
  145. RETURN i;
  146. END NewSym;
  147. (* GetSym Get symbol sp in sn
  148. ----------------------------------------------------------------------*)
  149. PROCEDURE GetSym (sp: INTEGER; VAR sn: SymbolNode);
  150. BEGIN
  151. sn := st^[sp]
  152. END GetSym;
  153. (* PutSym Replace symbol with index snix by sn
  154. ----------------------------------------------------------------------*)
  155. PROCEDURE PutSym (sp: INTEGER; sn: SymbolNode);
  156. BEGIN
  157. st^[sp] := sn
  158. END PutSym;
  159. (* FindSym Find index of symbol with name n
  160. ----------------------------------------------------------------------*)
  161. PROCEDURE FindSym (n: Name): INTEGER;
  162. VAR
  163. i: INTEGER;
  164. BEGIN
  165. i := 0; (*search in terminal list*)
  166. WHILE (i <= maxT) & (FileIO.Compare(st^[i].name, n) # 0) DO
  167. INC(i)
  168. END;
  169. IF i <= maxT THEN RETURN i END;
  170. i := firstNt; (*search in nonterminal/pragma list*)
  171. WHILE (i < maxSymbols) & (FileIO.Compare(st^[i].name, n) # 0) DO
  172. INC(i)
  173. END;
  174. IF i < maxSymbols THEN RETURN i ELSE RETURN noSym END
  175. END FindSym;
  176. (* PrintSet Print set s
  177. ----------------------------------------------------------------------*)
  178. PROCEDURE PrintSet (f: FileIO.File; s: ARRAY OF BITSET; indent: INTEGER);
  179. CONST
  180. maxLineLen = 80;
  181. VAR
  182. col, i, len: INTEGER;
  183. empty: BOOLEAN;
  184. sn: SymbolNode;
  185. BEGIN
  186. i := 0; col := indent; empty := TRUE;
  187. WHILE i <= maxT DO
  188. IF Sets.In(s, i) THEN
  189. empty := FALSE; GetSym(i, sn); len := FileIO.SLENGTH(sn.name);
  190. IF col + len + 2 > maxLineLen THEN
  191. FileIO.WriteLn(f); col := 1;
  192. WHILE col < indent DO FileIO.Write(f, " "); INC(col) END
  193. END;
  194. FileIO.WriteString(f, sn.name);
  195. FileIO.WriteString(f, " ");
  196. INC(col, len + 2)
  197. END;
  198. INC(i)
  199. END;
  200. IF empty THEN FileIO.WriteString(f, "-- empty set --") END;
  201. FileIO.WriteLn(f)
  202. END PrintSet;
  203. (* NewSet Stores s as a new set and return its index
  204. ----------------------------------------------------------------------*)
  205. PROCEDURE NewSet (s: Set): INTEGER;
  206. (*any-set computation requires not to search if s is already in set*)
  207. BEGIN
  208. INC(maxSet); IF maxSet > maxSetNr THEN Restriction(3, maxSetNr) END;
  209. set[maxSet] := s; RETURN maxSet
  210. END NewSet;
  211. (* CompFirstSet Compute first symbols of (sub) graph at gp
  212. ----------------------------------------------------------------------*)
  213. PROCEDURE CompFirstSet (gp: INTEGER; VAR fs: Set);
  214. VAR
  215. visited: MarkList;
  216. PROCEDURE CompFirst (gp: INTEGER; VAR fs: Set);
  217. VAR
  218. s: Set;
  219. gn: GraphNode;
  220. sn: SymbolNode;
  221. BEGIN
  222. Sets.Clear(fs);
  223. WHILE (gp # 0) & ~ Sets.In(visited, gp) DO
  224. GetNode(gp, gn); Sets.Incl(visited, gp);
  225. CASE gn.typ OF
  226. nt:
  227. IF first[gn.p1 - firstNt].ready THEN
  228. Sets.Unite(fs, first[gn.p1 - firstNt].ts);
  229. ELSE
  230. GetSym(gn.p1, sn);
  231. CompFirst(sn.struct, s); Sets.Unite(fs, s);
  232. END;
  233. | t, wt:
  234. Sets.Incl(fs, gn.p1);
  235. | any:
  236. Sets.Unite(fs, set[gn.p1])
  237. | alt, iter, opt:
  238. CompFirst(gn.p1, s); Sets.Unite(fs, s);
  239. IF gn.typ = alt THEN CompFirst(gn.p2, s); Sets.Unite(fs, s) END
  240. ELSE (* eps, sem, sync, ind: nothing *)
  241. END;
  242. IF ~ DelNode(gn) THEN RETURN END;
  243. gp := ABS(gn.next)
  244. END
  245. END CompFirst;
  246. BEGIN (* ComputeFirstSet *)
  247. ClearMarkList(visited);
  248. CompFirst(gp, fs);
  249. IF ddt["I"] THEN
  250. FileIO.WriteLn(FileIO.StdOut);
  251. FileIO.WriteString(FileIO.StdOut, "ComputeFirstSet: gp = ");
  252. FileIO.WriteInt(FileIO.StdOut, gp, 1);
  253. FileIO.WriteLn(FileIO.StdOut);
  254. PrintSet(FileIO.StdOut, fs, 0);
  255. END;
  256. END CompFirstSet;
  257. (* CompFirstSets Compute first symbols of nonterminals
  258. ----------------------------------------------------------------------*)
  259. PROCEDURE CompFirstSets;
  260. VAR
  261. i: INTEGER;
  262. sn: SymbolNode;
  263. BEGIN
  264. i := firstNt;
  265. IF lastNt-firstNt > maxNt THEN Restriction(11, maxNt) END;;
  266. WHILE i <= lastNt DO first[i - firstNt].ready := FALSE; INC(i) END;
  267. i := firstNt;
  268. WHILE i <= lastNt DO (* for all nonterminals *)
  269. GetSym(i, sn); CompFirstSet(sn.struct, first[i - firstNt].ts);
  270. first[i - firstNt].ready := TRUE;
  271. INC(i)
  272. END;
  273. END CompFirstSets;
  274. (* CompExpected Compute symbols expected at location gp in Symbol sp
  275. ----------------------------------------------------------------------*)
  276. PROCEDURE CompExpected (gp, sp: INTEGER; VAR exp: Set);
  277. BEGIN
  278. CompFirstSet(gp, exp);
  279. IF DelGraph(gp) THEN Sets.Unite(exp, follow[sp - firstNt].ts) END
  280. END CompExpected;
  281. (* CompFollowSets Get follow symbols of nonterminals
  282. ----------------------------------------------------------------------*)
  283. PROCEDURE CompFollowSets;
  284. VAR
  285. sn: SymbolNode;
  286. curSy, i, size: INTEGER;
  287. visited: MarkList;
  288. PROCEDURE CompFol (gp: INTEGER);
  289. VAR
  290. s: Set;
  291. gn: GraphNode;
  292. BEGIN
  293. WHILE (gp > 0) & ~ Sets.In(visited, gp) DO
  294. GetNode(gp, gn); Sets.Incl(visited, gp);
  295. IF gn.typ = nt THEN
  296. CompFirstSet(ABS(gn.next), s);
  297. Sets.Unite(follow[gn.p1 - firstNt].ts, s);
  298. IF DelGraph(ABS(gn.next)) THEN
  299. Sets.Incl(follow[gn.p1 - firstNt].nts, curSy - firstNt)
  300. END
  301. ELSIF (gn.typ=opt) OR (gn.typ=iter) THEN CompFol(gn.p1)
  302. ELSIF gn.typ = alt THEN CompFol(gn.p1); CompFol(gn.p2)
  303. END;
  304. gp := gn.next
  305. END
  306. END CompFol;
  307. PROCEDURE Complete (i: INTEGER);
  308. VAR
  309. j: INTEGER;
  310. BEGIN
  311. IF Sets.In(visited, i) THEN RETURN END;
  312. Sets.Incl(visited, i);
  313. j := 0;
  314. WHILE j <= lastNt - firstNt DO (* for all nonterminals *)
  315. IF Sets.In(follow[i].nts, j) THEN
  316. Complete(j); Sets.Unite(follow[i].ts, follow[j].ts);
  317. (* fix 1.42 *) IF i = curSy THEN Sets.Excl(follow[i].nts, j) END
  318. END;
  319. INC(j)
  320. END;
  321. END Complete;
  322. BEGIN (* GetFollowSets *)
  323. size := (lastNt - firstNt + 2) DIV Sets.size;
  324. curSy := firstNt;
  325. WHILE curSy <= lastNt DO
  326. Sets.Clear(follow[curSy - firstNt].ts);
  327. i := 0;
  328. WHILE i <= size DO
  329. follow[curSy - firstNt].nts[i] := BITSET{}; INC(i)
  330. END;
  331. INC(curSy)
  332. END;
  333. ClearMarkList(visited);
  334. curSy := firstNt; (*get direct successors of nonterminals*)
  335. WHILE curSy <= lastNt DO
  336. GetSym(curSy, sn); CompFol(sn.struct);
  337. INC(curSy)
  338. END;
  339. curSy := 0; (*add indirect successors to follow.ts*)
  340. WHILE curSy <= lastNt - firstNt DO
  341. ClearMarkList(visited); Complete(curSy);
  342. INC(curSy);
  343. END;
  344. END CompFollowSets;
  345. (* CompAnySets Compute all any-sets
  346. ----------------------------------------------------------------------*)
  347. PROCEDURE CompAnySets;
  348. VAR
  349. curSy: INTEGER;
  350. sn: SymbolNode;
  351. PROCEDURE LeadingAny (gp: INTEGER; VAR a: GraphNode): BOOLEAN;
  352. VAR
  353. gn: GraphNode;
  354. BEGIN
  355. IF gp <= 0 THEN RETURN FALSE END;
  356. GetNode(gp, gn);
  357. IF (gn.typ = any) THEN a := gn; RETURN TRUE
  358. ELSE
  359. RETURN (gn.typ = alt) & (LeadingAny(gn.p1, a)
  360. OR LeadingAny(gn.p2, a))
  361. OR ((gn.typ=opt) OR (gn.typ=iter)) & LeadingAny(gn.p1, a)
  362. OR DelNode(gn) & LeadingAny(gn.next, a)
  363. END
  364. END LeadingAny;
  365. PROCEDURE FindAS (gp: INTEGER);
  366. VAR
  367. gn, gn2, a: GraphNode;
  368. s1, s2: Set;
  369. p: INTEGER;
  370. BEGIN
  371. WHILE gp > 0 DO
  372. GetNode(gp, gn);
  373. IF (gn.typ=opt) OR (gn.typ=iter) THEN
  374. FindAS(gn.p1);
  375. IF LeadingAny(gn.p1, a) THEN
  376. CompExpected(ABS(gn.next), curSy, s1);
  377. Sets.Differ(set[a.p1], s1)
  378. END
  379. ELSIF gn.typ = alt THEN
  380. p := gp; Sets.Clear(s1);
  381. WHILE p # 0 DO
  382. GetNode(p, gn2); FindAS(gn2.p1);
  383. IF LeadingAny(gn2.p1, a) THEN
  384. CompExpected(gn2.p2, curSy, s2); Sets.Unite(s2, s1);
  385. Sets.Differ(set[a.p1], s2)
  386. ELSE
  387. CompFirstSet(gn2.p1, s2); Sets.Unite(s1, s2)
  388. END;
  389. p := gn2.p2
  390. END
  391. END;
  392. gp := gn.next
  393. END
  394. END FindAS;
  395. BEGIN
  396. curSy := firstNt;
  397. WHILE curSy <= lastNt DO (* for all nonterminals *)
  398. GetSym(curSy, sn); FindAS(sn.struct);
  399. INC(curSy)
  400. END
  401. END CompAnySets;
  402. (* CompSyncSets Compute follow symbols of sync-nodes
  403. ----------------------------------------------------------------------*)
  404. PROCEDURE CompSyncSets;
  405. VAR
  406. curSy: INTEGER;
  407. sn: SymbolNode;
  408. visited: MarkList;
  409. PROCEDURE CompSync (gp: INTEGER);
  410. VAR
  411. s: Set;
  412. gn: GraphNode;
  413. BEGIN
  414. WHILE (gp > 0) & ~ Sets.In(visited, gp) DO
  415. GetNode(gp, gn); Sets.Incl(visited, gp);
  416. IF gn.typ = sync THEN
  417. CompExpected(ABS(gn.next), curSy, s);
  418. Sets.Incl(s, eofSy); Sets.Unite(set[0], s);
  419. gn.p1 := NewSet(s); PutNode(gp, gn)
  420. ELSIF gn.typ = alt THEN CompSync(gn.p1); CompSync(gn.p2)
  421. ELSIF (gn.typ=opt) OR (gn.typ=iter) THEN CompSync(gn.p1)
  422. END;
  423. gp := gn.next
  424. END
  425. END CompSync;
  426. BEGIN
  427. curSy := firstNt; ClearMarkList(visited);
  428. WHILE curSy <= lastNt DO
  429. GetSym(curSy, sn); CompSync(sn.struct);
  430. INC(curSy);
  431. END
  432. END CompSyncSets;
  433. (* CompDeletableSymbols Compute all deletable symbols and print them
  434. ----------------------------------------------------------------------*)
  435. PROCEDURE CompDeletableSymbols;
  436. VAR
  437. changed, none: BOOLEAN;
  438. i: INTEGER;
  439. sn: SymbolNode;
  440. BEGIN
  441. REPEAT
  442. changed := FALSE;
  443. i := firstNt;
  444. WHILE i <= lastNt DO (*for all nonterminals*)
  445. GetSym(i, sn);
  446. IF ~ sn.deletable & (sn.struct # 0) & DelGraph(sn.struct) THEN
  447. sn.deletable := TRUE; PutSym(i, sn); changed := TRUE
  448. END;
  449. INC(i)
  450. END;
  451. UNTIL ~ changed;
  452. FileIO.WriteString(CRS.lst, "Deletable symbols:");
  453. i := firstNt; none := TRUE;
  454. WHILE i <= lastNt DO
  455. GetSym(i, sn);
  456. IF sn.deletable THEN
  457. none := FALSE;
  458. FileIO.WriteLn(CRS.lst); FileIO.WriteString(CRS.lst, " ");
  459. FileIO.WriteString(CRS.lst, sn.name)
  460. END;
  461. INC(i);
  462. END;
  463. IF none THEN FileIO.WriteString(CRS.lst, " -- none --") END;
  464. FileIO.WriteLn(CRS.lst);
  465. END CompDeletableSymbols;
  466. (* CompSymbolSets Get first-sets, follow-sets, and sync-set
  467. ----------------------------------------------------------------------*)
  468. PROCEDURE CompSymbolSets;
  469. VAR
  470. i: INTEGER;
  471. sn: SymbolNode;
  472. BEGIN
  473. MovePragmas;
  474. CompDeletableSymbols;
  475. CompFirstSets;
  476. CompFollowSets;
  477. CompAnySets;
  478. CompSyncSets;
  479. IF ddt["F"] THEN
  480. i := firstNt;
  481. FileIO.WriteString(CRS.lst, "List of first & follow symbols:");
  482. FileIO.WriteLn(CRS.lst); FileIO.WriteLn(CRS.lst);
  483. WHILE i <= lastNt DO (* for all nonterminals *)
  484. GetSym(i, sn);
  485. FileIO.WriteString(CRS.lst, sn.name); FileIO.WriteLn(CRS.lst);
  486. FileIO.WriteString(CRS.lst, "first: ");
  487. PrintSet(CRS.lst, first[i - firstNt].ts, 10);
  488. FileIO.WriteString(CRS.lst, "follow: ");
  489. PrintSet(CRS.lst, follow[i - firstNt].ts, 10);
  490. FileIO.WriteLn(CRS.lst);
  491. INC(i);
  492. END;
  493. i := 0;
  494. FileIO.WriteLn(CRS.lst); FileIO.WriteLn(CRS.lst);
  495. FileIO.WriteString(CRS.lst, "List of sets (ANY, SYNC): ");
  496. IF maxSet < 0 THEN FileIO.WriteString(CRS.lst, " -- none --");
  497. ELSE FileIO.WriteLn(CRS.lst);
  498. END;
  499. WHILE i <= maxSet DO
  500. FileIO.WriteString(CRS.lst, " set[");
  501. FileIO.WriteInt(CRS.lst, i, 2);
  502. FileIO.WriteString(CRS.lst, "] = ");
  503. PrintSet(CRS.lst, set[i], 16);
  504. INC(i)
  505. END;
  506. FileIO.WriteLn(CRS.lst);
  507. END;
  508. END CompSymbolSets;
  509. (* GetFirstSet Get precomputed first-set for nonterminal sp
  510. ----------------------------------------------------------------------*)
  511. PROCEDURE GetFirstSet (sp: INTEGER; VAR s: Set);
  512. BEGIN
  513. s := first[sp - firstNt].ts
  514. END GetFirstSet;
  515. (* GetFollowSet Get precomputed follow-set for nonterminal snix
  516. ----------------------------------------------------------------------*)
  517. PROCEDURE GetFollowSet (sp: INTEGER; VAR s: Set);
  518. BEGIN
  519. s := follow[sp - firstNt].ts
  520. END GetFollowSet;
  521. (* GetSet Get set with index nr
  522. ----------------------------------------------------------------------*)
  523. PROCEDURE GetSet (nr: INTEGER; VAR s: Set);
  524. BEGIN
  525. s := set[nr]
  526. END GetSet;
  527. (* PrintSymbolTable Print symbol table
  528. ----------------------------------------------------------------------*)
  529. PROCEDURE PrintSymbolTable;
  530. VAR
  531. i: INTEGER;
  532. PROCEDURE WriteBool (b: BOOLEAN);
  533. BEGIN
  534. IF b THEN FileIO.WriteString(CRS.lst, " TRUE ");
  535. ELSE FileIO.WriteString(CRS.lst, " FALSE");
  536. END;
  537. END WriteBool;
  538. PROCEDURE WriteTyp1 (typ: INTEGER);
  539. BEGIN
  540. CASE typ OF
  541. unknown: FileIO.WriteString(CRS.lst, " unknown");
  542. | t : FileIO.WriteString(CRS.lst, " t ");
  543. | pr : FileIO.WriteString(CRS.lst, " pr ");
  544. | nt : FileIO.WriteString(CRS.lst, " nt ");
  545. END;
  546. END WriteTyp1;
  547. BEGIN (* PrintSymbolTable *)
  548. FileIO.WriteString(CRS.lst, "SymbolTable:");
  549. FileIO.WriteLn(CRS.lst); FileIO.WriteLn(CRS.lst);
  550. FileIO.WriteString(CRS.lst, "nr definition ");
  551. IF (*CRT.*) ddt["N"] OR (*CRT.*) symNames THEN
  552. FileIO.WriteString(CRS.lst, "constant ")
  553. END;
  554. FileIO.WriteString(CRS.lst, "typ hasAttrs struct del line");
  555. FileIO.WriteLn(CRS.lst); FileIO.WriteLn(CRS.lst);
  556. i := 0;
  557. WHILE i < maxSymbols DO
  558. FileIO.WriteInt(CRS.lst, i, 3); FileIO.WriteText(CRS.lst, "", 3);
  559. FileIO.WriteText(CRS.lst, st^[i].name, 26);
  560. IF (*CRT.*) ddt["N"] OR (*CRT.*) symNames THEN
  561. IF i <= maxT THEN
  562. FileIO.WriteText(CRS.lst, st^[i].constant, 16);
  563. ELSE
  564. FileIO.WriteText(CRS.lst, "", 16);
  565. END;
  566. END;
  567. WriteTyp1(st^[i].typ);
  568. WriteBool(st^[i].attrPos.beg >= FileIO.Long0);
  569. FileIO.WriteInt(CRS.lst, st^[i].struct, 5);
  570. WriteBool(st^[i].deletable);
  571. FileIO.WriteInt(CRS.lst, st^[i].line, 5);
  572. FileIO.WriteLn(CRS.lst);
  573. IF i = maxT THEN i := firstNt ELSE INC(i) END
  574. END;
  575. FileIO.WriteLn(CRS.lst); FileIO.WriteLn(CRS.lst);
  576. END PrintSymbolTable;
  577. (* NewClass Define a new character class
  578. ----------------------------------------------------------------------*)
  579. PROCEDURE NewClass (name: Name; set: Set): INTEGER;
  580. BEGIN
  581. INC(maxC); IF maxC > maxClasses THEN Restriction(4, maxClasses) END;
  582. IF name[0] = "#" THEN
  583. name[1] := CHR(ORD("A") + dummyName); INC(dummyName)
  584. END;
  585. chClass[maxC].name := name; chClass[maxC].set := NewSet(set);
  586. RETURN maxC
  587. END NewClass;
  588. (* ClassWithName Return index of class with name n
  589. ----------------------------------------------------------------------*)
  590. PROCEDURE ClassWithName (n: Name): INTEGER;
  591. VAR
  592. i: INTEGER;
  593. BEGIN
  594. i := maxC;
  595. WHILE (i >= 0) & (FileIO.Compare(chClass[i].name, n) # 0) DO
  596. DEC(i)
  597. END;
  598. RETURN i
  599. END ClassWithName;
  600. (* ClassWithSet Return index of class with the specified set
  601. ----------------------------------------------------------------------*)
  602. PROCEDURE ClassWithSet (s: Set): INTEGER;
  603. VAR
  604. i: INTEGER;
  605. BEGIN
  606. i := maxC;
  607. WHILE (i >= 0) & ~ Sets.Equal(set[chClass[i].set], s) DO DEC(i) END;
  608. RETURN i
  609. END ClassWithSet;
  610. (* GetClass Return character class n
  611. ----------------------------------------------------------------------*)
  612. PROCEDURE GetClass (n: INTEGER; VAR s: Set);
  613. BEGIN
  614. GetSet(chClass[n].set, s);
  615. END GetClass;
  616. (* GetClassName Get the name of class n
  617. ----------------------------------------------------------------------*)
  618. PROCEDURE GetClassName (n: INTEGER; VAR name: Name);
  619. BEGIN
  620. name := chClass[n].name
  621. END GetClassName;
  622. (* XRef Produce a cross reference listing of all symbols
  623. ----------------------------------------------------------------------*)
  624. PROCEDURE XRef;
  625. CONST
  626. maxLineLen = 80;
  627. TYPE
  628. ListPtr = POINTER TO ListNode;
  629. ListNode = RECORD
  630. next: ListPtr;
  631. line: INTEGER;
  632. END;
  633. ListHdr = RECORD
  634. name: Name;
  635. lptr: ListPtr;
  636. END;
  637. VAR
  638. gn: GraphNode;
  639. col, i: INTEGER;
  640. l, p, q: ListPtr;
  641. sn: SymbolNode;
  642. xList: ARRAY [0 .. maxSymbols] OF ListHdr;
  643. BEGIN (* XRef *)
  644. IF maxT <= 0 THEN RETURN END;
  645. MovePragmas;
  646. (* initialize cross reference list *)
  647. i := 0;
  648. WHILE i <= lastNt DO (* for all symbols *)
  649. GetSym(i, sn); xList[i].name := sn.name; xList[i].lptr := NIL;
  650. IF i = maxP THEN i := firstNt ELSE INC(i) END
  651. END;
  652. (* search lines where symbol has been referenced *)
  653. i := 1;
  654. WHILE i <= nNodes DO (* for all graph nodes *)
  655. GetNode(i, gn);
  656. IF (gn.typ = t) OR (gn.typ = wt) OR (gn.typ = nt) THEN
  657. Storage.ALLOCATE(l, SYSTEM.TSIZE(ListNode));
  658. l^.next := xList[gn.p1].lptr; l^.line := gn.line;
  659. xList[gn.p1].lptr := l
  660. END;
  661. INC(i);
  662. END;
  663. (* search lines where symbol has been defined and insert in order *)
  664. i := 1;
  665. WHILE i <= lastNt DO (*for all symbols*)
  666. GetSym(i, sn); p := xList[i].lptr; q := NIL;
  667. WHILE (p # NIL) & (p^.line > sn.line) DO q := p; p := p^.next END;
  668. Storage.ALLOCATE(l, SYSTEM.TSIZE(ListNode)); l^.next := p;
  669. l^.line := -sn.line;
  670. IF q # NIL THEN q^.next := l ELSE xList[i].lptr := l END;
  671. IF i = maxP THEN i := firstNt ELSE INC(i) END
  672. END;
  673. (* print cross reference listing *)
  674. FileIO.WriteString(CRS.lst, "Cross reference list:");
  675. FileIO.WriteLn(CRS.lst); FileIO.WriteLn(CRS.lst);
  676. FileIO.WriteString(CRS.lst, "Terminals:"); FileIO.WriteLn(CRS.lst);
  677. FileIO.WriteString(CRS.lst, " 0 EOF"); FileIO.WriteLn(CRS.lst);
  678. i := 1;
  679. WHILE i <= lastNt DO (* for all symbols *)
  680. IF i = maxT THEN
  681. FileIO.WriteLn(CRS.lst);
  682. FileIO.WriteString(CRS.lst, "Pragmas:"); FileIO.WriteLn(CRS.lst);
  683. ELSE
  684. FileIO.WriteInt(CRS.lst, i, 3); FileIO.WriteString(CRS.lst, " ");
  685. FileIO.WriteText(CRS.lst, xList[i].name, 25);
  686. l := xList[i].lptr; col := 35;
  687. WHILE l # NIL DO
  688. IF col + 5 > maxLineLen THEN
  689. FileIO.WriteLn(CRS.lst); FileIO.WriteText(CRS.lst, "", 30);
  690. col := 35
  691. END;
  692. IF l^.line = 0 THEN FileIO.WriteString(CRS.lst, "undef")
  693. ELSE FileIO.WriteInt(CRS.lst, l^.line, 5)
  694. END;
  695. INC(col, 5);
  696. l := l^.next
  697. END;
  698. FileIO.WriteLn(CRS.lst);
  699. END;
  700. IF i = maxP THEN
  701. FileIO.WriteLn(CRS.lst);
  702. FileIO.WriteString(CRS.lst, "Nonterminals:");
  703. FileIO.WriteLn(CRS.lst);
  704. i := firstNt
  705. ELSE INC(i)
  706. END
  707. END;
  708. FileIO.WriteLn(CRS.lst); FileIO.WriteLn(CRS.lst);
  709. END XRef;
  710. (* NewNode Generate a new graph node and return its index gp
  711. ----------------------------------------------------------------------*)
  712. PROCEDURE NewNode (typ, p1, line: INTEGER): INTEGER;
  713. BEGIN
  714. INC(nNodes); IF nNodes > maxNodes THEN Restriction(1, maxNodes) END;
  715. gn^[nNodes].typ := typ; gn^[nNodes].next := 0;
  716. gn^[nNodes].p1 := p1; gn^[nNodes].p2 := 0;
  717. gn^[nNodes].pos.beg := - FileIO.Long1; (* Bugfix - PDT *)
  718. gn^[nNodes].pos.len := 0; gn^[nNodes].pos.col := 0;
  719. gn^[nNodes].line := line;
  720. RETURN nNodes;
  721. END NewNode;
  722. (* CompleteGraph Set right ends of graph gp to 0
  723. ----------------------------------------------------------------------*)
  724. PROCEDURE CompleteGraph (gp: INTEGER);
  725. VAR
  726. p: INTEGER;
  727. BEGIN
  728. WHILE gp # 0 DO
  729. p := gn^[gp].next; gn^[gp].next := 0; gp := p
  730. END
  731. END CompleteGraph;
  732. (* ConcatAlt Make (gL2, gR2) an alternative of (gL1, gR1)
  733. ----------------------------------------------------------------------*)
  734. PROCEDURE ConcatAlt (VAR gL1, gR1: INTEGER; gL2, gR2: INTEGER);
  735. VAR
  736. p: INTEGER;
  737. BEGIN
  738. gL2 := NewNode(alt, gL2, 0); p := gL1;
  739. WHILE gn^[p].p2 # 0 DO p := gn^[p].p2 END;
  740. gn^[p].p2 := gL2; p := gR1;
  741. WHILE gn^[p].next # 0 DO p := gn^[p].next END;
  742. gn^[p].next := gR2
  743. END ConcatAlt;
  744. (* ConcatSeq Make (gL2, gR2) a successor of (gL1, gR1)
  745. ----------------------------------------------------------------------*)
  746. PROCEDURE ConcatSeq (VAR gL1, gR1: INTEGER; gL2, gR2: INTEGER);
  747. VAR
  748. p, q: INTEGER;
  749. BEGIN
  750. p := gn^[gR1].next; gn^[gR1].next := gL2; (*head node*)
  751. WHILE p # 0 DO (*substructure*)
  752. q := gn^[p].next; gn^[p].next := -gL2; p := q
  753. END;
  754. gR1 := gR2
  755. END ConcatSeq;
  756. (* MakeFirstAlt Generate alt-node with (gL,gR) as only alternative
  757. ----------------------------------------------------------------------*)
  758. PROCEDURE MakeFirstAlt (VAR gL, gR: INTEGER);
  759. BEGIN
  760. gL := NewNode(alt, gL, 0); gn^[gL].next := gR; gR := gL
  761. END MakeFirstAlt;
  762. (* MakeIteration Enclose (gL, gR) into iteration node
  763. ----------------------------------------------------------------------*)
  764. PROCEDURE MakeIteration (VAR gL, gR: INTEGER);
  765. VAR
  766. p, q: INTEGER;
  767. BEGIN
  768. gL := NewNode(iter, gL, 0); p := gR; gR := gL;
  769. WHILE p # 0 DO
  770. q := gn^[p].next; gn^[p].next := - gL; p := q
  771. END
  772. END MakeIteration;
  773. (* MakeOption Enclose (gL, gR) into option node
  774. ----------------------------------------------------------------------*)
  775. PROCEDURE MakeOption (VAR gL, gR: INTEGER);
  776. BEGIN
  777. gL := NewNode(opt, gL, 0); gn^[gL].next := gR; gR := gL
  778. END MakeOption;
  779. (* StrToGraph Generate node chain from characters in s
  780. ----------------------------------------------------------------------*)
  781. PROCEDURE StrToGraph (s: ARRAY OF CHAR; VAR gL, gR: INTEGER);
  782. VAR
  783. i, len: CARDINAL;
  784. BEGIN
  785. gR := 0; i := 1; len := FileIO.SLENGTH(s) - 1; (*strip quotes*)
  786. WHILE i < len DO
  787. gn^[gR].next := NewNode(char, ORD(s[i]), 0); gR := gn^[gR].next;
  788. INC(i)
  789. END;
  790. gL := gn^[0].next; gn^[0].next := 0
  791. END StrToGraph;
  792. (* DelGraph Check if graph starting with index gp is deletable
  793. ----------------------------------------------------------------------*)
  794. PROCEDURE DelGraph (gp: INTEGER): BOOLEAN;
  795. VAR
  796. gn: GraphNode;
  797. BEGIN
  798. IF gp = 0 THEN RETURN TRUE END; (*end of graph found*)
  799. GetNode(gp, gn);
  800. RETURN DelNode(gn) & DelGraph(ABS(gn.next));
  801. END DelGraph;
  802. (* DelNode Check if graph node gn is deletable
  803. ----------------------------------------------------------------------*)
  804. PROCEDURE DelNode (gn: GraphNode): BOOLEAN;
  805. VAR
  806. sn: SymbolNode;
  807. PROCEDURE DelAlt (gp: INTEGER): BOOLEAN;
  808. VAR
  809. gn: GraphNode;
  810. BEGIN
  811. IF gp <= 0 THEN RETURN TRUE END; (*end of graph found*)
  812. GetNode(gp, gn);
  813. RETURN DelNode(gn) & DelAlt(gn.next);
  814. END DelAlt;
  815. BEGIN
  816. IF gn.typ = nt THEN GetSym(gn.p1, sn); RETURN sn.deletable
  817. ELSIF gn.typ = alt THEN
  818. RETURN DelAlt(gn.p1) OR (gn.p2 # 0) & DelAlt(gn.p2)
  819. ELSE RETURN (gn.typ = eps) OR (gn.typ = iter)
  820. OR (gn.typ = opt) OR (gn.typ = sem) OR (gn.typ = sync)
  821. END
  822. END DelNode;
  823. (* PrintGraph Print the graph
  824. ----------------------------------------------------------------------*)
  825. PROCEDURE PrintGraph;
  826. VAR
  827. i: INTEGER;
  828. PROCEDURE WriteTyp2 (typ: INTEGER);
  829. BEGIN
  830. CASE typ OF
  831. nt : FileIO.WriteString(CRS.lst, "nt ")
  832. | t : FileIO.WriteString(CRS.lst, "t ")
  833. | wt : FileIO.WriteString(CRS.lst, "wt ")
  834. | any : FileIO.WriteString(CRS.lst, "any ")
  835. | eps : FileIO.WriteString(CRS.lst, "eps ")
  836. | sem : FileIO.WriteString(CRS.lst, "sem ")
  837. | sync: FileIO.WriteString(CRS.lst, "sync")
  838. | alt : FileIO.WriteString(CRS.lst, "alt ")
  839. | iter: FileIO.WriteString(CRS.lst, "iter")
  840. | opt : FileIO.WriteString(CRS.lst, "opt ")
  841. ELSE FileIO.WriteString(CRS.lst, "--- ")
  842. END;
  843. END WriteTyp2;
  844. BEGIN (* PrintGraph *)
  845. FileIO.WriteString(CRS.lst, "GraphList:");
  846. FileIO.WriteLn(CRS.lst); FileIO.WriteLn(CRS.lst);
  847. FileIO.WriteString(CRS.lst, " nr typ next p1 p2 line");
  848. (* useful for debugging - PDT *)
  849. FileIO.WriteString(CRS.lst, " posbeg poslen poscol");
  850. (* *)
  851. FileIO.WriteLn(CRS.lst); FileIO.WriteLn(CRS.lst);
  852. i := 0;
  853. WHILE i <= nNodes DO
  854. FileIO.WriteInt(CRS.lst, i, 3); FileIO.WriteString(CRS.lst, " ");
  855. WriteTyp2(gn^[i].typ); FileIO.WriteInt(CRS.lst, gn^[i].next, 7);
  856. FileIO.WriteInt(CRS.lst, gn^[i].p1, 7);
  857. FileIO.WriteInt(CRS.lst, gn^[i].p2, 7);
  858. FileIO.WriteInt(CRS.lst, gn^[i].line, 7);
  859. (* useful for debugging - PDT *)
  860. FileIO.WriteInt(CRS.lst, FileIO.INTL(gn^[i].pos.beg), 7);
  861. FileIO.WriteCard(CRS.lst, gn^[i].pos.len, 7);
  862. FileIO.WriteInt(CRS.lst, gn^[i].pos.col, 7);
  863. (* *)
  864. FileIO.WriteLn(CRS.lst);
  865. INC(i);
  866. END;
  867. FileIO.WriteLn(CRS.lst); FileIO.WriteLn(CRS.lst);
  868. END PrintGraph;
  869. (* FindCircularProductions Test grammar for circular derivations
  870. ----------------------------------------------------------------------*)
  871. PROCEDURE FindCircularProductions (VAR ok: BOOLEAN);
  872. TYPE
  873. ListEntry = RECORD
  874. left: INTEGER;
  875. right: INTEGER;
  876. deleted: BOOLEAN;
  877. END;
  878. VAR
  879. changed, onLeftSide,
  880. onRightSide: BOOLEAN;
  881. i, j, listLength: INTEGER;
  882. list: ARRAY [0 .. maxList] OF ListEntry;
  883. singles: MarkList;
  884. sn: SymbolNode;
  885. PROCEDURE GetSingles (gp: INTEGER; VAR singles: MarkList);
  886. VAR
  887. gn: GraphNode;
  888. BEGIN
  889. IF gp <= 0 THEN RETURN END; (* end of graph found *)
  890. GetNode (gp, gn);
  891. IF gn.typ = nt THEN
  892. IF DelGraph(ABS(gn.next)) THEN Sets.Incl(singles, gn.p1) END
  893. ELSIF (gn.typ = alt) OR (gn.typ = iter) OR (gn.typ = opt) THEN
  894. IF DelGraph(ABS(gn.next)) THEN
  895. GetSingles(gn.p1, singles);
  896. IF gn.typ = alt THEN GetSingles(gn.p2, singles) END
  897. END
  898. END;
  899. IF DelNode(gn) THEN GetSingles(gn.next, singles) END
  900. END GetSingles;
  901. BEGIN (* FindCircularProductions *)
  902. i := firstNt; listLength := 0;
  903. WHILE i <= lastNt DO (* for all nonterminals i *)
  904. ClearMarkList(singles); GetSym(i, sn);
  905. GetSingles(sn.struct, singles); (* get nt's j such that i-->j *)
  906. j := firstNt;
  907. WHILE j <= lastNt DO (* for all nonterminals j *)
  908. IF Sets.In(singles, j) THEN
  909. list[listLength].left := i; list[listLength].right := j;
  910. list[listLength].deleted := FALSE;
  911. INC(listLength);
  912. IF listLength > maxList THEN Restriction(9, maxList) END
  913. END;
  914. INC(j)
  915. END;
  916. INC(i)
  917. END;
  918. REPEAT
  919. i := 0; changed := FALSE;
  920. WHILE i < listLength DO
  921. IF ~ list[i].deleted THEN
  922. j := 0; onLeftSide := FALSE; onRightSide := FALSE;
  923. WHILE j < listLength DO
  924. IF ~ list[j].deleted THEN
  925. IF list[i].left = list[j].right THEN onRightSide := TRUE END;
  926. IF list[j].left = list[i].right THEN onLeftSide := TRUE END
  927. END;
  928. INC(j)
  929. END;
  930. IF ~ onRightSide OR ~ onLeftSide THEN
  931. list[i].deleted := TRUE; changed := TRUE
  932. END
  933. END;
  934. INC(i)
  935. END
  936. UNTIL ~ changed;
  937. FileIO.WriteString(CRS.lst, "Circular derivations: ");
  938. i := 0; ok := TRUE;
  939. WHILE i < listLength DO
  940. IF ~ list[i].deleted THEN
  941. ok := FALSE;
  942. FileIO.WriteLn(CRS.lst); FileIO.WriteString(CRS.lst, " ");
  943. GetSym(list[i].left, sn); FileIO.WriteText(CRS.lst, sn.name, 20);
  944. FileIO.WriteString(CRS.lst, " --> ");
  945. GetSym(list[i].right, sn); FileIO.WriteText(CRS.lst, sn.name, 20);
  946. END;
  947. INC(i)
  948. END;
  949. IF ok THEN FileIO.WriteString(CRS.lst, " -- none --") END;
  950. FileIO.WriteLn(CRS.lst);
  951. END FindCircularProductions;
  952. (* LL1Test Collect terminal sets and checks LL(1) conditions
  953. ----------------------------------------------------------------------*)
  954. PROCEDURE LL1Test (VAR ll1: BOOLEAN);
  955. VAR
  956. sn: SymbolNode;
  957. curSy: INTEGER;
  958. PROCEDURE LL1Error (cond, ts: INTEGER);
  959. VAR
  960. sn: SymbolNode;
  961. BEGIN
  962. ll1 := FALSE;
  963. FileIO.WriteLn(CRS.lst);
  964. FileIO.WriteString(CRS.lst, " LL(1) error in ");
  965. GetSym(curSy, sn); FileIO.WriteString(CRS.lst, sn.name);
  966. FileIO.WriteString(CRS.lst, ": ");
  967. IF ts > 0 THEN
  968. GetSym(ts, sn); FileIO.WriteString(CRS.lst, sn.name);
  969. FileIO.WriteString(CRS.lst, " is ");
  970. END;
  971. CASE cond OF
  972. 1: FileIO.WriteString(CRS.lst,
  973. "the start of several alternatives.")
  974. | 2: FileIO.WriteString(CRS.lst,
  975. "the start & successor of a deletable structure")
  976. | 3: FileIO.WriteString(CRS.lst,
  977. "an ANY node that matches no symbol")
  978. END;
  979. END LL1Error;
  980. PROCEDURE Check (cond: INTEGER; VAR s1, s2: Set);
  981. VAR
  982. i: INTEGER;
  983. BEGIN
  984. i := 0;
  985. WHILE i <= maxT DO
  986. IF Sets.In(s1, i) & Sets.In(s2, i) THEN LL1Error(cond, i) END;
  987. INC(i)
  988. END
  989. END Check;
  990. PROCEDURE CheckAlternatives (gp: INTEGER);
  991. VAR
  992. gn, gn1: GraphNode;
  993. s1, s2: Set;
  994. p: INTEGER;
  995. BEGIN
  996. WHILE gp > 0 DO
  997. GetNode(gp, gn);
  998. IF gn.typ = alt THEN
  999. p := gp; Sets.Clear(s1);
  1000. WHILE p # 0 DO (*for all alternatives*)
  1001. GetNode(p, gn1); CompExpected(gn1.p1, curSy, s2);
  1002. Check(1, s1, s2);
  1003. Sets.Unite(s1, s2);
  1004. CheckAlternatives(gn1.p1);
  1005. p := gn1.p2
  1006. END
  1007. ELSIF (gn.typ = opt) OR (gn.typ = iter) THEN
  1008. CompExpected(gn.p1, curSy, s1);
  1009. CompExpected(ABS(gn.next), curSy, s2);
  1010. Check(2, s1, s2);
  1011. CheckAlternatives(gn.p1)
  1012. ELSIF gn.typ = any THEN
  1013. GetSet(gn.p1, s1);
  1014. IF Sets.Empty(s1) THEN LL1Error(3, 0) END
  1015. (*e.g. {ANY} ANY or [ANY] ANY*)
  1016. END;
  1017. gp := gn.next
  1018. END
  1019. END CheckAlternatives;
  1020. BEGIN (* LL1Test *)
  1021. FileIO.WriteString(CRS.lst, "LL(1) conditions:");
  1022. curSy := firstNt; ll1 := TRUE;
  1023. WHILE curSy <= lastNt DO (*for all nonterminals*)
  1024. GetSym(curSy, sn); CheckAlternatives(sn.struct);
  1025. INC(curSy)
  1026. END;
  1027. IF ll1 THEN FileIO.WriteString(CRS.lst, " -- ok --") END;
  1028. FileIO.WriteLn(CRS.lst);
  1029. END LL1Test;
  1030. (* TestCompleteness Test if all nonterminals have productions
  1031. ----------------------------------------------------------------------*)
  1032. PROCEDURE TestCompleteness (VAR ok: BOOLEAN);
  1033. VAR
  1034. sp: INTEGER;
  1035. sn: SymbolNode;
  1036. BEGIN
  1037. FileIO.WriteString(CRS.lst, "Undefined nonterminals: ");
  1038. sp := firstNt; ok := TRUE;
  1039. WHILE sp <= lastNt DO (*for all nonterminals*)
  1040. GetSym(sp, sn);
  1041. IF sn.struct = 0 THEN
  1042. ok := FALSE;
  1043. FileIO.WriteLn(CRS.lst); FileIO.WriteString(CRS.lst, " ");
  1044. FileIO.WriteString(CRS.lst, sn.name);
  1045. END;
  1046. INC(sp)
  1047. END;
  1048. IF ok THEN FileIO.WriteString(CRS.lst, " -- none --") END;
  1049. FileIO.WriteLn(CRS.lst);
  1050. END TestCompleteness;
  1051. (* TestIfAllNtReached Test if all nonterminals can be reached
  1052. ----------------------------------------------------------------------*)
  1053. PROCEDURE TestIfAllNtReached (VAR ok: BOOLEAN);
  1054. VAR
  1055. gn: GraphNode;
  1056. sp: INTEGER;
  1057. reached: MarkList;
  1058. sn: SymbolNode;
  1059. PROCEDURE MarkReachedNts (gp: INTEGER);
  1060. VAR
  1061. gn: GraphNode;
  1062. sn: SymbolNode;
  1063. BEGIN
  1064. WHILE gp > 0 DO
  1065. GetNode(gp, gn);
  1066. IF gn.typ = nt THEN
  1067. IF ~ Sets.In(reached, gn.p1) THEN (*new nt reached*)
  1068. Sets.Incl(reached, gn.p1);
  1069. GetSym(gn.p1, sn); MarkReachedNts(sn.struct)
  1070. END
  1071. ELSIF (gn.typ = alt) OR (gn.typ = iter) OR (gn.typ = opt) THEN
  1072. MarkReachedNts(gn.p1);
  1073. IF gn.typ = alt THEN MarkReachedNts(gn.p2) END
  1074. END;
  1075. gp := gn.next
  1076. END
  1077. END MarkReachedNts;
  1078. BEGIN (* TestIfAllNtReached *)
  1079. ClearMarkList(reached);
  1080. GetNode(root, gn); Sets.Incl(reached, gn.p1);
  1081. GetSym(gn.p1, sn); MarkReachedNts(sn.struct);
  1082. FileIO.WriteString(CRS.lst, "Unreachable nonterminals:");
  1083. sp := firstNt; ok := TRUE;
  1084. WHILE sp <= lastNt DO (*for all nonterminals*)
  1085. IF ~ Sets.In(reached, sp) THEN
  1086. ok := FALSE; GetSym(sp, sn);
  1087. FileIO.WriteLn(CRS.lst); FileIO.WriteString(CRS.lst, " ");
  1088. FileIO.WriteString(CRS.lst, sn.name)
  1089. END;
  1090. INC(sp)
  1091. END;
  1092. IF ok THEN FileIO.WriteString(CRS.lst, " -- none --") END;
  1093. FileIO.WriteLn(CRS.lst);
  1094. END TestIfAllNtReached;
  1095. (* TestIfNtToTerm Test if all nonterminals can be derived to terminals
  1096. ----------------------------------------------------------------------*)
  1097. PROCEDURE TestIfNtToTerm (VAR ok: BOOLEAN);
  1098. VAR
  1099. changed: BOOLEAN;
  1100. sp: INTEGER;
  1101. sn: SymbolNode;
  1102. termList: MarkList;
  1103. PROCEDURE IsTerm (gp: INTEGER): BOOLEAN;
  1104. VAR
  1105. gn: GraphNode;
  1106. BEGIN
  1107. WHILE gp > 0 DO
  1108. GetNode(gp, gn);
  1109. IF (gn.typ = nt) & ~ Sets.In(termList, gn.p1)
  1110. OR (gn.typ = alt) & ~ IsTerm(gn.p1)
  1111. & ((gn.p2 = 0) OR ~ IsTerm(gn.p2)) THEN
  1112. RETURN FALSE
  1113. END;
  1114. gp := gn.next
  1115. END;
  1116. RETURN TRUE
  1117. END IsTerm;
  1118. BEGIN (* TestIfNtToTerm *)
  1119. ClearMarkList(termList);
  1120. REPEAT
  1121. sp := firstNt; changed := FALSE;
  1122. WHILE sp <= lastNt DO
  1123. IF ~ Sets.In(termList, sp) THEN
  1124. GetSym(sp, sn);
  1125. IF IsTerm(sn.struct) THEN
  1126. Sets.Incl(termList, sp); changed := TRUE
  1127. END
  1128. END;
  1129. INC(sp)
  1130. END
  1131. UNTIL ~ changed;
  1132. FileIO.WriteString(CRS.lst, "Underivable nonterminals:");
  1133. sp := firstNt; ok := TRUE;
  1134. WHILE sp <= lastNt DO
  1135. IF ~ Sets.In(termList, sp) THEN
  1136. ok := FALSE; GetSym(sp, sn);
  1137. FileIO.WriteLn(CRS.lst); FileIO.WriteString(CRS.lst, " ");
  1138. FileIO.WriteString(CRS.lst, sn.name);
  1139. END;
  1140. INC(sp)
  1141. END;
  1142. IF ok THEN FileIO.WriteString(CRS.lst, " -- none --") END;
  1143. FileIO.WriteLn(CRS.lst);
  1144. END TestIfNtToTerm;
  1145. (* ASCIIName Assigns the wellknown ASCII-Name in lowercase
  1146. ----------------------------------------------------------------------*)
  1147. PROCEDURE ASCIIName (ascii: CHAR; VAR asciiname: Name);
  1148. VAR
  1149. N : CARDINAL;
  1150. BEGIN
  1151. CASE ascii OF
  1152. 00C : asciiname := "nul"
  1153. | 01C : asciiname := "soh"
  1154. | 02C : asciiname := "stx"
  1155. | 03C : asciiname := "etx"
  1156. | 04C : asciiname := "eot"
  1157. | 05C : asciiname := "enq"
  1158. | 06C : asciiname := "ack"
  1159. | 07C : asciiname := "bel"
  1160. | 10C : asciiname := "bs"
  1161. | 11C : asciiname := "ht"
  1162. | 12C : asciiname := "lf"
  1163. | 13C : asciiname := "vt"
  1164. | 14C : asciiname := "ff"
  1165. | 15C : asciiname := "cr"
  1166. | 16C : asciiname := "so"
  1167. | 17C : asciiname := "si"
  1168. | 20C : asciiname := "dle"
  1169. | 21C : asciiname := "dc1"
  1170. | 22C : asciiname := "dc2"
  1171. | 23C : asciiname := "dc3"
  1172. | 24C : asciiname := "dc4"
  1173. | 25C : asciiname := "nak"
  1174. | 26C : asciiname := "syn"
  1175. | 27C : asciiname := "etb"
  1176. | 30C : asciiname := "can"
  1177. | 31C : asciiname := "em"
  1178. | 32C : asciiname := "sub"
  1179. | 33C : asciiname := "esc"
  1180. | 34C : asciiname := "fs"
  1181. | 35C : asciiname := "gs"
  1182. | 36C : asciiname := "rs"
  1183. | 37C : asciiname := "us"
  1184. | " " : asciiname := "sp"
  1185. | "!" : asciiname := "bang"
  1186. | '"' : asciiname := "dquote"
  1187. | "#" : asciiname := "hash"
  1188. | "$" : asciiname := "dollar"
  1189. | "%" : asciiname := "percent"
  1190. | "&" : asciiname := "and"
  1191. | "'" : asciiname := "squote"
  1192. | "(" : asciiname := "lparen"
  1193. | ")" : asciiname := "rparen"
  1194. | "*" : asciiname := "star"
  1195. | "+" : asciiname := "plus"
  1196. | "," : asciiname := "comma"
  1197. | "-" : asciiname := "minus"
  1198. | "." : asciiname := "point"
  1199. | "/" : asciiname := "slash"
  1200. | "0" : asciiname := "zero"
  1201. | "1" : asciiname := "one"
  1202. | "2" : asciiname := "two"
  1203. | "3" : asciiname := "three"
  1204. | "4" : asciiname := "four"
  1205. | "5" : asciiname := "five"
  1206. | "6" : asciiname := "six"
  1207. | "7" : asciiname := "seven"
  1208. | "8" : asciiname := "eight"
  1209. | "9" : asciiname := "nine"
  1210. | ":" : asciiname := "colon"
  1211. | ";" : asciiname := "semicolon"
  1212. | "<" : asciiname := "less"
  1213. | "=" : asciiname := "equal"
  1214. | ">" : asciiname := "greater"
  1215. | "?" : asciiname := "query"
  1216. | "@" : asciiname := "at"
  1217. | "A" .. "Z", "a" .. "z"
  1218. : asciiname := " "; asciiname[0] := ascii
  1219. | "[" : asciiname := "lbrack"
  1220. | "\" : asciiname := "backslash"
  1221. | "]" : asciiname := "rbrack"
  1222. | "^" : asciiname := "uparrow"
  1223. | "_" : asciiname := "underscore"
  1224. | "`" : asciiname := "accent"
  1225. | "{" : asciiname := "lbrace"
  1226. | "|" : asciiname := "bar"
  1227. | "}" : asciiname := "rbrace"
  1228. | "~" : asciiname := "tilde"
  1229. | 177C: asciiname := "delete"
  1230. ELSE
  1231. N := ORD(ascii);
  1232. asciiname := 'ascii ';
  1233. asciiname[6] := CHR(N MOD 10 + ORD('0'));
  1234. N := N DIV 10;
  1235. asciiname[5] := CHR(N MOD 10 + ORD('0'));
  1236. asciiname[4] := CHR(N DIV 10 + ORD('0'));
  1237. END
  1238. END ASCIIName;
  1239. (* BuildName Build new Name to represent old string
  1240. ----------------------------------------------------------------------*)
  1241. PROCEDURE BuildName (VAR old, new: ARRAY OF CHAR);
  1242. VAR
  1243. ForLoop, I, TargetIndex: CARDINAL;
  1244. AsciiName: Name;
  1245. BEGIN
  1246. TargetIndex := 0;
  1247. FOR ForLoop := 1 TO FileIO.SLENGTH(old) - 2 DO
  1248. CASE old[ForLoop] OF
  1249. "A" .. "Z", "a" .. "z":
  1250. IF TargetIndex <= HIGH(new) THEN
  1251. new[TargetIndex] := old[ForLoop];
  1252. INC(TargetIndex);
  1253. END;
  1254. ELSE
  1255. ASCIIName(old[ForLoop], AsciiName);
  1256. FOR I := 0 TO FileIO.SLENGTH(AsciiName) - 1 DO
  1257. IF TargetIndex <= HIGH(new) THEN
  1258. new[TargetIndex] := AsciiName[I];
  1259. INC(TargetIndex);
  1260. END;
  1261. END;
  1262. END;
  1263. END;
  1264. IF TargetIndex <= HIGH(new) THEN new[TargetIndex] := 0C END;
  1265. END BuildName;
  1266. (* SymName Generates a new name for a symbol constant
  1267. ----------------------------------------------------------------------*)
  1268. PROCEDURE SymName (symn: Name; VAR conn: Name);
  1269. BEGIN
  1270. IF (symn[0] = '"') OR (symn[0] = "'") THEN
  1271. IF FileIO.SLENGTH(symn) = 3 THEN
  1272. ASCIIName(symn[1], conn);
  1273. ELSE
  1274. BuildName(symn, conn);
  1275. END;
  1276. ELSE
  1277. conn := symn;
  1278. END;
  1279. FileIO.Concat(conn, "Sym", conn);
  1280. END SymName;
  1281. (* AssignSymNames Assigns the user defined or generated token names
  1282. ----------------------------------------------------------------------*)
  1283. PROCEDURE AssignSymNames (default: BOOLEAN; VAR thereExists: BOOLEAN);
  1284. PROCEDURE AssignDef (VAR n (*is not modified*), const: Name);
  1285. VAR
  1286. ForLoop: CARDINAL;
  1287. BEGIN
  1288. FOR ForLoop := 1 TO lastName DO
  1289. IF FileIO.Compare(n, tt[ForLoop].definition) = 0 THEN
  1290. const := tt[ForLoop].name; thereExists := TRUE; RETURN;
  1291. END;
  1292. END;
  1293. IF default THEN SymName(n, const); ELSE const := ""; END;
  1294. END AssignDef;
  1295. VAR
  1296. ForLoop: INTEGER;
  1297. BEGIN
  1298. thereExists := default;
  1299. st^[0].constant := "EOFSYM";
  1300. FOR ForLoop := 1 TO maxP DO
  1301. AssignDef(st^[ForLoop].name, st^[ForLoop].constant)
  1302. END;
  1303. st^[maxT].constant := "NOSYM";
  1304. END AssignSymNames;
  1305. BEGIN (* CRT *)
  1306. ch := "A"; WHILE ch <= "Z" DO ddt[ch] := FALSE; INC(ch) END;
  1307. maxSet := 0; Sets.Clear(set[0]); Sets.Incl(set[0], eofSy);
  1308. firstNt := maxSymbols; maxP := maxSymbols; maxT := -1; maxC := -1;
  1309. lastNt := maxP - 1;
  1310. dummyName := 0; lastName := 0; symNames := FALSE;
  1311. (* The dummy node gn^[0] ensures that none of the procedures
  1312. above have to check for 0 indices. *)
  1313. Storage.ALLOCATE(gn, SYSTEM.TSIZE(GraphList));
  1314. Storage.ALLOCATE(st, SYSTEM.TSIZE(SymbolTable));
  1315. nNodes := 0;
  1316. gn^[0].typ := -1; gn^[0].p1 := 0; gn^[0].p2 := 0;
  1317. gn^[0].next := 0; gn^[0].line := 0;
  1318. gn^[0].pos.beg := - FileIO.Long1;
  1319. gn^[0].pos.len := 0; gn^[0].pos.col := 0;
  1320. (* debug info when choosing constants - PDT
  1321. FileIO.WriteString(FileIO.StdOut, "Symbol table");
  1322. FileIO.WriteCard(FileIO.StdOut, SIZE(SymbolTable), 1);
  1323. FileIO.WriteLn(FileIO.StdOut);
  1324. FileIO.WriteString(FileIO.StdOut, "Class table ");
  1325. FileIO.WriteCard(FileIO.StdOut, SIZE(ClassTable), 1);
  1326. FileIO.WriteLn(FileIO.StdOut);
  1327. FileIO.WriteString(FileIO.StdOut, "Name table ");
  1328. FileIO.WriteCard(FileIO.StdOut, SIZE(NameTable), 1);
  1329. FileIO.WriteLn(FileIO.StdOut);
  1330. FileIO.WriteString(FileIO.StdOut, "Graph list ");
  1331. FileIO.WriteCard(FileIO.StdOut, SIZE(GraphList), 1);
  1332. FileIO.WriteLn(FileIO.StdOut);
  1333. *)
  1334. END CRT.