/* voc 2.1.0 [2024/08/23]. Bootstrapping compiler for address size 8, alignment 8. xrtspaSF */

#define SHORTINT INT8
#define INTEGER  INT16
#define LONGINT  INT32
#define SET      UINT32

#include "SYSTEM.h"
#include "Configuration.h"
#include "OPM.h"
#include "OPT.h"


static INT16 OPC_indentLevel;
static INT8 OPC_hashtab[105];
static CHAR OPC_keytab[50][9];
static BOOLEAN OPC_GlbPtrs;
static CHAR OPC_BodyNameExt[13];


export void OPC_Andent (OPT_Struct typ);
static void OPC_AnsiParamList (OPT_Object obj, BOOLEAN showParamNames);
export OPT_Object OPC_BaseTProc (OPT_Object obj);
export void OPC_BegBlk (void);
export void OPC_BegStat (void);
static void OPC_CProcDefs (OPT_Object obj, INT16 vis);
export void OPC_Case (INT64 caseVal, INT16 form);
static void OPC_CharacterLiteral (INT64 c);
export void OPC_Cmp (INT16 rel);
export void OPC_CompleteIdent (OPT_Object obj);
export void OPC_Constant (OPT_Const con, INT16 form);
static void OPC_DeclareBase (OPT_Object dcl);
static void OPC_DeclareObj (OPT_Object dcl, BOOLEAN scopeDef);
static void OPC_DeclareParams (OPT_Object par, BOOLEAN macro);
static void OPC_DeclareTProcs (OPT_Object obj, BOOLEAN *empty);
static void OPC_DefAnonRecs (OPT_Node n);
export void OPC_DefineInter (OPT_Object proc);
static void OPC_DefineTProcMacros (OPT_Object obj, BOOLEAN *empty);
static void OPC_DefineTProcTypes (OPT_Object obj);
static void OPC_DefineType (OPT_Struct str);
export void OPC_EndBlk (void);
export void OPC_EndBlk0 (void);
export void OPC_EndStat (void);
export void OPC_EnterBody (void);
export void OPC_EnterProc (OPT_Object proc);
export void OPC_ExitBody (void);
export void OPC_ExitProc (OPT_Object proc, BOOLEAN eoBlock, BOOLEAN implicitRet);
static void OPC_FieldList (OPT_Struct typ, BOOLEAN last, INT32 *off, INT32 *n, INT32 *curAlign);
static void OPC_FillGap (INT32 gap, INT32 off, INT32 align, INT32 *n, INT32 *curAlign);
export void OPC_GenBdy (OPT_Node n);
static void OPC_GenDynTypes (OPT_Node n, INT16 vis);
export void OPC_GenEnumPtrs (OPT_Object var);
export void OPC_GenHdr (OPT_Node n);
export void OPC_GenHdrIncludes (void);
static void OPC_GenHeaderMsg (void);
export void OPC_Halt (INT32 n);
export void OPC_Ident (OPT_Object obj);
static void OPC_IdentList (OPT_Object obj, INT16 vis);
static void OPC_Include (CHAR *name, ADDRESS name__len);
static void OPC_IncludeImports (OPT_Object obj, INT16 vis);
export void OPC_Increment (BOOLEAN decrement);
export void OPC_Indent (INT16 count);
export void OPC_Init (void);
static void OPC_InitImports (OPT_Object obj);
static void OPC_InitKeywords (void);
export void OPC_InitTDesc (OPT_Struct typ);
static void OPC_InitTProcs (OPT_Object typ, OPT_Object obj);
export void OPC_IntLiteral (INT64 n, INT32 size);
export void OPC_Len (OPT_Object obj, OPT_Struct array, INT64 dim);
static void OPC_LenList (OPT_Object par, BOOLEAN ansiDefine, BOOLEAN showParamName);
static INT16 OPC_Length (CHAR *s, ADDRESS s__len);
export BOOLEAN OPC_NeedsRetval (OPT_Object proc);
export INT32 OPC_NofPtrs (OPT_Struct typ);
static INT16 OPC_PerfectHash (CHAR *s, ADDRESS s__len);
static BOOLEAN OPC_Prefixed (OPT_ConstExt x, CHAR *y, ADDRESS y__len);
static void OPC_ProcHeader (OPT_Object proc, BOOLEAN define);
static void OPC_ProcPredefs (OPT_Object obj, INT8 vis);
static void OPC_PutBase (OPT_Struct typ);
static void OPC_PutPtrOffsets (OPT_Struct typ, INT32 adr, INT32 *cnt);
static void OPC_RegCmds (OPT_Object obj);
export void OPC_SetInclude (BOOLEAN exclude);
static void OPC_Stars (OPT_Struct typ, BOOLEAN *openClause);
static void OPC_Str1 (CHAR *s, ADDRESS s__len, INT32 x);
static void OPC_StringLiteral (CHAR *s, ADDRESS s__len, INT32 l);
export void OPC_TDescDecl (OPT_Struct typ);
export void OPC_TypeDefs (OPT_Object obj, INT16 vis);
export void OPC_TypeOf (OPT_Object ap);
static BOOLEAN OPC_Undefined (OPT_Object obj);


void OPC_Init (void)
{
	OPC_indentLevel = 0;
	__MOVE("__init(void)", OPC_BodyNameExt, 13);
}

void OPC_Indent (INT16 count)
{
	OPC_indentLevel += count;
}

void OPC_BegStat (void)
{
	INT16 i;
	i = OPC_indentLevel;
	while (i > 0) {
		OPM_Write(0x09);
		i -= 1;
	}
}

void OPC_EndStat (void)
{
	OPM_Write(';');
	OPM_WriteLn();
}

void OPC_BegBlk (void)
{
	OPM_Write('{');
	OPM_WriteLn();
	OPC_indentLevel += 1;
}

void OPC_EndBlk (void)
{
	OPC_indentLevel -= 1;
	OPC_BegStat();
	OPM_Write('}');
	OPM_WriteLn();
}

void OPC_EndBlk0 (void)
{
	OPC_indentLevel -= 1;
	OPC_BegStat();
	OPM_Write('}');
}

static void OPC_Str1 (CHAR *s, ADDRESS s__len, INT32 x)
{
	CHAR ch;
	INT16 i;
	__DUP(s, s__len, CHAR);
	ch = s[0];
	i = 0;
	while (ch != 0x00) {
		if (ch == '#') {
			OPM_WriteInt(x);
		} else {
			OPM_Write(ch);
		}
		i += 1;
		ch = s[__X(i, s__len)];
	}
	__DEL(s);
}

static INT16 OPC_Length (CHAR *s, ADDRESS s__len)
{
	INT16 i;
	i = 0;
	while (s[__X(i, s__len)] != 0x00) {
		i += 1;
	}
	return i;
}

static INT16 OPC_PerfectHash (CHAR *s, ADDRESS s__len)
{
	INT16 i, h;
	i = 0;
	h = 0;
	while ((s[__X(i, s__len)] != 0x00 && i < 5)) {
		h = 3 * h + (INT16)s[__X(i, s__len)];
		i += 1;
	}
	return (int)__MOD(h, 105);
}

void OPC_Ident (OPT_Object obj)
{
	INT16 mode, level, h;
	mode = obj->mode;
	level = obj->mnolev;
	if ((__IN(mode, 0x62, 32) && level > 0) || __IN(mode, 0x14, 32)) {
		OPM_WriteStringVar((void*)obj->name, 256);
		h = OPC_PerfectHash((void*)obj->name, 256);
		if (OPC_hashtab[__X(h, 105)] >= 0) {
			if (__STRCMP(OPC_keytab[__X(OPC_hashtab[__X(h, 105)], 50)], obj->name) == 0) {
				OPM_Write('_');
			}
		}
	} else if ((mode == 5 && __IN(obj->typ->form, 0x90, 32))) {
		if (obj->typ == OPT_adrtyp) {
			OPM_WriteString((CHAR*)"ADDRESS", 8);
		} else {
			if (obj->typ->form == 4) {
				OPM_WriteString((CHAR*)"INT", 4);
			} else {
				OPM_WriteString((CHAR*)"UINT", 5);
			}
			OPM_WriteInt(__ASHL(obj->typ->size, 3));
		}
	} else {
		if (mode != 5 || obj->linkadr != 2) {
			if (mode == 13) {
				OPC_Ident(obj->link->typ->strobj);
			} else if (level < 0) {
				OPM_WriteStringVar((void*)OPT_GlbMod[__X(-level, 64)]->name, 256);
				if (OPM_currFile == 0) {
					OPT_GlbMod[__X(-level, 64)]->vis = 1;
				}
			} else {
				OPM_WriteStringVar((void*)OPM_modName, 32);
			}
			OPM_Write('_');
		} else if (obj == OPT_sysptrtyp->strobj || obj == OPT_bytetyp->strobj) {
			OPM_WriteString((CHAR*)"SYSTEM_", 8);
		}
		OPM_WriteStringVar((void*)obj->name, 256);
	}
}

