1321 lines
24 KiB
C
1321 lines
24 KiB
C
/* C O D E G E N E R A T I O N R O U T I N E S */
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "parameters.h"
|
|
#include "debug.h"
|
|
#include <assert.h>
|
|
#include <em.h>
|
|
#include <em_reg.h>
|
|
#include <em_abs.h>
|
|
|
|
#include "LLlex.h"
|
|
#include "Lpars.h"
|
|
#include "def.h"
|
|
#include "desig.h"
|
|
#include "f_info.h"
|
|
#include "idf.h"
|
|
#include "main.h"
|
|
#include "misc.h"
|
|
#include "node.h"
|
|
#include "required.h"
|
|
#include "scope.h"
|
|
#include "type.h"
|
|
#include "code.h"
|
|
#include "tmpvar.h"
|
|
#include "typequiv.h"
|
|
#include "error.h"
|
|
|
|
int fp_used;
|
|
|
|
static void CodeUoper(register struct node *);
|
|
static void CodeBoper(register struct node *, /* the expression tree itself */
|
|
label);
|
|
static void CodeSet(register struct node *);
|
|
static void CodeEl(register struct node *, register struct type *);
|
|
static void CodePString(struct node *, struct type *);
|
|
/* General internal system API calls */
|
|
static void CodeStd(struct node *);
|
|
|
|
static void genrck(register struct type *);
|
|
static void RegisterMessages(register struct def *);
|
|
static void CodeConfDescr(register struct type *, register struct type *);
|
|
|
|
extern void call_ini(void);
|
|
|
|
|
|
|
|
static void CodeFil(void)
|
|
{
|
|
if (!options['L'])
|
|
C_fil_dlb((label ) 1, (arith) 0);
|
|
}
|
|
|
|
void routine_label(register struct def * df)
|
|
{
|
|
df->prc_label = ++data_label;
|
|
C_df_dlb(df->prc_label);
|
|
C_rom_scon(df->df_idf->id_text, (arith)(strlen(df->df_idf->id_text) + 1));
|
|
}
|
|
|
|
void RomString(register struct node *nd)
|
|
{
|
|
C_df_dlb(++data_label);
|
|
|
|
/* A string of the string_type is null-terminated. */
|
|
if (nd->nd_type == string_type)
|
|
C_rom_scon(nd->nd_STR, nd->nd_SLE + 1); /* with trailing '\0' */
|
|
else
|
|
C_rom_scon(nd->nd_STR, nd->nd_SLE); /* no trailing '\0' */
|
|
|
|
nd->nd_SLA = data_label;
|
|
}
|
|
|
|
void RomReal(register struct node *nd)
|
|
{
|
|
if (!nd->nd_RLA)
|
|
{
|
|
C_df_dlb(++data_label);
|
|
nd->nd_RLA = data_label;
|
|
C_rom_fcon(nd->nd_REL, nd->nd_type->tp_size);
|
|
}
|
|
}
|
|
|
|
void BssVar(void)
|
|
{
|
|
/* generate bss segments for global variables */
|
|
register struct def *df = GlobalScope->sc_def;
|
|
|
|
while (df)
|
|
{
|
|
if (df->df_kind == D_VARIABLE)
|
|
{
|
|
C_df_dnam(df->var_name);
|
|
|
|
/* ??? undefined value ??? */
|
|
C_bss_cst(df->df_type->tp_size, (arith) 0, 0);
|
|
}
|
|
df = df->df_nextinscope;
|
|
}
|
|
}
|
|
|
|
static arith CodeGtoDescr(register struct scope *sc)
|
|
{
|
|
/* Create code for goto descriptors
|
|
*/
|
|
|
|
register struct node *lb = sc->sc_lablist;
|
|
int first = 1;
|
|
|
|
while (lb)
|
|
{
|
|
if (lb->nd_def->lab_descr)
|
|
{
|
|
if (first)
|
|
{
|
|
/* create local for target SP */
|
|
sc->sc_off = -WA(pointer_size - sc->sc_off);
|
|
C_ms_gto();
|
|
first = 0;
|
|
}
|
|
C_df_dlb(lb->nd_def->lab_descr);
|
|
C_rom_ilb(lb->nd_def->lab_no);
|
|
C_rom_cst(sc->sc_off);
|
|
}
|
|
lb = lb->nd_next;
|
|
}
|
|
if (!first)
|
|
return sc->sc_off;
|
|
else
|
|
return (arith) 0;
|
|
}
|
|
|
|
arith CodeBeginBlock(register struct def *df)
|
|
{
|
|
/* Generate code at the beginning of the main program,
|
|
procedure or function.
|
|
*/
|
|
|
|
arith StackAdjustment = 0;
|
|
arith offset = 0; /* offset to save StackPointer */
|
|
|
|
TmpOpen(df->prc_vis->sc_scope);
|
|
|
|
if (df->df_kind == D_MODULE) /* nothing */
|
|
;
|
|
else if (df->df_kind == D_PROGRAM)
|
|
{
|
|
C_exp("_m_a_i_n");
|
|
C_pro_narg("_m_a_i_n");
|
|
C_ms_par((arith) 0);
|
|
offset = CodeGtoDescr(df->prc_vis->sc_scope);
|
|
CodeFil();
|
|
|
|
/* initialize external files */
|
|
call_ini();
|
|
/* ignore floating point underflow */C_lim();
|
|
C_loc((arith)(1 << EFUNFL));
|
|
C_ior(int_size);
|
|
C_sim();
|
|
}
|
|
else if (df->df_kind & (D_PROCEDURE | D_FUNCTION))
|
|
{
|
|
struct type *tp;
|
|
register struct paramlist *param;
|
|
|
|
C_pro_narg(df->prc_name);
|
|
C_ms_par(df->df_type->prc_nbpar);
|
|
|
|
offset = CodeGtoDescr(df->prc_vis->sc_scope);
|
|
CodeFil();
|
|
|
|
if (options['t'])
|
|
{
|
|
C_lae_dlb(df->prc_label, (arith) 0);
|
|
C_cal("procentry");
|
|
C_asp(pointer_size);
|
|
}
|
|
|
|
/* prc_bool is the local variable that indicates if the
|
|
* function result is assigned. This and can be disabled
|
|
* with the -R option. The variable, however, is always
|
|
* allocated and initialized.
|
|
*/
|
|
if (df->prc_res)
|
|
{
|
|
C_zer((arith) int_size);
|
|
C_stl(df->prc_bool);
|
|
}
|
|
for (param = ParamList(df->df_type) ; param; param = param->next)
|
|
{
|
|
if (!IsVarParam(param))
|
|
{
|
|
tp = TypeOfParam(param);
|
|
|
|
if (IsConformantArray(tp))
|
|
{
|
|
/* Here, we have to make a copy of the
|
|
array. We must also remember how much
|
|
room is reserved for copies, because
|
|
we have to adjust the stack pointer
|
|
before we return.
|
|
*/
|
|
|
|
if (!StackAdjustment)
|
|
{
|
|
/* First time we get here
|
|
*/
|
|
StackAdjustment = NewInt(0);
|
|
C_loc((arith) 0);
|
|
C_stl(StackAdjustment);
|
|
}
|
|
/* Address of array */
|
|
C_lol(param->par_def->var_off);
|
|
|
|
/* First compute size of the array */
|
|
C_lol(tp->arr_cfdescr + word_size);
|
|
C_inc();
|
|
/* gives number of elements */
|
|
C_lol(tp->arr_cfdescr + 2 * word_size);
|
|
/* size of elements */
|
|
C_mli(word_size);
|
|
C_loc(word_size - 1);
|
|
C_adi(word_size);
|
|
C_loc(word_size - 1);
|
|
C_com(word_size);
|
|
C_and(word_size);
|
|
C_dup(word_size);
|
|
C_lol(StackAdjustment);
|
|
C_adi(word_size);
|
|
C_stl(StackAdjustment);
|
|
/* remember stack adjustments */
|
|
|
|
C_los(word_size); /* copy */
|
|
C_lor((arith) 1);
|
|
/* push new address of array
|
|
... downwards ... ???
|
|
*/
|
|
C_stl(param->par_def->var_off);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
crash("(CodeBeginBlock)");
|
|
/*NOTREACHED*/
|
|
}
|
|
|
|
if (offset)
|
|
{
|
|
/* save SP for non-local jump */
|
|
C_lor((arith) 1);
|
|
C_stl(offset);
|
|
}
|
|
return StackAdjustment;
|
|
}
|
|
|
|
void CodeEndBlock(register struct def *df, arith StackAdjustment)
|
|
{
|
|
if (df->df_kind == D_PROGRAM)
|
|
{
|
|
C_loc((arith) 0);
|
|
C_cal("_hlt");
|
|
}
|
|
else if (df->df_kind & (D_PROCEDURE | D_FUNCTION))
|
|
{
|
|
struct type *tp;
|
|
|
|
if (StackAdjustment)
|
|
{
|
|
/* remove copies of conformant arrays */
|
|
C_lol(StackAdjustment);
|
|
C_ass(word_size);
|
|
FreeInt(StackAdjustment);
|
|
}
|
|
if (!options['n'])
|
|
RegisterMessages(df->prc_vis->sc_scope->sc_def);
|
|
|
|
if (options['t'])
|
|
{
|
|
C_lae_dlb(df->prc_label, (arith) 0);
|
|
C_cal("procexit");
|
|
C_asp(pointer_size);
|
|
}
|
|
if ( (tp = ResultType(df->df_type)) )
|
|
{
|
|
if (!options['R'])
|
|
{
|
|
C_lin((arith) LineNumber);
|
|
C_lol(df->prc_bool);
|
|
C_cal("_nfa");
|
|
C_asp(word_size);
|
|
}
|
|
if (tp->tp_size == word_size)
|
|
C_lol(-tp->tp_size);
|
|
else if (tp->tp_size == 2 * word_size)
|
|
C_ldl(-tp->tp_size);
|
|
else
|
|
{
|
|
C_lal(-tp->tp_size);
|
|
C_loi(tp->tp_size);
|
|
}
|
|
|
|
C_ret(tp->tp_size);
|
|
}
|
|
else
|
|
C_ret((arith) 0);
|
|
}
|
|
else
|
|
{
|
|
crash("(CodeEndBlock)");
|
|
/*NOTREACHED*/
|
|
}
|
|
|
|
C_end(-df->prc_vis->sc_scope->sc_off);
|
|
TmpClose();
|
|
}
|
|
|
|
void CodeExpr(register struct node *nd, register struct desig *ds,
|
|
label true_label)
|
|
{
|
|
register struct type *tp = nd->nd_type;
|
|
|
|
if (tp->tp_fund == T_REAL)
|
|
fp_used = 1;
|
|
|
|
switch (nd->nd_class)
|
|
{
|
|
case Value:
|
|
switch (nd->nd_symb)
|
|
{
|
|
case INTEGER:
|
|
C_loc(nd->nd_INT);
|
|
break;
|
|
case REAL:
|
|
RomReal(nd);
|
|
C_lae_dlb(nd->nd_RLA, (arith) 0);
|
|
C_loi(tp->tp_size);
|
|
break;
|
|
case STRING:
|
|
if (tp->tp_fund == T_CHAR)
|
|
C_loc(nd->nd_INT);
|
|
else
|
|
C_lae_dlb(nd->nd_SLA, (arith) 0);
|
|
break;
|
|
case NIL:
|
|
C_zer(pointer_size);
|
|
break;
|
|
default:
|
|
crash("(CodeExpr Value)");
|
|
/*NOTREACHED*/
|
|
}
|
|
ds->dsg_kind = DSG_LOADED;
|
|
break;
|
|
|
|
case Uoper:
|
|
CodeUoper(nd);
|
|
ds->dsg_kind = DSG_LOADED;
|
|
break;
|
|
|
|
case Boper:
|
|
CodeBoper(nd, true_label);
|
|
ds->dsg_kind = DSG_LOADED;
|
|
true_label = NO_LABEL;
|
|
break;
|
|
|
|
case Set:
|
|
{
|
|
register arith *st = nd->nd_set;
|
|
register int i;
|
|
|
|
ds->dsg_kind = DSG_LOADED;
|
|
if (!st)
|
|
{
|
|
C_zer(tp->tp_size);
|
|
break;
|
|
}
|
|
for (i = tp->tp_size / word_size, st += i; i > 0; i--)
|
|
C_loc(*--st);
|
|
|
|
}
|
|
break;
|
|
|
|
case Xset:
|
|
CodeSet(nd);
|
|
ds->dsg_kind = DSG_LOADED;
|
|
break;
|
|
|
|
case Call:
|
|
CodeCall(nd);
|
|
ds->dsg_kind = DSG_LOADED;
|
|
break;
|
|
|
|
case NameOrCall:
|
|
{
|
|
/* actual procedure/function parameter */
|
|
struct node *left = nd->nd_left;
|
|
struct def *df = left->nd_def;
|
|
|
|
if (df->df_kind & D_ROUTINE)
|
|
{
|
|
int level = df->df_scope->sc_level;
|
|
|
|
if (level <= 0 || (df->df_flags & D_EXTERNAL))
|
|
C_zer(pointer_size);
|
|
else
|
|
C_lxl((arith)(proclevel - level));
|
|
|
|
C_lpi(df->prc_name);
|
|
ds->dsg_kind = DSG_LOADED;
|
|
break;
|
|
}
|
|
assert(df->df_kind == D_VARIABLE);
|
|
assert(df->df_type->tp_fund & T_ROUTINE);
|
|
|
|
CodeDesig(left, ds);
|
|
break;
|
|
}
|
|
|
|
case Arrow:
|
|
case Arrsel:
|
|
case Def:
|
|
case LinkDef:
|
|
CodeDesig(nd, ds);
|
|
break;
|
|
|
|
case Cast:
|
|
{
|
|
/* convert integer to real */
|
|
struct node *right = nd->nd_right;
|
|
|
|
CodePExpr(right);
|
|
Int2Real(right->nd_type->tp_size);
|
|
ds->dsg_kind = DSG_LOADED;
|
|
break;
|
|
}
|
|
case IntCoerc:
|
|
{
|
|
/* convert integer to long integer */
|
|
struct node *right = nd->nd_right;
|
|
|
|
CodePExpr(right);
|
|
Int2Long();
|
|
ds->dsg_kind = DSG_LOADED;
|
|
break;
|
|
}
|
|
case IntReduc:
|
|
{
|
|
/* convert a long to an integer */
|
|
struct node *right = nd->nd_right;
|
|
|
|
CodePExpr(right);
|
|
Long2Int();
|
|
ds->dsg_kind = DSG_LOADED;
|
|
break;
|
|
}
|
|
default:
|
|
crash("(CodeExpr : bad node type)");
|
|
/*NOTREACHED*/
|
|
} /* switch class */
|
|
|
|
if (true_label)
|
|
{
|
|
/* Only for boolean expressions
|
|
*/
|
|
CodeValue(ds, tp);
|
|
C_zeq(true_label);
|
|
}
|
|
}
|
|
|
|
static void CodeUoper(register struct node *nd)
|
|
{
|
|
register struct type *tp = nd->nd_type;
|
|
|
|
CodePExpr(nd->nd_right);
|
|
|
|
switch (nd->nd_symb)
|
|
{
|
|
case '-':
|
|
assert(tp->tp_fund & T_NUMERIC);
|
|
if (tp->tp_fund == T_INTEGER || tp->tp_fund == T_LONG)
|
|
C_ngi(tp->tp_size);
|
|
else
|
|
C_ngf(tp->tp_size);
|
|
break;
|
|
|
|
case NOT:
|
|
C_teq();
|
|
break;
|
|
|
|
case '(':
|
|
break;
|
|
|
|
default:
|
|
crash("(CodeUoper)");
|
|
/*NOTREACHED*/
|
|
}
|
|
}
|
|
|
|
/* truthvalue() serves as an auxiliary function of CodeBoper */
|
|
static void truthvalue(int relop)
|
|
{
|
|
switch (relop)
|
|
{
|
|
case '<':
|
|
C_tlt();
|
|
break;
|
|
case LESSEQUAL:
|
|
C_tle();
|
|
break;
|
|
case '>':
|
|
C_tgt();
|
|
break;
|
|
case GREATEREQUAL:
|
|
C_tge();
|
|
break;
|
|
case '=':
|
|
C_teq();
|
|
break;
|
|
case NOTEQUAL:
|
|
C_tne();
|
|
break;
|
|
default:
|
|
crash("(truthvalue)");
|
|
/*NOTREACHED*/
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void Operands(register struct node *leftop, register struct node *rightop)
|
|
{
|
|
CodePExpr(leftop);
|
|
CodePExpr(rightop);
|
|
}
|
|
|
|
static void CodeBoper(register struct node *expr, /* the expression tree itself */
|
|
label true_label) /* label to jump to in logical exprs */
|
|
{
|
|
register struct node *leftop = expr->nd_left;
|
|
register struct node *rightop = expr->nd_right;
|
|
register struct type *tp = expr->nd_type;
|
|
|
|
switch (expr->nd_symb)
|
|
{
|
|
case '+':
|
|
Operands(leftop, rightop);
|
|
switch (tp->tp_fund)
|
|
{
|
|
case T_INTEGER:
|
|
case T_LONG:
|
|
C_adi(tp->tp_size);
|
|
break;
|
|
case T_REAL:
|
|
C_adf(tp->tp_size);
|
|
break;
|
|
case T_SET:
|
|
C_ior(tp->tp_size);
|
|
break;
|
|
default:
|
|
crash("(CodeBoper: bad type +)");
|
|
}
|
|
break;
|
|
|
|
case '-':
|
|
Operands(leftop, rightop);
|
|
switch (tp->tp_fund)
|
|
{
|
|
case T_INTEGER:
|
|
case T_LONG:
|
|
C_sbi(tp->tp_size);
|
|
break;
|
|
case T_REAL:
|
|
C_sbf(tp->tp_size);
|
|
break;
|
|
case T_SET:
|
|
C_com(tp->tp_size);
|
|
C_and(tp->tp_size);
|
|
break;
|
|
default:
|
|
crash("(CodeBoper: bad type -)");
|
|
}
|
|
break;
|
|
|
|
case '*':
|
|
Operands(leftop, rightop);
|
|
switch (tp->tp_fund)
|
|
{
|
|
case T_INTEGER:
|
|
case T_LONG:
|
|
C_mli(tp->tp_size);
|
|
break;
|
|
case T_REAL:
|
|
C_mlf(tp->tp_size);
|
|
break;
|
|
case T_SET:
|
|
C_and(tp->tp_size);
|
|
break;
|
|
default:
|
|
crash("(CodeBoper: bad type *)");
|
|
}
|
|
break;
|
|
|
|
case '/':
|
|
Operands(leftop, rightop);
|
|
if (tp->tp_fund == T_REAL)
|
|
C_dvf(tp->tp_size);
|
|
else
|
|
crash("(CodeBoper: bad type /)");
|
|
break;
|
|
|
|
case DIV:
|
|
case MOD:
|
|
Operands(leftop, rightop);
|
|
if (tp->tp_fund == T_INTEGER)
|
|
{
|
|
C_cal(expr->nd_symb == MOD ? "_mdi" : "_dvi");
|
|
C_asp(2 * tp->tp_size);
|
|
C_lfr(tp->tp_size);
|
|
}
|
|
else if (tp->tp_fund == T_LONG)
|
|
{
|
|
C_cal(expr->nd_symb == MOD ? "_mdil" : "_dvil");
|
|
C_asp(2 * tp->tp_size);
|
|
C_lfr(tp->tp_size);
|
|
}
|
|
else
|
|
crash("(CodeBoper: bad type MOD)");
|
|
break;
|
|
|
|
case '<':
|
|
case LESSEQUAL:
|
|
case '>':
|
|
case GREATEREQUAL:
|
|
case '=':
|
|
case NOTEQUAL:
|
|
CodePExpr(leftop);
|
|
CodePExpr(rightop);
|
|
tp = BaseType(rightop->nd_type);
|
|
|
|
switch (tp->tp_fund)
|
|
{
|
|
case T_INTEGER:
|
|
case T_LONG:
|
|
C_cmi(tp->tp_size);
|
|
break;
|
|
case T_REAL:
|
|
C_cmf(tp->tp_size);
|
|
break;
|
|
case T_ENUMERATION:
|
|
case T_CHAR:
|
|
C_cmu(word_size);
|
|
break;
|
|
case T_POINTER:
|
|
C_cmp();
|
|
break;
|
|
|
|
case T_SET:
|
|
if (expr->nd_symb == GREATEREQUAL)
|
|
{
|
|
/* A >= B is the same as A equals A + B
|
|
*/
|
|
C_dup(2 * tp->tp_size);
|
|
C_asp(tp->tp_size);
|
|
C_ior(tp->tp_size);
|
|
expr->nd_symb = '=';
|
|
}
|
|
else if (expr->nd_symb == LESSEQUAL)
|
|
{
|
|
/* A <= B is the same as A - B = []
|
|
*/
|
|
C_com(tp->tp_size);
|
|
C_and(tp->tp_size);
|
|
C_zer(tp->tp_size);
|
|
expr->nd_symb = '=';
|
|
}
|
|
C_cms(tp->tp_size);
|
|
break;
|
|
|
|
case T_STRINGCONST:
|
|
case T_ARRAY:
|
|
C_loc((arith) IsString(tp));
|
|
C_cal("_bcp");
|
|
C_asp(2 * pointer_size + word_size);
|
|
C_lfr(word_size);
|
|
break;
|
|
|
|
case T_STRING:
|
|
C_cmp();
|
|
break;
|
|
|
|
default:
|
|
crash("(CodeBoper : bad type COMPARE)");
|
|
}
|
|
truthvalue(expr->nd_symb);
|
|
if (true_label != NO_LABEL )
|
|
C_zeq(true_label);
|
|
break;
|
|
|
|
case IN:
|
|
/* In this case, evaluate right hand side first! The INN
|
|
instruction expects the bit number on top of the stack
|
|
*/
|
|
CodePExpr(rightop);
|
|
CodePExpr(leftop);
|
|
if (rightop->nd_type == emptyset_type)
|
|
C_and(rightop->nd_type->tp_size);
|
|
else
|
|
C_inn(rightop->nd_type->tp_size);
|
|
|
|
if (true_label != NO_LABEL )
|
|
C_zeq(true_label);
|
|
break;
|
|
|
|
case AND:
|
|
case OR:
|
|
Operands(leftop, rightop);
|
|
if (expr->nd_symb == AND)
|
|
C_and(tp->tp_size);
|
|
else
|
|
C_ior(tp->tp_size);
|
|
if (true_label != NO_LABEL )
|
|
C_zeq(true_label);
|
|
break;
|
|
default:
|
|
crash("(CodeBoper Bad operator %s\n)", symbol2str(expr->nd_symb));
|
|
}
|
|
}
|
|
|
|
|
|
static void CodeSet(register struct node *nd)
|
|
{
|
|
register struct type *tp = nd->nd_type;
|
|
|
|
C_zer(tp->tp_size);
|
|
nd = nd->nd_right;
|
|
while (nd)
|
|
{
|
|
assert(nd->nd_class == Link && nd->nd_symb == ',');
|
|
|
|
CodeEl(nd->nd_left, tp);
|
|
nd = nd->nd_right;
|
|
}
|
|
}
|
|
|
|
static void CodeEl(register struct node *nd, register struct type *tp)
|
|
{
|
|
if (nd->nd_class == Link && nd->nd_symb == UPTO)
|
|
{
|
|
Operands(nd->nd_left, nd->nd_right);
|
|
C_loc(tp->tp_size); /* push size */
|
|
C_cal("_bts"); /* library routine to fill set */
|
|
C_asp(3 * word_size);
|
|
}
|
|
else
|
|
{
|
|
CodePExpr(nd);
|
|
C_set(tp->tp_size);
|
|
C_ior(tp->tp_size);
|
|
}
|
|
}
|
|
|
|
static struct type * CodeParameters(struct paramlist *param, struct node *arg)
|
|
{
|
|
register struct type *tp, *left_tp, *last_tp = (struct type *) 0;
|
|
struct node *left;
|
|
struct desig ds;
|
|
|
|
assert(param && arg);
|
|
|
|
if (param->next)
|
|
last_tp = CodeParameters(param->next, arg->nd_right);
|
|
|
|
tp = TypeOfParam(param);
|
|
left = arg->nd_left;
|
|
left_tp = left->nd_type;
|
|
|
|
if (IsConformantArray(tp))
|
|
{
|
|
if (last_tp != tp)
|
|
/* push descriptors only once */
|
|
CodeConfDescr(tp, left_tp);
|
|
|
|
CodeDAddress(left);
|
|
return tp;
|
|
}
|
|
if (IsVarParam(param))
|
|
{
|
|
CodeDAddress(left);
|
|
return tp;
|
|
}
|
|
if (left_tp->tp_fund == T_STRINGCONST)
|
|
{
|
|
CodePString(left, tp);
|
|
return tp;
|
|
}
|
|
|
|
ds = InitDesig;
|
|
CodeExpr(left, &ds, NO_LABEL );
|
|
CodeValue(&ds, left_tp);
|
|
|
|
RangeCheck(tp, left_tp);
|
|
if (tp == real_type && BaseType(left_tp) == int_type)
|
|
Int2Real(int_size);
|
|
|
|
return tp;
|
|
}
|
|
|
|
static void CodeConfDescr(register struct type *ftp, register struct type *atp)
|
|
{
|
|
struct type *elemtp = ftp->arr_elem;
|
|
|
|
if (IsConformantArray(elemtp))
|
|
CodeConfDescr(elemtp, atp->arr_elem);
|
|
|
|
if (atp->tp_fund == T_STRINGCONST)
|
|
{
|
|
C_loc((arith) 1);
|
|
C_loc(atp->tp_psize - 1);
|
|
C_loc((arith) 1);
|
|
}
|
|
else if (IsConformantArray(atp))
|
|
{
|
|
if (atp->arr_sclevel < proclevel)
|
|
{
|
|
C_lxa((arith) proclevel - atp->arr_sclevel);
|
|
C_adp(atp->arr_cfdescr);
|
|
}
|
|
else
|
|
C_lal(atp->arr_cfdescr);
|
|
|
|
C_loi(3 * word_size);
|
|
}
|
|
else
|
|
{ /* normal array */
|
|
assert(atp->tp_fund == T_ARRAY);
|
|
assert(!IsConformantArray(atp));
|
|
C_lae_dlb(atp->arr_ardescr, (arith) 0);
|
|
C_loi(3 * word_size);
|
|
}
|
|
}
|
|
|
|
static void CodePString(struct node *nd, struct type *tp)
|
|
{
|
|
/* no null padding */
|
|
C_lae_dlb(nd->nd_SLA, (arith) 0);
|
|
C_loi(tp->tp_size);
|
|
}
|
|
|
|
void CodeCall(register struct node *nd)
|
|
{
|
|
/* Generate code for a procedure call. Checking of parameters
|
|
and result is already done.
|
|
*/
|
|
register struct node *left = nd->nd_left;
|
|
register struct node *right = nd->nd_right;
|
|
register struct def *df = left->nd_def;
|
|
register struct type *result_tp;
|
|
|
|
assert(IsProcCall(left));
|
|
|
|
if (left->nd_type == std_type)
|
|
{
|
|
CodeStd(nd);
|
|
return;
|
|
}
|
|
|
|
if (right)
|
|
(void) CodeParameters(ParamList(left->nd_type), right);
|
|
|
|
assert(left->nd_class == Def);
|
|
|
|
if (df->df_kind & D_ROUTINE)
|
|
{
|
|
int level = df->df_scope->sc_level;
|
|
|
|
if (level > 0 && !(df->df_flags & D_EXTERNAL))
|
|
C_lxl((arith)(proclevel - level));
|
|
C_cal(df->prc_name);
|
|
C_asp(left->nd_type->prc_nbpar);
|
|
}
|
|
else
|
|
{
|
|
label l1 = ++text_label;
|
|
label l2 = ++text_label;
|
|
|
|
assert(df->df_kind == D_VARIABLE);
|
|
|
|
/* Push value of procedure/function parameter */
|
|
CodePExpr(left);
|
|
|
|
/* Test if value is a global or local procedure/function */
|
|
C_exg(pointer_size);
|
|
C_dup(pointer_size);
|
|
C_zer(pointer_size);
|
|
C_cmp();
|
|
|
|
C_zeq(l1);
|
|
/* At this point, on top of the stack the LB */
|
|
C_exg(pointer_size);
|
|
/* Now, the name of the procedure/function */C_cai();
|
|
C_asp(pointer_size + left->nd_type->prc_nbpar);
|
|
C_bra(l2);
|
|
|
|
/* value is a global procedure/function */
|
|
C_df_ilb(l1);
|
|
C_asp(pointer_size); /* no LB needed */
|
|
C_cai();
|
|
C_asp(left->nd_type->prc_nbpar);
|
|
C_df_ilb(l2);
|
|
}
|
|
|
|
if ( (result_tp = ResultType(left->nd_type)) )
|
|
C_lfr(result_tp->tp_size);
|
|
}
|
|
|
|
static void CodeStd(struct node *nd)
|
|
{
|
|
register struct node *arg = nd->nd_right;
|
|
register struct node *left = arg->nd_left;
|
|
register struct type *tp = BaseType(left->nd_type);
|
|
int req = nd->nd_left->nd_def->df_value.df_reqname;
|
|
|
|
assert(arg->nd_class == Link && arg->nd_symb == ',');
|
|
|
|
switch (req)
|
|
{
|
|
case R_ABS:
|
|
CodePExpr(left);
|
|
if (tp == int_type)
|
|
C_cal("_abi");
|
|
else if (tp == long_type)
|
|
C_cal("_abl");
|
|
else
|
|
C_cal("_abr");
|
|
C_asp(tp->tp_size);
|
|
C_lfr(tp->tp_size);
|
|
break;
|
|
|
|
case R_SQR:
|
|
CodePExpr(left);
|
|
C_dup(tp->tp_size);
|
|
if (tp == int_type || tp == long_type)
|
|
C_mli(tp->tp_size);
|
|
else
|
|
C_mlf(real_size);
|
|
break;
|
|
|
|
case R_SIN:
|
|
case R_COS:
|
|
case R_EXP:
|
|
case R_LN:
|
|
case R_SQRT:
|
|
case R_ARCTAN:
|
|
assert(tp == real_type);
|
|
CodePExpr(left);
|
|
switch (req)
|
|
{
|
|
case R_SIN:
|
|
C_cal("_sin");
|
|
break;
|
|
case R_COS:
|
|
C_cal("_cos");
|
|
break;
|
|
case R_EXP:
|
|
C_cal("_exp");
|
|
break;
|
|
case R_LN:
|
|
C_cal("_log");
|
|
break;
|
|
case R_SQRT:
|
|
C_cal("_sqt");
|
|
break;
|
|
case R_ARCTAN:
|
|
C_cal("_atn");
|
|
break;
|
|
default:
|
|
crash("(CodeStd)");
|
|
/*NOTREACHED*/
|
|
}
|
|
C_asp(real_size);
|
|
C_lfr(real_size);
|
|
break;
|
|
|
|
case R_TRUNC:
|
|
assert(tp == real_type);
|
|
CodePExpr(left);
|
|
Real2Int();
|
|
break;
|
|
|
|
case R_ROUND:
|
|
assert(tp == real_type);
|
|
CodePExpr(left);
|
|
C_cal("_rnd");
|
|
C_asp(real_size);
|
|
C_lfr(real_size);
|
|
Real2Int();
|
|
break;
|
|
|
|
case R_ORD:
|
|
CodePExpr(left);
|
|
break;
|
|
|
|
case R_CHR:
|
|
CodePExpr(left);
|
|
genrck(char_type);
|
|
break;
|
|
|
|
case R_SUCC:
|
|
case R_PRED:
|
|
CodePExpr(left);
|
|
C_loc((arith) 1);
|
|
if (tp == long_type)
|
|
Int2Long();
|
|
|
|
if (req == R_SUCC)
|
|
C_adi(tp->tp_size);
|
|
else
|
|
C_sbi(tp->tp_size);
|
|
|
|
if (bounded(left->nd_type))
|
|
genrck(left->nd_type);
|
|
break;
|
|
|
|
case R_ODD:
|
|
CodePExpr(left);
|
|
C_loc((arith) 1);
|
|
if (tp == long_type)
|
|
Int2Long();
|
|
C_and(tp->tp_size);
|
|
if (tp == long_type)
|
|
Long2Int(); /* bool_size == int_size */
|
|
break;
|
|
|
|
case R_EOF:
|
|
case R_EOLN:
|
|
CodeDAddress(left);
|
|
if (req == R_EOF)
|
|
C_cal("_efl");
|
|
else
|
|
C_cal("_eln");
|
|
C_asp(pointer_size);
|
|
C_lfr(word_size);
|
|
break;
|
|
|
|
case R_REWRITE:
|
|
case R_RESET:
|
|
CodeDAddress(left);
|
|
if (tp == text_type)
|
|
C_loc((arith) 0);
|
|
else
|
|
C_loc(tp->next->tp_psize);
|
|
/* ??? elements of packed size ??? */
|
|
if (req == R_REWRITE)
|
|
C_cal("_cre");
|
|
else
|
|
C_cal("_opn");
|
|
C_asp(pointer_size + word_size);
|
|
break;
|
|
|
|
case R_PUT:
|
|
case R_GET:
|
|
CodeDAddress(left);
|
|
if (req == R_PUT)
|
|
C_cal("_put");
|
|
else
|
|
C_cal("_get");
|
|
C_asp(pointer_size);
|
|
break;
|
|
|
|
case R_PAGE:
|
|
CodeDAddress(left);
|
|
C_cal("_pag");
|
|
C_asp(pointer_size);
|
|
break;
|
|
|
|
case R_PACK:
|
|
{
|
|
label lba = tp->arr_ardescr;
|
|
|
|
CodeDAddress(left);
|
|
arg = arg->nd_right;
|
|
left = arg->nd_left;
|
|
CodePExpr(left);
|
|
arg = arg->nd_right;
|
|
left = arg->nd_left;
|
|
CodeDAddress(left);
|
|
C_lae_dlb(left->nd_type->arr_ardescr, (arith) 0);
|
|
C_lae_dlb(lba, (arith) 0);
|
|
C_cal("_pac");
|
|
C_asp(4 * pointer_size + word_size);
|
|
break;
|
|
}
|
|
|
|
case R_UNPACK:
|
|
{
|
|
/* change sequence of arguments of the library routine
|
|
_unp to merge code of R_PACK and R_UNPACK.
|
|
*/
|
|
label lba, lbz = tp->arr_ardescr;
|
|
|
|
tp = tp->arr_elem;
|
|
if (tp->tp_fund == T_SUBRANGE && tp->sub_lb >= 0)
|
|
{
|
|
C_loc((arith) 1);
|
|
}
|
|
else
|
|
C_loc((arith) 0);
|
|
CodeDAddress(left);
|
|
arg = arg->nd_right;
|
|
left = arg->nd_left;
|
|
CodeDAddress(left);
|
|
lba = left->nd_type->arr_ardescr;
|
|
arg = arg->nd_right;
|
|
left = arg->nd_left;
|
|
CodePExpr(left);
|
|
C_lae_dlb(lbz, (arith) 0);
|
|
C_lae_dlb(lba, (arith) 0);
|
|
C_cal("_unp");
|
|
C_asp(4 * pointer_size + 2 * word_size);
|
|
break;
|
|
}
|
|
|
|
case R_NEW:
|
|
case R_DISPOSE:
|
|
CodeDAddress(left);
|
|
C_loc(PointedtoType(tp)->tp_size);
|
|
if (req == R_NEW)
|
|
C_cal("_new");
|
|
else
|
|
C_cal("_dis");
|
|
C_asp(pointer_size + word_size);
|
|
break;
|
|
|
|
case R_HALT:
|
|
if (left)
|
|
CodePExpr(left);
|
|
else
|
|
C_zer(int_size);
|
|
C_cal("_hlt"); /* can't return */
|
|
C_asp(int_size); /* help the optimizer(s) */
|
|
break;
|
|
|
|
default:
|
|
crash("(CodeStd)");
|
|
/*NOTREACHED*/
|
|
}
|
|
}
|
|
|
|
void Long2Int(void)
|
|
{
|
|
/* convert a long to integer */
|
|
|
|
if (int_size == long_size)
|
|
return;
|
|
|
|
C_loc(long_size);
|
|
C_loc(int_size);
|
|
C_cii();
|
|
}
|
|
|
|
void Int2Long(void)
|
|
{
|
|
/* convert integer to long */
|
|
|
|
if (int_size == long_size)
|
|
return;
|
|
C_loc(int_size);
|
|
C_loc(long_size);
|
|
C_cii();
|
|
}
|
|
|
|
void Int2Real(arith size)
|
|
/* size is different for integers and longs */
|
|
{
|
|
/* convert integer to real */
|
|
C_loc(size);
|
|
C_loc(real_size);
|
|
C_cif();
|
|
}
|
|
|
|
void Real2Int(void)
|
|
{
|
|
/* convert real to integer */
|
|
C_loc(real_size);
|
|
C_loc(int_size);
|
|
C_cfi();
|
|
}
|
|
|
|
void RangeCheck(register struct type *tpl, register struct type *tpr)
|
|
{
|
|
/* Generate a range check if neccessary
|
|
*/
|
|
|
|
arith llo, lhi, rlo, rhi;
|
|
|
|
if (bounded(tpl))
|
|
{
|
|
/* in this case we might need a range check */
|
|
if (!bounded(tpr))
|
|
/* yes, we need one */
|
|
genrck(tpl);
|
|
else
|
|
{
|
|
/* both types are restricted. check the bounds to see
|
|
whether we need a range check. We don't need one
|
|
if the range of values of the right hand side is a
|
|
subset of the range of values of the left hand side.
|
|
*/
|
|
getbounds(tpl, &llo, &lhi);
|
|
getbounds(tpr, &rlo, &rhi);
|
|
if (llo > rlo || lhi < rhi)
|
|
genrck(tpl);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void genrck(register struct type *tp)
|
|
{
|
|
/* Generate a range check descriptor for type "tp" when
|
|
necessary. Return its label.
|
|
*/
|
|
|
|
arith lb, ub;
|
|
register label o1;
|
|
int newlabel = 0;
|
|
|
|
if (options['R'])
|
|
return;
|
|
|
|
getbounds(tp, &lb, &ub);
|
|
|
|
if (tp->tp_fund == T_SUBRANGE)
|
|
{
|
|
if (!(o1 = tp->sub_rck))
|
|
{
|
|
tp->sub_rck = o1 = ++data_label;
|
|
newlabel = 1;
|
|
}
|
|
}
|
|
else if (!(o1 = tp->enm_rck))
|
|
{
|
|
tp->enm_rck = o1 = ++data_label;
|
|
newlabel = 1;
|
|
}
|
|
if (newlabel)
|
|
{
|
|
C_df_dlb(o1);
|
|
C_rom_cst(lb);
|
|
C_rom_cst(ub);
|
|
}
|
|
C_lae_dlb(o1, (arith) 0);
|
|
C_rck(word_size);
|
|
}
|
|
|
|
void CodePExpr(register struct node *nd)
|
|
{
|
|
/* Generate code to push the value of the expression "nd"
|
|
on the stack.
|
|
*/
|
|
|
|
struct desig designator;
|
|
struct type *tp = BaseType(nd->nd_type);
|
|
|
|
designator = InitDesig;
|
|
CodeExpr(nd, &designator, NO_LABEL );
|
|
if (tp->tp_fund & (T_ARRAY | T_RECORD))
|
|
CodeAddress(&designator);
|
|
else
|
|
CodeValue(&designator, nd->nd_type);
|
|
}
|
|
|
|
void CodeDAddress(struct node *nd)
|
|
{
|
|
/* Generate code to push the address of the designator "nd"
|
|
on the stack.
|
|
*/
|
|
|
|
struct desig designator;
|
|
|
|
designator = InitDesig;
|
|
CodeDesig(nd, &designator);
|
|
CodeAddress(&designator);
|
|
}
|
|
|
|
void CodeDStore(register struct node *nd)
|
|
{
|
|
/* Generate code to store the expression on the stack
|
|
into the designator "nd".
|
|
*/
|
|
|
|
struct desig designator;
|
|
|
|
designator = InitDesig;
|
|
CodeDesig(nd, &designator);
|
|
CodeStore(&designator, nd->nd_type);
|
|
}
|
|
|
|
static void RegisterMessages(register struct def *df)
|
|
{
|
|
register struct type *tp;
|
|
|
|
for (; df; df = df->df_nextinscope)
|
|
{
|
|
if (df->df_kind == D_VARIABLE && !(df->df_flags & D_NOREG))
|
|
{
|
|
/* Examine type and size
|
|
*/
|
|
tp = BaseType(df->df_type);
|
|
if (df->df_flags & D_VARPAR || tp->tp_fund & T_POINTER)
|
|
C_ms_reg(df->var_off, pointer_size, reg_pointer, 0);
|
|
|
|
else if (df->df_flags & D_LOOPVAR)
|
|
C_ms_reg(df->var_off, tp->tp_size, reg_loop, 2);
|
|
else if (tp->tp_fund & T_NUMERIC)
|
|
C_ms_reg(df->var_off, tp->tp_size,
|
|
tp->tp_fund == T_REAL ? reg_float : reg_any, 0);
|
|
}
|
|
}
|
|
}
|