{$S+} {recursion on} {$K1} {$K2} {$K7} {$K12} {$K13} {$K14} { reduce symbol table space } module compiler; {$I global.inc} var sy: external symbol; {last symbol read by insymbol} id: external alfa; {identifier from insymbol} inum: external integer; {integer from insymbol} rnum: external real; {real number from insymbol} sleng: external integer; {string length} ch: external char; {last character read from source program} line: external array [1.. llng] of char; cc: external integer; {character counter} lc: external integer; {program location counter} ll: external integer; {length of current line} errs: external set of er; errpos: external integer; progname: external alfa; skipflag: external boolean; constbegsys, typebegsys, blockbegsys, facbegsys, statbegsys: external symset; key: external array [1.. nkw] of alfa; ksy: external array [1.. nkw] of symbol; sps: external array [char] of symbol; {special aymbols} t, a, b, sx, c1, c2: external integer; {indices to tables} stantyps: external typset; display: external array [0.. lmax] of integer; {identifier table} tab: external array [0.. tmax] of {identifier table} packed record name: alfa; link: index; obj: object; typ: types; ref: index; normal: boolean; lev: 0.. lmax; adr: integer; end; atab: external array [1.. amax] of {array table} packed record inxtyp, eltyp: types; elref, low, high, elsize, size: index; end; btab: external array [1..bmax] of {block-table} packed record last, lastpar, psize, vsize: index end; stab: external packed array [0.. smax] of char; {string table} code: external array [0.. cmax] of order; tabchar : char; {holds tab char for scanner } procedure abort; { return to CP/M } begin inline("JMP/ $00/ $00) end; procedure errormsg; var k: er; msg: array [er] of alfa; begin msg[erid] := 'identifier'; msg[ertyp] := 'type '; msg[erkey] := 'keyword '; msg[erpun] := 'punctuatio'; msg[erpar] := 'parameter '; msg[ernf] := 'not found '; msg[erdup] := 'duplicate '; msg[erch] := 'character '; msg[ersh] := 'too short '; msg[erln] := 'too long '; writeln('compilation errors'); writeln; writeln('key words'); for k := erid to erln do if k in errs then writeln(ord(k), ' ', msg[k]) end {errormsg}; procedure endskip; begin {underline skips part of input} while errpos < cc do begin write('-'); errpos := errpos + 1 end; skipflag := false end {endskip}; procedure nextch; {read next character; process line end} begin if cc = ll then begin if eof(input) then begin writeln; writeln('program incomplete'); errormsg; {goto 99} abort; end; if errpos <> 0 then begin if skipflag then endskip; writeln; errpos := 0 end; write(lc: 5, ' '); ll := 0; cc := 0; while not eoln(input) do begin ll := ll + 1; read(ch); write(ch); line[ll] := ch end; writeln; ll := ll + 1; read(line[ll]); end; cc := cc + 1; ch := line[cc]; end {nextch}; procedure error(n: er); begin if errpos = 0 then write('****'); if cc > errpos then begin write(' ': cc - errpos, '^', ord(n): 2); errpos := cc + 3; errs := errs + [n] end end {error}; procedure fatal(n: integer); var msg: array [1..6] of alfa; begin writeln; errormsg; msg[1] := 'identifier'; msg[2] := 'procedures'; msg[3] := 'string '; msg[4] := 'arrays '; msg[5] := 'level '; msg[6] := 'code '; writeln('compiler table for ', msg[n], ' is too small'); { goto 99; terminate compilation} abort; end {fatal}; procedure insymbol; {reads next symbol} label 1, 2, 3; var i, j, k, e: integer; begin {insymbol} 1: while ch in [' ',tabchar] do nextch; case ch of 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm' , 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y' , 'z': begin {identifier or wordsymbol} k := 0; id := ' '; repeat if k < alng then begin k := k + 1; id[k] := ch end; nextch until not (ch in [ 'a' .. 'z', '0' .. '9']); i := 1; j := nkw; {binary search} repeat k := (i + j) div 2; if id <= key[k] then j := k - 1; if id >= key[k] then i := k + 1 until i > j; if i - 1 > j then sy := ksy[k] else sy := ident end; '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': begin {number} k := 0; inum := 0; sy := intcon; repeat inum := inum * 10 + ord(ch) - ord('0'); k := k + 1; nextch until not (ch in [ '0' .. '9']); if (k > kmax) or (inum > nmax) then begin error(erln); inum := 0; k := 0 end; end; ':' {, col}: begin nextch; {mod mh} if ch = '=' then begin sy := becomes; nextch end else sy := colon end; '<': begin nextch; if ch = '=' then begin sy := leq; nextch end else if ch = '>' then begin sy := neq; nextch end else sy := lss end; '>': begin nextch; if ch = '=' then begin sy := geq; nextch end else sy := gtr end; '.': begin nextch; if ch = '.' then begin sy := colon; nextch end else if ch = ')' then begin sy := rbrack; nextch end else sy := period end; '''': begin k := 0; 2: nextch; if ch = '''' then begin nextch; if ch <> '''' then goto 3 end; if sx + k = smax then fatal(3); stab[sx + k] := ch; k := k + 1; if cc = 1 then begin {end of line} k := 0; end else goto 2; 3: if k = 1 then begin sy := charcon; inum := ord(stab[sx]) end else if k = 0 then begin error(ersh); sy := charcon; inum := 0 end else begin sy := string; inum := sx; sleng := k; sx := sx + k end end; '(': begin nextch; if ch = '.' then begin sy := lbrack; nextch end else if ch <> '*' then sy := lparent else begin {comment} nextch; repeat while ch <> '*' do nextch; nextch until ch = ')'; nextch; goto 1 end end; '+', '-', '*', ')', '=', ',', ';','[',']' : begin sy := sps[ch]; nextch end; '$', '!', '@', '^', '?', {'""',} '&', '/','\' : begin error(erch); nextch; goto 1 end end end {insymbol}; procedure enterstandardids(x0: alfa; x1: object; x2: types; x3: integer); begin t := t + 1; {enter standard identifier} with tab[t] do begin name := x0; link := t - 1; obj := x1; typ := x2; ref := 0; normal := true; lev := 0; adr := x3 end end {enter}; procedure enterarray(tp: types; l, h: integer); begin if l > h then error(ertyp); if (abs(l) > xmax) or (abs(h) > xmax) then begin error(ertyp); l := 0; h := 0; end; if a = amax then fatal(4) else begin a := a + 1; with atab[a] do begin inxtyp := tp; low := l; high := h end end {enterarray}; end {enterarray}; {fix mh} procedure enterblock; begin if b = bmax then fatal(2) else begin b := b + 1; btab[b].last := 0; btab[b].lastpar := 0 end end {enterblock}; procedure emit(fct: integer); begin if lc = cmax then fatal(6); code[lc].f := fct; lc := lc + 1; end {emit}; procedure emit1(fct, b: integer); begin if lc = cmax then fatal(6); with code[lc] do begin f := fct; y := b end; lc := lc + 1; end {emit1}; procedure emit2(fct, a, b: integer); begin if lc = cmax then fatal(6); with code[lc] do begin f := fct; x := a; y := b end; lc := lc + 1; end {emit2}; procedure block(fsys: symset; isfun: boolean; level: integer); type conrec = record tp: types; i: integer end; var dx: integer; {data allocation index} prt: integer; {t-index of this procedure} prb: integer; {b-index of this procedure} x: integer; procedure skip(fsys: symset; n: er); begin error(n); skipflag := true; while not (sy in fsys) do insymbol; if skipflag then endskip; end {skip}; procedure test(s1, s2: symset; n: er); begin if not (sy in s1) then skip(s1 + s2, n) end {test}; procedure testsemicolon; begin if sy = semicolon then insymbol else error(erpun); test([ident] + blockbegsys, fsys, erkey); end {testsemicolon}; procedure enter(id: alfa; k: object); var j, l: integer; begin if t = tmax then fatal(1) else begin tab[0].name := id; j := btab[display[level]].last; l := j; while tab[j].name <> id do j := tab[j].link; if j <> 0 then error(erdup) else begin t := t + 1; with tab[t] do begin name := id; link := l; obj := k; typ := notyp; ref := 0; lev := level; adr := 0 end; btab[display[level]].last := t end end end {enter}; function loc(id: alfa): integer; var i, j: integer; {locate id in table} begin i := level; tab[0].name := id; {sentinel} repeat j := btab[display[i]].last; while tab[j].name <> id do j := tab[j].link; i := i - 1; until (i < 0) or (j <> 0); if j = 0 then error(ernf); loc := j end {loc}; procedure entervariable; begin if sy = ident then begin enter(id, variable); insymbol end else error(erid) end {entervariable}; procedure constant(fsys: symset; var c: conrec); var x, sign: integer; begin c.tp := notyp; c.i := 0; test(constbegsys, fsys, erkey); if sy in constbegsys then begin if sy = charcon then begin c.tp := chars; c.i := inum; insymbol end else begin sign := 1; if sy in [plus, minus] then begin if sy = minus then sign := - 1; insymbol end; if sy = ident then begin x := loc(id); if x <> 0 then if tab[x].obj <> konstant then error(ertyp) else begin c.tp := tab[x].typ; c.i := sign * tab[x].adr end; insymbol end else if sy = intcon then begin c.tp := ints; c.i := sign * inum; insymbol end else skip(fsys, erkey) end; test(fsys, [], erkey); end end {constant}; procedure typ(fsys: symset; var tp: types; var rf, sz: integer); var x: integer; eltp: types; elrf: integer; elsz, offset, t0, t1: integer; procedure arraytyp(var aref, arsz: integer); var eltp: types; low, high: conrec; elrf, elsz: integer; begin constant([colon, rbrack, ofsy] + fsys, low); if sy = colon then insymbol else error(erpun); constant([rbrack, comma, ofsy] + fsys, high); if high.tp <> low.tp then begin error(ertyp); high.i := low.i end; enterarray(low.tp, low.i, high.i); aref := a; if sy = comma then begin insymbol; eltp := arrays; arraytyp(elrf, elsz) end else begin if sy = rbrack then insymbol else error(erpun); if sy = ofsy then insymbol else error(erkey); typ(fsys, eltp, elrf, elsz) end; with atab[aref] do begin arsz := (high - low + 1) * elsz; size := arsz; eltyp := eltp; elref := elrf; elsize := elsz end; end {arraytyp}; begin {typ} tp := notyp; rf := 0; sz := 0; test(typebegsys, fsys, erid); if sy in typebegsys then begin if sy = ident then begin x := loc(id); if x <> 0 then with tab[x] do if obj <> type1 then error(ertyp) else begin tp := typ; rf := ref; sz := adr; if tp = notyp then error(ertyp) end; insymbol end else if sy = arraysy then begin insymbol; if sy = lbrack then insymbol else error(erpun); tp := arrays; arraytyp(rf, sz) end else test(fsys, [], erkey); end end {typ}; procedure parameterlist; {formal parameter list} var tp: types; rf, sz, x, t0: integer; valpar: boolean; begin insymbol; tp := notyp; rf := 0; sz := 0; test([ident, varsy], fsys + [rparent], erpar); while sy in [ident, varsy] do begin if sy <> varsy then valpar := true else begin insymbol; valpar := false end; t0 := t; entervariable; while sy = comma do begin insymbol; entervariable; end; if sy = colon then begin insymbol; if sy <> ident then error(erid) else begin x := loc(id); insymbol; if x <> 0 then with tab[x] do if obj <> type1 then error(ertyp) else begin tp := typ; rf := ref; if valpar then sz := adr else sz := 1 end; end; test([semicolon, rparent], [comma, ident] + fsys, erpun) end else error(erpun); while t0 < t do begin t0 := t0 + 1; with tab[t0] do begin typ := tp; ref := rf; normal := valpar; adr := dx; lev := level; dx := dx + sz end end; if sy <> rparent then begin if sy = semicolon then insymbol else error(erpun); test([ident, varsy], [rparent] + fsys, erkey); end end; if sy = rparent then begin insymbol; test([semicolon, colon], fsys, erkey); end else error(erpun) end {parameterlist}; procedure constdeclaration; var c: conrec; begin insymbol; test([ident], blockbegsys, erid); while sy = ident do begin enter(id, konstant); insymbol; if sy = eql then insymbol else error(erpun); constant([semicolon, comma, ident] + fsys, c); tab[t].typ := c.tp; tab[t].ref := 0; tab[t].adr := c.i; testsemicolon end end {constdeclaration}; procedure typedeclaration; var tp: types; rf, sz, t1: integer; begin insymbol; test([ident], blockbegsys, erid); while sy = ident do begin enter(id, type1); t1 := t; insymbol; if sy = eql then insymbol else error(erpun); typ([semicolon, comma, ident] + fsys, tp, rf, sz); with tab[t1] do begin typ := tp; ref := rf; adr := sz end; testsemicolon end end {typedeclaration}; procedure vardeclaration; var t0, t1, rf, sz: integer; tp: types; begin insymbol; while sy = ident do begin t0 := t; entervariable; while sy = comma do begin insymbol; entervariable; end; if sy = colon then insymbol else error(erpun); t1 := t; typ([semicolon, comma, ident] + fsys, tp, rf, sz); while t0 < t1 do begin t0 := t0 + 1; with tab[t0] do begin typ := tp; ref := rf; lev := level; adr := dx; normal := true; dx := dx + sz end end; testsemicolon end end {variab|edeclaration}; procedure procdeclaration; var isfun: boolean; begin isfun := sy = functionsy; insymbol; if sy <> ident then begin error(erid); id := ' '; end; if isfun then enter(id, funktion) else enter(id, prozedure); tab[t].normal := true; insymbol; block([semicolon] + fsys, isfun, level + 1); if sy = semicolon then insymbol else error(erpun); emit(32 + ord(isfun)) {exit} end {proceduredeclaration}; procedure statement(fsys: symset); var i: integer; x: item; procedure expression(fsys: symset; var x: item); forward; procedure selector(fsys: symset; var v: item); var x: item; a, j: integer; begin if sy <> lbrack then error(ertyp); repeat insymbol; expression(fsys + [comma, rbrack], x); if v.typ <> arrays then error(ertyp) else begin a := v.ref; if atab[a].inxtyp <> x.typ then error(ertyp) else emit1(21, a); v.typ := atab[a].eltyp; v.ref := atab[a].elref end until sy <> comma; if sy = rbrack then insymbol else error(erpun); test(fsys, [], erkey); end {selector}; procedure call(fsys: symset; i: integer); var x: item; lastp, cp, k: integer; begin emit1(18, i); {markstack} lastp := btab[tab[i].ref].lastpar; cp := i; if sy = lparent then begin {actual parameter list} repeat insymbol; if cp >= lastp then error(erpar) else begin cp := cp + 1; if tab[cp].normal then begin {value parameter} expression(fsys + [comma, colon, rparent], x); if x.typ = tab[cp].typ then begin if x.ref <> tab[cp].ref then error(ertyp) else if x.typ = arrays then emit1(22, atab[x.ref]. size) end else if x.typ <> notyp then error(ertyp); end else begin {variable parameter} if sy <> ident then error(erid) else begin k := loc(id); insymbol; if k <> 0 then begin if tab[k].obj <> variable then error(erpar); x.typ := tab[k].typ; x.ref := tab[k].ref; if tab[k].normal then emit2(0, tab[k].lev, tab[k].adr) else emit2(1, tab[k].lev, tab[k].adr); if sy = lbrack then selector(fsys + [comma, colon, rparent], x); if (x.typ <> tab[cp].typ) or (x.ref <> tab[cp]. ref) then error(ertyp) end end end end; test([comma, rparent], fsys, erkey); until sy <> comma; if sy = rparent then insymbol else error(erpun) end; if cp < lastp then error(erpar); {too few actual parameters} emit1(19, btab[tab[i].ref].psize - 1); if tab[i].lev < level then emit2(3, tab[i].lev, level) end {call}; function resulttype(a, b: types): types; begin if (a > ints) or (b > ints) then begin error(ertyp); resulttype := notyp end else if (a = notyp) or (b = notyp) then resulttype := notyp else resulttype := ints end {resulttyp}; procedure expression; var y: item; op: symbol; procedure simpleexpression(fsys: symset; var x: item); var y: item; op: symbol; procedure term(fsys: symset; var x: item); var y: item; op: symbol; ts: typset; procedure factor(fsys: symset; var x: item); var i, f: integer; begin {factor} x.typ := notyp; x.ref := 0; test(facbegsys, fsys, erpun); while sy in facbegsys do begin if sy = ident then begin i := loc(id); insymbol; with tab[i] do case obj of konstant: begin x.typ := typ; x.ref := 0; emit1(24, adr) end; variable: begin x.typ := typ; x.ref := ref; if sy = lbrack then begin if normal then f := 0 else f := 1; emit2(f, lev, adr); selector(fsys, x); if x.typ in stantyps then emit(34) end else begin if x.typ in stantyps then if normal then f := 1 else f := 2 else if normal then f := 0 else f := 1; emit2(f, lev, adr) end end; type1, prozedure: error(ertyp); funktion: begin x.typ := typ; if lev <> 0 then call(fsys, i) else emit1(8, adr) end end {case, with} end else if sy in [charcon, intcon] then begin if sy = charcon then x.typ := chars else x.typ := ints; emit1(24, inum); x.ref := 0; insymbol end else if sy = lparent then begin insymbol; expression(fsys + [rparent], x); if sy = rparent then insymbol else error(erpun) end else if sy = notsy then begin insymbol; factor(fsys, x); if x.typ = bools then emit(35) else if x.typ <> notyp then error(ertyp) end; test(fsys, facbegsys, erkey); end {while} end {factor}; begin {term} factor(fsys + [times, idiv, imod, andsy], x); while sy in [times, idiv, imod, andsy] do begin op := sy; insymbol; factor(fsys + [times, idiv, imod, andsy], y); if op = times then begin x.typ := resulttype(x.typ, y.typ); if x.typ = ints then emit(57) end else if op = andsy then begin if (x.typ = bools) and (y.typ = bools) then emit(56) else begin if (x.typ <> notyp) and (y.typ <> notyp) then error(ertyp); x.typ := notyp end end else begin {op in[idiv, imod]} if (x.typ = ints) and (y.typ = ints) then if op = idiv then emit(58) else emit(59) else begin if (x.typ <> notyp) and (y.typ <> notyp) then error(ertyp); x.typ := notyp end end end end {term}; begin {simpleexpression} if sy in [plus, minus] then begin op := sy; insymbol; term(fsys + [plus, minus], x); if x.typ > ints then error(ertyp) else if op = minus then emit(36) end else term(fsys + [plus, minus, orsy], x); while sy in [plus, minus, orsy] do begin op := sy; insymbol; term(fsys + [plus, minus, orsy], y); if op = orsy then begin if (x.typ = bools) and (y.typ = bools) then emit(51) else begin if (x.typ <> notyp) and (y.typ <> notyp) then error(ertyp); x.typ := notyp end end else begin x.typ := resulttype(x.typ, y.typ); if x.typ = ints then if op = plus then emit(52) else emit(53) end end end {simpleexpression}; begin {expression}; simpleexpression(fsys + [eql, neq, lss, leq, gtr, geq], x); if sy in [eql, neq, lss, leq, gtr, geq] then begin op := sy; insymbol; simpleexpression(fsys, y); if (x.typ in [notyp, ints, bools, chars]) and (x.typ = y.typ) then case op of eql: emit(45); neq: emit(46); lss: emit(47); leq: emit(48); gtr: emit(49); geq: emit(50); end else error(ertyp); x.typ := bools end end {expression}; procedure assignment(lv, ad: integer); var x, y: item; f: integer; {tab[i]. obj in [variable,prozedure]} begin x.typ := tab[i].typ; x.ref := tab[i].ref; if tab[i].normal then f := 0 else f := 1; emit2(f, lv, ad); if sy = lbrack then selector([becomes, eql] + fsys, x); if sy = becomes then insymbol else error(erpun); expression(fsys, y); if x.typ = y.typ then if x.typ in stantyps then emit(38) else if x.ref <> y.ref then error(ertyp) else if x.typ = arrays then emit1(23, atab[x.ref].size) else error(ertyp) end {assignment}; procedure compoundstatement; begin insymbol; statement([semicolon, endsy] + fsys); while sy in [semicolon] + statbegsys do begin if sy = semicolon then insymbol else error(erpun); statement([semicolon, endsy] + fsys) end; if sy = endsy then insymbol else error(erkey) end {compoundstatement}; procedure ifstatement; var x: item; lc1, lc2: integer; begin insymbol; expression(fsys + [thensy, dosy], x); if not (x.typ in [bools, notyp]) then error(ertyp); lc1 := lc; emit(11); {jmpc} if sy = thensy then insymbol else error(erkey); statement(fsys + [elsesy]); if sy = elsesy then begin insymbol; lc2 := lc; emit(10); code[lc1].y := lc; statement(fsys); code[lc2].y := lc end else code[lc1].y := lc end {ifstatement}; procedure repeatstatement; var x: item; lc1: integer; begin lc1 := lc; insymbol; statement([semicolon, untilsy] + fsys); while sy in [semicolon] + statbegsys do begin if sy = semicolon then insymbol else error(erpun); statement([semicolon, untilsy] + fsys) end; if sy = untilsy then begin insymbol; expression(fsys, x); if not (x.typ in [bools, notyp]) then error(ertyp); emit1(11, lc1) end else error(erkey) end {repeatstatement}; procedure whilestatement; var x: item; lc1, lc2: integer; begin insymbol; lc1 := lc; expression(fsys + [dosy], x); if not (x.typ in [bools, notyp]) then error(ertyp); lc2 := lc; emit(11); if sy = dosy then insymbol else error(erkey); statement(fsys); emit1(10, lc1); code[lc2].y := lc end {whilestatement}; procedure forstatement; var cvt: types; x: item; i, lc1, lc2: integer; begin insymbol; if sy = ident then begin i := loc(id); insymbol; if i = 0 then cvt := tab[i].typ; if tab[i].obj = variable then begin cvt := tab[i].typ; if not tab[i].normal then error(ertyp) else emit2(0, tab[i].lev, tab[i].adr); if not (cvt in [notyp, ints, bools, chars]) then error(ertyp) end else begin error(ertyp); cvt := ints end end else skip([becomes, tosy, dosy] + fsys, erid); if sy = becomes then begin insymbol; expression([tosy, dosy] + fsys, x); if x.typ <> cvt then error(ertyp); end else skip([tosy, dosy] + fsys, erpun); if sy = tosy then begin insymbol; expression([dosy] + fsys, x); if x.typ <> cvt then error(ertyp) end else skip([dosy] + fsys, erkey); lc1 := lc; emit(14); if sy = dosy then insymbol else error(erkey); lc2 := lc; statement(fsys); emit1(15, lc2); code[lc1].y := lc end {forstatement}; procedure standproc(n: integer); var i, f: integer; x, y: item; begin case n of 1, 2: begin {read} if sy = lparent then begin repeat insymbol; if sy <> ident then error(erid) else begin i := loc(id); insymbol; if i <> 0 then if tab[i].obj <> variable then error(ertyp) else begin x.typ := tab[i].typ; x.ref := tab[i].ref; if tab[i].normal then f := 0 else f := 1; emit2(f, tab[i].lev, tab[i].adr); if sy = lbrack then selector(fsys + [comma, rparent], x); if x.typ in [ints, chars, notyp] then emit1(27, ord(x.typ)) else error(ertyp) end end; test([comma, rparent], fsys, erkey) until sy <> comma; if sy = rparent then insymbol else error(erpun) end; if n = 2 then emit(62) end; 3, 4: begin {write} if sy = lparent then begin repeat insymbol; if sy = string then begin emit1(24, sleng); emit1(28, inum); insymbol end else begin expression(fsys + [comma, colon, rparent], x); if not (x.typ in stantyps) then error(ertyp); emit1(29, ord(x.typ)) end until sy <> comma; if sy = rparent then insymbol else error(erpun) end; if n = 4 then emit(63) end; 5, 6: {wait, signal} if sy <> lparent then error(erpun) else begin insymbol; if sy <> ident then error(erid) else begin i := loc(id); insymbol; if i <> 0 then if tab[i].obj <> variable then error(ertyp) else begin x.typ := tab[i].typ; x.ref := tab[i].ref; if tab[i].normal then f := 0 else f := 1; emit2(f, tab[i].lev, tab[i]. adr); if sy = lbrack then selector(fsys + [rparent], x ); if x.typ = ints then emit(n + 1) else error(ertyp) end end; if sy = rparent then insymbol else error(erpun) end; end {case} end {standproc}; begin {statement} if sy in statbegsys + [ident] then case sy of ident: begin i := loc(id); insymbol; if i <> 0 then case tab[i].obj of konstant, type1: error(ertyp); variable: assignment(tab[i].lev, tab[i].adr); prozedure: if tab[i].lev <> 0 then call(fsys, i) else standproc(tab[i].adr); funktion: if tab[i].ref = display[level] then assignment(tab[i].lev + 1, 0) else error(ertyp) end end; beginsy: if id = 'cobegin ' then begin emit(4); compoundstatement; emit(5) end else compoundstatement; ifsy: ifstatement; whilesy: whilestatement; repeatsy: repeatstatement; forsy: forstatement; end; test(fsys, [], erpun) end {statement}; begin {block} tabchar := chr(9); dx := 5; prt := t; if level > lmax then fatal(5); test([lparent, colon, semicolon], fsys, erpun); enterblock; display[level] := b; prb := b; tab[prt].typ := notyp; tab[prt].ref := prb; if (sy = lparent) and (level > 1) then parameterlist; btab[prb].lastpar := t; btab[prb].psize := dx; if isfun then if sy = colon then begin insymbol; {function type} if sy = ident then begin x := loc(id); insymbol; if x <> 0 then if tab[x].obj <> type1 then error(ertyp) else if tab[x].typ in stantyps then tab[prt].typ := tab[x].typ else error(ertyp) end else skip([semicolon] + fsys, erid) end else error(erpun); if sy = semicolon then insymbol else error(erpun); repeat if sy = constsy then constdeclaration; if sy = typesy then typedeclaration; if sy = varsy then vardeclaration; btab[prb].vsize := dx; while sy in [proceduresy, functionsy] do procdeclaration; test([beginsy], blockbegsys + statbegsys, erkey) until sy in statbegsys; tab[prt].adr := lc; insymbol; statement([semicolon, endsy] + fsys); while sy in [semicolon] + statbegsys do begin if sy = semicolon then insymbol else error(erpun); statement([semicolon, endsy] + fsys) end; if sy = endsy then insymbol else error(erkey); test(fsys + [period], [], erkey); end {block}; modend.