static void OPC_Stars (OPT_Struct typ, BOOLEAN *openClause)
{
	INT16 pointers;
	*openClause = 0;
	if (((typ->strobj == NIL || typ->strobj->name[0] == 0x00) && typ->comp != 4)) {
		if (__IN(typ->comp, 0x0c, 32)) {
			OPC_Stars(typ->BaseTyp, &*openClause);
			*openClause = typ->comp == 2;
		} else if (typ->form == 12) {
			OPM_Write('(');
			OPM_Write('*');
		} else {
			pointers = 0;
			while (((typ->strobj == NIL || typ->strobj->name[0] == 0x00) && typ->form == 11)) {
				pointers += 1;
				typ = typ->BaseTyp;
			}
			if (pointers > 0) {
				if (typ->comp != 3) {
					OPC_Stars(typ, &*openClause);
				}
				if (*openClause) {
					OPM_Write('(');
					*openClause = 0;
				}
				while (pointers > 0) {
					OPM_Write('*');
					pointers -= 1;
				}
			}
		}
	}
}

static void OPC_DeclareObj (OPT_Object dcl, BOOLEAN scopeDef)
{
	OPT_Struct typ = NIL;
	BOOLEAN varPar, openClause;
	INT16 form, comp;
	typ = dcl->typ;
	varPar = ((dcl->mode == 2 && typ->comp != 2) || typ->comp == 3) || scopeDef;
	OPC_Stars(typ, &openClause);
	if (varPar) {
		if (openClause) {
			OPM_Write('(');
		}
		OPM_Write('*');
	}
	if (dcl->name[0] != 0x00) {
		OPC_Ident(dcl);
	}
	if ((varPar && openClause)) {
		OPM_Write(')');
	}
	openClause = 0;
	for (;;) {
		form = typ->form;
		comp = typ->comp;
		if (((typ->strobj != NIL && typ->strobj->name[0] != 0x00) || form == 10) || comp == 4) {
			break;
		} else if ((form == 11 && typ->BaseTyp->comp != 3)) {
			openClause = 1;
		} else if (form == 12 || __IN(comp, 0x0c, 32)) {
			if (openClause) {
				OPM_Write(')');
				openClause = 0;
			}
			if (form == 12) {
				OPM_Write(')');
				OPC_AnsiParamList(typ->link, 0);
				break;
			} else if (comp == 2) {
				OPM_Write('[');
				OPM_WriteInt(typ->n);
				OPM_Write(']');
			}
		} else {
			break;
		}
		typ = typ->BaseTyp;
	}
}

void OPC_Andent (OPT_Struct typ)
{
	if (typ->strobj == NIL || typ->align >= 65536) {
		OPM_WriteStringVar((void*)OPM_modName, 32);
		OPC_Str1((CHAR*)"__#", 4, __ASHR(typ->align, 16));
	} else {
		OPC_Ident(typ->strobj);
	}
}

static BOOLEAN OPC_Undefined (OPT_Object obj)
{
	return obj->name[0] == 0x00 || (((obj->mnolev >= 0 && obj->linkadr != (3 + OPM_currFile))) && obj->linkadr != 2);
}

static void OPC_DeclareBase (OPT_Object dcl)
{
	OPT_Struct typ = NIL, prev = NIL;
	OPT_Object obj = NIL;
	INT16 nofdims;
	INT32 off, n, dummy;
	typ = dcl->typ;
	prev = typ;
	while ((((((((typ->strobj == NIL || typ->comp == 3) || OPC_Undefined(typ->strobj)) && typ->comp != 4)) && typ->form != 10)) && !((typ->form == 11 && typ->BaseTyp->comp == 3)))) {
		prev = typ;
		typ = typ->BaseTyp;
	}
	obj = typ->strobj;
	if (typ->form == 10) {
		OPM_WriteString((CHAR*)"void", 5);
	} else if ((obj != NIL && !OPC_Undefined(obj))) {
		OPC_Ident(obj);
	} else if (typ->comp == 4) {
		OPM_WriteString((CHAR*)"struct ", 8);
		OPC_Andent(typ);
		if ((prev->form != 11 && (obj != NIL || dcl->name[0] == 0x00))) {
			if ((typ->BaseTyp != NIL && typ->BaseTyp->strobj->vis != 0)) {
				OPM_WriteString((CHAR*)" { /* ", 7);
				OPC_Ident(typ->BaseTyp->strobj);
				OPM_WriteString((CHAR*)" */", 4);
				OPM_WriteLn();
				OPC_Indent(1);
			} else {
				OPM_Write(' ');
				OPC_BegBlk();
			}
			OPC_FieldList(typ, 1, &off, &n, &dummy);
			OPC_EndBlk0();
		}
	} else if ((typ->form == 11 && typ->BaseTyp->comp == 3)) {
		typ = typ->BaseTyp->BaseTyp;
		nofdims = 1;
		while (typ->comp == 3) {
			nofdims += 1;
			typ = typ->BaseTyp;
		}
		OPM_WriteString((CHAR*)"struct ", 8);
		OPC_BegBlk();
		OPC_BegStat();
		OPC_Str1((CHAR*)"ADDRESS len[#]", 15, nofdims);
		OPC_EndStat();
		OPC_BegStat();
		__NEW(obj, OPT_ObjDesc);
		__NEW(obj->typ, OPT_StrDesc);
		obj->typ->form = 13;
		obj->typ->comp = 2;
		obj->typ->n = 1;
		obj->typ->BaseTyp = typ;
		obj->mode = 4;
		__MOVE("data", obj->name, 5);
		obj->linkadr = 0;
		OPC_DeclareBase(obj);
		OPM_Write(' ');
		OPC_DeclareObj(obj, 0);
		OPC_EndStat();
		OPC_EndBlk0();
	}
}

INT32 OPC_NofPtrs (OPT_Struct typ)
{
	OPT_Object fld = NIL;
	OPT_Struct btyp = NIL;
	INT32 n;
	if ((typ->form == 11 && typ->sysflag == 0)) {
		return 1;
	} else if ((typ->comp == 4 && __MASK(typ->sysflag, -256) == 0)) {
		btyp = typ->BaseTyp;
		if (btyp != NIL) {
			n = OPC_NofPtrs(btyp);
		} else {
			n = 0;
		}
		fld = typ->link;
		while ((fld != NIL && fld->mode == 4)) {
			if (__STRCMP(fld->name, "@ptr") != 0) {
				n = n + OPC_NofPtrs(fld->typ);
			} else {
				n += 1;
			}
			fld = fld->link;
		}
		return n;
	} else if (typ->comp == 2) {
		btyp = typ->BaseTyp;
		n = typ->n;
		while (btyp->comp == 2) {
			n = btyp->n * n;
			btyp = btyp->BaseTyp;
		}
		return OPC_NofPtrs(btyp) * n;
	} else {
		return 0;
	}
	__RETCHK;
}

static void OPC_PutPtrOffsets (OPT_Struct typ, INT32 adr, INT32 *cnt)
{
	OPT_Object fld = NIL;
	OPT_Struct btyp = NIL;
	INT32 n, i;
	if ((typ->form == 11 && typ->sysflag == 0)) {
		OPM_WriteInt(adr);
		OPM_WriteString((CHAR*)", ", 3);
		*cnt += 1;
		if (__MASK(*cnt, -16) == 0) {
			OPM_WriteLn();
			OPM_Write(0x09);
		}
	} else if ((typ->comp == 4 && __MASK(typ->sysflag, -256) == 0)) {
		btyp = typ->BaseTyp;
		if (btyp != NIL) {
			OPC_PutPtrOffsets(btyp, adr, &*cnt);
		}
		fld = typ->link;
		while ((fld != NIL && fld->mode == 4)) {
			if (__STRCMP(fld->name, "@ptr") != 0) {
				OPC_PutPtrOffsets(fld->typ, adr + fld->adr, &*cnt);
			} else {
				OPM_WriteInt(adr + fld->adr);
				OPM_WriteString((CHAR*)", ", 3);
				*cnt += 1;
				if (__MASK(*cnt, -16) == 0) {
					OPM_WriteLn();
					OPM_Write(0x09);
				}
			}
			fld = fld->link;
		}
	} else if (typ->comp == 2) {
		btyp = typ->BaseTyp;
		n = typ->n;
		while (btyp->comp == 2) {
			n = btyp->n * n;
			btyp = btyp->BaseTyp;
		}
		if (OPC_NofPtrs(btyp) > 0) {
			i = 0;
			while (i < n) {
				OPC_PutPtrOffsets(btyp, adr + i * btyp->size, &*cnt);
				i += 1;
			}
		}
	}
}

