| #!/bin/sh | |
| # Copyright (C) 2000-2026 Free Software Foundation, Inc. | |
| # 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/>. | |
| # | |
| # builds the pg.bnf from ppg.mod | |
| # usage buildpg ppg.mod destination [-e] | |
| # -e build without error recovery | |
| # | |
| PPGSRC=$1 | |
| PPGDST=$2 | |
| includeNonErrorChecking () { | |
| sed -e "1,/StartNonErrorChecking/d" < $PPGSRC |\ | |
| sed -e "1,/EndNonErrorChecking/!d" | |
| } | |
| includeErrorChecking () { | |
| sed -e "1,/StartErrorChecking/d" < $PPGSRC |\ | |
| sed -e "1,/EndErrorChecking/!d" | |
| } | |
| echo "% module" $PPGDST "begin" | |
| sed -e "1,/% declaration/!d" < $PPGSRC | sed -e "s/ppg/${PPGDST}/g" | |
| echo "% declaration" $PPGDST "begin" | |
| sed -e "1,/% declaration/d" < $PPGSRC | sed -e "1,/% rules/!d" | sed -e "s/ppg/${PPGDST}/g" | |
| if [ "$3" = "-e" ] ; then | |
| includeNonErrorChecking | |
| echo "% module" $PPGDST "end" | |
| sed -e "1,/% module pg end/d" < $PPGSRC | sed -e "s/ppg/${PPGDST}/g" | |
| else | |
| includeErrorChecking | |
| echo "% module" $PPGDST "end" | |
| sed -e "1,/% module pg end/d" < $PPGSRC | sed -e "s/ppg/${PPGDST}/g" |\ | |
| sed -e "s/WasNoError := Main() ;/Main({eoftok}) ;/" | |
| fi | |
| echo "% rules" | |
| cat << EOFEOF | sed -e "s/ppg/${PPGDST}/g" | |
| error 'WarnError' 'WarnString' | |
| tokenfunc 'GetCurrentTokenType()' | |
| token 'identifier' identtok -- internal token | |
| token 'literal' literaltok | |
| token '%' codetok | |
| token ':=' lbecomestok | |
| token '=:' rbecomestok | |
| token '|' bartok | |
| token '[' lsparatok | |
| token ']' rsparatok | |
| token '{' lcparatok -- left curly para | |
| token '}' rcparatok -- right curly para | |
| token '(' lparatok | |
| token ')' rparatok | |
| token "error" errortok | |
| token "tokenfunc" tfunctok | |
| token "symfunc" symfunctok | |
| token '"' dquotetok | |
| token "'" squotetok | |
| token "module" moduletok | |
| token "begin" begintok | |
| token "rules" rulestok | |
| token "end" endtok | |
| token '<' lesstok | |
| token '>' gretok | |
| token "token" tokentok | |
| token "special" specialtok | |
| token "first" firsttok | |
| token "follow" followtok | |
| token "BNF" BNFtok | |
| token "FNB" FNBtok | |
| token "declaration" declarationtok | |
| token "epsilon" epsilontok | |
| token '' eoftok -- internal token | |
| special Ident first { < identtok > } follow { } | |
| special Modula2Code first { } follow { '%' } | |
| special StartModName first { < identtok > } follow { } | |
| special EndModName first { < identtok > } follow { } | |
| special DoDeclaration first { < identtok > } follow { } | |
| special CollectLiteral first { < literaltok > } follow { } | |
| special CollectTok first { < identtok > } follow { } | |
| special DefineToken first { < identtok > } follow { } | |
| BNF | |
| Rules := "%" "rules" { Defs } ExtBNF =: | |
| Special := Ident | |
| % VAR p: ProductionDesc ; % | |
| % p := NewProduction() ; | |
| p^.statement := NewStatement() ; | |
| p^.statement^.followinfo^.calcfollow := TRUE ; | |
| p^.statement^.followinfo^.epsilon := false ; | |
| p^.statement^.followinfo^.reachend := false ; | |
| p^.statement^.ident := CurrentIdent ; | |
| p^.statement^.expr := NIL ; | |
| p^.firstsolved := TRUE ; | |
| p^.followinfo^.calcfollow := TRUE ; | |
| p^.followinfo^.epsilon := false ; | |
| p^.followinfo^.reachend := false % | |
| First Follow [ "epsilon" % p^.statement^.followinfo^.epsilon := true ; (* these are not used - but they are displayed when debugging *) | |
| p^.statement^.followinfo^.reachend := true ; | |
| p^.followinfo^.epsilon := true ; | |
| p^.followinfo^.reachend := true | |
| % ] | |
| [ Literal % p^.description := LastLiteral % ] | |
| =: | |
| Factor := "%" Modula2Code "%" | | |
| Ident % WITH CurrentFactor^ DO | |
| type := id ; | |
| ident := CurrentIdent | |
| END ; % | | |
| Literal % WITH CurrentFactor^ DO | |
| type := lit ; | |
| string := LastLiteral ; | |
| IF GetSymKey(Aliases, LastLiteral)=NulName | |
| THEN | |
| WarnError1('no token defined for literal %s', LastLiteral) | |
| END | |
| END ; % | | |
| "{" % WITH CurrentFactor^ DO | |
| type := mult ; | |
| expr := NewExpression() ; | |
| CurrentExpression := expr ; | |
| END ; % | |
| Expression "}" | | |
| "[" % WITH CurrentFactor^ DO | |
| type := opt ; | |
| expr := NewExpression() ; | |
| CurrentExpression := expr ; | |
| END ; % | |
| Expression "]" | | |
| "(" % WITH CurrentFactor^ DO | |
| type := sub ; | |
| expr := NewExpression() ; | |
| CurrentExpression := expr ; | |
| END ; % | |
| Expression ")" =: | |
| Statement := % VAR i: IdentDesc ; % | |
| Ident | |
| % VAR p: ProductionDesc ; % | |
| % p := FindDefinition(CurrentIdent^.name) ; | |
| IF p=NIL | |
| THEN | |
| p := NewProduction() | |
| ELSE | |
| IF NOT ((p^.statement=NIL) OR (p^.statement^.expr=NIL)) | |
| THEN | |
| WarnError1('already declared rule %s', CurrentIdent^.name) | |
| END | |
| END ; | |
| i := CurrentIdent ; % | |
| ":=" | |
| % VAR e: ExpressionDesc ; % | |
| % e := NewExpression() ; | |
| CurrentExpression := e ; % | |
| % VAR s: StatementDesc ; % | |
| % s := NewStatement() ; | |
| WITH s^ DO | |
| ident := i ; | |
| expr := e | |
| END ; % | |
| Expression | |
| % p^.statement := s ; % | |
| "=:" =: | |
| Defs := "special" Special | "token" Token | "error" ErrorProcedures | | |
| "tokenfunc" TokenProcedure | "symfunc" SymProcedure =: | |
| ExtBNF := "BNF" { Production } "FNB" =: | |
| Main := Header Decls Footer Rules =: | |
| Header := "%" "module" StartModName =: | |
| Decls := "%" "declaration" DoDeclaration =: | |
| Footer := "%" "module" EndModName =: | |
| First := "first" "{" { LitOrTokenOrIdent | |
| % WITH CurrentSetDesc^ DO | |
| next := TailProduction^.first ; | |
| END ; | |
| TailProduction^.first := CurrentSetDesc | |
| % | |
| } "}" =: | |
| Follow := "follow" "{" { LitOrTokenOrIdent | |
| % WITH CurrentSetDesc^ DO | |
| next := TailProduction^.followinfo^.follow ; | |
| END ; | |
| TailProduction^.followinfo^.follow := CurrentSetDesc | |
| % | |
| } "}" =: | |
| LitOrTokenOrIdent := Literal % CurrentSetDesc := NewSetDesc() ; | |
| WITH CurrentSetDesc^ DO | |
| type := litel ; | |
| string := LastLiteral ; | |
| END ; | |
| % | | |
| '<' CollectTok '>' | | |
| Ident % CurrentSetDesc := NewSetDesc() ; | |
| WITH CurrentSetDesc^ DO | |
| type := idel ; | |
| ident := CurrentIdent ; | |
| END ; | |
| % =: | |
| Literal := '"' CollectLiteral '"' | | |
| "'" CollectLiteral "'" =: | |
| CollectTok := % CurrentSetDesc := NewSetDesc() ; | |
| WITH CurrentSetDesc^ DO | |
| type := tokel ; | |
| string := GetCurrentToken() ; | |
| END ; | |
| IF NOT ContainsSymKey(Values, GetCurrentToken()) | |
| THEN | |
| AddEntry(Values, GetCurrentToken(), LargestValue) ; | |
| AddEntry(ReverseValues, Name(LargestValue), GetCurrentToken()) ; | |
| AddEntry(Aliases, GetCurrentToken(), GetCurrentToken()) ; | |
| AddEntry(ReverseAliases, GetCurrentToken(), GetCurrentToken()) ; | |
| INC(LargestValue) | |
| END ; | |
| AdvanceToken() ; % =: | |
| CollectLiteral := % LastLiteral := GetCurrentToken() ; | |
| AdvanceToken ; % =: | |
| DefineToken := % AddEntry(Aliases, LastLiteral, GetCurrentToken()) ; | |
| AddEntry(ReverseAliases, GetCurrentToken(), LastLiteral) ; | |
| AddEntry(Values, GetCurrentToken(), LargestValue) ; | |
| AddEntry(ReverseValues, Name(LargestValue), GetCurrentToken()) ; | |
| INC(LargestValue) ; | |
| AdvanceToken ; % =: | |
| Token := Literal DefineToken =: | |
| ErrorProcedures := Literal % ErrorProcArray := LastLiteral % | |
| Literal % ErrorProcString := LastLiteral % =: | |
| TokenProcedure := Literal % TokenTypeProc := LastLiteral % =: | |
| SymProcedure := Literal % SymIsProc := LastLiteral % =: | |
| Production := Statement =: | |
| Expression := % VAR t1, t2: TermDesc ; | |
| e : ExpressionDesc ; % | |
| % e := CurrentExpression ; | |
| t1 := NewTerm() ; | |
| CurrentTerm := t1 ; % | |
| Term % e^.term := t1 ; % | |
| { "|" % t2 := NewTerm() ; | |
| CurrentTerm := t2 % | |
| Term % t1^.next := t2 ; | |
| t1 := t2 % } =: | |
| Term := % VAR t1: TermDesc ; f1, f2: FactorDesc ; % | |
| % CurrentFactor := NewFactor() ; | |
| f1 := CurrentFactor ; | |
| t1 := CurrentTerm ; % | |
| Factor % t1^.factor := f1 ; | |
| f2 := NewFactor() ; | |
| CurrentFactor := f2 % | |
| { Factor % f1^.next := f2 ; | |
| f1 := f2 ; | |
| f2 := NewFactor() ; | |
| CurrentFactor := f2 ; % } | |
| =: | |
| FNB | |
| EOFEOF |