[comp.sys.transputer] Unix Occam Compiler

ttork@ewu.UUCP (Terry Torkelson) (11/15/90)

Just received this from Mr Shapira:

>Hello,
>	This is the first shar file out of four. Each file creates a directory
>	named like it (e.g. this file, comp, will create a directory ./comp),
>	so be carefull to give it another name (e.g. comp.shar).
>	Also note that I have put a dash-line at the end of the file. So you
>	can see if you recieved it all.
>
>Have fun,
>--Amos Shapira
>amoss@batata.huji.ac.il

----------comp.shar----------
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	comp
# This archive created: Thu Apr 19 16:54:01 1990
export PATH; PATH=/bin:$PATH
if test ! -d 'comp'
then
	mkdir 'comp'
fi
cd 'comp'
if test ! -d 'h'
then
	mkdir 'h'
fi
cd 'h'
if test -f 'conf.h'
then
	echo shar: will not over-write existing file "'conf.h'"
else
cat << \SHAR_EOF > 'conf.h'
/* $Header: conf.h,v 1.1 86/11/04 10:06:14 gil Exp $ */

/*
 * This is the configuration file for the OCCAM compiler.
 * It contains a few parameters that determine the support of
 * non-standard options.
 * See the user manual for detailed description of these options.
 * When noted, the runtime library should be configured to support
 * the option.
 * This is done by setting the options in the library's
 * configuration file, ../inter/conf.h
 *
 * The options are:
 */

/* S_VMS: support for special system VMS-compatible channels syntax
 * (mainly the 'AT' declaration).
 * NOTE: Should be set in the runtime library as well.
 */
/* #define	S_VMS */


/* BUFF_CHANS: support for decalration of buffered channels -
 *	que chname(size):
 * NOTE: Should be set in the runtime library as well.
 */
#define	BUFF_CHANS
SHAR_EOF
fi # end of overwriting check
if test -f 'error.h'
then
	echo shar: will not over-write existing file "'error.h'"
else
cat << \SHAR_EOF > 'error.h'
#ifndef ERR_LIST
#include "errors.h"
#endif
#ifndef EXT
#define EXT extern
#endif
EXT	ErrChar;
#define ErrRet() if(InError) return

enum err_type { WARNING, ERROR, COMPILER_ERROR, RECOVER };

struct error_list {
	enum err_type	type;
	char		*str;
};

extern struct error_list Err_list[];
SHAR_EOF
fi # end of overwriting check
if test -f 'hash.h'
then
	echo shar: will not over-write existing file "'hash.h'"
else
cat << \SHAR_EOF > 'hash.h'
#define NULL 0
struct hashent {
	char		*h_name;
	struct	decl	*h_decl;
	int		h_count;	/* number of times this name is
					 * declared global */
};
#define insert(where, what) {	Hash[where].h_name = strsave(what);\
				Hash[where].h_decl = NULL;\
			}
#define HASHSZ 1033
struct hashent Hash[HASHSZ];	/* note: HASHSZ SHOULD BE PRIME !!*/

SHAR_EOF
fi # end of overwriting check
if test -f 'lex.h'
then
	echo shar: will not over-write existing file "'lex.h'"
else
cat << \SHAR_EOF > 'lex.h'
/* $Header: lex.h,v 1.2 85/02/12 15:46:34 gil Exp $ */
/* trick: define EXT where the actual allocation is to be performed. */
#ifndef EXT
#define	EXT	extern
#endif

EXT int 	PrevIndent,
		CurIndent;	/* save previous indent level, with
				 : comparison to current indent level.
				 */
EXT int		lines;		/* lines counter */

char	*strsave();
#define TABSZ 8
extern char yytext[];
extern yyleng;
extern FILE *yyin;
typedef union lval {
	int	lv_intval;
	char	lv_charval;
	int	lv_hashval;
	char	*lv_strval;
} Lval;
#define	v_intval	Lval.lv_intval
#define v_charval	Lval.lv_charval
#define v_hashval	Lval.lv_hashval
#define v_strval	Lval.lv_strval

#define noval		0
#define INT		1
#define STR		2
#define HASH		3
#define CHAR		4
#define	operator	5
#define	reserved	6
SHAR_EOF
fi # end of overwriting check
if test -f 'machine.h'
then
	echo shar: will not over-write existing file "'machine.h'"
else
cat << \SHAR_EOF > 'machine.h'
#define NBBY 8
#define NBPL 4
#define N_OPER 4
#define MAXINT 2147483647
#define STARTCODE 0

#define BYTE_SIZE	1
#define INT_SIZE	4
#define ARG_SIZE	4

#define ARG_START	4
#ifdef vax
#define SP_START	8
#else
#ifdef tahoe
#define	SP_START	56
#endif tahoe
#endif not vax
#ifdef vax
#define NREG	10			/* registers 0-10 can allocated as
					 : temporaries */
#else tahoe
#define	NREG	11
#endif
#define	reg(i)	(1<<(i))		/* bit mask for register i */
#define OtherRegs	(0)		/* mask for registers which should
					 : not be used	*/
#define	DontUse		(0)		/*   " "	*/
#define	ShouldBeMasked(i)	(i > 5)	/* register 0-5 should not be in
					 : 'calls' mask */

#define	ADDRMASK	(reg(0):reg(1):reg(2):reg(3):reg(4):reg(5))
#define	TEMPMASK	(reg(0):reg(1))
#define	CODEMASK	(0)
/* The following instructions numbers should not conflict with the numbers
 : generated by yacc in y.tab.h */
#define MOVREF	1		/* movl */
#define MOVL	2		/*  ""  */
#define CMP	3		/* cmpl */
#define JMP	4		/* jbr	*/
#define	TST	5		/* tstl */
#define JUMP	6		/* jmp	*/

#define roundup(n)	(((n) + (INT_SIZE - 1)) & ~(INT_SIZE - 1))

#define SP	14		/* register no. of the stack-pointer */
#ifdef vax
#define	DP	11		/* display pointer is r11 */
#else tahoe
#define	DP	12		/* r12 on tahoe */
#endif

#define	TIME_COUNTER	0	/* Time counter for each process is at top of
				 : display */

SHAR_EOF
fi # end of overwriting check
if test -f 'parse.h'
then
	echo shar: will not over-write existing file "'parse.h'"
else
cat << \SHAR_EOF > 'parse.h'
#ifndef EXT
#define EXT extern
#endif

EXT prnt;
EXT int balagan, declaration;
#define MAXPARLEVEL	128
#define MAXINDENTLEVEL	128
#define MAX_STACK	128

typedef	struct expr {
	int	e_flags;
	addr	e_slen;			/* slice length */
	Quadl	e_false;
	addr	e_place;
} Expr;
/* Some macros to make life easier... */
#define e_cval		e_place.d_offset
#define E_TYPE	0xff
#define		ET_INT		0x1
#define		ET_CHAR		0x1
#define		ET_BOOL		0x1
#define		ET_CHAN		0x2	/* channel - used only for parameter
					 : passing */
#define		ET_SLICE	0x3
#define		ET_CHANTAB	0x4
#define		ET_INTTAB	0x8
#define	ET_TABMASK	0xc
#define	E_KIND	0xff00
#define		EK_VAR		0x100
#define		EK_CONST	0x200
#define		EK_EXP		0x400
#define E_OTHER	0xff0000
#define		EBYTE_SUBSCRIPT	0x10000

#define	IsConst(e)	((e.e_flags&E_KIND) == EK_CONST)
#define	IsEtab(e)	(e.e_flags&ET_TABMASK)
#define IsVar(e)	((e.e_flags&E_KIND) == EK_VAR)
#define	IsSlice(e)	((e.e_flags&E_TYPE) == ET_SLICE)
/* Using temporary storage */
#define IsTemp(e)	((e.e_flags&E_KIND) == EK_EXP)
#define IsReadOnly(e)	(e.e_place.d_flags&AF_RO)

#define	Addr(e)		(e).e_place

typedef struct	cond_list {
	Label	c_out;
	Quadl	c_next;
} Cond;


typedef struct	guard {
	Expr	gu_chan;
	Quadl	gu_next;
} Guard;

typedef struct	replicator {
	Label	r_loop;
	Label	r_out;
	addr	r_var;
	addr	r_to;
} Repl;

typedef	int	Buffer;

#define	NALT	8	/* number of nested alts (ALT ALT) */
typedef struct alt {
	addr	a_argcnt,	/* Number of alt requests */
		a_pushcnt;	/* Actual number of parameters pushed */
	int	a_nsave;	/* Number of saved replicated alt counters */
	addr	a_save[NALT];	/* Saved data */
	Label	a_out;
	Buffer	a_flowbuf,	/* buffer for alt's flow code (pushes+call) */
		a_textbuf;	/* buffer for the alt processes parsed
				 : meanwhile */
} Alt;

extern	Expr		Bool(), CharVal(), IntVal(), IndexedVar(),
			ByteIndexedVar(), Identifier(), ArithOp(), Rand(),
			Ror(), EvalBool(), CmpOp(), MonOp(), StrVal(),
			CondExpr(), ByteSlice(), IntSlice(), StrToSlice(),
			LocalClock(), TimeChan(), Zero();
extern	addr		NewCounter();
extern	Repl		Loop(), NewRepl();
extern	DType		DeclParam(), DeclParamTab();
extern	Buffer		CurBuf, NewBuf(), ToBuf(), Sbuf();

extern Buffer	MainText;
extern int	NoMain;

#define C_TRUE 0xffffffff
#define C_FALSE 0

#define CVAL(v)	(v)
#define TRUE_VAL(tv)	((tv) ? C_TRUE : C_FALSE)

#define MON(op) (op : 0x8000)

SHAR_EOF
fi # end of overwriting check
if test -f 'reserved.h'
then
	echo shar: will not over-write existing file "'reserved.h'"
else
cat << \SHAR_EOF > 'reserved.h'
struct reswords	{
	char	*rs_word;
	int	rs_token;
	int	rs_type;
};

extern struct reswords	ReservedWords[];
extern int		nreserved;
SHAR_EOF
fi # end of overwriting check
if test -f 'y.tab.h'
then
	echo shar: will not over-write existing file "'y.tab.h'"
else
cat << \SHAR_EOF > 'y.tab.h'
# define AFTER 257
# define FALSE 258
# define LT_TOK 259
# define RIGHT_TOK 260
# define ALT 261
# define FCHAN_TOK 262
# define MINUS_TOK 263
# define RP_TOK 264
# define AND 265
# define FOR 266
# define MOD_TOK 267
# define RSHIFT_TOK 268
# define AND_TOK 269
# define GE_TOK 270
# define MULT_TOK 271
# define SEMICOLON_TOK 272
# define ASSIGN_TOK 273
# define GT_TOK 274
# define NEQ_TOK 275
# define SEQ 276
# define BYTE 277
# define ID_TOK 278
# define NEWLINE 279
# define SKIP 280
# define CHAN 281
# define IF 282
# define NOT 283
# define STRING 284
# define CHARACTER 285
# define INP_TOK 286
# define NOW 287
# define TABLE 288
# define COMA_TOK 289
# define INTEGER 290
# define OR 291
# define TRUE 292
# define COND_TOK 293
# define LBR_TOK 294
# define OR_TOK 295
# define VALUE 296
# define DEF 297
# define LEFT_TOK 298
# define PAR 299
# define VAR 300
# define DIV_TOK 301
# define LE_TOK 302
# define PLUS_TOK 303
# define WAIT 304
# define EQ_TOK 305
# define LP_TOK 306
# define PROC 307
# define WHILE 308
# define EXTERN 309
# define LSHIFT_TOK 310
# define RBR_TOK 311
# define XOR_TOK 312
# define AT 313
# define QUE 314

typedef union  {
	Expr	Expr;
	Decl	Decl;
	int	Hv;
	Op	Op;
	Lval	Lval;
	Args	Args;
	Quadl	Quadl;
	Label	Label;
	Cond	Cond;
	Guard	Guard;
	Repl	Repl;
	DType	DType;
} YYSTYPE;
extern YYSTYPE yylval;
SHAR_EOF
fi # end of overwriting check
if test -f 'addr.h'
then
	echo shar: will not over-write existing file "'addr.h'"
else
cat << \SHAR_EOF > 'addr.h'
typedef unsigned int	u_int;
typedef unsigned short	u_short;
typedef	int		addr_t;
typedef	int		Op;
/* An address is computed by DIS[d_disp]+d_offset
 : display starts at 1, d_disp = 0 means immediate mode */

typedef struct addr {			/* address format */
	char	d_flags;
	char	d_reg;
	short	d_disp;			/* entry # in display */
	addr_t	d_offset;		/* offset */
} addr;
/* Address types (special meanings place in the display) */
#define AD_REGISTER	(-1)
#define	AD_IMMED	0
#define AD_GLOBAL	1

#define AF_AP		0x1
#define AF_PTR		0x2
#define	AF_REG		0x4
#define AF_FP		0x8
#define	AF_SUB		0x10
#define	AF_RO		0x20
#define	AF_BYTE		0x40
#define	AF_LABEL	0x80

#define	IsReg(a)	((a).d_disp == AD_REGISTER)
#define	IsByte(a)	((a).d_flags & AF_BYTE)
#define SameAddr(a1, a2) ((a1).d_disp == (a2).d_disp && (a1).d_offset == (a2).d_
offset)
#define	NullA(a)	((a).d_disp == AD_REGISTER && (a).d_offset == -1)

/* The 8'th bit of a parameter type (in d.d_args) is set, if the parameter is
 : passed by reference */
#define TYPE_REF		(1<<8)
#define	TYPE_EXTRN		(1<<9)
#define EXT_BITS		(0xff00)
#define	ByRef(t)	(DType)((int)(t):TYPE_REF)
#define IsByRef(t)	((int)(t)&TYPE_REF)
#define	Extern(t)	(DType)((int)(t):TYPE_EXTRN)
#define	IsExtern(t)	((int)(t)&TYPE_EXTRN)
#define	Type(t)		(DType)((int)(t)&~EXT_BITS)
#define	IsTab(t)	(Type(t) == DINT_TAB :: Type(t) == DCHAN_TAB)

enum	type 	{ UNDEF, DPROC, DINT, DCHAN, DINT_TAB, DCHAN_TAB, TAB };
typedef enum type	DType;

struct	args	{			/* procedure argument list */
	int		a_nargs;
	DType	*a_argt;
};
typedef struct args Args;

struct proc_info {
	int	pi_masklabel;
	Args	pi_args;
};
typedef struct proc_info	Pinfo;

typedef struct decl {
	DType	d_type;
	int		d_flags;
#define DF_DEF		0x1
#define DF_REF		0x2
	int		d_level;
	addr		d_addr;	/* if d_disp == AD_GLOBAL then put in
				 : d_offset a pointer to the NAME of the
				 : variable */
	union	dinfo {
		int		di_nel;		/* no. of elements in array */
		Pinfo		di_proc;	/* proc info: arguments + mask
						 : labels. */
	}		d_info;
#define d_cval	(int)d_addr.d_offset
#define d_nel	d_info.di_nel
#define d_args	d_info.di_proc.pi_args
#define d_masklabel	d_info.di_proc.pi_masklabel
	struct	decl	*d_next;
	struct	hashent	*d_hnext;
} *Decl;
#define IsDef(dec)	((dec)->d_flags & DF_DEF)
#define IsRef(dec)	((dec)->d_flags & DF_REF)
#define IsProc(dec)	((dec)->d_type == DPROC)
#define	IsIdent(dec)	((dec)->d_type != DPROC && (dec)->d_type != UNDEF)

extern addr	NullAddr;
extern addr_t	Sp;
extern int 	DispLevel;	/* the display level (incremented for each
				 : proc xxx) */
extern int	ProcCount[];
/*
 : Process ounter.
 : We need this counter - extra to the display - because we don't need to
 : creat a new DISPLAY for each (non declared) process (it will never
 : be INVOKED from any other place in the program). however -  the local
 : variables have only the PROCESS a scope.
 */

extern	struct decl	*DeclExternProc(), *ForwardDeclProc(), *DeclDefTab();
extern	char		*GenDefLabel(), *GenLabelName();
extern	addr_t		AllocStack();
extern	addr		NewTemp(), GenSave(), makeaddr(), RegAddr(),
			GenIntSubscript(), GenByteSubscript(),
			Lvalue(), Addr(), DeclRepVar(),	GetAddr(),
			GenSliceAddr(),
			Register(), Immediate(), Eval();
extern	Args		MakeArg(), AddArg();
extern	DType	Etype();

extern	Args		NoArgs;
extern	char		*ProcName[];

#define  new(type)	(struct type *) calloc(1, sizeof(struct type))

SHAR_EOF
fi # end of overwriting check
if test -f 'all.h'
then
	echo shar: will not over-write existing file "'all.h'"
else
cat << \SHAR_EOF > 'all.h'
#include "conf.h"
#include "machine.h"
#include "addr.h"
#include "lex.h"
#include "hash.h"
#include "back.h"
#include "parse.h"
#include "error.h"
#include "reserved.h"
#ifndef DEF
#include "y.tab.h"
#endif
SHAR_EOF
fi # end of overwriting check
if test -f 'back.h'
then
	echo shar: will not over-write existing file "'back.h'"
else
cat << \SHAR_EOF > 'back.h'
typedef int Label;

typedef struct quad_list {
	int	q_nquads;
	Label	*q_quads;
} Quadl;

extern Quadl	MakeList(), Merge(), AddList();;
extern Quadl	NewProcess();
extern Label	ReplProc(), Land(), Lor();

extern Quadl NullQuadl;
#define	NullQ(ql)	((ql).q_nquads == 0)
SHAR_EOF
fi # end of overwriting check
if test -f 'errors.h'
then
	echo shar: will not over-write existing file "'errors.h'"
else
cat << \SHAR_EOF > 'errors.h'
#define	ERR_LIST
#define	INTEGER_OVERFLOW		1
#define	NEWLINE_IN_CHAR_CONST 		2
#define	CHAR_CONST_TOO_LONG 		3
#define	EMPTY_CHAR_CONST		4
#define	ESCAPE_CHAR			5
#define	NO_SPECIAL_MEANING		6
#define	UNFINISHED_STR			7
#define	HASH_FULL			8
#define	ODD_NO_OF_BLANKS		9
#define	ILLEGAL_CHAR			10
#define	LEX_INTERNAL_ERROR		11
#define	EXPECTED_EOF			12
#define	UNEXPECTED_EOF			13
#define	EXPECTED_CONST			14
#define	TYPE_MISMATCH			15
#define	DIV_BY_ZERO			16
#define	OP_MISMATCH			17
#define	UNDEF_VAR			18
#define	MULTIPLY_DECLARED_VAR		19
#define	LVAL_REQ			20
#define	CHANNEL_REQ			21
#define	PROC_REQUIRED			22
#define	UNDEF_PROC			23
#define	ILL_NUM_OF_ARGS		24
#define	EXTERN_EXISTS			25
#define	TABLE_REQUIRED			26
#define	VALUE_PARAM_ASSIGN		27
#define	SLICE_REQUIRED			28
#define	DIFF_SLICES			29
#define	TOO_MANY_ERRORS		30
#define	MISSING_PARAM_TYPE		31
#define	EXTRA_INDENT			32
#define	EXPECT_SHIFTED_PROC		33
#define	SYNT_ERR_NEAR			34
#define	EXTERN_NAME_OVERLOAD		35
#define	IDENT_REQUIRED			36
#define	VMS_UNSUPPORTED		37
SHAR_EOF
fi # end of overwriting check
cd ..
if test -f 'decl.c'
then
	echo shar: will not over-write existing file "'decl.c'"
else
cat << \SHAR_EOF > 'decl.c'
static char *rcsid = "$Header: decl.c,v 2.3 86/11/03 13:49:50 gil Exp $";

/*
 * $Log:	decl.c,v $
 * Revision 2.3  86/11/03  13:49:50  gil
 * support for VMS and special INPUT/OUTPUT channels are 'ifdef'ed.
 *
 * Revision 2.2  86/11/01  12:19:59  gil
 * added declaration of buffered channels (channels have buffer sizes now).
 *
 * Revision 2.1  86/10/30  16:05:59  gil
 * This version was submitted for the project. It is free of all major bugs.
 *
 */

#include <stdio.h>
#include "all.h"

extern CurBuf, RO_DataBuf;
extern	char	*calloc(), *malloc(), *sprintf();

int DispLevel = AD_GLOBAL;
addr_t Sp = SP_START;
DType ParamTypeConv();
char *ProcName[MAX_STACK];
int  ProcCount[MAX_STACK];
Args NoArgs = { 0, NULL };

DType	settabtype(), settype(), declparam();
char	*UniqueGName();

static struct hashent	*LastVar = NULL;
static addr_t		ArgAddr = ARG_START;
static int	fextern;	/* flag: external declaration */

char *
printnum(name, num)
	char *num;
{

	return(sprintf(malloc(strlen(name)+6), "%s%d", name, num));
}

Decl
Declare(hv) {

	Decl	d, nd;

	d = Hash[hv].h_decl;

	if (d != NULL && d->d_addr.d_disp == DispLevel &&
				d->d_level == ProcCount[DispLevel]) {
		Error(ERROR, MULTIPLY_DECLARED_VAR);
		return NULL;
	}
	Hash[hv].h_decl = nd = new(decl);
	nd->d_level = ProcCount[DispLevel];
	nd->d_addr = NullAddr;

	/* chain identifiers of current level (display) for easy freeing */
	nd->d_next = d;
	nd->d_hnext = LastVar;
	LastVar = &Hash[hv];
	
	return nd;
}

Decl
DeclChanOrVar(hv) {
	register Decl	nd;

	if ((nd = Declare(hv)) == NULL)
		return nd;
	nd->d_addr.d_disp = DispLevel;
	if (fextern)
		nd->d_addr.d_offset = (addr_t)UniqueGName(hv);
	else if (DispLevel == AD_GLOBAL) {
		nd->d_addr.d_offset = (addr_t)UniqueGName(hv);
		GenGlobal(nd, INT_SIZE);
	} else
		nd->d_addr.d_offset = AllocStack(INT_SIZE);
	return nd;
}

DeclVar(hv) {
	Decl	nd;

	nd = DeclChanOrVar(hv);
	if(nd != NULL)
		if (fextern)
			nd->d_type = Extern(DINT);
		else
			nd->d_type = DINT;
}

Decl
DeclTab(hv, e, esize)
	Expr	e;
{
	Decl	nd;

	if(!fextern && !IsConst(e)) {
		Error(ERROR, EXPECTED_CONST);
		return NULL;
	}
	if ((nd = Declare(hv)) == NULL)
		return NULL;
	nd->d_addr.d_disp = DispLevel;
	if (fextern)
		nd->d_addr.d_offset = (addr_t)UniqueGName(hv);
	else if (DispLevel == AD_GLOBAL) {
		nd->d_addr.d_offset = (addr_t)UniqueGName(hv);
		GenGlobal(nd, e.e_cval * esize);
	}
	else
		nd->d_addr.d_offset = AllocStack(roundup(e.e_cval * esize));

	nd->d_nel = e.e_cval;
	return nd;
}

DeclVarTab(hv, e)
	Expr	e;
{
	register Decl	nd;

	nd = DeclTab(hv, e, INT_SIZE);
	if(nd != NULL)
		if (fextern)
			nd->d_type = Extern(DINT_TAB);
		else
			nd->d_type = DINT_TAB;
}

DeclVarByteTab(hv, e)
	Expr	e;
{
	register Decl	nd;
	nd = DeclTab(hv, e, 1);
	if(nd != NULL)
		if (fextern)
			nd->d_type = Extern(DINT_TAB);
		else
			nd->d_type = DINT_TAB;
}

DeclChanTab(hv, e, bufsiz)
	Expr	e, bufsiz;
{
	register Decl	nd;

	if(!fextern && !IsConst(bufsiz)) {
		Error(ERROR, EXPECTED_CONST);
		return;
	}
	nd = DeclTab(hv, e, INT_SIZE);
	if(nd != NULL)
		if (fextern)
			nd->d_type = Extern(DCHAN_TAB);
		else {
			nd->d_type = DCHAN_TAB;
			AllocChanTable(nd, bufsiz.e_place);
		}
}


static int	byte_def_tab = 0;

SetByte() { byte_def_tab = 1; }
UnsetByte() { byte_def_tab = 0; }

Decl
DeclDefTab(hv)
{
	register Decl	nd;
	
	if ((nd = Declare(hv)) == NULL)
		return;

	nd->d_addr.d_disp = DispLevel;
	if (DispLevel == AD_GLOBAL) {
		nd->d_addr.d_offset = (addr_t)UniqueGName(hv);
		GenDef(nd->d_addr.d_offset);
	} else {
		nd->d_addr.d_offset = (addr_t)
					strsave(GenDefLabel(NewLabel()));
		nd->d_addr.d_flags := AF_LABEL;
	}

	nd->d_flags = DF_DEF;
	nd->d_type = DINT_TAB;

	return nd;
}

DeclDefEl(e)
	Expr	e;
{
	if (!IsConst(e)) {
		Error(ERROR, EXPECTED_CONST);
		return;
	}
	GenDefEl(e.e_cval, byte_def_tab);
}

DeclDefStr(hv, s)
	char	*s;
{
	Decl	nd;

	if ((nd = Declare(hv)) == NULL)
		return;

	nd->d_addr.d_disp = DispLevel;
	if (DispLevel == AD_GLOBAL) {
		nd->d_addr.d_offset = (addr_t)UniqueGName(hv);
		GenDef(nd->d_addr.d_offset);
	} else {
		nd->d_addr.d_offset = (addr_t)
					strsave(GenDefLabel(NewLabel()));
		nd->d_addr.d_flags := AF_LABEL;
	}
	GenDefStr(s);

	nd->d_flags = DF_DEF;
	nd->d_type = DINT_TAB;
}

DeclDef(hv, e)
	Expr e;
{

	register Decl	nd;

	if (!IsConst(e)) {
		Error(ERROR, EXPECTED_CONST);
		return;
	}	
	if ((nd = Declare(hv)) == NULL)
		return;
	nd->d_type = DINT;
	nd->d_flags = DF_DEF;
	nd->d_addr = e.e_place;
}

DeclChan(hv, bufsiz)
	Expr	bufsiz;
{

	register Decl	nd;

	if(!fextern && !IsConst(bufsiz)) {
		Error(ERROR, EXPECTED_CONST);
		return;
	}
	nd = DeclChanOrVar(hv);
	if(nd == NULL)
		return;
	if (fextern)
		nd->d_type = Extern(DCHAN);
	else {
		nd->d_type = DCHAN;
		AllocChan(nd->d_addr, bufsiz.e_place);
	}
}

DeclChanAt(hv, e)
	Expr	e;
{
#ifdef	S_VMS
	DeclChan(hv, Zero());
	if (!IsConst(e)) {
		Error(ERROR, EXPECTED_CONST);
		return;
	}	
	if (fextern)
		return;
	GenPush(0, e.e_place);
	GenPush(0, Hash[hv].h_decl->d_addr);
	GenFuncCall(Immediate(2), "chat", 1, NullAddr);
#else	S_VMS
	Error(ERROR, VMS_UNSUPPORTED);
#endif	S_VMS
}

DeclTimeChan(hv)
{
	DeclChan(hv, Zero());
	GenPush(0, Hash[hv].h_decl->d_addr);
	GenFuncCall(Immediate(1), "chtime", 1, NullAddr);
}

Repl
NewRepl(hv)
{
	Repl	r;

	Decl	d;

	ProcCount[DispLevel]++;	/* incremented for the time of replicator
				 : 'parameter' (loop variable) declaration.
				 */
	if((d = Declare(hv)) == NULL)
		return r;

	d->d_type = DINT;
	d->d_addr = GetAddr();
	d->d_addr.d_flags := AF_RO;
	ProcCount[DispLevel]--;	/* was incremented for the time of replicator
				 : 'parameter' declaration. */
	r.r_var = d->d_addr;
	r.r_loop = NewLabel();
	r.r_out = NewLabel();
	return r;

}

StartProc(hv) {

	PushBuf();
	GenProc(hv);
}

EndProc(hv) {

	GenEndProc(Hash[hv].h_decl->d_masklabel);
	Pop();
	PopBuf();
}

FreeProc(plevel) {
/* Free vars of process; in case of DECLARED proc it frees also the
 : proc's PARAMETERS.
 */
	FreeVars(plevel);
}

Decl
ForwardDeclProc(hv) {
/*
 : Declare the process without arguments (and possibly other specifications).
 : Do this BEFORE incrementing display level, and thus the process' scope
 : will include the former process (contrary to the new process' vars and
 : parameters.
 */

	register Decl	nd;

	if ((nd = Declare(hv)) == NULL)
		return;

	if (ProcCount[DispLevel] != 1)
		ProcName[DispLevel] = printnum(Hash[hv].h_name,
						ProcCount[DispLevel]);
	else
		ProcName[DispLevel] = Hash[hv].h_name;

	nd->d_addr.d_offset = (addr_t) ProcName[DispLevel];
	nd->d_addr.d_disp = DispLevel;
	/* The process' declaration needs to be freed one level AFTER its
	 : local vars (and parameters). Therefore - d_disp here is one LESS
	 : than the parameters (since 'DispLevel' is incremented only in
	 : 'StartProc').
	 */
	nd->d_type = DPROC;
	StartProc(hv);
	Push();
	ProcCount[DispLevel]++;	/* incremented for the time of parameters'
				 : declarations. */
	return nd;
}

DeclProc(d, args)
	Args args;
	Decl	d;
{

	ArgAddr = ARG_START;
	d->d_args = args;
	ProcCount[DispLevel]--;	/* was incremented for the time of
				 : parameters' declarations */
}

Decl
DeclExternProc(hv)
{
	register Decl	d, nd;

	d = Hash[hv].h_decl;
	while(d != NULL) {
		if (d->d_addr.d_disp == AD_GLOBAL) {
			Error(ERROR, EXTERN_EXISTS);
			return;
		}
		d = d->d_next;
	}
	if ((nd = Declare(hv)) == NULL)
		return;

	nd->d_type = Extern(DPROC);
	nd->d_addr.d_offset = (addr_t) Hash[hv].h_name;
	nd->d_addr.d_disp = DispLevel;
	Push();
	ProcCount[DispLevel]++;	/* incremented for the time of parameters'
				 : declarations. */
	return nd;
}


FreeVars(plevel) {

/*
 : Free Vars of current process:
 : - Don't free all vars of the current display (use ProcCount).
 : - Don't free the process declaration itself - it's still in scope for
 :   one more level (this is taken care of in the declaration: the process'
 :   declaration accepts the proc-level of the former process.
 */
	register Decl	d;
	register struct hashent *hp;

#ifdef TRACEFREE
	printf("# Displevel: %d ProcCount[DispLevel]; %d\n", DispLevel, ProcCount[DispL
evel]);
#endif
	for(hp = LastVar; hp != NULL;) {
		d = hp->h_decl;

#ifdef TRACEFREE
		printf("# %s %d %d - ", hp->h_name, d->d_level,
			d->d_addr.d_disp);
#endif

		if (d->d_level < plevel)
			break;
#ifdef TRACEFREE
		printf("Freed\n");
#endif
		hp->h_decl = d->d_next;
		hp =  d->d_hnext;
		if(!(d->d_addr.d_flags & AF_AP) && !IsExtern(d->d_type))
			if(Type(d->d_type) == DCHAN)
				DisposeChan(d->d_addr);
			else if(Type(d->d_type) == DCHAN_TAB)
				DisposeChanTab(d);
		free(d);
	}
	LastVar = hp;
#ifdef TRACEFREE
	printf("Break\n");
#endif
}

/* declare procedure parameters */
static int	last_type = -1;

DType
DeclParam(type, hv)
{
	return(declparam(type, hv, 0));
}

DType
DeclParamTab(type, hv)
{
	return(declparam(type, hv, 1));
}

DType
declparam(type, hv, istab)
{

	register Decl	nd;
	DType	t;

	if((nd = Declare(hv)) == NULL)
		return;

	nd->d_addr.d_flags = AF_AP;
	nd->d_addr.d_disp = DispLevel;
	nd->d_addr..d_offset = ArgAddr;
	ArgAddr += ARG_SIZE;	/* since we pass table by reference, this is
				 : correct for tabs, too. */
	if (type == -1)
		if (last_type == -1) {
			Error(ERROR, MISSING_PARAM_TYPE);
			return;
		} else
			type = last_type;

	t = ParamTypeConv(type);
	last_type = type;
	if (istab)
		return settabtype(nd, type, t);
	else
		return settype(nd, t);
	/*UNREACHED*/
}

DType
settype(d, dtype)
	Decl	d;
	DType dtype;
{

	d->d_type = Type(dtype);
	if(IsByRef(dtype))
		d->d_addr.d_flags := AF_PTR;
	else
		d->d_addr.d_flags := AF_RO;
	return dtype;		
}

DType
settabtype(d, ptype, dtype)
	Decl	d;
	DType dtype;
{

	switch (ptype) {
	
	case VAR :
		d->d_type = ByRef(DINT_TAB);
		break;
	case VALUE:
		d->d_type = DINT_TAB;
		break;
	case CHAN:
		d->d_type = DCHAN_TAB;
		break;
	default:
		panic("settabtype: bad type");
		break;
	}

	if(!IsByRef(dtype))
		d->d_addr.d_flags := AF_RO;
	d->d_addr.d_flags := AF_PTR;
	return(d->d_type);
}

EndParams() { last_type = -1; }

static struct hashent *VarStack[MAX_STACK];
static addr_t	SpStack[MAX_STACK];
static long	RegStack[MAX_STACK];
static long	MRegStack[MAX_STACK];
static int	BufStack[MAX_STACK];
extern long	RegistersUsed;
extern long	MaxTemp;

Push() {

	if (DispLevel >= MAX_STACK)
		panic("Push: stack overflow");
	VarStack[DispLevel] = LastVar;
	SpStack[DispLevel] = Sp;
	RegStack[DispLevel] = RegistersUsed;
	MRegStack[DispLevel] = MaxTemp;
	DispLevel++;

	LastVar = NULL;
	Sp = SP_START;
	ResetTmp();
}

Pop() {
	if (--DispLevel < 0)
		panic("Pop from top level");
	LastVar = VarStack[DispLevel];
	Sp = SpStack[DispLevel];
	RegistersUsed	= RegStack[DispLevel];
	MaxTemp		= MRegStack[DispLevel];
}

static bufs = 0;
PopBuf() {
	(void) ToBuf(BufStack[--bufs]);
}

PushBuf() {
	BufStack[bufs++] = CurBuf;
	(void) NewBuf();
}

set_extern() { fextern = 1; }
unset_extern() { fextern = 0; }

char *
UniqueGName(hv)
{
	register	l;
	register char	*cp;
	int		*hc;

	hc = &(Hash[hv].h_count);
	cp = Hash[hv].h_name;
	l = strlen(cp);

	if (*hc > 0 && fextern) {
		Error(WARNING, EXTERN_NAME_OVERLOAD, cp);
		return cp;
	}

	if (*hc > 0)
		cp = sprintf(malloc(l+5), "%s%d$", cp, *hc);

	(*hc)++;
	return cp;
}

SHAR_EOF
fi # end of overwriting check
if test -f 'err.c'
then
	echo shar: will not over-write existing file "'err.c'"
else
cat << \SHAR_EOF > 'err.c'
static char	rcsid[] = "$Header: err.c,v 2.1 86/10/30 16:06:01 gil Exp $";

/*
 * $Log:	err.c,v $
 * Revision 2.1  86/10/30  16:06:01  gil
 * This version was submitted for the project. It is free of all major bugs.
 *
 * Revision 1.1  86/01/04  14:20:32  gil
 * Initial revision
 *
 */

#include	<stdio.h>
#include "all.h"

extern	yychar;

#ifdef	NEWYACC
extern struct yytoken {
	char	*t_name;
	int	t_val;
} yytoks[];

char *
tokenname(t)
	register	t;
{
	register struct	yytoken	*tp;

	if(t == 0)
		return "-EOF-";
	for(tp = yytoks; tp->t_val > 0; tp++)
		if(t == tp->t_val)
			break;
	return tp->t_name;
}

#else	NEWYACC
char	*
tokenname(t)
{
	return "";
}
#endif

ProcError() {
	Error(ERROR, SYNT_ERR_NEAR, tokenname(ErrChar));
/*	fprintf(stderr, "Syntax Error on %s\n", tokenname(ErrChar)); */
}

yyerror(s)
	char	*s;
{
	if(yychar == 0)
		LexError(ERROR, UNEXPECTED_EOF);

	ErrChar = yychar;		/* Save the first erroneous token
					 : for error detection by
					 : SyntErr or LHSExpr */
/*	fprintf(stderr, "yyerror: Error char %s\n", tokenname(yychar)); */
}

ShiftError() {
	Error(ERROR, EXPECT_SHIFTED_PROC, tokenname(yychar));
/*	fprintf(stderr, "Expected shifted process, on %s\n",
						tokenname(yychar)); */
}
SHAR_EOF
fi # end of overwriting check
if test -f 'error_list.c'
then
	echo shar: will not over-write existing file "'error_list.c'"
else
cat << \SHAR_EOF > 'error_list.c'
#define	ERR_LIST
#include "error.h"
struct error_list Err_list[] = {
	WARNING,	"No Error",
	RECOVER	,	"Integer overflow",
#define	INTEGER_OVERFLOW		1
	RECOVER	,	"Newline in character constant",
#define	NEWLINE_IN_CHAR_CONST 		2
	RECOVER	,	"Character constant too long",
#define	CHAR_CONST_TOO_LONG 		3
	WARNING	,	"Empty character constant",
#define	EMPTY_CHAR_CONST		4
	WARNING	,	"'*' is escape character",
#define	ESCAPE_CHAR			5
	WARNING	,	"Escape has no special meaning",
#define	NO_SPECIAL_MEANING		6
	RECOVER	,	"Unfinished string",
#define	UNFINISHED_STR			7
	COMPILER_ERROR ,	"Hash table is full",
#define	HASH_FULL			8
	WARNING	,	"Odd number of blanks",
#define	ODD_NO_OF_BLANKS		9
	ERROR	,	"Illegal character",
#define	ILLEGAL_CHAR			10
	COMPILER_ERROR ,	"Lexical error",
#define	LEX_INTERNAL_ERROR		11
	ERROR	,	"Eof Expected - Quit",
#define	EXPECTED_EOF			12
	ERROR	,	"Unexpected Eof",
#define	UNEXPECTED_EOF			13
	RECOVER	,	"Expected constant expression",
#define	EXPECTED_CONST			14
	ERROR	,	"Type mismatch",
#define	TYPE_MISMATCH			15
	RECOVER	,	"Division by zero",
#define	DIV_BY_ZERO			16
	RECOVER	,	"Illegal operand",
#define	OP_MISMATCH			17
	RECOVER	,	"Undefined variable \"%s\"",
#define	UNDEF_VAR			18
	ERROR	,	"Multiply declared var",
#define	MULTIPLY_DECLARED_VAR		19
	RECOVER ,	"Lvalue requierd",
#define	LVAL_REQ			20
	ERROR	,	"Channel required",
#define	CHANNEL_REQ			21
	ERROR	,	"Process required",
#define	PROC_REQUIRED			22
	WARNING ,	"Undefined proc \"%s\", assumed external",
#define	UNDEF_PROC			23
	ERROR	,	"Wrong number of arguments",
#define	ILL_NUM_OF_ARGS		24
	ERROR	,	"External definition cannot be overlapped",
#define	EXTERN_EXISTS			25
	ERROR	,	"Table required",
#define	TABLE_REQUIRED			26
	WARNING	,	"Assigment to Read Only variable",
#define	VALUE_PARAM_ASSIGN		27
	ERROR	,	"Slice required",
#define	SLICE_REQUIRED			28
	ERROR	,	"Slices should be of the same type",
#define	DIFF_SLICES			29
	COMPILER_ERROR ,	"Too many errors",
#define	TOO_MANY_ERRORS		30
	ERROR	,	"missing parameters' type (var, value or chan)",
#define	MISSING_PARAM_TYPE		31
	WARNING	,	"Extra indentation, taken as one indent",
#define	EXTRA_INDENT			32
	RECOVER	,	"Expected shifted process near token %s",
#define	EXPECT_SHIFTED_PROC		33
	ERROR	,	"Syntax Error near token %s",
#define	SYNT_ERR_NEAR			34
	WARNING	,	"External %s is already declared global",
#define	EXTERN_NAME_OVERLOAD		35
	ERROR	,	"Bad identifier type - \"%s\"",
#define	IDENT_REQUIRED			36
	ERROR	,	"VMS (placed) channels are not supported",
#define	VMS_UNSUPPORTED		37
};
SHAR_EOF
fi # end of overwriting check
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
# configurable parameteres
################################################################################
CC=cc
YACC=/usr/bin/yacc
LEX=lex