static void OPC_InitTProcs (OPT_Object typ, OPT_Object obj)
{
	if (obj != NIL) {
		OPC_InitTProcs(typ, obj->left);
		if (obj->mode == 13) {
			OPC_BegStat();
			OPM_WriteString((CHAR*)"__INITBP(", 10);
			OPC_Ident(typ);
			OPM_WriteString((CHAR*)", ", 3);
			OPC_Ident(obj);
			OPC_Str1((CHAR*)", #)", 5, __ASHR(obj->adr, 16));
			OPC_EndStat();
		}
		OPC_InitTProcs(typ, obj->right);
	}
}

static void OPC_PutBase (OPT_Struct typ)
{
	if (typ != NIL) {
		OPC_PutBase(typ->BaseTyp);
		OPC_Ident(typ->strobj);
		OPM_WriteString((CHAR*)"__typ", 6);
		OPM_WriteString((CHAR*)", ", 3);
	}
}

static void OPC_LenList (OPT_Object par, BOOLEAN ansiDefine, BOOLEAN showParamName)
{
	OPT_Struct typ = NIL;
	INT16 dim;
	if (showParamName) {
		OPC_Ident(par);
		OPM_WriteString((CHAR*)"__len", 6);
	}
	dim = 1;
	typ = par->typ->BaseTyp;
	while (typ->comp == 3) {
		if (ansiDefine) {
			OPM_WriteString((CHAR*)", ADDRESS ", 11);
		} else {
			OPM_WriteString((CHAR*)", ", 3);
		}
		if (showParamName) {
			OPC_Ident(par);
			OPM_WriteString((CHAR*)"__len", 6);
			OPM_WriteInt(dim);
		}
		typ = typ->BaseTyp;
		dim += 1;
	}
}

static void OPC_DeclareParams (OPT_Object par, BOOLEAN macro)
{
	OPM_Write('(');
	while (par != NIL) {
		if (macro) {
			OPM_WriteStringVar((void*)par->name, 256);
		} else {
			if ((par->mode == 1 && par->typ->form == 5)) {
				OPM_Write('_');
			}
			OPC_Ident(par);
		}
		if (par->typ->comp == 3) {
			OPM_WriteString((CHAR*)", ", 3);
			OPC_LenList(par, 0, 1);
		} else if ((par->mode == 2 && par->typ->comp == 4)) {
			OPM_WriteString((CHAR*)", ", 3);
			OPM_WriteStringVar((void*)par->name, 256);
			OPM_WriteString((CHAR*)"__typ", 6);
		}
		par = par->link;
		if (par != NIL) {
			OPM_WriteString((CHAR*)", ", 3);
		}
	}
	OPM_Write(')');
}

static void OPC_DefineTProcTypes (OPT_Object obj)
{
	OPT_Object par = NIL;
	if (obj->typ != OPT_notyp) {
		OPC_DefineType(obj->typ);
	}
	par = obj->link;
	while (par != NIL) {
		OPC_DefineType(par->typ);
		par = par->link;
	}
}

static void OPC_DeclareTProcs (OPT_Object obj, BOOLEAN *empty)
{
	if (obj != NIL) {
		OPC_DeclareTProcs(obj->left, &*empty);
		if (obj->mode == 13) {
			if (obj->typ != OPT_notyp) {
				OPC_DefineType(obj->typ);
			}
			if (OPM_currFile == 0) {
				if (obj->vis == 1) {
					OPC_DefineTProcTypes(obj);
					OPM_WriteString((CHAR*)"import ", 8);
					*empty = 0;
					OPC_ProcHeader(obj, 0);
				}
			} else {
				*empty = 0;
				OPC_DefineTProcTypes(obj);
				if (obj->vis == 0) {
					OPM_WriteString((CHAR*)"static ", 8);
				} else {
					OPM_WriteString((CHAR*)"export ", 8);
				}
				OPC_ProcHeader(obj, 0);
			}
		}
		OPC_DeclareTProcs(obj->right, &*empty);
	}
}

OPT_Object OPC_BaseTProc (OPT_Object obj)
{
	OPT_Struct typ = NIL, base = NIL;
	INT32 mno;
	typ = obj->link->typ;
	if (typ->form == 11) {
		typ = typ->BaseTyp;
	}
	base = typ->BaseTyp;
	mno = __ASHR(obj->adr, 16);
	while ((base != NIL && mno < base->n)) {
		typ = base;
		base = typ->BaseTyp;
	}
	OPT_FindField(obj->name, typ, &obj);
	return obj;
}

static void OPC_DefineTProcMacros (OPT_Object obj, BOOLEAN *empty)
{
	if (obj != NIL) {
		OPC_DefineTProcMacros(obj->left, &*empty);
		if ((((obj->mode == 13 && obj == OPC_BaseTProc(obj))) && (OPM_currFile != 0 || obj->vis == 1))) {
			OPM_WriteString((CHAR*)"#define __", 11);
			OPC_Ident(obj);
			OPC_DeclareParams(obj->link, 1);
			OPM_WriteString((CHAR*)" __SEND(", 9);
			if (obj->link->typ->form == 11) {
				OPM_WriteString((CHAR*)"__TYPEOF(", 10);
				OPC_Ident(obj->link);
				OPM_Write(')');
			} else {
				OPC_Ident(obj->link);
				OPM_WriteString((CHAR*)"__typ", 6);
			}
			OPC_Str1((CHAR*)", #, ", 6, __ASHR(obj->adr, 16));
			if (obj->typ == OPT_notyp) {
				OPM_WriteString((CHAR*)"void", 5);
			} else {
				OPC_Ident(obj->typ->strobj);
			}
			OPM_WriteString((CHAR*)"(*)", 4);
			OPC_AnsiParamList(obj->link, 0);
			OPM_WriteString((CHAR*)", ", 3);
			OPC_DeclareParams(obj->link, 1);
			OPM_Write(')');
			OPM_WriteLn();
		}
		OPC_DefineTProcMacros(obj->right, &*empty);
	}
}

static void OPC_DefineType (OPT_Struct str)
{
	OPT_Object obj = NIL, field = NIL, par = NIL;
	BOOLEAN empty;
	if (OPM_currFile == 1 || str->ref < 255) {
		obj = str->strobj;
		if (obj == NIL || OPC_Undefined(obj)) {
			if (obj != NIL) {
				if (obj->linkadr == 1) {
					if (str->form != 11) {
						OPM_Mark(244, str->txtpos);
						obj->linkadr = 2;
					}
				} else {
					obj->linkadr = 1;
				}
			}
			if (str->comp == 4) {
				if (str->BaseTyp != NIL) {
					OPC_DefineType(str->BaseTyp);
				}
				field = str->link;
				while ((field != NIL && field->mode == 4)) {
					if (field->vis != 0 || OPM_currFile == 1) {
						OPC_DefineType(field->typ);
					}
					field = field->link;
				}
			} else if (str->form == 11) {
				if (str->BaseTyp->comp != 4) {
					OPC_DefineType(str->BaseTyp);
				}
			} else if (__IN(str->comp, 0x0c, 32)) {
				if ((str->BaseTyp->strobj != NIL && str->BaseTyp->strobj->linkadr == 1)) {
					OPM_Mark(244, str->txtpos);
					str->BaseTyp->strobj->linkadr = 2;
				}
				OPC_DefineType(str->BaseTyp);
			} else if (str->form == 12) {
				if (str->BaseTyp != OPT_notyp) {
					OPC_DefineType(str->BaseTyp);
				}
				field = str->link;
				while (field != NIL) {
					OPC_DefineType(field->typ);
					field = field->link;
				}
			}
		}
		if ((obj != NIL && OPC_Undefined(obj))) {
			OPM_WriteString((CHAR*)"typedef", 8);
			OPM_WriteLn();
			OPM_Write(0x09);
			OPC_Indent(1);
			obj->linkadr = 1;
			OPC_DeclareBase(obj);
			OPM_Write(' ');
			obj->typ->strobj = NIL;
			OPC_DeclareObj(obj, 0);
			obj->typ->strobj = obj;
			obj->linkadr = 3 + OPM_currFile;
			OPC_EndStat();
			OPC_Indent(-1);
			OPM_WriteLn();
			if (obj->typ->comp == 4) {
				empty = 1;
				OPC_DeclareTProcs(str->link, &empty);
				OPC_DefineTProcMacros(str->link, &empty);
				if (!empty) {
					OPM_WriteLn();
				}
			}
		}
	}
}

static BOOLEAN OPC_Prefixed (OPT_ConstExt x, CHAR *y, ADDRESS y__len)
{
	INT16 i;
	__DUP(y, y__len, CHAR);
	i = 0;
	while ((*x)[__X(i + 1, 256)] == y[__X(i, y__len)]) {
		i += 1;
	}
	__DEL(y);
	return y[__X(i, y__len)] == 0x00;
}

