packages feed

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

MODULE EBNF;
(*====================================================================
    Version  : 1.00  04 Feb 1989  C. Lins
    Compiler : JPI TopSpeed Modula-2 Compiler
    Component: EBNF

    INTRODUCTION
    This is the main module to the tool EBNF. It reads a language
    specification in EBNF format from a file. It writes to standard
    output two lists: one of terminal symbols, the other of nonterminals.

    The input source is checked for conformity with the EBNF syntax. The
    errors that can result from an ill-formed specification are listed
    in the procedure WrErrorCodes in this module.

    REVISION HISTORY
    v1.00  04 Feb 1989  C. Lins:
      Initial implementation derived from Wirth's Programming in
                        Modula-2, 4th edition, pp 96-100.
    v1.01  06 Dec 1989  Iain Houston:
      Adapted to JPI TopSpeed Modula2 compiler.
      Improved error reporting.
====================================================================*)

FROM    EBNFScanner IMPORT
        (*--type*)      Symbol,
        (*--var *)      source, theSymbol, lineNo, theIdent, errorsFound,
        (*--proc*)      GetSymbol, MarkError, SkipLine;

FROM    EBNFTable IMPORT
        (*--type*)      SymbolTable,
        (*--proc*)      Create, Record, Tabulate, Overflow;

FROM    FIO IMPORT
        (*--proc*)      AssignBuffer,
        (*--const*)     BufferOverhead;

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

FROM    FIO IMPORT
        (*--var*)      EOF,
        (*--proc*)     Exists, Open, Close, File, RdChar;

FROM    Lib IMPORT
        (*--proc*)      ParamStr;

VAR     terminals       : SymbolTable;
        nonTerminals    : SymbolTable;
        fileName        : ARRAY [0..64] OF CHAR;


PROCEDURE SkipToSymbol (    errorNo : INTEGER (*--in   *));
BEGIN
        MarkError(errorNo);
        WHILE (theSymbol < lparen) OR (theSymbol > period) DO
                GetSymbol;
        END (*--while*);
END SkipToSymbol;

PROCEDURE Expression;

        PROCEDURE Term;

                PROCEDURE Factor;
                BEGIN
                        IF (theSymbol = identifier) THEN
                                Record(nonTerminals, theIdent, lineNo);
                                GetSymbol;

                        ELSIF (theSymbol = literal) THEN
                                Record(terminals, theIdent, lineNo);
                                GetSymbol;

                        ELSIF (theSymbol = lparen) THEN
                                GetSymbol;
                                Expression;
                                IF (theSymbol = rparen) THEN
                                        GetSymbol;
                                ELSE
                                        SkipToSymbol(2);
                                END (*--if*);

                        ELSIF (theSymbol = lbraket) THEN
                                GetSymbol;
                                Expression;
                                IF (theSymbol = rbraket) THEN
                                        GetSymbol;
                                ELSE
                                        SkipToSymbol(3);
                                END (*--if*);

                        ELSIF (theSymbol = lbrace) THEN
                                GetSymbol;
                                Expression;
                                IF (theSymbol = rbrace) THEN
                                        GetSymbol;
                                ELSE
                                        SkipToSymbol(4);
                                END (*--if*);

                        ELSE
                                SkipToSymbol(5);
                        END (*--if*);
                END Factor;

        BEGIN           (*-- Term --*)
                Factor;
                WHILE (theSymbol < bar) DO
                        Factor;
                END (*--while*);
        END Term;

BEGIN           (*-- Expression --*)
        Term;
        WHILE (theSymbol = bar) DO
                GetSymbol;
                Term;
        END (*--while*);
END Expression;

PROCEDURE Production;
BEGIN
        (*-- theSymbol = identifier --*)
        Record(nonTerminals, theIdent, -lineNo);
        GetSymbol;
        IF (theSymbol = eql) THEN
                GetSymbol;
        ELSE
                SkipToSymbol(7);
        END (*--if*);
        Expression;
        IF (theSymbol # period) THEN
                MarkError(8);
                SkipLine;
        END (*--if*);
        GetSymbol;
END Production;

PROCEDURE WrErrorCodes;
BEGIN
        WrLn;WrLn;WrLn;
        WrStr('Syntax errors were found. Errors were coded as follows:');
        WrLn;WrLn;
        WrStr('1.  <reserved>                                      ');WrLn;
        WrStr('2.  Missing right parentheses                       ');WrLn;
        WrStr('3.  Missing right bracket                           ');WrLn;
        WrStr('4.  Missing right brace                             ');WrLn;
        WrStr('5.  Identifier, literal, "(", "[", or "{" expected  ');WrLn;
        WrStr('6.  Symbol table overflow                           ');WrLn;
        WrStr('7.  Equal sign expected                             ');WrLn;
        WrStr('8.  Period expected                                 ');WrLn
END WrErrorCodes;

PROCEDURE Main;
BEGIN   (*--Main*)
        terminals   := Create();
        nonTerminals:= Create();

        GetSymbol;
        WHILE (theSymbol = identifier) & ~Overflow() DO
                Production;
        END (*--while*);
        IF Overflow() THEN
                WrLn;
                WrStr("### EBNF: Symbol Table Overflow");
                WrLn;
        END (*--if*);
        WrLn;WrLn;
        WrStr("Non-Terminal Symbols");WrLn;
        Tabulate(nonTerminals);WrLn;
        WrStr("Terminal Symbols");WrLn;
        Tabulate(terminals);
        IF errorsFound THEN WrErrorCodes END
END Main;

CONST   toolName= "EBNF Tool";
CONST   version = "  OS/2 v1.1  02 Dec 1989";
CONST   author1 = "  by Iain Houston,";
CONST   author2 = "  after Chuck Lins.";

VAR sBuff: ARRAY [0..(2*512+BufferOverhead)] OF BYTE;

BEGIN
        WrStr(toolName);
        WrStr(version);WrLn;
        WrStr(author1);WrLn;
        WrStr(author2);WrLn;
        WrLn;

        ParamStr( fileName, 1);   (*--find fileName from invocation argument*)
        IF Exists( fileName ) THEN
                source := Open( fileName );
                WrStr('Reading a language definition from ');
                WrStr(fileName);
                WrLn;WrLn;
                AssignBuffer(source, sBuff);
                Main;
                Close(source);
                WrLn;
                WrStr("Normal program termination.")
        ELSE
                WrStr("Couldn't find the file ");
                WrStr(fileName);
                WrLn;
                WrStr("Program terminated.");
        END     (*--IF Exists*)
END EBNF.