CFLAGS=-Ih -DYYDEBUG -g
YFLAGS=-d
LFLAGS=

# notice: the order of files in OBJS counts.
OBJS=	error_list.o\
	lex.yy.o\
	y.tab.o\
	back.o\
	decl.o\
	err.o\
	expr.o\
	extern.o\
	gen.o\
	hash.o\
	init.o\
	io.o\
	lex.o\
	main.o\
	newbuf.o\
	par.o\
	print.o\
	proc.o\
	repl.o\
	reserved.o\
	reserved_words.o\
	slice.o\
	tab.o\
	temp.o\
	$(EMPTY)

ocp:	$(OBJS)
	$(CC) $(CFLAGS) -o ocp $(OBJS) -ll

lex.yy.c:	occam.lex
	$(LEX) $(LFLAGS) occam.lex

y.tab.c:	parse.y
	$(YACC) $(YFLAGS) parse.y
	mv y.tab.h h

error_list.o: error_list.c h/errors.h h/error.h
error_list.c: err_types
	sh ../tools/makeerrs

reserved_words.c: reserved_words
	csh -f ../tools/reserve

clean:
	-rm *.o lex.yy.c y.tab.c ocp

# dependencies on header files.
################################################################################
back.o:	h/conf.h
back.o:	h/machine.h
back.o:	h/addr.h
back.o:	h/lex.h
back.o:	h/hash.h
back.o:	h/back.h
back.o:	h/parse.h
back.o:	h/error.h
back.o:	h/reserved.h
back.o:	h/y.tab.h

decl.o:	h/conf.h
decl.o:	h/machine.h
decl.o:	h/addr.h
decl.o:	h/lex.h
decl.o:	h/hash.h
decl.o:	h/back.h
decl.o:	h/parse.h
decl.o:	h/error.h
decl.o:	h/reserved.h
decl.o:	h/y.tab.h

err.o:	h/conf.h
err.o:	h/machine.h
err.o:	h/addr.h
err.o:	h/lex.h
err.o:	h/hash.h
err.o:	h/back.h
err.o:	h/parse.h
err.o:	h/error.h
err.o:	h/reserved.h
err.o:	h/y.tab.h

error_list.o:	h/error.h

expr.o:	h/conf.h
expr.o:	h/machine.h
expr.o:	h/addr.h
expr.o:	h/lex.h
expr.o:	h/hash.h
expr.o:	h/back.h
expr.o:	h/parse.h
expr.o:	h/error.h
expr.o:	h/reserved.h
expr.o:	h/y.tab.h

extern.o:	h/conf.h
extern.o:	h/machine.h
extern.o:	h/addr.h
extern.o:	h/lex.h
extern.o:	h/hash.h
extern.o:	h/back.h
extern.o:	h/parse.h
extern.o:	h/error.h
extern.o:	h/reserved.h
extern.o:	h/y.tab.h

hash.o:	h/hash.h

gen.o:	h/conf.h
gen.o:	h/machine.h
gen.o:	h/addr.h
gen.o:	h/lex.h
gen.o:	h/hash.h
gen.o:	h/back.h
gen.o:	h/parse.h
gen.o:	h/error.h
gen.o:	h/reserved.h
gen.o:	h/y.tab.h

init.o:	h/conf.h
init.o:	h/machine.h
init.o:	h/addr.h
init.o:	h/lex.h
init.o:	h/hash.h
init.o:	h/back.h
init.o:	h/parse.h
init.o:	h/error.h
init.o:	h/reserved.h
init.o:	h/y.tab.h

io.o:	h/conf.h
io.o:	h/machine.h
io.o:	h/addr.h
io.o:	h/lex.h
io.o:	h/hash.h
io.o:	h/back.h
io.o:	h/parse.h
io.o:	h/error.h
io.o:	h/reserved.h
io.o:	h/y.tab.h

lex.o:	h/conf.h
lex.o:	h/machine.h
lex.o:	h/addr.h
lex.o:	h/lex.h
lex.o:	h/hash.h
lex.o:	h/back.h
lex.o:	h/parse.h
lex.o:	h/error.h
lex.o:	h/reserved.h
lex.o:	h/y.tab.h

lex.yy.o:	h/conf.h
lex.yy.o:	h/machine.h
lex.yy.o:	h/addr.h
lex.yy.o:	h/lex.h
lex.yy.o:	h/hash.h
lex.yy.o:	h/back.h
lex.yy.o:	h/parse.h
lex.yy.o:	h/error.h
lex.yy.o:	h/reserved.h
lex.yy.o:	h/y.tab.h

main..o:	h/conf.h
main.o:	h/machine.h
main.o:	h/addr.h
main.o:	h/lex.h
main.o:	h/hash.h
main.o:	h/back.h
main.o:	h/parse.h
main.o:	h/error.h
main.o:	h/reserved.h
main.o:	h/y.tab.h

newbuf.o:	h/conf.h
newbuf.o:	h/machine.h
newbuf.o:	h/addr.h
newbuf.o:	h/lex.h
newbuf.o:	h/hash.h
newbuf.o:	h/back.h
newbuf.o:	h/parse.h
newbuf.o:	h/error.h
newbuf.o:	h/reserved.h
newbuf.o:	h/y.tab.h

par.o:	h/conf.h
par.o:	h/machine.h
par.o:	h/addr.h
par.o:	h/lex.h
par.o:	h/hash.h
par.o:	h/back.h
par.o:	h/parse.h
par.o:	h/error.h
par.o:	h/reserved.h
par.o:	h/y.tab.h

print.o:	h/error.h

proc.o:	h/conf.h
proc.o:	h/machine.h
proc.o:	h/addr.h
proc.o:	h/lex.h
proc.o:	h/hash.h
proc.o:	h/back.h
proc.o:	h/parse.h
proc.o:	h/error.h
proc.o:	h/reserved.h
proc.o:	h/y.tab.h

repl.o:	h/conf.h
repl.o:	h/machine.h
repl.o:	h/addr.h
repl.o:	h/lex.h
repl.o:	h/hash.h
repl.o:	h/back.h
repl.o:	h/parse.h
repl.o:	h/error.h
repl.o:	h/reserved.h
repl.o:	h/y.tab.h

reserved.o:	h/conf.h
reserved.o:	h/machine.h
reserved.o:	h/addr.h
reserved.o:	h/lex.h
reserved.o:	h/hash.h
reserved.o:	h/back.h
reserved.o:	h/parse.h
reserved.o:	h/error.h
reserved.o:	h/reserved.h
reserved.o:	h/y.tab.h

reserved_words.o:	h/conf.h
reserved_words.o:	h/machine.h
reserved_words.o:	h/addr.h
reserved_words.o:	h/lex.h
reserved_words.o:	h/hash.h
reserved_words.o:	h/back.h
reserved_words.o:	h/parse.h
reserved_words.o:	h/error.h
reserved_words.o:	h/reserved.h
reserved_words.o:	h/y.tab.h

slice.o:	h/conf.h
slice.o:	h/machine.h
slice.o:	h/addr.h
slice.o:	h/lex.h
slice.o:	h/hash.h
slice.o:	h/back.h
slice.o:	h/parse.h
slice.o:	h/error.h
slice.o:	h/reserved.h
slice.o:	h/y.tab.h

tab.o:	h/conf.h
tab.o:	h/machine.h
tab.o:	h/addr.h
tab.o:	h/lex.h
tab.o:	h/hash.h
tab.o:	h/back.h
tab.o:	h/parse.h
tab.o:	h/error.h
tab.o:	h/reserved.h
tab.o:	h/y.tab.h

temp.o:	h/addr.h
temp.o:	h/machine.h

y.tab.o:	h/conf.h
y.tab.o:	h/machine.h
y.tab.o:	h/addr.h
y.tab.o:	h/lex.h
y.tab.o:	h/hash.h
y.tab.o:	h/back.h
y.tab.o:	h/parse.h
y.tab.o:	h/error.h
y.tab.o:	h/reserved.h
SHAR_EOF
fi # end of overwriting check
if test -f 'expr.c'
then
	echo shar: will not over-write existing file "'expr.c'"
else
cat << \SHAR_EOF > 'expr.c'
static char	rcsid[] = "$Header: expr.c,v 2.2 86/11/01 12:20:30 gil Exp $";

/*
 * $Log:	expr.c,v $
 * Revision 2.2  86/11/01  12:20:30  gil
 * added 'Zero()' for buffered channels of size zero (regular channels).
 *
 * Revision 2.1  86/10/30  16:06:04  gil
 * This version was submitted for the project. It is free of all major bugs.
 *
 * Revision 1.2  86/03/19  15:26:56  gil
 * report variable name on errors.
 *
 * Revision 1.1  86/01/04  14:20:34  gil
 * Initial revision
 *
 */

#include <stdio.h>
#include "all.h"

#define SameType(e1, e2)	((e1.e_flags&E_TYPE) == (e2.e_flags&E_TYPE))
#define ABS(x)			((x) > 0 ? (x) : -(x))
#define Null_tf(e)		(e).e_false = NullQuadl;

#define	LastLabelIn(ql)	(ql.q_quads[ql.q_nquads-1])
#define EMPTY_LABEL	-1
#define EmptyLabel(l)	((l) == EMPTY_LABEL)

static addr	AnyAddr = { 0, 0, AD_GLOBAL, (addr_t) "UndefinedVar" };
extern addr NewTemp();
extern addr	TimeCounter;

Expr
EmptyExpr() {

	Expr	e;
	
	e.e_flags = EK_CONST:ET_INT;
	e.e_slen = NullAddr;
	e.e_false = NullQuadl;
	e.e_place = NullAddr;
	return e;
}

Expr
Zero() {
	Expr	e;

	e.e_flags = EK_CONST:ET_INT;
	e.e_slen = NullAddr;
	e.e_false = NullQuadl;
	e.e_place = Immediate(0);
	return e;
}
	
addr
Eval(op, l1, l2)
	addr l1, l2;
{
	register int v1 = (int)l1.d_offset, v2 = (int)l2.d_offset, v;

	switch (op) {

	case PLUS_TOK:
#define	ADD_OVF(a, b)	((a > 0 && MAXINT-a < b) :: (a < 0 && -MAXINT-a > b))
		if(ADD_OVF(v1, v2)) {
			Error(ERROR, INTEGER_OVERFLOW);
			v = 0;
			break;
		}
		v = v1 + v2;
		break;
	case MINUS_TOK:
#define SUB_OVF(a, b)  ((a > 0 && MAXINT-a < -b) :: (a < 0 && -MAXINT-a > -b))
		if(SUB_OVF(v2, v1)) {
			Error(ERROR, INTEGER_OVERFLOW);
			v = 0;
			break;
		}
		v = v2 - v1;
		break;
#define MULT_OVF(a, b)	(a != 0 && MAXINT/ABS(a) < ABS(b))
	case MULT_TOK:
		if(MULT_OVF(v1, v2)) {
			Error(ERROR, INTEGER_OVERFLOW);
			v = 0;
			break;
		}
		v = v1 * v2;
		break;
#define DIVISION_BY_ZERO(a, b)	(b == 0)
	case DIV_TOK:
		if(DIVISION_BY_ZERO(v2, v1)) {
			Error(ERROR, DIV_BY_ZERO);
			v = 0;
			break;
		}
		v = v2 / v1;
		break;
	case OR_TOK:
		v = v1 : v2;
		break;
	case AND_TOK:
		v = v1 & v2;
		break;
	case XOR_TOK:
		v = v1 ^ v2;
		break;
	case LSHIFT_TOK:
		v = v1 << v2;
		break;
	case RSHIFT_TOK:
		v = v1 >> v2;
		break;
/* Comparison operators */

	case EQ_TOK:
		v = TRUE_VAL(v1 == v2);
		break;
	case GT_TOK:
		v = TRUE_VAL(v1 > v2);
		break;
	case GE_TOK:
		v = TRUE_VAL(v1 >=  v2);
		break;
	case LT_TOK:
		v = TRUE_VAL(v1 < v2);
		break;
	case LE_TOK:
		v = TRUE_VAL(v1 <= v2);
		break;
	case NEQ_TOK:
		v = TRUE_VAL(v1 != v2);
		break;
	case AFTER:	/* unsigned > comparison */
		v = TRUE_VAL((unsigned int)v1 > (unsigned int)v2);
		break;

/* Logical operators */
	case AND:
		v = TRUE_VAL(CVAL(v1) && CVAL(v2));
		break;
	case OR:
		v = TRUE_VAL(CVAL(v1) :: CVAL(v2));
		break;
	default:
		panic("Bad operator in Eval");
	}
	return Immediate(v);
}

Expr
IntVal(lv)
	union	lval	lv;
{
	Expr	e;

	e = EmptyExpr();
	e.e_flags = ET_INT:EK_CONST;
	e.e_place = Immediate(lv.lv_intval);
	return e;
}

Expr
CharVal(lv)
	union	lval	lv;
{
	Expr e;

	e = EmptyExpr();
	e.e_flags = ET_CHAR:EK_CONST;
	e.e_place = Immediate(lv.lv_charval);
	return e;
}

Expr
StrVal(s)
	char	*s;
{
	Expr	e;

	e = EmptyExpr();
	e.e_flags = ET_INTTAB:EK_CONST;
	e.e_place = NullAddr;
	e.e_place.d_flags = AF_LABEL;
	e.e_place.d_disp = AD_GLOBAL;
	e.e_place.d_offset = (addr_t)strsave(GenDefLabel(NewLabel()));
	GenDefStr(s);

	return e;
}

Expr
Bool(tv)
{
	Expr	e;

	e = EmptyExpr();
	e.e_flags = ET_BOOL:EK_CONST;
	e.e_place = Immediate(tv);
	return e;
}

Expr
LocalClock() {

	Expr	e;
	
	e.e_flags = EK_VAR:ET_INT;
	e.e_slen = NullAddr;
	e.e_false = NullQuadl;
	e.e_place = TimeCounter;
	return e;
}

Tconv(dtype)
	DType dtype;
{

	switch (Type(dtype)) {

	case DINT:
		return ET_INT;
	case DCHAN:
		return ET_CHAN;
	case DCHAN_TAB:
		return ET_CHANTAB;
	case DINT_TAB:
		return ET_INTTAB;
	default:
		panic("Tconv: bad type");
		/*NOTREACHED */
	}
}

DType
Etype(e)
	Expr e;
{
	switch (e.e_flags&E_TYPE) {
		case ET_INT:
			return DINT;
		case ET_CHAN:
			return DCHAN;
		case ET_CHANTAB:
			return DCHAN_TAB;
		case ET_INTTAB:
			return DINT_TAB;
		default:
			panic("Etype: bad type");
			/*NOTREACHED*/
	}
}

Expr
MonOp(op, e1)
	Expr e1;
{
	Expr e;
	register v;

#define	MonOpOk(op, e)	(((op == NOT && (e.e_flags&E_TYPE) == ET_BOOL)) :: \
			  (op == MINUS_TOK && (e.e_flags&E_TYPE) == ET_INT))
	if(!MonOpOk(op, e1)) {
		Error(ERROR, OP_MISMATCH);
		return e1;
	}
	e = EmptyExpr();
	e.e_flags = e1.e_flags & E_TYPE;

	if(IsConst(e1)) {
		switch (op) {

		case MINUS_TOK:
			v = -(e1.e_cval);
			break;
		case NOT:
			v = TRUE_VAL( !(CVAL(e1.e_cval)) );
			break;
		default:
			panic("Bad monop");
			/*NOTREACHED*/
		}
		e.e_place = Immediate(v);
		e.e_flags := EK_CONST;
		return e;
	}
	e = EvalBool(e1);
	FreeExp(e1);
	e.e_place = NewTemp();
	e.e_flags := EK_EXP;
	Gen(MON(op), Addr(e1), NullAddr, e.e_place);
	return e;
}

Expr
Identifier(id)			/* return an expression for identifier */
	int id;
{
	Expr e;
	struct decl *d;

	d = Hash[id].h_decl;
	e = EmptyExpr();
	if (d == NULL) {
		Error(ERROR, UNDEF_VAR, Hash[id].h_name);
		e.e_place = AnyAddr;
		return e;
	}
	if (!IsIdent(d)) {
		Error(ERROR, IDENT_REQUIRED, Hash[id].h_name);
		e.e_place = AnyAddr;
		return e;
	}

	e.e_flags = Tconv(d->d_type);
	Null_tf(e);

	e.e_place = d->d_addr;
	if (IsDef(d))
		e.e_flags := EK_CONST;
	else
		e.e_flags := EK_VAR;
	return e;
}

FreeExp(e)
	Expr e;
{
	if (NullA(e.e_place))
		return;
 	if(IsTemp(e) :: (IsVar(e) && (e.e_place.d_flags & AF_SUB)))
		FreeTmp(e.e_place);
	if((e.e_flags&E_TYPE) == ET_SLICE)
		FreeTmp(e.e_slen);
}

#ifdef notdef
addr
Addr(e)
	Expr e;
{
	return e.e_place;
}
#endif

Expr
EvalBool(e)
	Expr	e;
{

	Label	true_l;
	
	if(IsConst(e) :: !NullA(e.e_place))
		return e;
/*	if (!NullA(e.e_place)) {
		BackPatch(e.e_false);	????
		return e;
	} */
	e.e_place = NewTemp();
	GenAssignConst(C_TRUE, e.e_place);
	true_l = NewLabel();
	GenJmp(JMP, true_l);
	BackPatch(e.e_false);
	GenAssignConst(C_FALSE, e.e_place);
	GenLabel(true_l);
	Null_tf(e);
	return e;
}

Expr
BinOp(op, e1, e2, type)
	Expr e1, e2;
{
	Expr	e;

	e = EmptyExpr();
	e2 = EvalBool(e2);	/* e1 already evaluated */
	if(IsConst(e1) && IsConst(e2)) {
		e.e_place = Eval(op, e1.e_place, e2.e_place);
		e.e_flags = type : EK_CONST;
		return e;
	}
	FreeExp(e1);
	FreeExp(e2);
	e.e_place = NewTemp();
	Gen(op, Addr(e1), Addr(e2), e.e_place);
	e.e_flags = type : EK_EXP;
	return e;
}

#define ArithOk(e1, e2)		(((e1.e_flags & E_TYPE) == ET_INT) && \
				 ((e2.e_flags & E_TYPE) == ET_INT))
#define CmpOk(e1, e2)	SameType(e1, e2)
#define LLogOk(e)		((e.e_flags & E_TYPE) == ET_BOOL)
#define RLogOk(e)		LLogOk(e)

Expr
CmpOp(op, e1, e2)
	Expr e1, e2;
{
	Expr	e;

	e = EmptyExpr();
	if(!CmpOk(e1, e2)) {
		Error(ERROR, TYPE_MISMATCH);
		return e1;
	}
	if(IsConst(e1) && IsConst(e2)) {
		e.e_place = Eval(op, e1.e_place, e2.e_place);
		e.e_flags = ET_BOOL : EK_CONST;
		return e;
	}
	FreeExp(e1);
	FreeExp(e2);

	e = EvalBool(e2);
	e.e_place = NewTemp();
	GenCmp(op, Addr(e1), Addr(e2), e.e_place);
	e.e_flags = ET_BOOL : EK_EXP;
	return e;
}

Label
Land(e1)
	Expr	e1;
{
/* intermiediate: left hand side of e1 AND e2. return the 'false' address. */
	Label	false_l;

	/* check type for this operation */
	if (!LLogOk(e1)) {
		Error(ERROR, TYPE_MISMATCH);
		return EMPTY_LABEL;
	}
		
	/* handle lhs constant */
	if (IsConst(e1))
		return EMPTY_LABEL;
	
	/* code generation for testing of lhs.
	 : produce the jump to a 'false' label already here,
	 : for the case lhs=false. */
	false_l = NewLabel();

	if (!NullA(e1.e_place)) {
		GenTst(Addr(e1));
		FreeExp(e1);
		GenJmp(NEQ_TOK, false_l);
		/* now follows the code for 'e2' in 'Rand' */
	}
	return false_l;
}

Expr
Rand(e1, false_l, e2)
	Expr	e1, e2;
	Label	false_l;
{
/* right hand side of e1 and e2 */

	Expr	e;

	/* check types for this operator */
	if (!RLogOk(e2)) {
		Error(ERROR, TYPE_MISMATCH);
		return e1;
	}

	/* handle constants (either both operands, or just one operand) */
	if (IsConst(e1))
		if (IsConst(e2)) {
			e2.e_place = Eval(AND, e1.e_place, e2.e_place);
			return e2;	/* flags and all stay the same */
 		} else {
			if (!CVAL(e1.e_cval))	/* false AND e2 --> false */
				return e1;
			/* else - true AND e2 --> e2, generate code */
		}
	else if (IsConst(e2))
		if (CVAL(e2.e_cval)) {		/* e1 AND true --> e1 */
			e.e_false = AddList(e1.e_false, false_l);
			goto ret;
		} else {			/* e1 AND false --> false */
			BackPatch(e1.e_false);	/* here IS false.. */
			GenLabel(false_l);
			return e2;
		}

	/*
	 : Generate code for computing this operation, using flow control.
	 : Assume that lhs of this 'and' is true "here" and false at 'ql'.
	 */
	e = EmptyExpr();
	e.e_false = Merge(e1.e_false, e2.e_false);
	if (!EmptyLabel(false_l))
		e.e_false = AddList(e.e_false, false_l);
	if (NullQ(e.e_false))
		e.e_false = MakeList(NewLabel());
	if (!NullA(e2.e_place)) {
		GenTst(Addr(e2));
		FreeExp(e2);
		/* if got here, than 'e.e_false' cannot be empty */
		GenJmp(NEQ_TOK, LastLabelIn(e.e_false));
		/* "now", again, follow the true actions */
	}
ret:
	e.e_place = NullAddr;
	e.e_flags = ET_BOOL : EK_EXP;
	return e;
}

Label
Lor(e1)
	Expr	e1;
{
/* intermediate: left hand side of e1 OR e2. return the 'true' address. */
	Label	true_l;

	/* check type for this operation */
	if (!LLogOk(e1)) {
		Error(ERROR, TYPE_MISMATCH);
		return EMPTY_LABEL;
	}
	
	/* handle constant lhs. */
	if (IsConst(e1))
		return EMPTY_LABEL;
		
	/* code generation for testing of lhs.
	 : produce the jump to a 'true' label already here,
	 : for the case lhs=true, and the whole expression is true. */
	true_l = NewLabel();

	if (!NullA(e1.e_place))	{
		GenTst(Addr(e1));
		FreeExp(e1);
		GenJmp(EQ_TOK, true_l);
	}  else		/* here it is 'true', and the expression is true */
		GenJmp(JMP, true_l);
	BackPatch(e1.e_false);

	/* now follows the code for 'e2' in 'Ror' */
	return true_l;
}

Expr
Ror(e1, true_l, e2)
	Expr	e1, e2;
	Label	true_l;
{
/* right hand side of e1 and e2 */
	Label	false_l;
	Expr	e;

	/* check type for this operation */
	if (!RLogOk(e2)) {
		Error(ERROR, TYPE_MISMATCH);
		return e1;
	}

	/* handle constant (either both, or just one) */
	if (IsConst(e1))
		if (IsConst(e2)) {
			e2.e_place = Eval(OR, e1.e_place, e2.e_place);
			return e2;	/* flags and all stay the same */
		} else {
			if (CVAL(e1.e_cval))	/* true OR e2 --> true */
				return e1;
			/* else - false OR e2 --> e2, generate code */
		}
	else if (IsConst(e2))
		if (CVAL(e2.e_cval)) {	/* e1 OR true --> true */
			GenLabel(true_l);
			return e2;
		} else	{		/* e1 OR false --> e1 */
			false_l = NewLabel();
			e.e_false = AddList(e1.e_false, false_l);
			GenJmp(JMP, false_l);
			goto ret;
		}

	/*
	 : Generate code for computing this operation, using flow control.
	 : Assume that lhs of this 'or' is false "here" and true at 'true_l'.
	 */
	e = EmptyExpr();
	e.e_false = e2.e_false;
	if (!NullA(e2.e_place)) {
		GenTst(Addr(e2));
		FreeExp(e2);
		false_l = NewLabel();
		e.e_false = AddList(e.e_false, false_l);
		GenJmp(NEQ_TOK, false_l);
	}
ret:
	GenLabel(true_l);
	/* now follows the 'true' actions */
	e.e_place = NullAddr;
	e.e_flags = ET_BOOL : EK_EXP;
	return e;
}

Expr
ArithOp(op, e1, e2)
	Expr e1, e2;
{
	if(!ArithOk(e1, e2)) {
		Error(ERROR, TYPE_MISMATCH);
		return e1;
	}
	return BinOp(op, e1, e2, ET_INT);
}

addr
Lvalue(var)
	Expr var;
{

	if(Etype(var) != DINT :: !IsVar(var)) {
		Error(ERROR, LVAL_REQ);
		return NullAddr;
	}
	if (IsReadOnly(var))
		Error(WARNING, VALUE_PARAM_ASSIGN);

	return var.e_place;
}

Assign(lval, e)
	Expr lval, e;
{
	addr	dst;

	if((lval.e_flags & E_TYPE) == ET_SLICE)
		return AssignSlice(lval, e);
	dst = Lvalue(lval);
	if(NullA(dst))
		return;
	Gen(MOVL, Addr(e), NullAddr, dst);
	FreeExp(lval, e);
}

AssignSlice(lval, e)
	Expr	lval, e;
{
	if((e.e_flags & E_TYPE) != ET_SLICE)
		Error(ERROR, SLICE_REQUIRED);
	if((e.e_place.d_flags & AF_BYTE) != (lval.e_place.d_flags&AF_BYTE))
		Error(ERROR, DIFF_SLICES);
	GenBcopy(Addr(e), lval.e_place, e.e_slen);
	FreeExp(lval, e);
}

Expr
CondExpr(e)
	Expr	e;
{
	Label false_l;

	if (NullA(e.e_place))
		return e;

	GenTst(Addr(e));
	false_l = NewLabel();
	GenJmp(NEQ_TOK, false_l);
	e.e_false = MakeList(false_l);
	return e;
}

Expr
Index(hv, e, isbyte)
	Expr	e;
{
	struct decl	*d;
	Expr		ne;

	d = Hash[hv].h_decl;
	if (d == NULL) {
		Error(ERROR, UNDEF_VAR, Hash[hv].h_name);
		return e;
	}
	ne = EmptyExpr();	
	if(Type(d->d_type) != DINT_TAB && Type(d->d_type) != DCHAN_TAB) {
		Error(ERROR, TABLE_REQUIRED);
		return ne;
	}
	if(Type(d->d_type) == DINT_TAB)
		ne.e_flags = ET_INT:EK_VAR;
	else
		ne.e_flags = ET_CHAN;
	if(isbyte)
		ne.e_place = GenByteSubscript(d->d_addr, Addr(e));
	else
		ne.e_place = GenIntSubscript(d->d_addr, Addr(e));
	return ne;
}

Expr
IndexedVar(hv, e)
	Expr	e;
{
	return Index(hv, e, 0);
}

Expr
ByteIndexedVar(hv, e)
	Expr	e;
{
	return Index(hv, e, 1);
}
SHAR_EOF
fi # end of overwriting check
if test -f 'extern.c'
then
	echo shar: will not over-write existing file "'extern.c'"
else
cat << \SHAR_EOF > 'extern.c'
static char	rcsid[] = "$Header: extern.c,v 2.1 86/10/30 16:06:09 gil Exp $";

/*
 * $Log:	extern.c,v $
 * Revision 2.1  86/10/30  16:06:09  gil
 * This version was submitted for the project. It is free of all major bugs.
 *
 * Revision 1.1  86/01/04  14:20:36  gil
 * Initial revision
 *
 */

#include <stdio.h>
/* define EXT here for the variables to be allocated main. */
#define EXT
#include "all.h"
/*#include "yacc_macros.h"*/

SHAR_EOF
fi # end of overwriting check
if test -f 'gen.c'
then
	echo shar: will not over-write existing file "'gen.c'"
else
cat << \SHAR_EOF > 'gen.c'
static char *rcsid = "$Header: gen.c,v 2.2 87/05/01 11:10:38 gil Exp $";
#include <stdio.h>
#include <ctype.h>
#include "all.h"

#define codef stdout
#ifdef vax
#define DCONV(lvl)	(((lvl)-(AD_GLOBAL+1))*INT_SIZE*2+INT_SIZE)
#else tahoe
/* on tahoe there is no ap */
#define DCONV(lvl)	(((lvl)-AD_GLOBAL)*INT_SIZE)
#endif

/* This macro is used to tell Gen not to free temporary storage, since
 : operation is not yet finished */
#define	DONT_FREE	(1<<14)
#define	DontFree(op)	((op):DONT_FREE)

#define	PBYTE(isbyte)	((isbyte) ? 'b' : 'l')


#define ADDR(a)	a.d_disp, a.d_offset
#define OFFT(a)	a.d_offset

#define	Commute(a)	(commute&(1<<a))

extern	commute;
extern	naddr;
extern	char *Inst();
extern	(*func)();

extern	MaxTemp;
extern	counting;	/* 1 if commands counting is turned on */
#ifdef vax
int	stack_reserve = 1;
#else
int	stack_reserve = 0;
#endif

addr	NullAddr = { 0, 0, AD_REGISTER, -1 };
Buffer	DataBuf, 		/* for data segment */
	RO_DataBuf;		/* for read-only data, declared 'text' but
				 : doesn't mingle with the code. */
Buffer	MainText;		/* for separate compilation */
int	NoMain;			/*	"		    */

addr		TimeCounter = { AF_REG, 0, DP, -TIME_COUNTER };
static	addr	GlobalCounter = { 0, 0, AD_GLOBAL, (int)"CommandsTime"};
static	InData;

extern char	*sprintf();

InitCode() {
/*
 : Start buffers and generate buffer headers (text, data, etc.).
 : Order of initialization is important; Buffers will be flushed in
 : that order.
 */
	DataBuf = NewBuf();
	pcode("\t.align\t1\n");
/*	pcode("\t.data\n");
	pcode("\t.globl\t__localclock\n"); */
	RO_DataBuf = NewBuf();
	pcode("\t.text\n");
	pcode("\t.align\t1\n");
	MainText = NewBuf();
	pcode("\t.text\n");
	pcode("\t.align\t1\n");
	pcode("\t.globl\t_oc_main\n");
	pcode("_oc_main:\n");
	InData = 0;
}

EndCode() {
	CountFlush();
#ifdef vax
	pcode("\tcalls\t$0,_endproc\n");
#else tahoe
	pcode("\tcallf\t$4,_endproc\n");
#endif
}

/*
 : gaddr:
 : Resolve indirect addresses.
 : Returns the address of an intermidiate which contains the computed address.
 */
addr
gaddr(a, canbebyte)
	addr a;
{
	addr ra;
	register i;

	if(a.d_disp <= AD_GLOBAL :: a.d_disp >= DispLevel) {
		if(!IsByte(a) :: canbebyte :: a.d_disp == AD_REGISTER ::
		   a.d_disp == AD_IMMED)
			return a;

		ra = NullAddr;		/* resolve byte addresses */
		ra.d_disp = AD_REGISTER;
		ra.d_offset = newreg();
		pcode("\tmovzbl\t");
		paddr(a);
		pcode(",r%d\n", ra.d_offset);
		return ra;
	}

	ra = a;
	ra.d_flags := AF_REG;
	ra.d_disp = newreg();
#ifdef vax
	if(a.d_flags & AF_AP)
		i = DCONV(a.d_disp)+INT_SIZE;
	else
#endif
		i = DCONV(a.d_disp);


#ifdef vax
	pcode("\tmovl\t-%d(r11),r%d\n", i, ra.d_disp);
#else tahoe
	pcode("\tmovl\t-%d(r12),r%d\n", i, ra.d_disp);
#endif
	if(!canbebyte && IsByte(a)) {
		pcode("movzbl\t");
		paddrs(2, ra, Register(ra.d_disp));
		ra = Register(ra.d_disp);
	}
	return ra;
}

/*
 : Generate a code for one instruction.
 : accepts quadruple code: [Instruction, Arg1, Arg2, Result].
 : Inst(op) returns the instruction name, and puts the number of
 : of operands for this instruction in 'naddr'.
 : Further optimization is done when one of the arguments is the same is the
 : result; In VAX the same instruction could be performed on 2 or 3 arguments.
 : When addresses are not absolute or fp/ap relative, the should be computed
 : and the result is the instruction operand. This is done by 'gaddr'.
 */
Gen(op, a1, a2, res)
	addr a1, a2, res;
{
	char *s;
	int	byte = 0, free = 1;

	if(op & DONT_FREE) {
		free = 0;
		op &= ~DONT_FREE;
	}
	commute = 0xff;
	naddr = 3;
	func = NULL;
	s = Inst(op);
	if(func != NULL)
		if((*func)(op, &a1, &a2, &res))
			return;
	if(naddr == 1) {
		a1 = gaddr(a1, 1);

		pcode("\t%s%c\t", s, PBYTE(IsByte(a1)));
		paddr(a1); pcode("\n");
		endaddr();
		return;
	}
	res = gaddr(res, 1);
	if(naddr == 2) {
		if(IsByte(a1))
			byte = 1;
		a1 = gaddr(a1, byte);
		pcode("\t%s%c\t", s, PBYTE(byte));
		paddr(a1), pcode(",");
	} else
	if(Commute(1) && SameAddr(a1, res)) {
		if(IsByte(a1))
			byte = 1;
		a2 = gaddr(a2, byte);
		pcode("\t%s%c2\t", s, PBYTE(byte));
		paddr(a2); pcode(",");
	} else
	if(Commute(2) && SameAddr(a2, res)) {
		if(IsByte(a2))
			byte = 1;
		a1 = gaddr(a1, byte);
		pcode("\t%s%c2\t", s, PBYTE(byte));
		paddr(a1); pcode(",");
	} else {
		if(IsByte(a1) && IsByte(a2))
			byte = 1;

		a1 = gaddr(a1, byte);
		a2 = gaddr(a2, byte);
		pcode("\t%s%c3\t", s, PBYTE(byte));
		paddr(a1); pcode(",");
		paddr(a2); pcode(",");
	}
	if((byte && IsByte(res)) :: (!byte && !IsByte(res)))
		paddr(res);
	else if(!byte && IsByte(res)) {
		int	r;

		r = newreg();
		pcode("r%d\n", r);
		pcode("\tcvtlb\tr%d,");
		paddr(res);
	} else if(byte && !IsByte(res)) {
		int	r;

		r = newreg();
		pcode("r%d\n", r);
		pcode("\tcvtbl\tr%d,");
		paddr(res);
	}

	pcode("\n");
	if(free)
		endaddr();

}

/*
 : Print an address.
 : Valid addressing modes:
 :	1. register relative. [register displacement, register displacement
 : deffered].
 :	2. Absolute. (labels).
 :	3. Immediate. (constants).
 :	4. fp or ap relative. Arguments, Local variables, Temporaries.
 :	Other addresses (Local variables/arguments) not of this Display level
 : 	should be resolved by gaddr.
 */