static void OPC_CProcDefs (OPT_Object obj, INT16 vis)
{
	INT16 i;
	OPT_ConstExt ext = NIL;
	INT16 _for__7;
	if (obj != NIL) {
		OPC_CProcDefs(obj->left, vis);
		if ((((obj->mode == 9 && (INT16)obj->vis >= vis)) && obj->adr == 1)) {
			ext = obj->conval->ext;
			i = 1;
			if (((*ext)[1] != '#' && !(OPC_Prefixed(ext, (CHAR*)"extern ", 8) || OPC_Prefixed(ext, (CHAR*)"import ", 8)))) {
				OPM_WriteString((CHAR*)"#define ", 9);
				OPC_Ident(obj);
				OPC_DeclareParams(obj->link, 1);
				OPM_Write(0x09);
			}
			_for__7 = (INT16)(*obj->conval->ext)[0];
			i = i;
			while (i <= _for__7) {
				OPM_Write((*obj->conval->ext)[__X(i, 256)]);
				i += 1;
			}
			OPM_WriteLn();
		}
		OPC_CProcDefs(obj->right, vis);
	}
}

void OPC_TypeDefs (OPT_Object obj, INT16 vis)
{
	if (obj != NIL) {
		OPC_TypeDefs(obj->left, vis);
		if ((obj->mode == 5 && obj->typ->txtpos > 0)) {
			OPC_DefineType(obj->typ);
		}
		OPC_TypeDefs(obj->right, vis);
	}
}

static void OPC_DefAnonRecs (OPT_Node n)
{
	OPT_Object o = NIL;
	OPT_Struct typ = NIL;
	while ((n != NIL && n->class == 14)) {
		typ = n->typ;
		if ((typ->strobj == NIL && (OPM_currFile == 1 || typ->ref < 255))) {
			OPC_DefineType(typ);
			__NEW(o, OPT_ObjDesc);
			o->typ = typ;
			o->name[0] = 0x00;
			OPC_DeclareBase(o);
			OPC_EndStat();
			OPM_WriteLn();
		}
		n = n->link;
	}
}

void OPC_TDescDecl (OPT_Struct typ)
{
	INT32 nofptrs;
	OPT_Object o = NIL;
	OPC_BegStat();
	OPM_WriteString((CHAR*)"__TDESC(", 9);
	OPC_Andent(typ);
	OPC_Str1((CHAR*)", #", 4, typ->n + 1);
	OPC_Str1((CHAR*)", #) = {__TDFLDS(", 18, OPC_NofPtrs(typ));
	OPM_Write('"');
	if (typ->strobj != NIL) {
		OPM_WriteStringVar((void*)typ->strobj->name, 256);
	}
	OPM_Write('"');
	OPC_Str1((CHAR*)", #), {", 8, typ->size);
	nofptrs = 0;
	OPC_PutPtrOffsets(typ, 0, &nofptrs);
	OPC_Str1((CHAR*)"#}}", 4, -((nofptrs + 1) * OPM_AddressSize));
	OPC_EndStat();
}

void OPC_InitTDesc (OPT_Struct typ)
{
	OPC_BegStat();
	OPM_WriteString((CHAR*)"__INITYP(", 10);
	OPC_Andent(typ);
	OPM_WriteString((CHAR*)", ", 3);
	if (typ->BaseTyp != NIL) {
		OPC_Andent(typ->BaseTyp);
	} else {
		OPC_Andent(typ);
	}
	OPC_Str1((CHAR*)", #)", 5, typ->extlev);
	OPC_EndStat();
	if (typ->strobj != NIL) {
		OPC_InitTProcs(typ->strobj, typ->link);
	}
}

static void OPC_FillGap (INT32 gap, INT32 off, INT32 align, INT32 *n, INT32 *curAlign)
{
	INT32 adr;
	adr = off;
	OPT_Align(&adr, align);
	if ((*curAlign < align && gap - (adr - off) >= align)) {
		gap -= (adr - off) + align;
		OPC_BegStat();
		switch (align) {
			case 2: 
				OPM_WriteString((CHAR*)"INT16", 6);
				break;
			case 4: 
				OPM_WriteString((CHAR*)"INT32", 6);
				break;
			case 8: 
				OPM_WriteString((CHAR*)"INT64", 6);
				break;
			default: 
				OPM_LogWLn();
				OPM_LogWStr((CHAR*)"Unexpected enclosing alignment in FillGap.", 43);
				break;
		}
		OPC_Str1((CHAR*)" _prvt#", 8, *n);
		*n += 1;
		OPC_EndStat();
		*curAlign = align;
	}
	if (gap > 0) {
		OPC_BegStat();
		OPC_Str1((CHAR*)"char _prvt#", 12, *n);
		*n += 1;
		OPC_Str1((CHAR*)"[#]", 4, gap);
		OPC_EndStat();
	}
}

static void OPC_FieldList (OPT_Struct typ, BOOLEAN last, INT32 *off, INT32 *n, INT32 *curAlign)
{
	OPT_Object fld = NIL;
	OPT_Struct base = NIL;
	INT32 gap, adr, align, fldAlign;
	fld = typ->link;
	align = __MASK(typ->align, -65536);
	if (typ->BaseTyp != NIL) {
		OPC_FieldList(typ->BaseTyp, 0, &*off, &*n, &*curAlign);
	} else {
		*off = 0;
		*n = 0;
		*curAlign = 1;
	}
	while ((fld != NIL && fld->mode == 4)) {
		if ((OPM_currFile == 0 && fld->vis == 0) || (((OPM_currFile == 1 && fld->vis == 0)) && typ->mno != 0)) {
			fld = fld->link;
			while ((((fld != NIL && fld->mode == 4)) && fld->vis == 0)) {
				fld = fld->link;
			}
		} else {
			adr = *off;
			fldAlign = OPT_BaseAlignment(fld->typ);
			OPT_Align(&adr, fldAlign);
			gap = fld->adr - adr;
			if (fldAlign > *curAlign) {
				*curAlign = fldAlign;
			}
			if (gap > 0) {
				OPC_FillGap(gap, *off, align, &*n, &*curAlign);
			}
			OPC_BegStat();
			OPC_DeclareBase(fld);
			OPM_Write(' ');
			OPC_DeclareObj(fld, 0);
			*off = fld->adr + fld->typ->size;
			base = fld->typ;
			fld = fld->link;
			while ((((((((fld != NIL && fld->mode == 4)) && fld->typ == base)) && fld->adr == *off)) && ((OPM_currFile == 1 || fld->vis != 0) || fld->typ->strobj == NIL))) {
				OPM_WriteString((CHAR*)", ", 3);
				OPC_DeclareObj(fld, 0);
				*off = fld->adr + fld->typ->size;
				fld = fld->link;
			}
			OPC_EndStat();
		}
	}
	if (last) {
		adr = typ->size - __ASHR(typ->sysflag, 8);
		if (adr == 0) {
			gap = 1;
		} else {
			gap = adr - *off;
		}
		if (gap > 0) {
			OPC_FillGap(gap, *off, align, &*n, &*curAlign);
		}
	}
}

static void OPC_IdentList (OPT_Object obj, INT16 vis)
{
	OPT_Struct base = NIL;
	BOOLEAN first;
	INT16 lastvis;
	base = NIL;
	first = 1;
	while ((obj != NIL && obj->mode != 13)) {
		if ((__IN(vis, 0x05, 32) || (vis == 1 && obj->vis != 0)) || (vis == 3 && !obj->leaf)) {
			if (obj->typ != base || (INT16)obj->vis != lastvis) {
				if (!first) {
					OPC_EndStat();
				}
				first = 0;
				base = obj->typ;
				lastvis = obj->vis;
				OPC_BegStat();
				if ((vis == 1 && obj->vis != 0)) {
					OPM_WriteString((CHAR*)"import ", 8);
				} else if ((obj->mnolev == 0 && vis == 0)) {
					if (obj->vis == 0) {
						OPM_WriteString((CHAR*)"static ", 8);
					} else {
						OPM_WriteString((CHAR*)"export ", 8);
					}
				}
				if ((((vis == 2 && obj->mode == 1)) && base->form == 5)) {
					OPM_WriteString((CHAR*)"double", 7);
				} else {
					OPC_DeclareBase(obj);
				}
			} else {
				OPM_Write(',');
			}
			OPM_Write(' ');
			if ((((vis == 2 && obj->mode == 1)) && base->form == 5)) {
				OPM_Write('_');
			}
			OPC_DeclareObj(obj, vis == 3);
			if (obj->typ->comp == 3) {
				OPC_EndStat();
				OPC_BegStat();
				base = OPT_adrtyp;
				OPM_WriteString((CHAR*)"ADDRESS ", 9);
				OPC_LenList(obj, 0, 1);
			} else if ((obj->mode == 2 && obj->typ->comp == 4)) {
				OPC_EndStat();
				OPC_BegStat();
				OPM_WriteString((CHAR*)"ADDRESS *", 10);
				OPC_Ident(obj);
				OPM_WriteString((CHAR*)"__typ", 6);
				base = NIL;
			} else if ((((((__IN(5, OPM_Options, 32) && vis == 0)) && obj->mnolev > 0)) && obj->typ->form == 11)) {
				OPM_WriteString((CHAR*)" = NIL", 7);
			}
		}
		obj = obj->link;
	}
	if (!first) {
		OPC_EndStat();
	}
}

