|
DataMuseum.dkPresents historical artifacts from the history of: RC4000/8000/9000 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about RC4000/8000/9000 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 203520 (0x31b00) Types: TextFile Names: »p2rcpas«
└─⟦2c55ea56f⟧ Bits:30001844 SW-save af projekt 1000, Alarm-system └─⟦6b41451d2⟧ └─⟦this⟧ »p2rcpas«
(*$R+ let main be resident *) program pass2(input='pascalpif',output,slang); label 9999,1; (*$R- *) const version = 'pascal pass2 version 1980.06.27'; lowerror = 301; (* first error number *) higherror = 408; (* last error number *) alfalength = 12; maxident = 3333; (* maximum number of nodeidents from pass1 *) defaultcode = 1500; (* default value of maxindex *) alfatypeident = 97; (* to find the standard type alfa *) maxbit = 23; (* number of bits in one CM-word minus 1*) oneword = 2; (* number of addressing units (halfwords) in one CM-word *) maxreg = 3; (* number of registers - 1 *) noofreg = 4; (* number of registers *) maxint = 8388607; (* 2**23 -1 *) minint =-8388608; (* -2**23 *) firstchar = 32; lastchar = 126; maxaddress = maxint; maxworkspace = 2; (* maximum number of words for temporary storage in code *) maxnest = 20; (* maximum depth of nesting of structure *) maxparamoffset = 512; (* maximum number of halfwords for parameters *) maxshortcopy = 24; (* maximum number of halfwords in shortcopy *) maxordinal = 2047; (* maximum ordinal number for variables *) minparamordinal = -2036;(* ordinal of first parameter to a procedure *) standardentries = 10; (* space for running system entries, allocated in main instead of parameters *) stringmax = 100; (* maximum length of a string *) mintemporary = 48; (* minimum number of halfwords for temporaries *) procdescrlength = 1; (* procedure descriptor increment *) intsize = 2; (* number of halfwords needed for an integer *) realsize = 4; (* number of halfwords needed for a real *) ptrsize = 2; (* number of halfwords needed for a pointer *) setsize = 12; (* number of halfwords needed for a set *) asciiperword = 3; (* number of chars held in one word *) bitperascii = 8; (* number of bits used by one variable of standard type ASCII *) nilvalue = -2047;(* value of the pointer constant NIL *) stackaddr = 2; (* the register holding the address of current activation record *) blockmark = 12; (* size of fixed part of an activation record *) returnaddroffset= -2041;(* offset in data block to return address *) dynlinkoffset = -2037;(* offset in data block to dynamic link *) calloffset = -2047;(* offset in main data block to address of call-routine *) returnoffset = -2045;(* offset in main data block to address of return-routine *) stdcalloffset = -2035;(* offset in main data block to address of standard-routine *) erroroffset = -2033;(* offset in main data block to address of error-routine *) valueoffset = -2031;(* offset in main data block to address of routine to read in a block af values *) binaryget = 28672; (* library addr of binary get: 7 < 12 + 0 *) binaryput = 28673; (* library addr of binary put: 7 < 12 + 1 *) newoffset = -2029;(* offset in main data block to address of new *) disposeoffset = -2027;(* offset in main data block to address of dispose *) maxsignedhalfword= 2047; minsignedhalfword= -2048; maxhalfword = 4095; maxcode = 1018; (* maximum number of codewords and constants in one block *) maxvalue = 512; (* maximum number of halfwords in valuelist *) directmode = false;(* addressing is direct *) indirectmode = true; (* addressing is indirect *) reladdr = true; (* address mode is relative *) absaddr = false;(* address mode is absolute *) h0 = -36; (* relative addr. of buffer and share descriptor *) h4 = 8; (* relative addr. of user's parameters part *) h5 = 50; (* length of zone descriptor in halfwords *) h6 = 24; (* length of share descriptor in halfwords *) h20 = 360; (* current input zone descriptor *) h21 = 410; (* current output zone descriptor *) current_process = 66; process_start = 22; filenamelength = 8; (* length of file name in halfwords *) bufferlength = 512; (* length of file buffer in halfwords *) segmentlgt = 512; (* length in halfwords of a segment on disc *) type addressrange = 0..maxaddress; nodeident = 0..maxident; halfword = 0..maxhalfword; signedhalfword = minsignedhalfword..maxsignedhalfword; bitrange = 0..maxbit; regrange = 0..maxreg; stringrange = 1..stringmax; symbolptr = ^symbolnode; pseudoptr = ^pseudonode; stringptr = ^stringnode; setptr = ^setnode; addrptr = ^addrnode; codeptr = ^codenode; caselabptr = ^caselabnode; valueptr = ^valuenode; jumpchainptr = ^jumpchainnode; packkind = (paack, unpack, hlfword, signedhlfword); ckind = (signedshortconst, wordconst, realconst, setconst, stringconst); valuekind = (procfunc, expression, variable, tmp, wordcst, shortsignedcst, longcst, reg, valueinit); skipkind = (skipfalse, skiptrue, noskip); intmtwords = (enone, ename, eprogram, econst, etype, evar, efield, etagfield, evalparam, evarparam, effunc, efproc, eproc, efunc, emodule, esystem, epascal, efortran, estandard, eint, eext, elabel, elabeldef, escalar, einteger, ereal, eboolean, eascii, estring, esubrange, earray, erecord, eset, efile, epointer, eunpacked, epacked, eseq, erandom, ebackref, enamelist, efix, eparam, edeclaration, escalarlist, evarlist, ecaselist, erecordlabel, etagelement, eforward, eendprogram, eendmodule, eendnamelist, eendvarlist, eendcaselist, ecase, eoff, eotherwise, egotoendcase, eendcase, ecaselabel, ewhile, ewhiledo, eendwhile, ewith, ewithdo, ewithvar, ewithname, eendwith, erepeat, euntil, eendrepeat, efor, eforinit, efortodo, efordowntodo, efortoend, efordntoend, eif, ethen, eelse, eendif, enamecode, efunction, econstcode, ereference, eindex, eload, estore, estorefunc, estartset, esetrange, eendset, eleftconv, erightconv, enot, emult, eadd, edif, erealdiv, eintdiv, emod, eand, eor, esetdif, esetunion, esetinter, eminus, eeq, ene, elt, ele, ege, egt, ein, evalue, evaluename, evaluenaend, eelementbegin,eelementend, efieldbegin, efieldend, estorevalue, eendvalue, ecallproc, ecallfunc, eformat, eendcall, eblockbegin, eblockend, egoto, elinenumber, eoption); operators = eset..eendcall; mkind = esystem..estandard; standards = (ps_put, ps_get, ps_reset, ps_rewrite, ps_new, ps_dispose, ps_read, ps_readln, ps_write, ps_writeln, ps_page, ps_open, ps_close, ps_putrand, ps_getrand, ps_pack, ps_unpack, fs_abs, fs_sqr, fs_sin, fs_cos, fs_exp, fs_ln, fs_sqrt, fs_arctan, fs_odd, fs_eof, fs_eoln, fs_trunc, fs_round, fs_ord, fs_chr, fs_succ, fs_pred , fs_sinh, fs_arcsin, fs_system, fs_monitor, fs_clock, ps_date, ps_time, ps_replace, last_std ); opcodes = (aw, d0, bl, hl, la, lo, lx, wa, ws, am, wm, al, ri, jl, jd, je, xl, bs, ba, bz, rl, sp, re, rs, wd, rx, hs, xs, gg, di, d2, d1, ci, ac, ns, nd, as, ad, ls, ld, sh, sl, se, sn, so, sz, sx, gp, fa, fs, fm, ks, fd, cf, dl, ds, aa, ss); (* d1, d2 are nonexisting opcodes*) addrnode = packed record case boolean of false: ( index : pseudoptr; packk:packkind; bitstart:bitrange; case simpleaddr:boolean of true : (blocknumber,ordinal:integer); false : (postordinal:integer; reference:addrptr) ); true: ( zzint : integer;); end; symbolnode = packed record next : symbolptr; (* to chain elements in free list *) case key : intmtwords of ename : ( case namekind : intmtwords of econst : (constname: alfa; constant : symbolptr ) ; etype : ( typdescr : symbolptr ) ; (* not used *) effunc, evar, efield, evarparam, evalparam, etagfield, efile, efproc : ( vartypedescr : symbolptr ; varaddr : addrnode; case boolean of true : ( valparordinal : integer); false : ( extname : stringptr) ); eprogram, efunc, eproc : ( routinename : ^alfa; functype : symbolptr ; blocklevel : signedhalfword; coreresident : boolean; case standard : boolean of true : ( stnd_name : standards ) ; false : (starttmp, availtmp : signedhalfword; declarationlist, paramlist : symbolptr; routinedescr : integer )); emodule : (modulename : alfa; modulekind : mkind) ); econst : ( consttype : symbolptr ; startchain, constindex : integer; case constkind : ckind of signedshortconst, wordconst : (intval : integer); realconst : (realval : real); setconst : (setval : setptr); stringconst : (stringval : stringptr) ) ; elabel : ( labellevel : halfword; labelordinal : signedhalfword; labeladdroffset, procaddr : integer ); etype : ( packedtype : packkind ; size : addressrange ; bitsize : halfword; (*Used for packing*) case typkind : intmtwords of esubrange : ( subtyp : symbolptr ; firstconst, lastconst : integer ) ; einteger, ereal : (noth: 0..0); escalar, eboolean, eascii : ( lastscalar : integer; namelist : addressrange ); (* number of the list of scalarnames *) estring : ( length : stringrange ) ; earray: ( indextyp, valtyp : symbolptr ; packedval, (* true if array elements are packed *) stringcomp : boolean); erecord : ( varlist : symbolptr ); eset : ( setoftyp : symbolptr ) ; efile : ( randomfile : boolean ; fileindextyp,elementtyp : symbolptr ) ; epointer : ( pointertotyp : symbolptr ) ) ; enamelist : (case listkind : intmtwords of efix : (byteoffset : integer; bitoffset : halfword; packlist : boolean; lastfixlist,oldvarlist : symbolptr ); edeclaration : (discaddr, codelength, maxstackoffset, startline, firstlineofproc : integer ); eparam : (displayoffset : signedhalfword; initlist : valueptr; valuesegment, lengthofvalue : integer; filelist, (* list of local files *) copyvalparam : symbolptr ); (* list of value parameters to copy at entry *) escalarlist : ( nothi:0..0 )); etagelement : ( labellist, nexttag, varlst : symbolptr ; tagsize : addressrange ) ; ecaselist, erecordlabel : ( reclabvalue : integer ; nextreclab : symbolptr ) ; evarlist : ( fixsize : addressrange ;(* length of preceeding fixlist *) taglist : symbolptr ) end ; stringnode = record next : stringptr; length : 0..stringmax; returnable : boolean; (* true if this node may be returned after use *) case boolean of false: (str : packed arrayÆstringrangeÅ of char); true: (alfastr : packed arrayÆ1..alfalengthÅ of char); end; setnode = record case integer of 0 : (val : set of 0..71); 1 : (hlfwords : packed arrayÆ1..setsizeÅ of halfword); 2 : (bits : packed arrayÆ0..143Å of 0..1); end; pseudonode = packed record typ : symbolptr; next : pseudoptr; case kind : valuekind of procfunc : (symb : symbolptr ); (* procedure as parameter or a functioncall *) expression : ( leftoperand,rightoperand : pseudoptr; operator : operators); variable,tmp : (addr : addrnode); shortsignedcst, wordcst : (constant : integer); longcst : (constptr : symbolptr); reg : (regno:regrange; sameregister : pseudoptr); valueinit : (valcount : integer; pack : boolean); end; packindicator = record (* used for packed arrays to communicate the element size *) size : integer; (* and the bitstart (kept in a register connected to ps) *) ps : pseudoptr; (* between the procedures that have to load/store an element *) end; regnode = record user : pseudoptr; (*pseudonodes using the register*) valid : boolean; (* flag telling if the content of the register is meaningfull *) lastused : addressrange; case kind:valuekind of variable, tmp: (locassociated : boolean; (*tells if the variable has a location associated or not (used for temporary var's) *) addr:addrnode); shortsignedcst, wordcst : (constant : integer); longcst : (constptr : symbolptr) end; nestingnode = record startindex, index : integer; case intmtwords of eif : (skipif : skipkind); (* used by IF <constant> ... *) ecase : (labelchain : caselabptr; lowlabel,highlabel : integer; otherw : boolean); ewithvar : (withvar : pseudoptr); efor : (stepregister : regrange); ecallproc, ecallfunc : (procfunc : symbolptr; oldtop : pseudoptr); end; jumpchainnode = record next : jumpchainptr; jumpindex : integer; end; caselabnode = record next : caselabptr; labval : integer; codindex : integer; end; opnode = packed record case integer of 0 : (opcode : opcodes; w : regrange; relative : boolean; indirect : boolean; index : regrange; displacement : signedhalfword); 1 : (constval : integer); 2 : (realval1 : integer); 3 : (realval2 : integer); 4 : (str : packed arrayÆ1..asciiperwordÅ of char); 5 : (half1,half2 : halfword); end; codenode =record case integer of 1 : (c : arrayÆ1..6000Å of opnode); 500 : (code500 : arrayÆ1..500Å of opnode); 1000 : (code1000 : arrayÆ1..1000Å of opnode); 1500 : (code1500 : arrayÆ1..1500Å of opnode); 2000 : (code2000 : arrayÆ1..2000Å of opnode); 2500 : (code2500 : arrayÆ1..2500Å of opnode); 3000 : (code3000 : arrayÆ1..3000Å of opnode); 3500 : (code3500 : arrayÆ1..3500Å of opnode); 4000 : (code4000 : arrayÆ1..4000Å of opnode); 4500 : (code4500 : arrayÆ1..4500Å of opnode); 5000 : (code5000 : arrayÆ1..5000Å of opnode); 5500 : (code5500 : arrayÆ1..5500Å of opnode); 6000 : (code6000 : arrayÆ1..6000Å of opnode); end; valuenode = record next : valueptr; ordinal : integer; initval : opnode; end; var slangmode, printproctable, compilertest : boolean; (* for test only *) slang : file of integer; (* for slang code *) linetable : file of integer; (* holds correspondence between linenumbers and codeaddresses *) index : array ÆnodeidentÅ of symbolptr; code : codeptr; codefilename : alfa; lefthandside : boolean; strnodecount, (* number of used string nodes *) addrnodecount, (* number of used address nodes *) psnodecount, (* number of used pseudo nodes *) caslabcount, (* number of used case label nodes *) valnodecount, (* number of used value nodes *) symbnodecount, (* number of used symbol nodes *) i, l, inputordinal, (* ordinal of pointer to file INPUT *) outputordinal, (* ordinal of pointer to file OUTPUT *) valueword, (* the last value read *) wordoffset, (* offset to the next word to initialize in value *) nextbit, (* offset to the next bit to initialize in value *) noofvalue, (* number of words to initialize in this value-part *) highvalue, (* highest offset in value-part *) paramoffset, (* offset to last parameter put on stack *) maxstack, (* offset to top of current activation record *) linetablelgt, (* number of words in line table *) lengthofentrycode, (* number of instructions in the entry code part *) codesegment, (* number of first free segment of code *) lastindex, (* index to the last used codenode *) heapsize, (* startsize for heap *) maxindex, (* index to the highest allocated codenode *) outconstlimit, (* when codeallocation reaches this index all constants must be allocated *) ndepth, (* temporary, holding depth of nesting *) display, (* offset to the first word in current display *) currentline, (* last linenumber read *) procfuncoffset, (* first free byteaddress in the block of procedure/function addresses *) programident, (* the PIF-identification of the program name *) lastnodeident, (* indexÆlastnodeidentÅ points to last entered node in symboltable *) labnumber, (* the start of a possible label list *) namelistsize, (* length of last namelist,fix or varlist *) localordinal, (* first free byteaddress relative to current blockaddress *) fstfreetmp, (* index of the first free temporary location *) nooffreetmp, (* number of free temporary locations *) level : integer; (* current level of block ( an even number ) *) packedvalue, (* true if the fields are packed used in value-part *) resident, (* true if procedures must be core resident *) lineoutput, (* true if line numbers must be remembered for error checking *) noconstcheck, (* false if subrange check was performed on constant *) check, (* true if the optional checking is on *) alwayscheck, (* true if index check always should be performed *) standenvir : boolean; (* true while reading standard environment *) s, s1, (* temporaries *) intchain, (* chain of integer constants in this block *) constchain, (* chain of other constants used in this block *) settype, (* type of the empty set *) inputfilename, (* standard file input, if in programhead *) outputfilename, (* standard file output *) integertype, (* standard type integer *) booltype, (* standard type boolean *) realtype, (* standard type real *) alfatype, (* standard type alfa *) asciitype, (* standard type ascii *) fieldlist, (* list of fields in last allocated word *) sortlist, (* sorted list of not yet allocated variables *) scalartype, (* holding the type when reading scalarlist *) freesymbol, (* list of free symbolnodes *) currentproc, (* last entered procedure *) currentmodule, (* if reading a <module declaration part> then the last module name else NIL *) currentcase, (* last label in record *) currentvarlist, (* last entered varlist *) currentfixlist : symbolptr; (* pointer to last entered fixlist *) ps, pseudo, leftps, (* temporaries *) powersetpseudo, (* the constant part of a powerset *) freepseudo, (* free list of pseudoptr *) pseudotop : pseudoptr; (* top of the pseudoevaluationstack *) freestring : stringptr; (* free list of stringnodes *) sett : setptr; (* temporary *) freeaddress, (* free list of address nodes *) address : addrptr; (* temporary *) lab, freecaselab : caselabptr; (* list of free caselabnodes *) shortjumps : jumpchainptr; (* list of index to chain of not yet finished short jumps *) freevalue, (* list of free valuenodes *) valuelist : valueptr; (* chain of valuenodes *) standardcounter : standards;(* next standard function/procedure number in PIF *) intermitword : intmtwords; powerset : setnode; (* the constant part of a set, while reading the set specification *) chartonumber : arrayÆ'0'..'F'Å of integer; konvrelation : arrayÆelt..egtÅ of elt..egt; stdroutine : arrayÆps_put .. last_stdÅ of integer; (* holds procedure/function number *) readkind : arrayÆescalar .. easciiÅ of integer; writekind : arrayÆescalar .. estringÅ of integer; neststack : arrayÆ1..maxnestÅ of nestingnode; workspace : arrayÆ1..maxworkspaceÅ of integer; (* index to a chain of opcodes using temporary storage in code *) power : arrayÆ0..maxbitÅ of integer; (* power of two *) mnemonics : arrayÆopcodesÅ of packed arrayÆ1..2Å of char; register : array Æ0..maxregÅ of regnode; (* internal register descriptors *) bitmask : array Æ0..24Å of integer; (* masks for packing and unpacking *) packptr : packindicator; errormarks : packed array Æ lowerror .. higherror Å of boolean; errorcount : integer; value (*make some bitmasks for unpacking*) bitmask= ( 0, (* 2**0 - 1 *) 1, (* 2**1 - 1 *) 3, (* 2**2 - 1 *) 7, (* 2**3 - 1 *) 15, (* 2**4 - 1 *) 31, (* 2**5 - 1 *) 63, (* 2**6 - 1 *) 127, (* 2**7 - 1 *) 255, (* 2**8 - 1 *) 511, (* 2**9 - 1 *) 1023, (* 2**10 - 1 *) 2047, (* 2**11 - 1 *) 4095, (* 2**12 - 1 *) 8191, (* 2**13 - 1 *) 16383, (* 2**14 - 1 *) 32767, (* 2**15 - 1 *) 65535, (* 2**16 - 1 *) 131071, (* 2**17 - 1 *) 262143, (* 2**18 - 1 *) 524287, (* 2**19 - 1 *) 1048575, (* 2**20 - 1 *) 2097151, (* 2**21 - 1 *) 4194303, (* 2**22 - 1 *) 8388607, (* 2**23 - 1 *) -1); (* 2**24 - 1 *) (* initialize the registers *) register = (<0..3>*(nil,false,0,longcst:(nil))); strnodecount = 0; addrnodecount = 0; psnodecount = 0; caslabcount = 0; valnodecount = 0; symbnodecount = 0; compilertest = false; printproctable = false; (* option survey.no default *) slangmode=false; (* option c- default *) inputordinal = minsignedhalfword; outputordinal = minsignedhalfword; paramoffset=-2; linetablelgt = 0; lastindex = 0; heapsize = 0; currentline = 0; procfuncoffset =0; localordinal = minparamordinal; (* ... or some similar value, used when reading environment *) level=-4; ndepth = 0; resident = false; lineoutput = false; check = true; alwayscheck = false; (* set by option 't+' *) standenvir =true; intchain=nil; constchain=nil; inputfilename = nil; fieldlist = nil; sortlist = nil; freesymbol = nil; currentproc = nil; currentmodule = nil; currentcase = nil; currentvarlist = nil; currentfixlist = nil; freeaddress = nil; freepseudo = nil; pseudotop = nil; freestring = nil; freecaselab = nil; shortjumps=nil; freevalue = nil; valuelist = nil; standardcounter =ps_put; chartonumber= (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, <':' .. '@'>*0, 10, 11, 12, 13, 14, 15); konvrelation= (egt, ege, ele, elt); stdroutine= (20482, 24578, 16386, 16388, newoffset, disposeoffset, 24576, 24577, 20480, 20481, 20482, 16384, 16390, 1, 1, 28674, 28676, 0, 0, 12294, 12292, 4098, 4096, 8194, 12288, 0, 0, 1, 1, 1, 1, 1, 1, 1, 4100, 8192, 4102, 16396, 4104, 8196, 8198, 16394, 0); (* const binaryget = 7 < 12 + 0; binaryput = 7 < 12 + 1; *) readkind= (0, 6, 8, 0, 0); writekind= (0, 32770, (* default format 8 *) 57344, (* default format 14 *) 24580, (* default format 6 *) 4102, (* default format 1 *) 8); (* default format length of string *) workspace= (0,0); power= (1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, -8388608); mnemonics = ('aw', 'do', 'bl', 'hl', 'la', 'lo', 'lx', 'wa', 'ws', 'am', 'wm', 'al', 'ri', 'jl', 'jd', 'je', 'xl', 'bs', 'ba', 'bz', 'rl', 'sp', 're', 'rs', 'wd', 'rx', 'hs', 'xs', 'gg', 'di', 'd2', 'd1', 'ci', 'ac', 'ns', 'nd', 'as', 'ad', 'ls', 'ld', 'sh', 'sl', 'se', 'sn', 'so', 'sz', 'sx', 'gp', 'fa', 'fs', 'fm', 'ks', 'fd', 'cf', 'dl', 'ds', 'aa', 'ss'); errormarks = (<lowerror .. higherror> * false ); errorcount = 0; procedure error(number:integer); begin writeln( 'error no', number : 4, ' in line no ', currentline : 1 ) ; errorcount := errorcount + 1; errormarks Æ number Å := true; end;(*PROCEDURE error*) procedure printerrors; var i, currenttextno : integer; ch : char; begin page(output); writeln(output,'number of errors :', errorcount : 4); writeln(output); writeln(output,'error description'); open(input,'pascalenv'); reset(input); (* scan the environment file until end of standard environment *) repeat readln(ch); until ch = '*'; (* the environment must be separated from the errortexts by at least one line starting with an '*' !!!!!!!!!!! *) repeat readln(i); until i = 22222; (* pass2 errors must be preceded by a line starting with '22222' !!!!!!!!!!!! *) currenttextno := lowerror - 1; for i := currenttextno + 1 to higherror do if errormarksÆiÅ then begin (* find the text *) while i > currenttextno do begin if not eof(input) then readln(input); if not eof(input) then read(currenttextno) else currenttextno := higherror + 1; end; write(output,i : 4, ': '); if i <> currenttextno then write(output, ' (no text) ') else while not eoln(input) do begin read(ch); write(output,ch); end; writeln(output); end; (* for i := .... *) close(input); end; (* printerrors *) procedure stop(no : integer); begin error(no); writeln(' fatal error, compilation stops'); goto 9999; end; function getnumber:integer; var n:integer; begin read(n); getnumber:=n; end; procedure readalfa( var alf : alfa ) ; var i : integer ; a : arrayÆ1..alfalengthÅ of char; begin i:=1; repeat read(aÆiÅ); i:=i+1; until input^=' '; for i := i to alfalength do aÆiÅ:=' '; pack(a,1,alf); end ; function getintmtwords : intmtwords ; (* reads in a coded PIF word ( not nessecarily an opcode ) *) var cheat : record case boolean of false : ( a : intmtwords ) ; true : ( b : integer ) ; end ; begin read( cheat.b ) ; getintmtwords := cheat.a ; end ; function getsymbptr : symbolptr ; (* reads a nodeident (a <ref> or an (N) ) from input and converts it *) (* into the corresponding symbolptr *) var n : integer ; symbol : symbolptr; begin read( n ) ; get(input); (* skip space *) if n > maxident then error(401) else if n= 0 then getsymbptr := nil else begin if indexÆ n Å = nil (* i. e. this entrance has not been referenced before *) then begin if freesymbol = nil then begin symbnodecount := symbnodecount + 1; new(symbol); end else begin symbol := freesymbol; freesymbol := symbol^.next; end; lastnodeident := n; indexÆnÅ := symbol; end ; getsymbptr := indexÆ n Å ; end; end ; procedure forgetsymbptr(ident:nodeident) ; (* may only be used when one know for sure, that the nodeident will never be referenced later on *) var symbol:symbolptr; begin symbol:=indexÆidentÅ; if symbol <> nil then begin indexÆidentÅ:=nil; symbol^.next:=freesymbol; freesymbol:=symbol; end; end ; function newstring:stringptr; var string : stringptr; begin if freestring=nil then begin strnodecount := strnodecount + 1; new(string); end else begin string:=freestring; freestring:=string^.next; end; string^.returnable:=true; newstring:=string; end; procedure returnstring(string:stringptr); begin if string <> nil then if string^.returnable then begin string^.next:=freestring; freestring:=string; end; end; function newaddress : addrptr; var adr : addrptr; begin if freeaddress = nil then begin addrnodecount := addrnodecount + 1; new(adr); end else begin adr := freeaddress; freeaddress := adr^.reference; end; adr^.reference := nil; newaddress := adr; end; procedure returnaddress(var adr : addrptr); (* return the list of address nodes starting at adr *) var boo : boolean; adr1 : addrptr; begin if compilertest then begin adr1 := nil; repeat with adr^ do begin boo := simpleaddr; simpleaddr := false; if not boo then adr1 := reference else adr1 := nil; reference := freeaddress; freeaddress := adr; zzint := -20000; postordinal := 1000000; end; adr := adr1 until boo; end else begin adr1 := adr; while not adr1^.simpleaddr do adr1 := adr1^.reference; (* writeln(currentproc^.routinename^, currentline - currentproc^.declarationlist^.firstlineofproc, ord(adr), ord(adr1), ord(freeaddress)); *) with adr1^ do begin simpleaddr := false; reference := freeaddress; end; (* freeaddress := adr; no reuse of the nodes *) adr := nil; end; end; (* return address chain *) function newpseudo:pseudoptr; var ps:pseudoptr; begin if freepseudo = nil then begin psnodecount := psnodecount + 1; new(ps); end else begin ps:=freepseudo; freepseudo:=ps^.next; end; newpseudo:=ps; end; procedure returnpseudo(var ps:pseudoptr); (* return the pseudonode pointed to by ps to the free list and set the parameter to ps^.next. If ps is pointed to by a registernode then remove ps from this register. *) var pseudo, pseudo1 : pseudoptr; size : integer; begin if ps <> nil then begin pseudo:=ps; if pseudo^.kind=reg then with registerÆpseudo^.regnoÅ do begin if user = pseudo then user:=pseudo^.sameregister else begin pseudo1:=user; while pseudo1 <> nil do begin if pseudo1^.sameregister = pseudo then pseudo1^.sameregister:=pseudo^.sameregister; pseudo1:=pseudo1^.sameregister; end; end; end else if pseudo^.kind = tmp then begin (* return temporary storage *) size:=pseudo^.typ^.size; nooffreetmp:=nooffreetmp+size; fstfreetmp:=fstfreetmp-size; end; with pseudo^ do if (kind = tmp) or (kind = variable) then if not addr.simpleaddr then returnaddress(addr.reference); ps:=pseudo^.next; pseudo^.next:=freepseudo; freepseudo:=pseudo; end; end; function newcaselab:caselabptr; var cas:caselabptr; begin if freecaselab = nil then begin caslabcount := caslabcount + 1; new(cas); end else begin cas:=freecaselab; freecaselab:=cas^.next; end; newcaselab:=cas; end; procedure returncaselab(cas:caselabptr); (* return the caselabnode pointed to by cas to the free list *) begin if cas <> nil then begin cas^.next:=freecaselab; freecaselab:=cas; end; end; function newvalue:valueptr; var val:valueptr; begin if freevalue = nil then begin valnodecount := valnodecount + 1; new(val); end else begin val:=freevalue; freevalue:=val^.next; end; newvalue:=val; end; procedure returnvalue(var val:valueptr); (* return the valuenode pointed to by val to the free list *) var valu : valueptr; begin valu:=val; if valu <> nil then begin val:=valu^.next; valu^.next:=freevalue; freevalue:=valu; end; end; procedure comptestoutput; (* if compilertest then produce statistics about the heap usage *) var count : integer; begin page(output); writeln(output,' information about the amount of used heap storage'); writeln(output); writeln(output,' ':17, 'max number of used nodes number of returned nodes'); count := 0; while freestring <> nil do begin count := count + 1; freestring := freestring^.next; end; writeln(output, 'string nodes : ', strnodecount, count : 25); count := 0; while freeaddress <> nil do begin count := count + 1; freeaddress := freeaddress^.reference; end; writeln(output,'address nodes : ', addrnodecount, count : 25); count := 0; while freepseudo <> nil do begin count := count + 1; freepseudo := freepseudo^.next; end; writeln(output, 'pseudo nodes : ',psnodecount, count : 25); count := 0; while freecaselab <> nil do begin count := count + 1; freecaselab := freecaselab^.next; end; writeln(output,'case label nodes : ',caslabcount, count : 25); count := 0; while freevalue <> nil do begin count := count + 1; freevalue := freevalue^.next; end; writeln(output,'value nodes : ',valnodecount, count : 25); count := 0; while freesymbol <> nil do begin count := count + 1; freesymbol := freesymbol^.next; end; writeln(output,'symbol nodes : ',symbnodecount, count : 25); end; procedure initialize; var ch : char; codesize, i, codeword : integer; paslib : file of integer; (* file containing the entry code to copy *) begin (* initialize *) if compilertest then writeln(output,version); lefthandside := false; for i := 0 to maxident do indexÆ i Å := nil ; codesize:=defaultcode; rewrite(linetable); new(settype); (* type of a constant set *) with settype^ do begin key:=etype; packedtype:=unpack; size:=setsize; typkind:=eset; setoftyp:=nil; end; intermitword:=getintmtwords; while intermitword = eoption do begin get(input); read(ch); if ch = 'f' then begin get(input); get(input); readalfa(codefilename); lefthandside := true; end else if ch = 'h' then read(heapsize) else if ch = 's' then read(codesize) else if ch = 'p' then begin printproctable := true; readln; (* skip 'yes' *); end; intermitword:=getintmtwords; end; if lefthandside then begin open(slang,codefilename); rewrite(slang); (* copy entry code from pascallib *) open(paslib,'pascallib'); (* do not care about a warning (165) *) reset(paslib); read(paslib,i, lengthofentrycode); (* skip word(0) *) for i := 1 to lengthofentrycode do begin read(paslib,codeword); write(slang,codeword); end; close(paslib); open(paslib,' '); (* do not call remove entry with name=pascallib *) for i := 1 to ((segmentlgt - ((lengthofentrycode*oneword) mod segmentlgt)) mod segmentlgt) div oneword do write(slang,0); (* fill the segment *) codesegment := (lengthofentrycode * oneword + (segmentlgt-1)) div segmentlgt; end; heapsize:=heapsize*oneword; if codesize < 0 then codesize:=0 else if codesize>6000 then codesize:=6000; codesize:=(codesize+499) div 500; maxindex:=codesize*500; case codesize of 0,1:begin maxindex:=500; new(code,500); end; 2:new(code,1000); 3:new(code,1500); 4:new(code,2000); 5:new(code,2500); 6:new(code,3000); 7:new(code,3500); 8:new(code,4000); 9:new(code,4500); 10:new(code,5000); 11:new(code,5500); 12:new(code,6000); end; end; procedure routinedescriptorwords; (* output the words which describes the procedures/functions as the last segment of a program *) const routine_descr_length = 4; (* number of words used to describe each routine: 1) start segment, 2) codelength in halfwords, 3) stack appetite - 2048 in halfwords, 4) line table entry *) var i, l, int, lengthofcode, no_of_resident, erroraddr, procaddr, infaddr : integer; tail : array Æ1..10Å of integer; begin lengthofcode:=0; no_of_resident:=0; erroraddr:=codesegment; reset(linetable); if lefthandside then for l:=1 to linetablelgt do begin read(linetable,int); write(slang,int); end; int := 0; if lefthandside then for i := 1 to ((segmentlgt-((linetablelgt*oneword) mod segmentlgt)) mod segmentlgt) div oneword do write(slang,int); codesegment:=(linetablelgt*oneword+(segmentlgt-1)) div segmentlgt + codesegment; procaddr := codesegment; l := 0; (* only used if slangmode = true *) lastindex := 0; for i:=programident to lastnodeident do if indexÆiÅ <> nil then with indexÆiÅ^ do begin if key = ename then if (namekind = eproc) or (namekind = efunc) or (namekind = eprogram) then begin if coreresident then begin no_of_resident:=no_of_resident+1; code^.cÆno_of_residentÅ.constval:=routinedescr; end; with declarationlist^ do begin lengthofcode:=lengthofcode+codelength; if slangmode or printproctable then begin if l = 0 then begin page(output); writeln(output,' procedure table '); writeln(output); writeln(output,' nr name line segm length stack alarm'); writeln(output); end; writeln(output, l:4,' ',indexÆiÅ^.routinename^,firstlineofproc:6,discaddr:6 ,codelength ,maxstackoffset ,startline); l := l + procdescrlength; end; if lefthandside then begin write(slang,discaddr); write(slang,codelength); write(slang,maxstackoffset); write(slang,startline); lastindex := lastindex + routine_descr_length; end; end; end; end; if lefthandside then for l := 1 to ((segmentlgt - ((lastindex*oneword) mod segmentlgt)) mod segmentlgt) div oneword do write(slang,int); (* fill the rest of the segment with zero(s) *) codesegment := (procfuncoffset * oneword * routine_descr_length + (segmentlgt - 1)) div segmentlgt + codesegment; infaddr := codesegment; if slangmode or printproctable then begin writeln(output); writeln(output); writeln(output); writeln(output,' information segment:', infaddr : 5); writeln(output,heapsize (* startsize of heap *) ,procfuncoffset ,procaddr ,erroraddr); for l:=1 to no_of_resident do writeln(output,code^.cÆlÅ.constval); end; if lefthandside then begin lastindex := 0; (* used for counting number of words in the information part *) write(slang,heapsize,procfuncoffset,procaddr,erroraddr); lastindex := lastindex + 4; for i:=1 to no_of_resident do begin write(slang,code^.cÆiÅ.constval); lastindex := lastindex + 1; end; write(slang,-1); lastindex := lastindex + 1; repeat write(slang,infaddr); lastindex := lastindex + 1; until (lastindex mod (segmentlgt div oneword)) = 0; (*last word of the segment has been written *) close(slang); (* change entry, insert the address of the information segment *) if monitor(42 (*lookup entry*), codefilename, tail) = 0 then begin tailÆ8Å := 0; (* segment with entry code = 0 *) tailÆ9Å := 2*4096 + 0; (* contents key := 2 , entry point := 0 *) tailÆ10Å := lengthofentrycode * oneword; if monitor(44 (*change entry*), codefilename, tail) <> 0 then writeln(output,'??? warning, error in call of change entry'); end; end; writeln(output,'Code:', lengthofcode div 1024:3,'K +',lengthofcode mod 1024:5,' Halfwords'); if errorcount > 0 then writeln(output,'Error(s) found in pass2'); end; procedure outconstblock(jump : boolean); forward; procedure makerelcode(op:opcodes;disp:integer); forward; function emitcode : integer; (* emits code and constants for a procedure and returns the number of the first segment of the produced code *) var i, j : integer; zero : integer; begin outconstblock(false); intchain:=nil; constchain:=nil; emitcode := codesegment; i := codesegment; (* for slangmode, the start segment of the procedure *) codesegment := codesegment + (lastindex*oneword+(segmentlgt-1))div segmentlgt; zero := 0; if lefthandside then for j := 1 to ((segmentlgt div oneword) - lastindex mod (segmentlgt div oneword)) mod (segmentlgt div oneword) do write(slang,zero); with code^ do if slangmode then begin writeln(output); writeln(output,'s.w. ',currentproc^.routinename^,'segment:',i:5); for l:=1 to lastindex do with cÆlÅ do begin write(output,(l-1)*oneword : 4, ':', constval : 9,' '); write(output,mnemonicsÆopcodeÅ); if relative then write(output,'. w', w:1) else write(output,' w', w:1); if indirect then write(output,' (') else write(output, ' '); if index > 0 then write(output,'x', index:1) else write(output,' '); if displacement <> 0 then begin if displacement > 0 then if index <> 0 then write(output,'+') else write(output,' '); write(output,displacement:1); end else if index = 0 then write(output,' 0'); if indirect then write(output,')'); if relative then write(output,displacement+ (l-1)*oneword); writeln(output); end; writeln(output,'e.'); end; if lefthandside then with code^ do for i:=1 to lastindex do write(slang,cÆiÅ.constval); end; procedure outcode(word:opnode); (* put word into next available word in the structure holding the code for this procedure *) begin if lastindex >= maxindex then stop(405); if lastindex >= outconstlimit then outconstblock(true); lastindex:=lastindex+1; code^.cÆlastindexÅ := word; end; procedure makeallcode(op:opcodes;ac:regrange;rel,ind:boolean;x:regrange;disp:integer); (* generate a word of code with the fields set according to parameters *) var word : opnode; begin with word do begin opcode:=op; w:=ac; relative:=rel; indirect:=ind; index:=x; displacement:=disp; end; outcode(word); end; procedure makecode(op:opcodes;ac:regrange;disp:integer); (* generate a word of code with the operator,w,displacement set according to parameters and the rest of the fields set by default *) var word : opnode; value word = (0:(ks,0,false,false,0,0)); begin with word do begin opcode:=op; w:=ac; displacement:=disp; end; outcode(word); end; procedure makewrelcode(op:opcodes; ac:regrange; disp:integer); (* generate a word of code with the operator,w,displacement set according to parameters and the rest of the fields set by default *) var word : opnode; value word = (0:(ks,0,true,false,0,0)); begin with word do begin opcode:=op; w:=ac; displacement:=disp; end; outcode(word); end; procedure makerelcode; (* (op:opcodes;disp:integer) FORWARD declared *) (* generate a word of code with the operator,displacement set according to parameters and the rest of the fields set by default *) var word : opnode; value word = (0:(ks,0,true,false,0,0)); begin with word do begin opcode:=op; w:=0; displacement:=disp; end; outcode(word); end; procedure makeindirectcode(op:opcodes;ac,x:regrange;disp:integer); (* generate a word of code with the operator,w,index,displacement set according to parameters and the rest of the fields set by default *) var word : opnode; value word = (0:(ks,0,false,true,0,0)); begin with word do begin opcode:=op; w:=ac; index:=x; displacement:=disp; end; outcode(word); end; procedure makeindexcode(op:opcodes;ac,x:regrange;disp:integer); (* generate a word of code with the operator,w,index,displacement set according to parameters and the rest of the fields set by default *) var word : opnode; value word = (0:(ks,0,false,false,0,0)); begin with word do begin opcode:=op; w:=ac; index:=x; displacement:=disp; end; outcode(word); end; procedure makewordcode(val:integer); var word:opnode; begin word.constval:=val; outcode(word); end; procedure reservecode(number : integer); (* reserve number words of code in the block of code *) begin if lastindex + number >= outconstlimit then outconstblock(true); end; procedure makeconst(val:integer; symb:symbolptr); (* if symb = NIL then insert val in the chain of integer constants else insert symb in a chain. Insert the index of the last made code in the chain for the constant *) (* the address (after 'outconstblock') will, depending on symb^.constkind, be 1) for wordconst : first halfword 2) for realconst : third halfword 3) for stringconst and setconst : first halfword *) var s, symbol : symbolptr; i : integer; begin if symb = nil then begin s:=intchain; while s <> nil do begin if s^.intval = val then begin symb:=s; s:=nil; end else s:=s^.next; end; if symb = nil then begin new(symb); with symb^ do begin next:=intchain; key:=econst; consttype:=integertype; startchain:=0; constindex:=0; constkind:=wordconst; intval:=val; end; intchain:=symb; end; end else if symb^.constkind = wordconst then begin (* insert symbol in chain of integers *) s:=intchain; val:=symb^.intval; symbol:=nil; while s <> nil do begin if s^.intval = val then begin symbol:=s; s:=nil; end else s:=s^.next; end; if symbol = nil then begin symb^.next:=intchain; symb^.startchain:=0; symb^.constindex:=0; intchain:=symb; end else symb:=symbol; end else begin s:=constchain; symbol:=nil; while s <> nil do begin if s = symb then begin symbol:=s; s:=nil; end else s:=s^.next; end; if symbol = nil then begin symb^.next:=constchain; constchain:=symb; symb^.startchain:=0; symb^.constindex:=0; end; end; if (symb^.constindex <> 0) and (symb^.constindex-lastindex >= minsignedhalfword div oneword) then code^.cÆlastindexÅ.displacement:=(symb^.constindex-lastindex)*oneword else begin symb^.constindex:=0; i:=symb^.startchain; if i <> 0 then i:=i-lastindex; symb^.startchain:=lastindex; code^.cÆlastindexÅ.displacement:=i; outconstlimit:=outconstlimit-symb^.consttype^.size div oneword; end; end; (* makeconst *) procedure putreal(realvalue : real; codeoffset : integer); var exp : integer; rc8000real : packed record case boolean of true : (i1 : integer; i2 : integer); false : (realval : real); end; word : opnode; begin with rc8000real do begin realval := realvalue; word.realval1 := i1; code^.cÆcodeoffsetÅ := word; word.realval2 := i2; code^.cÆcodeoffset + 1Å := word; end; end; (* put real *) procedure outconstblock; (* jump:boolean FORWARD declared *) (* output all not yet allocated*) var s : symbolptr; word : opnode; i, j, jumpindex : integer; sjump : jumpchainptr; procedure insertchain(chain : integer); var disp : integer; begin disp:=chain; with code^ do while disp <> 0 do with cÆchainÅ do begin disp:=displacement; displacement:=(lastindex-chain)*oneword; chain:=chain+disp; end; end; begin (* outconstblock *) if jump then begin outconstlimit:=outconstlimit+1; makerelcode(jl,0); jumpindex:=lastindex; end; (* prevent recursive calling from outcode *) outconstlimit := maxindex; s:=intchain; while s <> nil do begin if s^.constindex = 0 then begin s^.constindex:=lastindex + 1; word.constval:=s^.intval; outcode(word); insertchain(s^.startchain); s^.startchain:=0; end; s:=s^.next; end; for i:=1 to maxworkspace do begin if workspaceÆiÅ <> 0 then begin word.constval:=i; outcode(word); insertchain(workspaceÆiÅ); workspaceÆiÅ:=0; end; end; s:= constchain; while s <> nil do begin if s^.constindex = 0 then begin case s^.constkind of realconst: begin if lastindex + realsize div oneword >= maxindex then stop ( 405 ); (* use option codesize *) putreal(s^.realval,lastindex+1); lastindex := lastindex + realsize div oneword; s^.constindex:=lastindex; insertchain(s^.startchain); end; setconst: begin lastindex := lastindex + 1; (* prepare call of insertchain *) insertchain(s^.startchain); lastindex := lastindex - 1; (* reestablish pointer *) s^.constindex:=lastindex; for i:=1 to setsize div oneword do begin word.half1:=s^.setval^.hlfwordsÆi*oneword-1Å; word.half2:=s^.setval^.hlfwordsÆi*onewordÅ; outcode(word); end; end; stringconst: begin lastindex := lastindex + 1; (* prepare call of insertchain *) insertchain(s^.startchain); lastindex := lastindex - 1; (* reestablish pointer *) s^.constindex:=lastindex; with s^.stringval^ do begin j:=0; for i:=1 to length do begin j:=j+1; word.strÆjÅ:=strÆiÅ; if j mod asciiperword =0 then begin outcode(word); j:=0; end; end; if j <> 0 then begin for i:=j +1 to asciiperword do word.strÆiÅ:=' '; outcode(word); end; end; returnstring(s^.stringval); end; end; end; s^.startchain:=0; s:=s^.next; end; if maxindex-lastindex < maxcode then outconstlimit:=maxindex else outconstlimit:=lastindex+maxcode; if jump then begin for i:=1 to ndepth do with neststackÆiÅ do begin if index <> 0 then begin makerelcode(jl,index-lastindex-1); index:=lastindex; end; end; sjump:=shortjumps; while sjump <> nil do begin makerelcode(jl,sjump^.jumpindex-lastindex-1); sjump^.jumpindex:=lastindex; sjump:=sjump^.next; end; code^.cÆjumpindexÅ.displacement:=(lastindex-jumpindex+1)*oneword; end; end; (* outconstblock *) function makerealconst(val:real) : symbolptr; (* search through the list of long constants, if val is found then the result is this symbolnode else the result is a new allocated symbolnode containing the constant val *) var symb, newsymb : symbolptr; begin symb:=constchain; newsymb:=nil; while symb <> nil do begin if (symb^.constkind = realconst) and (symb^.realval = val) then begin newsymb:=symb; symb:=nil; end else symb:=symb^.next; end; if newsymb = nil then begin new(newsymb); with newsymb^ do begin next:=constchain; key:=econst; consttype:=realtype; startchain:=0; constindex:=0; constkind:=realconst; realval:=val; end; constchain:=newsymb; end; makerealconst:=newsymb; end; procedure nextline ; (* correct use of this procedure ensures that variable intermitword *) (* always contains a PIF opcode, as the first code on a line is an opcode *) begin readln ; intermitword := getintmtword ; end ; function getbasetype(symbol:symbolptr):intmtwords; (*translate symbol^.key into name(intmtword)*) begin if symbol = nil then getbasetype := enone else with symbol^ do case typkind of esubrange: getbasetype:=subtyp^.typkind; escalar,eboolean,eascii, eset,efile, epointer,einteger,ereal, erecord: getbasetype:=typkind; estring: if length=1 then getbasetype:=eascii else getbasetype:=estring; earray: if stringcomp then getbasetype:=estring else getbasetype:=earray end; end; (*FUNCTION getbasetype*) procedure readconst; (*reads a constant*) var s:symbolptr; ch:char; lngt,i:integer; procedure readsign(var sign:boolean); (*reads an optional sign*) begin sign := ch = '-' ; if (ch='+') or (ch='-') then read( ch ) ; end; (*PROCEDURE readsign*) function readint:integer; (*The result is the value read on input*) label 9999; (*jump hereto if number to large*) var isign:boolean; digits:set of '0'..'F'; limit,base,fig:integer; procedure readbase; (* note: limit is defined thus: when a number read is smaller than limit, *) (* it is possible to append any digit from set digits to it without *) (* risk of overflow; if not, we must read the next digit (if any) with special care *) begin if ch='#' then begin read(ch); if ch='O' then begin base:=8; digits:=Æ'0'..'7'Å; limit:=-1048576;(* -2**20 *) end else if ch='H' then begin base:=16; digits:=Æ'0'..'9','A'..'F'Å; limit:=-524288; (* -2**19 *) end else begin base:=2; digits:=Æ'0'..'1'Å; limit:=-4194304; (* -2**22 *) end; read( ch ) ; end else begin base:=10; digits:=Æ'0'..'9'Å; limit:=-838860; end; end; (*PROCEDURE readbase*) begin (*readint*) readsign(isign); readbase; fig:=0; repeat if fig>limit then fig:=fig*base-chartonumberÆchÅ else if base<>10 then begin if (fig=limit) and (ch='0') and isign then fig:=fig*base else begin error(302); goto 9999; end; end else if (fig=limit) and ((ch<='7') or isign and (ch='8')) then fig:=fig*10-chartonumberÆchÅ else begin error(301); goto 9999; end; read(ch); until (ch=' '); 9999: if isign then readint:=fig else readint:=-fig; end; (*PROCEDURE readint*) function readreal:real; const limit=3435973835.0; lim1=616; lim2=-616; type posint=0..lim1; var msign,scsign:boolean; exp,exp2:integer; fig,res1:real; function ten(e:posint):real; var i:integer; t:real; begin i:=0; t:=1.0; repeat if odd(e) then case i of 0:t:=t*1.0E1; 1:t:=t*1.0E2; 2:t:=t*1.0E4; 3:t:=t*1.0E8; 4:t:=t*1.0E16; 5:t:=t*1.0E32; 6:t:=t*sqr(1.0E32); 7:t:=t*sqr(sqr(1.0E32)); 8:t:=t*sqr(sqr(sqr(1.0E32))); 9:t:=t*sqr(sqr(sqr(sqr(1.0E32)))); end; e:=e div 2; i:=i+1; until e=0; ten:=t; end; (*FUNCTION ten*) begin (* readreal *) readsign(msign); fig:=0; exp:=0; repeat if fig<limit then fig:=fig*10+chartonumberÆchÅ else exp:=exp+1; read(ch); until not(ch in Æ'0'..'9'Å); if ch='.' then begin (*read fraction*) read(ch); while (ch in Æ'0'..'9'Å) do begin if fig<limit then begin fig:=fig*10+chartonumberÆchÅ; exp:=exp-1; end; read(ch); end; end; if ch='E' then begin (*read scale factor*) read(ch); readsign(scsign); exp2:=0; while (ch<>' ') do begin if exp2<limit then exp2:=exp2*10+chartonumberÆchÅ; read(ch); end; if scsign then exp:=exp-exp2 else exp:=exp+exp2; end; if exp<lim2 then begin fig:=0; exp:=0; end else if exp>lim1 then begin error(303); exp:=0; end; if msign then res1:=-fig else res1:=fig; if exp<0 then readreal:=res1/ten(-exp) else if exp<>0 then readreal:=res1*ten(exp) else readreal:=res1; end; (*FUNCTION readreal*) begin (*readconst*) (* PIF opcode const has just been read *) s := getsymbptr; with s^ do begin key := econst ; consttype := getsymbptr; read( ch ); case consttype^.typkind of einteger, escalar, eboolean, eascii: begin constkind:=wordconst; intval:=readint; if (intval<=maxsignedhalfword) and (intval>=minsignedhalfword) then constkind:=signedshortconst end; ereal: begin constkind:=realconst; realval:=readreal; end; estring: begin lngt:=consttype^.length; if lngt>stringmax then begin error(402); lngt:=stringmax; end; constkind:=stringconst; stringval:=newstring; with stringval^ do begin length:=lngt; for i := 1 to lngt do begin strÆiÅ:=ch; read(ch); end; end; end; (*estring*) epointer: begin (* the pointer value NIL *) constkind:=signedshortconst; intval:=nilvalue; end; end; (*CASE *) end (* WITH s^ DO ... *) ; end; (*PROCEDURE readconst*) procedure readlabeldecl ; var s : symbolptr ; begin (* PIF opcode label has just been read *) s := getsymbptr ; with s^ do begin key := elabel ; labellevel:=level; labelordinal:=localordinal; if localordinal >= maxordinal -oneword -mintemporary then error(306) else localordinal:=localordinal+oneword; procaddr:=procfuncoffset-procdescrlength; end ; end ; function log2(x:integer):integer; var i,j:integer; begin if x>=maxint div 2 then log2:=maxbit else begin i:=0; j:=1; repeat i:=i+1; j:=j*2; until j > x; log2:=i; end; end; procedure insertsorted(symbol:symbolptr); (*insert symbol which must be a variable in a list sorted after the length of storage requirement *) var length:integer; s,s1:symbolptr; begin length:=symbol^.vartypedescr^.size; symbol^.next:=nil; if sortlist = nil then sortlist:=symbol else begin s:=sortlist; if s^.vartypedescr^.size >= length then begin symbol^.next:=s; sortlist:=symbol; end else begin while length > s^.vartypedescr^.size do begin s1:=s; s:=s^.next; if s = nil then begin s:=s1; length:=0; end; end; if length <> 0 then symbol^.next:=s; s1^.next:=symbol; end; end; end; procedure reallocatefields; var flist : symbolptr; shift : bitrange; begin flist:=fieldlist; fieldlist:=nil; if flist <> nil then if flist^.next = nil then with flist^.varaddr do begin (* only one field in this word *) packk:=unpack; end else begin shift:=maxbit+1-flist^.varaddr.bitstart-flist^.vartypedescr^.bitsize; repeat with flist^.varaddr do begin bitstart:=bitstart+shift; flist:=flist^.next; end; until flist=nil; end; end; procedure readnamedef ; var a : alfa ; aptr : ^alfa; s, s1: symbolptr; i, j : integer; n : nodeident ; ch : char ; address : addrptr; string : stringptr; externalfile : boolean; begin (* PIF opcode name has just been read *) s := getsymbptr ; readalfa( a ) ; (* if name is a scalar constant, a proc/func, a program, or a module we need the name itself *) with s^ do begin key := ename ; namekind := getintmtwords ; case namekind of etype : forgetsymbptr(lastnodeident) ; (* as name of type is never used *) econst : begin constant:=getsymbptr; if constant^.consttype = scalartype then begin constname:=a; scalartype^.lastscalar:=constant^.intval; if constant^.consttype^.typkind = eascii then forgetsymbptr(lastnodeident); end else begin if constant^.constkind=stringconst then constant^.stringval^.returnable:=false; forgetsymbptr(lastnodeident); end; end ; effunc, efproc, evarparam : if standenvir then forgetsymbptr(lastnodeident) (* parameters of standard procedures are never used by this program *) else with varaddr do begin valparordinal:=0; if namekind <> efproc then vartypedescr := getsymbptr ; index:=nil; bitstart := 0; packk:=unpack; simpleaddr:=true; blocknumber:=level; ordinal:=localordinal; localordinal:=localordinal+oneword; if namekind <> evarparam then localordinal:=localordinal+oneword; end; evalparam, evar: if standenvir then forgetsymbptr(lastnodeident) else with varaddr do begin valparordinal:=0; vartypedescr:=getsymbptr; index:=nil; packk:=unpack; if (vartypedescr^.size <= 4) and (localordinal < maxordinal-4-mintemporary) then begin simpleaddr:=true; bitstart := 0; blocknumber:=level; ordinal:=localordinal; localordinal:=localordinal+vartypedescr^.size; end else begin if namekind=evalparam then begin valparordinal:=localordinal; localordinal:=localordinal+oneword; end; insertsorted(s); end; end; efield, etagfield: begin s1:=getsymbptr; vartypedescr:=s1; i:=s1^.size; j:=s1^.bitsize; with varaddr,currentfixlist^ do begin simpleaddr:=true; if packlist then begin packk:=s1^.packedtype; if j+bitoffset > maxbit+1 then begin (*not enough free bits in this word *) reallocatefields; s^.next:=nil; fieldlist:=s; bitstart:=0; ordinal:=byteoffset+oneword; byteoffset:=byteoffset+i; bitoffset:=j; end else begin s^.next:=fieldlist; fieldlist:=s; bitstart:=bitoffset; ordinal:=byteoffset; bitoffset:=bitoffset+j; byteoffset:=byteoffset+i-oneword; end; end else begin bitstart:=0; ordinal:=byteoffset; packk:=unpack; byteoffset:=byteoffset+i; end; end; end; efunc, eproc : begin new(aptr); aptr^ := a; routinename := aptr; blocklevel:=level; coreresident:=resident; standard := standenvir; if currentmodule = nil then begin currentproc:=s; paramlist:=getsymbptr; paramlist^.displayoffset:=localordinal; routinedescr := procfuncoffset ; starttmp:=0; availtmp:=0; procfuncoffset:=procfuncoffset+procdescrlength; (* Note that the level is 1 less than the level of the parameter and variables *) end else if currentmodule^.modulekind = esystem then begin stnd_name := standardcounter ; standardcounter := succ( standardcounter ) ; n:=getnumber; (* parameter list is not used *) end; if namekind = efunc then functype := getsymbptr ; end ; eprogram : begin (* note, that a program has no parameter list; therefore all the work done for *) (* a procedure on namelist, param has to be done here for the program. *) programident:=lastnodeident; new(aptr); aptr^ := a; routinename := aptr; blocklevel:=level; coreresident:=resident; standard:=false; currentproc:=s; routinedescr:=procfuncoffset; procfuncoffset:=procfuncoffset+procdescrlength; starttmp:=0; availtmp:=0; localordinal:=minparamordinal+standardentries; new(s1); with s1^ do begin key:=enamelist; listkind:=eparam; displayoffset:=localordinal; localordinal := localordinal + oneword; copyvalparam:=nil; filelist:=nil; initlist:=nil; lengthofvalue:=0; end; paramlist:=s1; alfatype:=indexÆalfatypeidentÅ; end ; efile : begin externalfile:= getintmtwords = eext; vartypedescr := getsymbptr ; with varaddr do begin index:=nil; packk:=unpack; simpleaddr:=true; blocknumber:=level; if blocknumber < 0 then begin (* standard file INPUT or OUTPUT *) blocknumber:=0; ordinal:=localordinal; if a = 'INPUT ' then begin inputordinal:=ordinal; inputfilename:=s; end else begin outputordinal:=ordinal; outputfilename:=s; end; localordinal:=localordinal+oneword; address := newaddress; address^:=varaddr; simpleaddr:=false; postordinal:=0; reference:=address; end else insertsorted(s); (* remember filedeclaration for later allocation *) end; if externalfile then begin new(string); extname:=string; i:=0; if not eoln(input) then read(ch); while (not eoln(input)) and (i<alfalength) do begin i:=i+1; string^.strÆiÅ:=ch; read(ch); end; if i<=1 then string^.length:=0 else begin for i:=i+1 to filenamelength div oneword *asciiperword do string^.strÆiÅ:=' '; string^.length:=filenamelength div oneword *asciiperword; end; end else extname:=nil; end; emodule : begin modulename:=a; currentmodule:=s; modulekind:=getintmtwords; end; end (* CASE namekind OF ... *) ; end (* WITH s^ .. *) ; end (* readnamedef *) ; procedure allocatelist; var firsttemp, i: integer; slist, vallist, fillist, s : symbolptr; address : addrptr; tmpallocated : boolean; begin (* allocate the variables in the sorted list *) slist:=sortlist; sortlist:=nil; vallist:=nil; fillist:=nil; tmpallocated:=false; while slist <> nil do with slist^,varaddr do begin if tmpallocated or ( localordinal+vartypedescr^.size < maxordinal-mintemporary) then begin index:=nil; packk:=unpack; bitstart:=0; simpleaddr:=true; blocknumber:=level; ordinal:=localordinal; localordinal:=localordinal+vartypedescr^.size; if namekind = evalparam then begin s:=next; next:=vallist; vallist:=slist; slist:=s; end else if namekind = efile then begin if namekind = efile then ordinal:=ordinal+(filenamelength-h0); s:=next; next:=fillist; fillist:=slist; slist:=s; end else slist:=next; end else begin (* no more space in first block *) firsttemp:=localordinal; localordinal:=localordinal+mintemporary; tmpallocated:=true; end; end; if not tmpallocated then firsttemp:=localordinal; with currentproc^ do begin if availtmp = 0 then begin starttmp:=firsttemp; availtmp:=mintemporary; paramlist^.copyvalparam:=vallist; paramlist^.filelist:=fillist; if not tmpallocated then localordinal:=localordinal+mintemporary; declarationlist^.maxstackoffset:=localordinal; end; end; end; (* allocatelist *) procedure readnamelist ; var s:symbolptr; begin s:=getsymbptr; with s^ do begin key:=enamelist; listkind := getintmtwords ; case listkind of eparam : if standenvir then forgetsymbptr(lastnodeident) (* no parameterlists for standardfunctions *) else begin if currentproc <> nil then allocatelist; localordinal:=minparamordinal; copyvalparam:=nil; filelist:=nil; initlist:=nil; lengthofvalue:=0; level := level + oneword ; end ; edeclaration : begin level := level + oneword ; if currentproc <> nil then currentproc^.declarationlist:=s; localordinal:=localordinal+level+oneword;(*storage for display *) if localordinal > maxordinal-mintemporary then error(306); end ; escalarlist : forgetsymbptr(lastnodeident); efix : begin if currentvarlist=nil then byteoffset:=0 else byteoffset:=currentvarlist^.fixsize; bitoffset:=0; lastfixlist:=currentfixlist; oldvarlist:=currentvarlist; currentvarlist:=nil; currentfixlist:=s; packlist:=getintmtwords = epacked; end end; (* CASE LISTKIND OF *) end (* WITH s^ ... *) ; end (* readnamelist ... *) ; procedure sizeoftype(symb:symbolptr; first,last:integer); begin with symb^ do begin packedtype:=paack; if first > 0 then first:=0; size:=intsize; if getbasetype(symb) = eascii then bitsize:=bitperascii else bitsize:=log2(last-first); if (first>=minsignedhalfword) and (last<=maxsignedhalfword) then begin if first<0 then begin bitsize:=(maxbit+1) div 2; packedtype:=signedhlfword; end; end else if (first>=0) and (last<=maxhalfword)and (bitsize=(maxbit+1) div 2) then packedtype:=hlfword else if first < 0 then begin bitsize:=maxbit+1; packedtype:=unpack; end; end; end; (* sizeoftype *) procedure readendnamelist ; begin case getintmtwords of escalarlist : begin sizeoftype(scalartype,0,scalartype^.lastscalar); scalartype:=nil; end; edeclaration :begin if currentproc <> nil then allocatelist; lastindex:=0; if maxindex-lastindex < maxcode then outconstlimit:=maxindex else outconstlimit:=maxcode; labnumber:=getnumber+1; end; eparam : if not standenvir then begin level:=level-oneword; end ; efix : with currentfixlist^ do begin reallocatefields; namelistsize:=byteoffset; if bitoffset>0 then namelistsize:=namelistsize+oneword; currentfixlist:=lastfixlist; end ; end ; (*CASE getintmtwords OF ... *) end (* readendnamelist *) ; procedure readtypegeneral ; var noofwords, noofelements, elementsperword, first, last : integer ; mini, maxi, s : symbolptr ; begin (*readtypegeneral*) s := getsymbptr ; with s^ do begin bitsize:=maxbit+1; packedtype:=unpack; key := etype ; typkind := getintmtwords ; case typkind of einteger : begin size := intsize ; integertype:=s; end; ereal: begin size := realsize ; realtype:=s; end; esubrange : begin subtyp := getsymbptr ; mini := getsymbptr ; maxi := getsymbptr ; first:=mini^.intval; last:=maxi^.intval; firstconst:=first; lastconst:=last; if first > last then begin error(307) ; size:=intsize; end else sizeoftype(s,first,last); end; eboolean : begin scalartype:=s; namelist:=getnumber; booltype:=s; end; escalar: begin namelist:=getnumber; scalartype:=s; (* preparing for the following (namelist, scalar) *) end ; eascii : begin namelist:=getnumber; scalartype:=s; (* preparing for the following (namelist, scalar) *) asciitype:=s; end ; earray : begin if getintmtwords=epacked then packedtype:=paack; packedval:=false; indextyp := getsymbptr ; valtyp := getsymbptr ; with indextyp ^ do case typkind of esubrange : begin s^.stringcomp:=((subtyp^.typkind=einteger) and (getbasetype(s^.valtyp)=eascii) and (s^.packedtype=paack) and (firstconst=1)); first := firstconst ; last := lastconst ; end ; escalar, eboolean, eascii : begin stringcomp:=false; first := 0 ; last := lastscalar ; end ; einteger : begin stringcomp:=false; first:=-maxint-1; last:=maxint; end; end ; noofelements:=last-first+1; if noofelements<0 then begin noofelements:=1; error(304); end; if (packedtype=paack) and (valtyp^.size=oneword) then begin elementsperword:=(maxbit+1) div valtyp^.bitsize; if elementsperword > 1 then begin noofwords:=noofelements div elementsperword; if noofelements mod elementsperword > 0 then noofwords:=noofwords+1; size:=noofwords*oneword; packedval:=true; end else size:=noofelements*oneword; end else size:=valtyp^.size*noofelements; if size<0 then begin size:=oneword; error(304); end; end ; erecord : begin (* global namelistsize was set by preceding fixlist or varlist *) size := namelistsize ; if getintmtwords=epacked then packedtype:=paack; varlist:=currentvarlist; currentvarlist:=nil; end ; eset : begin if getintmtwords=epacked then packedtype:=paack; size := setsize ; setoftyp := getsymbptr ; end ; efile : begin if getintmtwords=epacked then packedtype:=paack; randomfile := erandom = getintmtwords ; if randomfile then begin fileindextype:=getsymbptr; error(406); end; elementtyp := getsymbptr ; size := filenamelength +h5+h6+bufferlength; if getbasetype(elementtyp) <> eascii then size:=size+elementtyp^.size; end ; epointer : begin size := ptrsize ; pointertotyp := getsymbptr ; end ; estring : begin length := getnumber ; noofwords := length div asciiperword; if length mod asciiperword > 0 then noofwords:=noofwords+1; size:=noofwords*oneword; end ; end (* CASE typkind OF .. *) end (* WITH s^ DO ... *); end (* readtypegeneral *) ; procedure readrecordlabel; var s,s1,s2:symbolptr; labelvalue:integer; multilabel:boolean; begin s:=getsymbptr; s1:=getsymbptr; labelvalue:=s1^.intval; s1:=currentvarlist^.taglist; multilabel:=false; while s1 <> nil do begin s2:=s1^.labellist^.nextreclab; while s2 <> nil do begin if labelvalue=s2^.reclabvalue then multilabel:=true; s2:=s2^.nextreclab; end; s1:=s1^.nexttag; end; if multilabel then error(308); with s^ do begin key:=erecordlabel; reclabvalue:=labelvalue; nextreclab:=nil; end; currentcase^.nextreclab:=s; currentcase:=s; end; (* readrecordlabel *) procedure newtop(op:operators; exptyp:symbolptr; psleft,psright:pseudoptr); (* pop two top elements from pseudostack (if psright=NIL just one) and push a new element on pseudostack, with operator op, leftoperand =psleft and rightoperand=psright *) var pseudo:pseudoptr; begin pseudotop:=pseudotop^.next; if psright <> nil then pseudotop:=pseudotop^.next; pseudo:=newpseudo; with pseudo^ do begin typ:=exptyp; next:=pseudotop; kind:=expression; leftoperand:=psleft; rightoperand:=psright; operator:=op; end; pseudotop:=pseudo; end; procedure indexaddress(var arr : addrnode; var elementlength : integer); forward; procedure changeamcode(disp : integer); forward; procedure amchange(bn : integer; var disp : integer); forward; function sameaddress(addr1,addr2 : addrnode) : boolean; (* true if the address chains starting with addr1 and addr2 are equivalent *) var notfinished : boolean; begin notfinished := true; while notfinished do with addr1 do if (packk = addr2.packk) and (bitstart = addr2.bitstart) and (simpleaddr = addr2.simpleaddr) and (index = addr2.index) then begin if simpleaddr then begin sameaddress := (blocknumber = addr2.blocknumber) and (ordinal = addr2.ordinal); notfinished := false; end else if (postordinal = addr2.postordinal) and (reference <> nil) and (addr2.reference <> nil) then begin addr1 := reference^; addr2 := addr2.reference^; end else begin notfinished := false; sameaddress := false; end; end else begin notfinished := false; sameaddress := false; end; end; (* same address *) procedure storetmp(ps : pseudoptr); (* store the content of the register (ps) into the first free temporary and let ps be of kind tmp *) var regnumber : regrange; next,samereg : pseudoptr; op : opcodes; adjustment : integer; begin if ps <> nil then begin if ps^.typ^.size > oneword then begin (* size must be 4 !! *) adjustment := oneword; op := ds; end else begin adjustment := 0; op := rs; end; if nooffreetmp <= 2 then error(311); if ps^.kind <> reg then error(403) else begin samereg := ps^.sameregister; regnumber := ps^.regno; if (op = ds) and (registerÆregnumberÅ.user = registerÆ(regnumber+1) mod noofregÅ.user) then regnumber := (regnumber + 1) mod noofreg; next := ps; repeat with next^ do begin kind := tmp; with addr do begin index := nil; packk := unpack; bitstart := 0; simpleaddr := true; blocknumber := level; ordinal := fstfreetmp; end; end; next := samereg; if next <> nil then if next^.kind <> reg then next := nil else samereg := next^.sameregister; until next = nil; makeindexcode(op,regnumber,stackaddr,fstfreetmp+adjustment); with registerÆregnumberÅ do begin user := nil; lastused := lastindex; valid := true; kind := tmp; locassociated := true; addr := ps^.addr; end; if op = ds then registerÆ(regnumber+maxreg) mod noofregÅ := registerÆregnumberÅ; fstfreetmp := fstfreetmp + oneword + adjustment; nooffreetmp := nooffreetmp - oneword - adjustment; end; end; end; (* store temporary *) procedure loadnotsimple(var addr : addrnode; regnumber : regrange; var pckptr : packindicator); forward; procedure loadaddress(regnumber : regrange; ps : pseudoptr); forward; procedure loadregister(regnumber : regrange; ps : pseudoptr); forward; procedure forgetregisters; (* forget all about the content of the registers *) var j : integer; begin for j := 0 to maxreg do with registerÆjÅ do begin user := nil; valid := false; end; end; (* forget registers *) procedure registerstore(regnumber:regrange; nodestroy:integer); forward; function freeregister(index : boolean) : regrange; (* get a free register *) var count, old, oldused, firstreg : integer; found : boolean; begin if index then firstreg := 1 else firstreg := 0; count := firstreg; repeat with registerÆcountÅ do found := (user = nil) and (not valid) and (count <> stackaddr); count := count + 1; until (found or (count > maxreg)); if not found then begin (* look for a register holding a constant *) count := firstreg; repeat with registerÆcountÅ do found := (count <> stackaddr) and ((kind = shortsignedcst) or (kind = wordcst)); count := count + 1; until (found or (count > maxreg)); if not found then (* force a free register *) begin old := firstreg; oldused := registerÆoldÅ.lastused; for count := firstreg + 1 to maxreg do if count <> stackaddr then with registerÆcountÅ do if lastused < oldused then begin oldused := lastused; old := count; end; count := old; end else count := count - 1; if registerÆcountÅ.user <> nil then registerstore(count,-1); end else count := count - 1; registerÆcountÅ.valid := false; freeregister := count; end; (* free register *) procedure makeregister(ps : pseudoptr; regtostore : integer); (* if regtostore < 0 then get a free register and connect it with ps else connect ps and regtostore, the internal knowledge of regtostore will be destroyed *) var w : regrange; begin if regtostore < 0 then w := freeregister(false) else w := regtostore; with registerÆwÅ do begin user := ps; lastused := lastindex; kind := variable; valid := true; locassociated := false; (* no address associated yet *) addr.simpleaddr:=true; addr.blocknumber:=-2; end; (* with w do *) if ps^.typ^.size > oneword then registerÆ(w+1) mod noofregÅ := registerÆwÅ; with ps^ do begin kind := reg; regno := w; sameregister := nil; end; (* with ps^ do *) end; (* make register *) procedure registerstore; (* regnumber:regrange; nodestroy : integer *) (*make code to store the content of registerÆregnumberÅ into the address specified in the register node, but only if kind = variable, see the special use of kind in procedure load . If nodestroy <> -1 then register(nodestroy) will remain unchanged after the call of the procedure, even if user = nil *) var next, nextnext, index1, ps, ps1 : pseudoptr; found, amcode, field, addressmode : boolean; count, disp, disp1, shift, siz : integer; freereg, v, v1, w, stackp, regtostore : regrange; addr1 : addrnode; pckptr : packindicator; begin (* register store *) regtostore := regnumber; with registerÆregnumberÅ do if (kind = variable) or (kind = tmp) then begin if (user <> nil) and (kind = variable) and (not locassociated) then storetmp(user) (* make code to store the content of the register into the first free temporary location *) else begin if kind = variable then begin locassociated := false; (* force storing in a temporary *) if user <> nil then if user^.typ^.size > oneword then registerÆ(regnumber+1) mod noofregÅ.locassociated := false; (* make code to store the content of the register *) with addr do if simpleaddr and (packk = unpack) then begin v := stackaddr; if index <> nil then begin ps := user; if ps = nil then begin ps := newpseudo; ps^.typ := integertype; makeregister(ps,regnumber); end; addr1 := addr; indexaddress(addr1,siz); with addr1 do if index^.kind = reg then begin reservecode(8); v1 := index^.regno; if ps^.kind <> reg then (* the register has been used for index calculation, and the former contents are stored in a temporary *) begin if (v1 = regnumber) or ((ps^.typ^.size > oneword) and (v1 = ((regnumber+1) mod noofreg))) then storetmp(registerÆv1Å.user); loadregister(regnumber,ps); end; if index^.kind = reg then if v1 = 0 then makeindirectcode(am,0,0,0) (* am (0) *) else makeindexcode(am,0,v1,0) (* am x *) else makeindirectcode(am,0,stackaddr,index^.addr.ordinal); registerÆv1Å.valid := v1 = regnumber; end; addr := addr1; index1 := index; returnpseudo(index1); index := nil; end; if blocknumber = level then begin if abs(ordinal) <= maxordinal then disp := ordinal else begin if code^.cÆlastindexÅ.opcode = am then changeamcode(ordinal) else begin makeallcode(am,0,reladdr,indirectmode,0,0); makeconst(ordinal,nil); end; disp := 0; end; end else (* block number <> level *) begin disp := ordinal; amchange(blocknumber,disp); with code^.cÆlastindexÅ do if (indirect = directmode) and (index <> 0) then (* am x? *) begin v := index; lastindex := lastindex - 1; (* the am instruction is not necessary *) end else v := 0; end; makeindexcode(rs,regnumber,v,disp); end else (* not simple address or packk <> unpack *) if packk <> unpack then (* pack and store !! *) begin if index <> nil then begin addr1 := addr; ps := registerÆregnumberÅ.user; if ps = nil then begin ps := newpseudo; ps^.typ := integertype; makeregister(ps,regnumber); end; stackp := stackaddr; indexaddress(addr1,siz); with addr1 do if index^.kind = reg then begin reservecode(6); ps1 := nil; field := siz = maxbit; v1 := index^.regno; if field then begin siz := ps^.typ^.bitsize; (* a packed field, not an array element *) stackp := 0; disp := maxbit + 1 - bitstart - siz; (* number of bits to shift *) addressmode := directmode; end else begin (* the bitstart of the array element is in register(v1-1), the mask shifting uses 24-reg(v1-1)-siz *) makeindirectcode(am,0,0,oneword*((v1+maxreg) mod noofreg)); makecode(ac,(v1+maxreg) mod noofreg,siz - 24); ps1 := newpseudo; ps1^.typ := integertype; makeregister(ps1,(v1+maxreg) mod noofreg); storetmp(ps1); disp := ps1^.addr.ordinal; (* tmp *) stackp := stackaddr; addressmode := indirectmode; end; if regnumber = 0 then w := 1 else w := noofreg - regnumber; if simpleaddr then begin if blocknumber <> level then makeindexcode(wa,index^.regno,stackaddr,display+blocknumber); if abs(ordinal) > maxordinal then begin makewrelcode(wa,index^.regno,0); makeconst(ordinal,nil); end; storetmp(index); (* this is done to simplify the compiler, and it is most often necessary anyway, because the RC8000 only has four registers *) end else begin storetmp(index); (* this is done to simplify the compiler, and it is most often necessary anyway, because the RC8000 only has four registers *) loadnotsimple(reference^,w,pckptr); makeindexcode(wa,w,stackaddr,index^.addr.ordinal); if abs(postordinal) > maxordinal then begin makewrelcode(wa,w,0); makeconst(postordinal,nil); end; makeindexcode(rs,w,stackaddr,index^.addr.ordinal); end; if ps^.kind <> reg then (* tmp *) loadregister(regnumber,ps); (* get the original content back *) if siz = (maxbit + 1) div oneword then (* halfword *) makecode(bz,regnumber,regnumber*oneword + 1); (* remove the sign extension from signed halfwords *) makewrelcode(rl,w,0); makeconst(bitmaskÆsizÅ, nil); (* right justified mask *) makeallcode(ls,w,absaddr,addressmode,stackp,disp); makeallcode(ls,regnumber,absaddr,addressmode,stackp,disp); makeindexcode(ac,w,w,1); (* complement the mask *) makeindirectcode(am,0,stackaddr,index^.addr.ordinal); if simpleaddr then begin if blocknumber <> level then stackp := 0 else stackp := stackaddr; if abs(ordinal) <= maxordinal then disp := ordinal else disp := 0; end (* simple address *) else begin if abs(postordinal) <= maxordinal then disp := postordinal else disp := 0; stackp := 0; end; makeindexcode(la,w,stackp,disp); makecode(lo,regnumber,oneword*w); makeindirectcode(am,0,stackaddr,index^.addr.ordinal); (* tmp *) makeindexcode(rs,regnumber,stackp,disp); registerÆwÅ.valid := false; registerÆregnumberÅ.valid := false; if ps1 <> nil then returnpseudo(ps1); end (* index^.kind = reg *) else begin index1 := index; returnpseudo(index1); index := nil; end; addr := addr1; end; (* index <> nil *) if index <> nil then (* index was changed to nil in the former section if all the array indices were constant therefore it is tested once more*) begin addr := addr1; index1 := index; returnpseudo(index1); index := nil; end else begin if simpleaddr then begin if blocknumber = level then stackp := stackaddr else stackp := 0; (* indicates that an am instruction is required before the la, and rs *) disp := ordinal; end else begin lastused := lastindex; (* avoid freeing of register(regnumber) *) disp := freeregister(true); loadnotsimple(reference^,disp,pckptr); ps := newpseudo; ps^.typ := integertype; stackp := disp; makeregister(ps,stackp); disp := postordinal; (* even displacement *) end; siz := user^.typ^.bitsize; shift := maxbit - bitstart + 1 - siz; if (siz = (maxbit + 1) div oneword) and ((shift = 0) or (shift = (maxbit+1) div oneword)) then begin (* half word *) if shift = 0 then (* right half word *) disp := disp + 1; if stackp = 0 then begin reservecode(4); makeindirectcode(am,0,stackaddr,display+blocknumber); (* am (x2+BN+display) *) end; if abs(disp) <= maxordinal then makeindexcode(hs,regnumber,stackp,disp) else begin if code^.cÆlastindexÅ.opcode = am then changeamcode(disp) else begin makeallcode(am,0,reladdr,indirectmode,0,0); makeconst(disp,nil); end; makeindexcode(hs,regnumber,stackp,0); end; end else (* not a half word *) begin lastused := lastindex; (* avoid freeing of register(regnumber) *) w := freeregister(false); makewrelcode(rl,w,0); makeconst(-1 - bitmaskÆmaxbit - bitstart + 1Å + bitmaskÆshiftÅ,nil); disp1 := disp; if abs(disp) <= maxordinal then begin if stackp = 0 then makeindirectcode(am,0,stackaddr,display+blocknumber); (* am (x2+BN+display) *) makeindexcode(la,w,stackp,disp1); end else begin if stackp = 0 then amchange(blocknumber,disp1) else begin reservecode(2); makeallcode(am,0,reladdr,indirectmode,0,0); makeconst(disp,nil); disp1 := 0; end; makeindexcode(la,w,stackp,disp1); end; if shift <> 0 then makecode(ls,regnumber,shift); makecode(lo,regnumber,oneword * w); if abs(disp) > maxordinal then begin if stackp = 0 then amchange(blocknumber,disp) else begin reservecode(2); makeallcode(am,0,reladdr,indirectmode,0,0); makeconst(disp,nil); end; end else if stackp = 0 then makeindirectcode(am,0,stackaddr,display+blocknumber); (* am (x2+BN+display) *) makeindexcode(rs,regnumber,stackp,disp1); registerÆwÅ.valid := false; end; (* not half word *) if not simpleaddr then begin (* register(stackp) has been reserved for address information which is of no interest any more *) registerÆstackpÅ.valid := false; returnpseudo(ps); end; registerÆregnumberÅ.valid := false; (* do not remember packed results *) end; end (* packk <> unpack *) else begin (* not simple addr and packk = unpack *) count := maxreg; repeat found := (registerÆcountÅ.user = nil) and (count <> stackaddr) and (count <> nodestroy); count := count - 1; until (found or (count < 0)); freereg := count + 1; if not found or (freereg=0)then begin if regnumber = 0 then freereg := maxreg else freereg := noofreg - regnumber; storetmp(registerÆfreeregÅ.user); end; registerÆfreeregÅ.valid := false; ps := registerÆregnumberÅ.user; if ps = nil then begin ps := newpseudo; ps^.typ := integertype; makeregister(ps,regnumber); end; addr1 := addr; (* for two reasons: 1: to be used as parameter (packed) 2: in case of temp store of rightside-value: don't forget the address *) loadnotsimple(reference^,freereg,pckptr); if index <> nil then begin ps1 := newpseudo; ps1^.typ := integertype; makeregister(ps1,freereg); indexaddress(addr1,siz); with addr1 do begin if index^.kind = reg then begin v1 := index^.regno; if ps1^.kind <> reg then begin makeindexcode(wa,v1,stackaddr,ps1^.addr.ordinal); index^ := ps1^; freereg := v1; makeregister(ps1,freereg); end else begin with registerÆv1Å do begin user := nil; valid := false; end; makecode(wa,freereg,oneword*v1); end; end; (* index = register *) end; (* with addr1 do *) returnpseudo(ps1); end; (* if index <> nil *) if ps^.kind <> reg then begin if (freereg = regnumber) or ((ps^.typ^.size > oneword) and (freereg=((regnumber+1) mod noofreg))) then begin if regnumber = 0 then v1 := maxreg else v1 := noofreg - regnumber; makecode(rl,v1,oneword*freereg); with registerÆfreeregÅ do begin user := nil; valid := false; end; freereg := v1; makeregister(ps1,freereg); end; loadregister(regnumber,ps); end; addr := addr1; (* this assignment has been delayed until 'regnumber' really (again) contained the rightside-value *) index1 := index; returnpseudo(index1); index := nil; if abs(postordinal) <= maxordinal then disp := postordinal else begin reservecode(2); disp := 0; makeallcode(am,0,reladdr,indirectmode,0,0); makeconst(postordinal,nil); end; makeindexcode(rs,regnumber,freereg,disp); end; kind := tmp; (* prevent storing the register more than once *) locassociated := true; end; (* if kind = variable *) if user <> nil then begin next := user; repeat if next^.kind <> reg then nextnext := nil else nextnext := next^.sameregister; if locassociated then begin next^.kind := variable; next^.addr := addr; end else next^.kind := tmp; next := nextnext; until next = nil; end; end; if not addr.simpleaddr then begin field := valid; (* valid is false for packed fields *) forgetregisters; (* avoid unpredictable side effects with pointer variables and VAR parameters *) valid := field; end; end (* if (kind = variable) or (kind = tmp) *) else (* constant *) if (user <> nil) and (kind <> expression) then (* cheat *) begin next := user; repeat if next^.kind <> reg then nextnext := nil else begin nextnext := next^.sameregister; next^.kind := kind; if kind = longcst then next^.constptr := constptr else (* one-word constant *) next^.constant := constant; end; next := nextnext; until next = nil; end; (* constant *) registerÆregtostoreÅ.user := nil; end; (* register store *) procedure store(regnumber : regrange; ps : pseudoptr); (*change the register desription to be ps and the pseudonode to be of kind register, and let register.kind := variable, and make code to store the content of the register *) var count : integer; nextreg : regrange; notvalid : boolean; begin if (ps^.kind <> variable) and (ps^.kind <> tmp) then error(403) else begin for count := 0 to maxreg do with registerÆcountÅ do if ((user <> nil) or valid) and ((kind = variable) and sameaddress(ps^.addr,addr)) then begin user := nil; valid := false; end; with registerÆregnumberÅ do begin if ((kind=tmp) or (kind=variable) ) and valid then if not addr.simpleaddr then returnaddress(addr.reference); user := ps; valid := true; kind := variable; addr := ps^.addr; notvalid := addr.index <> nil; (* if array ref then forget the reg contents after storing *) locassociated := ps^.kind = variable; with ps^ do begin if typ^.size > oneword then begin nextreg := (regnumber + 1) mod noofreg; registerÆ nextreg Å := registerÆ regnumber Å; end; kind := reg; regno := regnumber; sameregister := nil; end; registerstore(regnumber,regnumber); if notvalid then registerÆregnumberÅ.valid := false; if ps^.typ^.size > oneword then begin registerÆ nextreg Å := registerÆ regnumber Å; with code^.cÆlastindexÅ do begin opcode := ds; displacement := displacement + oneword; w := (w + 1) mod noofreg; end; end; end; end; end; (* store *) procedure storeregisters(nostore : pseudoptr); (* store away all registers holding variables, without destroying the one (if any) specified by nostore *) var j, savereg : integer; begin if nostore <> nil then savereg := nostore^.regno else savereg := -1; for j := maxreg downto 0 do with registerÆjÅ do begin if (user <> nil) then registerstore(j,savereg); valid := false; end; end; procedure loadsimple(var addr:addrnode; regnumber:regrange; var pckptr : packindicator); var v, v1, siz, regnr : integer; index1 : pseudoptr; amcode : boolean; begin pckptr.size := maxbit; regnr := regnumber; if regnumber = 0 then begin if registerÆ3Å.user = nil then regnumber := 3 else if registerÆ1Å.user = nil then regnumber := 1 else error(403); registerÆregnumberÅ.valid := false; end; v := regnumber; with addr do begin if index <> nil then indexaddress(addr,siz); if blocknumber = level then begin if index <> nil then begin if index^.kind = reg then begin reservecode(3); v := index^.regno; with pckptr do if siz <> maxbit then begin size := siz; ps := newpseudo; ps^.typ := integertype; makeregister(ps,(v+maxreg) mod noofreg); storetmp(ps); end; if v = 0 then makeindirectcode(am,0,0,0) (* am (0) *) else makeindexcode(am,0,v,0); (* am x *) end; index1 := index; returnpseudo(index1); index := nil; registerÆvÅ.valid := registerÆvÅ.user <> nil; end; if abs(ordinal) < maxordinal then makeindexcode(rl,regnr,stackaddr,ordinal) else begin reservecode(5); with code^.cÆlastindexÅ do begin amcode := opcode = am; v1 := index; (* if index <> stackaddr and amcode then array-index = register(index) *) end; if amcode then begin with code^ do cÆlastindex + 1Å := cÆlastindexÅ; lastindex := lastindex - 1; makewrelcode(wa,v1,0); (* v1 <> stackaddr !! *) makeconst(ordinal,nil); lastindex := lastindex + 1; end else (* not amcode *) begin makeallcode(am,0,reladdr,indirectmode,0,0); (* am. (ordinalconst) *) makeconst(ordinal,nil); end; makeindexcode(rl,regnr,stackaddr,0); end; end else begin if index = nil then makeindexcode(rl,regnumber,stackaddr,display+blocknumber) else begin reservecode(4); v := 0; if index^.kind = reg then begin reservecode(3); v := index^.regno; with pckptr do if siz <> maxbit then begin size := siz; ps := newpseudo; ps^.typ := integertype; makeregister(ps,(v+maxreg) mod noofreg); storetmp(ps); end; makeindexcode(wa,v,stackaddr,display+blocknumber); if v = 0 then makeindirectcode(am,0,0,0); (* am (0) *) end else makeindirectcode(am,0,stackaddr,display + blocknumber); index1 := index; returnpseudo(index1); index := nil; registerÆvÅ.valid := registerÆvÅ.user <> nil; end; if abs(ordinal) < maxordinal then makeindexcode(rl,regnr,v,ordinal) else begin reservecode(5); with code^.cÆlastindexÅ do begin amcode := opcode = am; v1 := index; (* if index <> stackaddr and amcode then array-index = register(index) *) end; if amcode then begin if v1 <> stackaddr then begin with code^ do cÆlastindex + 1Å := cÆlastindexÅ; lastindex := lastindex - 1; makewrelcode(wa,v1,0); (* v1 <> stackaddr !! *) makeconst(ordinal,nil); lastindex := lastindex + 1; end else begin (* delete am (x2+display+BN); and make wa to the free register regnumber *) lastindex := lastindex -1; makeindexcode(rl,regnumber,stackaddr,display+blocknumber); makewrelcode(wa,regnumber,0); makeconst(ordinal,nil); v := regnumber; end; end else (* not amcode *) begin makeallcode(am,0,reladdr,indirectmode,0,0); makeconst(ordinal,nil); end; makeindexcode(rl,regnr,v,0); end; end; end; (* with ... *) end; (* load simple *) procedure indexcode(var address : addrnode; var pckptr : packindicator; var v : regrange; preserve : pseudoptr; double : boolean); (* v is an index register containing address information preserve is (if present) a register which must not be used for the index, double tells if register(preserve - 1) must be zeroed before the am instructions, this is necessary before a wd , note: the procedure may terminate with at most one am-instruction *) var ps, index1 : pseudoptr; returnps : boolean; ww, w, w1, siz : integer; begin pckptr.size := maxbit; with address do begin if preserve <> nil then w1 := preserve^.regno; ps := registerÆvÅ.user; if ps = nil then begin returnps := true; ps := newpseudo; ps^.typ := integertype; makeregister(ps,v); end else returnps := false; indexaddress(address,siz); if index^.kind = reg then begin w := index^.regno; with pckptr do if siz <> maxbit then begin size := siz; ps := newpseudo; ps^.typ := integertype; makeregister(ps,(w+maxreg) mod noofreg); storetmp(ps); end; if preserve <> nil then begin if preserve^.kind <> reg then (* preserve is a temporary *) begin if (w = w1) or ((preserve^.typ^.size > oneword) and (w = ((w1+1) mod noofreg))) then storetmp(registerÆwÅ.user); loadregister(w1,preserve); end; if double and (index^.kind = reg) then begin ww := (w1 + maxreg) mod noofreg; if w = ww then storetmp(registerÆwÅ.user); (* sign extension before a wd instruction *) makecode(bl, ww, 2*w1); makecode(bl, ww, 2*ww); end; end; if ps^.kind <> reg then (* the register has been used for index calculation, and the former content is stored in a temporary *) begin if index^.kind = reg then begin v := w; makeindexcode(wa,w,stackaddr,ps^.addr.ordinal); (* tmp *) if w = 0 then begin reservecode(4); makeindirectcode(am,0,0,0); (* am (0) *) end; end else begin v := 0; if nooffreetmp < 4 then error(311); makeindexcode(rs,1,stackaddr,fstfreetmp); makeindexcode(rl,1,stackaddr,index^.addr.ordinal); makeindexcode(wa,1,stackaddr,ps^.addr.ordinal); makeindexcode(rs,1,stackaddr,ps^.addr.ordinal); makeindexcode(rl,1,stackaddr,fstfreetmp); reservecode(4); makeindirectcode(am,0,stackaddr,ps^.addr.ordinal); (* am (x2+tmp) *) end; end else begin reservecode(4); if index^.kind = reg then if w = 0 then makeindirectcode(am,0,0,0) (* am (0) *) else makeindexcode(am,0,w,0) (* am x *) else makeindirectcode(am,0,stackaddr,index^.addr.ordinal); end; index1 := index; returnpseudo(index1); index := nil; registerÆwÅ.valid := registerÆwÅ.user <> nil; end; end; if returnps then returnpseudo(ps); end; (* index code *) procedure loadnotsimple; (* FORWARD declared with parameter list: (VAR addr:addrnode; regnumber:regrange; VAR pckptr : packindicator) *) var v : regrange; count, amcount, disp, regnr : integer; index1 : pseudoptr; begin regnr := regnumber; if regnumber = 0 then begin if registerÆ3Å.user = nil then regnumber := 3 else if registerÆ1Å.user = nil then regnumber := 1 else error(403); registerÆregnumberÅ.valid := false; end; if addr.simpleaddr then loadsimple(addr,regnumber,pckptr) else begin loadnotsimple(addr.reference^,regnumber,pckptr); with addr do begin v := regnumber; if index <> nil then indexcode(addr,pckptr,v,nil,false); if abs(postordinal) <= maxordinal then disp := postordinal else begin amcount := 0; with code^ do begin while cÆlastindex - amcountÅ.opcode = am do amcount := amcount + 1; for count := 1 to amcount do cÆlastindex + 2 -countÅ := cÆlastindex + 1 - countÅ; lastindex := lastindex - amcount; makewrelcode(wa,v,0); makeconst(postordinal,nil); lastindex := lastindex + amcount; end; (*with code*) disp := 0; end; makeindexcode(rl,regnr,v,disp); end; (* with ... *) end; end; (* load not simple *) procedure changeamcode; (* disp : integer *) var v : integer; begin with code^ do begin v := cÆlastindexÅ.index; if (v <> stackaddr) and (not((v=0) and (cÆlastindexÅ.indirect=directmode))) then begin cÆlastindex + 1Å := cÆlastindexÅ; lastindex := lastindex -1; makewrelcode(wa,v,0); makeconst(disp,nil); lastindex := lastindex + 1; end else (* index = stackadr, i.e. am (x2+tmp) *) begin cÆlastindex + 1Å := cÆlastindexÅ; lastindex := lastindex - 1; if nooffreetmp < 4 then error(311); makeindexcode(rs,1,stackaddr,fstfreetmp); lastindex := lastindex + 1; with cÆlastindexÅ do begin opcode := rl; indirect := directmode; w := 1; end; makewrelcode(wa,1,0); makeconst(disp,nil); makeindexcode(rs,1,stackaddr,fstfreetmp+oneword); makeindexcode(rl,1,stackaddr,fstfreetmp); reservecode(4); makeindirectcode(am,0,stackaddr,fstfreetmp+oneword); end; end; end; procedure addresscode(var address : addrnode; w, x : regrange); var v : integer; index1 : pseudoptr; begin with address do begin if index <> nil then begin if index^.kind = reg then begin reservecode(4); v := index^.regno; with code^.cÆlastindexÅ do if opcode = am then begin opcode := wa; w := v; indirect := directmode; end; if v = 0 then makeindirectcode(am,0,0,0) (* am (0) *) else if x <> 0 then makeindexcode(am,0,v,0) (* am x? *) else x := v; registerÆvÅ.valid := false; end; index1 := index; returnpseudo(index1); index := nil; end; if abs(ordinal) <= maxordinal then makeindexcode(al,w,x,ordinal) else begin reservecode(3); with code^, cÆlastindexÅ do if opcode = am then changeamcode(ordinal) else (* former instruction <> am *) begin makeallcode(am,0,reladdr,indirectmode,0,0); (* am. (ordinalconst) *) makeconst(ordinal,nil); end; makeindexcode(al,w,x,0); end; end; end; (* address code *) procedure loadaddress; (* FORWARD declared (regnumber : regrange; ps : pseudoptr) *) (* load the address of the variable with address in ps into regnumber *) var v : regrange; count, amcount, regnr, size : integer; pckptr : packindicator; begin if registerÆregnumberÅ.user <> nil then registerstore(regnumber,-1); regnr := regnumber; with ps^ do begin case kind of variable, tmp: begin if regnumber = 0 then begin if registerÆmaxregÅ.user = nil then regnumber := maxreg else if registerÆ1Å.user = nil then regnumber := 1 else error(403); registerÆregnumberÅ.valid := false; end; with addr do if simpleaddr then begin if index <> nil then indexaddress(addr,size); if blocknumber = level then addresscode(addr,regnr,stackaddr) else begin if index = nil then makeindexcode(rl,regnumber,stackaddr,display+blocknumber) else begin regnumber := 0; reservecode(5); makeindirectcode(am,0,stackaddr,display+blocknumber); end; addresscode(addr, regnr, regnumber); end; end else begin loadnotsimple(reference^,regnumber,pckptr); v := regnumber; if index <> nil then indexcode(addr,pckptr,v,nil,false); if (postordinal <> 0) or (regnr <> v) then if abs(postordinal) <= maxordinal then makeindexcode(al,regnr,v,postordinal) else begin with code^ do begin amcount := 0; while cÆlastindex - amcountÅ.opcode = am do amcount := amcount + 1; for count := 1 to amcount do cÆlastindex + 2 -countÅ := cÆlastindex + 1 - countÅ; lastindex := lastindex - amcount; makewrelcode(wa,v,0); makeconst(postordinal,nil); lastindex := lastindex + amcount; end; (*with code*) makeindexcode(al,regnr,v,0); end; end; end; (* variable, tmp *) shortsignedcst, wordcst: begin reservecode(2); makewrelcode(al,regnumber,0); makeconst(constant,nil); end; longcst: begin reservecode(typ^.size div oneword + 2); makewrelcode(al,regnumber,0); makeconst(0,constptr); end; (* long constant *) end; registerÆregnrÅ.valid := false; (* the content of the register node is unspecified *) end; end; (* load address *) procedure searchregisters(ps : pseudoptr; var regfound : boolean); (* search the registers to see if ps is there *) var found : boolean; count : integer; begin if ps^.kind = reg then begin count := ps^.regno; found := true; end else begin found := false; count := -1; repeat count := count + 1; with registerÆcountÅ do if (user <> nil) or valid then if (kind = ps^.kind) or ((kind = tmp) and (ps^.kind = variable)) then case kind of variable, tmp: found := sameaddress(addr,ps^.addr) and locassociated; shortsignedcst, wordcst: found := constant = ps^.constant; longcst: found := constptr = ps^.constptr end; (* case kind *) until (found or (count = maxreg)); end; if found then with registerÆcountÅ do begin if ps^.typ^.size > oneword then begin if kind = longcst then (* if the variable/constant is in reg(maxreg) and (0) then count := maxreg *) begin if (constptr = registerÆmaxregÅ.constptr) and registerÆmaxregÅ.valid and (registerÆmaxregÅ.kind = longcst) then begin count := maxreg; registerÆmaxregÅ.user := ps; end else if (constptr = registerÆ1Å.constptr) and registerÆ1Å.valid and (registerÆ1Å.kind = longcst) then registerÆ1Å.user := ps else found := false; end else (* variable or tmp *) if sameaddress(addr,registerÆmaxregÅ.addr) and registerÆmaxregÅ.valid then begin registerÆmaxregÅ.user := ps; count := maxreg; end else if (count = 0) and sameaddress(addr,registerÆ1Å.addr) and registerÆ1Å.valid then registerÆ1Å.user := ps else found := false; end; if found and (ps^.kind <> reg) then begin ps^.kind := reg; ps^.sameregister := user; user := ps; ps^.regno := count; end; end; regfound := found; end; (* search the registers for ps *) procedure loadregister; (* regnumber : regrange; ps : pseudoptr *) (* load register(regnumber) with ps *) var help, shift, siz, count : integer; found : boolean; pckptr : packindicator; begin searchregisters(ps, found); with registerÆregnumberÅ do begin if (user <> nil) and (not (locassociated and sameaddress(addr,ps^.addr))) and ((ps^.kind <> reg) or (ps^.regno <> regnumber)) then registerstore(regnumber,-1); case ps^.kind of reg: begin with ps^ do begin if regno = regnumber then registerÆregnumberÅ.user := ps else if typ^.size > oneword then begin makecode(dl,(regnumber+1) mod noofreg,((regno+1) mod noofreg)*oneword); help := (regno + maxreg) mod noofreg; registerÆregnumberÅ := registerÆregnoÅ; registerÆ(regnumber + maxreg) mod noofregÅ := registerÆhelpÅ; with registerÆhelpÅ do begin user := nil; valid := false; end; end else begin if regno = 0 then makecode(rl,regnumber,0) else makeindexcode(al,regnumber,regno,0); registerÆregnumberÅ := registerÆregnoÅ; user := ps; lastused := lastindex; with registerÆregnoÅ do begin user := nil; valid := false; end; end; end; (* with ... *) end; (* kind = reg *) variable, tmp: begin with ps^.addr do case packk of hlfword, signedhlfword, paack: (* unpack and load register *) begin if simpleaddr then loadsimple(ps^.addr, regnumber,pckptr) else loadnotsimple(ps^.addr, regnumber,pckptr); if pckptr.size = maxbit then siz := ps^.typ^.bitsize else begin siz := pckptr.size; makeindirectcode(am,0,stackaddr,pckptr.ps^.addr.ordinal); returnpseudo(pckptr.ps); end; shift := bitstart + siz - 1 - maxbit; if (shift <> 0) or (pckptr.size <> maxbit) then makecode(ls,regnumber,shift); if siz = (maxbit + 1) div oneword then (* halfwords are loaded with byte instructions *) if packk = signedhlfword then makecode(bl,regnumber,regnumber*oneword+1) else makecode(bz,regnumber,regnumber*oneword+1) else if (bitstart <> 0 ) or (pckptr.size <> maxbit) then begin makewrelcode(la,regnumber,0); makeconst(bitmaskÆsizÅ,nil); end; end; (* hlfword, signedhlfwrd, paack *) unpack: if ps^.typ^.size > oneword then (* need 2 registers *) begin if regnumber = maxreg then begin user := nil; valid := false; (* free registers 0 and 1 *) for count := 0 to 1 do with registerÆcountÅ do if user <> nil then registerstore(count,-1); end else if regnumber = 0 then if (registerÆ1Å.user <> ps) and ((registerÆ1Å.user <> nil) or registerÆ1Å.valid) then registerstore(1,-1); regnumber := 1; if ps^.addr.simpleaddr then loadsimple(ps^.addr,regnumber,pckptr) else loadnotsimple(ps^.addr,regnumber,pckptr); (* change the code from rl to dl *) with code^.cÆlastindexÅ do begin opcode := dl; displacement := displacement + oneword; end; for count := 0 to 1 do with registerÆcountÅ do begin user := ps; lastused := lastindex; valid := true; locassociated := true; kind := tmp; addr := ps^.addr; end; regnumber := (regnumber + maxreg) mod noofreg; end else if simpleaddr then loadsimple(ps^.addr,regnumber,pckptr) else loadnotsimple(ps^.addr,regnumber,pckptr); end; (* case packk of *) siz := ps^.typ^.size; if siz = oneword then begin user := ps; locassociated := ps^.kind = variable; kind := tmp; (* this is done to avoid storing of unchanged registers *) valid := true; lastused := lastindex; addr := ps^.addr; end; if ps^.kind = tmp then begin nooffreetmp := nooffreetmp + siz; fstfreetmp := fstfreetmp - siz; end; end; (* variable, tmp: *) shortsignedcst, wordcst: begin constant := ps^.constant; if ps^.kind = shortsignedcst then makecode(al,regnumber,constant) else begin makewrelcode(rl,regnumber,0); makeconst(constant,nil); end; user := ps; lastused := lastindex; valid := true; kind := ps^.kind; end; longcst: (* load of a real const or string const *) begin if ps^.typ^.size = oneword then (* constant string *) begin with registerÆregnumberÅ do begin if (user <> nil) or valid then registerstore(regnumber,-1); user := ps; lastused := lastindex; valid := true; kind := longcst; constptr := ps^.constptr; end; makewrelcode(rl,regnumber,0); makeconst(0,ps^.constptr); end else (*real or double-word string *) begin if regnumber = maxreg then begin user := nil; valid := false; end; for count := 0 to 1 do with registerÆcountÅ do begin if (user <> nil) or valid then registerstore(count,-1); user := ps; lastused := lastindex; valid := true; kind := longcst; constptr := ps^.constptr; end; regnumber := 0; reservecode(8); if ps^.typ^.typkind <> ereal then makecode(am, 0, oneword); (* the address of the constant denotes the first word *) makewrelcode(dl,1,0); makeconst(0,ps^.constptr); end; end; expression,procfunc,valueinit: error(403); end; (* case kind of *) ps^.kind := reg; ps^.regno := regnumber; ps^.sameregister := nil; end; (* with registerÆregnumberÅ do *) end; (* load register *) procedure load(ps:pseudoptr); (* load the variable with address in ps into register(s) the resultant register is always the first one, even for reals *) var count, oldused, firstreg : integer; found : boolean; result : regrange; begin (* load *) searchregisters(ps,found); if not found then begin (* look for a free register, or free one *) if (ps^.kind = shortsignedcst) or (ps^.kind = wordcst) or (ps^.kind = longcst) then firstreg := 0 else firstreg := 1; count := firstreg; repeat with registerÆcountÅ do if (user = nil) and (count <> stackaddr) and not valid then (* a free register is found *) begin found := true; result := count; end; count := count + 1; until (found or (count > maxreg)); if not found then begin (* use the oldest register, after storing the content *) result := firstreg; oldused := registerÆresultÅ.lastused; for count := firstreg + 1 to maxreg do if count <> stackaddr then with registerÆcountÅ do if lastused < oldused then begin oldused := lastused; result := count; end; end; loadregister(result,ps); end; end; (* load *) procedure amchange; (* bn : integer; VAR disp : integer *) var move, v1 : integer; begin with code^ do begin reservecode(6); if abs(disp) <= maxordinal then move := 1 else move := 2; if cÆlastindexÅ.opcode = am then begin v1 := cÆlastindexÅ.index; if v1 <> stackaddr then begin cÆlastindex+moveÅ := cÆlastindexÅ; lastindex := lastindex - 1; if move = 2 then begin makewrelcode(wa,v1,0); makeconst(disp,nil); disp := 0; end; makeindexcode(wa,v1,stackaddr,display+bn); lastindex := lastindex + 1; end (* v1 <> stackaddr *) else begin if nooffreetmp < 4 then error(311); cÆlastindex + 1Å := cÆlastindexÅ; lastindex := lastindex - 1; makeindexcode(rs,1,stackaddr,fstfreetmp); lastindex := lastindex + 1; with cÆlastindexÅ do begin (* change am (x2+tmp) to rl 1,x2+tmp *) opcode := rl; w := 1; indirect := directmode; end; if move = 2 then begin makewrelcode(wa,1,0); makeconst(disp,nil); disp := 0; end; makeindexcode(wa,1,stackaddr,display+bn); makeindexcode(rs,1,stackaddr,fstfreetmp+oneword); makeindexcode(rl,1,stackaddr,fstfreetmp); makeindirectcode(am,0,stackaddr,fstfreetmp+oneword); end; end else (* not am code *) begin if move = 2 then begin if nooffreetmp < 4 then error(311); makeindexcode(rs,1,stackaddr,fstfreetmp); makeindexcode(rl,1,stackaddr,display+bn); makewrelcode(wa,1,0); makeconst(disp,nil); makeindexcode(rs,1,stackaddr,fstfreetmp+oneword); makeindexcode(rl,1,stackaddr,fstfreetmp); makeindirectcode(am,0,stackaddr,fstfreetmp+oneword); disp := 0; end else (* disp <= maxordinal *) makeindirectcode(am,0,stackaddr,display+bn); end; end; end; procedure operation( op : opcodes; expr, left, right : pseudoptr); (* make code for: load(left) . op w right it may save some code to do the address calculation for left and right in parallel *) var v, w, x : regrange; disp, rsize, count : integer; found : boolean; index1 : pseudoptr; pckptr : packindicator; procedure checkdoubleregister(op : opcodes; var operand : regrange); (* if op is a double register operation then make code to save the content of the register used in connection with operand by op; if the operand register is maxreg then use registers 0 and maxreg, i.e. save reg(0) and move the content of reg(maxreg) to reg(0) and change operand to 0 *) var reserve : integer; begin (* check double register *) if (op=wm) or (op=wd) or (op=ci) then begin reserve := (operand + maxreg) mod noofreg; if reserve = stackaddr then begin (* use reg(0) and (maxreg), i.e. let (0) be the operand register *) with registerÆ0Å do if user <> nil then registerstore(0,maxreg); registerÆ0Å := registerÆmaxregÅ; with registerÆmaxregÅ do begin user := nil; valid := false; end; makeindexcode(al,0,maxreg,0); reserve := maxreg; operand := 0; end else (* reserve <> stackaddr *) with registerÆreserveÅ do begin if user <> nil then registerstore(reserve,-1); valid := false; user := nil; end; if op = wd then begin (* sign extension *) makecode(bl, reserve, 2*operand); makecode(bl, reserve, 2*reserve); end; end; (* op = wm or wd or ci *) end; (* check double register *) procedure load_packed_right; (* in case of a packed right operand the operand is loaded and it is assured that the left operand is in register w at procedure exit, and if op=wd the sign extension is done once more. disp and v is assigned suitable for "makeindexcode(op, w, v, disp)" *) begin load(right); (* check whether right can stay in a register *) if (w=right^.regno) or ((op = wd) and (right^.regno = (w + maxreg) mod noofreg)) then begin storetmp(right); (* register(right) is needed for the operation *) disp := right^.addr.ordinal; v := stackaddr; end else begin v := 0; disp := right^.regno * oneword; with registerÆ disp div 2 Å do begin user := nil; valid := false; end; end; (* now assure that left is in register w *) with left^ do if kind <> reg then if (kind = variable) or (kind = tmp) then loadregister(w, left) else (* kind = word constant or short signed constant *) if abs(constant) <= maxordinal then makecode(al, w, constant) else begin makewrelcode(rl, w, 0); makeconst(constant, nil); end; if op = wd then (* extend the sign of left *) checkdoubleregister(wd, w); end; (* load packed right *) procedure load_not_simple_right(right : pseudoptr); (* get a register and load a pointer to the start of the structure denoted by right, and assure that left is still in register w at exit; let v and disp be prepared for "makeindexcode(op, w, v, disp) " , at exit there is still reservecode'd 3 words *) begin with right^.addr do begin if w <> 0 then begin v := noofreg - w; if (registerÆvÅ.user <> nil) or registerÆvÅ.valid then registerstore(v,w); (* do not destroy w *) end else begin (* use register 1 to avoid convflict with a possible sign extension in register 3 *) with register Æ 1 Å do if (user <> nil) or valid then registerstore( 1, w ); v := 1; end; (* w = 0 *) loadnotsimple(reference^,v,pckptr); with left^ do if kind <> reg then (*left must be loaded once more *) begin if (kind = variable) or (kind = tmp) then (* left is temporary stored, or "easy" to load again without destroying registers *) loadregister(w, left) else if (kind = wordcst) or (kind = shortsignedcst) then if abs(constant) <= maxordinal then makecode(al,w,constant) else begin makewrelcode(rl,w,0); makeconst(constant,nil); end else (* longconstant *) begin makewrelcode(dl,w,0); makeconst(0,constptr); end; checkdoubleregister(op,w); end; if rsize > oneword then postordinal := postordinal + oneword; if index <> nil then indexcode(right^.addr,pckptr,v,left,op=wd); registerÆvÅ.valid := false; (* forget the contents of reg(v) *) if abs(postordinal) <= maxordinal then disp := postordinal else begin disp := 0; if code^.cÆlastindexÅ.opcode = am then changeamcode(postordinal) else begin reservecode(5); makeallcode(am,0,reladdr,indirectmode,0,0); makeconst(postordinal,nil); end; end; (* note: we still have reservecode'd about 3 words *) end; (* with right^.regno do *) end; (* load not simple right *) (* ****** operation ****** *) begin w := stackaddr; rsize := right^.typ^.size; searchregisters(left,found); case left^.kind of shortsignedcst, wordcst, longcst, reg: begin with left^ do begin if kind <> reg then load(left); if rsize > oneword then w := (regno + 1) mod noofreg else w := regno; end; (* with *) checkdoubleregister(op,w); searchregisters(right, found); case right^.kind of reg: begin with right^ do if rsize > oneword then v := (regno + 1) mod noofreg else v := regno; reservecode(3); makecode(op,w,v*oneword); end; (* reg: *) variable, tmp: begin with right^.addr do if packk = unpack then if simpleaddr then begin if index <> nil then indexaddress(right^.addr,count); if rsize > oneword then ordinal := ordinal + oneword; if index <> nil then begin if index^.kind = reg then begin x := index^.regno; if left^.kind <> reg then (* left is a temporary *) begin if (x = w) or ((rsize > oneword) and (x = ((w+maxreg) mod noofreg))) then storetmp(registerÆxÅ.user); loadregister(w,left); end; if (op = wd) and (index^.kind = reg) then (* the sign extension may have been destroyed during index calculation, e.g. the calculated index may be in the register needed by wd, therefore it is checked once more *) checkdoubleregister(wd (* op = wd *), w ); reservecode(5); (* 5 in order to ensure a call of amchange *) if index^.kind = reg then if x = 0 then makeindirectcode(am,0,0,0) (* am (0) *) else makeindexcode(am,0,x,0) (* am x *) else makeindirectcode(am,0,stackaddr,index^.addr.ordinal); registerÆxÅ.valid := registerÆxÅ.user^.sameregister <> nil; end; index1 := index; returnpseudo(index1); index := nil; end; if blocknumber <> level then begin disp := ordinal; amchange(blocknumber, disp); v := 0; end else begin v := stackaddr; if abs(ordinal) <= maxordinal then disp := ordinal else begin if code^.cÆlastindexÅ.opcode = am then changeamcode(ordinal) else begin reservecode(5); makeallcode(am,0,reladdr,indirectmode,0,0); makeconst(ordinal,nil); end; disp := 0; end; end; end else begin (* not simpleaddr *) load_not_simple_right(right); (* with left kept in register w , the address of right is calculated, resulting in v and disp properly initialized for "op w v+disp" *) end else (* packk <> unpack *) load_packed_right; reservecode(3); makeindexcode(op,w,v,disp); end; shortsignedcst, wordcst:begin reservecode(4); makewrelcode(op,w,0); makeconst(right^.constant,nil); end; longcst: begin reservecode(4); makewrelcode(op,w,0); makeconst(0,right^.constptr); end; expression,procfunc,valueinit: error(403); end; (* case right^.kind *) end; (* left^.kind = reg or shortsignedcst or wordcst *) variable, tmp: begin searchregisters(right, found); case right^.kind of reg: begin if left^.typ^.size > oneword then begin if sameaddress(registerÆ0Å.addr, registerÆ1Å.addr) then v := 1 else v := 0; with registerÆ0Å do begin user := nil; valid := false; end; if v = 1 then count := 1 else count := maxreg; with registerÆcountÅ do begin user := nil; valid := false; end; if nooffreetmp < 4 then error(311); makeindexcode(ds,v,stackaddr,fstfreetmp+oneword); load(left); w := (left^.regno + 1) mod noofreg; reservecode(3); makeindexcode(op,w,stackaddr,fstfreetmp+oneword); end else begin load(left); w := left^.regno; checkdoubleregister(op, w); if right^.kind = reg then begin reservecode(3); makecode(op,w,right^.regno*oneword) end else begin registerÆwÅ.kind := variable; operation(op, expr, left, right); end; end; end; (* right^.kind = reg *) variable, tmp: with left^ do begin if addr.simpleaddr and right^.addr.simpleaddr and (addr.blocknumber = right^.addr.blocknumber) then begin if (addr.blocknumber = level) or (addr.index <> nil) or (addr.packk <> unpack) then begin w := freeregister(false); if (addr.packk = unpack) and (rsize = oneword) then begin loadsimple(addr,w,pckptr); makeregister(left,w); end else loadregister(w,left); w := regno; (* only changed for reals *) with registerÆwÅ do (* force temporary storing of w if necessary *) begin kind := variable; locassociated := false; end; if rsize > oneword then with registerÆ(w+1) mod noofregÅ do begin kind := variable; locassociated := false; end; v := stackaddr; end (* if blocknumber = level *) else begin (* use w3 as stackpointer for the stackframe of which left and right are variables *) storeregisters(nil); w := 1; makeindexcode(rl,maxreg,stackaddr,display+addr.blocknumber); with addr do if abs(ordinal) < maxordinal then disp := ordinal else begin reservecode(3); makeallcode(am,0,reladdr,indirectmode,0,0); makeconst(ordinal,nil); disp := 0; end; v := maxreg; makeindexcode(rl,w,v,disp); if rsize > oneword then begin w := 0; makeregister(left,w); registerÆ1Å := registerÆ0Å; with code^.cÆlastindexÅ do begin opcode := dl; displacement := displacement + oneword; end; end else makeregister(left,w); end; (* now left is loaded into reg(w) *) (* perform sign extension in case of op=wd *) checkdoubleregister(op, w); with right^.addr do begin if packk = unpack then begin if index <> nil then begin indexaddress(right^.addr,count); if index^.kind = reg then begin v := stackaddr; (* a possible common display in reg(3) may have been destroyes *) x := index^.regno; if left^.kind <> reg then (* left is a temporary *) begin if (x = w) or ((rsize > oneword) and (x = ((w+1) mod noofreg))) then storetmp(registerÆxÅ.user); loadregister(w,left); end; if (op = wd) and (index^.kind = reg) then (* the sign extension may have been destroyed during index calculation therefore it is performed once more *) checkdoubleregister( wd (* op=wd *), w); reservecode(5); if index^.kind = reg then if x = 0 then makeindirectcode(am,0,0,0) (* am (0) *) else makeindexcode(am,0,x,0) (* am x *) else makeindirectcode(am,0,stackaddr,index^.addr.ordinal); registerÆxÅ.valid := registerÆxÅ.user^.sameregister <> nil; end; index1 := index; returnpseudo(index1); index := nil; end; if (blocknumber <> level) and (v <> maxreg) then (* (v=maxreg) <=> register(maxreg) = display + bn *) begin count := 0; amchange(blocknumber,count);(* second parameter is not used *) x := code^.cÆlastindexÅ.index; if (x <> 0) and (x <> stackaddr) then begin (* the am instruction is not needed *) v := x; lastindex := lastindex - 1; end else v := 0; end; if rsize > oneword then begin w := (w+1) mod noofreg; ordinal := ordinal + oneword; end; if abs(ordinal) <= maxordinal then disp := ordinal else begin if code^.cÆlastindexÅ.opcode = am then changeamcode(ordinal) else begin reservecode(5); makeallcode(am,0,reladdr,indirectmode,0,0); makeconst(ordinal,nil); end; disp := 0; end; end else (* packed right operand *) load_packed_right; end; reservecode(3); makeindexcode(op,w,v,disp); end else begin (* not simpleaddr or left.BN <> right.BN *) load(left); if rsize > oneword then begin with registerÆregnoÅ do begin locassociated := false; kind := variable; end; w := (regno + 1) mod noofreg end else w := regno; with registerÆwÅ do begin locassociated := false; kind := variable; (* ensure temporary storing if necessary *) end; checkdoubleregister(op, w); with right^.addr do if packk = unpack then if simpleaddr then begin if index <> nil then begin indexaddress(right^.addr,count); if index^.kind = reg then begin v := index^.regno; if left^.kind <> reg then (* left is a temporary *) begin if (v = w) or ((rsize > oneword) and (v = ((w+maxreg) mod noofreg))) then storetmp(registerÆvÅ.user); loadregister(w,left); end; reservecode(5); if index^.kind = reg then if index^.regno = 0 then makeindirectcode(am,0,0,0) (* am (0) *) else makeindexcode(am,0,index^.regno,0) (* am x *) else makeindirectcode(am,0,stackaddr,index^.addr.ordinal); registerÆvÅ.valid := registerÆvÅ.user^.sameregister <> nil; end; index1 := index; returnpseudo(index1); index := nil; end; if rsize > oneword then ordinal := ordinal + oneword; if blocknumber <> level then begin disp := ordinal; amchange(blocknumber, disp); v := 0; end else begin v := stackaddr; if abs(ordinal) < maxordinal then disp := ordinal else begin if code^.cÆlastindexÅ.opcode = am then changeamcode(ordinal) else begin reservecode(5); makeallcode(am,0,reladdr,indirectmode,0,0); makeconst(ordinal,nil); end; disp := 0; end; end; end else begin (* not simpleaddr *) load_not_simple_right(right); (* with left kept in register w the address of right is calculated, resulting in v and disp properly initialized for " op w v+disp " *) end else (* packkind <> unpack *) load_packed_right; reservecode(3); makeindexcode(op,w,v,disp); end; end; (* variable, tmp *) shortsignedcst, wordcst: begin load(left); w := left^.regno; checkdoubleregister(op,w); reservecode(4); makewrelcode(op,w,0); makeconst(right^.constant,nil); end; longcst: begin load(left); w := (left^.regno + 1) mod noofreg; (* must be a double register *) reservecode(5); makewrelcode(op,w,0); makeconst(0,right^.constptr); end; expression,procfunc,valueinit: error(403); end; (* case right^.kind *) end; (* left^.kind = variable or tmp *) expression,procfunc,valueinit: error(403); end; (* case left^.kind of *) if w = stackaddr then error(403) else with registerÆwÅ do begin user := expr; lastused := lastindex; valid := true; kind := variable; with addr do begin index := nil; simpleaddr := true; blocknumber := level; end; locassociated := false; end; (* if double register operation then update the second register *) (* except for wm, we are not interested in the overflow part *) if op in Æwd, ci, fa, fs, fm, fdÅ then begin registerÆ(maxreg+w) mod noofregÅ := registerÆwÅ; if op <> wd then w := (w + maxreg) mod noofreg; end; with expr^ do begin kind := reg; regno := w; sameregister := nil; end; end; (* operation *) procedure evaltoresult(ps:pseudoptr; skipk:skipkind); forward; procedure pushnest; var nd:integer; begin read(nd); if nd > maxnest then stop(404); with neststackÆndÅ do begin startindex:=lastindex; index:=0; end; ndepth:=nd; end; procedure commute(typ:symbolptr); var pseudo : pseudoptr; begin pseudo:=pseudotop^.next; if ((pseudo^.kind=wordcst) or (pseudo^.kind=shortsignedcst)) and ((pseudotop^.kind=wordcst) or (pseudotop^.kind=shortsignedcst)) then begin (* only integer constants *) case intermitwords of emult: pseudo^.constant:= pseudo^.constant * pseudotop^.constant; eadd: pseudo^.constant:= pseudo^.constant + pseudotop^.constant; eeq: pseudo^.constant:= ord(pseudo^.constant = pseudotop^.constant); ene: pseudo^.constant:= ord(pseudo^.constant <> pseudotop^.constant); end; if (pseudo^.constant <= maxsignedhalfword) and (pseudo^.constant >= minsignedhalfword) then pseudo^.kind:=shortsignedcst else pseudo^.kind:=wordcst; returnpseudo(pseudotop); end else begin if (pseudotop^.kind=expression) or (pseudo^.kind=wordcst) or (pseudo^.kind=shortsignedcst) or (pseudo^.kind=longcst) then begin (*exchange top and top-1 *) pseudotop^.next:=pseudo^.next; pseudo^.next:=pseudotop; pseudotop:=pseudo; end; newtop(intermitword,typ,pseudotop^.next,pseudotop); end; end; (* commute *) procedure copyshort(length,start:integer; reverse:boolean); (* copy length bytes starting with that which has address in register 1 to that which has address in register 2 + start if reverse then copy the other way destroyes register 0 and 3 length +start must be less than maxordinal *) var i:integer; begin if reverse then begin for i:=0 to length div (2*oneword) -1 do begin makeindexcode(dl,0,2,i*(2*oneword)+oneword+start); makeindexcode(ds,0,1,i*(2*oneword)+oneword); end; if odd(length div oneword) then begin makeindexcode(rl,0,2,length-oneword+start); makeindexcode(rs,0,1,length-oneword); end; end else begin for i:=0 to length div (2*oneword) -1 do begin makeindexcode(dl,0,1,i*(2*oneword)+oneword); makeindexcode(ds,0,2,i*(2*oneword)+oneword+start); end; if odd(length div oneword) then begin makeindexcode(rl,0,1,length-oneword); makeindexcode(rs,0,2,length-oneword+start); end; end; end; (* copyshort *) procedure copylong(length:integer; pseudo:pseudoptr); (* copy length >=4 bytes starting with that which has address in register 1 to that which has address in pseudo. Destroyes register 0 and 3 *) var psfrom : pseudoptr; distance, lgt : integer; begin psfrom:=newpseudo; psfrom^.typ:=integertype; makeregister(psfrom,1); loadaddress(3,pseudo); if psfrom^.kind <> reg then makeindexcode(rl,1,stackaddr,psfrom^.addr.ordinal); returnpseudo(psfrom); storeregisters(nil); reservecode(16); if length > maxshortcopy then begin lgt:=length-2*oneword; if lgt < maxsignedhalfword then makeindexcode(al,0,1,lgt) else begin makeindexcode(al,0,1,0); makewrelcode(wa,0,0); makeconst(lgt,nil); end; distance:=workspaceÆ1Å; if distance <> 0 then distance:=distance-lastindex-1; makewrelcode(rs,0,distance); workspaceÆ1Å:=lastindex; end; distance:=workspaceÆ2Å; if distance <> 0 then distance:=distance-lastindex-1; makewrelcode(rs,2,distance); workspaceÆ2Å:=lastindex; (* remember upper limit and stackaddr in 2 words *) makeindexcode(al,2,3,0); if length <= maxshortcopy then copyshort(length,0,false) else begin makeindexcode(dl,0,1,oneword); makeindexcode(ds,0,2,oneword); makeindexcode(al,2,2,2*oneword); makeindexcode(al,1,1,2*oneword); makeallcode(sh,1,true,true,0,workspaceÆ1Å-lastindex-1); workspaceÆ1Å:=lastindex; makerelcode(jl,-5*oneword); if odd(length div oneword) then begin makeindexcode(rl,0,1,0); makeindexcode(rs,0,2,0); end end; makewrelcode(rl,2,workspaceÆ2Å-lastindex-1); workspaceÆ2Å:=lastindex; end; (* copylong *) procedure forstatement(skip,skip1:opcodes; increment:integer); var w:integer; s:symbolptr; pseudo : pseudoptr; begin with pseudotop^ do begin if kind = expression then evaltoresult(pseudotop,noskip); if kind <> shortsignedcst then begin if kind <> reg then load(pseudotop); storetmp(pseudotop); end; case next^.kind of expression:begin evaltoresult(next,noskip); w:=next^.regno; registerÆwÅ.user:=nil; storeregisters(next); if w=0 then begin w:=1; makecode(rl,1,0); end; end; variable:begin load(next); w:=next^.regno; storeregisters(next); end; shortsignedcst:begin storeregisters(nil); w:=1; makecode(al,1,next^.constant); end; wordcst:begin storeregisters(nil); makewrelcode(rl,1,0); makeconst(next^.constant,nil); w:=1; end; end; reservecode(5); if kind = shortsignedcst then makecode(skip1,w,constant) else makeindirectcode(skip1,w,stackaddr,addr.ordinal); makerelcode(jl,4*oneword); if kind = shortsignedcst then makecode(skip,w,constant) else makeindirectcode(skip,w,stackaddr,addr.ordinal); makerelcode(jl,0); pushnest; with neststackÆndepthÅ do begin index:=lastindex; stepregister:=w; end; outconstlimit:=outconstlimit-1; makeindexcode(al,w,w,increment); end; s:=getsymbptr; pseudo:=newpseudo; with pseudo^ do begin typ:=s^.vartypedescr; kind:=variable; addr:=s^.varaddr; end; store(w,pseudo); returnpseudo(pseudo); end; (* forstatement *) procedure jump(jumplength:integer); begin if jumplength < maxsignedhalfword then makerelcode(jl,-jumplength) else if jumplength < maxhalfword then begin makecode(am,0,minsignedhalfword); makerelcode(jl,-minsignedhalfword-jumplength-oneword); end else begin makewrelcode(rl,1,0); makeconst(-jumplength-oneword,nil); makeallcode(jl,0,true,false,1,0); end; end; procedure boolexpression; var regnumber : regrange; begin with pseudotop^ do begin ndepth:=getnumber; if kind = expression then begin storeregisters(nil); evaltoresult(pseudotop,skiptrue); end else begin if kind <> reg then load(pseudotop); regnumber := regno; storeregisters(pseudotop); reservecode(2); makecode(se,regnumber,1); makerelcode(jl,0); end; end; returnpseudo(pseudotop); end; procedure convertconstant(newtyp:symbolptr); var localsymb : symbolptr; string : stringptr; l, j : integer; begin with pseudotop^ do case newtyp^.typkind of ereal:if (kind=shortsignedcst) or (kind=wordcst) then begin constptr:=makerealconst(constant); kind:=longcst; end else newtop(erightconv,newtyp,pseudotop,nil); estring, earray:begin if kind = shortsignedcst then begin new(localsymb); with localsymb^ do begin key:=econst; consttype:=newtyp; startchain:=0; constindex:=0; constkind:=stringconst; stringval:=newstring; with stringval^ do begin strÆ1Å:=chr(pseudotop^.constant); length:=1; end; end; kind:=longcst; constptr:=localsymb; end; if kind = longcst then begin (* let constanttype be the newtype in order to assure correct reservation of room for the constant *) constptr^.consttype := newtyp; with constptr^.stringval^ do begin if newtyp^.typkind = estring then l:=newtyp^.length else l:=newtyp^.indextyp^.lastconst; if l<=stringmax then begin for j:=length+1 to l do strÆjÅ:=' '; length:=l; end else error(313); end; end else error(313); end; esubrange, eascii:if kind = longcst then begin string:=constptr^.stringval; kind:=shortsignedcst; constant:=ord(string^.strÆ1Å); returnstring(string); end else error(313); end; pseudotop^.typ:=newtyp; end; (* convertconstant *) procedure callstandard; forward; procedure blockbegin; var alfatointeger : record case boolean of true: (alf : alfa); false: (i1,i2,i3,i4 : integer) end; labeldecl : boolean; l : integer; s, filename : symbolptr; pseudo : pseudoptr; vallist : valueptr; begin currentproc:=getsymbptr; with currentproc^ do begin declarationlist^.firstlineofproc := currentline; fstfreetmp:=starttmp; nooffreetmp:=availtmp; if not lineoutput then begin (* start output of line number table for this procedure *) (* remember start of line table for this procedure *) declarationlist^.startline:=linetablelgt; lineoutput:=true; linetablelgt:=linetablelgt+6; (* startline number (1) name (4) first entry (1) *) linetable^:=currentline; put(linetable); with alfatointeger do begin (* now the procedure name is inserted *) alf := routinename^; linetable^ := i1; put(linetable); linetable^ := i2; put(linetable); linetable^ := i3; put(linetable); linetable^ := i4; put(linetable); end; linetable^:=lastindex * oneword; put(linetable); end; display:=paramlist^.displayoffset; maxstack:=declarationlist^.maxstackoffset; makeindexcode(rs,stackaddr,stackaddr,level+display); if namekind <> eprogram then copyshort(level,display,false); (* initialize variables from value-part *) if paramlist^.lengthofvalue > 0 then if paramlist^.initlist = nil then with paramlist^ do begin (* read the values from disc *) makeindexcode(al,0,stackaddr,display+level+oneword); makecode(al,1,lengthofvalue); if level > 0 then begin makeindexcode(rl,3,stackaddr,display); l:=3; end else l:=stackaddr; makeindirectcode(jl,3,l,valueoffset); makewordcode(valuesegment); end else with code^ do begin vallist:=paramlist^.initlist; l:=paramlist^.lengthofvalue; makerelcode(jl,l+oneword); l:=l div oneword; l:=l+lastindex; lastindex:=l; repeat cÆlÅ:=vallist^.initval; vallist:=vallist^.next; l:=l-1; until vallist = nil; vallist:=paramlist^.initlist; l:=-oneword; repeat with vallist^ do if next <> nil then begin if next^.ordinal = ordinal -oneword then begin makewrelcode(dl,0,l); makeindexcode(ds,0,stackaddr,ordinal); l:=l-4*oneword; returnvalue(vallist); end else begin makewrelcode(rl,0,l); makeindexcode(rs,0,stackaddr,ordinal); l:=l-3*oneword; end; end else begin makewrelcode(rl,0,l); makeindexcode(rs,0,stackaddr,ordinal); l:=l-3*oneword; end; returnvalue(vallist); until vallist = nil; end; end; (* initialize labels, first label if present is found in indexÆlabnumberÅ *) labeldecl := indexÆlabnumberÅ <> nil; while labeldecl do begin with indexÆlabnumberÅ^ do if key = elabel then begin makewrelcode(rl,0,2*oneword); makerelcode(jl,2*oneword); makewordcode(0); labeladdroffset := lastindex; makeindexcode(rs,0,stackaddr,labelordinal); end else labeldecl := (key = ename) and (namekind = efile); labnumber := labnumber + 1; if indexÆlabnumberÅ = nil then labeldecl := false; end; if currentproc^.namekind = eprogram then begin makecode(rl,1,current_process); makeindexcode(rl,1,1,process_start); makeindexcode(al,3,1,h21); makeindexcode(rs,3,stackaddr,outputordinal); if inputordinal > minsignedhalfword then begin makeindexcode(al,1,1,h20); makeindexcode(rs,1,stackaddr,inputordinal); if inputfilename^.extname <> nil then if inputfilename^.extname^.length > 0 then begin (* open on input *) new(filename); with filename^ do begin key:=econst; consttype:=alfatype; constkind:=stringconst; stringval:=inputfilename^.extname; end; makewrelcode(al,0,0); makeconst(0,filename); callstandard; makewordcode(stdroutineÆps_openÅ); makewordcode(1); makeindexcode(rl,1,stackaddr,inputordinal); callstandard; makewordcode(stdroutineÆps_resetÅ); end; end; if outputfilename^.extname^.length > 0 then begin (* open on output *) new(filename); with filename^ do begin key:=econst; consttype:=alfatype; constkind:=stringconst; stringval:=outputfilename^.extname; end; makeindexcode(rl,1,stackaddr,outputordinal); makewrelcode(al,0,0); makeconst(0,filename); callstandard; makewordcode(stdroutineÆps_openÅ); makewordcode(1); makeindexcode(rl,1,stackaddr,outputordinal); callstandard; makewordcode(stdroutineÆps_rewriteÅ); end; end; s:=currentproc^.paramlist^.copyvalparam; while s <> nil do begin (* copy value parameters *) makeindexcode(rl,1,stackaddr,s^.valparordinal); l:=s^.vartypedescr^.size; if s^.varaddr.simpleaddr then begin if (l <= maxshortcopy) and (s^.varaddr.ordinal + l < maxordinal) then copyshort(l,s^.varaddr.ordinal,false) else begin pseudo := newpseudo; (* temporary node *) pseudo^.kind:=variable; pseudo^.addr:=s^.varaddr; copylong(l,pseudo); returnpseudo(pseudo); end; end; s:=s^.next; end; s:=currentproc^.paramlist^.filelist; if s <> nil then begin pseudo:=newpseudo; while s <> nil do begin (* initialize local files *) pseudo^.kind:=variable; pseudo^.addr:=s^.varaddr; loadaddress(1,pseudo); new(filename); with filename^ do begin key:=econst; consttype:=alfatype; constkind:=stringconst; end; if s^.extname <> nil then begin (* copy filename *) filename^.stringval:=s^.extname; with filename^.stringval^ do if length = 0 then begin length:=alfalength; alfastr:=' '; end; end else begin filename^.stringval:=newstring; with filename^.stringval^ do begin length:=alfalength; alfastr:=' '; end; end; makewrelcode(al,0,0); makeconst(0,filename); (* call initfile *) callstandard; makewordcode(stdroutineÆps_openÅ); if getbasetype(s^.vartypedescr^.elementtyp) = eascii then l:=1 else l:=0; makewordcode(l); s:=s^.next; end; returnpseudo(pseudo); end; end; (* blockbegin *) procedure blockend; var s, returnlast : symbolptr; pseudo : pseudoptr; i, id : integer; begin storeregisters(nil); s:=currentproc^.paramlist^.filelist; if s <> nil then begin (* close or return local files *) pseudo:=newpseudo; while s <> nil do begin pseudo^.typ:=s^.vartypedescr^.elementtyp; pseudo^.kind:=variable; pseudo^.addr:=s^.varaddr; loadaddress(1,pseudo); callstandard; i:=stdroutineÆps_closeÅ; if s^.extname = nil then i:=i+2; (* remove entry *) makewordcode(i); s:=s^.next; end; returnpseudo(pseudo); end; if currentproc^.namekind = eprogram then begin (* program end, call runtime error('endprogram') *) makecode(al,1,0); makeindirectcode(jl,3,stackaddr,erroroffset); end else begin makeindexcode(rl,3,stackaddr,display); makeindirectcode(jl,0,3,returnoffset); end; level:=level-oneword; if lineoutput then begin lineoutput:=false; linetablelgt:=linetablelgt+1; linetable^:=lastindex * oneword; put(linetable); end; with currentproc^.declarationlist^ do begin discaddr:=emitcode; codelength:=lastindex*oneword; end; (* return local symbols *) id:=lastnodeident; returnlast:=currentproc^.declarationlist; s:=indexÆidÅ; while s <> returnlast do begin if s <> nil then if ((s^.key <> econst) and not ((s^.key = enamelist) and (s^.listkind = edeclaration)) and not ((s^.key = etype) and (s^.typkind = estring)) and not ((s^.key = ename) and (s^.namekind in Æeprogram,eproc,efuncÅ))) or ((s^.key = econst) and (s^.constkind = stringconst)) then begin (* return symbol to free list *) s^.next:=freesymbol; freesymbol:=s; indexÆidÅ:=nil; end; id:=id-1; s:=indexÆidÅ; end; end; (* blockend *) procedure checkrange(checkpseudo:pseudoptr; first,last:integer); begin with checkpseudo^ do if (kind=shortsignedcst) or (kind=wordcst) then begin if (constant<first) or (constant>last) then error(312); end else if registerÆregnoÅ.kind in Æshortsignedcst,wordcstÅ then with registerÆregnoÅ do begin if (constant < first) or (constant > last) then error(312); end else if (typ^.typkind <> esubrange) or alwayscheck or ((typ^.firstconst < first) or (typ^.lastconst > last)) then begin reservecode(7); if (last >= minsignedhalfword) and (last <= maxsignedhalfword) then makecode(sh,regno,last) else begin makeallcode(sh,regno,true,true,0,0); makeconst(last,nil); end; if first < -maxint then makerelcode(jl,2*oneword) (* skip allways *) else begin first:=first-1; if (first >= minsignedhalfword) and (first <= maxsignedhalfword) then makecode(sh,regno,first) else begin makeallcode(sh,regno,true,true,0,0); makeconst(first,nil); end; end; makecode(d2, regno, -2); (* force alarm *) end; end; procedure callroutine; var dispreg : integer; begin if level > 0 then begin dispreg := 3; makeindexcode(rl,dispreg,1,0); end else dispreg := stackaddr; reservecode(2); makeindirectcode(jl,3,dispreg,calloffset); makewordcode(maxstack+maxordinal+paramoffset+oneword+1); if paramoffset > maxparamoffset then error(314); end; procedure loadformal(var routineaddr:addrnode); begin with routineaddr do if blocknumber = level then makeindexcode(dl,1,stackaddr,ordinal+oneword) else begin makeindexcode(rl,1,stackaddr,display+blocknumber); makeindexcode(dl,1,1,ordinal); end; end; procedure actualparam(formalparam:symbolptr; actual:pseudoptr); var w : regrange; paramsize : integer; store : opcodes; paramkind : intmtwords; begin if formalparam = nil then paramkind:=evalparam (* call a formal procedure *) else paramkind:=formalparam^.namekind; store:=rs; case paramkind of evalparam:begin if actual^.kind = expression then evaltoresult(actual,noskip); paramsize:=actual^.typ^.size; if paramsize <= 4 then begin if actual^.kind <> reg then load(actual); w:=actual^.regno; if check and (formalparam <> nil) then with formalparam^.vartypedescr^ do if typkind = esubrange then checkrange(actual,firstconst,lastconst); registerÆwÅ.user:=nil; if paramsize=2*oneword then begin store:=ds; w:=(w+1) mod noofreg; registerÆwÅ.user:=nil; end; end else begin loadaddress(1,actual); paramsize:=oneword; w:=1; end; end; evarparam: begin if actual^.addr.packk <> unpack then error( 323 ); (* packed fields not allowed as VAR-parameters *) loadaddress(1,actual); paramsize:=oneword; w:=1; end; effunc, efproc:with actual^.symb^ do begin storeregisters(nil); if (namekind=efproc) or (namekind =effunc) then loadformal(varaddr) else begin makeindexcode(al,1,stackaddr,display); makewrelcode(rl,0,0); makeconst(routinedescr,nil); end; store:=ds; paramsize:=2*oneword; w:=1; end; end; paramoffset:=paramoffset+paramsize; if maxstack+paramoffset <= maxsignedhalfword then makeindexcode(store,w,stackaddr,maxstack+paramoffset) else begin reservecode(3); makeallcode(am,0,true,true,0,0); makeconst(maxstack+paramoffset,nil); makeindexcode(store,w,stackaddr,0); end; end; (* actualparam *) procedure callstandard; var w : regrange; begin if level > 0 then begin makeindexcode(rl,3,stackaddr,display); w:=3; end else w:=stackaddr; reservecode(4); makeindirectcode(jl,3,w,stdcalloffset); forgetregisters; end; procedure standardprocedure; var pseudo, ps, psnext, param, filparam : pseudoptr; tagvalue, length, relative1, relative2, argument, argument2, argument3, routinenumber : integer; second, found : boolean; node, nodetype, s1, s2 : symbolptr; kind : intmtwords; standardname : standards; procedure readwritebinary(kind:integer; var par : pseudoptr); var param : pseudoptr; begin param:=par; filparam^.typ:=integertype; par:=nil; if filparam^.kind = reg then storetmp(filparam); repeat if param^.kind = expression then begin evaltoresult(param,noskip); storetmp(param); end; loadaddress(0,param); if second or (filparam^.kind <> reg) then makeindexcode(rl,1,stackaddr,filparam^.addr.ordinal); callstandard; makewordcode(kind); makewordcode(param^.typ^.size); returnpseudo(param); second:=true; until param = nil; end; function defaultfile(fileordinal : integer) : pseudoptr; (* make a pseudonode describing one of the standardfiles INPUT or OUTPUT *) var fil : pseudoptr; begin fil:=newpseudo; with fil^ do begin typ:=asciitype; kind:=variable; with addr do begin index:=nil; packk:=unpack; simpleaddr:=true; blocknumber:=0; ordinal:=fileordinal; end; end; loadregister(1,fil); defaultfile:=fil; end; (* defaultfile *) procedure pack_unpack(param_a,param_i,param_z:pseudoptr; prockind:integer); var length_a, length_z : integer; begin param:=nil; if getbasetype(param_a^.typ^.valtyp) <> eascii then error(408); if param_i^.kind = expression then evaltoresult(param_i,noskip) else if param_i^.kind <> reg then load(param_i); with param_z^.typ^.indextyp^ do if typkind <> esubrange then length_z:=lastscalar+1 else length_z:=lastconst-firstconst+1; with param_a^.typ^.indextyp^ do if typkind <> esubrange then length_a:=lastscalar+1 else begin length_a:=lastconst-firstconst+1; if check then checkrange(param_i,firstconst,lastconst-length_z+1); makewrelcode(ws,param_i^.regno,0); makeconst(firstconst,nil); end; if length_a < length_z then error(320); makecode(as,param_i^.regno,1); (* not correct if oneword <> 2 ! *) makeregister(param_i,param_i^.regno); loadaddress(0,param_a); param_a^.typ:=param_a^.typ^.valtyp; makeregister(param_a,0); operation(wa,param_a,param_a,param_i); loadaddress(1,param_z); if param_a^.kind <> reg then loadregister(0,param_a); callstandard; makewordcode(prockind); makewordcode(length_z); returnpseudo(param_a); returnpseudo(param_i); returnpseudo(param_z); end; (* pack_unpack *) begin (* standardprocedure *) param:=nil; pseudo:=pseudotop; with neststackÆndepthÅ do begin while pseudo <> oldtop do begin (* reverse the list of parameters *) psnext:=pseudo^.next; pseudo^.next:=param; param:=pseudo; pseudo:=psnext; end; standardname := procfunc^.stnd_name; routinenumber:=stdroutineÆstandardnameÅ; case standardname of ps_put, ps_get, ps_reset, ps_rewrite, ps_close: begin storeregisters(nil); param^.typ := param^.typ^.elementtyp; loadaddress(1,param); if standardname = ps_reset then begin (* make a call of reset and a call of get *) callstandard; (*register 1 must remain unchanged !!! *) makewordcode(routinenumber); standardname := ps_get; routinenumber := stdroutineÆstandardnameÅ; end; (* reset *) if ((standardname=ps_put)or(standardname=ps_get)) and (getbasetype(param^.typ) <> eascii) then (* binary io *) begin makeindexcode(rl,0,1,h4+4); (* load bufferaddress *) if standardname = ps_put then routinenumber := binaryput else routinenumber := binaryget; length := param^.typ^.size (* the buffer length *) end else length := 10; (* the relative entry of the lib-segment for put *) callstandard; makewordcode(routinenumber); if (standardname=ps_put) or (routinenumber=binaryget) then makewordcode(length); end; (* put, get, reset, rewrite, close *) ps_new:begin storeregisters(nil); loadaddress(1,param); nodetype:=param^.typ^.pointertotyp; returnpseudo(param); if param = nil then length:=nodetype^.size else begin node:=nodetype^.varlist; repeat (* search through the list of tag values *) if (param^.kind <> shortsignedcst) and (param^.kind <> wordcst) then begin error(316); tagvalue:=1; end else tagvalue:=param^.constant; found:=false; s1:=node^.taglist; while (s1 <> nil) and (not found) do begin length:=s1^.tagsize; s2:=s1^.labellist^.nextreclab; while s2 <> nil do begin if tagvalue = s2^.reclabvalue then found:=true; s2:=s2^.nextreclab; end; s1:=s1^.nexttag; end; if not found then error(317); returnpseudo(param); node:=node^.varlst; until (node = nil) or (param = nil); end; if param <> nil then error(318); if length < maxsignedhalfword then makecode(al,0,length) else begin makewrelcode(rl,0,0); makeconst(length,nil); end; makeindexcode(rl,3,stackaddr,display); makeindirectcode(jl,3,3,routinenumber); forgetregisters; end; ps_readln, ps_read:begin storeregisters(nil); if param = nil then filparam:=defaultfile(inputordinal) else if param^.typ^.typkind = efile then begin param^.typ:=param^.typ^.elementtyp; loadaddress(1,param); filparam:=param; param:=filparam^.next; end else filparam:=defaultfile(inputordinal); makeregister(filparam,1); second:=false; if getbasetype(filparam^.typ) = eascii then begin if param = nil then begin (* readln *) callstandard; makewordcode(routinenumber+10); end else repeat if param^.addr.packk <> unpack then error( 323 ); (* packed fields must not be used as VAR-parameters *) loadaddress(0,param); kind:=getbasetype(param^.typ); argument:=readkindÆkindÅ; if kind = eascii then with param^.typ^ do begin if typkind = esubrange then if (firstconst >= firstchar) and (lastconst <= lastchar) then argument:=4; (* char *) end else if kind = escalar then error(407); if filparam^.kind <> reg then makeindexcode(rl,1,stackaddr,filparam^.addr.ordinal); returnpseudo(param); if (param <> nil) and (filparam^.kind <> reg) then storeregisters(nil); callstandard; if param = nil then makewordcode(routinenumber+argument) else begin makewordcode(stdroutineÆps_readÅ+argument); loadregister(1,filparam); end; until param = nil; end else readwritebinary(7*4096,param); returnpseudo(filparam); end; ps_writeln, ps_write:begin storeregisters(nil); if param = nil then filparam:=defaultfile(outputordinal) else if param^.typ^.typkind = efile then begin param^.typ:=param^.typ^.elementtyp; loadaddress(1,param); filparam:=param; param:=filparam^.next; end else filparam:=defaultfile(outputordinal); makeregister(filparam,1); second:=false; if param = nil then begin (* writeln *) callstandard; makewordcode(routinenumber+2); makewordcode(12); end else begin if param^.next <> nil then with param^.next^ do if (next <> nil) or (kind <> expression) or (operator <> eformat) then storetmp(filparam); if getbasetype(filparam^.typ) <> eascii then readwritebinary(7*4096+1,param) else repeat argument3:=-1; relative1:=0; relative2:=0; if param^.next = nil then argument:=routinenumber else begin argument:=stdroutineÆps_writeÅ; with param^.next^ do if (kind = expression) and (operator = eformat) then begin if param^.next^.next = nil then argument:=routinenumber; if leftoperand^.kind = expression then evaltoresult(leftoperand,noskip) else if leftoperand^.kind <> reg then load(leftoperand); reservecode(50); (* call of write must be within range*) makewrelcode(hs,leftoperand^.regno,0); relative2:=lastindex; ps:=leftoperand; returnpseudo(ps); if rightoperand <> nil then begin if rightoperand^.kind = expression then evaltoresult(rightoperand,noskip) else if rightoperand^.kind <> reg then load(rightoperand); makewrelcode(hs,rightoperand^.regno,0); relative1:=lastindex; ps:=rightoperand; returnpseudo(ps); end; end; end; if param^.kind = expression then evaltoresult(param,noskip); kind:=getbasetype(param^.typ); argument2:=writekindÆkindÅ; case kind of ereal:begin if param^.kind = reg then storetmp(param); if param^.kind = longcst then begin reservecode(4); makecode(am,0,-oneword); end; loadaddress(0,param); end; eboolean, eascii, einteger:begin argument:=argument+2; if (param^.kind <> reg) or (param^.regno <> 0) then loadregister(0,param); end; escalar: error(407); estring:begin argument:=argument+2; with param^.typ^ do begin if typkind = estring then begin argument3:=length; argument2:=argument2+argument3*(maxhalfword+1); end else if typkind = earray then begin argument3:=indextyp^.lastconst; argument2:=argument2+argument3*(maxhalfword+1); end; end; loadaddress(0,param); end; end; if second or (filparam^.kind <> reg) then makeindexcode(rl,1,stackaddr,filparam^.addr.ordinal); callstandard; makewordcode(argument); makewordcode(argument2); if (relative2 <> 0) and (lastindex-relative2 > maxsignedhalfword div oneword) then error(319) else begin if relative1 <> 0 then code^.cÆrelative1Å.displacement:=(lastindex-relative1)*oneword+1; if relative2 <> 0 then code^.cÆrelative2Å.displacement:=(lastindex-relative2)*oneword; end; if argument3 >= 0 then makewordcode(argument3); returnpseudo(param); if param <> nil then if (param^.kind = expression) and (param^.operator = eformat) then returnpseudo(param); second:=true; until param = nil; end; returnpseudo(filparam); end; ps_page:begin storeregisters(nil); loadaddress(1,param); makecode(al,0,ord(ff)); callstandard; makewordcode(routinenumber); makewordcode(writekindÆeasciiÅ); end; ps_open:begin filparam:=param; param:=filparam^.next; if param^.kind = variable then begin if param^.typ^.size <> filenamelength then error(313); end else begin pseudotop:=param; convertconstant(alfatype); end; loadaddress(0,param); param^.typ:=integertype; makeregister(param,0); loadaddress(1,filparam); if param^.kind <> reg then loadregister(0,param); callstandard; makewordcode(routinenumber); if getbasetype(filparam^.typ^.elementtyp) = eascii then length:=1 else length:=0; makewordcode(length); returnpseudo(filparam); end; ps_putrand, ps_getrand:error(406); ps_pack:pack_unpack(param,param^.next,param^.next^.next,routinenumber); ps_unpack:pack_unpack(param^.next,param^.next^.next,param,routinenumber); ps_replace, ps_date, ps_time:begin storeregisters(nil); if procfunc^.stnd_name = ps_replace then if level <> 0 then error(322); loadaddress(1,param); callstandard; makewordcode(routinenumber); end; end; returnpseudo(param); end; pseudotop:=pseudo; end; (* standardprocedure *) procedure insertaddr(chainindex, jumpindex : integer); (* insert displacement part of the jump-chain starting with chainindex, so that the jumps are to jumpindex *) var i, distance : integer; begin with code^ do repeat with cÆchainindexÅ do begin distance:=(jumpindex-chainindex)*oneword; if distance > maxsignedhalfword then begin jumpindex:=chainindex-i; distance:=(jumpindex-chainindex)*oneword; end; i:=displacement; displacement:=distance; chainindex:=chainindex+i; end; until i=0; end; procedure newshortjump; (* remember the chain of short jumps starting in lastindex *) var sjump : jumpchainptr; begin new(sjump); sjump^.jumpindex:=lastindex; sjump^.next:=shortjumps; shortjumps:=sjump; outconstlimit:=outconstlimit-1; end; function poweroftwo(c:integer):integer; (* if c is a power of 2 then the result is that power else result is -1 *) var i,j,low,high : integer; begin if c=2 then poweroftwo:=1 else begin low:=1; high:=maxbit; i:=(maxbit+1) div 2; for j:=1 to 5 do begin if bitmaskÆiÅ > c then high:=i else low:=i; i:=(low+high) div 2; end; if c-bitmaskÆlowÅ = 1 then poweroftwo:=low else poweroftwo:=-1; end; end; procedure evaltoresult; (* (ps:pseudoptr ; skipk:skipkind) FORWARD declared *) var pseudo, left, right : pseudoptr; i, j, oldparam, w, w_1 : integer; skip : opcodes; procedure inoperator; var jindex, highset : integer; begin with left^ do begin if (right^.kind = variable) then with right^.addr do if (index <> nil) or (not simpleaddr) or (blocknumber <> level) or (ordinal > maxordinal) then begin loadaddress(3,right); right^.typ:=integertype; makeregister(right,3); end; loadregister(1,left); registerÆ1Å.user:=nil; reservecode(13); highset:=maxint; with typ^ do if (typkind = einteger) or ((typkind = esubrange) and (firstconst < 0)) then makecode(sl,regno,0) else if typkind = esubrange then highset:=lastconst else if typkind = escalar then highset:=lastscalar; if highset <= maxbit then begin (* must be in first word of set *) makeindexcode(al,0,1,0); case right^.kind of longcst: begin makewrelcode(rl,1,0); with right^.constptr^.setval^ do makeconst(hlfwordsÆ1Å*4096+hlfwordsÆ2Å,nil); end; variable: begin right^.typ:=integertype; loadregister(1,right); end; reg: makeindexcode(rl,1,3,0); tmp: makeindexcode(rl,1,stackaddr,right^.addr.ordinal); end; end else begin if highset >= setsize*((maxbit+1) div oneword) then begin makecode(sl,regno,setsize*((maxbit+1) div oneword)); makerelcode(jl,0); jindex:=lastindex; end; makecode(al,0,0); makewrelcode(wd,1,0); makeconst(maxbit+1,nil); makecode(as,1,1); (* not correct if oneword <> 2 ! *) with right^ do case kind of variable:begin makeindexcode(am,0,1,0); makeindexcode(rl,1,stackaddr,addr.ordinal); end; tmp:begin makeindexcode(wa,1,stackaddr,addr.ordinal); makeindexcode(rl,1,1,0); end; longcst: begin reservecode(setsize+1); makeallcode(rl,1,true,false,1,0); makeconst(0,constptr); end; reg:begin makeindexcode(am,0,1,0); makeindexcode(rl,1,regno,0); end; end; end; forgetregisters; makeindirectcode(ls,1,0,0); reservecode(2); if skipk = skiptrue then begin makecode(sl,1,0); if highset < setsize*(maxbit+1) div oneword then jindex:=lastindex+1; makerelcode(jl,jindex-lastindex-1); end else begin makecode(sh,1,-1); if skipk = skipfalse then begin makerelcode(jl,0); if highset >= setsize*(maxbit+1) div oneword then insertaddr(jindex,lastindex+1); end else begin makecode(am,0,1); makecode(al,1,0); makeregister(ps,1); if highset >= setsize*(maxbit+1) div oneword then insertaddr(jindex,lastindex); end; end; end; end; procedure setoperation(op:opcodes); var invert : boolean; temp : signedhalfword; i, siz : integer; procedure fastsetoperation(op:opcodes; pseudo:pseudoptr; index1,index2:regrange; disp1,disp2:signedhalfword); var localtemp, i : integer; begin localtemp:=temp+oneword; reservecode(setsize+1); loadaddress(1,pseudo); storeregisters(nil); (* reserve a work set *) fstfreetmp := fstfreetmp + siz; nooffreetmp := nooffreetmp - siz; if nooffreetmp < 0 then error(314) else for i:=1 to pseudo^.typ^.size div (2*oneword) do begin makeindexcode(dl,0,index1,disp1); if invert then begin makewrelcode(lx,0,0); makeconst(-1,nil); makeindexcode(ac,3,3,1); end; makeindexcode(op,3,index2,disp2); makeindexcode(op,0,index2,disp2+oneword); makeindexcode(ds,0,stackaddr,localtemp); disp1:=disp1+2*oneword; disp2:=disp2+2*oneword; localtemp:=localtemp+2*oneword; end; end; begin (* setoperation *) invert:=false; if op = ac then begin op:=la; invert:=true; end; siz:=right^.typ^.size; temp:=fstfreetmp; (* let temp be the address of the result (work set) of the operation *) if right^.kind = tmp then temp := temp - siz; if left^.kind = tmp then temp := temp - siz; if (right^.kind <> longcst) and right^.addr.simpleaddr and (right^.addr.index = nil) and (right^.addr.blocknumber = level) and (right^.addr.ordinal+siz <= maxordinal) then fastsetoperation(op,left,stackaddr,1,right^.addr.ordinal+oneword,0) else if (left^.kind <> longcst) and left^.addr.simpleaddr and (left^.addr.index = nil) and (left^.addr.blocknumber = level) and (left^.addr.ordinal+siz <= maxordinal) then fastsetoperation(op,right,1,stackaddr,oneword,left^.addr.ordinal) else begin (* operation on one word at a time *) reservecode(setsize+1); storeregisters(nil); loadaddress(1,left); left^.typ:=integertype; makeregister(left,1); reservecode(setsize+1); loadaddress(3,right); if left^.kind <> reg then loadregister(1,left); registerÆ1Å.user:=nil; registerÆ3Å.user:=nil; (* reserve a work set *) fstfreetmp := fstfreetmp + siz; nooffreetmp:= nooffreetmp - siz; if nooffreetmp < 0 then error(314) else for i:=0 to siz div oneword -1 do begin makeindexcode(rl,0,3,i*oneword); if invert then begin makewrelcode(lx,0,0); makeconst(-1,nil); end; makeindexcode(op,0,1,i*oneword); makeindexcode(rs,0,stackaddr,temp+i*oneword); end; end; if (right^.kind=tmp) and (left^.kind=tmp) then begin (* operation on two work set operands, the result is one work set, i.e. give one set back to the pool of free temp storage *) fstfreetmp := fstfreetmp - siz; nooffreetmp := nooffreetmp + siz; end; with ps^ do begin typ:=right^.typ; kind:=tmp; with addr do begin index:=nil; packk:=unpack; simpleaddr:=true; blocknumber:=level; ordinal:=temp; end; end; left^.kind:=expression; (* to avoid reclaiming of temporaries *) right^.kind:=expression; end; procedure standardfunction(funct,param : pseudoptr); var w : regrange; std_func : standards; constant : symbolptr; skip : opcodes; storeindex :integer; nextparam, param1, param2 : pseudoptr; begin std_func:=funct^.rightoperand^.symb^.stnd_name; if param <> nil then begin param:=param^.rightoperand; if param^.kind = expression then evaltoresult(param,noskip); end; case std_func of fs_abs:begin if param^.kind <> reg then load(param); w:=param^.regno; makecode(sh,w,-1); if param^.typ^.typkind = ereal then begin funct^.typ:=realtype; makeregister(funct,w); makewrelcode(fm,(w+1) mod noofreg , 0); constant:=makerealconst(-1); makeconst(0,constant); end else begin funct^.typ:=integertype; makeregister(funct,w); if w = 0 then makeindirectcode(ac,0,0,0) else makeindexcode(ac,w,w,0); end; end; fs_sqr:begin if param^.typ^.typkind = ereal then begin funct^.typ:=realtype; if param^.kind <> reg then load(param); operation(fm,funct,param,param); end else begin funct^.typ:=integertype; if (param^.kind <> reg) or (param^.regno =3) then loadregister(1,param); operation(wm,funct,param,param); end; end; fs_arcsin, fs_sinh, fs_arctan, fs_sqrt, fs_ln, fs_exp, fs_cos, fs_sin:begin loadregister(0,param); registerÆ0Å.user:=nil; registerÆ1Å.user:=nil; storeregisters(nil); callstandard; makewordcode(stdroutineÆstd_funcÅ); makeregister(funct,0); registerÆ1Å:=registerÆ0Å; end; fs_odd:begin if param^.kind <> reg then load(param); if skipk = noskip then begin makewrelcode(la,param^.regno,0); makeconst(1,nil); makeregister(funct,param^.regno); end else begin reservecode(2); if skipk = skiptrue then makecode(so,param^.regno,1) else makecode(sz,param^.regno,1); makerelcode(jl,0); forgetregisters; end; end; fs_eoln, fs_eof:begin loadaddress(1,param); makeindexcode(bz,1,1,stdroutineÆstd_funcÅ+h4); if skipk = noskip then makeregister(funct,1) else begin if skipk = skiptrue then skip:=se else skip:=sn; makecode(skip,1,1); makerelcode(jl,0); forgetregisters; end; end; fs_round, fs_trunc:begin if param^.kind <> reg then load(param); w:=(param^.regno+1) mod noofreg; if std_func = fs_trunc then begin reservecode(12); makecode(sl, param^.regno, 0); (* test if negative *) makerelcode(jl, 12); (* if positive then jump *) makewrelcode(fm, w, 0); (* negative: change sign *) constant := makerealconst(-1); makeconst(0, constant); makewrelcode(fs,w,0); constant:=makerealconst(0.5); makeconst(0,constant); makecode(cf, w, 0 ); (* convert to integer *) if w = 0 then makeindirectcode(ac, 0 , 0, 0) (* negate the result *) else makeindexcode(ac, w, w, 0); makerelcode(jl, 6) ; (* end of negative argument *) makewrelcode(fs, w, 0); makeconst(0,constant); end; makecode(cf,w,0); makeregister(funct,w); end; fs_ord, fs_chr:begin if param^.kind <> reg then load(param); makeregister(funct,param^.regno); end; fs_succ:begin if param^.kind <> reg then load(param); w:=param^.regno; if w = 0 then makewrelcode(ba,0,1) else makeindexcode(al,w,w,1); funct^.typ:=integertype; makeregister(funct,w); end; fs_pred:begin if param^.kind <> reg then load(param); w:=param^.regno; if w = 0 then makewrelcode(bs,0,1) else makeindexcode(al,w,w,-1); funct^.typ:=integertype; makeregister(funct,w); end; fs_system, fs_monitor:begin if param^.kind <> reg then load(param); reservecode(50); makewrelcode(rs,param^.regno,0); storeindex:=lastindex; nextparam:=funct^.leftoperand^.leftoperand; param1:=nextparam^.rightoperand; param1^.typ := integertype; (* force operand to simple size *) loadaddress(0,param1); makeregister(param1,0); param2:=nextparam^.leftoperand; returnpseudo(nextparam); nextparam:=param2^.rightoperand; loadaddress(1,nextparam); if param1^.kind <> reg then loadregister(0,param1); callstandard; makewordcode(stdroutineÆstd_funcÅ); makewordcode(0); if lastindex-storeindex >= maxsignedhalfword div oneword then error(319) else code^.cÆstoreindexÅ.displacement:=(lastindex-storeindex)*oneword; makeregister(funct,1); returnpseudo(param1); returnpseudo(param2); returnpseudo(nextparam); end; fs_clock:begin storeregisters(nil); callstandard; makewordcode(stdroutineÆstd_funcÅ); makeregister(funct,0); registerÆ1Å:=registerÆ0Å; end; end; returnpseudo(param); end; (* standardfunction *) procedure longcheck(op:opcodes;left,right:pseudoptr); (* set up a loop which checks one word of the structure in each passage. When op is false jump out of the loop *) var pseudo : pseudoptr; length : integer; begin loadaddress(1,right); storeregisters(right); right^.typ := integertype; makeregister(right,1); loadaddress(3,left); if right^.kind <> reg then (*temporary*) loadregister(1,right); length:=left^.typ^.size-oneword; if (length <= maxsignedhalfword) and (length >= minsignedhalfword) then makeindexcode(al,0,1,length) else begin makecode(rl,0,2); makerelcode(wa,0); makeconst(length,nil); end; pseudo:=newpseudo; with pseudo^ do begin typ:=integertype; kind:=reg; regno:=0; sameregister:=nil; end; storetmp(pseudo); reservecode(11); makeindexcode(rl,0,3,0); makeindirectcode(op,0,1,0); makerelcode(jl,6*oneword); makeindexcode(al,3,3,oneword); makeindexcode(al,1,1,oneword); makeindirectcode(sh,1,2,pseudo^.addr.ordinal); makerelcode(jl,-6*oneword); returnpseudo(pseudo); end; (* longcheck *) procedure stringcheck(op : opcodes; left,right : pseudoptr); (* make code for strinc comparison ( =, <>, < ) *) var noofelements,checklength, jumplength, next : integer; pseudo : pseudoptr; begin with left^.typ^ do begin if typkind = estring then noofelements := length mod asciiperword (* elements to check (0..2) *) else noofelements := indextyp^.lastconst mod asciiperword; checklength := size - oneword - ((noofelements+1)div 2)* 2; (* no of halfwords to check *) end; (* with left^.typ^ do *) if noofelements = 0 then begin if checklength >= 2 then begin longcheck(se,left,right); if (op = se) or (op = sl) then begin makerelcode(jl,2*oneword); (* skip on true *) if op = sl then makeindirectcode(sl,0,1,0); end; end else begin operation(op,ps,left,right); code^.cÆlastindexÅ.indirect := true; end; end else (* at most 1 or 2 elements of the last word of the strings are significant *) begin loadaddress(1,right); storeregisters(right); right^.typ := integertype; makeregister(right,1); loadaddress(3,left); reservecode(21); if checklength >= 2 then begin if right^.kind <> reg then (* stored in a temporary *) loadregister(1,right); if op = sn then jumplength := 22 else jumplength := 20; (* no of halfwords to bypass on loop exit *) next := 0; (* tells if x1 and x3 points at next word (0) or last tested word (2) *) if checklength < maxsignedhalfword then makeindexcode(al,0,1,checklength) else begin makecode(rl,0,2); makerelcode(wa,0); makeconst(checklength,nil); end; pseudo := newpseudo; with pseudo^ do begin typ := integertype; kind := reg; regno := 0; sameregister := nil; end; storetmp(pseudo); makeindexcode(rl,0,3,0); makeindirecttcode(se,0,1,0); makerelcode(jl,jumplength); (* exit of the loop *) makeindexcode(al,3,3,oneword); makeindexcode(al,1,1,oneword); makeindirectcode(sh,1,stackaddr,pseudo^.addr.ordinal); (*last element ? *) makerelcode(jl,-6 * oneword); returnpseudo(pseudo); end else (* checklength < 2, i.e. at most one word and some elements are to be compared *) begin if op = sn then jumplength := 14 else jumplength := 12; if checklength = 0 then (* one word *) begin next := oneword; (* x1 and x3 are not adjusted *) makeindexcode(rl,0,3,0); makeindirectcode(se,0,1,0); makerelcode(jl,jumplength); end else (* just one or two elements *) next := 0; end; makeindexcode(rl,0,3,next); makecode(ls,0,-24 + 8*noofelements); (* right justify *) makeindexcode(rl,1,1,next); makecode(ls,1,-24 + 8*noofelements); if op = sl then begin (* load w1 on loop exit *) makerelcode(jl,2*oneword); makeindexcode(rl,1,1,0); end; makeindexcode(op,0,1,0); end; end; (* string check *) procedure endoftest; begin forgetregisters; if skipk = noskip then begin makeregister(ps,-1); makecode(am,0,-1); makecode(al,ps^.regno,1); end else makerelcode(jl,0); end; (* endoftest *) procedure eqnerelation(eqne:opcodes); var left, right : pseudoptr; begin left:=ps^.leftoperand; right:=ps^.rightoperand; with left^.typ^ do if (size = oneword) and ((typkind <> estring) and ((typkind<> earray) or not stringcomp)) then begin if right^.kind = shortsignedcst then begin if left^.kind <> reg then load(left); reservecode(3); makecode(eqne,left^.regno,right^.constant); end else begin if right^.kind=reg then operation(eqne,ps,right,left) else operation(eqne,ps,left,right); code^.cÆlastindexÅ.indirect:=true; end; end else if typkind = ereal then begin if right^.kind = reg then operation(fs,ps,right,left) else operation(fs,ps,left,right); reservecode(3); makecode(eqne,ps^.regno,0); end else begin (* set, record or array *) if (typkind = estring) or ((typkind = earray) and stringcomp) then stringcheck(eqne,left,right) else begin longcheck(se,left,right); if eqne=se then makerelcode(jl,2*oneword);(* to get skip on true*) end; end; endoftest; end; (* eqnerelations *) procedure ltgtrelation(left,right : pseudoptr); begin if right^.kind = shortsignedcst then begin if left^.kind <> reg then load(left); reservecode(3); makecode(sl,left^.regno,right^.constant); end else if left^.kind = shortsignedcst then begin if right^.kind <> reg then load(right); reservecode(3); makecode(sh,right^.regno,left^.constant); end else if (getbasetype(left^.typ)=estring) then stringcheck(sl,left,right) else begin if left^.typ^.typkind = ereal then begin operation(fs,ps,left,right); makecode(sl,ps^.regno,0); end else begin if right^.kind=reg then operation(sh,ps,right,left) else operation(sl,ps,left,right); code^.cÆlastindexÅ.indirect:=true; end; end; endoftest; end; (* ltgtrelations *) procedure legerelation(left,right : pseudoptr); begin if left^.typ^.size = oneword then begin if (right^.kind = shortsignedcst) and (right^.constant <> maxsignedhalfword) then begin if left^.kind <> reg then load(left); reservecode(3); makecode(sl,left^.regno,right^.constant+1); end else if (left^.kind = shortsignedcst) and (left^.constant <> minsignedhalfword) then begin if right^.kind <> reg then load(right); reservecode(3); makecode(sh,right^.regno,left^.constant-1); end else begin if right^.kind=reg then operation(sl,ps,right,left) else operation(sh,ps,left,right); code^.cÆlastindexÅ.indirect:=true; makerelcode(jl,4); end; end else if left^.typ^.typkind = ereal then begin operation(fs,ps,right,left); reservecode(3); makeallcode(sz,ps^.regno,true,true,0,0); makeconst(-maxint-1,nil); end else if left^.typ^.typkind = eset then begin longcheck(so,right,left); if skipk=skiptrue then makerelcode(jl,2*oneword); end else begin longcheck(se,left,right); makerelcode(jl,3*oneword); makeindirectcode(sl,0,1,0); end; endoftest; end; (* legerelations *) procedure boolexp(pseudo:pseudoptr; skip:skipkind); begin if pseudo^.kind = expression then evaltoresult(pseudo,skip) else begin if pseudo^.kind <> reg then load(pseudo); reservecode(3); makecode(se,pseudo^.regno,ord(skip)); makerelcode(jl,0); forgetregisters; end; end; begin (* evaltoresult *) left:=ps^.leftoperand; right:=ps^.rightoperand; case ps^.operator of eor: begin boolexp(left,skipfalse); newshortjump; with shortjumps^ do if skipk = noskip then begin boolexp(right,skiptrue); insertaddr(lastindex,lastindex); lastindex:=lastindex-1; makeregister(ps,-1); makecode(am,0,-1); makecode(al,ps^.regno,1); insertaddr(jumpindex,lastindex); end else begin boolexp(right,skipk); if skipk = skiptrue then insertaddr(jumpindex,lastindex+1) else with code^ do begin (*insert a link into the chain of jumps *) i := lastindex; j := cÆiÅ.displacement; while j <> 0 do begin i := i + j; j := cÆiÅ.displacement; end; cÆiÅ.displacement := jumpindex - i; end; (* with .. *) end; shortjumps:=shortjumps^.next; end; eand: begin boolexp(left,skiptrue); newshortjump; with shortjumps^ do if skipk = noskip then begin boolexp(right,skiptrue); insertaddr(lastindex,lastindex); lastindex:=lastindex-1; makeregister(ps,-1); makecode(am,0,-1); insertaddr(jumpindex,lastindex); makecode(al,ps^.regno,1); end else begin boolexp(right,skipk); if skipk = skipfalse then insertaddr(jumpindex,lastindex+1) else with code^ do begin (*insert a link into the chain of jumps *) i := lastindex; j := cÆiÅ.displacement; while j <> 0 do begin i := i + j; j := cÆiÅ.displacement; end; cÆiÅ.displacement := jumpindex - i; end; (* with .. *) end; shortjumps:=shortjumps^.next; end; enot: begin if skipk=noskip then begin if left^.kind = expression then begin evaltoresult(left,skipfalse); insertaddr(lastindex,lastindex); lastindex:=lastindex-1; makeregister(ps,-1); makecode(am,0,-1); makecode(al,ps^.regno,1); end else begin makeregister(ps,-1); makecode(al,ps^.regno,1); operation(lx,ps,ps,left); (*?????????????????????? *) end; end else begin if skipk=skiptrue then skipk:=skipfalse else skipk:=skiptrue; boolexp(left,skipk); end; end; eeq, ene: if left^.typ^.typkind=eboolean then begin if left^.kind=expression then evaltoresult(left,noskip); if right^.kind=expression then begin storetmp(left); evaltoresult(right,noskip); end; end else begin if left^.kind=expression then evaltoresult(left,skipk); if right^.kind=expression then evaltoresult(right,skipk); end; erightconv, eminus: if left^.kind=expression then evaltoresult(left,skipk); eendcall:; (* do nothing *) eset: begin if left^.kind =longcst then begin (* copy constant part of set to temporary *) storeregisters(nil); reservecode(setsize+2); loadaddress(1,left); copyshort(left^.typ^.size,fstfreetmp,false); with left^ do begin kind:=tmp; with addr do begin index:=nil; packk:=unpack; simpleaddr:=true; blocknumber:=level; ordinal:=fstfreetmp; end; end; fstfreetmp:=fstfreetmp+left^.typ^.size; nooffreetmp:=nooffreetmp-left^.typ^.size; if nooffreetmp < 0 then error(311); end else evaltoresult(left,noskip); end; end (* CASE ps^.operator OF *) otherwise begin if right^.kind=expression then evaltoresult(right,skipk); if left^.kind=expression then evaltoresult(left,skipk); end; (* backtrack and make code *) if skipk=skipfalse then case ps^.operator of eeq:begin ps^.operator:=ene; skipk:=skiptrue; end; ene:begin ps^.operator:=eeq; skipk:=skiptrue; end; elt:begin ps^.operator:=ege; skipk:=skiptrue; end; egt:begin ps^.operator:=ele; skipk:=skiptrue; end; ege: if left^.typ^.typkind <> eset then begin ps^.operator:=elt; skipk:=skiptrue; end; ele: if left^.typ^.typkind <> eset then begin ps^.operator:=egt; skipk:=skiptrue; end; end (* CASE ps^.operator OF *) otherwise ; case ps^.operator of eor, eand, enot:; eeq: eqnerelation(se); ene: if (skipk = noskip) and (left^.typ^.typkind = eboolean) then begin if right^.kind = reg then operation(lx,ps,right,left) else operation(lx,ps,left,right) end else eqnerelation(sn); elt: ltgtrelations(left,right); egt: ltgtrelations(right,left); ele: legerelations(left,right); ege: legerelations(right,left); emult: if (right^.kind=shortsignedcst) or (right^.kind=wordcst) then begin i:=poweroftwo(right^.constant); if i>0 then begin if left^.kind <> reg then load(left); makecode(as,left^.regno,i); makeregister(ps,left^.regno); end else operation(wm,ps,left,right); end else if ps^.typ^.typkind <> ereal then begin if right^.kind=reg then operation(wm,ps,right,left) else operation(wm,ps,left,right); end else begin if right^.kind=reg then operation(fm,ps,right,left) else operation(fm,ps,left,right); end; eadd: if right^.kind = shortsignedcst then begin if left^.kind <> reg then load(left); if left^.regno = 0 then begin makewrelcode(wa,0,0); makeconst(right^.constant,nil); end else makeindexcode(al,left^.regno,left^.regno,right^.constant); makeregister(ps,left^.regno); end else if ps^.typ^.typkind=ereal then begin if right^.kind=reg then operation(fa,ps,right,left) else operation(fa,ps,left,right); end else if right^.kind=reg then operation(wa,ps,right,left) else operation(wa,ps,left,right); edif: if right^.kind=shortsignedcst then begin if left^.kind <> reg then load(left); if left^.regno = 0 then begin makewrelcode(ws,0,0); makeconst(right^.constant,nil); end else makeindexcode(al,left^.regno,left^.regno,-right^.constant); makeregister(ps,left^.regno); end else if ps^.typ^.typkind=ereal then operation(fs,ps,left,right) else operation(ws,ps,left,right); erealdiv: operation(fd,ps,left,right); eintdiv: begin if (right^.kind = shortsignedcst) or (right^.kind = wordcst) then i:=poweroftwo(right^.constant) else i := 0; if (i > 0) and (left^.typ^.typkind = esubrange) and (left^.typ^.firstconst >= 0) then (* only shift if the argument is positive *) begin if left^.kind <> reg then load(left); makecode(as,left^.regno,-i); makeregister(ps,left^.regno); end else begin operation(wd,ps,left,right); with registerÆ(ps^.regno+maxreg) mod noofregÅ do begin user:=nil; valid:=false; end; end; end; emod:begin operation(wd,ps,left,right); with registerÆps^.regnoÅ do begin user:=nil; valid:=false; end; ps^.regno:=(ps^.regno+maxreg) mod noofreg; end; eminus:begin if ps^.typ^.typkind =ereal then begin right:=newpseudo; with right^ do begin typ:=realtype; kind:=longcst; constptr:=makerealconst(0.0); end; operation(fs,ps,right,left); end else begin if (left^.kind=reg) and (left^.regno <> 0) then begin makeindexcode(ac,left^.regno,left^.regno,0); makeregister(ps,left^.regno); end else begin makeregister(ps,-1); operation(ac,ps,ps,left); code^.cÆlastindexÅ.indirect:=true; end; end; end; erightconv:if ps^.typ^.typkind = ereal then begin if left^.kind = reg then begin w:=left^.regno; if w = maxreg then begin loadregister(1,left); w:=1; end; end else begin loadregister(1,left); w:=1; end; w_1:=(w+maxreg) mod noofreg; with registerÆw_1Å do if (user <> nil) or valid then registerstore(w_1,w); makecode(ci,w,0); makeregister(ps,w_1); registerÆwÅ:=registerÆw_1Å; end else (* ? *); eendcall:with right^.symb^ do if (namekind = efunc) and standard then standardfunction(ps,left) else begin oldparam:=paramoffset; paramoffset:=paramoffset+blockmark; while left <> nil do begin actualparam(left^.typ,left^.rightoperand); pseudo:=left^.rightoperand; returnpseudo(pseudo); pseudo:=left; left:=left^.leftoperand; returnpseudo(pseudo) end; storeregisters(nil); paramoffset:=oldparam; if namekind = efunc then begin makeindexcode(al,1,stackaddr,display); makecode(al,0,routinedescr); callroutine; end else begin loadformal(varaddr); callroutine; end; oldparam:=oldparam+maxstack+oneword; makeregister(ps,0); if oldparam >= maxsignedhalfword then begin reservecode(3); makeallcode(am,0,true,true,0,0); makeconst(oldparam,nil); oldparam:=0; end; if ps^.typ^.typkind=ereal then begin makeindexcode(dl,1,stackaddr,oldparam+oneword); registerÆ1Å:=registerÆ0Å; end else begin makeindexcode(rl,0,stackaddr,oldparam); if (getbasetype(ps^.typ) = eboolean) and (skipk <> noskip) then begin if skipk = skiptrue then skip:=se else skip:=sn; makecode(skip,0,1); makerelcode(jl,0); forgetregisters; end; end; end; eset:begin if right^.operator = eset then begin pseudo:=right^.leftoperand; if pseudo^.kind = expression then evaltoresult(pseudo,noskip); loadregister(1,pseudo); reservecode(15); with pseudo^,typ^ do if (typkind = einteger) or ((typkind = esubrange) and (firstconst < 0)) then makecode(sl,regno,0); makecode(sl,pseudo^.regno,setsize * ((maxbit+1) div oneword)); makerelcode(jl,11*oneword); returnpseudo(pseudo); makecode(al,0,0); makewrelcode(wd,1,0); makeconst(maxbit+1,nil); makecode(as,1,1); makeindirectcode(ac,3,0,0); makewrelcode(rl,0,0); makeconst(minint,nil); makeindexcode(ls,0,3,0); makeindexcode(am,0,1,0); makeindexcode(lo,0,stackaddr,left^.addr.ordinal); makeindexcode(am,0,1,0); makeindexcode(rs,0,stackaddr,left^.addr.ordinal); end; ps^:=left^; left^.kind:=variable; end; ein:inoperator; esetinter: setoperation(la); esetunion: setoperation(lo); esetdif: setoperation(ac); end; (* CASE ps^.operator OF *) returnpseudo(left); returnpseudo(right); end; (* evaltoresult *) procedure endcasecode; var w, i, low, loww, startjump, otherwoffset, firstfreeindex : integer; lab, lab1 : caselabptr; procedure jumpforward(length,fromindex:integer); begin length:=(length+2)*oneword; with code^ do if length < maxsignedhalfword then cÆfromindex-2Å.displacement:=length else if length < maxhalfword then begin cÆfromindex-2Å.opcode:=am; cÆfromindex-1Å.displacement:=length-maxsignedhalfword; end else begin with cÆfromindex-2Å do begin opcode:=rl; w:=3; displacement:=2*oneword; end; with cÆfromindex-1Å do begin index:=3; relative:=true; end; cÆfromindexÅ.constval:=length-oneword; end; end; (* jumpforward *) begin (* endcasecode *) w:=pseudotop^.regno; with neststackÆgetnumberÅ do begin startjump:=lastindex; if (lowlabel = maxint) and (highlabel = -maxint) then (* empty case statement list, force otherwise action *) lowlabel := highlabel; if otherw or check then begin reservecode(5); (* reserve room for 3 instructions and possibly 2 constants *) if abs( highlabel) > maxsignedhalfword then begin makeallcode( sh, w, reladdr, indirectmode, 0, 0); makeconst( highlabel, nil ); end else makecode(sh,w,highlabel); if abs( lowlabel ) > maxsignedhalfword then begin makeallcode( sh, w, reladdr, indirectmode, 0, 0); makeconst( lowlabel - 1, nil ); makewrelcode( rl, w, 0); makeconst( lowlabel - 1, nil ); end else begin makecode(sh,w,lowlabel-1); makecode(al,w,lowlabel-1); end; end; if highlabel-lowlabel > maxcode-6 then error(310) else begin reservecode(highlabel-lowlabel+6); makecode(as,w,1); loww:=(4-lowlabel)*oneword; low:=loww; if (low < minsignedhalfword) or (low > maxsignedhalfword) then begin low:=0; makewrelcode(wa,w,6); end; makeallcode(rl,1,true,false,w,low); makeallcode(jl,0,true,false,1,0); makewordcode(loww); low:=lastindex; firstfreeindex:=low+highlabel-lowlabel+3; if otherw then otherwoffset:=labelchain^.codindex+1 else otherwoffset:=firstfreeindex; otherwoffset:=(otherwoffset-low+1)*oneword; for i:=low+1 to firstfreeindex-1 do makewordcode(otherwoffset); low:=low+2; lab:=labelchain; while lab <> nil do begin i:=lab^.codindex; code^.cÆlab^.labval-lowlabel+lowÅ.constval:=(i-low+4)*oneword; if i <> startindex then jumpforward(firstfreeindex-i,i); lab1:=lab; lab:=lab^.next; returncaselab(lab1); end; jumpforward(startjump-startindex+1,startindex); jumpforward(firstfreeindex-startjump,startjump); end; end; returnpseudo(pseudotop); end; (* endcasecode *) procedure indexaddress; (* VAR arr : addrnode; VAR elementlength : integer FORWARD declared *) var fixedbase, fixedrecbase, lowbound, elementsize, elementprindex, bitprelement, elementsprword, w, l : integer; left, right, oldright, oldpseudo, indexpseudo, recordbase : pseudoptr; varindexmet, packelements : boolean; begin left:=arr.index; oldpseudo:=nil; elementlength:=maxbit; (* represents no packing *) (* invert the list of indices *) while left <> nil do begin left^.next:=oldpseudo; oldpseudo:=left; left:=left^.leftoperand; end; fixedbase:=0; left:= oldpseudo; oldright:=nil; recordbase := nil; fixedrecbase := 0; varindexmet:=false; packelements:=false; elementprindex:=maxbit+1; while left <> nil do with left^ do begin right:=rightoperand; if right^.kind = expression then evaltoresult(right,noskip) else if right^.kind = variable then load(right); with typ^.indextyp^ do if typkind = esubrange then begin lowbound:=firstconst; if check then checkrange(right,lowbound,lastconst); end else lowbound:=0; with typ^.valtyp^ do begin if (typkind = earray) and (left^.next <> nil) then with indextyp^ do begin if typkind = esubrange then elementsize:=lastconst-firstconst+1 else elementsize:=lastscalar+1; elementprindex:=elementsize; end else begin elementsize:=size; packelements:=typ^.packedval; if packelements then begin bitprelement:=bitsize; elementsize:=1; elementlength:=bitprelement; elementsprword:=(maxbit+1) div bitprelement; if elementsprword > elementprindex then elementsprword:=elementprindex; end; end; end; if right^.kind = reg then begin varindexmet:=true; if oldright <> nil then begin operation(wa,right,right,oldright); with oldright^ do if kind = reg then registerÆregnoÅ.user:=nil; end; oldright:=right; end else begin (* constant index *) lowbound:=lowbound-right^.constant; if varindexmet then right:=oldright; end; if varindexmet and(elementsize > 1) then with right^ do begin (* unpacked elements *) l:=poweroftwo(elementsize); if l > 0 then with registerÆregnoÅ do begin makecode(as,regno,l); locassociated:=false; kind:=variable; lastused:=0; end else begin indexpseudo:=newpseudo; with indexpseudo^ do begin typ:=integertype; kind:=wordcst; constant:=elementsize; end; operation(wm,right,right,indexpseudo); registerÆright^.regnoÅ.lastused:=0; returnpseudo(indexpseudo); end; end; fixedbase:=(fixedbase-lowbound)*elementsize; if (typ^.valtyp^.typkind <> earray) or (next = nil) then begin (* this element is a record element or the last element of an index list *) if recordbase <> nil then begin (* add recordbase to array-relative *) operation(wa, right, right, recordbase); with recordbase^ do if kind = reg then with registerÆregnoÅ do (* forget the old recordbase *) begin user := nil; valid := false; end; end; (* if recordbase <> nil *) if varindexmet then recordbase := right; (* remember the recordbase register *) oldright := nil; (* force fresh index computing *) fixedrecbase := fixedrecbase + fixedbase; fixedbase := 0; varindexmet := false; end; (* typkind <> array or last element *) left:=next; end; fixedbase := fixedbase + fixedrecbase; indexpseudo:=arr.index; right:=indexpseudo^.rightoperand; (* return pseudo nodes, changed 79.12.18 *) returnpseudo(right); while oldpseudo^.next <> nil do begin right := oldpseudo^.rightoperand; returnpseudo(right); returnpseudo(oldpseudo); end; with indexpseudo^ do begin typ:=integertype; if not packelements then with arr do if simpleaddr then ordinal:=fixedbase+ordinal else postordinal:=postordinal+fixedbase; if recordbase<> nil then begin w := recordbase^.regno; if packelements then begin (* packed elements *) registerÆwÅ.user:=nil; storeregisters(nil); if w <> 1 then begin makecode(rl,1,w*oneword); w:=1; end; if (fixedbase < minsignedhalfword) or (fixedbase > maxsignedhalfword) then begin makewrelcode(wa,w,0); makeconst(fixedbase,nil); end else if fixedbase <> 0 then makeindexcode(al,w,w,fixedbase); makecode(bl, 0, 2); (* sign extension *) makecode(bl, 0, 0); makewrelcode(wd,w,0); makeconst(elementsprword,nil); makecode(as,w,1); if bitprelement <> 1 then begin l:=poweroftwo(bitprelement); if l>0 then makecode(as,0,l) else begin reservecode(2); makewrelcode(wm,0,0); makeconst(bitprelement,nil); end; end; end; makeregister(indexpseudo,w); end else begin (* constant index *) if packelements then with arr do begin (* packed elements *) bitstart:=bitstart+(fixedbase mod elementsprword)*bitprelement; if simpleaddr then ordinal:=(fixedbase div elementsprword)*oneword+ordinal else postordinal:=(fixedbase div elementsprword)*oneword+postordinal; end; end; end; end; procedure addvaluetolist(intval:integer; symb:symbolptr); var i, j, l, size : integer; word : opnode; val : valueptr; begin l:=(wordoffset-currentproc^.paramlist^.displayoffset-level) div oneword ; with code^ do (* use code^.c to hold values *) if symb = nil then with cÆlÅ do begin (* integer *) constval:=intval; wordoffset:=wordoffset+oneword; size:=1; l:=l+1; end else begin case symb^.constkind of realconst:begin putreal(symb^.realval,l); wordoffset:=wordoffset+realsize; size:=realsize div oneword; l:=l+size; end; setconst:begin size:=setsize div oneword; with symb^.setval^ do for i:=1 to setsize div oneword do begin word.half1:=hlfwordsÆi*oneword-1Å; word.half2:=hlfwordsÆi*onewordÅ; cÆlÅ:=word; l:=l+1; end; wordoffset:=wordoffset+setsize; end; stringconst:begin with symb^.stringval^ do begin size:=(length+(asciiperword-1)) div asciiperword; j:=0; for i:=1 to length do begin j:=j+1; word.strÆjÅ:=strÆiÅ; if j mod asciiperword = 0 then begin cÆlÅ:=word; j:=0; l:=l+1; end; end; if j <> 0 then begin for i:=j+1 to asciiperword do word.strÆiÅ:=' '; cÆlÅ:=word; l:=l+1; end; end; wordoffset:=wordoffset+size*oneword; end; end; end; if noofvalue <= maxvalue then begin (* add to valuelist *) for i:=size downto 1 do begin val:=newvalue; with val^ do begin next:=valuelist; ordinal:=wordoffset-i*oneword; initval:=code^.cÆl-iÅ; end; valuelist:=val; end; end; valueword:=0; nextbit:=0; end; (* addvaluetolist *) procedure storevalue; var valuetype, constvalue : symbolptr; string : pseudoptr; val, i : integer; begin valuetype:=getsymbptr; i:=getnumber; (* not used *) constvalue:=getsymbptr; if constvalue = nil then begin (* set *) constvalue:=pseudotop^.constptr; returnpseudo(pseudotop); end; if valuetype <> nil then with valuetype^ do begin if typkind = earray then begin (* convert strings *) string:=newpseudo; with string^ do begin next:=pseudotop; if constvalue^.constkind = stringconst then begin kind:=longcst; constptr:=constvalue; end else begin kind:=shortsignedcst; constant:=constvalue^.intval; end; end; pseudotop:=string; convertconstant(valuetype); constvalue:=pseudotop^.constptr; returnpseudo(pseudotop); end else val:=constvalue^.intval; if typkind = esubrange then if (val < firstconst) or (val > lastconst) then error(312); packedvalue:=pseudotop^.pack; if (packedtype = signedhlfword) and (val < 0) and packedvalue then val:=val+(maxhalfword+1); for i:=1 to pseudotop^.valcount do (* repeat array elements *) if (size = oneword) and (typkind <> earray) then begin if packedvalue then begin if nextbit + bitsize > maxbit+1 then begin (* new word *) valueword:=valueword*powerÆmaxbit+1-nextbitÅ; addvaluetolist(valueword,nil); end else valueword:=valueword*powerÆbitsizeÅ; valueword:=valueword+val; nextbit:=nextbit+bitsize; end else begin valueword:=val; addvaluetolist(valueword,nil); end; end else addvaluetolist(0,constvalue); if typkind = earray then returnstring(constvalue^.stringval); returnpseudo(pseudotop); end; end; (* storevalue *) procedure elementend; var size, i, j, l, val, last, first, woffset : integer; vallist : valueptr; begin with pseudotop^ do begin size:=typ^.size; if (nextbit > 0) and (typ^.bitsize > maxbit) then begin if nextbit <= maxbit then valueword:=valueword*powerÆmaxbit+1-nextbitÅ; addvaluetolist(valueword,nil); end; packedvalue:=pack; if valcount > 1 then begin (* repeat array elements *) if packedvalue then with typ^ do begin val:=valueword; if val < 0 then val:=val-minint; val:=val mod powerÆbitsizeÅ; (* ? *) for i:=2 to valcount do begin if nextbit+bitsize > maxbit+1 then begin (* new word *) valueword:=valueword*powerÆmaxbit+1-nextbitÅ; addvaluetolist(valueword,nil); end else valueword:=valueword*powerÆbitsizeÅ; valueword:=valueword+val; nextbit:=nextbit+bitsize; end end else begin size:=size div oneword; woffset:=wordoffset; l:=(woffset-currentproc^.paramlist^.displayoffset-level) div oneword; last:=l; first:=last-size; last:=last-1; with code^ do for i:=2 to valcount do begin for j:=first to last do begin cÆlÅ:=cÆjÅ; l:=l+1; if noofvalue <= maxvalue then begin vallist:=newvalue; with vallist^ do begin next:=valuelist; ordinal:=woffset; woffset:=woffset+oneword; initval:=cÆjÅ; end; valuelist:=vallist; end; end; end; wordoffset:=wordoffset+(valcount-1)*size*oneword; end; end; end; returnpseudo(pseudotop); end; (* elementend *) procedure fieldbegin; var ps : pseudoptr; field : symbolptr; begin field:=getsymbptr; if field <> nil then begin packedvalue:=field^.varaddr.packk <> unpack; if (nextbit > 0 ) and (nextbit <> field^.varaddr.bitstart) then begin valueword:=valueword*powerÆmaxbit+1-nextbitÅ; addvaluetolist(valueword,nil); end; nextbit:=field^.varaddr.bitstart; end; ps:=newpseudo; with ps^ do begin next:=pseudotop; kind:=valueinit; valcount:=1; pack:=packedvalue; end; pseudotop:=ps; end; (* fieldbegin *) begin (* pass2 *) initialize; while intermitword<>eendprogram do begin (* process one PIF statement *) case intermitword of enone:; ename: readnamedef ; econst: readconst ; elabel: readlabeldecl ; etype: readtypegeneral ; ebackref: begin s:=getsymbptr;(* not used *) currentproc:=getsymbptr; with currentproc^ do begin sortlist:=declarationlist; declarationlist:=nil; availtmp:=0; localordinal:=paramlist^.displayoffset; end; end; enamelist: readnamelist ; evarlist: begin s := getsymbptr ; with s^ do begin key := evarlist ; fixsize := namelistsize ; (* from preceding endnamelist, fix *) taglist := nil ; end ; currentvarlist := s ; end ; ecaselist: begin (*making a head of the case record label list *) currentcase := getsymbptr ; with currentcase^ do begin key:=ecaselist; nextreclab := nil ; end; end ; etagelement: begin s := getsymbptr ; with s^ do begin key := etagelement ; labellist := getsymbptr ; tagsize := namelistsize ; (*from preceding endnamelist, fix or endvarlist*) s1:=getsymbptr; currentvarlist:=s1^.oldvarlist; nexttag := currentvarlist ^.taglist ; varlst:=getsymbptr; currentvarlist^.taglist := s ; end ; end ; erecordlabel: readrecordlabel; eforward: begin currentproc^.declarationlist:=sortlist; sortlist:=nil; currentproc:=nil; end; eendvarlist: with currentvarlist^ do begin s := taglist ; namelistsize := fixsize ; while s <> nil do begin if namelistsize< s^.tagsize then namelistsize:=s^.tagsize; s:=s^.nexttag; end; (* WHILE s<>nil ... *) end ; eendnamelist: readendnamelist ; eendcaselist: (* nothing is done *); eendmodule: begin standenvir:=false; currentmodule:=nil; end; evalue: begin (* initialize the code area, the value 7654321 is used because it is an ill. pointer, an ill. index, and an ill. instruction *) for i := 1 to maxindex do code^.cÆiÅ.constval := 7654321; allocatelist; noofvalue:=0; highvalue:=minsignedhalfword; valuelist:=nil; end; eendvalue: begin if noofvalue <= maxvalue then begin (* remember the values until blockbegin *) with currentproc^.paramlist^ do begin initlist:=valuelist; lengthofvalue:=noofvalue; end; end else begin while valuelist <> nil do begin returnvalue(valuelist); end; highvalue:=highvalue-currentproc^.paramlist^.displayoffset-level; i:=(highvalue+(segmentlgt-3)) div segmentlgt; highvalue:=i*(segmentlgt div oneword); if highvalue > maxindex then begin error(405); highvalue:=maxindex; end; lastindex:=highvalue; with currentproc^.paramlist^ do begin valuesegment:=emitcode; lengthofvalue := codesegment - valuesegment; end; end; end; evaluename: begin s:=getsymbptr; wordoffset:=s^.varaddr.ordinal; nextbit:=0; valueword:=0; packedvalue:=s^.varaddr.packk <> unpack; noofvalue:=noofvalue+s^.vartypedescr^.size; if highvalue <= wordoffset then highvalue:=wordoffset+s^.vartypedescr^.size; if highvalue-currentproc^.paramlist^.displayoffset-level > maxindex*oneword then stop (405); end; evaluenaend: if nextbit <> 0 then begin valueword:=valueword*powerÆmaxbit+1-nextbitÅ; addvaluetolist(valueword,nil); end; eelementbegin: begin pseudo:=newpseudo; with pseudo^ do begin next:=pseudotop; typ:=getsymbptr; kind:=valueinit; valcount:=getnumber; pack:=packedvalue; packedvalue:=typ^.packedval; end; pseudotop:=pseudo; end; eelementend: elementend; efieldbegin: fieldbegin; efieldend: begin packedvalue:=pseudotop^.pack; returnpseudo(pseudotop); end; estorevalue: storevalue; eblockbegin: blockbegin; eblockend: blockend; enamecode: begin s:=getsymbptr; pseudo:=newpseudo; with pseudo^ do begin next:=pseudotop; with s^ do case namekind of efile, evar, evalparam:begin typ:=vartypedescr; kind:=variable; addr:=varaddr; if not addr.simpleaddr then (* namekind = file and file name is input or output *) (* take a copy of the address node *) begin address := newaddress; address^ := addr.reference^; addr.reference := address; end; (* at most one level of address nodes !!! *) end; evarparam:begin typ:=vartypedescr; kind:=variable; address := newaddress; address^:=varaddr; with addr do begin index:=nil; packk:=s^.varaddr.packk; bitstart := s^.varaddr.bitstart; (* 80.03.19 *) simpleaddr:=false; postordinal:=0; reference:=address; end end; effunc, efproc, efunc, eproc: begin (* procedure/function as parameter *) kind:=procfunc; if namekind=efunc then typ:=functype else if namekind=effunc then typ:=vartypedescr; if standard then begin (* ? *) end else symb:=s; end; end; end; pseudotop:=pseudo; end; efunction: begin s:=getsymbptr; pseudo:=newpseudo; with s^, pseudo^ do begin typ:=functype; next:=pseudotop; kind:=variable; with addr do begin index:=nil; packk:=unpack; simpleaddr:=true; blocknumber:=blocklevel+oneword; ordinal:=minparamordinal-blockmark; end; end; pseudotop:=pseudo; end; econstcode: begin s:=getsymbptr; pseudo:=newpseudo; with s^,pseudo^ do begin typ:=consttype; next:=pseudotop; if constkind = signedshortconst then begin kind:=shortsignedcst; constant:=intval; end else if constkind=wordconst then begin kind:=wordcst; constant:=intval; end else begin kind:=longcst; constptr:=s; end; end; pseudotop:=pseudo; end; efield: begin s:=getsymbptr; with pseudotop^ do begin with addr do begin if simpleaddr then ordinal:=ordinal+s^.varaddr.ordinal else postordinal:=postordinal+s^.varaddr.ordinal; packk:=s^.varaddr.packk; bitstart:=s^.varaddr.bitstart; end; typ:=s^.vartypedescr; end; end; ereference: with pseudotop^ do begin if typ^.typkind = efile then begin if addr.simpleaddr then addr.ordinal:=addr.ordinal+(h4+4) else addr.postordinal:=addr.postordinal+(h4+4); typ:=typ^.elementtyp; if getbasetype(typ) = eascii then goto 1; end else typ:=typ^.pointertotyp; address := newaddress; address^:=pseudotop^.addr; with addr do begin index:=nil; packk:=unpack; simpleaddr:=false; postordinal:=0; reference:=address; end; 1: end; eindex: begin pseudo:=pseudotop^.next; newtop(eindex,getsymbptr,pseudo^.addr.index,pseudotop); pseudo^.addr.index:=pseudotop; pseudo^.addr.packk:=pseudo^.typ^.valtyp^.packedtype; if not pseudo^.typ^.packedval then pseudo^.addr.packk:=unpack; pseudo^.typ:=pseudo^.typ^.valtyp; pseudotop:=pseudo; end; eload:; (* nothing is done *) estorefunc, estore: begin s:=pseudotop^.next^.typ; with s^, pseudotop^ do begin if kind=expression then begin if getbasetype(typ) = eboolean then storeregisters(nil); evaltoresult(pseudotop,noskip); end; if size > 4 then begin if size <= maxshortcopy then begin pseudo:=pseudotop^.next; if pseudo^.addr.simpleaddr and (pseudo^.addr.index = nil) and (pseudo^.addr.blocknumber = level) and (pseudo^.addr.ordinal+size <= maxordinal) then begin loadaddress(1,pseudotop); storeregisters(pseudotop); copyshort(size,pseudo^.addr.ordinal,false); end else if ((kind = variable) or (kind = tmp)) and addr.simpleaddr and (addr.index = nil) and (addr.blocknumber = level) and (addr.ordinal+size <= maxordinal) then begin loadaddress(1,pseudo); storeregisters(pseudo); copyshort(size,addr.ordinal,true); end else begin loadaddress(1,pseudotop); copylong(size,pseudo); end; end else begin loadaddress(1,pseudotop); copylong(size,next); end; returnpseudo(pseudotop); returnpseudo(pseudotop); end else with next^.typ^ do begin noconstcheck:=true; if kind <> reg then begin if ((kind=wordcst) or (kind = shortsignedcst)) and (typkind = esubrange) then begin checkrange(pseudotop,firstconst,lastconst); noconstcheck:=false; end; load(pseudotop); end; if check and noconstcheck and (typkind = esubrange) then checkrange(pseudotop,firstconst,lastconst); store(pseudotop^.regno,pseudotop^.next); returnpseudo(pseudotop); returnpseudo(pseudotop); end; end; end; estartset : begin for i:=1 to setsize do powerset.hlfwordsÆiÅ:=0; powersetpseudo:=newpseudo; with powersetpseudo^ do begin typ:=settype; next:=pseudotop; kind:=longcst; end; pseudotop:=powersetpseudo; end; eset: with pseudotop^ do if kind=shortsignedcst then begin if (constant<0) or (constant> (maxbit+1)*setsize div oneword -1 ) then error(305) else powerset.bitsÆconstantÅ:=1; returnpseudo(pseudotop); end else begin newtop(eset,typ,pseudotop,nil); newtop(eset,typ,pseudotop^.next,pseudotop); end; esetrange: with pseudotop^ do if (kind=shortsignedcst) and (next^.kind=shortsignedcst) then begin if (next^.constant < 0 ) or (constant > (maxbit+1)*setsize div oneword -1) then error(305) else for i:=next^.constant to constant do powerset.bitsÆiÅ:=1; returnpseudo(pseudotop); returnpseudo(pseudotop); end else begin error(315); newtop(esetrange,typ,next,pseudotop); newtop(eset,typ,pseudotop^.next,pseudotop); end; eendset: with powersetpseudo^ do begin new(s); constptr:=s; with s^ do begin key:=econst; consttype:=settype;(* ? *) startchain:=0; constindex:=0; constkind:=setconst; new(sett); sett^:=powerset; setval:=sett; end; end; erightconv: convertconstant(getsymbptr); eleftconv: begin pseudo:=pseudotop; pseudotop:=pseudotop^.next; s:=getsymbptr; convertconstant(getsymbptr); pseudo^.next:=pseudotop; pseudotop:=pseudo; end; enot: begin if pseudotop^.kind=shortsignedcst then begin pseudotop^.constant:=1-pseudotop^.constant; end else newtop(enot,booltype,pseudotop,nil); end; eand, eor: begin if intermitword=eand then i:=0 else i:=1; pseudo:=pseudotop^.next; if pseudo^.kind=shortsignedcst then begin if pseudo^.constant=i then begin pseudotop^.constant:=i; pseudotop^.kind:=shortsignedcst; end; returnpseudo(pseudo); pseudotop^.next:=pseudo; end else if pseudotop^.kind=shortsignedcst then begin if pseudotop^.constant=i then begin pseudo^.constant:=i; pseudo^.kind:=shortsignedcst; end; returnpseudo(pseudotop); end else begin if pseudotop^.kind=expression then newtop(intermitword,booltype,pseudo,pseudotop) else newtop(intermitword,booltype,pseudotop,pseudo); end; end; emult, eadd, esetunion, esetinter: commute(getsymbptr); eeq,ene: commute(booltype); elt, ele, ege, egt: begin pseudo:=pseudotop^.next; if ((pseudo^.kind=wordcst) or (pseudo^.kind=shortsignedcst)) and ((pseudotop^.kind=wordcst) or (pseudotop^.kind=shortsignedcst)) then begin case intermitword of elt: pseudo^.constant:= ord(pseudo^.constant < pseudotop^.constant); ele: pseudo^.constant:= ord(pseudo^.constant <= pseudotop^.constant); ege: pseudo^.constant:= ord(pseudo^.constant >= pseudotop^.constant); egt: pseudo^.constant:= ord(pseudo^.constant > pseudotop^.constant); end; pseudo^.kind:=shortsignedcst; pseudo^.typ:=booltype; returnpseudo(pseudotop); end else begin if (pseudotop^.kind=expression) or (pseudo^.kind=wordcst) or (pseudo^.kind=shortsignedcst) or (pseudo^.kind=longcst) then begin (*exchange top and top-1 *) pseudotop^.next:=pseudo^.next; pseudo^.next:=pseudotop; pseudotop:=pseudo; intermitword:=konvrelationÆintermitwordÅ; pseudo:=pseudotop^.next; end; if (pseudotop^.typ^.typkind=eboolean) and (pseudo^.kind=expression) then case intermitword of ele, elt: begin if intermitword=elt then intermitword:=eand else intermitword:=eor; ps:=pseudotop; pseudotop:=pseudo; newtop(enot,booltype,pseudo,nil); ps^.next:=pseudotop; pseudotop:=ps; newtop(intermitword,booltype,pseudotop^.next,pseudotop); end; egt, ege: begin if intermitword=ege then intermitword:=eand else intermitword:=eor; ps:=pseudotop; pseudotop:=pseudo; newtop(enot,booltype,pseudo,nil); ps^.next:=pseudotop; pseudotop:=ps; newtop(intermitword,booltype,pseudotop^.next,pseudotop); newtop(enot,booltype,pseudotop,nil); end; end else newtop(intermitword,booltype,pseudo,pseudotop); end; end; erealdiv,esetdif, eintdiv,emod, edif: begin pseudo:=pseudotop^.next; if ((pseudo^.kind=wordcst) or (pseudo^.kind=shortsignedcst)) and ((pseudotop^.kind=wordcst) or (pseudotop^.kind=shortsignedcst)) then begin case intermitwords of eintdiv:if pseudotop^.constant = 0 then error(324) else pseudo^.constant:= pseudo^.constant div pseudotop^.constant; emod:if pseudotop^.constant = 0 then error(324) else pseudo^.constant:= pseudo^.constant mod pseudotop^.constant; edif: pseudo^.constant:= pseudo^.constant - pseudotop^.constant; end; if (pseudo^.constant <= maxsignedhalfword) and (pseudo^.constant >= minsignedhalfword) then pseudo^.kind:=shortsignedcst else pseudo^.kind:=wordcst; returnpseudo(pseudotop); end else begin if (intermitword = eintdiv) or (intermitword = emod) then s:=pseudo^.typ else s:=getsymbptr; newtop(intermitword,s,pseudo,pseudotop); end; end; ein: newtop(ein,booltype,pseudotop^.next,pseudotop); eminus: with pseudotop^ do if (kind=shortsignedcst) or (kind=wordcst) then begin constant:=-constant; if (constant <= maxsignedhalfword) and (constant >= minsignedhalfword) then kind := shortsignedcst else kind := wordcst; end else begin newtop(eminus,typ,pseudotop,nil); end; eif: begin pushnest; neststackÆndepthÅ.skipif:=noskip; end; ethen: begin ndepth:=getnumber; if pseudotop^.kind = expression then begin evaltoresult(pseudotop,skiptrue); forgetregisters; end else begin if pseudotop^.kind = shortsignedcst then begin if pseudotop^.constant=0 then begin (* skip until else or endif *) repeat repeat nextline; if intermitword = econst then readconst else if intermitword = etype then readtypegeneral else if intermitword = elabeldef then error(321); until (intermitword = eelse) or (intermitword = eendif); until getnumber = ndepth; neststackÆndepthÅ.skipif:=skipfalse; end else neststackÆndepthÅ.skipif:=skiptrue; end else begin if pseudotop^.kind <> reg then load(pseudotop); i := pseudotop^.regno; storeregisters(pseudotop); reservecode(2); makecode(se,i,1); makerelcode(jl,0); outconstlimit:=outconstlimit-1; end; end; neststackÆndepthÅ.index:=lastindex; returnpseudo(pseudotop); end; eelse: begin ndepth:=getnumber; if neststackÆndepthÅ.skipif = noskip then begin storeregisters(nil); makerelcode(jl,0); insertaddr(neststackÆndepthÅ.index,lastindex+1); neststackÆndepthÅ.index:=lastindex; end else if neststackÆndepthÅ.skipif = skiptrue then begin repeat repeat nextline; if intermitword = econst then readconst else if intermitword = etype then readtypegeneral else if intermitword = elabeldef then error(321); until intermitword = eendif; until getnumber = ndepth; end; end; eendif: begin ndepth:=getnumber; if neststackÆndepthÅ.skipif = noskip then begin storeregisters(nil); insertaddr(neststackÆndepthÅ.index,lastindex+1); end; end; elabeldef: begin storeregisters(nil); s:=getsymbptr; code^.cÆs^.labeladdroffsetÅ.constval:=(lastindex)*oneword; end; egoto: begin storeregisters(nil); s:=getsymbptr; with s^ do if labellevel = level then begin makeindexcode(rl,3,stackaddr,labelordinal); makewrelcode(wa,3,2*oneword); makeallcode(jl,0,true,false,3,0); makewordcode((1-lastindex)*oneword); end else begin makeindexcode(rl,1,stackaddr,display+labellevel); makeindexcode(rs,1,stackaddr,dynlinkoffset); makeindexcode(rl,3,1,labelordinal); makewrelcode(rl,0,0); makeconst(procaddr,nil); makeindexcode(ds,0,stackaddr,returnaddroffset); makeindexcode(rl,3,stackaddr,display); makeindirectcode(jl,0,3,returnoffset); end; end; ecase: begin pushnest; with neststackÆndepthÅ do begin labelchain:=nil; lowlabel:=maxint; highlabel:=-maxint; otherw:=false; end; end; eoff: with pseudotop^ do begin if kind = expression then evaltoresult(pseudotop,noskip) else if kind <> reg then load(pseudotop); i:=regno; registerÆiÅ.kind:=expression; storeregisters(nil); if i=0 then begin makecode(rl,1,0); i:=1; end; kind:=reg; regno:=i; reservecode(3); makerelcode(jl,maxsignedhalfword); makecode(jl,0,0); makewordcode(0); pushnest; (* must! be called; side effect: nextstack Æ ndepth Å . startindex := lastindex *) end; ecaselabel: begin s:=getsymbptr; ndepth:=getnumber; with neststackÆndepthÅ do begin l:=s^.intval; if s^.consttype^.typkind = einteger then begin (* check multible occurences of the label *) lab:=labelchain; while lab <> nil do begin if lab^.labval = l then begin error(308); lab:=nil; end else lab:=lab^.next; end; end; lab:=newcaselab; with lab^ do begin next:=labelchain; labval:=l; codindex:=lastindex; end; labelchain:=lab; if lowlabel > l then begin if l < -maxint then error(309) else lowlabel:=l; end; if highlabel < l then highlabel:=l; end; end; egotoendcase: begin storeregisters(nil); reservecode(3); makerelcode(jl,maxsignedhalfword); makecode(jl,0,0); makewordcode(0); end; eotherwise: with neststackÆgetnumberÅ do begin otherw:=true; lab:=newcaselab; with lab^ do begin next:=labelchain; codindex:=lastindex; labval:=lowlabel-1; end; labelchain:=lab; end; eendcase: endcasecode; ewhile: begin storeregisters(nil); pushnest; end; ewhiledo: begin boolexpression; neststackÆndepthÅ.index:=lastindex; outconstlimit:=outconstlimit-1; end; eendwhile: begin storeregisters(nil); ndepth:=getnumber; i:=(lastindex-neststackÆndepthÅ.startindex)*oneword; jump(i); insertaddr(neststackÆndepthÅ.index,lastindex+1); end; erepeat: begin storeregisters(nil); pushnest; end; euntil: ; (* nothing is done *) eendrepeat: begin boolexpression; i:=(lastindex-neststackÆndepthÅ.startindex)*oneword; l:=lastindex; if i < maxsignedhalfword then insertaddr(lastindex,neststackÆndepthÅ.startindex+1) else begin reservecode(4); makerelcode(jl,3*oneword); insertaddr(l,lastindex+1); jump(i+2); end; end; efor,eforinit: (* nothing is done *); efortodo: forstatement(sl,sh,1); efordowntodo: forstatement(sh,sl,-1); efordntoend, efortoend: begin ndepth:=getnumber; s:=getsymbptr; pseudo:=newpseudo; with pseudo^ do begin next:=nil; typ:=s^.vartypedescr; kind:=variable; addr:=s^.varaddr; end; loadregister(neststackÆndepthÅ.stepregister,pseudo); storeregisters(pseudo); returnpseudo(pseudo); i:=(lastindex-neststackÆndepthÅ.startindex+2)*oneword; jump(i); insertaddr(neststackÆndepthÅ.index,lastindex+1); returnpseudo(pseudotop); returnpseudo(pseudotop); end; ewith:; (* nothing is done *) ewithvar: begin pushnest; with pseudotop^ do begin if (addr.index <> nil) or not addr.simpleaddr then begin address := newaddress; i:=freeregister(true); loadaddress(i,pseudotop); typ:=integertype; kind:=reg; regno:=i; sameregister:=nil; storetmp(pseudotop); address^:=addr; addr.simpleaddr:=false; addr.postordinal:=0; addr.reference:=address; end; end; neststackÆndepthÅ.withvar:=pseudotop; end; ewithdo:; (* nothing is done *) ewithname: begin pseudo:=newpseudo; pseudo^:=neststackÆgetnumberÅ.withvar^; (* take a copy of the addressnode, in case of notsimple with *) (* ... see returnpseudo,returnaddress ... *) if not pseudo^.addr.simpleaddr then begin address := newaddress; address^ := pseudo^.addr.reference^; pseudo^.addr.reference := address; end; (* at most one level of address nodes ! *) pseudo^.next:=pseudotop; pseudo^.kind:=variable; pseudotop:=pseudo; end; eendwith: begin ndepth:=getnumber+1; while neststackÆndepthÅ.withvar <> pseudotop do begin returnpseudo(pseudotop); end; returnpseudo(pseudotop); end; ecallproc: begin pushnest; with neststackÆndepthÅ do begin procfunc:=getsymbptr; oldtop:=pseudotop; end; paramoffset:=blockmark-oneword; end; ecallfunc: begin pushnest; s:=getsymbptr; neststackÆndepthÅ.procfunc:=s; pseudo:=newpseudo; with pseudo^ do begin next:=pseudotop; kind:=procfunc; symb:=s; if s^.namekind = efunc then typ:=s^.functype else typ:=s^.vartypedescr; end; pseudotop:=pseudo; end; eparam: begin ndepth:=getnumber; i:=getnumber; with neststackÆndepthÅ.procfunc^ do begin if standard then s:=nil else s:=getsymbptr; case namekind of eproc: if not standard then begin actualparam(s,pseudotop); returnpseudo(pseudotop); end; efproc: begin actualparam(nil,pseudotop); returnpseudo(pseudotop); end; effunc, efunc: newtop(eparam,s,pseudotop^.next,pseudotop); end; end; end; eformat: begin ndepth:=getnumber; if getnumber = 1 then newtop(eformat,nil,pseudotop,nil) else newtop(eformat,nil,pseudotop^.next,pseudotop); end; eendcall: begin ndepth:=getnumber; with neststackÆndepthÅ.procfunc^ do case namekind of eproc:begin paramoffset:=-oneword; if standard then standardprocedure else begin storeregisters(nil); makeindexcode(al,1,stackaddr,display); makecode(al,0,routinedescr); callroutine; end; end; efproc: begin storeregisters(nil); loadformal(varaddr); paramoffset:=-oneword; callroutine; end; effunc, efunc: begin pseudo:=pseudotop; newtop(eendcall,nil,pseudotop,nil); ps:=nil; while pseudo^.kind <> procfunc do begin leftps:=pseudo^.leftoperand; pseudo^.leftoperand:=ps; ps:=pseudo; pseudo:=leftps; end; pseudotop^.leftoperand:=ps; pseudotop^.rightoperand:=pseudo; if namekind = efunc then if functype = nil then pseudotop^.typ := ps^.rightoperand^.typ (* some standard functions with parameter dependent type, e.g. succ, pred, sqr, abs, ... *) else pseudotop^.typ := functype else pseudotop^.typ:=vartypedescr; end; end; end; elinenumber: begin read(currentline); if lineoutput then begin linetablelgt:=linetablelgt+1; linetable^:=lastindex*oneword; put(linetable); end; end; eoption: begin get(input); if input^='t' then begin get(input); check:=input^='+'; alwayscheck := check; end else if input^='r' then begin get(input); resident:=input^='+' end else if input^ = 'c' then begin get(input); slangmode := input^ = '+'; end; end; end; (* CASE intermitword OF *) nextline; end; (* WHILE intermitword <> eendprogram DO ... *) routinedescriptorwords; if compilertest then comptestoutput; 9999: if errorcount > 0 then printerrors; close(input); end. . ▶EOF◀