paddr(a)
	addr a;
{
	if(a.d_flags & AF_REG) {
		if (a.d_flags & AF_AP)
			pcode("%s%d(r%d)",
				(a.d_flags&AF_PTR) ? "*" : "",
					a.d_offset, a.d_disp);
		else		/* should ask about AF_PTR */
			pcode("%d(r%d)", -a.d_offset, a.d_disp);
		goto indexed;
	}
	if(a.d_flags & AF_LABEL) {
		pcode("%s", (char *)a.d_offset);
		goto indexed;
	}
	if(a.d_disp == AD_GLOBAL && (a.d_flags & AF_FP) == 0) {
		pcode("_%s", (char *)a.d_offset);
		goto indexed;
	}
	if(a.d_disp == AD_IMMED) {
		pcode("$%d", a.d_offset);
		return;
	}
	if(a.d_disp == AD_REGISTER) {
		pcode("r%d", a.d_offset);
		goto indexed;
	}
	if(a.d_disp == DispLevel) {
		if (a.d_flags & AF_AP)
#ifdef vax
			pcode("%s%d(ap)",
#else tahoe
			pcode("%s%d(fp)",
#endif
				(a.d_flags&AF_PTR) ? "*" : "",	a.d_offset);
		else
			pcode("-%d(fp)", a.d_offset);/* should ask about
						      : AF_PTR */
		goto indexed;
	}
	panic("bad address!!");
indexed:
	if(a.d_flags & AF_SUB)
		pcode("[r%d]", a.d_reg);
}

paddrs(ac, av)
	int	ac;
	addr	av;
{
	register addr	*ap = &av;
	
	while(--ac > 0) {
		paddr(*ap);
		pcode(",");
		ap++;
	}
	paddr(*ap);
	pcode("\n");
}

/*
 : GenGlobal:
 : Allocate space and declare global the declerand in 'd' of size 'size'.
 */
GenGlobal(d, size)
	struct decl *d;
{
	Buffer	obuf = ToBuf(DataBuf);
	pcode("\t.comm\t_%s,%d\n", d->d_addr.d_offset, size);
	ToBuf(obuf);
}

/*
 : GenLabelCall:
 : Call an internally created procedure, labeled (by the compiler) 'l'.
 */
GenLabelCall(l)
	Label	l;
{
	CountFlush();
#ifdef vax
	pcode("\tcalls\t$0,L%d\n", l);
#else tahoe
	pcode("\tcallf\t$4,L%d\n", l);
#endif
}

/*
 : GenFuncCall:
 : Generate a function call to 'fname' with 'nargs' arguments, putting
 : the returned value in 'result' (unless result == NullAddr).
 : 'DispLevel' is used for nested naming.
 */
GenFuncCall(nargs, fname, disp_level, result)
	addr nargs;
	char *fname;
	addr result;
{

	register i;

	CountFlush();
	nargs = gaddr(nargs, 0);
#ifdef tahoe
	if(nargs.d_disp == AD_IMMED) {
		nargs.d_offset *= 4;
		nargs.d_offset += 4;
	} else {
		pcode("	mull2	$4,");
		paddr(nargs);
		pcode("\n");
		pcode("	addl2	$4,");
		paddr(nargs);
		pcode("\n");
	}
	if(nargs.d_disp == AD_IMMED)
		pcode("\tcallf\t");
	else
#endif
		pcode("\tcalls\t");
	paddr(nargs);
	pcode(",");
	for(i = 1; i < disp_level;i++)
		pcode("_%s", ProcName[i]);
	pcode("_%s\n", fname);
	if(!NullA(result)) {
		pcode("\tmovl\tr0,");
		paddr(result);
		pcode("\n");
	}
	endaddr();
}

/*
 : GenProc:
 : Declare the process name.
 : Provide a label for the mask-words (used registers + size of local data).
 */
GenProc(hv) {
	register struct hashent *hp = &Hash[hv];
	int label, i;
	char *name;

/*	if(DispLevel == 1)
		pcode("\t.globl\t_%s\n", ProcName[1]); */
	pcode("\t.globl\t");
	for(i = 1; i <= DispLevel; i++)
		pcode("_%s", ProcName[i]);
	pcode("\n");
	for(i = 1; i <= DispLevel; i++)
		pcode("_%s", ProcName[i]);
	pcode(":\n");
	name = hp->h_name;
	hp->h_decl->d_masklabel = label = NewLabel();	
	GenStartProc(label);
}

/*
 : GenStartProc:
 : Generate the code at beginning of each function:
 : 1. mask word for used registers.
 : 2. decrement the stack-pointer by the size of local data.
 : 3. generate new display, while saving the old one.
 */
GenStartProc(masklabel)
{
	Label	l, l1;

	pcode("\t.word\tLM%d\n", masklabel);
#ifndef NOGROW
	if(stack_reserve) {
		pcode("\tsubl3\t_StackBase,sp,r0\n");
		pcode("\tsubl2\t_StackReserve,r0\n");
		pcode("\tcmpl\tr0,$LF%d\n", masklabel);
		pcode("\tjgeq\tL%d\n", l = NewLabel());
		pcode("\tpushl\tap\n\tpushl\t$LF%d\n\tpushal\tL%d\n", masklabel,
			l1 = NewLabel());
		pcode("\tcalls\t$3,_StackExpand\n\tret\n");
		GenLabel(l1);
		pcode("\t.word\t0x0\n");
		GenLabel(l);
	}
#endif
#ifdef vax
	pcode("\tsubl2\t$LF%d,sp\n", masklabel);
#else tahoe
	pcode("\tsubl3\t$LF%d,fp,sp\n", masklabel);
#endif
	SaveDisp();
}

/*
 : GenEndProc:
 : Generate the code at the end of each function:
 : 1. give (the now known) value to the mask-word and the local data size
 :    word.
 : 2. restore the previous display.
 : 3. generate a 'return from function' instruction.
 */
GenEndProc(masklabel)
{

	CountFlush();
	RestoreDisp();
	pcode("\t.set\tLM%d,0x%x\n", masklabel, MaxTemp);
	pcode("\t.set\tLF%d,%d\n", masklabel, Sp);
#ifdef vax
	pcode("\tret\n");
#else tahoe
	pcode("\tret#2\n");
#endif
}

/* GenLabel: Generate the machines label computed from 'l'. */
GenLabel(l)
	Label	l;
{
	CountFlush();
	pcode("L%d:\n", l);
}

/*
 : GenJmp:
 : Produce a jump instruction (conditional or not according to 'op').
 */
GenJmp(op, l)
	Label	l;
{

	CountFlush();
	pcode("\t%s\tL%d\n", Inst(op), l);
}

GenCmp(op, a1, a2, a)
	Op	op;
	addr	a1, a2, a;
{

	Label	false_l, true_l;
	int	byte = 0;

	/* cmpl	a1, a2 */
	if(IsByte(a1) && IsByte(a2))
		byte = 1;
	a1 = gaddr(a1, byte);
	a2 = gaddr(a2, byte);
	pcode("\tcmp%c\t", PBYTE(byte));
	paddr(a1); pcode(",");
	paddr(a2); pcode("\n");
	endaddr();

	/* tst & jmp */
	false_l = NewLabel();
	pcode("\t%s\tL%d\n", Inst(op), false_l);

	/* true action  */
	GenAssignConst(1, a);
	/* skip over false action */
	true_l = NewLabel();
	GenJmp(JMP, true_l);
	/* false action */
	GenLabel(false_l);
	GenAssignConst(0, a);
	GenLabel(true_l);
	endaddr();
}

GenAssignConst(c, a)
	addr	a;
{

	pcode("\tmov%c\t$%d,", PBYTE(IsByte(a)), c);
	a = gaddr(a, 1); paddr(a); pcode("\n");
	endaddr();
}

GenTst(a)
	addr	a;
{
	int	byte;

	byte = IsByte(a);
	a = gaddr(a, byte);
	pcode("\ttst%c\t", PBYTE(byte));
	paddr(a); pcode("\n");
	endaddr();
}

/*
 * The display is pointed by r11, each display entry contains the pair (ap,
 : fp). so the offset for display N's ap is -N*4(r11), (the fp is -N*4+4(r11))
 */

SaveDisp() {
#ifdef vax
	register int i = DCONV((DispLevel + 1)) + INT_SIZE;
	pcode("\tmovq\t-%d(r11),-8(fp)\n", i);	/* ap */
/* 	pcode("\tmovl\t-%d(r11),-8(fp)\n", i);	/* fp */

	pcode("\tmovq\tap,-%d(r11)\n", i);
/* 	pcode("\tmovl\tfp,-%d(r11)\n", i); */
#else tahoe
	register int i = DCONV((DispLevel + 1));
	pcode("\tmovl\t-%d(r12),-56(fp)\n", i);
	pcode("\tmovl\tfp,-%d(r12)\n", i);
#endif
}

RestoreDisp() {

#ifdef vax
	register i = DCONV(DispLevel) + INT_SIZE;
	pcode("\tmovq\t-8(fp),-%d(r11)\n", i);	/* ap */
/* 	pcode("\tmovl\t-12(fp),-%d(r11)\n", i);	/* fp */
#else tahoe
	register i = DCONV(DispLevel);
	pcode("\tmovl\t-56(fp),-%d(r12)\n", i);
#endif
}

static	addr extra;
long	regs;

newreg() {
	register int i = 0;
	if(regs & 1)
		if(regs & 2) {
			extra = NewTemp();
			if(extra.d_disp != AD_REGISTER)
				panic("can't get register");
			i = extra.d_offset;
			regs := 4;
		} else
			i = 1;
	regs := reg(i);
	return i;
}

endaddr() {
	if(regs & 4)
		FreeTmp(extra);
	regs = 0;
}

/*
 : Generate stack-push code.
 : If type == 1 push address, otherwise push value.
 : When a byte value is pushed, it should be converted to a long.
 */
GenPush(type, a)
	addr a;
{
	int	 byte;

	a = gaddr(a, type);
	byte = IsByte(a);
	pcode("\tpush%s%c\t", (type == 0) ? "" : "a", PBYTE(byte));
	paddr(a);
	pcode("\n");
	endaddr();
}

/* GenPushr:
 : Save the registers in 'mask' on the stack.
 */
GenPushr(mask)
{
#ifdef vax
	pcode("\tpushr\t$%d\n", mask);
#else tahoe
	register i, c;
	for(i = 0, c = 0; i < 16; i++)
		if(mask&(1<<i))
			c++;
	pcode("\
	pushl	$0\n\
	storer	$0x%x,(sp)\n\
	moval	(sp),r0\n\
	subl2	$%d,r0\n\
	movl	r0,sp\n",
	mask,	(c-1)*4);
#endif
}

addr
GenSave(a)
	addr a;
{
	addr na;

	if(a.d_disp != AD_IMMED && a.d_disp != AD_REGISTER)
		return a;
	na.d_disp = DispLevel;
	na.d_offset = AllocStack(INT_SIZE);
	na.d_flags = AF_FP;
	pcode("\tmovl\t");
	paddrs(2, a, na);
	return na;
}

GenPop(n) {
	if(n) {
		Sp -= INT_SIZE*n;
		pcode("\taddl2\t$%d,sp\n", n*INT_SIZE);
	}
}

addr
Register(rn)
{
	addr	a;
	
	a = NullAddr;
	a.d_disp = AD_REGISTER;
	a.d_offset = rn;
	return a;
}

addr
Immediate(v)
{
	addr	a;
	
	a = NullAddr;
	a.d_disp = AD_IMMED;
	a.d_offset = v;
	return a;
}


addr
RegAddr(a, r)
	addr	a, r;
{
/* Add to 'a' the register subscript in 'r'. */

	if(r.d_disp != AD_REGISTER)
		panic("RegAddr should be given a register");
	a.d_reg = r.d_offset;
	a.d_flags := AF_SUB;
	return a;
}

GenPushLabel(l)
	Label	l;
{
	pcode("\tpushl\t$L%d\n", l);
}

GenInc(a)
	addr	a;
{

	pcode("\tincl\t");
	paddr(a);
	pcode("\n");
}

GenGoto(a)
	addr a;
{
	CountFlush();
	a = gaddr(a, 0);
	pcode("\tjmp\t");
	if(a.d_disp == AD_REGISTER)
		pcode("*(r%d)", a.d_offset);
	else
		paddr(a);
	pcode("\n");
}


GenIndex(base, sub, res)
	addr	base, sub, res;
{
	register i = newreg();
	addr tmp;

	tmp.d_disp = AD_REGISTER;
	tmp.d_offset = i;
	tmp.d_flags = 0;
/*
 : ugh! This is ugly.
 : We want to use a compiler-register for the next TWO instructions.
 : We therefore resolve 'res' first, and so - even though compiler-registers
 : are freed after each instruction, it will NOT be used.
 */
	res = gaddr(res, 1);
	Gen(DontFree(MOVL), sub, NullAddr, tmp);
	tmp = RegAddr(base, tmp);
	if(IsByte(res))
		tmp.d_flags := AF_BYTE;
	Gen(MOVL, tmp, NullAddr, res);			/* this moves already
							 : the indexed
							 : address. */
}

addr
GenIntSubscript(base, sub)
	addr	base, sub;
{
	addr res;

	if(sub.d_disp == AD_IMMED && (base.d_flags & AF_PTR) == 0) {
		res = base;
		if(res.d_disp != AD_GLOBAL) {
			res.d_offset -= sub.d_offset*INT_SIZE;
/*			printf("res.d_offset = %d sub.d_offset=%d\n",res.d_offset, sub.d_offset); *
/
		}
		else {
			char buf[64];
			sprintf(buf, "%s+%d",	res.d_offset,
						sub.d_offset*INT_SIZE);
			res.d_offset = (int) strsave(buf);
		}
		return res;
	}
	if(sub.d_disp == AD_REGISTER)
		res = RegAddr(base, sub);
	else {
		res = NewTemp();
		if(res.d_disp == AD_REGISTER) {
			Gen(DontFree(MOVL), sub, NullAddr, res);
			res = RegAddr(base,  res);
		}
		else
			GenIndex(base, sub, res);
	}
	return res;
}

addr
GenByteSubscript(base, sub)
	addr	base, sub;
{
	addr res;

	if(sub.d_disp == AD_IMMED && (base.d_flags & AF_PTR) == 0) {
		res = base;
		if(res.d_disp != AD_GLOBAL)
			res.d_offset -= sub.d_offset;
		else {
			char buf[64];
			sprintf(buf, "%s+%d", res.d_offset, sub.d_offset);
			res.d_offset = (int) strsave(buf);
		}
		res.d_flags := AF_BYTE;
		return res;
	}
	if(sub.d_disp == AD_REGISTER)
		res = RegAddr(base, sub);
	else {
		res = NewTemp();
		if(res.d_disp == AD_REGISTER) {
			Gen(DontFree(MOVL), sub, NullAddr, res);
			res = RegAddr(base,  res);
		}
		else
			GenIndex(base, sub, res);
	}
	res.d_flags := AF_BYTE;
	return res;
}

addr
GenSliceAddr(base, off, isbyte)
	addr	base, off;
{
	if(isbyte)
		return GenByteSubscript(base, off);
	return GenIntSubscript(base, off);
}

GenDef(name)
	addr_t	name;
{
	Buffer obuf = ToBuf(RO_DataBuf);
	pcode("_%s:\n", name);
	ToBuf(obuf);
}

char *
GenDefLabel(l)
	Label	l;
{
	static char lbuf[10];
	Buffer	obuf = ToBuf(RO_DataBuf);
	
	sprintf(lbuf, "L%d", l);
	pcode("L%d:\n", l);
	ToBuf(obuf);

	return lbuf;
}

GenDefEl(i, isbyte)
{
	Buffer obuf = ToBuf(RO_DataBuf);
	if (isbyte)
		pcode("\t.byte\t%d\n", i);
	else
		pcode("\t.long\t%d\n", i);
	ToBuf(obuf);
}

GenDefStr(s)
	char	*s;	/* this is an occam string, i.e. first byte saves
			 : the length */
{
	Buffer obuf = ToBuf(RO_DataBuf);

	pcode("\t.asciz\t\"");
	if (s[0] != strlen(s) && Isprint(s[0]))
		pcode("%c", s[0]);
	else
		pcode("\\%03o", s[0]);
	for (s++; *s != '\0'; s++)
		if (Isprint(*s))
			pcode("%c", *s);
		else
			pcode("\\%03o", *s);
	pcode("\"\n");
			
	ToBuf(obuf);
}

GenAob(from, to, label)
	addr	from, to;
	Label	label;
{
/*
 : Add one to 'from', compare to 'to', if greater than or equal jump to label
 */
	Label	l;

	l = NewLabel();
	from = gaddr(from, 0);
	to = gaddr(to, 0);
	pcode("\taoblss\t");
	paddr(to); pcode(", ");
	paddr(from);
	pcode(", L%d\n", l);
	GenJmp(JMP, label);
	GenLabel(l);
}

char *
GenLabelName(l)
	Label	l;
{
	static char lbuf[10];

	return sprintf(lbuf, "L%d", l);
}

GenBcopy(from, to, count)
	addr	from, to, count;
{
	long	sm;
	extern	RegistersUsed;

	from = gaddr(from, 1);
	to = gaddr(to, 1);
	count = gaddr(count, 0);

#ifdef vax
	endaddr();

	sm = RegistersUsed&(reg(2):reg(3):reg(4):reg(5));
	if(sm)
		pcode("\tpushr\t$0x%x\n", sm);

	pcode("\tmovc3\t");
	paddrs(3, count, from, to);

	if(sm)
		pcode("\tpopr\t$0x%x\n", sm);
#else tahoe
	sm = RegistersUsed & reg(2);
	if(sm)
		pcode("\tpushl\tr2\n");
#define	MOV(instr, f, rx)	pcode("	instr	"), paddr(f), pcode(",r%d\n", rx)
	MOV(moval, from, 0);
	MOV(moval, to, 1);
	MOV(movl, count, 2);
#undef MOV
	pcode("\tmovblk\n");
	if(sm)
		pcode("\tmovl\t(sp)+,r2\n");
#endif
}

Isprint(c) {
	return isprint(c) && c != '\"';
}

static Counter, CounterResolution = 100;
/* Increment program time counter */
Count() {
	if(!counting)
		return;
	if(++Counter >= CounterResolution)
		CountFlush();
}

CountFlush() {
	if(!counting :: Counter == 0)
		return;
	if(Counter == 1) {
		GenInc(TimeCounter);
		GenInc(GlobalCounter);
	} else {
		Gen(PLUS_TOK, Immediate(Counter), TimeCounter, TimeCounter);
		Gen(PLUS_TOK, Immediate(Counter), GlobalCounter, GlobalCounter);
	}
	Counter = 0;
}

GenCallSelect(n)
	addr	n;
{
	Label	l, loop, lout;

	GenFuncCall(n, "chselect", 0, NullAddr);
#ifdef vax
	pcode("\tmovl\tsp,r1\n");	/* save sp */
	pcode("\tmoval\t4(r0),sp\n");	/* set sp */
	pcode("\tpopr\t(r0)\n");	/* pop saved registers */
	pcode("\tmovl\t(sp)+,r0\n");
	GenLabel(loop = NewLabel());
	pcode("\tsobgeq\tr0,L%d\n", l = NewLabel());
	pcode("\tjbr\tL%d\n", lout = NewLabel());
	GenLabel(l);
	pcode("\tmovl\t4(sp),*(sp)\n");	/* pop one pair */
	pcode("\taddl2\t$8,sp\n");	/* increment sp */
	GenJmp(JMP, loop);
	GenLabel(lout);

	pcode("\tmovl\t(sp)+,r0\n");
	pcode("\tmovl\tr1,sp\n");
	pcode("\tjmp\t(r0)\n");
#else tahoe
/*	pcode("	moval	4(r0),r0\n");	/* get the beginning of the saved data
					 : area (nregister) */
/*	pcode("	addl2	$8,r0\n"); */
	pcode("	movl	(r0),r1\n");	/* skip saved registers area */
	pcode("	moval	(r0)[r1],r1\n");
	pcode("	addl2	$4,r1\n");
	pcode("	movl	4(r0),r0\n");
	pcode("	loadr	r0,(r1)\n"); /* pop registers */
	pcode("	addl2	$4,r1\n");
	pcode("	movl	(r1),r0\n");	/* get count of pairs */
	pcode("	addl2	$4, r1\n");	/* skip registers */

	GenLabel(loop = NewLabel());	/* address fetching loop */
	pcode("	tstl	r0\n");
	pcode("	beql	L%d\n", lout = NewLabel());
	pcode("	movl	4(r1),*(r1)\n"); /* pop next pair */
	pcode("	addl2	$8,r1\n");
	pcode("	decl	r0\n");
	pcode("	jbr	L%d\n", loop);
	GenLabel(lout);
/*	pcode("	movl	(sp)+,_ANY\n");	 /* increment sp by 4 */
	pcode("	jmp	*(r1)\n");
#endif
}
SHAR_EOF
fi # end of overwriting check
if test -f 'hash.c'
then
	echo shar: will not over-write existing file "'hash.c'"
else
cat << \SHAR_EOF > 'hash.c'
static char	rcsid[] = "$Header: hash.c,v 2.1 86/10/30 16:07:32 gil Exp $";

/*
 * $Log:	hash.c,v $
 * Revision 2.1  86/10/30  16:07:32  gil
 * This version was submitted for the project. It is free of all major bugs.
 *
 * Revision 1.1  86/01/04  14:20:37  gil
 * Initial revision
 *
 */

/*
 : Hash functions-
 : Use two functions :
 : The first is straight forward. In case of collision, the second function
 : is used. The second function uses the first function's value as skip-value,
 : to obtain uniform distribution.
 */
#include <stdio.h>
#include "hash.h"

#define ALMOST_MAXINT	21474836

char	*strsave();

hash(str)
char *str;
{
/*
 : Sum ascii values (minus '0') of the string characters, multiplied
 : by 13. the the value modulo HASHSZ.
 */
	register val = 0;
	register char *s = str;

	while(*s) {
		val += (*s++ - '0') * 13;
		if (val > ALMOST_MAXINT)
			val >>= 4;
	}
	val %= HASHSZ;
	if(Hash[val].h_name && strcmp(str, Hash[val].h_name) != 0)
			 /* collision */
			return hash2(str, val);
	return val;
}

hash2(str, oldval)
char *str;
int oldval;
{

/*
 : Calculate a "decimal" value of 'str', and take it modulo 'oldval'
 : which is known to be < HASHSZ.
 : in case of collision - start skipping, with 'oldval' skip-size.
 */
	register char *s = str, c;
	register val = 0;
	register i;

	while(c = *s++) {
		val *= 10;
		val += c - '0';
		if (val > ALMOST_MAXINT)
			val = oldval;
	}
	val %= oldval;
	i = val;
	while(Hash[val].h_name && strcmp(Hash[val].h_name, str))  {
		val += oldval; val %= HASHSZ;
		if(i == val)	/* hash table is full */
			return -1;
	}
	return val;
}
SHAR_EOF
fi # end of overwriting check
if test -f 'init.c'
then
	echo shar: will not over-write existing file "'init.c'"
else
cat << \SHAR_EOF > 'init.c'
static char	rcsid[] = "$Header: init.c,v 2.3 86/11/03 13:49:54 gil Exp $";

/*
 * $Log:	init.c,v $
 * Revision 2.3  86/11/03  13:49:54  gil
 * support for VMS and special INPUT/OUTPUT channels are 'ifdef'ed.
 *
 * Revision 2.2  86/11/01  12:21:01  gil
 *
 *
 * Revision 2.1  86/10/30  16:07:34  gil
 * This version was submitted for the project. It is free of all major bugs.
 *
 * Revision 1.1  86/01/04  14:20:38  gil
 * Initial revision
 *
 */

#include <stdio.h>
#include "all.h"

struct	Init {
	char		*name;
	DType	type;
} InitTab[]= {
	"TIME", DCHAN,
	"INPUT", DCHAN,
	"OUTPUT", DCHAN,
	"ANY", DINT,
	NULL, UNDEF
};

InitSymb() {
	register struct	Init *ip;
	register hv;

	for(ip = InitTab; ip->name != NULL; ip++) {
		
		hv = hash(ip->name);
		insert(hv, ip->name);
		if (ip == InitTab) {	/* first is time channel */
			DeclTimeChan(hv);
			continue;
		}
		switch (Type(ip->type)) {
			case DCHAN:
				DeclChan(hv, Zero());
				break;
			case DINT:
				DeclVar(hv);
				break;
			default:
				panic("Bad initializer");
				/*NOTREACHED*/
		}
	}
}
SHAR_EOF
fi # end of overwriting check
if test -f 'io.c'
then
	echo shar: will not over-write existing file "'io.c'"
else
cat << \SHAR_EOF > 'io.c'
static char	*rcsid = "$Header: io.c,v 2.2 86/11/01 12:21:10 gil Exp $";

#include <stdio.h>
#include "all.h"

#define IOVLEN 2

#define bit(i) (1 << (i))

static int	IoNaddr = 0;	/* no. of i/o requests in list. */
static Buffer	SavedBuf;
static int	IoNsave;	/* no. of alt saved data */

Io(chan, rw)
	Expr	chan;
{
	if(Etype(chan) != DCHAN) {
		Error(ERROR, CHANNEL_REQ);
		return;
	}
	(void) GenPush(0, chan.e_place);
	GenFuncCall(Immediate((IoNaddr*IOVLEN)+3),
		    rw ? "chwrite" : "chread", 1,
		    NullAddr);
}

Wait(e)
	Expr	e;
{
	if(!IsVar(e) :: IsReg(e.e_place))
		GenPush(1, GenSave(Addr(e)));
	else
		GenPush(1, e.e_place);
	GenPush(0, Immediate(INT_SIZE));
	IoNaddr++;
}
	
Expr
TimeChan(e)
	Expr	e;
{
	int	hv;

	hv = hash("TIME");
	return(Identifier(hv));
}

/* StartPushArgs:
 : Start pushing the list of variables in this io-request;
 : Use "small" reversible buffers for the arguments (same as process
 : arguments, see proc.c).
 */
StartPushArgs() {
	SavedBuf = CurBuf;
	Sbuf();
	IoNaddr = 0;
}

/* EndPushArgs:
 : End pushing the arguments for this io request: reverse their order and
 : push their count, and the flag 'flag'.
 */
EndPushArgs(flag) {
	RevBuf(IoNaddr, SavedBuf);
	(void) GenPush(0, Immediate(IoNaddr));
	(void) GenPush(0, Immediate(flag));
}

	
/* PushOutputArg:
 : Push address of output-argument; save on the stack and push the address
 : in case of constant.
 */
PushOutputArg(e)
	Expr	e;
{

	if(IsSlice(e)) {
		(void) GenPush(1, e.e_place);
		(void) GenPush(0, e.e_slen);
	} else {
		if(!IsVar(e) :: IsReg(e.e_place))
			GenPush(1, GenSave(Addr(e)));
		else
			GenPush(1, e.e_place);
		GenPush(0, Immediate(INT_SIZE));
	}
	IoNaddr++;
}

/* PushInputArg:
 : Push address of input-argument; 'e' must contain an addressable variable
 : or a slice.
 */
PushInputArg(e)
	Expr	e;
{

	if(IsSlice(e)) {
		GenPush(1, e.e_place);
		GenPush(0, e.e_slen);
	} else {
		GenPush(1, Lvalue(e));
		GenPush(0, Immediate(INT_SIZE));
	}
	IoNaddr++;
}

AllocChan(ad, siz)
	addr ad;
	addr	siz;
{
	GenPush(0, siz);
	GenFuncCall(Immediate(1), "chopen", 1, ad);
}

AllocChanTable(d, siz)
	struct decl	*d;
	addr		siz;
{
	GenPush(0, Immediate(d->d_nel));
	GenPush(0, siz);
	GenPush(1, d->d_addr);
	GenFuncCall(Immediate(3), "chtabopen", 1, NullAddr);
}

DisposeChanTab(d)
	struct decl	*d;
{
	GenPush(0, Immediate(d->d_nel));
	GenPush(1, d->d_addr);
	GenFuncCall(Immediate(2), "chtabclose", 1, NullAddr);
}

DisposeChan(ad)
	addr ad;
{
	GenPush(0, ad);
	GenFuncCall(Immediate(1), "chclose", 1, NullAddr);
}

Alt	CurA;

struct alt_buf	{
	Alt		cur;
	struct alt_buf	*next;
} alt_stack;

StartAltCmd() {

	Label	l;
	struct alt_buf *this = (struct alt_buf *)
				malloc(sizeof (struct alt_buf));

/* - push this alt process (structure) on the alt_stack. */
	this->next = alt_stack.next;
	alt_stack.next = this;

/* - allocate new paramters' counters. */
	CurA.a_argcnt = NewCounter();
	CurA.a_pushcnt = NewCounter();

/* - allocate new buffers for nice flow. flow buf is used hence. */
	CurA.a_flowbuf = CurBuf;
	CurA.a_textbuf = NewBuf();	/* buffer for the processes' code */
	ToBuf(CurA.a_flowbuf);
/* - allocate a label for end of alt process. */
	CurA.a_out = NewLabel();
/* - initialize */
	CurA.a_nsave = 0;
}

EndAltCmd() {

	struct alt_buf	*this;

	this = alt_stack.next;

/* - AltSelect will handle the call and return of the selecting procedure. */
	AltSelect();

/* - concatanate the flow & text buffers in their order. */
	MergeBufs(CurA.a_flowbuf, CurA.a_textbuf);
	/* now we after all the pushes */
	
/* - produce the ending label. */
	GenLabel(CurA.a_out);

/* - Free the alternate process' data (counters, etc.). */
/* - Pop the alternate process from the stack. */
	alt_stack.next = this->next;
	free(this);
}

/* StartAlt:
 : Start a new nested alt;
 : add the new alt counter 'cnt' to the list of saved data.
 */
StartAlt(cnt)
	addr	cnt;
{
	CurA.a_save[CurA.a_nsave++] = cnt;
}

EndAlt() {
	CurA.a_nsave--;
}

/* StartAltIo:
 : Push all the ephemeral data of this process;
 : The select process will return a pointer to a record, pushed here,
 : containing:
 :	record length
 :	register mask
 :	saved registers
 :	count of pairs
 :	list of pairs (saved_value, address)
 :	process-label
 */
StartAltIo(proc_l)
	Label	proc_l;
{
 	register i;
	int	mask;
	int	Npair;
	int	nreg;
	

/* - push the alt-process saved data record */
	GenPushLabel(proc_l);
	Npair = 0;
	IoNsave = 0;
	for (i = 0; i < CurA.a_nsave; i++)
		if (!IsReg(CurA.a_save[i])) {
			GenPush(0, CurA.a_save[i]); /* the current value */
			GenPush(1, CurA.a_save[i]); /* the address */
			Npair++;
		}
	IoNsave = 2 * Npair;	
	GenPush(0, Immediate(Npair));
	mask = 0;
	for(i = 0, nreg = 0; i < CurA.a_nsave; i++)
		if (IsReg(CurA.a_save[i])) {
			mask := bit(CurA.a_save[i].d_offset);
			IoNsave++;
			nreg++;
		}
	if (mask)
		GenPushr(mask);
	GenPush(0, Immediate(mask));
#ifdef tahoe
	GenPush(0, Immediate(nreg));
	IoNsave++;
#endif
	IoNsave += 3;	/* the mask + the pair count + proc label */

}

/* EndAltIo:
 : End an io request in an alternate process:
 : the global request and argument counters are incremented.
 : The last argument are pushed.
 */
EndAltIo(chan)
	Expr	chan;
{

	register	i;
	int	mask;
	register	cnt;	/* count of saved data */

/* - increment the counters */
/*	IncArgCounter(CurA.a_pushcnt, IoNaddr * 2 + 3 + IoNsave); */
	IncArgCounter(CurA.a_pushcnt, IoNaddr * 2 + 4 + IoNsave);
	GenInc(CurA.a_argcnt);

/* - push the the saved data size & the channel id */
	GenPush(0, Immediate(IoNsave));
	GenPush(0, Addr(chan));
}

AltSelect()
{
	addr	a;

/* - push the last parameters (arg count, etc.) on the stack. */
/* - generate the call to the alternate-process handler ('chselect'). */
	GenInc(CurA.a_pushcnt); /* another argument: the request count */
	GenPush(0, CurA.a_argcnt);
	GenCallSelect(CurA.a_pushcnt);

/* - 'GenCallSelect' already generates the code for starting the selected
 *   process (restore its saved data and jump to its beginning). */

}

EndReplAlt(out, r)
	Quadl	out;
	Repl	r;
{
	EndAlt();
	BackPatch(out);
	GenJmp(JMP, r.r_loop);
	FreeRepl(r);
}

/* StartGuardP:
 : Start a process following a guard;
 : The process' code will be put on a different buffer 'a_textbuf' for
 : nice flow. The alt's counters can be freed for the process
 */
StartGuardP(l)
	Label	l;
{
	(void) ToBuf(CurA.a_textbuf);
	GenLabel(l);
/* - free the alt counters. */
}

EndGuardP() {

	GenJmp(JMP, CurA.a_out);
	(void) ToBuf(CurA.a_flowbuf);
/* - recapture the alt counters. */
}

addr
NewCounter() {

	addr	cntr;

	cntr = NewTemp();
	GenAssignConst(0, cntr);
	return cntr;
}

IncArgCounter(cntr, count)
	addr	cntr;
{

	Gen(PLUS_TOK, cntr, Immediate(count), cntr);
}
SHAR_EOF
fi # end of overwriting check
if test -f 'lex.c'
then
	echo shar: will not over-write existing file "'lex.c'"
else
cat << \SHAR_EOF > 'lex.c'
static char	rcsid[] = "$Header: lex.c,v 2.1 86/10/30 16:07:38 gil Exp $";

/*
 * $Log:	lex.c,v $
 * Revision 2.1  86/10/30  16:07:38  gil
 * This version was submitted for the project. It is free of all major bugs.
 *
 * Revision 1.1  86/01/04  14:20:40  gil
 * Initial revision
 *
 */

#include <stdio.h>
#include <ctype.h>
#include "all.h"

char *malloc();
extern int yyleng;

stoi(str, val, rad)
register char *str;
int *val;
{

/*
 : Convert string to positive integer, and return the value in '*val';
 : Return -1 if overflow occured, 0 else.
 */
	register maxdivrad = MAXINT/rad; /* save in register for efficiency */
	register v=0;

#define VAL(c)	(isdigit(*str) ? *str - '0' : \
			(isupper(*str) ? *str - 'A' + 10 : *str - 'a' + 10))

	while(*str) {
		if(v > maxdivrad ::
		   (v == maxdivrad && (MAXINT - maxdivrad*rad) < VAL(*str)))
			return -1;/* overflow */
		v *= rad;
		v += VAL(*str);
		str++;
	}
	*val = v;
	return(0);
#undef VAL
}

char *
strval(s)
	char *s;
{
/* return a pointer to a saved & expanded string representing 's'.
 : doesn't alter 's'.
 */

	register char	*p;
	int	l;

	l = yyleng - 2;
	p = malloc(l+2);	/* +2 for: 1. null char
				 :         2. first byte saves the length. */
	strncpy(p+1, s+1, l);	/* don't save the wrapping '"'s. */
	l = expand(p+1);	/* expand NEVER makes the string longer. */
	*p = l;
	p[l+1] = '\0';
	return p;
}

charval(s)
	char	*s;
{
/* return the character value of the quoted char in 's'.
 : doesn't alter 's'.
 */

	char	buf[64];

	s[yyleng] = '\0';	/* PATCH */
	strcpy(buf, s+1);	/* first character is 'quote'. */
	expand(buf);	
	return(buf[0]);
}

expand(s)
	char	*s;
{

	register char	*p, *q;
	register	i;
	int		j;
	int		sum;

	for(p = q = s, i = 0; *p; p++, q++, i++) {

		switch(*p) {

		case '*':
			switch(*++p) {

			case 'c':
			case 'C':
				*q = '\r';
				break;
			case 'n':
			case 'N':
				*q = '\n';
				break;
			case 't':
			case 'T':
				*q = '\t';
				break;
			case 's':
			case 'S':
				*q = ' ';
				break;
			case '#':	/* hexadecimal specification of the char */
#define HEXVAL(c)	(isupper(c) ? c - 'A' + 10 : c - 'a' + 10)
				p++;
				sum = HEXVAL(*p);
				if (isxdigit(*++p)) {
					sum *= 16;
					sum += HEXVAL(*p);
				} else
					p--;
				*q = sum;
				break;
#undef HEXVAL
				
			default:
				if (*p != '\'' && *p != '"' && *p != '*')
					LexError(WARNING, NO_SPECIAL_MEANING);
				*q = *p;
			}
			break;

		case '\\':

			switch(*++p) {

			case 'n':
				*q = '\n';
				break;
			case 'r':
				*q = '\r';
				break;
			case 't':
				*q = '\t';
				break;
			case 'f':
				*q = '\f';
				break;
			case 'v':
				*q = '\013';
				break;
			case 'b':
				*q = '\b';
				break;
			default:
				if (*p >= '0' && *p <= '7') {

#define OCTVAL(c)	(c - '0')			
					sum = 0;
					j = 0;
					do {
						sum *= 8;
						sum += OCTVAL(*p);
						p++;
					} while(j++ < 3 && *p >= '0' && *p <= '7');
					p--;
					*q = sum;
#undef OCTVAL
				} else
					*q = *p;
				break;
			}
			break;

		default:
			*q = *p;
			break;

		}
	}
	return i;
}
SHAR_EOF
fi # end of overwriting check
if test -f 'print.c'
then
	echo shar: will not over-write existing file "'print.c'"
else
cat << \SHAR_EOF > 'print.c'
static char	*rcsid = "$Header: print.c,v 2.1 86/10/30 16:07:45 gil Exp $";

/*
 * $Log:	print.c,v $
 * Revision 2.1  86/10/30  16:07:45  gil
 * This version was submitted for the project. It is free of all major bugs.
 *
 * Revision 1.2  86/02/08  12:14:43  gil
 * bug-fixed.
 *
 * Revision 1.1  86/01/04  14:21:20  gil
 * Initial revision
 *
 * Revision 1.1  85/12/08  10:33:24  dalia
 * Initial revision
 *
 */

#include <stdio.h>
#define EXT
#include "error.h"
/*
 : Printout code-lines + error messages.
 : All words + error messages of one line are accomulated.
 : When end-of-line is reached printing is done.
 :
 : This also enables the enhanced error-handling routine to inspect the
 : whole line when error is encountered.(not implemented yet)
 */

/* routines for printing of the input text. */

#define LINSIZ		512

extern char	yytext[];
extern int	yyleng;
extern int	CurIndent;
extern int	lines;
extern listing;
extern FILE	*lsp;
extern char	*inf;

static char	buf[LINSIZ+1];
static int	highs = 0;
static int	slines = 1;

blanks(s, n)
	register char 	*s;
	register int	n;
{
	while(n-- > 0)
		*s++ = ' ';
}

printout() {

	if (!listing) {
		outerrs();
		return;
	}
	if (highs == 0)	{	/* beginning of line - print indentation */
		highs += 2 * CurIndent;
		blanks(buf, highs);
	}

	if (highs + yyleng > LINSIZ)
		panic("str_alloc: line too long");

	strncpy(&buf[highs], yytext, yyleng);
	highs += yyleng;
	if (lines > slines)
		outline();
}

outline() {
	if (!listing)
		goto out;
	fprintf(lsp, "%-4d ", slines);
	if (buf[highs-1] != '\n')
		buf[highs++] = '\n';
	buf[highs] = '\0';
	fputs(buf, lsp);
	slines = lines;
	highs = 0;	
out:
	outerrs();
}

/* routines for priting error messages */

#define	MAX_ERRORS	16	/* maximum errors per line! */

static struct error {
	int	e_ind;	/* index of error in error-messages table */
	int	e_col;	/* for lexical errors: position in line (to
			 : be pointed to). default is zero (no pointer). */
	int	e_arg[4];
} errs[MAX_ERRORS];
static int nerrs = 0;

Error(type, num, a1, a2, a3, a4) {
/* syntactical or semantical errors; no pointer. */

	err(num, a1, a2, a3, a4);
	errs[nerrs].e_col = 0;
	nerrs++;
}

LexError(type, num, offset) {
/* token errors; produce column pointer to 'offset' within current token. */
	err(type, num);
	errs[nerrs].e_col = highs + offset - 1;
	nerrs++;
}

err(num, a0, a1, a2, a3) {

	enum err_type type = Err_list[num].type;

	if (nerrs >= MAX_ERRORS-2) {
		errs[MAX_ERRORS-1].e_ind = TOO_MANY_ERRORS;
		errs[MAX_ERRORS-1].e_col = 0;
		return;
	}
	if (type == COMPILER_ERROR)
		panic(Err_list[num].str);

	errs[nerrs].e_ind = num;
	errs[nerrs].e_arg[0] = a0;
	errs[nerrs].e_arg[1] = a1;
	errs[nerrs].e_arg[2] = a2;
	errs[nerrs].e_arg[3] = a3;
}

outerrs() {
	register	i, j;
	char		temp[512];
	register	c;
	register struct error *ep;

	if (nerrs == 0)
		return;

	c = 0;
	for (i = 0; i < nerrs; i++) {
		ep = &errs[i];
		fprintf(stderr, "\"%s\", line %d: ", inf, lines-1);
		switch(Err_list[ep->e_ind].type) {

		case WARNING:
			temp[c++] = 'W';
			fprintf(stderr, "Warning - ");
			break;

		case RECOVER:
			temp[c++] = 'e';
			fprintf(stderr, "error - ");
			break;

		case ERROR:
			temp[c++] = 'E';
			fprintf(stderr, "Error - ");
			break;
		
		default:
			panic("outerrs: unknown error type");
		}

/* number of minus'es: e_col 	- column of error
 :		       -1	- the 'C' at the beginning
 :		       +7	- the '# n ' of the line printout.
 :		i.e: e_col + 6
 :		     ---------
 */
		if (ep->e_col != 0) {
			for (j = ep->e_col + 6; j > 0; j--)
				temp[c++] = '-';
			temp[c++] = '^';
			temp[c++] = '-';
		}
		temp[c++] = '\0';
		if (listing) {
			fprintf(lsp, "%s ", temp);
			fprintf(lsp, Err_list[ep->e_ind].str,
				ep->e_arg[0], ep->e_arg[1],
				ep->e_arg[2], ep->e_arg[3]);
			putc('\n', lsp);
		}
		fprintf(stderr, Err_list[ep->e_ind].str,
			ep->e_arg[0], ep->e_arg[1],
			ep->e_arg[2], ep->e_arg[3]);
		putc('\n', stderr);
	}
	nerrs = 0;
}

panic(s)
char *s;
{
	outline();
	fprintf(stderr, "\nCompiler error: %s\n", s);
	_cleanup();
	abort();
	exit(1);
}

FlushErrs() {
	if(nerrs > 0) {
		lines++;
		outline();
	}
}
SHAR_EOF
fi # end of overwriting check
if test -f 'main.c'
then
	echo shar: will not over-write existing file "'main.c'"
else
cat << \SHAR_EOF > 'main.c'
static char	rcsid[] = "$Header: main.c,v 2.1 86/10/30 16:07:40 gil Exp $";

/*
 * $Log:	main.c,v $
 * Revision 2.1  86/10/30  16:07:40  gil
 * This version was submitted for the project. It is free of all major bugs.
 *
 * Revision 1.1  86/01/04  14:20:41  gil
 * Initial revision
 *
 */

#include <stdio.h>

/* define EXT here for the variables to be allocated main. */
#define EXT

#include "all.h"

#define	USAGE fprintf(stderr, "Usage: ocp [-d] [ inf [ outf ] ]\n")
extern	lines;
char	*strcpy();
char	*inf = "<stdin>";
char	*outf = "<stdout>";
static FILE	*out;
int	listing = 0,		/* produce program listing */
	counting = 1;		/* generate code for commands counting */
extern	stack_reserve;		/* if >= 0 generate code for automatic stack
				 : growth */
FILE	*lsp;	/* listing file file-pointer */
FILE	*listfile();

main(ac, av)
	char **av;
{
	int	i;
	extern	yydebug;
	char	*c;


	av++; ac--;
	while(**av == '-') {
		c = *av;
		while(*++c) switch (*c) {
			case 'd':
				yydebug++;
				break;
			case 'L':
				listing++;
				break;
			case 'C':
				counting = 0;
				break;
			case 'T':
				stack_reserve = 0;
				break;
			default:
				USAGE;
				exit(1);
		}
		av++;
		ac--;
	}
	if(ac > 2) {
		USAGE;
		exit(1);
	}
	if(ac > 0) {
		inf = *av;
		if(freopen(inf, "r", stdin) == NULL) {
			fprintf(stderr, "Cannot read ");
			perror(inf);
			exit(1);
		}
		ac--; av++;
		if (listing)
			lsp = listfile(inf);
	} else if (listing)
		lsp = stdout;
	if(ac > 0) {
		outf = *av;
		if(freopen(outf, "w", stdout) == NULL) {
			fprintf(stderr, "Cannot write ");
			perror(outf);
			exit(1);
		}
		ac--; av++;
	}
/*
 : Insert two dummy blanks at the beginning of each line for easy
 : handling of indentation.
 : The problem is as follows:
 : The lexical analyser is supposed to give 'output' (tokens) even when no
 : input is present; this is the case when a line starting with no blanks is
 : encountered and 'LEFT_TOK' tokens are to be detected.
 : The easy way to deal with the above problem is to use two dummy blanks
 : at the beginning of each line (= one indent token), and to decrement the
 : indent level of each line by one. Thus, blanks will be encountered at EACH
 : new line, and the indentation offset can be calculated.
 : The first two blanks are pushed in main(), before the first call to yylex().
 */
	yyunput(' ');
	yyunput(' ');

	InitCode();
	ResetTmp();
	InitSymb();

	lines = 1;
	if (i = yyparse()) {
		putchar('\n');
		outline();
		fprintf(stderr, "\"%s\", line %d: Parse failed\n", inf, lines);
	} else {
		FlushErrs();
		EndCode();
		FlushAll();
	}
	exit(i);
}

char *
strsave(s)
char *s;
{
/* allocate memory for 's' and save it. return the saved string. */
	return strcpy(malloc(strlen(s)+1), s);
}

get_token() {
	int	i;

/*
 : Get_token : does some pre-processing before the token returned from
 : 'yylex' is passed on to the parser.
 :		????
 */
	i = yylex();
	if (i && i != LEFT_TOK && i != RIGHT_TOK)
		printout();
	return i;
}

FILE *
listfile(fname)
	char	*fname;
{
	register char	*p;
	char	*rindex();
	char	lstname[128];
	FILE	*fp;
	
	if ((p = rindex(fname, '.')) == NULL)
		goto lstdout;

	strncpy(lstname, fname, p-fname);
	strcpy(&lstname[p-fname], ".lst");
	if ((fp = fopen(lstname, "w")) == NULL) {
		perror(lstname);
		goto lstdout;
	}
	return fp;

lstdout:
	fprintf(stderr, "%s: listing is done on stdout\n", inf);
	return stdout;
}
SHAR_EOF
fi # end of overwriting check
if test -f 'newbuf.c'
then
	echo shar: will not over-write existing file "'newbuf.c'"
else
cat << \SHAR_EOF > 'newbuf.c'
static char	rcsid[] = "$Header: newbuf.c,v 2.1 86/10/30 16:07:42 gil Exp $";

/*
 * $Log:	newbuf.c,v $
 * Revision 2.1  86/10/30  16:07:42  gil
 * This version was submitted for the project. It is free of all major bugs.
 *
 * Revision 1.1  86/01/04  14:20:42  gil
 * Initial revision
 *
 */

#include <stdio.h>
#include "all.h"

#define codefd 1

#define NBUF 256
#define GROW_SIZE 512

Buffer	CurBuf;

extern char *malloc(), *realloc();
struct buf {
	int b_size;
	int b_used;
	char *b_data;
} bufs[NBUF], *cur = bufs;

Buffer highb = 0;

Buffer
ToBuf(i) {
	int	obuf = CurBuf;

	cur = &bufs[i];
	CurBuf = i;
	return obuf;
}

Buffer
NewBuf() {
	ToBuf(highb++);
	cur->b_used = cur->b_size = 0;
	return highb - 1;
}

pcode(fmt, a1, a2, a3, a4, a5, a6, a7, a8)
	char *fmt;
{
	char line[256];
	int l;

	sprintf(line, fmt, a1, a2, a3, a4, a5, a6, a7, a8);

	l = strlen(line);
	asize(l);
	bcopy(line, &((cur->b_data)[cur->b_used]), l);
	cur->b_used += l;
}

static
asize(l)
{
#define	round(s, to)	((s+to-1)&~(to-1))
	if(cur->b_used + l > cur->b_size) {
		cur->b_size = round(cur->b_used + l, GROW_SIZE);
		if(cur->b_data)
			cur->b_data = realloc(	cur->b_data, cur->b_size);
		else
			cur->b_data = malloc(cur->b_size);
	}
}


FlushB(i)
	Buffer	i;
{
	register struct buf *b = &bufs[i];
	write(codefd, b->b_data, b->b_used);
}

FlushAll() {
	int i;

	fflush(stdout);
	for(i = 0; i < highb; i++)
		if (NoMain && i == MainText)
			continue;
		else
			FlushB(i);
}

Buffer
Sbuf()
{
	return NewBuf();
}

RevBuf(n, old)
	unsigned	n;
	Buffer		old;
{
	int	i, sz;
	struct	buf *b = cur;

	if(n == 0)
		return;
	if(n > highb)
		panic("reverse too much");
	highb -= n;
	for(i = 0, sz = 0; i < n; i++, b--)
		sz += b->b_used;
	b = cur;
	cur = &bufs[old];
	asize(sz);
	sz = cur->b_used;
	for(i = 0; i < n; i++, b--) {
		bcopy(b->b_data, cur->b_data+sz, b->b_used);
		sz += b->b_used;
		free(b->b_data);
		b->b_data = NULL;
		b->b_size = b->b_used = 0;
	}
	cur->b_used = sz;
	CurBuf = old;
}

MergeBufs(b1, b2)
	Buffer	b1, b2;
{

	struct buf	*bp1, *bp2;

	bp1 = &bufs[b1];
	bp2 = &bufs[b2];

	asize(bp2->b_used);
	bcopy(bp2->b_data, &((bp1->b_data)[bp1->b_used]), bp2->b_used);
	bp1->b_used += bp2->b_used;
	bp2->b_used = 0;
}

SHAR_EOF
fi # end of overwriting check
if test -f 'occam.lex'
then
	echo shar: will not over-write existing file "'occam.lex'"
else
cat << \SHAR_EOF > 'occam.lex'
blnks		[\ \t]
alpha		[a-zA-Z]
digit		[0-9]
hexdigit	[0-9a-fA-F]
newline {blnks}*((#({blnks}.*)?):("--".*))?\n
%{
static	char *rcsid = "$Header: occam.lex,v 2.1 86/10/30 16:09:08 gil Exp $";
#include <ctype.h>
#include "all.h"

#define ret(token, type)	{\
				lastop = 0;\
				if(type == reserved :: type == noval)\
					return (yylval.Op = token);\
				else if(type == operator) {\
					lastop = 1;\
					return (yylval.Op = token);\
				}\
				else return (token);\
			}

#define ERRORVAL() { \
	yylval.v_intval = -1; \
	lastop = 0;\
	break;\
	}
char *strcpy(), *malloc();
static int	lastop = 0, newline = 0;
%}

%%
%{
/*
 : Deal with indentation.
 : Inserted at the beginning of yylex; this is done to
 : avoid using states, with is inefficient.
 */
 	if (newline) {
		newline = 0;
		strcpy(yytext, "\n");
		goto newl;
	}
	if (CurIndent < PrevIndent) {
		PrevIndent--;
		ret (LEFT_TOK, noval);
	}
	if (CurIndent > PrevIndent) {
		PrevIndent++;
		ret (RIGHT_TOK, noval);
	}
%}
%{ /* reserved words - defined first to be prior identifiers */
%}
%{ /* operators and special signs */
%}
"*"		{  ret (MULT_TOK, operator); }
"/"		{  ret (DIV_TOK, operator); }
"+"		{  ret (PLUS_TOK, operator); }
"-"		{  ret (MINUS_TOK, operator); }
"="		{  ret (EQ_TOK, noval); }
">"		{  ret (GT_TOK, operator); }
">="		{  ret (GE_TOK, operator); }
"<"		{  ret (LT_TOK, operator); }
"<="		{  ret (LE_TOK, operator); }
"<>"		{  ret (NEQ_TOK, operator); }
","		{  ret (COMA_TOK, operator); }
"&"		{  ret (COND_TOK, operator); }
"<<"		{  ret (LSHIFT_TOK, operator); }
">>"		{  ret (RSHIFT_TOK, operator); }
"><"		{  ret (XOR_TOK, operator); }
"/\\"		{  ret (AND_TOK, operator); }
"\\/"		{  ret (OR_TOK, operator); }
"["		{  ret (LBR_TOK, operator); }
"]"		{  ret (RBR_TOK, noval); }
"("		{  ret (LP_TOK, operator); }
")"		{  ret (RP_TOK, noval); }
"\\"		{  ret (MOD_TOK, operator); }
"!"		{  ret (FCHAN_TOK, operator); }
"?"		{  ret (INP_TOK, operator); }
";"		{  ret (SEMICOLON_TOK, operator); }
":="		{  ret (ASSIGN_TOK, operator); }
":"		{
			printout();
			break;
		}
{digit}+	{
		/* integer - allowing integer starting with 0 (e.g. 003). */
			if (stoi(yytext, &(yylval.v_intval), 10) < 0) {

				LexError(WARNING, INTEGER_OVERFLOW, 1);
				yylval.v_intval = 0;
			}
			ret (INTEGER, INT);
		}
#{hexdigit}+	{
		/* integer - allowing integer starting with 0 (e.g. 003). */
			if (stoi(yytext, &(yylval.v_intval), 16) < 0) {

				LexError(WARNING, INTEGER_OVERFLOW, 1);
				yylval.v_intval = 0;
			}
			ret (INTEGER, INT);
		}
'[^'\n]*((\*''):(':\n))	{
		/*
		 : Character constant;
		 : We define it generally for the error handling.
		 */
		if (yytext[yyleng-1] == '\n') {
			LexError(ERROR, NEWLINE_IN_CHAR_CONST, yyleng);
			yytext[yyleng-1] = '\'';
			newline++;
		}
		if (yyleng > 4 :: (yyleng == 4 && yytext[1] != '*'))
			LexError (WARNING, CHAR_CONST_TOO_LONG, 3);
		if (yyleng <= 2) {
			LexError (WARNING, EMPTY_CHAR_CONST, 1);
			yylval.v_charval = '\0';
			ret (CHARACTER, CHAR);
		}
		if (yyleng == 3 && yytext[1] == '*')
			LexError(WARNING, ESCAPE_CHAR, 2);
		yylval.v_charval = charval(yytext);
		ret (CHARACTER, CHAR);
	}
\"([^"\n]:(\*\"))*(\n:\")	{
				/*
				 : String constant;
				 : Newline included for error handling.
				 */
					extern char *strval();

					if (yytext[yyleng-1] == '\n') {
						LexError(
						  WARNING, UNFINISHED_STR,
							 yyleng);
						yytext[yyleng-1] = '"';
						newline++;
					}
					yylval.v_strval =
						strval(yytext);
						/* including the quotes */
					ret (STRING, STR);
				}
{alpha}({alpha}:{digit}:".")*	{
		/* identifiers */
			register i;
			int	type;

			if((i = Reserved(yytext, &type)) > 0)
				ret(i, type);
			if((yylval.v_hashval = hash(yytext, 1)) < 0)
				LexError(COMPILER_ERROR, HASH_FULL, 1);
			if(Hash[yylval.v_hashval].h_name == NULL)
				insert(yylval.v_hashval, yytext);
			ret (ID_TOK, HASH);
		}
^{newline}	{
			lines++;
			printout();
			yyunput(' '), yyunput(' ');
			break;
		}
{newline}	{
			/* newline token - includes comemnts and blanks at
			 : end of line. */
		    newl:
			lines++;
			if(lastop) {
				printout();
				break;
			}
			yyunput(' ');
			yyunput(' ');	/* again - dummy blanks. */
			ret (NEWLINE, noval);
		}
^{blnks}*	{
			/*
			 : Blanks at beginning of line are operators.
			 : Calculate the indentation offset.
			 */
			register i = 0;
			register char *s = yytext;

			if(lastop) {
				lines--;
				printout();
				lines++;
				lastop = 0;
				break;
			}
			while(*s) {
				/* Calculate tab's shift */
				if(*s == '\t')
					i = ((i-2) / TABSZ + 1) * TABSZ + 2;
				else
					i++;
				s++;
			}
			if(i & 01) {
				   LexError(WARNING, ODD_NO_OF_BLANKS, i);
				   i++;/* round up */
			}
			CurIndent = i/2 - 1;	/* indent size is 2 blanks */
			if (CurIndent -1 > PrevIndent) {
				LexError(WARNING, EXTRA_INDENT, 2);
				PrevIndent = CurIndent - 1; /* shift it all to
							     : the right. */
			}
			return yylex();
		}
{blnks}+	{	printout();	 /* ignore blanks within the line */ }
.		{
			/* anything else - error !!! */
			if (!isalpha(yytext[0]) && !isdigit(yytext[0]))
				LexError(ERROR, ILLEGAL_CHAR, 1);
			else
				LexError(COMPILER_ERROR, LEX_INTERNAL_ERROR, 1);
			ERRORVAL();
		}
%%
SHAR_EOF
fi # end of overwriting check
if test -f 'par.c'
then
	echo shar: will not over-write existing file "'par.c'"
else
cat << \SHAR_EOF > 'par.c'
static char	rcsid[] = "$Header: par.c,v 2.1 86/10/30 16:07:44 gil Exp $";

/*
 * $Log:	par.c,v $
 * Revision 2.1  86/10/30  16:07:44  gil
 * This version was submitted for the project. It is free of all major bugs.
 *
 * Revision 1.1  86/01/04  14:20:44  gil
 * Initial revision
 *
 */

#include <stdio.h>
#include "all.h"

Quadl
NewProcess(ol)
	Quadl	ol;
{
	Label l;

	l = NewLabel();
	GenLabel(l);
	return AddList(ol, l);
}

EndProcess() {
	GenFuncCall(Immediate(0), "endproc", 1, NullAddr);
}

Par(l, ql)
	Quadl	ql;
	Label	l;
{
	register i = 0;

	GenLabel(l);
	for(i = 0; i < ql.q_nquads; i++) {
		GenPushLabel(ql.q_quads[i]);
		GenFuncCall(Immediate(1), "newproc", 1, NullAddr);
	}
	GenFuncCall(Immediate(0), "waitall", 1, NullAddr);
}
SHAR_EOF
fi # end of overwriting check
if test -f 'parse.y'
then
	echo shar: will not over-write existing file "'parse.y'"
else
cat << \SHAR_EOF > 'parse.y'
%token
	AFTER          FALSE          LT_TOK         RIGHT_TOK
	ALT            FCHAN_TOK      MINUS_TOK      RP_TOK
	AND            FOR            MOD_TOK        RSHIFT_TOK
	AND_TOK        GE_TOK         MULT_TOK       SEMICOLON_TOK
	ASSIGN_TOK     GT_TOK         NEQ_TOK        SEQ
	BYTE           ID_TOK         NEWLINE        SKIP
	CHAN           IF             NOT            STRING
	CHARACTER      INP_TOK        NOW            TABLE
	COMA_TOK       INTEGER        OR             TRUE
	COND_TOK       LBR_TOK        OR_TOK         VALUE
	DEF            LEFT_TOK       PAR            VAR
	DIV_TOK        LE_TOK         PLUS_TOK       WAIT
	EQ_TOK         LP_TOK         PROC           WHILE
	EXTERN         LSHIFT_TOK     RBR_TOK        XOR_TOK
	AT             QUE
/*
 : Tokens precedence and assoctive list
 */
%left	SEMICOLON_TOK COMA_TOK
%left	OR
%left	AND
%nonassoc EQ_TOK GT_TOK GE_TOK LT_TOK LE_TOK NEQ_TOK AFTER
%left	OR_TOK XOR_TOK
%left	AND_TOK
%left 	LSHIFT_TOK RSHIFT_TOK
%left	PLUS_TOK MINUS_TOK
%left	MULT_TOK DIV_TOK MOD_TOK
%nonassoc NOT
%{
#include <stdio.h>
#include "all.h"
#define yylex get_token

#define EMPTY		0
#define NONEMPTY	1
%}
%union {
	Expr	Expr;
	Decl	Decl;
	int	Hv;
	Op	Op;
	Lval	Lval;
	Args	Args;
	Quadl	Quadl;
	Label	Label;
	Cond	Cond;
	Guard	Guard;
	Repl	Repl;
	DType	DType;
}
%type	<Op>	SEMICOLON_TOK COMA_TOK OR AND EQ_TOK GT_TOK
		GE_TOK LT_TOK LE_TOK NEQ_TOK OR_TOK XOR_TOK
		AND_TOK LSHIFT_TOK RSHIFT_TOK PLUS_TOK MINUS_TOK
		MULT_TOK DIV_TOK NOT VAR CHAN VALUE MOD_TOK AFTER
%type	<Expr>	oexpression expression expr element const_el variable
		cexpression input output
%type	<Lval>	INTEGER TRUE FALSE ID_TOK CHARACTER STRING
%type	<Args>	opt_params params
%type	<Quadl>	conditional parallel_process guard_process guard_process_list
		alt_construct
%type	<Cond>	cond_list
%type	<Guard>	guard
%type	<Hv>	id_tok decl_list table_init table proc_call_w_params
%type	<Repl>	replicator
%type	<DType>	param
%%
prog		:	{ $<Hv>$ = ++ProcCount[DispLevel]; }
			main_process
			{ FreeProc($<Hv>1); }
		;

main_process	:	decl_list
			{	NoMain = 1; }
		:	decl_list statement
		;

process		:	{ $<Hv>$ = ++ProcCount[DispLevel]; }
			decl_list statement
			{ FreeProc($<Hv>1); }
		;

shifted_process	:	RIGHT_TOK process LEFT_TOK
		:	{ ShiftError(); }
			process
		;

statement	:	assignment NEWLINE
			{ Count(); }
		:	io	NEWLINE
			{ Count(); }
		:	construct
		:	proc_call NEWLINE
			{ Count(); }
		:	SKIP NEWLINE
			{ Count(); }
		:	error	NEWLINE
			{
				ProcError();
				yyerrok;
			}
		;

/* **** proc-call **** */
proc_call	:	id_tok
			{
				StartProcCall($1, 0);
				ProcCall($1);
			}
		:	proc_call_w_params	RP_TOK
			{	
				CheckNargs($1);
				ProcCall($1);
			}
		;

proc_call_w_params:	id_tok
			{ StartProcCall($1, 1); }
			LP_TOK cexpression
			{ $$ = $1; AddProcCall($1, $4); FreeExp($4); }
		:	proc_call_w_params
			{ Sbuf(); }
			COMA_TOK cexpression
			{ $$ = $1; AddProcCall($1, $4); FreeExp($4); }
		;

cexpression	:	expression
			{ $$ = $1; }
		:	STRING
			{ $$ = StrVal($1.lv_strval); }
		;

proc_list	:	process
		:	proc_list process
		;

construct	:	SEQ NEWLINE RIGHT_TOK proc_list LEFT_TOK
		:	SEQ NEWLINE
		:	SEQ replicator NEWLINE RIGHT_TOK process LEFT_TOK
			{
				GenJmp(JMP, $2.r_loop);
				GenLabel($2.r_out);
				FreeRepl($2);
			}
		:	IF NEWLINE RIGHT_TOK cond_list
			{ GenLabel($4.c_out); BackPatch($4.c_next); }
			LEFT_TOK
		:	IF replicator NEWLINE RIGHT_TOK conditional
			LEFT_TOK
			{
				GenJmp(JMP, $2.r_out);
				BackPatch($5);
				GenJmp(JMP, $2.r_loop);
				GenLabel($2.r_out);
			}
		:	WHILE
			{
				$<Cond>$.c_out = NewLabel();
				GenLabel($<Cond>$.c_out);
				Count();
			}
			expression
			{
				$<Expr>$ = CondExpr($3);
				FreeExp($3);
			}
			NEWLINE shifted_process
			{
				GenJmp(JMP, $<Cond>2.c_out);
				BackPatch($<Expr>4.e_false);
			}
		:	PAR	NEWLINE RIGHT_TOK
			{
				$<Label>$ = NewLabel();
				GenJmp(JMP, $<Label>$);
			}
				parallel_process LEFT_TOK
			{
				Par($<Label>4, $5);
			}
		:	PAR
			replicator NEWLINE RIGHT_TOK
			{ /* Count(); */ $<Label>$ = ReplProc($2); }
			process LEFT_TOK
			{
				EndReplProc($<Label>5, $2);
				FreeRepl($2);
			}
		:	{	StartAltCmd(); Count(); }
			alt_construct
			{	
				BackPatch($2);
				EndAltCmd();
			}
		;

alt_construct	:	ALT NEWLINE
			RIGHT_TOK guard_process_list LEFT_TOK
			{
				$$ = $4;
			}
		:	ALT
			replicator NEWLINE
			{ StartAlt($2.r_var); }
			RIGHT_TOK guard_process LEFT_TOK
			{	
				EndReplAlt($6, $2);
				$$ = MakeList($2.r_out);
			}
		;

replicator	:	id_tok EQ_TOK
			LBR_TOK expression FOR expression RBR_TOK
			{
				$$ = NewRepl($1);
				$$ = Loop($$, $4, $6);
				FreeExp($4); FreeExp($6);
			}
		;

guard_process_list:	guard_process
			{ $$ = $1; }
		:	guard_process_list
			{ BackPatch($1); }
			guard_process
			{ $$ = $3; }
		;

guard_process	:	{
				Label	tmpl;
				tmpl = NewLabel();
				StartAltIo(tmpl);
				$<Label>$ = tmpl;
			}
			guard NEWLINE
			{
				EndAltIo($2.gu_chan);
				StartGuardP($<Label>1);
			}
			shifted_process
			{ EndGuardP(); $$ = $2.gu_next; }
		:	alt_construct
			{ $$ = $1; }
		;

guard		:	input
			{ $$.gu_chan = $1; $$.gu_next = NullQuadl; }
		:	expr	COND_TOK	input
			{
				$$.gu_chan = $3;
				$$.gu_next = $1.e_false;
				FreeExp($1);
			}
		;

input		:	variable INP_TOK
			{ StartPushArgs(); }
			input_list
			{ EndPushArgs(0); $$ = $1; }
		:	variable
			INP_TOK
			{ StartPushArgs(); }
			AFTER expression
			{ Wait($5); EndPushArgs(1); $$ = $1; }
		:	WAIT NOW AFTER
			{ StartPushArgs(); }
			expression
			{ Wait($5); EndPushArgs(1); $$ = TimeChan(); }
		;

output		:	variable FCHAN_TOK
			{ StartPushArgs(); }
			output_list
			{ EndPushArgs(0); $$ = $1; }
		;

parallel_process:	{ $<Quadl>$ = NewProcess(NullQuadl); }
			process
			{
				EndProcess();
				$$ = $<Quadl>1;
			}
		:	parallel_process
			{ $<Quadl>$ = NewProcess($1); }
			process
			{
				EndProcess();
				$$ = $<Quadl>2;
			}
		;

/* **** declarations: proc **** */
decl_list	:	/* empty */
			{ $$ = EMPTY; }
		:	decl_list1
			{ $$ = NONEMPTY; }
		;

decl_list1	:	declaration
		:	decl_list1 declaration
		;

declaration	:	sdeclaration NEWLINE
		:	pdeclaration LEFT_TOK
		;

pdeclaration	:	PROC id_tok
			{ $<Decl>$ = ForwardDeclProc($2); }
			opt_params EQ_TOK
			{ DeclProc($<Decl>3, $4); }
			NEWLINE RIGHT_TOK process
			{ EndProc($2); }
		;

sdeclaration	:	VAR var_list
		:	DEF def_list
		:	CHAN chan_list
		:	QUE que_list
		:	EXTERN
			{ set_extern(); }
			VAR var_list
			{ unset_extern(); }
		:	EXTERN
			{ set_extern(); }
			CHAN chan_list
			{ unset_extern(); }
		:	EXTERN
			{ set_extern(); }
			QUE que_list
			{ unset_extern(); }
		:	EXTERN PROC id_tok
			{ $<Decl>$ = DeclExternProc($3); }
			opt_params
			{
			 	DeclProc($<Decl>4, $5);
				FreeProc(ProcCount[DispLevel]);
				Pop();
			}
		;

opt_params	:	/* empty */
			{ $$ = NoArgs; }
				/* NoArgs - epty struct args */
		:	LP_TOK params RP_TOK
			{ $$ = $2; EndParams(); }
		;

params		:	param
			{ $$ = MakeArg($1); }
		:	params	COMA_TOK	param
			{ $$ = AddArg($1, $3); }
		;

param		:	VAR id_tok
			{ $$ = DeclParam($1, $2); }
		:	VAR id_tok LBR_TOK RBR_TOK
			{ $$ = DeclParamTab($1, $2); }
		:	CHAN id_tok
			{ $$ = DeclParam($1, $2); }
		:	CHAN id_tok LBR_TOK RBR_TOK
			{ $$ = DeclParamTab($1, $2); }
		:	VALUE id_tok
			{ $$ = DeclParam($1, $2); }
		:	VALUE id_tok LBR_TOK RBR_TOK
			{ $$ = DeclParamTab($1, $2); }
		:	id_tok
			{ $$ = DeclParam(-1, $1); }
		:	id_tok LBR_TOK RBR_TOK
			{ $$ = DeclParamTab(-1, $1); }
		;

/* **** declaration: simple **** */
var_list	:	single_var
		:	var_list COMA_TOK single_var
		;
single_var	:	id_tok
			{ DeclVar($1); }
		:	id_tok	LBR_TOK expression RBR_TOK
			{ DeclVarTab($1, $3); FreeExp($3); }
		:	id_tok	LBR_TOK BYTE expression RBR_TOK
			{ DeclVarByteTab($1, $4); FreeExp($4); }
		:	id_tok	LBR_TOK RBR_TOK
			{ DeclVarTab($1, EmptyExpr()); }
		;

chan_list	:	single_chan
		:	chan_list COMA_TOK single_chan
		;

single_chan	:	id_tok
			{ DeclChan($1, Zero()); }
		:	id_tok LBR_TOK expression RBR_TOK
			{ DeclChanTab($1, $3, Zero()); FreeExp($3); }
		:	id_tok LBR_TOK RBR_TOK
			{ DeclChanTab($1, EmptyExpr(), EmptyExpr()); }
		:	id_tok AT expression
			{ DeclChanAt($1, $3); }
		;

que_list	:	single_que
		:	que_list COMA_TOK single_que
		;

single_que	:	id_tok LP_TOK expression RP_TOK
			{
#ifdef BUFF_CHANS
				DeclChan($1, $3);
#else
				Error(ERROR, BUFF_CHANS_UNSUPPORTED);
#endif
				FreeExp($3);
			}
		:	id_tok LP_TOK expression RP_TOK
				LBR_TOK expression RBR_TOK
			{
#ifdef	BUFF_CHANS
				DeclChanTab($1, $6, $3);
#else
				Error(ERROR, BUFF_CHANS_UNSUPPORTED);
#endif
				 FreeExp($3); FreeExp($6);
			}
		:	id_tok LP_TOK RP_TOK LBR_TOK RBR_TOK
			{
#ifdef	BUFF_CHANS
				DeclChanTab($1, EmptyExpr());
#else
				Error(ERROR, BUFF_CHANS_UNSUPPORTED);
#endif
			 }
		;

def_list	:	single_def
		:	def_list COMA_TOK single_def
		;

single_def	:	id_tok	EQ_TOK expression
			{ DeclDef($1, $3); FreeExp($3); }
		:	id_tok	EQ_TOK
			{ $<Decl>$ = DeclDefTab($1); }
			table
			{ $<Decl>3 ->d_nel = $4; }
		:	id_tok	EQ_TOK STRING
			{ DeclDefStr($1, $3.lv_strval); }
		;

table		:	TABLE LBR_TOK table_init RBR_TOK
			{ $$ = $3; }
		:	TABLE LBR_TOK BYTE
			{ SetByte(); }
			table_init RBR_TOK
			{ $$ = $5; UnsetByte(); }
		;

table_init	:	expression
			{ DeclDefEl($1); $$ = 1; }
		:	table_init COMA_TOK expression
			{ DeclDefEl($3); $$ = $1 + 1; }
		;

/* **** if **** */
cond_list	:	{ Count(); }
			conditional
			{
				$$.c_next = $2;
				$$.c_out  = NewLabel();
			}
		:	cond_list
			{
				GenJmp(JMP, $1.c_out);
				BackPatch($1.c_next);
				Count();
			}
			conditional
			{
				$$.c_out = $1.c_out;
				$$.c_next = $3;
			}
		;
		
conditional	:	expr NEWLINE
			{ $<Expr>$ = CondExpr($1); FreeExp($1); }
			shifted_process
			{ $$ = $<Expr>3.e_false; }
		:	IF NEWLINE RIGHT_TOK cond_list LEFT_TOK
			{	
				GenLabel($4.c_out);
				$$ = $4.c_next;
			}
		:	IF replicator NEWLINE RIGHT_TOK conditional
			LEFT_TOK
			{
				Label	tmpl;	/* success label */

				tmpl = NewLabel();
				GenJmp(JMP, tmpl);
				BackPatch($5);
				Count();
				GenJmp(JMP, $2.r_loop);
				GenLabel(tmpl);
				$$ = MakeList($2.r_out);
			}
		;

/* **** statements: assignment **** */
assignment	:	variable ASSIGN_TOK  expression
			{ Assign($1, $3); FreeExp($3); }
		;
		
/* **** expr **** */
expression	:	expr			%prec SEMICOLON_TOK
			{ $$ = EvalBool($1); }
		;


expr		:	element
			{ $$ = $1; }
		:	expr MULT_TOK
			{ $<Expr>$ = EvalBool($1); }
			expr
			{ $$ = ArithOp($2, $<Expr>3, $4); }
		:	expr DIV_TOK
			{ $<Expr>$ = EvalBool($1); }
			expr
			{ $$ = ArithOp($2, $4, $<Expr>3); }
		:	expr MOD_TOK
			{ $<Expr>$ = EvalBool($1); }
			expr
			{ $$ = ArithOp($2, $4, $<Expr>3); }
		:	expr PLUS_TOK
			{ $<Expr>$ = EvalBool($1); }
			expr
			{ $$ = ArithOp($2, $<Expr>3, $4); }
		:	expr MINUS_TOK
			{ $<Expr>$ = EvalBool($1); }
			expr
			{ $$ = ArithOp($2, $4, $<Expr>3); }
		:	expr LSHIFT_TOK
			{ $<Expr>$ = EvalBool($1); }
			expr
			{ $$ = ArithOp($2, $<Expr>3, $4); }
		:	expr RSHIFT_TOK
			{ $<Expr>$ = EvalBool($1); }
			expr
			{ $$ = ArithOp($2, $<Expr>3, $4); }
		:	expr AND_TOK
			{ $<Expr>$ = EvalBool($1); }
			expr
			{ $$ = ArithOp($2, $<Expr>3, $4); }
		:	expr OR_TOK
			{ $<Expr>$ = EvalBool($1); }
				expr
			{ $$ = ArithOp($2, $<Expr>3, $4); }
		:	expr XOR_TOK
			{ $<Expr>$ = EvalBool($1); }
				expr
			{ $$ = ArithOp($2, $<Expr>3, $4); }
		:	expr EQ_TOK
			{ $<Expr>$ = EvalBool($1); }
			expr
			{ $$ = CmpOp($2, $<Expr>3, $4); }
 		:	expr GT_TOK
			{ $<Expr>$ = EvalBool($1); }
			expr
			{ $$ = CmpOp($2, $<Expr>3, $4); }
 		:	expr GE_TOK
			{ $<Expr>$ = EvalBool($1); }
			expr
			{ $$ = CmpOp($2, $<Expr>3, $4); }
 		:	expr LT_TOK
			{ $<Expr>$ = EvalBool($1); }
			expr
			{ $$ = CmpOp($2, $<Expr>3, $4); }
 		:	expr LE_TOK
			{ $<Expr>$ = EvalBool($1); }
			expr
			{ $$ = CmpOp($2, $<Expr>3, $4); }
 		:	expr NEQ_TOK
			{ $<Expr>$ = EvalBool($1); }
			expr
			{ $$ = CmpOp($2, $<Expr>3, $4); }
		:	expr AND
			{ $<Label>$ = Land($1); }
			expr
			{ $$ = Rand($1, $<Label>3, $4); }
		:	expr OR	
			{ $<Label>$ = Lor($1); }
			expr
			{ $$ = Ror($1, $<Label>3, $4); }
		:	     NOT	element
			{ $$ = MonOp($1, $2); }
		:	     MINUS_TOK	element
			{ $$ = MonOp($1, $2); }
		:	expr AFTER
			{ $<Expr>$ = EvalBool($1); }
			expr
			{ $$ = CmpOp($2, $<Expr>3, $4); }
		;

element		:	const_el
		:	variable
		;

io		:	input
			{
				Io($1, 0);
			}
		:	output
			{
				Io($1, 1);
			}
		;

ivar		:	variable
			{
				PushInputArg($1);
				FreeExp($1);
			}
		;

input_list	:	ivar
		:	input_list SEMICOLON_TOK
			{ Sbuf(); }
			ivar
		;

output_list	:	oexpression
			{
				PushOutputArg($1);
				FreeExp($1);
			}
		:	output_list SEMICOLON_TOK
			{ Sbuf(); }
			oexpression
			{
				PushOutputArg($4);
				FreeExp($4);
			}
		;

oexpression	:	expression
			{ $$ = $1; }
		:	STRING
			{ $$ = StrToSlice($1); }
		;
				
const_el	:	INTEGER
			{ $$ = IntVal($1); }
		:	TRUE
			{ $$ = Bool(C_TRUE); }
		:	FALSE
			{ $$ = Bool(C_FALSE); }
 		:	NOW
			{ $$ = LocalClock(); }
 		:	CHARACTER
			{ $$ = CharVal($1); }
		:	LP_TOK  expr RP_TOK
			{ $$ = $2; }
		;

variable	:	id_tok
			{ $$ = Identifier($1); }
		:	id_tok LBR_TOK expression RBR_TOK
			{ $$ = IndexedVar($1, $3); }
		:	id_tok LBR_TOK BYTE expression RBR_TOK
			{ $$ = ByteIndexedVar($1, $4); }
		:	id_tok LBR_TOK expression FOR expression RBR_TOK
			{ $$ = IntSlice($1, $3, $5); }
		:	id_tok LBR_TOK BYTE expression FOR expression RBR_TOK
			{ $$ = ByteSlice($1, $4, $6); }
		;

id_tok		:	ID_TOK
			{ $$ = $1.lv_hashval; }
		;
%%
SHAR_EOF
fi # end of overwriting check
if test -f 'proc.c'
then
	echo shar: will not over-write existing file "'proc.c'"
else
cat << \SHAR_EOF > 'proc.c'
static char	rcsid[] = "$Header: proc.c,v 2.1 86/10/30 16:07:47 gil Exp $";

/*
 * $Log:	proc.c,v $
 * Revision 2.1  86/10/30  16:07:47  gil
 * This version was submitted for the project. It is free of all major bugs.
 *
 * Revision 1.1  86/01/04  14:20:47  gil
 * Initial revision
 *
 */

#include <stdio.h>
#include "all.h"

DType
ParamTypeConv(type) {
	switch (type) {
		case CHAN:
			return DCHAN;
		case VAR:
			return ByRef(DINT);
		case VALUE:
			return DINT;
		default:
			panic("Bad argument type");
	}
}

Args
MakeArg(dtype)
	DType	dtype;
{
	Args a;

	a.a_nargs = 1;
	a.a_argt = (DType *)calloc(1, sizeof(DType));
	a.a_argt[0] = dtype;
	return a;
}

Args
AddArg(a, dtype)
	Args	a;
	DType	dtype;
{

	Args	na;
	register n;

	na.a_nargs = n = a.a_nargs + 1;
	na.a_argt = (DType *)realloc(a.a_argt, n * sizeof(DType));
	na.a_argt[n-1] = dtype;
	return na;
}

static int Nargs = 0;	/* no. of arguments 'the' procedure was called with */
static int dontcheck = 0;	/* external/undef procedure - don't check
				 : no & type of arguments */
static int SavedBuf;

ProcCall(hv)
{
	register Decl	dp;
	
	if (Nargs > 0)
		RevBuf(Nargs, SavedBuf);

	dp = Hash[hv].h_decl;
	if (dp == NULL)
		GenFuncCall(Immediate(Nargs),
			Hash[hv].h_name,
			1,
			NullAddr);
	else
		GenFuncCall(Immediate(Nargs),
			(char *)dp->d_addr.d_offset,
			!IsExtern(dp->d_type) ? dp->d_addr.d_disp : 1,
			NullAddr);

	Nargs = 0;
	dontcheck = 0;
}

StartProcCall(hv, wp)
{

	struct decl	*dp;
	
	if (wp) {
		SavedBuf = CurBuf;
		Sbuf();
	}
	dp = Hash[hv].h_decl;
	if(dp == NULL) {
		Error(WARNING, UNDEF_PROC, Hash[hv].h_name);
		dontcheck = 1;
		return;
	}
	if(Type(dp->d_type) != DPROC) {
		Error(ERROR, PROC_REQUIRED);
		return;
	}
}

AddProcCall(hv, arg)
	Expr	arg;
{
	PushParam(Hash[hv].h_decl, arg);
	Nargs++;
}

CheckNargs(hv)
{

	Args	a;
	
	if (!dontcheck) {
		a = Hash[hv].h_decl->d_args;
		if (a.a_nargs != Nargs)
			Error(ERROR, ILL_NUM_OF_ARGS);
	}
}

PushParam(dp, arg)
	Decl	dp;
	Expr	arg;
{

	Args	a;
	DType	t;

	if (dontcheck)
		goto push;

	a = dp->d_args;
	if (Nargs > a.a_nargs) {
		dontcheck = 1;
		goto push;
	}

	t = a.a_argt[Nargs];

	if(Type(t) != Etype(arg)) {
		Error(ERROR, TYPE_MISMATCH);
		return;
	}
	if(IsByRef(t) && (IsConst(arg) :: IsTemp(arg))) {
		Error(ERROR, LVAL_REQ);
		return;
	}

push:
	if((!dontcheck && (IsByRef(t) :: IsTab(t)))  :: IsTab(Etype(arg)))
	   	GenPush(1, Addr(arg));	/* push ADDRESS */
	else
	   	GenPush(0, Addr(arg));
}

SHAR_EOF
fi # end of overwriting check
if test -f 'repl.c'
then
	echo shar: will not over-write existing file "'repl.c'"
else
cat << \SHAR_EOF > 'repl.c'
static char	rcsid[] = "$Header: repl.c,v 2.1 86/10/30 16:07:48 gil Exp $";

/*
 * $Log:	repl.c,v $
 * Revision 2.1  86/10/30  16:07:48  gil
 * This version was submitted for the project. It is free of all major bugs.
 *
 * Revision 1.1  86/01/04  14:20:50  gil
 * Initial revision
 *
 */

#include	<stdio.h>
#include	"all.h"

Repl
Loop(r, base, count)
	Repl		r;
	Expr		base, count;
{
	Label	l;

	if(IsConst(base))
		GenAssignConst(base.e_cval - 1, r.r_var);
	else
		Gen(MINUS_TOK, Immediate(1), base.e_place, r.r_var);
	if(IsConst(base) && IsConst(count))
		r.r_to = Eval(PLUS_TOK, base.e_place, count.e_place);
	else {
		r.r_to = GetAddr();
		Gen(PLUS_TOK, Addr(base), Addr(count), r.r_to);
	}

	GenLabel(r.r_loop);
	GenAob(	r.r_var, r.r_to, r.r_out);
	return r;
}

Label
ReplProc(r)
	Repl	r;
{
/*
 : documentation.
 */

	Label	ParL, 		/* label for start of parallel process */
		ProcL,		/* label for faked process (for 'calls') */
		MaskL;		/* label for masks at beginning of process */

	if (r.r_var.d_disp != AD_REGISTER)
		panic("using non register for replicator variable");
	ParL = NewLabel();
	GenPushLabel(ParL);
	GenFuncCall(Immediate(1), "newproc", 1, NullAddr);
	GenJmp(JMP, r.r_loop);

	GenLabel(ParL);

	ProcL = NewLabel();
	GenLabelCall(ProcL);
	GenFuncCall(Immediate(0), "endproc", 1, NullAddr);
	GenLabel(ProcL);

	MaskL = NewLabel();
	Push();
	GenStartProc(MaskL);
	return MaskL;
}

EndReplProc(MaskL, r)
	Label	MaskL;
	Repl	r;
{
	GenEndProc(MaskL);
	Pop();
	GenLabel(r.r_out);
	GenFuncCall(Immediate(0), "waitall", 1, NullAddr);
}

FreeRepl(r)
	Repl	r;
{
	FreeAddr(r.r_var);
	FreeAddr(r.r_to);
}
SHAR_EOF
fi # end of overwriting check
if test -f 'reserved_words.c'
then
	echo shar: will not over-write existing file "'reserved_words.c'"
else
cat << \SHAR_EOF > 'reserved_words.c'
#include <stdio.h>
#include "all.h"

struct reswords ReservedWords[] = {
	"AFTER"         ,AFTER           ,operator,
	"ALT"           ,ALT             ,reserved,
	"AND"           ,AND             ,operator,
	"AT"            ,AT              ,operator,
	"BYTE"          ,BYTE            ,operator,
	"CHAN"          ,CHAN            ,reserved,
	"DEF"           ,DEF             ,reserved,
	"EXTERN"        ,EXTERN          ,reserved,
	"FALSE"         ,FALSE           ,reserved,
	"FOR"           ,FOR             ,reserved,
	"IF"            ,IF              ,reserved,
	"NOT"           ,NOT             ,operator,
	"NOW"           ,NOW             ,reserved,
	"OR"            ,OR              ,operator,
	"PAR"           ,PAR             ,reserved,
	"PROC"          ,PROC            ,reserved,
	"QUE"           ,QUE             ,reserved,
	"SEQ"           ,SEQ             ,reserved,
	"SKIP"          ,SKIP            ,reserved,
	"TABLE"         ,TABLE           ,operator,
	"TRUE"          ,TRUE            ,reserved,
	"VALUE"         ,VALUE           ,reserved,
	"VAR"           ,VAR             ,reserved,
	"WAIT"          ,WAIT            ,reserved,
	"WHILE"         ,WHILE           ,reserved,
	"after"         ,AFTER           ,operator,
	"alt"           ,ALT             ,reserved,
	"and"           ,AND             ,operator,
	"at"            ,AT              ,operator,
	"byte"          ,BYTE            ,operator,
	"chan"          ,CHAN            ,reserved,
	"def"           ,DEF             ,reserved,
	"extern"        ,EXTERN          ,reserved,
	"false"         ,FALSE           ,reserved,
	"for"           ,FOR             ,reserved,
	"if"            ,IF              ,reserved,
	"not"           ,NOT             ,operator,
	"now"           ,NOW             ,reserved,
	"or"            ,OR              ,operator,
	"par"           ,PAR             ,reserved,
	"proc"          ,PROC            ,reserved,
	"que"           ,QUE             ,reserved,
	"seq"           ,SEQ             ,reserved,
	"skip"          ,SKIP            ,reserved,
	"table"         ,TABLE           ,operator,
	"true"          ,TRUE            ,reserved,
	"value"         ,VALUE           ,reserved,
	"var"           ,VAR             ,reserved,
	"wait"          ,WAIT            ,reserved,
	"while"         ,WHILE           ,reserved,
};
int nreserved = sizeof(ReservedWords)/sizeof(struct reswords);
SHAR_EOF
fi # end of overwriting check
if test -f 'Makefile.dist'
then
	echo shar: will not over-write existing file "'Makefile.dist'"
else
cat << \SHAR_EOF > 'Makefile.dist'
# configurable parameteres
################################################################################
CC=cc
YACC=/usr/bin/yacc
LEX=lex

CFLAGS=-Ih -DYYDEBUG
YFLAGS=-d
LFLAGS=

# notice: the order of files in OBJS counts.
OBJS=	error_list.o\
	lex.yy.o\
	y.tab.o\
	back.o\
	decl.o\
	err.o\
	expr.o\
	extern.o\
	gen.o\
	hash.o\
	init.o\
	io.o\
	lex.o\
	main.o\
	newbuf.o\
	par.o\
	print.o\
	proc.o\
	repl.o\
	reserved.o\
	reserved_words.o\
	slice.o\
	tab.o\
	temp.o\
	$(EMPTY)

ocp:	$(OBJS)
	$(CC) $(CFLAGS) -o ocp $(OBJS) -ll

lex.yy.c:	occam.lex
	$(LEX) $(LFLAGS) occam.lex

y.tab.c:	parse.y
	$(YACC) $(YFLAGS) parse.y
	mv y.tab.h h

clean:
	-rm *.o lex.yy.c y.tab.c ocp

# dependencies on header files.
################################################################################
back.o:	h/conf.h
back.o:	h/machine.h
back.o:	h/addr.h
back.o:	h/lex.h
back.o:	h/hash.h
back.o:	h/back.h
back.o:	h/parse.h
back.o:	h/error.h
back.o:	h/reserved.h
back.o:	h/y.tab.h

decl.o:	h/conf.h
decl.o:	h/machine.h
decl.o:	h/addr.h
decl.o:	h/lex.h
decl.o:	h/hash.h
decl.o:	h/back.h
decl.o:	h/parse.h
decl.o:	h/error.h
decl.o:	h/reserved.h
decl.o:	h/y.tab.h

err.o:	h/conf.h
err.o:	h/machine.h
err.o:	h/addr.h
err.o:	h/lex.h
err.o:	h/hash.h
err.o:	h/back.h
err.o:	h/parse.h
err.o:	h/error.h
err.o:	h/reserved.h
err.o:	h/y.tab.h

error_list.o:	h/error.h

expr.o:	h/conf.h
expr.o:	h/machine.h
expr.o:	h/addr.h
expr.o:	h/lex.h
expr.o:	h/hash.h
expr.o:	h/back.h
expr.o:	h/parse.h
expr.o:	h/error.h
expr.o:	h/reserved.h
expr.o:	h/y.tab.h

extern..o:	h/conf.h
extern.o:	h/machine.h
extern.o:	h/addr.h
extern.o:	h/lex.h
extern.o:	h/hash.h
extern.o:	h/back.h
extern.o:	h/parse.h
extern.o:	h/error.h
extern.o:	h/reserved.h
extern.o:	h/y.tab.h

hash.o:	h/hash.h

gen.o:	h/conf.h
gen.o:	h/machine.h
gen.o:	h/addr.h
gen.o:	h/lex.h
gen.o:	h/hash.h
gen.o:	h/back.h
gen.o:	h/parse.h
gen.o:	h/error.h
gen.o:	h/reserved.h
gen.o:	h/y.tab.h

init.o:	h/conf.h
init.o:	h/machine.h
init.o:	h/addr.h
init.o:	h/lex.h
init.o:	h/hash.h
init.o:	h/back.h
init.o:	h/parse.h
init.o:	h/error.h
init.o:	h/reserved.h
init.o:	h/y.tab.h

io.o:	h/conf.h
io.o:	h/machine.h
io.o:	h/addr.h
io.o:	h/lex.h
io.o:	h/hash.h
io.o:	h/back.h
io.o:	h/parse.h
io.o:	h/error.h
io.o:	h/reserved.h
io.o:	h/y.tab.h

lex.o:	h/conf.h
lex.o:	h/machine.h
lex.o:	h/addr.h
lex.o:	h/lex.h
lex.o:	h/hash.h
lex.o:	h/back.h
lex.o:	h/parse.h
lex.o:	h/error.h
lex.o:	h/reserved.h
lex.o:	h/y.tab.h

lex.yy.o:	h/conf.h
lex.yy.o:	h/machine.h
lex.yy.o:	h/addr.h
lex.yy.o:	h/lex.h
lex.yy.o:	h/hash.h
lex.yy.o:	h/back.h
lex.yy.o:	h/parse.h
lex.yy.o:	h/error.h
lex.yy.o:	h/reserved.h
lex.yy.o:	h/y.tab.h

main.o:	h/conf.h
main.o:	h/machine.h
main.o:	h/addr.h
main.o:	h/lex.h
main.o:	h/hash.h
main.o:	h/back.h
main.o:	h/parse.h
main.o:	h/error.h
main.o:	h/reserved.h
main.o:	h/y.tab.h

newbuf.o:	h/conf.h
newbuf.o:	h/machine.h
newbuf.o:	h/addr.h
newbuf.o:	h/lex.h
newbuf.o:	h/hash.h
newbuf.o:	h/back.h
newbuf.o:	h/parse.h
newbuf.o:	h/error.h
newbuf.o:	h/reserved.h
newbuf.o:	h/y.tab.h

par.o:	h/conf.h
par.o:	h/machine.h
par.o:	h/addr.h
par.o:	h/lex.h
par.o:	h/hash.h
par.o:	h/back.h
par.o:	h/parse.h
par.o:	h/error.h
par.o:	h/reserved.h
par.o:	h/y.tab.h

print.o:	h/error.h

proc.o:	h/conf.h
proc.o:	h/machine.h
proc.o:	h/addr.h
proc.o:	h/lex.h
proc.o:	h/hash.h
proc.o:	h/back.h
proc.o:	h/parse.h
proc.o:	h/error.h
proc.o:	h/reserved.h
proc.o:	h/y.tab.h

repl.o:	h/conf.h
repl.o:	h/machine.h
repl.o:	h/addr.h
repl.o:	h/lex.h
repl.o:	h/hash.h
repl.o:	h/back.h
repl.o:	h/parse.h
repl.o:	h/error.h
repl.o:	h/reserved.h
repl.o:	h/y.tab.h

reserved.o:	h/conf.h
reserved.o:	h/machine.h
reserved.o:	h/addr.h
reserved.o:	h/lex.h
reserved.o:	h/hash.h
reserved.o:	h/back.h
reserved.o:	h/parse.h
reserved.o:	h/error.h
reserved.o:	h/reserved.h
reserved.o:	h/y.tab.h

reserved_words.o:	h/conf.h
reserved_words.o:	h/machine.h
reserved_words.o:	h/addr.h
reserved_words.o:	h/lex.h
reserved_words.o:	h/hash.h
reserved_words.o:	h/back.h
reserved_words.o:	h/parse.h
reserved_words.o:	h/error.h
reserved_words.o:	h/reserved.h
reserved_words.o:	h/y.tab.h

slice.o:	h/conf.h
slice.o:	h/machine.h
slice.o:	h/addr.h
slice.o:	h/lex.h
slice.o:	h/hash.h
slice.o:	h/back.h
slice.o:	h/parse.h
slice.o:	h/error.h
slice.o:	h/reserved.h
slice.o:	h/y.tab.h

tab.o:	h/conf.h
tab.o:	h/machine.h
tab.o:	h/addr.h
tab.o:	h/lex.h
tab.o:	h/hash.h
tab.o:	h/back.h
tab.o:	h/parse.h
tab.o:	h/error.h
tab.o:	h/reserved.h
tab.o:	h/y.tab.h

temp.o:	h/addr.h
temp.o:	h/machine.h

y.tab.o:	h/conf.h
y.tab.o:	h/machine.h
y.tab.o:	h/addr.h
y.tab.o:	h/lex.h
y.tab.o:	h/hash.h
y.tab.o:	h/back.h
y.tab.o:	h/parse.h
y.tab.o:	h/error.h
y.tab.o:	h/reserved.h
SHAR_EOF
fi # end of overwriting check
if test -f 'slice.c'
then
	echo shar: will not over-write existing file "'slice.c'"
else
cat << \SHAR_EOF > 'slice.c'
static char	rcsid[] = "$Header: slice.c,v 2.1 86/10/30 16:07:52 gil Exp $";

/*
 * $Log:	slice.c,v $
 * Revision 2.1  86/10/30  16:07:52  gil
 * This version was submitted for the project. It is free of all major bugs.
 *
 * Revision 1.2  86/03/19  16:39:00  gil
 * print varibale name in error messages.
 *
 * Revision 1.1  86/01/04  14:20:52  gil
 * Initial revision
 *
 */

#include	<stdio.h>
#include	"all.h"
#define Null_tf(e)		(e).e_false = NullQuadl;

addr
MultByFour(count)
	Expr	count;
{
	addr r;

	if(IsConst(count))
		r = Eval(MULT_TOK, Immediate(4), count.e_place);
	else {
		r = GetAddr();
		Gen(MULT_TOK, Immediate(4), Addr(count), r);
	}
	return r;
}

Expr
Slice(hv, base, count, isbyte)
	Expr	base, count;
{

	Decl	d;
	Expr	ne;

	d = Hash[hv].h_decl;
	if (d == NULL) {
		Error(ERROR, UNDEF_VAR, Hash[hv].h_name);
		return ne;
	}
	Null_tf(ne);
	if(Type(d->d_type) != DINT_TAB) {
		Error(ERROR, TABLE_REQUIRED);
		return ne;
	}
	ne.e_flags = ET_SLICE;
	if(!isbyte)
		ne.e_slen = MultByFour(count);
	else
		ne.e_slen = Addr(count);
	ne.e_place = GenSliceAddr(d->d_addr, Addr(base), isbyte);
	return ne;
}

Expr
IntSlice(hv, base, count)
	Expr base, count;
{
	return Slice(hv, base, count, 0);
}

Expr
ByteSlice(hv, base, count)
	Expr	base, count;
{
	return Slice(hv, base, count, 1);
}

Expr
StrToSlice(s)
	char	*s;
{
	Expr e;

	e.e_flags = ET_SLICE:EK_CONST;
	e.e_place = NullAddr;
	e.e_place.d_flags = AF_LABEL;
	e.e_place.d_offset = (addr_t)strsave(GenDefLabel(NewLabel()));
	e.e_place.d_disp = 1;
	e.e_slen = Immediate(s[0]);
	Null_tf(e);
	GenDefStr(s+1);
	return e;
}
SHAR_EOF
fi # end of overwriting check
if test -f 'tab.c'
then
	echo shar: will not over-write existing file "'tab.c'"
else
cat << \SHAR_EOF > 'tab.c'
static char	rcsid[] = "$Header: tab.c,v 2.1 86/10/30 16:07:54 gil Exp $";

/*
 * $Log:	tab.c,v $
 * Revision 2.1  86/10/30  16:07:54  gil
 * This version was submitted for the project. It is free of all major bugs.
 *
 * Revision 1.1  86/01/04  14:20:53  gil
 * Initial revision
 *
 */

#include <stdio.h>
#include "all.h"

extern	addr gaddr();

static
addr
get_temp()
{
	addr	t;

	t = NullAddr;

	t.d_disp = AD_REGISTER;
	t.d_offset = newreg();
	return t;
}

mach_and(op, a1, a2, res)
	addr	*a1, *a2, *res;
{
	addr	t;

	t = get_temp();

	*a1 = gaddr(*a1, 0);
	pcode("\tmcoml\t");
	paddr(*a1); pcode(",");
	paddr(t); pcode("\n");
	*a1 = t;
	return 0;
}

mach_mod(op, a1, a2, res)
	addr	*a1, *a2, *res;
{
	addr t;

	t = get_temp();

	pcode("\tdivl3\t");
	*a1 = gaddr(*a1, 0);
	*a2 = gaddr(*a2, 0);
	paddr(*a1); pcode(",");
	paddr(*a2); pcode(",");
	paddr(t);
	pcode("\n\tmull2\t");
	paddr(*a1); pcode(",");
	paddr(t); pcode("\n");
	*a1 = t;
	return 0;
}

#ifdef vax
mach_ash(op, a1, a2, res)
	addr	*a1, *a2, *res;
{
	addr	t;

	if(op == RSHIFT_TOK) {
		t = get_temp();
		if(a2->d_disp == AD_IMMED) {
			a2->d_offset = -a2->d_offset;
			t = *a2;
		}
		else  {
			t = get_temp();
			*a2 = gaddr(*a2);
			pcode("\tmnegl\t");
			paddr(*a2); pcode(",");
			paddr(t); pcode("\n");
		}
	} else
		t = gaddr(*a2);
	*a1 = gaddr(*a1);
	pcode("\tashl\t");
	paddr(t); pcode(",");
	paddr(*a1); pcode(",");
	paddr(*res); pcode("\n");
	endaddr();
	return 1;
}
#endif
#ifdef tahoe
mach_shift(op, a1, a2, res)
	addr *a1, *a2, *res;
{
	*a1 = gaddr(*a1);
	*a2 = gaddr(*a2);
	*res = gaddr(*res);
	if(!IsReg(*a2)) {
		pcode("\tmovl\t"); paddr(*a2);
		*a2 = get_temp();
		pcode(", "); paddr(*a2);
		pcode("\n");
	}
	pcode("\tsh%cl\t", op == RSHIFT_TOK ? 'r' : 'l');
	paddrs(3, *a2, *a1, *res);
	endaddr();
}
#endif

int	naddr, commute;
int	(*func)();
#define	NonCommute(a)	(commute &= ~(1<<(a)))

char *
Inst(op) {
	switch (op) {
		case MULT_TOK:
			return "mul";
		case PLUS_TOK:
			return "add";
		case MINUS_TOK:
			NonCommute(1);
			return "sub";
		case DIV_TOK:
			NonCommute(1);
			return "div";
 		case OR_TOK:
#ifdef vax
			return "bis";
#else tahoe
			return "or";
#endif
		case AND_TOK:
#ifdef vax
			func = mach_and;
			return "bic";
#else tahoe
			return "and";
#endif
		case XOR_TOK:
			return "xor";
		case LSHIFT_TOK:
#ifdef vax
			func = mach_ash;
			return "ash";
#else tahoe
			func = mach_shift;
			return NULL;
#endif
		case RSHIFT_TOK:
#ifdef vax
			func = mach_ash;
			return "rsh";
#else tahoe
			func = mach_shift;
			return NULL;
#endif
		case MOD_TOK:
			func = mach_mod;
			return "sub";
/* for all compraison operation we creat a branch to the opposite
 : relation holds. */
		case EQ_TOK:
			return "jneq";
		case GT_TOK:
			return "jleq";
		case LT_TOK:
			return "jgeq";
		case LE_TOK:
			return "jgtr";
		case NEQ_TOK:
			return "jeql";
		case GE_TOK:
			return "jlss";
		case AFTER:
			return "jlssu";

		case MON(MINUS_TOK):
			naddr = 2;
			return "mneg";
		case MON(NOT):
			naddr = 2;
			return "mcom";
		case MOVREF:
		case MOVL:
			naddr = 2;
			return "mov";
		case CMP:
			naddr = 2;
			return "cmp";
		case JMP:
			naddr = 1;
			return "jbr";
		case TST:
			naddr = 1;
			return "tst";
		case JUMP:
			naddr = 1;
			return "jmp";
		default:
			panic("Unknown op\n");
	}
	/*NOTREACHED*/
}
SHAR_EOF
fi # end of overwriting check
if test -f 'temp.c'
then
	echo shar: will not over-write existing file "'temp.c'"
else
cat << \SHAR_EOF > 'temp.c'
static char	rcsid[] = "$Header: temp.c,v 2.1 86/10/30 16:07:55 gil Exp $";

/*
 * $Log:	temp.c,v $
 * Revision 2.1  86/10/30  16:07:55  gil
 * This version was submitted for the project. It is free of all major bugs.
 *
 * Revision 1.1  86/01/04  14:20:54  gil
 * Initial revision
 *
 */

#include "addr.h"
#include "machine.h"

#if NBBY*NBPL > NREG
long	RegistersUsed;
long	MaxTemp;

static long	DontFree;

#define bit(i) (1 << (i))

addr
GetTemp(mask, reuse)
	long	mask;
{
	addr a;
	register i;

	a = NullAddr;
	i = ffc(RegistersUsed:mask);

	a.d_flags = 0;
	if(i < 0 :: i >= NREG) {
		a.d_disp = DispLevel;
		a.d_offset = AllocStack(INT_SIZE);
		if(DispLevel == AD_GLOBAL) /* hack -
					    * should prevent using offset
					    * as a name for oc_main stack
					    * temporary allocation, and
					    * here fp == sp */
			a.d_flags = AF_FP;
		return a;
	}
	a.d_disp = AD_REGISTER;
	a.d_offset = i;
	RegistersUsed := bit(i);
	if(ShouldBeMasked(i))
		MaxTemp	:= bit(i);
	if(reuse)
		DontFree := bit(i);
	return a;
}

FreeTmp(a)
	addr a;
{
	register long mask;
	register i;

	if(a.d_flags & AF_SUB)
		i = a.d_reg;
	else
		if(a.d_disp != AD_REGISTER)
		/* panic("FreeTmp: Not a register"); */ return;
	else i = a.d_offset;
	mask = bit(i);
	if(DontFree & mask)
		return;
	if(i >= NREG :: i < 0)
		panic("Illegal register number");
	if((RegistersUsed & mask) == 0)
		panic("Freeing free register");
	RegistersUsed &= ~mask;
}

addr
NewTemp()
{
	addr	a;

	a = GetTemp(TEMPMASK, 0);
	return a;
}

addr
GetAddr() {
	addr	a;

	a = GetTemp(ADDRMASK, 1);
	return a;
}

FreeAddr(a)
	addr	a;
{
	if(a.d_disp == AD_REGISTER)
		DontFree &= ~bit(a.d_offset);
	FreeTmp(a);
}

ResetTmp() {
	RegistersUsed = DontUse:OtherRegs:DontFree;
	MaxTemp = OtherRegs;
}

ffc(l)
	long l;
{
	return (ffs(~l) - 1);
}

#else
!!
#endif

addr_t
AllocStack(nbytes) {
	Sp += roundup(nbytes);
	return Sp;
}

static Label;
NewLabel() {
	return ++Label;
}
SHAR_EOF
fi # end of overwriting check
if test -f 'reserved.c'
then
	echo shar: will not over-write existing file "'reserved.c'"
else
cat << \SHAR_EOF > 'reserved.c'
static char	rcsid[] = "$Header: reserved.c,v 2.1 86/10/30 16:07:50 gil Exp $";

/*
 * $Log:	reserved.c,v $
 * Revision 2.1  86/10/30  16:07:50  gil
 * This version was submitted for the project. It is free of all major bugs.
 *
 * Revision 1.1  86/01/04  14:20:51  gil
 * Initial revision
 *
 */

#include <stdio.h>
#include "all.h"

Reserved(s, type)
	char	*s;
	int	*type;
{
/* Perform a binary search for the name 's' in the 'ReservedWords' table
 : and return its token number and type. return 0 if not found.
 */

	register	high = nreserved, low = -1, mid, m;

	do {
		mid = (high + low)/2;
		if((m = strcmp(ReservedWords[mid].rs_word, s)) == 0) {
				*type = ReservedWords[mid].rs_type;
				return ReservedWords[mid].rs_token;
		}
		else if(m > 0)
			high = mid;
		else 	low = mid;
	} while(low+1 != high);
	return 0;		
}
/*
main() {
	char	s[100];
	while(gets(s) != NULL)
		printf("%s: %d\n", s, Reserved(s));
}
*/
SHAR_EOF
fi # end of overwriting check
if test -f 'err_types'
then
	echo shar: will not over-write existing file "'err_types'"
else
cat << \SHAR_EOF > 'err_types'
RECOVER	:INTEGER_OVERFLOW	:Integer overflow
RECOVER	:NEWLINE_IN_CHAR_CONST 	:Newline in character constant
RECOVER	:CHAR_CONST_TOO_LONG 	:Character constant too long
WARNING	:EMPTY_CHAR_CONST	:Empty character constant
WARNING	:ESCAPE_CHAR		:'*' is escape character
WARNING	:NO_SPECIAL_MEANING	:Escape has no special meaning
RECOVER	:UNFINISHED_STR		:Unfinished string
COMPILER_ERROR :HASH_FULL		:Hash table is full
WARNING	:ODD_NO_OF_BLANKS	:Odd number of blanks
ERROR	:ILLEGAL_CHAR		:Illegal character
COMPILER_ERROR :LEX_INTERNAL_ERROR	:Lexical error: internal error
ERROR	:EXPECTED_EOF		:Eof Expected - Quit
ERROR	:UNEXPECTED_EOF		:Unexpected Eof
RECOVER	:EXPECTED_CONST		:Expected constant expression
ERROR	:TYPE_MISMATCH		:Type mismatch
RECOVER	:DIV_BY_ZERO		:Division by zero
RECOVER	:OP_MISMATCH		:Illegal operand
RECOVER	:UNDEF_VAR		:Undefined variable \"%s\"
ERROR	:MULTIPLY_DECLARED_VAR	:Multiply declared var
RECOVER :LVAL_REQ		:Lvalue requierd
ERROR	:CHANNEL_REQ		:Channel required
ERROR	:PROC_REQUIRED		:Process required
WARNING :UNDEF_PROC		:Undefined proc \"%s\", assumed external
ERROR	:ILL_NUM_OF_ARGS	:Wrong number of arguments
ERROR	:EXTERN_EXISTS		:External definition cannot be overlapped
ERROR	:TABLE_REQUIRED		:Table required
WARNING	:VALUE_PARAM_ASSIGN	:Assigment to Read Only variable
ERROR	:SLICE_REQUIRED		:Slice required
ERROR	:DIFF_SLICES		:Slices should be of the same type
COMPILER_ERROR :TOO_MANY_ERRORS	:Too many errors
ERROR	:MISSING_PARAM_TYPE	:missing parameters' type (var, value or chan)
WARNING	:EXTRA_INDENT		:Extra indentation, taken as one indent
RECOVER	:EXPECT_SHIFTED_PROC	:Expected shifted process near token %s
ERROR	:SYNT_ERR_NEAR		:Syntax Error near token %s
WARNING	:EXTERN_NAME_OVERLOAD	:External %s is already declared global
ERROR	:IDENT_REQUIRED		:Bad identifier type - \"%s\"
ERROR	:VMS_UNSUPPORTED	:VMS (placed) channels are not supported
SHAR_EOF
fi # end of overwriting check
if test -f 'back.c'
then
	echo shar: will not over-write existing file "'back.c'"
else
cat << \SHAR_EOF > 'back.c'
static char	rcsid[] = "$Header: back.c,v 2.1 86/10/30 16:05:57 gil Exp $";

/*
 * $Log:	back.c,v $
 * Revision 2.1  86/10/30  16:05:57  gil
 * This version was submitted for the project. It is free of all major bugs.
 *
 * Revision 1.1  86/01/04  14:20:29  gil
 * Initial revision
 *
 */

#include <stdio.h>
#include "all.h"

Quadl NullQuadl  = { 0, (Label *)0 };

Quadl
MakeList(quad)
	Label	quad;
{

	Quadl q;
	
	q.q_nquads = 1;
	q.q_quads = (Label *) calloc(1, sizeof(Label));
	q.q_quads[0] = quad;
	return q;
}

Quadl
Merge(q1, q2)
	Quadl q1, q2;
{
	Quadl q;
	register Label *p, *np;
	register i;

	q.q_nquads = q1.q_nquads + q2.q_nquads;
	if (q.q_nquads > 0)
		np = q.q_quads  = (Label *)calloc(q.q_nquads, sizeof(Label));

	for(i = q1.q_nquads, p = q1.q_quads; i > 0; i--)
		*np++ = *p++;
	for(i = q2.q_nquads, p = q2.q_quads; i > 0; i--)
		*np++ = *p++;

	return q;
}

Quadl
AddList(ql, l)
	Quadl	ql;
	Label	l;
{
	Quadl q;
	register Label *p, *np;
	register i;

	if (NullQ(ql))
		return(MakeList(l));
	
	q.q_nquads = ql.q_nquads + 1;
	np = q.q_quads  = (Label *)calloc(q.q_nquads, sizeof(Label));

	for(i = ql.q_nquads, p = ql.q_quads; i > 0; i--)
		*np++ = *p++;
	*np++ = l;

	return q;
}

BackPatch(ql)
	Quadl	ql;
{

	register int i;
	register Label *j;
	
	for(j = ql.q_quads, i = ql.q_nquads; i-- > 0; j++)
		GenLabel(*j);
}
SHAR_EOF
fi # end of overwriting check
if test -f 'reserved_words'
then
	echo shar: will not over-write existing file "'reserved_words'"
else
cat << \SHAR_EOF > 'reserved_words'
"after"			AFTER	operator
"AFTER"			AFTER	operator
"alt"			ALT
"ALT"			ALT
"and"			AND	operator
"AND"			AND	operator
"at"			AT	operator
"AT"			AT	operator
"byte"			BYTE	operator
"BYTE"			BYTE	operator
"chan"			CHAN
"CHAN"			CHAN
"def"			DEF
"DEF"			DEF
"extern"		EXTERN
"EXTERN"		EXTERN
"false"			FALSE
"FALSE"			FALSE
"for"			FOR
"FOR"			FOR
"if"			IF
"IF"			IF
"not"			NOT	operator
"NOT"			NOT	operator
"now"			NOW
"NOW"			NOW
"or"			OR	operator
"OR"			OR	operator
"par"			PAR
"PAR"			PAR
"proc"			PROC
"PROC"			PROC
"que"			QUE
"QUE"			QUE
"seq"			SEQ
"SEQ"			SEQ
"skip"			SKIP
"SKIP"			SKIP
"table"			TABLE	operator
"TABLE"			TABLE	operator
"true"			TRUE
"TRUE"			TRUE
"value"			VALUE
"VALUE"			VALUE
"var"			VAR
"VAR"			VAR
"wait"			WAIT
"WAIT"			WAIT
"while"			WHILE
"WHILE"			WHILE
SHAR_EOF
fi # end of overwriting check
cd ..
#	End of shell archive
exit 0

----------end of comp.shar----------

ttork@ewu.UUCP (Terry Torkelson) (11/15/90)

----------sim.shar----------
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	sim
# This archive created: Thu Apr 19 16:54:29 1990
export PATH; PATH=/bin:$PATH
if test ! -d 'sim'
then
	mkdir 'sim'
fi
cd 'sim'
if test ! -d 'h'
then
	mkdir 'h'
fi
cd 'h'
if test -f 'trace.h'
then
	echo shar: will not over-write existing file "'trace.h'"
else
cat << \SHAR_EOF > 'trace.h'
/*
 *	Occam kernel tracer definitions.
 */
extern int tracer;		/* tracing flags */
extern char *BlockStat(), *Pinfo();

/* tracing options: */
#define TRACE_CSW	0x1		/* trace context switches */
#define	TRACE_FORK	0x2		/* trace forks */
#define	TRACE_BLOCK	0x4		/* trace blocks/unblocks */
#define	TRACE_IO	0x10		/* trace i/o events. */
#define	TRACE_MOREIO	0x20		/* trace more i/o events */
#define	TRACE_ALLIO	(TRACE_IO:TRACE_MOREIO)		/* trace all i/o
							 : operations */
#define	TRACE_ALL	(0xffff)

FILE	*tracef;
/*
 : TRACE(flags, (fmt, args...)):
 : 	flags - trace flags for which this trace message is applied.
 :	fmt, args - tracing message. passed to printf.
 */
#define	TRACE(flg, args)	if(tracer&(flg)) pflg(flg), ptrace args
#define	NTRACE(flg, args)	if(tracer&(flg)) sflg(flg), ptrace args
SHAR_EOF
fi # end of overwriting check
if test -f 'vmsio.h'
then
	echo shar: will not over-write existing file "'vmsio.h'"
else
cat << \SHAR_EOF > 'vmsio.h'
/*
 : $Header: vmsio.h,v 3.1 86/11/01 15:45:09 gil Exp $
 : VMS-Occam Compatible Channel definitions.
 */
#define	_InF(v)	(v+3)
#define	_OutF(v)	(v+11)

/* Channel Numbers: */
#define	C_Parameters	0
#define	C_Screen	1
#define	C_Keyboard	2
#define	C_Filein0	_InF(0)
#define	C_Filein1	_InF(1)
#define	C_Filein2	_InF(2)
#define	C_Filein3	_InF(3)
#define	C_Filein4	_InF(4)
#define	C_Filein5	_InF(5)
#define	C_Filein6	_InF(6)
#define	C_Filein7	_InF(7)
#define	C_Fileout0	_OutF(0)
#define	C_Fileout1	_OutF(1)
#define	C_Fileout2	_OutF(2)
#define	C_Fileout3	_OutF(3)
#define	C_Fileout4	_OutF(4)
#define	C_Fileout5	_OutF(5)
#define	C_Fileout6	_OutF(6)
#define	C_Fileout7	_OutF(7)

#define	V_NFILES	8

#define	WORDSIZE	4

#define	IsInf(f)	((f) < _OutF(0) && (f) >= _InF(0))
#define	IsOutf(f)	((f) >= _OutF(0))
#define	VFile(f) (((f) < C_Filein0) ? &StdFile[f] : \
		&VmsFile[IsInf(f) ? ((f) - C_Filein0) : ((f) - C_Fileout0)])

