613 lines
11 KiB
C
613 lines
11 KiB
C
/* $Header$ */
|
|
/*
|
|
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
|
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
|
*/
|
|
#include "em.h"
|
|
#include "expr.h"
|
|
#include "symtab.h"
|
|
#include "sizes.h"
|
|
#include "Lpars.h"
|
|
#include "code.h"
|
|
|
|
extern err;
|
|
|
|
static void subscript();
|
|
enum addr_val { address, value };
|
|
|
|
void code_val(e) register struct expr *e;
|
|
/* Compile e for its value, which is put on the stack. */
|
|
{
|
|
register struct expr *left, *right;
|
|
|
|
if (err) return;
|
|
|
|
switch(e->kind) {
|
|
case E_NODE:
|
|
left=e->u.node.left;
|
|
right=e->u.node.right;
|
|
|
|
switch (e->u.node.op) {
|
|
case '+':
|
|
case '-':
|
|
case '*':
|
|
case '/':
|
|
case BS:
|
|
code_val(left);
|
|
code_val(right);
|
|
xxi(e->u.node.op);
|
|
break;
|
|
case '<':
|
|
case '>':
|
|
case LE:
|
|
case GE:
|
|
case NE:
|
|
case '=':
|
|
code_val(left);
|
|
code_val(right);
|
|
cmi();
|
|
Txx(e->u.node.op);
|
|
break;
|
|
case AFTER:
|
|
code_val(left);
|
|
code_val(right);
|
|
xxi('-');
|
|
cvw();
|
|
tst();
|
|
Txx('>');
|
|
break;
|
|
case BA:
|
|
code_val(left);
|
|
code_val(right);
|
|
and();
|
|
break;
|
|
case BO:
|
|
code_val(left);
|
|
code_val(right);
|
|
ior();
|
|
break;
|
|
case BX:
|
|
code_val(left);
|
|
code_val(right);
|
|
xor();
|
|
break;
|
|
case AND:
|
|
case OR: {
|
|
int T=0, F=0, L=0;
|
|
|
|
code_bool(e, positive, &T, &F);
|
|
Label(T);
|
|
Loc(-1L);
|
|
branch(&L);
|
|
Label(F);
|
|
Loc(0L);
|
|
Label(L);
|
|
}break;
|
|
case LS:
|
|
code_val(left);
|
|
code_val(right);
|
|
cvw();
|
|
sli();
|
|
break;
|
|
case RS:
|
|
code_val(left);
|
|
code_val(right);
|
|
cvw();
|
|
sri();
|
|
break;
|
|
case '~':
|
|
code_val(left);
|
|
ngi();
|
|
break;
|
|
case NOT:
|
|
code_val(left);
|
|
com();
|
|
break;
|
|
case '[':
|
|
subscript(e, value);
|
|
break;
|
|
}
|
|
break;
|
|
case E_VAR: {
|
|
register struct symbol *var=e->u.var;
|
|
|
|
if (var->s_type&T_BUILTIN)
|
|
Loe(var->s_info.vc.st.builtin, var->s_info.vc.offset);
|
|
else
|
|
if (var->s_info.vc.st.level==curr_level)
|
|
if (var->s_type&T_PARAM && (var->s_type&T_TYPE)!=T_VALUE)
|
|
Lil(var->s_info.vc.offset);
|
|
else
|
|
Lol(var->s_info.vc.offset);
|
|
else {
|
|
if (var->s_info.vc.offset<0)
|
|
lxl(curr_level-var->s_info.vc.st.level);
|
|
else
|
|
lxa(curr_level-var->s_info.vc.st.level);
|
|
if (var->s_type&T_PARAM && (var->s_type&T_TYPE)!=T_VALUE)
|
|
Lif(var->s_info.vc.offset);
|
|
else
|
|
Lof(var->s_info.vc.offset);
|
|
}
|
|
}break;
|
|
case E_CONST:
|
|
Loc(e->u.cst);
|
|
break;
|
|
case E_NOW:
|
|
cal("now");
|
|
lfr(vz);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void subscript(e, av) register struct expr *e; enum addr_val av;
|
|
/* Produce code to compute the address or value of e->left[e->right] or
|
|
* the address of e->left[e->right->left FOR e->right->right].
|
|
*/
|
|
{
|
|
register char *des;
|
|
register struct expr *left;
|
|
register struct expr *index;
|
|
|
|
code_addr(left=e->u.node.left);
|
|
|
|
if ((index=e->u.node.right)->kind==E_NODE && index->u.node.op==FOR)
|
|
index=index->u.node.left;
|
|
|
|
if (left->arr_siz==0) {
|
|
if ((left->type&T_TYPE)==T_CHAN)
|
|
des="maxcdes";
|
|
else
|
|
des= e->type&T_BYTE ? "maxbdes" : "maxwdes";
|
|
} else {
|
|
register lsiz=left->arr_siz;
|
|
|
|
if (left->type&T_BYTE && !(e->type&T_BYTE))
|
|
lsiz/=vz;
|
|
else
|
|
if (!(left->type&T_BYTE) && e->type&T_BYTE)
|
|
lsiz*=vz;
|
|
|
|
if (e->type&T_ARR)
|
|
lsiz-=(e->arr_siz -1);
|
|
|
|
if (constant(index)) {
|
|
if (index->u.cst<0 || index->u.cst>=lsiz) {
|
|
warning("constant index outside vector");
|
|
lin();
|
|
loc(0);
|
|
trp();
|
|
}
|
|
} else {
|
|
loc(lsiz);
|
|
|
|
if ((left->type&T_TYPE)==T_CHAN)
|
|
des="chandes";
|
|
else
|
|
des= e->type&T_BYTE ? "bytedes" : "worddes";
|
|
ste(des, wz);
|
|
}
|
|
}
|
|
if (constant(index)) {
|
|
register offset=index->u.cst;
|
|
|
|
if ((left->type&T_TYPE)==T_CHAN)
|
|
offset*=(wz+vz);
|
|
else
|
|
if ( !(e->type&T_BYTE) )
|
|
offset*=vz;
|
|
|
|
if (av==address)
|
|
adp(offset);
|
|
else {
|
|
if (e->type&T_BYTE) {
|
|
adp(offset);
|
|
loi(1);
|
|
cwv();
|
|
} else
|
|
Lof(offset);
|
|
}
|
|
} else {
|
|
code_val(index);
|
|
cvw();
|
|
lin();
|
|
lae(des, 0);
|
|
if (av==address) {
|
|
aar();
|
|
} else {
|
|
lar();
|
|
if (e->type&T_BYTE) cwv();
|
|
}
|
|
}
|
|
}
|
|
|
|
void code_addr(e) register struct expr *e;
|
|
/* The address of e is wat we want. */
|
|
{
|
|
if (err) return;
|
|
|
|
switch(e->kind) {
|
|
case E_NODE:
|
|
subscript(e, address);
|
|
break;
|
|
case E_VAR: { /* variable or channel */
|
|
register struct symbol *var=e->u.var;
|
|
|
|
if (var->s_type&T_BUILTIN)
|
|
lae(var->s_info.vc.st.builtin, var->s_info.vc.offset);
|
|
else
|
|
if (var->s_info.vc.st.level==curr_level)
|
|
if (var->s_type&T_PARAM
|
|
&& (var->s_type&(T_TYPE|T_ARR))!=T_VALUE)
|
|
Lolp(var->s_info.vc.offset);
|
|
else
|
|
lal(var->s_info.vc.offset);
|
|
else {
|
|
if (var->s_info.vc.offset<0)
|
|
lxl(curr_level-var->s_info.vc.st.level);
|
|
else
|
|
lxa(curr_level-var->s_info.vc.st.level);
|
|
if (var->s_type&T_PARAM
|
|
&& (var->s_type&(T_TYPE|T_ARR))!=T_VALUE)
|
|
Lofp(var->s_info.vc.offset);
|
|
else
|
|
adp(var->s_info.vc.offset);
|
|
}
|
|
} break;
|
|
case E_TABLE:
|
|
case E_BTAB:
|
|
laedot(e->u.tab);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void code_bool(e, pos, T, F)
|
|
register struct expr *e;
|
|
register pos;
|
|
register int *T, *F;
|
|
/* if e = pos then
|
|
fall through or jump to T;
|
|
else
|
|
jump to F;
|
|
fi
|
|
*/
|
|
{
|
|
register Default=0;
|
|
|
|
if (err) return;
|
|
|
|
if (e->kind==E_NODE) {
|
|
register struct expr *left=e->u.node.left;
|
|
register struct expr *right=e->u.node.right;
|
|
|
|
switch(e->u.node.op) {
|
|
case '<':
|
|
case '>':
|
|
case LE:
|
|
case GE:
|
|
case NE:
|
|
case '=':
|
|
case AFTER:
|
|
code_val(left);
|
|
code_val(right);
|
|
bxx(pos, e->u.node.op, new_label(F));
|
|
break;
|
|
case AND:
|
|
case OR:
|
|
if ((e->u.node.op==AND && pos)
|
|
|| (e->u.node.op==OR && !pos)
|
|
) {
|
|
int L=0;
|
|
code_bool(left, pos, &L, F);
|
|
Label(L);
|
|
code_bool(right, pos, T, F);
|
|
} else {
|
|
int L=0;
|
|
code_bool(left, !pos, &L, T);
|
|
Label(L);
|
|
code_bool(right, pos, T, F);
|
|
}
|
|
break;
|
|
case NOT:
|
|
code_bool(left, !pos, T, F);
|
|
break;
|
|
default:
|
|
Default=1;
|
|
}
|
|
} else
|
|
Default=1;
|
|
|
|
if (Default) {
|
|
code_val(e);
|
|
if (vz>wz) {
|
|
ldc0();
|
|
cmi();
|
|
} else
|
|
tst();
|
|
if (pos) zeq(new_label(F)); else zne(new_label(F));
|
|
}
|
|
}
|
|
|
|
void code_assignment(e) register struct expr *e;
|
|
/* e->left := e->right */
|
|
{
|
|
register struct expr *left=e->u.node.left;
|
|
register struct expr *right=e->u.node.right;
|
|
|
|
if (left->type&T_ARR) {
|
|
register siz=left->arr_siz;
|
|
|
|
code_addr(right);
|
|
code_addr(left);
|
|
blm(left->type&T_BYTE ? siz : siz*vz);
|
|
} else {
|
|
code_val(right);
|
|
code_addr(left);
|
|
sti(left->type&T_BYTE ? 1 : vz);
|
|
}
|
|
}
|
|
|
|
void code_input(e) register struct expr *e;
|
|
/* Input one v from c ? v0; v1; ... */
|
|
{
|
|
if (e==nil) {
|
|
lae("any", 0);
|
|
cal("chan_in");
|
|
asp(pz);
|
|
} else
|
|
if (e->type&T_ARR) {
|
|
loc(e->arr_siz);
|
|
code_addr(e);
|
|
cal(e->type&T_BYTE ? "c_ba_in" : "c_wa_in");
|
|
asp(pz+wz);
|
|
} else {
|
|
code_addr(e);
|
|
cal(e->type&T_BYTE ? "cbyte_in" : "chan_in");
|
|
asp(pz);
|
|
}
|
|
}
|
|
|
|
void code_output(e) register struct expr *e;
|
|
/* Output one e from c ? e0; e1; ... */
|
|
{
|
|
if (e==nil) {
|
|
Loc(0L);
|
|
cal("chan_out");
|
|
asp(vz);
|
|
} else
|
|
if (e->type&T_ARR) {
|
|
loc(e->arr_siz);
|
|
code_addr(e);
|
|
cal(e->type&T_BYTE ? "c_ba_out" : "c_wa_out");
|
|
asp(pz+wz);
|
|
} else {
|
|
code_val(e);
|
|
cal("chan_out");
|
|
asp(vz);
|
|
}
|
|
}
|
|
|
|
void code_any(e, NO) register struct expr *e; int *NO;
|
|
/* Test if the channel (push address on stack) has input. If not so remove the
|
|
* channel pointer and jump to NO. Otherwise input values.
|
|
*/
|
|
{
|
|
int YES=0;
|
|
register struct expr_list *elp;
|
|
|
|
if (err) return;
|
|
|
|
code_addr(e->u.io.chan);
|
|
cal("chan_any");
|
|
lfr(wz);
|
|
tst();
|
|
zne(new_label(&YES));
|
|
asp(pz);
|
|
branch(NO);
|
|
Label(YES);
|
|
elp=e->u.io.args;
|
|
while (elp!=nil) {
|
|
code_input(elp->arg);
|
|
elp=elp->next;
|
|
}
|
|
asp(pz);
|
|
}
|
|
|
|
void code_void(e) register struct expr *e;
|
|
/* Assignment, I/O, or procedure call. */
|
|
{
|
|
if (err) return;
|
|
|
|
switch (e->kind) {
|
|
case E_NODE: /* Must be assignment */
|
|
code_assignment(e);
|
|
break;
|
|
case E_IO: {
|
|
register struct expr_list *elp;
|
|
|
|
code_addr(e->u.io.chan);
|
|
|
|
elp=e->u.io.args;
|
|
while (elp!=nil) {
|
|
if (e->u.io.out)
|
|
code_output(elp->arg);
|
|
else
|
|
code_input(elp->arg);
|
|
elp=elp->next;
|
|
}
|
|
asp(pz);
|
|
}
|
|
break;
|
|
case E_CALL: {
|
|
register size=0;
|
|
register struct expr_list *elp=e->u.call.c_args;
|
|
register struct symbol *proc=e->u.call.c_proc->u.var;
|
|
register struct par_list *pars=proc->s_info.proc.pars;
|
|
|
|
while (elp!=nil) {
|
|
if (pars->pr_type==T_VALUE) {
|
|
code_val(elp->arg);
|
|
size+=vz;
|
|
} else {
|
|
code_addr(elp->arg);
|
|
size+=pz;
|
|
}
|
|
elp=elp->next;
|
|
pars=pars->pr_next;
|
|
}
|
|
if (proc->s_type&T_BUILTIN) {
|
|
cal(proc->s_info.proc.st.builtin);
|
|
asp(size);
|
|
} else {
|
|
if (proc->s_info.proc.st.level>curr_level) {
|
|
/* Call down */
|
|
lor0();
|
|
} else
|
|
if (proc->s_info.proc.st.level==curr_level) {
|
|
/* Call at same level */
|
|
Lolp(0);
|
|
} else {
|
|
/* Call up */
|
|
lxa(curr_level-proc->s_info.proc.st.level);
|
|
loi(pz);
|
|
}
|
|
cal(proc_label(proc->s_info.proc.label, proc->s_name));
|
|
asp(size+pz);
|
|
if (proc->s_info.proc.file!=curr_file) fil();
|
|
}
|
|
} break;
|
|
}
|
|
}
|
|
|
|
void prologue(proc) register struct symbol *proc;
|
|
/* Open up the scope for a new proc definition. */
|
|
{
|
|
static P=0;
|
|
|
|
if (err) return;
|
|
|
|
proc->s_info.proc.st.level= ++curr_level;
|
|
proc->s_info.proc.file= curr_file;
|
|
proc->s_info.proc.label= ++P;
|
|
curr_offset=min_offset=0;
|
|
pro(proc_label(proc->s_info.proc.label, proc->s_name));
|
|
if (curr_level==1) fil();
|
|
}
|
|
|
|
void epilogue(proc) register struct symbol *proc;
|
|
/* Close the scope of a proc def. */
|
|
{
|
|
if (err) return;
|
|
|
|
curr_level--;
|
|
ret(0);
|
|
x_end(-min_offset);
|
|
}
|
|
|
|
void rep_init(v, e1, e2, r_info)
|
|
struct symbol *v;
|
|
register struct expr *e1, *e2;
|
|
register struct replicator *r_info;
|
|
/* Compile v=[e1 FOR e2]. Info tells rep_test what decisions rep_init makes. */
|
|
{
|
|
if (err) return;
|
|
|
|
r_info->BEGIN=r_info->END=0;
|
|
|
|
code_val(e1);
|
|
Stl(v->s_info.vc.offset);
|
|
|
|
if (!constant(e1) || !constant(e2)) {
|
|
if (constant(e2) && word_constant(e2->u.cst)) {
|
|
r_info->counter=memory(wz);
|
|
loc((int) e2->u.cst);
|
|
stl(r_info->counter);
|
|
} else {
|
|
r_info->counter=memory(vz);
|
|
code_val(e2);
|
|
Stl(r_info->counter);
|
|
}
|
|
}
|
|
if (!constant(e2) || e2->u.cst<=0L)
|
|
branch(&r_info->END);
|
|
Label(new_label(&r_info->BEGIN));
|
|
}
|
|
|
|
void rep_test(v, e1, e2, r_info)
|
|
register struct symbol *v;
|
|
register struct expr *e1, *e2;
|
|
register struct replicator *r_info;
|
|
{
|
|
if (err) return;
|
|
|
|
Inl(v->s_info.vc.offset);
|
|
|
|
if (constant(e1) && constant(e2)) {
|
|
Lol(v->s_info.vc.offset);
|
|
Loc(e1->u.cst+e2->u.cst);
|
|
if (vz>wz) {
|
|
cmi();
|
|
zlt(r_info->BEGIN);
|
|
} else
|
|
blt(r_info->BEGIN);
|
|
Label(r_info->END);
|
|
} else {
|
|
if (constant(e2) && word_constant(e2->u.cst)) {
|
|
del(r_info->counter);
|
|
Label(r_info->END);
|
|
lol(r_info->counter);
|
|
tst();
|
|
} else {
|
|
Del(r_info->counter);
|
|
Label(r_info->END);
|
|
Lol(r_info->counter);
|
|
if (vz>wz) {
|
|
ldc0();
|
|
cmi();
|
|
} else
|
|
tst();
|
|
}
|
|
zgt(r_info->BEGIN);
|
|
}
|
|
}
|
|
|
|
void chan_init(info, arr_siz) union type_info *info; int arr_siz;
|
|
/* Garbage disposal unit for fresh channels. */
|
|
{
|
|
if (err) return;
|
|
|
|
loc(arr_siz);
|
|
lal(info->vc.offset);
|
|
cal("c_init");
|
|
asp(wz+pz);
|
|
}
|
|
|
|
void leader()
|
|
{
|
|
init();
|
|
openfile((char *) nil);
|
|
magic();
|
|
meswp();
|
|
maxdes();
|
|
}
|
|
|
|
void header()
|
|
{
|
|
exp("main");
|
|
pro("main");
|
|
init_rt();
|
|
main_fil();
|
|
}
|
|
|
|
void trailer()
|
|
{
|
|
if (err)
|
|
meserr();
|
|
else {
|
|
loc(0);
|
|
ret(wz);
|
|
x_end(-min_offset);
|
|
}
|
|
closefile();
|
|
}
|