CRQ.frm 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  1. (* CR Main Module of Coco/R
  2. == =====================
  3. This is a compiler generator that produces a scanner and a parser
  4. from an attributed grammar, and optionally a complete small compiler.
  5. Original code in Oberon by Hanspeter Moessenboeck, ETH Zurich
  6. Ported at ETH to Apple Modula, and thence to JPI-2 Modula.
  7. JPI version of 27 January 1991 was then modified to make more
  8. portable by Pat Terry, January - October 1992
  9. This is the WinTel version
  10. This version outputs error messages in "standard" form for use with editors
  11. Usage:
  12. COCOR [-options] GrammarName[.atg] [$options]
  13. Input:
  14. attributed grammar input grammar
  15. scanner.frm frame file
  16. parser.frm frame file
  17. compiler.frm frame file (optional)
  18. (Frame files must be in the sme directory as the grammar, or may be
  19. found on a path specified by DOS environment variable CRFRAMES).
  20. Output:
  21. <GrammarName>S.def + mod generated scanner
  22. <GrammarName>P.def + mod generated parser
  23. <GrammarName>.err error numbers and corresponding error messages
  24. <GrammarName>.lst source listing with error messages and trace output
  25. Optionally
  26. <GrammarName>G.def + mod generated symbolic names
  27. <GrammarName>.mod generated compiler main module
  28. Implementation restrictions
  29. 1 too many nodes in graph (>1500) CRT.NewNode
  30. 2 too many symbols (>500) CRT.NewSym, MovePragmas
  31. 3 too many sets (>256 ANY-syms or SYNC syms) CRT.NewSet,
  32. 4 too many character classes (>250) CRT.NewClass
  33. 5 too many conditions in generated code (>100) CRX.NewCondSet
  34. 6 too many token names in "NAMES" (>100) CRT.NewName
  35. 7 too many states in automata (>500) CRA.NewState
  36. Trace output
  37. (To activate a trace switch, write "${letter}" in the input grammar, or
  38. invoke Coco with a second command line parameter)
  39. A Prints states of automaton
  40. C Generates complete compiler module
  41. D Suppresses Def Mod generation
  42. F Prints start symbols and followers of nonterminals.
  43. G Prints the top-down graph.
  44. I Trace of start symbol set computation.
  45. L Forces a listing (otherwise a listing is only printed if errors are found).
  46. M Suppresses FORWARD declarations in parser (for multipass compilers).
  47. N Uses default names for symbol value constants. This generates an
  48. extra module <grammar name>G, and corresponding import statements
  49. using constant names instead of numbers for symbols in parser and
  50. scanner.
  51. The constants are used unqualified and hence all needed constants
  52. have to be imported; so a complete import list for these constants
  53. is generated.
  54. There is no decision whether a constant is actually needed.
  55. The default conventions are (only terminals or pragmas can have names):
  56. single character --> <ASCII name (lowercase)>Sym
  57. eg. "+" --> plusSym
  58. character string --> <string>Sym
  59. eg. "PROGRAM" --> PROGRAMSym
  60. scanner token --> <token name>Sym
  61. eg. ident --> identSym
  62. O Trace of follow set computation (not yet implemented).
  63. P Generates parser only
  64. S Prints the symbol list.
  65. T Suppresses generation of def and mod files (grammar tests only).
  66. X Prints a cross reference list.
  67. ==========================================================================*)
  68. MODULE -->Grammar;
  69. FROM -->Scanner IMPORT lst, src, errors, directory, Error, CharAt;
  70. FROM -->Parser IMPORT Parse;
  71. IMPORT CRC, CRT, CRA, CRP, CRS, CRX, FileIO, Storage;
  72. IMPORT SYSTEM (* for TSIZE only *);
  73. CONST
  74. ATGExt = ".atg";
  75. LSTExt = ".lst";
  76. Version = "1.53q";
  77. ReleaseDate = "17 September 2002";
  78. TYPE
  79. INT32 = FileIO.INT32;
  80. VAR
  81. Options,
  82. GrammarName,
  83. ATGFileName,
  84. lstFileName: ARRAY [0 .. 63] OF CHAR;
  85. ll1: BOOLEAN; (* TRUE, if grammar is LL(1) *)
  86. IDE,
  87. ok: BOOLEAN; (* TRUE, if grammar tests ok so far *)
  88. MODULE ListHandler;
  89. (* ------------------- Source Listing and Error handler -------------- *)
  90. IMPORT FileIO, Storage, SYSTEM;
  91. IMPORT lst, CharAt, ATGFileName, IDE, errors, INT32;
  92. EXPORT StoreError, PrintListing;
  93. TYPE
  94. Err = POINTER TO ErrDesc;
  95. ErrDesc = RECORD
  96. nr, line, col: INTEGER;
  97. next: Err
  98. END;
  99. CONST
  100. tab = 11C;
  101. VAR
  102. firstErr, lastErr: Err;
  103. Extra: INTEGER;
  104. PROCEDURE StoreError (nr, line, col: INTEGER; pos: INT32);
  105. (* Store an error message for later printing *)
  106. VAR
  107. nextErr: Err;
  108. BEGIN
  109. Storage.ALLOCATE(nextErr, SYSTEM.TSIZE(ErrDesc));
  110. nextErr^.nr := nr; nextErr^.line := line; nextErr^.col := col;
  111. nextErr^.next := NIL;
  112. IF firstErr = NIL
  113. THEN firstErr := nextErr
  114. ELSE lastErr^.next := nextErr
  115. END;
  116. lastErr := nextErr;
  117. INC(errors)
  118. END StoreError;
  119. PROCEDURE GetLine (VAR pos: INT32;
  120. VAR line: ARRAY OF CHAR;
  121. VAR eof: BOOLEAN);
  122. (* Read a source line. Return empty line if eof *)
  123. VAR
  124. ch: CHAR;
  125. i: CARDINAL;
  126. BEGIN
  127. i := 0; eof := FALSE; ch := CharAt(pos); INC(pos);
  128. WHILE (ch # FileIO.CR) & (ch # FileIO.LF) & (ch # FileIO.EOF) DO
  129. line[i] := ch; INC(i); ch := CharAt(pos); INC(pos);
  130. END;
  131. eof := (i = 0) & (ch = FileIO.EOF); line[i] := 0C;
  132. IF ch = FileIO.CR THEN (* check for MsDos *)
  133. ch := CharAt(pos);
  134. IF ch = FileIO.LF THEN INC(pos); Extra := 0 END
  135. END
  136. END GetLine;
  137. PROCEDURE PrintErr (line: ARRAY OF CHAR; nr, col: INTEGER);
  138. (* Print an error message *)
  139. PROCEDURE Msg (s: ARRAY OF CHAR);
  140. BEGIN
  141. FileIO.WriteString(lst, s)
  142. END Msg;
  143. PROCEDURE Pointer;
  144. VAR
  145. i: INTEGER;
  146. BEGIN
  147. FileIO.WriteString(lst, "***** ");
  148. i := 0;
  149. WHILE i < col + Extra - 2 DO
  150. IF line[i] = tab
  151. THEN FileIO.Write(lst, tab)
  152. ELSE FileIO.Write(lst, ' ')
  153. END;
  154. INC(i)
  155. END;
  156. FileIO.WriteString(lst, "^ ")
  157. END Pointer;
  158. BEGIN
  159. IF ~ IDE THEN Pointer END;
  160. CASE nr OF
  161. -->Errors
  162. | 101: Msg("character set may not be empty")
  163. | 102: Msg("string literal may not extend over line end")
  164. | 103: Msg("a literal must not have attributes")
  165. | 104: Msg("this symbol kind not allowed in production")
  166. | 105: Msg("attribute mismatch between declaration and use")
  167. | 106: Msg("undefined string in production")
  168. | 107: Msg("name declared twice")
  169. | 108: Msg("this type not allowed on left side of production")
  170. | 109: Msg("earlier semantic action was not terminated")
  171. | 111: Msg("no production found for grammar name")
  172. | 112: Msg("grammar symbol must not have attributes")
  173. | 113: Msg("a literal must not be declared with a structure")
  174. | 114: Msg("semantic action not allowed here")
  175. | 115: Msg("undefined name")
  176. | 116: Msg("attributes not allowed in token declaration")
  177. | 117: Msg("name does not match grammar name")
  178. | 118: Msg("unacceptable constant value")
  179. | 119: Msg("may not ignore CHR(0)")
  180. | 120: Msg("token might be empty")
  181. | 121: Msg("token must not start with an iteration")
  182. | 122: Msg("comment delimiters may not be structured")
  183. | 123: Msg("only terminals may be weak")
  184. | 124: Msg("literal tokens may not contain white space")
  185. | 125: Msg("comment delimiter must be 1 or 2 characters long")
  186. | 126: Msg("character set contains more than one character")
  187. | 127: Msg("could not make deterministic automaton")
  188. | 128: Msg("semantic action text too long - please split it")
  189. | 129: Msg("literal tokens may not be empty")
  190. | 130: Msg("IGNORE CASE must appear earlier")
  191. ELSE Msg("Error: "); FileIO.WriteInt(lst, nr, 1);
  192. END;
  193. FileIO.WriteLn(lst)
  194. END PrintErr;
  195. PROCEDURE PrintListing;
  196. (* Print a source listing with error messages *)
  197. VAR
  198. nextErr: Err;
  199. eof: BOOLEAN;
  200. lnr, errC: INTEGER;
  201. srcPos: INT32;
  202. line: ARRAY [0 .. 255] OF CHAR;
  203. BEGIN
  204. IF ~ IDE THEN
  205. FileIO.WriteString(lst, "Listing:");
  206. FileIO.WriteLn(lst); FileIO.WriteLn(lst);
  207. END;
  208. srcPos := FileIO.Long0; nextErr := firstErr;
  209. GetLine(srcPos, line, eof); lnr := 1; errC := 0;
  210. WHILE ~ eof DO
  211. IF ~ IDE THEN
  212. FileIO.WriteInt(lst, lnr, 5); FileIO.WriteString(lst, " ");
  213. FileIO.WriteString(lst, line); FileIO.WriteLn(lst)
  214. END;
  215. WHILE (nextErr # NIL) & (nextErr^.line = lnr) DO
  216. IF IDE THEN
  217. FileIO.WriteString(lst, ATGFileName);
  218. FileIO.WriteString(lst, " (");
  219. FileIO.WriteCard(lst, lnr, 1);
  220. FileIO.WriteString(lst, ",");
  221. FileIO.WriteCard(lst, nextErr^.col-1, 0);
  222. FileIO.WriteString(lst, ") ")
  223. END;
  224. PrintErr(line, nextErr^.nr, nextErr^.col); INC(errC);
  225. nextErr := nextErr^.next
  226. END;
  227. GetLine(srcPos, line, eof); INC(lnr);
  228. END;
  229. IF nextErr # NIL THEN
  230. IF ~ IDE THEN FileIO.WriteInt(lst, lnr, 5); FileIO.WriteLn(lst) END;
  231. WHILE nextErr # NIL DO
  232. IF IDE THEN
  233. FileIO.WriteString(lst, ATGFileName);
  234. FileIO.WriteString(lst, " (");
  235. FileIO.WriteCard(lst, lnr, 1);
  236. FileIO.WriteString(lst, ",");
  237. FileIO.WriteCard(lst, nextErr^.col-1, 0);
  238. FileIO.WriteString(lst, ") ")
  239. END;
  240. PrintErr(line, nextErr^.nr, nextErr^.col); INC(errC);
  241. nextErr := nextErr^.next
  242. END
  243. END;
  244. IF ~ IDE AND (errC > 0) THEN
  245. FileIO.WriteLn(lst);
  246. FileIO.WriteInt(lst, errC, 5); FileIO.WriteString(lst, " error");
  247. IF errC # 1 THEN FileIO.Write(lst, "s") END;
  248. FileIO.WriteLn(lst); FileIO.WriteLn(lst); FileIO.WriteLn(lst);
  249. END
  250. END PrintListing;
  251. BEGIN
  252. firstErr := NIL; Extra := 1;
  253. END ListHandler;
  254. PROCEDURE SetOption (s: ARRAY OF CHAR);
  255. (* Set compiler options *)
  256. VAR
  257. i: CARDINAL;
  258. BEGIN
  259. i := 1;
  260. WHILE s[i] # 0C DO
  261. s[i] := CAP(s[i]);
  262. IF (s[i] >= "A") AND (s[i] <= "Z") THEN CRT.ddt[s[i]] := TRUE END;
  263. INC(i);
  264. END;
  265. END SetOption;
  266. PROCEDURE Msg (S: ARRAY OF CHAR);
  267. BEGIN
  268. FileIO.WriteString(FileIO.StdOut, S); FileIO.WriteLn(FileIO.StdOut);
  269. END Msg;
  270. (* --------------------------- Help ------------------------------- *)
  271. PROCEDURE Help;
  272. BEGIN
  273. Msg("Usage: COCOR [-Options] [Grammar[.atg]] [-Options]");
  274. Msg("Example: COCOR -mcs Test");
  275. Msg("");
  276. Msg("Options are");
  277. Msg("a - Trace automaton");
  278. Msg("c - Generate compiler module");
  279. Msg("d - Suppress generation of Definition Modules");
  280. Msg("f - Give Start and Follower sets");
  281. Msg("g - Print top-down graph");
  282. Msg("i - Trace start set computations");
  283. Msg("l - Force listing");
  284. Msg("m - (Multipass) Suppress FORWARD declarations");
  285. Msg("n - Generate symbolic names");
  286. Msg("p - Generate parser only");
  287. Msg("q - Generate error messages to interface with editor");
  288. Msg("s - Print symbol table");
  289. Msg("t - Grammar tests only - no code generated");
  290. Msg("x - Print cross reference list");
  291. Msg("COMPILER.FRM, SCANNER.FRM and PARSER.FRM must be in the working directory,");
  292. Msg("or on the path specified by the environment variable CRFRAMES");
  293. END Help;
  294. BEGIN (* CR *)
  295. FileIO.WriteString(FileIO.StdOut, "Coco/R (WinTel) - Compiler-Compiler V");
  296. FileIO.WriteString(FileIO.StdOut, Version);
  297. FileIO.WriteLn(FileIO.StdOut);
  298. FileIO.WriteString(FileIO.StdOut, "Released by Pat Terry ");
  299. FileIO.WriteString(FileIO.StdOut, ReleaseDate);
  300. FileIO.WriteLn(FileIO.StdOut);
  301. FileIO.NextParameter(GrammarName);
  302. IF (GrammarName[0] = "?")
  303. OR (GrammarName[0] = "/") AND (GrammarName[1] = "?") THEN
  304. Help; FileIO.QuitExecution
  305. END;
  306. IF GrammarName[0] = 0C THEN
  307. FileIO.WriteString(FileIO.StdOut, "(COCOR ? gives short help screen)");
  308. FileIO.WriteLn(FileIO.StdOut);
  309. END;
  310. WHILE (GrammarName[0] = "-") OR (GrammarName[0] = "/") DO
  311. (* accept options before filename *)
  312. SetOption(GrammarName); FileIO.NextParameter(GrammarName)
  313. END;
  314. ok := GrammarName[0] # 0C;
  315. REPEAT
  316. IF ~ ok THEN
  317. FileIO.WriteString(FileIO.StdOut, "Grammar[.atg] ? : ");
  318. FileIO.ReadString(FileIO.StdIn, GrammarName);
  319. IF ~ FileIO.Okay THEN FileIO.QuitExecution END;
  320. FileIO.ReadLn(FileIO.StdIn);
  321. END;
  322. FileIO.AppendExtension(GrammarName, ATGExt, ATGFileName);
  323. GrammarName := ATGFileName;
  324. FileIO.Open(src, GrammarName, FALSE);
  325. ok := FileIO.Okay;
  326. IF ~ ok THEN
  327. FileIO.WriteString(FileIO.StdOut, "File <");
  328. FileIO.WriteString(FileIO.StdOut, GrammarName);
  329. FileIO.WriteString(FileIO.StdOut, "> not found.");
  330. FileIO.WriteLn(FileIO.StdOut);
  331. END
  332. UNTIL ok;
  333. FileIO.NextParameter(Options);
  334. IF Options[0] # 0C THEN SetOption(Options) END;
  335. IDE := CRT.ddt["Q"];
  336. FileIO.ExtractDirectory(GrammarName, directory);
  337. FileIO.ChangeExtension(GrammarName, LSTExt, lstFileName);
  338. IF IDE
  339. THEN
  340. lst := FileIO.StdOut
  341. ELSE
  342. FileIO.Open(lst, lstFileName, TRUE);
  343. FileIO.WriteString(lst, "Coco/R - Compiler-Compiler V");
  344. FileIO.WriteString(lst, Version);
  345. FileIO.WriteLn(lst);
  346. FileIO.WriteString(lst, "Released by Pat Terry ");
  347. FileIO.WriteString(lst, ReleaseDate);
  348. FileIO.WriteLn(lst);
  349. FileIO.WriteString(lst, "Source file: ");
  350. FileIO.WriteString(lst, GrammarName);
  351. FileIO.WriteLn(lst); FileIO.WriteLn(lst);
  352. FileIO.WriteLn(FileIO.StdOut);
  353. FileIO.WriteString(FileIO.StdOut, "parsing file ");
  354. FileIO.WriteString(FileIO.StdOut, GrammarName);
  355. FileIO.WriteLn(FileIO.StdOut);
  356. END;
  357. CRS.Error := StoreError;
  358. CRP.Parse;
  359. (*
  360. IF ~ IDE THEN
  361. FileIO.WriteLn(FileIO.StdOut); FileIO.WriteElapsedTime(FileIO.StdOut)
  362. END;
  363. *)
  364. IF errors = 0 THEN
  365. IF ~ IDE
  366. THEN
  367. Msg("testing grammar");
  368. FileIO.WriteString(lst, "Grammar Tests:");
  369. FileIO.WriteLn(lst); FileIO.WriteLn(lst)
  370. ELSE
  371. FileIO.WriteLn(lst); FileIO.WriteString(lst, ATGFileName);
  372. FileIO.WriteString(lst, " (0, 0) Grammar tests"); FileIO.WriteLn(lst)
  373. END;
  374. CRT.CompSymbolSets;
  375. IF IDE THEN
  376. FileIO.WriteLn(lst); FileIO.WriteString(lst, ATGFileName);
  377. FileIO.WriteString(lst, " (0, 0) Undefined tests"); FileIO.WriteLn(lst)
  378. END;
  379. CRT.TestCompleteness(ok);
  380. IF ok
  381. THEN
  382. IF IDE THEN
  383. FileIO.WriteLn(lst); FileIO.WriteString(lst, ATGFileName);
  384. FileIO.WriteString(lst, " (0, 0) Unreachable tests"); FileIO.WriteLn(lst)
  385. END;
  386. CRT.TestIfAllNtReached(ok)
  387. END;
  388. IF ok THEN
  389. IF IDE THEN
  390. FileIO.WriteLn(lst); FileIO.WriteString(lst, ATGFileName);
  391. FileIO.WriteString(lst, " (0, 0) Circular tests"); FileIO.WriteLn(lst)
  392. END;
  393. CRT.FindCircularProductions(ok)
  394. END;
  395. IF ok THEN
  396. IF IDE THEN
  397. FileIO.WriteLn(lst); FileIO.WriteString(lst, ATGFileName);
  398. FileIO.WriteString(lst, " (0, 0) Underivable tests"); FileIO.WriteLn(lst)
  399. END;
  400. CRT.TestIfNtToTerm(ok)
  401. END;
  402. IF ok THEN
  403. IF IDE THEN
  404. FileIO.WriteLn(lst); FileIO.WriteString(lst, ATGFileName);
  405. FileIO.WriteString(lst, " (0, 0) LL(1) tests"); FileIO.WriteLn(lst)
  406. END;
  407. CRT.LL1Test(ll1)
  408. END;
  409. (*
  410. IF ~ IDE THEN
  411. FileIO.WriteLn(FileIO.StdOut); FileIO.WriteElapsedTime(FileIO.StdOut);
  412. FileIO.WriteLn(lst)
  413. END;
  414. *)
  415. IF ~ ok OR ~ ll1 OR CRT.ddt["L"] OR CRT.ddt["X"] THEN
  416. IF ~ IDE THEN Msg("listing") END;
  417. PrintListing; IF CRT.ddt["X"] THEN CRT.XRef; END;
  418. (*
  419. IF ~ IDE THEN
  420. FileIO.WriteLn(FileIO.StdOut); FileIO.WriteElapsedTime(FileIO.StdOut)
  421. END;
  422. *)
  423. END;
  424. IF CRT.ddt["N"] OR CRT.symNames THEN
  425. IF ~ IDE THEN Msg("symbol name assignment") END;
  426. CRT.AssignSymNames(CRT.ddt["N"], CRT.symNames);
  427. END;
  428. IF ok AND ~ CRT.ddt["T"] THEN
  429. IF ~ IDE THEN Msg("generating parser") END;
  430. CRX.GenCompiler;
  431. (*
  432. IF ~ IDE THEN
  433. FileIO.WriteLn(FileIO.StdOut); FileIO.WriteElapsedTime(FileIO.StdOut)
  434. END;
  435. *)
  436. IF CRT.genScanner AND ~ CRT.ddt["P"] THEN
  437. IF ~ IDE THEN Msg("generating scanner") END;
  438. CRA.WriteScanner(ok);
  439. IF CRT.ddt["A"] THEN CRA.PrintStates END;
  440. (*
  441. IF ~ IDE THEN
  442. FileIO.WriteLn(FileIO.StdOut); FileIO.WriteElapsedTime(FileIO.StdOut)
  443. END;
  444. *)
  445. END;
  446. IF CRT.ddt["C"] THEN
  447. IF ~ IDE THEN Msg("generating compiler") END;
  448. CRC.WriteDriver;
  449. (*
  450. IF ~ IDE THEN
  451. FileIO.WriteLn(FileIO.StdOut); FileIO.WriteElapsedTime(FileIO.StdOut);
  452. END;
  453. *)
  454. END;
  455. IF ~ IDE THEN CRX.WriteStatistics END;
  456. END;
  457. IF ~ ok THEN
  458. FileIO.WriteLn(FileIO.StdOut);
  459. IF IDE THEN
  460. FileIO.WriteString(lst, ATGFileName);
  461. FileIO.WriteString(lst, " (0, 0) ")
  462. END;
  463. FileIO.WriteString(FileIO.StdOut, "Compilation ended with errors in grammar tests.");
  464. ELSIF ~ ll1 THEN
  465. FileIO.WriteLn(FileIO.StdOut);
  466. IF IDE THEN
  467. FileIO.WriteString(lst, ATGFileName);
  468. FileIO.WriteString(lst, " (0, 0) ")
  469. END;
  470. FileIO.WriteString(FileIO.StdOut, "Compilation ended with LL(1) errors.");
  471. ELSE
  472. Msg("Compilation completed. No errors detected.");
  473. END;
  474. ELSE
  475. IF ~ IDE THEN Msg("listing") END;
  476. PrintListing; IF CRT.ddt["X"] THEN CRT.XRef END;
  477. IF ~ IDE THEN Msg("*** errors detected ***") END;
  478. END;
  479. FileIO.WriteLn(FileIO.StdOut);
  480. IF CRT.ddt["G"] THEN CRT.PrintGraph END;
  481. IF CRT.ddt["S"] THEN CRT.PrintSymbolTable END;
  482. FileIO.Close(lst); FileIO.Close(src);
  483. (*
  484. IF ~ IDE THEN
  485. FileIO.WriteLn(FileIO.StdOut); FileIO.WriteExecutionTime(FileIO.StdOut)
  486. END
  487. *)
  488. END -->Grammar.