static void OPC_AnsiParamList (OPT_Object obj, BOOLEAN showParamNames)
{
	CHAR name[32];
	OPM_Write('(');
	if (obj == NIL || obj->mode == 13) {
		OPM_WriteString((CHAR*)"void", 5);
	} else {
		for (;;) {
			OPC_DeclareBase(obj);
			if (showParamNames) {
				OPM_Write(' ');
				OPC_DeclareObj(obj, 0);
			} else {
				__COPY(obj->name, name, 32);
				obj->name[0] = 0x00;
				OPC_DeclareObj(obj, 0);
				__COPY(name, obj->name, 256);
			}
			if (obj->typ->comp == 3) {
				OPM_WriteString((CHAR*)", ADDRESS ", 11);
				OPC_LenList(obj, 1, showParamNames);
			} else if ((obj->mode == 2 && obj->typ->comp == 4)) {
				OPM_WriteString((CHAR*)", ADDRESS *", 12);
				if (showParamNames) {
					OPC_Ident(obj);
					OPM_WriteString((CHAR*)"__typ", 6);
				}
			}
			if (obj->link == NIL || obj->link->mode == 13) {
				break;
			}
			OPM_WriteString((CHAR*)", ", 3);
			obj = obj->link;
		}
	}
	OPM_Write(')');
}

static void OPC_ProcHeader (OPT_Object proc, BOOLEAN define)
{
	if (proc->typ == OPT_notyp) {
		OPM_WriteString((CHAR*)"void", 5);
	} else {
		OPC_Ident(proc->typ->strobj);
	}
	OPM_Write(' ');
	OPC_Ident(proc);
	OPM_Write(' ');
	OPC_AnsiParamList(proc->link, 1);
	if (!define) {
		OPM_Write(';');
	}
	OPM_WriteLn();
}

static void OPC_ProcPredefs (OPT_Object obj, INT8 vis)
{
	if (obj != NIL) {
		OPC_ProcPredefs(obj->left, vis);
		if ((((__IN(obj->mode, 0xc0, 32) && obj->vis >= vis)) && (obj->history != 4 || obj->mode == 6))) {
			if (vis == 1) {
				OPM_WriteString((CHAR*)"import ", 8);
			} else if (obj->vis == 0) {
				OPM_WriteString((CHAR*)"static ", 8);
			} else {
				OPM_WriteString((CHAR*)"export ", 8);
			}
			OPC_ProcHeader(obj, 0);
		}
		OPC_ProcPredefs(obj->right, vis);
	}
}

static void OPC_Include (CHAR *name, ADDRESS name__len)
{
	__DUP(name, name__len, CHAR);
	OPM_WriteString((CHAR*)"#include ", 10);
	OPM_Write('"');
	OPM_WriteStringVar((void*)name, name__len);
	OPM_WriteString((CHAR*)".h", 3);
	OPM_Write('"');
	OPM_WriteLn();
	__DEL(name);
}

static void OPC_IncludeImports (OPT_Object obj, INT16 vis)
{
	if (obj != NIL) {
		OPC_IncludeImports(obj->left, vis);
		if ((((obj->mode == 11 && obj->mnolev != 0)) && (INT16)OPT_GlbMod[__X(-obj->mnolev, 64)]->vis >= vis)) {
			OPC_Include(OPT_GlbMod[__X(-obj->mnolev, 64)]->name, 256);
		}
		OPC_IncludeImports(obj->right, vis);
	}
}

static void OPC_GenDynTypes (OPT_Node n, INT16 vis)
{
	OPT_Struct typ = NIL;
	while ((n != NIL && n->class == 14)) {
		typ = n->typ;
		if (vis == 0 || typ->ref < 255) {
			OPC_BegStat();
			if (vis == 1) {
				OPM_WriteString((CHAR*)"import ", 8);
			} else if ((typ->strobj != NIL && typ->strobj->mnolev > 0)) {
				OPM_WriteString((CHAR*)"static ", 8);
			} else {
				OPM_WriteString((CHAR*)"export ", 8);
			}
			OPM_WriteString((CHAR*)"ADDRESS *", 10);
			OPC_Andent(typ);
			OPM_WriteString((CHAR*)"__typ", 6);
			OPC_EndStat();
		}
		n = n->link;
	}
}

void OPC_GenHdr (OPT_Node n)
{
	OPM_currFile = 0;
	OPC_DefAnonRecs(n);
	OPC_TypeDefs(OPT_topScope->right, 1);
	OPM_WriteLn();
	OPC_IdentList(OPT_topScope->scope, 1);
	OPM_WriteLn();
	OPC_GenDynTypes(n, 1);
	OPM_WriteLn();
	OPC_ProcPredefs(OPT_topScope->right, 1);
	OPM_WriteString((CHAR*)"import ", 8);
	OPM_WriteString((CHAR*)"void *", 7);
	OPM_WriteStringVar((void*)OPM_modName, 32);
	OPM_WriteString(OPC_BodyNameExt, 13);
	OPC_EndStat();
	OPM_WriteLn();
	OPC_CProcDefs(OPT_topScope->right, 1);
	OPM_WriteLn();
	OPM_WriteString((CHAR*)"#endif // ", 11);
	OPM_WriteStringVar((void*)OPM_modName, 32);
	OPM_WriteLn();
}

static void OPC_GenHeaderMsg (void)
{
	INT16 i;
	OPM_WriteString((CHAR*)"/* ", 4);
	OPM_WriteString((CHAR*)"voc", 4);
	OPM_Write(' ');
	OPM_WriteString(Configuration_versionLong, 76);
	OPM_Write(' ');
	i = 0;
	while (i <= 31) {
		if (__IN(i, OPM_Options, 32)) {
			switch (i) {
				case 0: 
					OPM_Write('x');
					break;
				case 2: 
					OPM_Write('r');
					break;
				case 3: 
					OPM_Write('t');
					break;
				case 4: 
					OPM_Write('s');
					break;
				case 5: 
					OPM_Write('p');
					break;
				case 7: 
					OPM_Write('a');
					break;
				case 9: 
					OPM_Write('e');
					break;
				case 10: 
					OPM_Write('m');
					break;
				case 13: 
					OPM_Write('S');
					break;
				case 14: 
					OPM_Write('c');
					break;
				case 15: 
					OPM_Write('M');
					break;
				case 16: 
					OPM_Write('f');
					break;
				case 17: 
					OPM_Write('F');
					break;
				case 18: 
					OPM_Write('v');
					break;
				default: 
					OPM_LogWStr((CHAR*)"( more options defined in OPM than checked in OPC.GenHeaderMsg, if you are a compiler developer, add them to OPC.GenHeaderMsg", 126);
					OPM_LogWLn();
					break;
			}
		}
		i += 1;
	}
	OPM_WriteString((CHAR*)" */", 4);
	OPM_WriteLn();
}

void OPC_GenHdrIncludes (void)
{
	OPM_currFile = 2;
	OPC_GenHeaderMsg();
	OPM_WriteLn();
	OPM_WriteString((CHAR*)"#ifndef ", 9);
	OPM_WriteStringVar((void*)OPM_modName, 32);
	OPM_WriteString((CHAR*)"__h", 4);
	OPM_WriteLn();
	OPM_WriteString((CHAR*)"#define ", 9);
	OPM_WriteStringVar((void*)OPM_modName, 32);
	OPM_WriteString((CHAR*)"__h", 4);
	OPM_WriteLn();
	OPM_WriteLn();
	OPC_Include((CHAR*)"SYSTEM", 7);
	OPC_IncludeImports(OPT_topScope->right, 1);
	OPM_WriteLn();
}

void OPC_GenBdy (OPT_Node n)
{
	OPM_currFile = 1;
	OPC_GenHeaderMsg();
	OPM_WriteLn();
	OPM_WriteString((CHAR*)"#define SHORTINT INT", 21);
	OPM_WriteInt(__ASHL(OPT_sinttyp->size, 3));
	OPM_WriteLn();
	OPM_WriteString((CHAR*)"#define INTEGER  INT", 21);
	OPM_WriteInt(__ASHL(OPT_inttyp->size, 3));
	OPM_WriteLn();
	OPM_WriteString((CHAR*)"#define LONGINT  INT", 21);
	OPM_WriteInt(__ASHL(OPT_linttyp->size, 3));
	OPM_WriteLn();
	OPM_WriteString((CHAR*)"#define SET      UINT", 22);
	OPM_WriteInt(__ASHL(OPT_settyp->size, 3));
	OPM_WriteLn();
	OPM_WriteLn();
	OPC_Include((CHAR*)"SYSTEM", 7);
	OPC_IncludeImports(OPT_topScope->right, 0);
	OPM_WriteLn();
	OPC_DefAnonRecs(n);
	OPC_TypeDefs(OPT_topScope->right, 0);
	OPM_WriteLn();
	OPC_IdentList(OPT_topScope->scope, 0);
	OPM_WriteLn();
	OPC_GenDynTypes(n, 0);
	OPM_WriteLn();
	OPC_ProcPredefs(OPT_topScope->right, 0);
	OPM_WriteLn();
	OPC_CProcDefs(OPT_topScope->right, 0);
	OPM_WriteLn();
}

