Initial revision

This commit is contained in:
ceriel 1987-02-24 17:05:53 +00:00
parent a731f979b0
commit bc94559e4d
16 changed files with 3123 additions and 0 deletions

27
lang/occam/comp/Makefile Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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();