IMPLEMENTATION MODULE PL0Parser; FROM Storage IMPORT ALLOCATE, DEALLOCATE; IMPORT PL0Scanner; FROM PL0Scanner IMPORT TSymbol, sym, id, num; FROM PL0Scanner IMPORT Diff, KeepId, Mark, GetSym; FROM PL0Scanner IMPORT out, err, WrId; TYPE TObjClass = ( ocConst, ocVar, ocProc, ocHdr ); TObj = POINTER TO TObjDesc; TObjDesc = RECORD name: CARDINAL; next: TObj; CASE kind: TObjClass OF | ocConst..ocProc: | ocHdr : last, down: TObj; END; END; VAR topScope: TObj; PROCEDURE FreeObjsRec( o: TObj ); BEGIN IF o^.next # NIL THEN FreeObjsRec( o^.next ) END; DEALLOCATE( o, SIZE(o^) ); END FreeObjsRec; PROCEDURE FreeObjs( o: TObj ); VAR n: TObj; BEGIN WHILE o # NIL DO n := o^.next; DEALLOCATE( o, SIZE(o^) ); o := n; END; END FreeObjs; PROCEDURE DoFind( o: TObj ): TObj; BEGIN WHILE o # NIL DO IF Diff( id, o^.name ) = 0 THEN RETURN o; ELSE o := o^.next; END; END; RETURN o; END DoFind; PROCEDURE Err( n: CARDINAL ); BEGIN noErr := FALSE; Mark( n ); END Err; PROCEDURE NewObj( k: TObjClass ): TObj; VAR o: TObj; BEGIN o := DoFind( topScope^.next ); IF o # NIL THEN Err( 25 ) END; ALLOCATE( o, SIZE(o^) ); o^.name := id; o^.kind := k; o^.next := NIL; KeepId(); topScope^.last^.next := o; topScope^.last := o; RETURN o; END NewObj; PROCEDURE find( id: CARDINAL ): TObj; VAR h, o: TObj; BEGIN h := topScope; WHILE h # NIL DO o := DoFind( h^.next ); IF o # NIL THEN RETURN o END; h := h^.down; END; Err( 11 ); RETURN NIL; END find; PROCEDURE expression(); PROCEDURE factor(); VAR o: TObj; BEGIN IF sym = ident THEN o := find( id ); IF o # NIL THEN CASE o^.kind OF | ocConst, ocVar: | ocProc : Err( 21 ); END; END; GetSym(); ELSIF sym = number THEN GetSym(); ELSIF sym = lparen THEN GetSym(); expression(); IF sym = rparen THEN GetSym() ELSE Err( 7 ) END; ELSE Err( 8 ); END; END factor; PROCEDURE term(); BEGIN factor(); WHILE ( times <= sym ) & ( sym <= div ) DO GetSym(); factor(); END; END term; BEGIN IF ( plus <= sym ) & ( sym <= minus ) THEN GetSym(); term(); ELSE term(); END; WHILE ( plus <= sym ) & ( sym <= minus ) DO GetSym(); term(); END; END expression; PROCEDURE condition(); BEGIN IF sym = odd THEN GetSym(); expression(); ELSE expression(); IF ( eql <= sym ) & ( sym <= geq ) THEN GetSym(); expression(); ELSE Err( 20 ); END; END; END condition; PROCEDURE statement(); VAR o: TObj; BEGIN IF sym = ident THEN o := find( id ); GetSym(); IF sym = becomes THEN GetSym() ELSE Err( 13 ) END; expression(); ELSIF sym = call THEN GetSym; IF sym = ident THEN o := find( id ); GetSym() ELSE Err( 14 ) END; ELSIF sym = begin THEN GetSym(); statement(); WHILE sym = semicolon DO GetSym(); statement() END; IF sym = end THEN GetSym() ELSE Err( 17 ) END; ELSIF sym = if THEN GetSym(); condition(); IF sym = then THEN GetSym() ELSE Err( 16 ) END; statement(); ELSIF sym = while THEN GetSym(); condition(); IF sym = do THEN GetSym() ELSE Err( 18 ) END; statement ELSIF sym = read THEN GetSym(); IF sym = ident THEN o := find( id ); ELSE Err( 14 ) END; GetSym(); ELSIF sym = write THEN GetSym(); expression(); END; END statement; PROCEDURE block(); VAR h, o: TObj; PROCEDURE ConstDeclaration(); VAR o: TObj; BEGIN IF sym = ident THEN GetSym(); IF sym = eql THEN GetSym(); IF sym = number THEN o := NewObj( ocConst ); GetSym(); ELSE Err( 2 ); END; ELSE Err( 3 ); END; ELSE Err( 4 ); END; END ConstDeclaration; PROCEDURE VarDeclaration(); VAR o: TObj; BEGIN IF sym = ident THEN o := NewObj( ocVar ); GetSym(); ELSE Err( 4 ); END; END VarDeclaration; BEGIN ALLOCATE( h, SIZE(h^) ); h^.kind := ocHdr; h^.next := NIL; h^.last := h; h^.name := 0; h^.down := topScope; topScope := h; IF sym = const THEN GetSym(); ConstDeclaration(); WHILE sym = comma DO GetSym(); ConstDeclaration(); END; IF sym = semicolon THEN GetSym() ELSE Err( 5 ) END; END; IF sym = var THEN GetSym(); VarDeclaration(); WHILE sym = comma DO GetSym(); VarDeclaration(); END; IF sym = semicolon THEN GetSym() ELSE Err( 5 ) END; END; WHILE sym = procedure DO GetSym(); IF sym = ident THEN GetSym() ELSE Err( 4 ) END; o := NewObj( ocProc ); IF sym = semicolon THEN GetSym() ELSE Err( 5 ) END; block(); IF sym = semicolon THEN GetSym() ELSE Err( 5 ) END; END; statement(); h := topScope^.down; FreeObjs( topScope ); topScope := h; END block; PROCEDURE Parse(); BEGIN noErr := TRUE; topScope := NIL; PL0Scanner.Init(); GetSym(); block(); IF sym # period THEN Err( 9 ) END; PL0Scanner.Close(); END Parse; PROCEDURE End(); BEGIN END End; BEGIN END PL0Parser.