static void OPC_RegCmds (OPT_Object obj)
{
	if (obj != NIL) {
		OPC_RegCmds(obj->left);
		if ((obj->mode == 7 && obj->history != 4)) {
			if ((((obj->vis != 0 && obj->link == NIL)) && obj->typ == OPT_notyp)) {
				OPC_BegStat();
				OPM_WriteString((CHAR*)"__REGCMD(\"", 11);
				OPM_WriteStringVar((void*)obj->name, 256);
				OPM_WriteString((CHAR*)"\", ", 4);
				OPC_Ident(obj);
				OPM_Write(')');
				OPC_EndStat();
			}
		}
		OPC_RegCmds(obj->right);
	}
}

static void OPC_InitImports (OPT_Object obj)
{
	if (obj != NIL) {
		OPC_InitImports(obj->left);
		if ((obj->mode == 11 && obj->mnolev != 0)) {
			OPC_BegStat();
			OPM_WriteString((CHAR*)"__MODULE_IMPORT(", 17);
			OPM_WriteStringVar((void*)OPT_GlbMod[__X(-obj->mnolev, 64)]->name, 256);
			OPM_Write(')');
			OPC_EndStat();
		}
		OPC_InitImports(obj->right);
	}
}

void OPC_GenEnumPtrs (OPT_Object var)
{
	OPT_Struct typ = NIL;
	INT32 n;
	OPC_GlbPtrs = 0;
	while (var != NIL) {
		typ = var->typ;
		if (OPC_NofPtrs(typ) > 0) {
			if (!OPC_GlbPtrs) {
				OPC_GlbPtrs = 1;
				OPM_WriteString((CHAR*)"static void EnumPtrs(void (*P)(void*))", 39);
				OPM_WriteLn();
				OPC_BegBlk();
			}
			OPC_BegStat();
			if (typ->form == 11) {
				OPM_WriteString((CHAR*)"P(", 3);
				OPC_Ident(var);
				OPM_Write(')');
			} else if (typ->comp == 4) {
				OPM_WriteString((CHAR*)"__ENUMR(&", 10);
				OPC_Ident(var);
				OPM_WriteString((CHAR*)", ", 3);
				OPC_Andent(typ);
				OPM_WriteString((CHAR*)"__typ", 6);
				OPC_Str1((CHAR*)", #", 4, typ->size);
				OPM_WriteString((CHAR*)", 1, P)", 8);
			} else if (typ->comp == 2) {
				n = typ->n;
				typ = typ->BaseTyp;
				while (typ->comp == 2) {
					n = n * typ->n;
					typ = typ->BaseTyp;
				}
				if (typ->form == 11) {
					OPM_WriteString((CHAR*)"__ENUMP(", 9);
					OPC_Ident(var);
					OPC_Str1((CHAR*)", #, P)", 8, n);
				} else if (typ->comp == 4) {
					OPM_WriteString((CHAR*)"__ENUMR(", 9);
					OPC_Ident(var);
					OPM_WriteString((CHAR*)", ", 3);
					OPC_Andent(typ);
					OPM_WriteString((CHAR*)"__typ", 6);
					OPC_Str1((CHAR*)", #", 4, typ->size);
					OPC_Str1((CHAR*)", #, P)", 8, n);
				}
			}
			OPC_EndStat();
		}
		var = var->link;
	}
	if (OPC_GlbPtrs) {
		OPC_EndBlk();
		OPM_WriteLn();
	}
}

void OPC_EnterBody (void)
{
	OPM_WriteLn();
	OPM_WriteString((CHAR*)"export ", 8);
	if (__IN(10, OPM_Options, 32)) {
		OPM_WriteString((CHAR*)"int main(int argc, char **argv)", 32);
		OPM_WriteLn();
	} else {
		OPM_WriteString((CHAR*)"void *", 7);
		OPM_WriteString(OPM_modName, 32);
		OPM_WriteString(OPC_BodyNameExt, 13);
		OPM_WriteLn();
	}
	OPC_BegBlk();
	OPC_BegStat();
	if (__IN(10, OPM_Options, 32)) {
		OPM_WriteString((CHAR*)"__INIT(argc, argv)", 19);
	} else {
		OPM_WriteString((CHAR*)"__DEFMOD", 9);
	}
	OPC_EndStat();
	if ((__IN(10, OPM_Options, 32) && 0)) {
		OPC_BegStat();
		OPM_WriteString((CHAR*)"/*don`t do it!*/ printf(\"DEMO VERSION: DO NOT USE THIS PROGRAM FOR ANY COMMERCIAL PURPOSE\\n\")", 94);
		OPC_EndStat();
	}
	OPC_InitImports(OPT_topScope->right);
	OPC_BegStat();
	if (__IN(10, OPM_Options, 32)) {
		OPM_WriteString((CHAR*)"__REGMAIN(\"", 12);
	} else {
		OPM_WriteString((CHAR*)"__REGMOD(\"", 11);
	}
	OPM_WriteString(OPM_modName, 32);
	if (OPC_GlbPtrs) {
		OPM_WriteString((CHAR*)"\", EnumPtrs)", 13);
	} else {
		OPM_WriteString((CHAR*)"\", 0)", 6);
	}
	OPC_EndStat();
	if (__STRCMP(OPM_modName, "SYSTEM") != 0) {
		OPC_RegCmds(OPT_topScope);
	}
}

void OPC_ExitBody (void)
{
	OPC_BegStat();
	if (__IN(10, OPM_Options, 32)) {
		OPM_WriteString((CHAR*)"__FINI;", 8);
	} else {
		OPM_WriteString((CHAR*)"__ENDMOD;", 10);
	}
	OPM_WriteLn();
	OPC_EndBlk();
}

void OPC_DefineInter (OPT_Object proc)
{
	OPT_Object scope = NIL;
	scope = proc->scope;
	OPM_WriteString((CHAR*)"static ", 8);
	OPM_WriteString((CHAR*)"struct ", 8);
	OPM_WriteStringVar((void*)scope->name, 256);
	OPM_Write(' ');
	OPC_BegBlk();
	OPC_IdentList(proc->link, 3);
	OPC_IdentList(scope->scope, 3);
	OPC_BegStat();
	OPM_WriteString((CHAR*)"struct ", 8);
	OPM_WriteStringVar((void*)scope->name, 256);
	OPM_Write(' ');
	OPM_Write('*');
	OPM_WriteString((CHAR*)"lnk", 4);
	OPC_EndStat();
	OPC_EndBlk0();
	OPM_Write(' ');
	OPM_Write('*');
	OPM_WriteStringVar((void*)scope->name, 256);
	OPM_WriteString((CHAR*)"_s", 3);
	OPC_EndStat();
	OPM_WriteLn();
	OPC_ProcPredefs(scope->right, 0);
	OPM_WriteLn();
}

BOOLEAN OPC_NeedsRetval (OPT_Object proc)
{
	return (proc->typ != OPT_notyp && !proc->scope->leaf);
}

