(*$c+,t-,d-,l-*) (*********************************************** * * * Portable Pascal compiler * * ************************ * * * * Pascal P4 * * * * Authors: * * Urs Ammann * * Kesav Nori * * Christian Jacobi * * Address: * * Institut Fuer Informatik * * Eidg. Technische Hochschule * * CH-8096 Zuerich * * * * This code is fully documented in the book * * "Pascal Implementation" * * by Steven Pemberton and Martin Daniels * * published by Ellis Horwood, Chichester, UK * * ISBN: 0-13-653-0311 * * (also available in Japanese) * * * * Steven Pemberton, CWI/AA, * * Kruislaan 413, 1098 SJ Amsterdam, NL * * Steven.Pemberton@cwi.nl * * * ***********************************************) program pascalcompiler(input,output,prr); const displimit = 20; maxlevel = 10; intsize = 1; intal = 1; realsize = 1; realal = 1; charsize = 1; charal = 1; charmax = 1; boolsize = 1; boolal = 1; ptrsize = 1; adral = 1; setsize = 1; setal = 1; stackal = 1; stackelsize = 1; strglgth = 16; sethigh = 47; setlow = 0; ordmaxchar = 63; ordminchar = 0; maxint = 32767; lcaftermarkstack = 5; fileal = charal; (* stackelsize = minimum size for 1 stackelement = k*stackal stackal = scm(all other al-constants) charmax = scm(charsize,charal) scm = smallest common multiple lcaftermarkstack >= 4*ptrsize+max(x-size) = k1*stackelsize *) maxstack = 1; parmal = stackal; parmsize = stackelsize; recal = stackal; filebuffer = 4; maxaddr = maxint; type (*describing:*) (*************) marktype= ^integer; (*basic symbols*) (***************) symbol = (ident,intconst,realconst,stringconst,notsy,mulop,addop,relop, lparent,rparent,lbrack,rbrack,comma,semicolon,period,arrow, colon,becomes,labelsy,constsy,typesy,varsy,funcsy,progsy, procsy,setsy,packedsy,arraysy,recordsy,filesy,forwardsy, beginsy,ifsy,casesy,repeatsy,whilesy,forsy,withsy, gotosy,endsy,elsesy,untilsy,ofsy,dosy,tosy,downtosy, thensy,othersy); operator = (mul,rdiv,andop,idiv,imod,plus,minus,orop,ltop,leop,geop,gtop, neop,eqop,inop,noop); setofsys = set of symbol; chtp = (letter,number,special,illegal, chstrquo,chcolon,chperiod,chlt,chgt,chlparen,chspace); (*constants*) (***********) setty = set of setlow..sethigh; cstclass = (reel,pset,strg); csp = ^ constant; constant = record case cclass: cstclass of reel: (rval: packed array [1..strglgth] of char); pset: (pval: setty); strg: (slgth: 0..strglgth; sval: packed array [1..strglgth] of char) end; valu = record case intval: boolean of (*intval never set nor tested*) true: (ival: integer); false: (valp: csp) end; (*data structures*) (*****************) levrange = 0..maxlevel; addrrange = 0..maxaddr; structform = (scalar,subrange,pointer,power,arrays,records,files, tagfld,variant); declkind = (standard,declared); stp = ^ structure; ctp = ^ identifier; structure = packed record marked: boolean; (*for test phase only*) size: addrrange; case form: structform of scalar: (case scalkind: declkind of declared: (fconst: ctp); standard: ()); subrange: (rangetype: stp; min,max: valu); pointer: (eltype: stp); power: (elset: stp); arrays: (aeltype,inxtype: stp); records: (fstfld: ctp; recvar: stp); files: (filtype: stp); tagfld: (tagfieldp: ctp; fstvar: stp); variant: (nxtvar,subvar: stp; varval: valu) end; (*names*) (*******) idclass = (types,konst,vars,field,proc,func); setofids = set of idclass; idkind = (actual,formal); alpha = packed array [1..8] of char; identifier = packed record name: alpha; llink, rlink: ctp; idtype: stp; next: ctp; case klass: idclass of types: (); konst: (values: valu); vars: (vkind: idkind; vlev: levrange; vaddr: addrrange); field: (fldaddr: addrrange); proc, func: (case pfdeckind: declkind of standard: (key: 1..15); declared: (pflev: levrange; pfname: integer; case pfkind: idkind of actual: (forwdecl, externl: boolean); formal: ())) end; disprange = 0..displimit; where = (blck,crec,vrec,rec); (*expressions*) (*************) attrkind = (cst,varbl,expr); vaccess = (drct,indrct,inxd); attr = record typtr: stp; case kind: attrkind of cst: (cval: valu); varbl: (case access: vaccess of drct: (vlevel: levrange; dplmt: addrrange); indrct: (idplmt: addrrange)) end; testp = ^ testpointer; testpointer = packed record elt1,elt2 : stp; lasttestp : testp end; (*labels*) (********) lbp = ^ labl; labl = record nextlab: lbp; defined: boolean; labval, labname: integer end; extfilep = ^filerec; filerec = record filename:alpha; nextfile:extfilep end; (*-------------------------------------------------------------------------*) var prr: text; (* comment this out when compiling with pcom *) (*returned by source program scanner insymbol: **********) sy: symbol; (*last symbol*) op: operator; (*classification of last symbol*) val: valu; (*value of last constant*) lgth: integer; (*length of last string constant*) id: alpha; (*last identifier (possibly truncated)*) kk: 1..8; (*nr of chars in last identifier*) ch: char; (*last character*) eol: boolean; (*end of line flag*) (*counters:*) (***********) chcnt: integer; (*character counter*) lc,ic: addrrange; (*data location and instruction counter*) linecount: integer; (*switches:*) (***********) dp, (*declaration part*) prterr, (*to allow forward references in pointer type declaration by suppressing error message*) list,prcode,prtables: boolean; (*output options for -- source program listing -- printing symbolic code -- displaying ident and struct tables --> procedure option*) debug: boolean; (*pointers:*) (***********) parmptr, intptr,realptr,charptr, boolptr,nilptr,textptr: stp; (*pointers to entries of standard ids*) utypptr,ucstptr,uvarptr, ufldptr,uprcptr,ufctptr, (*pointers to entries for undeclared ids*) fwptr: ctp; (*head of chain of forw decl type ids*) fextfilep: extfilep; (*head of chain of external files*) globtestp: testp; (*last testpointer*) (*bookkeeping of declaration levels:*) (************************************) level: levrange; (*current static level*) disx, (*level of last id searched by searchid*) top: disprange; (*top of display*) display: (*where: means:*) array [disprange] of packed record (*=blck: id is variable id*) fname: ctp; flabel: lbp; (*=crec: id is field id in record with*) case occur: where of (* constant address*) crec: (clev: levrange; (*=vrec: id is field id in record with*) cdspl: addrrange);(* variable address*) vrec: (vdspl: addrrange) end; (* --> procedure withstatement*) (*error messages:*) (*****************) errinx: 0..10; (*nr of errors in current source line*) errlist: array [1..10] of packed record pos: integer; nmr: 1..400 end; (*expression compilation:*) (*************************) gattr: attr; (*describes the expr currently compiled*) (*structured constants:*) (***********************) constbegsys,simptypebegsys,typebegsys,blockbegsys,selectsys,facbegsys, statbegsys,typedels: setofsys; chartp : array[char] of chtp; rw: array [1..35(*nr. of res. words*)] of alpha; frw: array [1..9] of 1..36(*nr. of res. words + 1*); rsy: array [1..35(*nr. of res. words*)] of symbol; ssy: array [char] of symbol; rop: array [1..35(*nr. of res. words*)] of operator; sop: array [char] of operator; na: array [1..35] of alpha; mn: array [0..60] of packed array [1..4] of char; sna: array [1..23] of packed array [1..4] of char; cdx: array [0..60] of -4..+4; pdx: array [1..23] of -7..+7; ordint: array [char] of integer; intlabel,mxint10,digmax: integer; (*-------------------------------------------------------------------------*) procedure mark(var p: marktype); begin end; procedure release(p: marktype); begin end; procedure endofline; var lastpos,freepos,currpos,currnmr,f,k: integer; begin if errinx > 0 then (*output error messages*) begin write(output,linecount:6,' **** ':9); lastpos := 0; freepos := 1; for k := 1 to errinx do begin with errlist[k] do begin currpos := pos; currnmr := nmr end; if currpos = lastpos then write(output,',') else begin while freepos < currpos do begin write(output,' '); freepos := freepos + 1 end; write(output,'^'); lastpos := currpos end; if currnmr < 10 then f := 1 else if currnmr < 100 then f := 2 else f := 3; write(output,currnmr:f); freepos := freepos + f + 1 end; writeln(output); errinx := 0 end; linecount := linecount + 1; if list and (not eof(input)) then begin write(output,linecount:6,' ':2); if dp then write(output,lc:7) else write(output,ic:7); write(output,' ') end; chcnt := 0 end (*endofline*) ; procedure error(ferrnr: integer); begin if errinx >= 9 then begin errlist[10].nmr := 255; errinx := 10 end else begin errinx := errinx + 1; errlist[errinx].nmr := ferrnr end; errlist[errinx].pos := chcnt end (*error*) ; procedure insymbol; (*read next basic symbol of source program and return its description in the global variables sy, op, id, val and lgth*) label 1,2,3; var i,k: integer; digit: packed array [1..strglgth] of char; string: packed array [1..strglgth] of char; lvp: csp; test: boolean; procedure nextch; begin if eol then begin if list then writeln(output); endofline end; if not eof(input) then begin eol := eoln(input); read(input,ch); if list then write(output,ch); chcnt := chcnt + 1 end else begin writeln(output,' *** eof ','encountered'); test := false end end; procedure options; begin repeat nextch; if ch <> '*' then begin if ch = 't' then begin nextch; prtables := ch = '+' end else if ch = 'l' then begin nextch; list := ch = '+'; if not list then writeln(output) end else if ch = 'd' then begin nextch; debug := ch = '+' end else if ch = 'c' then begin nextch; prcode := ch = '+' end; nextch end until ch <> ',' end (*options*) ; begin (*insymbol*) 1: repeat while ((ch = ' ') or (ch = ' ')) and not eol do nextch; test := eol; if test then nextch until not test; if chartp[ch] = illegal then begin sy := othersy; op := noop; error(399); nextch end else case chartp[ch] of letter: begin k := 0; repeat if k < 8 then begin k := k + 1; id[k] := ch end ; nextch until chartp[ch] in [special,illegal,chstrquo,chcolon, chperiod,chlt,chgt,chlparen,chspace]; if k >= kk then kk := k else repeat id[kk] := ' '; kk := kk - 1 until kk = k; for i := frw[k] to frw[k+1] - 1 do if rw[i] = id then begin sy := rsy[i]; op := rop[i]; goto 2 end; sy := ident; op := noop; 2: end; number: begin op := noop; i := 0; repeat i := i+1; if i<= digmax then digit[i] := ch; nextch until chartp[ch] <> number; if ((ch = '.') and (input^ <> '.')) or (ch = 'e') then begin k := i; if ch = '.' then begin k := k+1; if k <= digmax then digit[k] := ch; nextch; (*if ch = '.' then begin ch := ':'; goto 3 end;*) if chartp[ch] <> number then error(201) else repeat k := k + 1; if k <= digmax then digit[k] := ch; nextch until chartp[ch] <> number end; if ch = 'e' then begin k := k+1; if k <= digmax then digit[k] := ch; nextch; if (ch = '+') or (ch ='-') then begin k := k+1; if k <= digmax then digit[k] := ch; nextch end; if chartp[ch] <> number then error(201) else repeat k := k+1; if k <= digmax then digit[k] := ch; nextch until chartp[ch] <> number end; new(lvp,reel); sy:= realconst; lvp^.cclass := reel; with lvp^ do begin for i := 1 to strglgth do rval[i] := ' '; if k <= digmax then for i := 2 to k + 1 do rval[i] := digit[i-1] else begin error(203); rval[2] := '0'; rval[3] := '.'; rval[4] := '0' end end; val.valp := lvp end else 3: begin if i > digmax then begin error(203); val.ival := 0 end else with val do begin ival := 0; for k := 1 to i do begin if ival <= mxint10 then ival := ival*10+ordint[digit[k]] else begin error(203); ival := 0 end end; sy := intconst end end end; chstrquo: begin lgth := 0; sy := stringconst; op := noop; repeat repeat nextch; lgth := lgth + 1; if lgth <= strglgth then string[lgth] := ch until (eol) or (ch = ''''); if eol then error(202) else nextch until ch <> ''''; lgth := lgth - 1; (*now lgth = nr of chars in string*) if lgth = 0 then error(205) else if lgth = 1 then val.ival := ord(string[1]) else begin new(lvp,strg); lvp^.cclass:=strg; if lgth > strglgth then begin error(399); lgth := strglgth end; with lvp^ do begin slgth := lgth; for i := 1 to lgth do sval[i] := string[i] end; val.valp := lvp end end; chcolon: begin op := noop; nextch; if ch = '=' then begin sy := becomes; nextch end else sy := colon end; chperiod: begin op := noop; nextch; if ch = '.' then begin sy := colon; nextch end else sy := period end; chlt: begin nextch; sy := relop; if ch = '=' then begin op := leop; nextch end else if ch = '>' then begin op := neop; nextch end else op := ltop end; chgt: begin nextch; sy := relop; if ch = '=' then begin op := geop; nextch end else op := gtop end; chlparen: begin nextch; if ch = '*' then begin nextch; if ch = '$' then options; repeat while (ch <> '*') and not eof(input) do nextch; nextch until (ch = ')') or eof(input); nextch; goto 1 end; sy := lparent; op := noop end; special: begin sy := ssy[ch]; op := sop[ch]; nextch end; chspace: sy := othersy end (*case*) end (*insymbol*) ; procedure enterid(fcp: ctp); (*enter id pointed at by fcp into the name-table, which on each declaration level is organised as an unbalanced binary tree*) var nam: alpha; lcp, lcp1: ctp; lleft: boolean; begin nam := fcp^.name; lcp := display[top].fname; if lcp = nil then display[top].fname := fcp else begin repeat lcp1 := lcp; if lcp^.name = nam then (*name conflict, follow right link*) begin error(101); lcp := lcp^.rlink; lleft := false end else if lcp^.name < nam then begin lcp := lcp^.rlink; lleft := false end else begin lcp := lcp^.llink; lleft := true end until lcp = nil; if lleft then lcp1^.llink := fcp else lcp1^.rlink := fcp end; fcp^.llink := nil; fcp^.rlink := nil end (*enterid*) ; procedure searchsection(fcp: ctp; var fcp1: ctp); (*to find record fields and forward declared procedure id's --> procedure proceduredeclaration --> procedure selector*) label 1; begin while fcp <> nil do if fcp^.name = id then goto 1 else if fcp^.name < id then fcp := fcp^.rlink else fcp := fcp^.llink; 1: fcp1 := fcp end (*searchsection*) ; procedure searchid(fidcls: setofids; var fcp: ctp); label 1; var lcp: ctp; begin for disx := top downto 0 do begin lcp := display[disx].fname; while lcp <> nil do if lcp^.name = id then if lcp^.klass in fidcls then goto 1 else begin if prterr then error(103); lcp := lcp^.rlink end else if lcp^.name < id then lcp := lcp^.rlink else lcp := lcp^.llink end; (*search not successful; suppress error message in case of forward referenced type id in pointer type definition --> procedure simpletype*) if prterr then begin error(104); (*to avoid returning nil, reference an entry for an undeclared id of appropriate class --> procedure enterundecl*) if types in fidcls then lcp := utypptr else if vars in fidcls then lcp := uvarptr else if field in fidcls then lcp := ufldptr else if konst in fidcls then lcp := ucstptr else if proc in fidcls then lcp := uprcptr else lcp := ufctptr; end; 1: fcp := lcp end (*searchid*) ; procedure getbounds(fsp: stp; var fmin,fmax: integer); (*get internal bounds of subrange or scalar type*) (*assume fsp<>intptr and fsp<>realptr*) begin fmin := 0; fmax := 0; if fsp <> nil then with fsp^ do if form = subrange then begin fmin := min.ival; fmax := max.ival end else if fsp = charptr then begin fmin := ordminchar; fmax := ordmaxchar end else if fconst <> nil then fmax := fconst^.values.ival end (*getbounds*) ; function alignquot(fsp: stp): integer; begin alignquot := 1; if fsp <> nil then with fsp^ do case form of scalar: if fsp=intptr then alignquot := intal else if fsp=boolptr then alignquot := boolal else if scalkind=declared then alignquot := intal else if fsp=charptr then alignquot := charal else if fsp=realptr then alignquot := realal else (*parmptr*) alignquot := parmal; subrange: alignquot := alignquot(rangetype); pointer: alignquot := adral; power: alignquot := setal; files: alignquot := fileal; arrays: alignquot := alignquot(aeltype); records: alignquot := recal; variant,tagfld: error(501) end end (*alignquot*); procedure align(fsp: stp; var flc: addrrange); var k,l: integer; begin k := alignquot(fsp); l := flc-1; flc := l + k - (k+l) mod k end (*align*); procedure printtables(fb: boolean); (*print data structure and name table*) var i, lim: disprange; procedure marker; (*mark data structure entries to avoid multiple printout*) var i: integer; procedure markctp(fp: ctp); forward; procedure markstp(fp: stp); (*mark data structures, prevent cycles*) begin if fp <> nil then with fp^ do begin marked := true; case form of scalar: ; subrange: markstp(rangetype); pointer: (*don't mark eltype: cycle possible; will be marked anyway, if fp = true*) ; power: markstp(elset) ; arrays: begin markstp(aeltype); markstp(inxtype) end; records: begin markctp(fstfld); markstp(recvar) end; files: markstp(filtype); tagfld: markstp(fstvar); variant: begin markstp(nxtvar); markstp(subvar) end end (*case*) end (*with*) end (*markstp*); procedure markctp; begin if fp <> nil then with fp^ do begin markctp(llink); markctp(rlink); markstp(idtype) end end (*markctp*); begin (*marker*) for i := top downto lim do markctp(display[i].fname) end (*marker*); procedure followctp(fp: ctp); forward; procedure followstp(fp: stp); begin if fp <> nil then with fp^ do if marked then begin marked := false; write(output,' ':4,ord(fp):6,size:10); case form of scalar: begin write(output,'scalar':10); if scalkind = standard then write(output,'standard':10) else write(output,'declared':10,' ':4,ord(fconst):6); writeln(output) end; subrange: begin write(output,'subrange':10,' ':4,ord(rangetype):6); if rangetype <> realptr then write(output,min.ival,max.ival) else if (min.valp <> nil) and (max.valp <> nil) then write(output,' ',min.valp^.rval:9, ' ',max.valp^.rval:9); writeln(output); followstp(rangetype); end; pointer: writeln(output,'pointer':10,' ':4,ord(eltype):6); power: begin writeln(output,'set':10,' ':4,ord(elset):6); followstp(elset) end; arrays: begin writeln(output,'array':10,' ':4,ord(aeltype):6,' ':4, ord(inxtype):6); followstp(aeltype); followstp(inxtype) end; records: begin writeln(output,'record':10,' ':4,ord(fstfld):6,' ':4, ord(recvar):6); followctp(fstfld); followstp(recvar) end; files: begin write(output,'file':10,' ':4,ord(filtype):6); followstp(filtype) end; tagfld: begin writeln(output,'tagfld':10,' ':4,ord(tagfieldp):6, ' ':4,ord(fstvar):6); followstp(fstvar) end; variant: begin writeln(output,'variant':10,' ':4,ord(nxtvar):6, ' ':4,ord(subvar):6,varval.ival); followstp(nxtvar); followstp(subvar) end end (*case*) end (*if marked*) end (*followstp*); procedure followctp; var i: integer; begin if fp <> nil then with fp^ do begin write(output,' ':4,ord(fp):6,' ',name:9,' ':4,ord(llink):6, ' ':4,ord(rlink):6,' ':4,ord(idtype):6); case klass of types: write(output,'type':10); konst: begin write(output,'constant':10,' ':4,ord(next):6); if idtype <> nil then if idtype = realptr then begin if values.valp <> nil then write(output,' ',values.valp^.rval:9) end else if idtype^.form = arrays then (*stringconst*) begin if values.valp <> nil then begin write(output,' '); with values.valp^ do for i := 1 to slgth do write(output,sval[i]) end end else write(output,values.ival) end; vars: begin write(output,'variable':10); if vkind = actual then write(output,'actual':10) else write(output,'formal':10); write(output,' ':4,ord(next):6,vlev,' ':4,vaddr:6 ); end; field: write(output,'field':10,' ':4,ord(next):6,' ':4,fldaddr:6); proc, func: begin if klass = proc then write(output,'procedure':10) else write(output,'function':10); if pfdeckind = standard then write(output,'standard':10, key:10) else begin write(output,'declared':10,' ':4,ord(next):6); write(output,pflev,' ':4,pfname:6); if pfkind = actual then begin write(output,'actual':10); if forwdecl then write(output,'forward':10) else write(output,'notforward':10); if externl then write(output,'extern':10) else write(output,'not extern':10); end else write(output,'formal':10) end end end (*case*); writeln(output); followctp(llink); followctp(rlink); followstp(idtype) end (*with*) end (*followctp*); begin (*printtables*) writeln(output); writeln(output); writeln(output); if fb then lim := 0 else begin lim := top; write(output,' local') end; writeln(output,' tables '); writeln(output); marker; for i := top downto lim do followctp(display[i].fname); writeln(output); if not eol then write(output,' ':chcnt+16) end (*printtables*); procedure genlabel(var nxtlab: integer); begin intlabel := intlabel + 1; nxtlab := intlabel end (*genlabel*); procedure block(fsys: setofsys; fsy: symbol; fprocp: ctp); var lsy: symbol; test: boolean; procedure skip(fsys: setofsys); (*skip input string until relevant symbol found*) begin if not eof(input) then begin while not(sy in fsys) and (not eof(input)) do insymbol; if not (sy in fsys) then insymbol end end (*skip*) ; procedure constant(fsys: setofsys; var fsp: stp; var fvalu: valu); var lsp: stp; lcp: ctp; sign: (none,pos,neg); lvp: csp; i: 2..strglgth; begin lsp := nil; fvalu.ival := 0; if not(sy in constbegsys) then begin error(50); skip(fsys+constbegsys) end; if sy in constbegsys then begin if sy = stringconst then begin if lgth = 1 then lsp := charptr else begin new(lsp,arrays); with lsp^ do begin aeltype := charptr; inxtype := nil; size := lgth*charsize; form := arrays end end; fvalu := val; insymbol end else begin sign := none; if (sy = addop) and (op in [plus,minus]) then begin if op = plus then sign := pos else sign := neg; insymbol end; if sy = ident then begin searchid([konst],lcp); with lcp^ do begin lsp := idtype; fvalu := values end; if sign <> none then if lsp = intptr then begin if sign = neg then fvalu.ival := -fvalu.ival end else if lsp = realptr then begin if sign = neg then begin new(lvp,reel); if fvalu.valp^.rval[1] = '-' then lvp^.rval[1] := '+' else lvp^.rval[1] := '-'; for i := 2 to strglgth do lvp^.rval[i] := fvalu.valp^.rval[i]; fvalu.valp := lvp; end end else error(105); insymbol; end else if sy = intconst then begin if sign = neg then val.ival := -val.ival; lsp := intptr; fvalu := val; insymbol end else if sy = realconst then begin if sign = neg then val.valp^.rval[1] := '-'; lsp := realptr; fvalu := val; insymbol end else begin error(106); skip(fsys) end end; if not (sy in fsys) then begin error(6); skip(fsys) end end; fsp := lsp end (*constant*) ; function equalbounds(fsp1,fsp2: stp): boolean; var lmin1,lmin2,lmax1,lmax2: integer; begin if (fsp1=nil) or (fsp2=nil) then equalbounds := true else begin getbounds(fsp1,lmin1,lmax1); getbounds(fsp2,lmin2,lmax2); equalbounds := (lmin1=lmin2) and (lmax1=lmax2) end end (*equalbounds*) ; function comptypes(fsp1,fsp2: stp) : boolean; (*decide whether structures pointed at by fsp1 and fsp2 are compatible*) var nxt1,nxt2: ctp; comp: boolean; ltestp1,ltestp2 : testp; begin if fsp1 = fsp2 then comptypes := true else if (fsp1 <> nil) and (fsp2 <> nil) then if fsp1^.form = fsp2^.form then case fsp1^.form of scalar: comptypes := false; (* identical scalars declared on different levels are not recognized to be compatible*) subrange: comptypes := comptypes(fsp1^.rangetype,fsp2^.rangetype); pointer: begin comp := false; ltestp1 := globtestp; ltestp2 := globtestp; while ltestp1 <> nil do with ltestp1^ do begin if (elt1 = fsp1^.eltype) and (elt2 = fsp2^.eltype) then comp := true; ltestp1 := lasttestp end; if not comp then begin new(ltestp1); with ltestp1^ do begin elt1 := fsp1^.eltype; elt2 := fsp2^.eltype; lasttestp := globtestp end; globtestp := ltestp1; comp := comptypes(fsp1^.eltype,fsp2^.eltype) end; comptypes := comp; globtestp := ltestp2 end; power: comptypes := comptypes(fsp1^.elset,fsp2^.elset); arrays: begin comp := comptypes(fsp1^.aeltype,fsp2^.aeltype) and comptypes(fsp1^.inxtype,fsp2^.inxtype); comptypes := comp and (fsp1^.size = fsp2^.size) and equalbounds(fsp1^.inxtype,fsp2^.inxtype) end; records: begin nxt1 := fsp1^.fstfld; nxt2 := fsp2^.fstfld; comp:=true; while (nxt1 <> nil) and (nxt2 <> nil) do begin comp:=comp and comptypes(nxt1^.idtype,nxt2^.idtype); nxt1 := nxt1^.next; nxt2 := nxt2^.next end; comptypes := comp and (nxt1 = nil) and (nxt2 = nil) and(fsp1^.recvar = nil)and(fsp2^.recvar = nil) end; (*identical records are recognized to be compatible iff no variants occur*) files: comptypes := comptypes(fsp1^.filtype,fsp2^.filtype) end (*case*) else (*fsp1^.form <> fsp2^.form*) if fsp1^.form = subrange then comptypes := comptypes(fsp1^.rangetype,fsp2) else if fsp2^.form = subrange then comptypes := comptypes(fsp1,fsp2^.rangetype) else comptypes := false else comptypes := true end (*comptypes*) ; function string(fsp: stp) : boolean; begin string := false; if fsp <> nil then if fsp^.form = arrays then if comptypes(fsp^.aeltype,charptr) then string := true end (*string*) ; procedure typ(fsys: setofsys; var fsp: stp; var fsize: addrrange); var lsp,lsp1,lsp2: stp; oldtop: disprange; lcp: ctp; lsize,displ: addrrange; lmin,lmax: integer; procedure simpletype(fsys:setofsys; var fsp:stp; var fsize:addrrange); var lsp,lsp1: stp; lcp,lcp1: ctp; ttop: disprange; lcnt: integer; lvalu: valu; begin fsize := 1; if not (sy in simptypebegsys) then begin error(1); skip(fsys + simptypebegsys) end; if sy in simptypebegsys then begin if sy = lparent then begin ttop := top; (*decl. consts local to innermost block*) while display[top].occur <> blck do top := top - 1; new(lsp,scalar,declared); with lsp^ do begin size := intsize; form := scalar; scalkind := declared end; lcp1 := nil; lcnt := 0; repeat insymbol; if sy = ident then begin new(lcp,konst); with lcp^ do begin name := id; idtype := lsp; next := lcp1; values.ival := lcnt; klass := konst end; enterid(lcp); lcnt := lcnt + 1; lcp1 := lcp; insymbol end else error(2); if not (sy in fsys + [comma,rparent]) then begin error(6); skip(fsys + [comma,rparent]) end until sy <> comma; lsp^.fconst := lcp1; top := ttop; if sy = rparent then insymbol else error(4) end else begin if sy = ident then begin searchid([types,konst],lcp); insymbol; if lcp^.klass = konst then begin new(lsp,subrange); with lsp^, lcp^ do begin rangetype := idtype; form := subrange; if string(rangetype) then begin error(148); rangetype := nil end; min := values; size := intsize end; if sy = colon then insymbol else error(5); constant(fsys,lsp1,lvalu); lsp^.max := lvalu; if lsp^.rangetype <> lsp1 then error(107) end else begin lsp := lcp^.idtype; if lsp <> nil then fsize := lsp^.size end end (*sy = ident*) else begin new(lsp,subrange); lsp^.form := subrange; constant(fsys + [colon],lsp1,lvalu); if string(lsp1) then begin error(148); lsp1 := nil end; with lsp^ do begin rangetype:=lsp1; min:=lvalu; size:=intsize end; if sy = colon then insymbol else error(5); constant(fsys,lsp1,lvalu); lsp^.max := lvalu; if lsp^.rangetype <> lsp1 then error(107) end; if lsp <> nil then with lsp^ do if form = subrange then if rangetype <> nil then if rangetype = realptr then error(399) else if min.ival > max.ival then error(102) end; fsp := lsp; if not (sy in fsys) then begin error(6); skip(fsys) end end else fsp := nil end (*simpletype*) ; procedure fieldlist(fsys: setofsys; var frecvar: stp); var lcp,lcp1,nxt,nxt1: ctp; lsp,lsp1,lsp2,lsp3,lsp4: stp; minsize,maxsize,lsize: addrrange; lvalu: valu; begin nxt1 := nil; lsp := nil; if not (sy in (fsys+[ident,casesy])) then begin error(19); skip(fsys + [ident,casesy]) end; while sy = ident do begin nxt := nxt1; repeat if sy = ident then begin new(lcp,field); with lcp^ do begin name := id; idtype := nil; next := nxt; klass := field end; nxt := lcp; enterid(lcp); insymbol end else error(2); if not (sy in [comma,colon]) then begin error(6); skip(fsys + [comma,colon,semicolon,casesy]) end; test := sy <> comma; if not test then insymbol until test; if sy = colon then insymbol else error(5); typ(fsys + [casesy,semicolon],lsp,lsize); while nxt <> nxt1 do with nxt^ do begin align(lsp,displ); idtype := lsp; fldaddr := displ; nxt := next; displ := displ + lsize end; nxt1 := lcp; while sy = semicolon do begin insymbol; if not (sy in fsys + [ident,casesy,semicolon]) then begin error(19); skip(fsys + [ident,casesy]) end end end (*while*); nxt := nil; while nxt1 <> nil do with nxt1^ do begin lcp := next; next := nxt; nxt := nxt1; nxt1 := lcp end; if sy = casesy then begin new(lsp,tagfld); with lsp^ do begin tagfieldp := nil; fstvar := nil; form:=tagfld end; frecvar := lsp; insymbol; if sy = ident then begin new(lcp,field); with lcp^ do begin name := id; idtype := nil; klass:=field; next := nil; fldaddr := displ end; enterid(lcp); insymbol; if sy = colon then insymbol else error(5); if sy = ident then begin searchid([types],lcp1); lsp1 := lcp1^.idtype; if lsp1 <> nil then begin align(lsp1,displ); lcp^.fldaddr := displ; displ := displ+lsp1^.size; if (lsp1^.form <= subrange) or string(lsp1) then begin if comptypes(realptr,lsp1) then error(109) else if string(lsp1) then error(399); lcp^.idtype := lsp1; lsp^.tagfieldp := lcp; end else error(110); end; insymbol; end else begin error(2); skip(fsys + [ofsy,lparent]) end end else begin error(2); skip(fsys + [ofsy,lparent]) end; lsp^.size := displ; if sy = ofsy then insymbol else error(8); lsp1 := nil; minsize := displ; maxsize := displ; repeat lsp2 := nil; if not (sy in fsys + [semicolon]) then begin repeat constant(fsys + [comma,colon,lparent],lsp3,lvalu); if lsp^.tagfieldp <> nil then if not comptypes(lsp^.tagfieldp^.idtype,lsp3)then error(111); new(lsp3,variant); with lsp3^ do begin nxtvar := lsp1; subvar := lsp2; varval := lvalu; form := variant end; lsp4 := lsp1; while lsp4 <> nil do with lsp4^ do begin if varval.ival = lvalu.ival then error(178); lsp4 := nxtvar end; lsp1 := lsp3; lsp2 := lsp3; test := sy <> comma; if not test then insymbol until test; if sy = colon then insymbol else error(5); if sy = lparent then insymbol else error(9); fieldlist(fsys + [rparent,semicolon],lsp2); if displ > maxsize then maxsize := displ; while lsp3 <> nil do begin lsp4 := lsp3^.subvar; lsp3^.subvar := lsp2; lsp3^.size := displ; lsp3 := lsp4 end; if sy = rparent then begin insymbol; if not (sy in fsys + [semicolon]) then begin error(6); skip(fsys + [semicolon]) end end else error(4); end; test := sy <> semicolon; if not test then begin displ := minsize; insymbol end until test; displ := maxsize; lsp^.fstvar := lsp1; end else frecvar := nil end (*fieldlist*) ; begin (*typ*) if not (sy in typebegsys) then begin error(10); skip(fsys + typebegsys) end; if sy in typebegsys then begin if sy in simptypebegsys then simpletype(fsys,fsp,fsize) else (*^*) if sy = arrow then begin new(lsp,pointer); fsp := lsp; with lsp^ do begin eltype := nil; size := ptrsize; form:=pointer end; insymbol; if sy = ident then begin prterr := false; (*no error if search not successful*) searchid([types],lcp); prterr := true; if lcp = nil then (*forward referenced type id*) begin new(lcp,types); with lcp^ do begin name := id; idtype := lsp; next := fwptr; klass := types end; fwptr := lcp end else begin if lcp^.idtype <> nil then if lcp^.idtype^.form = files then error(108) else lsp^.eltype := lcp^.idtype end; insymbol; end else error(2); end else begin if sy = packedsy then begin insymbol; if not (sy in typedels) then begin error(10); skip(fsys + typedels) end end; (*array*) if sy = arraysy then begin insymbol; if sy = lbrack then insymbol else error(11); lsp1 := nil; repeat new(lsp,arrays); with lsp^ do begin aeltype := lsp1; inxtype := nil; form:=arrays end; lsp1 := lsp; simpletype(fsys + [comma,rbrack,ofsy],lsp2,lsize); lsp1^.size := lsize; if lsp2 <> nil then if lsp2^.form <= subrange then begin if lsp2 = realptr then begin error(109); lsp2 := nil end else if lsp2 = intptr then begin error(149); lsp2 := nil end; lsp^.inxtype := lsp2 end else begin error(113); lsp2 := nil end; test := sy <> comma; if not test then insymbol until test; if sy = rbrack then insymbol else error(12); if sy = ofsy then insymbol else error(8); typ(fsys,lsp,lsize); repeat with lsp1^ do begin lsp2 := aeltype; aeltype := lsp; if inxtype <> nil then begin getbounds(inxtype,lmin,lmax); align(lsp,lsize); lsize := lsize*(lmax - lmin + 1); size := lsize end end; lsp := lsp1; lsp1 := lsp2 until lsp1 = nil end else (*record*) if sy = recordsy then begin insymbol; oldtop := top; if top < displimit then begin top := top + 1; with display[top] do begin fname := nil; flabel := nil; occur := rec end end else error(250); displ := 0; fieldlist(fsys-[semicolon]+[endsy],lsp1); new(lsp,records); with lsp^ do begin fstfld := display[top].fname; recvar := lsp1; size := displ; form := records end; top := oldtop; if sy = endsy then insymbol else error(13) end else (*set*) if sy = setsy then begin insymbol; if sy = ofsy then insymbol else error(8); simpletype(fsys,lsp1,lsize); if lsp1 <> nil then if lsp1^.form > subrange then begin error(115); lsp1 := nil end else if lsp1 = realptr then begin error(114); lsp1 := nil end else if lsp1 = intptr then begin error(169); lsp1 := nil end else begin getbounds(lsp1,lmin,lmax); if (lmin < setlow) or (lmax > sethigh) then error(169); end; new(lsp,power); with lsp^ do begin elset:=lsp1; size:=setsize; form:=power end; end else (*file*) if sy = filesy then begin insymbol; error(399); skip(fsys); lsp := nil end; fsp := lsp end; if not (sy in fsys) then begin error(6); skip(fsys) end end else fsp := nil; if fsp = nil then fsize := 1 else fsize := fsp^.size end (*typ*) ; procedure labeldeclaration; var llp: lbp; redef: boolean; lbname: integer; begin repeat if sy = intconst then with display[top] do begin llp := flabel; redef := false; while (llp <> nil) and not redef do if llp^.labval <> val.ival then llp := llp^.nextlab else begin redef := true; error(166) end; if not redef then begin new(llp); with llp^ do begin labval := val.ival; genlabel(lbname); defined := false; nextlab := flabel; labname := lbname end; flabel := llp end; insymbol end else error(15); if not ( sy in fsys + [comma, semicolon] ) then begin error(6); skip(fsys+[comma,semicolon]) end; test := sy <> comma; if not test then insymbol until test; if sy = semicolon then insymbol else error(14) end (* labeldeclaration *) ; procedure constdeclaration; var lcp: ctp; lsp: stp; lvalu: valu; begin if sy <> ident then begin error(2); skip(fsys + [ident]) end; while sy = ident do begin new(lcp,konst); with lcp^ do begin name := id; idtype := nil; next := nil; klass:=konst end; insymbol; if (sy = relop) and (op = eqop) then insymbol else error(16); constant(fsys + [semicolon],lsp,lvalu); enterid(lcp); lcp^.idtype := lsp; lcp^.values := lvalu; if sy = semicolon then begin insymbol; if not (sy in fsys + [ident]) then begin error(6); skip(fsys + [ident]) end end else error(14) end end (*constdeclaration*) ; procedure typedeclaration; var lcp,lcp1,lcp2: ctp; lsp: stp; lsize: addrrange; begin if sy <> ident then begin error(2); skip(fsys + [ident]) end; while sy = ident do begin new(lcp,types); with lcp^ do begin name := id; idtype := nil; klass := types end; insymbol; if (sy = relop) and (op = eqop) then insymbol else error(16); typ(fsys + [semicolon],lsp,lsize); enterid(lcp); lcp^.idtype := lsp; (*has any forward reference been satisfied:*) lcp1 := fwptr; while lcp1 <> nil do begin if lcp1^.name = lcp^.name then begin lcp1^.idtype^.eltype := lcp^.idtype; if lcp1 <> fwptr then lcp2^.next := lcp1^.next else fwptr := lcp1^.next; end else lcp2 := lcp1; lcp1 := lcp1^.next end; if sy = semicolon then begin insymbol; if not (sy in fsys + [ident]) then begin error(6); skip(fsys + [ident]) end end else error(14) end; if fwptr <> nil then begin error(117); writeln(output); repeat writeln(output,' type-id ',fwptr^.name); fwptr := fwptr^.next until fwptr = nil; if not eol then write(output,' ': chcnt+16) end end (*typedeclaration*) ; procedure vardeclaration; var lcp,nxt: ctp; lsp: stp; lsize: addrrange; begin nxt := nil; repeat repeat if sy = ident then begin new(lcp,vars); with lcp^ do begin name := id; next := nxt; klass := vars; idtype := nil; vkind := actual; vlev := level end; enterid(lcp); nxt := lcp; insymbol; end else error(2); if not (sy in fsys + [comma,colon] + typedels) then begin error(6); skip(fsys+[comma,colon,semicolon]+typedels) end; test := sy <> comma; if not test then insymbol until test; if sy = colon then insymbol else error(5); typ(fsys + [semicolon] + typedels,lsp,lsize); while nxt <> nil do with nxt^ do begin align(lsp,lc); idtype := lsp; vaddr := lc; lc := lc + lsize; nxt := next end; if sy = semicolon then begin insymbol; if not (sy in fsys + [ident]) then begin error(6); skip(fsys + [ident]) end end else error(14) until (sy <> ident) and not (sy in typedels); if fwptr <> nil then begin error(117); writeln(output); repeat writeln(output,' type-id ',fwptr^.name); fwptr := fwptr^.next until fwptr = nil; if not eol then write(output,' ': chcnt+16) end end (*vardeclaration*) ; procedure procdeclaration(fsy: symbol); var oldlev: 0..maxlevel; lcp,lcp1: ctp; lsp: stp; forw: boolean; oldtop: disprange; llc,lcm: addrrange; lbname: integer; markp: marktype; procedure parameterlist(fsy: setofsys; var fpar: ctp); var lcp,lcp1,lcp2,lcp3: ctp; lsp: stp; lkind: idkind; llc,lsize: addrrange; count: integer; begin lcp1 := nil; if not (sy in fsy + [lparent]) then begin error(7); skip(fsys + fsy + [lparent]) end; if sy = lparent then begin if forw then error(119); insymbol; if not (sy in [ident,varsy,procsy,funcsy]) then begin error(7); skip(fsys + [ident,rparent]) end; while sy in [ident,varsy,procsy,funcsy] do begin if sy = procsy then begin error(399); repeat insymbol; if sy = ident then begin new(lcp,proc,declared,formal); with lcp^ do begin name := id; idtype := nil; next := lcp1; pflev := level (*beware of parameter procedures*); klass:=proc;pfdeckind:=declared;pfkind:=formal end; enterid(lcp); lcp1 := lcp; align(parmptr,lc); (*lc := lc + some size *) insymbol end else error(2); if not (sy in fsys + [comma,semicolon,rparent]) then begin error(7);skip(fsys+[comma,semicolon,rparent])end until sy <> comma end else begin if sy = funcsy then begin error(399); lcp2 := nil; repeat insymbol; if sy = ident then begin new(lcp,func,declared,formal); with lcp^ do begin name := id; idtype := nil; next := lcp2; pflev := level (*beware param funcs*); klass:=func;pfdeckind:=declared; pfkind:=formal end; enterid(lcp); lcp2 := lcp; align(parmptr,lc); (*lc := lc + some size*) insymbol; end; if not (sy in [comma,colon] + fsys) then begin error(7);skip(fsys+[comma,semicolon,rparent]) end until sy <> comma; if sy = colon then begin insymbol; if sy = ident then begin searchid([types],lcp); lsp := lcp^.idtype; if lsp <> nil then if not(lsp^.form in[scalar,subrange,pointer]) then begin error(120); lsp := nil end; lcp3 := lcp2; while lcp2 <> nil do begin lcp2^.idtype := lsp; lcp := lcp2; lcp2 := lcp2^.next end; lcp^.next := lcp1; lcp1 := lcp3; insymbol end else error(2); if not (sy in fsys + [semicolon,rparent]) then begin error(7);skip(fsys+[semicolon,rparent])end end else error(5) end else begin if sy = varsy then begin lkind := formal; insymbol end else lkind := actual; lcp2 := nil; count := 0; repeat if sy = ident then begin new(lcp,vars); with lcp^ do begin name:=id; idtype:=nil; klass:=vars; vkind := lkind; next := lcp2; vlev := level; end; enterid(lcp); lcp2 := lcp; count := count+1; insymbol; end; if not (sy in [comma,colon] + fsys) then begin error(7);skip(fsys+[comma,semicolon,rparent]) end; test := sy <> comma; if not test then insymbol until test; if sy = colon then begin insymbol; if sy = ident then begin searchid([types],lcp); lsp := lcp^.idtype; lsize := ptrsize; if lsp <> nil then if lkind=actual then if lsp^.form<=power then lsize := lsp^.size else if lsp^.form=files then error(121); align(parmptr,lsize); lcp3 := lcp2; align(parmptr,lc); lc := lc+count*lsize; llc := lc; while lcp2 <> nil do begin lcp := lcp2; with lcp2^ do begin idtype := lsp; llc := llc-lsize; vaddr := llc; end; lcp2 := lcp2^.next end; lcp^.next := lcp1; lcp1 := lcp3; insymbol end else error(2); if not (sy in fsys + [semicolon,rparent]) then begin error(7);skip(fsys+[semicolon,rparent])end end else error(5); end; end; if sy = semicolon then begin insymbol; if not (sy in fsys + [ident,varsy,procsy,funcsy]) then begin error(7); skip(fsys + [ident,rparent]) end end end (*while*) ; if sy = rparent then begin insymbol; if not (sy in fsy + fsys) then begin error(6); skip(fsy + fsys) end end else error(4); lcp3 := nil; (*reverse pointers and reserve local cells for copies of multiple values*) while lcp1 <> nil do with lcp1^ do begin lcp2 := next; next := lcp3; if klass = vars then if idtype <> nil then if (vkind=actual)and(idtype^.form>power) then begin align(idtype,lc); vaddr := lc; lc := lc+idtype^.size; end; lcp3 := lcp1; lcp1 := lcp2 end; fpar := lcp3 end else fpar := nil end (*parameterlist*) ; begin (*procdeclaration*) llc := lc; lc := lcaftermarkstack; forw := false; if sy = ident then begin searchsection(display[top].fname,lcp); (*decide whether forw.*) if lcp <> nil then begin if lcp^.klass = proc then forw := lcp^.forwdecl and(fsy=procsy)and(lcp^.pfkind=actual) else if lcp^.klass = func then forw:=lcp^.forwdecl and(fsy=funcsy)and(lcp^.pfkind=actual) else forw := false; if not forw then error(160) end; if not forw then begin if fsy = procsy then new(lcp,proc,declared,actual) else new(lcp,func,declared,actual); with lcp^ do begin name := id; idtype := nil; externl := false; pflev := level; genlabel(lbname); pfdeckind := declared; pfkind := actual; pfname := lbname; if fsy = procsy then klass := proc else klass := func end; enterid(lcp) end else begin lcp1 := lcp^.next; while lcp1 <> nil do begin with lcp1^ do if klass = vars then if idtype <> nil then begin lcm := vaddr + idtype^.size; if lcm > lc then lc := lcm end; lcp1 := lcp1^.next end end; insymbol end else begin error(2); lcp := ufctptr end; oldlev := level; oldtop := top; if level < maxlevel then level := level + 1 else error(251); if top < displimit then begin top := top + 1; with display[top] do begin if forw then fname := lcp^.next else fname := nil; flabel := nil; occur := blck end end else error(250); if fsy = procsy then begin parameterlist([semicolon],lcp1); if not forw then lcp^.next := lcp1 end else begin parameterlist([semicolon,colon],lcp1); if not forw then lcp^.next := lcp1; if sy = colon then begin insymbol; if sy = ident then begin if forw then error(122); searchid([types],lcp1); lsp := lcp1^.idtype; lcp^.idtype := lsp; if lsp <> nil then if not (lsp^.form in [scalar,subrange,pointer]) then begin error(120); lcp^.idtype := nil end; insymbol end else begin error(2); skip(fsys + [semicolon]) end end else if not forw then error(123) end; if sy = semicolon then insymbol else error(14); if sy = forwardsy then begin if forw then error(161) else lcp^.forwdecl := true; insymbol; if sy = semicolon then insymbol else error(14); if not (sy in fsys) then begin error(6); skip(fsys) end end else begin lcp^.forwdecl := false; mark(markp); repeat block(fsys,semicolon,lcp); if sy = semicolon then begin if prtables then printtables(false); insymbol; if not (sy in [beginsy,procsy,funcsy]) then begin error(6); skip(fsys) end end else error(14) until (sy in [beginsy,procsy,funcsy]) or eof(input); release(markp); (* return local entries on runtime heap *) end; level := oldlev; top := oldtop; lc := llc; end (*procdeclaration*) ; procedure body(fsys: setofsys); const cstoccmax=65; cixmax=1000; type oprange = 0..63; var llcp:ctp; saveid:alpha; cstptr: array [1..cstoccmax] of csp; cstptrix: 0..cstoccmax; (*allows referencing of noninteger constants by an index (instead of a pointer), which can be stored in the p2-field of the instruction record until writeout. --> procedure load, procedure writeout*) entname, segsize: integer; stacktop, topnew, topmax: integer; lcmax,llc1: addrrange; lcp: ctp; llp: lbp; procedure mes(i: integer); begin topnew := topnew + cdx[i]*maxstack; if topnew > topmax then topmax := topnew end; procedure putic; begin if ic mod 10 = 0 then writeln(prr,'i',ic:5) end; procedure gen0(fop: oprange); begin if prcode then begin putic; writeln(prr,mn[fop]:4) end; ic := ic + 1; mes(fop) end (*gen0*) ; procedure gen1(fop: oprange; fp2: integer); var k: integer; begin if prcode then begin putic; write(prr,mn[fop]:4); if fop = 30 then begin writeln(prr,sna[fp2]:12); topnew := topnew + pdx[fp2]*maxstack; if topnew > topmax then topmax := topnew end else begin if fop = 38 then begin write(prr,''''); with cstptr[fp2]^ do begin for k := 1 to slgth do write(prr,sval[k]:1); for k := slgth+1 to strglgth do write(prr,' '); end; writeln(prr,'''') end else if fop = 42 then writeln(prr,chr(fp2)) else writeln(prr,fp2:12); mes(fop) end end; ic := ic + 1 end (*gen1*) ; procedure gen2(fop: oprange; fp1,fp2: integer); var k : integer; begin if prcode then begin putic; write(prr,mn[fop]:4); case fop of 45,50,54,56: writeln(prr,' ',fp1:3,fp2:8); 47,48,49,52,53,55: begin write(prr,chr(fp1)); if chr(fp1) = 'm' then write(prr,fp2:11); writeln(prr) end; 51: case fp1 of 1: writeln(prr,'i ',fp2); 2: begin write(prr,'r '); with cstptr[fp2]^ do for k := 1 to strglgth do write(prr,rval[k]); writeln(prr) end; 3: writeln(prr,'b ',fp2); 4: writeln(prr,'n'); 6: writeln(prr,'c ''':3,chr(fp2),''''); 5: begin write(prr,'('); with cstptr[fp2]^ do for k := setlow to sethigh do if k in pval then write(prr,k:3); writeln(prr,')') end end end; end; ic := ic + 1; mes(fop) end (*gen2*) ; procedure gentypindicator(fsp: stp); begin if fsp<>nil then with fsp^ do case form of scalar: if fsp=intptr then write(prr,'i') else if fsp=boolptr then write(prr,'b') else if fsp=charptr then write(prr,'c') else if scalkind = declared then write(prr,'i') else write(prr,'r'); subrange: gentypindicator(rangetype); pointer: write(prr,'a'); power: write(prr,'s'); records,arrays: write(prr,'m'); files,tagfld,variant: error(500) end end (*typindicator*); procedure gen0t(fop: oprange; fsp: stp); begin if prcode then begin putic; write(prr,mn[fop]:4); gentypindicator(fsp); writeln(prr); end; ic := ic + 1; mes(fop) end (*gen0t*); procedure gen1t(fop: oprange; fp2: integer; fsp: stp); begin if prcode then begin putic; write(prr,mn[fop]:4); gentypindicator(fsp); writeln(prr,fp2:11) end; ic := ic + 1; mes(fop) end (*gen1t*); procedure gen2t(fop: oprange; fp1,fp2: integer; fsp: stp); begin if prcode then begin putic; write(prr,mn[fop]: 4); gentypindicator(fsp); writeln(prr,fp1:3+5*ord(abs(fp1)>99),fp2:8); end; ic := ic + 1; mes(fop) end (*gen2t*); procedure load; begin with gattr do if typtr <> nil then begin case kind of cst: if (typtr^.form = scalar) and (typtr <> realptr) then if typtr = boolptr then gen2(51(*ldc*),3,cval.ival) else if typtr=charptr then gen2(51(*ldc*),6,cval.ival) else gen2(51(*ldc*),1,cval.ival) else if typtr = nilptr then gen2(51(*ldc*),4,0) else if cstptrix >= cstoccmax then error(254) else begin cstptrix := cstptrix + 1; cstptr[cstptrix] := cval.valp; if typtr = realptr then gen2(51(*ldc*),2,cstptrix) else gen2(51(*ldc*),5,cstptrix) end; varbl: case access of drct: if vlevel<=1 then gen1t(39(*ldo*),dplmt,typtr) else gen2t(54(*lod*),level-vlevel,dplmt,typtr); indrct: gen1t(35(*ind*),idplmt,typtr); inxd: error(400) end; expr: end; kind := expr end end (*load*) ; procedure store(var fattr: attr); begin with fattr do if typtr <> nil then case access of drct: if vlevel <= 1 then gen1t(43(*sro*),dplmt,typtr) else gen2t(56(*str*),level-vlevel,dplmt,typtr); indrct: if idplmt <> 0 then error(400) else gen0t(26(*sto*),typtr); inxd: error(400) end end (*store*) ; procedure loadaddress; begin with gattr do if typtr <> nil then begin case kind of cst: if string(typtr) then if cstptrix >= cstoccmax then error(254) else begin cstptrix := cstptrix + 1; cstptr[cstptrix] := cval.valp; gen1(38(*lca*),cstptrix) end else error(400); varbl: case access of drct: if vlevel <= 1 then gen1(37(*lao*),dplmt) else gen2(50(*lda*),level-vlevel,dplmt); indrct: if idplmt <> 0 then gen1t(34(*inc*),idplmt,nilptr); inxd: error(400) end; expr: error(400) end; kind := varbl; access := indrct; idplmt := 0 end end (*loadaddress*) ; procedure genfjp(faddr: integer); begin load; if gattr.typtr <> nil then if gattr.typtr <> boolptr then error(144); if prcode then begin putic; writeln(prr,mn[33]:4,' l':8,faddr:4) end; ic := ic + 1; mes(33) end (*genfjp*) ; procedure genujpxjp(fop: oprange; fp2: integer); begin if prcode then begin putic; writeln(prr, mn[fop]:4, ' l':8,fp2:4) end; ic := ic + 1; mes(fop) end (*genujpxjp*); procedure gencupent(fop: oprange; fp1,fp2: integer); begin if prcode then begin putic; writeln(prr,mn[fop]:4,fp1:4,'l':4,fp2:4) end; ic := ic + 1; mes(fop) end; procedure checkbnds(fsp: stp); var lmin,lmax: integer; begin if fsp <> nil then if fsp <> intptr then if fsp <> realptr then if fsp^.form <= subrange then begin getbounds(fsp,lmin,lmax); gen2t(45(*chk*),lmin,lmax,fsp) end end (*checkbnds*); procedure putlabel(labname: integer); begin if prcode then writeln(prr, 'l', labname:4) end (*putlabel*); procedure statement(fsys: setofsys); label 1; var lcp: ctp; llp: lbp; procedure expression(fsys: setofsys); forward; procedure selector(fsys: setofsys; fcp: ctp); var lattr: attr; lcp: ctp; lsize: addrrange; lmin,lmax: integer; begin with fcp^, gattr do begin typtr := idtype; kind := varbl; case klass of vars: if vkind = actual then begin access := drct; vlevel := vlev; dplmt := vaddr end else begin gen2t(54(*lod*),level-vlev,vaddr,nilptr); access := indrct; idplmt := 0 end; field: with display[disx] do if occur = crec then begin access := drct; vlevel := clev; dplmt := cdspl + fldaddr end else begin if level = 1 then gen1t(39(*ldo*),vdspl,nilptr) else gen2t(54(*lod*),0,vdspl,nilptr); access := indrct; idplmt := fldaddr end; func: if pfdeckind = standard then begin error(150); typtr := nil end else begin if pfkind = formal then error(151) else if (pflev+1<>level)or(fprocp<>fcp) then error(177); begin access := drct; vlevel := pflev + 1; dplmt := 0 (*impl. relat. addr. of fct. result*) end end end (*case*) end (*with*); if not (sy in selectsys + fsys) then begin error(59); skip(selectsys + fsys) end; while sy in selectsys do begin (*[*) if sy = lbrack then begin repeat lattr := gattr; with lattr do if typtr <> nil then if typtr^.form <> arrays then begin error(138); typtr := nil end; loadaddress; insymbol; expression(fsys + [comma,rbrack]); load; if gattr.typtr <> nil then if gattr.typtr^.form<>scalar then error(113) else if not comptypes(gattr.typtr,intptr) then gen0t(58(*ord*),gattr.typtr); if lattr.typtr <> nil then with lattr.typtr^ do begin if comptypes(inxtype,gattr.typtr) then begin if inxtype <> nil then begin getbounds(inxtype,lmin,lmax); if debug then gen2t(45(*chk*),lmin,lmax,intptr); if lmin>0 then gen1t(31(*dec*),lmin,intptr) else if lmin<0 then gen1t(34(*inc*),-lmin,intptr); (*or simply gen1(31,lmin)*) end end else error(139); with gattr do begin typtr := aeltype; kind := varbl; access := indrct; idplmt := 0 end; if gattr.typtr <> nil then begin lsize := gattr.typtr^.size; align(gattr.typtr,lsize); gen1(36(*ixa*),lsize) end end until sy <> comma; if sy = rbrack then insymbol else error(12) end (*if sy = lbrack*) else (*.*) if sy = period then begin with gattr do begin if typtr <> nil then if typtr^.form <> records then begin error(140); typtr := nil end; insymbol; if sy = ident then begin if typtr <> nil then begin searchsection(typtr^.fstfld,lcp); if lcp = nil then begin error(152); typtr := nil end else with lcp^ do begin typtr := idtype; case access of drct: dplmt := dplmt + fldaddr; indrct: idplmt := idplmt + fldaddr; inxd: error(400) end end end; insymbol end (*sy = ident*) else error(2) end (*with gattr*) end (*if sy = period*) else (*^*) begin if gattr.typtr <> nil then with gattr,typtr^ do if form = pointer then begin load; typtr := eltype; if debug then gen2t(45(*chk*),1,maxaddr,nilptr); with gattr do begin kind := varbl; access := indrct; idplmt := 0 end end else if form = files then typtr := filtype else error(141); insymbol end; if not (sy in fsys + selectsys) then begin error(6); skip(fsys + selectsys) end end (*while*) end (*selector*) ; procedure call(fsys: setofsys; fcp: ctp); var lkey: 1..15; procedure variable(fsys: setofsys); var lcp: ctp; begin if sy = ident then begin searchid([vars,field],lcp); insymbol end else begin error(2); lcp := uvarptr end; selector(fsys,lcp) end (*variable*) ; procedure getputresetrewrite; begin variable(fsys + [rparent]); loadaddress; if gattr.typtr <> nil then if gattr.typtr^.form <> files then error(116); if lkey <= 2 then gen1(30(*csp*),lkey(*get,put*)) else error(399) end (*getputresetrewrite*) ; procedure read; var llev:levrange; laddr:addrrange; lsp : stp; begin llev := 1; laddr := lcaftermarkstack; if sy = lparent then begin insymbol; variable(fsys + [comma,rparent]); lsp := gattr.typtr; test := false; if lsp <> nil then if lsp^.form = files then with gattr, lsp^ do begin if filtype = charptr then begin llev := vlevel; laddr := dplmt end else error(399); if sy = rparent then begin if lkey = 5 then error(116); test := true end else if sy <> comma then begin error(116); skip(fsys + [comma,rparent]) end; if sy = comma then begin insymbol; variable(fsys + [comma,rparent]) end else test := true end; if not test then repeat loadaddress; gen2(50(*lda*),level-llev,laddr); if gattr.typtr <> nil then if gattr.typtr^.form <= subrange then if comptypes(intptr,gattr.typtr) then gen1(30(*csp*),3(*rdi*)) else if comptypes(realptr,gattr.typtr) then gen1(30(*csp*),4(*rdr*)) else if comptypes(charptr,gattr.typtr) then gen1(30(*csp*),5(*rdc*)) else error(399) else error(116); test := sy <> comma; if not test then begin insymbol; variable(fsys + [comma,rparent]) end until test; if sy = rparent then insymbol else error(4) end else if lkey = 5 then error(116); if lkey = 11 then begin gen2(50(*lda*),level-llev,laddr); gen1(30(*csp*),21(*rln*)) end end (*read*) ; procedure write; var lsp: stp; default : boolean; llkey: 1..15; llev:levrange; laddr,len:addrrange; begin llkey := lkey; llev := 1; laddr := lcaftermarkstack + charmax; if sy = lparent then begin insymbol; expression(fsys + [comma,colon,rparent]); lsp := gattr.typtr; test := false; if lsp <> nil then if lsp^.form = files then with gattr, lsp^ do begin if filtype = charptr then begin llev := vlevel; laddr := dplmt end else error(399); if sy = rparent then begin if llkey = 6 then error(116); test := true end else if sy <> comma then begin error(116); skip(fsys+[comma,rparent]) end; if sy = comma then begin insymbol; expression(fsys+[comma,colon,rparent]) end else test := true end; if not test then repeat lsp := gattr.typtr; if lsp <> nil then if lsp^.form <= subrange then load else loadaddress; if sy = colon then begin insymbol; expression(fsys + [comma,colon,rparent]); if gattr.typtr <> nil then if gattr.typtr <> intptr then error(116); load; default := false end else default := true; if sy = colon then begin insymbol; expression(fsys + [comma,rparent]); if gattr.typtr <> nil then if gattr.typtr <> intptr then error(116); if lsp <> realptr then error(124); load; error(399); end else if lsp = intptr then begin if default then gen2(51(*ldc*),1,10); gen2(50(*lda*),level-llev,laddr); gen1(30(*csp*),6(*wri*)) end else if lsp = realptr then begin if default then gen2(51(*ldc*),1,20); gen2(50(*lda*),level-llev,laddr); gen1(30(*csp*),8(*wrr*)) end else if lsp = charptr then begin if default then gen2(51(*ldc*),1,1); gen2(50(*lda*),level-llev,laddr); gen1(30(*csp*),9(*wrc*)) end else if lsp <> nil then begin if lsp^.form = scalar then error(399) else if string(lsp) then begin len := lsp^.size div charmax; if default then gen2(51(*ldc*),1,len); gen2(51(*ldc*),1,len); gen2(50(*lda*),level-llev,laddr); gen1(30(*csp*),10(*wrs*)) end else error(116) end; test := sy <> comma; if not test then begin insymbol; expression(fsys + [comma,colon,rparent]) end until test; if sy = rparent then insymbol else error(4) end else if lkey = 6 then error(116); if llkey = 12 then (*writeln*) begin gen2(50(*lda*),level-llev,laddr); gen1(30(*csp*),22(*wln*)) end end (*write*) ; procedure pack; var lsp,lsp1: stp; begin error(399); variable(fsys + [comma,rparent]); lsp := nil; lsp1 := nil; if gattr.typtr <> nil then with gattr.typtr^ do if form = arrays then begin lsp := inxtype; lsp1 := aeltype end else error(116); if sy = comma then insymbol else error(20); expression(fsys + [comma,rparent]); if gattr.typtr <> nil then if gattr.typtr^.form <> scalar then error(116) else if not comptypes(lsp,gattr.typtr) then error(116); if sy = comma then insymbol else error(20); variable(fsys + [rparent]); if gattr.typtr <> nil then with gattr.typtr^ do if form = arrays then begin if not comptypes(aeltype,lsp1) or not comptypes(inxtype,lsp) then error(116) end else error(116) end (*pack*) ; procedure unpack; var lsp,lsp1: stp; begin error(399); variable(fsys + [comma,rparent]); lsp := nil; lsp1 := nil; if gattr.typtr <> nil then with gattr.typtr^ do if form = arrays then begin lsp := inxtype; lsp1 := aeltype end else error(116); if sy = comma then insymbol else error(20); variable(fsys + [comma,rparent]); if gattr.typtr <> nil then with gattr.typtr^ do if form = arrays then begin if not comptypes(aeltype,lsp1) or not comptypes(inxtype,lsp) then error(116) end else error(116); if sy = comma then insymbol else error(20); expression(fsys + [rparent]); if gattr.typtr <> nil then if gattr.typtr^.form <> scalar then error(116) else if not comptypes(lsp,gattr.typtr) then error(116); end (*unpack*) ; procedure new; label 1; var lsp,lsp1: stp; varts: integer; lsize: addrrange; lval: valu; begin variable(fsys + [comma,rparent]); loadaddress; lsp := nil; varts := 0; lsize := 0; if gattr.typtr <> nil then with gattr.typtr^ do if form = pointer then begin if eltype <> nil then begin lsize := eltype^.size; if eltype^.form = records then lsp := eltype^.recvar end end else error(116); while sy = comma do begin insymbol;constant(fsys + [comma,rparent],lsp1,lval); varts := varts + 1; (*check to insert here: is constant in tagfieldtype range*) if lsp = nil then error(158) else if lsp^.form <> tagfld then error(162) else if lsp^.tagfieldp <> nil then if string(lsp1) or (lsp1 = realptr) then error(159) else if comptypes(lsp^.tagfieldp^.idtype,lsp1) then begin lsp1 := lsp^.fstvar; while lsp1 <> nil do with lsp1^ do if varval.ival = lval.ival then begin lsize := size; lsp := subvar; goto 1 end else lsp1 := nxtvar; lsize := lsp^.size; lsp := nil; end else error(116); 1: end (*while*) ; gen2(51(*ldc*),1,lsize); gen1(30(*csp*),12(*new*)); end (*new*) ; procedure mark; begin variable(fsys+[rparent]); if gattr.typtr <> nil then if gattr.typtr^.form = pointer then begin loadaddress; gen1(30(*csp*),23(*sav*)) end else error(116) end(*mark*); procedure release; begin variable(fsys+[rparent]); if gattr.typtr <> nil then if gattr.typtr^.form = pointer then begin load; gen1(30(*csp*),13(*rst*)) end else error(116) end (*release*); procedure abs; begin if gattr.typtr <> nil then if gattr.typtr = intptr then gen0(0(*abi*)) else if gattr.typtr = realptr then gen0(1(*abr*)) else begin error(125); gattr.typtr := intptr end end (*abs*) ; procedure sqr; begin if gattr.typtr <> nil then if gattr.typtr = intptr then gen0(24(*sqi*)) else if gattr.typtr = realptr then gen0(25(*sqr*)) else begin error(125); gattr.typtr := intptr end end (*sqr*) ; procedure trunc; begin if gattr.typtr <> nil then if gattr.typtr <> realptr then error(125); gen0(27(*trc*)); gattr.typtr := intptr end (*trunc*) ; procedure odd; begin if gattr.typtr <> nil then if gattr.typtr <> intptr then error(125); gen0(20(*odd*)); gattr.typtr := boolptr end (*odd*) ; procedure ord; begin if gattr.typtr <> nil then if gattr.typtr^.form >= power then error(125); gen0t(58(*ord*),gattr.typtr); gattr.typtr := intptr end (*ord*) ; procedure chr; begin if gattr.typtr <> nil then if gattr.typtr <> intptr then error(125); gen0(59(*chr*)); gattr.typtr := charptr end (*chr*) ; procedure predsucc; begin if gattr.typtr <> nil then if gattr.typtr^.form <> scalar then error(125); if lkey = 7 then gen1t(31(*dec*),1,gattr.typtr) else gen1t(34(*inc*),1,gattr.typtr) end (*predsucc*) ; procedure eof; begin if sy = lparent then begin insymbol; variable(fsys + [rparent]); if sy = rparent then insymbol else error(4) end else with gattr do begin typtr := textptr; kind := varbl; access := drct; vlevel := 1; dplmt := lcaftermarkstack end; loadaddress; if gattr.typtr <> nil then if gattr.typtr^.form <> files then error(125); if lkey = 9 then gen0(8(*eof*)) else gen1(30(*csp*),14(*eln*)); gattr.typtr := boolptr end (*eof*) ; procedure callnonstandard; var nxt,lcp: ctp; lsp: stp; lkind: idkind; lb: boolean; locpar, llc: addrrange; begin locpar := 0; with fcp^ do begin nxt := next; lkind := pfkind; if not externl then gen1(41(*mst*),level-pflev) end; if sy = lparent then begin llc := lc; repeat lb := false; (*decide whether proc/func must be passed*) if lkind = actual then begin if nxt = nil then error(126) else lb := nxt^.klass in [proc,func] end else error(399); (*For formal proc/func, lb is false and expression will be called, which will always interpret a proc/func id at its beginning as a call rather than a parameter passing. In this implementation, parameter procedures/functions are therefore not allowed to have procedure/function parameters*) insymbol; if lb then (*pass function or procedure*) begin error(399); if sy <> ident then begin error(2); skip(fsys + [comma,rparent]) end else begin if nxt^.klass = proc then searchid([proc],lcp) else begin searchid([func],lcp); if not comptypes(lcp^.idtype,nxt^.idtype) then error(128) end; insymbol; if not (sy in fsys + [comma,rparent]) then begin error(6); skip(fsys + [comma,rparent]) end end end (*if lb*) else begin expression(fsys + [comma,rparent]); if gattr.typtr <> nil then if lkind = actual then begin if nxt <> nil then begin lsp := nxt^.idtype; if lsp <> nil then begin if (nxt^.vkind = actual) then if lsp^.form <= power then begin load; if debug then checkbnds(lsp); if comptypes(realptr,lsp) and (gattr.typtr = intptr) then begin gen0(10(*flt*)); gattr.typtr := realptr end; locpar := locpar+lsp^.size; align(parmptr,locpar); end else begin loadaddress; locpar := locpar+ptrsize; align(parmptr,locpar) end else if gattr.kind = varbl then begin loadaddress; locpar := locpar+ptrsize; align(parmptr,locpar); end else error(154); if not comptypes(lsp,gattr.typtr) then error(142) end end end else (*lkind = formal*) begin (*pass formal param*) end end; if (lkind = actual) and (nxt <> nil) then nxt := nxt^.next until sy <> comma; lc := llc; if sy = rparent then insymbol else error(4) end (*if lparent*); if lkind = actual then begin if nxt <> nil then error(126); with fcp^ do begin if externl then gen1(30(*csp*),pfname) else gencupent(46(*cup*),locpar,pfname); end end; gattr.typtr := fcp^.idtype end (*callnonstandard*) ; begin (*call*) if fcp^.pfdeckind = standard then begin lkey := fcp^.key; if fcp^.klass = proc then begin if not(lkey in [5,6,11,12]) then if sy = lparent then insymbol else error(9); case lkey of 1,2, 3,4: getputresetrewrite; 5,11: read; 6,12: write; 7: pack; 8: unpack; 9: new; 10: release; 13: mark end; if not(lkey in [5,6,11,12]) then if sy = rparent then insymbol else error(4) end else begin if lkey <= 8 then begin if sy = lparent then insymbol else error(9); expression(fsys+[rparent]); load end; case lkey of 1: abs; 2: sqr; 3: trunc; 4: odd; 5: ord; 6: chr; 7,8: predsucc; 9,10: eof end; if lkey <= 8 then if sy = rparent then insymbol else error(4) end; end (*standard procedures and functions*) else callnonstandard end (*call*) ; procedure expression; var lattr: attr; lop: operator; typind: char; lsize: addrrange; procedure simpleexpression(fsys: setofsys); var lattr: attr; lop: operator; signed: boolean; procedure term(fsys: setofsys); var lattr: attr; lop: operator; procedure factor(fsys: setofsys); var lcp: ctp; lvp: csp; varpart: boolean; cstpart: setty; lsp: stp; begin if not (sy in facbegsys) then begin error(58); skip(fsys + facbegsys); gattr.typtr := nil end; while sy in facbegsys do begin case sy of (*id*) ident: begin searchid([konst,vars,field,func],lcp); insymbol; if lcp^.klass = func then begin call(fsys,lcp); with gattr do begin kind := expr; if typtr <> nil then if typtr^.form=subrange then typtr := typtr^.rangetype end end else if lcp^.klass = konst then with gattr, lcp^ do begin typtr := idtype; kind := cst; cval := values end else begin selector(fsys,lcp); if gattr.typtr<>nil then(*elim.subr.types to*) with gattr,typtr^ do(*simplify later tests*) if form = subrange then typtr := rangetype end end; (*cst*) intconst: begin with gattr do begin typtr := intptr; kind := cst; cval := val end; insymbol end; realconst: begin with gattr do begin typtr := realptr; kind := cst; cval := val end; insymbol end; stringconst: begin with gattr do begin if lgth = 1 then typtr := charptr else begin new(lsp,arrays); with lsp^ do begin aeltype := charptr; form:=arrays; inxtype := nil; size := lgth*charsize end; typtr := lsp end; kind := cst; cval := val end; insymbol end; (* ( *) lparent: begin insymbol; expression(fsys + [rparent]); if sy = rparent then insymbol else error(4) end; (*not*) notsy: begin insymbol; factor(fsys); load; gen0(19(*not*)); if gattr.typtr <> nil then if gattr.typtr <> boolptr then begin error(135); gattr.typtr := nil end; end; (*[*) lbrack: begin insymbol; cstpart := [ ]; varpart := false; new(lsp,power); with lsp^ do begin elset:=nil;size:=setsize;form:=power end; if sy = rbrack then begin with gattr do begin typtr := lsp; kind := cst end; insymbol end else begin repeat expression(fsys + [comma,rbrack]); if gattr.typtr <> nil then if gattr.typtr^.form <> scalar then begin error(136); gattr.typtr := nil end else if comptypes(lsp^.elset,gattr.typtr) then begin if gattr.kind = cst then if (gattr.cval.ival < setlow) or (gattr.cval.ival > sethigh) then error(304) else cstpart := cstpart+[gattr.cval.ival] else begin load; if not comptypes(gattr.typtr,intptr) then gen0t(58(*ord*),gattr.typtr); gen0(23(*sgs*)); if varpart then gen0(28(*uni*)) else varpart := true end; lsp^.elset := gattr.typtr; gattr.typtr := lsp end else error(137); test := sy <> comma; if not test then insymbol until test; if sy = rbrack then insymbol else error(12) end; if varpart then begin if cstpart <> [ ] then begin new(lvp,pset); lvp^.pval := cstpart; lvp^.cclass := pset; if cstptrix = cstoccmax then error(254) else begin cstptrix := cstptrix + 1; cstptr[cstptrix] := lvp; gen2(51(*ldc*),5,cstptrix); gen0(28(*uni*)); gattr.kind := expr end end end else begin new(lvp,pset); lvp^.pval := cstpart; lvp^.cclass := pset; gattr.cval.valp := lvp end end end (*case*) ; if not (sy in fsys) then begin error(6); skip(fsys + facbegsys) end end (*while*) end (*factor*) ; begin (*term*) factor(fsys + [mulop]); while sy = mulop do begin load; lattr := gattr; lop := op; insymbol; factor(fsys + [mulop]); load; if (lattr.typtr <> nil) and (gattr.typtr <> nil) then case lop of (***) mul: if (lattr.typtr=intptr)and(gattr.typtr=intptr) then gen0(15(*mpi*)) else begin if lattr.typtr = intptr then begin gen0(9(*flo*)); lattr.typtr := realptr end else if gattr.typtr = intptr then begin gen0(10(*flt*)); gattr.typtr := realptr end; if (lattr.typtr = realptr) and(gattr.typtr=realptr)then gen0(16(*mpr*)) else if(lattr.typtr^.form=power) and comptypes(lattr.typtr,gattr.typtr)then gen0(12(*int*)) else begin error(134); gattr.typtr:=nil end end; (* / *) rdiv: begin if gattr.typtr = intptr then begin gen0(10(*flt*)); gattr.typtr := realptr end; if lattr.typtr = intptr then begin gen0(9(*flo*)); lattr.typtr := realptr end; if (lattr.typtr = realptr) and (gattr.typtr=realptr)then gen0(7(*dvr*)) else begin error(134); gattr.typtr := nil end end; (*div*) idiv: if (lattr.typtr = intptr) and (gattr.typtr = intptr) then gen0(6(*dvi*)) else begin error(134); gattr.typtr := nil end; (*mod*) imod: if (lattr.typtr = intptr) and (gattr.typtr = intptr) then gen0(14(*mod*)) else begin error(134); gattr.typtr := nil end; (*and*) andop:if (lattr.typtr = boolptr) and (gattr.typtr = boolptr) then gen0(4(*and*)) else begin error(134); gattr.typtr := nil end end (*case*) else gattr.typtr := nil end (*while*) end (*term*) ; begin (*simpleexpression*) signed := false; if (sy = addop) and (op in [plus,minus]) then begin signed := op = minus; insymbol end; term(fsys + [addop]); if signed then begin load; if gattr.typtr = intptr then gen0(17(*ngi*)) else if gattr.typtr = realptr then gen0(18(*ngr*)) else begin error(134); gattr.typtr := nil end end; while sy = addop do begin load; lattr := gattr; lop := op; insymbol; term(fsys + [addop]); load; if (lattr.typtr <> nil) and (gattr.typtr <> nil) then case lop of (*+*) plus: if (lattr.typtr = intptr)and(gattr.typtr = intptr) then gen0(2(*adi*)) else begin if lattr.typtr = intptr then begin gen0(9(*flo*)); lattr.typtr := realptr end else if gattr.typtr = intptr then begin gen0(10(*flt*)); gattr.typtr := realptr end; if (lattr.typtr = realptr)and(gattr.typtr = realptr) then gen0(3(*adr*)) else if(lattr.typtr^.form=power) and comptypes(lattr.typtr,gattr.typtr) then gen0(28(*uni*)) else begin error(134); gattr.typtr:=nil end end; (*-*) minus: if (lattr.typtr = intptr)and(gattr.typtr = intptr) then gen0(21(*sbi*)) else begin if lattr.typtr = intptr then begin gen0(9(*flo*)); lattr.typtr := realptr end else if gattr.typtr = intptr then begin gen0(10(*flt*)); gattr.typtr := realptr end; if (lattr.typtr = realptr)and(gattr.typtr = realptr) then gen0(22(*sbr*)) else if (lattr.typtr^.form = power) and comptypes(lattr.typtr,gattr.typtr) then gen0(5(*dif*)) else begin error(134); gattr.typtr := nil end end; (*or*) orop: if(lattr.typtr=boolptr)and(gattr.typtr=boolptr)then gen0(13(*ior*)) else begin error(134); gattr.typtr := nil end end (*case*) else gattr.typtr := nil end (*while*) end (*simpleexpression*) ; begin (*expression*) simpleexpression(fsys + [relop]); if sy = relop then begin if gattr.typtr <> nil then if gattr.typtr^.form <= power then load else loadaddress; lattr := gattr; lop := op; if lop = inop then if not comptypes(gattr.typtr,intptr) then gen0t(58(*ord*),gattr.typtr); insymbol; simpleexpression(fsys); if gattr.typtr <> nil then if gattr.typtr^.form <= power then load else loadaddress; if (lattr.typtr <> nil) and (gattr.typtr <> nil) then if lop = inop then if gattr.typtr^.form = power then if comptypes(lattr.typtr,gattr.typtr^.elset) then gen0(11(*inn*)) else begin error(129); gattr.typtr := nil end else begin error(130); gattr.typtr := nil end else begin if lattr.typtr <> gattr.typtr then if lattr.typtr = intptr then begin gen0(9(*flo*)); lattr.typtr := realptr end else if gattr.typtr = intptr then begin gen0(10(*flt*)); gattr.typtr := realptr end; if comptypes(lattr.typtr,gattr.typtr) then begin lsize := lattr.typtr^.size; case lattr.typtr^.form of scalar: if lattr.typtr = realptr then typind := 'r' else if lattr.typtr = boolptr then typind := 'b' else if lattr.typtr = charptr then typind := 'c' else typind := 'i'; pointer: begin if lop in [ltop,leop,gtop,geop] then error(131); typind := 'a' end; power: begin if lop in [ltop,gtop] then error(132); typind := 's' end; arrays: begin if not string(lattr.typtr) then error(134); typind := 'm' end; records: begin error(134); typind := 'm' end; files: begin error(133); typind := 'f' end end; case lop of ltop: gen2(53(*les*),ord(typind),lsize); leop: gen2(52(*leq*),ord(typind),lsize); gtop: gen2(49(*grt*),ord(typind),lsize); geop: gen2(48(*geq*),ord(typind),lsize); neop: gen2(55(*neq*),ord(typind),lsize); eqop: gen2(47(*equ*),ord(typind),lsize) end end else error(129) end; gattr.typtr := boolptr; gattr.kind := expr end (*sy = relop*) end (*expression*) ; procedure assignment(fcp: ctp); var lattr: attr; begin selector(fsys + [becomes],fcp); if sy = becomes then begin if gattr.typtr <> nil then if (gattr.access<>drct) or (gattr.typtr^.form>power) then loadaddress; lattr := gattr; insymbol; expression(fsys); if gattr.typtr <> nil then if gattr.typtr^.form <= power then load else loadaddress; if (lattr.typtr <> nil) and (gattr.typtr <> nil) then begin if comptypes(realptr,lattr.typtr)and(gattr.typtr=intptr)then begin gen0(10(*flt*)); gattr.typtr := realptr end; if comptypes(lattr.typtr,gattr.typtr) then case lattr.typtr^.form of scalar, subrange: begin if debug then checkbnds(lattr.typtr); store(lattr) end; pointer: begin if debug then gen2t(45(*chk*),0,maxaddr,nilptr); store(lattr) end; power: store(lattr); arrays, records: gen1(40(*mov*),lattr.typtr^.size); files: error(146) end else error(129) end end (*sy = becomes*) else error(51) end (*assignment*) ; procedure gotostatement; var llp: lbp; found: boolean; ttop,ttop1: disprange; begin if sy = intconst then begin found := false; ttop := top; while display[ttop].occur <> blck do ttop := ttop - 1; ttop1 := ttop; repeat llp := display[ttop].flabel; while (llp <> nil) and not found do with llp^ do if labval = val.ival then begin found := true; if ttop = ttop1 then genujpxjp(57(*ujp*),labname) else (*goto leads out of procedure*) error(399) end else llp := nextlab; ttop := ttop - 1 until found or (ttop = 0); if not found then error(167); insymbol end else error(15) end (*gotostatement*) ; procedure compoundstatement; begin repeat repeat statement(fsys + [semicolon,endsy]) until not (sy in statbegsys); test := sy <> semicolon; if not test then insymbol until test; if sy = endsy then insymbol else error(13) end (*compoundstatemenet*) ; procedure ifstatement; var lcix1,lcix2: integer; begin expression(fsys + [thensy]); genlabel(lcix1); genfjp(lcix1); if sy = thensy then insymbol else error(52); statement(fsys + [elsesy]); if sy = elsesy then begin genlabel(lcix2); genujpxjp(57(*ujp*),lcix2); putlabel(lcix1); insymbol; statement(fsys); putlabel(lcix2) end else putlabel(lcix1) end (*ifstatement*) ; procedure casestatement; label 1; type cip = ^caseinfo; caseinfo = packed record next: cip; csstart: integer; cslab: integer end; var lsp,lsp1: stp; fstptr,lpt1,lpt2,lpt3: cip; lval: valu; laddr, lcix, lcix1, lmin, lmax: integer; begin expression(fsys + [ofsy,comma,colon]); load; genlabel(lcix); lsp := gattr.typtr; if lsp <> nil then if (lsp^.form <> scalar) or (lsp = realptr) then begin error(144); lsp := nil end else if not comptypes(lsp,intptr) then gen0t(58(*ord*),lsp); genujpxjp(57(*ujp*),lcix); if sy = ofsy then insymbol else error(8); fstptr := nil; genlabel(laddr); repeat lpt3 := nil; genlabel(lcix1); if not(sy in [semicolon,endsy]) then begin repeat constant(fsys + [comma,colon],lsp1,lval); if lsp <> nil then if comptypes(lsp,lsp1) then begin lpt1 := fstptr; lpt2 := nil; while lpt1 <> nil do with lpt1^ do begin if cslab <= lval.ival then begin if cslab = lval.ival then error(156); goto 1 end; lpt2 := lpt1; lpt1 := next end; 1: new(lpt3); with lpt3^ do begin next := lpt1; cslab := lval.ival; csstart := lcix1 end; if lpt2 = nil then fstptr := lpt3 else lpt2^.next := lpt3 end else error(147); test := sy <> comma; if not test then insymbol until test; if sy = colon then insymbol else error(5); putlabel(lcix1); repeat statement(fsys + [semicolon]) until not (sy in statbegsys); if lpt3 <> nil then genujpxjp(57(*ujp*),laddr); end; test := sy <> semicolon; if not test then insymbol until test; putlabel(lcix); if fstptr <> nil then begin lmax := fstptr^.cslab; (*reverse pointers*) lpt1 := fstptr; fstptr := nil; repeat lpt2 := lpt1^.next; lpt1^.next := fstptr; fstptr := lpt1; lpt1 := lpt2 until lpt1 = nil; lmin := fstptr^.cslab; if lmax - lmin < cixmax then begin gen2t(45(*chk*),lmin,lmax,intptr); gen2(51(*ldc*),1,lmin); gen0(21(*sbi*)); genlabel(lcix); genujpxjp(44(*xjp*),lcix); putlabel(lcix); repeat with fstptr^ do begin while cslab > lmin do begin gen0(60(*ujc error*)); lmin := lmin+1 end; genujpxjp(57(*ujp*),csstart); fstptr := next; lmin := lmin + 1 end until fstptr = nil; putlabel(laddr) end else error(157) end; if sy = endsy then insymbol else error(13) end (*casestatement*) ; procedure repeatstatement; var laddr: integer; begin genlabel(laddr); putlabel(laddr); repeat statement(fsys + [semicolon,untilsy]); if sy in statbegsys then error(14) until not(sy in statbegsys); while sy = semicolon do begin insymbol; repeat statement(fsys + [semicolon,untilsy]); if sy in statbegsys then error(14) until not (sy in statbegsys); end; if sy = untilsy then begin insymbol; expression(fsys); genfjp(laddr) end else error(53) end (*repeatstatement*) ; procedure whilestatement; var laddr, lcix: integer; begin genlabel(laddr); putlabel(laddr); expression(fsys + [dosy]); genlabel(lcix); genfjp(lcix); if sy = dosy then insymbol else error(54); statement(fsys); genujpxjp(57(*ujp*),laddr); putlabel(lcix) end (*whilestatement*) ; procedure forstatement; var lattr: attr; lsy: symbol; lcix, laddr: integer; llc: addrrange; begin llc := lc; with lattr do begin typtr := nil; kind := varbl; access := drct; vlevel := level; dplmt := 0 end; if sy = ident then begin searchid([vars],lcp); with lcp^, lattr do begin typtr := idtype; kind := varbl; if vkind = actual then begin access := drct; vlevel := vlev; dplmt := vaddr end else begin error(155); typtr := nil end end; if lattr.typtr <> nil then if (lattr.typtr^.form > subrange) or comptypes(realptr,lattr.typtr) then begin error(143); lattr.typtr := nil end; insymbol end else begin error(2); skip(fsys + [becomes,tosy,downtosy,dosy]) end; if sy = becomes then begin insymbol; expression(fsys + [tosy,downtosy,dosy]); if gattr.typtr <> nil then if gattr.typtr^.form <> scalar then error(144) else if comptypes(lattr.typtr,gattr.typtr) then begin load; store(lattr) end else error(145) end else begin error(51); skip(fsys + [tosy,downtosy,dosy]) end; if sy in [tosy,downtosy] then begin lsy := sy; insymbol; expression(fsys + [dosy]); if gattr.typtr <> nil then if gattr.typtr^.form <> scalar then error(144) else if comptypes(lattr.typtr,gattr.typtr) then begin load; if not comptypes(lattr.typtr,intptr) then gen0t(58(*ord*),gattr.typtr); align(intptr,lc); gen2t(56(*str*),0,lc,intptr); genlabel(laddr); putlabel(laddr); gattr := lattr; load; if not comptypes(gattr.typtr,intptr) then gen0t(58(*ord*),gattr.typtr); gen2t(54(*lod*),0,lc,intptr); lc := lc + intsize; if lc > lcmax then lcmax := lc; if lsy = tosy then gen2(52(*leq*),ord('i'),1) else gen2(48(*geq*),ord('i'),1); end else error(145) end else begin error(55); skip(fsys + [dosy]) end; genlabel(lcix); genujpxjp(33(*fjp*),lcix); if sy = dosy then insymbol else error(54); statement(fsys); gattr := lattr; load; if lsy=tosy then gen1t(34(*inc*),1,gattr.typtr) else gen1t(31(*dec*),1,gattr.typtr); store(lattr); genujpxjp(57(*ujp*),laddr); putlabel(lcix); lc := llc; end (*forstatement*) ; procedure withstatement; var lcp: ctp; lcnt1: disprange; llc: addrrange; begin lcnt1 := 0; llc := lc; repeat if sy = ident then begin searchid([vars,field],lcp); insymbol end else begin error(2); lcp := uvarptr end; selector(fsys + [comma,dosy],lcp); if gattr.typtr <> nil then if gattr.typtr^.form = records then if top < displimit then begin top := top + 1; lcnt1 := lcnt1 + 1; with display[top] do begin fname := gattr.typtr^.fstfld; flabel := nil end; if gattr.access = drct then with display[top] do begin occur := crec; clev := gattr.vlevel; cdspl := gattr.dplmt end else begin loadaddress; align(nilptr,lc); gen2t(56(*str*),0,lc,nilptr); with display[top] do begin occur := vrec; vdspl := lc end; lc := lc+ptrsize; if lc > lcmax then lcmax := lc end end else error(250) else error(140); test := sy <> comma; if not test then insymbol until test; if sy = dosy then insymbol else error(54); statement(fsys); top := top-lcnt1; lc := llc; end (*withstatement*) ; begin (*statement*) if sy = intconst then (*label*) begin llp := display[level].flabel; while llp <> nil do with llp^ do if labval = val.ival then begin if defined then error(165); putlabel(labname); defined := true; goto 1 end else llp := nextlab; error(167); 1: insymbol; if sy = colon then insymbol else error(5) end; if not (sy in fsys + [ident]) then begin error(6); skip(fsys) end; if sy in statbegsys + [ident] then begin case sy of ident: begin searchid([vars,field,func,proc],lcp); insymbol; if lcp^.klass = proc then call(fsys,lcp) else assignment(lcp) end; beginsy: begin insymbol; compoundstatement end; gotosy: begin insymbol; gotostatement end; ifsy: begin insymbol; ifstatement end; casesy: begin insymbol; casestatement end; whilesy: begin insymbol; whilestatement end; repeatsy: begin insymbol; repeatstatement end; forsy: begin insymbol; forstatement end; withsy: begin insymbol; withstatement end end; if not (sy in [semicolon,endsy,elsesy,untilsy]) then begin error(6); skip(fsys) end end end (*statement*) ; begin (*body*) if fprocp <> nil then entname := fprocp^.pfname else genlabel(entname); cstptrix := 0; topnew := lcaftermarkstack; topmax := lcaftermarkstack; putlabel(entname); genlabel(segsize); genlabel(stacktop); gencupent(32(*ent1*),1,segsize); gencupent(32(*ent2*),2,stacktop); if fprocp <> nil then (*copy multiple values into local cells*) begin llc1 := lcaftermarkstack; lcp := fprocp^.next; while lcp <> nil do with lcp^ do begin align(parmptr,llc1); if klass = vars then if idtype <> nil then if idtype^.form > power then begin if vkind = actual then begin gen2(50(*lda*),0,vaddr); gen2t(54(*lod*),0,llc1,nilptr); gen1(40(*mov*),idtype^.size); end; llc1 := llc1 + ptrsize end else llc1 := llc1 + idtype^.size; lcp := lcp^.next; end; end; lcmax := lc; repeat repeat statement(fsys + [semicolon,endsy]) until not (sy in statbegsys); test := sy <> semicolon; if not test then insymbol until test; if sy = endsy then insymbol else error(13); llp := display[top].flabel; (*test for undefined labels*) while llp <> nil do with llp^ do begin if not defined then begin error(168); writeln(output); writeln(output,' label ',labval); write(output,' ':chcnt+16) end; llp := nextlab end; if fprocp <> nil then begin if fprocp^.idtype = nil then gen1(42(*ret*),ord('p')) else gen0t(42(*ret*),fprocp^.idtype); align(parmptr,lcmax); if prcode then begin writeln(prr,'l',segsize:4,'=',lcmax); writeln(prr,'l',stacktop:4,'=',topmax) end end else begin gen1(42(*ret*),ord('p')); align(parmptr,lcmax); if prcode then begin writeln(prr,'l',segsize:4,'=',lcmax); writeln(prr,'l',stacktop:4,'=',topmax); writeln(prr,'q') end; ic := 0; (*generate call of main program; note that this call must be loaded at absolute address zero*) gen1(41(*mst*),0); gencupent(46(*cup*),0,entname); gen0(29(*stp*)); if prcode then writeln(prr,'q'); saveid := id; while fextfilep <> nil do begin with fextfilep^ do if not ((filename = 'input ') or (filename = 'output ') or (filename = 'prd ') or (filename = 'prr ')) then begin id := filename; searchid([vars],llcp); if llcp^.idtype<>nil then if llcp^.idtype^.form<>files then begin writeln(output); writeln(output,' ':8,'undeclared ','external ', 'file',fextfilep^.filename:8); write(output,' ':chcnt+16) end end; fextfilep := fextfilep^.nextfile end; id := saveid; if prtables then begin writeln(output); printtables(true) end end; end (*body*) ; begin (*block*) dp := true; repeat if sy = labelsy then begin insymbol; labeldeclaration end; if sy = constsy then begin insymbol; constdeclaration end; if sy = typesy then begin insymbol; typedeclaration end; if sy = varsy then begin insymbol; vardeclaration end; while sy in [procsy,funcsy] do begin lsy := sy; insymbol; procdeclaration(lsy) end; if sy <> beginsy then begin error(18); skip(fsys) end until (sy in statbegsys) or eof(input); dp := false; if sy = beginsy then insymbol else error(17); repeat body(fsys + [casesy]); if sy <> fsy then begin error(6); skip(fsys) end until ((sy = fsy) or (sy in blockbegsys)) or eof(input); end (*block*) ; procedure programme(fsys:setofsys); var extfp:extfilep; begin if sy = progsy then begin insymbol; if sy <> ident then error(2); insymbol; if not (sy in [lparent,semicolon]) then error(14); if sy = lparent then begin repeat insymbol; if sy = ident then begin new(extfp); with extfp^ do begin filename := id; nextfile := fextfilep end; fextfilep := extfp; insymbol; if not ( sy in [comma,rparent] ) then error(20) end else error(2) until sy <> comma; if sy <> rparent then error(4); insymbol end; if sy <> semicolon then error(14) else insymbol; end; repeat block(fsys,period,nil); if sy <> period then error(21) until (sy = period) or eof(input); if list then writeln(output); if errinx <> 0 then begin list := false; endofline end end (*programme*) ; procedure stdnames; begin na[ 1] := 'false '; na[ 2] := 'true '; na[ 3] := 'input '; na[ 4] := 'output '; na[ 5] := 'get '; na[ 6] := 'put '; na[ 7] := 'reset '; na[ 8] := 'rewrite '; na[ 9] := 'read '; na[10] := 'write '; na[11] := 'pack '; na[12] := 'unpack '; na[13] := 'new '; na[14] := 'release '; na[15] := 'readln '; na[16] := 'writeln '; na[17] := 'abs '; na[18] := 'sqr '; na[19] := 'trunc '; na[20] := 'odd '; na[21] := 'ord '; na[22] := 'chr '; na[23] := 'pred '; na[24] := 'succ '; na[25] := 'eof '; na[26] := 'eoln '; na[27] := 'sin '; na[28] := 'cos '; na[29] := 'exp '; na[30] := 'sqrt '; na[31] := 'ln '; na[32] := 'arctan '; na[33] := 'prd '; na[34] := 'prr '; na[35] := 'mark '; end (*stdnames*) ; procedure enterstdtypes; begin (*type underlying:*) (******************) new(intptr,scalar,standard); (*integer*) with intptr^ do begin size := intsize; form := scalar; scalkind := standard end; new(realptr,scalar,standard); (*real*) with realptr^ do begin size := realsize; form := scalar; scalkind := standard end; new(charptr,scalar,standard); (*char*) with charptr^ do begin size := charsize; form := scalar; scalkind := standard end; new(boolptr,scalar,declared); (*boolean*) with boolptr^ do begin size := boolsize; form := scalar; scalkind := declared end; new(nilptr,pointer); (*nil*) with nilptr^ do begin eltype := nil; size := ptrsize; form := pointer end; new(parmptr,scalar,standard); (*for alignment of parameters*) with parmptr^ do begin size := parmsize; form := scalar; scalkind := standard end ; new(textptr,files); (*text*) with textptr^ do begin filtype := charptr; size := charsize; form := files end end (*enterstdtypes*) ; procedure entstdnames; var cp,cp1: ctp; i: integer; begin (*name:*) (*******) new(cp,types); (*integer*) with cp^ do begin name := 'integer '; idtype := intptr; klass := types end; enterid(cp); new(cp,types); (*real*) with cp^ do begin name := 'real '; idtype := realptr; klass := types end; enterid(cp); new(cp,types); (*char*) with cp^ do begin name := 'char '; idtype := charptr; klass := types end; enterid(cp); new(cp,types); (*boolean*) with cp^ do begin name := 'boolean '; idtype := boolptr; klass := types end; enterid(cp); cp1 := nil; for i := 1 to 2 do begin new(cp,konst); (*false,true*) with cp^ do begin name := na[i]; idtype := boolptr; next := cp1; values.ival := i - 1; klass := konst end; enterid(cp); cp1 := cp end; boolptr^.fconst := cp; new(cp,konst); (*nil*) with cp^ do begin name := 'nil '; idtype := nilptr; next := nil; values.ival := 0; klass := konst end; enterid(cp); for i := 3 to 4 do begin new(cp,vars); (*input,output*) with cp^ do begin name := na[i]; idtype := textptr; klass := vars; vkind := actual; next := nil; vlev := 1; vaddr := lcaftermarkstack+(i-3)*charmax; end; enterid(cp) end; for i:=33 to 34 do begin new(cp,vars); (*prd,prr files*) with cp^ do begin name := na[i]; idtype := textptr; klass := vars; vkind := actual; next := nil; vlev := 1; vaddr := lcaftermarkstack+(i-31)*charmax; end; enterid(cp) end; for i := 5 to 16 do begin new(cp,proc,standard); (*get,put,reset*) with cp^ do (*rewrite,read*) begin name := na[i]; idtype := nil; (*write,pack*) next := nil; key := i - 4; (*unpack,pack*) klass := proc; pfdeckind := standard end; enterid(cp) end; new(cp,proc,standard); with cp^ do begin name:=na[35]; idtype:=nil; next:= nil; key:=13; klass:=proc; pfdeckind:= standard end; enterid(cp); for i := 17 to 26 do begin new(cp,func,standard); (*abs,sqr,trunc*) with cp^ do (*odd,ord,chr*) begin name := na[i]; idtype := nil; (*pred,succ,eof*) next := nil; key := i - 16; klass := func; pfdeckind := standard end; enterid(cp) end; new(cp,vars); (*parameter of predeclared functions*) with cp^ do begin name := ' '; idtype := realptr; klass := vars; vkind := actual; next := nil; vlev := 1; vaddr := 0 end; for i := 27 to 32 do begin new(cp1,func,declared,actual); (*sin,cos,exp*) with cp1^ do (*sqrt,ln,arctan*) begin name := na[i]; idtype := realptr; next := cp; forwdecl := false; externl := true; pflev := 0; pfname := i - 12; klass := func; pfdeckind := declared; pfkind := actual end; enterid(cp1) end end (*entstdnames*) ; procedure enterundecl; begin new(utypptr,types); with utypptr^ do begin name := ' '; idtype := nil; klass := types end; new(ucstptr,konst); with ucstptr^ do begin name := ' '; idtype := nil; next := nil; values.ival := 0; klass := konst end; new(uvarptr,vars); with uvarptr^ do begin name := ' '; idtype := nil; vkind := actual; next := nil; vlev := 0; vaddr := 0; klass := vars end; new(ufldptr,field); with ufldptr^ do begin name := ' '; idtype := nil; next := nil; fldaddr := 0; klass := field end; new(uprcptr,proc,declared,actual); with uprcptr^ do begin name := ' '; idtype := nil; forwdecl := false; next := nil; externl := false; pflev := 0; genlabel(pfname); klass := proc; pfdeckind := declared; pfkind := actual end; new(ufctptr,func,declared,actual); with ufctptr^ do begin name := ' '; idtype := nil; next := nil; forwdecl := false; externl := false; pflev := 0; genlabel(pfname); klass := func; pfdeckind := declared; pfkind := actual end end (*enterundecl*) ; procedure initscalars; begin fwptr := nil; prtables := false; list := true; prcode := true; debug := true; dp := true; prterr := true; errinx := 0; intlabel := 0; kk := 8; fextfilep := nil; lc := lcaftermarkstack+filebuffer*charmax; (* note in the above reservation of buffer store for 2 text files *) ic := 3; eol := true; linecount := 0; ch := ' '; chcnt := 0; globtestp := nil; mxint10 := maxint div 10; digmax := strglgth - 1; end (*initscalars*) ; procedure initsets; begin constbegsys := [addop,intconst,realconst,stringconst,ident]; simptypebegsys := [lparent] + constbegsys; typebegsys:=[arrow,packedsy,arraysy,recordsy,setsy,filesy]+simptypebegsys; typedels := [arraysy,recordsy,setsy,filesy]; blockbegsys := [labelsy,constsy,typesy,varsy,procsy,funcsy,beginsy]; selectsys := [arrow,period,lbrack]; facbegsys := [intconst,realconst,stringconst,ident,lparent,lbrack,notsy]; statbegsys := [beginsy,gotosy,ifsy,whilesy,repeatsy,forsy,withsy,casesy]; end (*initsets*) ; procedure inittables; procedure reswords; begin rw[ 1] := 'if '; rw[ 2] := 'do '; rw[ 3] := 'of '; rw[ 4] := 'to '; rw[ 5] := 'in '; rw[ 6] := 'or '; rw[ 7] := 'end '; rw[ 8] := 'for '; rw[ 9] := 'var '; rw[10] := 'div '; rw[11] := 'mod '; rw[12] := 'set '; rw[13] := 'and '; rw[14] := 'not '; rw[15] := 'then '; rw[16] := 'else '; rw[17] := 'with '; rw[18] := 'goto '; rw[19] := 'case '; rw[20] := 'type '; rw[21] := 'file '; rw[22] := 'begin '; rw[23] := 'until '; rw[24] := 'while '; rw[25] := 'array '; rw[26] := 'const '; rw[27] := 'label '; rw[28] := 'repeat '; rw[29] := 'record '; rw[30] := 'downto '; rw[31] := 'packed '; rw[32] := 'forward '; rw[33] := 'program '; rw[34] := 'function'; rw[35] := 'procedur'; frw[1] := 1; frw[2] := 1; frw[3] := 7; frw[4] := 15; frw[5] := 22; frw[6] := 28; frw[7] := 32; frw[8] := 34; frw[9] := 36; end (*reswords*) ; procedure symbols; begin rsy[ 1] := ifsy; rsy[ 2] := dosy; rsy[ 3] := ofsy; rsy[ 4] := tosy; rsy[ 5] := relop; rsy[ 6] := addop; rsy[ 7] := endsy; rsy[ 8] := forsy; rsy[ 9] := varsy; rsy[10] := mulop; rsy[11] := mulop; rsy[12] := setsy; rsy[13] := mulop; rsy[14] := notsy; rsy[15] := thensy; rsy[16] := elsesy; rsy[17] := withsy; rsy[18] := gotosy; rsy[19] := casesy; rsy[20] := typesy; rsy[21] := filesy; rsy[22] := beginsy; rsy[23] := untilsy; rsy[24] := whilesy; rsy[25] := arraysy; rsy[26] := constsy; rsy[27] := labelsy; rsy[28] := repeatsy; rsy[29] := recordsy; rsy[30] := downtosy; rsy[31] := packedsy; rsy[32] := forwardsy; rsy[33] := progsy; rsy[34] := funcsy; rsy[35] := procsy; ssy['+'] := addop ; ssy['-'] := addop; ssy['*'] := mulop; ssy['/'] := mulop ; ssy['('] := lparent; ssy[')'] := rparent; ssy['$'] := othersy ; ssy['='] := relop; ssy[' '] := othersy; ssy[','] := comma ; ssy['.'] := period; ssy['''']:= othersy; ssy['['] := lbrack ; ssy[']'] := rbrack; ssy[':'] := colon; ssy['^'] := arrow ; ssy['<'] := relop; ssy['>'] := relop; ssy[';'] := semicolon; end (*symbols*) ; procedure rators; var i: integer; begin for i := 1 to 35 (*nr of res words*) do rop[i] := noop; rop[5] := inop; rop[10] := idiv; rop[11] := imod; rop[6] := orop; rop[13] := andop; for i := ordminchar to ordmaxchar do sop[chr(i)] := noop; sop['+'] := plus; sop['-'] := minus; sop['*'] := mul; sop['/'] := rdiv; sop['='] := eqop; sop['<'] := ltop; sop['>'] := gtop; end (*rators*) ; procedure procmnemonics; begin sna[ 1] :=' get'; sna[ 2] :=' put'; sna[ 3] :=' rdi'; sna[ 4] :=' rdr'; sna[ 5] :=' rdc'; sna[ 6] :=' wri'; sna[ 7] :=' wro'; sna[ 8] :=' wrr'; sna[ 9] :=' wrc'; sna[10] :=' wrs'; sna[11] :=' pak'; sna[12] :=' new'; sna[13] :=' rst'; sna[14] :=' eln'; sna[15] :=' sin'; sna[16] :=' cos'; sna[17] :=' exp'; sna[18] :=' sqt'; sna[19] :=' log'; sna[20] :=' atn'; sna[21] :=' rln'; sna[22] :=' wln'; sna[23] :=' sav'; end (*procmnemonics*) ; procedure instrmnemonics; begin mn[ 0] :=' abi'; mn[ 1] :=' abr'; mn[ 2] :=' adi'; mn[ 3] :=' adr'; mn[ 4] :=' and'; mn[ 5] :=' dif'; mn[ 6] :=' dvi'; mn[ 7] :=' dvr'; mn[ 8] :=' eof'; mn[ 9] :=' flo'; mn[10] :=' flt'; mn[11] :=' inn'; mn[12] :=' int'; mn[13] :=' ior'; mn[14] :=' mod'; mn[15] :=' mpi'; mn[16] :=' mpr'; mn[17] :=' ngi'; mn[18] :=' ngr'; mn[19] :=' not'; mn[20] :=' odd'; mn[21] :=' sbi'; mn[22] :=' sbr'; mn[23] :=' sgs'; mn[24] :=' sqi'; mn[25] :=' sqr'; mn[26] :=' sto'; mn[27] :=' trc'; mn[28] :=' uni'; mn[29] :=' stp'; mn[30] :=' csp'; mn[31] :=' dec'; mn[32] :=' ent'; mn[33] :=' fjp'; mn[34] :=' inc'; mn[35] :=' ind'; mn[36] :=' ixa'; mn[37] :=' lao'; mn[38] :=' lca'; mn[39] :=' ldo'; mn[40] :=' mov'; mn[41] :=' mst'; mn[42] :=' ret'; mn[43] :=' sro'; mn[44] :=' xjp'; mn[45] :=' chk'; mn[46] :=' cup'; mn[47] :=' equ'; mn[48] :=' geq'; mn[49] :=' grt'; mn[50] :=' lda'; mn[51] :=' ldc'; mn[52] :=' leq'; mn[53] :=' les'; mn[54] :=' lod'; mn[55] :=' neq'; mn[56] :=' str'; mn[57] :=' ujp'; mn[58] :=' ord'; mn[59] :=' chr'; mn[60] :=' ujc'; end (*instrmnemonics*) ; procedure chartypes; var i : integer; begin for i := ordminchar to ordmaxchar do chartp[chr(i)] := illegal; chartp['a'] := letter ; chartp['b'] := letter ; chartp['c'] := letter ; chartp['d'] := letter ; chartp['e'] := letter ; chartp['f'] := letter ; chartp['g'] := letter ; chartp['h'] := letter ; chartp['i'] := letter ; chartp['j'] := letter ; chartp['k'] := letter ; chartp['l'] := letter ; chartp['m'] := letter ; chartp['n'] := letter ; chartp['o'] := letter ; chartp['p'] := letter ; chartp['q'] := letter ; chartp['r'] := letter ; chartp['s'] := letter ; chartp['t'] := letter ; chartp['u'] := letter ; chartp['v'] := letter ; chartp['w'] := letter ; chartp['x'] := letter ; chartp['y'] := letter ; chartp['z'] := letter ; chartp['0'] := number ; chartp['1'] := number ; chartp['2'] := number ; chartp['3'] := number ; chartp['4'] := number ; chartp['5'] := number ; chartp['6'] := number ; chartp['7'] := number ; chartp['8'] := number ; chartp['9'] := number ; chartp['+'] := special ; chartp['-'] := special ; chartp['*'] := special ; chartp['/'] := special ; chartp['('] := chlparen; chartp[')'] := special ; chartp['$'] := special ; chartp['='] := special ; chartp[' '] := chspace ; chartp[','] := special ; chartp['.'] := chperiod; chartp['''']:= chstrquo; chartp['['] := special ; chartp[']'] := special ; chartp[':'] := chcolon ; chartp['^'] := special ; chartp[';'] := special ; chartp['<'] := chlt ; chartp['>'] := chgt ; ordint['0'] := 0; ordint['1'] := 1; ordint['2'] := 2; ordint['3'] := 3; ordint['4'] := 4; ordint['5'] := 5; ordint['6'] := 6; ordint['7'] := 7; ordint['8'] := 8; ordint['9'] := 9; end; procedure initdx; begin cdx[ 0] := 0; cdx[ 1] := 0; cdx[ 2] := -1; cdx[ 3] := -1; cdx[ 4] := -1; cdx[ 5] := -1; cdx[ 6] := -1; cdx[ 7] := -1; cdx[ 8] := 0; cdx[ 9] := 0; cdx[10] := 0; cdx[11] := -1; cdx[12] := -1; cdx[13] := -1; cdx[14] := -1; cdx[15] := -1; cdx[16] := -1; cdx[17] := 0; cdx[18] := 0; cdx[19] := 0; cdx[20] := 0; cdx[21] := -1; cdx[22] := -1; cdx[23] := 0; cdx[24] := 0; cdx[25] := 0; cdx[26] := -2; cdx[27] := 0; cdx[28] := -1; cdx[29] := 0; cdx[30] := 0; cdx[31] := 0; cdx[32] := 0; cdx[33] := -1; cdx[34] := 0; cdx[35] := 0; cdx[36] := -1; cdx[37] := +1; cdx[38] := +1; cdx[39] := +1; cdx[40] := -2; cdx[41] := 0; cdx[42] := 0; cdx[43] := -1; cdx[44] := -1; cdx[45] := 0; cdx[46] := 0; cdx[47] := -1; cdx[48] := -1; cdx[49] := -1; cdx[50] := +1; cdx[51] := +1; cdx[52] := -1; cdx[53] := -1; cdx[54] := +1; cdx[55] := -1; cdx[56] := -1; cdx[57] := 0; cdx[58] := 0; cdx[59] := 0; cdx[60] := 0; pdx[ 1] := -1; pdx[ 2] := -1; pdx[ 3] := -2; pdx[ 4] := -2; pdx[ 5] := -2; pdx[ 6] := -3; pdx[ 7] := -3; pdx[ 8] := -3; pdx[ 9] := -3; pdx[10] := -4; pdx[11] := 0; pdx[12] := -2; pdx[13] := -1; pdx[14] := 0; pdx[15] := 0; pdx[16] := 0; pdx[17] := 0; pdx[18] := 0; pdx[19] := 0; pdx[20] := 0; pdx[21] := -1; pdx[22] := -1; pdx[23] := -1; end; begin (*inittables*) reswords; symbols; rators; instrmnemonics; procmnemonics; chartypes; initdx; end (*inittables*) ; begin (*initialize*) (************) initscalars; initsets; inittables; (*enter standard names and standard types:*) (******************************************) level := 0; top := 0; with display[0] do begin fname := nil; flabel := nil; occur := blck end; enterstdtypes; stdnames; entstdnames; enterundecl; top := 1; level := 1; with display[1] do begin fname := nil; flabel := nil; occur := blck end; (*compile:*) rewrite(prr); (*comment this out when compiling with pcom *) (**********) insymbol; programme(blockbegsys+statbegsys-[casesy]); end.