DataMuseum.dk

Presents historical artifacts from the history of:

RC4000/8000/9000

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about RC4000/8000/9000

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download

⟦074162b01⟧ TextFile

    Length: 102912 (0x19200)
    Types: TextFile
    Names: »tpass5pasc«

Derivation

└─⟦2c55ea56f⟧ Bits:30001844 SW-save af projekt 1000, Alarm-system
    └─⟦6b41451d2⟧ 
        └─⟦this⟧ »tpass5pasc« 

TextFile

program pass5prog (in_pass5, out_pass5, ext_pass5, output);

const

default_lambda_version = 3;  (* determines micro-program version *)



var

pass5_ok :  boolean;
in_pass5 : file of integer;
out_pass5 : file of char;
ext_pass5 : file of integer;
lambda_version : integer;


value

pass5_ok = true;
lambda_version = default_lambda_version;



procedure  pass5( var pass5_ok : boolean );

label

   1 ;                   (*  exit on fatal error  *)

const

(*   const.   global for pass5:       *)

ownpassno = 5;  (* pass number of this pass *)
versionpass4 = 300;
versionpass5 = 215; (* 81.05.06 *)

const_niv_0 = 0;
const_size_nn = 16;

(*  repr. of standard values in pascal80 :  *)

const_nil_msp = 16384;    (*  01xxxxxxxxxxxxxx  *)
value_false = 0;
value_true = 1;
(*  masks for ps in reg. set *  *)
ps_mask_resume = 16;


(*  fields in the base_word of a pointer :  *)


c_field_lock = 0;  (*  the field Æ 0 .. 0 Å , i.e.  16 * 0 + 0  *)
c_field_nl = 1;    (*  the field Æ 0 .. 1 Å , i.e.  16 * 0 + 1  *)
c_field_nil = 17;  (*  the field Æ 1 .. 1 Å , i.e.  16 * 1 + 1  *)

(* definition of pass6-tokens *)
zbegin = 'b';
zendlist = '.'; (* end of declaration-list *)
zconst = 'c';
zend   = 'e';
zline  = 'l';
zoption= 'o';
zname  = 'z';
dollar_a = '1'; (* => $a *)
dollar_b = '2'; (* => $b *)
dollar_i = '3'; (* => $i *)

(* definition of identifiers for pass6 *)
c_name = 'c';  (* long constants, dope vectors *)
e_name = 'e';  (* external routines *)
l_name = 'l';  (* labels *)
r_name = 'r';  (* internal routine entries *)
x_name = 'x';  (* case labels *)

(* definition of used identifiers *)
id_entry = 'entry';
id_exit  = 'exit';
id_exception = 'exception';
id_param = 'param';
id_procinf = 'procinf';
id_name  = 'name';
id_except= 'exception';
id_appeval = 'appeval';
id_appstat = 'appstat';
id_default_appetite = 'defapp' ;
id_work    = 'work';
id_linetab = 'linetab';
id_continue= 'continue';
id_rep    = 'rep';
id_endrep   = 'endrep';
(* stdcall *)
id_sucpred = 'sucpred';
(* while *)
id_whrep = 'whrep';
id_whexit= 'whexit';
(* lock *)
id_cont  = 'cont';
id_exc   = 'exc';
(* if *)
id_ifelse = 'ifelse';
id_ifexit = 'ifexit';
(* repeat *)
id_rprep = 'rprep';
(* for *)
id_forrep   = 'forrep';
id_forstore = 'forstore';
id_forexit  = 'forexit';
(* case *)
id_casetab = 'casetab';
id_otherwise= 'otherwise';
id_caseexit= 'caseexit';
(* array-init *)
id_arrayrep = 'arrayrep';
id_index_store = 'ixstore';
(* names from lambda-environment *)
id_level       = 'level';
id_exmask      = 'exmask';
id_expoint     = 'expoint';
id_exic        = 'exic';
id_mkind       = 'mkind';
id_msize       = 'msize';
id_mstart      = 'mstart';
id_semchain    = 'semchain';
id_refchain    = 'refchain';
id_shadowchain = 'shadowchain';
id_osem        = 'osem';
id_oref        = 'oref';
id_oshadow     = 'oshadow';
id_cpexcfirst  = 'cpexcfirst';
id_exappetite  = 'exappetite';
id_exitappetite= 'exitappetite';
id_maxstack    = 'maxstack';
id_bonappetite = 'bonappetite';
id_plinetab    = 'plinetab';
id_rlinetab    = 'rlinetab';
(* misc *)
id_hardset     = 'hardset';

descr_max_param = 30;

c_size_opcode = 5;
c_size_identifier = 12;
c_size_string = 60;
c_size_option_list = 10;


(*  exception no.  , relative to the symbol  cpexcfirst ( see: lambdaenv ) :  *)
c_exc_case = 0;
c_exc_succ = 1;
c_exc_pred = 2;
c_exc_exch = 3;
c_exc_lock = 4;
c_exc_ref = 5;

c_exc_max = 47;

(* constants in pass 4 code *)

(* value of type_v in pass4 code *)

byte_typ = 1;   addr_typ = 5;
word_typ = 2;   set_typ  = 6;
field_typ= 3;
double_typ = 4;

(* values of type_o in pass 4 code *)

bool_typ = 1;      int_typ = 2;     real_typ = 3;     setof_typ = 4;
pointer_typ = 5;   sem_typ = 6;     ref_typ = 7;      shadow_typ = 8;
scalar_typ = 9;

(* compare function number in pass 4 code *)

xeq = 2;        xne = 3;         xlt = 4;
xgt = 5;        xle = 6;         xge = 7;
xeq_set = 8;    xne_set = 9;     xle_set = 10;
xge_set = 11;   xin = 12;        xeq_struc = 13;
xne_struc = 14;

(* std function number in pass 4 code *)

xord = 1;    xsucc = 2;     xpred = 3;     xchr = 4;

(* mode for for statement *)

xup = 1;     xdown = 2;
(* end pass 4 code constants *)


(*   offsets in the Process Descriptor :      *)

pd_count    =  0;
pd_param    =  2;
pd_linked   =  6;
pd_procinf  =  8;
pd_name     = 12;



(*   const. local to modules:       *)

ext_cat_name = 'platonlib';

ext_tab_max = 150;
max_param_table = 500;
ext_max_routine = 150; (* max no of words (of 2 chars each) pr inline routine *)
ext_max_charbuf = 5000; (* number of words in charbuf *)


(*   type definitions global for pass5:     *)

type

option_list = record
  no_of_options : integer;
options : array Æ 1 .. c_size_option_list Å of
record
pno, p1, p2 : integer;
end;
              end;

opcode = (
op_aaaaa,
op_pexit, op_pcals,
op_revgb, op_revlb, op_revib,
op_revgw, op_revlw, op_reviw,
op_revgf, op_revlf, op_revif,
op_revgd, op_revld, op_revid,
op_revsb, op_revsw, op_revsf,
op_revsd, op_revsm,
op_revpd, op_revpw,
op_reaxd,
op_reagd, op_reald, op_reaid,
op_reaad, op_reasd,
op_uadhw, (* unsigned add *)
op_rechw, op_rechd,
op_renpb,
op_renhb, op_stnhb,
op_setst, op_setcr,
op_index, op_inprs, op_inpss,
op_intrs,
op_jmppd, op_jmcht,
op_jmzne, op_jmzeq, op_jmprw,
op_jmzgt, op_jmzlt,
op_stbsa, op_stwsa, op_stxsa,
op_moveg, op_moveb,
op_stvgb, op_stvlb, op_stvib,
op_stvgw, op_stvlw, op_stviw,
op_stvgf, op_stvlf, op_stvif,
op_stvgd, op_stvld, op_stvid,
op_stvsb, op_stvsw, op_stvsf,
op_stvsd,
op_ult  , op_eq   , op_ne   ,
op_lt   , op_gt   , op_le   ,
op_ge   ,
op_seteq, op_setsb, op_setsp,
op_setun, op_setdi, op_setin,
op_not  , op_and  , op_or   ,
op_xor,
op_settm, op_setad, op_stcea,
op_teqad,
op_compl,
op_neg  , op_div  , op_add  ,
op_sub  , op_mul  , op_mod  ,
op_udiv, op_uadd,
op_usub, op_umul, op_umod,
op_mxept, op_mbset, op_mbtes,
op_iocda,
op_csell,
op_cexch,
op_llock, op_lrese,
op_cgreg, op_crget, op_crput,
op_xxxxx);

opcode_range = op_aaaaa .. op_xxxxx;

identifier = packed array Æ 1 .. c_size_identifier Å of char;

exc_code = 0 .. c_exc_max;

string = packed array Æ 1 .. c_size_string Å of char;

context = record
niv : integer;
stack_size : integer;
max_stack_size : integer;
work : integer;
max_work : integer
end;

frame_kind = (g_frame, l_frame, i_frame, s_frame);

addr_kind_type = ( addr, stack_addr, packed_arr );

varvalue_descr = record
kind : integer;
size : integer;
val  : integer;
end;

varaddr_descr = record
kind : addr_kind_type;
access : frame_kind;
niv : integer;
offset : integer;
size : integer
end;

opcode_def = record
opname : packed array Æ 1 .. c_size_opcode Å of char;
opappetite : integer;
end;

pass4codes =
(
xfirstcode,
xmodule,        xeom,           xprocess,       xblock,
xlength,        xendblock,      xbody,          xinitialize,
xstrucinit,     xsimpleinit,    xextexception,    xexception,
xallocpool,     xinitvar,       xinitrecord,    xendinitrec,
xinitarray,     xendinitarr,    xpoolfield,     xinitfield,
xstrucfield,    xendfield,      xelement,       xpoolcomp,
xreccomp,       xendreccomp,    xarraycomp,     xendarray,
xproc,          xextproc,       xfunc,          xextfunc,
xparamtype,     xendbody,       xproccall,      xextproccall,
xendproccall,   xprocessparam,  xendprocessparam,xvarpointer,
xtempointer,    xvalueparam,    xvarparam,      xassignstat,
xleft,          xassign,        xcasestat,      xcase,
xendcase,       xcaserange,     xcaselabel,     xotherwise,
xforstat,       xleftfor,       xforstore,      xdo,
xendfor,        xgoto,
xifstat,        xifexpr,        xelse,          xif,
xrepeat,        xuntil,         xendrepeat,     xwhile,
xwhileexpr,     xendwhile,      xwithstat,      xendwith,
xlockstat,      xlockvar,       xendlock,       xchannel,
xchanvar,       xendchannel,    xexchstat,      xexchange,
xnot,           xneg,           xcompare,       xcompstruc,
xdiv,           xmul,           xmod,           xor,
xadd,           xsub,           xand,           xrangetest,
xconst,         xlconst,        xset,           xinclude,
xincludeint,    xendset,        xdeflix,        xinitconst,
xvar,           xindvar,        xpackedrec,     xaddr,
xindaddr    ,   xpackedarr,     xdope,          xfield,
xindexexpr,     xcindex,        xfunccall,      xfcall,
xextfunccall,   xnewline,       xerror,         xerrortext,
xerrorno,     xoption,
xextprocess,    xcaddr,         xwithvar,       xendfunccall,
xendcaselist,   xendcasestat,   xbegincode,     xendcode,
xcodeline,      xsetconst,       xarglistsize,   xstdfunc,
xsetinit,       xsetexpr,
xlastcode);

pass4codeindex = 0..150;  (* number of pass4codes *)
(* end pass 4 codes *)

