blob: a1dc169e0216356d7c2d3fda1fd683012cec3edb [file] [log] [blame]
(* bnflex.mod provides a simple lexical package for pg.
Copyright (C) 2001-2026 Free Software Foundation, Inc.
Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.
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
<http://www.gnu.org/licenses/>. *)
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<MaxNameLength) AND (PutChar(GetChar())#nul) AND
(PutChar(GetChar())#lf) AND (PutChar(GetChar())#QuoteChar) DO
a[i] := GetChar() ;
INC(i)
END ;
IF PutChar(GetChar())=QuoteChar
THEN
CurrentType := literaltok ;
a[i] := nul ;
CurrentToken := MakeKey(a)
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
END
ELSE
SkipComments ;
IF (PutChar(GetChar())='"') OR (PutChar(GetChar())="'")
THEN
a[i] := GetChar() ;
QuoteChar := a[i] ;
INC(i) ;
InQuote := TRUE ;
a[i] := nul ;
CurrentToken := MakeKey(a) ;
CurrentType := VAL(TokenType, GetSymKey(ReservedWords, CurrentToken))
ELSE
WHILE (i<MaxNameLength) AND (PutChar(GetChar())#nul) AND
(PutChar(GetChar())#lf) AND (PutChar(GetChar())#QuoteChar) AND
(NOT IsWhite(PutChar(GetChar()))) DO
a[i] := GetChar() ;
INC(i)
END ;
a[i] := nul ;
CurrentToken := MakeKey(a) ;
IF GetSymKey(ReservedWords, CurrentToken)=0
THEN
CurrentType := identtok
ELSE
CurrentType := VAL(TokenType, GetSymKey(ReservedWords, CurrentToken))
END
END
END ;
IF Debugging
THEN
WriteToken
END
END AdvanceToken ;
(*
SymIs - if t is equal to the current token the next token is read
and true is returned, otherwise false is returned.
*)
PROCEDURE SymIs (t: TokenType) : BOOLEAN ;
BEGIN
IF CurrentType=t
THEN
AdvanceToken ;
RETURN( TRUE )
ELSE
RETURN( FALSE )
END
END SymIs ;
(*
IsSym - returns the result of the comparison between the current token
type and t.
*)
PROCEDURE IsSym (t: TokenType) : BOOLEAN ;
BEGIN
RETURN( t=CurrentType )
END IsSym ;
(*
PushBackToken - pushes a token back onto input.
*)
PROCEDURE PushBackToken (t: Name) ;
VAR
a: ARRAY [0..MaxNameLength] OF CHAR ;
BEGIN
GetKey(t, a) ;
PutString(a)
END PushBackToken ;
(*
SetDebugging - sets the debugging flag.
*)
PROCEDURE SetDebugging (flag: BOOLEAN) ;
BEGIN
Debugging := flag
END SetDebugging ;
(*
Init - initialize the modules global variables.
*)
PROCEDURE Init ;
VAR
a: ARRAY [0..1] OF CHAR ;
BEGIN
InitTree(ReservedWords) ;
Debugging := FALSE ;
a[0] := nul ;
PutSymKey(ReservedWords, MakeKey(a) , ORD(eoftok)) ;
PutSymKey(ReservedWords, MakeKey('%') , ORD(codetok)) ;
PutSymKey(ReservedWords, MakeKey(':=') , ORD(lbecomestok)) ;
PutSymKey(ReservedWords, MakeKey('=:') , ORD(rbecomestok)) ;
PutSymKey(ReservedWords, MakeKey('|') , ORD(bartok)) ;
PutSymKey(ReservedWords, MakeKey('[') , ORD(lsparatok)) ;
PutSymKey(ReservedWords, MakeKey(']') , ORD(rsparatok)) ;
PutSymKey(ReservedWords, MakeKey('{') , ORD(lcparatok)) ;
PutSymKey(ReservedWords, MakeKey('}') , ORD(rcparatok)) ;
PutSymKey(ReservedWords, MakeKey('(') , ORD(lparatok)) ;
PutSymKey(ReservedWords, MakeKey(')') , ORD(rparatok)) ;
PutSymKey(ReservedWords, MakeKey('<') , ORD(lesstok)) ;
PutSymKey(ReservedWords, MakeKey('>') , 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:
*)