struct	vms_file {
	int	vms_message;
	enum	vstat { NORMAL, FILENAME, ARGSTR } vms_stat;
	FILE	*vms_fp;
	char	*vms_name;
} VmsFile[V_NFILES], StdFile[3];

typedef struct vms_file	VmsChan;
/* Control Values */
#define	V_ClosedOK	-1
#define	V_CloseFile	-2
#define	V_EndBuffer	-3
#define	V_EndFile	-4
#define	V_EndName	-5
#define	V_EndParameterString	-6
#define	V_EndRecord	-7
#define	V_NextRecord	-9
#define	V_OpenedOK	-10
#define	V_OpenForRead	-11
#define	V_OpenForWrite	-12

/* Error Values */
#define	E_FileNameTooLong	0x80000000	
#define	E_InputFileNotOpened	0x80000001	
#define	E_OutputFileNotCreated	0x80000002	

#define	E_InputRecordTooLong	0x80000004	
#define	E_ReadFailed	0x80000008	

#define	E_OutputRecordTooLong	0x80000010	

#define	E_WriteFailed	0x80000020	

#define	E_CloseFailed	0x80000040	
SHAR_EOF
fi # end of overwriting check
if test -f 'chan.h'
then
	echo shar: will not over-write existing file "'chan.h'"
