program pascals(input,output); (*$u-,t-,p-,s10000b*) (*author: n.wirth, e.t.h. ch-8092 zurich, 1.3.76*) (* updated 19.3.80, 22.4.81 msp uwa for csc *) label 99; const nkw = 27; (*no. of key words*) alng = 10; (*no. of significant chars in identifiers*) llng = 121; (*input line length*) emax = 322; (*max exponent of real numbers*) emin =-292; (*min exponent*) kmax = 15; (*max no. of significant digits*) tmax = 100; (*size of table*) bmax = 20; (*size of block-table*) amax = 30; (*size of array-table*) c2max = 35; (*size of real constant table*) csmax = 30; (*max no. of cases*) cmax = 800; (*size of code*) lmax = 7; (*maximum level*) smax = 600; (*size of string-table*) ermax = 58; (*max error no.*) omax = 63; (*highest order code*) xmax = 131071; (*2**17 - 1*) nmax = maxint; (*2**48-1 on CYBER*) lineleng = 132; (*output line length*) linelimit = 350; stacksize = 1450; type symbol = (intcon,realcon,charcon,string, notsy,plus,minus,times,idiv,rdiv,imod,andsy,orsy, eql,neq,gtr,geq,lss,leq, lparent,rparent,lbrack,rbrack,comma,semicolon,period, colon,becomes,constsy,typesy,varsy,functionsy, proceduresy,arraysy,recordsy,programsy,ident, beginsy,ifsy,casesy,repeatsy,whilesy,forsy, endsy,elsesy,untilsy,ofsy,dosy,tosy,downtosy,thensy); index = -xmax .. +xmax; alfa = packed array [1..alng] of char; object = (konstant,variable,type1,prozedure,funktion); types = (notyp,ints,reals,bools,chars,arrays,records); symset = set of symbol; typset = set of types; item = record typ: types; ref: index; end ; order = packed record f: -omax..+omax; x: -lmax..+lmax; y: -nmax..+nmax; end ; var sy: symbol; (*last symbol read by insymbol*) id: alfa; (*identifier from insymbol*) inum: integer; (*integer from insymbol*) rnum: real; (*real number from insymbol*) sleng: integer; (*string length*) ch: char; (*last character read from source program*) line: array [1..llng] of char; cc: integer; (*character counter*) lc: integer; (*program location counter*) ll: integer; (*length of current line*) errs: set of 0..ermax; errpos: integer; progname: alfa; iflag, oflag, skipflag: boolean; constbegsys,typebegsys,blockbegsys,facbegsys,statbegsys: symset; key: array [1..nkw] of alfa; ksy: array [1..nkw] of symbol; sps: array [char] of symbol; (*special symbols*) t,a,b,sx,c1,c2: integer; (*indices to tables*) stantyps: typset; display: array [0 .. lmax] of integer; tab: 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: array [1 .. amax] of (*array-table*) packed record inxtyp, eltyp: types; elref, low, high, elsize, size: index; end ; btab: array [1 .. bmax] of (*block-table*) packed record last, lastpar, psize, vsize: index end ; stab: packed array [0..smax] of char; (*string table*) rconst: array [1 .. c2max] of real; code: array [0 .. cmax] of order; procedure errormsg; var k: integer; begin k:=0; writeln; writeln(' error codes:'); while errs <> [] do begin while not (k in errs) do k:=k+1; write(k,' '); case k of 0 : writeln(' identifier not declared'); 1 : writeln(' identifier declared twice'); 2 : writeln(' identifier expected'); 3 : writeln(' ''program'' expected'); 4 : writeln(' '')'' expected'); 5 : writeln(' '':'' expected'); 6 : writeln(' incorrect symbol'); 7 : writeln(' identifier or ''var'' expected'); 8 : writeln(' ''of'' expected'); 9 : writeln(' ''('' expected'); 10 : writeln(' identifier, ''array'' or ''record'' expected'); 11 : writeln(' pected'); 12 : writeln(' '']'' expected'); 13 : writeln(' ''..'' expected'); 14 : writeln(' '';'' expected'); 15 : writeln(' function must be integer,real,boolean or char'); 16 : writeln(' ''='' expected'); 17 : writeln(' expression must be boolean'); 18 : writeln(' control var must be integer,char or boolean'); 19 : writeln(' ''for'' limits of wrong type'); 20 : writeln(' no file ''output'' in program heading'); 21 : writeln(' number too large'); 22 : writeln(' ''.'' expected. check begin--ends'); 23 : writeln(' ''case'' expression must be integer,char or boolean'); 24 : writeln(' illegal character'); 25 : writeln(' ''='' must precede constant or identifier'); 26 : writeln(' array index of wrong type'); 27 : writeln(' array bounds not valid'); 28 : writeln(' array not declared'); 29 : writeln(' type identifier expected'); 30 : writeln(' undefined type'); 31 : writeln(' record not declared'); 32 : writeln(' operand must be of type boolean'); 33 : writeln(' illegal type in arithmetic expression'); 34 : writeln(' operand must be of type integer'); 35 : writeln(' may not compare these types'); 36 : writeln(' actual and formal params of different type'); 37 : writeln(' variable expected'); 38 : writeln(' string must contain chars'); 39 : writeln(' incorrect number of params'); 40 : writeln(' can only read integer,real,char'); 41 : writeln(' can only write integer,real,char,boolean'); 42 : writeln(' only applies to reals'); 43 : writeln(' only applies to integers'); 44 : writeln(' identifier is wrong kind'); 45 : writeln(' assignment to identifier not allowed here'); 46 : writeln(' types of variable and expression different'); 47 : writeln(' case label of wrong type'); 48 : writeln(' argument is of wrong type'); 49 : writeln(' program too large for pascals'); 50 : writeln(' constant begins with bad symbol'); 51 : writeln(' '':='' expected'); 52 : writeln(' ''then'' expected'); 53 : writeln(' ''until'' expected'); 54 : writeln(' ''do'' expected'); 55 : writeln(' ''to'' expected'); 56 : writeln(' ''begin'' expected'); 57 : writeln(' ''end'' expected'); 58 : writeln(' identifier,const,''not'' or ''('' expected'); end; errs:=errs-[k] end end (*errormsg*) ; procedure endskip; begin (*underline skipped 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 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: integer); begin if errpos = 0 then write(' ****'); if cc > errpos then begin write(' ': cc-errpos, '^', n:2); errpos := cc+3; errs := errs + [n] end end (*error*) ; procedure fatal(n: integer); var msg: array [1..7] of alfa; begin writeln; errormsg; msg[ 1] := 'identifier'; msg[ 2] := 'procedures'; msg[ 3] := 'reals '; msg[ 4] := 'arrays '; msg[ 5] := 'levels '; msg[ 6] := 'code '; msg[ 7] := 'strings '; writeln(' compiler table for ', msg[n], ' is too small'); goto 99 (* terminate compilation*) end (*fatal*) ; (*-----------------------------------------------------------insymbol-*) procedure insymbol; (*reads next symbol*) label 1,2,3; var i,j,k,e: integer; procedure readscale; var s, sign: integer; begin nextch; sign := 1; s := 0; if ch = '+' then nextch else if ch = '-' then begin nextch; sign := -1 end ; if not (ch in ['0'..'9']) then error(40) else repeat s := 10*s + ord(ch) - ord('0'); nextch until not (ch in ['0'..'9']); e := s*sign + e end (*readscale*) ; procedure adjustscale; var s: integer; d,t: real; begin if k+e > emax then error(21) else if k+e < emin then rnum := 0 else begin s := abs(e); t := 1.0; d := 10.0; repeat while not odd(s) do begin s := s div 2; d := sqr(d) end ; s := s-1; t := d*t until s = 0; if e >= 0 then rnum := rnum*t else rnum := rnum/t end end (*adjustscale*) ; begin (*insymbol*) 1: while (ch = ' ') or (ch=' '(*tab*)) 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(21); inum := 0; k := 0 end ; if ch = '.' then begin nextch; if ch = '.' then ch := ':' else begin sy := realcon; rnum := inum; e := 0; while ch in ['0'..'9'] do begin e := e-1; rnum := 10.0*rnum + (ord(ch)-ord('0')); nextch end ; if e = 0 then error(40); if ch = 'e' then readscale; if e <> 0 then adjustscale end end else if ch = 'e' then begin sy := realcon; rnum := inum; e := 0; readscale; if e <> 0 then adjustscale end ; end; '%',':' : begin nextch; 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 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(7); 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(38); sy := charcon; inum := 0 end else begin sy := string; inum := sx; sleng := k; sx := sx+k end end ; '(' : begin nextch; 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(24); nextch; goto 1 end end end (*insymbol*) ; (*---------------------------------------------------------- enter ---*) procedure enter(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(27); if (abs(l)>xmax) or (abs(h)>xmax) then begin error(27); 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 end (*enterarray*) ; 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 enterreal(x: real); begin if c2 = c2max-1 then fatal(3) else begin rconst[c2+1] := x; c1 := 1; while rconst[c1] <> x do c1 := c1+1; if c1 > c2 then c2 := c1 end end (*enterreal*) ; 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 printtables; var i: integer; o: order; begin writeln('0identifiers link obj typ ref nrm lev adr'); for i := btab[1].last +1 to t do with tab[i] do writeln(i,' ',name,link:5, ord(obj):5, ord(typ):5, ref:5, ord(normal):5, lev:5, adr:5); writeln('0blocks last lpar psze vsze'); for i := 1 to b do with btab[i] do writeln(i, last:5, lastpar:5, psize:5, vsize:5); writeln('0arrays xtyp etyp eref low high elsz size'); for i := 1 to a do with atab[i] do writeln(i, ord(inxtyp):5, ord(eltyp):5, elref:5, low:5, high:5, elsize:5, size:5); writeln('0code:'); for i := 0 to lc-1 do begin if i mod 5 = 0 then begin writeln; write(i:5) end ; o := code[i]; write(o.f:5); if o.f < 31 then if o.f < 4 then write(o.x:2, o.y:5) else write(o.y:7) else write(' '); write(',') end ; writeln end (*printtables*) ; (*-------------------------------------------------------------block--*) procedure block(fsys: symset; isfun: boolean; level: integer); type conrec = record case tp: types of ints,chars,bools: (i: integer); reals: (r: real) 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: integer); begin error(n); skipflag := true; while not (sy in fsys) do insymbol; if skipflag then endskip end (*skip*) ; procedure test(s1,s2: symset; n: integer); begin if not (sy in s1) then skip(s1+s2,n) end (*test*) ; procedure testsemicolon; begin if sy = semicolon then insymbol else begin error(14); if sy in [comma,colon] then insymbol end ; test([ident]+blockbegsys, fsys, 6) 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(1) 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(0); loc := j end (*loc*) ; procedure entervariable; begin if sy = ident then begin enter(id,variable); insymbol end else error(2) end (*entervariable*) ; procedure constant(fsys: symset; var c: conrec); var x, sign: integer; begin c.tp := notyp; c.i := 0; test(constbegsys, fsys, 50); 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(25) else begin c.tp := tab[x].typ; if c.tp = reals then c.r := sign*rconst[tab[x].adr] else 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 if sy = realcon then begin c.tp := reals; c.r := sign*rnum; insymbol end else skip(fsys,50) end; test(fsys, [], 6) 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,rparent,ofsy]+fsys, low); if low.tp = reals then begin error(27); low.tp := ints; low.i := 0 end ; if sy = colon then insymbol else error(13); constant([rbrack,comma,rparent,ofsy]+fsys, high); if high.tp <> low.tp then begin error(27); 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 begin error(12); if sy = rparent then insymbol end ; if sy = ofsy then insymbol else error(8); 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, 10); 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(29) else begin tp := typ; rf := ref; sz := adr; if tp = notyp then error(30) end ; insymbol end else if sy = arraysy then begin insymbol; if sy = lbrack then insymbol else begin error(11); if sy = lparent then insymbol end ; tp := arrays; arraytyp(rf,sz) end else begin (*records*) insymbol; enterblock; tp := records; rf := b; if level = lmax then fatal(5); level := level+1; display[level] := b; offset := 0; while not (sy in fsys-[semicolon,comma,ident]+[endsy]) do begin (*field section*) if sy = ident then begin t0 := t; entervariable; while sy = comma do begin insymbol; entervariable end ; if sy = colon then insymbol else error(5); t1 := t; typ(fsys+[semicolon,endsy,comma,ident],eltp,elrf,elsz); while t0 < t1 do begin t0 := t0+1; with tab[t0] do begin typ := eltp; ref := elrf; normal := true; adr := offset; offset := offset + elsz end end end ; if sy <> endsy then begin if sy = semicolon then insymbol else begin error(14); if sy = comma then insymbol end ; test([ident,endsy,semicolon], fsys, 6) end end ; btab[rf].vsize := offset; sz := offset; btab[rf].psize := 0; insymbol; level := level-1 end ; test(fsys, [], 6) 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], 7); 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(2) else begin x := loc(id); insymbol; if x <> 0 then with tab[x] do if obj <> type1 then error(29) else begin tp := typ; rf := ref; if valpar then sz := adr else sz := 1 end ; end ; test([semicolon,rparent], [comma,ident]+fsys, 14) end else error(5); 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 begin error(14); if sy = comma then insymbol end ; test([ident,varsy], [rparent]+fsys, 6) end end (*while*) ; if sy = rparent then begin insymbol; test([semicolon,colon], fsys, 6) end else error(4) end (*parameterlist*) ; procedure constantdeclaration; var c: conrec; begin insymbol; test([ident], blockbegsys, 2); while sy = ident do begin enter(id,konstant); insymbol; if sy = eql then insymbol else begin error(16); if sy = becomes then insymbol end ; constant([semicolon,comma,ident]+fsys,c); tab[t].typ := c.tp; tab[t].ref := 0; if c.tp = reals then begin enterreal(c.r); tab[t].adr := c1 end else tab[t].adr := c.i; testsemicolon end end (*constantdeclaration*) ; procedure typedeclaration; var tp: types; rf, sz, t1: integer; begin insymbol; test([ident], blockbegsys, 2); while sy = ident do begin enter(id,type1); t1 := t; insymbol; if sy = eql then insymbol else begin error(16); if sy = becomes then insymbol end ; 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 variabledeclaration; 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(5); 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 (*variabledeclaration*) ; procedure procdeclaration; var isfun: boolean; begin isfun := sy = functionsy; insymbol; if sy <> ident then begin error(2); 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(14); emit(32+ord(isfun)) (*exit*) end (*proceduredeclaration*) ; (*---------------------------------------------------------statement--*) 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 (*sy in [lparent, lbrack, period]*) repeat if sy = period then begin insymbol; (*field selector*) if sy <> ident then error(2) else begin if v.typ <> records then error(31) else begin (*ield identifier*) j := btab[v.ref] .last; tab[0].name := id; while tab[j].name <> id do j := tab[j].link; if j = 0 then error(0); v.typ := tab[j].typ; v.ref := tab[j].ref; a := tab[j].adr; if a <> 0 then emit1(9,a) end ; insymbol end end else begin (*array selector*) if sy <> lbrack then error(11); repeat insymbol; expression(fsys+[comma,rbrack], x); if v.typ <> arrays then error(28) else begin a := v.ref; if atab[a].inxtyp <> x.typ then error(26) else if atab[a].elsize = 1 then emit1(20,a) else emit1(21,a); v.typ := atab[a].eltyp; v.ref := atab[a].elref end until sy <> comma; if sy = rbrack then insymbol else begin error(12); if sy = rparent then insymbol end end until not (sy in [lbrack,lparent,period]); test(fsys, [], 6) end (*selector*) ; procedure call(fsys: symset; i: integer); var x: item; lastp, cp, k: integer; begin emit1(18,i); (*mark stack*) lastp := btab[tab[i].ref].lastpar; cp := i; if sy = lparent then begin (*actual parameter list*) repeat insymbol; if cp >= lastp then error(39) 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(36) else if x.typ = arrays then emit1(22,atab[x.ref].size) else if x.typ = records then emit1(22,btab[x.ref].vsize) end else if (x.typ=ints) and (tab[cp].typ=reals) then emit1(26,0) else if x.typ<>notyp then error(36); end else begin (*variable parameter*) if sy <> ident then error(2) else begin k := loc(id); insymbol; if k <> 0 then begin if tab[k].obj <> variable then error(37); 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 in [lbrack,lparent,period] then selector(fsys+[comma,colon,rparent], x); if (x.typ<>tab[cp].typ) or (x.ref<>tab[cp].ref) then error(36) end end end end ; test([comma,rparent], fsys, 6) until sy <> comma; if sy = rparent then insymbol else error(4) end ; if cp < lastp then error(39); (*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>reals) or (b>reals) then begin error(33); resulttype := notyp end else if (a=notyp) or (b=notyp) then resulttype := notyp else if a=ints then if b=ints then resulttype := ints else begin resulttype := reals; emit1(26,1) end else begin resulttype := reals; if b=ints then emit1(26,0) end end (*resulttype*) ; 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; procedure standfct(n: integer); var ts: typset; begin (*standard function no. n*) if sy = lparent then insymbol else error(9); if n < 17 then begin expression(fsys+[rparent],x); case n of (*abs,sqr*) 0,2: begin ts := [ints,reals]; tab[i].typ := x.typ; if x.typ = reals then n := n+1 end ; (*odd,chr*) 4,5: ts := [ints]; (*ord*) 6: ts := [ints,bools,chars]; (*succ,pred*) 7,8: begin ts := [ints,bools,chars]; tab[i].typ := x.typ end ; (*round,trunc*) 9,10,11,12,13,14,15,16: (*sin,cos,...*) begin ts := [ints,reals]; if x.typ = ints then emit1(26,0) end ; end ; if x.typ in ts then emit1(8,n) else if x.typ <> notyp then error(48); end else (*eof,eoln*) begin (*n in [17,18]*) if sy <> ident then error(2) else if id <> 'input ' then error(0) else insymbol; emit1(8,n); end ; x.typ := tab[i].typ; if sy = rparent then insymbol else error(4) end (*standfct*) ; begin (*factor*) x.typ := notyp; x.ref := 0; test(facbegsys, fsys, 58); 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; if x.typ = reals then emit1(25,adr) else emit1(24,adr) end ; variable: begin x.typ := typ; x.ref := ref; if sy in [lbrack,lparent,period] 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(44); funktion :begin x.typ := typ; if lev <> 0 then call(fsys, i) else standfct(adr) end end (*case,with*) end else if sy in [charcon,intcon,realcon] then begin if sy = realcon then begin x.typ := reals; enterreal(rnum); emit1(25, c1) end else begin if sy = charcon then x.typ := chars else x.typ := ints; emit1(24, inum) end ; x.ref := 0; insymbol end else if sy = lparent then begin insymbol; expression(fsys+[rparent], x); if sy = rparent then insymbol else error(4) 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(32) end ; test(fsys, facbegsys, 6) end (*while*) end (*factor*) ; begin (*term*) factor(fsys+[times,rdiv,idiv,imod,andsy], x); while sy in [times,rdiv,idiv,imod,andsy] do begin op := sy; insymbol; factor(fsys+[times,rdiv,idiv,imod,andsy], y); if op = times then begin x.typ := resulttype(x.typ, y.typ); case x.typ of notyp: ; ints : emit(57); reals: emit(60); end end else if op = rdiv then begin if x.typ = ints then begin emit1(26,1); x.typ := reals end ; if y.typ = ints then begin emit1(26,0); y.typ := reals end ; if (x.typ=reals) and (y.typ=reals) then emit(61) else begin if (x.typ<>notyp) and (y.typ<>notyp) then error(33); x.typ := notyp end 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(32); 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(34); 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 > reals then error(33) 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(32); x.typ := notyp end end else begin x.typ := resulttype(x.typ, y.typ); case x.typ of notyp: ; ints : if op = plus then emit(52) else emit(53); reals: if op = plus then emit(54) else emit(55) end 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 begin if x.typ = ints then begin x.typ := reals; emit1(26,1) end else if y.typ = ints then begin y.typ := reals; emit1(26,0) end ; if (x.typ=reals) and (y.typ=reals) then case op of eql: emit(39); neq: emit(40); lss: emit(41); leq: emit(42); gtr: emit(43); geq: emit(44); end else error(35) end ; 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 in [lbrack,lparent,period] then selector([becomes,eql]+fsys, x); if sy = becomes then insymbol else begin error(51); if sy = eql then insymbol end ; 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(46) else if x.typ = arrays then emit1(23, atab[x.ref].size) else emit1(23, btab[x.ref].vsize) else if (x.typ=reals) and (y.typ=ints) then begin emit1(26,0); emit(38) end else if (x.typ<>notyp) and (y.typ<>notyp) then error(46) end (*assignment*) ; procedure compoundstatement; var iscompound:boolean (* check for extra begin..ends *); begin insymbol; iscompound:=false; statement([semicolon,endsy]+fsys); while sy in [semicolon]+statbegsys do begin if sy = semicolon then insymbol else error(14); iscompound:=true; statement([semicolon,endsy]+fsys) end ; if sy = endsy then insymbol else error(57); if not iscompound and (errs=[]) then writeln(' last begin..end pair superflous') end (*compoundstatemenet*) ; procedure ifstatement; var x: item; lc1,lc2: integer; begin insymbol; expression(fsys+[thensy,dosy], x); if not (x.typ in [bools,notyp]) then error(17); lc1 := lc; emit(11); (*jmpc*) if sy = thensy then insymbol else begin error(52); if sy = dosy then insymbol end ; 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 casestatement; var x: item; i,j,k,lc1: integer; casetab: array [1..csmax] of packed record val, lc: index end ; exittab: array [1..csmax] of integer; procedure caselabel; var lab: conrec; k: integer; begin constant(fsys+[comma,colon], lab); if lab.tp <> x.typ then error(47) else if i = csmax then fatal(6) else begin i := i+1; k := 0; casetab[i].val := lab.i; casetab[i].lc := lc; repeat k := k+1 until casetab[k].val = lab.i; if k < i then error(1); (*multiple definition*) end end (*caselabel*) ; procedure onecase; begin if sy in constbegsys then begin caselabel; while sy = comma do begin insymbol; caselabel end ; if sy = colon then insymbol else error(5); statement([semicolon,endsy]+fsys); j := j+1; exittab[j] := lc; emit(10) end end (*onecase*) ; begin insymbol; i := 0; j := 0; expression(fsys+[ofsy,comma,colon], x); if not (x.typ in [ints,bools,chars,notyp]) then error(23); lc1 := lc; emit(12); (*jmpx*) if sy = ofsy then insymbol else error(8); onecase; while sy = semicolon do begin insymbol; onecase end ; code[lc1].y := lc; for k := 1 to i do begin emit1(13,casetab[k].val); emit1(13,casetab[k].lc) end ; emit1(10,0); for k := 1 to j do code[exittab[k]].y := lc; if sy = endsy then insymbol else error(57) end (*casestatement*) ; 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(14); statement([semicolon,untilsy]+fsys) end ; if sy = untilsy then begin insymbol; expression(fsys, x); if not (x.typ in [bools,notyp]) then error(17); emit1(11,lc1) end else error(53) 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(17); lc2 := lc; emit(11); if sy = dosy then insymbol else error(54); statement(fsys); emit1(10,lc1); code[lc2].y := lc end (*whilestatement*) ; procedure forstatement; var cvt: types; x: item; i,f,lc1,lc2: integer; begin insymbol; if sy = ident then begin i := loc(id); insymbol; if i = 0 then cvt := ints else if tab[i].obj = variable then begin cvt := tab[i].typ; if not tab[i].normal then error(37) else emit2(0, tab[i].lev, tab[i].adr); if not (cvt in [notyp,ints,bools,chars]) then error(18) end else begin error(37); cvt := ints end end else skip([becomes,tosy,downtosy,dosy]+fsys, 2); if sy = becomes then begin insymbol; expression([tosy,downtosy,dosy]+fsys, x); if x.typ <> cvt then error(19); end else skip([tosy,downtosy,dosy]+fsys, 51); f := 14; if sy in [tosy, downtosy] then begin if sy = downtosy then f := 16; insymbol; expression([dosy]+fsys, x); if x.typ <> cvt then error(19) end else skip([dosy]+fsys, 55); lc1 := lc; emit(f); if sy = dosy then insymbol else error(54); lc2 := lc; statement(fsys); emit1(f+1,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 not iflag then begin error(20); iflag := true end ; if sy = lparent then begin repeat insymbol; if sy <> ident then error(2) else begin i := loc(id); insymbol; if i <> 0 then if tab[i].obj <> variable then error(37) 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 in [lbrack,lparent,period] then selector(fsys+[comma,rparent], x); if x.typ in [ints,reals,chars,notyp] then emit1(27, ord(x.typ)) else error(41) end end ; test([comma,rparent], fsys, 6); until sy <> comma; if sy = rparent then insymbol else error(4) 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(41); if sy = colon then begin insymbol; expression(fsys+[comma,colon,rparent], y); if y.typ <> ints then error(43); if sy = colon then begin if x.typ <> reals then error(42); insymbol; expression(fsys+[comma,rparent], y); if y.typ <> ints then error(43); emit(37) end else emit1(30, ord(x.typ)) end else emit1(29, ord(x.typ)) end until sy <> comma; if sy = rparent then insymbol else error(4) end ; if n = 4 then emit(63) 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(45); 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(45) end end ; beginsy: compoundstatement; ifsy: ifstatement; casesy: casestatement; whilesy: whilestatement; repeatsy: repeatstatement; forsy: forstatement; end else if errs=[] then writeln('^':cc+6,'warning: null statement'); test(fsys, [], 14) end (*statement*) ; begin (*block*) dx := 5; prt := t; if level > lmax then fatal(5); test([lparent,colon,semicolon], fsys, 14); 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(29) else if tab[x].typ in stantyps then tab[prt].typ := tab[x].typ else error(15) end else skip([semicolon]+fsys, 2) end else error(5); if sy = semicolon then insymbol else error(14); repeat if sy = constsy then constantdeclaration; if sy = typesy then typedeclaration; if sy = varsy then variabledeclaration; btab[prb].vsize := dx; while sy in [proceduresy,functionsy] do procdeclaration; test([beginsy], blockbegsys+statbegsys, 56) 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(14); statement([semicolon,endsy]+fsys) end ; if sy = endsy then insymbol else error(57); test(fsys+[period], [], 6) end (*block*) ; (*-------------------------------------------------------interpret---*) procedure interpret; (*global code, tab, btab*) label 98; (*trap label*) var ir: order; (*instruction buffer*) pc: integer; (*program counter*) ps: (run,fin,caschk,divchk,inxchk,stkchk,linchk,lngchk,redchk); t: integer; (*top stack index*) b: integer; (*base index*) lncnt, ocnt, blkcnt, chrcnt: integer; (*counters*) h1,h2,h3,h4: integer; fld: array [1..4] of integer; (*default field widths*) display: array [1..lmax] of integer; s: array [1..stacksize] of (*blockmark: *) record case types of (* s[b+0] = fct result *) ints: (i: integer); (* s[b+1] = return adr *) reals: (r: real); (* s[b+2] = static link *) bools: (b: boolean); (* s[b+3] = dynamic link*) chars: (c: char) (* s[b+4] = table index *) end ; undefval: record case types of ints: (i: integer); reals: (r: real); bools: (b: boolean); chars: (c: alfa) end; begin (*interpret*) s[1].i := 0; s[2].i := 0; s[3].i := -1; s[4].i := btab[1].last; t := btab[2].vsize - 1; pc := tab[s[4].i].adr; undefval.c[1]:=''''; for b:=2 to 10 do undefval.c[b]:=chr(0); for b:=5 to t do s[b].r:=undefval.r; b := 0; display[1] := 0; ps := run; lncnt := 0; ocnt := 0; chrcnt := 0; fld[1] := 10; fld[2] := 22; fld[3] := 10; fld[4] := 1; repeat ir := code[pc]; pc := pc+1; ocnt := ocnt + 1; case ir.f of 0: begin (*load address*) t := t+1; if t > stacksize then ps := stkchk else s[t].i := display[ir.x] + ir.y end ; 1: begin (*load value*) t := t+1; if t > stacksize then ps := stkchk else s[t] := s[display[ir.x] + ir.y] end ; 2: begin (*load indirect*) t := t+1; if t > stacksize then ps := stkchk else s[t] := s[s[display[ir.x] + ir.y].i] end ; 3: begin (*update display*) h1 := ir.y; h2 := ir.x; h3 := b; repeat display[h1] := h3; h1 := h1-1; h3 := s[h3+2].i until h1 = h2 end ; 8: case ir.y of 0: s[t].i := abs(s[t].i); 1: s[t].r := abs(s[t].r); 2: s[t].i := sqr(s[t].i); 3: s[t].r := sqr(s[t].r); 4: s[t].b := odd(s[t].i); 5: begin (* s[t].c := chr(s[t].i); *) if (s[t].i < 0) or (s[t].i > 63) then ps := inxchk end ; 6: (* s[t].i := ord(s[t].c) *); 7: s[t].c := succ(s[t].c); 8: s[t].c := pred(s[t].c); 9: s[t].i := round(s[t].r); 10: s[t].i := trunc(s[t].r); 11: s[t].r := sin(s[t].r); 12: s[t].r := cos(s[t].r); 13: s[t].r := exp(s[t].r); 14: s[t].r := ln(s[t].r); 15: s[t].r := sqrt(s[t].r); 16: s[t].r := arctan(s[t].r); 17: begin t := t+1; if t > stacksize then ps := stkchk else s[t].b := eof(input) end ; 18: begin t := t+1; if t > stacksize then ps := stkchk else s[t].b := eoln(input) end ; end ; 9: s[t].i := s[t].i + ir.y; (*offset*) 10: pc := ir.y; (*jump*) 11: begin (*conditional jump*) if not s[t].b then pc := ir.y; t := t-1 end ; 12: begin (*switch*) h1 := s[t].i; t := t-1; h2 := ir.y; h3 := 0; repeat if code[h2].f <> 13 then begin h3 := 1; ps := caschk end else if code[h2].y = h1 then begin h3 := 1; pc := code[h2+1].y end else h2 := h2 + 2 until h3 <> 0 end ; 14: begin (*for1up*) h1 := s[t-1].i; if h1 <= s[t].i then s[s[t-2].i].i := h1 else begin t := t-3; pc := ir.y end end ; 15: begin (*for2up*) h2 := s[t-2].i; h1 := s[h2].i + 1; if h1 <= s[t].i then begin s[h2].i := h1; pc := ir.y end else t := t-3; end ; 16: begin (*for1down*) h1 := s[t-1].i; if h1 >= s[t].i then s[s[t-2].i].i := h1 else begin pc := ir.y; t := t-3 end end ; 17: begin (*for2down*) h2 := s[t-2].i; h1 := s[h2].i - 1; if h1 >= s[t].i then begin s[h2].i := h1; pc := ir.y end else t := t-3; end ; 18: begin (*mark stack*) h1 := btab[tab[ir.y].ref].vsize; if t+h1 > stacksize then ps := stkchk else begin t := t+5; s[t-1].i := h1-1; s[t].i := ir.y end end ; 19: begin (*call*) h1 := t - ir.y; (*h1 points to base*) h2 := s[h1+4].i; (*h2 points to tab*) h3 := tab[h2].lev; display[h3+1] := h1; h4 := s[h1+3].i + h1; s[h1+1].i := pc; s[h1+2].i := display[h3]; s[h1+3].i := b; for h3 := t+1 to h4 do s[h3].r := undefval.r; b := h1; t := h4; pc := tab[h2].adr end ; 20: begin (*index1*) h1 := ir.y; (*h1 points to atab*) h2 := atab[h1].low; h3 := s[t].i; if h3 < h2 then ps := inxchk else if h3 > atab[h1].high then ps := inxchk else begin t := t-1; s[t].i := s[t].i + (h3-h2) end end ; 21: begin (*index*) h1 := ir.y; (*h1 points to atab*) h2 := atab[h1].low; h3 := s[t].i; if h3 < h2 then ps := inxchk else if h3 > atab[h1].high then ps := inxchk else begin t := t-1; s[t].i := s[t].i + (h3-h2)*atab[h1].elsize end end ; 22: begin (*load block*) h1 := s[t].i; t := t-1; h2 := ir.y + t; if h2 > stacksize then ps := stkchk else while t < h2 do begin t := t+1; s[t] := s[h1]; h1 := h1+1 end end ; 23: begin (*copy block*) h1 := s[t-1].i; h2 := s[t].i; h3 := h1 + ir.y; while h1 < h3 do begin s[h1] := s[h2]; h1 := h1+1; h2 := h2+1 end ; t := t-2 end ; 24: begin (*literal*) t := t+1; if t > stacksize then ps := stkchk else s[t].i := ir.y end ; 25: begin (*load real*) t := t+1; if t > stacksize then ps := stkchk else s[t].r := rconst[ir.y] end ; 26: begin (*float*) h1 := t - ir.y; s[h1].r := s[h1].i end ; 27: begin (*read*) if eof(input) then ps := redchk else case ir.y of 1: read(s[s[t].i].i); 2: read(s[s[t].i].r); 4: read(s[s[t].i].c); end ; t := t-1 end ; 28: begin (*write string*) h1 := s[t].i; h2 := ir.y; t := t-1; chrcnt := chrcnt+h1; if chrcnt > lineleng then ps := lngchk; repeat write(stab[h2]); h1 := h1-1; h2 := h2+1 until h1 = 0 end ; 29: begin (*write1*) chrcnt := chrcnt + fld[ir.y]; if chrcnt > lineleng then ps := lngchk else case ir.y of 1: write(s[t].i: fld[1]); 2: write(s[t].r: fld[2]); 3: write(s[t].b: fld[3]); 4: write(chr(s[t].i mod 64)); end ; t := t-1 end ; 30: begin (*write2*) chrcnt := chrcnt + s[t].i; if chrcnt > lineleng then ps := lngchk else case ir.y of 1: write(s[t-1].i: s[t].i); 2: write(s[t-1].r: s[t].i); 3: write(s[t-1].b: s[t].i); 4: write(chr(s[t-1].i mod 64): s[t].i); end ; t := t-2 end ; 31: ps := fin; 32: begin (*exit procedure*) t := b-1; pc := s[b+1].i; b := s[b+3].i end ; 33: begin (*exit function*) t := b; pc := s[b+1].i; b := s[b+3].i end ; 34: s[t] := s[s[t].i]; 35: s[t].b := not s[t].b; 36: s[t].i := - s[t].i; 37: begin chrcnt := chrcnt + s[t-1].i; if chrcnt > lineleng then ps := lngchk else write(s[t-2].r: s[t-1].i: s[t].i); t := t-3 end ; 38: begin (*store*) s[s[t-1].i] := s[t]; t := t-2 end ; 39: begin t := t-1; s[t].b := s[t].r = s[t+1].r end ; 40: begin t := t-1; s[t].b := s[t].r <> s[t+1].r end ; 41: begin t := t-1; s[t].b := s[t].r < s[t+1].r end ; 42: begin t := t-1; s[t].b := s[t].r <= s[t+1].r end ; 43: begin t := t-1; s[t].b := s[t].r > s[t+1].r end ; 44: begin t := t-1; s[t].b := s[t].r >= s[t+1].r end ; 45: begin t := t-1; s[t].b := s[t].i = s[t+1].i end ; 46: begin t := t-1; s[t].b := s[t].i <> s[t+1].i end ; 47: begin t := t-1; s[t].b := s[t].i < s[t+1].i end ; 48: begin t := t-1; s[t].b := s[t].i <= s[t+1].i end ; 49: begin t := t-1; s[t].b := s[t].i > s[t+1].i end ; 50: begin t := t-1; s[t].b := s[t].i >= s[t+1].i end ; 51: begin t := t-1; s[t].b := s[t].b or s[t+1].b end ; 52: begin t := t-1; s[t].i := s[t].i + s[t+1].i end ; 53: begin t := t-1; s[t].i := s[t].i - s[t+1].i end ; 54: begin t := t-1; s[t].r := s[t].r + s[t+1].r; end ; 55: begin t := t-1; s[t].r := s[t].r - s[t+1].r; end ; 56: begin t := t-1; s[t].b := s[t].b and s[t+1].b end ; 57: begin t := t-1; s[t].i := s[t].i * s[t+1].i end ; 58: begin t := t-1; if s[t+1].i = 0 then ps := divchk else s[t].i := s[t].i div s[t+1].i end ; 59: begin t := t-1; if s[t+1].i = 0 then ps := divchk else s[t].i := s[t].i mod s[t+1].i end ; 60: begin t := t-1; s[t].r := s[t].r * s[t+1].r; end ; 61: begin t := t-1; s[t].r := s[t].r / s[t+1].r; end ; 62: if eof(input) then ps := redchk else readln; 63: begin writeln; lncnt := lncnt + 1; chrcnt := 0; if lncnt > linelimit then ps := linchk end end (*case*) ; until ps <> run; 98: if ps <> fin then begin writeln; write('0halt at', pc:5, ' because of '); case ps of run: writeln('error (see dayfile)'); caschk: writeln('undefined case'); divchk: writeln('division by 0'); inxchk: writeln('invalid index'); stkchk: writeln('storage overflow'); linchk: writeln('too much output'); lngchk: writeln('line too long'); redchk: writeln('reading past end of file'); end ; h1 := b; blkcnt := 10; (*post mortem dump*) repeat writeln; blkcnt := blkcnt - 1; if blkcnt = 0 then h1 := 0; h2 := s[h1+4].i; if h1<>0 then writeln(' ', tab[h2].name, ' called at', s[h1+1].i: 5); h2 := btab[tab[h2].ref].last; while h2 <> 0 do with tab[h2] do begin if obj = variable then if typ in stantyps then begin write(' ', name, ' = '); if normal then h3 := h1+adr else h3 := s[h1+adr].i; if undefined(s[h3].r) then writeln(' undefined') else case typ of ints: writeln(s[h3].i); reals: writeln(s[h3].r); bools: writeln(s[h3].b); chars: writeln(chr(s[h3].i mod 64)); end end ; h2 := link end ; h1 := s[h1+3].i until h1 < 0; end ; writeln; writeln(ocnt, ' steps') end (*interpret*) ; (*------------------------------------------------------------main----*) begin (*main*) message('- pascals (12 mar 80)'); writeln; writeln; writeln; key[ 1] := 'and '; key[ 2] := 'array '; key[ 3] := 'begin '; key[ 4] := 'case '; key[ 5] := 'const '; key[ 6] := 'div '; key[ 8] := 'downto '; (* do and downto have a common stem *) key[ 7] := 'do '; (* reverse in DEC computers, see ksy too *) key[ 9] := 'else '; key[10] := 'end '; key[11] := 'for '; key[12] := 'function '; key[13] := 'if '; key[14] := 'mod '; key[15] := 'not '; key[16] := 'of '; key[17] := 'or '; key[18] := 'procedure '; key[19] := 'program '; key[20] := 'record '; key[21] := 'repeat '; key[22] := 'then '; key[23] := 'to '; key[24] := 'type '; key[25] := 'until '; key[26] := 'var '; key[27] := 'while '; ksy[ 1] := andsy; ksy[ 2] := arraysy; ksy[ 3] := beginsy; ksy[ 4] := casesy; ksy[ 5] := constsy; ksy[ 6] := idiv; ksy[ 8] := downtosy; (* see key above ^^^^^^^^^^^^^^^^^^ *) ksy[ 7] := dosy; ksy[ 9] := elsesy; ksy[10] := endsy; ksy[11] := forsy; ksy[12] := functionsy; ksy[13] := ifsy; ksy[14] := imod; ksy[15] := notsy; ksy[16] := ofsy; ksy[17] := orsy; ksy[18] := proceduresy; ksy[19] := programsy; ksy[20] := recordsy; ksy[21] := repeatsy; ksy[22] := thensy; ksy[23] := tosy; ksy[24] := typesy; ksy[25] := untilsy; ksy[26] := varsy; ksy[27] := whilesy; sps['+'] := plus; sps['-'] := minus; sps['*'] := times; sps['/'] := rdiv; sps['('] := lparent; sps[')'] := rparent; sps['='] := eql; sps[','] := comma; sps['['] := lbrack; sps[']'] := rbrack; sps['"'] := neq; sps['&'] := andsy; sps[';'] := semicolon; constbegsys := [plus,minus,intcon,realcon,charcon,ident]; typebegsys := [ident,arraysy,recordsy]; blockbegsys := [constsy,typesy,varsy,proceduresy,functionsy,beginsy]; facbegsys := [intcon,realcon,charcon,ident,lparent,notsy]; statbegsys := [beginsy,ifsy,whilesy,repeatsy,forsy,casesy]; stantyps := [notyp,ints,reals,bools,chars]; lc := 0; ll := 0; cc := 0; ch := ' '; errpos := 0; errs := []; insymbol; t := -1; a := 0; b := 1; sx := 0; c2 := 0; display[0] := 1; iflag := false; oflag := false; skipflag := false; if sy <> programsy then error(3) else begin insymbol; if sy <> ident then error(2) else begin progname := id; insymbol; if sy <> lparent then error(9) else repeat insymbol; if sy <> ident then error(2) else begin if id = 'input ' then iflag := true else if id = 'output ' then oflag := true else error(0); insymbol end until sy <> comma; if sy = rparent then insymbol else error(4); if not oflag then error(20) end end ; enter(' ', variable, notyp, 0); (*sentinel*) enter('false ', konstant, bools, 0); enter('true ', konstant, bools, 1); enter('real ', type1, reals, 1); enter('char ', type1, chars, 1); enter('boolean ', type1, bools, 1); enter('integer ', type1, ints , 1); enter('abs ', funktion, reals,0); enter('sqr ', funktion, reals,2); enter('odd ', funktion, bools,4); enter('chr ', funktion, chars,5); enter('ord ', funktion, ints, 6); enter('succ ', funktion, chars,7); enter('pred ', funktion, chars,8); enter('round ', funktion, ints, 9); enter('trunc ', funktion, ints, 10); enter('sin ', funktion, reals, 11); enter('cos ', funktion, reals, 12); enter('exp ', funktion, reals, 13); enter('ln ', funktion, reals, 14); enter('sqrt ', funktion, reals, 15); enter('arctan ', funktion, reals, 16); enter('eof ', funktion, bools, 17); enter('eoln ', funktion, bools, 18); enter('read ', prozedure, notyp, 1); enter('readln ', prozedure, notyp, 2); enter('write ', prozedure, notyp, 3); enter('writeln ', prozedure, notyp, 4); enter(' ', prozedure, notyp, 0); with btab[1] do begin last := t; lastpar := 1; psize := 0; vsize := 0 end ; block(blockbegsys+statbegsys, false, 1); (* parse prog body *) if sy <> period then error(22); emit(31); (*halt*) if btab[2].vsize > stacksize then error(49); if progname = 'test0 ' then printtables; if errs = [] then begin (* for VAX no segmented files if iflag then begin getseg(input); if eof(input) then writeln(' input data missing') else begin writeln(' (eor)'); copy input data while not eof(input) do begin write(' '); while not eoln(input) do begin read(ch); write(ch) end ; writeln; read(ch) end ; getseg(input,0) end end ; writeln(' (eof)'); writeln; not VAX *) interpret end else errormsg; 99: writeln end.