|
@@ -0,0 +1,245 @@
|
|
|
|
|
+MODULE -->Grammar;
|
|
|
|
|
+(* This is an example of a rudimentary main module for use with COCO/R.
|
|
|
|
|
+ It assumes the FileIO/Storage I/O libraries (as supplied with this
|
|
|
|
|
+ project) are available.
|
|
|
|
|
+ The auxiliary modules <Grammar>S (scanner) and <Grammar>P (parser)
|
|
|
|
|
+ are assumed to have been constructed with COCO/R compiler generator. *)
|
|
|
|
|
+
|
|
|
|
|
+ FROM -->Scanner IMPORT lst, src, errors, Error, CharAt;
|
|
|
|
|
+ FROM -->Parser IMPORT Parse, Successful;
|
|
|
|
|
+ IMPORT
|
|
|
|
|
+ Strings, Storage, SYSTEM, FileIO;
|
|
|
|
|
+ (* and any others needed *)
|
|
|
|
|
+
|
|
|
|
|
+ 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;
|
|
|
|
|
+ TabSize = 8;
|
|
|
|
|
+
|
|
|
|
|
+ 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 WriteLine (line: ARRAY OF CHAR);
|
|
|
|
|
+ VAR
|
|
|
|
|
+ i, col, j: CARDINAL;
|
|
|
|
|
+ BEGIN
|
|
|
|
|
+ col := 1;
|
|
|
|
|
+ i := 0;
|
|
|
|
|
+ WHILE line[i] # 0C DO
|
|
|
|
|
+ IF line[i] = tab
|
|
|
|
|
+ THEN
|
|
|
|
|
+ FOR j := 1 TO TabSize - (col MOD TabSize) + 1 DO
|
|
|
|
|
+ Write(lst, ' '); INC(col);
|
|
|
|
|
+ END
|
|
|
|
|
+ ELSE Write(lst, line[i]); INC(col)
|
|
|
|
|
+ END;
|
|
|
|
|
+ INC(i)
|
|
|
|
|
+ END;
|
|
|
|
|
+ WriteLn(lst);
|
|
|
|
|
+ END WriteLine;
|
|
|
|
|
+
|
|
|
|
|
+ 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;
|
|
|
|
|
+ c, j: CARDINAL;
|
|
|
|
|
+ BEGIN
|
|
|
|
|
+ WriteString(lst, "***** ");
|
|
|
|
|
+ i := 0; c := 1;
|
|
|
|
|
+ WHILE i < col + Extra - 2 DO
|
|
|
|
|
+ IF line[i] = tab
|
|
|
|
|
+ THEN
|
|
|
|
|
+ FOR j := 1 TO TabSize - (c MOD TabSize) + 1 DO
|
|
|
|
|
+ Write(lst, ' '); INC(c);
|
|
|
|
|
+ END
|
|
|
|
|
+ ELSE Write(lst, ' '); INC(c)
|
|
|
|
|
+ END;
|
|
|
|
|
+ INC(i)
|
|
|
|
|
+ END;
|
|
|
|
|
+ WriteString(lst, "^ ")
|
|
|
|
|
+ END Pointer;
|
|
|
|
|
+
|
|
|
|
|
+ BEGIN
|
|
|
|
|
+ Pointer;
|
|
|
|
|
+ CASE nr OF
|
|
|
|
|
+ -->Errors
|
|
|
|
|
+ (* add customized cases here *)
|
|
|
|
|
+ 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, " ");
|
|
|
|
|
+ WriteLine(line);
|
|
|
|
|
+ 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 as complete file name by appending ext to oldName
|
|
|
|
|
+ Examples: (assume ext = "EXT")
|
|
|
|
|
+ old.any ==> old.EXT
|
|
|
|
|
+ old ==> old.EXT
|
|
|
|
|
+ This is not a file renaming facility, merely a string manipulation
|
|
|
|
|
+ routine. *)
|
|
|
|
|
+ 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;
|
|
|
|
|
+
|
|
|
|
|
+ BEGIN
|
|
|
|
|
+ (* check on correct parameter usage *)
|
|
|
|
|
+ FileIO.NextParameter(sourceName);
|
|
|
|
|
+ IF sourceName[0] = 0C THEN
|
|
|
|
|
+ FileIO.WriteString(FileIO.StdOut, "No input file specified");
|
|
|
|
|
+ HALT
|
|
|
|
|
+ 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;
|
|
|
|
|
+
|
|
|
|
|
+ (* install error reporting procedure - Scanner.Error *)
|
|
|
|
|
+ Error := StoreError;
|
|
|
|
|
+
|
|
|
|
|
+ (* instigate the compilation - Parser.Parse *)
|
|
|
|
|
+ FileIO.WriteString(FileIO.StdOut, "Parsing"); FileIO.WriteLn(FileIO.StdOut);
|
|
|
|
|
+ Parse;
|
|
|
|
|
+
|
|
|
|
|
+ (* generate the source listing on lst file *)
|
|
|
|
|
+ PrintListing;
|
|
|
|
|
+ IF lst # FileIO.StdOut THEN FileIO.Close(lst) END;
|
|
|
|
|
+
|
|
|
|
|
+ (* examine the outcome *)
|
|
|
|
|
+ IF NOT Successful()
|
|
|
|
|
+ THEN
|
|
|
|
|
+ FileIO.WriteString(FileIO.StdOut, "Incorrect source");
|
|
|
|
|
+ ELSE
|
|
|
|
|
+ FileIO.WriteString(FileIO.StdOut, "Parsed correctly");
|
|
|
|
|
+ (* ++++++++ Add further activities if required ++++++++++ *)
|
|
|
|
|
+ END;
|
|
|
|
|
+ END -->Grammar.
|