void OPC_EnterProc (OPT_Object proc)
{
	OPT_Object var = NIL, scope = NIL;
	OPT_Struct typ = NIL;
	INT16 dim;
	if (proc->vis != 1) {
		OPM_WriteString((CHAR*)"static ", 8);
	}
	OPC_ProcHeader(proc, 1);
	OPC_BegBlk();
	scope = proc->scope;
	OPC_IdentList(scope->scope, 0);
	if (!scope->leaf) {
		OPC_BegStat();
		OPM_WriteString((CHAR*)"struct ", 8);
		OPM_WriteStringVar((void*)scope->name, 256);
		OPM_Write(' ');
		OPM_WriteString((CHAR*)"_s", 3);
		OPC_EndStat();
	}
	if (OPC_NeedsRetval(proc)) {
		OPC_BegStat();
		OPC_Ident(proc->typ->strobj);
		OPM_WriteString((CHAR*)" __retval", 10);
		OPC_EndStat();
	}
	var = proc->link;
	while (var != NIL) {
		if ((var->typ->comp == 2 && var->mode == 1)) {
			OPC_BegStat();
			if (var->typ->strobj == NIL) {
				OPM_Mark(200, var->typ->txtpos);
			} else {
				OPC_Ident(var->typ->strobj);
			}
			OPM_Write(' ');
			OPC_Ident(var);
			OPM_WriteString((CHAR*)"__copy", 7);
			OPC_EndStat();
		}
		var = var->link;
	}
	var = proc->link;
	while (var != NIL) {
		if ((((__IN(var->typ->comp, 0x0c, 32) && var->mode == 1)) && var->typ->sysflag == 0)) {
			OPC_BegStat();
			if (var->typ->comp == 2) {
				OPM_WriteString((CHAR*)"__DUPARR(", 10);
				OPC_Ident(var);
				OPM_WriteString((CHAR*)", ", 3);
				if (var->typ->strobj == NIL) {
					OPM_Mark(200, var->typ->txtpos);
				} else {
					OPC_Ident(var->typ->strobj);
				}
			} else {
				OPM_WriteString((CHAR*)"__DUP(", 7);
				OPC_Ident(var);
				OPM_WriteString((CHAR*)", ", 3);
				OPC_Ident(var);
				OPM_WriteString((CHAR*)"__len", 6);
				typ = var->typ->BaseTyp;
				dim = 1;
				while (typ->comp == 3) {
					OPM_WriteString((CHAR*)" * ", 4);
					OPC_Ident(var);
					OPM_WriteString((CHAR*)"__len", 6);
					OPM_WriteInt(dim);
					typ = typ->BaseTyp;
					dim += 1;
				}
				OPM_WriteString((CHAR*)", ", 3);
				if (typ->strobj == NIL) {
					OPM_Mark(200, typ->txtpos);
				} else {
					OPC_Ident(typ->strobj);
				}
			}
			OPM_Write(')');
			OPC_EndStat();
		}
		var = var->link;
	}
	if (!scope->leaf) {
		var = proc->link;
		while (var != NIL) {
			if (!var->leaf) {
				OPC_BegStat();
				OPM_WriteString((CHAR*)"_s", 3);
				OPM_Write('.');
				OPC_Ident(var);
				OPM_WriteString((CHAR*)" = ", 4);
				if (__IN(var->typ->comp, 0x0c, 32)) {
					OPM_WriteString((CHAR*)"(void*)", 8);
				} else if (var->mode != 2) {
					OPM_Write('&');
				}
				OPC_Ident(var);
				if (var->typ->comp == 3) {
					typ = var->typ;
					dim = 0;
					do {
						OPM_WriteString((CHAR*)"; ", 3);
						OPM_WriteString((CHAR*)"_s", 3);
						OPM_Write('.');
						OPC_Ident(var);
						OPM_WriteString((CHAR*)"__len", 6);
						if (dim != 0) {
							OPM_WriteInt(dim);
						}
						OPM_WriteString((CHAR*)" = ", 4);
						OPC_Ident(var);
						OPM_WriteString((CHAR*)"__len", 6);
						if (dim != 0) {
							OPM_WriteInt(dim);
						}
						typ = typ->BaseTyp;
					} while (!(typ->comp != 3));
				} else if ((var->mode == 2 && var->typ->comp == 4)) {
					OPM_WriteString((CHAR*)"; ", 3);
					OPM_WriteString((CHAR*)"_s", 3);
					OPM_Write('.');
					OPC_Ident(var);
					OPM_WriteString((CHAR*)"__typ", 6);
					OPM_WriteString((CHAR*)" = ", 4);
					OPC_Ident(var);
					OPM_WriteString((CHAR*)"__typ", 6);
				}
				OPC_EndStat();
			}
			var = var->link;
		}
		var = scope->scope;
		while (var != NIL) {
			if (!var->leaf) {
				OPC_BegStat();
				OPM_WriteString((CHAR*)"_s", 3);
				OPM_Write('.');
				OPC_Ident(var);
				OPM_WriteString((CHAR*)" = ", 4);
				if (var->typ->comp != 2) {
					OPM_Write('&');
				} else {
					OPM_WriteString((CHAR*)"(void*)", 8);
				}
				OPC_Ident(var);
				OPC_EndStat();
			}
			var = var->link;
		}
		OPC_BegStat();
		OPM_WriteString((CHAR*)"_s", 3);
		OPM_Write('.');
		OPM_WriteString((CHAR*)"lnk", 4);
		OPM_WriteString((CHAR*)" = ", 4);
		OPM_WriteStringVar((void*)scope->name, 256);
		OPM_WriteString((CHAR*)"_s", 3);
		OPC_EndStat();
		OPC_BegStat();
		OPM_WriteStringVar((void*)scope->name, 256);
		OPM_WriteString((CHAR*)"_s", 3);
		OPM_WriteString((CHAR*)" = ", 4);
		OPM_Write('&');
		OPM_WriteString((CHAR*)"_s", 3);
		OPC_EndStat();
	}
}

void OPC_ExitProc (OPT_Object proc, BOOLEAN eoBlock, BOOLEAN implicitRet)
{
	OPT_Object var = NIL;
	BOOLEAN indent;
	indent = eoBlock;
	if ((implicitRet && proc->typ != OPT_notyp)) {
		OPM_Write(0x09);
		OPM_WriteString((CHAR*)"__RETCHK;", 10);
		OPM_WriteLn();
	} else if (!eoBlock || implicitRet) {
		if (!proc->scope->leaf) {
			if (indent) {
				OPC_BegStat();
			} else {
				indent = 1;
			}
			OPM_WriteStringVar((void*)proc->scope->name, 256);
			OPM_WriteString((CHAR*)"_s", 3);
			OPM_WriteString((CHAR*)" = ", 4);
			OPM_WriteString((CHAR*)"_s", 3);
			OPM_Write('.');
			OPM_WriteString((CHAR*)"lnk", 4);
			OPC_EndStat();
		}
		var = proc->link;
		while (var != NIL) {
			if ((((var->typ->comp == 3 && var->mode == 1)) && var->typ->sysflag == 0)) {
				if (indent) {
					OPC_BegStat();
				} else {
					indent = 1;
				}
				OPM_WriteString((CHAR*)"__DEL(", 7);
				OPC_Ident(var);
				OPM_Write(')');
				OPC_EndStat();
			}
			var = var->link;
		}
	}
	if (eoBlock) {
		OPC_EndBlk();
		OPM_WriteLn();
	} else if (indent) {
		OPC_BegStat();
	}
}

void OPC_CompleteIdent (OPT_Object obj)
{
	INT16 comp, level;
	level = obj->mnolev;
	if (obj->adr == 1) {
		if (obj->typ->comp == 4) {
			OPC_Ident(obj);
			OPM_WriteString((CHAR*)"__", 3);
		} else {
			OPM_WriteString((CHAR*)"(*(", 4);
			OPC_Ident(obj->typ->strobj);
			OPM_WriteString((CHAR*)"*)&", 4);
			OPC_Ident(obj);
			OPM_Write(')');
		}
	} else if ((level != OPM_level && level > 0)) {
		comp = obj->typ->comp;
		if ((obj->mode != 2 && comp != 3)) {
			OPM_Write('*');
		}
		OPM_WriteStringVar((void*)obj->scope->name, 256);
		OPM_WriteString((CHAR*)"_s", 3);
		OPM_WriteString((CHAR*)"->", 3);
		OPC_Ident(obj);
	} else {
		OPC_Ident(obj);
	}
}

void OPC_TypeOf (OPT_Object ap)
{
	INT16 i;
	__ASSERT(ap->typ->comp == 4, 0);
	if (ap->mode == 2) {
		if ((INT16)ap->mnolev != OPM_level) {
			OPM_WriteStringVar((void*)ap->scope->name, 256);
			OPM_WriteString((CHAR*)"_s->", 5);
			OPC_Ident(ap);
		} else {
			OPC_Ident(ap);
		}
		OPM_WriteString((CHAR*)"__typ", 6);
	} else if (ap->typ->strobj != NIL) {
		OPC_Ident(ap->typ->strobj);
		OPM_WriteString((CHAR*)"__typ", 6);
	} else {
		OPC_Andent(ap->typ);
	}
}

void OPC_Cmp (INT16 rel)
{
	switch (rel) {
		case 9: 
			OPM_WriteString((CHAR*)" == ", 5);
			break;
		case 10: 
			OPM_WriteString((CHAR*)" != ", 5);
			break;
		case 11: 
			OPM_WriteString((CHAR*)" < ", 4);
			break;
		case 12: 
			OPM_WriteString((CHAR*)" <= ", 5);
			break;
		case 13: 
			OPM_WriteString((CHAR*)" > ", 4);
			break;
		case 14: 
			OPM_WriteString((CHAR*)" >= ", 5);
			break;
		default: 
			OPM_LogWStr((CHAR*)"unhandled case in OPC.Cmp, rel = ", 34);
			OPM_LogWNum(rel, 0);
			OPM_LogWLn();
			break;
	}
}

static void OPC_CharacterLiteral (INT64 c)
{
	if (c < 32 || c > 126) {
		OPM_WriteString((CHAR*)"0x", 3);
		OPM_WriteHex(c);
	} else {
		OPM_Write('\'');
		if ((c == 92 || c == 39) || c == 63) {
			OPM_Write('\\');
		}
		OPM_Write(__CHR(c));
		OPM_Write('\'');
	}
}

