rs@uunet.UU.NET (Rich Salz) (07/30/87)
Submitted-by: Per Bergsten <mcvax!enea!chalmers!holtec!perb> Posting-number: Volume 10, Issue 74 Archive-name: ptoc/Part10 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 10 (of 12)." # Contents: ptc.p.2 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'ptc.p.2' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'ptc.p.2'\" else echo shar: Extracting \"'ptc.p.2'\" \(52771 characters\) sed "s/^X//" >'ptc.p.2' <<'END_OF_FILE' X if sp^.lt = lforwlab then X sp^.lt := llabel X else X error(emuldeflab); X end; X oldlbl := tp X end; X X (* Parse declaration and statement-body for prog/subs. *) X procedure pbody(tp : treeptr); X X var tq : treeptr; X X begin X statlvl := statlvl + 1; X if currsym.st = slabel then X begin X tp^.tsublab := plabel; X linkup(tp, tp^.tsublab) X end X else X tp^.tsublab := nil; X if currsym.st = sconst then X begin X tp^.tsubconst := pconst; X linkup(tp, tp^.tsubconst) X end X else X tp^.tsubconst := nil; X if currsym.st = stype then X begin X tp^.tsubtype := ptype; X linkup(tp, tp^.tsubtype) X end X else X tp^.tsubtype := nil; X if currsym.st = svar then X begin X tp^.tsubvar := pvar; X linkup(tp, tp^.tsubvar) X end X else X tp^.tsubvar := nil; X tp^.tsubsub := nil; X tq := nil; X while (currsym.st = sproc) or (currsym.st = sfunc) do X begin X if tq = nil then X begin X tq := psubs; X tp^.tsubsub := tq X end X else begin X tq^.tnext := psubs; X tq := tq^.tnext X end X end; X linkup(tp, tp^.tsubsub); X checksymbol([sbegin, seof]); X if currsym.st = sbegin then X begin X tp^.tsubstmt := pbegin(false); X linkup(tp, tp^.tsubstmt) X end; X statlvl := statlvl - 1 X end; X X (* Parse program-declaration. *) X function pprogram : treeptr; X X var tp : treeptr; X X (* Parse a program parameter id-list. *) X function pprmlist : treeptr; X X label 999; X X var tp, X tq : treeptr; X din, X dut : idptr; X X begin X tp := nil; X din := deftab[dinput]^.tidl^.tsym^.lid; X dut := deftab[doutput]^.tidl^.tsym^.lid; X while (currsym.vid = din) or (currsym.vid = dut) do X begin X (* ignore input/output as parameters so that X they will be bound to stdin/stdout unless X declared as variables *) X if currsym.vid = din then X defnams[dinput]^.lused := true X else X defnams[doutput]^.lused := true; X nextsymbol([scomma, srpar]); X if currsym.st = srpar then X goto 999; X nextsymbol([sid]) X end; X tq := newid(currsym.vid); X tq^.tsym^.lt := lpointer; X tp := tq; X nextsymbol([scomma, srpar]); X while currsym.st = scomma do X begin X nextsymbol([sid]); X if currsym.vid = din then X defnams[dinput]^.lused := true X else if currsym.vid = dut then X defnams[doutput]^.lused := true X else begin X tq^.tnext := newid(currsym.vid); X tq := tq^.tnext; X tq^.tsym^.lt := lpointer; X end; X nextsymbol([scomma, srpar]) X end; X 999: X pprmlist := tp X end; X X begin (* pprogram *) X enterscope(nil); X tp := mknode(npgm); X nextsymbol([sid]); X tp^.tstat := statlvl; X tp^.tsubid := mknode(nid); X tp^.tsubid^.tup := tp; X tp^.tsubid^.tsym := mksym(lidentifier); X tp^.tsubid^.tsym^.lid := currsym.vid; X tp^.tsubid^.tsym^.lsymdecl := tp^.tsubid; X linkup(tp, tp^.tsubid); X nextsymbol([slpar, ssemic]); X if currsym.st = slpar then X begin X nextsymbol([sid]); X tp^.tsubpar := pprmlist; X linkup(tp, tp^.tsubpar); X nextsymbol([ssemic]) X end X else X tp^.tsubpar := nil; X nextsymbol([slabel, sconst, stype, svar, X sproc, sfunc, sbegin]); X pbody(tp); X checksymbol([sdot]); X tp^.tscope := currscope; X leavescope; X pprogram := tp X end; (* pprogram *) X X (* Parse a module. *) X function pmodule : treeptr; X X var tp : treeptr; X X begin (* pmodule *) X enterscope(nil); X tp := mknode(npgm); X tp^.tstat := statlvl; X tp^.tsubid := nil; X tp^.tsubpar := nil; X pbody(tp); X checksymbol([ssemic]); X tp^.tscope := currscope; X leavescope; X pmodule := tp X end; (* pmodule *) X X X (* Parse label-clause. *) X function plabel; X X var tp, X tq : treeptr; X X begin X tq := nil; X repeat X nextsymbol([sinteger]); X if tq = nil then X begin X tq := newlbl; X tp := tq X end X else begin X tq^.tnext := newlbl; X tq := tq^.tnext; X end; X nextsymbol([scomma, ssemic]) X until currsym.st = ssemic; X nextsymbol([sconst, stype, svar, sbegin, sproc, sfunc]); X plabel := tp X end; X X (* Parse an id-list. *) X function pidlist; X X var tp, X tq : treeptr; X X begin X tq := newid(currsym.vid); X tq^.tsym^.lt := l; X tp := tq; X nextsymbol([scomma, scolon, seq, srpar]); X while currsym.st = scomma do X begin X nextsymbol([sid]); X tq^.tnext := newid(currsym.vid); X tq := tq^.tnext; X tq^.tsym^.lt := l; X nextsymbol([scomma, scolon, seq, srpar]) X end; X pidlist := tp X end; X X (* Parse const-clause. *) X function pconst; X X var tp, X tq : treeptr; X X begin X tq := nil; X nextsymbol([sid]); X repeat X if tq = nil then X begin X tq := mknode(nconst); X tq^.tattr := anone; X tp := tq X end X else begin X tq^.tnext := mknode(nconst); X tq := tq^.tnext; X tq^.tattr := anone X end; X tq^.tidl := pidlist(lidentifier); X checksymbol([seq]); X nextsymbol([sid, schar, sstring, sinteger, sreal, X splus, sminus]); X tq^.tbind := pconstant(true); X nextsymbol([ssemic]); X nextsymbol([sid, stype, svar, sbegin, X sfunc, sproc, seof]) X until currsym.st <> sid; X pconst := tp X end; X X (* Parse a declared constant or a case-statment const. *) X function pconstant; X X var tp, X tq : treeptr; X neg : boolean; X X begin X neg := currsym.st = sminus; X if currsym.st in [splus, sminus] then X if realok then X nextsymbol([sid, sinteger, sreal]) X else X nextsymbol([sid, sinteger]); X if currsym.st = sid then X tp := oldid(currsym.vid, lidentifier) X else X tp := mklit; X if neg then X begin X tq := mknode(numinus); X tq^.texps := tp; X tp := tq X end; X pconstant := tp X end; X X (* Parse a record (or record-variant) declaration. *) X (* Cs is the expected closing symbol, dp the scope. *) X function precord; X X label 999; X X var tp, X tq, X tl, X tv : treeptr; X tsym : lexsym; X X begin X tp := mknode(nrecord); X tp^.tflist := nil; X tp^.tvlist := nil; X tp^.tuid := nil; X tp^.trscope := nil; X if cs = send then X begin X enterscope(dp); X dp := currscope X end; X nextsymbol([sid, scase] + [cs]); X tq := nil; X while currsym.st = sid do X begin X if tq = nil then X begin X tq := mknode(nfield); X tq^.tattr := anone; X tp^.tflist := tq X end X else begin X tq^.tnext := mknode(nfield); X tq := tq^.tnext; X tq^.tattr := anone X end; X tq^.tidl := pidlist(lfield); X checksymbol([scolon]); X leavescope; X tq^.tbind := ptypedef; X enterscope(dp); X if currsym.st = ssemic then X nextsymbol([sid, scase] + [cs]) X end; X if currsym.st = scase then X begin X nextsymbol([sid]); X tsym := currsym; X nextsymbol([scolon, sof]); X if currsym.st = scolon then X begin X tv := newid(tsym.vid); X if tq = nil then X begin X tq := mknode(nfield); X tp^.tflist := tq X end X else begin X tq^.tnext := mknode(nfield); X tq := tq^.tnext X end; X tq^.tidl := tv; X tv^.tsym^.lt := lfield; X nextsymbol([sid]); X leavescope; X tq^.tbind := oldid(currsym.vid, lidentifier); X enterscope(dp); X nextsymbol([sof]) X end; X tq := nil; X repeat X tv := nil; X repeat X nextsymbol([sid, sinteger, schar, splus, X sminus] + [cs]); X if currsym.st = cs then X goto 999; X if tv = nil then X begin X tv := pconstant(false); X tl := tv X end X else begin X tv^.tnext := pconstant(false); X tv := tv^.tnext X end; X nextsymbol([scolon, scomma]) X until currsym.st = scolon; X nextsymbol([slpar]); X if tq = nil then X begin X tq := mknode(nvariant); X tp^.tvlist := tq; X end X else begin X tq^.tnext := mknode(nvariant); X tq := tq^.tnext; X end; X tq^.tselct := tl; X tq^.tvrnt := precord(srpar, dp) X until currsym.st = cs X end; X 999: X if cs = send then X begin X tp^.trscope := dp; X leavescope X end; X nextsymbol([ssemic, send, srpar]); X (* currsym is the symbol following record end/rpar, X (usually semicolon, sometimes enclosing end/rpar) *) X precord := tp X end; X X function ptypedef; X X var tp, X tq : treeptr; X st : symtyp; X ss : symset; X X begin X nextsymbol([sid, slpar, sarrow, sinteger, schar, splus, sminus, X spacked, sarray, srecord, sfile, sset]); X X (* the "packed" keyword is completely ignored *) X if currsym.st = spacked then X nextsymbol([sarray, srecord, sfile, sset]); X X ss := [ssemic, send, srpar, scomma, srbrack]; X case currsym.st of X splus, X sminus, X schar, X sinteger, X sid: X begin X st := currsym.st; X tp := pconstant(false); X if st = sid then X nextsymbol([sdotdot] + ss) X else X nextsymbol([sdotdot]); X if currsym.st = sdotdot then X begin X nextsymbol([sid, sinteger, schar, X splus, sminus]); X tq := mknode(nsubrange); X tq^.tlo := tp; X tq^.thi := pconstant(false); X tp := tq; X nextsymbol(ss) X end X end; X slpar: X begin X tp := mknode(nscalar); X nextsymbol([sid]); X tp^.tscalid := pidlist(lidentifier); X checksymbol([srpar]); X nextsymbol(ss) X end; X sarrow: X begin X tp := mknode(nptr); X nextsymbol([sid]); X tp^.tptrid := oldid(currsym.vid, lpointer); X tp^.tptrflag := false; X nextsymbol([ssemic, send, srpar]) X end; X sarray: X begin X nextsymbol([slbrack]); X tp := mknode(narray); X tp^.taindx := ptypedef; (* parse subrange ... *) X tq := tp; X while currsym.st = scomma do X begin X (* expand: array [ A , B ] of X X to: array [ A ] of array [ B ] of X *) X tq^.taelem := mknode(narray); X tq := tq^.taelem; X tq^.taindx := ptypedef (* ... again *) X end; X checksymbol([srbrack]); X nextsymbol([sof]); X tq^.taelem := ptypedef X end; X srecord: X tp := precord(send, nil); X sfile, X sset: X begin X if currsym.st = sfile then X tp := mknode(nfileof) X else begin X tp := mknode(nsetof); X usesets := true X end; X nextsymbol([sof]); X tp^.tof := ptypedef X end X end; X (* at this point "currsym" holds the symbol following the type X (usually semicolon, sometimes the following end/rpar) *) X ptypedef := tp X end; X X (* Parse type-clause. *) X function ptype; X X var tp, X tq : treeptr; X X begin X tq := nil; X nextsymbol([sid]); X repeat X if tq = nil then X begin X tq := mknode(ntype); X tq^.tattr := anone; X tp := tq X end X else begin X tq^.tnext := mknode(ntype); X tq := tq^.tnext; X tq^.tattr := anone X end; X tq^.tidl := pidlist(lidentifier); X checksymbol([seq]); X tq^.tbind := ptypedef; X nextsymbol([sid, svar, sbegin, sfunc, sproc, seof]) X until currsym.st <> sid; X ptype := tp; X end; X X (* Parse var-clause. *) X function pvar; X X var ti, X tp, X tq : treeptr; X X begin X tq := nil; X nextsymbol([sid]); X repeat X if tq = nil then X begin X tq := mknode(nvar); X tq^.tattr := anone; X tp := tq X end X else begin X tq^.tnext := mknode(nvar); X tq := tq^.tnext; X tq^.tattr := anone X end; X X ti := newid(currsym.vid); X tq^.tidl := ti; X nextsymbol([scomma, scolon]); X while currsym.st = scomma do X begin X nextsymbol([sid]); X ti^.tnext := newid(currsym.vid); X ti := ti^.tnext; X nextsymbol([scomma, scolon]) X end; X X tq^.tbind := ptypedef; X nextsymbol([sid, sbegin, sfunc, sproc, seof]) X until currsym.st <> sid; X pvar := tp X end; X X (* Parse subroutine-declaration. *) X function psubs; X X var tp, (* return value *) X tv, tq : treeptr; (* temporary *) X func : boolean; (* true for functions *) X colsem : symtyp; (* colon/semicolon *) X X begin X (* parsing function or procedure *) X func := currsym.st = sfunc; X if func then X colsem := scolon X else X colsem := ssemic; X X (* parse id, it may already be forward declared *) X nextsymbol([sid]); X tq := newid(currsym.vid); X if tq^.tup = nil then X begin X enterscope(nil); X (* id wasn't previously declared, params possible *) X if func then X tp := mknode(nfunc) X else X tp := mknode(nproc); X tp^.tstat := statlvl; X tp^.tsubid := tq; X linkup(tp, tq); X nextsymbol([slpar, colsem]); X if currsym.st = slpar then X begin X tp^.tsubpar := psubpar; X linkup(tp, tp^.tsubpar); X nextsymbol([colsem]) X end X else X tp^.tsubpar := nil; X if func then X begin X (* parse function type *) X nextsymbol([sid]); X tp^.tfuntyp := oldid(currsym.vid, lidentifier); X nextsymbol([ssemic]) X end X else X tp^.tfuntyp := mknode(nempty); X linkup(tp, tp^.tfuntyp); X nextsymbol([sextern, sforward, X slabel, sconst, stype, svar, X sproc, sfunc, sbegin]); X end X else begin X (* id was forward declared => X pick up declarations from parameterlist *) X enterscope(tq^.tup^.tscope); X if func then X tp := mknode(nfunc) X else X tp := mknode(nproc); X tp^.tfuntyp := tq^.tup^.tfuntyp; X (* steal id and params from forward decl *) X tv := tq^.tup^.tsubpar; X tp^.tsubpar := tv; X while tv <> nil do X begin X tv^.tup := tp; X tv := tv^.tnext X end; X tp^.tsubid := tq; X tq^.tup := tp; X (* id was forward declared => X no params, no function type, no forward *) X nextsymbol([ssemic]); X nextsymbol([slabel, sconst, stype, svar, X sproc, sfunc, sbegin]); X end; X if currsym.st in [sforward, sextern] then X begin X tp^.tsubid^.tsym^.lt := lforward; X nextsymbol([ssemic]); X tp^.tsublab := nil; X tp^.tsubconst := nil; X tp^.tsubtype := nil; X tp^.tsubvar := nil; X tp^.tsubsub := nil; X tp^.tsubstmt := nil X end X else X pbody(tp); X nextsymbol([sproc, sfunc, sbegin, seof]); X tp^.tscope := currscope; X leavescope; X psubs := tp X end; X X (* Parse a conformant array index type. *) X function pconfsub : treeptr; X X var tp : treeptr; X X begin X tp := mknode(nsubrange); X nextsymbol([sid]); X tp^.tlo := newid(currsym.vid); X nextsymbol([sdotdot]); X nextsymbol([sid]); X tp^.thi := newid(currsym.vid); X nextsymbol([scolon]); X pconfsub := tp X end; X X (* Parse a conformant array-declaration. *) X function pconform : treeptr; X X var tp, tq : treeptr; X X begin X nextsymbol([slbrack]); X tp := mknode(nconfarr); X tp^.tcuid := mkvariable('S'); X tp^.tcindx := pconfsub; (* parse subrange ... *) X nextsymbol([sid]); X tp^.tindtyp := oldid(currsym.vid, lidentifier); X nextsymbol([ssemic, srbrack]); X tq := tp; X while currsym.st = ssemic do X begin X error(econfconf); (* what size does tp have *) X X (* expand: array [ A ; B ] of X X to: array [ A ] of array [ B ] of X *) X tq^.tcelem := mknode(nconfarr); X tq := tq^.tcelem; X tq^.tcindx := pconfsub; (* ... again *) X nextsymbol([sid]); X tq^.tindtyp := oldid(currsym.vid, lidentifier); X nextsymbol([ssemic, srbrack]) X end; X nextsymbol([sof]); X nextsymbol([sid, sarray]); X case currsym.st of X sid: X tq^.tcelem := oldid(currsym.vid, lidentifier); X sarray: X begin X error(econfconf); (* what size does tp have *) X X tq^.tcelem := pconform X end; X end;(* case *) X pconform := tp X end; X X (* Parse subroutine parameter list. *) X function psubpar; X X var tp, X tq : treeptr; X nt : treetyp; X X begin X tq := nil; X repeat X nextsymbol([sid, svar, sfunc, sproc]); X case currsym.st of X sid: X nt := nvalpar; X svar: X nt := nvarpar; X sfunc: X nt := nparfunc; X sproc: X nt := nparproc; X end; X if nt <> nvalpar then X nextsymbol([sid]); X if tq = nil then X begin X tq := mknode(nt); X tp := tq X end X else begin X tq^.tnext := mknode(nt); X tq := tq^.tnext X end; X case nt of X nvarpar, X nvalpar: X begin X tq^.tidl := pidlist(lidentifier); X tq^.tattr := anone; X checksymbol([scolon]); X if nt = nvalpar then X nextsymbol([sid]) X else X nextsymbol([sid, sarray]); X case currsym.st of X sid: X tq^.tbind := X oldid(currsym.vid, lidentifier); X sarray: X tq^.tbind := pconform X end;(* case *) X nextsymbol([srpar, ssemic]) X end; X nparproc: X begin X tq^.tparid := newid(currsym.vid); X nextsymbol([ssemic, slpar, srpar]); X if currsym.st = slpar then X begin X enterscope(nil); X tq^.tparparm := psubpar; X nextsymbol([ssemic, srpar]); X leavescope X end X else X tq^.tparparm := nil; X tq^.tpartyp := nil X end; X nparfunc: X begin X tq^.tparid := newid(currsym.vid); X nextsymbol([scolon, slpar]); X if currsym.st = slpar then X begin X enterscope(nil); X tq^.tparparm := psubpar; X nextsymbol([scolon]); X leavescope X end X else X tq^.tparparm := nil; X nextsymbol([sid]); X tq^.tpartyp := oldid(currsym.vid, lidentifier); X nextsymbol([srpar, ssemic]) X end X end (* case *) X until currsym.st = srpar; X psubpar := tp X end; X X (* Parse a (possibly labeled) statement. *) X function plabstmt; X X var tp : treeptr; X X begin X nextsymbol([sid, sinteger, sif, swhile, srepeat, sfor, scase, X swith, sbegin, sgoto, X selse, ssemic, send, suntil]); X if currsym.st = sinteger then X begin X tp := mknode(nlabstmt); X tp^.tlabno := oldlbl(true); X nextsymbol([scolon]); X nextsymbol([sid, sif, swhile, srepeat, sfor, scase, X swith, sbegin, sgoto, X selse, ssemic, send, suntil]); X tp^.tstmt := pstmt X end X else X tp := pstmt; X plabstmt := tp X end; X X (* Parse an unlabeled statement. *) X function pstmt; X X var tp : treeptr; X X begin X case currsym.st of X sid: X tp := psimple; X sif: X tp := pif; X swhile: X tp := pwhile; X srepeat: X tp := prepeat; X sfor: X tp := pfor; X scase: X tp := pcase; X swith: X tp := pwith; X sbegin: X tp := pbegin(true); X sgoto: X tp := pgoto; X send, X selse, X suntil, X ssemic: X tp := mknode(nempty); X end; X pstmt := tp X end; X X (* Parse an assignment or a procedure call. *) X function psimple; X X var tq, X tp : treeptr; X X begin X tp := pvariable(oldid(currsym.vid, lidentifier)); X if currsym.st = sassign then X begin X tq := mknode(nassign); X tq^.tlhs := tp; X tq^.trhs := pexpr(nil); X tp := tq X end; X psimple := tp X end; X X (* Parse a varable-reference (or a subroutine-call). *) X function pvariable; X X var tp, X tq : treeptr; X X begin X nextsymbol([slpar, slbrack, sdot, sarrow, X sassign, ssemic, scomma, scolon, sdotdot, X splus, sminus, smul, sdiv, smod, squot, X sand, sor, sinn, srpar, srbrack, X sle, slt, seq, sge, sgt, sne, X send, suntil, sthen, selse, sdo, sdownto, sto, sof]); X if currsym.st in [slpar, slbrack, sdot, sarrow] then X begin X case currsym.st of X slpar: X begin X tp := mknode(ncall); X tp^.tcall := varptr; X tq := nil; X repeat X if tq = nil then X begin X tq := pexpr(nil); X tp^.taparm := tq X end X else begin X tq^.tnext := pexpr(nil); X tq := tq^.tnext X end; X until currsym.st = srpar X end; X slbrack: X begin X tq := varptr; X repeat X tp := mknode(nindex); X tp^.tvariable := tq; X tp^.toffset := pexpr(nil); X tq := tp X until currsym.st = srbrack X end; X sdot: X begin X tp := mknode(nselect); X tp^.trecord := varptr; X nextsymbol([sid]); X tq := typeof(varptr); X enterscope(tq^.trscope); X tp^.tfield := oldid(currsym.vid, lfield); X leavescope X end; X sarrow: X begin X tp := mknode(nderef); X tp^.texps := varptr X end X end;(* case *) X tp := pvariable(tp) X end X else begin X tp := varptr; X if tp^.tt = nid then X begin X tq := idup(tp); X if tq <> nil then X if tq^.tt in [nfunc, nproc, X nparproc, nparfunc] then X begin X (* subroutine-call without X parameters *) X tp := mknode(ncall); X tp^.tcall := varptr; X tp^.taparm := nil X end X end X end; X pvariable := tp X end; X X (* Parse an expression. *) X function pexpr; X X var tp, X tq : treeptr; X nt : treetyp; X next : boolean; X X function padjust(tu, tr : treeptr) : treeptr; X begin X if pprio[tu^.tt] >= pprio[tr^.tt] then X begin X if tr^.tt in [nnot, numinus, nuplus, X nset, nderef] then X tr^.texps := padjust(tu, tr^.texps) X else X tr^.texpl := padjust(tu, tr^.texpl); X padjust := tr X end X else begin X if tu^.tt in [nnot, numinus, nuplus, X nset, nderef] then X tu^.texps := tr X else X tu^.texpr := tr; X padjust := tu X end X end; X X begin X nextsymbol([sid, schar, sinteger, sreal, sstring, snil, X splus, sminus, snot, slpar, slbrack, srbrack]); X next := true; X case currsym.st of X splus: X begin X tp := mknode(nuplus); X tp^.texps := nil; X tp := pexpr(tp); X next := false X end; X sminus: X begin X tp := mknode(numinus); X tp^.texps := nil; X tp := pexpr(tp); X next := false X end; X snot: X begin X tp := mknode(nnot); X tp^.texps := nil; X tp := pexpr(tp); X next := false X end; X schar, X sinteger, X sreal, X sstring: X tp := mklit; X snil: X begin X usenilp := true; X tp := mknode(nnil); X end; X sid: X begin X tp := pvariable(oldid(currsym.vid, lidentifier)); X next := false X end; X slpar: X begin X tp := mknode(nuplus); X tp^.texps := pexpr(nil) X end; X slbrack: X begin X usesets := true; X tp := mknode(nset); X tp^.texps := nil; X tq := nil; X repeat X if tq = nil then X begin X tq := pexpr(nil); X tp^.texps := tq X end X else begin X tq^.tnext := pexpr(nil); X tq := tq^.tnext X end X until currsym.st = srbrack; X end; X srbrack: X begin X tp := mknode(nempty); X next := false X end X end; X if next then X nextsymbol([ X scolon, ssemic, scomma, sdotdot, srpar, srbrack, X sle, slt, seq, sge, sgt, sne, X splus, sminus, smul, sdiv, smod, squot, X sand, sor, sinn, X send, suntil, sthen, selse, sdo, sdownto, sto, X sof, slpar, slbrack]); X case currsym.st of X sdotdot: X nt := nrange; X splus: X nt := nplus; X sminus: X nt := nminus; X smul: X nt := nmul; X sdiv: X nt := ndiv; X smod: X nt := nmod; X squot: X begin X defnams[dreal]^.lused := true; X nt := nquot; X end; X sand: X nt := nand; X sor: X nt := nor; X sinn: X begin X nt := nin; X usesets := true X end; X sle: X nt := nle; X slt: X nt := nlt; X seq: X nt := neq; X sge: X nt := nge; X sgt: X nt := ngt; X sne: X nt := nne; X scolon: X nt := nformat; X sid, schar, sinteger, sreal, sstring, snil, X ssemic, scomma, slpar, slbrack, srpar, srbrack, X send, suntil, sthen, selse, sdo, sdownto, sto, sof: X nt := nnil X end;(* case *) X if nt in [nin .. nor, nand, nnot] then X defnams[dboolean]^.lused := true; X if nt <> nnil then X begin X (* binary operator *) X tq := mknode(nt); X tq^.texpl := tp; X tq^.texpr := nil; X tp := pexpr(tq) X end; X X (* this statement yilds proper operator precedence *) X if tnp <> nil then X tp := padjust(tnp, tp); X pexpr := tp X end; X X (* Parse a case-statement. *) X function pcase; X X label 999; X X var tp, X tq, X tv : treeptr; X X begin X tp := mknode(ncase); X tp^.tcasxp := pexpr(nil); X checksymbol([sof]); X tq := nil; X repeat X if tq = nil then X begin X tq := mknode(nchoise); X tp^.tcaslst := tq X end X else begin X tq^.tnext := mknode(nchoise); X tq := tq^.tnext X end; X tv := nil; X repeat X nextsymbol([sid, sinteger, schar, X splus, sminus, send, sother]); X if currsym.st in [send, sother] then X goto 999; X if tv = nil then X begin X tv := pconstant(false); X tq^.tchocon := tv X end X else begin X tv^.tnext := pconstant(false); X tv := tv^.tnext X end; X nextsymbol([scomma, scolon]) X until currsym.st = scolon; X tq^.tchostmt := plabstmt X until currsym.st = send; X 999: X if currsym.st = sother then X begin X nextsymbol([scolon, sid, sif, swhile, srepeat, sfor, X scase, swith, sbegin, sgoto, X selse, ssemic, send, suntil]); X if currsym.st = scolon then X nextsymbol([sid, sif, swhile, srepeat, sfor, X scase, swith, sbegin, sgoto, X selse, ssemic, send, suntil]); X tp^.tcasother := pstmt X end X else begin X tp^.tcasother := nil; X usecase := true X end; X nextsymbol([ssemic, send, selse, suntil]); X pcase := tp X end; X X (* Parse an if-statement. *) X function pif; X X var tp : treeptr; X X begin X tp := mknode(nif); X tp^.tifxp := pexpr(nil); X checksymbol([sthen]); X tp^.tthen := plabstmt; X if currsym.st = selse then X tp^.telse := plabstmt X else X tp^.telse := nil; X pif := tp; X end; X X (* Parse a while-statement. *) X function pwhile; X X var tp : treeptr; X X begin X tp := mknode(nwhile); X tp^.twhixp := pexpr(nil); X checksymbol([sdo]); X tp^.twhistmt := plabstmt; X pwhile := tp; X end; X X (* Parse a repeat-statement. *) X function prepeat; X X var tp, X tq : treeptr; X X begin X tp := mknode(nrepeat); X tq := nil; X repeat X if tq = nil then X begin X tq := plabstmt; X tp^.treptstmt := tq X end X else begin X tq^.tnext := plabstmt; X tq := tq^.tnext X end; X checksymbol([ssemic, suntil]) X until currsym.st = suntil; X tp^.treptxp := pexpr(nil); X prepeat := tp X end; X X (* Parse a for-statement. *) X function pfor; X X var tp : treeptr; X X begin X tp := mknode(nfor); X nextsymbol([sid]); X tp^.tforid := oldid(currsym.vid, lidentifier); X nextsymbol([sassign]); X tp^.tfrom := pexpr(nil); X checksymbol([sdownto, sto]); X tp^.tincr := currsym.st = sto; X tp^.tto := pexpr(nil); X checksymbol([sdo]); X tp^.tforstmt := plabstmt; X pfor := tp X end; X X (* Parse a with-statement. *) X function pwith; X X var tp, X tq : treeptr; X X begin X tp := mknode(nwith); X tq := nil; X repeat X if tq = nil then X begin X tq := mknode(nwithvar); X tp^.twithvar := tq X end X else begin X tq^.tnext := mknode(nwithvar); X tq := tq^.tnext X end; X enterscope(nil); X tq^.tenv := currscope; X tq^.texpw := pexpr(nil); X scopeup(tq^.texpw); X checksymbol([scomma, sdo]) X until currsym.st = sdo; X tp^.twithstmt := plabstmt; X tq := tp^.twithvar; X while tq <> nil do X begin X leavescope; X tq := tq^.tnext X end; X pwith := tp X end; X X (* Parse a goto-statement. *) X function pgoto; X X var tp : treeptr; X X begin X nextsymbol([sinteger]); X tp := mknode(ngoto); X tp^.tlabel := oldlbl(false); X nextsymbol([ssemic, send, suntil, selse]); X pgoto := tp X end; X X (* Parse a begin-statement. *) X function pbegin; X X var tp, X tq : treeptr; X X begin X tq := nil; X repeat X if tq = nil then X begin X tq := plabstmt; X tp := tq X end X else begin X tq^.tnext := plabstmt; X tq := tq^.tnext X end X until currsym.st = send; X if retain then X begin X tq := mknode(nbegin); X tq^.tbegin := tp; X tp := tq X end; X nextsymbol([send, selse, suntil, sdot, ssemic]); X pbegin := tp X end; X Xbegin (* parse *) X nextsymbol([spgm, sconst, stype, svar, sproc, sfunc]); X if currsym.st = spgm then X top := pprogram X else X top := pmodule; X nextsymbol([seof]); Xend; (* parse *) X X(* Compute value for a node (which must be some kind of constant). *) Xfunction cvalof(tp : treeptr) : integer; X Xvar v : integer; X tq : treeptr; X Xbegin X case tp^.tt of X nuplus: X cvalof := cvalof(tp^.texps); X numinus: X cvalof := - cvalof(tp^.texps); X nnot: X cvalof := 1 - cvalof(tp^.texps); X nid: X begin X tq := idup(tp); X if tq = nil then X fatal(etree); X tp := tp^.tsym^.lsymdecl; X case tq^.tt of X nscalar: X begin X v := 0; X tq := tq^.tscalid; X while tq <> nil do X if tq = tp then X tq := nil X else begin X v := v + 1; X tq := tq^.tnext X end; X cvalof := v X end; X nconst: X cvalof := cvalof(tq^.tbind); X end;(* case *) X end; X ninteger: X cvalof := tp^.tsym^.linum; X nchar: X cvalof := ord(tp^.tsym^.lchar); X end (* case *) Xend; (* cvalof *) X X(* Compute lower value of subrange or scalar type. *) Xfunction clower(tp : treeptr) : integer; X Xvar tq : treeptr; X Xbegin X tq := typeof(tp); X if tq^.tt = nscalar then X clower := scalbase X else if tq^.tt = nsubrange then X if tq^.tup^.tt = nconfarr then X clower := 0 X else X clower := cvalof(tq^.tlo) X else if tq = typnods[tchar] then X clower := 0 X else if tq = typnods[tinteger] then X clower := -maxint X else X fatal(etree) Xend; (* clower *) X X(* Compute upper value of subrange or scalar type. *) Xfunction cupper(tp : treeptr) : integer; X Xvar tq : treeptr; X i : integer; X Xbegin X tq := typeof(tp); X if tq^.tt = nscalar then X begin X tq := tq^.tscalid; X i := scalbase; X while tq^.tnext <> nil do X begin X i := i + 1; X tq := tq^.tnext X end; X cupper := i X end X else if tq^.tt = nsubrange then X if tq^.tup^.tt = nconfarr then X fatal(euprconf) X else X cupper := cvalof(tq^.thi) X else if tq = typnods[tchar] then X cupper := maxchar X else if tq = typnods[tinteger] then X cupper := maxint X else X fatal(etree) Xend; (* cupper *) X X(* Compute the number of elements in a subrange. *) Xfunction crange(tp : treeptr) : integer; X Xbegin X crange := cupper(tp) - clower(tp) + 1 Xend; X X(* Return number of words uset to store a set. *) Xfunction csetwords(i : integer) : integer; X Xbegin X i := (i+(setbits)) div (setbits+1); X if i > maxsetrange then X error(esetsize); X csetwords := i Xend; X X(* Return number of words uset to store a set. *) Xfunction csetsize(tp : treeptr) : integer; X Xvar tq : treeptr; X i : integer; X Xbegin X tq := typeof(tp^.tof); X i := clower(tq); X (* bits in sets are always numbered from 0, so we (arbitrarily) X decide that the base must be in the first 6 words to avoid X unnecessary waste of space *) X if (i < 0) or (i >= 6 * (setbits+1)) then X error(esetbase); X csetsize := csetwords(crange(tq)) + 1 Xend; X X(* Determine if tp is declared in the procedure it is used in. *) Xfunction islocal(tp : treeptr) : boolean; X Xvar tq : treeptr; X Xbegin X tq := tp^.tsym^.lsymdecl; X while not (tq^.tt in [nproc, nfunc, npgm]) do X tq := tq^.tup; X while not (tp^.tt in [nproc, nfunc, npgm]) do X tp := tp^.tup; X islocal := tp = tq Xend; X X(* Perform necessary transformations on tree and identifiers *) X(* before generating code. *) Xprocedure transform; X X X (* Rename function when used as a variable. *) X procedure renamf(tp : treeptr); X X var ip, iq : symptr; X tq, tv : treeptr; X X (* This procedure recursively descends the tree *) X (* and replaces function-assignments with variable *) X (* assignments. *) X procedure crtnvar(tp : treeptr); X X begin X while tp <> nil do X begin X case tp^.tt of X npgm: X crtnvar(tp^.tsubsub); X nfunc, X nproc: X begin X crtnvar(tp^.tsubsub); X crtnvar(tp^.tsubstmt) X end; X nbegin: X crtnvar(tp^.tbegin); X nif: X begin X crtnvar(tp^.tthen); X crtnvar(tp^.telse) X end; X nwhile: X crtnvar(tp^.twhistmt); X nrepeat: X crtnvar(tp^.treptstmt); X nfor: X crtnvar(tp^.tforstmt); X ncase: X begin X crtnvar(tp^.tcaslst); X crtnvar(tp^.tcasother) X end; X nchoise: X crtnvar(tp^.tchostmt); X nwith: X crtnvar(tp^.twithstmt); X nlabstmt: X crtnvar(tp^.tstmt); X nassign: X begin X (* revoke calls in assignment lhs, (mis- X parsed due to ambiguous syntax) *) X if tp^.tlhs^.tt = ncall then X begin X tp^.tlhs := tp^.tlhs^.tcall; X tp^.tlhs^.tup := tp X end; X (* function name -> variable name *) X tv := tp^.tlhs; X if tv^.tt = nid then X if tv^.tsym = ip then X tv^.tsym := iq X end; X nbreak, X npush, X npop, X ngoto, X nempty, X ncall: X (* no op *) X end;(* case *) X tp := tp^.tnext X end X end; X X begin (* renamf *) X while tp <> nil do X begin X case tp^.tt of X npgm, X nproc: X renamf(tp^.tsubsub); X nfunc: X begin X (* create a variable to hold return value *) X tq := mknode(nvar); X tq^.tattr := aregister; X tq^.tup := tp; X tq^.tidl := newid(mkvariable('R')); X tq^.tidl^.tup := tq; X tq^.tbind := tp^.tfuntyp; X (* put it FIRST among variables, see esubr() *) X tq^.tnext := tp^.tsubvar; X tp^.tsubvar := tq; X X iq := tq^.tidl^.tsym; X ip := tp^.tsubid^.tsym; X crtnvar(tp^.tsubsub); X crtnvar(tp^.tsubstmt); X (* process inner functions *) X renamf(tp^.tsubsub) X end; X end;(* case *) X tp := tp^.tnext X end X end; (* renamf *) X X (* This procedure rearranges the tree such that multiple *) X (* vardeclarations don't have (structured) types attached *) X (* to them. If such a declararation is found, a new name *) X (* is created and the type is moved to the type section. *) X procedure extract(tp : treeptr); X X var vp : treeptr; X X (* Create a declaration for tp, enter in pp type- *) X (* list and return an identifier referencing it. *) X function xtrit(tp, pp : treeptr; last : boolean) : treeptr; X X var np, rp : treeptr; X ip : idptr; X X begin X (* create new declaration *) X np := mknode(ntype); X ip := mkvariable('T'); X np^.tidl := newid(ip); X np^.tidl^.tup := np; X X (* create substitute id *) X rp := oldid(ip, lidentifier); X rp^.tup := tp^.tup; X rp^.tnext := tp^.tnext; X X (* steal type description *) X np^.tbind := tp; X tp^.tup := np; X tp^.tnext := nil; X X (* add new declaration to tree *) X np^.tup := pp; X if last and (pp^.tsubtype <> nil) then X begin X pp := pp^.tsubtype; X while pp^.tnext <> nil do X pp := pp^.tnext; X pp^.tnext := np X end X else begin X np^.tnext := pp^.tsubtype; X pp^.tsubtype := np; X end; X X xtrit := rp; X end; X X (* Extract anonymous enumeration types. *) X function xtrenum(tp, pp : treeptr) : treeptr; X X (* Name record-types referenced by ptrs. *) X procedure nametype(tp : treeptr); X X begin X tp := typeof(tp); X if tp^.tt = nrecord then X if tp^.tuid = nil then X tp^.tuid := mkvariable('S'); X end; X X begin X if tp <> nil then X begin X case tp^.tt of X nfield, X ntype, X nvar: X tp^.tbind := X xtrenum(tp^.tbind, pp); X X nscalar: X if tp^.tup^.tt <> ntype then X tp := xtrit(tp, pp, false); X X narray: X begin X tp^.taindx := xtrenum(tp^.taindx, pp); X tp^.taelem := xtrenum(tp^.taelem, pp); X end; X nrecord: X begin X tp^.tflist := xtrenum(tp^.tflist, pp); X tp^.tvlist := xtrenum(tp^.tvlist, pp); X end; X nvariant: X tp^.tvrnt := xtrenum(tp^.tvrnt, pp); X nfileof: X tp^.tof := xtrenum(tp^.tof, pp); X X nptr: X nametype(tp^.tptrid); X X nid, X nsubrange, X npredef, X nempty, X nsetof: X (* no op *) X end;(* case *) X tp^.tnext := xtrenum(tp^.tnext, pp) X end; X xtrenum := tp X end; X X begin (* extract *) X while tp <> nil do X begin X (* tp points to a program/procedure/function node *) X tp^.tsubtype := xtrenum(tp^.tsubtype, tp); X tp^.tsubvar := xtrenum(tp^.tsubvar, tp); X vp := tp^.tsubvar; X while vp <> nil do X begin X (* variables of structured unnamed types *) X if vp^.tbind^.tt in [nscalar, narray, X nrecord, nfileof] then X vp^.tbind := xtrit(vp^.tbind, tp, true); X vp := vp^.tnext X end; X extract(tp^.tsubsub); X tp := tp^.tnext X end X end; (* extract *) X X (* This procedure moves all local constants and types *) X (* used in nested procedures to the outermost declaration *) X (* level so that nested procedures may be extracted. *) X procedure global(tp, dp : treeptr; depend : boolean); X X label 555; X X var ip : treeptr; X dep : boolean; X X (* Mark all declared identifiers as unused. *) X procedure markdecl(xp : treeptr); X X begin X while xp <> nil do X begin X case xp^.tt of X nid: X xp^.tsym^.lused := false; X nconst: X markdecl(xp^.tidl); X ntype, X nvar, X nvalpar, X nvarpar, X nfield: X begin X markdecl(xp^.tidl); X if xp^.tbind^.tt <> nid then X markdecl(xp^.tbind) X end; X nscalar: X markdecl(xp^.tscalid); X nrecord: X begin X markdecl(xp^.tflist); X markdecl(xp^.tvlist) X end; X nvariant: X markdecl(xp^.tvrnt); X nconfarr: X if xp^.tcelem^.tt <> nid then X markdecl(xp^.tcelem); X narray: X if xp^.taelem^.tt <> nid then X markdecl(xp^.taelem); X nsetof, X nfileof: X if xp^.tof^.tt <> nid then X markdecl(xp^.tof); X nparproc, X nparfunc: X markdecl(xp^.tparid); X nptr, X nsubrange: X (* no op *) X end;(* case *) X xp := xp^.tnext X end X end; (* markdecl *) X X (* Move all marked declarations to global scope. *) X function movedecl(tp : treeptr) : treeptr; X X var ip, np : treeptr; X sp : symptr; X move : boolean; X X begin X if tp <> nil then X begin X move := false; X case tp^.tt of X nconst, X ntype: X ip := tp^.tidl X end;(* case *) X while ip <> nil do X begin X if ip^.tsym^.lused then X begin X move := true; X sp := ip^.tsym; X if sp^.lid^.inref > 1 then X begin X sp^.lid := X mkrename( 'M', sp^.lid); X sp^.lid^.inref := X sp^.lid^.inref - 1 X end; X ip := nil X end X else X ip := ip^.tnext X end; X if move then X begin X np := tp^.tnext; X tp^.tnext := nil; X ip := tp; X while ip^.tt <> npgm do X ip := ip^.tup; X tp^.tup := ip; X case tp^.tt of X nconst: X begin X if ip^.tsubconst = nil then X ip^.tsubconst := tp X else begin X ip := ip^.tsubconst; X while ip^.tnext <> nil X do ip := ip^.tnext; X ip^.tnext := tp X end X end; X ntype: X begin X if ip^.tsubtype = nil then X ip^.tsubtype := tp X else begin X ip := ip^.tsubtype; X while ip^.tnext <> nil X do ip := ip^.tnext; X ip^.tnext := tp X end X end X end;(* case *) X (* tp is moved, drop it and process X remainder of declarationlist *) X tp := movedecl(np) X end X else X tp^.tnext := movedecl(tp^.tnext) X end; X movedecl := tp X end; (* movedecl *) X X (* This procedure lifts out variables/parameters *) X (* used in nested procedures/functions. *) X procedure movevars(tp, vp : treeptr); X X label 555; X X var ep, dp, np : treeptr; X ip : idptr; X sp : symptr; X X (* Move a variable declaration to global *) X (* var declaration lists. *) X procedure moveglob(tp, dp : treeptr); X X begin X while tp^.tt <> npgm do X tp := tp^.tup; X dp^.tup := tp; X dp^.tnext := tp^.tsubvar; X tp^.tsubvar := dp X end; X X (* Create nodes for saving a global *) X (* pointer variable. *) X function stackop(decl, glob, loc : treeptr) : treeptr; X X var op, ip, dp, tp : treeptr; X X begin X (* create a new variable to hold old value X of the global variable during a call *) X ip := newid(mkvariable('F')); X case vp^.tt of X nvarpar, X nvalpar, X nvar: X begin X dp := mknode(nvarpar); X dp^.tattr := areference; X dp^.tidl := ip; X (* use same type as the global var *) X dp^.tbind := decl^.tbind X end; X nparproc, X nparfunc: X begin X dp := mknode(vp^.tt); X dp^.tparid := ip; X dp^.tparparm := nil; X dp^.tpartyp := vp^.tpartyp X end X end;(* case *) X ip^.tup := dp; X X (* add variable to declarationlists *) X tp := decl; X while not (tp^.tt in [nproc, nfunc, npgm]) do X tp := tp^.tup; X dp^.tup := tp; X if tp^.tsubvar = nil then X tp^.tsubvar := dp X else begin X tp := tp^.tsubvar; X while tp^.tnext <> nil do X tp := tp^.tnext; X tp^.tnext := dp X end; X dp^.tnext := nil; X X (* create an assignment saving value *) X op := mknode(npush); X op^.tglob := glob; X op^.tloc := loc; X op^.ttmp := ip; X stackop := op X end; X X (* Take a "push" node, create "pop" node *) X (* and add both to tree. *) X procedure addcode(tp, push : treeptr); X X var pop : treeptr; X X begin X pop := mknode(npop); X (* share variables with "push"-node *) X pop^.tglob := push^.tglob; X pop^.ttmp := push^.ttmp; X pop^.tloc := nil; X X (* add npush to head of statement list *) X push^.tnext := tp^.tsubstmt; X tp^.tsubstmt := push; X push^.tup := tp; X X (* add npop to end of statement list *) X while push^.tnext <> nil do X push := push^.tnext; X push^.tnext := pop; X pop^.tup := tp X end; X X begin (* movevars *) X while vp <> nil do X begin X case vp^.tt of X nvar, X nvalpar, X nvarpar: X dp := vp^.tidl; X nparproc, X nparfunc: X begin X dp := vp^.tparid; X if dp^.tsym^.lused then X begin X (* create a var declaration *) X ep := mknode(vp^.tt); X ep^.tparparm := nil; X ep^.tpartyp := vp^.tpartyp; X np := newid(mkrename('G', X dp^.tsym^.lid)); X ep^.tparid := np; X np^.tup := ep; X (* swap id's and symbols *) X sp := np^.tsym; X ip := sp^.lid; X np^.tsym^.lid := dp^.tsym^.lid; X dp^.tsym^.lid := ip; X np^.tsym := dp^.tsym; X dp^.tsym := sp; X np^.tsym^.lsymdecl := np; X dp^.tsym^.lsymdecl := dp; X (* make declaration global *) X moveglob(tp, ep); X (* add save/restore-code *) X addcode(tp, stackop(vp, np, dp)) X end; X goto 555 X end X end;(* case *) X while dp <> nil do X begin X if dp^.tsym^.lused then X begin X (* create a varpar declaration, X (nvarpar will cause emit to X treat the new identifier X as a pointer) *) X ep := mknode(nvarpar); X ep^.tattr := areference; X np := newid(mkrename('G', X dp^.tsym^.lid)); X ep^.tidl := np; X np^.tup := ep; X ep^.tbind := vp^.tbind; X if ep^.tbind^.tt = nid then X ep^.tbind^.tsym^.lused X := true; X (* swap id's and symbols *) X sp := np^.tsym; X ip := sp^.lid; X np^.tsym^.lid := dp^.tsym^.lid; X dp^.tsym^.lid := ip; X np^.tsym := dp^.tsym; X dp^.tsym := sp; X np^.tsym^.lsymdecl := np; X dp^.tsym^.lsymdecl := dp; X (* note that dp is referenced *) X dp^.tup^.tattr := aextern; X (* make declaration global *) X moveglob(tp, ep); X (* add save/restore-code *) X addcode(tp, stackop(vp, np, dp)) X end; X dp := dp^.tnext X end; X 555: X vp := vp^.tnext X end X end; (* movevars *) X X (* Break out a local variable and set the register *) X (* attribute. *) X procedure registervar(tp : treeptr); X X var vp, xp : treeptr; X X begin X vp := idup(tp); X tp := tp^.tsym^.lsymdecl; X (* vp points to nvar node *) X if (vp^.tidl <> tp) or (tp^.tnext <> nil) then X begin X (* tp is not alone in list of identifiers, X create a new nvar-node and hook up tp *) X xp := mknode(nvar); X xp^.tattr := anone; X xp^.tidl := tp; X tp^.tup := xp; X (* enter new nvar node among declarations *) X xp^.tup := vp^.tup; X xp^.tbind := vp^.tbind; (* borrow type *) X xp^.tnext := vp^.tnext; X vp^.tnext := xp; X (* break tp out of list of identifiers *) X if vp^.tidl = tp then X vp^.tidl := tp^.tnext X else begin X vp := vp^.tidl; X while vp^.tnext <> tp do X vp := vp^.tnext; X vp^.tnext := tp^.tnext X end; X tp^.tnext := nil X end; X (* tp is alone in this declaration, set attribute *) X if tp^.tup^.tattr = anone then X tp^.tup^.tattr := aregister X end; (* registervar *) X X (* Check static declarationlevel for a label *) X (* used in a non-local goto. *) X procedure cklevel(tp : treeptr); X X begin X tp := tp^.tsym^.lsymdecl; X while not(tp^.tt in [npgm, nproc, nfunc]) do X tp := tp^.tup; X if tp^.tstat > maxlevel then X maxlevel := tp^.tstat X end; X X begin (* global *) X while tp <> nil do X begin X case tp^.tt of X nproc, X nfunc: X begin X (* procid/parameters/const/type/var not used *) X markdecl(tp^.tsubid); X markdecl(tp^.tsubpar); X markdecl(tp^.tsubconst); X markdecl(tp^.tsubtype); X markdecl(tp^.tsubvar); X X (* mark those used in nested subroutines *) X global(tp^.tsubsub, tp, false); X X (* move out variables used in inner scope *) X movevars(tp, tp^.tsubpar); X movevars(tp, tp^.tsubvar); X (* move out const/type used in inner scope *) X tp^.tsubtype := movedecl(tp^.tsubtype); X tp^.tsubconst := movedecl(tp^.tsubconst); X X (* mark identifiers used in this subroutine *) X global(tp^.tsubstmt, tp, true); X global(tp^.tsubpar, tp, false); X global(tp^.tsubvar, tp, false); X global(tp^.tsubtype, tp, false); X global(tp^.tfuntyp, tp, false); X end; X X npgm: X begin X markdecl(tp^.tsubconst); X markdecl(tp^.tsubtype); X markdecl(tp^.tsubvar); X global(tp^.tsubsub, tp, false); X global(tp^.tsubstmt, tp, true) X end; X X nconst, X ntype, X nvar, X nfield, X nvalpar, X nvarpar: X begin X ip := tp^.tidl; X dep := depend; X while (ip <> nil) and not dep do X begin X (* for all used identifiers, propagate X the use to their bindings *) X if ip^.tsym^.lused then X dep := true; X ip := ip^.tnext X end; X global(tp^.tbind, dp, dep); X end; X nparproc, X nparfunc: X begin X global(tp^.tparparm, dp, depend); X global(tp^.tpartyp, dp, depend) X end; X nsubrange: X begin X global(tp^.tlo, dp, depend); X global(tp^.thi, dp, depend) X end; X nvariant: X begin X global(tp^.tselct, dp, depend); X global(tp^.tvrnt, dp, depend) X end; X nrecord: X begin X global(tp^.tflist, dp, depend); X global(tp^.tvlist, dp, depend) X end; X nconfarr: X begin X global(tp^.tcindx, dp, depend); X global(tp^.tcelem, dp, depend) X end; X narray: X begin X global(tp^.taindx, dp, depend); X global(tp^.taelem, dp, depend) X end; X nfileof, X nsetof: X global(tp^.tof, dp, depend); X nptr: X global(tp^.tptrid, dp, depend); X nscalar: X global(tp^.tscalid, dp, depend); X nbegin: X global(tp^.tbegin, dp, depend); X nif: X begin X global(tp^.tifxp, dp, depend); X global(tp^.tthen, dp, depend); X global(tp^.telse, dp, depend) X end; X nwhile: X begin X global(tp^.twhixp, dp, depend); X global(tp^.twhistmt, dp, depend) X end; X nrepeat: X begin X global(tp^.treptstmt, dp, depend); X global(tp^.treptxp, dp, depend) X end; X nfor: X begin X ip := idup(tp^.tforid); X if ip^.tup^.tt in [nproc, nfunc] then X registervar(tp^.tforid); X global(tp^.tforid, dp, depend); X global(tp^.tfrom, dp, depend); X global(tp^.tto, dp, depend); X global(tp^.tforstmt, dp, depend) X end; X ncase: X begin X global(tp^.tcasxp, dp, depend); X global(tp^.tcaslst, dp, depend); X global(tp^.tcasother, dp, depend) X end; X nchoise: X begin X global(tp^.tchocon, dp, depend); X global(tp^.tchostmt, dp, depend); X end; X nwith: X begin X global(tp^.twithvar, dp, depend); X global(tp^.twithstmt, dp, depend) X end; X nwithvar: X begin X ip := typeof(tp^.texpw); X if ip^.tuid = nil then X ip^.tuid := mkvariable('S'); X global(tp^.texpw, dp, depend); X end; X nlabstmt: X global(tp^.tstmt, dp, depend); X neq, nne, nlt, nle, ngt, nge: X begin X global(tp^.texpl, dp, depend); X global(tp^.texpr, dp, depend); X ip := typeof(tp^.texpl); X if (ip = typnods[tstring]) or X (ip^.tt = narray) then X usecomp := true; X ip := typeof(tp^.texpr); X if (ip = typnods[tstring]) or X (ip^.tt = narray) then X usecomp := true X end; X nin, nor, nplus, nminus, X nand, nmul, ndiv, nmod, nquot, X nformat, nrange: X begin X global(tp^.texpl, dp, depend); X global(tp^.texpr, dp, depend) X end; X X nassign: X begin X global(tp^.tlhs, dp, depend); X global(tp^.trhs, dp, depend) X end; X X nnot, X numinus, X nuplus, X nderef: X global(tp^.texps, dp, depend); X nset: X global(tp^.texps, dp, depend); X nindex: X begin X global(tp^.tvariable, dp, depend); X global(tp^.toffset, dp, depend) X end; X nselect: X global(tp^.trecord, dp, depend); X ncall: X begin X global(tp^.tcall, dp, depend); X global(tp^.taparm, dp, depend) X end; X nid: X begin X (* find declaration point *) X ip := idup(tp); X if ip = nil then X goto 555; X (* ip points to nconst/ntype/nvar/nproc/nfunc/ X nvalpar/nvarpar/nparproc or nparfunc node, X move to beginning of enclosing scope *) X repeat X ip := ip^.tup; X if ip = nil then X goto 555 X (* stop only for locally declared items, X for global or predefined identifiers X we will have gone to label 555 *) X until ip^.tt in [npgm, nproc, nfunc]; X if dp = ip then X begin X (* identifier used here, mark it used *) X if depend then X tp^.tsym^.lused := true X end X else begin X (* identifier declared in enclosing X scope, mark it used *) X tp^.tsym^.lused := true X end; X 555: X end; X ngoto: X if not islocal(tp^.tlabel) then X begin X tp^.tlabel^.tsym^.lgo := true; X usejmps := true; X cklevel(tp^.tlabel) X end; X X nbreak, X npush, X npop, X npredef, X nempty, X nchar, X ninteger, X nreal, X nstring, X nnil: X end;(* case *) X tp := tp^.tnext X end X end; (* global *) X X (* Rename identifiers identical to C keywords. *) X procedure renamc; X X var ip : idptr; X cn : cnames; X X begin X (* rename identifiers that mustn't be redefined X if C and Pascal semantix are to be preserved *) X for cn := cabort to cwrite do X begin X ip := mkrename('C', ctable[cn]); X ctable[cn]^.istr := ip^.istr X end X end; X X (* Rename subroutines declared in other subroutines such *) X (* that they can be moved to a global scope without name- *) X (* clashes. *) X procedure renamp(tp : treeptr; on : boolean); X X var sp : symptr; X X begin X (* tp points to subroutine-list *) X while tp <> nil do X begin X renamp(tp^.tsubsub, true); X if on and (tp^.tsubstmt <> nil) then X begin X (* change name of subroutine by prefixing X a unique name *) X sp := tp^.tsubid^.tsym; X if sp^.lid^.inref > 1 then X begin X sp^.lid := mkrename('P', sp^.lid); X sp^.lid^.inref := sp^.lid^.inref - 1 X end X end; X tp := tp^.tnext X end X end; X X (* Add initialization-code for file-variables. *) X procedure initcode(tp : treeptr); X X var ti, tq, tu, tv : treeptr; X X (* Determine if a type contains a file. *) X function filevar(tp : treeptr) : boolean; X X var fv : boolean; X tq : treeptr; X X begin X case tp^.tt of X npredef: X fv := tp = typnods[ttext]; X nfileof: X fv := true; X nconfarr: X fv := filevar(typeof(tp^.tcelem)); X narray: X fv := filevar(typeof(tp^.taelem)); X nrecord: X begin X fv := false; X tq := tp^.tvlist; X while tq <> nil do X begin X if filevar(tq^.tvrnt) then X error(evrntfile); X tq := tq^.tnext X end; X tq := tp^.tflist; X while tq <> nil do X begin X if filevar(typeof(tq^.tbind)) then X begin X fv := true; X tq := nil X end X else X tq := tq^.tnext X end X end; X nptr: X begin X fv := false; X if not tp^.tptrflag then X begin X tp^.tptrflag := true; X if filevar(typeof(tp^.tptrid)) then X error(evarfile); X tp^.tptrflag := false X end X end; X nsubrange, X nscalar, X nsetof: X fv := false X end; X filevar := fv X end; X X (* Create code for initialization of files. *) X function fileinit(ti, tq : treeptr; opn : boolean) : treeptr; X X var tx, ty, tz : treeptr; X X begin X (* create 1 statement initializing "ti" *) X case tq^.tt of X narray: X begin X (* create declaration for a loopvariable *) X tz := newid(mkvariable('I')); X ty := mknode(nvar); X ty^.tattr := aregister; X ty^.tidl := tz; X ty^.tbind := typeof(tq^.taindx); X tz := tq; X while not(tz^.tt in [nproc, nfunc, npgm]) do X tz := tz^.tup; X linkup(tz, ty); X if tz^.tsubvar = nil then X tz^.tsubvar := ty X else begin X tz := tz^.tsubvar; X while tz^.tnext <> nil do X tz := tz^.tnext; X tz^.tnext := ty X end; X ty := ty^.tidl; X (* create a loop initializing tq *) X tz := mknode(nindex); X tz^.tvariable := ti; X tz^.toffset := ty; X tz := fileinit(tz, tq^.taelem, opn); X tx := mknode(nfor); X tx^.tforid := ty; X ty := typeof(tq^.taindx); X if ty^.tt = nsubrange then X begin X tx^.tfrom := ty^.tlo; X END_OF_FILE if test 52771 -ne `wc -c <'ptc.p.2'`; then echo shar: \"'ptc.p.2'\" unpacked with wrong size! fi # end of 'ptc.p.2' fi echo shar: End of archive 10 \(of 12\). cp /dev/null ark10isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 12 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 12 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0 -- Rich $alz "Anger is an energy" Cronus Project, BBN Labs rsalz@bbn.com Moderator, comp.sources.unix sources@uunet.uu.net