pass5errors = (
ext_table_size,      (* ext_tab_max too small *)
ext_param_number,    (* error in user program *)
case_table_size,     (* size_case_table too small *)
case_table_empty,    (* error in user program *)
param_number,        (* error in user program *)
v_stack_size,        (* max_v_stack too small *)
case_label_error,    (* error in user program *)
compiler_error,      (* error in this pass *)
wrong_version,       (* wrong pass4-pass5 combination *)
unknown_lib,         (* platonlib does'nt exist *)
inconsistent_use,    (* error in user program *)
param_error,         (* inconsistent params in open routine *)
param_table_full,    (* max_param_table too small *)
pass4code_error      (* error in input data from pass4 *)
);


(*    type definitions from modules:     *)

usemodes = (sys_use, general_use);
ext_states = (ext_unused, ext_declared, ext_open, ext_closed);

param_index = 1 .. max_param_table;

param_descr = record
kind : integer;
size : integer;
end;

ext_index = 1 .. ext_tab_max;

ext_descr = packed record
state : ext_states;
mode  : usemodes;
id    : identifier;

(* parameter description *)
no_of_param : integer;
paramptr    : param_index;  (* index in param_table *)

(* special variables for open routines *)
appetite  : integer;
wordcount : integer;  (* no of words (of 2 chars each) in open routine *)
firstword : integer;  (* < 0: file position, > 0: index in char buf *)

(* special variables for closed routines *)
no_of_uses : integer;

(* link through ext_declared entries *)
decl_link : integer;
end;

callmodes = (int_call, ext_call, open_call);


  stat_acc_rec =
record

assign :
record

kind_type : array Æ addr_kind_type, 0 .. 6 Å of integer;
size : array Æ 0 .. 15 Å of integer

end;

end;



(*   var. declarations global for pass5:      *)


var

prolog_yes, epilog_yes, compress_yes, callpass6_yes, statacc_yes, summary_yes :  boolean;
old_create : boolean;
openroutine_yes: boolean;


op_table : array Æ opcode_range Å of opcode_def;


descr : record

(* in this variable the Descriptor Segment, part 1 is accumulated. *)

kind :  integer;
name :  identifier;

entry_point,
exit_point,
exception_point :  identifier;

default_appetite : integer;

appetite  : integer;

no_of_params  :  integer;
param  :  array Æ 1 .. descr_max_param Å of
record

kind  :  integer;
size  :  integer

end

end   (*  descr  *);


exc_hard : set of exc_code;

exc_descr : record

state : integer;
internal : boolean;
key : integer;
niv,
lix : integer

end;

c : context;

operand_situation: ( before_opands, after_short_const, after_opands );

op_load : array Æ 1..6 (* type_v *) , frame_kind Å of opcode;
op_store: array Æ 1..4 (* type_? *) , frame_kind Å of opcode;
op_comp : array Æ 1..11 Å of opcode;






(*    var. declarations from the modules:      *)

 in_item_count, in_line_no : integer;
in_options : option_list;
token: pass4codes;
convert_in_code : array Æ pass4codeindex Å of pass4codes;


mess_summ_state : integer;

out_state, out_pos : integer;

out_line_state : boolean;
out_special : boolean;

ext_tab :   array Æ 1 .. ext_tab_max Å of ext_descr;

not_resolved : integer;  (* links through all ext_declared *)
file_position: integer;  (* < 0: before reset, else positin in library file *)
global_paramptr: integer; (* index in param_table, of first free entry *)

param_table : array Æ param_index Å of param_descr;

ext_open_codes:
record
cur_word_ptr : integer; (* points at first free word in charbuf *)
charbuf : array Æ 1 .. ext_max_charbuf Å of integer;
end;


stat_acc :  stat_acc_rec;


value

op_table = (
('aaaaa',  0),
('pexit',  0), ('pcals',  0),                 (* no adjustment *)
('revgb',  2), ('revlb',  2), ('revib',  2),
('revgw',  2), ('revlw',  2), ('reviw',  2),
('revgf',  2), ('revlf',  2), ('revif',  2),
('revgd',  4), ('revld',  4), ('revid',  4),
('revsb', -2), ('revsw', -2), ('revsf', -2),
('revsd',  0), ('revsm', -6),                 (* adjust for <addr> and <size> *)
('revpd',  4), ('revpw',  2),
('reaxd',  4),
('reagd',  4), ('reald',  4), ('reaid',  4),
('reaad',  4), ('reasd',  0),
('uadhw',  0),                                (* unsigned add constant *)
('rechw',  2), ('rechd',  4),
('renpb', -2),
('renhb',  0), ('stnhb',  0),                 (* no adjustment *)
('setst', -6), ('setcr', -4),                 (* adjust for <addr> and(or) <size> *)
('index', -6), ('inprs', -8), ('inpss',-12),
('intrs', -4),
('jmppd', -4), ('jmcht', -2),
('jmzne', -2), ('jmzeq', -2), ('jmprw',  0),
('jmzgt', -2), ('jmzlt', -2),
('stbsa',-10), ('stwsa',-10), ('stxsa',-10),  (* adjust for 2*<addr> and <size > *)
('moveg',-10), ('moveb',-10),                 (* adjust for 2*<addr> and <size> *)
('stvgb', -2), ('stvlb', -2), ('stvib', -2),
('stvgw', -2), ('stvlw', -2), ('stviw', -2),
('stvgf', -2), ('stvlf', -2), ('stvif', -2),
('stvgd', -4), ('stvld', -4), ('stvid', -4),
('stvsb', -6), ('stvsw', -6), ('stvsf', -6),
('stvsd', -8),
('ult  ', -2), ('eq   ', -2), ('ne   ', -2),
('lt   ', -2), ('gt   ', -2), ('le   ', -2),
('ge   ', -2),
('seteq',  2), ('setsb',  2), ('setsp',  2),  (* add result *)
('setun',  0), ('setdi',  0), ('setin',  0),  (* no adjustment *)
('not  ',  0), ('and  ', -2), ('or   ', -2),
('xor ', -2),
('settm',  0),                                (* no adjustment *)
('setad', -2),                                (* remove <newsize> *)
('stcea', -8),
('teqad', -6),                                (* remove 2*<addr>, add boolean *)
('compl',   0),
('neg  ',  0), ('div  ', -2), ('add  ', -2),
('sub  ', -2), ('mul  ', -2), ('mod  ', -2),
('udiv', -2), ('uadd', -2),
('usub', -2), ('umul', -2), ('umod', -2),
('mxept', -2), ('mbset', -2), ('mbtes',  2),
('iocda', -2),
('csell', -2),
('cexch', -8),
('llock', -2), ('lrese',  0),
('cgreg',  2), ('crget',  0), ('crput', -4),
('xxxxx',  0) );

op_load  = (
(op_revgb, op_revlb, op_revib, op_revsb),
(op_revgw, op_revlw, op_reviw, op_revsw),
(op_revgf, op_revlf, op_revif, op_revsf),
(op_revgd, op_revld, op_revid, op_revsd),
(op_reagd, op_reald, op_reaid, op_xxxxx),
(op_reagd, op_reald, op_reaid, op_xxxxx) );

op_store = (
(op_stvgb, op_stvlb, op_stvib, op_stvsb),
(op_stvgw, op_stvlw, op_stviw, op_stvsw),
(op_stvgf, op_stvlf, op_stvif, op_stvsf),
(op_stvgd, op_stvld, op_stvid, op_stvsd) );

op_comp  = (
op_ult, op_eq, op_ne, op_lt, op_gt, op_le, op_ge,
op_seteq, op_seteq,
op_setsb, op_setsp );



(*    procedure declarations global for pass5:      *)



procedure eom;
begin
writeln (out_pass5);
close (in_pass5);
close (out_pass5);
close (ext_pass5);
end;


procedure printhead;
begin
write ('*** pass 5 line ', in_line_no:4, ',  ');
end;


procedure printstatus;
begin
writeln ('   token      =', ord(token));
writeln ('   no of items=', in_item_count);
writeln ('   stack      =', c.stack_size);
writeln ('   work       =', c.work);
end;


procedure error_this_pass (e: pass5errors);
begin
write('compiler error, error code = ', ord(e):1);
end;


procedure abort (e: pass5errors);
begin
write ('compilation terminated by ');
case e of
ext_table_size:         writeln ('external routine table overflow');
ext_param_number:       writeln ('too many params in declaration');
case_table_size:        writeln ('case label table overflow');
v_stack_size:           writeln ('operand stack overflow');
pass4code_error:        writeln ('pass 4 code error');
param_table_full:       writeln ('external routine param table full');
compiler_error:         writeln ('inconsistency in pass5');
wrong_version:          writeln ('wrong pass4/pass5 combination');
end
otherwise error_this_pass(e);
printstatus;
eom; eom;
end;


procedure error (e: pass5errors);
begin
printhead;
case e of
case_table_empty:     writeln ('no labels in case statement');
case_label_error:     writeln ('+decl caselabel');
param_number:         writeln ('too many formal parameters');
unknown_lib:          writeln ('platonlib does not exist');
inconsistent_use:     writeln ('user is not allowed to call system-routines');
end
otherwise abort(e);
pass5_ok := false;
end;


procedure evalstack_error;
begin
printhead;
writeln ('evaluation stack error');
printstatus;
c.stack_size := 0;
end;



procedure  context_eval(  change : integer );

begin

with c do
begin

stack_size := stack_size + change;
if stack_size > max_stack_size then  max_stack_size := stack_size

end

end;



procedure  context_work( change : integer );

begin

with c do
begin

work := work + change;
if work > max_work then max_work := work

end

end;




(*     procedure declarations from the modules:      *)


procedure get_token;

var
found : boolean;
pass5_yes : boolean;
no1, no2, passno : integer;

begin

found := false;

repeat
begin

read (in_pass5, no1);
token := convert_in_code Æ no1 Å;
in_item_count := in_item_count + 1;

case token of
xoption:
begin

read( in_pass5, passno );
read( in_pass5, no1 );
read( in_pass5, no2 );
in_item_count := in_item_count + 3;
pass5_yes := no2 <> 0;

if passno = 5 then
case no1 of
1: prolog_yes := pass5_yes;
2: epilog_yes := pass5_yes;
3: statacc_yes := pass5_yes;
4: compress_yes := pass5_yes;
5: callpass6_yes := pass5_yes;
6: summary_yes := pass5_yes;
7: old_create := pass5_yes;
8: lambda_version := no2;
9: openroutine_yes := pass5_yes;
end
otherwise (* blind *)
else
with in_options do
begin

if passno = 0 then (* version identification *)
if no1 = 4 (* pass 4 *) then
if (no2 div 100 <> versionpass4 div 100) or
(no2 mod 100 < versionpass4 mod 100) then
error (wrong_version);

if out_state = 1 (* after newline *) then
writeln (out_pass5, 'o.', passno, no1, no2, '.')
else

if no_of_options < c_size_option_list then
begin

out_special := true;

no_of_options := no_of_options + 1;
with options Æ no_of_options Å do
begin
pno := passno;
p1  := no1;
p2  := no2;
end;

end

end
end;
xnewline:
begin

read( in_pass5, in_line_no);
in_item_count := in_item_count + 1;

out_special := true;
out_line_state := true;
end;
end
otherwise found := true;

end
until  found;

end; (* get_token *)


procedure skip_token (t: pass4codes);
begin
if token <> t then error (pass4code_error);
get_token;
end;


function  in_integer : integer;

var   i : integer;

begin
read( in_pass5, i );
in_item_count := in_item_count + 1;
in_integer := i;
end;


procedure  in_identifier( var  ident : identifier );

var
i, j, w : integer;

begin

i := 1;

for j := 1 to 12 do
begin

read( in_pass5, w );
in_item_count := in_item_count + 1;

if i <= c_size_identifier then
begin

identÆ i Å := chr( w );
i := i + 1

end;

end;

while i <= c_size_identifier do
begin

identÆ i Å := ' ';
i := i + 1

end;

end (* in_identifier *);


procedure  in_init;

begin
open( in_pass5, 'pass4code' );
reset( in_pass5 );
in_item_count := 0;
in_line_no := 0;
in_options.no_of_options := 0;

(* initialize conversion-table *)
for token := xfirstcode to xlastcode do
convert_in_code Æ ord (token ) Å := token;
(* read first token *)
get_token;

out_line_state := false;  (* suppress previous reading of linenumbers *)
end;




procedure  mess_summary_line( name : identifier;  head_line, begin_line, end_line : integer;
                              appetite : integer; dynamic_variables : boolean ; process_appetite : integer );

var
dyn_mark : alfa;

begin

if summary_yes then
begin

if mess_summ_state = 0 then
begin

(*  print a header for the summary :  *)
writeln;
writeln( '   name        headline beginline endline  appetite(words) default create-size');
writeln;

mess_summ_state := 1

end;
if dynamic_variables then
dyn_mark := '+ dynamic'
else
dyn_mark := ' ';

write( '   ', name, head_line : 6, begin_line : 10, end_line : 8, '  :  ', appetite div 2 : 6 
, dyn_mark  );
if process_appetite <> 0 then
write( process_appetite : 12 );
writeln;

end

end;

procedure out_nl;
var
i : integer;

begin
   writeln( out_pass5 );

   out_state := 1;   out_pos := 0;

if out_special then
begin

out_special := false;

with in_options do
if no_of_options > 0 then
begin
for i := 1 to no_of_options do
with options Æ i Å do
writeln (out_pass5, 'o.', pno, p1, p2, '.');
no_of_options := 0;
end;

if out_line_state then
begin
writeln( out_pass5, 'l. ', in_line_no : 1);
out_line_state := false
end;

end;

end;


procedure  out_char( chr : char );

begin
write( out_pass5, chr );
out_pos := out_pos + 1
end;

procedure out_tab( pos : integer );

begin
if out_pos < pos then
begin
write( out_pass5, ' ' : pos - out_pos);
out_pos := pos;
end
end;


procedure out_integer( i : integer );

begin
if (i > 999) or (i < -99) then
begin
write (out_pass5, i : 6);  out_pos := out_pos + 6;
end
else
begin
write (out_pass5, i : 4);  out_pos := out_pos + 4;
end;
end;


procedure out_identifier( id : identifier );

var
       i, n : integer;

begin

n := c_size_identifier;
while ( idÆ n Å = ' ' ) and ( n > 1 ) do n := n - 1;

write( out_pass5, ' ', id : n );
out_pos := out_pos + n + 1;

end;


procedure out_def( id : identifier );

begin
   if out_state <> 1 then  out_nl;

   out_identifier ( id );
write( out_pass5, '= ' );  out_pos := out_pos + 2;

   out_state := 6
end;


procedure out_label( id : identifier );

begin
   if out_state <> 1 then  out_nl;

   out_identifier( id );
write( out_pass5, ': ' );  out_pos := out_pos + 2;

   out_state := 2
end;


procedure out_lix (id_letter: char; index: integer);
begin
write (out_pass5, id_letter:2, '#', index:1);
out_pos := out_pos + 4;  (* assume normally two-digit indices... *)
end;


procedure out_lix_label (id_letter: char; index: integer);
begin
out_nl;
out_lix (id_letter, index);
out_label (' ');
end;


procedure  out_comment( str : string );
var n: integer;

begin
   if out_state <> 5 then 
   begin
      if not compress_yes then  out_tab( 25 );
write( out_pass5, '; ' );  out_pos := out_pos + 2;
   end;
if not compress_yes then
begin
n := c_size_string;
while (str Æ n Å = ' ') and (n > 1) do n := n-1;
write (out_pass5, str:n);
out_pos := out_pos + n;
end;

   out_state := 5
end;


procedure out_start_param;

begin
case out_state of
3: out_state := 4;
4: out_char(',');
end otherwise error (compiler_error);
end;


procedure out_opcode( op : opcode );

var
      i   : integer;

begin
   if ( out_state <> 1 ) and ( out_state <> 2 ) then  out_nl;

   if not compress_yes then  out_tab( 5 );
with op_table Æ op Å , c do
begin
stack_size := stack_size + opappetite;
if stack_size > max_stack_size then max_stack_size := stack_size;
write (out_pass5, opname);
end;
out_pos := out_pos + c_size_opcode;
   out_state := 3
end;


procedure out_p_id (id: identifier);
begin
out_start_param;
out_identifier (id);
end;


procedure out_p_int (i: integer);
begin
out_start_param;
out_integer (i);
end;


procedure out_expr (id: identifier; i: integer);
begin
out_start_param;
out_identifier (id);
if i >= 0 then out_char ('+');
out_integer (i);
end;


procedure out_op_id (op: opcode; id: identifier);
begin
out_opcode (op);
out_identifier (id);
out_state := 4;
end;


procedure out_op_int (op: opcode; i: integer);
begin
out_opcode (op);
out_integer (i);
out_state := 4;
end;


procedure out_token (t: char);
begin
case t of
dollar_a: begin out_char ('$'); out_char ('a'); end;
dollar_b: begin out_char ('$'); out_char ('b'); end;
dollar_i: begin out_char ('$'); out_char ('i'); end;
end
otherwise
begin
if t <> zendlist then
out_char (t);
out_char ('.');
end;
out_state := 3;
end;


procedure out_init;

begin
open( out_pass5, 'pass5code' );
rewrite( out_pass5 );

out_state := 1;    out_pos := 0;

out_special := false;
out_line_state := false;
writeln (out_pass5, 'o.', 0 (* version id *), ownpassno, versionpass5, '.');

out_nl;

end;


procedure ext_init;
var
key : integer;
begin
not_resolved := -1;
ext_open_codes.cur_word_ptr := 1;
global_paramptr := 1;
file_position := -1;  (* before reset *)
open (ext_pass5, ext_cat_name);
for key := 1 to ext_tab_max do
with ext_tab Æ key Å do
state := ext_unused;
end;


procedure find_ext_routine;
var
key : integer;
begin

key := in_integer;
if key > ext_tab_max then error (ext_table_size);

with ext_tab Æ key Å do
begin
in_identifier (id);
no_of_param := in_integer;
no_of_uses := 0;
paramptr := global_paramptr;

get_token;
while token = xparamtype do
begin
if global_paramptr > max_param_table then error (param_table_full);
with param_table Æ global_paramptr Å do
begin
kind := in_integer;
size := in_integer;
end;
global_paramptr := global_paramptr + 1;
get_token;
end;

state := ext_declared;
decl_link := not_resolved;
not_resolved := key;
end;
end;  (* procedure find_ext_routine *)


procedure ext_copy_code (key : integer);
var
i, c, w : integer;
begin
with ext_tab Æ key Å do
with ext_open_codes do
begin

if firstword < 0 then
begin (* text not in charbuf, position the library-file *)
if (file_position = -1) or (-firstword < file_position) then
begin
reset (ext_pass5);
file_position := 0;
end;
for i := 1 to -(file_position + firstword) do get (ext_pass5);
end;

out_nl;

for i := 1 to wordcount do
begin
if firstword > 0 then
w := charbuf Æ i + firstword - 1 Å
else
read (ext_pass5, w);
c := w div 256;  if c = 10 then out_nl else out_char (chr(c));
c := w mod 256;  if c = 10 then out_nl else out_char (chr(c));
end;
end;
end; (* procedure ext_copy_code *)


procedure ext_scan;
const
size_of_codedescr = 8; (* no of words in descr, containing date etc *)
var
i, codewords, skipwords, codepos,
descr_length, no_of_pages, size_of_page, bytes_on_last_page, kind_of_obj,
app, pno,
curkey, prevkey : integer;
ident : identifier;
paramtab : array Æ 1 .. descr_max_param Å of param_descr;
found : boolean;

begin

reset (ext_pass5);
file_position := 0;

with ext_open_codes do
while not eof(ext_pass5) and (not_resolved > 0) do
begin
read (ext_pass5,
descr_length,
no_of_pages,
size_of_page,
bytes_on_last_page,
kind_of_obj);

(* read name *)
for i := 1 to 6 do
begin
read (ext_pass5, app);
ident Æ i*2-1 Å := chr (app div 256);
ident Æ i*2   Å := chr (app mod 256);
end;
for i := 13 to c_size_identifier do ident Æ i Å := ' ';

(* skip entry points etc *)
for i := 1 to 7 do get (ext_pass5);

read (ext_pass5, app, pno);
if pno > descr_max_param then error (ext_param_number);
for i := 1 to pno do
with paramtab Æ i Å do
read (ext_pass5, kind, size);

file_position := descr_length div 2 + file_position;
codewords := ((no_of_pages - 1) * size_of_page + bytes_on_last_page + 1) div 2;
skipwords := codewords;

if (kind_of_obj = 4) or (kind_of_obj = 5) then
begin (* open routine in library *)

for i := 1 to size_of_codedescr do
begin
get (ext_pass5); (* skip date etc *)
skipwords := skipwords - 1;
codewords := codewords - 1;
end;

curkey := not_resolved;
prevkey := -1;
codepos := - file_position;

repeat
with ext_tab Æ curkey Å do
begin
(* total match is: same name and paramlist *)
if no_of_param = pno then
if id        = ident then
begin
found := true;  (* assume same param-descr *)
for i := 1 to pno do
if param_table Æ paramptr - 1 + i Å <> paramtab Æ i Å then
found := false;
if found then
begin
state := ext_open;
appetite := app;
wordcount := codewords;

if prevkey = -1 then
not_resolved := decl_link
else
ext_tab Æ prevkey Å . decl_link := decl_link;
curkey := prevkey;

if skipwords > 0 then
if skipwords <= ext_max_routine then
(* routine is not too large *)
if cur_word_ptr + skipwords <= ext_max_charbuf then
begin (* there is room in charbuf *)
codepos := cur_word_ptr;
for i := 1 to skipwords do
read (ext_pass5, charbuf Æ i + codepos - 1 Å);
cur_word_ptr := cur_word_ptr + skipwords;
skipwords := 0;
end;

firstword := codepos;
end;
end;
prevkey := curkey;
curkey := decl_link;
end;
until curkey <= 0;
end;

(* skip any remaining part of code-body *)
for i := 1 to skipwords do get(ext_pass5);
file_position := file_position + codewords;
(* skip external link part *)
read (ext_pass5, pno);
file_position := file_position + 1;
for i := 1 to pno do
begin
(* skip external name *)
for pno := 1 to 6 do get (ext_pass5);
file_position := file_position + 6;
(* skip parameter list *)
read (ext_pass5, pno); (* number of params *)
file_position := file_position + 2*pno + 1;
for pno := 2*pno downto 1 do get (ext_pass5);
(* skip number of uses *)
get (ext_pass5);
file_position := file_position + 1;
end;
(* skip internal link part *)
read (ext_pass5, pno);
pno := pno * 4; (* four words per entry *)
for i := 1 to pno do get (ext_pass5);
file_position := file_position + pno + 1;

(* now the libraryfile is positioned at start of next entry *)
end; (* scan of library file *)

(* classify all remaining ext_declared as closed-routines *)
while not_resolved > 0 do
with ext_tab Æ not_resolved Å do
begin
state := ext_closed;
not_resolved := decl_link;
end;

end; (* procedure extscan *)


function getkind (key: integer) : callmodes;
begin
with ext_tab Æ key Å do
begin
if state = ext_declared then ext_scan;
if state = ext_open then
getkind := open_call
else
getkind := ext_call;
end;
end; (* procedure getkind *)


function ext_lookup (var key: integer; look_id: identifier) : callmodes;
var
i : integer;
found : boolean;
begin
i := 1;
found := false;
repeat
with ext_tab Æ i Å do
if state = ext_unused then
i := ext_tab_max + 1
else
if id = look_id then found := true
else
i := i + 1;
until found or (i > ext_tab_max);
if not found then error (compiler_error);
key := i;
ext_lookup := getkind (i);
end; (* procedure getkind *)


procedure  descr_end;

var
i, j, no_of_entries : integer;

begin

writeln (out_pass5, 'd.');
writeln (out_pass5, descr.name);
writeln (out_pass5, descr.kind);
writeln (out_pass5);

writeln (out_pass5, descr.entry_point);
writeln (out_pass5, descr.exception_point);
writeln (out_pass5, descr.exit_point);
writeln (out_pass5);

writeln (out_pass5, descr.default_appetite);
writeln (out_pass5, descr.appetite);
writeln (out_pass5);

writeln (out_pass5, descr.no_of_params);
for i := 1 to descr.no_of_params do
with descr.param Æ i Å do
writeln (out_pass5, kind, ',', size);
writeln (out_pass5);

no_of_entries := 0;
for i := 1 to ext_tab_max do
with ext_tab Æ i Å do
if state = ext_closed (* closed routine *) then
begin
if no_of_uses > 0 then
no_of_entries := no_of_entries + 1
end;

writeln( out_pass5, no_of_entries );

for i := 1 to ext_tab_max do
with ext_tab Æ i Å do
begin
if state = ext_closed (* closed routine *) then
begin
if no_of_uses > 0 then
begin
writeln (out_pass5);
writeln (out_pass5, id);
writeln (out_pass5, no_of_param);
for j := 1 to no_of_param do
with param_table Æ paramptr + j - 1 Å do
writeln (out_pass5, kind, ',', size);
writeln (out_pass5, no_of_uses);
writeln (out_pass5, e_name, '#', i:1);
end;
end;
no_of_uses := 0;
end;
end; (* descr_end *)



procedure code_call_proc
(use: usemodes; callkind: callmodes; key, niv, lix, paramlength: integer);

begin

if callkind <> int_call then
with ext_tab Æ key Å do
begin
no_of_uses := no_of_uses + 1;
if no_of_uses = 1 then
mode := use;
if mode <> use then
error(inconsistent_use);
end;

case callkind of

open_call:
begin
ext_copy_code (key);
with ext_tab Æ key Å do
begin
context_eval (appetite);
context_eval (-appetite-paramlength);
end;
end;

int_call,
ext_call:
begin
out_opcode (op_pcals);  context_eval ( - const_size_nn - paramlength);
out_p_int (const_size_nn - 2 + paramlength);
out_p_int (c.niv - niv);
out_start_param;
if callkind = int_call then
out_lix (r_name, lix)
else
out_lix (e_name, key);

end;

end; (* case *)

end; (* procedure code_call_proc *)


procedure  code_initvar( kind, offset, type_o : integer;
       var ref_count : integer);
forward;


procedure get_niv_offset ( var v : varaddr_descr );

begin
with v do
begin

kind := addr;
niv := in_integer; offset := in_integer;
size := 0;

if niv = const_niv_0 then access := g_frame
else
if niv = c.niv then access := l_frame
else
access := i_frame;

end;
end; (* get niv, offset *)



procedure  load_address( var  v : varaddr_descr; offset_zero : boolean);

(* the execution of this procedure enforces  'v.kind' = 'addr'    *)

begin

case  v.kind  of

addr:
  begin

out_opcode (op_load Æ 5, v.access Å );

if v.access = i_frame then
begin
out_p_int( c.niv - v.niv )
end;

out_p_int( v.offset );

v.kind := stack_addr;   v.offset := 0;   v.access := s_frame;
end;

stack_addr:
  if  ( offset_zero ) and ( v.offset <> 0 ) then
begin
out_opcode( op_reasd );
out_p_int( v.offset );

v.offset := 0
end;

packed_arr: error (compiler_error);

end

end;



procedure  code_exc_trigger( exception_no : integer);

begin

out_opcode( op_rechw );
out_expr (id_cpexcfirst, exception_no);

out_opcode( op_mxept );
out_comment( '   trigger exception no. : ' ); out_integer( exception_no )


end;


procedure  code_allocpool( kind, offset, number, size : integer);

var
w_offset, stack_size, paramlength, key, refs : integer;

begin

(*  init. the semaphore of the pool to nil :  *)

if kind = 2 then
begin

out_opcode( op_revpd )

end;

code_initvar( kind, offset, 6, refs);

out_comment( '   start init. of pool. ' );


(*  prepare call of the routine: _initpool_rc  :  *)

if kind = 2 then
begin

(*  save the address on the stack in a working location:   *)

if offset <> 0 then
begin

out_opcode( op_reasd );
out_p_int (offset);

end;

w_offset := c.work;  context_work( 4 );

out_opcode( op_stvld );
out_expr (id_work, w_offset);
out_comment( '   save address of the pool. ' )

end;
out_op_int (op_renhb, const_size_nn);  context_eval (const_size_nn);
out_comment( '   prepare call of _initpool_rc  . ' );

stack_size := c.stack_size;

(*  generate the actual parameters:  *)

if kind = 1 then 
begin
out_op_int (op_reald, offset);

end

else
if kind = 2 then
begin

out_opcode( op_revld );
out_expr (id_work, w_offset);

context_work( -4 )

end

else
error(compiler_error);

out_op_int (op_rechw, number);

if odd( size ) then size := size + 1;
size := size div 2;
if size = 32768 then size := - size;

out_op_int (op_rechw, size);

paramlength := c.stack_size - stack_size;

code_call_proc (sys_use, ext_lookup (key, '_initpool_rc'), key, const_niv_0, 0, paramlength);

end (* code_allocpool *);


procedure code_set_maxstack (reservation : identifier);
const lm_regno = -7;

begin

out_op_id (op_revgw, id_maxstack);

if reservation <> ' ' then
begin (* decrease maxstack by <reservation> *)
out_op_id (op_uadhw, reservation);
end;

out_opcode (op_cgreg);
out_op_int (op_uadhw, lm_regno);

out_opcode (op_crput);
end;


procedure code_exit;

var
key : integer;

begin

(* let the process use all of the allocated stack!!! *)
code_set_maxstack (' ');

out_op_int (op_renhb, const_size_nn);  context_eval (const_size_nn);

code_call_proc (sys_use, ext_lookup (key, '___exit___rc'), key, const_niv_0, 0, 0);
end; (* procedure code_exit *)


procedure  code_initvar( kind, offset, type_o : integer;
  var ref_count : integer);

var
o_i, o_c : identifier;

begin

ref_count := 0;

case type_o of

5 :   ;

6 :
begin
o_i := id_semchain;  o_c := id_osem
end;

7 :
begin
o_i := id_refchain;  o_c := id_oref;
ref_count := 1
end;

8 :
begin
o_i := id_shadowchain  ; o_c := id_oshadow
end

end
otherwise
error(pass4code_error);

if kind = 1 then
begin

out_op_int (op_rechw, const_nil_msp);
out_op_int (op_stvlw, offset);

if type_o <> 5 then
begin
out_op_id (op_revgd, o_i);
out_opcode (op_stvld);  out_expr (o_c, offset);
out_op_int (op_reald, offset);
out_op_id  (op_stvgd, o_i);
end;

end

else
if kind = 2 then
begin

if type_o <> 5 then
begin

out_opcode( op_revpd )

end;

out_op_int (op_rechw, const_nil_msp);
out_op_int (op_stvsw, offset);

if type_o <> 5 then
begin

if offset <> 0 then
begin
out_op_int (op_reasd, offset);
end;

out_opcode( op_revpd );
out_op_id (op_revgd, o_i);
out_op_id (op_stvsd, o_c);
out_op_id (op_stvgd, o_i);

end

end

else
error(compiler_error);

end  (*  code_initvar  *);



procedure  code_stat_to_dyn( size : integer );

begin

(*  this procedure moves ( conceptually !! ) a block of 'size' bytes
( which must be one or more sets ) from the static part of the 
evaluation stack, to the dynamic part.  *)

context_eval( -size )

end;


procedure  code_dyn_to_stat( size : integer );

begin

(* this procedure has the opposite effect as 'code_stat_to_dyn' *)

context_eval( size )

end;



procedure  code_exception;

const
hard_size_max = 20;

var
key, i, j, p, r, w, hard_size : integer;
hard_set : array Æ 0 .. hard_size_max Å of integer;
callkind : callmodes;

begin

if( exc_descr.state = 1 ) and ( epilog_yes ) then
begin
out_op_id (op_reaad, id_exit);
out_op_id (op_stvgd, id_expoint);

(* read current value of 'resume bit' *)
out_op_int (op_mbtes, ps_mask_resume);
out_op_int (op_rechw, value_false);
out_op_int (op_mbset, ps_mask_resume);

(*  output code to decrease lm ( in the reg. set ) by -exitappetite :  *)

code_set_maxstack (id_exitappetite);

out_op_int (op_renhb, const_size_nn);  context_eval (const_size_nn);
out_op_id  (op_revgw, id_exmask);

with exc_descr do
begin
if internal then
callkind := int_call
else
callkind := getkind (key);
code_call_proc (general_use, callkind, key, c.niv, lix, 2);
end;

(*  calculate :  hard_setÆ 0 .. hard_size Å       *)

if ( c_exc_max div 16 ) > hard_size_max then
error(compiler_error);

for i := 0 to hard_size_max do  hard_setÆ i Å := 0;

for i := 0 to c_exc_max do
if i in exc_hard then
begin

w := i div 16;  p := i mod 16;
r := 1;  for j := p to 14 do r := r*2;
hard_setÆ w Å := hard_setÆ w Å + r

end;

hard_size := hard_size_max;
while ( hard_setÆ hard_size Å = 0 ) and ( hard_size > 0 ) do
hard_size := hard_size - 1;

out_nl;  out_nl;
out_token (zbegin);
out_p_id (id_hardset);
out_token (zendlist);
out_nl;

out_op_id  (op_revgw, id_exmask);
out_op_id  (op_reaad, id_hardset);
out_op_int (op_rechw, 2 * hard_size + 2);

out_opcode( op_revsm );  context_eval( 2 * hard_size + 2 );
out_op_int (op_rechw, 2 * hard_size + 2);

code_stat_to_dyn( 2 * hard_size + 2 + 2 );

out_opcode( op_settm );

out_op_id  (op_jmzgt, id_exit);

(* reestablish maxstack *)

code_set_maxstack (id_bonappetite);

(* restore 'resume bit' *)
out_op_int (op_mbset, ps_mask_resume);

(* prepare return, load address before restoring 'expoint' *)
out_op_id  (op_revgd, id_exic);
out_op_id  (op_reaad, id_exception);
out_op_id  (op_stvgd, id_expoint);

out_opcode( op_jmppd );

out_nl;  out_nl;

out_label( id_hardset );
out_token (zconst);  out_integer( 2 * hard_size + 2 );

for i := 0 to hard_size do
begin
out_nl;
out_tab( 15 );  out_integer( hard_setÆ i Å )
end;

out_nl;
out_token (zend);  (* end of const *)
out_nl;
out_token (zend);  (* end of block *)
out_nl;

end

else
begin

if epilog_yes then error(pass4code_error); (* exceptionnot defined *);

out_op_id (op_jmprw, id_exception);

end

end (* code_exception  *);





procedure  code_ref_remove(ref_count : integer; dyn_refs : boolean);

var
work_size : integer;
jump : opcode;

begin

(* if not dyn_refs then
 remove ( and check = NIL ) 'ref_count' reference_type variables
from the chain of references 
else 
remove all reference type variables of local frame from the chain 
  *)

out_nl;
out_token (zbegin);
out_p_id (id_rep);
out_p_id (id_cont);
out_p_id ( id_endrep );
out_token (zendlist);
out_comment( '   remove and check reference_type variables.' );
if dyn_refs then
begin
out_op_int ( op_reald, -1 );
out_comment ( ' get lf ');
work_size := 6; jump := op_jmprw;
end
else

if ref_count > 1 then
begin
work_size := 2; jump := op_jmzne;
out_op_int (op_rechw, ref_count);
end;
out_label (id_rep);
out_op_id  (op_revgd, id_refchain);

out_opcode ( op_revpd );
if dyn_refs then
begin
out_opcode(op_reaxd);
out_op_int(op_revsw, -9);
out_comment(' push lf.disp ');
out_opcode( op_ult );
out_op_id ( op_jmzne, id_endrep );
out_op_int( op_stnhb, 2 ); (* no context eval here !! *)

out_opcode( op_revpd );
end;

out_opcode( op_revsf );
out_start_param;  out_integer( 0 );
out_start_param;  out_integer( c_field_nil );

out_op_id  (op_jmzne, id_cont);

code_exc_trigger( c_exc_ref);

out_label (id_cont);
out_op_id  (op_revsd, id_oref);
out_op_id  (op_stvgd, id_refchain);
if not dyn_refs then
if ref_count > 1 then
begin
out_op_int (op_uadhw, -1);
out_opcode (op_revpw);
end;
if (ref_count > 1) or dyn_refs then
begin
out_op_id  (jump, id_rep);
out_label(id_endrep);
out_op_int (op_stnhb, work_size);  context_eval (-work_size);
end;

out_nl;
out_token (zend);
out_nl;

end  (* code_ref_remove  *);




procedure  code_line_tab_header( name : identifier );

begin
out_token (zname);
out_p_id (name);
out_nl;
out_token (zend);

end  (*  code_line_tab_header  *);


procedure  stat_reset;

var
i: addr_kind_type;
j : integer;

begin

with stat_acc.assign do
begin

for i := addr to packed_arr do
for j := 0 to 6 do  kind_typeÆ i, j Å := 0;

for j := 0 to 15 do sizeÆ j Å := 0

end

end;


procedure  stat_print;

var
i: addr_kind_type;
j : integer;

begin

writeln;  writeln;
writeln( '   statistics from pass5: ' );
writeln;

writeln( '     assignment: ' );
writeln;
with stat_acc.assign do
begin

for i :=addr to packed_arr do
begin
for j := 0 to 6 do write( kind_typeÆ i, j Å );
writeln
end;
writeln;

for j := 0 to 7 do write( sizeÆ j Å );
writeln;
for j := 8 to 15 do write( sizeÆ j Å );
writeln;

end;

writeln

end;



procedure  stat_assign( l_v : varaddr_descr; l_type, l_size : integer;
      r_v : varvalue_descr );

var
i_kind : addr_kind_type;
i_type : integer;

begin

if statacc_yes then
with  stat_acc.assign do
begin

i_kind := l_v.kind;

i_type := l_type;
if ( i_type > 6 ) or ( i_type < 0 ) then i_type := 0;

kind_typeÆ i_kind, i_typeÅ := kind_typeÆ i_kind, i_type Å + 1;

if ( l_type = 5 ) or ( l_type = 6 ) then
begin

if ( l_size < 0 ) or ( l_size > 15 ) then
sizeÆ 0 Å := sizeÆ 0 Å + 1
else
sizeÆ l_size Å := sizeÆ l_size Å + 1

end

end

end;

procedure   find_exprs( var  v: varvalue_descr);
forward;


procedure   find_operand( var v: varvalue_descr);
forward;
 
 
procedure  find_func_call( var v : varvalue_descr);
forward;


procedure  find_call;
forward;


procedure  find_constants;
forward;


procedure  find_std_call(var v: varvalue_descr);
forward;


procedure  find_arglist;
forward;

procedure   find_statement;
forward;
procedure   find_varvalue( var  v: varvalue_descr);
forward;
procedure   find_varaddr( var  v: varaddr_descr);
forward;


procedure find_init;
forward;


procedure find_processparam;
forward;



procedure   find_assign;


var    l_v  , l_v_stat, templ_v :  varaddr_descr;
       r_v  :  varvalue_descr;
       l_type, l_first, l_number, l_size  : integer;


begin
get_token;

   find_varaddr( l_v);      l_v_stat := l_v;  
if token <> xleft then error(pass4code_error);

   l_type := in_integer;

   if l_type = 3 then
   begin
l_first := in_integer;  l_number := in_integer;
if l_number = 8 then
begin (* optimize 8-bit fields as bytes *)
if l_first = 0 then
l_type := 1   (* left byte, don't change offset *)
else
if l_first = 8 then
begin (* rigth byte, add one to offset *)
l_v.offset := l_v.offset + 1;
l_type := 1;
end;
end;
   end
   else
   if ( l_type = 5 )  or  ( l_type = 6 ) then  l_size := in_integer
else
if l_type = 7 then
get_niv_offset( templ_v );


   if ( l_type = 5 )  or  ( l_type = 6 ) or (l_type = 7) then
          load_address( l_v, true);


   get_token;
find_exprs( r_v);


 (*   here, tests can be inserted in order to check the
      consistency of  "r_v", "l_v" and "l_type".
 *)

  stat_assign( l_v_stat, l_type, l_size, r_v );  

skip_token (xassign);

   case l_v.kind of

 addr:
   begin

      out_opcode( op_storeÆ l_type, l_v.access Å );

      if l_v.access = i_frame then
      begin
         out_start_param;  out_integer( c.niv - l_v.niv )
      end;

      out_start_param;  out_integer( l_v.offset );

      if l_type = 3 then
      begin
         out_start_param;  out_integer( l_first*16 + l_first + l_number -1 )
      end

end;

stack_addr:
   begin

      if l_type = 6 then (* set *)
      begin

if r_v.kind <> 1 then  error(pass4code_error);

if r_v.size <> ( l_size + 2 ) then
begin

if r_v.size > 0 then
begin

code_stat_to_dyn( r_v.size );

r_v.size := 0

end;

out_opcode( op_rechw );
out_start_param;  out_integer( l_size );

out_opcode( op_setad );

code_dyn_to_stat( l_size + 2 )

end;

out_opcode( op_setst );  context_eval( - l_size );

      end  (* l_type = 6 *)

      else

      if l_type = 5 then (* static structure *)
      begin

         out_opcode( op_rechw );
         out_start_param;   out_integer( l_size );
out_opcode (op_moveg)

      end  (* l_type = 5 *)

else

if l_type = 7 then
begin (* dynamic structure *)
with templ_v do
begin
out_opcode( op_load Æ word_typ, access Å );
if access = i_frame then
out_p_int( c.niv - niv );
out_p_int( offset );
end; (* with *)
out_opcode( op_moveg );
end (* l_type = 7 *)

      else

      begin

      (*   l_type = 1, 2, 3 or 4 .  *)

out_opcode (op_store Æ l_type, s_frame Å);

         out_start_param;  out_integer( l_v.offset );

         if l_type = 3 then
         begin

            out_start_param;  out_integer( l_first*16 + l_first + l_number -1 )
         end

      end

end;

packed_arr:
   begin

if( r_v.kind <> 1 ) or ( ( r_v.size <> 0 ) and ( r_v.size <> 2 ) )
         then   error(pass4code_error);

      out_opcode( op_inpss )

end;

   end  (*  case l_v.kind of...  *)

end  (*  find_assign  *);





procedure  find_expr( var  v : varvalue_descr);

const

max_v_stack = 10;

var

(* .... for the Stack module :    *)

v_stack : array Æ 1 .. max_v_stack Å of varvalue_descr;

top_v_stack,
state_v_stack : integer;

(* .... for the rest of the procedure :    *)

v_o1, v_o2, v_r : varvalue_descr;

end_expr : boolean;

type_o, comp, size : integer;

template_v : varaddr_descr;



value

top_v_stack = 0;
state_v_stack = 0;

end_expr = false;


procedure  push_v_stack( v : varvalue_descr );

begin
if top_v_stack >= max_v_stack then
error (v_stack_size)
else
begin
top_v_stack := top_v_stack + 1;
v_stackÆ top_v_stack Å := v
end
end;


procedure  pop_v_stack( var  v : varvalue_descr );

begin
if top_v_stack <= 0 then error(compiler_error);
if state_v_stack = 1 then
begin
v.kind := 0;
v.size := 0
end
else
begin
v := v_stackÆ top_v_stack Å;
top_v_stack := top_v_stack - 1
end
end;


begin

operand_situation := before_opands;

repeat

case token of

xconst,
xlconst,
xfunccall,
xextfunccall,
xstdfunccall,
xprocessparam,
xsetconst,
xset,
xaddr,
xcaddr:
begin

(*   the next item on input is an operand.
     find the operand, and push the descriptor on
     the v_stack :
*)

if operand_situation = after_short_const then
begin
out_opcode (op_rechw);
out_start_param;  out_integer (v_r.val);
operand_situation := after_opands;
end;

find_operand (v_r);

if operand_situation = before_opands then
operand_situation := after_opands;

push_v_stack( v_r )
end;

(*   check the next item to see if it is an operator.
     generate the proper bis-instructions for the operator.
     take the descriptors for the operands from the v_stack,
     and store the descriptor of the result on the v_stack :
*)

xnot :

begin
type_o := in_integer;

if type_o = bool_typ then

out_opcode( op_not )
else (* integer *)
out_opcode( op_compl );


pop_v_stack( v_o1 );
if ( v_o1.kind <> 1 ) or ( v_o1.size <> 2 ) then error(compiler_error);

v_r.kind := 1;   v_r.size := 2;
push_v_stack ( v_r );
get_token;

end;


xneg :

begin

out_opcode( op_neg );

pop_v_stack( v_o1 );
if ( v_o1.kind <> 1 ) or ( v_o1.size <> 2 ) then error(compiler_error);

v_r.kind := 1;  v_r.size := 2;
push_v_stack( v_r );
get_token;

end;



xcompare :

begin

comp := in_integer;

if ( comp >= 1 ) and ( comp <= 7 ) then
begin

out_opcode( op_compÆ comp Å );

pop_v_stack( v_o2 );   pop_v_stack( v_o1 );
if ( v_o1.kind <> 1 ) or ( v_o1.size <> 2 ) or
   ( v_o2.kind <> 1 ) or ( v_o2.size <> 2 ) then error(compiler_error);

v_r.kind := 1;  v_r.size := 2;
push_v_stack( v_r )

end

else

if ( comp >= 8 ) and ( comp <= 11 ) then
begin

pop_v_stack( v_o2 );  pop_v_stack( v_o1 );
if ( v_o1.kind <> 1) or ( v_o2.kind <> 1 ) then error(compiler_error);

code_stat_to_dyn( v_o1.size + v_o2.size );

out_opcode( op_compÆ comp Å );
if comp = 9 then  out_opcode( op_not );

v_r.kind := 1;  v_r.size := 2;

push_v_stack( v_r )


end

else

if comp = 12 then
begin

pop_v_stack( v_o2 );   pop_v_stack( v_o1 );
if ( v_o1.kind <> 1 ) or ( v_o1.size <> 2 ) or
   ( v_o2.kind <> 1 )   then  error(compiler_error);

code_stat_to_dyn( v_o2.size );

out_opcode( op_settm );

v_r.kind := 1;  v_r.size := 2;
push_v_stack( v_r )

end

else
error(pass4code_error);
get_token;

end;


xcompstruc :

begin

comp := in_integer;   size := in_integer;

pop_v_stack (v_o2);  pop_v_stack (v_o1);
if (v_o1.kind <> v_o2.kind) or
(v_o1.size <> v_o2.size) or
(v_o1.size <> size) then
error (compiler_error);

if v_o1.kind = 2 then
begin (* compare arrays or records *)
out_opcode( op_rechw );
out_start_param;   out_integer( size );

out_opcode( op_stcea );
end
else (* compare pointers *)
out_opcode (op_teqad);
if comp = 14 then
out_opcode( op_not )
else
if comp <> 13 then
error(pass4code_error);


v_r.kind := 1;   v_r.size := 2;
push_v_stack( v_r );
get_token;

end;


xcompdynstruc :

begin

comp := in_integer;

get_niv_offset( template_v );

pop_v_stack ( v_o2 ); pop_v_stack ( v_o1 );

if v_o1.kind = 2 then
begin (* compare arrays or records *)
with template_v do
begin
out_opcode( op_load Æ word_typ, access Å );
if access = i_frame then
out_p_int( c.niv - niv );
out_p_int( offset );
end; (* with *)

out_opcode( op_stcea );

end
else
error( pass4code_error );

if comp = 14 then  (* <> *)
out_opcode( op_not )
else
if comp <> 13 then error( pass4code_error );

v_r.kind := 1; v_r.size := 2;

push_v_stack ( v_r );

get_token;

end; (* comp dyn struc *)


xdiv :

begin

out_opcode( op_div );

pop_v_stack( v_o2 );   pop_v_stack( v_o1 );
if ( v_o1.kind <> 1 ) or ( v_o1.size <> 2 ) or
   ( v_o2.kind <> 1 ) or ( v_o2.size <> 2 ) then error(compiler_error);

v_r.kind := 1;  v_r.size := 2;
push_v_stack( v_r );
get_token;

end;


xadd,
xsub,
xmul :

begin

type_o := in_integer;
if type_o = 3 then
error(compiler_error)
else
if type_o = 2 then
begin

if token = xadd then out_opcode( op_add )
else
if token = xsub then out_opcode( op_sub )
else
out_opcode( op_mul );

pop_v_stack( v_o2 );   pop_v_stack( v_o1 );
if ( v_o1.kind <> 1 ) or ( v_o1.size <> 2 ) or
   ( v_o2.kind <> 1 ) or ( v_o2.size <> 2 ) then error(compiler_error);

v_r.kind := 1;  v_r.size := 2;
push_v_stack( v_r )

end

else

if type_o = 4 then
begin

pop_v_stack( v_o2 );  pop_v_stack( v_o1 );
if ( v_o1.kind <> 1 ) or ( v_o2.kind <> 1 ) then error(compiler_error);

code_stat_to_dyn( v_o1.size + v_o2.size );

if token = xadd then out_opcode( op_setun )
else
if token = xsub then out_opcode( op_setdi )
else
out_opcode( op_setin );

v_r.kind := 1;   v_r.size := 0;
push_v_stack( v_r )

end

else
error(pass4code_error);
get_token;

end;


xor,
xxor,
xand :
begin

if token = xor then out_opcode( op_or )
else
if token = xxor then out_opcode ( op_xor )
else
out_opcode( op_and );

pop_v_stack( v_o2 );   pop_v_stack( v_o1 );
if ( v_o1.kind <> 1 ) or ( v_o1.size <> 2 ) or
   ( v_o2.kind <> 1 ) or ( v_o1.size <> 2 ) then error(compiler_error);

v_r.kind := 1;   v_r.size := 2;
push_v_stack( v_r );
get_token;

end;


xmod :

begin

out_opcode( op_mod );

pop_v_stack( v_o2 ) ;  pop_v_stack( v_o1 );
if ( v_o1.kind <> 1 ) or ( v_o1.size <> 2 ) or
   ( v_o2.kind <> 1 ) or ( v_o2.size <> 2 ) then error(compiler_error);

v_r.kind := 1;  v_r.size := 2;
push_v_stack( v_r );
get_token;

end;


xrangetest :

begin

out_opcode( op_reaad );
out_start_param;  out_lix (c_name, in_integer);

out_opcode( op_intrs );
get_token;

end;



xdynrangetest :

begin

if operand_situation = after_short_const then
begin
out_op_int( op_rechw, v_r.val);
operand_situation := after_opands;
end;

get_niv_offset ( template_v );

load_address( template_v, true );   (* ?????????????????????????????????? *)
 out_opcode( op_intrs );

get_token;


end; (* dyn range test *)


xsubdef: (* pop the stack *)
begin

pop_v_stack( v_o2 );

end_expr := true;

end;



end  (*  case  token of ......  *)

otherwise

(*  the input item is neither an operand nor an operator.
    this signals the end of an expression.
*)

end_expr := true

until  
end_expr;


pop_v_stack( v );

if top_v_stack <> 0 then error(compiler_error)


end;  (*  find_exprs  *)









procedure  find_operand( var v: varvalue_descr);

var   size, val   : integer;
v_c : varvalue_descr;
first_set : boolean;


begin

   case token of

 xconst:
   begin
val := in_integer;
if operand_situation = before_opands then
begin
v.val := val;
operand_situation := after_short_const;
end
else
begin
out_opcode (op_rechw);
out_start_param;  out_integer (val);
end;

      v.kind := 1;
      v.size := 2;
get_token;

   end  (* t_const *);

 xlconst:
   begin

      out_opcode( op_reaad );
out_start_param;  out_lix (c_name, in_integer);

      v.kind := 2;
      v.size := in_integer;
get_token;

   end  (* t_lconst *);

xfunccall,
xextfunccall,
xstdfunccall,
xprocessparam:
begin

find_func_call( v)

end  (*  func call  *);

xsetconst :
begin
val  := in_integer;  (* lix for the constant *)
size := in_integer;

out_opcode( op_reaad );
out_start_param;  out_lix (c_name, val);

out_opcode( op_rechw );
out_start_param;  out_integer( size );

out_opcode( op_revsm );  context_eval( size );
out_op_int (op_rechw, size);

v.kind := 1;
v.size := size + 2;
get_token;

end;

xset :
begin

first_set := true;
get_token;

repeat
begin

if token <> xendset then
find_exprs (v_c);

case token of
xendset:
begin
(* simulate empty set as:  (. 1 .. 0 .) *)
out_opcode (op_rechd);
out_start_param;  out_integer (1);
out_start_param;  out_integer (0);
end;
xinclude:
begin
out_opcode (op_revpw);
get_token;
end;
xsetexpr:
begin
get_token;
find_exprs (v_c);
skip_token (xincludeint);
end;
end
otherwise error(pass4code_error);

out_opcode( op_setcr );

if not( first_set ) then  out_opcode( op_setun );

first_set := false

end

until token = xendset;

get_token;

v.kind := 1;
v.size := 0
end;

end (* case token *)

otherwise
begin

         find_varvalue( v)

      end


end  (*   find_operand   *);


procedure find_exprs (var v: varvalue_descr);
(* similar to find_expr, but always delivers result on stack *)
begin
find_expr (v);
if operand_situation = after_short_const then
begin
out_opcode (op_rechw);
out_start_param;  out_integer (v.val);
operand_situation := after_opands;
end;
end;



procedure  find_func_call( var v : varvalue_descr);

begin

if token = xprocessparam then
find_processparam
else
begin

if token = xstdfunccall then
find_std_call (v)
else
find_call;

skip_token (xfcall);

end;

if token <> xendfunccall then
find_varvalue (v);  (* retrieve result of function-call *)

skip_token (xendfunccall);

end (*  find_func_call  *);



procedure  find_proc_call;

begin

if token = xprocessparam then
find_processparam
else
begin

find_call;

skip_token (xendpcall);

end

end  (*  find_proc_call  *);



procedure  find_call;

var
niv, lix, paramlength, appetite, key, stack_size : integer;
callkind : callmodes;
name, id : identifier;

begin

case token of

xproccall,
xfunccall:
begin (* internal routine *)

niv := in_integer;
lix := in_integer;

callkind := int_call;
end;
xextproccall,
xextfunccall:
begin (* external routine *)
key := in_integer;
niv := const_niv_0;
callkind := getkind (key);
end;

end (* case *)
otherwise error(pass4code_error);

if callkind <> open_call then
begin
(*  push anonymous parameters on the stack:  *)

out_opcode( op_renhb );  context_eval( const_size_nn );
out_start_param;   out_integer( const_size_nn );
out_comment( '   prepare call of closed routine. ' )

end;

stack_size := c.stack_size;

find_arglist;

paramlength := c.stack_size - stack_size;

code_call_proc (general_use, callkind, key, niv, lix, paramlength);


end (*  find_call  *);



procedure  find_constants;

var
n, p, i : integer;

begin

get_token;
while token = xdeflix do
begin

out_lix_label (c_name, in_integer);

get_token;  (* skip: xinitconst *)

n := in_integer;

out_tab( 15 ); out_token (zconst);  out_integer( 2*n );

p := 0;
for i := 1 to n do
begin
if p mod 5 = 0 then
begin
out_nl;   out_tab( 20 )
end
else
out_char (',');
out_integer( in_integer );
p := p + 1
end; 

out_nl;
out_tab( 15 );   out_token (zend);
out_nl;

get_token;
end;
end (*  find_constants  *);


procedure out_make_top_even;
(* make top of stack variable even, i.e. round up *)

begin

out_opcode( op_revpw );
out_op_int( op_rechw, 1 );
out_opcode( op_and );
out_opcode( op_uadd );

end;


procedure compute_number_of_elements ( dope_start : integer );

(* dope_start = ^ record
.                   size,
.                   first_index,
.                   last_index,
.                   element_size : integer;
.                 end

*)

const
one_shift_fifteen = -32768;

begin

out_op_int( op_revlw, dope_start + 4 );
out_comment(' compute no of elems ');
out_op_int( op_rechw, one_shift_fifteen );
out_opcode( op_xor );

out_op_int( op_revlw, dope_start + 2 );
out_op_int( op_rechw, one_shift_fifteen );
out_opcode( op_xor );

out_opcode( op_usub );
out_op_int( op_uadhw, 1 );
out_comment(' last - first + 1 ');

end;



procedure dyn_type_declaration;

var
template_v, template1_v : varaddr_descr;
size, first, last, dope_start : integer;
element_size, fields_pr_word, bits_pr_field : integer;
allign : boolean;
var_val_v : varvalue_descr;

begin

case token of
xarray1template,
xarray2template,
xarray3template : begin

dope_start := in_integer;
get_niv_offset( template_v );
case token of
xarray1template: begin (* dynamic index range, static comp *)
element_size := in_integer;
fields_pr_word := in_integer;
bits_pr_field := in_integer;

with template_v do
begin
(* load (first , last )  *)
out_opcode( op_load Æ double_typ, access Å );
if access = i_frame then
out_p_int( c.niv - niv );
out_p_int( offset + 2 );
end; (* with *)
out_op_int( op_stvld, dope_start + 2 );

if fields_pr_word = 1 then 
begin (* unpacked *)

out_op_int( op_rechw, element_size );
out_comment( ' unpacked dyn array, static comp ' );
if element_size > 2 then (* prepare multiplication *)
out_opcode( op_revpw );
out_op_int( op_stvlw, dope_start + 6 );

(* compute the size *)
compute_number_of_elements ( dope_start );
if element_size > 2 then
out_opcode( op_umul )
else
if element_size = 2 then
begin
out_opcode( op_revpw ); out_comment( ' * 2 (element size) ' );
out_opcode( op_uadd  );
end;
out_op_int( op_stvlw, dope_start );

end

else

begin (* packed array *)

out_op_int( op_rechw, fields_pr_word * 256 + bits_pr_field );
out_comment( ' packed dyn array, static comp ' );
out_op_int( op_stvlw, dope_start + 6 );

compute_number_of_elements( dope_start );
out_opcode( op_revpw );

out_op_int( op_rechw, fields_pr_word );
out_opcode( op_udiv );
out_opcode( op_revpw ); out_comment( ' * 2  ' );
out_opcode( op_uadd );

out_opcode( op_reaxd );  (* get number of elements *)
out_op_int( op_revsw, -3 );

out_op_int( op_rechw, fields_pr_word );
out_opcode( op_umod );
out_op_int( op_uadhw, 1 );
if bits_pr_field > 2 then
begin
out_op_int( op_rechw, bits_pr_field );

out_opcode( op_umul ); out_comment( ' * bits per field ' );
end
else
if bits_pr_field = 2 then
begin
out_opcode( op_revpw ); out_comment( ' * bits per field  (= 2 ) ' );
out_opcode( op_uadd );
end;
out_op_int( op_uadhw, -1 );
out_op_int( op_rechw, 8 );
out_opcode( op_umod );

out_opcode( op_uadd );

out_op_int( op_stvlw, dope_start );

out_op_int( op_stnhb, 2 ); context_eval( -2 );

end; (* packed *)

end; (* array1 template *)

xarray2template: (* static index, dynamic comp *)
begin

first := in_integer;
last  := in_integer;
allign := in_integer = 1;

out_op_int( op_rechw, first );
out_op_int( op_rechw, last  );
out_op_int( op_stvld, dope_start + 2 );

with template_v do
begin
out_opcode( op_load Æ word_typ, access Å );
if access = i_frame then
out_p_int( c.niv - niv );
out_p_int( offset );
end; (* with *)

if allign then out_make_top_even;

out_opcode( op_revpw );
out_op_int( op_stvlw, dope_start + 6 );

out_op_int( op_rechw, last - first + 1 );
out_opcode( op_umul );
out_op_int( op_stvlw, dope_start );

end; (* array2 template *)

xarray3template: (* dynamic index, dynamic comp *)
begin

get_niv_offset( template1_v );
allign := in_integer = 1;

with template1_v do
begin
out_opcode( op_load Æ double_typ, access Å );
if access = i_frame then
out_p_int( c.niv - niv );
out_p_int( offset + 2 );
end; (* wiht template1 *)
out_op_int( op_stvld, dope_start + 2 );

with template_v do
begin
out_opcode( op_load Æ word_typ, access Å );
if access = i_frame then
out_p_int( c.niv - niv );
out_p_int( offset );
end; (* with template *)
if allign then out_make_top_even;
out_opcode( op_revpw );
out_op_int( op_stvlw, dope_start + 6 );

compute_number_of_elemnts( dope_start );
out_opcode( op_umul );
out_op_int( op_stvlw, dope_start );

end; (* array3 template *)

end; (* case token of *)

get_token;

end; (* array 1, 2, 3 template *)


xrecordtemplate :
begin

size := in_integer; (* size of static part *)

get_niv_offset( template_v );

out_op_int( op_rechw, size );
with template_v do
begin
out_opcode( op_load Æ word_typ, access Å );
if access = i_frame then
out_p_int( c.niv - niv );
out_p_int( offset );
end; (* with template v *)
out_opcode( op_uadd );

get_token;

while token <> xendtemplate do
begin

case token of

xincfield: begin
out_op_int( op_uadhw, 1 );
get_token;
end; (* incfield *)

xfieldsize, xdynfieldsize :
begin

allign := in_integer = 1;
dope_start := in_integer;  (* field template *)

if allign then out_make_top_even;
(* assign to field template *)
out_opcode( op_revpw );
out_op_int( op_stvlw, dope_start );

if token = xfieldsize then
begin
size := in_integer;
if size <> 0 then
out_op_int( op_rechw, size );
end
else
begin
size := -1;  (* <> 0 !!! *)

get_niv_offset( template_v );
with template_v do
begin
out_opcode( op_load Æ word_typ, access Å );
if access = i_frame then
out_p_int( c.niv - niv );
out_p_int( offset );
end; (* with template v *)
end;

if size <> 0 then
out_opcode( op_uadd );

get_token;

end ; (* field size, dyn field size *)
end
otherwise


dyn_type_declaration;

end; (* while  *)

out_op_int( op_stvlw, in_integer );   (* record template *)
get_token;

end; (* record template *)

end
otherwise
if token <> xenddecl then
begin (* must be dynamic subrange type definition *)
(* ---> expr ---> expr ---> subdef( offset )  ---->   *)

find_exprs(  (* load expr1 and expr2  *) var_val_v );

(* initialize template *)
out_op_int( op_rechw, 2 );
if token <> xsubdef then error ( pass4code_error );
dope_start := in_integer;

out_op_int( op_stvlw, dope_start );
out_op_int( op_stvlw, dope_start + 4 );
out_op_int( op_stvlw, dope_start + 2 );
get_token;

end; (* subdef .... *)

end ; (* dyn type declaration *)



procedure find_sys_init( var ref_count : integer; var dyn_refs : boolean );

var 
type_o : integer;
kind, w_offset, offset, number, size, lower, upper : integer;
stack_save : integer;
va, dope_v, template_v : varaddr_descr;


procedure component_init( kind, offset : integer; var ref_count : integer );
(* kind = 1 <=> offset is local frame address of variable to initialize,
kind = 2  <=> (offset = 0) and address on top of stack  *)

var
new_kind, new_offset, refs : integer;



procedure  code_array_init(dynamic : boolean; kind, offset, w_offset, lower, upper, size : integer;
                        var ref_count : integer; templ_v : varaddr_descr );

var
refs : integer;

procedure load_from_template ( template_offset : integer );
begin
with templ_v do
begin
out_opcode( op_load Æ word_typ, access Å );
if access = i_frame then
out_p_int( c.niv - niv );
out_p_int( offset + template_offset );
end; (* with *)
end; (* load from template *)


begin

out_nl;  out_nl;
out_token (zbegin);
out_p_id (id_arrayrep);
out_p_id (id_index_store);
out_token (zendlist);
out_comment( '   initialize an array. ' );
out_nl;  out_nl;
(* pre condition:  lower  <=  upper   !!!   *)

if kind = 1 then
begin

out_opcode( op_reald );
out_start_param;  out_integer( offset );
kind := 2; offset := 0;


end;
if dynamic then
load_from_template ( 2 (* lower bound *) )
else
begin

out_opcode( op_rechw );
out_start_param;  out_integer( lower );
end;

out_op_id( op_jmprw, id_index_store ); (* do not count first time *)

out_label( id_arrayrep );

out_op_int( op_uadhw, 1 );
out_label( id_index_store );


out_opcode (op_stvlw);
out_start_param;  out_integer (w_offset);

out_opcode( op_revpd );
get_token;

component_init( kind, offset, refs );

if dynamic then
begin
load_from_template( 6 (* size *) );
out_opcode( op_uadd );
end
else
begin

out_opcode( op_reasd );
out_start_param;  out_integer( size );
end;
out_comment( '   addr := addr + size  . ' );

out_opcode( op_revlw );
out_start_param;  out_integer (w_offset);

out_opcode( op_revpw );
if dynamic then
load_from_template( 4 (* upper bound *) )
else
out_op_int( op_rechw, upper );

out_opcode( op_ge );
out_comment(' i >= upper ? ' );

out_op_id( op_jmzeq, id_arrayrep );
out_comment(' if i < upper then goto arrayrep ' );


out_opcode( op_stnhb );   context_eval (-6);
out_start_param;  out_integer(6);

out_nl;  out_nl;
out_token (zend);
out_nl;  out_nl;
if dynamic then
ref_count := refs  (* <> 0 if refs defined  *)
else

ref_count :=  refs * ( upper - lower + 1 )


end  (* code array init   *);

begin (* component init *)

ref_count := 0;

case token of

xvarinit :
begin

type_o := in_integer;
code_initvar( kind, offset, type_o, ref_count );
get_token;

end; (* var init *)


xpoolinit :
begin

number := in_integer;
size := in_integer;

code_allocpool ( kind, offset, number, size );
get_token;
 
end; (* pool init *)

xfieldinit,
xdynfieldinit : begin
repeat
if kind = 2 then
out_opcode( op_revpd );

case token of

xfieldinit :
begin
new_offset := offset + in_integer;
new_kind := kind;

end; (* field init *)

xdynfieldinit :
begin

if kind = 1 then
begin
out_op_int( op_reald, offset );
new_kind := 2; new_offset := 0;
end
else
begin 
new_kind := kind; new_offset := offset;
end; (* kind = 2 *)
get_niv_offset( template_v );
with template_v do
begin
out_opcode( op_load Æ word_typ, access Å );
if access = i_frame then
out_p_int( c.niv - niv );
out_p_int( offset );
end; (* with template v *)
out_opcode( op_uadd );

end; (* dyn field init *)
end (* case ... *)
otherwise
error ( pass4code_error );


get_token;
component_init( new_kind, new_offset, refs );
ref_count := ref_count + refs;

until token = xendinitfields;

get_token;

if kind = 2 then
begin
out_op_int( op_stnhb, 4 ); context_eval( -4 );
end;


end; (* field init and dyn field init *)


xarrayinit :
begin

w_offset := in_integer;
lower := in_integer;
upper := in_integer;
size := in_integer;

code_array_init( token = xarraydyninit, kind, offset, w_offset, lower, upper, size,
 refs, dope_v );
ref_count := ref_count + refs;

end; (* array init *)


xarraydyninit :
begin

w_offset := in_integer;
get_niv_offset( dope_v );
code_array_init( token = xarraydyninit, kind, offset, w_offset, 0, 0, 0, refs, dope_v);
ref_count := ref_count + refs;
dyn_refs := dyn_refs or ( refs > 0 );

end; (* array dyn init *)

end (* case *)
otherwise  error(pass4code_error );


end; (* component init *)





begin (* start of: find sys init *)
offset := in_integer;
if token = xsysinit then 
begin
kind := 1;
end
else
begin
out_op_int( op_revld, offset );
kind := 2;
offset := 0;
end;
get_token;
component_init( kind, offset, ref_count );

if (c.work <> 0) or (c.stack_size <> 0) then evalstack_error;

end; (* find sys init *)





procedure  find_block (outermost_level: boolean; param_length : integer; name : identifier );
type
skip_modes = (skip, dont_skip, end_skip, end_skip_block);

var
i, refcount, refs : integer;
var_length, proc_parlength, param_count,
roulix, rouniv : integer;
niv_pd, offset_pd : integer;
old_default_appetite : integer;
old_c : context;
external_pr : boolean;
name_pd : identifier;
line_no : integer;
local_dyn_refs,
end_init: boolean;
begin_line : integer;
jump_state : skip_modes; (* defines current state *)
pending_entry: boolean; (* true, when entry-point not defined yet *)
template_v : varaddr_descr;
dyn_var_offset : integer;
dyn_yes_or_no : boolean;

procedure skip_around (jump: skip_modes);
begin
if jump <> jump_state then
begin
if jump = skip then
begin
out_nl;
out_token (zbegin);
out_identifier (id_continue);
out_token (zendlist);
out_op_id (op_jmprw, id_continue);
end
else
if pending_entry then
begin
pending_entry := false;
(* define the entry-point *)
if outermost_level or (roulix = -1) then
out_label (id_entry);
if roulix <> -1 then
out_lix_label (r_name, roulix);

(* generate a prolog for the body *)
if prolog_yes or (roulix <> -1) then
begin
if old_create and (roulix = -1) then
out_op_int (op_renhb, param_length); (* move past inc-descr and params *)
(* insert link to line-table *)
out_op_id (op_reaad, id_linetab);
if roulix = -1 then
out_op_id (op_stvgd, id_plinetab)
else
out_op_id (op_stvld, id_rlinetab);
(* initialize max-stack register *)
if roulix = -1 then (* process body *)
code_set_maxstack (id_bonappetite);
(* allocate room for local variables *)
out_op_id (op_renhb, id_appstat);
out_nl;
end; (* prolog *)
end (* pending entry *)
else
begin
if jump <> end_skip_block then
out_label (id_continue);
if jump <> end_skip then
begin
out_nl;
out_token (zend);
end;
if jump = end_skip_block then
jump := dont_skip;
end;

jump_state := jump;
end; (* change of jumpstate *)
end; (* procedure skip-around *)

begin (* body of find block *)

if (token = xfunc) or (token = xproc) then
begin
roulix := in_integer;
in_identifier (name);
param_length := in_integer;
get_token;
if outermost_level then
with descr do
begin
exception_point := '0';
exit_point      := '0';
end;
end
else
roulix := -1;  (* i.e. process *)
if token <> xblock then error (pass4code_error);

line_no := in_line_no;
rouniv := in_integer;
get_token;

(* declare global-labels, at outermost level *)
if outermost_level then
begin
out_token (zbegin);
out_p_id (id_entry);
out_p_id (id_exit);
out_p_id (id_exception);
out_p_id (c_name); out_char ('#');
out_p_id (e_name); out_char ('#');
out_p_id (r_name); out_char ('#');
out_p_id (l_name); out_char ('#');
out_token (zendlist);
out_nl;
end;

(* two complete different bodies are recognized: *)
(*   1. code-bodies, i.e. 'beginbody'            *)
(*   2. normal-bodies, i.e. pascal80-generated   *)

if token = xbegincode then
begin (* code-body *)
(* make proper changes to 'descr' *)
i := in_integer;
if roulix <> -1 then (* only functions and procedures may be open-routines *)
if outermost_level and openroutine_yes then
with descr do
begin
entry_point := '0';
appetite    := i;
if kind = 2 then kind := 4
else if kind = 3 then kind := 5;
out_nl;
out_token (zoption);
out_integer (6);  (* pass no *)
out_integer (12); (* option = closed or open body *)
out_integer (0);  (* value = open body *)
out_char('.');    (* end of option *)
end
else
begin (* coderoutine must be closed anyway *)
out_nl;
out_lix_label (r_name, roulix);
end;
(* copy the code *)
out_nl;
get_token;
while token = xcodeline do
begin
for i := in_integer downto 1 do out_char (chr(in_integer));
out_nl;
get_token;
end;
skip_token (xendcode);
end (* code-body *)
else
begin (* normal-body *)

old_c := c;

with c do
begin

niv := rouniv;
stack_size := 0;
max_stack_size := 0;
work := 0;
max_work := 0

end;

(* declare routine-labels *)
out_nl;
out_token (zbegin);
out_p_id (id_appeval);
out_p_id (id_appstat);
out_p_id (id_work);
out_p_id (id_linetab);
out_token (zendlist);
out_nl;

refcount := 0;
local_dyn_refs := false;
dyn_yes_or_no := false;
end_init := false;
jump_state := skip;
pending_entry := true;

if outermost_level and (roulix = -1) then
skip_around (dont_skip);  (* outermost process must start immediatly *)

repeat
case token of
xextproc,
xextfunc:
find_ext_routine;
xproc,
xfunc:
begin
skip_around (skip);
find_block (false, 0-0-0, '******');
end;

xinitialize,
xextexception,
xexception :
begin
skip_around (dont_skip);
find_init;
end;


xsysinit,
xsysdyninit:
begin

skip_around( dont_skip );
find_sys_init( refs, local_dyn_refs );
refcount := refcount + refs;

end; (* sysinit and sysdyninit *)



xprocess,
xextprocess :
begin

external_pr := token = xextprocess;

(* declare inter-process labels *)
out_nl;
out_token (zbegin);
out_p_id (id_param);
out_p_id (id_procinf);
out_p_id( id_default_appetite );
out_p_id (id_name);
out_token (zendlist);

skip_around (skip);
out_comment( '   jump across the process declaration. ' );
out_nl;   out_nl;

offset_pd := in_integer;

in_identifier( name_pd );

if not ( external_pr ) then
begin
proc_parlength := in_integer

end;

(*  copy the parameter description into a constant block:  *)

param_count := in_integer;
out_label (id_param);
out_tab (15); out_token (zconst);
out_integer( 4 * param_count + 2 );
out_nl;   out_tab( 20 );   out_integer( param_count );

for i := 1 to param_count do
begin
get_token;  (* skip: xparamtype *)

out_nl;   out_tab( 20 );
out_integer( in_integer );
out_char (',');
out_integer( in_integer )

end;

out_nl;
out_tab (15); out_token (zend);
out_nl;

if not ( external_pr ) then
begin
out_token (zbegin);
out_p_id (id_entry);
out_p_id (id_exception);
out_p_id (id_exit);
out_token (zendlist);
out_label (id_procinf);
out_token (zconst); out_integer (16);
out_nl;  out_token (dollar_a);  out_p_id (id_entry);
out_nl;  out_token (dollar_a);  out_p_id (id_exception);
out_nl;  out_token (dollar_a);  out_p_id (id_exit);
out_nl;  out_token (dollar_i);  out_p_id( id_default_appetite);
out_nl;  out_token (dollar_i);  out_p_int (proc_parlength);
out_nl;
out_token (zend);
out_nl;

end;

if not ( external_pr ) then
begin
out_label (id_name);
out_token (zconst);  out_p_int (12);

for i := 1 to 12 do
begin

if ( i mod 2 ) = 1 then
begin
out_nl;   out_tab( 20 )
end
else
out_char (',');

out_token (dollar_b);

if i <= c_size_identifier then
out_integer( ord( name_pdÆ i Å ) )
else
out_integer( ord( ' ' ) )

end (*  i  ....  *);
out_nl;
out_token (zend);
out_nl

end;

(*  insert the body of the process declaration:  *)

get_token;
if not ( external_pr ) then
begin
old_default_appetite := descr.default_appetite;
descr.default_appetite := 0;
find_block (false, proc_parlength, name_pd);
out_def( id_default_appetite );
out_integer( descr . default_appetite );

descr . default_appetite := old_default_appetite;
out_nl;
out_token (zend);  out_comment ('end of internal process body');
end;

(*  generate code for the initialization of the Process Descriptor:  *)
skip_around (end_skip);
out_comment( '   initialize the fields in the Process Descriptor. ' );

out_opcode( op_rechw );
out_start_param;   out_integer( 0 );
out_opcode( op_stvgw );
out_start_param;   out_integer( offset_pd + pd_count );

out_op_id (op_reaad, id_param);
out_opcode( op_stvgd );
out_start_param;   out_integer( offset_pd + pd_param );

out_opcode( op_rechw );
out_start_param;
if external_pr then out_integer( 0 )
else out_integer( 1 );
out_opcode( op_stvgw );
out_start_param;   out_integer( offset_pd + pd_linked );

if not ( external_pr ) then
begin
out_op_id (op_reaad, id_procinf);
out_opcode( op_stvgd );
out_start_param;   out_integer( offset_pd + pd_procinf )

end;


if not ( external_pr ) then
begin

out_opcode( op_reagd );
out_start_param;   out_integer( offset_pd + pd_name );
out_op_id (op_reaad, id_name);
out_opcode( op_rechw );
out_start_param;   out_integer( 12 );
out_opcode (op_moveg);

end;

skip_around (end_skip_block);  out_comment ('end ..continue.. block');
out_nl;
out_token (zend);  out_comment ('end of internal process init');
out_nl;

end;


xarray1template, xarray2template, xarray3template,
xrecordtemplate :
begin
skip_around( dont_skip );
 dyn_type_declaration;
end;


xallocdynvar :
begin
skip_around( dont_skip );

dyn_var_offset := in_integer;  (* local frame adress of pointer to the variable *)

out_opcode( op_reaxd );  (* get last used *)
out_op_int( op_reasd, 1 ); (* even start address *)

out_op_int( op_stvld, dyn_var_offset ); (* initialize the pointer *)

(* reserve stack space *)

get_niv_offset( template_v );
with template_v do
begin
out_opcode( op_load Æ word_typ, access Å );
if access = i_frame then
out_p_int( c.niv - niv );
out_p_int( offset );
end; (* with *)

out_make_top_even;
out_opcode( op_renpb );
dyn_yes_or_no := true;

get_token;

end; (* alloc dyn var *)




end (*  case in_token of ......  *)

otherwise
if token <> xenddecl then
begin
skip_around( dont_skip );
dyn_type_declaration;
end
else
end_init := true;
until end_init;

skip_token (xenddecl);

(*  find statements:  *)

begin_line := in_line_no;

skip_around (dont_skip);
find_statement;

(*  find the appetite of the block:  *)

var_length := in_integer;

(*  generate the epilog of the block, depending on process or not:  *)

if roulix <> -1 then
begin (* function or procedure *)
if local_dyn_refs or (refcount > 0) then
code_ref_remove (refcount, local_dyn_refs);
out_opcode (op_pexit);
end
else
begin (* process *)

out_nl;  out_label( id_exit );

if epilog_yes then code_exit;

out_nl;  out_label( id_exception );

code_exception;

end; (* epilog of process *)

(*  define 'work' and the appetite symbols of the block:  *)

out_def( id_work );  out_integer( param_length + var_length - 1 );

out_def( id_appstat );
out_integer( var_length + c.max_work );

out_def( id_appeval );
out_integer( c.max_stack_size );

(*  print a line in the summary :  *)

if roulix <> -1 then
param_length := 0; (* don't include routine params in appetite *)

with descr do
default_appetite := default_appetite + ( var_length + c.max_work + 
  c.max_stack_size + param_length ) div 2;  (* words !! *)
mess_summary_line( name, line_no, begin_line, in_line_no,
 var_length + c.max_work + c.max_stack_size + param_length, dyn_yes_or_no ,
ord( roulix = -1 ) (* if  process *) * descr . default_appetite );


(*  generate the constant section of the block:  *)

find_constants;

(*  generate the line tab. header :  *)

out_nl;
out_label( id_linetab );
code_line_tab_header( name );
(* output an end-of-block *)
out_nl;
out_token (zend);  out_comment ('end of body');
if (c.work <> 0) or (c.stack_size <> 0) then evalstack_error;

c := old_c;

end; (* closed routine *)

if outermost_level then
begin
out_nl;
descr_end;
end;

(* skip endblock-parameters *)
if token <> xendblock then error (pass4code_error);
i := in_integer;
i := in_integer;
get_token;

end; (* find_block *)



procedure find_program;

var
p, param_length : integer;

begin

(* skip environment-declarations *)
while (token = xextproc) or (token = xextfunc) do
find_ext_routine;

repeat

case token of
xmodule:
begin
in_identifier (descr.name);
param_length := 0;
end;
xprocess:
begin
(* skip: offset *)
p := in_integer;
in_identifier (descr.name);
param_length := in_integer;
end;
end otherwise error (pass4code_error);

(* input and store the parameter list *)
descr.no_of_params := in_integer;
if descr.no_of_params > descr_max_params then
error (param_number);
for p := 1 to descr.no_of_params do
begin
get_token;
if token <> xparamtype then error (pass4code_error);
with descr.param Æ p Å do
begin
kind := in_integer;
size := in_integer;
end;
end;

with descr do
begin
entry_point     := id_entry;
exit_point      := id_exit;
exception_point := id_exception;
default_appetite := 0;
appetite        := param_length;
end;

get_token;
case token of
xproc:
descr.kind := 2;
xfunc:
descr.kind := 3;
end
otherwise descr.kind := 1;

find_block (true, param_length, descr.name);

until token = xeom;

out_nl;
out_token (zend);

end; (* find_program *)




procedure  find_std_call (var v:varvalue_descr);

var
i, no, limit : integer;

begin

no := in_integer;

if ( no = xsucc ) or ( no = xpred ) then
limit := in_integer;

(* read the arglist by hand... *)
get_token;
if token <> xvarparam then error (pass4code_error);
get_token;
repeat
case token of
xaddr:
begin
i := in_integer; i := in_integer;
end;
xindaddr: ;
end otherwise error (pass4code_error);
get_token;
until token = xvalueparam;

if in_integer <> 2 (* wordsize *) then error (compiler_error);
get_token;
find_exprs(v);
if v.kind <> 1 then error(compiler_error);

case no of
xord,
xchr: ;

xsucc,
xpred:
begin

out_nl;  out_nl;
out_token (zbegin);
out_p_id (id_sucpred);
out_token (zendlist);

if no = 2 then
out_comment( '   start of std. function :  succ . ' )
else
out_comment( '   start of std. function :  pred . ' );

out_opcode( op_revpw );

out_opcode( op_rechw );
out_start_param;  out_integer( limit );

out_opcode( op_eq );

out_op_id  (op_jmzeq, id_sucpred);

if no = 2 then
code_exc_trigger( c_exc_succ)
else
code_exc_trigger( c_exc_pred);

out_label (id_sucpred);
if no = xsucc then
out_op_int (op_uadhw, 1)
else
out_op_int (op_uadhw,-1);

out_nl;
out_token (zend);
end;
end otherwise error(pass4code_error);

end (*  find_std_call  *);



procedure  find_arglist;
(* note: token undef at entry !! *)

var
type_l, size_l : integer;
v_r : varvalue_descr;
v_l : varaddr_descr ;
end_arglist : boolean;

begin

end_arglist := false;
get_token;
repeat
case token of
xvalueparam:
begin

type_l := in_integer;

if ( type_l = 5 ) or ( type_l = 6 ) then
size_l := in_integer
else
if type_l = 4 then  size_l := 4 else size_l := 2;

get_token;
find_exprs( v_r);

if v_r.kind = 2 then
begin

if type_l <> 5 then error(pass4code_error);

if odd( size_l ) then size_l := size_l + 1;

if size_l <= 4 then
begin
out_opcode (op_load Æ size_l, s_frame Å );
out_start_param;  out_integer (0);
end

else

begin

out_opcode( op_rechw );
out_start_param;  out_integer( size_l );

out_opcode( op_revsm );  context_eval( size_l )

end;

end

else
if type_l = 6 then
begin

if v_r.size <> ( size_l + 2 ) then
begin

if v_r.size > 0 then
code_stat_to_dyn( v_r.size );

out_opcode( op_rechw );
out_start_param;  out_integer( size_l );

out_opcode( op_setad );

code_dyn_to_stat( size_l + 2 )

end;

out_opcode( op_stnhb );   context_eval (-2);
out_start_param;  out_integer( 2 )

end

else
if v_r.size <> size_l then
error(pass4code_error);
end;
xvarparam:
begin
get_token;
find_varaddr (v_l);
load_address (v_l, true);
end;

end
otherwise end_arglist := true;
until end_arglist;

end  (* find_arglist *);







procedure  find_while;

var  v: varvalue_descr;

begin

out_nl;
out_token (zbegin);
out_p_id (id_whrep);
out_p_id (id_whexit);
out_token (zendlist);
out_comment( '   start of while_statement. ' );

out_label( id_whrep );

get_token;
find_expr( v);
if operand_situation = after_short_const then
begin (* optimize on 'while true' *)
if v.val = value_false then
out_op_id (op_jmprw, id_whexit); (* skip on: 'while false' *)
(* don't test on: 'while true' *)
end
else
out_op_id (op_jmzeq, id_whexit);
out_comment( '   exit from while_statement. ' );

skip_token (xwhileexpr);
find_statement;
skip_token (xendwhile);

out_op_id (op_jmprw, id_whrep);
out_label (id_whexit);
out_nl;
out_token (zend);
out_comment( '   end of while_statement. ' );


end  (* find_while *) ;


procedure  find_lock;

var
v : varaddr_descr;
offset, size : integer;

begin
out_nl;
out_comment ('start of lock statement');
get_token;

find_varaddr( v);
load_address( v, true);
while (token <> xlockvar) and (token <> xlockdynvar) do
dyn_type_declaration;

if token = xlockvar then
begin
size := in_integer;
out_op_int( op_rechw, (size + 1) div 2 );
end
else
begin (* dyn lock var *)
get_niv_offset( v );
with v do
begin
out_opcode( op_load Æ word_typ, access Å );
if access = i_frame then
out_p_int( c.niv - niv );
out_p_int( offset );
end; (* with *)
(* convert size from bytes to words *)
out_op_int( op_uadhw, 1 ); out_comment( ' convert to words ' );
out_op_int( op_rechw, 2 );
out_opcode( op_udiv );
end; (* dyn lock var *)

out_op_int (op_llock, in_integer);
out_opcode (op_lrese);

get_token;
find_statement;
skip_token (xendlock);

out_opcode( op_rechw );
out_start_param;  out_integer( 0 );

out_opcode( op_stvsf );
out_start_param;  out_integer( 0 );
out_start_param;  out_integer( c_field_lock );
out_comment( '   end of a lock_statement.' );

end  (*  find_lock  *);



procedure  find_with;

var
v : varaddr_descr;

begin
get_token;
find_varaddr( v);
load_address (v, true);
if token <> xwithvar then error(pass4code_error);

out_opcode( op_stvld );
out_start_param;  out_integer( in_integer );
out_comment( '   save the with_addr. ' );

get_token;
find_statement;
skip_token (xendwith);

end  (*  find_with  *);


procedure  find_exchange;

var
type_v, size : integer;
v1, v2 : varaddr_descr;

begin
get_token;
find_varaddr( v1);
load_address (v1, true);
if token <> xleft then error(pass4code_error);

type_v := in_integer;
if type_v <> 4 then  error(pass4code_error);
get_token;
find_varaddr( v2);
load_address (v2, true);
skip_token (xexchange);
out_opcode (op_cexch);

end  (*  find_exchange  *);




procedure  find_label;

begin
out_lix_label (l_name, in_integer);
get_token;

end  (* find_label *);


procedure  find_goto;

begin

out_opcode( op_jmprw );
out_start_param;  out_lix (l_name, in_integer);
get_token;

end  (*  find_goto  *);


procedure  find_if;

var 
v : varvalue_descr;

begin
out_nl;
out_token (zbegin);
out_p_id (id_ifelse);
out_p_id (id_ifexit);
out_token (zendlist);
out_comment( '   start of if_statement. ' );

get_token;
find_exprs( v);

if ( v.kind <> 1 ) or
   ( ( v.size >= 0 ) and ( v.size <> 2 ) ) then
error(pass4code_error);
out_op_id  (op_jmzeq, id_ifelse);

skip_token (xifexpr);
find_statement;

if token = xelse then
begin
(*    else_part :  *)
out_op_id  (op_jmprw, id_ifexit);
out_label (id_ifelse);

get_token;
find_statement;

out_label( id_ifexit )

end

else

begin
(*    no else_part   *)
out_label (id_ifelse);
end;
out_nl;
out_token (zend);
out_comment( '   end of if_statement. ' );

skip_token (xif);

end (*  find_if  *);



procedure  find_repeat;

var
v : varvalue_descr;

begin
out_nl;
out_token (zbegin);
out_p_id (id_rprep);
out_token (zendlist);
out_comment( '   start of repeat_statement. ' );

out_label( id_rprep );

get_token;
find_statement;

skip_token(xuntil);
find_expr( v);

if ( v.kind <> 1 ) or
   ( ( v.size >= 0 ) and ( v.size <> 2 ) ) then
error(pass4code_error);
if operand_situation = after_short_const then
begin (* optimize on 'repeat ... until false' *)
if v.val = value_false then
out_op_id (op_jmprw, id_rprep); (* don't test on: '... until false' *)
(* exit immediatly on ' ... until true' *)
end
else
out_op_id  (op_jmzeq, id_rprep);

out_nl;
out_token (zend);
out_comment( '   end of repeat_statement. ' );

skip_token (xendrepeat);

end  (*  find_repeat  *);





procedure  find_for;

var
v_l : varaddr_descr;
v_r : varvalue_descr;
offset, type_v, mode, w_offset, remainder : integer;

begin
get_token;
out_nl;
out_token (zbegin);
out_p_id (id_forrep);
out_p_id (id_forstore);
out_p_id (id_forexit);
out_token (zendlist);

find_varaddr( v_l);
(* let intermidiate_frame be indirect-addressed *)
if v_l.access = i_frame then
load_address( v_l, true);

offset := in_integer;   w_offset := in_integer;   type_v := in_integer;

if ( type_v <> 1 ) and ( type_v <> 2 ) then
error(pass4code_error);

if v_l.kind <> addr then
begin
(* neither global nor local fram *)

out_opcode( op_revpd );

out_opcode( op_stvld );
out_start_param;   out_integer( offset );
out_comment( '   store addr. of the contr. var. ' );
end;

get_token;
find_exprs( v_r);
if ( v_r.kind <> 1 ) or ( ( v_r.size >= 0 ) and ( v_r.size <> 2 ) ) then
error(pass4code_error);

out_opcode( op_revpw );

get_token;
find_exprs( v_r);

if ( v_r.kind <> 1 ) or ( ( v_r.size >= 0 ) and ( v_r.size <> 2 ) ) then
error(pass4code_error);

out_opcode( op_revpw );

out_opcode( op_stvlw );
out_start_param;  out_integer(w_offset);
out_comment( '   save the limit value. ' );

mode := in_integer;
if ( mode <> 1 ) and ( mode <> 2 ) then
error(pass4code_error);

if mode = 1 then  out_opcode( op_le ) else  out_opcode( op_ge );
out_comment( '   compare the limit with the initial value . ' );
out_op_id  (op_jmzgt, id_forstore);
out_op_id  (op_jmprw, id_forexit);
out_label (id_forrep);

out_opcode ( op_uadhw );  (* increase or decrease *)
out_start_param;
if mode = 1 then out_integer (1)
else out_integer (-1);

out_label (id_forstore);
out_opcode (op_store Æ type_v, v_l.access Å );
out_start_param;  out_integer( v_l.offset );

get_token;
find_statement;
skip_token (xendfor);

if v_l.access = s_frame then

begin

out_opcode( op_revld );
out_start_param;  out_integer( offset );
out_comment( '   increment the contr. var. ' );

out_opcode( op_revpd );

end;

out_opcode (op_load Æ type_v, v_l.access Å );
out_start_param;  out_integer (v_l.offset);

out_opcode( op_revpw );

out_opcode( op_revlw );
out_start_param;  out_integer(w_offset);
if mode = 1 then
out_opcode ( op_lt )
else
out_opcode ( op_gt );
out_comment( '   check if limit is reached. ' );
out_op_id  (op_jmzgt, id_forrep);
out_label (id_forexit);

if v_l.access <> s_frame then
remainder := 2
else
remainder := 6;

out_opcode( op_stnhb );  context_eval( -remainder );
out_start_param; out_integer( remainder );

out_nl;
out_token (zend);
out_comment( '   end of for_statement. ' );


end  (*  find_for  *);



procedure  find_channel;

var
v : varaddr_descr;

begin
get_token;
out_op_id (op_revgb, id_level);  (* save oldlevel *)
find_varaddr( v);
load_address (v, true);
out_opcode (op_lrese);
out_opcode (op_revpd);

out_opcode( op_iocda );

out_opcode( op_csell );

skip_token (xchanvar);
find_statement;
skip_token (xendchannel);

out_opcode( op_rechw );
out_start_param;  out_integer( 0 );
out_op_int (op_stvsf, 0);
out_p_int (c_field_lock);

out_opcode( op_csell );  (* restore oldlevel *)

end  (*  find_channel  *);




procedure  find_case;

const
size_case_table = 30;

type
table_entry = record
first : integer;
last : integer;
x_index : integer;
end;

var
table : array Æ 1 .. size_case_table Å of table_entry;
v_r : varvalue_descr;
first, last , contents_of_table : integer;
otherwise_found : boolean;


procedure  add_to_table( f, l : integer);
var
i,j : integer;
begin
if f > l then
error (case_label_error)
else
begin
i := contents_of_table + 1;

repeat
i := i - 1;
until (i = 0) or (table Æ i Å . last < f);

if (i >= 0) and (i < contents_of_table) and (table Æ i+1 Å . first <= l) then
error (case_label_error)
else
begin (* the new entry is ok, so insert it between 'i' and 'i+1' *)
if contents_of_table = size_case_table then
error (case_table_size);
for j := contents_of_table downto i+1 do
table Æ j+1 Å := table Æ j Å;
contents_of_table := contents_of_table + 1;
with table Æ i+1 Å do
begin
first := f;
last  := l;
x_index := contents_of_table;
end;
out_lix_label (x_name, contents_of_table);
end;
end;
end; (* procedure add-to-table *)


procedure  out_table;

var
t : table_entry;
i, j, min, max, next : integer;
position_found : boolean;

begin

(*  output the sorted table as a single constant :  *)
if contents_of_table <= 0 then
begin (* empty case-table, simulate inconsistent case-range! *)
min := 1;
max := 0;
end
else
begin
min := table Æ 1 Å . first;
max := table Æ contents_of_table Å . last;
end;

out_label( id_casetab );   out_tab( 15 );
out_token (zconst);   out_integer( ( max - min + 1 ) * 4 + 8 );
out_comment( '   start of case_jump table. ' );
out_nl; out_token (dollar_i); out_integer (min);
out_nl; out_token (dollar_i); out_integer (max);
out_nl; out_token (dollar_a); out_identifier (id_otherwise);


next := min;

for i := 1 to contents_of_table do
with table Æ i Å do
begin

while next < first do
begin
out_nl; out_token (dollar_a); out_identifier (id_otherwise);
next := next + 1

end;

while next <= last do
begin
out_nl; out_token (dollar_a); out_lix (x_name, x_index);
next := next + 1

end

end;

out_nl;   out_tab( 15 );   out_token (zend);
out_comment( '   end of case_jump table. ' );

out_nl



end;

begin

contents_of_table := 0;
out_nl;
out_token (zbegin);
out_p_id (id_casetab);
out_p_id (id_otherwise);
out_p_id (id_caseexit);
out_p_id (x_name);  out_char('#');
out_token (zendlist);

get_token;
find_exprs( v_r);

if ( v_r.kind <> 1 ) or
   ( ( v_r.size >= 0 ) and ( v_r.size <> 2 ) ) then
error(pass4code_error);
out_op_id  (op_jmcht, id_casetab);

skip_token (xcase);

otherwise_found := false;

while  token <> xendcase do
begin

repeat 

case  token  of

xcaselabel :
begin

first := in_integer;
last := first;

add_to_table( first, last);

end;

xcaserange :
begin

first := in_integer;
last := in_integer;

if last < first then  error(case_label_error);

add_to_table( first, last);

end;

xotherwise :
begin

if otherwise_found then  error(pass4code_error);

otherwise_found := true;

out_label( id_otherwise );

end;

end

otherwise
error(pass4code_error);

get_token;

until ( token = xendcaselist );

get_token;
find_statement;
skip_token (xendcasestat);
out_op_id  (op_jmprw, id_caseexit);

end;


if not otherwise_found then
begin

out_label( id_otherwise );

code_exc_trigger( c_exc_case);
out_op_id  (op_jmprw, id_caseexit);

end;


out_table;
out_label (id_caseexit);
out_nl;
out_token (zend);

get_token;


end  (*  find_case  *);



procedure find_statement;
var
oldwork, oldstack : integer;
end_stat : boolean;
begin

end_stat := false;
repeat
oldwork := c.work;  oldstack := c.stack_size;
case token of
xassignstat:   find_assign;
xwhile:        find_while;
xproccall,
xextproccall,
xprocessparam: find_proc_call;
xlockstat:     find_lock;
xwithstat:     find_with;
xexchstat:     find_exchange;
xdeflix:       find_label;
xgoto:         find_goto;
xifstat:       find_if;
xrepeat:       find_repeat;
xforstat:      find_for;
xchannel:      find_channel;
xcasestat:     find_case;
end
otherwise end_stat := true;
if (c.work <> oldwork) or (c.stack_size <> oldstack) then evalstack_error;
until end_stat;
end;





procedure  find_varvalue( var  v:varvalue_descr);

var  type_v, first, number, size, niv, offset  : integer;
access : frame_kind;
     templ_v, va  : varaddr_descr;

begin

      find_varaddr( va);

      if va.kind = packed_arr then
      begin
         (*  push the value of an element in a packed array :  *)

          out_opcode( op_inprs );

          v.kind := 1;  v.size := 2

      end
      
      else

if token = xindvar then
      begin

         type_v := in_integer;

         if type_v = 3 then
         begin
first := in_integer;  number := in_integer;
if number = 8 then
begin (* optimize 8-bit fields as bytes *)
if first = 0 then
type_v := 1  (* left byte, don't change offset *)
else
if first = 8 then
begin  (* rigth byte, add one to offset *)
va.offset := va.offset + 1;
type_v := 1;
end;
end;
         end
         else
         if( type_v = 5 ) or ( type_v = 6 ) then  size := in_integer

else
if type_v = 7 then
begin
get_niv_offset( templ_v );
size := 0;  (* not used !!! *)
end;

         case type_v of

1, 2, 3, 4 :
begin

out_opcode (op_load Æ type_v, va.access Å);

if va.access = i_frame then
begin
out_start_param;  out_integer( c.niv - va.niv )
end;

out_start_param;  out_integer( va.offset );

if type_v = 3 then
begin
out_start_param;  out_integer( first * 16 + first + number - 1 )
end;

v.kind := 1;
if type_v = 4 then v.size := 4 else v.size := 2

end;

   5, 7:    begin

            load_address( va, true);
            v.kind := 2;  v.size := size

         end;

   6:    begin

            load_address( va, true);
            out_opcode( op_rechw );
            out_start_param;  out_integer( size );

            out_opcode( op_revsm );  context_eval (size);
out_op_int (op_rechw, size);

            v.kind := 1;   v.size := size + 2

         end
end; (* case type_v *)
get_token;

end; (* xindvar *)


end  (*  find_varvalue  *);





procedure   find_varaddr( var  v: varaddr_descr);
var
     r_v: varvalue_descr;
     dope_v: varaddr_descr;
end_addr : boolean;


begin

case token of
xaddr:
get_niv_offset (v);
xcaddr:
   begin
      v.kind := stack_addr;    v.offset := 0;    v.access := s_frame;
      v.size := 0;

      out_opcode( op_reaad );
out_start_param;  out_lix (c_name, in_integer);
end;
end
otherwise error(pass4code_error);

end_addr := false;
repeat
get_token;
case token of

 xfield:

      begin
         v.offset := v.offset + in_integer
      end;


xdynfield :
begin

load_address( v, true );
get_niv_offset( dope_v );

with dope_v do
begin
out_opcode( op_load Æ word_typ, access Å );
if access = i_frame then
out_p_int( c.niv - niv );
out_p_int( offset );
end; (* with *)
out_opcode( op_uadd );

end; (* dyn field *)


 xindexexpr:

      begin
load_address (v, false);

         get_token;
find_exprs( r_v);

case token of
xindex:
begin
get_niv_offset (dope_v);
load_address (dope_v, true);
end;
xcindex:
         begin

            out_opcode( op_reaad );
out_start_param;  out_lix (c_name, in_integer);
end;
end
otherwise error(pass4code_error);


         out_opcode( op_index )

        
      end  (*  t_indexexpr  *);

xindaddr:

      begin

out_opcode (op_load Æ 4, v.access Å );

if v.access = i_frame then
begin
              out_start_param;   out_integer( c.niv - v.niv );
           end;
            out_start_param;  out_integer( v.offset );

         v.kind := stack_addr;   v.offset := 0;   v.access := s_frame;

      end   (*  t_pushinda  *)

end
otherwise end_addr := true;
until end_addr;

if token = xpackedarr then
begin
load_address (v, true);

      get_token;
find_exprs( r_v);

if token = xcindex then
begin

      out_opcode( op_reaad );
out_start_param;  out_lix (c_name, in_integer);
end
else
begin (* xindex *)
get_niv_offset( dope_v );
load_address( dope_v, true );
end;

      v.kind := packed_arr;   v.size := 0;

get_token;

   end


end   (*  find_varaddr  *) ;




procedure  find_init;

var
type_o : integer;
i : integer;
w_offset, offset, number, size, size_l, size_c, lower, upper : integer;
stack_save : integer;
va : varaddr_descr;



begin

stack_save := c.stack_size;

case token of

xinitialize :
begin
get_token;
find_varaddr( va);
case token of
xstrucinit:
begin

size := in_integer;
i    := in_integer;  (* lix *)

load_address( va, true);

out_opcode( op_reaad );
out_start_param;  out_lix (c_name, i);

out_opcode( op_rechw );
out_start_param;  out_integer( size );
out_opcode (op_moveg)
end;
xsimpleinit:
begin

type_o := in_integer;
i := in_integer;

out_opcode( op_rechw );
out_start_param;  out_integer( i );

if va.kind = addr then
begin

if va.niv <> c.niv then  error(pass4code_error);

if ( type_o = 9 ) or ( type_o = 1 ) then
out_opcode( op_stvlb )
else
if type_o = 2 then
out_opcode( op_stvlw )
else
error(pass4code_error);

out_start_param;  out_integer( va.offset )

end

else
if va.kind = stack_addr then
begin

if ( type_o = 9 ) or ( type_o = 1 ) then
out_opcode( op_stvsb )
else
if type_o = 2 then
out_opcode( op_stvsw )
else
error(pass4code_error);

out_start_param;  out_integer( va.offset )

end

else
error(pass4code_error);
end;
xsetinit:
begin

load_address( va, true);

size_l := in_integer;
i      := in_integer;  (*lix *)
size_c := in_integer;

out_opcode( op_reaad );
out_start_param;  out_lix (c_name, i);

out_opcode( op_rechw );
out_start_param;  out_integer( size_c );

out_opcode( op_revsm );  context_eval( size_c );
out_op_int (op_rechw, size_c);

if size_l <> size_c then
begin

code_stat_to_dyn( size_c + 2 );

out_opcode( op_rechw );
out_start_param;  out_integer( size_l );

out_opcode( op_setad );

code_dyn_to_stat( size_l + 2 )

end;

out_opcode( op_setst );  context_eval( - size_l )
end;
end otherwise error(pass4code_error);

end;

xextexception:
with exc_descr do
begin

state := 1;
internal := false;
key := in_integer;

end;

xexception :
with exc_descr do
begin

state := 1;
internal := true;
niv := in_integer;   lix := in_integer

end;

end  (*  case  token  of .......  *)

otherwise
error(pass4code_error);

if stack_save <> c.stack_size then  evalstack_error;

get_token;

end  (*  find_init  *);




procedure  find_processparam;

var
niv_1,
offset_1, offset_2, offset_3, offset_4,
stack_size, param_length : integer;

begin

get_token;  (* skip: xprocessparam *)
if token <> xvarpointer then error(pass4code_error);

niv_1 := in_integer;   offset_1 := in_integer;
offset_2 := in_integer;

if niv_1 = const_niv_0 then
out_opcode( op_reagd )
else
if niv_1 = c.niv then
out_opcode( op_reald )
else
begin
out_opcode( op_reaid );
out_start_param;  out_integer( c.niv - niv_1 )
end;
out_start_param;  out_integer( offset_1 );
out_comment( '   start of process param. list . ' );

out_opcode( op_stvld );
out_start_param;  out_integer( offset_2 );

out_opcode( op_reaxd );

out_opcode( op_reasd );
out_start_param;  out_integer( 1 );

get_token;
if token <> xtempointer then error(pass4code_error);

offset_3 := in_integer;

out_opcode( op_stvld );
out_start_param;  out_integer( offset_3 );

stack_size := c.stack_size;

find_arglist;

param_length := c.stack_size - stack_size;

if token <> xarglistsize then error(pass4code_error);

offset_4 := in_integer;

out_opcode( op_rechw );
out_start_param;  out_integer( param_length );

out_opcode( op_stvlw );
out_start_param;  out_integer( offset_4 );
out_comment( '   end of process param. list . ' );

get_token;
case token of
xproccall,
xextproccall:
find_proc_call;
xfunccall,
xextfunccall:
begin

find_call;
skip_token (xfcall);
end;
xprocessparam:
find_processparam;
end
otherwise error(pass4code_error);

out_opcode( op_stnhb );  context_eval( -param_length );
out_start_param;  out_integer( param_length );

skip_token (xendprocessparam);

end  (*  find_processparam  *);





(*       body of pass5:      *)

begin

(*  initialize the set of hard exceptions :  *)

exc_hard := Æ 0 .. c_exc_max Å;

(*     initialize pass5 options to the default values :   *)

prolog_yes := true;
epilog_yes := true;
compress_yes := true;
callpass6_yes := true;
statacc_yes := false;
summary_yes := true;
old_create := false;
openroutine_yes := true;

(*  initialize the pseudo classes:  *)

mess_summ_state := 0;  (* before heading *)
out_init;
in_init;
ext_init;
  stat_reset;  


(*      generate code for one program:      *)

find_program;

(*     terminate the pseudo classes:        *)
if statacc_yes then stat_print;


1:      (*     exit from fatal errors      *)

pass5_ok := pass5_ok and callpass6_yes;
eom;

end     (*  pass5  *);


(*    body of the program:     *)

begin

pass5( pass5_ok );

if pass5_ok then
if lambda_version < 3 then
replace ('pass6v2')
else
replace( 'platonpass6' )
else
writeln( '*** compilation terminated after pass5' )

end.


▶EOF◀