packages feed

language-Modula2-0.1: examples/Modula-2_Libraries/C.-Lins_Modula-2_Software_Component_Library/Vol3/EBNF/EBNFSCAN.MOD

IMPLEMENTATION MODULE EBNFScanner;
(*====================================================================
    Version  : 1.0d2  06 Feb 1989  C. Lins
    Compiler : JPI's TopSpeed Modula-2 Compiler
    Component: EBNFScanner

    INTRODUCTION
    This module defines a scanner for EBNF.

    REVISION HISTORY
    v1.0d1  04 Feb 1989  C. Lins:
      Initial implementation derived from Wirth's Programming in
                        Modula-2, 4th edition, pp 96-100.
    v1.0d2  06 Feb 1989  C. Lins:
      Improved (speeded up) construction of unbounded string by
      creating all at once rather than adding a character at a time.
    v1.1    02 Dec 1989  I. S. C. Houston
      Adapted to JPI TopSpeed compiler and library
      and changed to take the language definition input
      from a named file.
      ====================================================================*)

FROM    CharItems IMPORT
        (*--cons*)      NullItem,
        (*--type*)      Item;

FROM    StrCSUMI IMPORT
        (*--cons*)      NullString,
        (*--type*)      String,
        (*--proc*)      Construct;

FROM    FIO IMPORT
        (*--var*)       EOF,
        (*--proc*)      RdChar;

FROM    IO    IMPORT
        (*--proc*)      WrChar, WrCharRep, WrStr, WrInt, WrLn;

IMPORT ASCII;

VAR     ch : CHAR;
        currentChar : INTEGER;
        colHiWater: INTEGER;
        errColIndex: INTEGER;

CONST   LineWidth = 256;
VAR     line: ARRAY [0..LineWidth-1] OF CHAR;

CONST   kMaxIdentifier = 30;

