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

 
Output of file : OXCCAX.C contained in archive : OXCC1432.ZIP
/*
oxccax.c -- architecture neutral format (anf) to asmcode 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]
[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 421

#include
#include
#include
#include
#include

#define SUPPORT_LONG_DOUBLE 0
#define SUPPORT_LONG_LONG 0

#define NEED_FUNCTHUNK 1
#include "oxanf.h"

#define PROG oxccax
#define USING_FRAMEWORK 1
#define HOST_IS_LITTLE_ENDIAN 1
#define REALLY_NEED_OFFSETS 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 *, ...);

#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

/* ====================== 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;
char *outname;
char *infile_name;
struct exec *header;
unsigned char **symaddr;
unsigned char **decladdr;
struct _nodeO *ob_freelist;
struct _nodeO *ob_usedhead;
struct _nodeO *ob_usedtail;
struct _nodeO *ob;
int numfiles;
int lastlabel;
int labelnum;
int botlabel;
int errors;
int numsyms;
int numdecls;
int numsegs;
int maxtemp;
int maxtempclass;
unsigned long total_size;
unsigned long thunk_offset;
unsigned long bss_offset;
long first_temp;
long killop;
long numnested;
long lastline;
void *reloctbl;
void *newreloctbl;
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;
int onodecnt;
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;
char target_assembler;
char target_hardware;
char target_debugger;
char target_os;
char memory_model;
char obj_format;
} *Piv;

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


/* 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);

/* 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();

/* ===================== ASMCODE OUTPUT GENERATOR ======================= */
#define SOURCE 0
#define DESTINATION 1
#define USE_ADDR (0x0001)
#define NEEDS_CONVERSION (0x0002)

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

typedef struct _nd {
unsigned char type;
unsigned char quals;
unsigned short atype;
short flags;
short opsize;
int size;
DATUM dat;
} ND, *PND;

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

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,0);

#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))
{
if(!StringInsert(iv->finalsymtbl, valp->symname, &result))
{/* New Entry */
result[1] = ++i;
}
}
}
}
}

