COMPILER Calc (* Incomplete four function calculator - CalcManager is "left as an exercise" *) FROM CalcManager IMPORT NewVar, GetVar, SetVar, ReadVal, WriteVal; TYPE String = ARRAY [0 .. 100] OF CHAR; PROCEDURE GetNumber (VAR Int : INTEGER); (* Convert latest token to integer value Int *) VAR I : CARDINAL; String : ARRAY [0 .. 20] OF CHAR; BEGIN CalcS.GetString(CalcS.pos, CalcS.len, String); I := 0; Int := 0; WHILE String[I] # 0C DO Int := 10 * Int + VAL(INTEGER, ORD(String[I]) - ORD('0')); INC(I) END; END GetNumber; PROCEDURE GetSpix (VAR spix : INTEGER); (* Compute hash total for latest spelling *) VAR IdentName : ARRAY [0 .. 20] OF CHAR; BEGIN CalcS.GetName(CalcS.pos, CalcS.len, IdentName); spix := 17 * ORD(IdentName[0]) + ORD(IdentName[1]) END GetSpix; IGNORE CASE CHARACTERS letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz". digit = "0123456789". eol = CHR(13) . COMMENTS FROM '--' TO eol TOKENS ident = letter {letter | digit} . number = digit {digit} . PRODUCTIONS Calc = [Declarations] StatSeq . Declarations (. VAR spix: INTEGER; .) = "VAR" Ident (. NewVar(spix) .) { ',' Ident (. NewVar(spix) .) } ';'. StatSeq = Stat {';' Stat}. Stat (. VAR spix, val: INTEGER; .) = "READ" Ident (. ReadVal(spix) .) | "WRITE" Expr (. WriteVal(val) .) | Ident ":=" Expr (. SetVar(spix, val) .) . Expr (. VAR termVal: INTEGER; .) = Term { '+' Term (. exprVal := exprVal + termVal .) | '-' Term (. exprVal := exprVal - termVal .) } . Term (. VAR factVal: INTEGER; .) = Fact { '*' Fact (. termVal := termVal * factVal .) | '/' Fact (. termVal := termVal DIV factVal .) } . Fact (. VAR spix: INTEGER; .) = Ident (. factVal := GetVar(spix) .) | number (. GetNumber(factVal) .) | '(' Expr ')' . Ident = ident (. GetSpix(spix) .) . END Calc.