PROCEDURE GetLine;
BEGIN
        IF (errColIndex > 0) THEN
                (*--terminate active error report line*)
                WrLn;
                errColIndex := 0;
        END (*--if*);

        (*--ignore linefeed*)
        REPEAT ch := RdChar(source)
        UNTIL (ch # ASCII.lf);

        IF EOF OR (ch = ASCII.sub) THEN
                line[0] := ASCII.del;
                colHiWater := 1
        ELSE
                (*--not at end of file*)
                INC(lineNo);
                WrInt(lineNo, 5);
                WrChar(" ");
                colHiWater := 0;

                LOOP
                        WrChar(ch);
                        line[colHiWater] := ch;
                        INC(colHiWater);

                        ch := RdChar(source);
                        IF EOF THEN ch := ASCII.nul END;

                        IF (ch = ASCII.cr) OR
                           (ch = ASCII.nul) THEN
                                EXIT (*--loop*)
                        END (*--if*);

                END (*--loop*);
                WrLn
        END (*--if*);
END GetLine;
(*--------------------*)

PROCEDURE GetChar;
BEGIN
        WHILE (colHiWater = currentChar) DO
                currentChar := 0;
                GetLine;
        END (*--while*);
        ch := line[currentChar];
        INC(currentChar);
END GetChar;
(*--------------------*)


PROCEDURE GetIdentifier;

VAR     theString : ARRAY [0..kMaxIdentifier] OF Item;
        index     : INTEGER;

BEGIN
        theSymbol := literal;
        index := 0;
        REPEAT
                theString[index] := ch;
                INC(index);
                IF (ch > "Z") THEN
                        theSymbol := identifier;
                END (*--if*);
                GetChar;
        UNTIL (CAP(ch) < "A") OR (CAP(ch) > "Z");
        theString[index] := NullItem; (*-- terminate the Modula string *)
        theIdent := NullString; (*-- make sure the previous identifier isn't
                                  -- automatically deallocated *)
        Construct(theIdent, theString);
END GetIdentifier;
(*--------------------*)

PROCEDURE GetLiteral (    termCh : CHAR);

VAR             theString : ARRAY [0..kMaxIdentifier] OF Item;
                index     : INTEGER;

BEGIN
        theSymbol := literal;
        GetChar;
        index := 0;
        WHILE (ch # termCh) DO
                theString[index] := ch;
                INC(index);
                GetChar;
        END (*--while*);
        theString[index] := NullItem; (*-- terminate the Modula string *)
        theIdent := NullString; (*-- make sure the previous identifier isn't
                                  -- automatically deallocated *)
        Construct(theIdent, theString);
        GetChar;
END GetLiteral;
(*--------------------*)


PROCEDURE WrSymbol;
BEGIN
        CASE theSymbol OF
        identifier:    WrStr("identifier");
        | literal:     WrStr("literal");
        | lparen:      WrStr("lparen");
        | rparen:      WrStr("rparen");
        | lbrace:      WrStr("lbrace");
        | rbrace:      WrStr("rbrace");
        | lbraket:     WrStr("lbraket");
        | rbraket:     WrStr("rbraket");
        | bar:         WrStr("bar");
        | eql:         WrStr("eql");
        | period:      WrStr("period");
        ELSE           WrStr("other");
        END (*--case*);
        WrLn;
END WrSymbol;

PROCEDURE       GetSymbol;
BEGIN
        WHILE (ch = ASCII.space) OR
              (ch = ASCII.cr) DO
                GetChar;
        END (*--while*);
        IF (ch = ASCII.slash) THEN
                SkipLine;
                WHILE (ch = ASCII.space) OR
                      (ch = ASCII.cr) DO
                        GetChar;
                END (*--while*);
        END (*--if*);

        IF (CAP(ch) >= "A") & (CAP(ch) <= "Z") THEN
                GetIdentifier;
        ELSIF (ch = ASCII.quote) OR (ch = ASCII.quotequote) THEN
                GetLiteral(ch);
        ELSIF (ch = ASCII.equalsign) THEN
                theSymbol := eql;
                GetChar;
        ELSIF (ch = ASCII.lparen) THEN
                theSymbol := lparen;
                GetChar;
        ELSIF (ch = ASCII.rparen) THEN
                theSymbol := rparen;
                GetChar;
        ELSIF (ch = ASCII.lbracket) THEN
                theSymbol := lbraket;
                GetChar;
        ELSIF (ch = ASCII.rbracket) THEN
                theSymbol := rbraket;
                GetChar;
        ELSIF (ch = ASCII.lbrace) THEN
                theSymbol := lbrace;
                GetChar;
        ELSIF (ch = ASCII.rbrace) THEN
                theSymbol := rbrace;
                GetChar;
        ELSIF (ch = ASCII.bar) THEN
                theSymbol := bar;
                GetChar;
        ELSIF (ch = ASCII.period) THEN
                theSymbol := period;
                GetChar;
        ELSIF (ch = ASCII.del) THEN
                theSymbol := other;
        ELSE
                theSymbol := other;
                GetChar;
        END (*--if*);
END GetSymbol;
(*--------------------*)

PROCEDURE       MarkError (    errorNo : INTEGER);
BEGIN
        errorsFound := TRUE;
        IF (errColIndex = 0) THEN (*--start error report line*)
                WrChar("*");
                WrCharRep(" ",3);
        END (*--if*);
        WrCharRep(" ",currentChar);
        WrChar("^");
        WrInt(errorNo, 1);
        INC(errColIndex, 2);
END MarkError;
(*--------------------*)

PROCEDURE SkipLine;
VAR thisLineNo: INTEGER;
BEGIN
        thisLineNo := lineNo;
        WHILE (thisLineNo = lineNo) DO
                GetChar
        END (*--while*);
        GetChar;
END SkipLine;
(*--------------------*)

BEGIN
        theIdent       := NullString;
        theSymbol      := other;
        errorsFound    := FALSE;
        lineNo         := 0;
        currentChar    := 0;
        colHiWater     := 0;
        errColIndex    := 0;
        ch             := " ";

END EBNFScanner.