static void
unlink_obs(Piv iv, PNODEO p)
{
PNODEO np;
PNODEO q;

if((np = p->next))
{
q = iv->ob_freelist;
p->next = 0;
iv->ob_freelist = np;
if(np)
{
while(np->next)
np = np->next;
np->next = q;
}
}
}
static void *
new_nodeO(Piv iv)
{
PNODEO p;
if(iv->ob_freelist)
{
p = iv->ob_freelist;
iv->ob_freelist = p->next;
memset(p, 0, sizeof(NODEO));
return p;
}
else if(iv->obufcnt < sizeof(NODEO))
{/* Allocate a new chunk of linked list space */
iv->obufcnt = 4080;
iv->obuf = Ccalloc(iv->category+1, 1, iv->obufcnt);
}
p = (PNODEO)iv->obuf;
iv->obuf += sizeof(NODEO);
++iv->onodecnt;
return p;
}
static void
link_ob(Piv iv)
{/* Attach to the used list */
#if 0
if(iv->obuf != (unsigned char*)&iv->obufstart)
{/* Suppress duplicate RETs */
if(buf[0] == RET && (iv->obuf[8] == RET || iv->obuf[9] == RETSTRUCT) )
{
return;
}
}
#endif

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 int
check_conversion(PopA dst, PopA src)
{
long dsize = GL(dst->dsize);
long ssize = GL(src->dsize);
unsigned short ddtype = GS(dst->dtype) & 0xff;
unsigned short sdtype = GS(src->dtype) & 0xff;

if(GS(src->atype) & (A_ABSOLUTE|A_POINTER|A_VALUE) == (A_POINTER|A_VALUE))
return 0;
switch(ddtype)
{
case 0: /* dest is signed integer */
{
switch(sdtype)
{
case 0:
case D_UNSIGNED:
case D_SEGMENT:
case D_POINTER:
case D_FUNCPTR:
{
if(dsize <= ssize)
return 0;
return 1;
}
case D_FLOAT:
{
return 1;
}
default:
return 0;
}
}
case D_UNSIGNED: /* dest is unsigned integer */
case D_SEGMENT:
{
switch(sdtype)
{
case 0:
case D_UNSIGNED:
case D_SEGMENT:
case D_POINTER:
case D_FUNCPTR:
{
if(dsize <= ssize)
return 0;
return 1;
}
case D_FLOAT:
{
return 1;
}
default:
return 0;
}
}
case D_FLOAT: /* dest is float, double, long double */
{
switch(sdtype)
{
case 0:
case D_UNSIGNED:
case D_SEGMENT:
case D_POINTER:
case D_FUNCPTR:
return 1;
case D_FLOAT:
{
if(dsize == ssize)
return 0;
return 1;
}
default:
return 0;
}
}
case D_POINTER:
case D_FUNCPTR: /* dest is pointer */
{
switch(sdtype)
{
case 0:
case D_UNSIGNED:
case D_SEGMENT:
case D_POINTER:
case D_FUNCPTR:
{
if(dsize <= ssize)
return 0;
return 1;
}
case D_FLOAT:
{
return 1;
}
default:
return 0;
}
}
default:
return 0;
}
}
static int
get_size(int type, int size)
{
switch(type)
{
case D_ARRAY:
case D_STRUCT:
case D_FUNCTION:
return 4;

default:
return size;
}
return 0;
}
static void

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

if(optype <= OPIMMED4)
{
pnd->type = optype >> 5;
pnd->quals = Q_CONST;
pnd->size = 8;
pnd->opsize = 8;
pnd->atype = A_IMMED;
switch(pnd->type)
{
case D_SIGNED:
{
if(isize > 8)
{
memcpy(&pnd->dat, ptr, isize);
}
else if(isize == 8)
{
pnd->dat.Udouble = *((double*)ptr);
}
else
{
long l[2];
l[0] = 0;
l[1] = 0;
if(isize == 4)
l[0] = *((long*)ptr);
else if(isize == 2)
l[0] = *((short*)ptr);
else if(isize == 1)
l[0] = *((char*)ptr);
if(l[0] < 0)
l[1] = -1;
pnd->dat.Udouble = *((double*)l);
}
}
case D_UNSIGNED:
case D_POINTER:
{
if(isize > 8)
{
memcpy(&pnd->dat, ptr, isize);
}
else if(isize == 8)
{
pnd->dat.Udouble = *((double*)ptr);
}
else
{
unsigned long l[2];
l[0] = 0;
l[1] = 0;
if(isize == 4)
l[0] = *((unsigned long*)ptr);
else if(isize == 2)
l[0] = *((unsigned short*)ptr);
else if(isize == 1)
l[0] = *((unsigned char*)ptr);
pnd->dat.Udouble = *((double*)l);
}
}
case D_FLOAT:
{
if(isize == 4)
{
pnd->dat.Udouble = *((float*)ptr);
}
else if(isize > 8)
{
#if SUPPORT_LONG_DOUBLE
pnd->dat.Ulongdouble = *((long double)ptr);
#else
pnd->dat.Udouble = 0.0;
#endif
}
else
{
pnd->dat.Udouble = *((double*)ptr);
}
}
}
}
else
{
unsigned short type = GS(ptr->dtype);
pnd->type = type & 0xff;
pnd->quals = (type >> 8) & 0xff;
pnd->size = GL(ptr->dsize);
pnd->opsize = get_size(pnd->type, pnd->size);
pnd->atype = GS(ptr->atype);
pnd->dat.Ulong = GL(ptr->offset);
if(optype == OPAUTO)
{
long pofs = GL(ptr->pofs);
if(pofs >= 0)
{
pnd->dat.Ulong = pofs;
pnd->atype &= ~A_AUTO;
pnd->atype |= A_PARAM;
}
}
}
}
static void *
decode_anf(Piv iv, unsigned char *p)
{
PopA dptr;
PopA lptr;
PopA rptr;
int loptype, roptype;

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

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

dptr = (PopA)(p+8);
lptr = (PopA)(((char*)dptr) + (p[1] & 0x1f));
rptr = (PopA)(((char*)lptr) + (p[2] & 0x1f));
loptype = p[2] & 0xe0;
roptype = p[3] & 0xe0;

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 jmptrueop:
case jmpfalseop:
case retdataop:
{/* 1 address mode */
set_op(&iv->ob->d, dptr, p[1]);
break;
}
case getvalop:
case derefop:
case assignop:
case duptmpop:
{/* 2 address mode */
set_op(&iv->ob->d, dptr, p[1]);
set_op(&iv->ob->l, lptr, p[2]);

if(*p == getvalop && ((GS(lptr->dtype)&0xff) == D_FUNCTION))
{
iv->ob->l.flags |= USE_ADDR;
}
else if( *p != derefop
&& loptype > OPIMMED4
&& check_conversion(dptr, lptr))
{
iv->ob->l.flags |= NEEDS_CONVERSION;
}
break;
}
case truthop:
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 */
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 lshop:
case rshop:
case modop:
case orop:
case xorop:
case andop:
case eqop:
case neqop:
case ltop:
case gtop:
case leop:
case geop:
{/* 3 address mode */
set_op(&iv->ob->d, dptr, p[1]);
set_op(&iv->ob->l, lptr, p[2]);
set_op(&iv->ob->r, rptr, p[3]);

if(loptype <= OPIMMED4 || roptype <= OPIMMED4)
{/* immediates are commensurate already */
}
else
{/* ensure commensurate data */
if(check_conversion(dptr, rptr))
iv->ob->r.flags |= NEEDS_CONVERSION;
if(check_conversion(dptr, lptr))
iv->ob->l.flags |= NEEDS_CONVERSION;
}

break;
}
case getbitfieldop:
case putbitfieldop:
case callfuncop:
{/* 3 address mode */
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:
{
*p = nopop;
break;
}
}/* END: switch(*p) */
link_ob(iv);
return POP->next;
}
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_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];
int sacnt, spcnt, i;

