一个Modula-2语言分析器

源代码在线查看: mod2.frm

软件大小: 787 K
上传用户: zhangtaoai007
关键词: Modula 语言 分析器
下载地址: 免注册下载 普通下载 VIP

相关代码

				MODULE -->Grammar;
				(* Simple Modula-2 pretty printer program *)
				
				  FROM -->Scanner IMPORT lst, src, errors, Error, CharAt;
				  FROM -->Parser IMPORT Parse, Successful;
				  IMPORT
				    Prettier, ProgramArgs, Strings,
				    SYSTEM, Storage, TextIO, WholeIO, StdChans, SeqFile, ChanConsts, IOChan;
				    (* and any others needed *)
				
				  TYPE
				    INT32 = INTEGER (* 32 bit integers needed *);
				
				  MODULE ListHandler;
				  (* ------------------- Source Listing and Error handler -------------- *)
				    IMPORT WholeIO, TextIO, Storage, SYSTEM;
				    IMPORT lst, CharAt, errors, INT32;
				    EXPORT StoreError, PrintListing;
				
				    CONST
				      CR = 15C;
				      LF = 12C;
				      EOF = 0C;
				
				    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
				        Storage.ALLOCATE(nextErr, SYSTEM.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
				          TextIO.WriteString(lst, s)
				        END Msg;
				
				      PROCEDURE Pointer;
				        VAR
				          i: INTEGER;
				        BEGIN
				          TextIO.WriteString(lst, "*****  ");
				          i := 0;
				          WHILE i < col + Extra - 2 DO
				            IF line[i] = tab
				              THEN TextIO.WriteChar(lst, tab)
				              ELSE TextIO.WriteChar(lst, ' ')
				            END;
				            INC(i)
				          END;
				          TextIO.WriteString(lst, "^ ")
				        END Pointer;
				
				      BEGIN
				        Pointer;
				        CASE nr OF
				        -->Errors
				        (* add customized cases here *)
				        ELSE Msg("Error: "); WholeIO.WriteInt(lst, nr, 0);
				        END;
				        TextIO.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
				        TextIO.WriteString(lst, "Listing:");
				        TextIO.WriteLn(lst); TextIO.WriteLn(lst);
				        srcPos := 0; nextErr := firstErr;
				        GetLine(srcPos, line, eof); lnr := 1; errC := 0;
				        WHILE ~ eof DO
				          WholeIO.WriteInt(lst, lnr, 5); TextIO.WriteString(lst, "  ");
				          TextIO.WriteString(lst, line); TextIO.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
				          WholeIO.WriteInt(lst, lnr, 5); TextIO.WriteLn(lst);
				          WHILE nextErr # NIL DO
				            PrintErr(line, nextErr^.nr, nextErr^.col); INC(errC);
				            nextErr := nextErr^.next
				          END
				        END;
				        TextIO.WriteLn(lst);
				        WholeIO.WriteInt(lst, errC, 5); TextIO.WriteString(lst, " error");
				        IF errC # 1 THEN TextIO.WriteChar(lst, "s") END;
				        TextIO.WriteLn(lst); TextIO.WriteLn(lst); TextIO.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, resultsName: ARRAY [0 .. 255] OF CHAR;
				    StdOut: IOChan.ChanId;
				    res: ChanConsts.OpenResults;
				
				  BEGIN
				    StdOut := StdChans.StdOutChan();
				    TextIO.WriteString(StdOut, "Modula-2 pretty printer");
				    TextIO.WriteLn(StdOut);
				
				    (* check on correct parameter usage *)
				    (* you may need ProgramArgs.NextArg(); to skip program name *)
				    IF ProgramArgs.IsArgPresent()
				      THEN
				        TextIO.ReadToken(ProgramArgs.ArgChan(), sourceName);
				      ELSE
				        TextIO.WriteString(StdOut, "No input file specified");
				        HALT
				    END;
				
				    (* open the source file - Scanner.src *)
				    SeqFile.OpenRead(src, sourceName, SeqFile.raw + SeqFile.old + SeqFile.read, res);
				    IF res # SeqFile.opened THEN
				      TextIO.WriteString(StdOut, "Could not open input file");
				      TextIO.WriteLn(StdOut);
				      HALT
				    END;
				
				    ChangeExtension(sourceName, ".NEW", resultsName);
				    SeqFile.OpenWrite(Prettier.results, resultsName,
				                      SeqFile.raw + SeqFile.text + SeqFile.old, res);
				    IF res # SeqFile.opened THEN
				      TextIO.WriteString(StdOut, "Could not open listing file");
				      TextIO.WriteLn(StdOut);
				      Prettier.results := StdOut;
				    END;
				
				    (* install error reporting procedure - Scanner.Error *)
				    Error := StoreError;
				
				    (* instigate the compilation - Parser.Parse *)
				    TextIO.WriteString(StdOut, "Parsing"); TextIO.WriteLn(StdOut);
				    Parse;
				
				    (* examine the outcome *)
				    IF NOT Successful()
				      THEN
				        (* open the output file for the source listing - Scanner.lst *)
				        ChangeExtension(sourceName, ".LST", listName);
				        SeqFile.OpenWrite(lst, listName, SeqFile.write + SeqFile.old, res);
				        IF res # SeqFile.opened THEN
				          TextIO.WriteString(StdOut, "Could not open listing file");
				          TextIO.WriteLn(StdOut);
				          (* default Scanner.lst to screen *) lst := StdOut;
				        END;
				        (* generate the source listing on lst file *)
				        PrintListing;
				        IF lst # StdOut THEN SeqFile.Close(lst) END;
				        TextIO.WriteString(StdOut, "Incorrect source - see ");
				        TextIO.WriteString(StdOut, listName);
				      ELSE
				        TextIO.WriteString(StdOut, "Parsed correctly - see ");
				        TextIO.WriteString(StdOut, resultsName);
				    END;
				    IF Prettier.results # StdOut THEN
				      SeqFile.Close(Prettier.results)
				    END;
				  END -->Grammar.
							

相关资源