else
cat << \SHAR_EOF > 'chan.h'
#define	min(a, b)	((a) > (b) ? (b) : (a))
#define	max(a, b)	((a) > (b) ? (a) : (b))

typedef struct {
	int	io_len;
	char	*io_data;
} IoVec;

typedef struct ioblock {
	IoVec		*b_data;
	int		b_ndata;
	int		b_dind; /* index of data array; used also for flags */
#define	BD_FAFTER	-1	/* if 'after' operation on the time channel */
	Process		*b_proc;
	int		b_id;
	struct ioblock	*b_next;
} IoBlock;

typedef struct channel {
	int	ch_flags;
	int	ch_siz;		/* for buffered channels: sizeof buffer */
	IoBlock	ch_read;	/* read-requests' queue */
	IoBlock	ch_write;	/* write-requests' queue */
#if (defined(S_SYS) :: defined(S_VMS))
	int	ch_fd;		/* file descriptor for special channels */
#endif	/* S_SYS :: S_VMS */
	struct channel *ch_nxt;
}  Channel;

#ifdef S_SYS
#	define	CH_SYS		01
#	define	CH_DEV		04
#	define IsSpecial(ch)		((ch)->ch_flags & CH_SYS)
#	define	IsSpecialDevice(ch)	((ch)->ch_flags & CH_DEV)
#endif S_SYS

#ifdef S_VMS
#	define	CH_VMS		02
#	define	IsVms(ch)		((ch)->ch_flags & CH_VMS)
#endif  S_VMS

#define CH_TIME		08
#define IsTime(ch)		((ch)->ch_flags & CH_TIME)

#define	chanof(id)	(&chans[id])
#define chidof(ch)	(ch - chans)

#define	MAX_CHANS	512
extern Channel chans[];
extern Channel *free_chans;

#define F_AFTER	1

extern int	time_ch;

#define	new(type)	(struct type *)calloc(1, sizeof(struct type))
SHAR_EOF
fi # end of overwriting check
if test -f 'conf.h'
then
	echo shar: will not over-write existing file "'conf.h'"