/* Scan over the bracket and pick up the dimension computations */
sacnt = spcnt = 0;
p = POP->next;
while(p < q)
{
if(*p == arraydimsop)
{
void *qq = skip_bracket(p);
sadims[sacnt] = p;
sadimsq[sacnt++] = qq;
p = qq;
}
else if(*p == ptrdimsop)
{
void *qq = skip_bracket(p);
spdims[spcnt] = p;
spdimsq[spcnt++] = 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 remainder of the array element bracket */
p = sp;
sacnt = spcnt = 0;
p = POP->next;
while(p < q)
{
if(*p == arraydimsop)
p = ((Pop)sadimsq[sacnt++])->next;
else if(*p == ptrdimsop)
p = ((Pop)spdimsq[spcnt++])->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) == 1)
return *result;
return 0;
}
static void *
do_funcall(Piv iv, unsigned char *p)
{
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]);
}
}
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 */
}
return ((Pop)q)->next;
}
static void *
do_cond(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_twopath(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_logical(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_binop(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_strelem(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_ptrelem(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_argload(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_preincr(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_postincr(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_compound(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_unop(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_expr(Piv iv, unsigned char *p)
{
unsigned char *q = skip_bracket(p);

while(p < q)
{
switch(*p)
{
case arrayelemop:
p = do_arrayelem(iv, p);
break;
case funcallop:
p = do_funcall(iv, p);
break;
case condop:
p = do_cond(iv, p);
break;
case twopathop:
p = do_twopath(iv, p);
break;
case logicalop:
p = do_logical(iv, p);
break;
case binopop:
p = do_binop(iv, p);
break;
case strelemop:
p = do_strelem(iv, p);
break;
case ptrelemop:
p = do_ptrelem(iv, p);
break;
case argloadop:
p = do_argload(iv, p);
break;
case preincrdecop:
p = do_preincr(iv, p);
break;
case postincrdecop:
p = do_postincr(iv, p);
break;
case compoundop:
p = do_compound(iv, p);
break;
case unopop:
p = do_unop(iv, p);
break;
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 void *
do_stmt(Piv iv, unsigned char *p)
{
void *node = iv->ob_usedtail;
void *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 0
if(iv->listing_wanted)
{
obuf[0] = NFUNC;
*((char**)&obuf[1]) = iv->symaddr[GS(POPI->funcdef.symnum)];
link_ob(iv);
}
#endif
iv->numnested += 1;
break;
}
case nestedfuncexitop:
{
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 >= '2')
{
PRINTF("Line=%u\n", GL(POP->data));
}
if(iv->listing_wanted)
{
#if 0
obuf[0] = LINENO;
*((long*)&obuf[1]) = GL(POP->data);
link_ob(iv);
#endif
}
iv->lastline = GL(POP->data);
break;
default:
break;
}
unlink_obs(iv, node);
return q;
}
static void *
do_something(Piv iv, unsigned char *p)
{
if(*p < labelop)
return decode_anf(iv, p);
else if(*p >= condop && *p <= unopop)
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
start_unix_func(Piv iv, unsigned char *p)
{
static char *sbuf ="\tpushl %ebp\n\tmovl %esp,%ebp\n";
char *funcname = iv->symaddr[GS(POPI->funcdef.symnum)];

fprintf(iv->outfile, ".align 2\n_%s:\n",funcname);
fwrite(sbuf, 1, strlen(sbuf), iv->outfile);
iv->botlabel = ++iv->labelnum;
}
static void
end_unix_func(Piv iv, unsigned char *p)
{
static char *ebuf = "\tleave\n\tret\n\n";
Cfreecat(iv->category+1);
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->numnested = 0;

fprintf(iv->outfile, "L%u:\n", iv->botlabel);
fwrite(ebuf, 1, strlen(ebuf), iv->outfile);
}
static void *
dumpa_unix_func(Piv iv, unsigned char *p)
{
start_unix_func(iv, p);
if((p = POP->next))
{
for(;;)
{
if(*p == funcexitop)
{
end_unix_func(iv, p);
break;
}
else
p = do_something(iv, p);
}
}
return p;
}
static int
isa_reloc_loc(Piv iv, long offset, char **psymb, int *poffs)
{
long key[2];
struct _rval *vp;
struct _dval *dp;
unsigned char *p;
Pafile pf;

key[0] = offset;
key[1] = 0;
if(SymFind(iv->newreloctbl, &key, &vp))
{
p = vp->p;
pf = iv->files[vp->fileno];
*poffs = vp->offset;
if(*p == extlocop)
{
if(vp->rsym <= 0)
return 0;
*psymb = pf->symaddr[vp->rsym];
return 1;
}
else
{
key[0] = vp->base;
if(SymFind(iv->datatbl, &key, &dp))
{
p = dp->p;
switch(*p)
{
case datablockop:
case bssblockop:
case thunkblockop:
*psymb = pf->symaddr[GS(POPI->s.symnum)];
return 1;
case mallocblockop:
case stringblockop:
*psymb = (void*)vp->base; /* must concoct a symbol */
return 2;
}
}
return 0;
}
}
return 0;
}
static void
dump_unix_header(Piv iv)
{
fprintf(iv->outfile, "\t.file\t\"%s\"\n_oxcc_compiled:\n\n",
filenameof(iv->infile_name));
}
static void
dump_unix_globals(Piv iv)
{
if(SymHead(iv->gbltbl))
{
while(SymNext(iv->gbltbl))
{
struct _gloval *valp;
unsigned char opcode;

SymValue(iv->gbltbl, &valp);
if((opcode = *(valp->p)))
{
if(opcode == glodatop || opcode == glofuncop)
{
fprintf(iv->outfile,".globl _%s\n", valp->symname);
}
}
}
}
}
static void
dump_unix_bss(Piv iv)
{
if(SymHead(iv->datatbl))
{
while(SymNext(iv->datatbl))
{
unsigned char *p;
long size;
unsigned char opcode, prevopcode = 0;
unsigned long *key;
struct _dval *val;
SymKey(iv->datatbl, &key);
SymValue(iv->datatbl, &val);
p = val->p;
opcode = *p;
if(val->prevp)
prevopcode = *(val->prevp);
size = val->size;
if(opcode == bssblockop)
{
if(prevopcode == globssop)
{
fprintf(iv->outfile, ".comm _%s,%d\n",
iv->symaddr[GS(POP->data2)], size);
}
else
{
fprintf(iv->outfile, ".lcomm _%s,%d\n",
iv->symaddr[GS(POP->data2)], size);
}
}
}
}
}
static void
dump_unix_bytes(Piv iv, unsigned char *cp, int cnt)
{
int first=0, width = 0;
while(cnt > 0)
{
if(width == 0) {
width = fprintf(iv->outfile," .byte ");
first = 0;
}
while(width <= 75 && cnt > 0)
{
if(!first++)
width += fprintf(iv->outfile,"0x%x", *cp++);
else
width += fprintf(iv->outfile,",0x%x", *cp++);
--cnt;
}
fputc('\n', iv->outfile);
width = 0;
}
}
static void
dump_unix_shorts(Piv iv, unsigned short *cp, int cnt)
{
int first=0, width = 0;
while(cnt > 1)
{
if(width == 0) {
width = fprintf(iv->outfile," .word ");
first = 0;
}
while(width <= 73 && cnt > 0)
{
if(!first++)
width += fprintf(iv->outfile,"0x%x", *cp++);
else
width += fprintf(iv->outfile,",0x%x", *cp++);
cnt -= 2;
}
fputc('\n', iv->outfile);
width = 0;
}
if(cnt > 0)
dump_unix_bytes(iv, (unsigned char *)cp, cnt);
}
static void
dump_unix_longs(Piv iv, unsigned long *cp, int cnt, long offset)
{
int first = 0, width = 0;
int rtyp;
char *psymb;
int extra;

while(cnt > 3)
{
if(width == 0) {
width = fprintf(iv->outfile," .long ");
first = 0;
}
while(width <= 69 && cnt > 0)
{
if(!first++)
{
if((rtyp = isa_reloc_loc(iv, offset, &psymb, &extra)))
{

if(rtyp == 1)
{
if(extra == 0)
{
width += fprintf(iv->outfile,"_%s", psymb);
}
else if(extra < 0)
{
width += fprintf(iv->outfile,"_%s%d", psymb,extra);
}
else
{
width += fprintf(iv->outfile,"_%s+%d", psymb,extra);
}
}
else
{
if(extra == 0)
{
width += fprintf(iv->outfile,"_$%p", psymb);
}
else if(extra < 0)
{
width += fprintf(iv->outfile,"_$%p%d", psymb,extra);
}
else
{
width += fprintf(iv->outfile,"_$%p+%d", psymb,extra);
}
}
}
else
{
width += fprintf(iv->outfile,"0x%x", *cp++);
}
}
else
{
if((rtyp = isa_reloc_loc(iv, offset, &psymb, &extra)))
{
if(rtyp == 1)
{
if(extra == 0)
{
width += fprintf(iv->outfile,",_%s", psymb);
}
else if(extra < 0)
{
width += fprintf(iv->outfile,",_%s%d", psymb,extra);
}
else
{
width += fprintf(iv->outfile,",_%s+%d", psymb,extra);
}
}
else
{
if(extra == 0)
{
width += fprintf(iv->outfile,",_$%p", psymb);
}
else if(extra < 0)
{
width += fprintf(iv->outfile,",_$%p%d", psymb,extra);
}
else
{
width += fprintf(iv->outfile,",_$%p+%d", psymb,extra);
}
}
}
else
{
width += fprintf(iv->outfile,",0x%x", *cp++);
}
}
offset += 4;
cnt -= 4;
}
fputc('\n', iv->outfile);
width = 0;
}
if(cnt > 0)
dump_unix_shorts(iv, (unsigned short*)cp, cnt);
}
static void
dump_unix_strings(Piv iv)
{
fprintf(iv->outfile,"\n.data\n");
if(SymHead(iv->datatbl))
{
while(SymNext(iv->datatbl))
{
unsigned char *p;
long size;
unsigned char opcode;
unsigned long *key;
struct _dval *val;

SymKey(iv->datatbl, &key);
SymValue(iv->datatbl, &val);
p = val->p;
opcode = *p;
size = val->size;
if(opcode == stringblockop)
{
fprintf(iv->outfile,"_$%x:\n", GL(POP->data1));
dump_unix_bytes(iv, p+24, size);
}
}
}
}
static void
dump_unix_data(Piv iv)
{
long mark[2];

fprintf(iv->outfile,"\n");
if(SymHead(iv->datatbl))
{
while(SymNext(iv->datatbl))
{
unsigned char *p;
long size;
unsigned char opcode;
unsigned long *key;
struct _dval *val;
long offset;

SymGetMark(iv->datatbl, mark);
SymKey(iv->datatbl, &key);
SymValue(iv->datatbl, &val);
p = val->p;
opcode = *p;
size = val->size;
offset = GL(POP->data1);
if(opcode == datablockop)
{
if(size > 3)
fprintf(iv->outfile, ".align 2\n_%s:\n",
iv->symaddr[GS(POP->data2)]);
else if(size > 1)
fprintf(iv->outfile, ".align 1\n_%s:\n",
iv->symaddr[GS(POP->data2)]);
dump_unix_longs(iv, (long*)(p+24), size, offset);
}
else if(opcode == mallocblockop)
{
fprintf(iv->outfile, ".align 2\n_$%x:\n", offset);

dump_unix_longs(iv, (long*)(p+24), size, offset);
}
SymSetMark(iv->datatbl, mark);
}
}
}
static void
dump_unix_funcs(Piv iv)
{
Pafile pf;
unsigned char *p;
int i;

fprintf(iv->outfile, "\n\n.text\n");
for(i = 0; i < iv->numfiles; ++i)
{
iv->filenum = i;
pf = iv->files[i];
p = pf->file_p;

while(*p != endfileop)
{
if(*p == labelop)
{
newlabel_insert(iv, GL( POP->data ));
}
else if(*p == gfuncdefop || *p == sfuncdefop)
{
p = dumpa_unix_func(iv, p);
}
else if(*p == anfblockop)
{
PERROR(pName ": Sorry, Outer anf blocks not handled.\n");
}
p = POP->next;
}
}
}
static void
gen_unix_output(Piv iv)
{
long tim = time(0);
char *date = ctime(&tim);

fprintf(iv->outfile,"// `%s' %s// ", iv->outname, date);
fprintf(iv->outfile,notice,MAJOR_VERSION,MINOR_VERSION);
fprintf(iv->outfile,"\n\n");

dump_unix_header(iv);
dump_unix_globals(iv);
dump_unix_strings(iv);
dump_unix_data(iv);
dump_unix_funcs(iv);
dump_unix_bss(iv);
}
static void
gen_dos_output(Piv iv)
{
long tim = time(0);
char *date = ctime(&tim);
fprintf(iv->outfile,"; `%s' %s\n;", iv->outname, date);
fprintf(iv->outfile,notice,MAJOR_VERSION,MINOR_VERSION);
fprintf(iv->outfile,"\n\n");
}
static int
gen_output(Piv iv, char *outpath)
{/* Assembler output */
char *cp;
Pafile pf;
char outname[256];

strcpy(outname, outpath);
pf = iv->files[0];
iv->target_assembler = pf->header_p->hdr.target_assembler;
iv->target_hardware = pf->header_p->hdr.target_hardware;
iv->target_debugger = pf->header_p->hdr.target_debugger;
iv->target_os = pf->header_p->hdr.target_os;
iv->memory_model = pf->header_p->hdr.memory_model;
iv->obj_format = pf->header_p->hdr.obj_format;
if((cp = strrchr(outname, '.')))
{
if(iv->target_assembler == UNIX || iv->target_assembler == GAS)
strcpy(cp, ".s");
else strcpy(cp, ".asm");
}
else
{
if(iv->target_assembler == UNIX || iv->target_assembler == GAS)
strcat(outname, ".s");
else
strcat(outname, ".asm");
}
if(!(iv->outfile = fopen(outname, "wb")))
{
PERROR(pName ": Cannot open output file %s\n", outname);
}
if(!(iv->outname = strrchr(outname, '/')))
iv->outname = outname;

make_final_symtab(iv);

iv->ob = new_nodeO(iv); /* setup first output node */
link_ob(iv); /* null node never unlinked */
if(iv->target_assembler == UNIX || iv->target_assembler == GAS)
gen_unix_output(iv);
else
gen_dos_output(iv);

fclose(iv->outfile);
iv->outfile = 0;
return iv->errors;
}
/* ======================= END ASMCODE 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];
return p;
}
size = sizeof(struct _nodeM) + levels * sizeof(void*);
p = new_chunk(bp, size, type);
p->levels = levels;
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
{/* 44 bytes -- adjust size to suit application */
unsigned long value[5]; /* 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 -1;
}
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 -1;
}
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) == 1)
{
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) == 1)
{
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) == 1)
{
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)
{
*p = 0;
break;
}
else
{/* may be needed for code generation */
*p = aliastmpop;
}
}
}
}
if(*p)
{
if(*p == jmptrueop || *p == jmpfalseop)
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) == 1)
{
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) == 1)
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) == 1)
{
*result = ++iv->labelnum;
}
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) == 1)
{
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 = fileno; /* fileno */
val.opcode = *p; /* opcode */
val.rsize = GL(POPI->reloc.rsize); /* reloc size */
val.p = p; /* pointer to input buffer */
val.base = 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, 18);
}
static void
data_insert(void *tbl, unsigned long offset,
unsigned long size, void *p, void *prevp)
{
static long locid = 1;
struct _dkey key;
struct _dval val;

unsigned char opcode, prevopcode = 0;

key.offset = offset;
key.pad = 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 == 'I')
{
PRINTF("OP(%d '%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);
pf->decladdr = Ccalloc(iv->category, sizeof(void*), pf->numdecls);

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 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);
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);
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), pf->numdecls);
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);
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 20 bytes */
unsigned long size;
unsigned char *p;
unsigned char unused[12];
/* 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(vp->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(vp->rsize == 4)
{/* 32 bit relocation */
unsigned long *lp;

