compiler.frm 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. MODULE -->Grammar;
  2. (* This is an example of a rudimentary main module for use with COCO/R.
  3. It assumes the FileIO/Storage I/O libraries (as supplied with this
  4. project) are available.
  5. The auxiliary modules <Grammar>S (scanner) and <Grammar>P (parser)
  6. are assumed to have been constructed with COCO/R compiler generator. *)
  7. FROM -->Scanner IMPORT lst, src, errors, Error, CharAt;
  8. FROM -->Parser IMPORT Parse, Successful;
  9. IMPORT
  10. Strings, Storage, SYSTEM, FileIO;
  11. (* and any others needed *)
  12. TYPE
  13. INT32 = FileIO.INT32 (* 32 bit integers needed *);
  14. MODULE ListHandler;
  15. (* ------------------- Source Listing and Error handler -------------- *)
  16. FROM FileIO IMPORT CR, LF, EOF, File, StdOut,
  17. WriteString, Write, WriteLn, WriteInt, Long0;
  18. FROM Storage IMPORT ALLOCATE;
  19. FROM SYSTEM IMPORT TSIZE;
  20. IMPORT lst, CharAt, errors, INT32;
  21. EXPORT StoreError, PrintListing, PrintConsoleErrors;
  22. TYPE
  23. Err = POINTER TO ErrDesc;
  24. ErrDesc = RECORD
  25. nr, line, col: INTEGER;
  26. next: Err
  27. END;
  28. CONST
  29. tab = 11C;
  30. VAR
  31. firstErr, lastErr: Err;
  32. Extra: INTEGER;
  33. PROCEDURE StoreError (nr, line, col: INTEGER; pos: INT32);
  34. (* Store an error message for later printing *)
  35. VAR
  36. nextErr: Err;
  37. BEGIN
  38. ALLOCATE(nextErr, TSIZE(ErrDesc));
  39. nextErr^.nr := nr; nextErr^.line := line; nextErr^.col := col;
  40. nextErr^.next := NIL;
  41. IF firstErr = NIL
  42. THEN firstErr := nextErr
  43. ELSE lastErr^.next := nextErr
  44. END;
  45. lastErr := nextErr;
  46. INC(errors)
  47. END StoreError;
  48. PROCEDURE GetLine (VAR pos: INT32;
  49. VAR line: ARRAY OF CHAR;
  50. VAR eof: BOOLEAN);
  51. (* Read a source line. Return empty line if eof *)
  52. VAR
  53. ch: CHAR;
  54. i: CARDINAL;
  55. BEGIN
  56. i := 0; eof := FALSE; ch := CharAt(pos); INC(pos);
  57. WHILE (ch # CR) & (ch # LF) & (ch # EOF) DO
  58. line[i] := ch; INC(i); ch := CharAt(pos); INC(pos);
  59. END;
  60. eof := (i = 0) & (ch = EOF); line[i] := 0C;
  61. IF ch = CR THEN (* check for MsDos *)
  62. ch := CharAt(pos);
  63. IF ch = LF THEN INC(pos); Extra := 0 END
  64. END
  65. END GetLine;
  66. PROCEDURE ErrText (nr: INTEGER; f: File);
  67. (* Error message text for nr on file f (listing and console share it) *)
  68. PROCEDURE Msg (s: ARRAY OF CHAR);
  69. BEGIN
  70. WriteString(f, s)
  71. END Msg;
  72. BEGIN
  73. CASE nr OF
  74. -->Errors
  75. (* add customized cases here *)
  76. | 200: Msg("duplicate identifier")
  77. | 201: Msg("undeclared identifier")
  78. | 202: Msg("module name mismatch")
  79. | 210: Msg("incompatible assignment")
  80. | 211: Msg("arithmetic operand must be numeric")
  81. | 212: Msg("boolean operand required")
  82. | 213: Msg("incompatible comparison")
  83. | 214: Msg("BOOLEAN condition required")
  84. | 215: Msg("not a RECORD type")
  85. | 216: Msg("unknown field")
  86. | 217: Msg("not an ARRAY type")
  87. | 218: Msg("array index must be integer")
  88. | 219: Msg("not a POINTER type")
  89. | 220: Msg("FOR needs integer variable and bounds")
  90. | 221: Msg("not a type name")
  91. | 222: Msg("set operand mismatch")
  92. | 223: Msg("cyclical type definition")
  93. | 224: Msg("ordinal type required")
  94. | 230: Msg("not supported yet")
  95. | 231: Msg("opaque type outside definition")
  96. | 232: Msg("bad RETURN")
  97. ELSE Msg("Error: "); WriteInt(f, nr, 0);
  98. END
  99. END ErrText;
  100. PROCEDURE PrintErr (line: ARRAY OF CHAR; nr, col: INTEGER);
  101. (* Print an error message *)
  102. PROCEDURE Pointer;
  103. VAR
  104. i: INTEGER;
  105. BEGIN
  106. WriteString(lst, "***** ");
  107. i := 0;
  108. WHILE i < col + Extra - 2 DO
  109. IF line[i] = tab
  110. THEN Write(lst, tab)
  111. ELSE Write(lst, ' ')
  112. END;
  113. INC(i)
  114. END;
  115. WriteString(lst, "^ ")
  116. END Pointer;
  117. BEGIN
  118. Pointer;
  119. ErrText(nr, lst);
  120. WriteLn(lst)
  121. END PrintErr;
  122. PROCEDURE PrintListing;
  123. (* Print a source listing with error messages *)
  124. VAR
  125. nextErr: Err;
  126. eof: BOOLEAN;
  127. lnr, errC: INTEGER;
  128. srcPos: INT32;
  129. line: ARRAY [0 .. 255] OF CHAR;
  130. BEGIN
  131. WriteString(lst, "Listing:");
  132. WriteLn(lst); WriteLn(lst);
  133. srcPos := 0; nextErr := firstErr;
  134. GetLine(srcPos, line, eof); lnr := 1; errC := 0;
  135. WHILE ~ eof DO
  136. WriteInt(lst, lnr, 5); WriteString(lst, " ");
  137. WriteString(lst, line); WriteLn(lst);
  138. WHILE (nextErr # NIL) & (nextErr^.line = lnr) DO
  139. PrintErr(line, nextErr^.nr, nextErr^.col); INC(errC);
  140. nextErr := nextErr^.next
  141. END;
  142. GetLine(srcPos, line, eof); INC(lnr);
  143. END;
  144. IF nextErr # NIL THEN
  145. WriteInt(lst, lnr, 5); WriteLn(lst);
  146. WHILE nextErr # NIL DO
  147. PrintErr(line, nextErr^.nr, nextErr^.col); INC(errC);
  148. nextErr := nextErr^.next
  149. END
  150. END;
  151. WriteLn(lst);
  152. WriteInt(lst, errC, 5); WriteString(lst, " error");
  153. IF errC # 1 THEN Write(lst, 's') END;
  154. WriteLn(lst); WriteLn(lst); WriteLn(lst);
  155. END PrintListing;
  156. PROCEDURE PrintConsoleErrors (fname: ARRAY OF CHAR);
  157. (* "file:line:col: message" errors on StdOut, for editor
  158. integration. Columns are 1-based token starts, matching the
  159. listing carets (NOT the col-1 of CRQ.FRM). *)
  160. PROCEDURE WriteNum (n: INTEGER);
  161. (* FileIO.WriteInt pads a leading blank; editors want none. *)
  162. VAR
  163. buf: ARRAY [0 .. 15] OF CHAR;
  164. i: CARDINAL;
  165. BEGIN
  166. IF n < 0 THEN Write(StdOut, "-"); n := -n END;
  167. i := 0;
  168. IF n = 0 THEN buf[0] := "0"; i := 1 END;
  169. WHILE (n > 0) & (i <= HIGH(buf)) DO
  170. buf[i] := CHR(ORD("0") + VAL(CARDINAL, n MOD 10));
  171. n := n DIV 10; INC(i)
  172. END;
  173. WHILE i > 0 DO DEC(i); Write(StdOut, buf[i]) END
  174. END WriteNum;
  175. VAR
  176. e: Err;
  177. BEGIN
  178. e := firstErr;
  179. WHILE e # NIL DO
  180. WriteString(StdOut, fname);
  181. Write(StdOut, ":");
  182. WriteNum(e^.line);
  183. Write(StdOut, ":");
  184. WriteNum(e^.col);
  185. WriteString(StdOut, ": ");
  186. ErrText(e^.nr, StdOut);
  187. WriteLn(StdOut);
  188. e := e^.next
  189. END
  190. END PrintConsoleErrors;
  191. BEGIN
  192. firstErr := NIL; Extra := 1;
  193. END ListHandler;
  194. (* --------------------------- main module ------------------------------- *)
  195. PROCEDURE ChangeExtension (oldName, Ext: ARRAY OF CHAR;
  196. VAR newName: ARRAY OF CHAR);
  197. (* Constructs newName as complete file name by appending ext to oldName
  198. Examples: (assume ext = "EXT")
  199. old.any ==> old.EXT
  200. old ==> old.EXT
  201. This is not a file renaming facility, merely a string manipulation
  202. routine. *)
  203. VAR
  204. i, l: CARDINAL;
  205. BEGIN
  206. Strings.Assign(oldName, newName);
  207. i := LENGTH(oldName); l := i;
  208. WHILE (i > 0) & (oldName[i -1] # '.')
  209. & (oldName[i -1] # '\') & (oldName[i -1] # '/') DO
  210. DEC(i)
  211. END;
  212. IF (i > 0) & (oldName[i-1] = '.') THEN
  213. Strings.Delete(newName, i - 1, l + 1 - i)
  214. END;
  215. IF Ext[0] = '.' THEN Strings.Delete(Ext, 0, 1) END;
  216. Strings.Append(".", newName);
  217. Strings.Append(Ext, newName)
  218. END ChangeExtension;
  219. VAR
  220. sourceName, listName: ARRAY [0 .. 255] OF CHAR;
  221. BEGIN
  222. (* check on correct parameter usage *)
  223. FileIO.NextParameter(sourceName);
  224. IF sourceName[0] = 0C THEN
  225. FileIO.WriteString(FileIO.StdOut, "No input file specified");
  226. HALT
  227. END;
  228. (* open the source file - Scanner.src *)
  229. FileIO.Open(src, sourceName, FALSE);
  230. IF ~ FileIO.Okay THEN
  231. FileIO.WriteString(FileIO.StdOut, "Could not open input file");
  232. FileIO.WriteLn(FileIO.StdOut);
  233. HALT
  234. END;
  235. (* open the output file for the source listing - Scanner.lst *)
  236. ChangeExtension(sourceName, ".LST", listName);
  237. FileIO.Open(lst, listName, TRUE);
  238. IF ~ FileIO.Okay THEN
  239. FileIO.WriteString(FileIO.StdOut, "Could not open listing file");
  240. FileIO.WriteLn(FileIO.StdOut);
  241. (* default Scanner.lst to screen *) lst := FileIO.StdOut;
  242. END;
  243. (* install error reporting procedure - Scanner.Error *)
  244. Error := StoreError;
  245. (* instigate the compilation - Parser.Parse *)
  246. FileIO.WriteString(FileIO.StdOut, "Parsing"); FileIO.WriteLn(FileIO.StdOut);
  247. Parse;
  248. (* generate the source listing on lst file *)
  249. PrintListing;
  250. IF lst # FileIO.StdOut THEN FileIO.Close(lst) END;
  251. (* examine the outcome *)
  252. IF NOT Successful()
  253. THEN
  254. PrintConsoleErrors(sourceName);
  255. FileIO.WriteString(FileIO.StdOut, "Incorrect source");
  256. ELSE
  257. FileIO.WriteString(FileIO.StdOut, "Parsed correctly");
  258. (* ++++++++ Add further activities if required ++++++++++ *)
  259. END;
  260. END -->Grammar.