else
cat << \SHAR_EOF > 'conf.h'
/* $Header: conf.h,v 3.3 86/11/04 09:56:28 gil Exp $ */

/*
 * This is a configuration file for the OCCAM runtime library.
 * It contains a few parameters that determine if certain options will be
 * supported by the library.
 * See the user manual for detailed description of these options.
 * When noted, the compiler should be configured to support the option in the
 * language syntax. This is done by setting the options in the compiler's
 * configuration file, ../h/conf.h
 *
 * The options are:
 */

/* S_SYS: include the code for special system channels. With this option
 * set the system will support actions on UNIX files through special channels.
 */
#define	S_SYS

/* S_VMS: include the code for special VMS channels - these are special system
 * channels that conform to the system channels protocol of the INMOS VAX/VMS
 * version of OCCAM.
 * NOTE: Should be set in the compiler as well.
 */
/* #define	S_VMS */

/* BUFF_CHAN: include the code for buffered channels.
 * If you don't intend to use buffered channels switch it off for better
 * performance.
 * NOTE: Should be set in the compiler as well.
 */
#define	BUFF_CHANS
SHAR_EOF
fi # end of overwriting check
if test -f 'process.h.bak'
then
	echo shar: will not over-write existing file "'process.h.bak'"
else
cat << \SHAR_EOF > 'process.h.bak'
#include <sys/types.h>

#ifdef vax
typedef	struct	{
	int	r2, r3, r4, r5, r6, r7, r8, r9, r10;
			/* general purpose registers */
	caddr_t	st_dp;	/* display pointer (occam ext. r11) */
	caddr_t	st_ap;	/* argument pointer */
	caddr_t	st_fp;	/* frame pointer */
	caddr_t	st_sp;	/* stack pointer */
	caddr_t	st_pc;	/* program counter */

} SavedData;
#else tahoe
typedef struct	{
	int	r2, r3, r4, r5, r6, r7, r8, r9, r10, r11;
	caddr_t	st_dp;	 	/* display pointer (r12) */
	caddr_t	st_fp;
	caddr_t	st_sp;
	caddr_t	st_pc;
} SavedData;
#endif

typedef	struct {
	int	s_size;
	caddr_t	s_bottom;
} Stack;

#ifdef vax
#define DISPSIZE	(8*2*4)		/* Display contains now 8 levels */
#else tahoe
#define DISPSIZE	(8*4)		/* Display contains now 8 levels */
#endif
#define	COUNTSIZE	4		/* commands counter */
#define topof(s)	((s).s_bottom + (s).s_size - (DISPSIZE + COUNTSIZE))
#define	dispof(s)	((s).s_bottom + (s).s_size - COUNTSIZE)
#define	bdispof(s)	((s).s_bottom + (s).s_size - (DISPSIZE + COUNTSIZE))
#define	timeof(s)	((s).s_bottom + (s).s_size - COUNTSIZE)
#define	realtop(s)	((s).s_bottom + (s).s_size)

typedef	struct {
	int	pi_sontime;	/* maximum sons' parallel time */
	int	pi_time;
} Sinfo;

typedef struct process {
	int	p_pid;
	int	p_ppid;
	struct process	*p_parent;
	int	p_nsons;
	int	p_nzomb;
	Sinfo	p_info;
#define	p_time	p_info.pi_time
#define	p_sontime p_info.pi_sontime
	int	p_flags;
	int	p_eventid;	/* unique id for io events */
	int	p_chid;		/* for select: channel on which io is done */
	enum	pstat { BLOCK_CHILD, BLOCK_IO, RUNNING } p_stat;
	struct process	*p_nxt,
			*p_prv;
	SavedData	p_save;
	int		p_kmode;	/* should be in saved data */
	Stack		p_stack;
	Stack		p_curstack;
} Process;

#define PF_ZOMB	1

#define NPROC 256
/* definitions for random pickings. recommended that R == NPROC */
#define	R	256.0
#define MASKR	0xff
#define	STACK_SIZE	(8*1024)	/* Default stack size = 8k */
#define	nproc NPROC

Process	*runq, *waitq, *freeq, proctable[NPROC];
extern Process *proc;

extern int	kmode;
#define	Kmode_On	 kmode++
#define	Kmode_Off	 kmode--

extern int time_ch;
extern int CommandsTime;
extern int IdleTime;

#include	"trace.h"
SHAR_EOF
fi # end of overwriting check
if test -f 'process.h'
then
	echo shar: will not over-write existing file "'process.h'"
else
cat << \SHAR_EOF > 'process.h'
#include <sys/types.h>

#ifdef vax
typedef	struct	{
	int	r2, r3, r4, r5, r6, r7, r8, r9, r10;
			/* general purpose registers */
	caddr_t	st_dp;	/* display pointer (occam ext. r11) */
	caddr_t	st_ap;	/* argument pointer */
	caddr_t	st_fp;	/* frame pointer */
	caddr_t	st_sp;	/* stack pointer */
	caddr_t	st_pc;	/* program counter */

} SavedData;
#else tahoe
typedef struct	{
	int	r2, r3, r4, r5, r6, r7, r8, r9, r10, r11;
	caddr_t	st_dp;	 	/* display pointer (r12) */
	caddr_t	st_fp;
	caddr_t	st_sp;
	caddr_t	st_pc;
} SavedData;
#endif

typedef	struct {
	int	s_size;
	caddr_t	s_bottom;
} Stack;
#define	SMASK	(char)0xbc
#define StackMask(p)	((p) == &proctable[0] :: \
			 (p)->p_stack.s_bottom[0] == SMASK)

#ifdef vax
#define DISPSIZE	(8*2*4)		/* Display contains now 8 levels */
#else tahoe
#define DISPSIZE	(8*4)		/* Display contains now 8 levels */
#endif
#define	COUNTSIZE	4		/* commands counter */
#define topof(s)	((s).s_bottom + (s).s_size - (DISPSIZE + COUNTSIZE))
#define	dispof(s)	((s).s_bottom + (s).s_size - COUNTSIZE)
#define	bdispof(s)	((s).s_bottom + (s).s_size - (DISPSIZE + COUNTSIZE))
#define	timeof(s)	((s).s_bottom + (s).s_size - COUNTSIZE)
#define	realtop(s)	((s).s_bottom + (s).s_size)

typedef	struct {
	int	pi_sontime;	/* maximum sons' parallel time */
	int	pi_time;
} Sinfo;

typedef struct process {
	int	p_pid;
	int	p_ppid;
	struct process	*p_parent;
	int	p_nsons;
	int	p_nzomb;
	Sinfo	p_info;
#define	p_time	p_info.pi_time
#define	p_sontime p_info.pi_sontime
	int	p_flags;
	int	p_eventid;	/* unique id for io events */
	int	p_chid;		/* for select: channel on which io is done */
	enum	pstat { BLOCK_CHILD, BLOCK_IO, RUNNING } p_stat;
	struct process	*p_nxt,
			*p_prv;
	SavedData	p_save;
	int		p_kmode;	/* should be in saved data */
	Stack		p_stack;
	Stack		p_curstack;
} Process;

#define PF_ZOMB	1

#define NPROC 256
/* definitions for random pickings. recommended that R == NPROC */
#define	R	256.0
#define MASKR	0xff
#define	STACK_SIZE	(8*1024)	/* Default stack size = 8k */
#define	nproc NPROC

Process	*runq, *waitq, *freeq, proctable[NPROC];
extern Process *proc;

extern int	kmode;
#define	Kmode_On	 kmode++
#define	Kmode_Off	 kmode--

extern int time_ch;
extern int CommandsTime;
extern int IdleTime;

#include	"trace.h"
SHAR_EOF
fi # end of overwriting check
cd ..
if test -f 'ext.c'
then
	echo shar: will not over-write existing file "'ext.c'"
else
cat << \SHAR_EOF > 'ext.c'
static char	rcsid[] = "$Header: ext.c,v 3.3 86/11/03 12:34:59 gil Exp $";

/*
 * $Log:	ext.c,v $
 * Revision 3.3  86/11/03  12:34:59  gil
 * buffered channels and special channels are wrapped within 'ifdefs' for
 * flexible configuration.
 *
 * Revision 3.2  86/11/02  09:09:27  gil
 * somehow the buffered-cahnnels version got in the way as revision 3.1, BEWARE.
 *
 * Revision 2.1  86/10/30  18:14:52  gil
 * This version was submitted for the project. It is free of all major bugs.
 *
 * Revision 1.1  86/01/04  14:48:59  gil
 * Initial revision
 *
 */

#include <stdio.h>
#include "trace.h"

chtabopen(tab, siz, nel)
	register int	*tab;
{
	TRACE(TRACE_IO, ("open channel table at 0x%x - %d", tab, nel));
	while (nel--)
		*tab++ = chopen(siz);
}

chtabclose(tab, nel)
	register int	*tab;
{
	TRACE(TRACE_IO, ("close channel table at 0x%x - %d", tab, nel));
	while(nel--)
		chclose(*tab++);
}

int dflag;
#define debugfp stderr
/*VARARGS1*/
debug(fmt, a1, a2, a3, a4, a5, a6)
	char *fmt;
{
	if(dflag)
		fprintf(debugfp, fmt, a1, a2, a3, a4, a5, a6);
}

bcopy(from, to, len)
	register int	*from, *to;
	register len;
{

	len >>= 2;
	while(len--)
		*to++ = *from++;
}

SHAR_EOF
fi # end of overwriting check
if test -f 'machdep.s'
then
	echo shar: will not over-write existing file "'machdep.s'"
else
cat << \SHAR_EOF > 'machdep.s'
	.globl	_SetJmp			# the _Setjmp subroutine in VAX
					# became _setjmp procedure for TAHOE
_SetJmp:
	.word	0x0
	movl	4(fp),r1
	storer	$0x1ffc,(r1)
	addl2	$44,r1
	movl	(fp),(r1)
	addl2	$4,r1
	movab	8(fp),(r1)
	addl2	$4,r1
	movl	-8(fp),(r1)
	clrl	r0
	ret

	.globl	_LongJmp		# the _Longjmp subroutine in VAX
					# became _longjmp procedure for TAHOE
_LongJmp:
	.word	0x0000
	movl	4(fp),r1
	loadr	$0x3ffc,(r1)
	addl2	$48,r1
#	movl	(r2),r1
	movl	(r1),r0
	addl2	$4,r1
#	movab	(sp),r0
#	cmpl	r1,r0				# must be a pop
#	bgequ	lj2
#	pushab	lj1
#	callf	$8,_panic
lj2:
	movl	r0,sp
	movl	$1,r0
	jmp	*(r1)

lj1:	.asciz	"longjmp"
SHAR_EOF
fi # end of overwriting check
if test -f 'chq.c'
then
	echo shar: will not over-write existing file "'chq.c'"
else
cat << \SHAR_EOF > 'chq.c'
/* $Header: chq..c,v 3.3 86/11/03 12:34:56 gil Exp $ */

/*
 * $Log:	chq.c,v $
 * Revision 3.3  86/11/03  12:34:56  gil
 * buffered channels and special channels are wrapped within 'ifdefs' for
 * flexible configuration.
 *
 * Revision 3.2  86/11/03  11:08:21  gil
 * this version supports buffered channel.
 *
 * Revision 3.1  86/11/01  15:42:53  gil
 * *** empty log message ***
 *
 */

#include <stdio.h>
#include "conf.h"
#include "process.h"
#include "chan.h"


IO(ch, tm)
	Channel	*ch;
	int	tm;
{

	if (IsTime(ch)) {
		debug("[%d] read time\n",
			ch->ch_read.b_next->b_proc - proctable);
		tread(ch, tm);
#ifdef	S_VMS
	} else if (IsVms(ch)) {
		debug("(%d) i/o in vms channel\n", chidof(ch));
		VmsIO(ch, tm);
#endif S_VMS
#ifdef S_SYS
	} else if (IsSpecial(ch)) {	/* this is s UNIX channel */
		debug("(%d) i/o in sys channel\n", chidof(ch));
		SysIO(ch, tm);
#endif S_SYS
	} else
		IoMove(ch, tm);
}

IoMove(ch, tm)
	Channel	*ch;
	int	tm;
{

	IoBlock		*rblk, *wblk;
	register	ri, wi;
	register	i, n;
	int		len;

	rblk = ch->ch_read.b_next;
	wblk = ch->ch_write.b_next;

	if (rblk->b_ndata != wblk->b_ndata)
		panic("noncompatible receive-send request on channel\n");
		
	n = rblk->b_ndata;
	for (i = 0; i < n; i++, ri++, wi++) {

		if (rblk->b_data[i].io_len != wblk->b_data[i].io_len)	
			panic("noncompatible sizes in receive-send\n");
		len = rblk->b_data[i].io_len;
		NTRACE(TRACE_IO,
		       ("[%d] sent %d bytes from %s to %s", chidof(ch), len,
		         Pinfo(wblk->b_proc), Pinfo(rblk->b_proc)));
		bcopy(wblk->b_data[i].io_data,rblk->b_data[i].io_data, len);
	}

	ReadDone(ch, tm);
	WriteDone(ch, tm);
}

#ifdef	S_SYS
SysIO(ch, tm)
	Channel	*ch;
{

	IoBlock		*rblk, *wblk;

	rblk = ch->ch_read.b_next;
	wblk = ch->ch_write.b_next;

	if (!rblk)
		SysWrite(ch, tm);
	else if (!wblk)
		SysRead(ch, tm);
	else if (rblk->b_proc->p_time < wblk->b_proc->p_time)
		SysRead(ch, tm);
	else
		SysWrite(ch, tm);
}
#endif	S_SYS

#ifdef	S_VMS
VmsIO(ch, tm)
	Channel	*ch;
{

	IoBlock		*rblk, *wblk;

	rblk = ch->ch_read.b_next;
	wblk = ch->ch_write.b_next;

	if (!rblk)
		VmsWrite(ch, tm);
	else if (!wblk)
		VmsRead(ch, tm);
	else if (rblk->b_proc->p_time < wblk->b_proc->p_time)
		VmsRead(ch, tm);
	else
		VmsWrite(ch, tm);
}
#endif	S_VMS

/* EnterRequest:
 * Enter the read/write request into the channel's read/write queue,
 */
EnterRequest(io_list, flags, len, arg_iov, id)
	IoBlock	*io_list;
	IoVec	*arg_iov;
{

	register IoBlock	*blk;
	register IoBlock	*iob;
	register IoBlock	*ip;
	register	i;

	blk = new(ioblock);

	for (iob = io_list; iob->b_next; iob = iob->b_next)
		;
	blk->b_next = iob->b_next;
	iob->b_next = blk;	

	blk->b_ndata = len;
	blk->b_proc = proc;
	blk->b_id   = id;
	blk->b_data = (IoVec *)calloc(len, sizeof(IoVec));
	for(i = 0; i < len; i++)
		blk->b_data[i] = *arg_iov++;
		/* notice: this means that iov.io_data is passed
		 : by REFERENCE */
}

ReadDone(ch, time)
	Channel	*ch;
{
	register IoBlock	*ip;

	ip = ch->ch_read.b_next;
	ip->b_proc->p_time = time;
	ip->b_proc->p_chid = chidof(ch);
	ip->b_proc->p_eventid = 0;
		unblock(ip->b_proc, BLOCK_IO);
	free(ip->b_data);
	ch->ch_read.b_next = ip->b_next;
	free(ip);
}

WriteDone(ch, time)
	Channel	*ch;
{
	register IoBlock	*ip;
	register		n;

#ifdef	BUFF_CHANS
	/* notice: we walk n steps (and not n-1) because the current IO is
 	 * not freed yet. */
	for (ip = ch->ch_write.b_next, n = ch->ch_siz;
	     ip && n > 0;
	     ip = ip->b_next, n--)
		;

	if (ip) {
		ip->b_proc->p_time = time;
		unblock(ip->b_proc, BLOCK_IO);
	}

	ip = ch->ch_write.b_next;

#else	BUFF_CHANS
	ip = ch->ch_write.b_next;
	ip->b_proc->p_time = time;
	unblock(ip->b_proc, BLOCK_IO);
#endif	BUFF_CHANS

	free(ip->b_data);
	ch->ch_write.b_next = ip->b_next;
	free(ip);
}


TimeOf(ch)
	Channel	*ch;
{
/* return -1 if no I/O ready on 'ch', otherwise return the time of the I/O
 * operation
 */

	register IoBlock	*rfirst, *wfirst, *temp;
	IoVec			*iov;

	Expire(ch);

	rfirst = ch->ch_read.b_next;
	wfirst = ch->ch_write.b_next;

	if (IsTime(ch)) {
		if (rfirst == NULL)
			return -1;
		return(rfirst->b_proc->p_time);
	}

#ifdef	S_SYS
	if (IsSpecial(ch)) {
	
		if (rfirst && wfirst)
			return (
			  min(rfirst->b_proc->p_time,wfirst->b_proc->p_time)
			);

		if (rfirst)
			return(rfirst->b_proc->p_time);

		if (wfirst)
			return(wfirst->b_proc->p_time);

		return -1;
	}
#endif	S_SYS
	
	if (!rfirst :: !wfirst) {
		return -1;
	}
		
	debug("channel %d is ready for I/O\n", chidof(ch));

	return (max(wfirst->b_proc->p_time, rfirst->b_proc->p_time));
}


Expire(ch)
	Channel	*ch;
{

	register IoBlock	*rfirst;
	register IoBlock	*Iob;

	rfirst = &ch->ch_read;
	while (rfirst->b_next &&
	       rfirst->b_next->b_next->b_id &&
	       rfirst->b_next->b_proc->p_eventid != rfirst->b_next->b_id)
	{
		Iob = rfirst->b_next;
		rfirst->b_next = Iob->b_next;
		free(Iob->b_data);
		free(Iob);
	}
}

Size(Ioq)
	register IoBlock	*Ioq;
{
	register	i;

	for (i = 0; Ioq; Ioq = Ioq->b_next, i++)
		;
	return i;
}
SHAR_EOF
fi # end of overwriting check
if test -f 'stck.c'
then
	echo shar: will not over-write existing file "'stck.c'"
else
cat << \SHAR_EOF > 'stck.c'
static char	rcsid[] = "$Header: stck.c,v 3.2 86/11/03 12:35:11 gil Exp $";

/*
 * $Log:	stck.c,v $
 * Revision 3.2  86/11/03  12:35:11  gil
 * buffered channels and special channels are wrapped within 'ifdefs' for
 * flexible configuration.
 *
 * Revision 3.1  86/11/01  15:45:04  gil
 * A cleaner version, with timeout forced before each synchronization event.
 *
 * Revision 2.1  86/10/30  18:15:02  gil
 * This version was submitted for the project. It is free of all major bugs.
 *
 * Revision 1.1  86/01/04  14:49:05  gil
 * Initial revision
 *
 */

#include <stdio.h>
#include "conf.h"
#include "process.h"

caddr_t	StackBase;
int	StackReserve = 128;

Stack	NextStack;

extern kmode;

#ifdef vax
StackExpand(addr, sz, ap)
	caddr_t	addr, ap;
{
	register caddr_t	r11, r10, r9;
	int i;
	Stack	s, NewStack();

	Kmode_On;

	s = proc->p_curstack;
	proc->p_curstack = NextStack;
	r10 = realtop(proc->p_curstack);
/*	printf("stack expand addr: %x sz %d ap %x\n", addr, sz, ap); */
	write(1, "#", 1);
	asm("movl r10,sp")
/* call to functions will be executed on the new stack from this point */
	if(proc->p_curstack.s_size < (i = sz + StackReserve * 2)) {
		proc->p_curstack = NewStack(i);
		r10 = realtop(proc->p_curstack);
		asm("movl r10,sp")
	} else
		NextStack = NewStack(0);
		
	SetStack(&(proc->p_curstack));
	Kmode_Off;
	r10 = ap;
	r9 = addr;
	asm("callg (r10),(r9)")
	Kmode_On;
	FreeStack(proc->p_curstack);
	proc->p_curstack = s;
	SetStack(&(proc->p_curstack));
	Kmode_Off;
}
#else
StackExpand() {}
#endif

SetStack(s)
	register Stack	*s;
{
	StackBase = s->s_bottom;
}

#ifdef notdef
stacktrace() {
	register r12, r11;

	r12 = 0;
#ifdef tahoe
	asm("moval	(sp),r12")
	asm("movl	fp,r11")
#else vax
	asm("movl	sp, r11")
	asm("movl	fp, r10")
#endif
	fprintf(stderr, "proc: %d base: %x top: 0x%x sp: 0x%x fp: 0x%x used: %d\n",
		proc->p_pid, proc->p_stack.s_bottom,
		realtop(proc->p_stack), r12, r11, realtop(proc->p_stack)-r12);
}
#endif
SHAR_EOF
fi # end of overwriting check
if test -f 'test.c'
then
	echo shar: will not over-write existing file "'test.c'"
else
cat << \SHAR_EOF > 'test.c'
static char	rcsid[] = "$Header: test.c,v 3.1 86/11/01 15:45:06 gil Exp $";

/*
 * $Log:	test.c,v $
 * Revision 3.1  86/11/01  15:45:06  gil
 * A cleaner version, with timeout forced before each synchronization event.
 *
 * Revision 2.1  86/10/30  18:15:05  gil
 * This version was submitted for the project. It is free of all major bugs.
 *
 * Revision 1.1  86/01/04  14:49:07  gil
 * Initial revision
 *
 */

test(){}

SHAR_EOF
fi # end of overwriting check
if test -f 'vmschan.c'
then
	echo shar: will not over-write existing file "'vmschan.c'"
else
cat << \SHAR_EOF > 'vmschan.c'
static	char	*rcsid = "$Header: vmschan.c,v 3.2 86/11/03 12:35:16 gil Exp $";
#include <stdio.h>
#include "conf.h"
#include "process.h"
#include "chan.h"
#include <sys/ioctl.h>
#include "vmsio.h"
#define	IsAtty	isatty

extern	char	*calloc();

#ifdef	S_VMS
	
chat(chid, vmsfd)
{
	Channel	*ch;
	
	ch = chanof(chid);
	ch->ch_flags = CH_VMS;
	ch->ch_fd = vmsfd;
}

VmsInit(av)
	char	**av;
{
	static	char	vmsbuf[256];

	while(*av) {
		strcat(vmsbuf, *av);
		if(*++av == NULL)
			break;
		strcat(vmsbuf, " ");
	}
	StdFile[C_Parameters].vms_stat = ARGSTR;
	StdFile[C_Parameters].vms_name = vmsbuf;

	StdFile[C_Keyboard].vms_stat = NORMAL;
	StdFile[C_Keyboard].vms_fp = stdin;

	StdFile[C_Screen].vms_stat = NORMAL;
	StdFile[C_Screen].vms_fp = stdout;
}


VmsWrite(ch, tm)
	Channel	*ch;
{
	IoBlock		*wblk;
	IoVec		*vv;
	register	i;
	int		len;
	VmsChan		*vc;

	vc = VFile(ch->ch_fd);
	
	wblk = ch->ch_write.b_next;
	vv = wblk->b_data;
	len = wblk->b_ndata;
	for(i = 0; i < len; i++, vv++) {
		if(vv->io_len != WORDSIZE)
			panic("non word messages are not alloud in Vms\n");
		Vwrite(vc, *vv->io_data);
	}
	WriteDone(ch, tm);
}

VmsRead(ch, tm)
	Channel	*ch;
{
	IoBlock		*rblk;
	IoVec		*vv;
	int		len;
	register 	i;
	VmsChan		*vc;

	vc = VFile(ch->ch_fd);
	
	rblk = ch->ch_read.b_next;
	vv = rblk->b_data;
	len = rblk->b_ndata;
	for(i = 0; i < len; i++, vv++) {
		if(vv->io_len != WORDSIZE)
			panic("non word messages are not alloud in Vms\n");
		Vread(vc, vv->io_data);
	}
	ReadDone(ch, tm);
}

VmsSelect() {
	panic("vms select not implemented yet");
	return 0;
}

Vread(vc, c)
	VmsChan	*vc;
	int	*c;
{
	int	cnt;

	if(vc->vms_message) {
		*c = vc->vms_message;
		vc->vms_message = 0;
		return;
	}
	if(vc->vms_stat == ARGSTR) {
		if((*c = *(vc->vms_name)) == '\0')
			*c = V_EndParameterString;
		else
			vc->vms_name++;
		return;
	}
	if(vc->vms_fp == NULL)
		panic("vms: can't read from closed file\n");
	if((vc->vms_fp->_flag & _IOREAD) == 0)
		panic("vms: file not open for reading\n");
again:
	if(vc->vms_fp->_cnt > 0) {
		*c = Getc(vc->vms_fp);
		return;
	}
	if(feof(vc->vms_fp)) {
		*c = V_EndFile;
		return;
	}
	if(IsAtty(vc->vms_fp)) {
		do
			ioctl(fileno(vc->vms_fp), FIONREAD, &cnt);
		while(cnt == 0 && vc->vms_fp->_cnt == 0 && Swtch());
		goto again;
	} else
		*c = Getc(vc->vms_fp);
}

Swtch() {
	swtch();
	return 1;
}

Getc(fp)
	FILE	*fp;
{
	int c;

	if((c = getc(fp)) == EOF) {
		if(ferror(fp))
			c = E_ReadFailed;
		else
			c = V_EndFile;
	}
	else if(c == '\n')
		c = V_EndRecord;
	return c;
}

Flush(vc)
	VmsChan	*vc;
{
	fflush(vc->vms_fp);
	if(ferror(vc->vms_fp))
		vc->vms_message = E_WriteFailed;
	else
		vc->vms_message = V_NextRecord;
}

Vwrite(vc, c)
	VmsChan	*vc;
{
	if(c < 0)
		goto control;

write:
	if(vc->vms_stat == NORMAL) {
		if(vc->vms_fp == NULL)
			panic("try to write on a closed file\n");
		putc(c, vc->vms_fp);
		if(c == '\n')
			Flush(vc);
	} else
	if(vc->vms_stat == FILENAME)
		AddC(vc, c);
	return;

control:
	switch (c) {
		case V_EndRecord:
			c = '\n';
			goto write;

		case V_NextRecord:
			break;

		case V_EndBuffer:
			if(vc->vms_fp == NULL)
				panic("flushing a closed file\n");
			Flush(vc);
			break;

		case V_OpenForRead:
			vc->vms_message = V_OpenForRead;
			vc->vms_stat = FILENAME;
			vc->vms_name = calloc(256, 1); /* XXX */
			break;

		case V_OpenForWrite:
			vc->vms_message = V_OpenForWrite;
			vc->vms_stat = FILENAME;
			vc->vms_name = calloc(256, 1); /* XXX */
			break;

		case V_EndName:
			OpenFile(vc);
			break;

		case V_CloseFile:
			CloseFile(vc);
			break;

		case V_EndFile:
			Flush(vc);
			break;
		default:
			panic("bad request\n");
	}
}

OpenFile(vc)
	VmsChan	*vc;
{
	char	*ms;

	if(vc->vms_message == V_OpenForRead)
		ms = "r";
	else
		ms = "w";
	vc->vms_fp = fopen(vc->vms_name+1, ms);
	if(vc->vms_fp == NULL)
		vc->vms_message = (vc->vms_message == V_OpenForRead) ?
				E_InputFileNotOpened :
				E_OutputFileNotCreated;
	else
		vc->vms_message = V_OpenedOK;
	vc->vms_stat = NORMAL;
	free(vc->vms_name);
}

AddC(vc, c)
	VmsChan	*vc;
{
	vc->vms_name[++(vc->vms_name[0])] = c;
}

CloseFile(vc)
	VmsChan	*vc;
{
	if(vc->vms_fp == NULL)
		panic("trying to close a closed file\n");
	fclose(vc->vms_fp);
	vc->vms_message = V_ClosedOK;
	vc->vms_fp = NULL;
}
#endif	S_VMS
SHAR_EOF
fi # end of overwriting check
if test -f 'chan.c'
then
	echo shar: will not over-write existing file "'chan.c'"
else
cat << \SHAR_EOF > 'chan.c'
static char	rcsid[] = "$Header: chan.c,v 3.4 86/11/03 12:34:21 gil Exp $";

/*
 : $Header: chan.c,v 3.4 86/11/03 12:34:21 gil Exp $
 */

/* $Log:	chan.c,v $
 * Revision 3.4  86/11/03  12:34:21  gil
 * buffered channels and special channels are wrapped within 'ifdefs' for
 * flexible configuration.
 *
 * Revision 3.3  86/11/03  11:08:08  gil
 * this version supports buffered channel.
 *
 * Revision 3.2  86/11/02  09:37:03  gil
 * fixed the race (Kmode_On should be BEFORE resched).
 *
 * Revision 3.1  86/11/01  15:48:04  gil
 * A cleaner version, with timeout forced before each synchronization event.
 *
 * Revision 2.1  86/10/30  18:14:49  gil
 * This version was submitted for the project. It is free of all major bugs.
 *
 * Revision 1.4  86/08/04  17:24:35  gil
 * 1. fixed few bugs
 * 2. change format of tracing messages
 *
 * Revision 1.3  86/05/29  10:28:49  gil
 * this version fits the new ready-requests-queue mechanism.
 *
 */

#include <stdio.h>
#include "conf.h"
#include "process.h"
#include "chan.h"

Channel	chans[MAX_CHANS];
Channel	*free_chans;

extern char	*calloc();
int	Eventid = 1;
int	time_ch;		/* keep the special time channel */

InitChans() {

	register i, j;
	
	for(i = 0, j = MAX_CHANS - 1; i < j; i++)
		chans[i].ch_nxt = &chans[i+1];
	chans[j].ch_nxt = NULL;
	free_chans = chans;
}

chopen(siz)
{

	register Channel *ch;

	Kmode_On;
	if (free_chans == NULL) {
		panic("no more channels\n");
		/*NOTREACHED*/
	}
	ch = free_chans;
	free_chans = free_chans->ch_nxt;
	Kmode_Off;
	TRACE(TRACE_IO, ("opened %d(%d)", ch-chans, siz));
	ch->ch_siz = siz;
	ch->ch_read.b_next = NULL;
	ch->ch_write.b_next = NULL;
	return (ch - chans);
}

chclose(chid) {

	register Channel *ch;

	Kmode_On;	
	if (chid < 0 :: chid >= MAX_CHANS)
		panic("bad channel\n");
	ch = &chans[chid];
	ch->ch_nxt = free_chans;
	free_chans = ch;
	ch->ch_read.b_next = 0;
	ch->ch_write.b_next = 0;
	TRACE(TRACE_IO, ("closed %d", chid));
	Kmode_Off;
}

chread(chid, flags, len, iov)
	IoVec	iov;
{

	register Channel	*ch;
	register		tm;

	ch = chanof(chid);
	timesync(proc);
	TRACE(TRACE_IO, ("read on %d", chid));
	if (IsTime(ch) && (flags & BD_FAFTER)) {
		proc->p_time =
		   max(proc->p_time, *((int *)(iov.io_data)));
		timewrite(proc);
		return;
	}
	Kmode_On;
	resched(0);
	EnterRequest(&(ch->ch_read), flags, len, &iov, 0);
	if ((tm = TimeOf(ch)) >= 0)
		IO(ch, tm);
	else
		block(proc, BLOCK_IO);
	Kmode_Off;
}

chwrite(chid, flags, len, iov)
	IoVec	iov;
{

	register Channel *ch;
	register	tm;

	ch = chanof(chid);
	timesync(proc);
	TRACE(TRACE_IO, ("write on %d", chid));
	Kmode_On;
	resched(0);
	EnterRequest(&(ch->ch_write), flags, len, &iov, 0);
	if ((tm = TimeOf(ch)) >= 0)
		IO(ch, tm);
#ifdef	BUFF_CHANS
	else if (!ch->ch_siz :: Size(ch->ch_write.b_next) > ch->ch_siz)
#else
	else
#endif
		block(proc, BLOCK_IO);
	Kmode_Off;
}

char *
chselect(nargs, arg1)
{
	struct IoReq {
		int	chid;
		int	nret;	/* saved data buf length */
		int	flags;
		int	len;
		IoVec	iov;
		/* Saved data [nret*4] */
	} *ap = (struct IoReq *)&arg1, *cp = ap;
	Channel *ch;
/*
 : This requires explanation:
 : We push quintets of 	< chid, nret, flags, len, iov >	as accepted
 : by 'chread'/'chwrite'. the problem is the 'iov' is actually a vector
 : of struct IoVec, and its length is given by 'len', and at the end of
 : each quintet is a data-buffer of length 'nret' * intsize.
 : So, when we advance to next quintet, the increment is of dynamic size,
 : which is:
 : 		sizeof (chid)
 :	    +	sizeof (flags)
 :	    +	sizeof (len)
 :	    +	sizeof (nret)
 :	    +	len * sizeof (iov)
 :	    +	nret * sizeof (int)
*/

	register i, n;
	int	ret;
	char	*p;
	char	b[5];
	static char buf[512];
	Channel	*chose = NULL;

	Kmode_On;
	Eventid++;
	sprintf(buf, "select on:");
	proc->p_eventid = Eventid;
	timesync(proc);
	resched(1);	/* let all the write-requests to get ready */
	resched(1);	/* let all the write-requests be acutally delivered */
	for(n = 1, i = nargs; i > 0; i--) {
		sprintf(b, " %d", cp->chid);
		strcat(buf, b);
		ch = chanof(cp->chid);
		EnterRequest(&(ch->ch_read), cp->flags, cp->len,
							&(cp->iov), Eventid);
		if (TimeOf(ch) >= 0) {
			if ((random() & MASKR) < (R / (float)n))
				/* first one alwaysgets chosen */
				chose = ch;
			n++;
		}
		cp = (struct IoReq *) ((char *)cp +
					sizeof(IoVec) * (cp->len-1) +
					cp->nret * sizeof(int));
		cp++;
	}
	TRACE(TRACE_IO, (buf));
	if (chose != NULL)
		IO(chose, TimeOf(chose));
	else
		block(proc, BLOCK_IO);

	for(cp = ap, i = nargs; i > 0; i--) {
		if(cp->chid == proc->p_chid) {
			p = (char *)(cp+1) + (cp->len - 1)* sizeof(IoVec);
			debug("chselect: 1st reg is %d\treg mask %x\n",
				((int *)p)[1], *((int *)p));
			debug("chselect: len = %d\n", cp->len);
			TRACE(TRACE_IO,
			      ("channel %d selected", cp->chid));
			Kmode_Off;
			return p;
		}
		cp = (struct IoReq *) ((char *)cp +
					sizeof(IoVec) * (cp->len-1) +
					cp->nret * sizeof(int));
		cp++;
	}
	panic("select channel disappeared");
	Kmode_Off;
}
SHAR_EOF
fi # end of overwriting check
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
# configurable parameters.
################################################################################
DESTDIR=/m/usr/gil
CC=cc
AS=as

CFLAGS=-Ih -g
################################################################################

LIB=lsim.a
OBJS=	chan.o\
	chq.o\
	ext.o\
	machdep.o\
	proto.o\
	sched.o\
	stck.o\
	sysio.o\
	test.o\
	vmschan.o\
	${EMPTY}

$(LIB): $(OBJS)
	ar cr $(LIB) $(OBJS)
	ranlib $(LIB)

install: $(LIB)
	mv $(LIB) $(DESTDIR)/lib/lsim.a
	ranlib $(DESTDIR)/lib/lsim.a

# dependencies on header files
################################################################################
chan.c:	h/conf.h
chan.c:	h/process.h
chan.c:	h/chan.h

chq.c:	h/conf.h
chq.c:	h/process.h
chq.c:	h/chan.h

ext.c:	h/trace.h

sched.c:	h/conf.h
sched.c:	h/process.h

stck.c:	h/conf.h
stck.c:	h/process.h

sysio.c:	h/conf.h
sysio.c:	h/process.h
sysio.c:	h/chan.h

vmschan.c:	h/conf.h
vmschan.c:	h/process.h
vmschan.c:	h/chan.h
vmschan.c:	h/vmsio.h
SHAR_EOF
fi # end of overwriting check
if test -f 'machdep.s.vax'
then
	echo shar: will not over-write existing file "'machdep.s.vax'"
else
cat << \SHAR_EOF > 'machdep.s.vax'
#	set/long jmp, no documatation since the source got lost, this is a
# disassembly.
		.globl	_SetJmp
_SetJmp:	.word 0x0
		movl	4(ap),r1
		movq	r2,(r1)+
		movq	r4,(r1)+
		movq	r6,(r1)+
		movq	r8,(r1)+
		movq	r10,(r1)+
		movq	8(fp),(r1)+
		moval	4(ap),(r1)+
		movl	16(fp),(r1)+
		movl	$0,r0
		ret

		.globl	_LongJmp
_LongJmp:	.word 0x0
		movl	4(ap),r1
		movq	(r1)+,r2
		movq	(r1)+,r4
		movq	(r1)+,r6
		movq	(r1)+,r8
		movq	(r1)+,r10
		movq	(r1)+,ap
		movl	(r1)+,sp
		movl	$1,r0
		jmp	*(r1)
SHAR_EOF
fi # end of overwriting check
if test -f 'sched.c'
then
	echo shar: will not over-write existing file "'sched.c'"
else
cat << \SHAR_EOF > 'sched.c'
static char rcsid[] = "$Header: sched.c,v 3.3 87/02/17 10:55:41 gil Exp $";

/*
 * $Log:	sched.c,v $
 * Revision 3.3  87/02/17  10:55:41  gil
 * Eventid removed.
 *
 * Revision 3.2  86/11/03  12:35:07  gil
 * buffered channels and special channels are wrapped within 'ifdefs' for
 * flexible configuration.
 *
 * Revision 3.1  86/11/01  15:42:58  gil
 * *** empty log message ***
 *
 * Revision 2.1  86/10/30  18:14:59  gil
 * This version was submitted for the project. It is free of all major bugs.
 *
 * Revision 1.6  86/07/07  17:08:34  gil
 * Cleaner version.
 * Removed cpu clock, sched and unused variables.
 *
 * Revision 1.5  86/07/07  16:47:12  gil
 * Working version.
 *
 * Revision 1.3  86/03/24  14:55:52  gil
 * added time synchronization for waiting processes.
 *
 * Revision 1.2  86/03/17  13:50:58  gil
 * *** empty log message ***
 *
 */

#include <stdio.h>
#include <sys/time.h>
#include "conf.h"
#include "process.h"

#define max(a, b)	((a) > (b) ? (a) : (b))

Process *proc;
/* dummy-firsts for: */
Process	wdummy,				/* wait-queue */
	rdummy,				/* run-queue */
	fdummy;				/* free-queue */

int	kmode;
extern	char	*malloc();	

#ifdef vax
#define savefp()	asm("	movl 12(fp), r11")
#define	saveap()	asm("	movl 8(fp),  r11")
#else tahoe
#define savefp()	asm("	movl (fp), r12")
#endif

Process *
nextrun()
{
	Process *run;

	run = runq->p_nxt;
	if (run == NULL)
		Deadlock();

	return run;
}

swtch() {
	register caddr_t fp;	/* must be r11(vax) r12(tahoe) */
	register Process *p;
	int	savedkmode = 0;

	p = nextrun();

	savefp();
	if(proc && !StackMask(proc))
		panic("Process Stack Underflow");
	if(p == proc)		/* no context switching is done - return */
		return;
	if(proc != NULL)
		if(save(proc)) {		/* save status */
			debug("start %d with kmode %d\n",
					proc-proctable, savedkmode);
			return;
		}
	
	if(!StackMask(p))
		panic("Process %s Stack Damaged", Pinfo(p));
	TRACE(TRACE_CSW, ("switching to %s", Pinfo(p)));
	resume(p);		/* transfer control to p - return on previous
				 : line... */
}