static void OPC_StringLiteral (CHAR *s, ADDRESS s__len, INT32 l)
{
	INT32 i;
	INT16 c;
	__DUP(s, s__len, CHAR);
	OPM_Write('"');
	i = 0;
	while (i < l) {
		c = (INT16)s[__X(i, s__len)];
		if (c < 32 || c > 126) {
			OPM_Write('\\');
			OPM_Write(__CHR(48 + __ASHR(c, 6)));
			c = __MASK(c, -64);
			OPM_Write(__CHR(48 + __ASHR(c, 3)));
			c = __MASK(c, -8);
			OPM_Write(__CHR(48 + c));
		} else {
			if ((c == 92 || c == 34) || c == 63) {
				OPM_Write('\\');
			}
			OPM_Write(__CHR(c));
		}
		i += 1;
	}
	OPM_Write('"');
	__DEL(s);
}

void OPC_Case (INT64 caseVal, INT16 form)
{
	CHAR ch;
	OPM_WriteString((CHAR*)"case ", 6);
	switch (form) {
		case 3: 
			OPC_CharacterLiteral(caseVal);
			break;
		case 4: 
			OPM_WriteInt(caseVal);
			break;
		default: 
			OPM_LogWStr((CHAR*)"unhandled case in OPC.Case, form = ", 36);
			OPM_LogWNum(form, 0);
			OPM_LogWLn();
			break;
	}
	OPM_WriteString((CHAR*)": ", 3);
}

void OPC_SetInclude (BOOLEAN exclude)
{
	if (exclude) {
		OPM_WriteString((CHAR*)" &= ~", 6);
	} else {
		OPM_WriteString((CHAR*)" |= ", 5);
	}
}

void OPC_Increment (BOOLEAN decrement)
{
	if (decrement) {
		OPM_WriteString((CHAR*)" -= ", 5);
	} else {
		OPM_WriteString((CHAR*)" += ", 5);
	}
}

void OPC_Halt (INT32 n)
{
	OPC_Str1((CHAR*)"__HALT(#)", 10, n);
}

void OPC_IntLiteral (INT64 n, INT32 size)
{
	if ((((size > 4 && n <= 2147483647)) && n > (-2147483647-1))) {
		OPM_WriteString((CHAR*)"((INT", 6);
		OPM_WriteInt(__ASHL(size, 3));
		OPM_WriteString((CHAR*)")(", 3);
		OPM_WriteInt(n);
		OPM_WriteString((CHAR*)"))", 3);
	} else {
		OPM_WriteInt(n);
	}
}

void OPC_Len (OPT_Object obj, OPT_Struct array, INT64 dim)
{
	INT64 d;
	d = dim;
	while (d > 0) {
		array = array->BaseTyp;
		d -= 1;
	}
	if (array->comp == 3) {
		OPC_CompleteIdent(obj);
		OPM_WriteString((CHAR*)"__len", 6);
		if (dim != 0) {
			OPM_WriteInt(dim);
		}
	} else {
		OPM_WriteInt(array->n);
	}
}

void OPC_Constant (OPT_Const con, INT16 form)
{
	INT16 i;
	UINT64 s;
	INT64 hex;
	BOOLEAN skipLeading;
	switch (form) {
		case 1: 
			OPM_WriteInt(con->intval);
			break;
		case 2: 
			OPM_WriteInt(con->intval);
			break;
		case 3: 
			OPC_CharacterLiteral(con->intval);
			break;
		case 4: 
			OPM_WriteInt(con->intval);
			break;
		case 5: 
			OPM_WriteReal(con->realval, 'f');
			break;
		case 6: 
			OPM_WriteReal(con->realval, 0x00);
			break;
		case 7: 
			OPM_WriteString((CHAR*)"0x", 3);
			skipLeading = 1;
			s = con->setval;
			i = 64;
			do {
				hex = 0;
				do {
					i -= 1;
					hex = __ASHL(hex, 1);
					if (__IN(i, s, 64)) {
						hex += 1;
					}
				} while (!(__MASK(i, -8) == 0));
				if (hex != 0 || !skipLeading) {
					OPM_WriteHex(hex);
					skipLeading = 0;
				}
			} while (!(i == 0));
			if (skipLeading) {
				OPM_Write('0');
			}
			break;
		case 8: 
			OPC_StringLiteral(*con->ext, 256, con->intval2 - 1);
			break;
		case 9: 
			OPM_WriteString((CHAR*)"NIL", 4);
			break;
		default: 
			OPM_LogWStr((CHAR*)"unhandled case in OPC.Constant, form = ", 40);
			OPM_LogWNum(form, 0);
			OPM_LogWLn();
			break;
	}
}

static struct InitKeywords__46 {
	INT8 *n;
	struct InitKeywords__46 *lnk;
} *InitKeywords__46_s;

static void Enter__47 (CHAR *s, ADDRESS s__len);

static void Enter__47 (CHAR *s, ADDRESS s__len)
{
	INT16 h;
	__DUP(s, s__len, CHAR);
	h = OPC_PerfectHash((void*)s, s__len);
	OPC_hashtab[__X(h, 105)] = *InitKeywords__46_s->n;
	__COPY(s, OPC_keytab[__X(*InitKeywords__46_s->n, 50)], 9);
	*InitKeywords__46_s->n += 1;
	__DEL(s);
}

static void OPC_InitKeywords (void)
{
	INT8 n, i;
	struct InitKeywords__46 _s;
	_s.n = &n;
	_s.lnk = InitKeywords__46_s;
	InitKeywords__46_s = &_s;
	n = 0;
	i = 0;
	while (i <= 104) {
		OPC_hashtab[__X(i, 105)] = -1;
		i += 1;
	}
	Enter__47((CHAR*)"ADDRESS", 8);
	Enter__47((CHAR*)"INT16", 6);
	Enter__47((CHAR*)"INT32", 6);
	Enter__47((CHAR*)"INT64", 6);
	Enter__47((CHAR*)"INT8", 5);
	Enter__47((CHAR*)"UINT16", 7);
	Enter__47((CHAR*)"UINT32", 7);
	Enter__47((CHAR*)"UINT64", 7);
	Enter__47((CHAR*)"UINT8", 6);
	Enter__47((CHAR*)"asm", 4);
	Enter__47((CHAR*)"auto", 5);
	Enter__47((CHAR*)"break", 6);
	Enter__47((CHAR*)"case", 5);
	Enter__47((CHAR*)"char", 5);
	Enter__47((CHAR*)"const", 6);
	Enter__47((CHAR*)"continue", 9);
	Enter__47((CHAR*)"default", 8);
	Enter__47((CHAR*)"do", 3);
	Enter__47((CHAR*)"double", 7);
	Enter__47((CHAR*)"else", 5);
	Enter__47((CHAR*)"enum", 5);
	Enter__47((CHAR*)"extern", 7);
	Enter__47((CHAR*)"export", 7);
	Enter__47((CHAR*)"float", 6);
	Enter__47((CHAR*)"for", 4);
	Enter__47((CHAR*)"fortran", 8);
	Enter__47((CHAR*)"goto", 5);
	Enter__47((CHAR*)"if", 3);
	Enter__47((CHAR*)"import", 7);
	Enter__47((CHAR*)"int", 4);
	Enter__47((CHAR*)"long", 5);
	Enter__47((CHAR*)"register", 9);
	Enter__47((CHAR*)"return", 7);
	Enter__47((CHAR*)"short", 6);
	Enter__47((CHAR*)"signed", 7);
	Enter__47((CHAR*)"sizeof", 7);
	Enter__47((CHAR*)"size_t", 7);
	Enter__47((CHAR*)"static", 7);
	Enter__47((CHAR*)"struct", 7);
	Enter__47((CHAR*)"switch", 7);
	Enter__47((CHAR*)"typedef", 8);
	Enter__47((CHAR*)"union", 6);
	Enter__47((CHAR*)"unsigned", 9);
	Enter__47((CHAR*)"void", 5);
	Enter__47((CHAR*)"volatile", 9);
	Enter__47((CHAR*)"while", 6);
	InitKeywords__46_s = _s.lnk;
}


export void *OPC__init(void)
{
	__DEFMOD;
	__MODULE_IMPORT(Configuration);
	__MODULE_IMPORT(OPM);
	__MODULE_IMPORT(OPT);
	__REGMOD("OPC", 0);
	__REGCMD("BegBlk", OPC_BegBlk);
	__REGCMD("BegStat", OPC_BegStat);
	__REGCMD("EndBlk", OPC_EndBlk);
	__REGCMD("EndBlk0", OPC_EndBlk0);
	__REGCMD("EndStat", OPC_EndStat);
	__REGCMD("EnterBody", OPC_EnterBody);
	__REGCMD("ExitBody", OPC_ExitBody);
	__REGCMD("GenHdrIncludes", OPC_GenHdrIncludes);
	__REGCMD("Init", OPC_Init);
/* BEGIN */
	OPC_InitKeywords();
	__ENDMOD;
}
