Category : Recently Uploaded Files
Archive   : OXCC1432.ZIP
Filename : OXCCB.C

 
Output of file : OXCCB.C contained in archive : OXCC1432.ZIP
/*
oxccb.c -- v1.430 architecture neutral format (anf) to bytecode generator

Copyright (c) 1995
Norman D. Culver dba
Oxbow Software
1323 S.E. 17th Street #662
Ft. Lauderdale, FL 33316
(305) 527-1663 Voice
(305) 760-7584 Fax
(305) 760-4679 Data
[email protected]
All rights reserved.

* Redistribution and use in source and binary forms are permitted
* provided that: (1) source distributions retain this entire copyright
* notice and comment, and (2) distributions including binaries display
* the following acknowledgement: ``This product includes software
* developed by Norman D. Culver dba Oxbow Software''
* in the documentation or other materials provided with the distribution
* and in all advertising materials mentioning features or use of this
* software.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.

*/
#define MAJOR_VERSION 1
#define MINOR_VERSION 431

void oxcc_debug();
int __builtin_iv();
void bterpdebug(void);

#include
#include
#include
#include
#include

#define SUPPORT_LONG_DOUBLE 0
#define SUPPORT_LONG_LONG 1

#define NEED_SPELLING 1
#define NEED_BYTECODES 1
#define NEED_AOUT_FORMAT 1
#include "oxbytes.h"

#define NEED_FUNCTHUNK 1
#include "oxanf.h"

#define PROG oxccb
#define USING_FRAMEWORK 1
#define HOST_IS_LITTLE_ENDIAN 1
#define REALLY_NEED_OFFSETS 1
#define FUNCDATA (iv->category+1)

#define VFPRINTF(a,b) vfprintf(stderr,a,b)
#define PERROR prerror
#define PWARN prwarn
#define PRINTF info
static void prerror(const char *, ...);
static void prwarn(const char *, ...);
static void info(const char *, ...);
int cfeprintf(const char *, ...);

#define FILEWRITE(buf, cnt)\
{if(!iv->errors){if(fwrite(buf, 1, cnt, iv->outfile) != cnt)iv->errors = 12;}}

#define ROUNDUP(a, b) \
if(b > 1) { \
int _x = b-1; \
int _y; \
if((_y = (a & _x))) \
a += b-_y; \
}

#define KEYEQ(a,b) ((a)[0] == (b)[0] && (a)[1] == (b)[1])
#define KEYLT(a,b) (((a)[1] < (b)[1]) || ((a)[1] == (b)[1] && (a)[0] < (b)[0]))
#define MIN(a,b) (((a) < (b)) ? (a) : (b))

/* ======================== CONCATENIZATION MACROS ==================== */

#define _cat2_(a, b) a##b
#define _cat_(a, b) _cat2_(a, b)
#define Global(a) _cat_(PROG, a)

#define _pname2_(x) #x
#define _pname1_(x) _pname2_(x)
#define pName _pname1_(PROG)


/* ============== ENDIAN MACROS (input format is litle endian) ==== */

#if HOST_IS_LITTLE_ENDIAN
#define GL(a) a
#define GS(a) a
#define PL(a) a
#define PS(a) a
#else
#endif

/* =================== INPUT DATA FORMATS ========================== */

#define INFILE_SYMNUM 1
#define OUTFILE_SYMNUM 2

static unsigned char binops[] = {0,0,
ADD,SUB,MUL,DIV,LSH,RSH,MOD,OR,XOR,AND,EQ,NE,LT,GT,LE,GE,
NEG,COMP,NOT
};
/* ====================== STRUCTURES AND TYPEDEFS ======================== */
typedef struct _jl {
struct _jl *next;
void *p;
char *q;
long *plabelval;
long offset;
} *PJL;

typedef struct _el {
struct _el *next;
long spot;
short symnum;
} *PEL;

typedef struct _afile {
unsigned char *file_p;
PopI header_p;
PopI size_p;
unsigned char *symtext_p;
unsigned char *prog_p;
unsigned char *data_p;
unsigned char *switch_p;
unsigned char *decl_p;
unsigned char *maxtemp_p;
unsigned char *seg_p;
unsigned char **symaddr;
unsigned char **decladdr;
unsigned long thunk_offset;
unsigned long bss_offset;
int maxtemp;
int maxtempclass;
void *datatbl;
short *symtran;
unsigned short *decltran;
int filenum;
int numsyms;
int numdecls;
int numrelocs;
int numsegs;
} *Pafile;

typedef struct _iv {
int category;
FILE *outfile;
struct exec *header;
unsigned char **symaddr;
unsigned char **decladdr;
int remove_infile;
int argc;
char **argv;
int numfiles;
int lastlabel;
int errors;
int numsyms;
int numdecls;
int numsegs;
int maxtemp;
int maxtempclass;
unsigned long total_size;
unsigned long thunk_offset;
unsigned long bss_offset;

struct _nodeO *ob_usedhead;
struct _nodeO *ob_usedtail;
struct _nodeO *ob;
unsigned char *ob_buf;
int ob_bufcnt;
struct _nodeO *first_ob;

struct _nodeC *cod_usedhead;
struct _nodeC *cod_usedtail;
struct _nodeC *cod;
unsigned char *cod_buf;
int cod_bufcnt;
struct _nodeC *first_cod;
struct _nodeC *regcode;

long first_temp;
long killop;
long stackdepth;
long maxdepth;
long mindepth;
long numnested;
long lastline;
void *reloctbl;
void *extrntbl;
void *gbltbl;
void *symtbl;
void *labeltbl;
void *newlabeltbl;
void *tmptbl;
void *segtbl;
void *functbl;
void *finalsymtbl;
void *finalstringpack;
long finalpacksize;
void *datatbl;
void *builtintbl;
int in_builtin;
int has_structret;
int temps_written;
unsigned char *obuf;
unsigned char *obufstart;
PEL extbuf;
void *extbufstart;
int extcnt;
int extbufcnt;
PEL finextbuf;
void *finextbufstart;
int finextcnt;
int finextbufcnt;
PJL jbuf;
void *jbufstart;
int jmpcnt;
int jbufcnt;
long obufcnt;
long out_offset;
long func_offset;
int extmark;
short markedsym[10];
char *markedbuf[10];
int filenum;
Pafile files[1024];
char debug;
char only_debug;
char strip;
char listing_wanted;
} *Piv;

struct _gloval {
char *symname;
int symnum;
unsigned char *p;
Pafile pf;
};
struct _rkey {/* key area of reloctbl node */
unsigned long spot;
short fileno;
unsigned char opcode;
char rsize;
};
struct _rval {/* value area of reloctbl node */
unsigned char *p;
unsigned long *base;
long offset;
short rsym;
};


/* Internal User API */
static void *Cmalloc(int category, unsigned amount);
static void *Ccalloc(int category, unsigned nelems, unsigned elemsize);
static void *Crealloc(int category, void* buf, unsigned newsize);
static void Cfree(int category, void* buf);
static void Cfreecat(int category);
static int Cmemrange(int category, unsigned* minp, unsigned* maxp);
static int Cusedrange(int category, unsigned* minp, unsigned* maxp);
static void Ctotrange(unsigned* minp,unsigned* maxp);
static int Cnewcat(void);
static void *Ccatcheck(int category, void *start);
static void Cguard(int category);
static void* NewSymTable(int category, int nbins);
static int SymFind(void *tbl, void *key, void *result);
static int SymFindRange(void *tbl, void *key, void *result);
static void *SymInsert(void *tbl, void *key, void *value, int datsiz);
static int StringInsert(void *tbl, char *string, void *result);
static int StringFind(void *tbl, char *string, void *result);
static void SymDelete(void *tbl, void *key);
static int SymHead(void *tbl);
static int SymNext(void *tbl);
static void SymGetMark(void *tbl, void *markptr);
static int SymMarkNext(void *tbl, void *mark);
static void SymSetMark(void *tbl, void *markptr);
static void SymKey(void *tbl, void *keyptr);
static void SymValue(void *tbl, void *datptr);
static void *seg_find(Piv iv, int id);
static char *filenameof(char *path);
static char *propernameof(Piv iv, char *name);

/* END: User API */

/* ====================== PUT UNIQUE CODE HERE ========================= */
static void newlabel_insert(Piv iv, long label);
static long newlabel_fix(Piv iv, long label);
static void *do_stmt(Piv iv, unsigned char *p);
static void *do_expr(Piv iv, unsigned char *p);
static void do_bracket(Piv iv, unsigned char *p, unsigned char *q);
static void *do_something(Piv iv, unsigned char *p);
extern char *ctime();

/* ===================== BYTECODE OUTPUT GENERATOR ======================= */
struct _nodeOBUF
{
struct _nodeOBUF *next;
long cnt;
char buf[1];
};
typedef struct _nodeC
{
struct _nodeC *next;
struct _nodeOBUF *ee;
} NODEC, *PNODEC;

typedef struct _nodeO
{
struct _nodeO *next;
unsigned char *p;
ND d;
ND l;
ND r;
PNODEC startinst;
PNODEC endinst;
} NODEO, *PNODEO;

static unsigned char get_datasize(unsigned char, PND);
static void link_cod(Piv);

static char *notice =
" Generated by Oxbow Software Bytecode Backend version %d.%d\n*/\n\n";

static struct _nd longtype = {D_SIGNED,0,B4,0,4,0,0};
static struct _nd longlongtype = {D_SIGNED,0,B8,0,8,0,0};
static char padit[8]; /* in bss */

void
bterpdebug(){}

static long
symnumof(Piv iv, char *symb)
{
struct _gloval *valp;

if(StringFind(iv->gbltbl, symb, &valp))
return (long)valp->pf->symtran[valp->symnum];
return 0;
}
static void
buildin(Piv iv, char *symb, unsigned char code)
{
long key[2];

if((key[0] = symnumof(iv, symb)))
{
key[1] = 0;
SymInsert(iv->builtintbl, key, &code, 1);
}
}
static void
install_builtins(Piv iv)
{/* USE THIS TO INSTALL WHATEVER BUILTINS ARE IN THE TARGET INTERPRETER */
#define BUILDIN(a,b) buildin(iv,#a,b)

iv->builtintbl = NewSymTable(iv->category, 191);

BUILDIN(alloca,ALLOCA);
BUILDIN(strlen,STRLEN);
BUILDIN(strcpy,STRCPY);
BUILDIN(strcat,STRCAT);
BUILDIN(memcpy,MEMCPY);
BUILDIN(memmove,MEMMOVE);
BUILDIN(bzero,BZERO);
BUILDIN(malloc,MALLOC);
BUILDIN(calloc,CALLOC);
BUILDIN(realloc,REALLOC);
BUILDIN(setjmp,SETJMP);
BUILDIN(longjmp,LONGJMP);
BUILDIN(abort,ABORT);
BUILDIN(exit, EXIT);
BUILDIN(_exit,EXIT);
BUILDIN(bterpdebug,DEBUG);
BUILDIN(bterpnodebug,NODEBUG);

#undef BUILDIN
}
static long
final_strofs(Piv iv, char *string)
{
long *result;

if(StringFind(iv->finalsymtbl, string, &result))
return result[2];
return 0;
}
static short
final_symnum(Piv iv, short symnum)
{
long *result;

if(StringFind(iv->finalsymtbl, iv->symaddr[symnum], &result)) {
return result[1]-1;
}
return 0;
}
static void
make_final_symtab(Piv iv)
{
int i;
iv->finalsymtbl = NewSymTable(iv->category, 0);
if(SymHead(iv->gbltbl))
{
i = 0;
while(SymNext(iv->gbltbl))
{
long *result;
struct _gloval *valp;

SymValue(iv->gbltbl, &valp);
if(*(valp->p))
{
long key[2];
key[0] = valp->pf->symtran[valp->symnum];
key[1] = 0;
if(!SymFind(iv->builtintbl, key, NULL))
{
if(!StringInsert(iv->finalsymtbl, valp->symname, &result))
{/* New Entry */
result[1] = ++i;
}
}
}
}
}
}
static void
adjust_labels(Piv iv, long base, long adjust)
{
long *key;
long *val;
if(SymHead(iv->newlabeltbl))
{
while(SymNext(iv->newlabeltbl))
{
SymKey(iv->newlabeltbl, &key);
SymValue(iv->newlabeltbl, &val);
if(key[1] == iv->filenum && val[0] > base) {
val[0] += adjust;
}
}
}
}
static void
addto_extlist(Piv iv, char *buf)
{
void *next;
while(iv->extmark > 0)
{
long offset = iv->markedbuf[iv->extmark] - buf;
next = iv->extbuf;
if(iv->extbufcnt >= sizeof(struct _el))
{
iv->extbuf++;
}
else
{
iv->extbufcnt = 4080;
iv->extbuf = Ccalloc(FUNCDATA, 1, iv->extbufcnt);
}
*((void**)next) = iv->extbuf;
iv->extbuf->spot = iv->out_offset+iv->func_offset+offset;
iv->extbuf->symnum = iv->markedsym[iv->extmark];
++iv->extcnt;
--iv->extmark;
iv->extbufcnt -= sizeof(struct _el);
}
}
static void
save_extlocs(Piv iv)
{
PEL pel = iv->extbufstart;
void *next;

while(pel)
{
next = iv->finextbuf;
if(iv->finextbufcnt >= sizeof(struct _el))
{
iv->finextbuf++;
}
else
{
iv->finextbufcnt = 4080;
iv->finextbuf = Ccalloc(iv->category, 1, iv->finextbufcnt);
}
*((void**)next) = iv->finextbuf;
iv->finextbuf->spot = pel->spot;
iv->finextbuf->symnum = pel->symnum;
++iv->finextcnt;
iv->finextbufcnt -= sizeof(struct _el);
pel = pel->next;
}
}
static void
adjust_externs(Piv iv, long base, long adjust)
{
PEL pel = iv->extbufstart;

while(pel)
{
if(pel->spot > base)
pel->spot += adjust;
pel = pel->next;
}
}

static int
shorten_jmps(Piv iv)
{
int scnt;
PJL jp;
long jmp_offset;
long label_offset;
long diff;
long offset_adjust;
int sign;
unsigned char *q, *osiz;
int cursize, newsize;

scnt = 0;
jp = iv->jbufstart;
offset_adjust = 0;
while(jp)
{
osiz = jp->q+4; /* points to size in obuf */
q = osiz+4; /* points to the JMP inst in obuf */
cursize = *q & 3; /* from the output bytecode */
jmp_offset = jp->offset + offset_adjust;
jp->offset = jmp_offset; /* reset the offset for this inst */
label_offset = *jp->plabelval;
diff = label_offset - jmp_offset;

sign = 1;
if(diff < 0)
{
sign = -1;
diff = -diff;
}
if(diff < 0x7fL)
newsize = 0;
else if(diff < 0x7fffL)
newsize = 1;
else if(diff < 0x007fffffL)
newsize = 2;
else
newsize = 3;
if(cursize != newsize)
{/* DO SOMETHING */
long adj;
static long codesize[4] = {2L,3L,4L,5L};
++scnt; /* something changed */
*q &= 0xfc; /* mask opcode */
*q |= newsize; /* set size in opcode */
*((long*)osiz) = codesize[newsize]; /* set new output size */
adj = codesize[newsize] - codesize[cursize];
offset_adjust += adj; /* jmps below this point have new offset */
if(sign > 0) diff += adj; /* label is below this point */

/* Adjust all labels below this point */
adjust_labels(iv, jmp_offset, adj);
/* adjust all external address spots (text relocs) below this point */
adjust_externs(iv, jmp_offset, adj);
}
diff *= sign; /* restore sign to the relative address */

/* generate the pc relative address */

++q; /* points the the address field of the JMP inst */
if(newsize == 0)
*((signed char*)q) = (signed char)(diff & 0xff);
else if(newsize == 1)
*((short*)q) = (short)(diff & 0xffff);
else if(newsize == 2)
*((long*)q) = diff<<8;
else
*((long*)q) = diff;
jp = jp->next;
}/* END: while (jp) */

return scnt;
}

static void
setup_jmps(Piv iv, unsigned char *pdef)
{
struct {
long k1;
long k2;
} key;
long *result;
PJL jp;
unsigned char *p;

jp = iv->jbufstart;
while(jp)
{
p = jp->p;
key.k1 = GL( POP->data ); /* label number from source code */
key.k2 = iv->filenum; /* source file number */
if(SymFind(iv->newlabeltbl, &key, &result))
{
jp->plabelval = result; /* save pointer to label value */
}
else
{
PERROR(pName ":Syserr: jmp setup failed for `%s' label=%d file=%d p=%x code=%d\n",
iv->symaddr[GL(((Pop)pdef)->data)], key.k1, key.k2, p, *p);
}
jp = jp->next;
}
}
static void
addto_jmplist(Piv iv, unsigned char *p, void *q)
{
void *next = iv->jbuf;

if(iv->jbufcnt >= sizeof(struct _jl))
{
iv->jbuf++;
}
else
{
iv->jbufcnt = 4080;
iv->jbuf = Ccalloc(FUNCDATA, 1, iv->jbufcnt);
}
*((void**)next) = iv->jbuf;
iv->jbuf->p = p;
iv->jbuf->q = q;
iv->jbuf->offset = iv->out_offset+iv->func_offset-5;
iv->jbufcnt -= sizeof(struct _jl);
}
static void
save_maxdepth(Piv iv, long symnum)
{
long key[2];
long val[3];

if(iv->functbl == 0)
{
iv->functbl = NewSymTable(iv->category, 277);
}
key[0] = symnum;
key[1] = 0;
val[0] = iv->maxdepth + (4*iv->numnested);
val[1] = iv->mindepth;
val[2] = 0;
SymInsert(iv->functbl, key, val, 12);
}