save(p)
	Process *p;
{

	p->p_kmode = kmode;
	return SetJmp(&(p->p_save));
}

resume(p)
	Process *p;
{
	debug("resuming %d pc %x\n", (p - proctable), p->p_save.st_pc);
	proc = p;
	SetStack(&(proc->p_curstack));
	kmode = p->p_kmode;
	sigsetmask(0);
	LongJmp(&(p->p_save));
	/*NOTREACHED*/
}

/* tick - interupt routine, called on each clock tick. */
tick() {

	if (kmode) {
		sigsetmask(0);
		return;
	}
	Kmode_On;
	resched(0);
	debug("kmode: %d\n", kmode);
	Kmode_Off;
	return;
}

resched(pri)
{
	if (proc != NULL) {
		timesync(proc);
		FreeMe(proc);
		if (pri)
			PriEnterMe(proc, runq);
		else
			EnterMe(proc, runq);
	}
	swtch();
}

int	DefaultStackSize = STACK_SIZE;

Stack
NewStack(sz)
{
	Stack s;

	if(sz == 0)
		sz = DefaultStackSize;
	s.s_bottom = malloc(sz);
	if(s.s_bottom == NULL)
		panic("alloc stack failed\n");
	s.s_bottom[0] = SMASK;
	s.s_size   = sz;
	return s;
}

FreeStack(s)
	Stack	s;
{
	free(s.s_bottom);
}

Process *
freeslot() {
	register Process *p;

	p = freeq->p_nxt;
	if(p == NULL)
		panic("no more process\n");
	freeq->p_nxt = p->p_nxt;
	p->p_nxt = NULL;
	p->p_prv = NULL;
	return p;
}

newproc(addr)
	caddr_t addr;
{
	register caddr_t save;	/* Must be in r11 (r12 on tahoe) */
/****	Don't use any other register for local storage	****/
	Process *p, *q;

	Kmode_On;
	p = proc;
	p->p_nsons++;

	q = freeslot();

	q->p_pid = genpid();
	q->p_ppid = p->p_pid;
	q->p_parent = p;
	q->p_nzomb = q->p_nsons = q->p_sontime = 0;
	timesync(p);
	q->p_time = p->p_time;	/* start with father's time */
	q->p_flags = 0;
	q->p_stack = NewStack(0);
	q->p_curstack = q->p_stack;
	SetJmp(&(q->p_save));
	q->p_save.st_dp = dispof(q->p_stack);
#ifdef vax
	saveap();
	q->p_save.st_ap = save;
#endif
	savefp();
	q->p_save.st_fp = save;
	q->p_save.st_sp = topof(q->p_stack);
	q->p_save.st_pc = addr;
	q->p_kmode = 0;
	/* Initialize the display */
	bcopy(bdispof(p->p_stack), bdispof(q->p_stack), DISPSIZE);
	timewrite(q);
	TRACE(TRACE_FORK, ("create %d at 0x%x", q->p_pid, addr));
	setrun(q);
	Kmode_Off;
	return;
}

endproc() {

	Kmode_On;
	timesync(proc);
	TRACE(TRACE_FORK, ("ended"));
	debug("endproc %d\n", proc - proctable);
	FreeMe(proc);
	if(proc->p_parent) {
		proc->p_parent->p_nsons--;
		WakePapa(proc->p_parent);
		/* Dalia was slightly drunk when she wrote this.
		 : please don't change */
	}
	if (proc->p_nsons > 0 :: proc->p_nzomb > 0) {
		proc->p_flags := PF_ZOMB;
		if(proc->p_parent)
			proc->p_parent->p_nzomb++;
		while(proc->p_nsons > 0 :: proc->p_nzomb > 0)
			block(proc, BLOCK_CHILD);
		if(proc->p_parent)
			proc->p_parent->p_nzomb--;
		WakePapa(proc->p_parent);
	}
	EnterMe(proc, freeq);
	FreeStack(proc->p_stack);
	proc = NULL;
	swtch();
	/*NOTREACHED*/
}

setrun(p)
	Process *p;
{
	debug("setrun: %d\n", p-proctable);
	p->p_stat = RUNNING;
	EnterMe(p, runq);
}

WakePapa(papa)
	Process *papa;
{
	if(papa) {
		papa->p_sontime = max(papa->p_sontime, proc->p_time);
		if(papa->p_nsons == 0)
			unblock(papa, BLOCK_CHILD);
	}
}

waitall() {

	Kmode_On;
	timesync(proc);
	while (proc->p_nsons > 0)
		block(proc, BLOCK_CHILD);

	proc->p_time = proc->p_sontime;
	proc->p_sontime = 0;
	timewrite(proc);
	Kmode_Off;
}

genpid() {
	static pid = 1;

	return pid++;
}

extern Stack	NextStack;

initproc() {
	register j, i;

	Kmode_On;
	NextStack = NewStack(0);
	for(i = 1, j = nproc - 1; i < j; i++) {
		proctable[i].p_nxt = &proctable[i+1];
		proctable[i+1].p_prv = &proctable[i];
	}
	proctable[j].p_nxt = NULL;

	freeq = &fdummy;
	fdummy.p_nxt = &proctable[1];
	proctable[1].p_prv = freeq;

	wdummy.p_nxt = wdummy.p_prv = NULL;
	waitq = &wdummy;

	proc = &proctable[0];
	runq = &rdummy;
	rdummy.p_nxt = proc;
	rdummy.p_prv = NULL;
	proc->p_prv = runq;

	Kmode_Off;
}

block(p, block_stat)
	Process	*p;
	enum pstat block_stat;
{

	TRACE(TRACE_BLOCK, ("blocked, on %s", BlockStat(block_stat)));
	debug("block %d\n", p - proctable);
	p->p_stat = block_stat;
	FreeMe(p);
	EnterMe(p, waitq);
	if (proc == p)
		swtch();
}

unblock(p, block_stat)
	Process	*p;
	enum pstat block_stat;
{

	debug("unblock %d\n", p - proctable);
	TRACE(TRACE_BLOCK,
	      ("unblock %s, on %s", Pinfo(p), BlockStat(block_stat)));
	if (p->p_stat == block_stat) {
		timewrite(p);
		FreeMe(p);
		setrun(p);
	}
}

EnterMe(pp, queue)
	Process	*pp, *queue;
{

	register		n;
	register Process	*q, *chose;

	for (q = queue;
	     q->p_nxt && q->p_nxt->p_time < pp->p_time;
	     q = q->p_nxt)
		;

	for (chose = q, n = 2;
	     q->p_nxt && q->p_nxt->p_time == pp->p_time;
	     q = q->p_nxt, n++)
	
	     	if ((random() & MASKR) < (R / (float)n))
			chose = q->p_nxt;

	pp->p_nxt = chose->p_nxt;
	pp->p_prv = chose;
	if (chose->p_nxt)
		chose->p_nxt->p_prv = pp;
	chose->p_nxt = pp;
}

PriEnterMe(pp, queue)
	Process	*pp, *queue;
{

	register Process	*q;

	for (q = queue;
	     q->p_nxt && q->p_nxt->p_time <= pp->p_time;
	     q = q->p_nxt)
		;

	pp->p_nxt = q->p_nxt;
	pp->p_prv = q;
	if (q->p_nxt)
		q->p_nxt->p_prv = pp;
	q->p_nxt = pp;
}

FreeMe(p)
	Process	*p;
{

	register Process *q;

	q = p->p_nxt;
	if(p->p_prv != NULL)
		p->p_prv->p_nxt = q;
	if(q != NULL)
		q->p_prv = p->p_prv;
}

Deadlock() {

	if (waitq->p_nxt != NULL)
		panic("deadlock\n");
	printf("process terminated successfully\n");
	exit(0);
}

timesync(p)
	Process	*p;
{
	p->p_time = *(int *)timeof(p->p_stack);
	debug("[%d] time %d\n", proc-proctable, p->p_time);
}

timewrite(p)
	Process	*p;
{
	*(int *) timeof(p->p_stack) = p->p_time;
}
SHAR_EOF
fi # end of overwriting check
if test -f 'proto.c'
then
	echo shar: will not over-write existing file "'proto.c'"
else
cat << \SHAR_EOF > 'proto.c'
static char	rcsid[] = "$Header: proto.c,v 3.2 86/11/03 12:35:04 gil Exp $";

/*
 * $Log:	proto.c,v $
 * Revision 3.2  86/11/03  12:35:04  gil
 * buffered channels and special channels are wrapped within 'ifdefs' for
 * flexible configuration.
 *
 * Revision 3.1  86/11/01  15:48:08  gil
 * A cleaner version, with timeout forced before each synchronization event.
 *
 * Revision 2.1  86/10/30  18:14:57  gil
 * This version was submitted for the project. It is free of all major bugs.
 *
 * Revision 1.1  86/01/04  14:49:02  gil
 * Initial revision
 *
 */

#include	<stdio.h>
#include	<signal.h>
#include	<sys/time.h>
#include 	"conf.h"
#include	"process.h"

extern tick();
#define	ALOT	(512*1024)
static char	display[DISPSIZE+COUNTSIZE];
extern	dflag;
int	qflag;
extern	DefaultStackSize, StackReserve;
char	*progname;
int	CommandsTime;

main(ac, av)
	char **av;
{
	register char *r11, i = 25;
	int	oc_main();


	progname = av[0];
	tracef = stderr;

	setlinebuf(stderr);
	while(**++av == '-')
	switch(*++*av) {
		case 'd':
			dflag++;
			break;
		case 's':
			{
			int s = atoi(++*av);
			if(s < DISPSIZE+64) {
			    	fprintf(stderr, "%d: Stack too small\n", s);
				break;
			    }
			debug("StackSize: %d\n", s);
			DefaultStackSize = s;
			break;
			}
		case 'r':
			{
			int s = atoi(++*av);
			if(s < 0) {
			    	fprintf(stderr, "Cannot UnReserve stack\n");
				break;
			    }
			debug("ReserveStack: %d\n", s);
			StackReserve = s;
			break;
			}
		case 'i':
			i = atoi(++*av);
			if(i < 1) {
			fprintf(stderr, "%d: Bad interval\n",
				i);
				i = 25;
			     }
			    debug("Will interupt %d times/sec\n", i);
			break;
		case 't':
			if(*++*av == '\0')
				tracer := TRACE_ALL;
			else
				tracer := tflag(*av);
			break;
		case 'q':
			qflag++;
			break;
		case 'f':
			if(*++*av == '\0')
				tracef = stdout;
			else {
				if((tracef = fopen(*av, "w")) == NULL) {
					fprintf(stderr,
					       "Cannot open trace file ");
					fflush(stderr);
					perror(*av);
					exit(1);
				}
			}
			break;
	
		default:
			fprintf	(stderr, "%c: Unknown option\n", **av);
			break;
	}
	srandom((int)time(0));
	initproc();
	InitChans();
#ifdef	S_VMS
	VmsInit(av);
#endif	S_VMS
	signal(SIGVTALRM, tick);
	inton(i);
	r11 = &display[DISPSIZE+COUNTSIZE];
	proc->p_stack.s_bottom = r11 - ALOT;
	proc->p_stack.s_size	 = ALOT;
	newproc(oc_main);
	test();
	waitall();
	if(!qflag)
		fprintf(stderr,
			"Executed %d instructions in %d time\n",
			CommandsTime, proctable[0].p_time);
	exit(0);
}

intoff() {
	struct itimerval it;
	it.it_interval.tv_sec = it.it_value.tv_usec = 0;
	it.it_value = it.it_interval;
	setitimer(ITIMER_VIRTUAL, &it, 0);
}

int	Ival;			/* IPS */

inton(t) {
	struct itimerval it;

	Ival = t;
	it.it_interval.tv_usec = 1000000/t;
	it.it_interval.tv_sec = 0;
	it.it_value = it.it_interval;
	setitimer(ITIMER_VIRTUAL, &it, 0);
}

panic(s, a1, a2, a3, a4) {
	fprintf(stderr, "Panic: %s: ", Pinfo(proc));
	fprintf(stderr, s, a1, a2, a3, a4);
	putc('\n', stderr);
	exit(1);
}


tflag(s)
	char	*s;
{
	int f = 0;

	while(*s) {
		switch (*s) {
			case 'c':
				f := TRACE_CSW;
				break;
			case 'f':
			case 's':
				f := TRACE_FORK;
				break;
			case 'b':
				f := TRACE_BLOCK;
				break;
			case 'a':
				f := TRACE_ALLIO;
				break;
			case 'i':
				f := TRACE_IO;
				break;
			default:
				fprintf(stderr, "%c: unknown trace flag\n",
					*s);
					break;
		}
		s++;
	}
	return f;
}

int	tracer;
char	*tstr = "\1CSW\0\2FORK\0\4BLOCK\0\010TIME\0\020IO\0\040MOREIO\0\100CPUT";

pflg(flg)
{

	fprintf(tracef, "%s", Pinfo(proc));
	nflg(flg);
}

sflg(flg)
{
	fprintf(tracef, "[ Sys   ]");
	nflg(flg);
}

char *
Pinfo(p)
	Process	*p;
{
	static char buf[3][128];
	static use;
	register char *s;

	s = buf[use++%3];
	if(p)
		sprintf(s, "[%-3d,%2d]", p->p_pid, p->p_time);
	else
		sprintf(s, "[ Nop   ]");
}

char *
BlockStat(b)
	enum pstat b;
{
	switch (b) {
		case BLOCK_CHILD:
			return "child event";
		case BLOCK_IO:
			return "I/O event";
		case RUNNING:
			return "Running???!!!";
		default:
			return "Unknown Status";
	}
}


nflg(flg)
{
	register char *s;
	register once = 0, c;

	putc('<', tracef);
	for(s = tstr; *s; s++) {
		c = *s;
		if(c & flg) {
			if(once)
				putc(',', tracef);
			once = 1;
			while(*++s)
				putc(*s, tracef);
		} else
			while(*++s)
				;
	}
	putc('>', tracef);
	putc(' ', tracef);
}

/*VARARGS*/
ptrace(fmt, a1, a2, a3, a4, a5, a6)
	char	*fmt;
{
	fprintf(tracef, fmt, a1, a2, a3, a4, a5, a6);
	putc('\n', tracef);
}
SHAR_EOF
fi # end of overwriting check
if test -f 'sched.s'
then
	echo shar: will not over-write existing file "'sched.s'"
else
cat << \SHAR_EOF > 'sched.s'
.data
.data
_rcsid:.long	0x61654824
.long	0x3a726564
.long	0x68637320
.long	0x632e6465
.long	0x3320762c
.long	0x3820322e
.long	0x31312f36
.long	0x2033302f
.long	0x333a3231
.long	0x37303a35
.long	0x6c696720
.long	0x70784520
.long	0x2420
.comm	_runq,4
.comm	_waitq,4
.comm	_freeq,4
.comm	_proctable,32768
.comm	_tracef,4
.comm	_proc,4
.comm	_wdummy,128
.comm	_rdummy,128
.comm	_fdummy,128
.comm	_kmode,4
.text
LL0:.align	1
.globl	_nextrun
.set	L41,0x0
.data
.text
_nextrun:.word	L41
subl2	$4,sp
movl	_runq,r0
movl	44(r0),-4(fp)
jneq	L45
calls	$0,_Deadlock
L45:movl	-4(fp),r0
ret
.align	1
.globl	_swtch
.data	1
L57:.ascii	"start %d with kmode %d\12\0"
.text
.data	1
L61:.ascii	"switching to %s\0"
.text
.set	L48,0x800
.data
.text
_swtch:.word	L48
subl2	$4,sp
clrl	-4(fp)
calls	$0,_nextrun
movl	r0,r11
cmpl	r11,_proc
jneq	L52
ret
L52:tstl	_proc
jeql	L53
pushl	_proc
calls	$1,_save
tstl	r0
jeql	L53
pushl	-4(fp)
subl3	$_proctable,_proc,r0
divl3	$128,r0,-(sp)
pushal	L57
calls	$3,_debug
ret
L53:jlbc	_tracer,L58
pushl	$1
calls	$1,_pflg
pushl	r11
calls	$1,_Pinfo
pushl	r0
pushal	L61
calls	$2,_ptrace
L58:pushl	r11
calls	$1,_resume
ret
.align	1
.globl	_save
.set	L63,0x0
.data
.text
_save:.word	L63
movl	4(ap),r0
movl	_kmode,108(r0)
addl3	$52,4(ap),-(sp)
calls	$1,_SetJmp
ret
.align	1
.globl	_resume
.data	1
L72:.ascii	"resuming %d pc %x\12\0"
.text
.set	L68,0x0
.data
.text
_resume:.word	L68
movl	4(ap),r0
pushl	104(r0)
subl3	$_proctable,r0,r0
divl3	$128,r0,-(sp)
pushal	L72
calls	$3,_debug
movl	4(ap),_proc
addl3	$120,_proc,-(sp)
calls	$1,_SetStack
movl	4(ap),r0
movl	108(r0),_kmode
pushl	$0
calls	$1,_sigsetmask
addl3	$52,4(ap),-(sp)
calls	$1,_LongJmp
ret
.align	1
.globl	_tick
.data	1
L83:.ascii	"kmode\72 %d\12\0"
.text
.set	L77,0x0
.data
.text
_tick:.word	L77
tstl	_kmode
jeql	L81
pushl	$0
calls	$1,_sigsetmask
ret
L81:incl	_kmode
pushl	$0
calls	$1,_resched
pushl	_kmode
pushal	L83
calls	$2,_debug
decl	_kmode
ret
.align	1
.globl	_resched
.set	L84,0x0
.data
.align	2
.globl	_DefaultStackSize
_DefaultStackSize:.long	8192
.text
_resched:.word	L84
tstl	_proc
jeql	L88
pushl	_proc
calls	$1,_timesync
pushl	_proc
calls	$1,_FreeMe
tstl	4(ap)
jeql	L91
pushl	_runq
pushl	_proc
calls	$2,_PriEnterMe
jbr	L88
L91:pushl	_runq
pushl	_proc
calls	$2,_EnterMe
L88:calls	$0,_swtch
ret
.align	1
.globl	_NewStack
.data	1
L104:.ascii	"alloc stack failed\12\0"
.text
.lcomm	L105,8
.set	L97,0x0
.data
.text
_NewStack:.word	L97
subl2	$8,sp
tstl	4(ap)
jneq	L101
movl	_DefaultStackSize,4(ap)
L101:pushl	4(ap)
calls	$1,_malloc
movl	r0,-4(fp)
tstl	r0
jneq	L102
pushal	L104
calls	$1,_panic
L102:movl	4(ap),-8(fp)
moval	-8(fp),r0
movab	L105,r1
movq	(r0),(r1)
movab	L105,r0
ret
.align	1
.globl	_FreeStack
.set	L107,0x0
.data
.text
_FreeStack:.word	L107
pushl	8(ap)
calls	$1,_free
ret
.align	1
.globl	_freeslot
.data	1
L118:.ascii	"no more process\12\0"
.text
.set	L113,0x800
.data
.text
_freeslot:.word	L113
movl	_freeq,r0
movl	44(r0),r11
jneq	L117
pushal	L118
calls	$1,_panic
L117:movl	_freeq,r0
movl	44(r11),44(r0)
clrl	44(r11)
clrl	48(r11)
movl	r11,r0
ret
.align	1
.globl	_newproc
.data	1
L128:.ascii	"create %d at 0x%x\0"
.text
.set	L120,0x800
.data
.text
_newproc:.word	L120
subl2	$8,sp
incl	_kmode
movl	_proc,-4(fp)
movl	-4(fp),r0
incl	12(r0)
calls	$0,_freeslot
movl	r0,-8(fp)
calls	$0,_genpid
movl	r0,*-8(fp)
movl	-8(fp),r0
movl	*-4(fp),4(r0)
movl	-8(fp),r0
movl	-4(fp),8(r0)
movl	-8(fp),r0
clrl	20(r0)
movl	-8(fp),r1
movl	20(r0),12(r1)
movl	-8(fp),r0
movl	12(r1),16(r0)
pushl	-4(fp)
calls	$1,_timesync
movl	-4(fp),r0
movl	-8(fp),r1
movl	24(r0),24(r1)
movl	-8(fp),r0
clrl	28(r0)
pushl	$0
calls	$1,_NewStack
addl3	$112,-8(fp),r1
movq	(r0),(r1)
addl3	$112,-8(fp),r0
addl3	$120,-8(fp),r1
movq	(r0),(r1)
addl3	$52,-8(fp),-(sp)
calls	$1,_SetJmp
movl	-8(fp),r0
movl	r0,r1
addl3	112(r1),116(r0),r0
subl2	$4,r0
movl	r0,88(r1)
movl	8(fp),  r11
movl	-8(fp),r0
movl	r11,92(r0)
movl	12(fp), r11
movl	-8(fp),r0
movl	r11,96(r0)
movl	-8(fp),r0
movl	r0,r1
addl3	112(r1),116(r0),r0
subl2	$68,r0
movl	r0,100(r1)
movl	-8(fp),r0
movl	4(ap),104(r0)
movl	-8(fp),r0
clrl	108(r0)
pushl	$64
movl	-8(fp),r0
movl	r0,r1
addl3	112(r1),116(r0),r0
subl3	$68,r0,-(sp)
movl	-4(fp),r0
movl	r0,r1
addl3	112(r1),116(r0),r0
subl3	$68,r0,-(sp)
calls	$3,_bcopy
pushl	-8(fp)
calls	$1,_timewrite
jbc	$1,_tracer,L127
pushl	$2
calls	$1,_pflg
pushl	4(ap)
pushl	*-8(fp)
pushal	L128
calls	$3,_ptrace
L127:pushl	-8(fp)
calls	$1,_setrun
decl	_kmode
ret
.align	1
.globl	_endproc
.data	1
L136:.ascii	"ended\0"
.text
.data	1
L137:.ascii	"endproc %d\12\0"
.text
.set	L131,0x0
.data
.text
_endproc:.word	L131
incl	_kmode
pushl	_proc
calls	$1,_timesync
jbc	$1,_tracer,L135
pushl	$2
calls	$1,_pflg
pushal	L136
calls	$1,_ptrace
L135:subl3	$_proctable,_proc,r0
divl3	$128,r0,-(sp)
pushal	L137
calls	$2,_debug
pushl	_proc
calls	$1,_FreeMe
movl	_proc,r0
tstl	8(r0)
jeql	L138
movl	8(r0),r0
decl	12(r0)
movl	_proc,r0
pushl	8(r0)
calls	$1,_WakePapa
L138:movl	_proc,r0
tstl	12(r0)
jgtr	L9999
tstl	16(r0)
jleq	L140
L9999:movl	_proc,r0
bisl2	$1,28(r0)
movl	_proc,r0
tstl	8(r0)
jeql	L142
movl	8(r0),r0
incl	16(r0)
jbr	L142
L9998:pushl	$0
pushl	_proc
calls	$2,_block
L142:movl	_proc,r0
tstl	12(r0)
jgtr	L9998
tstl	16(r0)
jgtr	L9998
tstl	8(r0)
jeql	L145
movl	8(r0),r0
decl	16(r0)
L145:movl	_proc,r0
pushl	8(r0)
calls	$1,_WakePapa
L140:pushl	_freeq
pushl	_proc
calls	$2,_EnterMe
movl	_proc,r0
subl2	$8,sp
movq	112(r0),(sp)
calls	$2,_FreeStack
clrl	_proc
calls	$0,_swtch
ret
.align	1
.globl	_setrun
.data	1
L150:.ascii	"setrun\72 %d\12\0"
.text
.set	L146,0x0
.data
.text
_setrun:.word	L146
subl3	$_proctable,4(ap),r0
divl3	$128,r0,-(sp)
pushal	L150
calls	$2,_debug
movl	4(ap),r0
movl	$2,40(r0)
pushl	_runq
pushl	4(ap)
calls	$2,_EnterMe
ret
.align	1
.globl	_WakePapa
.set	L151,0x0
.data
.text
_WakePapa:.word	L151
tstl	4(ap)
jeql	L155
movl	4(ap),r0
movl	_proc,r1
cmpl	20(r0),24(r1)
jleq	L9997
movl	20(r0),r0
jbr	L9996
L9997:movl	_proc,r0
movl	24(r0),r0
L9996:movl	4(ap),r1
movl	r0,20(r1)
movl	4(ap),r0
tstl	12(r0)
jneq	L155
pushl	$0
pushl	r0
calls	$2,_unblock
L155:ret
.align	1
.globl	_waitall
.set	L159,0x0
.data
.text
_waitall:.word	L159
incl	_kmode
pushl	_proc
calls	$1,_timesync
jbr	L163
L2000002:pushl	$0
pushl	_proc
calls	$2,_block
L163:movl	_proc,r0
tstl	12(r0)
jgtr	L2000002
movl	r0,r1
movl	20(r0),24(r1)
movl	_proc,r0
clrl	20(r0)
pushl	_proc
calls	$1,_timewrite
decl	_kmode
ret
.align	1
.globl	_genpid
.data
.align	2
L169:.long	1
.text
.set	L165,0x0
.data
.text
_genpid:.word	L165
movl	L169,r0
incl	L169
ret
.align	1
.globl	_initproc
.set	L172,0xc00
.data
.text
_initproc:.word	L172
incl	_kmode
pushl	$0
calls	$1,_NewStack
movq	(r0),_NextStack
movl	$1,r10
movzbl	$255,r11
jbr	L178
L2000004:addl3	$1,r10,r0
ashl	$7,r0,r0
addl2	$_proctable,r0
ashl	$7,r10,r1
movl	r0,_proctable+44(r1)
ashl	$7,r10,r0
addl2	$_proctable,r0
addl3	$1,r10,r1
ashl	$7,r1,r1
movl	r0,_proctable+48(r1)
incl	r10
L178:cmpl	r10,r11
jlss	L2000004
ashl	$7,r11,r0
clrl	_proctable+44(r0)
moval	_fdummy,_freeq
moval	_proctable+128,_fdummy+44
movl	_freeq,_proctable+176
clrl	_wdummy+48
movl	_wdummy+48,_wdummy+44
moval	_wdummy,_waitq
moval	_proctable,_proc
moval	_rdummy,_runq
movl	_proc,_rdummy+44
clrl	_rdummy+48
movl	_proc,r0
movl	_runq,48(r0)
decl	_kmode
ret
.align	1
.globl	_block
.data	1
L184:.ascii	"blocked, on %s\0"
.text
.data	1
L185:.ascii	"block %d\12\0"
.text
.set	L179,0x0
.data
.text
_block:.word	L179
jbc	$2,_tracer,L183
pushl	$4
calls	$1,_pflg
pushl	8(ap)
calls	$1,_BlockStat
pushl	r0
pushal	L184
calls	$2,_ptrace
L183:subl3	$_proctable,4(ap),r0
divl3	$128,r0,-(sp)
pushal	L185
calls	$2,_debug
movl	4(ap),r0
movl	8(ap),40(r0)
pushl	4(ap)
calls	$1,_FreeMe
pushl	_waitq
pushl	4(ap)
calls	$2,_EnterMe
cmpl	_proc,4(ap)
jneq	L186
calls	$0,_swtch
L186:ret
.align	1
.globl	_unblock
.data	1
L191:.ascii	"unblock %d\12\0"
.text
.data	1
L193:.ascii	"unblock %s, on %s\0"
.text
.set	L187,0x0
.data
.text
_unblock:.word	L187
subl3	$_proctable,4(ap),r0
divl3	$128,r0,-(sp)
pushal	L191
calls	$2,_debug
jbc	$2,_tracer,L192
pushl	$4
calls	$1,_pflg
pushl	8(ap)
calls	$1,_BlockStat
pushl	r0
pushl	4(ap)
calls	$1,_Pinfo
pushl	r0
pushal	L193
calls	$3,_ptrace
L192:movl	4(ap),r0
cmpl	40(r0),8(ap)
jneq	L194
pushl	r0
calls	$1,_timewrite
pushl	4(ap)
calls	$1,_FreeMe
pushl	4(ap)
calls	$1,_setrun
L194:ret
.align	1
.globl	_EnterMe
.data
.align	2
L207:.double	0d2.56000000000000000000e+02
.text
.set	L195,0xe00
.data
.text
_EnterMe:.word	L195
subl2	$8,sp
movl	8(ap),r10
jbr	L201
L2000006:movl	44(r10),r0
movl	4(ap),r1
cmpl	24(r0),24(r1)
jgeq	L200
movl	44(r10),r10
L201:tstl	44(r10)
jneq	L2000006
L200:movl	r10,r9
movl	$2,r11
jbr	L204
L2000008:movl	44(r10),r0
movl	4(ap),r1
cmpl	24(r0),24(r1)
jneq	L203
calls	$0,_random
movzbl	r0,r0
cvtld	r0,-8(fp)
cvtld	r11,r0
divd3	r0,L207,r2
cmpd	-8(fp),r2
jgeq	L202
movl	44(r10),r9
L202:movl	44(r10),r10
incl	r11
L204:tstl	44(r10)
jneq	L2000008
L203:movl	4(ap),r0
movl	44(r9),44(r0)
movl	4(ap),r0
movl	r9,48(r0)
tstl	44(r9)
jeql	L208
movl	44(r9),r0
movl	4(ap),48(r0)
L208:movl	4(ap),44(r9)
ret
.align	1
.globl	_PriEnterMe
.set	L209,0x800
.data
.text
_PriEnterMe:.word	L209
movl	8(ap),r11
jbr	L215
L2000010:movl	44(r11),r0
movl	4(ap),r1
cmpl	24(r0),24(r1)
jgtr	L214
movl	44(r11),r11
L215:tstl	44(r11)
jneq	L2000010
L214:movl	4(ap),r0
movl	44(r11),44(r0)
movl	4(ap),r0
movl	r11,48(r0)
tstl	44(r11)
jeql	L216
movl	44(r11),r0
movl	4(ap),48(r0)
L216:movl	4(ap),44(r11)
ret
.align	1
.globl	_FreeMe
.set	L217,0x800
.data
.text
_FreeMe:.word	L217
movl	4(ap),r0
movl	44(r0),r11
tstl	48(r0)
jeql	L221
movl	48(r0),r0
movl	r11,44(r0)
L221:tstl	r11
jeql	L222
movl	4(ap),r0
movl	48(r0),48(r11)
L222:ret
.align	1
.globl	_Deadlock
.data	1
L228:.ascii	"deadlock\12\0"
.text
.data	1
L230:.ascii	"process terminated successfully\12\0"
.text
.set	L223,0x0
.data
.text
_Deadlock:.word	L223
movl	_waitq,r0
tstl	44(r0)
jeql	L227
pushal	L228
calls	$1,_panic
L227:pushal	L230
calls	$1,_printf
pushl	$0
calls	$1,_exit
ret
.align	1
.globl	_timesync
.data	1
L236:.ascii	"[%d] time %d\12\0"
.text
.set	L232,0x0
.data
.text
_timesync:.word	L232
movl	4(ap),r0
movl	r0,r1
addl3	112(r1),116(r0),r0
movl	-4(r0),24(r1)
movl	4(ap),r0
pushl	24(r0)
subl3	$_proctable,_proc,r0
divl3	$128,r0,-(sp)
pushal	L236
calls	$3,_debug
ret
.align	1
.globl	_timewrite
.set	L237,0x0
.data
.text
_timewrite:.word	L237
movl	4(ap),r0
movl	r0,r1
movl	r1,r2
addl3	112(r2),116(r1),r1
movl	24(r0),-4(r1)
ret

SHAR_EOF
fi # end of overwriting check
if test -f 'sysio.c'
then
	echo shar: will not over-write existing file "'sysio.c'"
else
cat << \SHAR_EOF > 'sysio.c'
static	char	*rcsid = "$Header: sysio.c,v 3.3 86/11/03 12:35:14 gil Exp $";
#include <stdio.h>
#include "conf.h"
#include "process.h"
#include "chan.h"
#include <sys/uio.h>
#include <sys/ioctl.h>
#include <sys/file.h>

chtime(chid) {

	Channel	*ch;

	ch = chanof(chid);
	ch->ch_flags = CH_TIME;
	time_ch = chid;
}

tread(ch, time)
	Channel	*ch;
	int	time;
{
	register IoVec	*iov;
	IoBlock		*blk;

	blk = ch->ch_read.b_next;

	for (iov = blk->b_data;
	     iov < &blk->b_data[blk->b_ndata];
	     iov++) {
		if (iov->io_len != sizeof(blk->b_proc->p_time))
			debug("time request is longword length\n");
		*(int *)iov->io_data = time;
		iov++;
	}
	ReadDone(ch, time);
	return 1;
}

#ifdef	S_SYS
/* allocate special time channel */
chassign(chid, fd, mode)
{
	Channel	*ch;
	
	ch = chanof(chid);
	ch->ch_flags = CH_SYS;
	ch->ch_fd = fd;
	if(isatty(fd))
		ch->ch_flags := CH_DEV;
}

SysWrite(ch, time)
	Channel	*ch;
{
	IoBlock		*wblk;
	IoVec		*vv;
	int		l;
	register 	i = 0, m;
	int		len;

	wblk = ch->ch_write.b_next;
	vv = wblk->b_data;
	len = wblk->b_ndata;
	
	for(i = 0; i < len; i++, vv++) {
		m = vv->io_len;
		vv->io_len = (int) vv->io_data;
		vv->io_data = (char *) m;
	}
	if(writev(ch->ch_fd, wblk->b_data, len) < 0)
		perror("writev");
	NTRACE(TRACE_IO,
	       ("[%d] write %d blocks, from %s (UNIX fd=%d)", chidof(ch),
	        len, Pinfo(wblk->b_proc), ch->ch_fd));

	WriteDone(ch, time);
}

SysRead(ch, time)
	Channel	*ch;
{
	IoBlock		*rblk;
	IoVec		*vv;
	int		l;
	register 	i = 0, m;
	int		len;

	rblk = ch->ch_read.b_next;
	vv = rblk->b_data;
	len = rblk->b_ndata;
	
	if(IsSpecialDevice(ch)) {
		l = 0;
		
		while(vv->io_len > 0 && l <= 0) {
			ioctl(ch->ch_fd, FIONREAD, &l);
			if(l <= 0)
				swtch();
			while(l > 0) {
				m = min(l, vv->io_len);
				read(ch->ch_fd, vv->io_data, m);
				vv->io_data += m;
				vv->io_len -= m;
				l -= m;
				if(vv->io_len == 0)
					if(++i == len)
						break;
					else
						vv++;
			}
		}
		return;
	}

	for(i = 0; i < len; i++, vv++) {
		m = vv->io_len;
		vv->io_len = (int) vv->io_data;
		vv->io_data = (char *) m;
	}
	if(readv(ch->ch_fd, rblk->b_data, len) < 0)
		perror("readv");
	NTRACE(TRACE_IO,
	       ("[%d] read %d blocks, to %s (UNIX fd=%d)", chidof(ch),
	        len, Pinfo(rblk->b_proc), ch->ch_fd));

	ReadDone(ch, time);
}

SpecialSelect() {
	debug("Not implemented yet");
	return 0;
}

#endif S_SYS
SHAR_EOF
fi # end of overwriting check
cd ..
#	End of shell archive
exit 0

----------end of sim.shar----------

-- 
-
-	Terry Torkelson				Internet: ttork%ewu@uunet.uu.net
-	Eastern Washington University		uucp: 	  uunet!isc-br!ewu!ttork
-						tellynet: 509-359-6016

ttork@ewu.UUCP (Terry Torkelson) (11/15/90)

----------test.shar----------
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	test
# This archive created: Thu Apr 19 16:54:38 1990
export PATH; PATH=/bin:$PATH
if test ! -d 'test'
then
	mkdir 'test'
fi
cd 'test'
if test -f 'semaphore.oc'
then
	echo shar: will not over-write existing file "'semaphore.oc'"
else
cat << \SHAR_EOF > 'semaphore.oc'
-- counting semaphore handler using buffered-channels in Occam.

extern proc pnum(value n):

def MAXSEM = 5:
def MAXN = 100:        	-- maximum size of buffer of semaphores

que sempool(MAXN)[MAXSEM]:
var nsem:
var s:

proc setsem(value v, var sn) =

  seq
    sn := nsem
    nsem := nsem + 1
    seq j = [0 for v]
      sempool[sn] ! ANY :

proc p(value sn) =
  sempool[sn] ? ANY :

proc v(value sn) =
  sempool[sn] ! ANY :

seq
  setsem(3, s)
  -- first run without semahpores
  par p = [0 for 2]
    seq q = [0 for 10]
      pnum(p)

  -- then run with semaphores
  par i = [0 for 2]
    seq k = [0 for 10]
      seq
        p(s)
	pnum(i)
        v(s)
SHAR_EOF
fi # end of overwriting check
if test -f 'SEM'
then
	echo shar: will not over-write existing file "'SEM'"
else
cat << \SHAR_EOF > 'SEM'
Executed 126 instructions in 66 time
1
1
1
1
1
1
1
1
1
1
0
0
0
0
0
0
0
0
0
0
0
1
0
1
1
0
0
1
0
1
1
0
0
1
1
0
0
1
0
1
SHAR_EOF
fi # end of overwriting check
if test -f 'RAND'
then
	echo shar: will not over-write existing file "'RAND'"
else
cat << \SHAR_EOF > 'RAND'
Panic: [8  ,101]: deadlock

5
9
6
6
5
3
5
6
8
1
5
6
1
8
7
2
7
5
9
3
8
6
3
8
7
1
3
3
4
4
9
3
8
5
1
9
5
6
3
4
0
9
8
5
1
3
8
8
3
4
SHAR_EOF
fi # end of overwriting check
if test -f 'TRACE'
then
	echo shar: will not over-write existing file "'TRACE'"
