|
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: 84480 (0x14a00) Types: TextFile Names: »procpass3«
└─⟦2c55ea56f⟧ Bits:30001844 SW-save af projekt 1000, Alarm-system └─⟦6b41451d2⟧ └─⟦this⟧ »procpass3«
(*QQQ*) (* procedures used for testoutput purposes *) procedure changeline; begin testlinecnt := testlinecnt + 1; if testlinecnt mod lines_pr_page = 1 then begin page (output); writeln (output); write (cur_date, ' ', cur_time, ' platon, pass3, version ', version); end; writeln (output); end; procedure continue_line; begin (* used for alligning testoutput on consequtive lines *) changeline; write (output, ' '); end; (*QQQ*) (* procedures for reading pass1-code file *) function passin : integer; (* delivers the next pass1-code as integer value *) var i: integer; begin read (pass1file, i); passin := i; if testinput then write (output, ' ', i:1, '*'); end; function password : codes; (* delivers the next pass1-code as code value *) var i: integer; begin read (pass1file, i); password := convtable Æ i Å; if testinput then write (output, ' ', i:1, '>'); end; (*QQQ*) (* procedures for reading the pass1-label file *) function labelin : integer; (* delivers the next pass1-label-value as integer value *) var i: integer; begin read (pass1labels, i); labelin := i; if testinput then write (output, ' ', i:1, '+'); end; (*QQQ*) (* procedures for writing the pass3file *) procedure emitin (i: integer); (* outputs the value as integer value *) begin write (pass3file, i); if testoutput then write (output, ' ', i:1, ' '); end; procedure emit (code: pass3codes); (* outputs the codeword as integer value *) var i: integer; begin i := ord (code); write (pass3file, i); if testoutput then write (output, ' ', i:1, '<'); end; procedure emitid (xcode: pass3codes; xnix: nameptr); begin emit (xcode); emitin (ord (xnix) ); end; procedure terminate; var err: pass3errors; ch : char; begin (* terminate use of files *) emit (xeom); close (pass3file); close (pass1file); close (pass1labels); (* if any errormessages then print the descriptions *) if no_of_errors > 0 then begin (* at least one error, therefor prepare the errorlist *) changeline; write (output, 'error description'); changeline; open (input, 'pass3errors'); reset (input); (* find the start of error-table *) repeat readln (input, ch); until ch = '('; for err := noerror to lastpass3error do begin if error_bitmap Æ err Å then begin write (ord (err) : 4, ' = '); while not eoln (input) do begin read (input, ch); write (output, ch); end; changeline; end; readln (input); end; (* scan when errors *) end; (* if any errors *) end; (*QQQ*) (* procedures for error-handling etc *) procedure warning (error: pass3errors); begin if (no_of_errors = 0) or testing then changeline; write (output, '*** pass ', own_passno:1, ' line ', cur_lineno:4, '.', cur_opandno:1, ', error ', ord (error):2); changeline; no_of_errors := no_of_errors + 1; error_bitmap Æ error Å := true; end; procedure error (err: pass3errors); begin call_pass4 := false; (* avoid calling pass4 automaticly *) emit (xerror); emitin (own_passno); emitin (ord (err)); emit (xerrorno); emitin (cur_opandno); warning (err); error_bitmap Æ err Å := true; end; procedure suppress_error (kind: codes; err: pass3errors); (* the error-message will be suppressed, if already after error *) (* the typename if stacktop will be set to error-type *) begin if kind <> cerrorkind then error (err); with opands Æ stacktop Å do op_typename := error_typename; end; procedure break; (* used when a call-trace is wanted *) begin terminate; (* terminate the files etc *) writeln; writeln ('***** intentionally error...'); emit (xeom); (* this will provoke an error, which will produce the trace *) (* the program is terminated *) end; procedure stop (cause: stopcodes); begin writeln (output); writeln ('*** error found in pass3, at sourceline: ', cur_lineno:1); case cause of too_many_names: writeln ('max_names exceeded', max_names); too_many_types: writeln ('max_types exceeded', max_types); too_many_strings: writeln ('max_strings exceeded', max_strings); too_many_labels: writeln ('max_labels exceeded', max_labels); too_many_opands: writeln ('max_opands exceeded', max_opands); too_many_levels: writeln ('max_levels exceeded', max_levels); too_many_pushnames: writeln ('max_pushnames exceeded', max_pushnames); too_many_nested_calls: writeln ('max_nested_calls exceeded', max_nested_calls); end otherwise writeln ('??? stop-cause = ', ord (cause):1); call_pass4 := false; (* suppress automatic call of next pass *) goto 999; (* terminate program *) end; procedure comp_error (cause: comp_errorcodes); begin writeln; writeln ('*** program inconsistency in pass3, at sourceline ', cur_lineno:1); write (' cause is: '); case cause of unknown_namekind: write ('unknown-namekind'); unknown_argkind: write ('unknown-argkind'); unknown_opcode: write ('unknown-opcode'); unknown_paramkind: write ('unknown-paramkind'); unknown_routinekind: write ('unknown-routinekind'); unknown_spix: write ('unknown-spix'); unknown_stdtype_name: write ('unknown-stdtype-name'); unknown_typekind: write ('unknown-typekind'); unknown_rectype: write ('unknown-rectype'); inconsist_alloc: write ('inconsistent-alloc'); unstack_nontype: write ('unstack-nontype'); end otherwise write ('??? = ', ord(cause):1 ); break; (* terminate program, with call-trace *) end; (* procedure comp_error *) procedure readoption; (* reads: passno, option number, option value *) (* if passno is not current pass then emit the option *) var passno, optno, optvalue: integer; begin passno := passin; optno := passin; optvalue := passin; if passno <> own_passno then begin emit (xoption); emitin (passno); emitin (optno); emitin (optvalue); end else begin case optno of 1: testinput := optvalue = 1; 2: testoutput := optvalue = 1; 3: call_pass4 := optvalue = 1; 4: lambda_version := optvalue = 1; end otherwise; (* case, otherwise blind *) end; testing := testinput or testoutput; end; (* procedure readoption *) (*QQQ*) (* procedures for allocating/releasing structures *) function alloc_string: stringptr; (* deliver a stringnode *) var string: stringptr; begin string := freestrings; if string = nilstring then stop (too_many_strings); with strings Æ string Å do begin alloc_string := string; freestrings := nextstr; nextstr := nilstring; end; end; procedure release_string (xstring: stringptr); (* releases a whole list, constituting a literal *) var string: stringptr; begin string := xstring; (* scan the list to find the termination *) repeat with strings Æ string Å do begin string := nextstr; if string = nilstring then nextstr := freestrings; (* insert in front of free nodes *) end; until string = nilstring; freestrings := xstring; (* first free in the list *) end; function alloc_opand: opandptr; (* delivers an opand node, initialized with cur_lineno *) var opand: opandptr; begin opand := freeopands; if opand = nilopand then stop (too_many_opands); with opands Æ opand Å do begin alloc_opand := opand; freeopands := next; next := nilopand; op_lineno := cur_lineno; op_name := nilname; op_value := nilstring; op_packflag := false; end; end; procedure release_expr (expr: opandptr); (* works as 'emitexpr', but does only the releasing *) begin while expr <> nilopand do with opands Æ expr Å do begin if left <> nilopand then release_expr (left); if op_value <> nilstring then release_string (op_value); next := freeopands; freeopands := expr; expr := rigth; end; end; (* procedure release-expr *) function alloc_namenode: nameptr; (* delivers a namenode, initialized as dummy *) var name: nameptr; begin name := freenames; if name = nilname then stop (too_many_names); (* initialize *) with names Æ name Å do begin alloc_namenode := name; freenames := nextname; (* unlink from free-chain *) nextname := nilname; forward_decl := false; external_decl := false; func_assigned := false; usedlevel := lowestlevel - 1; (* i.e. not used *) params := nilname; typ := dummy_typenode; end; end; procedure release_typenode (xtype: typeptr); forward; procedure releasenames (xnamelist : nameptr); (* releases all namenodes in the list *) (* if a namenode is a typename, the corresponding typenode *) (* will be released too *) var name: nameptr; begin while xnamelist <> nilname do with names Æ xnamelist Å do begin if params <> nilname then releasenames (params); (* release paramlists of inner routines *) if typ <> dummy_typenode then if namekind <> cundeclared then release_typenode (typ); (* release typenode of local type *) (* insert in free-chain *) name := nextname; nextname := freenames; freenames := xnamelist; xnamelist := name; end; (* with xnamelist *) end; function alloc_typenode : typeptr; (* delivers a typenode, initialized as dummy *) var name : nameptr; begin name := freetypename; if name = nilname then stop (too_many_types); with names Æ name Å do with types Æ typ Å do begin alloc_typenode := typ; freetypename := nextname; nextname := nilname; typ := dummy_typenode; releasenames (name); (* initialize typenode *) element := nilname; index := nilname; subexpr := nilopand; typekind := cnocode; contents:= ÆÅ; packflag:= false; emitted := false; end; (* with typenode *) end; procedure release_typenode (xtype: typeptr); var name: nameptr; begin with types Æ xtype Å do begin if typekind = crecord then releasenames (element); (* release field-list of record *) if subexpr <> nilopand then release_expr (subexpr); end; (* with xtype *) name := alloc_namenode; with names Æ name Å do begin namekind := ctype; typ := xtype; nextname := freetypename; freetypename := name; end; end; function alloc_label: labelptr; (* delivers a labelnode *) var lab: labelptr; begin lab := freelabels; if lab = nillabel then stop (too_many_labels); with labels Æ lab Å do begin alloc_label := lab; freelabels := prevlabel; prevlabel := nillabel; end; end; (*QQQ*) function readstring: stringptr; (* reads: length, char Æ 1 .. length Å from pass1file *) (* and packs into stringnodes *) var length: integer; curstr: stringptr; i, portion: str_index; begin length := passin; (* get length of string *) curstr := alloc_string; readstring := curstr; (* result is (first) stringnode *) portion := maxstring; while length > 0 do with strings Æ curstr Å do begin (* read a portion of the string *) stringlgt := length; if length < portion then portion := length; length := length - portion; for i := 1 to portion do str Æ i Å := chr (passin); if length > 0 then nextstr := alloc_string; curstr := nextstr; end; (* with curstr *) end; (* procedure readstring *) procedure emitstring (string: stringptr); var length: integer; curstr: stringptr; i, portion: str_index; begin curstr := string; portion := maxstring; with strings Æ curstr Å do length := stringlgt; emitin (length); if length > 0 then repeat with strings Æ curstr Å do begin if portion > stringlgt then portion := stringlgt; for i := 1 to portion do emitin ( ord ( str Æ i Å ) ); curstr := nextstr; end; (* with curstr *) until curstr = nilstring; end; (* procedure emitstring *) procedure emit_extname (opand: opandptr); begin emit (xname); with opands Æ opand Å do emitstring (op_value); release_expr (opand); end; procedure stdspix (xspix: integer; xstdname: stdname_range); (* inserts the value 'xspix' in stdspix-table *) (* ... the value -1 is <dummy-value> *) var i: stdname_range; begin stdspix_table Æ xstdname Å := xspix; maxstdspix := -1; (* assume all entries are dummy *) (* maxstdspix is used when determining a spix to be 'special' *) for i := canonymous to cord do if maxstdspix < stdspix_table Æ i Å then maxstdspix := stdspix_table Æ i Å; end; procedure standardname; (* called from initialization and mainloop *) (* it will read: (spix,stdname) , and insert in tabel *) begin stdspix (passin (* = spix *), password (* = stdname *) ); anonymous_spix := stdspix_table Æ canonymous Å; exception_spix := stdspix_table Æ cexception Å; end; procedure specialspix (xname: nameptr); (* called from mainloop, when a 'special'-spix has been defined *) (* the action depends on the spix *) label 99; var i: stdname_range; begin with names Æ xname Å do (* namenode of special interest *) with types Æ typ Å do (* the corresponding typenode (in case of type...) *) for i := canonymous to cord do (* scan the stdspix-table to find the rigth spix *) if stdspix_table Æ i Å = spix (* of namenode *) then begin (* remove it from table (... optimalization ...) *) stdspix (-1, i); case i of canonymous: ; (* empty *) cboolean: begin boolean_typename := xname; emitid (xboolean, xname); end; cchar: begin char_typename := xname; emitid (xchar, xname); end; cshadow: begin shadow_typename := xname; contents := Æ t_shadow Å; (* force this special content *) emitid (xshadow, xname); end; creference: begin reference_typename := xname; contents := Æ t_reference Å; (* force this special content *) emitid (xreference, xname); end; csemaphore: begin contents := Æ t_semaphore Å; (* force this special content *) emitid (xsemaphore, xname); end; cson: son_typename := xname; cprocessrec: processrec_typename := xname; cexception: exception_procname := xname; cabs: abs_procname := xname; csucc: begin succ_procname := xname; emitid (xsucc, xname); end; cpred: begin pred_procname := xname; emitid (xpred, xname); end; cchr: emitid (xchr, xname); cord: begin ord_procname := xname; emitid (xord, xname); end; end otherwise if compilertest then comp_error (unknown_stdtype_name); goto 99; (* goto found *) end; (* for i in stdspix_range *) (* in case the loop terminates: severe error *) if compilertest then comp_error (unknown_spix); 99: ; (* found: *) end; (* procedure specialspix *) procedure set_error_type; (* if the current type was an implicit type definition, *) (* it will be released at block-end *) begin cur_typename := error_typename; cur_typenode := error_typenode; end; (* procedures for inserting/retrieving names *) procedure searchspix (xspix: spixrange; firstlevel, lastlevel: levelrange); (* searches among all names in the levels to find 'xspix' *) (* the global variables 'retrieved_name'/'retrieved_level' *) (* describe the result of the procedure: *) (* xspix not found: 'retrieved_name' = nilname (-level undef) *) (* xspix found: 'retrieved_name/level' identifies the namenode *) label 99; var name: nameptr; level: levelrange; begin for level := lastlevel downto firstlevel do with namestack Æ level Å do begin name := firstname; while name <> nilname do with names Æ name Å do begin if spix (* of name *) = xspix then goto 99; (* found *) name := nextname; (* follow chain *) end; end; (* for level *) name := nilname; (* name not found *) 99:; (* found *) retrieved_level := level; (* undef, if not found *) retrieved_name := name; (* nilname, if not found *) end; (* procedure searchspix *) function findname (xspix: spixrange) : nameptr; (* delivers the namenode with the searched spix *) (* if the spix was'nt found, the result is 'nilname' *) begin searchspix (xspix, processparamlevel, namelevel); if retrieved_name = nilname then searchspix (xspix, lowestlevel, lastgloballevel); findname := retrieved_name; end; function newname (xspix: spixrange) : nameptr; (* a new namenode is inserted at current namelevel *) (* the namenode is initialized as dummy *) label 99; var name : nameptr; begin if xspix <> anonymous_spix then begin (* explicit spix'es may not exist already at current namelevel *) (* ... except forward declared routine-names ... *) name := findname (xspix); if name <> nilname then begin (* the name already existed at some level *) (* check the consistency *) with names Æ name Å do (* namenode of just found name *) if retrieved_level = namelevel then begin (* double-declaration is suppressed, in case the previous decl was forward *) if forward_decl then (* it was really forward declared *) (* now test that it is similar to the new one *) if namekind = cur_namekind then goto 99; (* skip initialization etc *) (* otherwise is will be flagged as error *) error (double_declaration); xspix := anonymous_spix; (* i.e. this name can never be retrieved *) end (* if already on namelevel *) else begin (* test that this (global) name has'nt been used previously on this level *) if usedlevel (* of name *) = namelevel then error (inconsistent_use); end; end; (* if existing name *) end; (* if explicit spix *) (* allocate and initialize a new namenode *) name := alloc_namenode; with names Æ name Å do begin spix := xspix; namekind := cur_namekind; typename := nil_typename; (* insert in list of names of same level *) with namestack Æ namelevel Å do if insert_in_front then begin (* only function-return-value are inserted in front ... *) with names Æ name Å do nextname := firstname; (* insert in front of existing list *) if firstname = nilname then lastname := name; firstname := name; end else begin if firstname = nilname then firstname := name else with names Æ lastname Å do nextname := name; (* insert in rear of existing list *) lastname := name; end; (* with namelevel *) end; (* with name *) 99:; (* after init of namenode *) newname := name; end; (* procedure newname *) function new_undecl (xspix: spixrange): nameptr; (* the routine creates a new namenode with the spix given *) (* and marks it as undeclared *) var name: nameptr; begin name := newname (xspix); with names Æ name Å do begin namekind := cundeclared; typename := error_typename; typ := error_typenode; end; (* nbnbnb: make a 'pseudo'-declaration of the name *) emitid (xundeclid, name); new_undecl := name; end; (* procedure new-undecl *) function usename (xspix: spixrange) : nameptr; (* the routine will search for the given spix, and mark the namenode *) (* as being used on current namelevel *) (* if the name does'nt exist, a new namenode will be created *) var name: nameptr; begin cur_opandno := cur_opandno + 1; name := findname (xspix); if name = nilname then begin (* the name did'nt exist, create e new namenode *) error (undeclared); name := new_undecl (xspix); end; (* if undeclared *) (* test for recursive use of constants, i.e. using before defining *) with names Æ name Å do if namekind = cconstant then if usedlevel = lowestlevel - 1 (* i.e. just after declaration *) then begin error (recursive_constant_use); name := new_undecl (xspix); end; (* mark the name as being used on current level *) with names Æ name Å do usedlevel := namelevel; usename := name; (* deliver the used name node *) end; (* procedure usename *) procedure end_level_use (firstlevel, lastlevel: levelrange); (* all names in the outpointed namelevels are tested for use *) (* on current namelevel *) (* if a name was used on current namelevel, it will be flagged *) (* as if it had been used on preceding namelevel *) var name: nameptr; level: levelrange; begin for level := lastlevel downto firstlevel do with namestack Æ level Å do begin name := firstname; while name <> nilname do with names Æ name Å do begin if usedlevel = namelevel then if namelevel = processparamlevel then usedlevel := lastgloballevel else usedlevel := usedlevel - 1; name := nextname; (* follow chain *) end; end; end; (* procedure end_level_use *) procedure end_global_use; (* called when terminating a namelevel *) (* if global variables have been used at this namelevel *) (* their uselevel will be decreased as is they were used at *) (* preceding namelevel *) begin end_level_use (processparamlevel, namelevel - 1); end_level_use (lowestlevel, lastgloballevel); end; (*QQQ*) (* procedures for handling push/pop of names *) procedure pushname (xname: nameptr); begin pushnamestack Æ pushnameindex Å := xname; if pushnameindex = max_pushnames then stop (too_many_pushnames); pushnameindex := pushnameindex + 1; end; function popname : nameptr; begin pushnameindex := pushnameindex - 1; popname := pushnamestack Æ pushnameindex Å; end; (* pushlist/poplist are used for handling of nested namelists *) procedure pushlist; begin pushname (listfirst); pushname (listlast); listfirst := nilname; listlast := nilname; end; procedure poplist; begin listlast := popname; listfirst := popname; end; (* pushtype/poptype are used for handling of nested types *) procedure pushtype; begin pushname (cur_typename); end; procedure poptype; begin cur_typename := popname; with names Æ cur_typename Å do cur_typenode := typ; if compilertest then if cur_typenode = dummy_typenode then begin comp_error (unstack_nontype); set_error_type; end; end; (* procedures for handling of nested procedure calls (or indexing etc) *) procedure pushcall; begin if callindex = max_nested_calls then stop (too_many_nested_calls); with calls Æ callindex Å do begin callkind := argkind; callformal := curformal; callowner := arglist_owner; call_afterfunc:= after_funccall; call_functemp := functempvar; call_countprocess := count_processparam; end; after_funccall := false; (* assume not function call *) count_processparam := 0; callindex := callindex + 1; end; (* procedure pushcall *) procedure popcall; (* works opposite of pushcall *) begin callindex := callindex - 1; with calls Æ callindex Å do begin argkind := callkind; curformal := callformal; arglist_owner := callowner; after_funccall:= call_afterfunc; functempvar := call_functemp; count_processparam := call_countprocess; end; end; (* procedure popcall *) (* procedures for creating new opand-nodes, whether operators or operands *) procedure oper (mode: opmodes; xopcode: codes; xtypename: nameptr); (* inserts an opandnode as unary or binary operator *) var oldtop: opandptr; begin (* move stacktop to another opand, and use the stacktop for the new one *) (* this makes it possible to 'insert' in the middle of the opand-tree *) oldtop := alloc_opand; opands Æ oldtop Å := opands Æ stacktop Å; with opands Æ stacktop Å do (* new opand node *) begin opcode := xopcode; if mode = unary then begin left := nilopand; rigth := oldtop; next := nexttop; end else begin (* binary*) left := nexttop; rigth := oldtop; next := opands Æ left Å . next; nexttop := next; end; op_lineno := 0; (* dummy *) op_name := nilname; op_value := nilstring; op_typename := xtypename; end; (* with (new) stacktop *) end; (* procedure oper *) procedure newopand (xcode: codes; xtypename: nameptr); (* insert an operand at stacktop *) var oldtop: opandptr; begin if retain_top then begin (* if insertion in middle of list then don't 'move' stacktop *) oldtop := alloc_opand; opands Æ oldtop Å := opands Æ stacktop Å; with opands Æ stacktop Å do begin op_lineno := 0; op_name := nilname; op_value := nilstring; end; end else begin oldtop := stacktop; stacktop := alloc_opand; end; with opands Æ stacktop Å do (* new opand node *) begin opcode := xcode; left := nilopand; rigth := nilopand; next := oldtop; op_typename := xtypename; end; nexttop := oldtop; end; (* procedure newopand *) function take_stacktop : opandptr; (* used when the top-expression is to be saved a while *) begin take_stacktop := stacktop; stacktop := nexttop; nexttop := opands Æ stacktop Å . next; end; procedure insert_functype (xtypename: nameptr); begin with names Æ functempvar Å do typename := xtypename; end; procedure prepare_call (opand: opandptr); (* used to prepare a routine-call *) (* nb: 'pushcall' must have been called previously *) var saved_stacktop : opandptr; saved_nexttop : opandptr; begin with opands Æ opand Å do (* opand contains id, holding routine *) with names Æ op_name Å do (* namenode of routine *) begin (* initialize global variables, describing arguments to this routine *) argkind := cargument; curformal := params; (* first of formal list *) arglist_owner := op_name; (* set this routine as owner of formal list *) if namekind (* of routine *) = cfunction then begin (* save stacktop etc and restore later *) (* simulate that 'opand' is stacktop *) saved_stacktop := stacktop; saved_nexttop := nexttop; stacktop := opand; nexttop := opands Æ stacktop Å . next; retain_top := true; (* reserve temp name, for identifying temp-return-value *) functempvar := alloc_namenode; insert_functype (typename (* of function *) ); (* insert opand, pointing at this temp-name *) oper (unary, cfunctrailer, nilname (* irrell typename *) ); with opands Æ stacktop Å do op_name := functempvar; (* insert operand, to be used as actual argument for the return-value *) newopand (cfunctemp, nilname (* irrell typename *) ); with opands Æ stacktop Å do op_name := functempvar; (* bind this actual-argument onto the function *) (* ... see also 'actparam' ... *) oper (binary, argkind, nilname (* irrell typename *) ); with opands Æ stacktop Å do op_name := curformal; (* let opname point at first formal name, i.e. 'funcval' *) if compilertest then if (stacktop <> opand) or (nexttop <> opands Æ opand Å . next) then begin writeln(stacktop,opand,nexttop, opandsÆopandÅ.next); break; end; retain_top := false; stacktop := saved_stacktop; nexttop := saved_nexttop; end; end; (* with namenode of routine *) end; (* procedure prepare-call *) procedure terminate_call (opand: opandptr); (* used by 'endactual' to test total match of formal lists etc *) label 10; var saved_stacktop : opandptr; saved_nexttop : opandptr; begin (* save stacktop etc and restore later *) (* simulate that 'opand' is stacktop *) saved_stacktop := stacktop; saved_nexttop := nexttop; stacktop := opand; nexttop := opands Æ stacktop Å . next; case argkind of cstrucrecord, cargument: begin (* test that all recfields (respectively all formals) have been matched *) while curformal <> nilname do with names Æ curformal Å do case namekind (* of curformal *) of crecfield, cvarp, cvaluep: begin error (too_few_parameters); goto 10; end; cfuncval, cundeclared, (* undeclared typename *) cscalarelem, ctype: curformal := nextname; (* i.e. skip in formal-list *) end otherwise if compilertest then comp_error (unknown_namekind); 10:; end; (* argkind = strucrecord or argument *) end (* case argkind *) otherwise; (* no check *) (* insert opands, describing the proper end-list *) case argkind of cindex: ; (* nothing *) cstrucarray, cstrucrecord: oper (unary, cendstruc, arglist_owner); cargument: with names Æ arglist_owner Å do case namekind of cprocess: begin oper (unary, ccallprocess, nilname (* no type *) ); with opands Æ stacktop Å do op_name := nextname (* of process *); (* remember the sonvar-name, for later use *) end; cprocedure, cfunction: begin (* first insert operators for later counting in opand-stack *) while count_processparam > 0 do begin count_processparam := count_processparam - 1; oper (unary, cendprocessparam, nilname (* irrell typename *) ); end; case namekind (* of arglist-owner *) of cprocedure: oper (unary, cendproc, nilname (* irrell typename *) ); cfunction: begin with names Æ functempvar Å do (* namenode, containing function-type *) oper (unary, cfcall, typename (* of function-type *) ); with calls Æ callindex - 1 Å do (* i.e. determine the value to be unstacked *) call_afterfunc := true; end; end otherwise (* not possible *); (* case procedure or function *) end; end otherwise; (* case namekind *) cerrorarg: ; (* don't care anyway *) end (* case argkind *) otherwise if compilertest then comp_error (unknown_argkind); (* unstack nested call *) popcall; if compilertest then if (opand <> stacktop) or (nexttop <> opandsÆopandÅ.next) then begin writeln(stacktop,opand,nexttop,opandsÆopandÅ.next); break; end; (* restore thereal stacktop and nexttop *) stacktop := saved_stacktop; nexttop := saved_nexttop; end; (* procedure terminate-call *) procedure terminate_funccall (opand: opandptr); (* ensures that the 'endfunccall' is emitted (as late as possible) after a function call *) var saved_stacktop : opandptr; saved_nexttop : opandptr; begin if after_funccall then begin (* save stacktop etc and restore later *) (* simulate that 'opand' is stacktop *) saved_stacktop := stacktop; saved_nexttop := nexttop; stacktop := opand; nexttop := opands Æ stacktop Å . next; with opands Æ stacktop Å do oper (unary, cendvariable, op_typename (* continue with op-type *) ); (* unstack from call-stack *) after_funccall := false; if compilertest then if (opand <> stacktop) or (nexttop <> opandsÆopandÅ.next) then begin write(stacktop,opand,nexttop,opandsÆopandÅ.next); break; end; (* restore the real stacktop and nexttop *) stacktop := saved_stacktop; nexttop := saved_nexttop; end; end; procedure make_call (opand: opandptr); (* if the operand is a routine-ident, a (parameter-less) call will be made *) begin with opands Æ opand Å do if opcode = cid then with names Æ op_name Å do case namekind of cprocess, cprocedure, cfunction: begin pushcall; prepare_call (opand); terminate_call (opand); terminate_funccall (opand); end; end otherwise; (* other namekinds are not routine-calls *) end; (* procedure make-call *) (*QQQ*) (* procedures for handling level-change etc *) procedure newnamelevel; (* initializes a new namelevel, with an empty namelist *) begin if namelevel = max_levels then stop (too_many_levels); namelevel := namelevel + 1; with namestack Æ namelevel Å do begin firstname := nilname; namelistkind := levelkind; withname := nilname; (* assume normal level *) if namelistkind = processlevel then processparamlevel := namelevel; end; levelkind := irrell_level; (* prepare for next level to be normal *) end; procedure insert_namelist (first: nameptr); (* initializes current namelevel with the namelist given *) begin with namestack Æ namelevel Å do begin firstname := first; lastname := firstname; while names Æ lastname Å . nextname <> nilname do lastname := names Æ lastname Å . nextname; end; end; procedure endnamelevel; begin (* the variable 'processparamlevel' must be reinitialized, when *) (* leaving a process. *) if namelevel = processparamlevel then repeat processparamlevel := processparamlevel - 1; until (namestack Æ processparamlevel Å . namelistkind = processlevel) or (processparamlevel = lastgloballevel - 1); end_global_use; namelevel := namelevel - 1; end; procedure test_recursive_type; (* will test that 'cur_typename' is a defined type *) begin with names Æ cur_typename Å do if spix (* of typename *) <> anonymous_spix then (* recursion only possible with named types *) with types Æ typ Å do if not emitted then begin error (recursive_use_of_type); set_error_type; end; end; (*QQQ*) function empty_paramlist (paramlist: nameptr): boolean; (* returns false, if the paramlist contains 'varparam' or 'valueparam' *) label 99; begin while paramlist <> nilname do with names Æ paramlist Å do if (namekind = cvarp) or (namekind = cvaluep) then begin empty_paramlist := false; goto 99; end else paramlist := nextname; (* follow chain *) (* the list did'nt contain var- or valueparam *) empty_paramlist := true; 99: ; end; (* procedure empty-paramlist *) procedure compare_paramlists; (* compares the previous paramlist of 'cur_routine' *) (* with param-list in current namelevel *) (* the new paramlist may be empty or exactly the same *) (* the new paramlist is released and replaced by the original list *) var newparam, oldparam: nameptr; errorflag: boolean; begin errorflag := false; (* suppose no errors *) with namestack Æ namelevel Å do with names Æ cur_routine Å do begin newparam := firstname; (* first of new parameter list *) if not empty_paramlist (newparam) then begin oldparam := params; (* first of old parameter list (of cur_routine) *) (* compare the two lists *) (* they both terminate with nilname *) while oldparam <> newparam do with names Æ oldparam Å do begin if (* they must have identical names *) (spix <> names Æ newparam Å . spix) or (* both must be 'cvarp' or 'cvaluep' *) (namekind <> names Æ newparam Å . namekind) or (* they must have same type *) (typename <> names Æ newparam Å . typename) then errorflag := true; oldparam := nextname; newparam := names Æ newparam Å . nextname; end; (* with/while more params *) if errorflag then error (paramlist_changed_since_forwarddecl); end; (* if new paramlist not empty *) (* release the new paramlist and replace it by the old one *) releasenames (firstname (* of namelevel *) ); insert_namelist (params (* of cur-routine *) ); end; (* with cur_routine *) end; (* procedure compare_paramlists *) (*QQQ*) procedure begin_block; (* called before first local declaration in a routine *) begin expecting_block := false; (* indicate that the procedure has been called *) with names Æ cur_routine Å do begin if namekind <> cprocess then cur_blockno := cur_blockno + 1; forward_decl := false; (* because here comes the body *) end; emit (xblock); emitin (cur_blockno); end; (*QQQ*) (* procedures for emitting identifiers and types *) procedure emitexpr (expr: opandptr); (* the expression is emitted, and maybe released (depending on 'expr-release') *) procedure emitboth; begin with opands Æ expr Å do begin emitexpr (left); emitexpr (rigth); end; end; procedure emit_arith (outcode: pass3codes); begin with opands Æ expr Å do begin if left <> nilopand then begin emitexpr (left); emit (xgetvalue); end; emitexpr (rigth); emit (outcode); end; end; begin if expr <> nilopand then with opands Æ expr Å do begin (* note: only 'newopand' inserts proper lineno in opands *) if op_lineno <> 0 then if op_lineno <> emit_lineno then begin emit (xnewline); emitin (op_lineno); emit_lineno := op_lineno; end; expr_level := expr_level + 1; if expr_level = 1 then begin emit (xexpr); (* this is the start of a whole expression *) if testoutput then continue_line; end; if opcode = cnocode then emitboth else case opcode (* of opand *) of cid: begin (* identifier: action depends on namekind *) with names Æ op_name Å do (* namenode of identifier *) case namekind (* of namenode *) of cundeclared, cscalarelem, cconstant, cvar, cvarp, cvaluep, cfuncval: begin emitid (xvar, op_name); emitin ( ord(typename) ); end; cprocess: ; (* nothing *) (* start of process param sequence *) cprocedure: begin (* start of procedure call-sequence *) emitid (xproccall, op_name); end; cfunction: begin (* start of function call sequence *) emitid (xfunccall, op_name); (* the temp-return-value and the type are emitted by 'functrailer' *) end; ctype: begin (* start of structured constant sequence *) emitid (xstrucconst, op_name (* name of type itself *)); end; end (* case namekind *) otherwise if true then write (output, '*** id: namekind = ', ord(namekind):1) else if compilertest then comp_error (unknown_namekind); end; (* opcode = 'id' *) cliteral: begin emit (xliteral); with names Æ op_typename Å do (* namenode of opand-type *) with types Æ typ Å do (* corresponding typenode *) if typekind (* of opand-typenode *) = cinteger then emitin ( ord(lit_integer) ) else with strings Æ op_value Å do if stringlgt = 1 then emitin ( ord(lit_char) ) else emitin ( ord(lit_string_or_empty) ); emitstring (op_value); end; cskipparam: emit (xnull); cfunctrailer: begin emitexpr (rigth); (* emit funccall etc *) emitin (ord (op_name) ); (* name of temp-return-value *) with names Æ op_name Å do (* namenode of functemp var *) emitin (ord (typename) ); (* typename of function *) end; cfunctemp: begin (* this is almost an 'id', but the namenode does'nt contain typename *) (* used for actual argment, to match 'funcval' *) emitid (xvar, op_name); with names Æ op_name Å do (* namenode of functemp var *) emitin ( ord (typename) ); if expr_release then releasenames (op_name); (* because it was a temporary *) end; cfcall: begin emitexpr (rigth); (* note: it is an unary operator *) emit (xfcall); emitin (count_processparam); count_processparam := 0; (* note: the 'endfunccall' is emitted after any indexing,uparrow etc *) end; cendproc: begin emitexpr (rigth); (* note: it is an unary operator *) emit (xendproc); emitin (count_processparam); count_processparam := 0; end; ccallprocess: emitexpr (rigth); (* note: it is an unary operator *) cendprocessparam: begin emitexpr (rigth); (* note: it is an unary operator *) count_processparam := count_processparam + 1; end; (* emission of set_values *) csetlist: emit (xset); cs_element: begin emitboth; emit (xinclude); end; cm_element: begin emitexpr (left); emit (xsetexpr); emitexpr (rigth); emit (xincluderange); end; cendsetlist: begin emitexpr (rigth); (* note: unary operator *) (* note: pass4 will generate its own type description, using this type-nix *) emitid (xendset, op_typename); if expr_release then if not op_packflag then (* dont't release, when const-declaration *) releasenames (op_typename); (* because it was a temporary *) end; cfield: begin emitexpr (rigth); (* nb: field is unary operator *) emit (xfield); emitin (ord (op_name) ); (* field name *) emitin (ord (op_typename) ); (* field type name *) end; cuparrow: begin emitexpr (rigth); (* nb: uparrow is unary operator *) emitid (xarrow, op_typename); end; crange: begin emitexpr (rigth); (* note: unary operator *) emitid (xrange, op_typename); end; cerrorarg, (* midlertidig ************************************** *) cindex: begin emitexpr (left); (* array name etc *) emit (xindexexpr); emitexpr (rigth); (* index expression *) emit (xindex); emitin (ord (op_name) ); (* array type name *) emitin (ord (op_typename) ); (* element type name *) end; cprocessargument: begin (* parameter, describing a process-'call' *) (* emit the argument-expression at once (i.e. the process-params) *) (* and then later simulate a normal argument *) emit (xprocessparam); emit (xvarpointer); emitin ( ord (op_name) ); (* son-var of process *) emitin ( ord (op_typename) ); (* temp var, for addressing the 'processrec' *) emit (xtempointer); emitexpr (rigth); (* emit the process-params *) emit (xarglistsize); emitexpr (left); (* previous routine-ident and arguments *) end; cargument: begin (* argument-list of routine call *) emitexpr (left); (* previous routine-ident and arguments *) emitid (xactual, op_name); emitexpr (rigth); (* argument expression *) emit (xendactual); end; cdoubleparam: begin (* used for repetition in structured array-values *) emitexpr (left); (* emit repeat-value *) emit (xtimes); emitexpr (rigth); (* emit the struc-value *) end; cendvariable: begin (* made by 'cendvariable', if after function call *) emitexpr (rigth); (* note: unary operator *) emit (xendfunccall); end; cstrucarray, cstrucrecord: begin emitboth; (* emit previous struc-elements and value component *) emitid (xstruc, op_typename); end; cendstruc: begin emitexpr (rigth); (* note: it is an unary operator *) emit (xendstruc); end; cendassign: begin emit (xassignstat); emitexpr (left); (* variable *) emit (xbecomes); emitexpr (rigth); (* expression *) emit (xassign); end; cendexchange: begin emit (xexchangestat); emitexpr (left); (* lefthand variable *) emit (xbecomes); emitexpr (rigth); (* rigthhand variable *) emit (xexchange); end; crangefirst: begin emitexpr (left); (* first range *) emit (xgetexpr); emitexpr (rigth); (* last range *) end; cplus: emit_arith (xadd); cminus: emit_arith (xsub); cstar: emit_arith (xmul); cslash, (* until further same as div... *) cdiv: emit_arith (xdiv); cmod: emit_arith (xmod); ceq: emit_arith (xeq); cne: emit_arith (xne); clt: emit_arith (xlt); cle: emit_arith (xle); cgt: emit_arith (xgt); cge: emit_arith (xge); cin: emit_arith (xin); cor: emit_arith (xor); cand: emit_arith (xand); cnot: emit_arith (xnot); cuminus: emit_arith (xneg); cuplus: emitexpr (rigth); (* blind operator *) end (* case opcode of opand *) otherwise if compilertest then comp_error (unknown_opcode); if testoutput then continue_line; if expr_release then begin if op_value <> nilstring then release_string (op_value); if expr = stacktop then stacktop := next; next := freeopands; freeopands := expr; end; expr_level := expr_level - 1; end; (* with expr *) end; (* procedure emitexpr *) procedure emit_and_release (expr: opandptr); (* emits - and releases - the expression *) begin expr_release := true; emitexpr (expr); expr_release := false; (* in case stacktop has been updated, now update nexttop *) nexttop := opands Æ stacktop Å . next; end; procedure prepare_statement; (* the procedure will emit all pending expressions *) (* .... but maybe it should rather test for pending expressions ? *) (**) (* furthermore it will set a flag, used to determine how *) (* a function-identifier should be interpreted *) begin while stacktop <> nilopand do emit_and_release (stacktop); before_assign := true; end; procedure prepare_expression; (* works in coorporation with prepare-statement *) begin before_assign := false; end; procedure emittype (xtypename: nameptr); label 10; (* loop in cscalar *) var name: nameptr; begin with names Æ xtypename Å do with types Æ typ Å do begin if emitted then emitid (xtype, xtypename) else begin (* this is the first time the typename is emitted *) (* emit the whole definition *) emitted := true; case typekind of calias: begin (* output: <type> redeftype(nix) *) emittype (element); emitid (xredeftype, xtypename); end; cscalar: begin (* output: ( scalarid(nix) )* scalardef(nix) *) name := element; (* first scalar name of scalartype *) 10: (* loop *) with names Æ name Å do if namekind = cscalarelem then (* the scalar names are in the common namelist *) if typename = xtypename then begin emitid (xscalarid, name); name := nextname; (* follow chain *) if testoutput then continue_line; goto 10; (* goto loop *) end; emitid (xscalardef, xtypename); end; csubrange: begin (* output: <expr> <expr> subdef(typenix, elementnix) *) emit_and_release (subexpr); (* emit both expressions *) subexpr := nilopand; emitid (xsubdef, xtypename); emitin (ord (index) ); (* nix of element type *) end; cpointer: begin (* output: <type> pointerdef(nix) *) emittype (element); emitid (xpointerdef, xtypename); end; creadonly: begin (* output: <type> frozendef(nix) *) emittype (element); emitid (xfrozendef, xtypename); end; carray: begin (* output: <indextype> <elementtype> (packed) arraydef(nix) *) emittype (index); emittype (element); if packflag (* of array type *) then emitid (xpackedarraydef, xtypename) else emitid (xarraydef, xtypename); end; crecord: begin (* output: *) (* packedrecord/record *) (* ( fieldid(nix) <type> fielddef )* *) (* recdef(nix) *) if packflag (* of record type *) then emit (xpackedrecord) else emit (xrecord); name := element; (* first name in field list *) while name <> nilname do with names Æ name Å do begin if namekind (* of fieldname/local typedef *) = crecfield then begin if testoutput then continue_line; emitid (xfieldid, name); emittype (typename); emit (xfielddef); end; name := nextname; (* follow chain *) end; emitid (xrecdef, xtypename); end; cset: begin (* output: <type> setdef(nix) *) emittype (element); emitid (xsetdef, xtypename); end; cpool: begin (* output: <expr> <type> pooldef(nix) *) emit_and_release (subexpr); subexpr := nilopand; emittype (element); emitid (xpooldef, xtypename); end; cinteger: emitid (xinteger, xtypename); creal: emitid (xreal, xtypename); cniltype: emitid (xniltype,xtypename); cerrorkind: emitid (xerrortype, xtypename); ctext: emitid (xstringtype, xtypename); end (* case typekind *) otherwise if true then write(' unknown typekind = ', ord (typekind)) else comp_error(unknown_typekind); end; (* if not emitted yet *) end; (* with typ/typename *) end; (* procedure emittype *) (*QQQ*) procedure emitformal (plist: nameptr); (* output: ( paramid(nix) <type> cparam/vparam )* *) procedure emit_one_formal (xparamkind: pass3codes); begin if testoutput then continue_line; emitid (xparamid, plist); emittype ( names Æ plist Å . typename ); emit (xparamkind); end; begin while plist <> nilname do with names Æ plist Å do (* namenode of current parameter *) begin case namekind of cfuncval: emit_one_formal (xvarparam); (* function value *) cvaluep: emit_one_formal (xvalueparam); (* value parameter *) cvarp: emit_one_formal (xvarparam); (* var parameter *) ctype, (* implicit type decls *) cundeclared, (* undeclared typenames *) cscalarelem: (* scalar-elems of implicit typedecls *) ; (* no action *) end otherwise comp_error(unknown_paramkind); plist := nextname; (* follow chain *) end; (* while/with plist *) end; procedure emitroutinehead (xname: nameptr); (* 'xname' is the namenode of the routine *) (* if this is second emit of routinehead, i.e. earlier was 'forward' *) (* then emit short description, (* otherwise emit the complete routine head *) begin with names Æ xname Å do (* namenode of routine *) if forward_decl then begin case namekind of cprocess, cprocedure: emitid (xsecprocid, xname); cfunction: emitid (xsecfuncid, xname); end otherwise if compilertest then comp_error (unknown_namekind); end else begin case namekind of cprocess: emitid (xprocessid, xname); cprocedure: emitid (xprocid, xname); cfunction: emitid (xfuncid, xname); end otherwise comp_error(unknown_routinekind); if namekind = cprocess then begin (* emit the son var nix *) emitin (ord (nextname) ); (* 'sonvar' is next to 'processname' *) emitin ( ord (son_typename) ); (* type-nix of 'sonvariable' *) end; (* emit external name of the routine *) emit_extname (opand_procname); (* emit formallist *) emitformal (params); end; (* if first emission of this routine head *) (* set flag to look for first local declaration *) expecting_block := true; end; (* procedure emitroutinehead *) function testprocessparam (xtypename: nameptr; dangerous: boolean) : boolean; (* returns true, if the type contains (or may reach via pointers) *) (* shadow, reference or pool *) (* or *) (* a pointer, which it not protected *) var no_of_pointers : typeptr; (* counts number of tested pointer-types *) checked_pointers : packed array Æ typeptr Å of nameptr; (* contains typenames *) param_error : boolean; procedure test (xtypename: nameptr; dangerous: boolean); var field: nameptr; ptr_index: typeptr; begin if not param_error then with names Æ xtypename Å do (* namenode of the type to be tested *) with types Æ typ Å do (* corresponding typenode *) if Æ t_shadow, t_reference, t_pool Å * contents (* of typenode *) <> ÆÅ then param_error := true else if t_pointer in contents (* of typenode *) then case typekind (* of typenode *) of carray: test (element, dangerous); crecord: begin field := element; while field <> nilname do with names Æ field Å do (* namenode of field *) begin test (typename, dangerous); field := nextname; end; end; creadonly: test (element, false); cpointer: if dangerous then param_error := true else (* test that the outpointed type has'nt been tested already *) (* i.e. 'recursive' pointer *) for ptr_index := niltype to no_of_pointers do if ptr_index = no_of_pointers then begin checked_pointers Æ no_of_pointers Å := element; no_of_pointers := no_of_pointers + 1; test (element, true); (* from now on: really dangerous ... *) end else if checked_pointers Æ ptr_index Å = element then ptr_index := no_of_pointers; (* force fast exit of loop *) end (* case *) otherwise if compilertest then comp_error (unknown_typekind); end; (* procedure test *) begin (* body of testprocessparam *) no_of_pointers := niltype; param_error := false; test (xtypename, dangerous); testprocessparam := param_error; end; (* procedure testprocessparam *) (*QQQ*) (* procedures for handling of label declarations/definitions/use *) procedure pseudodefine (xscopeno: labelrange; xspix: spixrange); (* the label-definition is inserted in the local label-list *) var curlabel: labelptr; multdef : boolean; begin (* test for multiple definition *) curlabel := lastlabel; multdef := false; (* suppose ok *) while curlabel <> nillabel do with labels Æ curlabel Å do begin if labelspix = xspix then begin multdef := true; multflag := true; (* mark the labelnode as inconsistent *) end; curlabel := prevlabel; (* follow chain backwards *) end; (* allocate and initialize a new labelnode *) curlabel := alloc_label; with labels Æ curlabel Å do begin labelspix := xspix; labelscope := xscopeno; labelstate := outside_scope; multflag := multdef; (* mark it as (in)consistent *) used_from_inner_routines := false; prevlabel := lastlabel; (* insert in front of other label defs *) lastlabel := curlabel; (* test for declaration on current namelevel *) searchspix (xspix, namelevel, namelevel); labelname := retrieved_name; (* = nilname, if undeclared *) with names Æ labelname Å do if namekind <> clabel then labelname := nilname; (* test for use from inner routines *) (* if so, it better be defined at outermost labelscope *) if labelname <> nilname then with names Æ labelname Å do if usedlevel >= lowestlevel then (* it has been used *) used_from_inner_routines := true; end; (* with curlabel *) end; (* procedure pseudodefine *) procedure initlabels; (* called at enddeclaration, at 'begin' *) (* initializes the labelnodes from 'pass3labels' *) var lab: labelptr; begin (* set all labelnodes in free-list *) freelabels := nillabel; for lab := nillabel to max_labels do with labels Æ lab Å do begin prevlabel := freelabels; freelabels := lab; end; lastlabel := nillabel; (* initialize list of defined labels *) while convtable Æ labelin (* = rectype in labelfile *) Å = clabeldef do pseudodefine (labelin (* = scopeno *), labelin (* = spix *) ); end; (* procedure initlabels *) procedure definelabel (xscopeno: labelrange; xspix: spixrange); (* searches the local labels to retrieve the wanted label *) var curlabel: labelptr; begin (* check the list of defined labels to produce errors *) curlabel := lastlabel; while curlabel <> nillabel do with labels Æ curlabel Å do if labelspix = xspix then begin if multflag then error (multiple_defined_label); if labelname = nilname then error (label_not_declared); if used_from_inner_routines then error (label_used_from_inner); (* nbnbnb hvem checker erkl paa yderste scope ? *) (* output: label(labelnix) *) emitid (xlabel, labelname); curlabel := nillabel; end else curlabel := prevlabel; end; procedure set_label_state (setscope: boolean); (* used by: begin/end-label-scope *) (* the labelstates, belonging to current labelscope are set *) (* to inside/outside label scope *) var curlabel: labelptr; begin curlabel := lastlabel; while curlabel <> nillabel do with labels Æ curlabel Å do begin (* first: reopen any labels, hidden by this labelscope *) if labelstate = hidden_by_lock_or_channel then if hiddenscope = cur_labelscope then labelstate := inside_scope; (* it must be: clear-scope *) (* second: hide all open labels, if start of lock or channel statements *) if start_of_protected then (* first setscope in lock-channel *) if labelstate = inside_scope then begin labelstate := hidden_by_lock_or_channel; hiddenscope := cur_labelscope; end; (* third: open or close label, when belonging to this labelscope *) if labelscope = cur_labelscope then if setscope then labelstate := inside_scope else labelstate := outside_scope; curlabel := prevlabel; end; (* while/with curlabel *) start_of_protected := false; end; (* procedure set_label_state *) function check_label (labname: nameptr) : pass3errors; (* used when referring to a labelname *) var curlabel: labelptr; begin check_label := noerror; (* suppose found and ok *) with names Æ labname Å do begin if namekind <> clabel then check_label := not_label_name else begin (* check locally declared label *) curlabel := lastlabel; while curlabel <> nillabel do with labels Æ curlabel Å do begin if labelspix = spix (* of labelname *) then begin (* it was locally declared, now check the labelscope *) case labelstate of outside_scope: check_label := label_used_outside_scope; (* i.e. goto leading into control structure *) hidden_by_lock_or_channel: check_label := label_defined_outside_lock_or_channel; (* i.e. goto out of lock or channel statement *) end otherwise; if multflag then check_label := erroneous_label; if labelname = nilname then check_label := label_not_locally_declared; end; curlabel := prevlabel; end; (* while/with curlabel *) (* note: *) (* if label is global to current block, it will be *) (* checked later, that the label is defined in the *) (* outermost labelscope of that block *) end; (* if namekind = label *) end; (* with labname *) end; (* procedure checklabel *) procedure testvalue (opand: opandptr); (* tests that the opand posseses a value *) label 98; begin with opands Æ opand Å do case opcode of cid: with names Æ op_name Å do (* namenode of identifier *) (* certain of the namekinds are illegal in expressions *) case namekind of clabel, cprocess, cprocedure, ctype, cprefix: goto 98; (* error *) cundeclared, (* don't cause error-cascades *) cvar, cvarp, cvaluep, cfuncval, cscalarelem, cconstant: ; (* ok *) cfunction: make_call (opand); (* assume that the paramlist was empty *) end otherwise; (* case *) cindex, cfield, cendstruc, cuparrow, cliteral, cfcall, (* when fielding or indexing on function value *) cendvariable, (* after function call and any fielding or indexing *) cfunctemp, (* used when describing 'processcall' as actual param *) cendsetlist, cdoubleparam, cerrorarg, cplus, cminus, cstar, cslash, cdiv, cmod, ceq, cne, clt, cle, cgt, cge, cin, cor, cand, cnot, cuminus, cuplus: ; (* ok *) end (* case opcode *) otherwise 98: (* error *) begin error (illegal_in_expr); op_typename := error_typename; (* try to prevent error-cascades *) end; end; (* procedure testvalue *) procedure testvariable (opand: opandptr); (* tests that the opand may be used as <variable> *) label 99; (* opand ok *) begin with opands Æ opand Å do case opcode of cindex, cfield, cuparrow: goto 99; (* ok *) cid: with names Æ op_name Å do (* namenode of variable *) case namekind (* of namenode *) of cfunction: make_call (opand); (* terminate an erroneous parameter-less function *) cundeclared, (* don't cause error-cascades *) cvar, cvarp, cvaluep, cfuncval: goto 99; (* ok *) end otherwise (* continue *); (* case namekind *) end otherwise; (* case opcode *) error (not_variable); 99: ; (* ok *) end; (* procedure testvariable *) function testfrozen (opand: opandptr): boolean; var all_tested : boolean; begin testfrozen := false; all_tested := false; repeat with opands Æ opand Å do with names Æ op_typename Å do (* typename of operand *) with types Æ typ Å do (* corresponding typenode *) if typekind = creadonly then begin testfrozen := true; all_tested := true; end else (* follow typenodes backwards for records and arrays *) (* to search for 'readonly' types *) case opcode (* of opand *) of cindex : opand := left; (* follow the array-operand *) cfield : opand := rigth; (* follow the record-operand *) end (* case *) otherwise all_tested := true; until all_tested; end; (* procedure testfrozen *) procedure testassignable (opand: opandptr); (* generates an error, if operand cannot be assigned *) begin testvariable (opand); (* it has to be a variable *) with opands Æ opand Å do with names Æ op_typename Å do (* namenode of operand-type *) with types Æ typ Å do (* corresponding typenode *) if (contents (* of typenode *) * Æ t_semaphore, t_pool, t_reference, t_shadow, t_readonly Å <> ÆÅ) or testfrozen (opand) then error (not_assignable); end; (* procedure testassignable *) procedure testexchangable (opand: opandptr); (* generates en error, if operand cannot be exchanged *) begin testvariable (opand); (* it has to be a variable *) with opands Æ opand Å do with names Æ op_typename Å do (* namenode of operand-type *) with types Æ typ Å do (* corresponding typenode *) if contents (* of typenode *) * Æ t_semaphore, t_pool, t_readonly Å <> ÆÅ then error (not_exchangeable); end; (* procedure testexchangable *) procedure testunpacked (opand: opandptr); (* generates an error, if the operand is packed *) begin with opands Æ opand Å do if op_packflag then error (variable_may_not_be_packed); end; (* procedure testunpacked *) procedure resolve_named_type ( xxtypename: nameptr; var xtypename: nameptr; var xelement: nameptr; var xtypekind: codes); (* ************** *) forward; (* ********* *) procedure resolvetype ( opand: opandptr; var xtypename: nameptr; var xelement: nameptr; var xtypekind: codes); label 10; var local_typename: nameptr; local_element: nameptr; local_kind: codes; begin testvalue (opand); (* the operand must posses a value *) local_typename := opands Æ opand Å . op_typename; 10: (* after stripping of superflous type inf *) with names Æ local_typename Å do with types Æ typ Å do begin if typekind = csubrange then begin local_typename := index; goto 10; end; if typekind = creadonly then begin local_typename := element; goto 10; end; xtypename := local_typename; xtypekind := typekind; xelement := element; if xtypekind = cset then (* resolve element-type *) resolve_named_type (element, xelement, local_element, local_kind); if xtypekind = calias then resolve_named_type (element, local_typename, xelement, xtypekind); end; (* with names,types *) end; (* procedure resolvetype *) procedure resolve_named_type ( xxtypename: nameptr; (* typename to be resolved *) var xtypename: nameptr; var xelement: nameptr; var xtypekind: codes); begin (* seperates the type into its components, stripping subrange etc. *) opands Æ nilopand Å . op_typename := xxtypename; (* use as working cell *) resolvetype (nilopand, xtypename, xelement, xtypekind); end; function unstripfrozen (xtypename: nameptr): nameptr; label 10; begin 10: with names Æ xtypename Å do (* namenode of type *) with types Æ typ Å do (* corresponding typenode *) if typekind = creadonly then begin xtypename := element; (* follow typename-chain *) goto 10; (* repeat search for several 'frozen' in row *) end; unstripfrozen := xtypename; (* deliver unstrip'ed typename *) end; procedure equaltypes (leftop, rigthop: opandptr; wanted_typename: nameptr; errorcode: pass3errors); begin resolvetype (leftop, lefttypename, leftelement, leftbasekind); resolvetype (rigthop, rigthtypename, rigthelement, rigthbasekind); if (lefttypename <> rigthtypename) or (lefttypename <> wanted_typename) then error (errorcode); end; procedure assure (opand: opandptr; wanted_typename: nameptr; errorcode: pass3errors); (* modifies 'optypename' if any error is produced *) begin resolvetype (opand, exprtypename, exprelement, exprbasekind); if exprtypename <> wanted_typename then if exprbasekind <> cerrorkind then (* suppress error-cascades *) begin error (errorcode); with opands Æ opand Å do op_typename := error_typename; end; end; procedure testindex (var xtypename: nameptr); (* tests that the typekind is enumeration kind *) begin resolve_named_type (xtypename, exprtypename, exprelement, exprbasekind); case exprbasekind of cerrorkind, (* don't cause error-cascades *) cinteger, cscalar: ; (* ok *) end otherwise begin error (not_index_type); xtypename := error_typename; end; end; (* procedure testindex *) function testenumeration (opand: opandptr): nameptr; (* works as 'testindex', but works on an opand *) var local_typename: nameptr; begin testvalue (opand); with opands Æ opand Å do begin local_typename := op_typename; testindex (local_typename); op_typename := local_typename; testenumeration := op_typename; end; end; (* procedure testenumeration *) procedure set_procedure; (* handles set-values *) begin case rectype of csetlist: (* prepare s-element or m-element to be binary operators *) newopand (csetlist, nil_typename); cs_element, cm_element: begin rigthtypename := testenumeration (stacktop); if rectype = cm_element then begin lefttypename := testenumeration (nexttop); if lefttypename <> rigthtypename then error (mixed_types_in_setlist); oper (binary, rectype, rigthtypename); rectype := cnocode; (* let rectype describe simple binding *) end; (* compare element-type with previous type in setlist *) with opands Æ nexttop Å do (* previous setlist-element or dummy-element *) if op_typename (* of nexttop *) <> rigthtypename then if op_typename <> nil_typename then (* suppress error for very first element *) error (mixed_types_in_setlist); oper (binary, rectype, rigthtypename); end; cendsetlist: begin (* construct a typenode: set of <typename> *) exprtypename := alloc_namenode; with names Æ exprtypename Å do begin namekind := ctype; typename := nil_typename; typ := alloc_typenode; with types Æ typ Å do begin typekind := cset; element := opands Æ stacktop Å . op_typename; contents := Æ t_simple Å; end; end; (* with exprtypename *) oper (unary, cendsetlist, exprtypename); end; end (* case rectype *) otherwise if compilertest then comp_error (unknown_rectype); end; (* procedure set-procedure *) procedure export_procedure; var errortxt: pass3errors; opand: opandptr; expkind: (undefkind, constkind, varkind); begin case rectype of cexport: begin (* save the external name, to be emitted later *) opand_procname := take_stacktop; end; cexportvalue, cexportsize, cexportdisp, cexportoffset, cexportaddr: begin (* opand_procname holds external name *) (* stacktop holds variable to be exported * (* exportvalue: only const *) (* exportsize : const or var *) (* exportdisp : field (of const or var) *) (* exportoffset: only var *) (* exportaddr : const or var *) resolvetype (stacktop, exprtypename, exprelement, exprbasekind); if exprbasekind <> cerrorkind then begin (* find the identifier, in front of any possible fields *) opand := stacktop; while opands Æ opand Å . opcode = cfield do opand := opands Æ opand Å . rigth; errortxt := noerror; (* suppose no errors... *) (* decide kind of identifier *) with opands Æ opand Å do (* opcode = 'cid' ... *) with names Æ op_name Å do (* namenode of identifier *) case namekind (* of identifier *) of cvar, cvarp, cvaluep, cfuncval: expkind := varkind; cconstant: expkind := constkind; end otherwise expkind := undefkind; case rectype of cexportvalue: if expkind <> constkind then errortxt := const_export_only; cexportsize, cexportdisp, cexportaddr: if (expkind <> constkind) and (expkind <> varkind) then errortxt := const_or_var_export_only else if rectype = cexportdisp then if opand = stacktop (* i.e. no field-operators *) then errortxt := disp_export_must_have_fields; cexportoffset: if expkind <> varkind then errortxt := var_export_only; end; (* case *) if errortxt <> noerror then error (errortxt); end; (* if no error-operand *) case rectype of cexportvalue : emit (xexportvalue); cexportsize : emit (xexportsize); cexportdisp : emit (xexportdispl); cexportoffset: emit (xexportoffset); cexportaddr : emit (xexportaddr); end; emit_extname (opand_procname); emit_and_release (stacktop); emit (xendexport); end; end (* case rectype... *) otherwise if compilertest then comp_error(unknown_rectype); end; (* procedure export-procedure *) function allow_text_literals: boolean; (* implicit parameters: left... and rigth... *) (* returns true, if one is textliteral and the other is ( text or array of char *) begin allow_text_literals := ( ((leftbasekind = ctext) and (rigthbasekind = ctext)) or ((leftbasekind = ctext) and (rigthbasekind = carray) and (rigthelement = char_typename)) or ((rigthbasekind = ctext) and (leftbasekind = carray) and (leftelement = char_typename)) ); end; procedure relation (rel: codes); (* creates a binary operation node, working on top and nexttop *) (* in case of errors, the resulting type etc will be set to error-values *) var rel_error: pass3errors; begin resolvetype (nexttop, lefttypename, leftelement, leftbasekind); resolvetype (stacktop, rigthtypename, rigthelement, rigthbasekind); rel_error := noerror; if rigthbasekind = cerrorkind then leftbasekind := rigthbasekind; (* suppress error-cascades *) case leftbasekind of cscalar: (* both must be scalars, belonging to the same scalar-type *) if (leftbasekind <> rigthbasekind) or (leftelement <> rigthelement) then rel_error := relation_error; carray, ctext, crecord: (* both must belong to the same type, and only '=' or '<>' *) if ((lefttypename <> rigthtypename) and (not allow_text_literals)) or ((rel <> ceq) and (rel <> cne)) then rel_error := relation_error else (* test that the record does'nt contains system types *) with names Æ lefttypename Å do with types Æ typ Å do (* typenode of one of the operands *) if contents * Æ t_semaphore, t_pool, t_reference, t_shadow Å <> ÆÅ then rel_error := relation_error; cpointer: (* both must be pointers to same type, and only '=' or '<>' *) (* note: especially used by the monitor-process... *) if (leftbasekind <> rigthbasekind) or (leftelement <> rigthelement) or ((rel <> ceq) and (rel <> cne)) then rel_error := relation_error; cset: (* both must be sets, with same elementtypes (or empty) *) if (leftbasekind <> rigthbasekind) (* both 'set' *) or ((leftelement <> rigthelement) (* with same element-type *) and (leftelement <> nil_typename) (* allow empty sets *) and (rigthelement <> nil_typename)) or (rel = clt) or (rel = cgt) then rel_error := relation_error; cerrorkind: ; (* anything allowed *) cinteger, creal: (* simple version: demand same type *) if leftbasekind <> rigthbasekind then rel_error := relation_error; end otherwise rel_error := relation_error; (* perform the binary operation *) if rel_error <> noerror then begin oper (binary, rel, error_typename); error (rel_error); end else oper (binary, rel, boolean_typename); end; (* procedure relation *) procedure arithop (operator: codes); (* creates a binary operation node, working on stacktop and nexttop *) (* in case of errors, the resulting type etc will be set to error-values *) var arith_error: pass3errors; begin resolvetype (nexttop, lefttypename, leftelement, leftbasekind); resolvetype (stacktop, rigthtypename, rigthelement, rigthbasekind); arith_error := noerror; if rigthbasekind = cerrorkind then begin lefttypename := error_typename; leftbasekind := rigthbasekind; end; if leftbasekind <> rigthbasekind then arith_error := arithmetic_error else case leftbasekind of cinteger: if operator = cslash then arith_error := real_division_not_implemented; creal: arith_error := real_not_implemented; cset: if ((leftelement <> rigthelement) (* sets with same elementtypes *) and (leftelement <> nil_typename) (* allow empty sets *) and (rigthelement <> nil_typename)) or (operator = cslash) then arith_error := arithmetic_error; cerrorkind: ; (* allow anything *) end otherwise arith_error := arithmetic_error; if arith_error <> noerror then begin oper (binary, operator, error_typename); error (arith_error); end else oper (binary, operator, lefttypename); end; (* procedure arithop *) procedure test_value_compatible (errorcode: pass3errors); (* implicit params: left... and rigth... *) begin if rigthbasekind = cerrorkind then leftbasekind := rigthbasekind; case leftbasekind of carray: (* allow rigth to be text literal, when left is array of char *) if not allow_text_literals then error (errorcode); cpointer: (* both must be pointers to same type ( or to 'niltype' ) *) if (leftbasekind <> rigthbasekind) or ((leftelement <> rigthelement) (* to same type *) and (leftelement <> nil_typename) (* allow pointers to niltype *) and (rigthelement <> nil_typename)) then error (errorcode); cset: (* both must be sets, with same componenttypes (or empty) *) if (leftbasekind <> rigthbasekind) (* both sets *) or ((leftelement <> rigthelement) (* with same element-type *) and (rigthelement <> nil_typename)) (* allow rigth to be empty set *) then error (errorcode); cerrorkind: ; (* anything allowed *) end otherwise error (errorcode); end; (* procedure test_value_compatible *) procedure test_var_compatible (errorcode: pass3errors); (* implicit params: left... and rigth... *) begin if rigthbasekind = cerrorkind then leftbasekind := rigthbasekind; case leftbasekind of cpointer: (* both must be pointers, to same type (or to 'niltype') *) if (leftbasekind <> rigthbasekind) or ((leftelement <> rigthelement) (* pointer to same type *) and (leftelement <> nil_typename) (* allow pointers to niltype *) and (rigthelement <> nil_typename)) then (* suppress error message for the 'nil'-function, with actual shadow ... *) if (leftelement <> nil_typename) or (rigthtypename <> shadow_typename) then error (errorcode); cpool: (* both must be pool, but don't care about 'of-type' *) if leftbasekind <> rigthbasekind then error (errorcode); cerrorkind: ; (* anything allowed *) end otherwise error (errorcode); end; (* procedure test_var_compatible *) procedure testinitialize (xtypename: nameptr; errorcode: pass3errors); (* tests that stacktop may be 'assigned' to a *) (* variable of the given type *) begin (* special test for 'skipparam' *) with opands Æ stacktop Å do if opcode <> cskipparam then begin (*the type-comparison is omitted in case of 'skipparam' *) resolve_named_type (xtypename, lefttypename, leftelement, leftbasekind); resolvetype (stacktop, rigthtypename, rigthelement, rigthbasekind); if lefttypename <> rigthtypename then test_value_compatible (errorcode); end; end; procedure testrange (xtypename: nameptr); (* inserts a 'range-test', in case the type is a subrange *) var local_typename: nameptr; begin local_typename := unstripfrozen (xtypename); with names Æ local_typename Å do (* namenode of simplified type *) with types Æ typ Å do (* corresponding typenode *) if typekind = csubrange then oper (unary, crange, xtypename); end; procedure beginactual; (* called on the left paranthesis in a parameter-list *) label 1, 2; begin 1: (* repeat after parameter-less function-call *) pushcall; (* because of nested calls *) (* decide the kind of argument-list: index, parameter, strucconst *) (* stacktop describes the 'owner' *) with opands Æ stacktop Å do case opcode of cid: with names Æ op_name Å do (* namenode of 'owner' *) case namekind (* of owner *) of cprocess, cprocedure, cfunction: begin prepare_call (stacktop); if namekind = cfunction then if empty_paramlist (params) then begin (* the function did'nt have any formal parameters *) (* therefor the arglist must be an index-list *) terminate_call (stacktop); (* make the function-call *) goto 1; (* start all over again *) (* note: this time the arglist will be taken as an index-list *) end; end; ctype: begin (* the list is a struc-constant *) arglist_owner := op_name; (* remember the namenode of the type *) with types Æ typ Å do (* typenode of the type *) case typekind of carray: begin argkind := cstrucarray; curformal := element; (* typename of array elements *) end; crecord: begin argkind := cstrucrecord; curformal := element; (* first of field-name list *) end; end otherwise begin (* only array-types and record-types may be struc-consts *) argkind := cerrorarg; error (type_must_be_record_or_array); end; (* case typekind *) end; (* case namekind = ctype *) end (* case namekind *) otherwise begin 2: ; (* the argumentlist must be an index-list *) argkind := cindex; curformal := op_typename; (* typename ougth to be name of array-type *) end; end (* case opcode *) otherwise goto 2; (* assume index in all other cases *) end; (* procedure beginactual *) procedure act_param; (* called on: cdoubleparam-cactualparam *) label 5, 10; var sonvar_name: nameptr; loc_tempvar: nameptr; begin (* first bind any possible doubleparam to a single one *) if rectype = cdoubleparam then begin (* nexttop must be integer expression *) assure (nexttop, integer_typename, repetition_type); testvalue (stacktop); with opands Æ stacktop Å do oper (binary, cdoubleparam, op_typename (* propagate typename... *) ); end; (* argkind now describes how to interprete the actualarg *) case argkind of cerrorarg, cindex: begin (* curformal is typename of (supposed) array *) (* test that its typekind is 'carray' *) (* doubleparam is not allowed *) if rectype <> cactualparam then error (double_param_only_in_struc_const); curformal := unstripfrozen (curformal); (* in case the array itself was frozen *) with names Æ curformal Å do (* namenode of type *) with types Æ typ Å do (* corresponding typenode *) begin if argkind <> cerrorarg then (* suppress error-cascade *) case typekind (* of typenode *) of cerrorkind: ; (* nothing, but suppress error-cascade *) carray: begin with opands Æ stacktop Å do if opcode = cskipparam then error (skipparam_only_in_struc_const) else begin (* get basekind of indextype of the array *) resolve_named_type (index, lefttypename, leftelement, leftbasekind); (* get basekind of actual index expression *) resolvetype (stacktop, rigthtypename, rigthelement, rigthbasekind); if lefttypename <> rigthtypename then error (incompatible_index); end; end; end otherwise begin error (subscript_after_nonarray); argkind := cerrorarg; end; (* bind the index-expression to the owner *) oper (binary, argkind, element (* typename of array-element *)); with opands Æ stacktop Å do begin op_name := curformal; (* type-name of array *) op_packflag := packflag (* from typenode of the array *); end; (* let curformal be typename of array-element *) curformal := element; end; (* with curformal *) end; (* argkind = index *) cargument: begin (* curformal is name in formal param list *) while curformal <> nilname do (* skip implicit types and function-return-value *) with names Æ curformal Å do begin case namekind (* of formal name *) of cscalarelem, ctype, cundeclared, (* undeclared typename *) cfuncval: ; (* skip *) cvarp: begin (* check var parameter *) (* first test if the actual is a process-name *) with opands Æ stacktop Å do if opcode = cskipparam then begin error (skipparam_only_in_struc_const); goto 5; end else if opcode = cid then with names Æ op_name Å do (* namenode of identifier *) if namekind = cprocess then begin (* it was really a process-name *) (* exchange the identifier with the corresponding son-variable *) op_name := nextname (* of processname *); with names Æ op_name Å do (* namenode of son-var *) op_typename := typename (* of sonvar *) end; (* actual must be unpacked variable *) testvariable (stacktop); testunpacked (stacktop); (* the formaltype and the actualtype must match exactly, except for 'frozen' *) with opands Æ stacktop Å do (* now: typename = formal typename *) (* op-typename = actual typename *) if typename <> op_typename then begin (* try to remove readonly-marks from formal and actual types *) if unstripfrozen (typename) <> unstripfrozen (op_typename) then begin resolve_named_type (typename (* of curformal *), lefttypename, leftelement, leftbasekind); resolvetype (stacktop, rigthtypename, rigthelement, rigthbasekind); test_var_compatible (illegal_var_param_substitution); end else (* it helped... but in this case formal must be readonly *) if typename = unstripfrozen (typename) then (* formal was'nt frozen, but actual was *) error ( actual_may_not_be_frozen); end; (* if not direct match *) goto 5; end; cvaluep: begin (* check value parameter *) (* first test if the actual is a process-call *) make_call (stacktop); (* if parameter-less *) with opands Æ stacktop Å do if opcode = cskipparam then begin error (skipparam_only_in_struc_const); goto 5; end else if opcode = ccallprocess then begin count_processparam := count_processparam + 1; (* insert extra opands to describe the process-'call' as normal argument *) sonvar_name := op_name; (* get the name from the 'callprocess'-node *) (* get a temporary namenode for describing the 'processrec' *) loc_tempvar := functempvar; (* save the global variable *) functempvar := alloc_namenode; insert_functype (processrec_typename); (* bind the processcall to the normal paramlist *) oper (binary, cprocessargument, functempvar (* = temp variable *) ); with opands Æ stacktop Å do op_name := sonvar_name; (* create an operand, with 'processrec' type *) newopand (cfunctemp, nilname (* irrell typename *)); with opands Æ stacktop Å do op_name := functempvar; (* now: stacktop is a functemp-var, of processrec type *) functempvar := loc_tempvar; (* restore the global variable *) end; with names Æ curformal Å do begin if typename (* of curformal *) = nil_typename then begin (* test certain special std-functions *) if (arglist_owner = succ_procname) or (arglist_owner = pred_procname) then begin (* actual expression has to be enumeration *) rigthtypename := testenumeration (stacktop); insert_functype (rigthtypename); goto 5; end; if arglist_owner = ord_procname then begin (* actual expression has to be enumeration *) rigthtypename := testenumeration (stacktop); goto 5; end; if arglist_owner = abs_procname then begin (* actual expression must be integer (or subrange hereof) *) (* note: in future also real... *) assure (stacktop, integer_typename, illegal_value_param_substitution); insert_functype (integer_typename); goto 5; end; end; (* special functions *) resolve_named_type (typename, lefttypename, leftelement, leftbasekind); resolvetype (stacktop, rigthtypename, rigthelement, rigthbasekind); if lefttypename <> rigthtypename then test_value_compatible (illegal_value_param_substitution); (* note: implicit params: left... and rigth... *) testrange (typename (* of curformal *) ); end; (* with curformal *) goto 5; end; end otherwise if compilertest then comp_error (unknown_namekind); curformal := nextname; (* follow chain *) end; (* with curformal *) (* the formal paramlist was exhausted *) error (too_many_actual_params); 5: ; (* note: see also 'prepare_call' *) (* bind the actual parameter to the owner *) oper (binary, argkind, nilname (* irrell typename *) ); with opands Æ stacktop Å do op_name := curformal; (* let opname point at current formal name *) (* let curformal be the next in formal-list *) with names Æ curformal Å do curformal := nextname; end; (* argkind = cargument *) cstrucarray: begin (* curformal is element typename *) (* check transfer to array-element *) testinitialize (curformal, struc_arr_incompatible); oper (binary, argkind, curformal (* = element typename *) ); end; cstrucrecord: begin (* curformal is name in field list *) while curformal <> nilname do (* skip implicit types in field list *) with names Æ curformal Å do begin if namekind = crecfield then begin (* check transfer to field *) testinitialize (typename, struc_rec_incompatible); goto 10; end; curformal := nextname; end; (* with curformal *) error (too_many_values_in_record_struc); 10: ; (* bind the value to the owner *) with names Æ curformal Å do (* namenode of field name *) begin oper (binary, argkind, curformal (* i.e. fieldname itself *) ); curformal := nextname; end; end; end (* case argkind *) otherwise if compilertest then comp_error (unknown_argkind); end; (* procedure actparam *) (*QQQ*) procedure initialize; var strptr: stringptr; err: pass3errors; begin (* initialize files *) reset (pass1file); reset (pass1labels); rewrite (pass3file); (* initialize conversion table *) for rectype := cnocode to clastcode do convtable Æ ord(rectype) Å := rectype; (* clear error-bitmap *) for err := noerror to lastpass3error do error_bitmap Æ err Å := false; (* initialize stdspix table *) (* all entries are set to: 'max-spix'... this will ensure *) (* that pass1 actually sends out initialization for these *) for rectype := canonymous to cord do stdspix (max_spix, rectype); (* initialize test facilities *) testinput := false; testoutput := false; testing := testinput or testoutput; testlinecnt := 0; call_pass4 := true; (* default = continue with pass4 *) lambda_version := true; (* default = rc3502 *) date (cur_date); time (cur_time); if testing then changeline; cur_lineno := 0; no_of_errors := 0; cur_opandno := 0; emit_lineno := 0; cur_blockno := process_block; (* initialize list structures *) (* initialize 'names' *) insert_in_front := false; (* default is: insert all names in rear *) freenames := nilname; for curname := nilname to max_names do with names Æ curname Å do begin namekind := cundeclared; nextname := freenames; freenames := curname; end; (* initialize 'types' *) freetypename := nilname; dummy_typenode := max_types; (* notice: must have the correct value from the very beginning *) for cur_typenode := niltype to max_types do begin with types Æ cur_typenode Å do begin typekind := cnocode; subexpr := nilopand; end; release_typenode (cur_typenode); end; (* initialize 'dummy_typenode' as the very first one *) cur_typenode := alloc_typenode; if compilertest then if dummy_typenode <> cur_typenode then comp_error (inconsist_alloc); (* initialize 'strings' *) freestrings := nilstring; for strptr := nilstring to max_strings do with strings Æ strptr Å do begin nextstr := freestrings; freestrings := strptr; end; (* initialize 'opands' *) freeopands := nilopand; for stacktop := nilopand to max_opands do with opands Æ stacktop Å do begin next := freeopands; opcode := cerrorarg; (* nbnbnbnbnbnb: skal laves bedre ved lejlighed *) (* initialized because it is used as 'working location' by 'testindex' *) freeopands := stacktop; end; (* initialize variables concerning opands *) stacktop := nilopand; nexttop := nilopand; (* initialize namestack etc *) namelevel := lowestlevel - 1; levelkind := processlevel; lastgloballevel := namelevel; newnamelevel; expecting_block := false; after_funccall := false; expr_release := false; retain_top := false; expr_level := 0; (* i.e. first 'emitexpr' is beginning of expression *) pushnameindex := 0; start_of_protected := false; (* initialize stack for holding arguments *) callindex := 0; argkind := cnocode; curformal := nilname; arglist_owner:= nilname; functempvar := nilname; count_processparam := 0; (* initialize important spix'es *) (* the following construction matches the main-loop *) endpass1 := false; repeat if testing then changeline; rectype := password; case rectype of cnewline: cur_lineno := passin; coption: readoption; cstandardname: standardname; end otherwise endpass1 := true; until endpass1; envir_spix := anonymous_spix; (* used as flag to omit 'typedef' for integer etc *) reset (pass1file); (* start all over again, later *) (* initialze important name/type nodes *) error_typename := alloc_namenode; error_typenode := alloc_typenode; with names Æ error_typename Å do begin spix := anonymous_spix; namekind := cerrorkind; typename := error_typename; typ := error_typenode; end; with types Æ error_typenode Å do typekind := cerrorkind; with types Æ dummy_typenode Å do typekind := cnocode; text_typename := alloc_namenode; with names Æ text_typename Å do begin spix := anonymous_spix; namekind := ctype; typ := alloc_typenode; with types Æ typ Å do typekind := ctext; end; names Æ nilname Å := names Æ error_typename Å; types Æ niltype Å := types Æ dummy_typenode Å; set_error_type; emittype (error_typename); emittype (text_typename); prepare_expression; end; (* procedure initialize *) \f ▶EOF◀