(* bnflex.mod provides a simple lexical package for pg. Copyright (C) 2001-2023 Free Software Foundation, Inc. Contributed by Gaius Mulley . This file is part of GNU Modula-2. GNU Modula-2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNU Modula-2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Modula-2; see the file COPYING3. If not see . *) IMPLEMENTATION MODULE bnflex ; FROM PushBackInput IMPORT GetCh, PutCh, PutString, WarnError ; FROM SymbolKey IMPORT SymbolTree, InitTree, PutSymKey, GetSymKey ; FROM ASCII IMPORT tab, lf, nul ; FROM Debug IMPORT Halt ; FROM NameKey IMPORT Name, LengthKey, MakeKey, GetKey, WriteKey, NulName ; FROM StrLib IMPORT StrEqual, StrLen ; FROM FIO IMPORT File, IsNoError ; FROM StrCase IMPORT Lower ; FROM StdIO IMPORT Write ; IMPORT PushBackInput ; CONST MaxNameLength = 8192 ; VAR f : File ; ReservedWords: SymbolTree ; CurrentToken : Name ; CurrentType : TokenType ; Debugging , InQuote : BOOLEAN ; QuoteChar : CHAR ; (* OpenSource - Attempts to open the source file, a. The success of the operation is returned. *) PROCEDURE OpenSource (a: ARRAY OF CHAR) : BOOLEAN ; BEGIN f := PushBackInput.Open(a) ; RETURN( IsNoError(f) ) END OpenSource ; (* CloseSource - Closes the current open file. *) PROCEDURE CloseSource ; BEGIN PushBackInput.Close(f) END CloseSource ; (* GetChar - returns the current character on the input stream. *) PROCEDURE GetChar () : CHAR ; BEGIN RETURN( PushBackInput.GetCh(f) ) END GetChar ; (* PutChar - pushes a character onto the push back stack, it also returns the character which has been pushed. *) PROCEDURE PutChar (ch: CHAR) : CHAR ; BEGIN RETURN( PushBackInput.PutCh(ch) ) END PutChar ; (* EatChar - consumes the next character in the input. *) PROCEDURE EatChar ; BEGIN IF PushBackInput.GetCh(f)=nul THEN END END EatChar ; (* IsWhite - returns TRUE if, ch, is a space or a tab. *) PROCEDURE IsWhite (ch: CHAR) : BOOLEAN ; BEGIN RETURN( (ch=' ') OR (ch=tab) OR (ch=lf) ) END IsWhite ; (* SkipWhite - skips all white space. *) PROCEDURE SkipWhite ; BEGIN WHILE IsWhite(PutChar(GetChar())) DO EatChar END END SkipWhite ; (* SkipUntilEoln - skips until a lf is seen. It consumes the lf. *) PROCEDURE SkipUntilEoln ; BEGIN WHILE (PutChar(GetChar())#lf) AND (PutChar(GetChar())#nul) DO EatChar END ; IF PutChar(GetChar())=lf THEN EatChar END END SkipUntilEoln ; (* SkipUntilWhite - skips all characters until white space is seen. *) PROCEDURE SkipUntilWhite ; BEGIN WHILE ((NOT IsWhite(PutChar(GetChar()))) AND (PutChar(GetChar())#nul)) OR (PutChar(GetChar())=lf) DO EatChar END END SkipUntilWhite ; (* IsReserved - returns TRUE if the name is a reserved word. *) PROCEDURE IsReserved (name: Name) : BOOLEAN ; BEGIN RETURN (GetSymKey(ReservedWords, name)#0) END IsReserved ; (* GetCurrentTokenType - returns the type of current token. *) PROCEDURE GetCurrentTokenType () : TokenType ; BEGIN RETURN( CurrentType ) END GetCurrentTokenType ; (* GetCurrentToken - returns the NameKey of the current token. *) PROCEDURE GetCurrentToken () : Name ; BEGIN RETURN( CurrentToken ) END GetCurrentToken ; (* SkipComments - consumes comments. *) PROCEDURE SkipComments ; BEGIN SkipWhite ; WHILE PutChar(GetChar())='-' DO IF (GetChar()='-') AND (PutChar(GetChar())='-') THEN (* found comment, skip it *) SkipUntilEoln ; SkipWhite ELSE (* no second '-' found thus restore first '-' *) IF PutChar('-')='-' THEN END ; RETURN END END END SkipComments ; (* WriteToken - *) PROCEDURE WriteToken ; BEGIN WriteKey(CurrentToken) ; Write(' ') END WriteToken ; (* AdvanceToken - advances to the next token. *) PROCEDURE AdvanceToken ; VAR a: ARRAY [0..MaxNameLength] OF CHAR ; i: CARDINAL ; BEGIN i := 0 ; IF InQuote THEN IF CurrentType=literaltok THEN IF PutChar(GetChar())=QuoteChar THEN a[i] := GetChar() ; InQuote := FALSE ; INC(i) ; a[i] := nul ; CurrentToken := MakeKey(a) ; CurrentType := VAL(TokenType, GetSymKey(ReservedWords, CurrentToken)) ELSE IF QuoteChar='"' THEN WarnError('missing " at the end of a literal') ELSE WarnError("missing ' at the end of a literal") END ; InQuote := FALSE (* to avoid a contineous list of the same error message *) END ELSE WHILE (i') , ORD(gretok)) ; PutSymKey(ReservedWords, MakeKey('error') , ORD(errortok)) ; PutSymKey(ReservedWords, MakeKey('tokenfunc') , ORD(tfunctok)) ; PutSymKey(ReservedWords, MakeKey('symfunc') , ORD(symfunctok)) ; PutSymKey(ReservedWords, MakeKey("'") , ORD(squotetok)) ; PutSymKey(ReservedWords, MakeKey('"') , ORD(dquotetok)) ; PutSymKey(ReservedWords, MakeKey('module') , ORD(moduletok)) ; PutSymKey(ReservedWords, MakeKey('begin') , ORD(begintok)) ; PutSymKey(ReservedWords, MakeKey('rules') , ORD(rulestok)) ; PutSymKey(ReservedWords, MakeKey('end') , ORD(endtok)) ; PutSymKey(ReservedWords, MakeKey('declaration'), ORD(declarationtok)) ; PutSymKey(ReservedWords, MakeKey('token') , ORD(tokentok)) ; PutSymKey(ReservedWords, MakeKey('special') , ORD(specialtok)) ; PutSymKey(ReservedWords, MakeKey('first') , ORD(firsttok)) ; PutSymKey(ReservedWords, MakeKey('follow') , ORD(followtok)) ; PutSymKey(ReservedWords, MakeKey('epsilon') , ORD(epsilontok)) ; PutSymKey(ReservedWords, MakeKey('BNF') , ORD(BNFtok)) ; PutSymKey(ReservedWords, MakeKey('FNB') , ORD(FNBtok)) ; CurrentToken := NulName ; CurrentType := identtok ; InQuote := FALSE END Init ; BEGIN Init END bnflex. (* * Local variables: * compile-command: "../bin2/m2f -quiet -g -verbose -M \"../libs ../gm2s\" bnflex.mod" * End: *)