else
cat << \SHAR_EOF > 'TRACE'
[0  , 0]<FORK> create 1 at 0x48
[1  , 0]<IO> opened 0(0)
[1  , 0]<IO> opened 1(0)
[1  , 0]<IO> opened 2(0)
[1  , 0]<IO> open channel table at 0x4E4C - 5
[1  , 0]<IO> opened 3(0)
[1  , 0]<IO> opened 4(0)
[1  , 0]<IO> opened 5(0)
[1  , 0]<IO> opened 6(0)
[1  , 0]<IO> opened 7(0)
[1  , 0]<IO> opened 8(0)
[1  , 0]<FORK> create 2 at 0xA8
[1  , 0]<FORK> create 3 at 0xBE
[2  , 0]<IO> read on 8
[3  , 0]<FORK> create 4 at 0xD8
[3  , 0]<FORK> create 5 at 0xD8
[3  , 0]<FORK> create 6 at 0xD8
[3  , 0]<FORK> create 7 at 0xD8
[3  , 0]<FORK> create 8 at 0xD8
[6  ,2000]<IO> write on 8
[8  ,4000]<IO> write on 8
[5  ,1000]<IO> write on 8
[4  , 0]<IO> write on 8
[ Sys   ]<IO> [8] sent 4 bytes from [4  , 0] to [2  , 0]
[4  , 1]<IO> read on 3
[2  , 1]<IO> read on 8
[7  ,3000]<IO> write on 8
[ Sys   ]<IO> [8] sent 4 bytes from [5  ,1000] to [2  , 1]
[5  ,1001]<IO> read on 4
[2  ,1001]<IO> read on 8
[ Sys   ]<IO> [8] sent 4 bytes from [6  ,2000] to [2  ,1001]
[6  ,2001]<IO> read on 5
[2  ,2001]<IO> read on 8
[ Sys   ]<IO> [8] sent 4 bytes from [7  ,3000] to [2  ,2001]
[7  ,3001]<IO> read on 6
[2  ,3001]<IO> read on 8
[ Sys   ]<IO> [8] sent 4 bytes from [8  ,4000] to [2  ,3001]
[8  ,4001]<IO> read on 7
[2  ,4001]<IO> write on 3
[ Sys   ]<IO> [3] sent 4 bytes from [2  ,4001] to [4  , 1]
[2  ,4002]<IO> write on 4
[4  ,4002]<IO> write on 8
[ Sys   ]<IO> [4] sent 4 bytes from [2  ,4002] to [5  ,1001]
[2  ,4003]<IO> write on 5
[5  ,5003]<IO> write on 8
[ Sys   ]<IO> [5] sent 4 bytes from [2  ,4003] to [6  ,2001]
[2  ,4004]<IO> write on 6
[6  ,6004]<IO> write on 8
[ Sys   ]<IO> [6] sent 4 bytes from [2  ,4004] to [7  ,3001]
[2  ,4005]<IO> write on 7
[7  ,7005]<IO> write on 8
[ Sys   ]<IO> [7] sent 4 bytes from [2  ,4005] to [8  ,4001]
[2  ,4006]<IO> read on 8
[8  ,8006]<IO> write on 8
[ Sys   ]<IO> [8] sent 4 bytes from [4  ,4002] to [2  ,4006]
[2  ,4007]<IO> read on 8
[4  ,4007]<IO> read on 3
[ Sys   ]<IO> [8] sent 4 bytes from [5  ,5003] to [2  ,4007]
[5  ,5004]<IO> read on 4
[2  ,5004]<IO> read on 8
[ Sys   ]<IO> [8] sent 4 bytes from [6  ,6004] to [2  ,5004]
[6  ,6005]<IO> read on 5
[2  ,6005]<IO> read on 8
[ Sys   ]<IO> [8] sent 4 bytes from [7  ,7005] to [2  ,6005]
[7  ,7006]<IO> read on 6
[2  ,7006]<IO> read on 8
[2  ,7006]<IO> read on 8
b[ Sys   ]<IO> [8] sent 4 bytes from [8  ,8006] to [2  ,7006]
[8  ,8007]<IO> read on 7
[2  ,8007]<IO> write on 3
[ Sys   ]<IO> [3] sent 4 bytes from [2  ,8007] to [4  ,4007]
[2  ,8008]<IO> write on 4
[4  ,8009]<FORK> ended
[ Sys   ]<IO> [4] sent 4 bytes from [2  ,8008] to [5  ,5004]
[2  ,8009]<IO> write on 5
[5  ,8010]<FORK> ended
[ Sys   ]<IO> [5] sent 4 bytes from [2  ,8009] to [6  ,6005]
[2  ,8010]<IO> write on 6
[6  ,8011]<FORK> ended
[ Sys   ]<IO> [6] sent 4 bytes from [2  ,8010] to [7  ,7006]
[2  ,8011]<IO> write on 7
[7  ,8012]<FORK> ended
[ Sys   ]<IO> [7] sent 4 bytes from [2  ,8011] to [8  ,8007]
[2  ,8013]<FORK> ended
[8  ,8013]<FORK> ended
[3  ,8013]<FORK> ended
[1  ,8013]<IO> closed 8
[1  ,8013]<IO> close channel table at 0x4E4C - 5
[1  ,8013]<IO> closed 3
[1  ,8013]<IO> closed 4
[1  ,8013]<IO> closed 5
[1  ,8013]<IO> closed 6
[1  ,8013]<IO> closed 7
[1  ,8013]<FORK> ended
Executed 20046 instructions in 8013 time
SHAR_EOF
fi # end of overwriting check
if test -f 'RESULTS'
then
	echo shar: will not over-write existing file "'RESULTS'"
else
cat << \SHAR_EOF > 'RESULTS'
** compiling simple
** running simple
** compiling pr459
SHAR_EOF
fi # end of overwriting check
if test -f 'itoa.oc'
then
	echo shar: will not over-write existing file "'itoa.oc'"
else
cat << \SHAR_EOF > 'itoa.oc'
-- convert (positive) integer to string (decimal representation) and print it.

extern proc chassign(chan c, value fd, mode):

def MAX = 200:	-- should be enough..

var str[BYTE MAX]:
var x:

proc convert(value n, var pos) =

  var tmp:
  var nn:

  seq
    nn := n
    pos := MAX -1
    while (nn > 0 and pos > 0)
      seq
	tmp := nn / 10
	tmp := nn - tmp*10
	nn := nn / 10
	str[BYTE pos] := '0' + tmp
	pos := pos - 1 :

seq
  chassign(OUTPUT, 1, 1)
  convert(1223, x)
  OUTPUT ! str[BYTE x for MAX-x]
  OUTPUT ! "*n"
SHAR_EOF
fi # end of overwriting check
if test -f 'simple.oc'
then
	echo shar: will not over-write existing file "'simple.oc'"
else
cat << \SHAR_EOF > 'simple.oc'
-- some simple OCCAM constructs.

var a:
chan c:
def N = 20:

seq
  a := 1
  while (a < N)
    a := a + 1
  par
    c ? ANY
    c ! N
  seq i = [0 for N]
    a := a / 2
SHAR_EOF
fi # end of overwriting check
if test -f 'RESULTS.good'
then
	echo shar: will not over-write existing file "'RESULTS.good'"
else
cat << \SHAR_EOF > 'RESULTS.good'
** compiling simple
** running simple
Executed 62 instructions in 61 time
** compiling pr459
** running pr459
Executed 1 instructions in 1 time
459
** compiling randgen
** running randgen
** compiling prog
** running prog with tracing
** compiling itoa
** running itoa
   seq j = [0 for 1000*n]
        skip
      sync ! DONE
      c ? ANY :

proc manager =

  seq h = [0 for N]
    seq
      seq k = [0 for NPROC]
        sync ? ANY
      seq l = [0 for NPROC]
        chtab[l] ! ACK :

par
  manager
  par p = [0 for NPROC]
    worker(chtab[p], p)
SHAR_EOF
fi # end of overwriting check
if test -f 'randgen.oc'
then
	echo shar: will not over-write existing file "'randgen.oc'"
else
cat << \SHAR_EOF > 'randgen.oc'
-- random number generator using 'ALT'. produces a random series of N numbers
-- in the range 0..MAX.

extern proc pnum(value n):

def MAX = 10:
def N = 50:

chan	chtab[MAX]:

proc select =

  seq i = [0 for N]
    alt j = [0 for MAX]
      chtab[j] ? ANY
        pnum(j) :

proc foreversend(chan c) =

  while TRUE
    c ! ANY :

par
  select
  par k = [0 for MAX]
    foreversend(chtab[k])
SHAR_EOF
fi # end of overwriting check
if test -f 'pnum.c'
then
	echo shar: will not over-write existing file "'pnum.c'"
else
cat << \SHAR_EOF > 'pnum.c'
pnum(n)
{
	printf("%d\n", n);
}
SHAR_EOF
fi # end of overwriting check
if test -f 'pr459.oc'
then
	echo shar: will not over-write existing file "'pr459.oc'"
else
cat << \SHAR_EOF > 'pr459.oc'
extern proc pnum(value n):
pnum(459)
SHAR_EOF
fi # end of overwriting check
cd ..
#	End of shell archive
exit 0

----------end of test.shar----------

-- 
-
-	Terry Torkelson				Internet: ttork%ewu@uunet.uu.net
-	Eastern Washington University		uucp: 	  uunet!isc-br!ewu!ttork
-						tellynet: 509-359-6016

ttork@ewu.UUCP (Terry Torkelson) (11/15/90)

----------tools.shar----------
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	tools
# This archive created: Thu Apr 19 16:54:45 1990
export PATH; PATH=/bin:$PATH
if test ! -d 'tools'
then
	mkdir 'tools'
fi
cd 'tools'
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
# configurable definitions:
################################################################################
CC=/bin/cc
CNAME=cc
AS=/bin/as
ASNAME=as
CPP=/lib/cpp
CPPNAME=cpp

SRCDIR=..
DESTDIR=/m/usr/gil/occam
# OCCDIR and BINDIR should exist
OCCDIR=$(DESTDIR)/lib
BINDIR=$(DESTDIR)/bin
OCP=$(OCCDIR)/ocp
OCPNAME=ocp
LIB=$(OCCDIR)/lsim.a
LIBNAME=lsim.a
OCCNAME=occ
OCC=$(BINDIR)/occ
################################################################################

CFLAGS= \
	-DCC=\"$(CC)\" -DCNAME=\"$(CNAME)\" -DAS=\"$(AS)\" \
	-DASNAME=\"$(ASNAME)\" -DCPP=\"$(CPP)\" -DCPPNAME=\"$(CPPNAME)\" \
	-DOCCDIR=\"$(OCCDIR)\" -DOCP=\"$(OCP)\" -DOCPNAME=\"$(OCPNAME)\" \
	-DLIB=\"$(LIB)\" -DLIBNAME=\"$(LIBNAME)\"

$(OCCNAME):	occ.c Makefile
	$(CC) $(CFLAGS) -o $(OCCNAME) occ.c

# installation of $(OCC), $(OCP), $(LIB).
# $(OCP) and $(LIB) should be prepared in the source directories
#	$(SRCDIR)/{comp,sim}
install:	$(OCCNAME) $(SRCDIR)/comp/$(OCPNAME) $(SRCDIR)/sim/$(LIBNAME)
	@echo installing $(OCCNAME) $(OCPNAME) $(LIBNAME)
	-install $(OCCNAME) $(OCC)
	-install $(SRCDIR)/comp/$(OCPNAME) $(OCP)
	-install $(SRCDIR)/sim/$(LIBNAME) $(LIB)
	ranlib $(LIB)
SHAR_EOF
fi # end of overwriting check
if test -f 'ocp.1'
then
	echo shar: will not over-write existing file "'ocp.1'"
else
cat << \SHAR_EOF > 'ocp.1'
.TH OCP 1N "15 November 1986"
.UC 4
.SH NAME
ocp \-
.B Occam
language system
.SH SYNOPSIS
.B ocp
[
.I \-S
] [
.I \-L
] [
.I \-C
] [
.I \-T
] [
.I \-c
] [
.B
cc
.I flags
] [
.I files..
]
.sp
.B <prog>
[
.I \-s
<sz>
] [
.I \-i
<n>
] [
.I \-r
<sz>
] [
.I \-d
]
[
.I \-t
[opts]
]
[
.I \-q
]
[
.I \-f
[<file-name>]
]
.SH DESCRIPTION
.PP
Ocp is an
.B OCCAM
compiler.
.B OCCAM
is a computer language which supports parallel execution of
program parts, It is used on the
.I Transputer
parallel computer.
The Ocp system provides a compiler and a runtime library used to run
.B Occam
programs on the UNIX/VAX system.
.PP
The occam compiler accepts a list of arguments, interpreted as follows:
.PP
Arguments whose names end with
.B `.oc'
are taken to be occam source programs.
They are compiled, and an object file with the suffix `.o' substituting `.oc'
is left, for further linking.
.PP
Other file names are taken to be acceptable arguments to
.B cc(1)
and passed unchanged to the C-compiler (see below).
.PP
The following options are interpreted by
.IR ocp :
.TP 3
.B \-L
Produce program listing for the named
.B OCCAM
programs on the corresponding files suffixed '.lst'.
.TP 3
.B -C
Do not generate code for run-time commands counting.
.TP 3
.B -T
By default, the compiler generates code for automatic stack expansion
when the current stack is exhausted. When this option is raised, the above
code is not produced by the compiler. Resulting a more efficient code.
.TP 3
.B \-c
Suppress the loading phase of the compilation, and force
an object file to be produced even if only one program is compiled.
.TP 3
.B \-S
Compile the named
.B OCCAM
programs, and leave the assembler-language
output on corresponding files suffixed `.s'.
This option suppresses the loading phase.
.PP
The loading phase is done by the C-compiler
.IR (cc(1))
including the loading of the runtime library, compilation of other
files (as mentioned above) and interpretation of all other flags.
.SH Language Additions
.PP
In addition to the standard
.B OCCAM
language the
.B Ocp
system provides the following extensions:
.PP
As mentioned above, separate compilation of partial
.B OCCAM
programs is supported by the system. The linking of the produced
object files with any other UNIX object file is done by the standard
loader
.IR ld(1).
The naming convention for global data agrees with that of the C-compiler
(i.e. names are prefixed with '_').
The loading phase includes the loading of the C-library (libc), which includes
interface to system calls and a buffered-io library.
.PP
A cross files (and possibly cross languages) variable-sharing is provided by
an external declaration.
.br
syntax:
.br
.nf
	\fIextern\fR <occam-declaration>
.fi
The object declared external via this statement is linked with the original
object (declared normally, in a different file/part),
and may be used normally throughout the program.
.PP
Recursion is allowed in programs. Note should be taken of the stack size
consideration made by the compiler and the runtime library.
The user should use carefully the -T, -s, and -r options in order to tune
his program memory/cpu usage.
.PP
Strings are heavily supported by the compiler:
calls of the form:
.br
.nf
	foo("hello world")
.fi
.br
when `foo' is a declared procedure are allowed.
.br
Passing of strings through channels is also supported, as in:
.br
.nf
	OUTPUT ! "hello world*n"
.fi
.br
The C-language string convention is supported (using `\\' as
escape character).
.PP
.SH Channel behavior
.PP
Special channels are supported in three forms:
.TP 3
VAX/VMS\-OCCAM compatible special channels.
The VAX/VMS special channels are used to connect
.B OCCAM
programs with UNIX files and special files (terminal, keyboard, etc.),
in a compatible manner with the INMOS VAX/VMS-OCCAM special channels.
.TP 3
Special channels for I/O.
The special I/O channels are used to connect
.B OCCAM
programs to UNIX files.
In this form, the channels are used as one-way data streams (to a
file or from it).
One special function is called to attach a channel to a file:
.br
.nf
	\fBchassign\fR(<chname>, <fd>, <mode>)
.fi
.br
.I Chassign
associates the channel named `chname' with the file descriptor `fd' obtained
from
.I open, dup, creat,
or
.IR pipe(2).
The mode `mode' must agree with the mode of the open file:
.br
0 - for read only
.br
1 - for write only
.br
2 - for read & write
.br
Further access to the channel is in the usual way.
.br
Two special channels are automatically declared upon invoking of the
compiler: INPUT & OUTPUT. They can further be assigned to any file-descriptor.
.TP 3
Special VAX/VMS\-OCCAM compatible TIME channel.
The special time channel provides a different, VAX/VMS compatible,
interface for the local clock. Thus, the local clock can be accessed
in two equivalent ways:
.br
`TIME ? <var>' :: `<var> := NOW'.
.br
`TIME ? AFTER <expr>' :: `WAIT NOW AFTER <expr>'.
.PP
Channel messages of different sizes are prohibited by the system.
When read and write requests of different sizes are encountered on a
channel, the systems panics and quits.
.SH Runtime Library
.PP
The runtime library provides a virtual parallel machine interface
which matches the abstract
.B OCCAM
machine to which the compiler is designed.
The library simulates the
.B OCCAM
primitives for parallel processes and channel operations.
It provides a scheduler and timer for parallel processes, and a connected
channeled message passing.
.PP
The parallelism simulation is done by the scheduler;
At a pre-defined interval (user tunable, see below) a context-switching
between running processes is performed, thus sharing the sequential time
(more or less) equally between the processes.
Memory is allocated for each process, separately, for the local data,
and its size is pre-defined (user-tunable, see below).
.br
Stacks are expanded when stack bottom is reached.
When a process' stack is exhausted, an additional stack is allocated for
it. This stack is automatically freed on return from
the routine in which stack overflow has occurred.
If the user program uses a known fixed stack size, it should be run with the
\-T option to gain performance improvement.
.PP
All the runtime routines are loaded in the linking phase.
The execution of any
.B OCCAM
program starts in a proto-type routine that acts as a father process to
all processes.
The `proto' routine accepts the following options:
.TP 3
.B \-s<stacksize>
Determine the local-data size for all processes. Default is 8Kb.
.TP 3
.B \-r<reserve-size>
Determine the reservation stack space, this size is used as a minimal
reservation space when generating code for automatic stack expansion.
see the -T compiler option.
.TP 3
.B \-i<n>
Specify the interval for context-switching. 'n' is the number per
cpu-second switches. Default is 25.
.TP 3
.B \-d
.br
Run in debug mode. In this mode the library routines print out
messages for debugging.
.TP 3
.B \-t[options..]
.br
Turn on trace flags according to `options':
.br
.RS 3
.TP 6
\fB`c'\fR \- trace context switching.
.TP 6
\fB`f'\fR \- trace forks (creation of new processes).
.TP 6
\fB`s'\fR \- same as `f'.
.TP 6
\fB`b'\fR \- trace blocking/unblocking of processes on events.
.TP 6
\fB`i'\fR \- trace i/o events.
.RE
.IP
Empty `options' implies all trace flags.
.TP 3
.B \-f[filename]
.br
By default, tracing messages are sent to \fIstderr\fP.
When this option is given tracing messages are sent to \fIfilename\fP.
If \fIfilename\fP is not given \fIstdout\fP is used.
.TP 3
.B \-q
.br
Quiet mode. Without this flag the program will print out counting of
the parallel and sequential instruction-count
.B (OCCAM
instruction level)
upon termination.
.SH Not Supported
The special
.B OCCAM
configuration directives PRI ALT, PRI PAR, PLACED PAR, ALLOCATE,
are not supported
since they do not have a meaningful semantics in the system.
.SH ERRORS
The system will panic with an error message on the following events:
.sp
.IP "no more channels -"
Channels pool has been exhausted.
.IP "select channel disappeared -"
Internal error. Shouldn't happen.
.IP "noncompatible receive-send request on channel -"
Requests for sending/receiving messages of different sizes on a channel.
.IP "noncompatible sizes in receive-send -"
Requests for sending/receiving operands of different types on channel.
.IP "alloc stack failed -"
Stack memory have been exhausted.
.IP "no more process -"
Processes pool has been exhausted.
.IP "deadlock -"
Deadlock situation.
.IP "non word messages are not allowed in Vms -"
Attempt to send operand of compound type on VMS special channel.
.IP "vms select not implemented yet -"
Attempt to use ALT on VMS channels.
.IP "vms: can't read from closed file -"
Attempt to read from a VMS special channel connected to a closed file.
.IP "vms: file not open for reading -"
attempt to read from a write-only file-connected VMS special channel.
.IP "try to write on a closed file -"
Attempt to write to a VMS special channel connected to a closed file.
.IP "flushing a closed file -"
Attempt to flush a VMX channel connected to a closed file.
.IP "bad request -"
Bad request code on VMS special channel.
.IP "trying to close a closed file -"
Attempt to close a VMS channel connected to a closed file.
.SH FILES
.SH SEE ALSO
"OCCAM programming manual", INMOS Limited, Prentice Hall International.
.br
"Occam programming system, VAX/VMS host manual", INMOS Limited.
.br
"A UNIX Occam system", TR, Hebrew Uni. Jerusalem.
.IR cc(1),
.IR ld(1),
.IR open(2),
.IR creat(2),
.IR dup(2)
.SH BUGS
The stack handling mechanism is very subtle and should be
tuned carefully for each program.
There is no syntax-error handling yet. The compiler will produce
lexical & semantical error messages. In case of syntax error
only the line number will be printed out.
.sp 1
Please report any other bugs via electronic mail to:
.br
.ti 1i
csnet: dalia@huji
.br
.ti 1i
bitnet: dalia@hujics
.br
.ti 1i
uucp: decvax!huji!dalia
.SH AUTHOR
Dalia Malki & Gil Shwed, Hebrew University, Jerusalem.
SHAR_EOF
fi # end of overwriting check
if test -f 'ocp.n'
then
	echo shar: will not over-write existing file "'ocp.n'"
else
cat << \SHAR_EOF > 'ocp.n'


OCP(1N)                    UNIX Programmer's Manual                    OCP(1N)




NAME
      ocp - Occam language system

SYNOPSIS
      ocp [ -_S ] [ -_L ] [ -_C ] [ -_T ] [ -_c ] [ cc _f_l_a_g_s ] [
_f_i_l_e_s.. ]

      <prog> [ -_s <sz> ] [ -_i <n> ] [ -_r <sz> ] [ -_d ] [ -_t [opts] ] [
 -_q ] [
      -_f [<file-name>] ]

DESCRIPTION
      Ocp is an OCCAM compiler.  OCCAM is a computer language which supports
      parallel execution of program parts, It is used on the _T_r_a_n_s_p_
u_t_e_r paral-
      lel computer.  The Ocp system provides a compiler and a runtime library
      used to run Occam programs on the UNIX/VAX system.

      The occam compiler accepts a list of arguments, interpreted as follows:

      Arguments whose names end with `.oc' are taken to be occam source pro-
      grams.  They are compiled, and an object file with the suffix `.o' sub-
      stituting `.oc' is left, for further linking.

      Other file names are taken to be acceptable arguments to cc(1) and
      passed unchanged to the C-compiler (see below).

      The following options are interpreted by _o_c_p:

      -L Produce program listing for the named OCCAM programs on the
         corresponding files suffixed '.lst'.

      -C Do not generate code for run-time commands counting.

      -T By default, the compiler generates code for automatic stack expansion
         when the current stack is exhausted. When this option is raised, the
         above code is not produced by the compiler. Resulting a more effi-
         cient code.

      -c Suppress the loading phase of the compilation, and force an object
         file to be produced even if only one program is compiled.

      -S Compile the named OCCAM programs, and leave the assembler-language
         output on corresponding files suffixed `.s'.  This option suppresses
         the loading phase.

      The loading phase is done by the C-compiler (_c_c(_1)) including the lo
ad-
      ing of the runtime library, compilation of other files (as mentioned
      above) and interpretation of all other flags.

Language Additions
      In addition to the standard OCCAM language the Ocp system provides the
      following extensions:

      As mentioned above, separate compilation of partial OCCAM programs is
      supported by the system. The linking of the produced object files with
      any other UNIX object file is done by the standard loader _l_d(_1).  Th
e
      naming convention for global data agrees with that of the C-compiler
      (i.e. names are prefixed with '_').  The loading phase includes the
      loading of the C-library (libc), which includes interface to system
      calls and a buffered-io library.

      A cross files (and possibly cross languages) variable-sharing is pro-
      vided by an external declaration.
      syntax:
            _e_x_t_e_r_n <occam-declaration>
      The object declared external via this statement is linked with the ori-
      ginal object (declared normally, in a different file/part), and may be
      used normally throughout the program.

      Recursion is allowed in programs. Note should be taken of the stack size
      consideration made by the compiler and the runtime library.  The user
      should use carefully the -T, -s, and -r options in order to tune his
      program memory/cpu usage.





Printed 11/20/86               15 November 1986                              1






OCP(1N)                    UNIX Programmer's Manual                    OCP(1N)




      Strings are heavily supported by the compiler: calls of the form:
            foo("hello world")
      when `foo' is a declared procedure are allowed.
      Passing of strings through channels is also supported, as in:
            OUTPUT ! "hello world*n"
      The C-language string convention is supported (using `\' as escape char-
      acter).

Channel behavior
      Special channels are supported in three forms:

      VAX/VMS-OCCAM compatible special channels.
         The VAX/VMS special channels are used to connect OCCAM programs with
         UNIX files and special files (terminal, keyboard, etc.), in a compa-
         tible manner with the INMOS VAX/VMS-OCCAM special channels.

      Special channels for I/O.
         The special I/O channels are used to connect OCCAM programs to UNIX
         files.  In this form, the channels are used as one-way data streams
         (to a file or from it).  One special function is called to attach a
         channel to a file:
               chassign(<chname>, <fd>, <mode>)
         _C_h_a_s_s_i_g_n associates the channel named `chname' with the
 file descrip-
         tor `fd' obtained from _o_p_e_n, _d_u_p, _c_r_e_a_t, or _p
_i_p_e(_2).  The mode `mode'
         must agree with the mode of the open file:
         0 - for read only
         1 - for write only
         2 - for read & write
         Further access to the channel is in the usual way.
         Two special channels are automatically declared upon invoking of the
         compiler: INPUT & OUTPUT. They can further be assigned to any file-
         descriptor.

      Special VAX/VMS-OCCAM compatible TIME channel.
         The special time channel provides a different, VAX/VMS compatible,
         interface for the local clock. Thus, the local clock can be accessed
         in two equivalent ways:
         `TIME ? <var>' :: `<var> := NOW'.
         `TIME ? AFTER <expr>' :: `WAIT NOW AFTER <expr>'.

      Channel messages of different sizes are prohibited by the system.  When
      read and write requests of different sizes are encountered on a channel,
      the systems panics and quits.

Runtime Library
      The runtime library provides a virtual parallel machine interface which
      matches the abstract OCCAM machine to which the compiler is designed.
      The library simulates the OCCAM primitives for parallel processes and
      channel operations.  It provides a scheduler and timer for parallel
      processes, and a connected channeled message passing.

      The parallelism simulation is done by the scheduler; At a pre-defined
      interval (user tunable, see below) a context-switching between running
      processes is performed, thus sharing the sequential time (more or less)
      equally between the processes.  Memory is allocated for each process,
      separately, for the local data, and its size is pre-defined (user-
      tunable, see below).
      Stacks are expanded when stack bottom is reached.  When a process' stack
      is exhausted, an additional stack is allocated for it. This stack is
      automatically freed on return from the routine in which stack overflow
      has occurred.  If the user program uses a known fixed stack size, it
      should be run with the -T option to gain performance improvement.

      All the runtime routines are loaded in the linking phase.  The execution
      of any OCCAM program starts in a proto-type routine that acts as a
      father process to all processes.  The `proto' routine accepts the fol-
      lowing options:

      -s<stacksize>
         Determine the local-data size for all processes. Default is 8Kb.

      -r<reserve-size>




Printed 11/20/86               15 November 1986                              2






OCP(1N)                    UNIX Programmer's Manual                    OCP(1N)




         Determine the reservation stack space, this size is used as a minimal
         reservation space when generating code for automatic stack expansion.
         see the -T compiler option.

      -i<n>
         Specify the interval for context-switching. 'n' is the number per
         cpu-second switches. Default is 25.

      -d
         Run in debug mode. In this mode the library routines print out mes-
         sages for debugging.

      -t[options..]
         Turn on trace flags according to `options':

         `c' - trace context switching.

         `f' - trace forks (creation of new processes).

         `s' - same as `f'.

         `b' - trace blocking/unblocking of processes on events.

         `i' - trace i/o events.

         Empty `options' implies all trace flags.

      -f[filename]
         By default, tracing messages are sent to _s_t_d_e_r_r.  When this
 option is
         given tracing messages are sent to _f_i_l_e_n_a_m_e.  If _f_i
_l_e_n_a_m_e is not
         given _s_t_d_o_u_t is used.

      -q
         Quiet mode. Without this flag the program will print out counting of
         the parallel and sequential instruction-count (OCCAM instruction
         level) upon termination.

Not Supported
      The special OCCAM configuration directives PRI ALT, PRI PAR, PLACED PAR,
      ALLOCATE, are not supported since they do not have a meaningful seman-
      tics in the system.

ERRORS
      The system will panic with an error message on the following events:


      no more channels -
            Channels pool has been exhausted.

      select channel disappeared -
            Internal error. Shouldn't happen.

      noncompatible receive-send request on channel -
            Requests for sending/receiving messages of different sizes on a
            channel.

      noncompatible sizes in receive-send -
            Requests for sending/receiving operands of different types on
            channel.

      alloc stack failed -
            Stack memory have been exhausted.

      no more process -
            Processes pool has been exhausted.

      deadlock -
            Deadlock situation.

      non word messages are not allowed in Vms -
            Attempt to send operand of compound type on VMS special channel.





Printed 11/20/86               15 November 1986                              3






OCP(1N)                    UNIX Programmer's Manual                    OCP(1N)




      vms select not implemented yet -
            Attempt to use ALT on VMS channels.

      vms: can't read from closed file -
            Attempt to read from a VMS special channel connected to a closed
            file.

      vms: file not open for reading -
            attempt to read from a write-only file-connected VMS special chan-
            nel.

      try to write on a closed file -
            Attempt to write to a VMS special channel connected to a closed
            file.

      flushing a closed file -
            Attempt to flush a VMX channel connected to a closed file.

      bad request -
            Bad request code on VMS special channel.

      trying to close a closed file -
            Attempt to close a VMS channel connected to a closed file.

FILES
SEE ALSO
      "OCCAM programming manual", INMOS Limited, Prentice Hall International.
      "Occam programming system, VAX/VMS host manual", INMOS Limited.
      "A UNIX Occam system", TR, Hebrew Uni. Jerusalem.  _c_c(_1), _l_d(_1
),
      _o_p_e_n(_2), _c_r_e_a_t(_2), _d_u_p(_2)

BUGS
      The stack handling mechanism is very subtle and should be tuned care-
      fully for each program.  There is no syntax-error handling yet. The com-
      piler will produce lexical & semantical error messages. In case of syn-
      tax error only the line number will be printed out.

      Please report any other bugs via electronic mail to:
            csnet: dalia@huji
            bitnet: dalia@hujics
            uucp: decvax!huji!dalia

AUTHOR
      Dalia Malki & Gil Shwed, Hebrew University, Jerusalem.
































Printed 11/20/86               15 November 1986                              4




SHAR_EOF
fi # end of overwriting check
if test -f 'reserve'
then
	echo shar: will not over-write existing file "'reserve'"
else
cat << \SHAR_EOF > 'reserve'
#! /bin/csh -f
set words = reserved_words
sort $words : \
awk	'BEGIN {\
printf "#include <stdio.h>\n#include \"all.h\"\n\nstruct reswords ReservedWords[
] = {\n"; }\
	/^#/ { next }\
	{ if(NF == 3) type = $3; else type = "reserved"; \
	printf "\t%-16s,%-16s,%s,\n", $1, $2, type }\
	END { printf "};\nint nreserved = sizeof(ReservedWords)/sizeof(struct reswords)
;\n" }\
	'	> reserved_words.c
SHAR_EOF
fi # end of overwriting check
if test -f 'makeerrs'
then
	echo shar: will not over-write existing file "'makeerrs'"
else
cat << \SHAR_EOF > 'makeerrs'
#! /bin/sh
awk '
BEGIN {
	printf "#define	ERR_LIST\n";
	printf "#include \"error.h\"\n";
	printf "struct error_list Err_list[] = {\n";
	printf "	WARNING,	\"No Error\",\n";
	FS=":";
}
{
	n++;
	printf "	%s,	\"%s\",\n#define	%s	%d\n", $1, $3, $2, n;
}
END {
	printf"};\n";
}' < ../comp/err_types > ../comp/error_list.c
grep "^#define" < ../comp/error_list.c > ../comp/h/errors.h

SHAR_EOF
fi # end of overwriting check
if test -f 'occ.c'
then
	echo shar: will not over-write existing file "'occ.c'"
else
cat << \SHAR_EOF > 'occ.c'
#include <stdio.h>

#define	MAXARGS	128

#define	load_occam()	(!cflag && !Sflag)

char	*malloc(), *strcpy(), *rindex();
char	*mktemp();

static char	*pname;
static char	*args[MAXARGS];
static int	args_cnt;
static char	ocpflags[20], ocpn = 1;

static int	Sflag;		/* leave assembler files */
static int	cflag;		/* separate compilation: leave .o files */
static int	Lflag;		/* listing flag; passed to ocp (ONLY) */
static int	Cflag;		/* no counter flag; passed to ocp (ONLY) */
static int	Tflag;		/* don't generate code for automatic stack
				 : expansion */

int	vflg;
char	*Occdir;

char	*tflags(), *setsuf(), *getenv();

main(ac, av)
	char	**av;
{
	register	i;
	register char	*p;
	int		ccflag;
	int		was_error = 0;

	if(Occdir == NULL && (Occdir = getenv("OCCDIR")) == NULL)
	   	Occdir = OCCDIR;

	pname = av[0];
	args[args_cnt++] = CNAME;
	for(i = 1; i < ac; i++) {
		if (av[i][0] == '-')
			av[i] = tflags(&av[i][1]);
	}

	for(i = 1; i < ac; i++) {
		if (occam_suffix(av[i])) {
			if (cpp_suffix(av[i]) && pass_cpp(av[i]))
				was_error = 1;
			else if (occam_comp(av[i]) == 0) {
				if (load_occam()) {
					args[args_cnt++] = setsuf(av[i],"o");
				}
			} else
				was_error = 1;
		} else if (av[i][0])
			args[args_cnt++] = av[i];
	}
	
	ccflag = 0;
	for (i = 1; i < args_cnt; i++)
		if (args[args_cnt][0] != '-')
			ccflag++;

	if (ccflag) {
		char	buf[128];

		sprintf(buf, "%s/%s", Occdir, LIBNAME);
		args[args_cnt++] = buf;
		args[args_cnt] = (char *)0;
		if (execute(CC, args) != 0)
			was_error = 1;
	}
	exit(was_error);
}

execute(prog, argv)
	char	*prog, **argv;
{

	int	f;
	int	s;
	char	buf[128];

	if(prog[0] != '/') {
		sprintf(buf, "%s/%s", Occdir, prog);
		prog = buf;
	}
	if(vflg) {
		char	**av;
		printf("exec %s: ", prog);
		for(av = argv; *av; av++)
			printf("%s ", *av);
		printf("\n");
	}	
	fflush(stdout);
	if ((f = fork()) > 0) {
		wait(&s);
		return s;
	} else if (f == 0) {
		int	i;

		execv(prog, argv);
		Prerror("Cannot execute %s: ", prog);
		perror(NULL);
		exit(1);
	} else
		Prerror("cannot fork\n");
}

Prerror(fmt, a, b, c, d, e)
	char	*fmt;
{
	fprintf(stderr, "%s: ", pname);
	fprintf(stderr, fmt, a, b, c, d, e);
}

char
*tflags(options)
	char	*options;
{

	register char	*p;
	char	*nopts;		/* new option string, stripped from
				 : the local options */
	register char	*np;

	np = nopts = malloc(strlen(options)+2);	/* at most */
	*np++ = '-';
	for (p = options; *p; p++)
		switch(*p) {
	
		case 'S':
			if (!Sflag) {	/* first time.. */
				*np++ = 'S';
			}
			Sflag = 1;
			break;
		case 'c':
			if (!cflag) {
				*np++ = 'c';
			}
			cflag = 1;
			break;
		case 'L':
			if (!Lflag) {
				ocpflags[ocpn++] = 'L';
			}
			Lflag = 1;
			break;
		case 'C':
			if(!Cflag) {
				ocpflags[ocpn++] = 'C';
			}
			Cflag = 1;
			break;
		case 'T':
			if(!Tflag) {
				ocpflags[ocpn++] = 'T';
			}
			Tflag = 1;
			break;
		case 'v':
			vflg++;
			break;
		default:	/* maybe a c-flag? */
			*np++ = *p;
			break;
		}

	if (np-nopts == 1)
		nopts[0] = '\0';	/* avoid just '-' */
	*np = '\0';
	return nopts;
}

occam_suffix(name)
	char	*name;
{

	register	l;
	
	l = strlen(name);
	if(l < 4)
		return 0;
	if (strcmp(&name[l-3], ".oc") == 0 :: strcmp(&name[l-4], ".occ") == 0)
		return 1;
	return 0;
}

cpp_suffix(name)
	char	*name;
{
	register	l;
	
	l = strlen(name);
	if(l < 4)
		return 0;
	if (strcmp(&name[l-4], ".occ") == 0)
		return 1;
	return 0;
}

static char	*TMPS = 	"/tmp/ocsXXXXXX";
static char	template[30];	/* big enough to hold /tmp/... */

occam_comp(prog)
	char	*prog;
{

	char	*sname;
	char	*oname;
	register	i;
	char	*ocp_args[5];
	int	s;

/* first - activate the code generator 'ocp' */
	
	if (Sflag)
		sname = setsuf(prog, "s");
	else {
		strcpy(template, TMPS);
		sname = mktemp(template);
	}

	i = 0;
	ocp_args[i++] = OCPNAME;
	if (ocpn > 1) {
		ocpflags[0] = '-';
		ocp_args[i++] = ocpflags;
	}
	ocp_args[i++] = prog;
	ocp_args[i++] = sname;
	ocp_args[i] = (char *)0;
	
	if ((s = execute(OCP, ocp_args)) != 0 :: Sflag)
		goto remove;

/* now - if everytihing is fine, activate the assembler */

	oname = setsuf(prog, "o");

	i = 0;
	ocp_args[i++] = ASNAME;
	ocp_args[i++] = "-o";
	ocp_args[i++] = oname;
	ocp_args[i++] = sname;
	ocp_args[i] = '\0';
	
	s = execute(AS, ocp_args);

remove:
	if (!Sflag)
		unlink(sname);
	return s;
}

char
*setsuf(name, suf)
	char	*name, *suf;
{

	char	*c, *p;

	c = strcpy(malloc(strlen(name)), name);
	if ((p = rindex(c, '.')) == NULL) {
		Prerror("setsuf - name %s has no suffix");
		return NULL;
	}
	strcpy(p+1, suf);
	return c;
}

pass_cpp(s)
	char	*s;
{
	register	l = strlen(s);
	char		buf[128], *args[4];

	strcpy(buf, s);
	s[l-1] = '\0';

	args[0] = CPPNAME;
	args[1] = buf;
	args[2] = s;
	args[3] = NULL;
	return execute(CPP, args);
}
SHAR_EOF
fi # end of overwriting check
cd ..
#	End of shell archive
exit 0

----------end of tools.shar----------

-- 
-
-	Terry Torkelson				Internet: ttork%ewu@uunet.uu.net
-	Eastern Washington University		uucp: 	  uunet!isc-br!ewu!ttork
-						tellynet: 509-359-6016

swansonc@AGNES.ACC.STOLAF.EDU (Chris Swanson, St. Olaf College) (12/01/90)

I have had a few people that have downloaded the copy of the
distribution that I made available from our ftp host (nic.stolaf.edu -
130.71.128.8 - anonymous - pub/unix_occam)

I have not had a chance to look at it personally, and won't for
atleast 2 weeks [ finals time here :( ].  If someone wants to fix this
problem in the sources, let me know and I'll replace the code here
with the correct one.  If noone want's to, I will do so, but not until
after the new year.

        -Chris


-- 
Chris Swanson, Chem/C-S/Pre-med Undergrad, St. Olaf College, Northfield,MN 55057
	INTERNET:  swansonc@acc.stolaf.edu	UUCP: swansonc@stolaf
    	AT&T:	   Work: (507)-645-6845		Home: (507)-663-6424
	I would deny this reality, but that wouldn't pay the bills...

onders@picasso.ipl.rpi.edu (Timothy E. Onders) (12/07/90)

Does anyone know of a Sun port of this compiler and the associated simultor
for either the Sun 3 or Sun 4 systems?  This one seems to be very Vax 11
depedent (considering parts are written in Vax asm).  Thanks for the help.
						Tim Onders
						onders@ipl.rpi.edu