| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346 |
- MODULE M2c;
- (* Minimal main module for the M2c Modula-2 compiler (Coco/R).
- Assumes the FileIO/Storage I/O libraries and the generated
- <Grammar>S (scanner) and <Grammar>P (parser) modules. *)
- FROM M2cS IMPORT lst, src, errors, Error, CharAt;
- FROM M2cP IMPORT Parse, Successful;
- IMPORT
- Strings, Storage, SYSTEM, FileIO, SymTab, MGen;
- TYPE
- INT32 = FileIO.INT32 (* 32 bit integers needed *);
- MODULE ListHandler;
- (* ------------------- Source Listing and Error handler -------------- *)
- FROM FileIO IMPORT CR, LF, EOF, WriteString, Write, WriteLn, WriteInt, Long0;
- FROM Storage IMPORT ALLOCATE;
- FROM SYSTEM IMPORT TSIZE;
- IMPORT lst, CharAt, errors, INT32;
- EXPORT StoreError, PrintListing;
- TYPE
- Err = POINTER TO ErrDesc;
- ErrDesc = RECORD
- nr, line, col: INTEGER;
- next: Err
- END;
- CONST
- tab = 11C;
- VAR
- firstErr, lastErr: Err;
- Extra: INTEGER;
- PROCEDURE StoreError (nr, line, col: INTEGER; pos: INT32);
- (* Store an error message for later printing *)
- VAR
- nextErr: Err;
- BEGIN
- ALLOCATE(nextErr, TSIZE(ErrDesc));
- nextErr^.nr := nr; nextErr^.line := line; nextErr^.col := col;
- nextErr^.next := NIL;
- IF firstErr = NIL
- THEN firstErr := nextErr
- ELSE lastErr^.next := nextErr
- END;
- lastErr := nextErr;
- INC(errors)
- END StoreError;
- PROCEDURE GetLine (VAR pos: INT32;
- VAR line: ARRAY OF CHAR;
- VAR eof: BOOLEAN);
- (* Read a source line. Return empty line if eof *)
- VAR
- ch: CHAR;
- i: CARDINAL;
- BEGIN
- i := 0; eof := FALSE; ch := CharAt(pos); INC(pos);
- WHILE (ch # CR) & (ch # LF) & (ch # EOF) DO
- line[i] := ch; INC(i); ch := CharAt(pos); INC(pos);
- END;
- eof := (i = 0) & (ch = EOF); line[i] := 0C;
- IF ch = CR THEN (* check for MsDos *)
- ch := CharAt(pos);
- IF ch = LF THEN INC(pos); Extra := 0 END
- END
- END GetLine;
- PROCEDURE PrintErr (line: ARRAY OF CHAR; nr, col: INTEGER);
- (* Print an error message *)
- PROCEDURE Msg (s: ARRAY OF CHAR);
- BEGIN
- WriteString(lst, s)
- END Msg;
- PROCEDURE Pointer;
- VAR
- i: INTEGER;
- BEGIN
- WriteString(lst, "***** ");
- i := 0;
- WHILE i < col + Extra - 2 DO
- IF line[i] = tab
- THEN Write(lst, tab)
- ELSE Write(lst, ' ')
- END;
- INC(i)
- END;
- WriteString(lst, "^ ")
- END Pointer;
- BEGIN
- Pointer;
- CASE nr OF
- 0: Msg("EOF expected")
- | 1: Msg("ident expected")
- | 2: Msg("integer expected")
- | 3: Msg("real expected")
- | 4: Msg("string expected")
- | 5: Msg("'FROM' expected")
- | 6: Msg("'IMPORT' expected")
- | 7: Msg("',' expected")
- | 8: Msg("';' expected")
- | 9: Msg("'BEGIN' expected")
- | 10: Msg("'END' expected")
- | 11: Msg("'CONST' expected")
- | 12: Msg("'TYPE' expected")
- | 13: Msg("'VAR' expected")
- | 14: Msg("'=' expected")
- | 15: Msg("':' expected")
- | 16: Msg("'PROCEDURE' expected")
- | 17: Msg("'(' expected")
- | 18: Msg("')' expected")
- | 19: Msg("'FORWARD' expected")
- | 20: Msg("'MODULE' expected")
- | 21: Msg("'EXPORT' expected")
- | 22: Msg("'.' expected")
- | 23: Msg("'[' expected")
- | 24: Msg("'..' expected")
- | 25: Msg("']' expected")
- | 26: Msg("'ARRAY' expected")
- | 27: Msg("'OF' expected")
- | 28: Msg("'RECORD' expected")
- | 29: Msg("'SET' expected")
- | 30: Msg("'POINTER' expected")
- | 31: Msg("'TO' expected")
- | 32: Msg("'EXIT' expected")
- | 33: Msg("':=' expected")
- | 34: Msg("'IF' expected")
- | 35: Msg("'THEN' expected")
- | 36: Msg("'ELSIF' expected")
- | 37: Msg("'ELSE' expected")
- | 38: Msg("'CASE' expected")
- | 39: Msg("'|' expected")
- | 40: Msg("'WHILE' expected")
- | 41: Msg("'DO' expected")
- | 42: Msg("'REPEAT' expected")
- | 43: Msg("'UNTIL' expected")
- | 44: Msg("'LOOP' expected")
- | 45: Msg("'FOR' expected")
- | 46: Msg("'BY' expected")
- | 47: Msg("'-' expected")
- | 48: Msg("'WITH' expected")
- | 49: Msg("'RETURN' expected")
- | 50: Msg("'NEW' expected")
- | 51: Msg("'DISPOSE' expected")
- | 52: Msg("'WriteInt' expected")
- | 53: Msg("'WriteString' expected")
- | 54: Msg("'^' expected")
- | 55: Msg("'#' expected")
- | 56: Msg("'<>' expected")
- | 57: Msg("'<' expected")
- | 58: Msg("'<=' expected")
- | 59: Msg("'>' expected")
- | 60: Msg("'>=' expected")
- | 61: Msg("'IN' expected")
- | 62: Msg("'+' expected")
- | 63: Msg("'OR' expected")
- | 64: Msg("'*' expected")
- | 65: Msg("'/' expected")
- | 66: Msg("'DIV' expected")
- | 67: Msg("'MOD' expected")
- | 68: Msg("'AND' expected")
- | 69: Msg("'&' expected")
- | 70: Msg("'HIGH' expected")
- | 71: Msg("'NOT' expected")
- | 72: Msg("'~' expected")
- | 73: Msg("'{' expected")
- | 74: Msg("'}' expected")
- | 75: Msg("'DEFINITION' expected")
- | 76: Msg("'IMPLEMENTATION' expected")
- | 77: Msg("not expected")
- | 78: Msg("invalid DefDecl")
- | 79: Msg("invalid MulOp")
- | 80: Msg("invalid Fact")
- | 81: Msg("invalid AddOp")
- | 82: Msg("invalid Rel")
- | 83: Msg("invalid ByLit")
- | 84: Msg("invalid AssignOrCall")
- | 85: Msg("invalid SimpleType")
- | 86: Msg("invalid Type")
- | 87: Msg("invalid ProcedureDecl")
- | 88: Msg("invalid Declaration")
- | 89: Msg("invalid Import")
- | 90: Msg("invalid Unit")
-
- (* add customized cases here *)
- | 200: Msg("duplicate identifier")
- | 201: Msg("undeclared identifier")
- | 202: Msg("module/procedure name mismatch")
- | 210: Msg("incompatible assignment")
- | 211: Msg("arithmetic operand must be numeric")
- | 212: Msg("boolean operand required")
- | 213: Msg("incompatible comparison")
- | 214: Msg("BOOLEAN condition required")
- | 215: Msg("not a RECORD type")
- | 216: Msg("unknown field")
- | 217: Msg("not an ARRAY type")
- | 218: Msg("array index must be integer")
- | 219: Msg("not a POINTER type")
- | 220: Msg("FOR needs integer variable and bounds")
- | 221: Msg("not a type name")
- | 222: Msg("set operand mismatch")
- | 223: Msg("cyclical type definition")
- | 224: Msg("ordinal type required")
- | 230: Msg("not supported in this phase")
- | 231: Msg("procedure forward mismatch or missing body")
- | 232: Msg("bad RETURN")
- | 233: Msg("invalid procedure call")
- ELSE Msg("Error: "); WriteInt(lst, nr, 0);
- END;
- WriteLn(lst)
- END PrintErr;
- PROCEDURE PrintListing;
- (* Print a source listing with error messages *)
- VAR
- nextErr: Err;
- eof: BOOLEAN;
- lnr, errC: INTEGER;
- srcPos: INT32;
- line: ARRAY [0 .. 255] OF CHAR;
- BEGIN
- WriteString(lst, "Listing:");
- WriteLn(lst); WriteLn(lst);
- srcPos := 0; nextErr := firstErr;
- GetLine(srcPos, line, eof); lnr := 1; errC := 0;
- WHILE ~ eof DO
- WriteInt(lst, lnr, 5); WriteString(lst, " ");
- WriteString(lst, line); WriteLn(lst);
- WHILE (nextErr # NIL) & (nextErr^.line = lnr) DO
- PrintErr(line, nextErr^.nr, nextErr^.col); INC(errC);
- nextErr := nextErr^.next
- END;
- GetLine(srcPos, line, eof); INC(lnr);
- END;
- IF nextErr # NIL THEN
- WriteInt(lst, lnr, 5); WriteLn(lst);
- WHILE nextErr # NIL DO
- PrintErr(line, nextErr^.nr, nextErr^.col); INC(errC);
- nextErr := nextErr^.next
- END
- END;
- WriteLn(lst);
- WriteInt(lst, errC, 5); WriteString(lst, " error");
- IF errC # 1 THEN Write(lst, 's') END;
- WriteLn(lst); WriteLn(lst); WriteLn(lst);
- END PrintListing;
- BEGIN
- firstErr := NIL; Extra := 1;
- END ListHandler;
- (* --------------------------- main module ------------------------------- *)
- PROCEDURE ChangeExtension (oldName, Ext: ARRAY OF CHAR;
- VAR newName: ARRAY OF CHAR);
- (* Constructs newName by replacing the extension of oldName with Ext. *)
- VAR
- i, l: CARDINAL;
- BEGIN
- Strings.Assign(oldName, newName);
- i := LENGTH(oldName); l := i;
- WHILE (i > 0) & (oldName[i -1] # '.')
- & (oldName[i -1] # '\') & (oldName[i -1] # '/') DO
- DEC(i)
- END;
- IF (i > 0) & (oldName[i-1] = '.') THEN
- Strings.Delete(newName, i - 1, l + 1 - i)
- END;
- IF Ext[0] = '.' THEN Strings.Delete(Ext, 0, 1) END;
- Strings.Append(".", newName);
- Strings.Append(Ext, newName)
- END ChangeExtension;
- VAR
- sourceName, listName: ARRAY [0 .. 255] OF CHAR;
- failed: BOOLEAN;
- BEGIN
- (* check on correct parameter usage *)
- FileIO.NextParameter(sourceName);
- IF sourceName[0] = 0C THEN
- FileIO.WriteString(FileIO.StdOut, "No input file specified");
- HALT
- END;
- (* one session for all files: definitions, then
- implementations, then the program (see M2c.atg) *)
- SymTab.Init;
- MGen.OpenModule("");
- (* install error reporting procedure - Scanner.Error *)
- Error := StoreError;
- failed := FALSE;
- LOOP
- IF sourceName[0] = 0C THEN EXIT END;
- (* open the source file - Scanner.src *)
- FileIO.Open(src, sourceName, FALSE);
- IF ~ FileIO.Okay THEN
- FileIO.WriteString(FileIO.StdOut, "Could not open input file");
- FileIO.WriteLn(FileIO.StdOut);
- HALT
- END;
- (* open the output file for the source listing - Scanner.lst *)
- ChangeExtension(sourceName, ".LST", listName);
- FileIO.Open(lst, listName, TRUE);
- IF ~ FileIO.Okay THEN
- FileIO.WriteString(FileIO.StdOut, "Could not open listing file");
- FileIO.WriteLn(FileIO.StdOut);
- (* default Scanner.lst to screen *) lst := FileIO.StdOut;
- END;
- (* instigate the compilation - Parser.Parse *)
- FileIO.WriteString(FileIO.StdOut, "Parsing ");
- FileIO.WriteString(FileIO.StdOut, sourceName);
- FileIO.WriteLn(FileIO.StdOut);
- Parse;
- (* generate the source listing on lst file *)
- PrintListing;
- IF lst # FileIO.StdOut THEN FileIO.Close(lst) END;
- (* fail fast: later files build on this one's tables *)
- IF NOT Successful()
- THEN
- FileIO.WriteString(FileIO.StdOut, "Incorrect source");
- FileIO.WriteLn(FileIO.StdOut);
- failed := TRUE;
- EXIT
- END;
- FileIO.NextParameter(sourceName);
- END;
- (* examine the outcome *)
- IF NOT failed THEN
- FileIO.WriteString(FileIO.StdOut, "Parsed correctly");
- END;
- END M2c.
|