(* Skeleton compiler which checks the syntax of its input text according to the following grammar. Principle is top-down, recursive descent with one symbol lookahead. (see also N. Wirth, Algorithms + Data Structures = Programs, Ch. 5, Prentice-Hall, Inc. 1975) program = block ".". block = ["CONST" ident "=" number {"," ident "=" number} ";"] ["VAR" ident {"," ident} ";"] ["PROCEDURE" ident ";" block ";"} statement. statement = ident ":=" expression| "CALL" ident | "BEGIN" statement {";" statement} "END" | "IF" condition "THEN" statement | "WHILE" condition "DO" statement]. condition = "ODD" expression | expression ("="|"#"|">"|"<"|"<="|">=") expression. expression= ["+"|"-"] term {("+"|"-") term}. term = factor {("*"|"/") factor}. factor = ident | number | "(" expression ")". *) MODULE plo; FROM InOut IMPORT OpenInput,Done,CloseInput,Read,in,WriteInt; FROM Terminal IMPORT WriteString,Write,WriteLn; CONST norw = 11; tmax = 100; nmax = 14; al = 10; chsetsize = 128; TYPE symbol = (nul,ident,number,plus,minus,times,slash,oddsym, eql,neq,lss,leq,gtr,geq,lparen,rparen,comma,semicolon, period,becomes,beginsym,endsym,ifsym,thensym, whilesym,dosym,callsym,constsym,varsym,procsym); alfa = ARRAY [0..al] OF CHAR; object = (constant,variable,prozedure); VAR tch,ch: CHAR; sym: symbol; id: alfa; num: INTEGER; cc: INTEGER; ll: INTEGER; kk: INTEGER; line: ARRAY [1..81] OF CHAR; a: alfa; word: ARRAY [1..norw] OF alfa; wsym: ARRAY [1..norw] OF symbol; ssym: ARRAY [0C..'}'] OF symbol; table:ARRAY [0..tmax] OF RECORD name: alfa; kind: object END; PROCEDURE error(n: INTEGER); VAR i: INTEGER; BEGIN FOR i := 1 TO cc DO Write(' ') END; Write('>'); WriteInt(n,2); HALT END error; PROCEDURE compalfa(a,b:alfa):symbol; VAR res: symbol; i: INTEGER; BEGIN i := 1; res := eql; LOOP IF CAP(a[i]) < CAP(b[i]) THEN res := lss; EXIT ELSIF CAP(a[i]) > CAP(b[i]) THEN res := gtr; EXIT ELSE INC(i) END; IF i >= al THEN EXIT END; END; RETURN(res); END compalfa; PROCEDURE getsym; VAR i,j,k: INTEGER; PROCEDURE getch; BEGIN IF cc = ll THEN IF in.eof THEN WriteString(' program incomplete'); HALT END; Read(ch); ll := 0; cc := 0; Write(' '); WHILE (ch <> 36C) AND NOT in.eof DO INC(ll); Write(ch); line[ll] := ch; Read(ch) END; WriteLn; END; INC(cc); ch := line[cc] END getch; BEGIN WHILE ch = ' ' DO getch END; IF (ch >= 'a') AND (ch <= 'z') THEN k := 0; REPEAT IF k < al THEN INC(k); a[k] := ch END; getch; UNTIL ((ch < 'a') OR (ch > 'z')) AND ((ch < '0') OR (ch > '9')); IF k >= kk THEN kk := k ELSE REPEAT a[kk] := ' '; DEC(kk); UNTIL kk = k END; id := a; i := 1; j := norw; REPEAT k := (i+j) DIV 2; IF compalfa(id,word[k]) # gtr THEN j := k-1 END; IF compalfa(id,word[k]) # lss THEN i := k+1 END; UNTIL i > j; IF i-1 > j THEN sym := wsym[k] ELSE sym := ident END; ELSIF (ch >= '0') AND (ch <= '9') THEN k := 0; num := 0; sym := number; REPEAT num := 10 * num + INTEGER((ORD(ch)-ORD('0'))); INC(k); getch; UNTIL (ch < '0') OR (ch > '9'); IF k > nmax THEN error(30) END; ELSIF ch = ':' THEN getch; IF ch = '=' THEN sym := becomes; getch ELSE sym := nul; END; ELSIF ch = '<' THEN getch; IF ch = '=' THEN sym := leq; getch ELSE sym := lss; END; ELSIF ch = '>' THEN getch; IF ch = '=' THEN sym := geq; getch ELSE sym := gtr; END; ELSE sym := ssym[ch]; getch END; END getsym; PROCEDURE block(tx: INTEGER); PROCEDURE enter(k: object); BEGIN INC(tx); WITH table[tx] DO name := id; kind := k; END; END enter; PROCEDURE position(id: alfa): INTEGER; VAR i: INTEGER; BEGIN table[0].name := id; i := tx; WHILE compalfa(table[i].name,id) # eql DO i := i-1 END; RETURN(i); END position; PROCEDURE constdeclaration; BEGIN IF sym = ident THEN getsym; IF sym = eql THEN getsym; IF sym = number THEN enter(constant); getsym ELSE error(2); END ELSE error(3) END ELSE error(4) END END constdeclaration; PROCEDURE vardeclaration; BEGIN IF sym = ident THEN enter(variable); getsym ELSE error(4) END; END vardeclaration; PROCEDURE statement; VAR i: INTEGER; PROCEDURE expression; PROCEDURE term; PROCEDURE factor; VAR i: INTEGER; BEGIN IF sym = ident THEN i := position(id); IF i = 0 THEN error(0) ELSIF table[i].kind = prozedure THEN error(21) END; getsym; ELSIF sym = number THEN getsym; ELSIF sym = lparen THEN getsym; expression; IF sym = rparen THEN getsym; ELSE error(22) END ELSE error(23) END; END factor; BEGIN (* term *) factor; WHILE (sym = times) OR (sym = slash) DO getsym; factor; END; END term; BEGIN (* expression *) IF (sym = plus) OR (sym = minus) THEN getsym; term ELSE term END; WHILE (sym = plus) OR (sym = minus) DO getsym; term END; END expression; PROCEDURE condition; BEGIN IF sym = oddsym THEN getsym; expression ELSE expression; IF (ORD(sym) < ORD(eql)) OR (ORD(sym) > ORD(geq)) THEN error(20) ELSE getsym; expression END END; END condition; BEGIN (* statement *) IF sym = ident THEN i := position(id); IF i = 0 THEN error (11) ELSIF table[i].kind # variable THEN error(12) END; getsym; IF sym = becomes THEN getsym ELSE error(13) END; expression ELSIF sym = callsym THEN getsym; IF sym # ident THEN error(14) ELSE i := position(id); IF i = 0 THEN error(11) ELSIF table[i].kind # prozedure THEN error(15) END; getsym END; ELSIF sym = ifsym THEN getsym; condition; IF sym = thensym THEN getsym ELSE error(16) END; statement; ELSIF sym = beginsym THEN getsym; statement; WHILE sym = semicolon DO getsym; statement END; IF sym = endsym THEN getsym ELSE error(17) END; ELSIF sym = whilesym THEN getsym; condition; IF sym = dosym THEN getsym ELSE error(18) END; statement END; END statement; BEGIN (* block *) IF sym = constsym THEN getsym; constdeclaration; WHILE sym = comma DO getsym; constdeclaration END; IF sym = semicolon THEN getsym ELSE error(5) END; END; IF sym = varsym THEN getsym; vardeclaration; WHILE sym = comma DO getsym; vardeclaration END; IF sym = semicolon THEN getsym ELSE error(5) END; END; WHILE sym = procsym DO getsym; IF sym = ident THEN enter(prozedure); getsym ELSE error(4); END; IF sym = semicolon THEN getsym ELSE error(5) END; block(tx); IF sym = semicolon THEN getsym ELSE error(5) END END; statement; END block; BEGIN (* main program *) FOR ch := 0C TO '}' DO ssym[ch] := nul END; word[ 1] := " BEGIN "; word[ 2] := " CALL "; word[ 3] := " CONST "; word[ 4] := " DO "; word[ 5] := " END "; word[ 6] := " IF "; word[ 7] := " ODD "; word[ 8] := " PROCEDURE"; word[ 9] := " THEN "; word[10] := " VAR "; word[11] := " WHILE "; wsym[ 1] := beginsym; wsym[ 2] := callsym; wsym[ 3] := constsym; wsym[ 4] := dosym; wsym[ 5] := endsym; wsym[ 6] := ifsym; wsym[ 7] := oddsym; wsym[ 8] := procsym; wsym[ 9] := thensym; wsym[10] := varsym; wsym[11] := whilesym; ssym['+'] := plus; ssym['-'] := minus; ssym['*'] := times; ssym['/'] := slash; ssym['('] := lparen; ssym[')'] := rparen; ssym['='] := eql; ssym[','] := comma; ssym['.'] := period; ssym['#'] := neq; ssym['<'] := lss; ssym['>'] := gtr; ssym[';'] := semicolon; Write(14C); OpenInput("PLO"); a[0] := ' '; in.eof := FALSE; cc := 0; ll := 0; ch := ' '; kk := al; getsym; block(0); IF sym # period THEN error(9) END; END plo.