Initial revision
This commit is contained in:
parent
a731f979b0
commit
bc94559e4d
16 changed files with 3123 additions and 0 deletions
27
lang/occam/comp/Makefile
Normal file
27
lang/occam/comp/Makefile
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
GFILES= occam.g
|
||||||
|
PRIMARY= occam.o Lpars.o keytab.o lex.yy.o code.o em.o
|
||||||
|
SECUNDARY= symtab.o expr.o builtin.o
|
||||||
|
TERTIARY= report.o
|
||||||
|
LLOPT=
|
||||||
|
LIBRARY= -lln libemk.a libsystem.a
|
||||||
|
|
||||||
|
all:
|
||||||
|
make dummy
|
||||||
|
make oc
|
||||||
|
|
||||||
|
dummy: $(GFILES)
|
||||||
|
LLgen $(LLOPT) $(GFILES)
|
||||||
|
touch dummy
|
||||||
|
|
||||||
|
oc: $(PRIMARY) $(SECUNDARY) $(TERTIARY)
|
||||||
|
$(CC) -o oc $(PRIMARY) $(SECUNDARY) $(TERTIARY) $(LIBRARY)
|
||||||
|
|
||||||
|
lex.yy.c: lex.l
|
||||||
|
lex lex.l
|
||||||
|
|
||||||
|
$(PRIMARY): Lpars.h
|
||||||
|
occam.o keytab.o: token.h
|
||||||
|
occam.o $(SECUNDARY): symtab.h expr.h
|
||||||
|
$(PRIMARY) $(SECUNDARY): sizes.h
|
||||||
|
occam.o code.o: code.h
|
||||||
|
code.o em.o: em.h
|
74
lang/occam/comp/builtin.c
Normal file
74
lang/occam/comp/builtin.c
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "symtab.h"
|
||||||
|
#include "expr.h"
|
||||||
|
#include "sizes.h"
|
||||||
|
|
||||||
|
void init_builtins()
|
||||||
|
/* Insert all builtin names into the outermost symbol table (first statement
|
||||||
|
* is sym_down() ). Note that this table is never destroy()ed, so static
|
||||||
|
* initializers may be used.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
union type_info info;
|
||||||
|
|
||||||
|
static char file[]="file";
|
||||||
|
|
||||||
|
static struct par_list
|
||||||
|
open_list[] = {
|
||||||
|
{ &open_list[1], nil, T_VAR }, /* File descriptor */
|
||||||
|
{ &open_list[2], nil, T_VALUE|T_ARR }, /* File name */
|
||||||
|
{ nil, nil, T_VALUE|T_ARR } /* "r", "w", "a" */
|
||||||
|
},
|
||||||
|
close_list[]= {
|
||||||
|
{ nil, nil, T_VALUE } /* File descriptor */
|
||||||
|
},
|
||||||
|
exit_list[]= {
|
||||||
|
{ nil, nil, T_VALUE } /* Exit code */
|
||||||
|
};
|
||||||
|
|
||||||
|
sym_down(); /* Add level of symbols above all others */
|
||||||
|
|
||||||
|
/* CHAN file[20], input=file[0], output=file[1], error=file[2]: */
|
||||||
|
|
||||||
|
info.vc.st.builtin=file;
|
||||||
|
info.vc.offset=0;
|
||||||
|
insert(file, T_CHAN|T_ARR|T_BUILTIN, _NFILE, info);
|
||||||
|
|
||||||
|
info.vc.st.builtin=file;
|
||||||
|
info.vc.offset=0;
|
||||||
|
insert("input", T_CHAN|T_BUILTIN, 1, info);
|
||||||
|
|
||||||
|
info.vc.st.builtin=file;
|
||||||
|
info.vc.offset=wz+pz;
|
||||||
|
insert("output", T_CHAN|T_BUILTIN, 1, info);
|
||||||
|
|
||||||
|
info.vc.st.builtin=file;
|
||||||
|
info.vc.offset=2*(wz+pz);
|
||||||
|
insert("error", T_CHAN|T_BUILTIN, 1, info);
|
||||||
|
|
||||||
|
/* DEF EOF= -1, TEXT= -2, RAW= -3: */
|
||||||
|
|
||||||
|
info.const=new_const(-1L);
|
||||||
|
insert("EOF", T_CONST|T_BUILTIN, 0, info);
|
||||||
|
|
||||||
|
info.const=new_const(-2L);
|
||||||
|
insert("TEXT", T_CONST|T_BUILTIN, 0, info);
|
||||||
|
|
||||||
|
info.const=new_const(-3L);
|
||||||
|
insert("RAW", T_CONST|T_BUILTIN, 0, info);
|
||||||
|
|
||||||
|
/* PROC open(VAR fd, VALUE name[], mode[])= .... : */
|
||||||
|
info.proc.st.builtin="b_open";
|
||||||
|
info.proc.pars=open_list;
|
||||||
|
insert("open", T_PROC|T_BUILTIN, 0, info);
|
||||||
|
|
||||||
|
/* PROC close(VALUE fd)= .... : */
|
||||||
|
info.proc.st.builtin="b_close";
|
||||||
|
info.proc.pars=close_list;
|
||||||
|
insert("close", T_PROC|T_BUILTIN, 0, info);
|
||||||
|
|
||||||
|
/* PROC exit(VALUE code)= .... : */
|
||||||
|
info.proc.st.builtin="b_exit";
|
||||||
|
info.proc.pars=exit_list;
|
||||||
|
insert("exit", T_PROC|T_BUILTIN, 0, info);
|
||||||
|
}
|
607
lang/occam/comp/code.c
Normal file
607
lang/occam/comp/code.c
Normal file
|
@ -0,0 +1,607 @@
|
||||||
|
#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->type&T_BUILTIN)
|
||||||
|
Loe(var->info.vc.st.builtin, var->info.vc.offset);
|
||||||
|
else
|
||||||
|
if (var->info.vc.st.level==curr_level)
|
||||||
|
if (var->type&T_PARAM && (var->type&T_TYPE)!=T_VALUE)
|
||||||
|
Lil(var->info.vc.offset);
|
||||||
|
else
|
||||||
|
Lol(var->info.vc.offset);
|
||||||
|
else {
|
||||||
|
if (var->info.vc.offset<0)
|
||||||
|
lxl(curr_level-var->info.vc.st.level);
|
||||||
|
else
|
||||||
|
lxa(curr_level-var->info.vc.st.level);
|
||||||
|
if (var->type&T_PARAM && (var->type&T_TYPE)!=T_VALUE)
|
||||||
|
Lif(var->info.vc.offset);
|
||||||
|
else
|
||||||
|
Lof(var->info.vc.offset);
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
case E_CONST:
|
||||||
|
Loc(e->u.const);
|
||||||
|
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.const<0 || index->u.const>=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.const;
|
||||||
|
|
||||||
|
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->type&T_BUILTIN)
|
||||||
|
lae(var->info.vc.st.builtin, var->info.vc.offset);
|
||||||
|
else
|
||||||
|
if (var->info.vc.st.level==curr_level)
|
||||||
|
if (var->type&T_PARAM
|
||||||
|
&& (var->type&(T_TYPE|T_ARR))!=T_VALUE)
|
||||||
|
Lolp(var->info.vc.offset);
|
||||||
|
else
|
||||||
|
lal(var->info.vc.offset);
|
||||||
|
else {
|
||||||
|
if (var->info.vc.offset<0)
|
||||||
|
lxl(curr_level-var->info.vc.st.level);
|
||||||
|
else
|
||||||
|
lxa(curr_level-var->info.vc.st.level);
|
||||||
|
if (var->type&T_PARAM
|
||||||
|
&& (var->type&(T_TYPE|T_ARR))!=T_VALUE)
|
||||||
|
Lofp(var->info.vc.offset);
|
||||||
|
else
|
||||||
|
adp(var->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.args;
|
||||||
|
register struct symbol *proc=e->u.call.proc->u.var;
|
||||||
|
register struct par_list *pars=proc->info.proc.pars;
|
||||||
|
|
||||||
|
while (elp!=nil) {
|
||||||
|
if (pars->type==T_VALUE) {
|
||||||
|
code_val(elp->arg);
|
||||||
|
size+=vz;
|
||||||
|
} else {
|
||||||
|
code_addr(elp->arg);
|
||||||
|
size+=pz;
|
||||||
|
}
|
||||||
|
elp=elp->next;
|
||||||
|
pars=pars->next;
|
||||||
|
}
|
||||||
|
if (proc->type&T_BUILTIN) {
|
||||||
|
cal(proc->info.proc.st.builtin);
|
||||||
|
asp(size);
|
||||||
|
} else {
|
||||||
|
if (proc->info.proc.st.level>curr_level) {
|
||||||
|
/* Call down */
|
||||||
|
lor0();
|
||||||
|
} else
|
||||||
|
if (proc->info.proc.st.level==curr_level) {
|
||||||
|
/* Call at same level */
|
||||||
|
Lolp(0);
|
||||||
|
} else {
|
||||||
|
/* Call up */
|
||||||
|
lxa(curr_level-proc->info.proc.st.level);
|
||||||
|
loi(pz);
|
||||||
|
}
|
||||||
|
cal(proc_label(proc->info.proc.label, proc->name));
|
||||||
|
asp(size+pz);
|
||||||
|
if (proc->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->info.proc.st.level= ++curr_level;
|
||||||
|
proc->info.proc.file= curr_file;
|
||||||
|
proc->info.proc.label= ++P;
|
||||||
|
curr_offset=min_offset=0;
|
||||||
|
pro(proc_label(proc->info.proc.label, proc->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);
|
||||||
|
_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->info.vc.offset);
|
||||||
|
|
||||||
|
if (!constant(e1) || !constant(e2)) {
|
||||||
|
if (constant(e2) && word_constant(e2->u.const)) {
|
||||||
|
r_info->counter=memory(wz);
|
||||||
|
loc((int) e2->u.const);
|
||||||
|
stl(r_info->counter);
|
||||||
|
} else {
|
||||||
|
r_info->counter=memory(vz);
|
||||||
|
code_val(e2);
|
||||||
|
Stl(r_info->counter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!constant(e2) || e2->u.const<=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->info.vc.offset);
|
||||||
|
|
||||||
|
if (constant(e1) && constant(e2)) {
|
||||||
|
Lol(v->info.vc.offset);
|
||||||
|
Loc(e1->u.const+e2->u.const);
|
||||||
|
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.const)) {
|
||||||
|
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);
|
||||||
|
_end(-min_offset);
|
||||||
|
}
|
||||||
|
closefile();
|
||||||
|
}
|
19
lang/occam/comp/code.h
Normal file
19
lang/occam/comp/code.h
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
struct replicator { /* Info transferred from rep_init to rep_test */
|
||||||
|
int counter;
|
||||||
|
int BEGIN;
|
||||||
|
int END;
|
||||||
|
};
|
||||||
|
|
||||||
|
void rep_init(), rep_test();
|
||||||
|
|
||||||
|
void code_val(), code_addr(), code_void();
|
||||||
|
void code_assignment(), code_input(), code_any(), code_output();
|
||||||
|
|
||||||
|
void code_bool();
|
||||||
|
#define positive 1 /* Use positive logic for boolean expression */
|
||||||
|
#define negative 0 /* Use negative logic, i.e. 0 = true */
|
||||||
|
|
||||||
|
void epilogue(), prologue();
|
||||||
|
void leader(), header(), trailer();
|
||||||
|
|
||||||
|
void chan_init();
|
405
lang/occam/comp/em.c
Normal file
405
lang/occam/comp/em.c
Normal file
|
@ -0,0 +1,405 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "sizes.h"
|
||||||
|
#include "Lpars.h"
|
||||||
|
#include "em_arith.h"
|
||||||
|
#include "em_label.h"
|
||||||
|
#include "em.h"
|
||||||
|
|
||||||
|
/* This file is used to shield code.c as much as possible from em dependant
|
||||||
|
* details. It introduces some call overhead but not enough for a coffee
|
||||||
|
* break. (Sorry)
|
||||||
|
* Note that functions with a leading upper case letter normally decide between
|
||||||
|
* word or double word arith.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int wz, pz;
|
||||||
|
static Lab=0;
|
||||||
|
char *malloc();
|
||||||
|
|
||||||
|
void init()
|
||||||
|
{
|
||||||
|
C_init((arith) wz, (arith) pz);
|
||||||
|
}
|
||||||
|
|
||||||
|
void openfile(file) char *file;
|
||||||
|
{
|
||||||
|
C_open(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
void meswp()
|
||||||
|
{
|
||||||
|
C_mes_begin(2);
|
||||||
|
C_cst((arith) wz);
|
||||||
|
C_cst((arith) pz);
|
||||||
|
C_mes_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void maxdes()
|
||||||
|
{
|
||||||
|
C_df_dnam("maxcdes");
|
||||||
|
rom(wz, 0L); rom(wz, -1L); rom(wz, (long) (wz+pz));
|
||||||
|
C_df_dnam("maxwdes");
|
||||||
|
rom(wz, 0L); rom(wz, -1L); rom(wz, (long) vz);
|
||||||
|
C_df_dnam("maxbdes");
|
||||||
|
rom(wz, 0L); rom(wz, -1L); rom(wz, 1L);
|
||||||
|
}
|
||||||
|
|
||||||
|
int new_label(L) register *L;
|
||||||
|
{
|
||||||
|
if (*L==0) *L= ++Lab;
|
||||||
|
return *L;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Label(L) register L;
|
||||||
|
{
|
||||||
|
if (L!=0) C_df_ilb((label) L);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Dot_label=0;
|
||||||
|
|
||||||
|
int new_dot_label(L) int *L;
|
||||||
|
{
|
||||||
|
return *L= ++Dot_label;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dot_label(L) int L;
|
||||||
|
{
|
||||||
|
C_df_dlb((label) L);
|
||||||
|
}
|
||||||
|
|
||||||
|
void branch(L) int *L;
|
||||||
|
{
|
||||||
|
C_bra((label) new_label(L));
|
||||||
|
}
|
||||||
|
|
||||||
|
char *proc_label(L, name) register L; register char *name;
|
||||||
|
{
|
||||||
|
static char *lab=nil;
|
||||||
|
register char *n;
|
||||||
|
|
||||||
|
if (lab!=nil) free(lab);
|
||||||
|
|
||||||
|
lab=malloc(strlen(name)+(1+sizeof(int)*3+1));
|
||||||
|
/* That is: P<L><name>\0 */
|
||||||
|
|
||||||
|
sprintf(lab, "P%d", L);
|
||||||
|
|
||||||
|
n=lab+strlen(lab);
|
||||||
|
|
||||||
|
while (*name!=0) {
|
||||||
|
*n++ = *name=='.' ? '_' : *name;
|
||||||
|
name++;
|
||||||
|
}
|
||||||
|
*n=0;
|
||||||
|
return lab;
|
||||||
|
}
|
||||||
|
|
||||||
|
void magic() /* magic? should be called invisible */
|
||||||
|
{
|
||||||
|
C_magic();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cwv()
|
||||||
|
{
|
||||||
|
if (vz>wz) {
|
||||||
|
C_loc((arith) wz);
|
||||||
|
C_loc((arith) vz);
|
||||||
|
C_cii();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cvw()
|
||||||
|
{
|
||||||
|
if (vz>wz) {
|
||||||
|
C_loc((arith) vz);
|
||||||
|
C_loc((arith) wz);
|
||||||
|
C_cii();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Loc(const) long const;
|
||||||
|
{
|
||||||
|
if (vz>wz) C_ldc((arith) const); else C_loc((arith) const);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Lol(offset) int offset;
|
||||||
|
{
|
||||||
|
if (vz>wz) C_ldl((arith) offset); else C_lol((arith) offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Lolp(offset) int offset;
|
||||||
|
{
|
||||||
|
if (pz>wz) C_ldl((arith) offset); else C_lol((arith) offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Lil(offset) register offset;
|
||||||
|
{
|
||||||
|
if (vz>wz) {
|
||||||
|
Lolp(offset);
|
||||||
|
C_loi((arith) vz);
|
||||||
|
} else
|
||||||
|
C_lil((arith) offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Lof(offset) int offset;
|
||||||
|
{
|
||||||
|
if (vz>wz) C_ldf((arith) offset); else C_lof((arith) offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Lofp(offset) int offset;
|
||||||
|
{
|
||||||
|
if (pz>wz) C_ldf((arith) offset); else C_lof((arith) offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Lif(offset) register offset;
|
||||||
|
{
|
||||||
|
Lofp(offset);
|
||||||
|
C_loi((arith) vz);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Stl(offset) int offset;
|
||||||
|
{
|
||||||
|
if (vz>wz) C_sdl((arith) offset); else C_stl((arith) offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Inl(offset) register offset;
|
||||||
|
{
|
||||||
|
if (vz>wz) {
|
||||||
|
C_ldl((arith) offset);
|
||||||
|
C_ldc((arith) 1);
|
||||||
|
C_adi((arith) vz);
|
||||||
|
C_sdl((arith) offset);
|
||||||
|
} else
|
||||||
|
C_inl((arith) offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Del(offset) register offset;
|
||||||
|
{
|
||||||
|
if (vz>wz) {
|
||||||
|
C_ldl((arith) offset);
|
||||||
|
C_ldc((arith) 1);
|
||||||
|
C_sbi((arith) vz);
|
||||||
|
C_sdl((arith) offset);
|
||||||
|
} else
|
||||||
|
C_del((arith) offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Loe(name, offset) char *name; int offset;
|
||||||
|
{
|
||||||
|
if (vz>wz)
|
||||||
|
C_lde_dnam(name, (arith) offset);
|
||||||
|
else
|
||||||
|
C_loe_dnam(name, (arith) offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef int (*pfi)();
|
||||||
|
|
||||||
|
static int operators[]= { '<', '>', '=', GE, LE, NE };
|
||||||
|
|
||||||
|
extern C_blt(), C_bgt(), C_beq(), C_bge(), C_ble(), C_bne();
|
||||||
|
extern C_tlt(), C_tgt(), C_teq(), C_tge(), C_tle(), C_tne();
|
||||||
|
extern C_zlt(), C_zgt(), C_zeq(), C_zge(), C_zle(), C_zne();
|
||||||
|
|
||||||
|
static pfi C_bxx[]= { C_blt, C_bgt, C_beq, C_bge, C_ble, C_bne };
|
||||||
|
static pfi C_txx[]= { C_tlt, C_tgt, C_teq, C_tge, C_tle, C_tne };
|
||||||
|
static pfi C_zxx[]= { C_zlt, C_zgt, C_zeq, C_zge, C_zle, C_zne };
|
||||||
|
|
||||||
|
void bxx(pos, op, L) register pos, op, L;
|
||||||
|
{
|
||||||
|
register i;
|
||||||
|
|
||||||
|
if (op==AFTER) {
|
||||||
|
C_sbi((arith) vz);
|
||||||
|
if (vz>wz) {
|
||||||
|
C_ldc((arith) 0);
|
||||||
|
C_cmi((arith) vz);
|
||||||
|
}
|
||||||
|
if (pos) C_zle((label) L); else C_zgt((label) L);
|
||||||
|
} else {
|
||||||
|
for (i=0; operators[i]!=op; i++) ;
|
||||||
|
if (pos && (i+=3)>=6) i-=6;
|
||||||
|
if (vz>wz) {
|
||||||
|
C_cmi((arith) vz);
|
||||||
|
(C_zxx[i])((label) L);
|
||||||
|
} else {
|
||||||
|
(C_bxx[i])((label) L);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Txx(op) register int op;
|
||||||
|
{
|
||||||
|
register i;
|
||||||
|
|
||||||
|
for (i=0; operators[i]!=op; i++) ;
|
||||||
|
|
||||||
|
(C_txx[i])();
|
||||||
|
cwv();
|
||||||
|
C_ngi((arith) vz);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern C_adi(), C_sbi(), C_mli(), C_dvi(), C_rmi();
|
||||||
|
|
||||||
|
void xxi(op) register op;
|
||||||
|
{
|
||||||
|
static int operators[]= { '+', '-', '*', '/', BS };
|
||||||
|
static pfi C_xxi[]= { C_adi, C_sbi, C_mli, C_dvi, C_rmi };
|
||||||
|
register i;
|
||||||
|
|
||||||
|
for (i=0; operators[i]!=op; i++) ;
|
||||||
|
|
||||||
|
(C_xxi[i])((arith) vz);
|
||||||
|
}
|
||||||
|
|
||||||
|
void aar() { C_aar((arith) wz); }
|
||||||
|
void adp(offset) int offset; { C_adp((arith) offset); }
|
||||||
|
void and() { C_and((arith) vz); }
|
||||||
|
void asp(size) int size; { C_asp((arith) size); }
|
||||||
|
void blm(size) int size; { C_blm((arith) size); }
|
||||||
|
void blt(lab) int lab; { C_blt((label) lab); }
|
||||||
|
void cal(lab) char *lab; { C_cal(lab); }
|
||||||
|
void cmi() { C_cmi((arith) vz); }
|
||||||
|
void com() { C_com((arith) vz); }
|
||||||
|
void del(offset) int offset; { C_del((arith) offset); }
|
||||||
|
void _end(size) int size; { C_end((arith) size); }
|
||||||
|
void exp(lab) char *lab; { C_exp(lab); }
|
||||||
|
void ior() { C_ior((arith) vz); }
|
||||||
|
void lae(lab, offset) char *lab; int offset;
|
||||||
|
{ C_lae_dnam(lab, (arith) offset); }
|
||||||
|
void laedot(lab) int lab; { C_lae_dlb((label) lab, (arith) 0); }
|
||||||
|
void lal(offset) int offset; { C_lal((arith) offset); }
|
||||||
|
void lar() { C_lar((arith) wz); }
|
||||||
|
void ldc0() { C_ldc((arith) 0); }
|
||||||
|
void ldl(offset) int offset; { C_ldl((arith) offset); }
|
||||||
|
void lfr(size) int size; { C_lfr((arith) size); }
|
||||||
|
void loc(cst) int cst; { C_loc((arith) cst); }
|
||||||
|
void loi(size) int size; { C_loi((arith) size); }
|
||||||
|
void lol(offset) int offset; { C_lol((arith) offset); }
|
||||||
|
void lor0() { C_lor((arith) 0); }
|
||||||
|
void lxa(offset) int offset; { C_lxa((arith) offset); }
|
||||||
|
void lxl(offset) int offset; { C_lxl((arith) offset); }
|
||||||
|
void meserr() { C_mes_begin(0); C_mes_end(); }
|
||||||
|
void ngi() { C_ngi((arith) vz); }
|
||||||
|
void pro(lab) char *lab; { C_pro_narg(lab); }
|
||||||
|
void ret(size) int size; { C_ret((arith) size); }
|
||||||
|
void init_rt() { C_cal("init"); }
|
||||||
|
void sli() { C_sli((arith) vz); }
|
||||||
|
void sri() { C_sri((arith) vz); }
|
||||||
|
void ste(lab, offset) char *lab; int offset;
|
||||||
|
{ C_ste_dnam(lab, (arith) offset); }
|
||||||
|
void sti(size) int size; { C_sti((arith) size); }
|
||||||
|
void stl(offset) int offset; { C_stl((arith) offset); }
|
||||||
|
void trp() { C_trp(); }
|
||||||
|
void tst() { /* No flags in EM */ }
|
||||||
|
void xor() { C_xor((arith) vz); }
|
||||||
|
void zeq(lab) int lab; { C_zeq((label) lab); }
|
||||||
|
void zgt(lab) int lab; { C_zgt((label) lab); }
|
||||||
|
void zlt(lab) int lab; { C_zlt((label) lab); }
|
||||||
|
void zne(lab) int lab; { C_zne((label) lab); }
|
||||||
|
|
||||||
|
char *itoa(i) long i;
|
||||||
|
{
|
||||||
|
static char a[sizeof(long)*3];
|
||||||
|
sprintf(a, "%D", i);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rom(size, c) int size; long c;
|
||||||
|
{
|
||||||
|
C_rom_icon(itoa(c), (arith) size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void lin()
|
||||||
|
{
|
||||||
|
static oldline=0;
|
||||||
|
extern yylineno;
|
||||||
|
|
||||||
|
if (yylineno!=oldline)
|
||||||
|
C_lin((arith) (oldline=yylineno));
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ftree {
|
||||||
|
char *file;
|
||||||
|
int lab;
|
||||||
|
struct ftree *left, *right;
|
||||||
|
} std_f = { "stdin", 0, nil, nil }, *curr_f= &std_f, *main_f=nil;
|
||||||
|
|
||||||
|
char *curr_file="stdin";
|
||||||
|
|
||||||
|
static void do_fil(f) struct ftree *f;
|
||||||
|
{
|
||||||
|
if (f->lab==0) {
|
||||||
|
dot_label(new_dot_label(&f->lab));
|
||||||
|
C_rom_scon(f->file, (arith) strlen(f->file));
|
||||||
|
}
|
||||||
|
C_fil_dlb((label) f->lab);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fil()
|
||||||
|
{
|
||||||
|
do_fil(curr_f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main_fil()
|
||||||
|
{
|
||||||
|
do_fil(main_f==nil ? &std_f : main_f);
|
||||||
|
}
|
||||||
|
|
||||||
|
int set_file(f) char *f;
|
||||||
|
{
|
||||||
|
char *strcpy();
|
||||||
|
static struct ftree *ftop=nil;
|
||||||
|
register struct ftree *pf, **apf= &ftop;
|
||||||
|
register cmp;
|
||||||
|
|
||||||
|
while ((pf= *apf)!=nil && (cmp=strcmp(f, pf->file))!=0)
|
||||||
|
apf= cmp<0 ? &pf->left : &pf->right;
|
||||||
|
|
||||||
|
if (pf==nil) {
|
||||||
|
*apf= pf= (struct ftree *) malloc(sizeof *pf);
|
||||||
|
pf->file=strcpy(malloc(strlen(f)+1), f);
|
||||||
|
pf->lab=0;
|
||||||
|
pf->left=pf->right=nil;
|
||||||
|
}
|
||||||
|
curr_f=pf;
|
||||||
|
curr_file=pf->file;
|
||||||
|
if (main_f==nil) {
|
||||||
|
main_f=curr_f;
|
||||||
|
return 0;
|
||||||
|
} else
|
||||||
|
return curr_f!=main_f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void par_begin()
|
||||||
|
{
|
||||||
|
C_lal((arith) curr_offset);
|
||||||
|
C_cal("pc_begin");
|
||||||
|
C_asp((arith) pz);
|
||||||
|
}
|
||||||
|
|
||||||
|
void par_fork(NONZERO) int *NONZERO;
|
||||||
|
{
|
||||||
|
C_cal("pc_fork");
|
||||||
|
C_lfr((arith) wz);
|
||||||
|
C_zne((label) new_label(NONZERO));
|
||||||
|
}
|
||||||
|
|
||||||
|
void resumenext()
|
||||||
|
{
|
||||||
|
C_cal("resumene");
|
||||||
|
}
|
||||||
|
|
||||||
|
void no_deadlock()
|
||||||
|
{
|
||||||
|
C_zre_dnam("deadlock", (arith) 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void par_end()
|
||||||
|
{
|
||||||
|
C_cal("parend");
|
||||||
|
}
|
||||||
|
|
||||||
|
void closefile()
|
||||||
|
{
|
||||||
|
C_close();
|
||||||
|
}
|
21
lang/occam/comp/em.h
Normal file
21
lang/occam/comp/em.h
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#ifndef nil
|
||||||
|
#define nil 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define word_constant(c) (-32768L<=(c) && (c)<=32767L)
|
||||||
|
void Label(), dot_label(), branch();
|
||||||
|
int new_label(), new_dot_label();
|
||||||
|
char *proc_label();
|
||||||
|
extern char *curr_file;
|
||||||
|
|
||||||
|
void cwv(), cvw();
|
||||||
|
void bxx(), Loc(), Lol(), Lolp(), Lil(), Lof(), Lofp(), Lif();
|
||||||
|
void Txx(), xxi(), Stl(), Inl(), Del(), Loe();
|
||||||
|
void cmi(), ngi(), and(), ior(), xor(), sli(), sri(), com(), lar(), lxl();
|
||||||
|
void lxa(), lfr(), ste(), lae(), aar(), lal(), adp(), ldc0(), zeq(), zne();
|
||||||
|
void zlt(), zgt(), blm(), sti(), cal(), asp(), loc(), lor0(), loi(), pro();
|
||||||
|
void ret(), _end(), stl(), laedot(), del(), lol(), ldl(), meswp(), meserr();
|
||||||
|
void init_rt(), exp(), rom(), blt(), magic(), lin(), tst(), fil(), trp();
|
||||||
|
void main_fil(), init(), openfile(), closefile(), maxdes();
|
||||||
|
|
||||||
|
void par_begin(), par_fork(), par_end(), resumenext(), no_deadlock();
|
471
lang/occam/comp/expr.c
Normal file
471
lang/occam/comp/expr.c
Normal file
|
@ -0,0 +1,471 @@
|
||||||
|
#include "symtab.h"
|
||||||
|
#include "sizes.h"
|
||||||
|
#include "expr.h"
|
||||||
|
#include "Lpars.h"
|
||||||
|
|
||||||
|
static void rvalue(), assignable(), inputable(), outputable(), subscriptable();
|
||||||
|
static void assigned();
|
||||||
|
|
||||||
|
/* The new_* functions make use of the used() and assinged() functions to
|
||||||
|
* make known what is done to a variable.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct expr *new_node(op, left, right, byte)
|
||||||
|
int op;
|
||||||
|
register struct expr *left, *right;
|
||||||
|
int byte;
|
||||||
|
/* Makes a new node with given operator, left and right operand.
|
||||||
|
* Constant folding is done if possible.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
if (op!=FOR && constant(left) && (right==nil || constant(right))) {
|
||||||
|
register long lc, rc;
|
||||||
|
|
||||||
|
lc=left->u.const;
|
||||||
|
rc=right->u.const;
|
||||||
|
|
||||||
|
switch (op) {
|
||||||
|
case '+': lc+=rc; break;
|
||||||
|
case '-': lc-=rc; break;
|
||||||
|
case '*': lc*=rc; break;
|
||||||
|
case '/': if (rc==0L)
|
||||||
|
report("division by zero");
|
||||||
|
else
|
||||||
|
lc/=rc;
|
||||||
|
break;
|
||||||
|
case BS: lc%=rc; break;
|
||||||
|
case '<': lc= lc<rc ? -1L : 0L; break;
|
||||||
|
case '>': lc= lc>rc ? -1L : 0L; break;
|
||||||
|
case LE: lc= lc<=rc ? -1L : 0L; break;
|
||||||
|
case GE: lc= lc>=rc ? -1L : 0L; break;
|
||||||
|
case NE: lc= lc!=rc ? -1L : 0L; break;
|
||||||
|
case '=': lc= lc==rc ? -1L : 0L; break;
|
||||||
|
case AFTER: lc= (lc-rc)>0 ? -1L : 0L; break;
|
||||||
|
case BA: lc&=rc; break;
|
||||||
|
case BO: lc|=rc; break;
|
||||||
|
case BX: lc^=rc; break;
|
||||||
|
case AND: lc= lc&&rc ? -1L : 0L; break;
|
||||||
|
case OR: lc= lc||rc ? -1L : 0L; break;
|
||||||
|
case LS: lc<<=rc; break;
|
||||||
|
case RS: lc>>=rc; break;
|
||||||
|
case '~': lc= -lc; break;
|
||||||
|
case NOT: lc= ~lc; break;
|
||||||
|
default:
|
||||||
|
report("illegal operator on constants");
|
||||||
|
}
|
||||||
|
destroy(right);
|
||||||
|
|
||||||
|
left->u.const=lc;
|
||||||
|
return left;
|
||||||
|
} else {
|
||||||
|
register struct expr *pe;
|
||||||
|
int type=0, arr_siz=1;
|
||||||
|
|
||||||
|
switch (op) {
|
||||||
|
case '+': case '-': case '*': case '/':
|
||||||
|
case BS: case '<': case '>': case LE:
|
||||||
|
case GE: case NE: case '=': case AFTER:
|
||||||
|
case BA: case BO: case BX: case AND:
|
||||||
|
case OR: case LS: case RS:
|
||||||
|
rvalue(left);
|
||||||
|
rvalue(right);
|
||||||
|
type=T_VALUE;
|
||||||
|
break;
|
||||||
|
case '~':
|
||||||
|
case NOT:
|
||||||
|
rvalue(left);
|
||||||
|
type=T_VALUE;
|
||||||
|
break;
|
||||||
|
case AS:
|
||||||
|
assignable(left, right);
|
||||||
|
type=T_VOID;
|
||||||
|
break;
|
||||||
|
case '[':
|
||||||
|
subscriptable(left, right, byte, &type, &arr_siz);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pe= (struct expr *) malloc(sizeof *pe);
|
||||||
|
|
||||||
|
pe->kind=E_NODE;
|
||||||
|
pe->type=type;
|
||||||
|
pe->arr_siz=arr_siz;
|
||||||
|
pe->u.node.op=op;
|
||||||
|
pe->u.node.left=left;
|
||||||
|
pe->u.node.right=right;
|
||||||
|
|
||||||
|
return pe;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct expr *new_var(var)
|
||||||
|
register struct symbol *var;
|
||||||
|
/* Given a variable an expression node is constructed. Note the changes in
|
||||||
|
* type! T_VAR becomes T_VALUE with flag T_LVALUE.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
register struct expr *pe;
|
||||||
|
|
||||||
|
pe= (struct expr *) malloc(sizeof *pe);
|
||||||
|
|
||||||
|
pe->kind=E_VAR;
|
||||||
|
|
||||||
|
if ((var->type&T_TYPE)==T_VAR || var->type&T_NOTDECL) {
|
||||||
|
pe->type=(var->type&(~T_TYPE));
|
||||||
|
pe->type|=T_VALUE|T_LVALUE;
|
||||||
|
} else
|
||||||
|
pe->type=var->type;
|
||||||
|
|
||||||
|
pe->arr_siz=var->arr_siz;
|
||||||
|
|
||||||
|
pe->u.var=var;
|
||||||
|
|
||||||
|
return pe;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct expr *new_const(const)
|
||||||
|
long const;
|
||||||
|
/* Make a constant, which is a VALUE, of course. */
|
||||||
|
{
|
||||||
|
register struct expr *pe;
|
||||||
|
|
||||||
|
pe= (struct expr *) malloc(sizeof *pe);
|
||||||
|
|
||||||
|
pe->kind=E_CONST;
|
||||||
|
pe->type=T_VALUE;
|
||||||
|
pe->u.const=const;
|
||||||
|
|
||||||
|
return pe;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct expr *new_table(kind, tab)
|
||||||
|
register kind;
|
||||||
|
register struct table *tab;
|
||||||
|
/* One table is being made, it is no doubt a VALUEd ARRay, but maybe even a
|
||||||
|
* BYTE array. A label is reserved for it and the individual elements are
|
||||||
|
* rommified.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
register struct expr *pe;
|
||||||
|
|
||||||
|
pe= (struct expr *) malloc(sizeof *pe);
|
||||||
|
|
||||||
|
pe->kind=kind;
|
||||||
|
pe->type=T_VALUE|T_ARR;
|
||||||
|
if (kind==E_BTAB) pe->type|=T_BYTE;
|
||||||
|
dot_label(new_dot_label(&pe->u.tab));
|
||||||
|
|
||||||
|
pe->arr_siz=0;
|
||||||
|
while (tab!=nil) {
|
||||||
|
register struct table *junk=tab;
|
||||||
|
|
||||||
|
rom(kind==E_BTAB ? 1 : vz, tab->val);
|
||||||
|
|
||||||
|
tab=tab->next;
|
||||||
|
pe->arr_siz++;
|
||||||
|
free(junk);
|
||||||
|
}
|
||||||
|
|
||||||
|
return pe;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct expr *copy_const(e) struct expr *e;
|
||||||
|
/* If you double it up, you've got one you can throw away. (Or do something
|
||||||
|
* useful with).
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
register struct expr *c;
|
||||||
|
|
||||||
|
c= (struct expr *) malloc(sizeof *c);
|
||||||
|
|
||||||
|
*c= *e;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct expr *new_now()
|
||||||
|
/* Now is the time to make a VALUE cell for the clock. */
|
||||||
|
{
|
||||||
|
register struct expr *pe;
|
||||||
|
|
||||||
|
pe= (struct expr *) malloc(sizeof *pe);
|
||||||
|
|
||||||
|
pe->kind=E_NOW;
|
||||||
|
pe->type=T_VALUE;
|
||||||
|
|
||||||
|
return pe;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct expr *new_io(out, chan, args)
|
||||||
|
int out;
|
||||||
|
register struct expr *chan;
|
||||||
|
struct expr_list *args;
|
||||||
|
/* Either c ? v0; v1; v2; ... (out=0) or c ! e0; e1; e2; ... (out=1). */
|
||||||
|
{
|
||||||
|
register struct expr *pe;
|
||||||
|
|
||||||
|
if ( ( (chan->type&T_TYPE) != T_CHAN || (chan->type&T_ARR) )
|
||||||
|
&& ! (chan->type&T_NOTDECL)
|
||||||
|
)
|
||||||
|
report("channel variable expected");
|
||||||
|
used(chan);
|
||||||
|
|
||||||
|
pe= (struct expr *) malloc(sizeof *pe);
|
||||||
|
|
||||||
|
pe->kind=E_IO;
|
||||||
|
pe->type=T_VOID;
|
||||||
|
pe->u.io.out=out;
|
||||||
|
pe->u.io.chan=chan;
|
||||||
|
pe->u.io.args=args;
|
||||||
|
|
||||||
|
return pe;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct expr *new_call(proc, args)
|
||||||
|
struct expr *proc;
|
||||||
|
struct expr_list *args;
|
||||||
|
/* Dial proc(arg1, arg2, ...) and you'll hear the tone of this function.
|
||||||
|
* Dialing yourself is not allowed, but it will work if you ignore the
|
||||||
|
* compiler generated noise.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
register struct expr *pe;
|
||||||
|
|
||||||
|
pe= (struct expr *) malloc(sizeof *pe);
|
||||||
|
|
||||||
|
used(proc);
|
||||||
|
|
||||||
|
check_recursion(proc);
|
||||||
|
|
||||||
|
pe->kind=E_CALL;
|
||||||
|
pe->type=T_VOID;
|
||||||
|
pe->u.call.proc=proc;
|
||||||
|
pe->u.call.args=args;
|
||||||
|
|
||||||
|
return pe;
|
||||||
|
}
|
||||||
|
|
||||||
|
void table_add(aapt, val) register struct table ***aapt; long val;
|
||||||
|
/* Adds a value to a table using a hook to a hook. */
|
||||||
|
{
|
||||||
|
register struct table *pt;
|
||||||
|
|
||||||
|
pt= (struct table *) malloc(sizeof *pt);
|
||||||
|
|
||||||
|
pt->val=val;
|
||||||
|
pt->next= **aapt;
|
||||||
|
|
||||||
|
**aapt=pt;
|
||||||
|
*aapt= &pt->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
void expr_list_add(aaelp, arg)
|
||||||
|
register struct expr_list ***aaelp;
|
||||||
|
struct expr *arg;
|
||||||
|
/* Another add, this time for actual arguments and the like. */
|
||||||
|
{
|
||||||
|
register struct expr_list *elp;
|
||||||
|
|
||||||
|
elp= (struct expr_list *) malloc(sizeof *elp);
|
||||||
|
|
||||||
|
elp->arg=arg;
|
||||||
|
elp->next= **aaelp;
|
||||||
|
**aaelp=elp;
|
||||||
|
*aaelp= &elp->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
void check_io(out, arg) int out; struct expr *arg;
|
||||||
|
{
|
||||||
|
if (out)
|
||||||
|
outputable(arg);
|
||||||
|
else
|
||||||
|
inputable(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void check_wait(e) struct expr *e;
|
||||||
|
{
|
||||||
|
if ((e->type&T_TYPE)!=T_VALUE)
|
||||||
|
report("WAIT process needs valued operand");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void assigned(e) register struct expr *e;
|
||||||
|
/* Tries to tell e that it is assigned to. */
|
||||||
|
{
|
||||||
|
if (e->kind==E_VAR || (e->kind==E_NODE && e->u.node.op=='['
|
||||||
|
&& (e=e->u.node.left)->kind==E_VAR)
|
||||||
|
) {
|
||||||
|
register struct symbol *var;
|
||||||
|
|
||||||
|
if ((var=e->u.var)->type&T_REP) {
|
||||||
|
warning("replicator index %s may not be assigned",
|
||||||
|
var->name);
|
||||||
|
var->type&= ~T_REP;
|
||||||
|
}
|
||||||
|
var->type|=T_ASSIGNED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void used(e) register struct expr *e;
|
||||||
|
{
|
||||||
|
if (e->kind==E_VAR || (e->kind==E_NODE && e->u.node.op=='['
|
||||||
|
&& (e=e->u.node.left)->kind==E_VAR)
|
||||||
|
) {
|
||||||
|
register struct symbol *var;
|
||||||
|
|
||||||
|
if ( ! ( (var=e->u.var)->type&(T_ASSIGNED|T_BUILTIN))
|
||||||
|
&& (var->type&T_TYPE)==T_VAR
|
||||||
|
&& var->info.vc.st.level==curr_level)
|
||||||
|
warning("%s used before assigned", var->name);
|
||||||
|
var->type|=(T_USED|T_ASSIGNED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rvalue(e) register struct expr *e;
|
||||||
|
{
|
||||||
|
if ((e->type&T_TYPE)!=T_VALUE || e->type&T_ARR)
|
||||||
|
report("illegal operand of arithmetic operator");
|
||||||
|
used(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void assignable(l, r) register struct expr *l, *r;
|
||||||
|
/* See if l can be assigned r. */
|
||||||
|
{
|
||||||
|
if ( ! ( (l->type&T_LVALUE && (r->type&T_TYPE)==T_VALUE
|
||||||
|
&& (l->type&T_ARR)==(r->type&T_ARR))
|
||||||
|
|| (l->type|r->type)&T_NOTDECL
|
||||||
|
))
|
||||||
|
report("operands of assignment are not conformable");
|
||||||
|
else
|
||||||
|
if (l->type&T_ARR && ! ( (l->type|r->type)&T_NOTDECL ) ) {
|
||||||
|
register lsiz=l->arr_siz, rsiz=r->arr_siz;
|
||||||
|
|
||||||
|
if (lsiz!=0 && rsiz!=0 && lsiz!=rsiz)
|
||||||
|
report("arrays have incompatible sizes");
|
||||||
|
}
|
||||||
|
used(r);
|
||||||
|
assigned(l);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void inputable(e) struct expr *e;
|
||||||
|
{
|
||||||
|
if ( ! (e->type&T_LVALUE) )
|
||||||
|
report("operand of input process can't be assigned");
|
||||||
|
|
||||||
|
assigned(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void outputable(e) struct expr *e;
|
||||||
|
{
|
||||||
|
if ( ! ( (e->type&T_TYPE)==T_VALUE ) )
|
||||||
|
report("operand of output process has no value");
|
||||||
|
used(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void subscriptable(l, r, byte, atype, arr_siz)
|
||||||
|
register struct expr *l, *r;
|
||||||
|
register byte;
|
||||||
|
int *atype, *arr_siz;
|
||||||
|
/* Tries to subscript l by r, returning type and array size for slices. */
|
||||||
|
{
|
||||||
|
register type= (l->type&T_TYPE)|byte;
|
||||||
|
|
||||||
|
if ( !(l->type&(T_ARR|T_NOTDECL) ) )
|
||||||
|
report("indexing on a non-array");
|
||||||
|
else
|
||||||
|
if ( ! ( (r->type&T_TYPE)==T_VALUE
|
||||||
|
|| (r->kind==E_NODE && r->u.node.op==FOR)
|
||||||
|
) )
|
||||||
|
report("index is not computable");
|
||||||
|
|
||||||
|
type|=(l->type&T_LVALUE);
|
||||||
|
|
||||||
|
if (r->kind==E_NODE && r->u.node.op==FOR) {
|
||||||
|
type|=T_ARR;
|
||||||
|
if (r->u.node.right->kind!=E_CONST)
|
||||||
|
report("slice must be of constant size");
|
||||||
|
else
|
||||||
|
*arr_siz=r->u.node.right->u.const;
|
||||||
|
used(r->u.node.left);
|
||||||
|
} else
|
||||||
|
used(r);
|
||||||
|
*atype=type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void check_param(aform, act, err)
|
||||||
|
struct par_list **aform;
|
||||||
|
register struct expr *act;
|
||||||
|
int *err;
|
||||||
|
/* Test if formal parameter *aform corresponds with actual act. Err returns
|
||||||
|
* error status. The aform hook is set to the next formal after the check.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
register struct par_list *form= *aform;
|
||||||
|
register struct expr *left;
|
||||||
|
register struct symbol *var;
|
||||||
|
static char NONCORR[]="actual and formal parameter don't correspond";
|
||||||
|
|
||||||
|
if (form==nil) {
|
||||||
|
if (! *err) {
|
||||||
|
report("too many actual parameters");
|
||||||
|
*err=1;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((form->type&T_ARR)!=(act->type&T_ARR) && !(act->type&T_NOTDECL) ) {
|
||||||
|
report(NONCORR);
|
||||||
|
} else {
|
||||||
|
switch (form->type&T_TYPE) {
|
||||||
|
case T_VAR:
|
||||||
|
if ( ! (
|
||||||
|
(act->type&T_TYPE)==T_VALUE
|
||||||
|
&& act->type&T_LVALUE
|
||||||
|
&& !(act->type&T_BYTE)
|
||||||
|
))
|
||||||
|
report(NONCORR);
|
||||||
|
assigned(act);
|
||||||
|
used(act);
|
||||||
|
break;
|
||||||
|
case T_CHAN:
|
||||||
|
if((act->type&T_TYPE)!=T_CHAN && !(act->type&T_NOTDECL))
|
||||||
|
report(NONCORR);
|
||||||
|
used(act);
|
||||||
|
break;
|
||||||
|
case T_VALUE:
|
||||||
|
if ((act->type&T_TYPE)!=T_VALUE)
|
||||||
|
report(NONCORR);
|
||||||
|
used(act);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*aform= form->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy(e) register struct expr *e;
|
||||||
|
/* Opposite of making. */
|
||||||
|
{
|
||||||
|
if (e!=nil) {
|
||||||
|
switch (e->kind) {
|
||||||
|
case E_NODE:
|
||||||
|
destroy(e->u.node.left);
|
||||||
|
destroy(e->u.node.right);
|
||||||
|
break;
|
||||||
|
case E_IO:
|
||||||
|
case E_CALL:
|
||||||
|
destroy(e->kind==E_IO ? e->u.io.chan : e->u.call.proc);
|
||||||
|
{
|
||||||
|
register struct expr_list *elp, *junk;
|
||||||
|
|
||||||
|
elp= e->kind==E_IO ? e->u.io.args : e->u.call.args;
|
||||||
|
|
||||||
|
while (elp!=nil) {
|
||||||
|
destroy(elp->arg);
|
||||||
|
junk=elp;
|
||||||
|
elp=elp->next;
|
||||||
|
free(junk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
free(e);
|
||||||
|
}
|
||||||
|
}
|
61
lang/occam/comp/expr.h
Normal file
61
lang/occam/comp/expr.h
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
#define E_NODE 0
|
||||||
|
#define E_VAR 1 /* Variable *or* channel */
|
||||||
|
#define E_CONST 2
|
||||||
|
#define E_TABLE 3
|
||||||
|
#define E_BTAB 4
|
||||||
|
#define E_NOW 5
|
||||||
|
#define E_IO 6
|
||||||
|
#define E_CALL 7
|
||||||
|
|
||||||
|
struct table {
|
||||||
|
long val;
|
||||||
|
struct table *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct expr;
|
||||||
|
|
||||||
|
struct expr_list {
|
||||||
|
struct expr *arg;
|
||||||
|
struct expr_list *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct expr {
|
||||||
|
short kind;
|
||||||
|
short type;
|
||||||
|
int arr_siz;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
int op;
|
||||||
|
struct expr *left, *right;
|
||||||
|
} node;
|
||||||
|
|
||||||
|
struct symbol *var;
|
||||||
|
|
||||||
|
long const;
|
||||||
|
|
||||||
|
int tab;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
int out;
|
||||||
|
struct expr *chan;
|
||||||
|
struct expr_list *args;
|
||||||
|
} io;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct expr *proc;
|
||||||
|
struct expr_list *args;
|
||||||
|
} call;
|
||||||
|
} u;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct expr *new_node(), *new_var(), *new_const(), *new_table(), *new_now();
|
||||||
|
struct expr *new_io(), *new_call(), *copy_const();
|
||||||
|
void table_add(), expr_list_add();
|
||||||
|
void check_param(), check_io(), check_wait();
|
||||||
|
void destroy(), used();
|
||||||
|
|
||||||
|
#define valueless(e) (((e)->type&T_TYPE)==T_VOID)
|
||||||
|
#define valued(e) (((e)->type&T_TYPE)==T_VALUE)
|
||||||
|
#define input_process(e) ((e)->kind==E_IO && !(e)->u.io.out)
|
||||||
|
#define constant(e) ((e)->kind==E_CONST)
|
||||||
|
#define arr_constant(e) ((e)->kind==E_TABLE || (e)->kind==E_BTAB)
|
82
lang/occam/comp/keytab.c
Normal file
82
lang/occam/comp/keytab.c
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
/* keytab.c */
|
||||||
|
# include "Lpars.h"
|
||||||
|
# include <ctype.h>
|
||||||
|
|
||||||
|
# define NKEYWORDS ((sizeof keytab) / (sizeof *keytab))
|
||||||
|
# define MAXKEYLEN 8
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int k_token;
|
||||||
|
char *k_str;
|
||||||
|
} KTAB;
|
||||||
|
|
||||||
|
KTAB keytab[] = {
|
||||||
|
{ AFTER, "AFTER" }, { ALLOCATE, "ALLOCATE" },
|
||||||
|
{ ALT, "ALT" }, { AND, "AND" },
|
||||||
|
{ ANY, "ANY" }, { BYTE, "BYTE" },
|
||||||
|
{ CHAN, "CHAN" }, { DEF, "DEF" },
|
||||||
|
{ FALSE, "FALSE" }, { FOR, "FOR" },
|
||||||
|
{ IF, "IF" }, { LOAD, "LOAD" },
|
||||||
|
{ NOT, "NOT" }, { NOW, "NOW" },
|
||||||
|
{ OR, "OR" }, { PAR, "PAR" },
|
||||||
|
{ PLACED, "PLACED" }, { PORT, "PORT" },
|
||||||
|
{ PRI, "PRI" }, { PROC, "PROC" },
|
||||||
|
{ SEQ, "SEQ" }, { SKIP, "SKIP" },
|
||||||
|
{ TABLE, "TABLE" }, { TRUE, "TRUE" },
|
||||||
|
{ VALUE, "VALUE" }, { VAR, "VAR" },
|
||||||
|
{ WAIT, "WAIT" }, { WHILE, "WHILE" },
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The table of keywords is searched for the occurence of `str',
|
||||||
|
* if found the corresponding token number is returned,
|
||||||
|
* otherwise IDENTIFIER is the returned token number.
|
||||||
|
*/
|
||||||
|
keyword(str) char *str;
|
||||||
|
{
|
||||||
|
register int high= NKEYWORDS-1;
|
||||||
|
register int low= 0;
|
||||||
|
register int i, cmp;
|
||||||
|
char *lowerupper();
|
||||||
|
register char *key;
|
||||||
|
|
||||||
|
if ((key=lowerupper(str))==0) return IDENTIFIER;
|
||||||
|
|
||||||
|
do {
|
||||||
|
i= (high+low) / 2;
|
||||||
|
if ((cmp= strcmp(key, keytab[i].k_str)) == 0) break;
|
||||||
|
else if (cmp > 0) low= i+1;
|
||||||
|
else high= i-1;
|
||||||
|
} while (low <= high);
|
||||||
|
|
||||||
|
return low<=high ? keytab[i].k_token : IDENTIFIER;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *lowerupper(str) register char *str;
|
||||||
|
{
|
||||||
|
static char keyword[MAXKEYLEN+1];
|
||||||
|
register char *key=keyword;
|
||||||
|
|
||||||
|
if (islower(*str)) {
|
||||||
|
do
|
||||||
|
*key++ = toupper(*str++);
|
||||||
|
while (key<keyword+MAXKEYLEN && islower(*str));
|
||||||
|
} else {
|
||||||
|
do
|
||||||
|
*key++ = *str++;
|
||||||
|
while (key<keyword+MAXKEYLEN && isupper(*str));
|
||||||
|
}
|
||||||
|
*key=0;
|
||||||
|
|
||||||
|
return *str==0 ? keyword : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *keyname(key) register int key;
|
||||||
|
{
|
||||||
|
register KTAB *kp;
|
||||||
|
|
||||||
|
for (kp= keytab; kp< keytab+NKEYWORDS; kp++)
|
||||||
|
if (kp->k_token == key) return kp->k_str;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
344
lang/occam/comp/lex.l
Normal file
344
lang/occam/comp/lex.l
Normal file
|
@ -0,0 +1,344 @@
|
||||||
|
%{
|
||||||
|
/* lex.l */
|
||||||
|
# include <ctype.h>
|
||||||
|
# include "token.h"
|
||||||
|
# include "Lpars.h"
|
||||||
|
|
||||||
|
# define TAB 8 /* Size of a acsii tab (\t) in spaces */
|
||||||
|
# if (TAB&(TAB-1))!=0
|
||||||
|
# define TABSTOP(ind) ((ind)+TAB-(ind)%TAB)
|
||||||
|
# else
|
||||||
|
# define TABSTOP(ind) (((ind)+TAB)&(~(TAB-1)))
|
||||||
|
# endif
|
||||||
|
|
||||||
|
char *malloc(), *strcpy();
|
||||||
|
|
||||||
|
struct token token;
|
||||||
|
int ind=0; /* Indentation level of current line */
|
||||||
|
static int tab=0; /* First indentation found */
|
||||||
|
|
||||||
|
int included=0; /* Is current file included? */
|
||||||
|
%}
|
||||||
|
|
||||||
|
%%
|
||||||
|
'((\*[^\n])|([^'\n*]))*' {
|
||||||
|
if ((token.t_lval=char_constant(yytext+1))== -1L)
|
||||||
|
report("%s not a character constant", yytext);
|
||||||
|
|
||||||
|
return CHAR_CONST;
|
||||||
|
}
|
||||||
|
'[^'\n]*'? {
|
||||||
|
report("missing '.");
|
||||||
|
token.t_lval= -1L;
|
||||||
|
|
||||||
|
return CHAR_CONST;
|
||||||
|
}
|
||||||
|
\"((\*[^\n])|([^"\n*]))*\" {
|
||||||
|
char *string();
|
||||||
|
|
||||||
|
token.t_sval=string(yytext);
|
||||||
|
|
||||||
|
return STRING;
|
||||||
|
}
|
||||||
|
\"[^"\n]*\"? {
|
||||||
|
report("missing \".");
|
||||||
|
token.t_sval="";
|
||||||
|
|
||||||
|
return STRING;
|
||||||
|
}
|
||||||
|
#[ \t]*"line"?[ \t]*[0-9]+[ \t]*\"[^"\n]*\" {
|
||||||
|
set_line_file(yytext);
|
||||||
|
tab=0;
|
||||||
|
}
|
||||||
|
#[A-Fa-f0-9]+ {
|
||||||
|
long hex_number();
|
||||||
|
|
||||||
|
token.t_lval=hex_number(yytext+1);
|
||||||
|
|
||||||
|
return NUMBER;
|
||||||
|
}
|
||||||
|
[0-9]+ {
|
||||||
|
long number();
|
||||||
|
|
||||||
|
token.t_lval=number(yytext);
|
||||||
|
|
||||||
|
return NUMBER;
|
||||||
|
}
|
||||||
|
[A-Za-z][A-Za-z0-9.]* {
|
||||||
|
register key;
|
||||||
|
|
||||||
|
if ((key=keyword(yytext))==IDENTIFIER)
|
||||||
|
token.t_sval=strcpy(malloc(yyleng+1), yytext);
|
||||||
|
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
\n[ \f\t]*/"--" {/* Line with only a comment, don't set tab */}
|
||||||
|
|
||||||
|
\n[ \f\t]* {
|
||||||
|
|
||||||
|
ind=indentation(yytext+1);
|
||||||
|
if (tab==0)
|
||||||
|
tab=ind;
|
||||||
|
else
|
||||||
|
if (ind%tab!=0)
|
||||||
|
warning("indentation not on a %d space boundary", tab);
|
||||||
|
}
|
||||||
|
[ \f\t] { /* Nothing */ }
|
||||||
|
[-=<>:,;+*/\[\]()?!&] return yytext[0];
|
||||||
|
|
||||||
|
"\\" return BS;
|
||||||
|
":=" return AS;
|
||||||
|
"<=" return LE;
|
||||||
|
">=" return GE;
|
||||||
|
"<>" return NE;
|
||||||
|
"<<" return LS;
|
||||||
|
">>" return RS;
|
||||||
|
"/\\" return BA;
|
||||||
|
"\\/" return BO;
|
||||||
|
"><" return BX;
|
||||||
|
|
||||||
|
"--"[^\n]* { /* Comment is skipped */ }
|
||||||
|
. {
|
||||||
|
warning((' '<=yytext[0] && yytext[0]<0177) ? "%s'%c')" : "%soctal: %o)",
|
||||||
|
"bad character seen (", yytext[0]&0377);
|
||||||
|
}
|
||||||
|
%%
|
||||||
|
char *string(s) char *s;
|
||||||
|
{
|
||||||
|
register c;
|
||||||
|
register char *p= s;
|
||||||
|
char *str= s;
|
||||||
|
|
||||||
|
str++; p++;
|
||||||
|
while (*str != '"') {
|
||||||
|
if ((c=character(&str)) != -1)
|
||||||
|
*p++= c;
|
||||||
|
else
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
*p=0;
|
||||||
|
*s=p-(s+1);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
long number(s) register char *s;
|
||||||
|
{
|
||||||
|
static char max_str[]="2147483647";
|
||||||
|
int maxlen=sizeof max_str-1;
|
||||||
|
long atol();
|
||||||
|
long num;
|
||||||
|
|
||||||
|
while (*s=='0') { /* skip leading nulls */
|
||||||
|
*s++;
|
||||||
|
yyleng--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*s==0)
|
||||||
|
num=0L;
|
||||||
|
else {
|
||||||
|
if ((yyleng>maxlen) || (yyleng==maxlen && strcmp(s, max_str)>0))
|
||||||
|
warning("integer constant overflow.");
|
||||||
|
|
||||||
|
num=atol(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
long hex_number(s) register char *s;
|
||||||
|
{
|
||||||
|
long number=0L;
|
||||||
|
|
||||||
|
while (*s)
|
||||||
|
number=(number<<4)+hextoint(*s++);
|
||||||
|
|
||||||
|
return number;
|
||||||
|
}
|
||||||
|
|
||||||
|
int hextoint(c) register c;
|
||||||
|
{
|
||||||
|
register val;
|
||||||
|
|
||||||
|
if (islower(c))
|
||||||
|
val=(c-'a')+10;
|
||||||
|
else
|
||||||
|
if (isupper(c))
|
||||||
|
val=(c-'A')+10;
|
||||||
|
else
|
||||||
|
val=c-'0';
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
int character(S) register char **S;
|
||||||
|
{
|
||||||
|
register char *s= *S;
|
||||||
|
register c, cc;
|
||||||
|
|
||||||
|
if ((c= *s++)=='*') {
|
||||||
|
switch (c= *s++) {
|
||||||
|
case 'c':
|
||||||
|
cc='\r';
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
cc='\n';
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
cc='\t';
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
cc=' ';
|
||||||
|
break;
|
||||||
|
case '#':
|
||||||
|
if (isxdigit(c= *s++) && isxdigit(*s)) {
|
||||||
|
cc= (hextoint(c)<<4)+hextoint(*s++);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
report("two digit hexadecimal const expected.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
cc=c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
cc=c;
|
||||||
|
|
||||||
|
*S=s;
|
||||||
|
return cc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int char_constant(s) char *s;
|
||||||
|
{
|
||||||
|
register cc;
|
||||||
|
|
||||||
|
cc=character(&s);
|
||||||
|
|
||||||
|
return (*s=='\'' && cc!= -1) ? cc : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int indentation(s) register char *s;
|
||||||
|
{
|
||||||
|
register in=0, c;
|
||||||
|
|
||||||
|
while (c= *s++) {
|
||||||
|
if (c=='\t')
|
||||||
|
in=TABSTOP(in);
|
||||||
|
else
|
||||||
|
if (c=='\f')
|
||||||
|
in=0;
|
||||||
|
else
|
||||||
|
in++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return in;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tabulated(oind, ind) register oind, ind;
|
||||||
|
{
|
||||||
|
if (tab>0 && ind>oind+tab)
|
||||||
|
warning("process' indentation too large (changed to %d tab%s)",
|
||||||
|
oind/tab+1, oind>=tab ? "s" : "");
|
||||||
|
return ind>oind;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rep_tk=0;
|
||||||
|
struct token rep_token;
|
||||||
|
|
||||||
|
void repeat_token(tk)
|
||||||
|
{
|
||||||
|
rep_tk=tk;
|
||||||
|
rep_token=token;
|
||||||
|
}
|
||||||
|
|
||||||
|
scanner()
|
||||||
|
{
|
||||||
|
register tk;
|
||||||
|
|
||||||
|
if (rep_tk>0) {
|
||||||
|
tk=rep_tk;;
|
||||||
|
rep_tk=0;
|
||||||
|
token=rep_token;
|
||||||
|
return tk;
|
||||||
|
} else
|
||||||
|
return yylex();
|
||||||
|
}
|
||||||
|
|
||||||
|
char *tokenname(tk, inst) register tk, inst;
|
||||||
|
{
|
||||||
|
if (tk<0400) {
|
||||||
|
static char c[7];
|
||||||
|
|
||||||
|
if (' '<tk && tk<='~')
|
||||||
|
sprintf(c, "'%c'", tk);
|
||||||
|
else
|
||||||
|
sprintf(c, "'*#%02x'", tk);
|
||||||
|
return c;
|
||||||
|
} else {
|
||||||
|
switch (tk) {
|
||||||
|
char *keyname();
|
||||||
|
char fake_id[1+sizeof(int)*3+1];
|
||||||
|
static fake_cnt=0;
|
||||||
|
default:
|
||||||
|
return keyname(tk);
|
||||||
|
case IDENTIFIER:
|
||||||
|
if (inst) {
|
||||||
|
sprintf(fake_id, "_%d", ++fake_cnt);
|
||||||
|
token.t_sval=strcpy(malloc(strlen(fake_id)+1),
|
||||||
|
fake_id);
|
||||||
|
return "IDENTIFIER";
|
||||||
|
} else
|
||||||
|
return token.t_sval;
|
||||||
|
case NUMBER:
|
||||||
|
case CHAR_CONST:
|
||||||
|
token.t_lval=0L;
|
||||||
|
return "NUMBER";
|
||||||
|
case STRING:
|
||||||
|
if (inst) {
|
||||||
|
token.t_sval=malloc(1);
|
||||||
|
token.t_sval[0]=0;
|
||||||
|
} else
|
||||||
|
free(token.t_sval);
|
||||||
|
return "STRING";
|
||||||
|
case AS: case LE: case GE: case NE:
|
||||||
|
case LS: case RS: case BA: case BO:
|
||||||
|
case BX: case BS: {
|
||||||
|
static int op[]= {
|
||||||
|
AS, LE, GE, NE, LS, RS, BA, BO, BX, BS
|
||||||
|
};
|
||||||
|
static char *opc[]= {
|
||||||
|
":=", "<=", ">=", "<>", "<<", ">>", "/\\",
|
||||||
|
"\\/", "><", "\\"
|
||||||
|
};
|
||||||
|
register i;
|
||||||
|
static char qopc[5];
|
||||||
|
|
||||||
|
for (i=0; op[i]!=tk; i++) ;
|
||||||
|
sprintf(qopc, "'%s'", opc[i]);
|
||||||
|
return qopc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set_line_file(l) register char *l;
|
||||||
|
{
|
||||||
|
register char *file;
|
||||||
|
|
||||||
|
while (*l<'0' || *l>'9') l++;
|
||||||
|
|
||||||
|
yylineno=0;
|
||||||
|
while ('0'<=*l && *l<='9')
|
||||||
|
yylineno=yylineno*10+(*l++ - '0');
|
||||||
|
|
||||||
|
yylineno--;
|
||||||
|
|
||||||
|
while (*l++!='"');
|
||||||
|
|
||||||
|
file=l;
|
||||||
|
while (*l++!='"');
|
||||||
|
*--l=0;
|
||||||
|
|
||||||
|
included=set_file(file);
|
||||||
|
}
|
684
lang/occam/comp/occam.g
Normal file
684
lang/occam/comp/occam.g
Normal file
|
@ -0,0 +1,684 @@
|
||||||
|
/* OCCAM */
|
||||||
|
{
|
||||||
|
#include "token.h"
|
||||||
|
#include "symtab.h"
|
||||||
|
#include "expr.h"
|
||||||
|
#include "code.h"
|
||||||
|
#include "sizes.h"
|
||||||
|
|
||||||
|
#define MAXERRORS 10 /* Maximum number of insert/delete errors */
|
||||||
|
|
||||||
|
static void nonconst(), nonpositive(), rep_cleanup(), check_assoc();
|
||||||
|
void init_builtins();
|
||||||
|
|
||||||
|
extern int yylineno, LLsymb;
|
||||||
|
union type_info info, none;
|
||||||
|
}
|
||||||
|
%token AFTER, ALLOCATE, ALT, AND, ANY, BYTE, CHAN, DEF, FALSE, FOR, IF, LOAD;
|
||||||
|
%token NOT, NOW, OR, PAR, PLACED, PORT, PRI, PROC, SEQ, SKIP, TABLE, TRUE;
|
||||||
|
%token VALUE, VAR, WAIT, WHILE;
|
||||||
|
%token IDENTIFIER, NUMBER, CHAR_CONST, STRING;
|
||||||
|
%token AS, LE, GE, NE, LS, RS, BA, BO, BX, BS;
|
||||||
|
|
||||||
|
%start occam, program;
|
||||||
|
|
||||||
|
program : { init_builtins();
|
||||||
|
header();
|
||||||
|
}
|
||||||
|
process
|
||||||
|
;
|
||||||
|
|
||||||
|
process : primitive
|
||||||
|
| construct
|
||||||
|
| { sym_down(); }
|
||||||
|
declaration ':' process
|
||||||
|
{ sym_up(); }
|
||||||
|
;
|
||||||
|
|
||||||
|
primitive { struct expr *e; } :
|
||||||
|
statement(&e) { if (!valueless(e))
|
||||||
|
report("primitive may not have a value");
|
||||||
|
code_void(e);
|
||||||
|
destroy(e);
|
||||||
|
}
|
||||||
|
| WAIT val_expr(&e) { int BEGIN=0, END=0, TEST=0;
|
||||||
|
check_wait(e);
|
||||||
|
no_deadlock();
|
||||||
|
branch(&TEST);
|
||||||
|
Label(new_label(&BEGIN));
|
||||||
|
resumenext();
|
||||||
|
Label(TEST);
|
||||||
|
code_bool(e, positive, &END, &BEGIN);
|
||||||
|
Label(END);
|
||||||
|
destroy(e);
|
||||||
|
}
|
||||||
|
| SKIP
|
||||||
|
;
|
||||||
|
|
||||||
|
guard(register *F;) { struct expr *e1, *e2;
|
||||||
|
register full_guard=0;
|
||||||
|
int T=0;
|
||||||
|
static char EXPECT_INP[]="input process expected as guard";
|
||||||
|
} :
|
||||||
|
expression(&e1)
|
||||||
|
[ '&' { full_guard=1;
|
||||||
|
if (!valued(e1))
|
||||||
|
report("boolean part of guard has no value");
|
||||||
|
code_bool(e1, positive, &T, F);
|
||||||
|
Label(T);
|
||||||
|
}
|
||||||
|
[ statement(&e2)
|
||||||
|
{ if (!input_process(e2))
|
||||||
|
report(EXPECT_INP);
|
||||||
|
code_any(e2, F);
|
||||||
|
destroy(e2);
|
||||||
|
}
|
||||||
|
| WAIT val_expr(&e2)
|
||||||
|
{ check_wait(e2);
|
||||||
|
code_bool(e2, positive, &T, F);
|
||||||
|
Label(T);
|
||||||
|
destroy(e2);
|
||||||
|
}
|
||||||
|
| SKIP
|
||||||
|
]
|
||||||
|
]?
|
||||||
|
{ if (!full_guard) {
|
||||||
|
if (!input_process(e1))
|
||||||
|
report(EXPECT_INP);
|
||||||
|
code_any(e1, F);
|
||||||
|
}
|
||||||
|
destroy(e1);
|
||||||
|
}
|
||||||
|
| WAIT val_expr(&e1)
|
||||||
|
{ check_wait(e1);
|
||||||
|
code_bool(e1, positive, &T, F);
|
||||||
|
Label(T);
|
||||||
|
destroy(e1);
|
||||||
|
}
|
||||||
|
| SKIP
|
||||||
|
;
|
||||||
|
|
||||||
|
guarded_process(register *END;) { struct symbol *v;
|
||||||
|
struct expr *e1, *e2;
|
||||||
|
struct replicator to_test;
|
||||||
|
register line, oind;
|
||||||
|
int F=0;
|
||||||
|
} :
|
||||||
|
guard(&F) process { branch(END);
|
||||||
|
Label(F);
|
||||||
|
}
|
||||||
|
| ALT { line=yylineno; oind=ind; }
|
||||||
|
[ %if (line==yylineno)
|
||||||
|
replicator(&v, &e1, &e2)
|
||||||
|
{ rep_init(v, e1, e2, &to_test); }
|
||||||
|
guarded_process(END)
|
||||||
|
{ rep_test(v, e1, e2, &to_test);
|
||||||
|
rep_cleanup(e1, e2);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
[ %while (tabulated(oind, ind)) guarded_process(END) ]*
|
||||||
|
]
|
||||||
|
;
|
||||||
|
|
||||||
|
conditional(register *END; ) { struct symbol *v;
|
||||||
|
struct expr *e1, *e2;
|
||||||
|
struct replicator to_test;
|
||||||
|
register line, oind;
|
||||||
|
int T=0, F=0;
|
||||||
|
} :
|
||||||
|
val_expr(&e1) { if (!valued(e1))
|
||||||
|
report("conditional needs valued expression");
|
||||||
|
code_bool(e1, positive, &T, &F);
|
||||||
|
Label(T);
|
||||||
|
destroy(e1);
|
||||||
|
}
|
||||||
|
process
|
||||||
|
{ branch(END);
|
||||||
|
Label(F);
|
||||||
|
}
|
||||||
|
| IF { line=yylineno; oind=ind; }
|
||||||
|
[ %if (line==yylineno)
|
||||||
|
replicator(&v, &e1, &e2)
|
||||||
|
{ rep_init(v, e1, e2, &to_test); }
|
||||||
|
conditional(END)
|
||||||
|
{ rep_test(v, e1, e2, &to_test);
|
||||||
|
rep_cleanup(e1, e2);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
[ %while (tabulated(oind, ind)) conditional(END) ]*
|
||||||
|
]
|
||||||
|
;
|
||||||
|
|
||||||
|
replicator(register struct symbol **s; register struct expr **e1, **e2; )
|
||||||
|
{ register char *index; }:
|
||||||
|
IDENTIFIER { index=token.t_sval; }
|
||||||
|
'=' '[' val_expr(e1) FOR val_expr(e2) ']'
|
||||||
|
{ if (!valued(*e1) || !valued(*e2))
|
||||||
|
report("replicator needs valued expressions");
|
||||||
|
sym_down();
|
||||||
|
var_memory(&info, T_VAR, 1);
|
||||||
|
*s=insert(index,
|
||||||
|
T_VAR|T_REP|T_USED|T_ASSIGNED, 1, info);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
construct { struct symbol *v;
|
||||||
|
struct expr *e1, *e2;
|
||||||
|
struct replicator to_test;
|
||||||
|
register line, oind;
|
||||||
|
int BEGIN=0, END=0, NONZERO;
|
||||||
|
}:
|
||||||
|
SEQ { line=yylineno; oind=ind; }
|
||||||
|
[ %if (line==yylineno)
|
||||||
|
replicator(&v, &e1, &e2)
|
||||||
|
{ rep_init(v, e1, e2, &to_test); }
|
||||||
|
process
|
||||||
|
{ rep_test(v, e1, e2, &to_test);
|
||||||
|
rep_cleanup(e1, e2);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
[ %while (tabulated(oind, ind)) process ]*
|
||||||
|
]
|
||||||
|
| PRI ?
|
||||||
|
[ PAR { line=yylineno; oind=ind;
|
||||||
|
par_begin();
|
||||||
|
}
|
||||||
|
[ %if (line==yylineno)
|
||||||
|
replicator(&v, &e1, &e2)
|
||||||
|
{ rep_init(v, e1, e2, &to_test);
|
||||||
|
NONZERO=0;
|
||||||
|
par_fork(&NONZERO);
|
||||||
|
}
|
||||||
|
process
|
||||||
|
{ branch(&END);
|
||||||
|
Label(NONZERO);
|
||||||
|
rep_test(v, e1, e2, &to_test);
|
||||||
|
rep_cleanup(e1, e2);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
[ %while (tabulated(oind, ind))
|
||||||
|
{ NONZERO=0;
|
||||||
|
par_fork(&NONZERO);
|
||||||
|
}
|
||||||
|
process
|
||||||
|
{ branch(&END);
|
||||||
|
Label(NONZERO);
|
||||||
|
}
|
||||||
|
]*
|
||||||
|
]
|
||||||
|
{ Label(END);
|
||||||
|
par_end();
|
||||||
|
}
|
||||||
|
| ALT { line=yylineno; oind=ind;
|
||||||
|
no_deadlock();
|
||||||
|
Label(new_label(&BEGIN));
|
||||||
|
}
|
||||||
|
[ %if (line==yylineno)
|
||||||
|
replicator(&v, &e1, &e2)
|
||||||
|
{ rep_init(v, e1, e2, &to_test); }
|
||||||
|
guarded_process(&END)
|
||||||
|
{ rep_test(v, e1, e2, &to_test);
|
||||||
|
rep_cleanup(e1, e2);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
[ %while (tabulated(oind, ind)) guarded_process(&END)
|
||||||
|
]*
|
||||||
|
]
|
||||||
|
{ resumenext();
|
||||||
|
branch(&BEGIN);
|
||||||
|
Label(END);
|
||||||
|
}
|
||||||
|
]
|
||||||
|
| IF { line=yylineno; oind=ind; }
|
||||||
|
[ %if (line==yylineno)
|
||||||
|
replicator(&v, &e1, &e2)
|
||||||
|
{ rep_init(v, e1, e2, &to_test); }
|
||||||
|
conditional(&END)
|
||||||
|
{ rep_test(v, e1, e2, &to_test);
|
||||||
|
rep_cleanup(e1, e2);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
[ %while (tabulated(oind, ind)) conditional(&END) ]*
|
||||||
|
]
|
||||||
|
{ Label(END); }
|
||||||
|
| WHILE val_expr(&e1) { if (!valued(e1))
|
||||||
|
report("WHILE needs valued expression");
|
||||||
|
branch(&END);
|
||||||
|
Label(new_label(&BEGIN));
|
||||||
|
}
|
||||||
|
process
|
||||||
|
{ int DONE=0;
|
||||||
|
Label(END);
|
||||||
|
code_bool(e1, negative, &DONE, &BEGIN);
|
||||||
|
Label(DONE);
|
||||||
|
destroy(e1);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
subscript(register *byte; register struct expr **e; )
|
||||||
|
{ struct expr *e1;
|
||||||
|
register slice=0, err=0;
|
||||||
|
} :
|
||||||
|
'[' { *byte=0; }
|
||||||
|
[ BYTE { *byte=T_BYTE; }
|
||||||
|
]?
|
||||||
|
val_expr(e) { if (!valued(*e))
|
||||||
|
err++;
|
||||||
|
}
|
||||||
|
[ FOR expression(&e1)
|
||||||
|
{ static char siz[]="slize size";
|
||||||
|
if (!constant(e1)) {
|
||||||
|
if (!err)
|
||||||
|
nonconst(siz);
|
||||||
|
destroy(e1);
|
||||||
|
e1=new_const(0L);
|
||||||
|
} else
|
||||||
|
if (e1->u.const<=0)
|
||||||
|
nonpositive(siz);
|
||||||
|
*e=new_node(FOR, *e, e1);
|
||||||
|
slice=1;
|
||||||
|
}
|
||||||
|
]?
|
||||||
|
']'
|
||||||
|
{ if (err)
|
||||||
|
report(slice ?
|
||||||
|
"slice must be '[' value FOR constant ']'" :
|
||||||
|
"subscript needs valued expression");
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
chan { register type, arr_siz=1; register char *name; struct expr *e; }:
|
||||||
|
IDENTIFIER { type=T_CHAN;
|
||||||
|
name=token.t_sval;
|
||||||
|
}
|
||||||
|
[ '[' expression(&e) ']'
|
||||||
|
{ static char siz[]="channel array size";
|
||||||
|
if (!constant(e))
|
||||||
|
nonconst(siz);
|
||||||
|
else
|
||||||
|
if (e->u.const<0)
|
||||||
|
nonpositive(siz);
|
||||||
|
else
|
||||||
|
arr_siz=e->u.const;
|
||||||
|
destroy(e);
|
||||||
|
type|=T_ARR;
|
||||||
|
}
|
||||||
|
]?
|
||||||
|
{ chan_memory(&info, arr_siz);
|
||||||
|
chan_init(&info, arr_siz);
|
||||||
|
insert(name, type, arr_siz, info);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
var { register type, byte=0, arr_siz=1;
|
||||||
|
register char *name;
|
||||||
|
struct expr *e;
|
||||||
|
}:
|
||||||
|
IDENTIFIER { type=T_VAR; name=token.t_sval; }
|
||||||
|
[ '['
|
||||||
|
[ BYTE { byte=T_BYTE; }
|
||||||
|
]?
|
||||||
|
expression(&e) ']'
|
||||||
|
{ static char siz[]="variable array size";
|
||||||
|
if (!constant(e))
|
||||||
|
nonconst(siz);
|
||||||
|
else
|
||||||
|
if (e->u.const<=0)
|
||||||
|
nonpositive(siz);
|
||||||
|
else
|
||||||
|
arr_siz=e->u.const;
|
||||||
|
destroy(e);
|
||||||
|
type|=T_ARR|byte;
|
||||||
|
}
|
||||||
|
]?
|
||||||
|
{ var_memory(&info, type, arr_siz);
|
||||||
|
insert(name, type, arr_siz, info);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
const_def { register char *name; struct expr *e; }:
|
||||||
|
IDENTIFIER { name=token.t_sval; }
|
||||||
|
'=' expression(&e)
|
||||||
|
{ if (!constant(e) && !arr_constant(e))
|
||||||
|
nonconst("expression in constant definition");
|
||||||
|
info.const=e;
|
||||||
|
insert(name, T_CONST|T_USED, 0, info);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
form_parm(register struct par_list ***aapars; register *g_type;)
|
||||||
|
{ register char *name;
|
||||||
|
register type= *g_type;
|
||||||
|
}:
|
||||||
|
[ VAR { type=T_VAR|T_ASSIGNED|T_USED; }
|
||||||
|
| CHAN { type=T_CHAN; }
|
||||||
|
| VALUE { type=T_VALUE|T_ASSIGNED; }
|
||||||
|
]?
|
||||||
|
IDENTIFIER {
|
||||||
|
if (type<0) {
|
||||||
|
report("VAR, CHAN or VALUE expected");
|
||||||
|
type=T_VAR;
|
||||||
|
}
|
||||||
|
name=token.t_sval;
|
||||||
|
*g_type=type;
|
||||||
|
}
|
||||||
|
[ '[' ']'
|
||||||
|
{ type|=T_ARR; }
|
||||||
|
]?
|
||||||
|
{ pars_add(aapars, type&(T_TYPE|T_ARR),
|
||||||
|
insert(name, type|T_PARAM, 0, none));
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
form_parms(struct par_list **apars;) { int type= -1; }:
|
||||||
|
'(' form_parm(&apars, &type)
|
||||||
|
[ ',' form_parm(&apars, &type)
|
||||||
|
]*
|
||||||
|
')'
|
||||||
|
;
|
||||||
|
|
||||||
|
declaration:
|
||||||
|
VAR
|
||||||
|
var [ ',' var ]*
|
||||||
|
| CHAN
|
||||||
|
chan [ ',' chan ]*
|
||||||
|
| DEF
|
||||||
|
const_def [ ',' const_def ]*
|
||||||
|
| proc_declaration
|
||||||
|
;
|
||||||
|
|
||||||
|
proc_declaration { struct par_list *pars=nil;
|
||||||
|
register struct symbol *proc;
|
||||||
|
int OVER=0;
|
||||||
|
register old_min_offset;
|
||||||
|
}:
|
||||||
|
PROC IDENTIFIER { branch(&OVER);
|
||||||
|
proc=insert(token.t_sval,
|
||||||
|
T_PROC|T_RECURS, 0, none);
|
||||||
|
old_min_offset=min_offset;
|
||||||
|
sym_down();
|
||||||
|
prologue(proc);
|
||||||
|
}
|
||||||
|
form_parms(&pars) ? { form_offsets(pars);
|
||||||
|
proc->info.proc.pars=pars;
|
||||||
|
}
|
||||||
|
'=' process { epilogue(proc);
|
||||||
|
sym_up();
|
||||||
|
proc->type&= ~T_RECURS;
|
||||||
|
min_offset=old_min_offset;
|
||||||
|
Label(OVER);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
vector_constant(register struct expr **e;)
|
||||||
|
{ struct table *pt=nil, **apt= &pt;
|
||||||
|
register Tlen=0;
|
||||||
|
}:
|
||||||
|
table(e)
|
||||||
|
| STRING { register char *ps= token.t_sval;
|
||||||
|
register len;
|
||||||
|
|
||||||
|
Tlen+= len= (*ps++ & 0377);
|
||||||
|
while (--len>=0)
|
||||||
|
table_add(&apt, (long) *ps++);
|
||||||
|
}
|
||||||
|
[ %while (1) STRING
|
||||||
|
{ register char *ps= token.t_sval;
|
||||||
|
register len;
|
||||||
|
|
||||||
|
Tlen+= len= (*ps++ & 0377);
|
||||||
|
while (--len>=0)
|
||||||
|
table_add(&apt, (long) *ps++);
|
||||||
|
}
|
||||||
|
]*
|
||||||
|
{ apt= &pt;
|
||||||
|
table_add(&apt, (long) Tlen);
|
||||||
|
*e=new_table(E_BTAB, pt);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
item(register struct expr **e;)
|
||||||
|
{ struct expr *e1;
|
||||||
|
register struct symbol *var;
|
||||||
|
struct par_list *pars=nil;
|
||||||
|
register line, oind;
|
||||||
|
int byte, err=0, subs_call=0;
|
||||||
|
struct expr_list *elp=nil, **aelp= &elp;
|
||||||
|
}:
|
||||||
|
IDENTIFIER { line=yylineno;
|
||||||
|
oind=ind;
|
||||||
|
var=searchall(token.t_sval);
|
||||||
|
|
||||||
|
if (var_constant(var))
|
||||||
|
*e=copy_const(var->info.const);
|
||||||
|
else {
|
||||||
|
if (var_proc(var))
|
||||||
|
pars=var->info.proc.pars;
|
||||||
|
*e=new_var(var);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[ %while (line==yylineno || tabulated(oind, ind))
|
||||||
|
[ subscript(&byte, &e1)
|
||||||
|
{ *e=new_node('[', *e, e1, byte); }
|
||||||
|
| '(' { if (!var_declared(var)) {
|
||||||
|
var->type=T_PROC|T_USED|T_NOTDECL;
|
||||||
|
var->info.proc.pars=nil;
|
||||||
|
err=1;
|
||||||
|
}
|
||||||
|
if (!var_proc(var)) {
|
||||||
|
report("%s is not a named process",
|
||||||
|
var->name);
|
||||||
|
err=1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expression(&e1)
|
||||||
|
{ check_param(&pars, e1, &err);
|
||||||
|
expr_list_add(&aelp, e1);
|
||||||
|
}
|
||||||
|
[ ',' expression(&e1)
|
||||||
|
{ check_param(&pars, e1, &err);
|
||||||
|
expr_list_add(&aelp, e1);
|
||||||
|
}
|
||||||
|
]*
|
||||||
|
{
|
||||||
|
if (pars!=nil)
|
||||||
|
report("too few actual parameters");
|
||||||
|
}
|
||||||
|
')'
|
||||||
|
{ *e=new_call(*e, elp); }
|
||||||
|
]
|
||||||
|
{ subs_call=1; }
|
||||||
|
]?
|
||||||
|
{ if (!subs_call && var_proc(var)) {
|
||||||
|
if (pars!=nil)
|
||||||
|
report("no actual parameters");
|
||||||
|
*e=new_call(*e, nil);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
| vector_constant(e)
|
||||||
|
[ subscript(&byte, &e1)
|
||||||
|
{ *e=new_node('[', *e, e1, byte); }
|
||||||
|
]?
|
||||||
|
;
|
||||||
|
|
||||||
|
statement(register struct expr **e;)
|
||||||
|
{ struct expr *e1;
|
||||||
|
struct expr_list *elp=nil, **aelp= &elp;
|
||||||
|
register out;
|
||||||
|
}:
|
||||||
|
item(e)
|
||||||
|
[ AS expression(&e1)
|
||||||
|
{ *e=new_node(AS, *e, e1); }
|
||||||
|
| [
|
||||||
|
'?' { out=0; }
|
||||||
|
| '!' { out=1; }
|
||||||
|
]
|
||||||
|
io_arg(&e1)
|
||||||
|
{ if (e1!=nil) check_io(out, e1);
|
||||||
|
expr_list_add(&aelp, e1);
|
||||||
|
}
|
||||||
|
[ %while (1) ';' io_arg(&e1)
|
||||||
|
{ if (e1!=nil) check_io(out, e1);
|
||||||
|
expr_list_add(&aelp, e1);
|
||||||
|
}
|
||||||
|
]*
|
||||||
|
{ *e=new_io(out, *e, elp); }
|
||||||
|
]?
|
||||||
|
;
|
||||||
|
|
||||||
|
io_arg(struct expr **e; ) :
|
||||||
|
expression(e)
|
||||||
|
| ANY { *e=nil; }
|
||||||
|
;
|
||||||
|
|
||||||
|
table(register struct expr **e;)
|
||||||
|
{ struct table *pt=nil, **apt= &pt;
|
||||||
|
struct expr *e1;
|
||||||
|
register type;
|
||||||
|
}:
|
||||||
|
TABLE '[' { type=E_TABLE; }
|
||||||
|
[ BYTE { type=E_BTAB; }
|
||||||
|
]?
|
||||||
|
expression(&e1) { if (!constant(e1))
|
||||||
|
nonconst("table element");
|
||||||
|
else
|
||||||
|
table_add(&apt, e1->u.const);
|
||||||
|
destroy(e1);
|
||||||
|
}
|
||||||
|
[ ',' expression(&e1)
|
||||||
|
{ if (!constant(e1))
|
||||||
|
nonconst("table element");
|
||||||
|
else
|
||||||
|
table_add(&apt, e1->u.const);
|
||||||
|
destroy(e1);
|
||||||
|
}
|
||||||
|
]*
|
||||||
|
{ *e=new_table(type, pt); }
|
||||||
|
']'
|
||||||
|
;
|
||||||
|
|
||||||
|
arithmetic_op: '+' | '-' | '*' | '/' | BS
|
||||||
|
;
|
||||||
|
|
||||||
|
comparison_op: '<' | '>' | LE | GE | NE | '=' | AFTER
|
||||||
|
;
|
||||||
|
|
||||||
|
logical_op: BA | BO | BX
|
||||||
|
;
|
||||||
|
|
||||||
|
boolean_op: AND | OR
|
||||||
|
;
|
||||||
|
|
||||||
|
shift_op: LS | RS
|
||||||
|
;
|
||||||
|
|
||||||
|
monadic_op(register *op;):
|
||||||
|
'-' { *op='~'; }
|
||||||
|
| NOT { *op=NOT; }
|
||||||
|
;
|
||||||
|
|
||||||
|
operator: arithmetic_op | comparison_op | logical_op | boolean_op | shift_op
|
||||||
|
;
|
||||||
|
|
||||||
|
element(register struct expr **e;) :
|
||||||
|
%default NUMBER { *e=new_const(token.t_lval); }
|
||||||
|
| statement(e)
|
||||||
|
| TRUE { *e=new_const(-1L); }
|
||||||
|
| FALSE { *e=new_const(0L); }
|
||||||
|
| NOW { *e=new_now(); }
|
||||||
|
| CHAR_CONST { *e=new_const(token.t_lval); }
|
||||||
|
| '(' expression(e) ')' { if (valueless(*e))
|
||||||
|
warning("primitive should not be parenthesized");
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
expression(register struct expr **e;)
|
||||||
|
{ int op=0;
|
||||||
|
struct expr *e1;
|
||||||
|
}:
|
||||||
|
element(e)
|
||||||
|
[ %while (1) { if (op!=0) check_assoc(op, LLsymb);
|
||||||
|
op=LLsymb;
|
||||||
|
}
|
||||||
|
operator element(&e1)
|
||||||
|
{ *e=new_node(op, *e, e1); }
|
||||||
|
]*
|
||||||
|
| monadic_op(&op) element(&e1)
|
||||||
|
{ *e=new_node(op, e1, nil); }
|
||||||
|
;
|
||||||
|
|
||||||
|
val_expr(register struct expr **e;) :
|
||||||
|
expression(e) { used(*e); }
|
||||||
|
;
|
||||||
|
|
||||||
|
%lexical scanner;
|
||||||
|
{
|
||||||
|
int err=0;
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
main(argc, argv) register argc; register char **argv;
|
||||||
|
{
|
||||||
|
wz= (argc>1 && strcmp(argv[1], "4")==0) ? 4 : 2;
|
||||||
|
pz= (argc>2 && strcmp(argv[2], "4")==0) ? 4 : wz;
|
||||||
|
|
||||||
|
leader();
|
||||||
|
occam();
|
||||||
|
trailer();
|
||||||
|
|
||||||
|
exit(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
LLmessage(tk) register tk;
|
||||||
|
{
|
||||||
|
static errors=0;
|
||||||
|
|
||||||
|
if (tk>0) {
|
||||||
|
repeat_token(LLsymb);
|
||||||
|
warning("syntax error: %s expected (inserted)", tokenname(tk, 1));
|
||||||
|
} else
|
||||||
|
if (tk==0)
|
||||||
|
warning("syntax error: bad token %s (deleted)", tokenname(LLsymb, 0));
|
||||||
|
else { /* tk<0 */
|
||||||
|
fprintf(stderr, "Compiler stack overflow. Compiler ends.");
|
||||||
|
err=1; trailer(); exit(1);
|
||||||
|
}
|
||||||
|
if (++errors==MAXERRORS) {
|
||||||
|
fprintf(stderr, "Too many insert/delete errors. Compiler ends.\n");
|
||||||
|
err=1; trailer(); exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nonconst(siz) char *siz;
|
||||||
|
{
|
||||||
|
report("%s should be a constant", siz);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nonpositive(siz) char *siz;
|
||||||
|
{
|
||||||
|
report("%s must be positive", siz);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rep_cleanup(e1, e2) struct expr *e1, *e2;
|
||||||
|
{
|
||||||
|
destroy(e1);
|
||||||
|
destroy(e2);
|
||||||
|
sym_up();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void check_assoc(prev_op, op) register prev_op, op;
|
||||||
|
{
|
||||||
|
switch (op) {
|
||||||
|
char prev[5];
|
||||||
|
case '+': case '*':
|
||||||
|
case AND: case OR:
|
||||||
|
case BA: case BO: case BX:
|
||||||
|
if (prev_op==op) break;
|
||||||
|
default:
|
||||||
|
strcpy(prev, tokenname(prev_op, 0));
|
||||||
|
|
||||||
|
warning("Operators %s and %s don't associate",
|
||||||
|
prev, tokenname(op, 0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
lang/occam/comp/report.c
Normal file
19
lang/occam/comp/report.c
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
extern int err, yylineno;
|
||||||
|
extern char *curr_file;
|
||||||
|
|
||||||
|
report(fmt, arg1, arg2, arg3) char *fmt;
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s (%d) F: ", curr_file, yylineno);
|
||||||
|
fprintf(stderr, fmt, arg1, arg2, arg3);
|
||||||
|
putc('\n', stderr);
|
||||||
|
err=1;
|
||||||
|
}
|
||||||
|
|
||||||
|
warning(fmt, arg1, arg2, arg3) char *fmt, *arg1;
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s (%d) E: ", curr_file, yylineno);
|
||||||
|
fprintf(stderr, fmt, arg1, arg2, arg3);
|
||||||
|
putc('\n', stderr);
|
||||||
|
}
|
5
lang/occam/comp/sizes.h
Normal file
5
lang/occam/comp/sizes.h
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
/* Variable size, wordsize, pointer size. Offsets for local variables. */
|
||||||
|
|
||||||
|
#define vz 4
|
||||||
|
extern int wz, pz;
|
||||||
|
extern int curr_level, curr_offset, min_offset;
|
202
lang/occam/comp/symtab.c
Normal file
202
lang/occam/comp/symtab.c
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
#include "symtab.h"
|
||||||
|
#include "expr.h"
|
||||||
|
#include "sizes.h"
|
||||||
|
|
||||||
|
int curr_level=0; /* Current local level */
|
||||||
|
int curr_offset=0; /* Current offset within this level */
|
||||||
|
int min_offset=0; /* Minimum of all offsets within current level */
|
||||||
|
|
||||||
|
static struct symtab *sym_table=nil;
|
||||||
|
|
||||||
|
char *malloc();
|
||||||
|
|
||||||
|
static struct symbol **search_sym(tree, name)
|
||||||
|
struct symbol **tree;
|
||||||
|
char *name;
|
||||||
|
/* Returns a hook in the tree to the where the given name is or should be. */
|
||||||
|
{
|
||||||
|
register struct symbol **aps=tree, *ps;
|
||||||
|
register cmp;
|
||||||
|
|
||||||
|
while ((ps= *aps)!=nil && (cmp=strcmp(name, ps->name))!=0)
|
||||||
|
aps= cmp<0 ? &ps->left : &ps->right;
|
||||||
|
|
||||||
|
return aps;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct symbol *insert(name, type, arr_siz, info)
|
||||||
|
char *name;
|
||||||
|
int type, arr_siz;
|
||||||
|
union type_info info;
|
||||||
|
/* Inserts an object with given name and other info into the current symbol
|
||||||
|
* tree. A pointer is returned to the inserted symbol so that more info may
|
||||||
|
* or changed. Nil is returned on redeclaration.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
register struct symbol **aps, *ps;
|
||||||
|
extern included;
|
||||||
|
|
||||||
|
if (*(aps=search_sym(&sym_table->local, name))!=nil) {
|
||||||
|
report("%s redeclared", name);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
ps= (struct symbol *) malloc(sizeof *ps);
|
||||||
|
|
||||||
|
ps->name=name;
|
||||||
|
|
||||||
|
if (included && curr_level==0) /* Top_level symbol in include file */
|
||||||
|
type|=T_USED; /* are always used */
|
||||||
|
ps->type=type;
|
||||||
|
ps->arr_siz=arr_siz;
|
||||||
|
ps->info=info;
|
||||||
|
ps->left=ps->right=nil;
|
||||||
|
*aps=ps;
|
||||||
|
|
||||||
|
return ps;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct symbol *searchall(name) char *name;
|
||||||
|
/* Searches for name in all symbol trees from the inner to the outermost.
|
||||||
|
* If it can't be found then it is inserted as undefined.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
register struct symtab *tab=sym_table;
|
||||||
|
register struct symbol *ps;
|
||||||
|
|
||||||
|
while (tab!=nil) {
|
||||||
|
if ((ps= *search_sym(&tab->local, name))!=nil) return ps;
|
||||||
|
|
||||||
|
tab=tab->global;
|
||||||
|
}
|
||||||
|
report("%s not declared", name);
|
||||||
|
return insert(name, T_NOTDECL, 0, none);
|
||||||
|
}
|
||||||
|
|
||||||
|
void check_recursion(proc)
|
||||||
|
register struct expr *proc;
|
||||||
|
{
|
||||||
|
if (proc->kind==E_VAR && proc->u.var->type&T_RECURS)
|
||||||
|
warning("recursion not allowed");
|
||||||
|
}
|
||||||
|
|
||||||
|
void sym_down()
|
||||||
|
{
|
||||||
|
register struct symtab *ps;
|
||||||
|
|
||||||
|
ps= (struct symtab *) malloc(sizeof *ps);
|
||||||
|
|
||||||
|
ps->local=nil;
|
||||||
|
ps->global=sym_table;
|
||||||
|
ps->old_offset=curr_offset;
|
||||||
|
|
||||||
|
sym_table=ps;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sym_destroy(ps) register struct symbol *ps;
|
||||||
|
{
|
||||||
|
if (ps!=nil) {
|
||||||
|
sym_destroy(ps->left);
|
||||||
|
sym_destroy(ps->right);
|
||||||
|
if ( !(ps->type&T_NOTDECL) ) {
|
||||||
|
if ( !(ps->type&T_USED) )
|
||||||
|
warning("%s: never used", ps->name);
|
||||||
|
else
|
||||||
|
if ( !(ps->type&T_ASSIGNED) && (ps->type&T_TYPE)==T_VAR)
|
||||||
|
warning("%s: never assigned", ps->name);
|
||||||
|
}
|
||||||
|
if ((ps->type&T_TYPE)==T_PROC) {
|
||||||
|
register struct par_list *par, *junk;
|
||||||
|
|
||||||
|
par=ps->info.proc.pars;
|
||||||
|
while (par!=nil) {
|
||||||
|
junk=par;
|
||||||
|
par=par->next;
|
||||||
|
free(junk);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
if ((ps->type&T_TYPE)==T_CONST)
|
||||||
|
destroy(ps->info.const);
|
||||||
|
free(ps->name);
|
||||||
|
free(ps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sym_up()
|
||||||
|
{
|
||||||
|
register struct symtab *ps;
|
||||||
|
|
||||||
|
ps=sym_table->global;
|
||||||
|
curr_offset=sym_table->old_offset;
|
||||||
|
|
||||||
|
sym_destroy(sym_table->local);
|
||||||
|
free(sym_table);
|
||||||
|
|
||||||
|
sym_table=ps;
|
||||||
|
}
|
||||||
|
|
||||||
|
void var_memory(info, type, n) register union type_info *info; int type, n;
|
||||||
|
/* Reserves local memory for an object, and stores it in its info field. */
|
||||||
|
{
|
||||||
|
info->vc.st.level=curr_level;
|
||||||
|
curr_offset-= (type&T_BYTE) ? (n+wz-1) & (~(wz-1)) : n*vz;
|
||||||
|
info->vc.offset=curr_offset;
|
||||||
|
if (curr_offset<min_offset) min_offset=curr_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
void chan_memory(info, n) register union type_info *info; int n;
|
||||||
|
{
|
||||||
|
info->vc.st.level=curr_level;
|
||||||
|
info->vc.offset= curr_offset-=n*(vz+wz);
|
||||||
|
if (curr_offset<min_offset) min_offset=curr_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
int memory(z) int z;
|
||||||
|
/* Reserves z memory bytes */
|
||||||
|
{
|
||||||
|
curr_offset-=z;
|
||||||
|
if (curr_offset<min_offset) min_offset=curr_offset;
|
||||||
|
return curr_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pars_add(aapars, type, var)
|
||||||
|
register struct par_list ***aapars;
|
||||||
|
int type;
|
||||||
|
struct symbol *var;
|
||||||
|
/* Add a formal variable to a parameter list using a hook to a hook. */
|
||||||
|
{
|
||||||
|
register struct par_list *pl;
|
||||||
|
|
||||||
|
pl= (struct par_list *) malloc(sizeof *pl);
|
||||||
|
|
||||||
|
pl->type=type;
|
||||||
|
pl->var=var;
|
||||||
|
pl->next= **aapars;
|
||||||
|
|
||||||
|
**aapars=pl;
|
||||||
|
*aapars= &pl->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
int form_offsets(pars) register struct par_list *pars;
|
||||||
|
/* Recursively assign offsets to formal variables. */
|
||||||
|
{
|
||||||
|
register struct symbol *var;
|
||||||
|
|
||||||
|
if (pars==nil) return pz;
|
||||||
|
|
||||||
|
if ((var=pars->var)!=nil) {
|
||||||
|
register offset=form_offsets(pars->next);
|
||||||
|
|
||||||
|
switch (var->type&T_TYPE) {
|
||||||
|
case T_VAR:
|
||||||
|
case T_CHAN:
|
||||||
|
var->info.vc.st.level=curr_level;
|
||||||
|
var->info.vc.offset=offset;
|
||||||
|
return offset+pz;
|
||||||
|
case T_VALUE:
|
||||||
|
var->info.vc.st.level=curr_level;
|
||||||
|
var->info.vc.offset=offset;
|
||||||
|
return offset+ ((var->type&T_ARR) ? pz : vz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
91
lang/occam/comp/symtab.h
Normal file
91
lang/occam/comp/symtab.h
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
#ifndef nil
|
||||||
|
#define nil 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Symbol/Expression type: */
|
||||||
|
#define T_VAR 0x0000
|
||||||
|
#define T_CHAN 0x0001
|
||||||
|
#define T_CONST 0x0002
|
||||||
|
#define T_VALUE 0x0003
|
||||||
|
#define T_PROC 0x0004
|
||||||
|
#define T_NOW 0x0005
|
||||||
|
#define T_VOID 0x0006
|
||||||
|
|
||||||
|
#define T_TYPE 0x0007 /* Mask for type bits */
|
||||||
|
|
||||||
|
/* Flags: */
|
||||||
|
#define T_ARR 0x0008 /* Object is an array */
|
||||||
|
#define T_BYTE 0x0010 /* Object is a byte array if T_ARR */
|
||||||
|
#define T_PARAM 0x0020 /* Formal parameter */
|
||||||
|
#define T_LVALUE 0x0040 /* This object may be assigned */
|
||||||
|
#define T_NOTDECL 0x0080 /* If you didn't declare it */
|
||||||
|
#define T_USED 0x0100 /* If you've used it */
|
||||||
|
#define T_ASSIGNED 0x0200 /* Or assigned it */
|
||||||
|
#define T_REP 0x0400 /* Replicator index */
|
||||||
|
#define T_BUILTIN 0x0800 /* Builtin name */
|
||||||
|
#define T_RECURS 0x1000 /* This proc is now compiled */
|
||||||
|
/* Note that some types and flags are only used for symbols, and others only
|
||||||
|
* for expressions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct symbol;
|
||||||
|
|
||||||
|
struct par_list { /* List of parameter types for a proc object */
|
||||||
|
struct par_list *next;
|
||||||
|
struct symbol *var; /* The formal parameter while visible */
|
||||||
|
int type; /* Its type */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct expr;
|
||||||
|
|
||||||
|
union storage { /* An object is found */
|
||||||
|
int level; /* either at a certain local level */
|
||||||
|
char *builtin; /* or using a global builtin name */
|
||||||
|
};
|
||||||
|
|
||||||
|
union type_info {
|
||||||
|
struct {
|
||||||
|
union storage st;
|
||||||
|
int offset; /* from its local level or builtin name */
|
||||||
|
} vc; /* Variable or channel */
|
||||||
|
|
||||||
|
struct expr *const;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
union storage st;
|
||||||
|
char *file; /* file it is in */
|
||||||
|
int label; /* A unique id*/
|
||||||
|
struct par_list *pars;
|
||||||
|
} proc;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct symbol {
|
||||||
|
char *name;
|
||||||
|
short type;
|
||||||
|
int arr_siz;
|
||||||
|
union type_info info;
|
||||||
|
struct symbol *left, *right;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct symtab {
|
||||||
|
struct symbol *local;
|
||||||
|
struct symtab *global;
|
||||||
|
int old_offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct symbol *insert();
|
||||||
|
struct symbol *searchall();
|
||||||
|
|
||||||
|
void sym_down();
|
||||||
|
void sym_up();
|
||||||
|
void var_memory(), chan_memory();
|
||||||
|
|
||||||
|
void pars_add();
|
||||||
|
int form_offsets();
|
||||||
|
void check_recursion();
|
||||||
|
|
||||||
|
#define var_constant(v) (((v)->type&T_TYPE)==T_CONST)
|
||||||
|
#define var_proc(v) (((v)->type&T_TYPE)==T_PROC)
|
||||||
|
#define var_declared(v) (! ((v)->type&T_NOTDECL))
|
||||||
|
|
||||||
|
extern union type_info none;
|
11
lang/occam/comp/token.h
Normal file
11
lang/occam/comp/token.h
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
/* token.h */
|
||||||
|
|
||||||
|
extern struct token {
|
||||||
|
long t_lval;
|
||||||
|
char *t_sval;
|
||||||
|
} token;
|
||||||
|
|
||||||
|
extern ind;
|
||||||
|
void repeat_token();
|
||||||
|
char *tokenname();
|
||||||
|
int tabulated();
|
Loading…
Reference in a new issue