if(noset)
goto reset32;

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 = (long)lp;
reset32:
{
struct _rkey key;
struct _rval val;

key.spot = GL(POPI->reloc.spot);
key.fileno = 0;
val.opcode = *p;
val.rsize = GL(POPI->reloc.rsize);
val.p = p;
val.base = GL(POPI->reloc.base);
val.offset = GL(POPI->reloc.offset);
val.rsym = GS(POPI->reloc.rsym);
val.fileno = kp->fileno;
SymInsert(iv->newreloctbl, &key, &val, 18);
}
}
else
{
++iv->errors;
PWARN(pName ":syserr: 32 bit object at offset %d not found\n",object_base);
}
}
else if(vp->rsize == 2)
{/* 16 bit relocation (MORE WORK NEEDED) */
unsigned short *sp;

if(noset)
goto reset16;
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 */
reset16:
{
struct _rkey key;
struct _rval val;

key.spot = GL(POPI->reloc.spot);
key.fileno = 0;
val.opcode = *p;
val.rsize = GL(POPI->reloc.rsize);
val.p = p;
val.base = GL(POPI->reloc.base);
val.offset = GL(POPI->reloc.offset);
val.rsym = GS(POPI->reloc.rsym);
val.fileno = kp->fileno;
SymInsert(iv->newreloctbl, &key, &val, 18);
}
}
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) == 0)
{/* 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) == 1)
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->newreloctbl = 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);
iv->decladdr = Ccalloc(iv->category, sizeof(void*), iv->numdecls);
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;

iv->infile_name = infile_name;
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->obuf = (char*)&iv->obufstart;
iv->jbuf = (PJL)&iv->jbufstart;
return iv;
}
void
Global(close_instance) (void *iv)
{
if(((Piv)iv)->outfile)
fclose(((Piv)iv)->outfile);
Cfreecat(((Piv)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 " [-odsLD?] [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"
" -? == 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;
int ret;

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 '?':
Usage();
return 0;
default:
PWARN(pName ": Invalid switch: %c\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) */

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;

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 : OXCCAX.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/