const
dbg = 0;
al=7; ll=40; txmax=50;
nul=0; ident=1; number=2;
plus=3; minus=4; times=5;
slash=6; oddsym=7; eql=8;
neq=9; lss=10; leq=11;
gtr=12; geq=13; lparen=14;
rparen=15; comma=16; semicolon=17;
period=18; becomes=19; beginsym=20;
endsym=21; ifsym=22; thensym=23;
whilesym=24; dosym=25;
constsym=27; varsym=28;
elsesym=30; repeatsym=31;
untilsym=32; writesym = 33;
constant=1; variable=2;
lit=1; lod=3; sto=4;
jmp=7; jpc=8;
add=21; sub=22; mul=23;
divcmd=24; eqlcmd=28; neqcmd=29;
lsscmd=30; leqcmd=31;
gtrcmd=32; geqcmd=33;
deccmd=34; chrcmd=35;
scrrow=$d6; flags=$02b1;
xreg=$02b3; yreg=$02b4;
clrscrline=$e9ff;
putrowcol=$e50a;
var line:array [ll] of char ;
id:array [al] of char ;
cc:integer ; ch:char ;
sym: integer ; num: integer ;
tabn: array [txmax] of integer ;
tabk: array [txmax] of integer ;
tabv: array [txmax] of integer ;
tx,lx,dx: integer ;
err: integer ;
procedure error(n);
begin
if err = 0 then
begin
write ("# ");
case n of
5: writeln ("; oder , erwartet");
9: writeln (". erwartet");
11: writeln ("bezeichner unbekannt");
12: writeln ("zuweisung zu konstante");
13: writeln (":= erwartet");
16: writeln ("then erwartet");
17: writeln ("; oder end erwartet");
18: writeln ("do erwartet");
20: writeln ("vergleichssymbol erwartet");
22: writeln ("schliessende klammer fehlt");
23: writeln ("falsches symbol am faktor-ende");
24: writeln ("until erwartet");
30: writeln ("zahl zu gross")
end
end ;
err := err + 1;
end ;
procedure getch;
var row: integer ;
begin
if (line[cc] = 13) or (cc = ll) then
begin
cc:= 0;
row := memc [scrrow];
write (chr (19));
memc [xreg] := 0;
call (clrscrline);
write (chr (19));
read (line);
memc [xreg] := row;
memc [yreg] := 0;
memc [flags] := 0;
call (putrowcol);
ch:= 32;
end
else
begin
ch := line[cc];
cc := cc + 1;
end ;
end ;
function getsum;
var i,sum: integer ;
begin
sum := 0;
for i:= 0 to al - 1 do
if id[i] >= 65 then
sum := sum + id[i] - 64;
getsum:= sum;
end ;
procedure getsym;
var k,q: integer ;
begin
sym := nul;
while ch = 32 do
getch;
if (ch >= 65) and (ch <=90) then
begin
k := 0;
repeat
if k < al then
begin
id[k] := ch;
k := k + 1;
end ;
getch;
until (ch < 65) or (ch > 90);
if k < al then
repeat
id[k] := 32;
k := k + 1;
until k = al;
q:= getsum;
if q = 37 then
sym := beginsym
else if q = 23 then
sym := endsym
else if q = 15 then
sym := ifsym
else if q = 47 then
sym := thensym
else if q = 57 then
sym := whilesym
else if q = 19 then
sym := dosym
else if q = 71 then
sym := constsym
else if q = 41 then
if id[0] = 69 then
sym := elsesym
else
sym := varsym
else if q = 65 then
sym := repeatsym
else if q = 76 then
sym := untilsym
else if q = 75 then
sym := writesym
else
sym := ident;
end
else if (ch >= 48) and (ch <= 57) then
begin
num := 0;
sym := number;
repeat
num := num * 10 + (ch - 48);
getch;
until (ch < 48) or (ch > 57);
if num > 65535 then
begin
error(30);
num := 0;
end
end
else if ch = 58 then
begin
getch;
if ch = 61 then
begin
sym := becomes;
getch;
end
end
else if ch = 60 then
begin
getch;
if ch = 62 then
begin
sym := neq;
getch;
end
else if ch = 61 then
begin
sym := leq;
getch;
end
else
sym := lss;
end
else if ch = 62 then
begin
getch;
if ch = 61 then
begin
sym := geq;
getch;
end
else
sym := gtr;
end
else if ch = 43 then
begin
sym := plus;
getch;
end
else if ch = 45 then
begin
sym := minus;
getch;
end
else if ch = 42 then
begin
sym := times;
getch;
end
else if ch = 47 then
begin
sym := slash;
getch;
end
else if ch = 44 then
begin
sym := comma;
getch;
end
else if ch = 59 then
begin
sym := semicolon;
getch;
end
else if ch = 40 then
begin
sym := lparen;
getch;
end
else if ch = 41 then
begin
sym := rparen;
getch;
end
else if ch = 61 then
begin
sym := eql;
getch;
end
else if ch = 46 then
sym := period;
if dbg then writeln ("sym:",sym);
end ;
procedure enter(kind);
begin
tx:= tx + 1;
(* if tx > txmax then *)
tabn[tx] := getsum;
tabk[tx] := kind;
case kind of
constant: tabv[tx] := num;
variable: begin
tabv[tx] := dx;
dx := dx + 1;
end
end
end ;
function position;
var i,sum: integer ;
begin
sum := getsum;
tabn[0] := sum;
i := tx;
while tabn[i] <> sum do
i := i - 1;
position := i;
end ;
procedure gen(fct, arg);
begin
write (" ");
case fct of
lit: writeln ("+lit ", arg);
lod: writeln ("+lod var", arg);
sto: writeln ("+sto var", arg);
jmp: writeln ("jmp lbl", arg);
jpc: writeln ("+jpc lbl", arg);
add: writeln ("jsr add");
sub: writeln ("jsr sub");
mul: writeln ("jsr mul");
divcmd: writeln ("jsr div");
eqlcmd: writeln ("jsr eql");
neqcmd: writeln ("jsr neq");
lsscmd: writeln ("jsr lss");
leqcmd: writeln ("jsr leq");
gtrcmd: writeln ("jsr gtr");
geqcmd: writeln ("jsr geq");
deccmd: writeln ("jsr outdec");
chrcmd: writeln ("jsr outchr")
end ;
end ;
function getlx;
begin
lx := lx + 1;
getlx := lx - 1;
end ;
procedure lbl(no);
begin
writeln ("lbl", no);
end ;
procedure constdecl;
begin
if sym = ident then
begin
getsym;
if sym = eql then
begin
getsym;
if sym = number then
begin
enter(constant);
getsym;
end
end
end
end ;
procedure vardecl;
begin
if sym = ident then
begin
enter(variable);
getsym;
end
end ;
procedure expression;
var addop: integer ;
procedure factor;
var i: integer ;
begin
if dbg then writeln ("factor");
if sym = ident then
begin
i := position;
if i = 0 then
error(11);
case tabk[i] of
constant: gen(lit, tabv[i]);
variable: gen(lod, tabv[i])
end ;
getsym;
end
else if sym = number then
begin
if num > 65535 then
begin
error(30);
num := 0;
end ;
gen(lit, num);
getsym;
end
else if sym = lparen then
begin
getsym;
expression;
if sym <> rparen then
error(22);
getsym;
end
else
error(23);
end ;
procedure term;
var mulop: integer ;
begin
if dbg then writeln ("term");
factor;
while (sym = times) or (sym = slash) do
begin
mulop := sym;
getsym;
factor;
if mulop = times then
gen(mul, 0)
else
gen(divcmd, 0);
end ;
end ;
begin
if dbg then writeln ("expression");
term;
while (sym = plus) or (sym = minus) do
begin
addop := sym;
getsym;
term;
if addop = plus then
gen(add, 0)
else
gen(sub, 0);
end ;
end ;
procedure condition;
var relop: integer ;
begin
if dbg then writeln ("condition");
expression;
case sym of
eql, neq, lss, leq, gtr, geq:
begin
relop := sym;
getsym;
expression;
case relop of
eql: gen(eqlcmd, 0);
neq: gen(neqcmd, 0);
lss: gen(lsscmd, 0);
leq: gen(leqcmd, 0);
gtr: gen(gtrcmd, 0);
geq: gen(geqcmd, 0)
end
end
else
begin
error(20);
getsym;
end
end ;
end ;
procedure statement;
var i,lx0,lx1: integer ;
begin
if dbg then writeln ("statement");
if sym = ident then
begin
i:= position;
if i = 0 then
error(11);
if tabk[i] <> variable then
begin
error(12);
i:= 0;
end ;
getsym;
if sym <> becomes then
error(13);
getsym;
expression;
if i <> 0 then
gen(sto, tabv[i]);
end
else if sym = ifsym then
begin
writeln ("; if");
lx0 := getlx;
lx1 := getlx;
getsym;
condition;
if sym <> thensym then
error(16);
getsym;
gen(jpc, lx0);
writeln ("; then");
statement;
if sym = elsesym then
begin
gen(jmp, lx1);
writeln ("; else");
lbl(lx0);
getsym;
statement;
writeln ("; endif");
lbl(lx1);
end
else
begin
writeln ("; endif");
lbl(lx0);
end
end
else if sym = beginsym then
begin
getsym;
statement;
while sym = semicolon do
begin
getsym;
statement;
end ;
if sym <> endsym then
error(17);
getsym;
end
else if sym = whilesym then
begin
writeln ("; while");
lx0 := getlx;
lx1 := getlx;
lbl(lx0);
getsym;
condition;
if sym <> dosym then
error(19);
getsym;
gen(jpc, lx1);
writeln ("; do");
statement;
gen(jmp, lx0);
writeln ("; endwhile");
lbl(lx1);
end
else if sym = repeatsym then
begin
writeln ("; repeat");
lx0 := getlx;
lbl(lx0);
getsym;
statement;
while sym = semicolon do
begin
getsym;
statement;
end ;
if sym <> untilsym then
error(24);
writeln ("; until");
getsym;
condition;
gen(jpc, lx0);
writeln ("; endrepeat");
end
else if sym = writesym then
begin
writeln ("; write");
getsym;
expression;
gen(deccmd, 0);
while sym = comma do
begin
gen(lit, 32);
gen(chrcmd, 0);
getsym;
expression;
gen(deccmd, 0);
end ;
gen(lit, 13);
gen(chrcmd, 0);
writeln ("; endwrite");
end ;
end ;
procedure block;
begin
if dbg then writeln ("block");
if sym = constsym then
begin
getsym;
constdecl;
while sym = comma do
begin
getsym;
constdecl;
end ;
if sym <> semicolon then
error(5);
getsym;
end ;
if sym = varsym then
begin
getsym;
vardecl;
while sym = comma do
begin
getsym;
vardecl;
end ;
if sym <> semicolon then
error(5);
getsym;
end ;
statement;
end ;
procedure dump;
var i: integer ;
begin
for i:= 0 to tx do
writeln (tabn[i],":",tabk[i],":",tabv[i]);
end ;
begin
cc:= 0; ch:= 32;
line[cc] := 13;
sym := nul; num := 0;
tx:= 0; tabn[0]:= 0;
tabk[0] := 0; tabv[0] := 0;
lx:= 1; dx:= 1;
err := 0;
writeln (chr (147));
getsym;
block;
if sym <> period then
error(9);
if err = 0 then dump;
end .