static long
get_maxdepth(Piv iv, short symnum)
{
long key[2];
long *result;

key[0] = symnum;
key[1] = 0;
if(SymFind(iv->functbl, key, &result))
{
return result[0];
}
return 0;
}
static void
printline(Piv iv, void *ptr)
{
fprintf(iv->outfile, "Line:%d:\n", *((long*)ptr));
}
static int
print8(Piv iv, unsigned char *ptr, int size, long offset, int lf)
{
char buf[40];
int i, j=0;

i = sprintf(buf, "%8.8x: ", offset);
while(j < size && j < 8)
{
i += sprintf(&buf[i], "%2.2x ", *ptr++);
++j;
}
if(lf)
buf[i++] = '\n';
else
{
while(i < 35)
buf[i++] = ' ';
}
buf[i] = 0;
fprintf(iv->outfile, buf);
return j;
}
static void
printinst(Piv iv, unsigned char *pc, long size)
{
int i, bufcnt;
unsigned char *epc;
char *pbuf[20];

bufcnt = 0;
epc = pc + size;
for( ;pc < epc; ++pc)
{
switch(*pc)
{
case LOCATE|J1:
case LOCATE|J2:
case LOCATE|J3:
case LOCATE|J4:
pbuf[bufcnt++] = "locate|";
pbuf[bufcnt++] = Jbuf[*pc & 0x03];
pc += Jcnt[*pc & 0x03];
break;
case LS|A1|B1:
case LS|A1|B2:
case LS|A1|B4:
case LS|A1|B8:
case LS|A2|B1:
case LS|A2|B2:
case LS|A2|B4:
case LS|A2|B8:
case LS|A3|B1:
case LS|A3|B2:
case LS|A3|B4:
case LS|A3|B8:
pbuf[bufcnt++] = "ls|";
pbuf[bufcnt++] = ABbuf[*pc & 0x0f];
pc += Acnt[(*pc>>2) & 0x03];
break;
case NEG|BYTE:
case NEG|SHORT:
case NEG|LONG:
case NEG|UBYTE:
case NEG|USHORT:
case NEG|ULONG:
case NEG|FLOAT:
case NEG|DOUBLE:
pbuf[bufcnt++] = "neg|";
pbuf[bufcnt++] = Tbuf[*pc & 0x07];
break;

case LM|A1|B1:
case LM|A1|B2:
case LM|A1|B4:
case LM|A1|B8:
case LM|A2|B1:
case LM|A2|B2:
case LM|A2|B4:
case LM|A2|B8:
case LM|A3|B1:
case LM|A3|B2:
case LM|A3|B4:
case LM|A3|B8:
case LM|A4|B1:
case LM|A4|B2:
case LM|A4|B4:
case LM|A4|B8:
pbuf[bufcnt++] = "lm|";
pbuf[bufcnt++] = ABbuf[*pc & 0x0f];
pc += Acnt[(*pc>>2) & 0x03];
break;

case COMP|B1:
case COMP|B2:
case COMP|B4:
case COMP|B8:
pbuf[bufcnt++] = "comp|";
pbuf[bufcnt++] = Bbuf[*pc & 0x03];
break;

case JMP|J1:
case JMP|J2:
case JMP|J3:
case JMP|J4:
pbuf[bufcnt++] = "jmp|";
pbuf[bufcnt++] = Jbuf[*pc & 0x03];
pc += Jcnt[*pc & 0x03];
break;

case JMPT|J1:
case JMPT|J2:
case JMPT|J3:
case JMPT|J4:
pbuf[bufcnt++] = "jmpt|";
pbuf[bufcnt++] = Jbuf[*pc & 0x03];
pc += Jcnt[*pc & 0x03];
break;

case LJMPT|J1:
case LJMPT|J2:
case LJMPT|J3:
case LJMPT|J4:
pbuf[bufcnt++] = "ljmpt|";
pbuf[bufcnt++] = Jbuf[*pc & 0x03];
pc += Jcnt[*pc & 0x03];
break;

case JMPF|J1:
case JMPF|J2:
case JMPF|J3:
case JMPF|J4:
pbuf[bufcnt++] = "jmpf|";
pbuf[bufcnt++] = Jbuf[*pc & 0x03];
pc += Jcnt[*pc & 0x03];
break;

case LJMPF|J1:
case LJMPF|J2:
case LJMPF|J3:
case LJMPF|J4:
pbuf[bufcnt++] = "ljmpf|";
pbuf[bufcnt++] = Jbuf[*pc & 0x03];
pc += Jcnt[*pc & 0x03];
break;

case NOT|B1:
case NOT|B2:
case NOT|B4: /* also FLOAT */
case NOT|B8: /* also DOUBLE */
pbuf[bufcnt++] = "not|";
pbuf[bufcnt++] = Bbuf[*pc & 0x03];
break;

case SS|A1|B1:
case SS|A1|B2:
case SS|A1|B4:
case SS|A1|B8:
case SS|A2|B1:
case SS|A2|B2:
case SS|A2|B4:
case SS|A2|B8:
case SS|A3|B1:
case SS|A3|B2:
case SS|A3|B4:
case SS|A3|B8:
pbuf[bufcnt++] = "ss|";
pbuf[bufcnt++] = ABbuf[*pc & 0x0f];
pc += Acnt[(*pc>>2) & 0x03];
break;

case TRUTHOF|B2:
case TRUTHOF|B4:
case TRUTHOF|B8:
pbuf[bufcnt++] = "truthof|";
pbuf[bufcnt++] = Bbuf[*pc & 0x03];
break;
case CVT:
{
unsigned char cvs,cvd;
pbuf[bufcnt++] = "cvt ";
++pc;
cvs = (*pc & 0x70)>>4;
cvd = (*pc & 0x07);
pbuf[bufcnt++] = Tbuf[cvd];
pbuf[bufcnt++] = "<-";
pbuf[bufcnt++] = Tbuf[cvs];
break;
}
case LI|B1:
case LI|B2:
case LI|B4:
case LI|B8:
pbuf[bufcnt++] = "li|";
pbuf[bufcnt++] = Bbuf[*pc & 0x03];
pc += Bcnt[*pc & 0x03];
break;

case LAI|D1:
case LAI|D2:
case LAI|D3:
case LAI|D4:
pbuf[bufcnt++] = "lai|";
pbuf[bufcnt++] = Dbuf[*pc & 0x03];
pc += Dcnt[*pc & 0x03];
break;

case LUI|B1:
case LUI|B2:
case LUI|B4:
case LUI|B8:
pbuf[bufcnt++] = "lui|";
pbuf[bufcnt++] = Bbuf[*pc & 0x03];
pc += Bcnt[*pc & 0x03];
break;

case IMMED:
{
++pc;
switch(*pc)
{
case SMI|A1|B1:
case SMI|A1|B2:
case SMI|A1|B4:
case SMI|A1|B8:
case SMI|A2|B1:
case SMI|A2|B2:
case SMI|A2|B4:
case SMI|A2|B8:
case SMI|A3|B1:
case SMI|A3|B2:
case SMI|A3|B4:
case SMI|A3|B8:
case SMI|A4|B1:
case SMI|A4|B2:
case SMI|A4|B4:
case SMI|A4|B8:
pbuf[bufcnt++] = "smi|";
pbuf[bufcnt++] = ABbuf[*pc & 0x0f];
pc += ABcnt[*pc & 0x0f];
break;

case SSI|A1|B1:
case SSI|A1|B2:
case SSI|A1|B4:
case SSI|A1|B8:
case SSI|A2|B1:
case SSI|A2|B2:
case SSI|A2|B4:
case SSI|A2|B8:
case SSI|A3|B1:
case SSI|A3|B2:
case SSI|A3|B4:
case SSI|A3|B8:
pbuf[bufcnt++] = "ssi|";
pbuf[bufcnt++] = ABbuf[*pc & 0x0f];
pc += ABcnt[*pc & 0x0f];
break;

case MODI|BYTE:
case MODI|SHORT:
case MODI|LONG:
case MODI|UBYTE:
case MODI|USHORT:
case MODI|ULONG:
pbuf[bufcnt++] = "modi|";
pbuf[bufcnt++] = Tbuf[*pc & 0x07];
pc += 2;
break;

case DEREF|BYTE:
case DEREF|SHORT:
case DEREF|LONG:
case DEREF|UBYTE:
case DEREF|USHORT:
case DEREF|ULONG:
case DEREF|FLOAT:
case DEREF|DOUBLE:
pbuf[bufcnt++] = "deref|";
pbuf[bufcnt++] = Tbuf[*pc & 0x07];
break;

case DEREF1|BYTE:
case DEREF1|SHORT:
case DEREF1|LONG:
case DEREF1|UBYTE:
case DEREF1|USHORT:
case DEREF1|ULONG:
case DEREF1|FLOAT:
case DEREF1|DOUBLE:
pbuf[bufcnt++] = "deref1|";
pbuf[bufcnt++] = Tbuf[*pc & 0x07];
break;
}
break;
}
case SM|A1|B1:
case SM|A1|B2:
case SM|A1|B4:
case SM|A1|B8:
case SM|A2|B1:
case SM|A2|B2:
case SM|A2|B4:
case SM|A2|B8:
case SM|A3|B1:
case SM|A3|B2:
case SM|A3|B4:
case SM|A3|B8:
case SM|A4|B1:
case SM|A4|B2:
case SM|A4|B4:
case SM|A4|B8:
pbuf[bufcnt++] = "sm|";
pbuf[bufcnt++] = ABbuf[*pc & 0x0f];
pc += Acnt[(*pc>>2) & 3];
break;

case ADD|BYTE:
case ADD|SHORT:
case ADD|LONG:
case ADD|UBYTE:
case ADD|USHORT:
case ADD|ULONG:
case ADD|FLOAT:
case ADD|DOUBLE:
pbuf[bufcnt++] = "add|";
pbuf[bufcnt++] = Tbuf[*pc & 0x07];
break;

case SUB|BYTE:
case SUB|SHORT:
case SUB|LONG:
case SUB|UBYTE:
case SUB|USHORT:
case SUB|ULONG:
case SUB|FLOAT:
case SUB|DOUBLE:
pbuf[bufcnt++] = "sub|";
pbuf[bufcnt++] = Tbuf[*pc & 0x07];
break;

case MUL|BYTE:
case MUL|SHORT:
case MUL|LONG:
case MUL|UBYTE:
case MUL|USHORT:
case MUL|ULONG:
case MUL|FLOAT:
case MUL|DOUBLE:
pbuf[bufcnt++] = "mul|";
pbuf[bufcnt++] = Tbuf[*pc & 0x07];
break;

case DIV|BYTE:
case DIV|SHORT:
case DIV|LONG:
case DIV|UBYTE:
case DIV|USHORT:
case DIV|ULONG:
case DIV|FLOAT:
case DIV|DOUBLE:
pbuf[bufcnt++] = "div|";
pbuf[bufcnt++] = Tbuf[*pc & 0x07];
break;

case OR|B1:
case OR|B2:
case OR|B4:
case OR|B8:
pbuf[bufcnt++] = "or|";
pbuf[bufcnt++] = Bbuf[*pc & 0x03];
break;

case AND|B1:
case AND|B2:
case AND|B4:
case AND|B8:
pbuf[bufcnt++] = "and|";
pbuf[bufcnt++] = Bbuf[*pc & 0x03];
break;

case MOD|BYTE:
case MOD|SHORT:
case MOD|LONG:
case MOD|UBYTE:
case MOD|USHORT:
case MOD|ULONG:
pbuf[bufcnt++] = "mod|";
pbuf[bufcnt++] = Tbuf[*pc & 0x07];
break;

case XTD:
{
++pc;
switch(*pc)
{
case LI:
pbuf[bufcnt++] = "li";
pc += XSZ;
break;

case LSH|B1:
case LSH|B2:
case LSH|B4:
case LSH|B8:
pbuf[bufcnt++] = "lsh|";
pbuf[bufcnt++] = Bbuf[*pc & 0x03];
break;

case LSHI|B1:
case LSHI|B2:
case LSHI|B4:
case LSHI|B8:
pbuf[bufcnt++] = "lshi|";
pbuf[bufcnt++] = Bbuf[*pc & 0x03];
++pc;
break;

case RSH|BYTE:
case RSH|SHORT:
case RSH|LONG:
case RSH|UBYTE:
case RSH|USHORT:
case RSH|ULONG:
pbuf[bufcnt++] = "rsh|";
pbuf[bufcnt++] = Tbuf[*pc & 0x07];
break;

case RSHI|BYTE:
case RSHI|SHORT:
case RSHI|LONG:
case RSHI|UBYTE:
case RSHI|USHORT:
case RSHI|ULONG:
pbuf[bufcnt++] = "rshi|";
pbuf[bufcnt++] = Tbuf[*pc & 0x07];
++pc;
break;

case BUILTIN:
{
pbuf[bufcnt++] = "builtin ";
++pc;
pbuf[bufcnt++] = BUbuf[*pc];
break;
} /* END: XTD BUILTIN */
case CLRDAT:
pbuf[bufcnt++] = "clrdat";
break;
case SWITCH:
pbuf[bufcnt++] = "switch";
pc += 2;
break;
case CALLSETUP:
pbuf[bufcnt++] = "callsetup";
pc += 4;
break;
case RETSTRUCT:
pbuf[bufcnt++] = "retstruct";
pc += 4;
break;
case PRUNESTRUCT:
pbuf[bufcnt++] = "prunestruct";
break;
case GETBITFIELD:
pbuf[bufcnt++] = "getbitfield";
pc += 3;
break;
case PUTBITFIELD:
pbuf[bufcnt++] = "putbitfield";
pc += 3;
break;
case IMMED:
{
++pc;
switch(*pc)
{
case SMI|A1:
case SMI|A2:
case SMI|A3:
case SMI|A4:
pbuf[bufcnt++] = "smi|";
pbuf[bufcnt++] = Abuf[(*pc>>2) & 0x03];
pc += Acnt[(*pc>>2) & 0x03] + XSZ;
break;

case SSI|A1:
case SSI|A2:
case SSI|A3:
pbuf[bufcnt++] = "ssi|";
pbuf[bufcnt++] = Abuf[(*pc>>2) & 0x03];
pc += Acnt[(*pc>>2) & 0x03] + XSZ;
break;

case MODI|LONGLONG:
case MODI|ULONGLONG:
pbuf[bufcnt++] = "modi|";
pbuf[bufcnt++] = XTbuf[*pc & 0x03];
pc += 2;
break;

case DEREF|LONGLONG:
case DEREF|ULONGLONG:
case DEREF|LONGDOUBLE:
pbuf[bufcnt++] = "deref|";
pbuf[bufcnt++] = XTbuf[*pc & 0x03];
break;

case DEREF1|LONGLONG:
case DEREF1|ULONGLONG:
case DEREF1|LONGDOUBLE:
pbuf[bufcnt++] = "deref1|";
pbuf[bufcnt++] = XTbuf[*pc & 0x03];
break;
}
break;
}/* END: XTD IMMED */

case ADD|LONGLONG:
case ADD|ULONGLONG:
case ADD|LONGDOUBLE:
pbuf[bufcnt++] = "add|";
pbuf[bufcnt++] = XTbuf[*pc & 0x03];
break;
case SUB|LONGLONG:
case SUB|ULONGLONG:
case SUB|LONGDOUBLE:
pbuf[bufcnt++] = "sub|";
pbuf[bufcnt++] = XTbuf[*pc & 0x03];
case MUL|LONGLONG:
case MUL|ULONGLONG:
case MUL|LONGDOUBLE:
pbuf[bufcnt++] = "mul|";
pbuf[bufcnt++] = XTbuf[*pc & 0x03];
break;
case DIV|LONGLONG:
case DIV|ULONGLONG:
case DIV|LONGDOUBLE:
pbuf[bufcnt++] = "div|";
pbuf[bufcnt++] = XTbuf[*pc & 0x03];
break;
case LT|LONGLONG:
case LT|ULONGLONG:
case LT|LONGDOUBLE:
pbuf[bufcnt++] = "lt|";
pbuf[bufcnt++] = XTbuf[*pc & 0x03];
break;
case GT|LONGLONG:
case GT|ULONGLONG:
case GT|LONGDOUBLE:
pbuf[bufcnt++] = "gt|";
pbuf[bufcnt++] = XTbuf[*pc & 0x03];
break;
case LE|LONGLONG:
case LE|ULONGLONG:
case LE|LONGDOUBLE:
pbuf[bufcnt++] = "le|";
pbuf[bufcnt++] = XTbuf[*pc & 0x03];
break;
case GE|LONGLONG:
case GE|ULONGLONG:
case GE|LONGDOUBLE:
pbuf[bufcnt++] = "ge|";
pbuf[bufcnt++] = XTbuf[*pc & 0x03];
break;
case NE|LONGLONG:
case NE|ULONGLONG:
case NE|LONGDOUBLE:
pbuf[bufcnt++] = "ne|";
pbuf[bufcnt++] = XTbuf[*pc & 0x03];
break;
case EQ|LONGLONG:
case EQ|ULONGLONG:
case EQ|LONGDOUBLE:
pbuf[bufcnt++] = "eq|";
pbuf[bufcnt++] = XTbuf[*pc & 0x03];
break;
case NEG|LONGLONG:
case NEG|ULONGLONG:
case NEG|LONGDOUBLE:
pbuf[bufcnt++] = "neg|";
pbuf[bufcnt++] = XTbuf[*pc & 0x03];
break;
case NOT|BX:
pbuf[bufcnt++] = "not|BX";
break;
case COMP|LONGLONG:
case COMP|ULONGLONG:
pbuf[bufcnt++] = "comp|";
pbuf[bufcnt++] = XTbuf[*pc & 0x03];
break;
case RSH|SLONGLONG:
case RSH|SULONGLONG:
pbuf[bufcnt++] = "rsh|";
pbuf[bufcnt++] = XTbuf[*pc & 0x03];
break;

case MOD|LONGLONG:
case MOD|ULONGLONG:
pbuf[bufcnt++] = "mod|";
pbuf[bufcnt++] = XTbuf[*pc & 0x03];
break;
case RSHI|SLONGLONG:
case RSHI|SULONGLONG:
pbuf[bufcnt++] = "rshi|";
pbuf[bufcnt++] = XTbuf[*pc & 0x07];
++pc;
break;
case TRUTHOF|BX:
pbuf[bufcnt++] = "truthof|BX";
break;

case LS|A1:
case LS|A2:
case LS|A3:
pbuf[bufcnt++] = "xtd ls|";
pbuf[bufcnt++] = Abuf[(*pc>>2) & 0x03];
pc += Acnt[(*pc>>2) & 0x03];
break;

case LM|A1:
case LM|A2:
case LM|A3:
case LM|A4:
pbuf[bufcnt++] = "xtd lm|";
pbuf[bufcnt++] = Abuf[(*pc>>2) & 0x03];
pc += Acnt[(*pc>>2) & 0x03];
break;

case SS|A1:
case SS|A2:
case SS|A3:
pbuf[bufcnt++] = "xtd ss|";
pbuf[bufcnt++] = Abuf[(*pc>>2) & 0x03];
pc += Acnt[(*pc>>2) & 0x03];
break;

case SM|A1:
case SM|A2:
case SM|A3:
case SM|A4:
pbuf[bufcnt++] = "xtd sm|";
pbuf[bufcnt++] = Abuf[(*pc>>2) & 0x03];
pc += Acnt[(*pc>>2) & 0x03];
break;

case MOVSS:
pbuf[bufcnt++] = "xtd movss";
++pc;
pbuf[bufcnt++] = SDbuf[*pc & 0x0f];
pc += SDcnt[*pc & 0x0f];
break;
case MOVSM:
pbuf[bufcnt++] = "xtd movsm";
++pc;
pbuf[bufcnt++] = SDbuf[*pc & 0x0f];
pc += SDcnt[*pc & 0x0f];
break;
case MOVMS:
pbuf[bufcnt++] = "xtd movms";
++pc;
pbuf[bufcnt++] = SDbuf[*pc & 0x0f];
pc += SDcnt[*pc & 0x0f];
break;
case MOVMM:
pbuf[bufcnt++] = "xtd movmm";
++pc;
pbuf[bufcnt++] = SDbuf[*pc & 0x0f];
pc += SDcnt[*pc & 0x0f];
break;
}
break;
}/* END: XTD */

case XOR|B1:
case XOR|B2:
case XOR|B4:
case XOR|B8:
pbuf[bufcnt++] = "xor|";
pbuf[bufcnt++] = Bbuf[*pc & 0x03];
break;

case GT|BYTE:
case GT|SHORT:
case GT|LONG:
case GT|UBYTE:
case GT|USHORT:
case GT|ULONG:
case GT|FLOAT:
case GT|DOUBLE:
pbuf[bufcnt++] = "gt|";
pbuf[bufcnt++] = Tbuf[*pc & 0x07];
break;

case LT|BYTE:
case LT|SHORT:
case LT|LONG:
case LT|UBYTE:
case LT|USHORT:
case LT|ULONG:
case LT|FLOAT:
case LT|DOUBLE:
pbuf[bufcnt++] = "lt|";
pbuf[bufcnt++] = Tbuf[*pc & 0x07];
break;

case GE|BYTE:
case GE|SHORT:
case GE|LONG:
case GE|UBYTE:
case GE|USHORT:
case GE|ULONG:
case GE|FLOAT:
case GE|DOUBLE:
pbuf[bufcnt++] = "ge|";
pbuf[bufcnt++] = Tbuf[*pc & 0x07];
break;

case LE|BYTE:
case LE|SHORT:
case LE|LONG:
case LE|UBYTE:
case LE|USHORT:
case LE|ULONG:
case LE|FLOAT:
case LE|DOUBLE:
pbuf[bufcnt++] = "le|";
pbuf[bufcnt++] = Tbuf[*pc & 0x07];
break;

case NE|BYTE:
case NE|SHORT:
case NE|LONG:
case NE|UBYTE:
case NE|USHORT:
case NE|ULONG:
case NE|FLOAT:
case NE|DOUBLE:
pbuf[bufcnt++] = "ne|";
pbuf[bufcnt++] = Tbuf[*pc & 0x07];
break;

case EQ|BYTE:
case EQ|SHORT:
case EQ|LONG:
case EQ|UBYTE:
case EQ|USHORT:
case EQ|ULONG:
case EQ|FLOAT:
case EQ|DOUBLE:
pbuf[bufcnt++] = "eq|";
pbuf[bufcnt++] = Tbuf[*pc & 0x07];
break;

case ARG:
pbuf[bufcnt++] = "arg";
break;
case ARGA:
pbuf[bufcnt++] = "arga";
break;
case ARGF:
pbuf[bufcnt++] = "argf";
break;

case MOVSS|B1:
case MOVSS|B2:
case MOVSS|B4:
case MOVSS|B8:
pbuf[bufcnt++] = "movss|";
pbuf[bufcnt++] = Bbuf[*pc & 0x03];
++pc;
pbuf[bufcnt++] = SDbuf[*pc & 0x0f];
pc += SDcnt[*pc & 0x0f];

break;

case MOVSM|B1:
case MOVSM|B2:
case MOVSM|B4:
case MOVSM|B8:
pbuf[bufcnt++] = "movsm|";
pbuf[bufcnt++] = Bbuf[*pc & 0x03];
++pc;
pbuf[bufcnt++] = SDbuf[*pc & 0x0f];
pc += SDcnt[*pc & 0x0f];
break;

case MOVMS|B1:
case MOVMS|B2:
case MOVMS|B4:
case MOVMS|B8:
pbuf[bufcnt++] = "movms|";
pbuf[bufcnt++] = Bbuf[*pc & 0x03];
++pc;
pbuf[bufcnt++] = SDbuf[*pc & 0x0f];
pc += SDcnt[*pc & 0x0f];
break;

case MOVMM|B1:
case MOVMM|B2:
case MOVMM|B4:
case MOVMM|B8:
pbuf[bufcnt++] = "movmm|";
pbuf[bufcnt++] = Bbuf[*pc & 0x03];
++pc;
pbuf[bufcnt++] = SDbuf[*pc & 0x0f];
pc += SDcnt[*pc & 0x0f];
break;

case DUMP:
pbuf[bufcnt++] = "dump ";
break;
case REGAIN:
pbuf[bufcnt++] = "regain ";
break;
case CALL:
pbuf[bufcnt++] = "call ";
break;
case RET:
pbuf[bufcnt++] = "ret ";
break;
case SWAP:
pbuf[bufcnt++] = "swap ";
break;
case SWAP4:
pbuf[bufcnt++] = "swap4 ";
break;
case SWAP4DEEP:
pbuf[bufcnt++] = "swap4deep ";
break;
case DUP:
pbuf[bufcnt++] = "dup ";
break;
case DUP4:
pbuf[bufcnt++] = "dup4 ";
break;
case ABSMEM:
pbuf[bufcnt++] = "absmem ";
break;
case ABSSTK:
pbuf[bufcnt++] = "absstk ";
break;
case MOVDA1:
pbuf[bufcnt++] = "movda1 ";
break;
case MOVDA2:
pbuf[bufcnt++] = "movda2 ";
break;
case MOVDA4:
pbuf[bufcnt++] = "movda4 ";
break;
case MOVDA8:
pbuf[bufcnt++] = "movda8 ";
break;
case MOVDAX:
pbuf[bufcnt++] = "movdax ";
break;
case MOVAA1:
pbuf[bufcnt++] = "movaa1 ";
break;
case MOVAA2:
pbuf[bufcnt++] = "movaa2 ";
break;
case MOVAA4:
pbuf[bufcnt++] = "movaa4 ";
break;
case MOVAA8:
pbuf[bufcnt++] = "movaa8 ";
break;
case MOVAAX:
pbuf[bufcnt++] = "movaax ";
break;
case MOVAAC:
pbuf[bufcnt++] = "movaac ";
break;
case NOP:
pbuf[bufcnt++] = "nop ";
break;
} /* END: switch(*pc) */
}/* END: for() */
for(i = 0; i < bufcnt; ++i)
fwrite(pbuf[i], 1, strlen(pbuf[i]), iv->outfile);
fwrite("\n", 1, 1, iv->outfile);
}/* END: printinst() */
static void
disassemble(Piv iv, void *ptr, long size)
{
int x;
long offset = iv->out_offset;

x = print8(iv, ptr, size, offset, 0);
printinst(iv, ptr, size);
while((size -= x) > 0)
{
offset += x;
((char*)ptr) += x;
x = print8(iv, ptr, size, offset, 1);
}
}
static void
reset_funcdata(Piv iv)
{
iv->obuf = (char*)&iv->obufstart;
iv->obufstart = 0;
iv->obufcnt = 0;
iv->func_offset = 0;
iv->jbuf = (PJL)&iv->jbufstart;
iv->jmpcnt = 0;
iv->jbufcnt = 0;
iv->jbufstart = 0;
iv->extbuf = (PEL)&iv->extbufstart;
iv->extcnt = 0;
iv->extbufcnt = 0;
iv->extbufstart = 0;
iv->stackdepth = 0;
iv->maxdepth = 0;
iv->mindepth = 0;
iv->numnested = 0;
iv->cod_bufcnt = 0;
iv->ob_bufcnt = 0;
iv->cod_usedhead = 0;
iv->ob_usedhead = 0;
iv->first_cod = 0;
iv->first_ob = 0;
Cfreecat(FUNCDATA);
}
static void
write_funcdata(Piv iv, unsigned char *pdef)
{
long *p;
if((p = (long*)iv->obufstart))
{
setup_jmps(iv, pdef);
while(shorten_jmps(iv))
;
while(p)
{
if(iv->listing_wanted)
{
if(((unsigned char*)p)[8] == LINENO)
{
printline(iv, &((unsigned char*)p)[9]);
}
else if(((unsigned char*)p)[8] == NFUNC)
{
char *funcname = *((char**)&(((char*)p)[9]));
fprintf(iv->outfile, "\n%8.8x: .nested .function _%s\n",
iv->out_offset, funcname);
}
else
{
disassemble(iv, &p[2], p[1]);
iv->out_offset += p[1];
}
}
else
{
FILEWRITE(&p[2],p[1]);
iv->out_offset += p[1];
}
p = (void*)p[0];
}
}
if(iv->debug >= '1')
cfeprintf("MAXDEPTH=%d MINDEPTH=%d func=%s\n",
iv->maxdepth, iv->mindepth, iv->symaddr[GL( ((Pop)pdef)->data )]);

save_maxdepth(iv, GL( ((Pop)pdef)->data ));
}
static void *
write_obuf(Piv iv, unsigned char *buf, long cnt)
{/* Output first goes to a linked list */
void *next = iv->obuf;

if(iv->obuf != (unsigned char*)&iv->obufstart)
{/* Suppress duplicate RETs */
if(buf[0] == RET && (iv->obuf[8] == RET || iv->obuf[9] == RETSTRUCT) )
{
return iv->obuf;
}
}
if(iv->obufcnt >= cnt+8)
{/* There is sufficient room in the current chunk */
long size = ((long*)iv->obuf)[1];
iv->obuf += size+8;
}
else
{/* Allocate a new chunk of linked list space */
iv->obufcnt = 4080;
iv->obuf = Ccalloc(FUNCDATA, 1, iv->obufcnt);
}

*((void**)next) = iv->obuf; /* link back to old entry */
((long*)iv->obuf)[1] = cnt; /* record the size of the data */
iv->obufcnt -= cnt+8; /* deduct data size plus overhead */
memcpy(&((long*)iv->obuf)[2], buf, cnt); /* copy the data to this area */
if(buf[0] != LINENO && buf[0] != NFUNC)
{/* A line number record is an anomoly */
if(iv->extmark)
addto_extlist(iv, buf); /* reference to external variable here */
iv->func_offset += cnt; /* increase the program counter */
}

iv->cod->ee = (struct _nodeOBUF *)iv->obuf; /* points to obuf chunks */
link_cod(iv);

return iv->obuf; /* return the address of this sub chunk */
}
static void
do_conversion(Piv iv, PND dst, PND src)
{
unsigned char obuf[2];
int dsize = dst->size;
int ssize = src->size;
unsigned char ddtype = dst->dtype;
unsigned char sdtype = src->dtype;
#define SRC(a) (a<<4)

if(src->atype & (A_ABSOLUTE|A_POINTER|A_VALUE) == (A_POINTER|A_VALUE))
{
if(src->atype & A_DATA)
obuf[0] = ABSMEM;
else if(src->atype & (A_AUTO|A_PARAM))
obuf[0] = ABSSTK;
else
PERROR(pName ": Line:%d bad conversion0\n", iv->lastline);
write_obuf(iv, obuf, 1);
return;
}
obuf[0] = CVT;
switch(ddtype)
{
case D_SIGNED: /* dest is signed integer */
{
if(dsize == 1)
obuf[1] = BYTE;
else if(dsize == 2)
obuf[1] = SHORT;
else if(dsize == 4)
obuf[1] = LONG;
else if(dsize == 8)
obuf[1] = CLONGLONG;
switch(sdtype)
{
case D_SIGNED:
{/* src is signed integer */
if(dsize <= ssize)
return;
if(ssize == 1)
obuf[1] |= SRC(BYTE);
else if(ssize == 2)
obuf[1] |= SRC(SHORT);
else if(ssize == 4)
obuf[1] |= SRC(LONG);
else if(ssize == 8)
obuf[1] |= SRC(CLONGLONG);
break;
}
case D_UNSIGNED:
case D_SEGMENT:
{/* src is unsigned integer */
if(dsize <= ssize)
return;
if(ssize == 1)
obuf[1] |= SRC(UBYTE);
else if(ssize == 2)
obuf[1] |= SRC(USHORT);
else if(ssize == 4)
obuf[1] |= SRC(ULONG);
else if(ssize == 8)
obuf[1] |= SRC(CULONGLONG);
break;
}
case D_FLOAT:
{/* src is floating point */
if(ssize == 4)
obuf[1] |= SRC(FLOAT);
else if(ssize == 8)
obuf[1] |= SRC(DOUBLE);
else
obuf[1] |= SRC(CLONGDOUBLE);
break;
}
case D_POINTER:
case D_FUNCPTR:
{/* src is unsigned int */
if(dsize <= ssize)
return;
if(ssize == 1)
obuf[1] |= SRC(UBYTE);
else if(ssize == 2)
obuf[1] |= SRC(USHORT);
else if(ssize == 4)
obuf[1] |= SRC(ULONG);
else if(ssize == 8)
obuf[1] |= SRC(CULONGLONG);
break;
}
default:
PERROR(pName ": Line:%d bad conversion1\n", iv->lastline);
}
break;
}
case D_UNSIGNED: /* dest is unsigned integer */
case D_SEGMENT:
{
if(dsize == 1)
obuf[1] = UBYTE;
else if(dsize == 2)
obuf[1] = USHORT;
else if(dsize == 4)
obuf[1] = ULONG;
else if(dsize == 8)
obuf[1] = CULONGLONG;
switch(sdtype)
{
case D_SIGNED:
{/* src is signed integer */
if(dsize <= ssize)
return;
if(ssize == 1)
obuf[1] |= SRC(BYTE);
else if(ssize == 2)
obuf[1] |= SRC(SHORT);
else if(ssize == 4)
obuf[1] |= SRC(LONG);
else if(ssize == 8)
obuf[1] |= SRC(CLONGLONG);
break;
}
case D_UNSIGNED:
case D_SEGMENT:
{/* src is unsigned integer */
if(dsize <= ssize)
return;
if(ssize == 1)
obuf[1] |= SRC(UBYTE);
else if(ssize == 2)
obuf[1] |= SRC(USHORT);
else if(ssize == 4)
obuf[1] |= SRC(ULONG);
else if(ssize == 8)
obuf[1] |= SRC(CULONGLONG);
break;
}
case D_FLOAT:
{/* src is floating point */
if(ssize == 4)
obuf[1] |= SRC(FLOAT);
else if(ssize == 8)
obuf[1] |= SRC(DOUBLE);
else
obuf[1] |= SRC(CLONGDOUBLE);
break;
}
case D_POINTER:
case D_FUNCPTR:
{/* src is unsigned integer */
if(dsize <= ssize)
return;
if(ssize == 1)
obuf[1] |= SRC(UBYTE);
else if(ssize == 2)
obuf[1] |= SRC(USHORT);
else if(ssize == 4)
obuf[1] |= SRC(ULONG);
else if(ssize == 8)
obuf[1] |= SRC(CULONGLONG);
break;
}
default:
PERROR(pName ": Line:%d bad conversion2\n", iv->lastline);
}
break;
}
case D_FLOAT: /* dest is float, double, long double */
{
if(dsize == 4)
obuf[1] = FLOAT;
else if(dsize == 8)
obuf[1] = DOUBLE;
else
obuf[1] = CLONGDOUBLE;
switch(sdtype)
{
case D_SIGNED:
{/* src is signed integer */
if(ssize == 1)
obuf[1] |= SRC(BYTE);
else if(ssize == 2)
obuf[1] |= SRC(SHORT);
else if(ssize == 4)
obuf[1] |= SRC(LONG);
else if(ssize == 8)
obuf[1] |= SRC(CLONGLONG);
break;
}
case D_UNSIGNED:
case D_SEGMENT:
{/* src is unsigned integer */
if(ssize == 1)
obuf[1] |= SRC(UBYTE);
else if(ssize == 2)
obuf[1] |= SRC(USHORT);
else if(ssize == 4)
obuf[1] |= SRC(ULONG);
else if(ssize == 8)
obuf[1] |= SRC(CULONGLONG);
break;
}
case D_FLOAT:
{/* src is floating point */
if(dsize == ssize)
return;
if(ssize == 4)
obuf[1] |= SRC(FLOAT);
else if(ssize == 8)
obuf[1] |= SRC(DOUBLE);
else
obuf[1] |= SRC(CLONGDOUBLE);
break;
}
case D_POINTER:
case D_FUNCPTR:
{/* src is unsigned integer */
if(ssize == 1)
obuf[1] |= SRC(UBYTE);
else if(ssize == 2)
obuf[1] |= SRC(USHORT);
else if(ssize == 4)
obuf[1] |= SRC(ULONG);
else if(ssize == 8)
obuf[1] |= SRC(CULONGLONG);
break;
}
default:
PERROR(pName ": Line:%d bad conversion3\n", iv->lastline);
}
break;
}
case D_POINTER:
case D_FUNCPTR:
{/* dest is unsigned integer */
if(dsize == 1)
obuf[1] = BYTE;
else if(dsize == 2)
obuf[1] = SHORT;
else if(dsize == 4)
obuf[1] = LONG;
else if(dsize == 8)
obuf[1] = CLONGLONG;
switch(sdtype)
{
case D_SIGNED:
{/* src is signed integer */
if(dsize <= ssize)
return;
if(ssize == 1)
obuf[1] |= SRC(BYTE);
else if(ssize == 2)
obuf[1] |= SRC(SHORT);
else if(ssize == 4)
obuf[1] |= SRC(LONG);
else if(ssize == 8)
obuf[1] |= SRC(CLONGLONG);
break;
}
case D_UNSIGNED:
case D_SEGMENT:
{/* src is unsigned integer */
if(dsize <= ssize)
return;
if(ssize == 1)
obuf[1] |= SRC(UBYTE);
else if(ssize == 2)
obuf[1] |= SRC(USHORT);
else if(ssize == 4)
obuf[1] |= SRC(ULONG);
else if(ssize == 8)
obuf[1] |= SRC(CULONGLONG);
break;
}
case D_FLOAT:
{/* src is floating point */
if(ssize == 4)
obuf[1] |= SRC(FLOAT);
else if(ssize == 8)
obuf[1] |= SRC(DOUBLE);
else
obuf[1] |= SRC(CLONGDOUBLE);
break;
}
case D_POINTER:
case D_FUNCPTR:
{/* src is unsigned integer */
if(dsize <= ssize)
return;
if(ssize == 1)
obuf[1] |= SRC(UBYTE);
else if(ssize == 2)
obuf[1] |= SRC(USHORT);
else if(ssize == 4)
obuf[1] |= SRC(ULONG);
else if(ssize == 8)
obuf[1] |= SRC(CULONGLONG);
break;
}
default:
PERROR(pName ": Line:%d bad conversion4\n", iv->lastline);
}
break;
}
default:
PRINTF("Line:%d no conversion\n", iv->lastline);
return;
}
write_obuf(iv, obuf, 2);
#undef SRC
}
static int
check_assignment_conversion(PND dst, PND src)
{
long dsize = dst->size;
long ssize = src->size;
unsigned char ddtype = dst->dtype;
unsigned char sdtype = src->dtype;
int ret = 0;

if(src->atype & (A_ABSOLUTE|A_POINTER|A_VALUE) == (A_POINTER|A_VALUE))
return 1;
switch(ddtype)
{
case D_SIGNED: /* dest is signed integer */
{
switch(sdtype)
{
case D_SIGNED:
case D_UNSIGNED:
case D_SEGMENT:
case D_POINTER:
case D_FUNCPTR:
{
if(dsize > ssize)
ret = 1;
break;
}
case D_FLOAT:
{
ret = 1;
break;
}
}
break;
}
case D_UNSIGNED: /* dest is unsigned integer */
case D_SEGMENT:
{
switch(sdtype)
{
case D_SIGNED:
case D_UNSIGNED:
case D_SEGMENT:
case D_POINTER:
case D_FUNCPTR:
{
if(dsize > ssize)
ret = 1;
break;
}
case D_FLOAT:
{
ret = 1;
break;
}
}
break;
}
case D_FLOAT: /* dest is float, double, long double */
{
if(sdtype == D_FLOAT)
{
if(dsize != ssize)
ret = 1;
}
else ret = 1;
break;
}
case D_POINTER:
case D_FUNCPTR: /* dest is pointer */
{
switch(sdtype)
{
case D_SIGNED:
case D_UNSIGNED:
case D_SEGMENT:
case D_POINTER:
case D_FUNCPTR:
{
if(dsize > ssize)
ret = 1;
break;
}
case D_FLOAT:
{
ret = 1;
break;
}
}
break;
}
}
return ret;
}
static int
check_binop_conversion(PND dst, PND src)
{
long dsize = dst->size;
long ssize = src->size;
unsigned char ddtype = dst->dtype;
unsigned char sdtype = src->dtype;
int ret = 0;

switch(ddtype)
{
case D_SIGNED: /* dest is signed integer */
{
switch(sdtype)
{
case D_SIGNED:
case D_UNSIGNED:
case D_SEGMENT:
case D_POINTER:
case D_FUNCPTR:
{
if(dsize > ssize)
ret = 1;
break;
}
}
break;
}
case D_UNSIGNED: /* dest is unsigned integer */
case D_SEGMENT:
{
switch(sdtype)
{
case D_SIGNED:
case D_UNSIGNED:
case D_SEGMENT:
case D_POINTER:
case D_FUNCPTR:
{
if(dsize > ssize)
ret = 1;
break;
}
}
break;
}
case D_FLOAT: /* dest is float, double, long double */
{
if(sdtype == D_FLOAT)
{
if(dsize > ssize)
ret = 1;
}
else ret = 1;
break;
}
case D_POINTER:
case D_FUNCPTR: /* dest is pointer */
{
switch(sdtype)
{
case D_SIGNED:
case D_UNSIGNED:
case D_SEGMENT:
case D_POINTER:
case D_FUNCPTR:
{
if(dsize > ssize)
ret = 1;
break;
}
}
break;
}
}
return ret;
}
static int
get_size(int type, int size)
{
switch(type)

{
case D_ARRAY:
case D_STRUCT:
case D_FUNCTION:
return B4;

default:
switch(size)
{
case 1:
return B1;
case 2:
return B2;
case 4:
return B4;
case 8:
return B8;
default:
#if SUPPORT_LONG_DOUBLE
return BX;
#endif
}
}
return 0;
}
static int
load_addr(Piv iv, unsigned char *poc, void *buf, PND pnd, int shft)
{/* Use the shortest possible representation */
long offset = pnd->OFFSET;
long ofs = offset >> 2;

if(pnd->atype & (A_EXTERN|A_ABSOLUTE))
{/* 4 bytes for absolute values */
*poc |= 3< *((long*)buf) = offset;
iv->extmark += 1;
iv->markedsym[iv->extmark] = pnd->SYMNUM;
iv->markedbuf[iv->extmark] = buf;
return 4;
}
if(offset & 0xff000000)
{/* Relative values are restricted to 28 bits max */
PERROR(pName ": Line:%d offset too large %x\n", iv->lastline, ofs);
return 0;
}
if(offset & 0xffff0000 || offset & 0x00000003)
{/* 3 bytes for large values and non-aligned values */
*poc |= 2< *((long*)buf) = offset;
return 3;
}
else if(ofs & 0xffffff00)
{/* 2 or fewer bytes for small aligned values */
*poc |= 1< *((short*)buf) = (short)ofs;
return 2;
}
else
{
*((char*)buf) = (char)ofs;
return 1;
}

}
static void
load_val(Piv iv, unsigned long val)
{
unsigned char obuf[10];

obuf[0] = LUI;
++iv->stackdepth;
if(val & 0xffff0000)
{
obuf[0] |= 2;
*((unsigned long*)&obuf[1]) = val;
write_obuf(iv, obuf, 5);
}
else if(val & 0xffffff00)
{
obuf[0] |= 1;
*((unsigned short*)&obuf[1]) = (unsigned short)val;
write_obuf(iv, obuf, 3);
}
else
{
obuf[1] = (unsigned char)val;
write_obuf(iv, obuf, 2);
}
}
static int
load_immed(Piv iv, unsigned char *poc, void *obuf, PND pnd, int osize)
{
unsigned short dtype = pnd->dtype;
unsigned char mosize = pnd->opsize;
void *ibuf = pnd->data;

if(osize >= 0)
{/* force the immediate value to conform to osize */
if(osize == mosize)
{
switch(osize)
{
case B1:
*((char*)obuf) = *((char*)ibuf);
return 1;
case B2:
*((short*)obuf) = *((short*)ibuf);
return 2;
case B4:
*((long*)obuf) = *((long*)ibuf);
return 4;
case B8:
*((double*)obuf) = *((double*)ibuf);
return 8;
case BX:
#if SUPPORT_LONG_DOUBLE
*((long double*)obuf) = *((long double*)ibuf);
else
memcpy(obuf, ibuf, XSZ);
#endif
return XSZ;
default:
PERROR(pName ": Line:%d LOAD IMMED SYSERR osize=%d\n", iv->lastline, osize);
}
}
else /* osize != mosize */
{
if(dtype == D_FLOAT)
{
float f;
double d;
#if SUPPORT_LONG_DOUBLE
long double ld;
#endif
switch(osize)
{
case B4:
switch(mosize)
{
case B8:
f = (float)*((double*)ibuf);
*((float*)obuf) = f;
return 4;
case BX:
#if SUPPORT_LONG_DOUBLE
f = (float)*((long double*)ibuf);
*((float*)obuf = f;
return 4;
#else
PERROR(pName ": Line:%d long double conversion not supported\n", iv->lastline);
#endif
default:
PERROR(pName ": Line:%d bad floating immediate input\n",iv->lastline);
}
case B8:
switch(mosize)
{
case B4:
d = (double)*((float*)ibuf);
*((double*)obuf) = d;
return 8;
case BX:
#if SUPPORT_LONG_DOUBLE
d = (double)*((long double*)ibuf);
*((double*)obuf = d;
return 8;
#else
PERROR(pName ": Line:%d long double conversion not supported\n", iv->lastline);
#endif
default:
PERROR(pName ": Line:%d bad floating immediate input\n", iv->lastline);
}
case BX:
#if SUPPORT_LONG_DOUBLE
switch(mosize)
{
case B4:
ld = (long double)*((float*)ibuf);
*((long double*)obuf) = ld;
return XSZ;
case B8:
ld = (long double)*((double*)ibuf);
*((long double*)obuf = ld;
return XSZ;
default:
PERROR(pName ": Line:%d bad floating immediate input\n", iv->lastline);
}
break;
#else
PERROR(pName ": Line:%d long double conversion not supported\n", iv->lastline);
#endif
break;
default:
PERROR(pName ": Line:%d bad floating immediate output\n", iv->lastline);
}
}/* END: dtype == D_FLOAT */
else if(dtype == D_UNSIGNED || dtype == D_POINTER)
{
switch(osize)
{
case B1:
*((unsigned char*)obuf) = *((unsigned char *)ibuf);
return 1;
case B2:
switch(mosize)
{
case B1:
*((unsigned short*)obuf) = *((unsigned char*)ibuf);
return 2;
case B4:
case B8:
*((unsigned short*)obuf) = *((unsigned short*)ibuf);
return 2;
case BX:
PERROR(pName ": Line:%d invalid integer size\n", iv->lastline);
default:
PERROR(pName ": Line:%d invalid immediate input\n", iv->lastline);
}
case B4:
switch(mosize)
{
case B1:
*((unsigned long*)obuf) = *((unsigned char*)ibuf);
return 4;
case B2:
*((unsigned long*)obuf) = *((unsigned short*)ibuf);
return 4;
case B8:
*((unsigned long*)obuf) = *((unsigned long*)ibuf);
return 4;
case BX:
PERROR(pName ": Line: invalid integer size\n", iv->lastline);
default:
PERROR(pName ": Line:%d invalid immediate input\n", iv->lastline);
}
case B8:
{
unsigned long l[2];
l[0] = 0;
l[1] = 0;
if(mosize == B4)
l[0] = *((unsigned long*)ibuf);
else if(mosize == B2)
l[0] = *((unsigned short*)ibuf);
else if(mosize == B1)
l[0] = *((unsigned char*)ibuf);
else
PERROR(pName ": Line:%d invalid integer size\n", iv->lastline);
memcpy(obuf, l, 8);
return 8;
}
default:
PERROR(pName ": Line:%d invalid integer size=%d\n",
iv->lastline, osize);
}
}
else /* signed integer */
{
switch(osize)
{
case B1:
*((char*)obuf) = *((char *)ibuf);
return 1;
case B2:
switch(mosize)
{
case B1:
*((short*)obuf) = *((char*)ibuf);
return 2;
case B4:
case B8:
*((short*)obuf) = *((short*)ibuf);
return 2;
case BX:
PERROR(pName ": Line:%d invalid integer size\n", iv->lastline);
default:
PERROR(pName ": Line:%d invalid immediate input\n",iv->lastline);
}
case B4:
switch(mosize)
{
case B1:
*((long*)obuf) = *((char*)ibuf);
return 4;
case B2:
*((long*)obuf) = *((short*)ibuf);
return 4;
case B8:
*((long*)obuf) = *((long*)ibuf);
return 4;
case BX:
PERROR(pName ": Line:%d invalid integer size\n", iv->lastline);
default:
PERROR(pName ": Line:%d invalid immediate input\n", iv->lastline);
}
case B8:
{
long l[2];
l[0] = 0;
l[1] = 0;
if(mosize == B4)
l[0] = *((long*)ibuf);
else if(mosize == B2)
l[0] = *((short*)ibuf);
else if(mosize == B1)
l[0] = *((char*)ibuf);
else
PERROR(pName ": Line:%d invalid integer size\n", iv->lastline);
if(l[0] < 0)
l[1] = -1;
memcpy(obuf, l, 8);
return 8;
}
default:
PERROR(pName ": Line:%d invalid integer size=%d\n",
iv->lastline, osize);
}
}/* END: signed integer */
}/* END: osize != mosize */
/* NOT REACHED */
PERROR(pName ": Line:%d LOAD IMMED SYSERR1 osize=%d mosize=%d\n", iv->lastline, osize, mosize);
return 0; /* suppress compiler warning */
}
else
{/* generate the shortest possible immediate value */
int thesize = 0;
if(dtype == D_FLOAT)
{
switch(mosize)
{
case B4:
*((float*)obuf) = *((float*)ibuf);
thesize = 4;
break;
case B8:
*((double*)obuf) = *((double*)ibuf);
thesize = 8;
break;
case BX:
#if SUPPORT_LONG_DOUBLE
*((long double*)obuf) = *((long double*)ibuf);
else
memcpy(obuf, ibuf, XSZ);
#endif
thesize = XSZ;
break;
default:
PERROR(pName ": Line:%d wrong sized floating immediate\n", iv->lastline);
}
}
else /* dtype not D_FLOAT */
{
int negative;
int sgned;
unsigned long ul[2];
long *sl;

ul[1] = 0;
negative = 0;
sl = ul;
if(dtype == D_UNSIGNED || dtype == D_POINTER)
{
sgned = 0;
if(mosize == B8)
{
ul[0] = *((unsigned long*)ibuf);
ul[1] = *((unsigned long*)(((char*)ibuf)+4));
}
else
{
if(mosize == B4)
ul[0] = *((unsigned long*)ibuf);
else if(mosize == B2)
ul[0] = *((unsigned short*)ibuf);
else if(mosize == B1)
ul[0] = *((unsigned char*)ibuf);
else
PERROR(pName ": Line:%d invalid integer immediate\n", iv->lastline);
}
}
else /* sgned */
{
sgned = 1;
if(mosize == B8)
{
sl[0] = *((long*)ibuf);
sl[1] = *((long*)(((char*)ibuf)+4));
if(sl[1] < 0)
{
negative = 1;
ul[1] = ~ul[1];
ul[0] = ~ul[0];
if(ul[0] == 0xffffffff)
{
ul[0] = 0;
ul[1] += 1;
}
else ul[0] += 1;
}
}
else
{
if(mosize == B4)
sl[0] = *((long*)ibuf);
else if(mosize == B2)
sl[0] = *((short*)ibuf);
else if(mosize == B1)
sl[0] = *((char*)ibuf);
else
PERROR(pName ": Line:%d invalid integer immediate\n",iv->lastline);
if(sl[0] < 0)
{
negative = 1;
sl[0] = -sl[0];
}
}
} /* END: sgned */
if(negative)
{
if(ul[1])
mosize = B8;
else if(ul[0] & 0xffff8000)
mosize = B4;
else if(ul[0] & 0xffffff80)
mosize = B2;
else
mosize = B1;
}
else
{
if(sgned)
{
if(ul[1])
mosize = B8;
else if(ul[0] & 0xffff8000)
{
if(!(ul[0] & 0xffff0000))
{
*poc = LUI;
mosize = B2;
}
else
mosize = B4;
}
else if(ul[0] & 0xffffff80)
{
if(!(ul[0] & 0xffffff00))
{
*poc = LUI;
mosize = B1;
}
else
mosize = B2;
}
else
mosize = B1;
}
else /* unsigned */
{
if(ul[1])
mosize = B8;
else if(ul[0] & 0xffff0000)
mosize = B4;
else if(ul[0] & 0xffffff00)
mosize = B2;
else
mosize = B1;
}
}
if(negative)
{
ul[1] = ~ul[1];
ul[0] = ~ul[0];
if(ul[0] == 0xffffffff)
{
ul[0] = 0;
ul[1] += 1;
}
else ul[0] += 1;
}
switch(mosize)
{
case B1:
*((char*)obuf) = *((char*)sl);
thesize = 1;
break;
case B2:
*((short*)obuf) = *((short*)sl);
thesize = 2;
break;
case B4:
*((long*)obuf) = *((long*)sl);
thesize = 4;
break;
case B8:
*((double*)obuf) = *((double*)sl);
thesize = 8;
break;
}
}/* END: not D_FLOAT */
*poc |= mosize;
return thesize;
}
}
static void
addr_toevalstack(Piv iv, PND pnd)
{
unsigned char obuf[20];
int atype = pnd->atype;

if(atype & (A_AUTO|A_PARAM|A_DATA))
{
int l;
obuf[0] = LAI;
l = 1;
l += load_addr(iv, &obuf[0], &obuf[1], pnd, 0);

write_obuf(iv, obuf, l);
if(atype & (A_AUTO|A_PARAM))
{
obuf[0] = ABSSTK;
write_obuf(iv, obuf, 1);
}
else if(l < 5)
{
obuf[0] = ABSMEM;
write_obuf(iv, obuf, 1);
}
++iv->stackdepth;
}
}
static void
data_toevalstack(Piv iv, PND pnd, PND dst)
{
unsigned char obuf[20];
int xtra, oc;
unsigned short dtype, atype;
unsigned char osize;

atype = pnd->atype;
dtype = pnd->dtype;
if(atype & A_IMMED)
{
if(dtype == D_UNSIGNED)
obuf[0] = LUI;
else
obuf[0] = LI;
xtra = load_immed(iv, &obuf[0], &obuf[1], pnd, -1);
write_obuf(iv, obuf, 1+xtra);
++iv->stackdepth;
return;
}
xtra = oc = 0;
osize = pnd->opsize;
if(osize == BX)
{
obuf[0] = XTD;
osize = 0;
oc = 1;
xtra = 1;
}
if(atype & (A_TEMP|A_RET))
{
if(atype & A_MEMADDR)
{
unsigned char xsize = get_datasize(0, pnd);
if(osize == B8 && dtype < D_FLOAT)
obuf[xtra++] = XTD;

if( dst
&& (pnd->TMPNUM == dst->TMPNUM)
&& ((dst->atype & (A_ABSOLUTE|A_MEMADDR))
== (A_ABSOLUTE|A_MEMADDR))
)
{/* generally used for a += b etc. */
obuf[xtra++] = IMMED;
obuf[xtra] = DEREF1|xsize;
write_obuf(iv, obuf, 1+xtra);
++iv->stackdepth;
}
else
{
obuf[xtra++] = IMMED;
obuf[xtra] = DEREF|get_datasize(0, pnd);
write_obuf(iv, obuf, 1+xtra);
}
pnd->atype &= ~A_MEMADDR;
pnd->atype |= A_VALUE;
}
return;
}

if(atype & (A_AUTO|A_PARAM))
{
if(atype & (A_POINTER|A_VALUE) == (A_POINTER|A_VALUE))
{/* Put address on eval stack */
addr_toevalstack(iv, pnd);
pnd->atype |= A_ABSOLUTE;
return;
}
else
{
obuf[oc] = LS|osize;
xtra += load_addr(iv, &obuf[oc], &obuf[oc+1], pnd, 2);
++iv->stackdepth;
}
}
else if(atype & A_DATA)
{
if(atype & (A_POINTER|A_VALUE) == (A_POINTER|A_VALUE))
{/* Put address on eval stack */
addr_toevalstack(iv, pnd);
pnd->atype |= A_ABSOLUTE;
return;
}
else
{
obuf[oc] = LM|osize;
xtra += load_addr(iv,&obuf[oc], &obuf[oc+1], pnd, 2);
++iv->stackdepth;
}
}
write_obuf(iv, obuf, 1+xtra);
}
static void
promote_arg(Piv iv, PND pnd, long argsize)
{
long dsize = pnd->size;
struct _nd dst;

if(dsize != argsize)
{
dst.size = argsize;
dst.dtype = pnd->dtype;
dst.atype = 0;
do_conversion(iv, &dst, pnd);
}
}
static unsigned char
arg_toevalstack(Piv iv, PND pnd, long argsize)
{
unsigned char dtype;

if(pnd->atype & A_IMMED)
{
data_toevalstack(iv, pnd, 0);
return ARG;
}
dtype = pnd->dtype;
if(dtype == D_STRUCT)
{
addr_toevalstack(iv, pnd);
return ARGA;
}
else if(dtype == D_FUNCTION)
{
addr_toevalstack(iv, pnd);
return ARGF;
}
else if(dtype == D_FUNCPTR)
{
data_toevalstack(iv, pnd, 0);
return ARGF;
}
else if(dtype == D_ARRAY)
{
addr_toevalstack(iv, pnd);
}
else
{
data_toevalstack(iv, pnd, 0);
promote_arg(iv, pnd, argsize);
}
return ARG;
}
static void
mov_esdata(Piv iv, unsigned short atype, int size)
{
unsigned char obuf[2];

if(atype & A_MEMADDR)
{
if(size == B1)
obuf[0] = MOVAA1;
else if(size == B2)
obuf[0] = MOVAA2;
else if(size == B4)
obuf[0] = MOVAA4;
else if(size == B8)
obuf[0] = MOVAA8;
#if SUPPORT_LONG_DOUBLE
else if(size == BX)
obuf[0] = MOVAAX;
#endif
else {obuf[0] = MOVAAC; size = XSZ;}
}
else
{
if(size == B1)
obuf[0] = MOVDA1;
else if(size == B2)
obuf[0] = MOVDA2;
else if(size == B4)
obuf[0] = MOVDA4;
else if(size == B8)
obuf[0] = MOVDA8;
#if SUPPORT_LONG_DOUBLE
else if(size == BX))
obuf[0] = MOVDAX;
#endif
else
PERROR(pName ": Line:%d illegal mov data size=%d\n", iv->lastline, size);
}
if(obuf[0] == MOVAAC)
{
load_val(iv, size);
--iv->stackdepth;
}
write_obuf(iv, obuf, 1);
iv->stackdepth -= 2;
}
static void
from_evalstack(Piv iv, PND d, PND s)
{
unsigned char obuf[20];
int xtra, oc;
unsigned short datype = d->atype;
unsigned char osize = d->opsize;

xtra = oc = 0;

if(datype & (A_TEMP|A_RET))
{
if(datype & A_MEMADDR)
{
mov_esdata(iv, s->atype, osize);
}
return;
}

if(osize == BX)
{
obuf[0] = XTD;
oc = 1;
osize = 0;
xtra = 1;
}
if(datype & (A_AUTO|A_PARAM))
{
obuf[oc] = SS|osize;
xtra += load_addr(iv, &obuf[oc], &obuf[oc+1], d, 2);
--iv->stackdepth;
}
else if(datype & OPDATA)
{
obuf[oc] = SM|osize;
xtra += load_addr(iv, &obuf[oc], &obuf[oc+1], d, 2);
--iv->stackdepth;
}
write_obuf(iv, obuf, 1+xtra);
}
static unsigned char
get_datasize(unsigned char opcode, PND pnd)
{
unsigned char dtype = pnd->dtype;
long dsize = pnd->size;

switch(dtype)
{
case D_ARRAY:
case D_FUNCTION:
case D_STRUCT:
return LONG;
}

if( opcode == orop
|| opcode == andop
|| opcode == notop
|| opcode == lshop
|| opcode == complop
|| opcode == xorop
)
{
if(dsize == 1)
return B1;
else if(dsize == 2)
return B2;
else if(dsize == 4)
return B4;
else if(dsize == 8)
return B8;
else
return BX;
}
else
{
if(dtype == D_UNSIGNED)
{
if(dsize == 1)
return UBYTE;
else if(dsize == 2)
return USHORT;
else if(dsize == 4)
return ULONG;
else
{
if(opcode == rshop)
return SULONGLONG;
return ULONGLONG;
}
}
else if(dtype == D_FLOAT)
{
if(dsize == 4)
return FLOAT;
else if(dsize == 8)
return DOUBLE;
else
return LONGDOUBLE;
}
else
{
if(dsize == 1)
return BYTE;
else if(dsize == 2)
return SHORT;
else if(dsize == 4)
return LONG;
else
{
if(opcode == rshop)
return SLONGLONG;
return LONGLONG;
}
}
}
return 0;
}
static void *
new_nodeO(Piv iv)
{
PNODEO p;

if(iv->ob_bufcnt < sizeof(NODEO))
{/* Allocate a new chunk of linked list space */
iv->ob_bufcnt = 4080;
iv->ob_buf = Ccalloc(FUNCDATA, 1, iv->ob_bufcnt);
}
p = (PNODEO)iv->ob_buf;
iv->ob_buf += sizeof(NODEO);
iv->ob_bufcnt -= sizeof(NODEO);
return p;
}
static void
link_ob(Piv iv)
{/* Attach to the used list */

if(!iv->ob_usedhead)
{
iv->ob_usedhead = iv->ob;
iv->ob_usedtail = iv->ob;
}
else
{
iv->ob_usedtail->next = iv->ob;
iv->ob_usedtail = iv->ob;
}
iv->ob = new_nodeO(iv);
}
static void *
new_nodeC(Piv iv)
{
PNODEC p;

if(iv->cod_bufcnt < sizeof(NODEC))
{/* Allocate a new chunk of linked list space */
iv->cod_bufcnt = 4080;
iv->cod_buf = Ccalloc(FUNCDATA, 1, iv->cod_bufcnt);
}
p = (PNODEC)iv->cod_buf;
iv->cod_buf += sizeof(NODEC);
iv->cod_bufcnt -= sizeof(NODEC);
return p;
}
static void
link_cod(Piv iv)
{/* Attach to the used list */

if(!iv->cod_usedhead)
{
iv->cod_usedhead = iv->cod;
iv->cod_usedtail = iv->cod;
}
else
{
iv->cod_usedtail->next = iv->cod;
iv->cod_usedtail = iv->cod;
}
iv->cod = new_nodeC(iv);
}
static PNODEC
gen_inst(Piv iv, PNODEO pnode)
{
unsigned char *p;
unsigned char obuf[40];
int xtra, oc;
unsigned char opcode;
PND d,l,r;

d = &pnode->d;
l = &pnode->l;
r = &pnode->r;
p = pnode->p;
opcode = *p;

xtra = oc = 0;

switch(opcode)
{
case regainop:
obuf[0] = REGAIN;
write_obuf(iv, obuf, 1);
++iv->stackdepth;
break;
case grabop:
obuf[0] = SWAP4DEEP;
write_obuf(iv, obuf, 1);
break;
case getvalop:
case derefop:
case assignop:
case duptmpop:
{
if( opcode == getvalop
&& !(l->atype & A_IMMED)
&& l->dtype == D_FUNCTION)
{
addr_toevalstack(iv, l);
}
else if( opcode != derefop
&& !(l->atype & A_IMMED)
&& check_assignment_conversion(d, l))
{/* Must move data through evaluation stack */
data_toevalstack(iv, l, d);
do_conversion(iv, d, l);
l->atype &= ~A_MEMADDR;
l->atype |= A_VALUE;
if(opcode == assignop)
from_evalstack(iv, d, l);
}
else
{/* Can move data directly from memory to memory */
unsigned char ddtype = d->dtype;
unsigned char osize = d->opsize;
unsigned short latype = l->atype;
unsigned short datype = d->atype;
if(osize == BX)
{
obuf[0] = XTD;
oc = 1;
osize = 0;
xtra = 1;
}
if(latype & A_IMMED)
{
if(datype & (A_TEMP|A_RET))
{
if(l->dtype == D_UNSIGNED)
obuf[oc] = LUI;
else
obuf[oc] = LI;
xtra += load_immed(iv, &obuf[oc], &obuf[oc+1], l, -1);
++iv->stackdepth;
if(datype & A_MEMADDR)
{
write_obuf(iv, obuf, 1+xtra);
mov_esdata(iv, 0, osize);
break;
}
}
else if(datype & (A_AUTO|A_PARAM))
{
int lx;
obuf[0] = IMMED;
oc = 1;
xtra = 1;
obuf[oc] = SSI|osize;
lx = load_addr(iv, &obuf[oc], &obuf[oc+1], d, 2);
lx += load_immed(iv, &obuf[oc], &obuf[oc+1+lx], l, osize);
xtra += lx;
}
else if(datype & A_DATA)
{
int lx;
obuf[0] = IMMED;
oc = 1;
xtra = 1;
obuf[oc] = SMI|osize;
lx = load_addr(iv, &obuf[oc], &obuf[oc+1], d, 2);
lx += load_immed(iv, &obuf[oc], &obuf[oc+1+lx], l, osize);
xtra += lx;
}
else
{
return iv->cod_usedtail;
}
}
else if(latype & (A_TEMP|A_RET))
{
if(datype & (A_TEMP|A_RET))
{
if(opcode == duptmpop)
{
if(osize <= B4)
obuf[0] = DUP4;
else
obuf[0] = DUP;
xtra = 0;
++iv->stackdepth;
}
else if(opcode == getvalop || opcode == derefop)
{
if(latype & A_MEMADDR)
{
unsigned char xsize = get_datasize(0, l);
if(osize == B8 && ddtype < D_FLOAT)
obuf[xtra++] = XTD;
if(datype & A_MEMADDR)
xsize = ULONG;
obuf[xtra++] = IMMED;
obuf[xtra] = DEREF|xsize;
}
else return iv->cod_usedtail; /* nop */
}
else if(datype & A_MEMADDR)
{
mov_esdata(iv, latype, osize);
break;
}
else
{/* move a value temp to a value temp, effective nop */
return iv->cod_usedtail;
}
}
else if(datype & (A_AUTO|A_PARAM))
{
if(latype & A_MEMADDR)
{
unsigned char xsize = get_datasize(0, l);
int qc = 1;
if( osize == BX
|| (osize == B8 && ddtype < D_FLOAT))
obuf[qc++] = XTD;
obuf[qc++] = IMMED;
obuf[qc] = DEREF|xsize;
write_obuf(iv, obuf+1, qc);
}
obuf[oc] = SS|osize;
xtra += load_addr(iv, &obuf[oc], &obuf[oc+1], d, 2);
--iv->stackdepth;
}
else if(datype & A_DATA)
{
if(latype & A_MEMADDR)
{
unsigned char xsize = get_datasize(0, l);
int qc = 1;
if( osize == BX
|| (osize == B8 && ddtype < D_FLOAT))
obuf[qc++] = XTD;
obuf[qc++] = IMMED;
obuf[qc] = DEREF|xsize;
write_obuf(iv, obuf+1, qc);
}
obuf[oc] = SM|osize;
xtra += load_addr(iv, &obuf[oc], &obuf[oc+1], d, 2);
--iv->stackdepth;
}
else
{
return iv->cod_usedtail;
}
}
else if(latype & (A_AUTO|A_PARAM))
{
int lx;
if((latype & (A_POINTER|A_VALUE)) == (A_POINTER|A_VALUE))
{/* Put address on eval stack */
addr_toevalstack(iv, l);
if(opcode == assignop)
from_evalstack(iv, d, l);
break;
}
if(datype & (A_TEMP|A_RET))
{
if(opcode == derefop)
osize = B4;
obuf[oc] = LS|osize;
xtra += load_addr(iv, &obuf[oc], &obuf[oc+1], l, 2);
++iv->stackdepth;
if(opcode == assignop)
{
/* Here we need a 'store from stack addr' inst */
if(datype & A_MEMADDR)
{/* Address was on the eval stack */
write_obuf(iv, obuf, 1+xtra);
mov_esdata(iv, 0, osize);
break;
}
}
}
else if(datype & (A_AUTO|A_PARAM))
{
obuf[oc] = MOVSS|osize;
obuf[++oc] = 0;
lx = load_addr(iv, &obuf[oc], &obuf[oc+1], l, 2);
lx += load_addr(iv, &obuf[oc], &obuf[oc+1+lx], d, 0);
xtra += lx+1;
}
else if(datype & A_DATA)
{
obuf[oc] = MOVSM|osize;
obuf[++oc] = 0;
lx = load_addr(iv, &obuf[oc], &obuf[oc+1], l, 2);
lx += load_addr(iv, &obuf[oc], &obuf[oc+1+lx], d, 0);
xtra += lx+1;
}
else
{
return iv->cod_usedtail;
}
}
else if(latype & A_DATA)
{
int lx;
if((latype & (A_POINTER|A_VALUE)) == (A_POINTER|A_VALUE))
{/* Put address on eval stack */
addr_toevalstack(iv, l);
if(opcode == assignop)
from_evalstack(iv, d, l);
break;
}
if(datype & (A_TEMP|A_RET))
{
if(opcode == derefop)
osize = B4;
obuf[oc] = LM|osize;
xtra += load_addr(iv, &obuf[oc], &obuf[oc+1], l, 2);
++iv->stackdepth;
if(opcode == assignop)
{
/* Here we need a 'store from stack addr' inst */
if(datype & A_MEMADDR)
{/* Address was on the eval stack */
write_obuf(iv, obuf, 1+xtra);
mov_esdata(iv, 0, osize);
break;
}
}
}
else if(datype & (A_AUTO|A_PARAM))
{
obuf[oc] = MOVMS|osize;
obuf[++oc] = 0;
lx = load_addr(iv, &obuf[oc], &obuf[oc+1], l, 2);
lx += load_addr(iv, &obuf[oc], &obuf[oc+1+lx], d, 0);
xtra += lx+1;
}
else if(datype & A_DATA)
{
obuf[oc] = MOVMM|osize;
obuf[++oc] = 0;
lx = load_addr(iv, &obuf[oc], &obuf[oc+1], l, 2);
lx += load_addr(iv, &obuf[oc], &obuf[oc+1+lx], d, 0);
xtra += lx+1;
}
else
{
return iv->cod_usedtail;
}
}
else
{
return iv->cod_usedtail;
}
write_obuf(iv, obuf, 1+xtra);
}/* END: move data directly */
if(opcode == assignop && iv->has_structret)
{
obuf[0] = XTD;
obuf[1] = PRUNESTRUCT;
write_obuf(iv, obuf, 2);
iv->has_structret = 0;
}
break;
}
case plusop:
case minusop:
case mulop:
case divop:
case orop:
case xorop:
case andop:
case eqop:
case neqop:
case ltop:
case gtop:
case leop:
case geop:
{/* BINOPS */
unsigned char ddtype;
unsigned char osize;
unsigned short latype = l->atype;
unsigned short ratype = r->atype;
PND bestptr = 0;

if(latype & A_IMMED || ratype & A_IMMED)
{
if(ratype & A_IMMED)
{/* IMMEDIATE IS ON THE RIGHT */
bestptr = l;

data_toevalstack(iv, l, d);
if(check_binop_conversion(r, l))
do_conversion(iv, r, l);

data_toevalstack(iv, r, d);

ddtype = bestptr->dtype;
osize = l->opsize;

if(osize == BX || (osize == B8 && ddtype != D_FLOAT))
obuf[oc++] = XTD;
obuf[oc++] = binops[opcode]|get_datasize(opcode, l);
--iv->stackdepth;
write_obuf(iv, obuf, oc);
}
else /* IMMEDIATE IS ON THE LEFT */
{
bestptr = r;
if(ratype & (A_TEMP|A_RET))
{
data_toevalstack(iv, r, d);
if(check_binop_conversion(l, r))
do_conversion(iv, l, r);
data_toevalstack(iv, l, d);

ddtype = bestptr->dtype;
osize = r->opsize;

if( opcode != plusop
&& opcode != eqop
&& opcode != neqop
&& opcode != andop
&& opcode != orop
&& opcode != mulop
&& opcode != xorop
)
{/* stack order relevant */
if(osize <= B4)
obuf[0] = SWAP4;
else
obuf[0] = SWAP;
write_obuf(iv, obuf, 1);
}
}
else
{
data_toevalstack(iv, l, d);
data_toevalstack(iv, r, d);
if(check_binop_conversion(l, r))
do_conversion(iv, l, r);

ddtype = r->dtype;
osize = r->opsize;
}

if(osize == BX || (osize == B8 && ddtype != D_FLOAT))
obuf[oc++] = XTD;
obuf[oc++] = binops[opcode]|get_datasize(opcode, l);
write_obuf(iv, obuf, oc);
--iv->stackdepth;
}/* END: IMMEDIATE IS ON LEFT */
}/* IMMEDIATES */
else
{/* NOT IMMEDIATES */

if(ratype & (A_TEMP|A_RET))
{/* RIGHT HAND SIDE IS ALREADY ON STACK */

data_toevalstack(iv, r, d);

if(latype & (A_TEMP|A_RET))
{/* LEFT HAND SIDE WAS ALSO ON STACK */

/* Is it the same data as right hand side ?? */
if(l->TMPNUM == r->TMPNUM)
{
if(r->opsize <= B4)
obuf[0] = DUP4;
else
obuf[0] = DUP;
write_obuf(iv, obuf, 1);
++iv->stackdepth;
l->atype = r->atype;
}
else
{
unsigned char lltype = l->dtype;
unsigned lsize = l->opsize;
if(latype & A_MEMADDR)
{
unsigned char xsize = get_datasize(0, l);
int qc = 0;

if( (l->TMPNUM == d->TMPNUM)
&& ((d->atype & (A_ABSOLUTE|A_MEMADDR))
== (A_ABSOLUTE|A_MEMADDR))
)
{/* it must expand with a DEREF1 */
if(lsize <= B4)
obuf[0] = DUP4;
else
obuf[0] = DUP;
obuf[1] = DUMP;
obuf[2] = DUMP;
write_obuf(iv, obuf, 3);

if( lsize == BX
|| (lsize == B8 && lltype < D_FLOAT))
obuf[qc++] = XTD;
obuf[qc++] = IMMED;
obuf[qc++] = DEREF1|xsize;
write_obuf(iv, obuf, qc);
++iv->stackdepth;
}
else
{
obuf[0] = DUMP;
write_obuf(iv, obuf, 1);

if( lsize == BX
|| (lsize == B8 && lltype < D_FLOAT))
obuf[qc++] = XTD;
obuf[qc++] = IMMED;
obuf[qc++] = DEREF|xsize;
write_obuf(iv, obuf, qc);
}
l->atype &= ~A_MEMADDR;
l->atype |= A_VALUE;

if(check_binop_conversion(r, l))
{
bestptr = r;
do_conversion(iv, r, l);
}
obuf[0] = REGAIN;
write_obuf(iv, obuf, 1);

if(!bestptr)
if(check_binop_conversion(l, r))
{
bestptr = l;
do_conversion(iv, l, r);
}
}
}
}
else
{/* LEFT HAND SIDE IS NOT ON STACK */

if(check_binop_conversion(l, r))
{
bestptr = l;
do_conversion(iv, l, r);
}
data_toevalstack(iv, l, d);
if(!bestptr)
if(check_binop_conversion(r, l))
{
bestptr = r;
do_conversion(iv, r, l);
}
if( opcode != plusop
&& opcode != eqop
&& opcode != neqop
&& opcode != andop
&& opcode != orop
&& opcode != mulop
&& opcode != xorop
)
{/* stack order relevant */
if(r->opsize <= B4)
obuf[0] = SWAP4;
else
obuf[0] = SWAP;
write_obuf(iv, obuf, 1);
}
}
}
else /* ONLY LEFT HAND SIDE CAN BE ON STACK */
{
data_toevalstack(iv, l, d);
if(check_binop_conversion(r, l))
{
bestptr = r;
do_conversion(iv, r, l);
}

data_toevalstack(iv, r, d);
if(!bestptr)
if(check_binop_conversion(l, r))
{
bestptr = l;
do_conversion(iv, l, r);
}
}
if(!bestptr)
bestptr = l;

ddtype = bestptr->dtype;
osize = bestptr->opsize;

if(osize == BX || (osize==B8 && ddtype != D_FLOAT))
obuf[oc++] = XTD;
obuf[oc++] = binops[opcode]|get_datasize(opcode, bestptr);
write_obuf(iv, obuf, oc);
--iv->stackdepth;
}/* END: NOT IMMEDIATES */

if(opcode >= eqop)
{
bestptr = &longtype;
}

if(check_assignment_conversion(d, bestptr))
do_conversion(iv, d, bestptr);
bestptr->atype &= ~A_MEMADDR;
bestptr->atype |= A_VALUE;
from_evalstack(iv, d, bestptr);

break;
}/* END: BINOPS */

case lshop:
case rshop:
{/* SHIFTS */
unsigned short latype = l->atype;
unsigned short ratype = r->atype;
PND bestptr;


if(latype & A_IMMED || ratype & A_IMMED)
{
if(ratype & A_IMMED)
{/* IMMEDIATE IS ON THE RIGHT */
data_toevalstack(iv, l, d);

obuf[0] = XTD;
if(opcode == lshop)
{
obuf[1] = LSHI|get_datasize(opcode, l);
obuf[2] = r->data->Uuchar;
}
else if(opcode == rshop)
{
obuf[1] = RSHI|get_datasize(opcode, l);
obuf[2] = r->data->Uuchar;
}
write_obuf(iv, obuf, 3);
}
else /* IMMEDIATE IS ON THE LEFT */
{
if(ratype & (A_TEMP|A_RET))
{
data_toevalstack(iv, r, d);
data_toevalstack(iv, l, d);
if(r->opsize <= B4)
obuf[0] = SWAP4;
else
obuf[0] = SWAP;
write_obuf(iv, obuf, 1);
}
else
{
data_toevalstack(iv, l, d);
data_toevalstack(iv, r, d);
}

obuf[0] = XTD;
obuf[1] = binops[opcode]|get_datasize(opcode, l);
write_obuf(iv, obuf, 2);
--iv->stackdepth;
}
}
else
{/* NOT IMMEDIATES */

if(ratype & (A_TEMP|A_RET))
{/* RIGHT HAND SIDE IS ALREADY ON STACK */

data_toevalstack(iv, r, d);

if(latype & (A_TEMP|A_RET))
{/* LEFT HAND SIDE WAS ALSO ON STACK */

/* Is it the same data as right hand side ?? */
if(l->TMPNUM == r->TMPNUM)
{
if(l->opsize <= B4 && r->opsize <= B4)
obuf[0] = DUP4;
else
obuf[0] = DUP;
write_obuf(iv, obuf, 1);
++iv->stackdepth;
l->atype = r->atype;
}
else
{/* reversed stack and not same data */

if(latype & A_MEMADDR)
{
unsigned char xsize = l->opsize;
int qc = 0;

if( (l->TMPNUM == d->TMPNUM)
&& ((d->atype & (A_ABSOLUTE|A_MEMADDR))
== (A_ABSOLUTE|A_MEMADDR))
)
{/* it must expand with a DEREF1 */
if(l->opsize <= B4)
obuf[0] = DUP4;
else
obuf[0] = DUP;
obuf[1] = DUMP;
obuf[2] = DUMP;
write_obuf(iv, obuf, 3);

if(l->opsize == B8)
obuf[qc++] = XTD;
obuf[qc++] = IMMED;
obuf[qc++] = DEREF1|xsize;
write_obuf(iv, obuf, qc);
++iv->stackdepth;
}
else
{
obuf[0] = DUMP;
write_obuf(iv, obuf, 1);

if(l->opsize == B8)
obuf[qc++] = XTD;
obuf[qc++] = IMMED;
obuf[qc++] = DEREF|xsize;
write_obuf(iv, obuf, qc);
}
l->atype &= ~A_MEMADDR;
l->atype |= A_VALUE;

obuf[0] = REGAIN;
write_obuf(iv, obuf, 1);
}
}
}
else
{/* LEFT HAND SIDE IS NOT ON STACK */

data_toevalstack(iv, l, d);
if(r->opsize <= B4 && l->opsize <= B4)
obuf[0] = SWAP4;
else
obuf[0] = SWAP;
write_obuf(iv, obuf, 1);
}
}
else /* ONLY LEFT HAND SIDE CAN BE ON STACK */
{
data_toevalstack(iv, l, d);
data_toevalstack(iv, r, d);
}

/* ENSURE THAT THE RIGHT SIDE IS A LONG OR A LONG LONG */
bestptr = (l->size > 4) ? &longlongtype : &longtype;
if(check_assignment_conversion(bestptr, r))
do_conversion(iv, bestptr, r);

obuf[0] = XTD;
obuf[1] = binops[opcode]|get_datasize(opcode, l);
write_obuf(iv, obuf, 2);
--iv->stackdepth;
}/* END: NOT IMMEDIATES */

if(check_assignment_conversion(d, l))
do_conversion(iv, d, l);
l->atype &= ~A_MEMADDR;
l->atype |= A_VALUE;
from_evalstack(iv, d, l);

break;
}/* END: SHIFTS */
case modop:
{/* MODULUS */
unsigned short latype = l->atype;
unsigned short ratype = r->atype;
PND bestptr;

if(latype & A_IMMED || ratype & A_IMMED)
{
if(ratype & A_IMMED)

{/* IMMEDIATE IS ON THE RIGHT */
data_toevalstack(iv, l, d);

if(l->opsize == B8)
{
obuf[oc++] = XTD;
}
if(d->size == 2)
{
obuf[oc++] = IMMED;
obuf[oc++] = MODI|get_datasize(opcode, l);
*((short*)&obuf[oc]) = r->data->Uushort;
xtra = 2;
}
else
{/* no fast instructions available */
data_toevalstack(iv, r, d);
obuf[oc++] = binops[opcode]|get_datasize(opcode, l);
--iv->stackdepth;
}
write_obuf(iv, obuf, oc+xtra);
}
else /* IMMEDIATE IS ON THE LEFT */
{

if(ratype & (A_TEMP|A_RET))
{
data_toevalstack(iv, r, d);
data_toevalstack(iv, l, d);
if(r->opsize <= B4)
obuf[0] = SWAP4;
else
obuf[0] = SWAP;
write_obuf(iv, obuf, 1);
}
else
{/* load eval stack without regard for conversion */
data_toevalstack(iv, l, d);
data_toevalstack(iv, r, d);
}

if(r->opsize == B8)
{
obuf[oc++] = XTD;
}
obuf[oc++] = binops[opcode]|get_datasize(opcode, l);
write_obuf(iv, obuf, oc);
--iv->stackdepth;
}
}
else
{/* NOT IMMEDIATES */
if(ratype & (A_TEMP|A_RET))
{/* RIGHT HAND SIDE IS ALREADY ON STACK */

data_toevalstack(iv, r, d);

if(latype & (A_TEMP|A_RET))
{/* LEFT HAND SIDE WAS ALSO ON STACK */

/* Is it the same data as right hand side ?? */
if(l->TMPNUM == r->TMPNUM)
{
if(l->opsize <= B4 && r->opsize <= B4)
obuf[0] = DUP4;
else
obuf[0] = DUP;
write_obuf(iv, obuf, 1);
++iv->stackdepth;
l->atype = r->atype;
}
else
{/* reversed stack and not same data */

if(latype & A_MEMADDR)
{
unsigned char xsize = get_datasize(0, l);
int qc = 0;

if( (l->TMPNUM == d->TMPNUM)
&& ((d->atype & (A_ABSOLUTE|A_MEMADDR))
== (A_ABSOLUTE|A_MEMADDR))
)
{/* it must expand with a DEREF1 */
if(r->opsize <= B4)
obuf[0] = DUP4;
else
obuf[0] = DUP;
obuf[1] = DUMP;
obuf[2] = DUMP;
write_obuf(iv, obuf, 3);

if(r->opsize == B8)
obuf[qc++] = XTD;
obuf[qc++] = IMMED;
obuf[qc++] = DEREF1|xsize;
write_obuf(iv, obuf, qc);
++iv->stackdepth;
}
else
{
obuf[0] = DUMP;
write_obuf(iv, obuf, 1);

if(r->opsize == B8)
obuf[qc++] = XTD;
obuf[qc++] = IMMED;
obuf[qc++] = DEREF|xsize;
write_obuf(iv, obuf, qc);
}
l->atype &= ~A_MEMADDR;
l->atype |= A_VALUE;

obuf[0] = REGAIN;
write_obuf(iv, obuf, 1);
}
}
}
else
{/* LEFT HAND SIDE IS NOT ON STACK */

data_toevalstack(iv, l, d);
if(r->opsize <= B4 && l->opsize <= B4)
obuf[0] = SWAP4;
else
obuf[0] = SWAP;
write_obuf(iv, obuf, 1);
}
}
else /* ONLY LEFT HAND SIDE CAN BE ON STACK */
{
data_toevalstack(iv, l, d);
data_toevalstack(iv, l, d);
}

/* ENSURE THAT THE RIGHT SIDE IS A LONG OR A LONG LONG */
bestptr = (l->size > 4) ? &longlongtype : &longtype;
if(check_assignment_conversion(bestptr, r))
do_conversion(iv, bestptr, r);

if(l->opsize == B8)
{
obuf[oc++] = XTD;
}
obuf[oc++] = binops[opcode]|get_datasize(opcode, l);
write_obuf(iv, obuf, oc);
--iv->stackdepth;
}/* END: NOT IMMEDIATES */

if(check_assignment_conversion(d, l))
do_conversion(iv, d, l);
l->atype &= ~A_MEMADDR;
l->atype |= A_VALUE;
from_evalstack(iv, d, l);

break;
}/* END: MODULUS */
case truthop:
case aliastmpop:
{/* no immediates */

data_toevalstack(iv, l, d);

if(l->opsize != B1)
{/* no need to get truth of byte sized elements */
if(l->opsize == BX)
{
obuf[oc++] = XTD;
}
obuf[oc++] = TRUTHOF|l->opsize;
write_obuf(iv, obuf, oc);
}
break;
}
case complop:
case notop:
{/* no immediates */
unsigned char osize = get_datasize(opcode, l);

data_toevalstack(iv, l, d);
if(osize == BX)
{/* only notop can operate on long double */
obuf[oc++] = XTD;
}
obuf[oc++] = binops[opcode]|osize;
write_obuf(iv, obuf, oc);
break;
}
case negop:
{/* no immediates */

data_toevalstack(iv, l, d);
if(l->opsize == BX || (l->opsize==B8 && l->dtype != D_FLOAT))
{
obuf[oc++] = XTD;
}
obuf[oc++] = binops[opcode]|get_datasize(opcode, l);
write_obuf(iv, obuf, oc);
break;
}
case copyop:
{
if(d->atype & (A_TEMP|A_RET))
{
if(!(l->atype & (A_TEMP|A_RET)))
{
data_toevalstack(iv, l, d);
}
}
else
{
if(!(l->atype & (A_TEMP|A_RET)))
{
data_toevalstack(iv, d, d);
data_toevalstack(iv, l, d);
}
else
{
data_toevalstack(iv, d, d);
obuf[0] = SWAP4;
write_obuf(iv, obuf, 1);
}
}
load_val(iv, d->size);
obuf[0] = MOVAAC;
write_obuf(iv, obuf, 1);
iv->stackdepth -= 3;
break;
}
case castop:
{
data_toevalstack(iv, l, d);
if(check_assignment_conversion(d, l))
do_conversion(iv, d, l);
break;
}
case jmploopop:
case jmpcontinueop:
case jmpbreakop:
case jmpgotoop:
case ljmptrueop:
case jmptrueop:
case ljmpfalseop:
case jmpfalseop:
case funcstartop:
case funcstopop:
{/* start with max sized jmps, they will be shortened later */
void *fixjmp;
if(opcode == jmptrueop)
{
obuf[0] = JMPT|J4;
--iv->stackdepth;
}
else if(opcode == ljmptrueop)
{
obuf[0] = LJMPT|J4;
}
else if(opcode == jmpfalseop)
{
obuf[0] = JMPF|J4;
--iv->stackdepth;
}
else if(opcode == ljmpfalseop)
{
obuf[0] = LJMPF|J4;
}
else if(opcode == funcstartop || opcode == funcstopop)
{
obuf[0] = LOCATE|J4;
}
else
obuf[0] = JMP|J4;
fixjmp = write_obuf(iv, obuf, 5);
addto_jmplist(iv, p, fixjmp);
break;
}
case clrdatop:
{
addr_toevalstack(iv, d);
data_toevalstack(iv, l, 0);
obuf[0] = XTD;
obuf[1] = CLRDAT;
write_obuf(iv, obuf, 2);
iv->stackdepth -= 2;
break;
}
case getbitfieldop:
{
data_toevalstack(iv, r, d);
obuf[0] = XTD;
obuf[1] = GETBITFIELD;
obuf[2] = l->data->uchr.d[0]; /* shift */
obuf[3] = l->data->uchr.d[1]; /* size */
obuf[4] = l->data->uchr.d[2]; /* sign */
write_obuf(iv, obuf, 5);
break;
}
case putbitfieldop:
{
if(!(d->atype & (A_TEMP|A_RET)))
{/* destination address to stack */
addr_toevalstack(iv, d);

if(!(r->atype & (A_TEMP|A_RET)))
{
data_toevalstack(iv, r, d);
}
else
{/* data was on stack */
obuf[0] = SWAP;
write_obuf(iv, obuf, 1);
}
}
else
{/* destination address is on stack */
data_toevalstack(iv, r, d);
}
if(check_assignment_conversion(d, r))
do_conversion(iv, d, r);

obuf[0] = XTD;
obuf[1] = PUTBITFIELD;
obuf[2] = l->data->uchr.d[0]; /* shift */
obuf[3] = l->data->uchr.d[1]; /* size */
obuf[4] = d->size;
write_obuf(iv, obuf, 5);
iv->stackdepth -= 2;
break;
}
case retstructop:
{
addr_toevalstack(iv, d);
obuf[0] = XTD;
obuf[1] = RETSTRUCT;
*((unsigned short*)&obuf[2]) = l->data->ulng.d[0] >>2; /* size */
*((unsigned short*)&obuf[4]) = l->data->ulng.d[1] >>2; /* offset */
write_obuf(iv, obuf, 6);
break;
}
case retdataop:
case retvoidop:
{
obuf[0] = RET;
write_obuf(iv, obuf, 1);
break;
}
case callfuncop:
{
obuf[0] = XTD;
obuf[1] = CALLSETUP;
*((long*)&obuf[2]) = l->data->ulng.d[0]; /* argsize */
write_obuf(iv, obuf, 6);
break;
}
case switchop:
{
void *fixjmp;
obuf[0] = XTD;
obuf[1] = SWITCH;
*((short*)(&obuf[2])) = d->data->ulng.d[1]; /* swnode */
write_obuf(iv, obuf, 4);

/* Default jmp */
obuf[0] = JMP|D4;
fixjmp = write_obuf(iv, obuf, 5);
addto_jmplist(iv, p, fixjmp);
--iv->stackdepth;
break;
}
case compsavop:
case totmpop:
{
data_toevalstack(iv, l, d);
break;
}
case argop:
{
unsigned char op = arg_toevalstack(iv, l, d->ARGSIZE);
if(!(iv->in_builtin))
{
load_val(iv, d->ARGOFS);
load_val(iv, d->ARGSIZE);
obuf[0] = op;
write_obuf(iv, obuf, 1);
iv->stackdepth -= 3;
}
break;
}
default:
{
#if 0
obuf[0] = NOP;
write_obuf(iv, obuf, 1);
#endif
break;
}
}/* END: switch(opcode) */
if(iv->stackdepth > iv->maxdepth)
iv->maxdepth = iv->stackdepth;
if(iv->stackdepth < iv->mindepth)
iv->mindepth = iv->stackdepth;

return iv->cod_usedtail;
}/* END: gen_inst() */

static void
set_op(PND pnd, PopA ptr, unsigned char otype)
{
unsigned char optype = otype & 0xe0;
unsigned char isize = otype & 0x1f;

pnd->data = (DATUM *)ptr;
if(optype <= OPIMMED4)
{
pnd->dtype = optype >> 5;
pnd->quals = Q_CONST;
pnd->size = isize;
pnd->opsize = get_size(pnd->dtype, isize);
pnd->atype = A_IMMED;
} /* END: OPIMMED */
else
{
unsigned short type = GS(ptr->dtype);
pnd->dtype = type & 0xff;
pnd->quals = (type >> 8) & 0xff;
pnd->size = GL(ptr->dsize);
pnd->opsize = get_size(pnd->dtype, pnd->size);
pnd->atype = GS(ptr->atype);

if(optype == OPAUTO)
{
if(GL(ptr->pofs) >= 0)
{
pnd->atype &= ~A_AUTO;
pnd->atype |= A_PARAM;
}
}
}
}/* END: set_op() */
static void *
decode_anf(Piv iv, unsigned char *p)
{
void *dptr;
void *lptr;
void *rptr;

if(iv->debug >= '4')
cfeprintf("DECODE inst(%u) `%s'\n", *p, oxgenops[*p]);

if(*p == 0)
return POP->next;


iv->ob->p = p;
switch(*p)
{
case regainop:
case grabop:
case retvoidop:
{/* 0 address mode */
break;
}
case jmploopop:
case jmpcontinueop:
case jmpbreakop:
case jmpgotoop:
case ljmptrueop:
case jmptrueop:
case ljmpfalseop:
case jmpfalseop:
case funcstartop:
case funcstopop:
case retdataop:
{/* 1 address mode */
dptr = (p+8);
set_op(&iv->ob->d, dptr, p[1]);
break;
}
case getvalop:
case derefop:
case assignop:
case duptmpop:
case truthop:
case aliastmpop:
case negop:
case complop:
case notop:
case copyop:
case castop:
case clrdatop:
case compsavop:
case totmpop:
case retstructop:
case switchop:
case argop:
{/* 2 address mode */
dptr = (p+8);
lptr = (((char*)dptr) + (p[1] & 0x1f));
set_op(&iv->ob->d, dptr, p[1]);
set_op(&iv->ob->l, lptr, p[2]);
break;
}
case plusop:
case minusop:
case mulop:
case divop:
case modop:
case orop:
case xorop:
case andop:
case eqop:
case neqop:
case ltop:
case gtop:
case leop:
case geop:
case lshop:
case rshop:
case getbitfieldop:
case callfuncop:
case putbitfieldop:
{/* 3 address mode */
dptr = (p+8);
lptr = (((char*)dptr) + (p[1] & 0x1f));
rptr = (((char*)lptr) + (p[2] & 0x1f));
set_op(&iv->ob->d, dptr, p[1]);
set_op(&iv->ob->l, lptr, p[2]);
set_op(&iv->ob->r, rptr, p[3]);
break;
}
default:
{
return POP->next;
}
}/* END: switch(*p) */

/* Save pointers to the machine instructions generated by this ANF code */
iv->ob->startinst = iv->cod;
iv->ob->endinst = gen_inst(iv, iv->ob);

if(iv->cod != iv->ob->startinst)
{/* instructions were generated */
link_ob(iv);
}
return POP->next;
}/* END: decode_anf() */

static void *
skip_bracket(unsigned char *p)
{
long opcode = *p;
int opcount = 0;

for(;;)
{
if(*p == opcode)
++opcount;
else if(*p == endop && GL(POP->data) == opcode)
{
if(--opcount == 0) {
return p;
}
}
else if(*p == endfileop || *p == endallop)
{
PERROR(pName ": Malformed input file3=%u=%p",*p, p);
}
p = POP->next;
}
return 0;
}
static void *
do_strelem(Piv iv, unsigned char *p)
{
void *sp = p;
unsigned char *q = skip_bracket(p);
void *elem[20];
void *elemq[20];
int elemcnt, i;

elemcnt = 0;
p = POP->next;
while(p < q)
{/* Pick up nested elements */
unsigned char opcode = *p;
if(opcode == strelemop || opcode == ptrelemop || opcode == arrayelemop)
{
void *qq = skip_bracket(p);
elem[elemcnt] = p;
elemq[elemcnt++] = qq;
p = qq;
}
p = POP->next;
}

/* Dump the nested elements in the order encountered */
for(i = 0; i < elemcnt; ++i)
{
do_something(iv, elem[i]);
}

/* Dump the remainder of bracket */
p = sp;
elemcnt = 0;
p = POP->next;
while(p < q)
{
unsigned char opcode = *p;
if(opcode == strelemop || opcode == ptrelemop || opcode == arrayelemop)
p = ((Pop)elemq[elemcnt++])->next;
else
p = do_something(iv, p);
}
return ((Pop)q)->next;
}
static void *
do_ptrelem(Piv iv, unsigned char *p)
{
void *sp = p;
unsigned char *q = skip_bracket(p);
void *elem[20];
void *elemq[20];
int elemcnt, i;

elemcnt = 0;
p = POP->next;
while(p < q)
{/* Pick up nested elements */
unsigned char opcode = *p;
if(opcode == arrayelemop || opcode == ptrelemop || opcode == strelemop)
{
void *qq = skip_bracket(p);
elem[elemcnt] = p;
elemq[elemcnt++] = qq;
p = qq;
}
p = POP->next;
}

/* Dump the nested elements in the order encountered */
for(i = 0; i < elemcnt; ++i)
{
do_something(iv, elem[i]);
}

/* Dump the remainder of bracket */
p = sp;
elemcnt = 0;
p = POP->next;
while(p < q)
{
unsigned char opcode = *p;
if(opcode == arrayelemop || opcode == strelemop || opcode == ptrelemop)
p = ((Pop)elemq[elemcnt++])->next;
else
p = do_something(iv, p);
}
return ((Pop)q)->next;
}
static void *
do_arrayelem(Piv iv, unsigned char *p)
{/* Arrange output for the stack machine */
void *sp = p;
unsigned char *q = skip_bracket(p);
void *sadims[10];
void *sadimsq[10];
void *spdims[10];
void *spdimsq[10];
void *elem[20];
void *elemq[20];
int sacnt, spcnt, elemcnt, i;

/* Scan over the bracket and pick up the dimension computations */
elemcnt= sacnt = spcnt = 0;
p = POP->next;
while(p < q)
{
unsigned char opcode = *p;
if(opcode == arraydimsop)
{
void *qq = skip_bracket(p);
sadims[sacnt] = p;
sadimsq[sacnt++] = qq;
p = qq;
}
else if(opcode == ptrdimsop)
{
void *qq = skip_bracket(p);
spdims[spcnt] = p;
spdimsq[spcnt++] = qq;
p = qq;
}
else if(opcode==arrayelemop || opcode==ptrelemop || opcode==strelemop)
{
void *qq = skip_bracket(p);
elem[elemcnt] = p;
elemq[elemcnt++] = qq;
p = qq;
}
p = POP->next;
}

/* Dump the dimension computations in stack order */
for(i = spcnt-1; i >= 0; --i)
{
do_bracket(iv, spdims[i], spdimsq[i]);
}
for(i = sacnt-1; i >= 0; --i)
{
do_bracket(iv, sadims[i], sadimsq[i]);
}

/* Dump the nested elements in the order encountered */
for(i = 0; i < elemcnt; ++i)
{
do_something(iv, elem[i]);
}

/* Dump the remainder of the bracket */
p = sp;
elemcnt = sacnt = spcnt = 0;
p = POP->next;
while(p < q)
{
unsigned char opcode = *p;
if(opcode == arraydimsop)
p = ((Pop)sadimsq[sacnt++])->next;
else if(opcode == ptrdimsop)
p = ((Pop)spdimsq[spcnt++])->next;
else if(opcode==arrayelemop || opcode==ptrelemop || opcode==strelemop)
p = ((Pop)elemq[elemcnt++])->next;
else
p = do_something(iv, p);
}
return ((Pop)q)->next;
}
static int
funcret_used(PopT op, unsigned char *p)
{
long tmpnum;
if( op->dtype == 0
&& op->dsize == 0)
{
return 1; /* void function */
}
tmpnum = op->tmpnum;

while(*p != funcexitop)
{
if(*p && *p <= (unsigned char)100)
{
unsigned char *qp = p+8;
if(*p == callfuncop)
{/* function using same temp */
if(GL(((PopT)qp)->tmpnum) == tmpnum)
{
return 1; /* not used earlier */
}
}
else
{
if((p[1]&0xe0) == OPRET)
{
if(GL(((PopT)qp)->tmpnum) == tmpnum)
{
return 0; /* ret used */
}
}
qp += p[1]&0x1f;
if((p[2]&0xe0) == OPRET)
{
if(GL(((PopT)qp)->tmpnum) == tmpnum)
{
return 0; /* ret used */
}
}
qp += p[2]&0x1f;
if((p[3]&0xe0) == OPRET)
{
if(GL(((PopT)qp)->tmpnum) == tmpnum)
{
return 0; /* ret used */
}
}
}
}
p = POP->next;
}
return 1; /* ret not used */
}
static unsigned char
check_for_builtin(Piv iv, unsigned char *p, int flag)
{
short symnum;
long key[2];
unsigned char *result;

if(flag == 0)
{
symnum = GS(((PopA)(p+20))->symnum);
}
else if(flag == 1)
{
symnum = GS(((PopI)(p+16))->s.symnum);
}
else if(flag == 2)
{
symnum = GS(POPI->s.symnum);
}
else return 0;

key[0] = symnum;
key[1] = 0;
if(SymFind(iv->builtintbl, key, &result))
return *result;
return 0;
}
static void *
do_funcall(Piv iv, unsigned char *p)
{/* Arrange output for the stack machine */
char obuf[4];
void *sp = p;
unsigned char *q = skip_bracket(p);
int argcnt, i, dump;
void *argloads[100];
void *argloadsq[100];
char *callop = 0;
unsigned char builtin = 0;

/* Scan over the bracket and pick up argument loads */
argcnt = 0;
p = POP->next;
while(p < q)
{
if(*p == getvalop && callop == 0)
{
builtin = check_for_builtin(iv, p, 0);
}
else if(*p == callfuncop)
callop = p;
else if(*p == argloadop)
{
void *qq = skip_bracket(p);
argloads[argcnt] = p;
argloadsq[argcnt++] = qq;
p = qq;
}
p = POP->next;
}

/* Check out whether the function return is used */
dump = funcret_used((PopT)(callop+8), q);

/* Calling an interpreter builtin ?? */
if(builtin)
{
iv->in_builtin = 1;

/* Dump the argument loads in order */
/* The ARG instruction will be suppressed because iv->in_builtin > 0 */
for(i = 0; i < argcnt; ++i)
{
do_bracket(iv, argloads[i], argloadsq[i]);
}
iv->stackdepth -= argcnt;

/* Generate the BUILTIN instruction */
i = 3;
++iv->stackdepth;
obuf[0] = XTD;
obuf[1] = BUILTIN;
obuf[2] = builtin;
if(dump)
{
obuf[3] = DUMP;
--iv->stackdepth;
i = 4;
}
write_obuf(iv, obuf, i);
iv->in_builtin = 0;
}
else
{
/* Generate the CALLSETUP instruction */
p = sp;
p = POP->next;
while(p < q)
{
if(*p == argloadop)
break;
else
p = do_something(iv, p);
}

/* Dump the argument loads in order */
for(i = 0; i < argcnt; ++i)
{
do_bracket(iv, argloads[i], argloadsq[i]);
}
/* Generate the CALL instruction */
i = 1;
obuf[0] = CALL;
if(dump)
{
obuf[1] = DUMP;
--iv->stackdepth;
i = 2;
}
write_obuf(iv, obuf, i);
if((GL(((Pop)(callop))->data1) & 0xff) == D_STRUCT)
{
++iv->has_structret;
}
}
return ((Pop)q)->next;
}
static void *
do_expr(Piv iv, unsigned char *p)
{
unsigned char *q = skip_bracket(p);

if(iv->debug >= '2')
cfeprintf("EXPR inst(%u) `%s'\n", *p, oxgenops[*p]);

while(p < q)
{
switch(*p)
{
case arrayelemop:
p = do_arrayelem(iv, p);
break;
case strelemop:
p = do_strelem(iv, p);
break;
case ptrelemop:
p = do_ptrelem(iv, p);
break;
case funcallop:
p = do_funcall(iv, p);
break;
case condop:
case twopathop:
case logicalop:
case binopop:
case argloadop:
case preincrdecop:
case postincrdecop:
case compoundop:
case unopop:
p = POP->next;
break;
default:
p = do_something(iv, p);
break;
}
}
return ((Pop)q)->next;
}
static void *
do_expstmt(Piv iv, unsigned char *p)
{
unsigned char *q = skip_bracket(p);

p = POP->next;
while(p < q)
{
p = do_something(iv, p);
}
return q;
}
static void *
do_ifstmt(Piv iv, unsigned char *p)
{
unsigned char *q = skip_bracket(p);

p = POP->next;
while(p < q)
{
p = do_something(iv, p);
}

return ((Pop)q)->next;
}
static void *
do_ifelsestmt(Piv iv, unsigned char *p)
{
unsigned char *q = skip_bracket(p);

p = POP->next;
while(p < q)
{
p = do_something(iv, p);
}

return ((Pop)q)->next;
}
static void *
do_switchstmt(Piv iv, unsigned char *p)
{
unsigned char *q = skip_bracket(p);

p = POP->next;
while(p < q)
{
p = do_something(iv, p);
}

return ((Pop)q)->next;
}
static void *
do_whilestmt(Piv iv, unsigned char *p)
{
unsigned char *q = skip_bracket(p);

p = POP->next;
while(p < q)
{
p = do_something(iv, p);
}
return ((Pop)q)->next;
}
static void *
do_dostmt(Piv iv, unsigned char *p)
{
unsigned char *q = skip_bracket(p);

p = POP->next;
while(p < q)
{
p = do_something(iv, p);
}
return ((Pop)q)->next;
}
static void *
do_forstmt(Piv iv, unsigned char *p)
{
unsigned char *q = skip_bracket(p);

p = POP->next;
while(p < q)
{
p = do_something(iv, p);
}
return ((Pop)q)->next;
}
static void *
do_asmstmt(Piv iv, unsigned char *p)
{
unsigned char *q = skip_bracket(p);

p = POP->next;
while(p < q)
{
p = do_something(iv, p);
}
return ((Pop)q)->next;
}
static void *
do_initstmt(Piv iv, unsigned char *p)
{
unsigned char *q = skip_bracket(p);

p = POP->next;
while(p < q)
{
p = do_something(iv, p);
}
return ((Pop)q)->next;
}
static void *
do_anfblock(Piv iv, unsigned char *p)
{
unsigned char *q = skip_bracket(p);

p = POP->next;
while(p < q)
{
p = do_something(iv, p);
}
return ((Pop)q)->next;
}
static char *
nodot(Piv iv, char *name)
{
char *cp;
if((cp = strchr(name, '.')))
{
char *newname;
newname = Cmalloc(iv->category, strlen(name)+1);
strcpy(newname,name);
cp = strchr(newname, '.');
*cp = 0;
return newname;
}
return name;
}
static void
printfunc(Piv iv, unsigned char *p)
{
char *funcname = nodot(iv, iv->symaddr[GS(POPI->funcdef.symnum)]);

if(*p == gfuncdefop)
{
fprintf(iv->outfile, "\n%8.8x: .global .function _%s\n",
iv->out_offset, funcname);
}
else if(*p == sfuncdefop)
{
fprintf(iv->outfile, "\n%8.8x: .local .function _%s\n",
iv->out_offset, funcname);
}
}
static void *
do_stmt(Piv iv, unsigned char *p)
{
void *q;

if(iv->debug >= '2')
cfeprintf("STMT inst(%u) `%s'\n", *p, oxgenops[*p]);

q = POP->next;

switch(*p)
{
case labelop:
newlabel_insert(iv, GL( POP->data));
break;
case gfuncdefop:
case sfuncdefop:
case funcexitop:
PERROR(pName ": Malformed input file1=%u=%p",*p, p);
case nestedfuncdefop:
{
if(iv->listing_wanted)
{
char obuf[8];
obuf[0] = NFUNC;
*((char**)&obuf[1]) = nodot(iv, iv->symaddr[GS(POPI->funcdef.symnum)]);
write_obuf(iv, obuf, 5);
}
iv->numnested += 1;
break;
}
case nestedfuncexitop:
{
char obuf[2];
obuf[0] = RET;
write_obuf(iv, obuf, 1);
break;
}
case anfblockop:
q = do_anfblock(iv, p);
break;
case expstmtop:
q = do_expstmt(iv, p);
break;
case ifstmtop:
q = do_ifstmt(iv, p);
break;
case ifelsestmtop:
q = do_ifelsestmt(iv, p);
break;
case switchstmtop:
q = do_switchstmt(iv, p);
break;
case whilestmtop:
q = do_whilestmt(iv, p);
break;
case dostmtop:
q = do_dostmt(iv, p);
break;
case forstmtop:
q = do_forstmt(iv, p);
break;
case asmstmtop:
q = do_asmstmt(iv, p);
break;
case initstmtop:
q = do_initstmt(iv, p);
break;
case lineop:
if(iv->debug >= '3')
{
cfeprintf("Line=%u depth=%d\n", GL(POP->data), iv->stackdepth);
}
if(iv->listing_wanted)
{
char obuf[8];
obuf[0] = LINENO;
*((long*)&obuf[1]) = GL(POP->data);
write_obuf(iv, obuf, 5);
}
iv->lastline = GL(POP->data);
break;
default:
break;
}
return q;
}
static void *
do_something(Piv iv, unsigned char *p)
{
if(*p < labelop)
return decode_anf(iv, p);
else if(*p >= condop && *p < symbop)
return do_expr(iv, p);
else
return do_stmt(iv, p);
}
static void
do_bracket(Piv iv, unsigned char *p, unsigned char *q)
{
p = POP->next;
while(p < q)
{
p = do_something(iv, p);
}
}
static void *
dumpa_func(Piv iv, unsigned char *p)
{
unsigned char obuf[2];
Pafile pf;
unsigned char *pdef = p;

iv->ob = new_nodeO(iv); /* setup first intermediate output node */
link_ob(iv); /* null node never unlinked */
iv->first_ob = iv->ob_usedtail;

iv->cod = new_nodeC(iv); /* setup first code node */
link_cod(iv); /* null node never unlinked */
iv->first_cod = iv->cod_usedtail;

pf = iv->files[iv->filenum];
if(iv->listing_wanted)
{
printfunc(iv, p);
}
p = POP->next;

for(;;)
{
if(*p == funcexitop)
{
obuf[0] = RET;
write_obuf(iv, obuf, 1);
write_funcdata(iv, pdef);
break;
}
else
p = do_something(iv, p);
}
save_extlocs(iv);
reset_funcdata(iv);
return p;
}
static void
dump_funcs(Piv iv)
{
long pad;
Pafile pf;
unsigned char *p;
int i;

#if 0
oxcc_debug(__builtin_iv(),0x40040);
#endif

reset_funcdata(iv);
for(i = 0; i < iv->numfiles; ++i)
{
iv->filenum = i;
pf = iv->files[i];
p = pf->file_p;
if(iv->listing_wanted)
fprintf(iv->outfile, "\n\nFile:%s:\n\n", pf->symaddr[1]);

while(*p != endfileop)
{
if(*p == labelop)
{
newlabel_insert(iv, GL( POP->data ));
}
else if(*p == lineop)
{
iv->lastline = GL(POP->data);
if(iv->debug >= '3')
{
cfeprintf("Line=%u depth=%d\n", iv->lastline, iv->stackdepth);
}
if(iv->listing_wanted)
fprintf(iv->outfile, "Line:%d:\n", iv->lastline);
}
else if(*p == gfuncdefop || *p == sfuncdefop)
{
p = dumpa_func(iv, p);
}
else if(*p == anfblockop)
{
PERROR(pName ": Sorry, Outer anf blocks not handled.\n");
}
p = POP->next;;
}
}

/* Start the data area on an 8 byte boundary */
if((pad = iv->out_offset & 7))
pad = 8-pad;
iv->out_offset += pad;

if(pad && !iv->listing_wanted)
FILEWRITE(padit, pad);
iv->header->a_text = iv->out_offset;
}
static void
fix_thunks(Piv iv)
{
Pafile pf;
int i;
unsigned char **vp;
unsigned char *p;

for(i = 0; i < iv->numfiles; ++i)
{
iv->filenum = i;
pf = iv->files[i];
if(SymHead(pf->datatbl))
{
while(SymNext(pf->datatbl))
{
SymValue(pf->datatbl, &vp);
p = vp[1];
if(*p == thunkblockop)
{/* rearrange the FUNCTHUNK */
unsigned short mods;
mods = GS(POP->data7);
mods &= 0xc000;
mods |= GS(POP->data9) & 0x1f1f;
PS( POP->data7 ) = mods;
PS( POP->data9) = get_maxdepth(iv, GS( POP->data2 ));
if(mods & Fextern)
{/* Put symbol number in the offset slot */
PL( POP->data5 ) = final_symnum(iv, GS( POP->data2 ));
}
else
{/* Put function offset in the offset slot */
PL( POP->data5 ) = newlabel_fix(iv, GL( POP->data5 ));
}
}
}
}
}
}
static void
printdata(Piv iv, char *sym, char *msg, void *ptr, int size,
long offset, int locid)
{
int x;

x = print8(iv, ptr, size, offset, 0);
if(locid > 0)
fprintf(iv->outfile," _%s.%d (%s)\n", sym, locid, msg);
else
fprintf(iv->outfile," _%s (%s)\n", sym, msg);
while((size -= x) > 0)
{
offset += x;
((char*)ptr) += x;
x = print8(iv, ptr, size, offset, 1);
}
}
static void
printbss(Piv iv, char *sym, int size, int offset, unsigned char prevopcode,
int locid)
{
if(prevopcode == globssop)
fprintf(iv->outfile, "%8.8x: _%s (BSS %d)\n", offset, sym, size);
else
fprintf(iv->outfile, "%8.8x: _%s.%d (bss %d)\n", offset, sym, locid, size);
}
static void
dump_data(Piv iv)
{
struct _val {
unsigned long size;
unsigned char *p;
unsigned char *prevp;
long locid;
};
struct _val *val;
unsigned long *key;
long datsize = 0;
long bsssize = 0;
long curr_offset = iv->out_offset;
unsigned char opcode, prevopcode = 0;

if(SymHead(iv->datatbl))
{
void *savaddr;
if(iv->listing_wanted)
{
fprintf(iv->outfile, "\n\t.data\n\n");
savaddr = iv->symaddr[0];
iv->symaddr[0] = "STRING_";
}
while(SymNext(iv->datatbl))
{
unsigned char *p;
long size;
long pad;
SymKey(iv->datatbl, &key);
SymValue(iv->datatbl, &val);
p = val->p;
opcode = *p;
if(val->prevp)
prevopcode = *(val->prevp);
size = val->size;
if((pad = size & 3)) /* the interpreter requires 4 byte alignment */
pad = 4-pad;

if( opcode == datablockop
|| opcode == mallocblockop
|| opcode == thunkblockop
|| opcode == stringblockop)
{
if(iv->listing_wanted)
{
char *msg;

if( opcode == datablockop
|| opcode == stringblockop)
{
if(prevopcode == glodatop)
msg = "DATA";
else
{
msg = "data";
}
}
else if(opcode == mallocblockop)
{
msg = "alloced";
}
else /* thunkblockop */
{
if(prevopcode == extfuncop)
{
long bu;
if((bu = check_for_builtin(iv, p, 2)))
{
Pft ft = (Pft)(p+24);
ft->funcaddr = bu;
ft->fmods |= Fbuiltin;
ft->fmods &= ~Fextern;
*(val->prevp) = 0xff;
msg = "thunk";
}
else
msg = "EXTHUNK";
}
else if(prevopcode == glofuncop)
msg = "THUNK";
else
{
msg = "thunk";
}
}
printdata(iv, iv->symaddr[GS(POP->data2)],
msg, p+24, size, GL(POP->data1), val->locid);
}
else
{
if(opcode == thunkblockop)
{
if(prevopcode == extfuncop)
{
long bu;
if((bu = check_for_builtin(iv, p, 2)))
{
Pft ft = (Pft)(p+24);
ft->funcaddr = bu;
ft->fmods |= Fbuiltin;
ft->fmods &= ~Fextern;
*(val->prevp) = 0xff;
}
}
}
FILEWRITE(p+24, size);
if(pad > 0)
FILEWRITE(padit, pad);
}
datsize += size+pad;
iv->out_offset += size+pad;
}
else if(opcode == bssblockop)
{
if(iv->listing_wanted)
{
printbss(iv, iv->symaddr[GS(POP->data2)], size,
GL(POP->data1), prevopcode, val->locid);
}
bsssize += size+pad;
}
}
if(iv->listing_wanted)
{
iv->symaddr[0] = savaddr;
}
}
iv->header->a_data = iv->out_offset - curr_offset;
if(datsize != iv->header->a_data)
PERROR(pName,":Syserr: data size incorrect (%d)!=(%d)\n",
datsize, iv->header->a_data);
}
static void
dump_bss(Piv iv)
{
iv->header->a_bss = iv->total_size - iv->bss_offset;
}
static void
make_final_string_pack(Piv iv)
{
long strsize = 0;
int strcnt = 0;
char *pack;
char *cp;
struct {
char *str;
long symnum;
long symofs;
} *val;

if(SymHead(iv->finalsymtbl))
{
while(SymNext(iv->finalsymtbl))
{
SymValue(iv->finalsymtbl, &val);
++strcnt;
val->symofs = strsize+4;
strsize += strlen(val->str)+2;
}
}
pack = Ccalloc(iv->category, 1, strsize+4);
*((long*)pack) = strsize + 4;
cp = pack + 4;
if(SymHead(iv->finalsymtbl))
{
while(SymNext(iv->finalsymtbl))
{
SymValue(iv->finalsymtbl, &val);
*cp++ = '_';
strcpy(cp, val->str);
cp += strlen(val->str)+1;
}
}
iv->finalstringpack = pack;
iv->finalpacksize = strsize+4;
}
static unsigned char *
dump_switch(Piv iv, unsigned char *p, int filenum)
{
struct nlist nl;
unsigned char *q = skip_bracket(p);

nl.n_type = N_SWTAB;
nl.n_other = 0;
while(p < q)
{
if(*p == switchidop)
{
nl.n_desc = GS(POP->data1); /* id */
}
else if(*p == casevalop)
{
long key[2];
long *result;
nl.n_un.n_strx = GL(POP->data1); /* value */
key[0] = GL(POP->data); /* label number */
key[1] = filenum;
if(SymFind(iv->newlabeltbl, &key, &result))
{
nl.n_value = *result; /* offset */
}
else
{
PERROR(pName ":Syserr: case label not found\n");
}
if(iv->listing_wanted)
{
/* print nothing */
}
else
{
FILEWRITE(&nl, sizeof(struct nlist));
iv->out_offset += sizeof(struct nlist);
}
}
p = POP->next;
}
return ((Pop)q)->next;
}
static void
dump_symbols(Piv iv)
{
long curr_offset = iv->out_offset;
int i;
struct nlist nl;

nl.n_other = 0;
nl.n_desc = 0;

make_final_string_pack(iv);

if(SymHead(iv->gbltbl))
{
if(iv->listing_wanted)
{
fprintf(iv->outfile, "\n\t.symbols\n\n");
}
while(SymNext(iv->gbltbl))
{
struct _gloval *valp;
unsigned char opcode;

SymValue(iv->gbltbl, &valp);
if((opcode = *(valp->p)))
{
PopI pp;
pp = (PopI) (((Pop)(valp->p))->next+8);
nl.n_un.n_strx = final_strofs(iv, valp->symname);
if(opcode == glodatop)
{
nl.n_type = N_DATA|N_EXT;
nl.n_value = pp->s.offset + iv->header->a_text;
}
else if(opcode == globssop)
{
nl.n_type = N_BSS|N_EXT;
nl.n_value = pp->s.offset + iv->header->a_text;
}
else if(opcode == glofuncop || opcode == extfuncop)
{/* The symbol is really a thunk in the data section */
nl.n_type = N_NDC|N_EXT;
nl.n_value = pp->s.offset;
}
else if(opcode == extvarop)
{
nl.n_type = N_UNDF|N_EXT;
nl.n_value = 0;
}
else if(opcode == 0xff)
{/* Builtin thunk */
continue;
}
if(iv->listing_wanted)
{
int symval = nl.n_value;
if(nl.n_type & (N_DATA|N_BSS))
symval -= iv->header->a_text;
fprintf(iv->outfile, "%8.8x: _%s\n", symval, valp->symname);
}
else
{
FILEWRITE(&nl, sizeof(struct nlist));
}
iv->out_offset += sizeof(struct nlist);
}
}
}
/* DUMP SWITCH TABLE INFO */
for(i = 0; i < iv->numfiles; ++i)
{
Pafile pf = iv->files[i];
unsigned char *p;
if((p = pf->switch_p))
{
while(*p != endfileop)
{
if(*p == switchidop)
{
p = dump_switch(iv, p, i);
}
else p = POP->next;
}
}
}
iv->header->a_syms = iv->out_offset - curr_offset;;
}/* END: dump_symbols() */

static void
dump_text_relocs(Piv iv)
{
long curr_offset = iv->out_offset;
PEL pel = iv->finextbufstart;
struct relocation_info r;

r.r_pcrel = 0;
r.r_extern = 1;
r.r_length = 2;
r.r_pad = 0;
if(pel && iv->listing_wanted)
{
fprintf(iv->outfile,"\n\t.textrels\n\n");
}
while(pel)
{
r.r_symbolnum = final_symnum(iv, pel->symnum);
r.r_address = pel->spot;
if(pel->symnum > 0)
{
if(iv->listing_wanted)
{
fprintf(iv->outfile,"%8.8x: .extern _%s\n",
r.r_address, iv->symaddr[pel->symnum]);
}
else
{
FILEWRITE(&r, sizeof(struct relocation_info));
}
iv->out_offset += sizeof(struct relocation_info);
}
pel = pel->next;
}
iv->header->a_trsize = iv->out_offset - curr_offset;

}/* END: dump_text_relocs() */

static void
dump_data_relocs(Piv iv)
{
long curr_offset = iv->out_offset;
struct relocation_info r;

r.r_pcrel = 0;
r.r_length = 2;
r.r_pad = 0;
if(SymHead(iv->reloctbl))
{
if(iv->listing_wanted)
{
fprintf(iv->outfile,"\n\t.datarels\n\n");
}
while(SymNext(iv->reloctbl))
{
struct _rkey *kp;
struct _rval *vp;
unsigned char *p;
int symnum;
SymKey(iv->reloctbl, &kp);
SymValue(iv->reloctbl, &vp);
p = vp->p; /* pointer to relocop in input buffer */
symnum = GS(POPI->reloc.rsym);

if(kp->rsize == 1)
r.r_length = 0;
else if(kp->rsize == 2)
r.r_length = 1;
else if(kp->rsize == 4)
r.r_length = 2;
else PERROR(pName ":error: reloc size too large\n");

r.r_address = GL( POPI->reloc.spot );
if(*p == extlocop)
{/* External variable */
r.r_extern = 1;
r.r_symbolnum = final_symnum(iv, symnum);
}
else if(*p)
{
r.r_extern = 0;
r.r_symbolnum = N_DATA;
}
if(*p)
{
if(iv->listing_wanted)
{
if(r.r_extern)
{
if(vp->rsym <= 0)
{/* an absolute value */
continue;
}
fprintf(iv->outfile,"%8.8x: .extern _%s\n",
r.r_address, iv->symaddr[symnum]);
}
else
{
fprintf(iv->outfile, "%8.8x: .segrel\n", r.r_address);
}
}
else
{
if(r.r_extern && vp->rsym <= 0)
{/* an absolute value */
continue;
}
FILEWRITE(&r, sizeof(struct relocation_info));
}
iv->out_offset += sizeof(struct relocation_info);
}
}
}
iv->header->a_drsize = iv->out_offset - curr_offset;

}/* END: dump_data_relocs() */

static void
prepare_data_relocs(Piv iv)
{
if(SymHead(iv->reloctbl))
{
while(SymNext(iv->reloctbl))
{
struct _rkey *kp;
struct _rval *vp;
unsigned char *p;
SymKey(iv->reloctbl, &kp);
SymValue(iv->reloctbl, &vp);
p = vp->p; /* pointer to relocop in input buffer */

if(*p == extlocop)
{/* External variable */
}
else if(*p)
{/* a.out format requires a flat address space for relocations */
if(kp->rsize == 1)
{
*((char*)vp->base) += iv->header->a_text;
}
else if(kp->rsize == 2)
{
*((short*)vp->base) += iv->header->a_text;
}
else if(kp->rsize == 4)
{
*(vp->base) += iv->header->a_text;
}
else PERROR(pName ":error: reloc size too large\n");

}
}

}
}/* END: prepare_data_relocs() */

static void
dump_symbol_strings(Piv iv)
{
if(iv->listing_wanted)
{
/* print nothing */
}
else
{
FILEWRITE(iv->finalstringpack, iv->finalpacksize);
}
}/* END: dump_symbol_strings() */

static int
gen_output(Piv iv, char *outpath)
{/* Bytecode output */
char *cp;
int i;
char outname[256];

strcpy(outname, outpath);
if((cp = strrchr(outname, '.')))
{
#if 0
if(iv->listing_wanted)
strcpy(cp, ".lst");
else
strcpy(cp, ".byt");
#endif
}
else
{
if(iv->listing_wanted)
strcat(outname, ".lst");
else
strcat(outname, ".byt");
}
for(i = 1; i < iv->argc; ++i)
{
if(!strcmp(outname, iv->argv[i]))
{
PERROR(pName ": ERROR output file `%s' is same as input file\n", outname);
}
}
if(!(iv->outfile = fopen(outname, "wb")))
{
PERROR(pName ": Cannot open output file %s\n", outname);
}

/* Allocate a header struct */
iv->header = Ccalloc(iv->category, 1, sizeof(struct exec));

if(iv->listing_wanted)
{
long tim = time(0);
char *date = ctime(&tim);
fprintf(iv->outfile,"/*\n `%s' %s", outname, date);
fprintf(iv->outfile,notice,MAJOR_VERSION,MINOR_VERSION);
}
else
{/* Seek past the header area */
iv->header->a_info = OMAGIC;
fseek(iv->outfile, sizeof(struct exec), SEEK_SET);
}
install_builtins(iv);
make_final_symtab(iv);

#if 0
if(iv->debug)
bterpdebug();
#endif
dump_funcs(iv);
fix_thunks(iv);
prepare_data_relocs(iv); /* adjust addresses for flat space */
dump_data(iv);
dump_bss(iv);
dump_text_relocs(iv);
dump_data_relocs(iv);
dump_symbols(iv);
dump_symbol_strings(iv);

/* Update the header block */
if(!iv->listing_wanted)
{
fseek(iv->outfile, 0, SEEK_SET);
FILEWRITE(iv->header, sizeof(struct exec));
}
fclose(iv->outfile);
iv->outfile = 0;
return iv->errors;
}
/* ======================= END BYTECODE OUTPUT GENERATOR ==================== */

/* ===================== GENERIC CODE BELOW THIS POINT ================== */
static jmp_buf run_env;
static void
prerror(const char *fmt, ...)
{
VFPRINTF(fmt, (char *)(((int *)(&fmt))+1));
longjmp(run_env, 3);
}
static void
prwarn(const char *fmt, ...)
{
VFPRINTF(fmt, (char *)(((int *)(&fmt))+1));
}
static void
info(const char *fmt, ...)
{
vfprintf(stdout, fmt, (char *)(((int *)(&fmt))+1));
}
/* ========================= MULTI HEAP MALLOC ========================== */
/*
NOTE: In a demand paged environment, this implementation of malloc
(using skip_lists) can be ENORMOUSLY faster than buddy_block
style mallocs.
*/

static void *do_sbrk(unsigned amount);


#define ALIGNMENTM (sizeof(int))
#define MAL_MAXLEVEL (12)
#define ROUNDING(a) ((ALIGNMENTM-((a)&(ALIGNMENTM-1)))&(ALIGNMENTM-1))
#define ALLOCSIZE (4096)
#define GUARDWORD (0xa7b3a7b3)
#define THEWELL do_sbrk

#define NUMTYPES 3
#define SIZEH 0
#define FREEH 1
#define USEDH 2

#define SKIPVARS NodePM update[MAL_MAXLEVEL+1];NodePM node,prev;int level

#define DELETENODE(TYPE) \
{for(level=0;level<=bp->TYPE##level; level++)\
{if(update[level]->fptr[level] == node)\
update[level]->fptr[level] = node->fptr[level];else break;}\
while(bp->TYPE##level>0 && bp->TYPE##header->fptr[bp->TYPE##level]==_NIL)\
bp->TYPE##level--;free_Mnode(bp,node,TYPE);}

#define INSERT() \
{while(level >= 0){\
node->fptr[level] = update[level]->fptr[level];\
update[level]->fptr[level] = node;level--;}}

#define SETLEVEL(TYPE) \
{level = getMlevel(bp, bp->TYPE##level);\
while(bp->TYPE##level < level)update[++bp->TYPE##level]=bp->TYPE##header;}

#define FINDKEY(TYPE, KEYVAL)\
{node = bp->TYPE##header;\
for(level = bp->TYPE##level; level >= 0; level--){\
while(node->fptr[level]->key < KEYVAL)\
node = node->fptr[level];\
update[level] = node;}prev=node;node=node->fptr[0];}

#define DETACH(SN)\
{SN->bptr->fptr=SN->fptr;if(SN->fptr)SN->fptr->bptr=SN->bptr;}

#define UNLINK(SN, N)\
{if(!sp->fptr&&sp->bptr->bptr<=(AddrP)(MAL_MAXLEVEL+1))dsize[N]=sp->size;\
DETACH(SN);free_addr(bp,SN);}

#define CHECKGUARDS(MSG)\
{if(bp->guarded){\
unsigned *p2;\
p2 = (void*)((char*)address+cursize-ALIGNMENTM);\
if(*address != (unsigned)GUARDWORD)\
PERROR(pName #MSG ": heap(%d) corrupted at 0x%x\n", bp->bincat, addr);\
if(*p2 != ~((unsigned)GUARDWORD))\
PERROR(pName #MSG ": heap(%d) corrupted by 0x%x\n", bp->bincat, addr);}}

struct _catlocs {
void *addr;
struct _catlocs *fptr;
};

typedef struct _nodeM
{
unsigned key;
unsigned value;
unsigned levels; /* must always be after value */
struct _nodeM *fptr[1];
} NodeM, *NodePM;

typedef struct _addr
{
struct _addr *fptr;
struct _addr *bptr;
NodePM maddr;
unsigned size;
} *AddrP;

struct _bins {
unsigned bits;
unsigned nbits;
NodePM SIZEHheader;
int SIZEHlevel;
NodePM FREEHheader;
int FREEHlevel;
NodePM USEDHheader;
int USEDHlevel;

unsigned bincat;
unsigned maxloc;
unsigned minloc;
struct _catlocs *catlocs;
struct _bins *fptr;
NodePM freenodes[NUMTYPES][MAL_MAXLEVEL+2];
struct _addr *freeaddrlocs;
char *chunkbase[NUMTYPES];
int chunksize[NUMTYPES];
int guarded;
int addrbump;
int overhead;
};

static struct _bins zbp;
static struct _bins *hmap[1009];
static struct _nodeM _nil = {0xffffffff,0,0,{0}};
static struct _nodeM *_NIL = &_nil;
static unsigned maxloc;
static unsigned minloc;
static struct _bins *freebinlocs;
static struct _catlocs *freecatlocs;
static char *binbase;
static int binsize;
static int chunksizes[] = {ALLOCSIZE,3*ALLOCSIZE,2*ALLOCSIZE};


#include "lrandom.c"

static struct _catlocs *
new_catloc(void)
{
struct _catlocs *p;
if((p=freecatlocs))
{
freecatlocs = p->fptr;
return p;
}
if(binsize < sizeof(struct _catlocs))
{
binbase = THEWELL(4096);
binsize = 4096;
}
binsize -= sizeof(struct _catlocs);
p = (void*)binbase;
binbase += sizeof(struct _catlocs);
return p;
}
static void
free_catloc(struct _catlocs *p)
{
p->fptr = freecatlocs;
freecatlocs = p;
}
static void *
new_chunk(struct _bins *bp, int size, int type)
{
char *p;
if(bp->chunksize[type] < size)
{
if(bp->bincat == 0) {
bp->chunkbase[type] = THEWELL(chunksizes[type]);
bp->chunksize[type] = chunksizes[type];
}
else {
struct _catlocs *cl;
bp->chunkbase[type] = Cmalloc(0,chunksizes[type]-zbp.overhead);
bp->chunksize[type] = chunksizes[type]-zbp.overhead;
cl = new_catloc();
cl->addr = bp->chunkbase[type];
cl->fptr = bp->catlocs;
bp->catlocs = cl;
}
}
bp->chunksize[type] -= size;
p = bp->chunkbase[type];
bp->chunkbase[type] += size;
return p;
}
static void *
new_Mnode(struct _bins *bp, int levels, int type)
{
int size;
NodePM p;

if((p=bp->freenodes[type][levels]))
{
bp->freenodes[type][levels] = p->fptr[0];
p->value = 0;
return p;
}
size = sizeof(struct _nodeM) + levels * sizeof(void*);
p = new_chunk(bp, size, type);
p->levels = levels;
p->value = 0;
return p;
}
static void
free_Mnode(struct _bins *bp, NodePM p, int type)
{
p->fptr[0] = bp->freenodes[type][p->levels];
bp->freenodes[type][p->levels] = p;
}
static struct _addr *
new_addr(struct _bins *bp)
{
struct _addr *p;
if((p=bp->freeaddrlocs))
{
bp->freeaddrlocs = p->fptr;
return p;
}
return new_chunk(bp, sizeof(struct _addr), FREEH);
}
static void
free_addr(struct _bins *bp, struct _addr *p)
{
p->fptr = bp->freeaddrlocs;
bp->freeaddrlocs = p;
}
static struct _bins *
new_bins(void)
{
struct _bins *p;
if((p=freebinlocs))
{
freebinlocs = p->fptr;
return p;
}
if(binsize < sizeof(struct _bins))
{
binbase = THEWELL(4096);
binsize = 4096;
}
binsize -= sizeof(struct _bins);
p = (struct _bins*)binbase;
binbase += sizeof(struct _bins);
return p;
}
static void
free_bins(struct _bins *p)
{
p->fptr = freebinlocs;
freebinlocs = p;
}
static int
getMlevel (struct _bins *p, int binlevel)
{
int level = -1;
int bits = 0;

while(bits == 0)
{
if (p->nbits == 0)
{
p->bits = lrandom();
p->nbits = 15;
}
bits = p->bits & 3;
p->bits >>= 2;
p->nbits--;

if(++level > binlevel)
break;
}
return (level > MAL_MAXLEVEL) ? MAL_MAXLEVEL : level;
}

static void
init_bins(struct _bins *bp, unsigned category)
{
int i;
int binnum = category % 1009;

bzero(bp, sizeof(struct _bins));
bp->bincat = category;
bp->minloc = 0xffffffff;
bp->fptr = hmap[binnum];
hmap[binnum] = bp;
bp->SIZEHheader = new_Mnode(bp, MAL_MAXLEVEL+1, SIZEH);
bp->FREEHheader = new_Mnode(bp, MAL_MAXLEVEL+1, FREEH);
bp->USEDHheader = new_Mnode(bp, MAL_MAXLEVEL+1, USEDH);

for(i = 0; i <= MAL_MAXLEVEL; ++i)
{
bp->SIZEHheader->fptr[i] = _NIL;
bp->FREEHheader->fptr[i] = _NIL;
bp->USEDHheader->fptr[i] = _NIL;
}
}

static struct _bins*
getcat(unsigned category)
{
struct _bins *hbp;

hbp = hmap[category % 1009];
while(hbp)
{
if(hbp->bincat == category)
return hbp;
hbp = hbp->fptr;
}
return 0;
}
static struct _bins *
initcat(unsigned category)
{
struct _bins *bp;


if(category == 0)
{
bp = &zbp;
if(zbp.SIZEHheader == 0)
init_bins(bp, category);
return bp;
}
/* do this to set zbp.overhead properly on startup */
if(zbp.SIZEHheader == 0)
initcat(0);

if((bp = new_bins()))
{
init_bins(bp, category);
return bp;
}
return 0;
}
static void *
do_sbrk(unsigned amount)
{
void *address;

address = sbrk(amount); /* OR WHATEVER TO ACCESS THE OPERATING SYSTEM */
if(address == (void*)-1)
{
PERROR(pName ": system out of memory\n");
abort();
}
return address;
}
static void *
getspace(struct _bins *bp, unsigned size, unsigned *remainder)
{
unsigned desired;
void *address;

desired = ((size+ALLOCSIZE-1)/ALLOCSIZE)*ALLOCSIZE;
if(bp->bincat == 0)
{
address = THEWELL(desired);
*remainder = desired - size;
}
else
{
struct _catlocs *cl;

if((desired-size) > zbp.overhead)
desired -= zbp.overhead;

address = Cmalloc(0, desired);
*remainder = desired - size;

/* save the gross allocations for the category */
cl = new_catloc();
cl->addr = address;
cl->fptr = bp->catlocs;
bp->catlocs = cl;
}
/* maintain address range info */
if((unsigned)address < bp->minloc)
bp->minloc = (unsigned)address;
if(((unsigned)address + desired) > bp->maxloc)
bp->maxloc = (unsigned)address + desired;
if(bp->minloc < minloc)
minloc = bp->minloc;
if(bp->maxloc > maxloc)
maxloc = bp->maxloc;
return address;
}
static void
addto_sizelist(struct _bins *bp, AddrP ap)
{
SKIPVARS;

/* INSERT IN SIZE LIST */
FINDKEY(SIZEH, ap->size)

if(node->key == ap->size)
{/* size node exists */
ap->fptr = (AddrP)node->value;
ap->bptr = (AddrP)&node->value;
if(ap->fptr) ap->fptr->bptr = ap;
node->value = (unsigned)ap;
}
else
{/* create new size node */
SETLEVEL(SIZEH)
node = new_Mnode(bp, level, SIZEH);
node->key = ap->size;
node->value = (unsigned)ap;
ap->fptr = 0;
ap->bptr = (AddrP)&node->value;
INSERT()
}
}
static void
addto_freelist(struct _bins *bp, void *addr, unsigned size)
{
SKIPVARS;
AddrP ap,sp;
unsigned dsize[2];

/* GET NEW ADDR STRUCT */
ap = new_addr(bp);
ap->size = size;

dsize[1] = dsize[0] = 0; /* sizenode deletion markers */

/* CHECK FREE LIST */
FINDKEY(FREEH, (unsigned)addr)

/* CHECK FOR MERGE OR INSERT */
if(prev->value && prev->key+((AddrP)prev->value)->size == (unsigned)addr)
{/* merge with previous block */
ap->size += ((AddrP)prev->value)->size;

if(prev->key + ap->size == node->key)
{/* merge with previous and next block */
sp = (AddrP) node->value;;
ap->size += sp->size;

/* delete size struct for next block */
UNLINK(sp, 0)

/* delete next block */
DELETENODE(FREEH);
}
/* delete size struct for prev block */
sp = (AddrP)prev->value;
UNLINK(sp, 1)

/* set new address struct */
prev->value = (unsigned)ap;
ap->maddr = prev;
}
else if(node->value && (char*)addr + size == (void*)node->key)
{/* merge with next block */
sp = (AddrP) node->value;;
node->key = (unsigned)addr;
ap->size += sp->size;

/* unlink size struct for next block */
UNLINK(sp,0)

/* set new address struct */
node->value = (unsigned)ap;
ap->maddr = node;
}
else
{/* insert in free list */

SETLEVEL(FREEH)
node = new_Mnode(bp, level, FREEH);
node->key = (unsigned)addr;
node->value = (unsigned)ap;
ap->maddr = node;
INSERT()
}
addto_sizelist(bp, ap);

/* Remove sizenodes eliminated by merge */
if(dsize[0])
{
FINDKEY(SIZEH, dsize[0])
if(node->value == 0)
DELETENODE(SIZEH)
}
if(dsize[1])
{
FINDKEY(SIZEH, dsize[1])
if(node->value == 0)
DELETENODE(SIZEH)
}
}
static void*
Cmalloc(int category, unsigned size)
{
SKIPVARS;
NodePM fnode;
unsigned remainder;
unsigned *address;
struct _bins *bp;

if(!(bp = getcat(category)))
if(!(bp = initcat(category)))
PERROR(pName ":Cmalloc: Strange error\n");

if(size == 0)
size = ALIGNMENTM;
else
size += ROUNDING(size);
size += bp->guarded;

/* check sizelist for candidate */
FINDKEY(SIZEH, size)
fnode = node;
trynext:
if(node->key != 0xffffffff)
{/* found an appropriately sized block */
AddrP sp = (AddrP)node->value;

if(!sp && node == fnode)
{
NodePM q;
q = node->fptr[0];
DELETENODE(SIZEH)
node = q;
goto trynext;
}
if(!sp)
{/* no available space at this size */
node = node->fptr[0];
goto trynext;
}

/* extract some space from this block */
remainder = node->key - size;
address = (void*)sp->maddr->key;
sp->maddr->key += size;
DETACH(sp);

if(node->value == 0)
{/* no more blocks of this size, delete sizenode */
if(node != fnode)
FINDKEY(SIZEH, size)
DELETENODE(SIZEH)
}

if(remainder == 0)
{/* no remaining space,the node in freelist is exhausted, delete it */
FINDKEY(FREEH, sp->maddr->key)
DELETENODE(FREEH)
free_addr(bp, sp);
}
else
{/* space remains in block, move it to new size loc */
sp->size = remainder;
addto_sizelist(bp, sp);
}
}
else
{
address = getspace(bp, size, &remainder);
if(remainder)
addto_freelist(bp, ((char*)address)+size, remainder);
}
if(bp->guarded)
{
*address = (unsigned)GUARDWORD;
*((unsigned*)(((char*)address)+size-ALIGNMENTM)) = ~((unsigned)GUARDWORD);

}
FINDKEY(USEDH, (unsigned)address)
if(node->key == (unsigned)address) {
PERROR(pName ":Cmalloc: bookkeeping nodes are corrupted at:0x%x\n", address);
}
SETLEVEL(USEDH)
node = new_Mnode(bp, level, USEDH);
node->key = (unsigned)address;
node->value = size;
INSERT()

return address+bp->addrbump;
}
static void*
Ccalloc(int category, unsigned cnt, unsigned elem_size)
{
unsigned size = cnt * elem_size;
void* buf;;

if((buf = Cmalloc(category, size)))
bzero(buf, size);
return buf;
};
static void
Cfree(int category, void* addr)
{
unsigned cursize;
unsigned *address;
struct _bins *bp;
SKIPVARS;

if(addr)
{
if(!(bp = getcat(category)))
PERROR(pName ":Cfree: non-existant category:%d at:0x%x\n",category,addr);

address = (void*)(((char*)addr)-(bp->guarded/2));
FINDKEY(USEDH, (unsigned)address)
if(node->key != (unsigned)address)
PERROR(pName ":Cfree: bogus address=0x%x\n", addr);

cursize = node->value;
CHECKGUARDS(:Cfree)
DELETENODE(USEDH)

addto_freelist(bp, address, cursize);
}
else PERROR(pName ":Cfree: null pointer in category %d\n", category);
}
static void*
Crealloc(int category, void* addr, unsigned newsize)
{
SKIPVARS;
unsigned cursize;
unsigned *address;

struct _bins *bp;
NodePM onode;

if(addr == 0)
return Cmalloc(category, newsize);
else
{
if(!(bp = getcat(category)))
PERROR(pName ":Crealloc: non-existant category:%d at:%x\n",category,addr);

if(newsize == 0)
newsize = ALIGNMENTM;
else
newsize += ROUNDING(newsize);
newsize += bp->guarded;

address = (void*)(((char*)addr)-(bp->guarded/2));
FINDKEY(USEDH, (unsigned)address)
if(node->key != (unsigned)address)
PERROR(pName ":Crealloc: bogus address=0x%x\n", addr);

cursize = node->value;
node->value = newsize;
onode = node;

CHECKGUARDS(:Crealloc)

if(newsize == cursize)
return addr;
if(newsize > cursize)
{/* check if block can be extended */
void *taddr = ((char*)address) + cursize;
unsigned extendsize = newsize-cursize;

/* check freelist for an available block at the right address */
FINDKEY(FREEH, (unsigned)taddr)
if(node->key == (unsigned)taddr)
{
AddrP sp = (AddrP)node->value;
if(sp->size >= extendsize)
{/* BLOCK CAN BE EXTENDED INTERNALLY */
node->key += extendsize;
sp->size -= extendsize;
DETACH(sp)
if(sp->size == 0)
{/* the extension block is used up, delete this node */
free_addr(bp, sp);
DELETENODE(FREEH)
}
else
{/* shift the remainder in the sizelist */
addto_sizelist(bp, sp);
}
/* SUCCESS */
if(bp->guarded)
{
*((unsigned*)(((char*)address)+newsize-ALIGNMENTM))
= ~((unsigned)GUARDWORD);
}
return addr;
}
}
/* HERE WE COULD CHECK OTHER SOURCES OF SPACE */

/* can't extend block, malloc some new space */
if((taddr = Cmalloc(category,newsize-bp->overhead)))
{
memmove(taddr,addr,cursize-bp->overhead);
onode->value = cursize;
Cfree(category, addr);
}
/* SUCCESS */
return taddr;
}
else
{/* shrink block */
if(bp->guarded)
{
*((unsigned*)(((char*)address)+newsize-ALIGNMENTM))
= ~((unsigned)GUARDWORD);
}
addto_freelist(bp, ((char*)address)+newsize, cursize-newsize);
return addr;
}
}
}
static void
Cfreecat(int category)
{
struct _bins *bp;

if(category == 0)
return;

if((bp = getcat(category)))
{
struct _catlocs *cl = bp->catlocs;
struct _bins *hbp;
struct _bins *prev;

while(cl)
{/* Space allocated to the category is moved to category 0 */
void *ql = cl->fptr;

Cfree(0, cl->addr);
free_catloc(cl);
cl = ql;
}
/* space for the _bins struct is placed on a free list */
hbp = hmap[category % 1009];
prev = 0;
while(hbp)
{
if(hbp->bincat == category)
{
if(prev == 0)
hmap[category % 1009] = hbp->fptr;
else
prev->fptr = hbp->fptr;
free_bins(hbp);
return;
}
prev = hbp;
hbp = hbp->fptr;
}
}
}
static int
Cmemrange(int category, unsigned *min, unsigned *max)
{
struct _bins *bp;

if((bp = getcat(category)))
{
*min = bp->minloc;
*max = bp->maxloc;
return 1;
}
return 0;
}
static int
Cusedrange(int category, unsigned *min, unsigned *max)
{
struct _bins *bp;
NodePM node;
int level;

if((bp = getcat(category)))
{
node = bp->USEDHheader;
*min = node->fptr[0]->key;
for(level = bp->USEDHlevel; level >= 0; level--)
while(node->fptr[level]->key < 0xffffffff)
node = node->fptr[level];
*max = node->key;
return 1;
}
return 0;
}
static void
Ctotrange(unsigned *min, unsigned *max)
{
*min = minloc;
*max = maxloc;
}
static int
Cnewcat(void)
{
static int cat;
return ++cat;
}
static void
Cguard(int category)
{
struct _bins *bp;

if(!(bp = getcat(category)))
if(!(bp = initcat(category)))
return;

if(!bp->guarded)
{
bp->guarded = 2*ALIGNMENTM;
bp->addrbump = 1;
bp->overhead += 2*ALIGNMENTM;
}
}
static void*
Ccatcheck(int category, void *start)
{
struct _bins *bp;
NodePM node,prev;
unsigned *p1,*p2;
if((bp = getcat(category)))
{
if(bp->guarded)
{
prev = 0;
node = bp->USEDHheader;
while((node = node->fptr[0]) != (NodePM)0xffffffff)
{
if((void*)node->key > start)
{
p1 = (unsigned*)node->key;
p2 = (void*)((char*)p1+node->value+ALIGNMENTM);
if(*p1 != (unsigned)GUARDWORD)
{
if(prev)
return (char*)prev->key+ALIGNMENTM;
else
return (void*)1;
}
if(*p2 != ~((unsigned)GUARDWORD))
return (char*)node->key+ALIGNMENTM;
}
prev = node;
}
}
}
return 0;
}
/* ====================== END MULTI-HEAP MALLOC ============================ */

/* ====================== SYMBOL TABLE HANDLERS ============================ */

typedef struct _key
{
unsigned long k[2];
unsigned long hv;
} KEY, *KEYP;

typedef struct _nodeS
{/* 40 bytes -- adjust size to suit application */
unsigned long value[4]; /* 16 bytes */
unsigned long key[2]; /* 8 bytes */
struct _nodeS *fptr[4]; /* 16 bytes */
} NodeS, *NodePS;

typedef struct _pbuf
{/* symbol table object */
int nbins; /* number of bins in dictionary */
int lastbin; /* for seq access */
NodePS lastptr; /* ditto */
int category; /* heap number */
char *chunkbase; /* node allocation base */
int chunksize; /* number of bytes available in current chunk */
NodePS freelist; /* list of freed nodes for allocation */
int level; /* sorted level */
int bits; /* sorted bits */
int bitcnt; /* sorted bitcnt */
NodePS header; /* sorted header */

NodePS bins[0]; /* bins if hashed dictionary */
} *PbufP;

#define SYM_MAXLEVEL 12
#define TBL ((PbufP)tbl)

static struct _nodeS _nnil = {{0,0,0,0},{0xffffffff,0xffffffff},{0,0,0,0}};
static struct _nodeS *_NNIL = &_nnil;

static int
getSlevel (PbufP tbl)
{
int level = -1;
int bits = 0;

while (bits == 0)
{
if (tbl->bitcnt == 0)
{
tbl->bits = lrandom();
tbl->bitcnt = 15;
}

bits = tbl->bits & 3;
tbl->bits >>= 2;
tbl->bitcnt--;

if(++level > tbl->level)
break;
}
return (level > SYM_MAXLEVEL) ? SYM_MAXLEVEL : level;

}

static void
hash(void *key, KEY *cat)
{
cat->k[0] = ((unsigned long*)key)[0];
cat->k[1] = ((unsigned long*)key)[1];
cat->hv = ((cat->k[0] ^ cat->k[1]) * 1103515245UL) + 12345;
}
static void
sym_hash(unsigned long *key, char *symb)
{
int len = strlen(symb);
int i;
for(i = 0; i < len; ++i)
((unsigned char *)key)[i & 7] ^= symb[i];
key[0] = ((key[0] ^ key[1]) * 1103515245UL) + 12345;
key[1] = len;
}
static void *
new_Snode(PbufP tbl, int levels)
{
NodePS p;
int size;
if(levels <= 3)
{
if(tbl->freelist)
{
p = tbl->freelist;
tbl->freelist = p->fptr[0];
p->fptr[0] = 0;
return p;
}
}
size = sizeof(struct _nodeS) + ((levels-3) * sizeof(void*));
if(tbl->chunksize < size)
{
tbl->chunkbase = Ccalloc(tbl->category, 1, 4080);
tbl->chunksize = 4080;
}
tbl->chunksize -= size;
p = (NodePS)tbl->chunkbase;
tbl->chunkbase += size;
return p;
}
static void
free_Snode(PbufP tbl, NodePS node)
{
bzero(node, sizeof(struct _nodeS));
node->fptr[0] = tbl->freelist;
tbl->freelist = node;
}

static void*
NewSymTable(int category, int nbins)
{
PbufP tbl;

tbl = Ccalloc(category, 1, nbins*sizeof(NodePS) + sizeof(struct _pbuf));
if(nbins == 0)
{/* sorted dictionary */
int i;
tbl->header = new_Snode(tbl, SYM_MAXLEVEL+1);
for(i = 0; i <= SYM_MAXLEVEL; ++i)
tbl->header->fptr[i] = _NNIL;
}
tbl->nbins = nbins;
tbl->category = category;
return tbl;
}
static int
SymFind(void *tbl, void *key, void *result)
{
NodePS node;

if(tbl && key)
{
if(TBL->nbins)
{/* hashed dictionary */
KEY cat;

hash(key, &cat);
if((node = TBL->bins[cat.hv % TBL->nbins]))
{
do {
if( node->key[0] == cat.k[0]
&& node->key[1] == cat.k[1])
{
if(result)
*((NodePS *)result) = node;
TBL->lastbin = cat.hv % TBL->nbins;
TBL->lastptr = node;
return 1;
}
} while((node = node->fptr[0]));
}
return 0;
}
else
{/* sorted dictionary */
int level;

node = TBL->header;
for(level = TBL->level; level >= 0; level--)
{
while( KEYLT(node->fptr[level]->key, ((unsigned long*)key)) )
node = node->fptr[level];
}
node = node->fptr[0];

TBL->lastptr = node;
if(result)
*((NodePS *)result) = node;
return (KEYEQ(node->key, ((unsigned long*)key))) ? 1 : 0;
}
}
return 0;
}
static int
SymFindRange(void *tbl, void *key, void *result)
{/* assumes 4 byte key and value (the value can be bigger) */
NodePS node;

if(tbl && key)
{
if(TBL->nbins)
{/* hashed dictionary */
return 0;
}
else
{/* sorted dictionary */
NodePS prev;
int level;

node = TBL->header;
for(level = TBL->level; level >= 0; level--)
{
while ( node->fptr[level]->key[0] < ((unsigned long*)key)[0] )
node = node->fptr[level];
}
prev = node;
node = node->fptr[0];

if( node->key[0] == ((unsigned long*)key)[0] )
{
TBL->lastptr = node;
if(result)
*((NodePS *)result) = node;
return 1;
}
if( ((unsigned long*)key)[0] < prev->key[0]+prev->value[0] )
{
TBL->lastptr = prev;
if(result)
*((NodePS *)result) = prev;
return 1;
}
return 0;
}
}
return 0;
}
static void *
SymInsert(void *tbl, void *key, void *value, int datsiz)
{
NodePS node;

if(tbl && key)
{
if(TBL->nbins)
{/* hashed dictionary */
KEY cat;
NodePS *binp;
hash(key, &cat);
node = new_Snode(tbl, 0);
TBL->lastbin = cat.hv % TBL->nbins;
TBL->lastptr = node;
binp = &TBL->bins[TBL->lastbin];
if(value && datsiz)
memcpy(node, value, MIN(datsiz,16));
node->key[0] = cat.k[0];
node->key[1] = cat.k[1];
node->fptr[0] = *binp;
*binp = node;
return node;
}
else
{/* sorted dictionary */
int level;
NodePS update[SYM_MAXLEVEL+1];

node = TBL->header;
for (level = TBL->level; level >= 0; level--)
{
while ( KEYLT(node->fptr[level]->key,((unsigned long*)key)) )
node = node->fptr[level];
update[level] = node;
}

level = getSlevel(tbl);

while(TBL->level < level)
update[++TBL->level] = TBL->header;

node = new_Snode(tbl, level);

if(value && datsiz)
memcpy(node, value, MIN(datsiz,16));
node->key[0] = ((unsigned long*)key)[0];
node->key[1] = ((unsigned long*)key)[1];

while(level >= 0)
{
node->fptr[level] = update[level]->fptr[level];
update[level]->fptr[level] = node;
level--;
}
TBL->lastptr = node;
return node;
}
}
return 0;
}
static int
StringFind(void *tbl, char *string, void *result)
{
unsigned long key[2];
struct {
char *symname;
} *valp;

key[0] = 0;
key[1] = 0;
sym_hash(key, string);

if(SymFind(tbl, key, &valp))
{
unsigned long *key1;
do {
if(!strcmp(string, valp->symname))
{
if(result)
*((void**)result) = valp;
return 1;
}
/* Check duplicates */
if(!SymNext(tbl))
break;
SymKey(tbl, &key1);
SymValue(tbl, &valp);
} while(KEYEQ(key, key1));
}
return 0;
}
static int
StringInsert(void *tbl, char *string, void *result)
{
unsigned long key[2];
struct {
char *symname;
} *valp;

key[0] = 0;
key[1] = 0;
sym_hash(key, string);
if(SymFind(tbl, key, &valp))
{/* hash keys match */
for(;;)
{/* check strings */
if(!strcmp(string, valp->symname))
{
if(result)
*((void**)result) = valp;
return 1;
}

/* Possible duplicate hash keys */
if(SymNext(tbl))
{
unsigned long *key1;
SymKey(tbl, &key1);
if(!KEYEQ(key, key1))
break;
} else break;
}
}
/* NOMATCH */
valp = SymInsert(tbl, key, &string, 4);
if(result)
*((void**)result) = valp;
return 0;
}
static void
SymDelete(void *tbl, void *key)
{
NodePS node;

if(tbl && key)
{
if(TBL->nbins)
{/* hashed dictionary */
KEY cat;
NodePS *binp;
NodePS prev = 0;

hash(key, &cat);
binp = &TBL->bins[cat.hv % TBL->nbins];
if((node = *binp))
{
do {
if( node->key[0] == cat.k[0]
&& node->key[0] == cat.k[1])
{
if(prev)
prev->fptr[0] = node->fptr[0];
else
*binp = node->fptr[0];

free_Snode(tbl, node);
if(TBL->lastptr == node)
{
TBL->lastptr = 0;
TBL->lastbin = TBL->nbins;
}
return;
}
prev = node;
} while((node = node->fptr[0]));
}
}
else
{/* sorted dictionary */
int level;
NodePS update[SYM_MAXLEVEL+1];

node = TBL->header;
for(level = TBL->level; level >= 0; level--)
{
while ( KEYLT(node->fptr[level]->key, ((unsigned long*)key)) )
node = node->fptr[level];
update[level] = node;
}
node = node->fptr[0];

if( KEYEQ(node->key, ((unsigned long*)key)) )
{
for(level = 0; level <= TBL->level; level++)
{
if (update[level]->fptr[level] == node)
update[level]->fptr[level] = node->fptr[level];
else break;
}

while((TBL->level > 0) && (TBL->header->fptr[TBL->level] == _NNIL))
TBL->level--;

if(TBL->lastptr == node)
TBL->lastptr = 0;
free_Snode(tbl, node);
}
}
}
}
static int
SymHead(void *tbl)
{/* Set up for sequential access */
int nbins;

if(tbl)
{
if((nbins = TBL->nbins))
{/* hashed dictionary */
NodePS node;
int i;
TBL->lastptr = 0;
for(i = 0; i < nbins; ++i)
{
if( (node = TBL->bins[i]) != 0)
{
TBL->lastbin = i;
return 1;
}
}
TBL->lastbin = nbins;
return 0; /* empty */
}
else
{/* sorted dictionary */
TBL->lastptr = TBL->header;
return (TBL->lastptr->fptr[0] == _NNIL) ? 0 : 1;
}
}
return 0;
}
static int
SymNext(void *tbl)
{/* Move to next sequential entry */
int nbins;

if(tbl)
{
if((nbins = TBL->nbins))
{/* hashed dictionary */
if(TBL->lastptr && ((TBL->lastptr = TBL->lastptr->fptr[0])))
return 1;
else
{
int i;
for(i = TBL->lastbin; i < nbins; ++i)
{
if((TBL->lastptr = TBL->bins[i]) != 0)
{
TBL->lastbin = i+1;
return 1;
}
}
return 0;
}
}
else
{/* sorted dictionary */
if(TBL->lastptr)
{
if(TBL->lastptr != _NNIL)
TBL->lastptr = TBL->lastptr->fptr[0];
return (TBL->lastptr == _NNIL) ? 0 : 1;
}
}
}
return 0;
}
static void
SymGetMark(void *tbl, void *markptr)
{
if(tbl && markptr)
{
((long*)markptr)[0] = TBL->lastbin;
((long*)markptr)[1] = (long)TBL->lastptr;
}
}
static int
SymMarkNext(void *tbl, void *mark)
{/* Mark current position, and move to next sequential entry */
SymGetMark(tbl, mark);
return SymNext(tbl);
}
static void
SymSetMark(void *tbl, void *markptr)
{
if(tbl && markptr)
{
TBL->lastbin = ((long*)markptr)[0];
TBL->lastptr = (NodePS)((long*)markptr)[1];
}
}
static void
SymKey(void *tbl, void *keyptr)
{/* Retrieve key info pointer for current spot */

if(tbl && keyptr && TBL->lastptr)
*((unsigned long**)keyptr) = &TBL->lastptr->key[0];
}
static void
SymValue(void *tbl, void *datptr)
{/* Retrieve value pointer for current spot */

if(tbl && datptr && TBL->lastptr)
*((unsigned long**)datptr) = &TBL->lastptr->value[0];
}

/* ==================== END SYMBOL TABLE HANDLERS ========================== */

/* ========================== OPTIMIZATION ================================= */
static int
forward(unsigned char *p)
{
unsigned char *next;

do {
next = (void*)((Pop)p)->next;
while( *next == 0
|| *next == lineop
|| *next == labelop)
next = (void*)((Pop)next)->next;

if(*next == endop)
{
if(*p == *(next+8))
{
*p = 0;
*next = 0;
return 1;
}
return 0;
}
} while(forward(next));

return 0;
}
static void
eliminate_extraneous_infops(Piv iv, int level)
{
Pafile pf;
unsigned char *p;
int i;
for(i = 0; i < iv->numfiles; ++i)
{
iv->filenum = i;
pf = iv->files[i];
if(!(p = pf->prog_p))
continue;
if(pf->header_p->hdr.opt_level >= level)
continue;
pf->header_p->hdr.opt_level = level;
while(*p != endfileop)
{
switch(*p)
{
case unopop:
case arrayelemop:
case ptrelemop:
case strelemop:
case ptrdimsop:
case arraydimsop:
forward(p);
break;
}
p = POP->next;
}
}
}
static void
clean_temps(Piv iv)
{
long *key;
long *val;
long hitemp = iv->first_temp & 0xffff0000;

if(iv->temps_written == 0)
return;

if(SymHead(iv->tmptbl))
{
while(SymNext(iv->tmptbl))
{
SymKey(iv->tmptbl, &key);

if((key[0] & 0xffff0000) == hitemp)
{
char *ptr;
long saveit;

SymValue(iv->tmptbl, &val);
saveit = val[1];
ptr = (void*)val[0];
val[0] = 0; /* allow reuse of this slot */
val[1] = 0;

while(ptr)
{
void *nptr = (void*)((PopT)ptr)->tmpnum;
((PopT)ptr)->tmpnum = key[0];

if(!saveit)
{
unsigned char *p = ptr-8;
unsigned char op = *p;

*p = 0;
++iv->killop;
if(op == duptmpop)
{/* special test for post increment */
p = POP->next;
p = POP->next;
if(*p == grabop)
*p = 0;
}
}
ptr = nptr;
}
}
}
if(!hitemp)
iv->temps_written = 0;
}
}

static void
read_temp(Piv iv, PopT ptr, unsigned long last)
{
unsigned long key[2];
long *result;

if(last == ptr->tmpnum)
return;

key[0] = ptr->tmpnum;
key[1] = 0;

if(SymFind(iv->tmptbl, key, &result))
{
result[1] = 1;
}
else PERROR(pName ":Syserr: read temp %d not found\n", key[0]);
}
static int
reading_self(unsigned char *p, long tmpnum)
{
if((p[2]&0xe0) == OPTEMP || (p[2]&0xe0) == OPRET)
{
return 1;
}
if((p[3]&0xe0) == OPTEMP || (p[3]&0xe0) == OPRET)
{
return 1;
}
return 0;
}
static long
write_temp(Piv iv, PopT ptr, unsigned char opcode)
{
long key[2];
long val[2];
long *result;
long hitemp = ptr->tmpnum & 0xffff0000;

if(ptr->atype & A_MEMADDR && opcode < duptmpop)
{/* actually reading from this destination slot */
read_temp(iv, ptr, 0);
return 0;
}

if(hitemp > (iv->first_temp & 0xffff0000))
{/* Inner block, CompoundExp or NestedFunc */
iv->first_temp = hitemp + 1;
}
else if(hitemp < (iv->first_temp & 0xffff0000))
{/* Exit inner block */
if(!reading_self(((char*)ptr)-8, ptr->tmpnum))
{
while(hitemp < (iv->first_temp & 0xffff0000))
{
clean_temps(iv);
iv->first_temp -= 0x00010000;
}
}
}
if(ptr->tmpnum == iv->first_temp)
{
if(!reading_self(((char*)ptr)-8, ptr->tmpnum))
clean_temps(iv);
}
++iv->temps_written;
key[0] = ptr->tmpnum;
key[1] = 0;

if(SymFind(iv->tmptbl, key, &result))
{
PopT optr = (PopT)result[0];
result[0] = (long)ptr;
ptr->tmpnum = (long)optr;
}
else
{
val[0] = (long)ptr;
val[1] = 0;

SymInsert(iv->tmptbl, key, val, 8);
ptr->tmpnum = 0;
}
return key[0];
}
static void
eliminate_unused_temps(Piv iv, int level)
{
Pafile pf;
unsigned char *p;
int i;
long last_write;

iv->tmptbl = NewSymTable(iv->category, 111);
for(i = 0; i < iv->numfiles; ++i)
{
iv->filenum = i;
pf = iv->files[i];
if(pf->header_p->hdr.opt_level >= level)
continue;
pf->header_p->hdr.opt_level = level;
rekill:
if(!(p = pf->prog_p))
continue;
iv->first_temp = 1;
iv->temps_written = 0;
iv->killop = 0;
while(*p != endfileop)
{
while(*p < labelop)
{
if(*p == truthop)
{/* truthops of single chars are unnecessary */
if((p[2]&0xe0) == OPTEMP)
{
if(((PopT)(p+20))->dsize == 1)
{
if(((PopT)(p+8))->tmpnum == ((PopT)(p+20))->tmpnum)
{
if(!(((PopT)(p+20))->atype & A_MEMADDR))
*p = 0;
break;
}
else
{/* may be needed for code generation */
*p = aliastmpop;
}
}
}
}
if(*p)
{
if( *p == jmptrueop
|| *p == jmpfalseop
|| *p == ljmptrueop
|| *p == ljmpfalseop)
read_temp(iv,(PopT)(p+4), 0);
if(*p == retdataop)
{
read_temp(iv, (PopT)p, 0);
}
else
{
last_write = 0;
if((p[1]&0xe0) == OPTEMP)
last_write = write_temp(iv, (PopT)(p+8), *p);
if((p[2]&0xe0) == OPTEMP || (p[2]&0xe0) == OPRET)
read_temp(iv, (PopT)((p+8+(p[1]&0x1f))), last_write);
if((p[3]&0xe0) == OPTEMP || (p[3]&0xe0) == OPRET)
read_temp(iv, (PopT)((p+8+(p[1]&0x1f))+(p[2]&0x1f)), last_write);
}
}
break;
}
p = POP->next;
}
do {
clean_temps(iv);
iv->first_temp -= 0x00010000;
} while(iv->first_temp > 0);
if(iv->killop)
{
goto rekill;
}
}
}
static void
retarget_jmps(Piv iv, int level)
{
Pafile pf;
unsigned char *p;
int i;
for(i = 0; i < iv->numfiles; ++i)
{
iv->filenum = i;
pf = iv->files[i];
if(!(p = pf->prog_p))
continue;
if(pf->header_p->hdr.opt_level >= level)
continue;
}
}


static void
optimize(Piv iv)
{
eliminate_extraneous_infops(iv, 50);
eliminate_unused_temps(iv, 51);
retarget_jmps(iv, 52);
}
/* ========================== END OPTIMIZATION ============================= */
/* ====================== BASIC INPUT FILE PROCESSING ====================== */
static long
label_insert(Piv iv, long label, int filenum, unsigned char *p)
{
long *result;
struct {
long k1;
long k2;
} key;

struct {
long newlabel;
} val;

key.k1 = label;
key.k2 = filenum;

/* check for duplicate label -- they happen */
if(SymFind(iv->labeltbl, &key, &result))
{
if(*p == labelop)
*p = 0; /* kill the instruction */
return 0;
}

val.newlabel = ++iv->lastlabel;
SymInsert(iv->labeltbl, &key, &val, 4);

#if REALLY_NEED_OFFSETS
key.k1 = val.newlabel;
val.newlabel = -1;
SymInsert(iv->newlabeltbl, &key, &val, 4);
#endif

return iv->lastlabel;
}
static long
label_find(Piv iv, long label, int filenum)
{
struct {
long k1;
long k2;
} key;

long *result;

key.k1 = label;
key.k2 = filenum;

if(SymFind(iv->labeltbl, &key, &result))
return *result;
else
return 0;
}
#if REALLY_NEED_OFFSETS
static void
newlabel_insert(Piv iv, long label)
{
struct {
long k1;
long k2;
} key;

long *result;

key.k1 = label;
key.k2 = iv->filenum;
if(SymFind(iv->newlabeltbl, &key, &result))
{
*result = iv->out_offset + iv->func_offset;
}
else PERROR(pName ":Syserr: Label %d not found\n", label);
}
static long
newlabel_fix(Piv iv, long label)
{
if(label)
{
struct {
long k1;
long k2;
} key ;

long *val;

key.k1 = label;
key.k2 = iv->filenum;
if(SymFind(iv->newlabeltbl, &key, &val))
{
return val[0];
}
}
return label;
}
#endif /* REALLY_NEED_OFFSETS */

static void
extern_insert(Piv iv, unsigned char *p, int filenum)
{
struct {
short k1;
short k2;
long k3;
} key;
struct {
unsigned char *p;
} val;

key.k1 = GS(POPI->s.symnum);
key.k2 = filenum;
key.k3 = 0;

val.p = p;
SymInsert(iv->extrntbl, &key, &val, 4);
}
static void
reloc_insert(Piv iv, int fileno, unsigned char *p)
{
struct _rkey key;
struct _rval val;

key.spot = GL(POPI->reloc.spot); /* reloc target offset */
key.fileno = (short)fileno; /* fileno */
key.opcode = *p; /* opcode */
key.rsize = GL(POPI->reloc.rsize); /* reloc size */

val.p = p; /* pointer to input buffer */
val.base = (void*)GL(POPI->reloc.base); /* base of data object pointed to */
val.offset = GL(POPI->reloc.offset); /* offset to be added to base */
val.rsym = GS(POPI->reloc.rsym); /* symbol number if external */
SymInsert(iv->reloctbl, &key, &val, 14);
}
static void
data_insert(void *tbl, unsigned long offset,
unsigned long size, void *p, void *prevp)
{
static long locid = 1;
struct {
unsigned long k1;
long k2;
} key;
struct {
unsigned long size;
void *p;
void *prevp;
long locid;
} val;
unsigned char opcode, prevopcode = 0;

key.k1 = offset;
key.k2 = 0;

val.size = size;
val.p = p;
val.prevp = prevp;
val.locid = 0;
opcode = *((unsigned char *)p);
if(prevp)
{
prevopcode = *((unsigned char*)prevp);
if( prevopcode != glodatop
&& prevopcode != glofuncop
&& prevopcode != extfuncop
&& prevopcode != globssop)
{
val.locid = locid++;
}
}
SymInsert(tbl, &key, &val, sizeof(val));
}

static void
global_insert(Piv iv, Pafile pf, unsigned char *p)
{
unsigned long key[2];
struct _gloval val;
PopI pp;
unsigned char opcode = *p;

if(opcode == extvarop)

pp = POPI;
else
pp = (PopI)(POP->next+8);

key[0] = 0;
key[1] = 0;

val.symnum = GS(pp->s.symnum);
val.symname = pf->symaddr[val.symnum];
val.p = p;
val.pf = pf;
if(val.symnum < 0 || val.symnum >= pf->numsyms)
{
PERROR(pName ":Syserr: BAD SYMNUM=%d opcode=%d\n", val.symnum, opcode);
}
sym_hash(key, val.symname);

/* Duplicate entries are allowed */
SymInsert(iv->gbltbl, key, &val, sizeof(val));
}

static int
setup_nodelinks(Piv iv, char *infile_name, void *inbuf, int insize)
{
unsigned char *p = inbuf;
unsigned char *endbuf = inbuf+insize;
Pafile pf=0;
int lastline = 0;
unsigned char *funcp;
unsigned char *nfuncp;

while(p < endbuf && *p != endallop)
{
unsigned char *q = p;
if(iv->debug >= '5')
{
cfeprintf("OP(%u '%s' p=%p line=%d)\n", *p, oxgenops[*p], p, lastline);
}
switch(*p)
{
case headerop:
if(iv->numfiles >= 1024) {
PERROR(pName ": Sorry, too many files\n");
}
pf = iv->files[iv->numfiles] =
Ccalloc(iv->category, 1, sizeof(struct _afile));
pf->filenum = iv->numfiles++;
pf->file_p = p;
pf->header_p = POPI;
if(iv->strip)
{/* Gonna strip declarations and line numbers */
pf->header_p->hdr.target_debugger = 0;
}
break;

case dataop:
pf->size_p = POPI;
pf->thunk_offset = GL(POPI->dat.thunk_offset);
pf->bss_offset = GL(POPI->dat.bss_offset);
break;
case gfuncdefop:
case sfuncdefop:
if(pf->prog_p == 0)
pf->prog_p = p;
funcp = p;
break;
case funcexitop:
PS(((PopI)(funcp+8))->funcdef.tempmax) = GL(POPI->funcexit.tempmax);
break;
case nestedfuncdefop:
nfuncp = p;
break;
case nestedfuncexitop:
PS(((PopI)(nfuncp+8))->funcdef.tempmax) = GL(POPI->funcexit.tempmax);
break;
case segdefop:
if(pf->seg_p == 0)
pf->seg_p = p;
pf->numsegs += 1;
iv->numsegs += 1;
break;
case lineop:
lastline = GL( POPI->line.line );
if(iv->strip)
*p = 0; /* strip line numbers */
break;
case declop:
if(iv->strip)
{/* strip declarations */
do {
*p = 0;
q += (long)GL(POP->next);
POP->next = q;
p = q;
} while(*p != endop);
*p = 0;
}
else
{
if(pf->decl_p == 0)
pf->decl_p = p;
pf->numdecls += 1;
iv->numdecls += 1;
}
break;
case switchidop:
if(pf->switch_p == 0)
pf->switch_p = p;
break;
case labelop:
PL( POP->data ) =
label_insert(iv, GL( POP->data ), pf->filenum, p);
break;
case symbop:
pf->numsyms = GL(POP->data);
iv->numsyms += pf->numsyms;
break;
case symblockop:
pf->symtext_p = p + 12;
goto blka;
case stringblockop:
case datablockop:
case mallocblockop:
case thunkblockop:
{
long size;
if(pf->data_p == 0)
pf->data_p = p;
blka:
size = GL(POP->data);
q += size+((4-(size&3))&3);
break;
}
case glofuncop:
case extfuncop:
case glodatop:
case globssop:
case extvarop:
case bssblockop:
if(pf->data_p == 0)
pf->data_p = p;
break;
case maxtempop:
pf->maxtemp = GL(POP->data);
pf->maxtempclass = GL(POP->data1);
pf->maxtemp_p = p;
break;
}
q += (long)GL(POP->next);
POP->next = q;
p = q;
}
if(*p != endallop)
{
PERROR(pName ": Malformed input file: %s\n", infile_name);
}
return 0;
}
static void
setup_syms_decls(Piv iv)
{
int i;

for(i = 0; i < iv->numfiles; ++i)
{
int symnum = 0;
Pafile pf = iv->files[i];
unsigned char *p = pf->file_p;
unsigned char *prevp = 0;

pf->symaddr = Ccalloc(iv->category, sizeof(void*), pf->numsyms+1);
pf->decladdr = Ccalloc(iv->category, sizeof(void*), pf->numdecls+1);

while(*p != endfileop)
{
switch(*p)
{
case symoffsetop:
pf->symaddr[symnum] = pf->symtext_p + GL(POP->data);
++symnum;
break;

case declop:
pf->decladdr[GS(POPI->dcl.declnum)] = p;
break;

case relocop:
case extlocop:
++pf->numrelocs;
reloc_insert(iv, i, p);
break;

case glodatop:
case globssop:
case glofuncop:
case extfuncop:
global_insert(iv, pf, p);
break;

case extvarop:
extern_insert(iv, p, i);
global_insert(iv, pf, p);
break;

case stringblockop:
case datablockop:
case mallocblockop:
case thunkblockop:
case bssblockop:
if(!pf->datatbl)
pf->datatbl = NewSymTable(iv->category, 0); /* sorted */

data_insert(pf->datatbl,GL(DATI.offset),GL(DATI.size),
p, prevp);
if(*p == thunkblockop) {
PL(POP->data5) = label_find(iv, GL(POP->data5), i);
}
break;

case jmploopop:
case jmpcontinueop:
case jmpbreakop:
case jmpgotoop:
case jmptrueop:
case jmpfalseop:
case ljmptrueop:
case ljmpfalseop:
case funcstartop:
case funcstopop:
case casevalop:
case switchop:
PL(POP->data) = label_find(iv, GL(POP->data), i);
break;
}
prevp = p;
p = POP->next;
}
}
}
static int
sym_insert(Piv iv, char *symname, int symnum)
{/* Used only for combining symbols in link phase */
struct {
char *symname;
int symnum;
} *valp;

if(StringInsert(iv->symtbl, symname, &valp))
return -valp->symnum; /* MATCH */
valp->symnum = symnum;
return symnum;
}
static void
combine_syms_decls(Piv iv)
{
int i,j;
Pafile pf;
int numsyms;
int numdecls;

/* COMBINE SYMBOLS */
pf = iv->files[0];
numsyms = pf->numsyms;
pf->symtran = Ccalloc(iv->category, sizeof(short), pf->numsyms+1);
memcpy(iv->symaddr, pf->symaddr, sizeof(void*) * numsyms);


for(i = 0; i < numsyms; ++i)
{/* file 0 */
sym_insert(iv, pf->symaddr[i], i);
pf->symtran[i] = i;
}
for(i = 1; i < iv->numfiles; ++i)
{
int start;

pf = iv->files[i];
pf->symtran = Ccalloc(iv->category, sizeof(short), pf->numsyms+1);
if(pf->header_p->hdr.target_debugger)
start = 1;
else
start = 3;
for(j = start; j < pf->numsyms; ++j)
{
int k;
if((k = sym_insert(iv, pf->symaddr[j], numsyms)) > 0)
{ /* new entry */
iv->symaddr[numsyms++] = pf->symaddr[j];
pf->symtran[j] = k;
}
else pf->symtran[j] = -k;
}
}
iv->numsyms = numsyms;

/* COMBINE DECLARATIONS */
pf = iv->files[0];
numdecls = pf->numdecls;
pf->decltran = Ccalloc(iv->category, sizeof(short), numdecls+1);
memcpy(iv->decladdr, pf->decladdr, sizeof(void*) * numdecls);
for(i = 0; i < numdecls; ++i)
{/* file 0 */
pf->decltran[i] = i;
}
for(i = 1; i < iv->numfiles; ++i)
{
pf = iv->files[i];
pf->decltran = Ccalloc(iv->category, sizeof(short), pf->numdecls+1);
if(pf->numdecls < 21)
continue;
for(j = 1; j <= 21; ++j)
pf->decltran[j] = j;
for(j = 22; j < pf->numdecls; ++j) {
iv->decladdr[numdecls] = pf->decladdr[j];
pf->decltran[j] = numdecls++;
}
}
iv->numdecls = numdecls;
}

static void
link_dups(Piv iv, int dupcnt, struct _gloval *valp[])
{
int i;
int vars[5] = {0,0,0,0,0};
unsigned long cdsize = 0;
unsigned long cdoffset = 0;
short cdfile = 0;
int cdnum = 0;
short segid = 0;

#define GDAT vars[0]
#define GBSS vars[1]
#define GFUNC vars[2]
#define EVAR vars[3]
#define EFUNC vars[4]

/* Count the types of matches */
for(i = 0; i <= dupcnt; ++i)
vars[*(valp[i]->p) - glodatop] += 1;

/* Check for errors */
if( GDAT > 1
|| GFUNC > 1
|| (GFUNC && (GDAT || GBSS || EVAR))
|| (EFUNC && (GDAT || GBSS || EVAR)))
{
++iv->errors;
for(i = 0; i < dupcnt; ++i)
{
PWARN(pName ": Symbol `%s' multiply defined or mistyped.\n",
valp[i]->symname);
PWARN(pName": In file: `%s'\n", valp[i]->pf->symaddr[INFILE_SYMNUM]);
}
return;
}
if(EFUNC && GFUNC)
{/* match up functions */
Pop dp;
for(i = 0; i <= dupcnt; ++i)
if(*(valp[i]->p) == glofuncop)
break;
dp = (Pop)((Pop)valp[i]->p)->next; /* points to thunkblockop */

cdoffset = GL(dp->data1); /* save this offset */
cdfile = valp[i]->pf->filenum; /* save this file */
for(i = 0; i <= dupcnt; ++i)
{
if(*(valp[i]->p) == extfuncop)
{
*(valp[i]->p) = 0; /* convert to nilop */
dp = (Pop)((Pop)valp[i]->p)->next; /* points to thunkblockop */

/* Kill the thunkblock */
*((char*)dp) = 0;
PL(dp->data4) = cdoffset; /* use this offset for access */
PS(((short*)dp)[1]) = cdfile; /* fileno to unused slots */
}
}
}
else if(EFUNC)
{/* multiple references to external function */
Pop dp = (Pop)((Pop)valp[0]->p)->next; /* points to first thunkblockop */

cdoffset = GL(dp->data1); /* save first offset */
cdfile = valp[0]->pf->filenum; /* save first file */
for(i = 1; i <= dupcnt; ++i)
{/* Kill all thunkblocks except the first */
*(valp[i]->p) = 0; /* convert to nilop */
dp = (Pop)((Pop)valp[i]->p)->next; /* points to thunkblockop */
*((char*)dp) = 0;
PL(dp->data4) = cdoffset; /* use this offset for access */
PS(((short*)dp)[1]) = cdfile; /* fileno to unused slots */
}
}
else if(GBSS)
{/* comdefs */
int multsize = 0;

/* PICK THE BIGGEST GLOBAL BSS (comdef) */
for(i = 0; i <= dupcnt; ++i)
{
Pop dp = (Pop)((Pop)valp[i]->p)->next; /* points to bssblockop */
if((short)dp->data4 && segid == 0)
{
segid = (short)dp->data4;
}
else if((short)dp->data4 && (short)dp->data4 != segid)
{
++iv->errors;
PWARN(pName ": Variable `%s' defined in multiple segments.\n",
valp[i]->symname);
PWARN(pName ": In file: `%s'\n", valp[i]->pf->symaddr[INFILE_SYMNUM]);
}
if(*(valp[i]->p) == globssop)
{
long size = GL(dp->data);
if(cdsize && size != cdsize)
multsize = 1;
if(size > cdsize) {
cdsize = size;
cdoffset = GL(dp->data1);
cdfile = valp[i]->pf->filenum;
cdnum = i;
}
}
}
if(GDAT)
{
/* INITIALIZED DATA WILL ALWAYS OVERRIDE BSS */
for(i = 0; i <= dupcnt; ++i)
{
if(*(valp[i]->p) == glodatop)
{
Pop dp = (Pop)((Pop)valp[i]->p)->next; /* points to datablockop */
long size = GL(dp->data);
if(cdsize && size != cdsize)
multsize = 1;
if(size < cdsize)
{
++iv->errors;
PWARN(pName ": Initialized variable `%s' of size (%d)\n",
valp[i]->symname, size);
PWARN(pName ": In file: `%s'\n",
valp[i]->pf->symaddr[INFILE_SYMNUM]);
PWARN(pName ": Is incommensurate with common size (%d).\n",
cdsize);
}
else
{
cdsize = size;
cdoffset = GL(dp->data1);
cdfile = valp[i]->pf->filenum;
cdnum = i;
}
}
}
}
if(multsize)
{
PWARN(pName ":warning: Common Variable `%s' has multiple sizes.\n",
valp[0]->symname);
for(i = 0; i <= dupcnt; ++i)
{
unsigned char opcode = *(valp[i]->p);
if(opcode == globssop || opcode == glodatop)
{
PWARN(pName ":warning:Size=%d in file: `%s'\n",
GL(((Pop)((Pop)valp[i]->p)->next)->data),
valp[i]->pf->symaddr[INFILE_SYMNUM]);
}
}
}
/* FINALLY, LINK COMMONS TO THE CHOSEN ONE */
for(i = 0; i <= dupcnt; ++i)
{
if(i != cdnum && *(valp[i]->p) == globssop)
{
Pop dp = (Pop)((Pop)valp[i]->p)->next; /* points to bssblockop */

*(valp[i]->p) = 0; /* globssop becomes nilop */
*((char*)dp) = 0; /* bssblockop becomes nilop */
PL(dp->data4) = cdoffset; /* use this new offset for access */
PS(((short*)dp)[1]) = cdfile; /* put fileno in unused slots */
}
}
}
else if(GDAT)
{
for(i = 0; i <= dupcnt; ++i)
{
Pop dp = (Pop)((Pop)valp[i]->p)->next; /* points to datablockop */
if((short)dp->data4 && segid == 0)
{
segid = (short)dp->data4;
}
else if((short)dp->data4 && (short)dp->data4 != segid)
{
++iv->errors;
PWARN(pName ": Variable `%s' defined in multiple segments.\n",
valp[i]->symname);
PWARN(pName ": In file: `%s'\n", valp[i]->pf->symaddr[INFILE_SYMNUM]);
}
if(*(valp[i]->p) == glodatop)
{
cdsize = GL(dp->data);
cdoffset = GL(dp->data1);
cdfile = valp[i]->pf->filenum;
cdnum = i;
break;
}
}
}
if(EVAR && (GDAT || GBSS))
{/* match up variables */
/* LINK EXTERNS TO THE CHOSEN ONE */
for(i = 0; i <= dupcnt; ++i)
{
if(*(valp[i]->p) == extvarop)
{
Pop dp = (Pop)valp[i]->p;

*((char*)dp) = 0; /* extvarop becomes nilop */
PL(dp->data1) = cdoffset; /* use this new offset for access */
PS(((short*)dp)[1]) = cdfile; /* put fileno in unused slots */
PS(dp->data4) = segid;
break;
}
}
}
#undef GDAT
#undef GBSS
#undef GFUNC
#undef EVAR
#undef EFUNC

}
static void
link_globals(Piv iv)
{
if(SymHead(iv->gbltbl))
{
struct _gloval *valp[1024]; /* pointers to symtable value structs */

/* Pass over the sorted symbol table and process duplicate entries */
while(SymNext(iv->gbltbl))
{
unsigned long *key;
long mark[2]; /* Table position saver */
int dupcnt = 0;
SymKey(iv->gbltbl, &key); /* Pointer to first key */
SymValue(iv->gbltbl, &valp[0]); /* Pointer to first value */

while(SymMarkNext(iv->gbltbl, mark))
{/* Look forward for duplicates */
unsigned long *key1;
SymKey(iv->gbltbl, &key1); /* Pointer to next key */
if(KEYEQ(key, key1))
{/* Hashed keys match, check the strings */
SymValue(iv->gbltbl, &valp[dupcnt+1]); /* Pointer to next value */
if(!strcmp(valp[dupcnt]->symname, valp[dupcnt+1]->symname))
{/* Duplicate entry found */
++dupcnt;
continue;
}
}
break;
}
if(dupcnt > 0)
{/* Process a collection of duplicate symbol names */
link_dups(iv, dupcnt, valp);
}
SymSetMark(iv->gbltbl, mark);

}/* END: while(SymNext) */
}/* END: if(SymHead) */
}
static void
realloc_data(Piv iv)
{
int i;
Pafile pf;
unsigned char *p, *prevp;
unsigned long offset = 0;

iv->datatbl = NewSymTable(iv->category, 0); /* sorted table */

for(i = 0; i < iv->numfiles; ++i)
{
pf = iv->files[i];
p = pf->data_p;
prevp = 0;
while(*p != endfileop)
{
if( *p == datablockop
|| *p == mallocblockop
|| *p == stringblockop)
{
PL(POP->data1) = offset;
data_insert(iv->datatbl, offset, GL(POP->data), p, prevp);
offset += GL(POP->data);
ROUNDUP(offset, 4);
}
prevp = p;
p = POP->next;
}
}
iv->thunk_offset = offset;

for(i = 0; i < iv->numfiles; ++i)
{
pf = iv->files[i];
p = pf->data_p;
prevp = 0;
while(*p != endfileop)
{
if(*p == thunkblockop)
{
PL(POP->data1) = offset;
data_insert(iv->datatbl, offset, GL(POP->data), p, prevp);
offset += GL(POP->data);
ROUNDUP(offset, 4);
}
prevp = p;
p = POP->next;
}
}
iv->bss_offset = offset;

for(i = 0; i < iv->numfiles; ++i)
{
pf = iv->files[i];
p = pf->data_p;
prevp = 0;
while(*p != endfileop)
{
if(*p == bssblockop)
{
PL(POP->data1) = offset;
data_insert(iv->datatbl, offset, GL(POP->data), p, prevp);
offset += GL(POP->data);
ROUNDUP(offset, 4);
}
prevp = p;
p = POP->next;
}
}
iv->total_size = offset;
}
static void
reset_data_relocs(Piv iv)
{/* Pass over initialized data and set new offsets in each relocatable slot */
struct _data {/* datatbl node */
/* value area 16 bytes */
unsigned long size;
unsigned char *p;
unsigned char opcode;
unsigned char unused[7];
/* key area 8 bytes */
unsigned long offset;
long unused1;
};
/* PASS OVER ALL THE ENTRIES IN `reloctbl' */
if(SymHead(iv->reloctbl))
{
while(SymNext(iv->reloctbl))
{
struct _rkey *kp;
struct _rval *vp;
struct _data *dp, *ndp;
unsigned char *p;
Pafile pf, npf;
unsigned long object_base;
int noset = 0;

SymKey(iv->reloctbl, &kp);
SymValue(iv->reloctbl, &vp);
npf = pf = iv->files[kp->fileno]; /* pointer to file struct */
p = vp->p; /* pointer to relocop in input buffer */

if(kp->opcode == extlocop)
{/* External variable */
short key[4];
struct {
unsigned char *p; /* pointer to extvarop in input buffer */
} *ep;
key[0] = vp->rsym; /* external symbol number */
key[1] = pf->filenum;
key[2] = 0;
key[3] = 0;

/* LOOK UP THE EXTERNAL SYMBOL */
if(SymFind(iv->extrntbl, key, &ep) && *(ep->p) == 0)
{/* symbol exists and the extvarop was filled in */

npf = iv->files[GS( ((short*)(ep->p))[1] )];
PL( POPI->reloc.base ) = GL( ((Pop)(ep->p))->data1 );
*p = relocop; /* switch input file from `extlocop' */
}
else
{/* Not found or not filled in, leave it alone */
noset = 1;
}
}

/* RESET THE ENTRY IN THE INITIALIZED DATA SLOT */
if(SymFindRange(pf->datatbl, &kp->spot, &dp))
{/* This entry describes a block of data containg the reloc target */
unsigned char *ip = dp->p; /* points to input buffer */
unsigned long extra = kp->spot - dp->offset; /* offset into data */


/* Reset the relocop target in the input file */

PL( POPI->reloc.spot ) = GL( ((PopI)(ip+8))->s.offset ) + extra;
if(noset)
continue;

if(kp->rsize == 4)
{/* 32 bit relocation */
unsigned long *lp;

lp = (unsigned long*)(ip+24+extra); /* pointer to target */
object_base = GL( POPI->reloc.base );

/* Find the object that the target points to */
relink32:
if(SymFindRange(npf->datatbl, &object_base, &ndp))
{
if(*(ndp->p) == 0)
{/* The found object is a discarded thunkblock, relink */
npf = iv->files[GS( ((short*)(ndp->p))[1] )];
object_base = GL( ((Pop)(ndp->p))->data4 );
goto relink32;
}
else
{/* Use the new offset in the input file */

object_base = GL( ((Pop)(ndp->p))->data1 );
}
PL( POPI->reloc.base ) = object_base; /* the `relocop' */
PL(*lp) = object_base + GL( POPI->reloc.offset );/* data */
vp->base = lp;
}
else
{
++iv->errors;
PWARN(pName ":syserr: 32 bit object at offset %d not found\n",object_base);

}
}
else if(kp->rsize == 2)
{/* 16 bit relocation (MORE WORK NEEDED) */
unsigned short *sp;

sp = (unsigned short*)(ip+24+extra); /* pointer to target */
object_base = GL( POPI->reloc.base );
relink16:
if(SymFindRange(npf->datatbl, &object_base, &ndp))
{
if(*(ndp->p) == 0)
{/* The found object is a discarded thunkblock, relink */
npf = iv->files[GS( ((short*)(ndp->p))[1] )];
object_base = GL( ((Pop)(ndp->p))->data4 );
goto relink16;
}
else
{/* Use the new offset in the input file */

object_base = GL( ((Pop)(ndp->p))->data1 );
}
PL( POPI->reloc.base ) = object_base; /* the `relocop' */
PS(*sp) = object_base + GL( POPI->reloc.offset );/* data */
}
else
{
++iv->errors;
PWARN(pName ":syserr: 16 bit object at offset %d not found\n", object_base);
}

}
}
else /* !SymFindRange */
{
++iv->errors;
PWARN(pName ":syserr: reloc not found at %d in file %d\n",
kp->spot, kp->fileno);
}
}/* END: While(SymNext) */
}/* END: if(SymHead) */
}
static void
reset_offset(Piv iv, Pafile pf, PopA pa)
{/* All offsets are guaranteed to be inside objects */
struct _data {/* datatbl node */
/* value area 16 bytes */
unsigned long size;
unsigned char *p;
unsigned long unused[2];
/* key area 8 bytes */
unsigned long offset;
long unused1;
};

unsigned long offset;
struct _data *dp;
unsigned long object_base;
long extra;
unsigned short atype;
short symnum;

offset = GL( pa->offset );
atype = GS( pa->atype );
symnum = GS( pa->symnum );

PS( pa->symnum ) = pf->symtran[symnum];
PS( pa->declnum ) = pf->decltran[GS(pa->declnum)];

if(atype & A_EXTERN)
{
short key[4];
struct {
unsigned char *p; /* pointer to extvarop in input buffer */
} *ep;
key[0] = symnum; /* external symbol number */
key[1] = pf->filenum;
key[2] = 0;
key[3] = 0;

/* LOOK UP THE EXTERNAL SYMBOL */
if(!SymFind(iv->extrntbl, key, &ep) && *(ep->p))
{/* symbol exists and the extvarop was filled in */

pf = iv->files[GS( ((short*)(ep->p))[1] )];
offset += GL( ((Pop)(ep->p))->data1 );
}
else
{/* Not found or not filled in, leave it alone */

return;
}
}
extra = 0; /* first time through */

/* Find the object that the offset points to */
relink:
if(SymFindRange(pf->datatbl, &offset, &dp))
{
if(extra == 0)
extra = offset - dp->offset;
object_base = dp->offset;

if(*(dp->p) == 0)
{/* The found object is a discarded block, relink */
pf = iv->files[GS( ((short*)(dp->p))[1] )];
offset = GL( ((Pop)(dp->p))->data4 );
goto relink;
}
else
{/* Use the adjusted offset in the input buffer */

object_base = GL( ((Pop)(dp->p))->data1 );
}
PL( pa->offset ) = object_base + extra;
if(atype & A_EXTERN)
{
PS( pa->atype ) = atype & ~A_EXTERN;
}
}
else
{
++iv->errors;
PWARN(pName ":syserr: object `%s' at offset %d not found\n",
pf->symaddr[symnum], offset);
}
}
static void
reset_text_relocs(Piv iv)
{/* Pass over text and set new offsets in instructions that reference data */
int i;

for(i = 0; i < iv->numfiles; ++i)
{
Pafile pf;
unsigned char *p;

pf = iv->files[i];
if(!(p = pf->prog_p))
continue;

while(*p != endfileop)
{
if(*p && *p <= (unsigned char)100)
{/* instruction */
int inc = 8;
if((p[1]&0xe0) == OPDATA)
reset_offset(iv, pf, POPA);
inc += (p[1]&0x1f);
if((p[2]&0xe0) == OPDATA)
reset_offset(iv, pf, POPA);
inc += (p[2]&0x1f);
if((p[3]&0xe0) == OPDATA)
reset_offset(iv, pf, POPA);
}
p = POP->next;
}
}

}
static void *
seg_find(Piv iv, int id)
{
long key[2];
void **result;

if(iv->segtbl)
{
key[0] = id;
key[1] = 0;
if(SymFind(iv->segtbl, key, &result))
return *result;
}
return 0;
}
static void
check_seg(Piv iv, unsigned char *p, Pafile pf)
{
PopI np, op;
if(!(iv->segtbl))
{
iv->segtbl = NewSymTable(iv->category, 111);
}
if((op = seg_find(iv, GS(POPI->segdef.segid))))
{
np = POPI;
if( GL(np->segdef.v1) == GL(op->segdef.v1)
&& GL(np->segdef.v2) == GL(op->segdef.v2)
&& GL(np->segdef.v3) == GL(op->segdef.v3))
{/* segments of same name have the same values */
*p = 0; /* kill the new definition */
return;
}
else
{/* segments of same name have different values */
++iv->errors;
PWARN(pName ":Segment `%s' defined differently.\n",
iv->symaddr[GS(POPI->segdef.segid)]);
PWARN(pName ": In file: `%s'\n", pf->symaddr[INFILE_SYMNUM]);
return;
}
}
else
{
long key[2];
PopI pp = POPI;
key[0] = GS(POPI->segdef.segid);
key[1] = 0;
SymInsert(iv->segtbl, key, &pp, 4);
}
}
static void
reset_syms_decls(Piv iv)
{
int i;
for(i = 0; i < iv->numfiles; ++i)
{
Pafile pf;
unsigned char *p;

pf = iv->files[i];
p = pf->file_p;

while(*p != endfileop)
{
if(*p == segdefop)
{
PS(POPI->segdef.segid) = pf->symtran[GS(POPI->segdef.segid)];
check_seg(iv, p, pf);
}
else if(i > 0)
{
switch(*p)
{
case declop:
if(GS(POPI->dcl.declnum) < 22)
{/* kill the base declarations */
*p = 0;
p = POP->next;
*p = 0;
}
else
PS(POPI->dcl.declnum)=pf->decltran[GS(POPI->dcl.declnum)];
break;
case extlocop:
PS(POPI->reloc.rsym) = pf->symtran[GS(POPI->reloc.rsym)];
break;
case gfuncdefop:
case sfuncdefop:
if(pf->numsegs)
PS(POPI->funcdef.segid) = pf->symtran[GS(POPI->funcdef.segid)];
case nestedfuncdefop:
PL(POPI->funcdef.symnum) = pf->symtran[GL(POPI->funcdef.symnum)];
break;
case bssblockop:
case datablockop:
if(pf->numsegs)
PS( POPI->s.segid ) = pf->symtran[GS(POPI->s.segid)];
case stringblockop:
case mallocblockop:
case thunkblockop:
case extvarop:
PS( POPI->s.symnum ) = pf->symtran[GS(POPI->s.symnum)];
PS( POPI->s.declnum ) = pf->decltran[GS(POPI->s.declnum)];
break;
case memberinfop:
case bfieldinfop:
PS(POPI->memb.symnum) = pf->symtran[GS(POPI->memb.symnum)];
PS(POPI->memb.declnum) = pf->decltran[GS(POPI->memb.declnum)];
PS(POPI->memb.cdeclnum) = pf->decltran[GS(POPI->memb.cdeclnum)];
break;
case structinfop:
PS(POPI->suinf.symnum) = pf->symtran[GS(POPI->suinf.symnum)];
break;
case funcptrinfop:
case ptrinfop:
PS(POPI->ptrinf.declnum) = pf->decltran[GS(POPI->ptrinf.declnum)];
break;
case funcinfop:
PS(POPI->funcd.declnum) = pf->decltran[GS(POPI->funcd.declnum)];
PS(POPI->funcd.symnum) = pf->symtran[GS(POPI->funcd.symnum)];
break;
case arrayinfop:
PS(POPI->ary.declnum) = pf->decltran[GS(POPI->ary.declnum)];
break;
case lineop:
PL(POPI->line.filenamenum) = pf->symtran[GL(POPI->line.filenamenum)];
break;
}/* END: switch(*p) */
}/* END: i > 0 */
p = POP->next;
}
}
}
static int
link_files(Piv iv)
{
iv->extrntbl = NewSymTable(iv->category, 4092); /* hashed table */
iv->reloctbl = NewSymTable(iv->category, 4092); /* hashed table */
iv->gbltbl = NewSymTable(iv->category, 0); /* sorted table */

setup_syms_decls(iv);

if(iv->numfiles > 1)
{
iv->symaddr = Ccalloc(iv->category, sizeof(void*), iv->numsyms+1);
iv->decladdr = Ccalloc(iv->category, sizeof(void*), iv->numdecls+1);
iv->symtbl = NewSymTable(iv->category, 0); /* sorted table */
combine_syms_decls(iv);

link_globals(iv);
realloc_data(iv);
reset_data_relocs(iv);
reset_text_relocs(iv);

reset_syms_decls(iv);
}
else
{
iv->symaddr = iv->files[0]->symaddr;
iv->decladdr = iv->files[0]->decladdr;
iv->symtbl = NewSymTable(iv->category, 0); /* sorted table */
combine_syms_decls(iv);

realloc_data(iv);
reset_data_relocs(iv);
reset_text_relocs(iv);
}
return iv->errors;
}

/* ======================== GLOBAL ROUTINES ========================== */
int
Global(readfile) (Piv iv, char *infile_name)
{
FILE *infile;
long infile_size;
char *inbuf;

if(!(infile = fopen(infile_name, "rb")))
{
PERROR(pName ": Can't open input file: %s\n", infile_name);
}
fseek(infile, 0, SEEK_END);
infile_size = ftell(infile);
fseek(infile, 0, SEEK_SET);

if(infile_size == 0)
{
PERROR(pName ": Empty input file: %s\n", infile_name);
}
inbuf = Cmalloc(iv->category, infile_size);

if(fread(inbuf, 1, infile_size, infile) != infile_size)
{
fclose(infile);
PERROR(pName ": Error reading input file: %s\n", infile_name);
}
fclose(infile);

if(setup_nodelinks(iv, infile_name, inbuf, infile_size))
return 4;
return 0;
}
int
Global(proc_files) (Piv iv, void *name)
{
int ret;

if(!(ret = link_files(iv)))
{
optimize(iv);
if(name)
iv->symaddr[2] = name; /* symbol 2 is the output filename */

ret = gen_output(iv, iv->symaddr[2]);
}
return ret;
}
void *
Global(open_instance) (void)
{
Piv iv;
int category;
category = Cnewcat();
iv = Ccalloc(category, 1, sizeof(struct _iv));
iv->category = category;
iv->finextbuf = (PEL)&iv->finextbufstart;
return iv;
}
void
Global(close_instance) (Piv iv)
{
if(iv->outfile)
fclose(iv->outfile);
if(iv->remove_infile)
{
int i;
for(i = 1; i < iv->argc; ++i)
unlink(propernameof(iv, iv->argv[i]));
}
Cfreecat(iv->category);
}

/* =========================== THE MAIN PROGRAM ======================= */

static char *
filenameof(char *path)
{
char *ret = path;
int i;

for(i = 0; path[i]; ++i)
if(path[i] == '/')
ret = &path[i+1];
return ret;
}

static char *
propernameof(Piv iv, char *path)
{
char *name = filenameof(path);
int namlen = strlen(name);
int i;
for(i = namlen-1; i >= 0; --i)
{
if(name[i] == '/' || name[i] == '\\')
break;
else if(name[i] == '.')
return path;
}
name = Cmalloc(iv->category, strlen(path)+8);
strcpy(name, path);
strcat(name, ".anf");
return name;
}
static void
Usage()
{
fputs(
"Usage: " pName " [-odsDLR?] [infile...]\n"
" -o outfile == name of output file\n"
" -d == print debug output\n"
" -D == only print debug output\n"
" -s == strip declarations and line numbers\n"
" -L == generate listing only (to .lst)\n"
" -R == remove input file\n"
" -? == print this message\n"
" Default input file is `code.anf'.\n"
" Default output file is specified by the input.\n"
,stderr);
}

#if USING_FRAMEWORK
int
PROG (int argc, char **argv)
#else
int
main (int argc, char **argv)
#endif
{
int i,j;
char *outfilename = 0;
volatile Piv iv;
char debug, only_debug, strip, listing_wanted, remove_infile;
int ret;

remove_infile = listing_wanted = strip = debug = only_debug = 0;

/* Get options */
for(i = 1; i < argc; ++i)
{
int trimsize = 1;

if(argv[i][0] == '-')
{
for (j=1; argv[i][j]; j++)
{
switch(argv[i][j])
{
case 'D':
only_debug = 1;
/* FALL THROUGH */
case 'd':
debug = argv[i][++j];
break;
case 's':
strip = 1;
break;
case 'o':
if(argv[i][j+1]) {
outfilename = &argv[i][j+1];
}
else if(i < argc-1) {
outfilename = argv[i+1];
trimsize = 2;
} else {
PWARN(pName ": no output filename\n");
Usage();
return 0;
}
goto trim;
break;
case 'L':
listing_wanted = 1;
break;
case 'R':
remove_infile = 1;
break;
case '?':
Usage();
return 0;
default:
PWARN(pName ": Invalid switch: 0x%x\n", argv[i][j]);
Usage();
return 0;
}
}/* END: for(j) */
trim:
/* Trim switch */
for(j = i; j < argc-trimsize; ++j)
argv[j] = argv[j+trimsize];
argc -= trimsize;
--i;
}/* END: if('-') */
}/* END: for(argc) */

#if 0
oxcc_debug(__builtin_iv(),0x40000);
#endif

iv = Global(open_instance) ();
if((ret = setjmp(run_env))) {
Global(close_instance) (iv);
#if USING_FRAMEWORK
return ret;
#else
exit(ret);
#endif
}
iv->debug = debug;
iv->only_debug = only_debug;
iv->labeltbl = NewSymTable(iv->category, 4092);
#if REALLY_NEED_OFFSETS
iv->newlabeltbl = NewSymTable(iv->category, 4092);
#endif
iv->strip = strip;
iv->listing_wanted = listing_wanted;
iv->remove_infile = remove_infile;
iv->argc = argc;
iv->argv = argv;

if(argc < 2)
{/* Default input filename is 'code.anf' */
ret = Global(readfile) (iv, "code.anf");
}
else
{/* READ EACH INPUT FILE */
for(i = 1; i < argc; ++i)
if((ret = Global(readfile) (iv, propernameof(iv,argv[i]))))
break;
}
if(!ret && !iv->only_debug)
{
ret = Global(proc_files) (iv, outfilename);
}
Global(close_instance) (iv);
#if USING_FRAMEWORK
return ret;
#else
exit(ret);
#endif
}



  3 Responses to “Category : Recently Uploaded Files
Archive   : OXCC1432.ZIP
Filename : OXCCB.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/