Category : Recently Uploaded Files
Archive   : OXCC1433.ZIP
Filename : BTERP.C

 
Output of file : BTERP.C contained in archive : OXCC1433.ZIP

/*
bterp.c -- v1.430 interpreter prototype for oxcc byte codes

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

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

*/

#define SUPPORT_LONG_LONG 1
#define SUPPORT_LONG_DOUBLE 1

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

#define NEED_FUNCTHUNK 1
#include "oxanf.h"
#include
#include
#include

#define PROG bterp
#define USING_FRAMEWORK 1

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

typedef struct _nodeS
{
unsigned long value;
unsigned long key[2];
struct _nodeS *fptr;
} NodeS, *NodePS;

typedef struct _callblk {
void *loc;
char *es;
unsigned short argofs;
unsigned short flags;
long argsiz;
char *base_stack; /* must be last element */
} *PCB;

typedef struct _stakblk {
void *backlink;
long first_loc;
long last_loc;
char *cbes;
void *thunkaddr;
int stksize;
} SB, *PSB;

typedef struct _fe {
char *filename;
long string_size;
char *strings;
char *text_start_address;
char *data_start_address;
char *bss_start_address;
} *FE;

typedef struct _iv {
struct _iv *piv;
char *text_base;
char *dd;
void **struclist;
long slcnt;
long strretcnt;
void *allocalist;
NodePS *swtable;
char *chunkbase;
void *chunklist;
long chunksize;
FE entry;
char *filename;
char *funcptr;
Pft ft;
long funcaddr;
long stksiz;
long argsiz;
long maxes;
char *base_stack;
char *e_stack;
jmp_buf jb;
#define MAX_RUNARGS 15
long run_argcnt;
char *run_args[MAX_RUNARGS];
int debug;
} *Piv;

typedef struct _retval {
void *ptr;
long p1;
long p2;
} RV;

int cfeprintf(const char *fmt, ...);

void _ExternCall();
void _ExternCallS();
void *oxlink_load_bare_symb(const char *symb, int dynlink);
void *oxlink_find_bare_func(const char *);
void *oxlink_find_func(const char *);
int oxlink_load_file(const char *);
int oxlink_load_object(const char *);
int oxlink_unload_file(const char *, int);
void oxlink_demand_load(void);
void oxlink_demand_noload(void);
void *oxlink_get_entry_struct(const char *filename);
char *oxlink_errstr(void);

static void* bterp_eval();

#define SZ (20) /* size of evaluation stack frame */

#define MIN(a,b) ((a
#define SRC(a) (a<<4)
#define G1(a) ((unsigned long)*((unsigned char*)(a)))
#define G2(a) ((unsigned long)*((unsigned short*)(a)))
#define G3(a) (*((unsigned long*)(a))&0x00ffffff)
#define G4(a) (*((unsigned long*)(a)))
#define G8(a) (*((double*)(a)))
#define GX(a) (*((long double*)(a)))
#define GP1(a) ((long)*((char*)(a)))
#define GP2(a) ((long)*((short*)(a)))
#define GP3(a) ((*((long*)(a))<<8)>>8)
#define GP4(a) (*((long*)(a)))

#define NEG_ES(t) {*((t*)es)=-(*((t*)es));break;}
#define NOT_ES(t) {*((t*)es)=!(*((t*)es));break;}
#define NOT_ES1 {*es=(((long*)es)[0]==0&&((long*)es)[1]==0)?1:0;}
#define COMP_ES(t) {*((t*)es)=~(*((t*)es));break;}
#define TRUTH_ES(t) {*((long*)es)=(*((t*)es))?1:0;break;}
#define TRUTH_ES1 {*((long*)es)=(((long*)es)[0]==0&&((long*)es)[1]==0)?0:1;}
#define GT_ES(t) {*((long*)oes)=(*((t*)oes)>*((t*)es))?1:0;es=oes;break;}
#define LT_ES(t) {*((long*)oes)=(*((t*)oes)<*((t*)es))?1:0;es=oes;break;}
#define GE_ES(t) {*((long*)oes)=(*((t*)oes)>=*((t*)es))?1:0;es=oes;break;}
#define LE_ES(t) {*((long*)oes)=(*((t*)oes)<=*((t*)es))?1:0;es=oes;break;}
#define NE_ES(t) {*((long*)oes)=(*((t*)oes)!=*((t*)es))?1:0;es=oes;break;}
#define EQ_ES(t) {*((long*)oes)=(*((t*)oes)==*((t*)es))?1:0;es=oes;break;}
#define ADD_ES(t) {*((t*)oes)+=*((t*)es);es=oes;break;}
#define SUB_ES(t) {*((t*)oes)-=*((t*)es);es=oes;break;}
#define MUL_ES(t) {*((t*)oes)*=*((t*)es);es=oes;break;}
#define DIV_ES(t) {*((t*)oes)/=*((t*)es);es=oes;break;}
#define OR_ES(t) {*((t*)oes)|=*((t*)es);es=oes;break;}
#define AND_ES(t) {*((t*)oes)&=*((t*)es);es=oes;break;}
#define XOR_ES(t) {*((t*)oes)^=*((t*)es);es=oes;break;}
#define MOD_ES(t) {*((t*)oes)%=*((unsigned long*)es);es=oes;break;}
#define MODL_ES(t) {*((t*)oes)%=*((unsigned long long*)es);es=oes;break;}
#define MODI_ES(t) {*((t*)es)%=*((unsigned short*)np);pc+=2;break;}
#define RSH_ES(t) {*((t*)oes)>>=*((unsigned char*)es);es=oes;break;}
#define LSH_ES(t) {*((t*)oes)<<=*((unsigned char*)es);es=oes;break;}
#define RSHI_ES(t) {*((t*)es)>>=*np;pc+=1;break;}
#define LSHI_ES(t) {*((t*)es)<<=*np;pc+=1;break;}
#define DEREF_ES(t) {*((long*)es)=**((t**)es);break;}
#define UDEREF_ES(t) {*((unsigned long*)es)=**((t**)es);break;}
#define FDEREF_ES(t) {*((t*)es)=**((t**)es);break;}
#define DEREF1_ES(t) {*((long*)nes)=**((t**)es);es=nes;break;}
#define UDEREF1_ES(t) {*((unsigned long*)nes)=**((t**)es);es=nes;break;}
#define FDEREF1_ES(t) {*((t*)nes)=**((t**)es);es=nes;break;}
#define SIGNE if(*(es+3)&0x80)*((long*)(es+4))=-1;else *((long*)(es+4))=0
#define USIGNE *((long*)(es+4))=0
#define LOADI1() {*((long*)nes)=GP1(np);es=nes;SIGNE;pc+=1;break;}
#define LOADI2() {*((long*)nes)=GP2(np);es=nes;SIGNE;pc+=2;break;}
#define LOADI4() {*((long*)nes)=GP4(np);es=nes;SIGNE;pc+=4;break;}
#define LOADUI1() {*((unsigned long*)nes)=G1(np);es=nes;USIGNE;pc+=1;break;}
#define LOADUI2() {*((unsigned long*)nes)=G2(np);es=nes;USIGNE;pc+=2;break;}
#define LOADUI4() {*((unsigned long*)nes)=G4(np);es=nes;USIGNE;pc+=4;break;}
#define LOADI8() {*((double*)nes)=G8(np);es=nes;pc+=8;break;}
#define LOADIX() {*((long double*)nes)=GX(np);es=nes;pc+=XSZ;break;}

#define LOADADDRI1() {*((unsigned long*)nes)=(G1(np)<<2);es=nes;pc+=1;break;}
#define LOADADDRI2() {*((unsigned long*)nes)=(G2(np)<<2);es=nes;pc+=2;break;}
#define LOADADDRI3() {*((unsigned long*)nes)=(G3(np));es=nes;pc+=3;break;}
#define LOADADDRI4() {*((unsigned long*)nes)=G4(np);es=nes;pc+=4;break;}

#define LOADSTK1(t) {*((t*)nes)=*((t*)(fs+(G1(np)<<2)));es=nes;pc+=1;break;}
#define LOADSTK2(t) {*((t*)nes)=*((t*)(fs+(G2(np)<<2)));es=nes;pc+=2;break;}
#define LOADSTK3(t) {*((t*)nes)=*((t*)(fs+(G3(np))));es=nes;pc+=3;break;}

#define STORSTK1(t) {*((t*)(fs+(G1(np)<<2)))=*((t*)es);es=oes;pc+=1;break;}
#define STORSTK2(t) {*((t*)(fs+(G2(np)<<2)))=*((t*)es);es=oes;pc+=2;break;}
#define STORSTK3(t) {*((t*)(fs+(G3(np)<<0)))=*((t*)es);es=oes;pc+=3;break;}

#define STORSTKI1(t) {*((t*)(fs+(G1(np)<<2)))=*((t*)(np+1));pc+=sizeof(t)+1;break;}
#define STORSTKI2(t) {*((t*)(fs+(G2(np)<<2)))=*((t*)(np+2));pc+=sizeof(t)+2;break;}
#define STORSTKI3(t) {*((t*)(fs+(G3(np)<<0)))=*((t*)(np+3));pc+=sizeof(t)+3;break;}

#define LOADMEM1(t) {*((t*)nes)=*((t*)(dd+(G1(np)<<2)));es=nes;pc+=1;break;}
#define LOADMEM2(t) {*((t*)nes)=*((t*)(dd+(G2(np)<<2)));es=nes;pc+=2;break;}
#define LOADMEM3(t) {*((t*)nes)=*((t*)(dd+(G3(np))));es=nes;pc+=3;break;}
#define LOADMEM4(t) {*((t*)nes)=*((t*)((void*)G4(np)));es=nes;pc+=4;break;}

#define STORMEM1(t) {*((t*)(dd+(G1(np)<<2)))=*((t*)es);es=oes;pc+=1;break;}
#define STORMEM2(t) {*((t*)(dd+(G2(np)<<2)))=*((t*)es);es=oes;pc+=2;break;}
#define STORMEM3(t) {*((t*)(dd+(G3(np)<<2)))=*((t*)es);es=oes;pc+=3;break;}
#define STORMEM4(t) {*((t*)((void*)G4(np)))=*((t*)es);es=oes;pc+=4;break;}

#define STORMEMI1(t) {*((t*)(dd+(G1(np)<<2)))=*((t*)(np+1));pc+=sizeof(t)+1;break;}
#define STORMEMI2(t) {*((t*)(dd+(G2(np)<<2)))=*((t*)(np+2));pc+=sizeof(t)+2;break;}

#define STORMEMI3(t) {*((t*)(dd+(G3(np)<<0)))=*((t*)(np+3));pc+=sizeof(t)+3;break;}
#define STORMEMI4(t) {*((t*)((void*)G4(np)))=*((t*)(np+4));pc+=sizeof(t)+4;break;}

static unsigned long bfields[33] = {
0x00000000,0x00000001,0x00000003,0x00000007,
0x0000000f,0x0000001f,0x0000003f,0x0000007f,
0x000000ff,0x000001ff,0x000003ff,0x000007ff,
0x00000fff,0x00001fff,0x00003fff,0x00007fff,
0x0000ffff,0x0001ffff,0x0003ffff,0x0007ffff,
0x000fffff,0x001fffff,0x003fffff,0x007fffff,
0x00ffffff,0x01ffffff,0x03ffffff,0x07ffffff,
0x0fffffff,0x1fffffff,0x3fffffff,0x7fffffff,
0xfffffff
};
static unsigned long tsfields[33] = {
0x00000000,0x00000001,0x00000002,0x00000004,
0x00000008,0x00000010,0x00000020,0x00000040,
0x00000080,0x00000100,0x00000200,0x00000400,
0x00000800,0x00001000,0x00002000,0x00004000,
0x00008000,0x00010000,0x00020000,0x00040000,
0x00080000,0x00100000,0x00200000,0x00400000,
0x00800000,0x01000000,0x02000000,0x04000000,
0x08000000,0x10000000,0x20000000,0x40000000,
0x80000000
};
static unsigned long sfields[33] = {
0x00000000,0xfffffffe,0xfffffffc,0xfffffff8,
0xfffffff0,0xffffffe0,0xffffffc0,0xffffff80,
0xffffff00,0xfffffe00,0xfffffc00,0xfffff800,
0xfffff000,0xffffe000,0xffffc000,0xffff8000,
0xffff0000,0xfffe0000,0xfffc0000,0xfff80000,
0xfff00000,0xffe00000,0xffc00000,0xff800000,
0xff000000,0xfe000000,0xfc000000,0xf8000000,
0xf0000000,0xe0000000,0xc0000000,0x80000000,
0x80000000
};
#if SUPPORT_LONG_LONG
static unsigned long long lbfields[65] = {
0x0000000000000000LL,0x0000000000000001LL,0x0000000000000003LL,0x0000000000000007LL,
0x000000000000000fLL,0x000000000000001fLL,0x000000000000003fLL,0x000000000000007fLL,
0x00000000000000ffLL,0x00000000000001ffLL,0x00000000000003ffLL,0x00000000000007ffLL,
0x0000000000000fffLL,0x0000000000001fffLL,0x0000000000003fffLL,0x0000000000007fffLL,
0x000000000000ffffLL,0x000000000001ffffLL,0x000000000003ffffLL,0x000000000007ffffLL,
0x00000000000fffffLL,0x00000000001fffffLL,0x00000000003fffffLL,0x00000000007fffffLL,
0x0000000000ffffffLL,0x0000000001ffffffLL,0x0000000003ffffffLL,0x0000000007ffffffLL,
0x000000000fffffffLL,0x000000001fffffffLL,0x000000003fffffffLL,0x000000007fffffffLL,
0x00000000ffffffffLL,0x00000001ffffffffLL,0x00000003ffffffffLL,0x00000007ffffffffLL,
0x0000000fffffffffLL,0x0000001fffffffffLL,0x0000003fffffffffLL,0x0000007fffffffffLL,
0x000000ffffffffffLL,0x000001ffffffffffLL,0x000003ffffffffffLL,0x000007ffffffffffLL,
0x00000fffffffffffLL,0x00001fffffffffffLL,0x00003fffffffffffLL,0x00007fffffffffffLL,
0x0000ffffffffffffLL,0x0001ffffffffffffLL,0x0003ffffffffffffLL,0x0007ffffffffffffLL,
0x000fffffffffffffLL,0x001fffffffffffffLL,0x003fffffffffffffLL,0x007fffffffffffffLL,
0x00ffffffffffffffLL,0x01ffffffffffffffLL,0x03ffffffffffffffLL,0x07ffffffffffffffLL,
0x0fffffffffffffffLL,0x1fffffffffffffffLL,0x3fffffffffffffffLL,0x7fffffffffffffffLL,
0xfffffffffffffffLL
};
static unsigned long long ltsfields[65] = {
0x0000000000000000LL,0x0000000000000001LL,0x0000000000000002LL,0x0000000000000004LL,
0x0000000000000008LL,0x0000000000000010LL,0x0000000000000020LL,0x0000000000000040LL,
0x0000000000000080LL,0x0000000000000100LL,0x0000000000000200LL,0x0000000000000400LL,
0x0000000000000800LL,0x0000000000001000LL,0x0000000000002000LL,0x0000000000004000LL,
0x0000000000008000LL,0x0000000000010000LL,0x0000000000020000LL,0x0000000000040000LL,
0x0000000000080000LL,0x0000000000100000LL,0x0000000000200000LL,0x0000000000400000LL,
0x0000000000800000LL,0x0000000001000000LL,0x0000000002000000LL,0x0000000004000000LL,
0x0000000008000000LL,0x0000000010000000LL,0x0000000020000000LL,0x0000000040000000LL,
0x0000000080000000LL,0x0000000100000000LL,0x0000000200000000LL,0x0000000400000000LL,
0x0000000800000000LL,0x0000001000000000LL,0x0000002000000000LL,0x0000004000000000LL,
0x0000008000000000LL,0x0000010000000000LL,0x0000020000000000LL,0x0000040000000000LL,
0x0000080000000000LL,0x0000100000000000LL,0x0000200000000000LL,0x0000400000000000LL,
0x0000800000000000LL,0x0001000000000000LL,0x0002000000000000LL,0x0004000000000000LL,
0x0008000000000000LL,0x0010000000000000LL,0x0020000000000000LL,0x0040000000000000LL,
0x0080000000000000LL,0x0100000000000000LL,0x0200000000000000LL,0x0400000000000000LL,
0x0800000000000000LL,0x1000000000000000LL,0x2000000000000000LL,0x4000000000000000LL,
0x8000000000000000LL
};
static unsigned long long lsfields[65] = {
0x0000000000000000LL,0xfffffffffffffffeLL,0xfffffffffffffffcLL,0xfffffffffffffff8LL,
0xfffffffffffffff0LL,0xffffffffffffffe0LL,0xffffffffffffffc0LL,0xffffffffffffff80LL,
0xffffffffffffff00LL,0xfffffffffffffe00LL,0xfffffffffffffc00LL,0xfffffffffffff800LL,
0xfffffffffffff000LL,0xffffffffffffe000LL,0xffffffffffffc000LL,0xffffffffffff8000LL,
0xffffffffffff0000LL,0xfffffffffffe0000LL,0xfffffffffffc0000LL,0xfffffffffff80000LL,
0xfffffffffff00000LL,0xffffffffffe00000LL,0xffffffffffc00000LL,0xffffffffff800000LL,
0xffffffffff000000LL,0xfffffffffe000000LL,0xfffffffffc000000LL,0xfffffffff8000000LL,
0xfffffffff0000000LL,0xffffffffe0000000LL,0xffffffffc0000000LL,0xffffffff80000000LL,
0xffffffff00000000LL,0xfffffffe00000000LL,0xfffffffc00000000LL,0xfffffff800000000LL,
0xfffffff000000000LL,0xffffffe000000000LL,0xffffffc000000000LL,0xffffff8000000000LL,
0xffffff0000000000LL,0xfffffe0000000000LL,0xfffffc0000000000LL,0xfffff80000000000LL,
0xfffff00000000000LL,0xffffe00000000000LL,0xffffc00000000000LL,0xffff800000000000LL,
0xffff000000000000LL,0xfffe000000000000LL,0xfffc000000000000LL,0xfff8000000000000LL,
0xfff0000000000000LL,0xffe0000000000000LL,0xffc0000000000000LL,0xff80000000000000LL,
0xff00000000000000LL,0xfe00000000000000LL,0xfc00000000000000LL,0xf800000000000000LL,
0xf000000000000000LL,0xe000000000000000LL,0xc000000000000000LL,0x8000000000000000LL,
0x8000000000000000LL
};
#endif /* SUPPORT_LONG_LONG */

static char thunk386[41] =
{/* THE EXTERNAL CALLBACK THUNK (Intel 386) */
0x55, /* pushl %ebp */
0x89,0xE5, /* movl %esp,%ebp */
0x68,0,0,0,0, /* pushl ft */
0x68,0,0,0,0, /* pushl iv */
0x68,0,0,0,0, /* pushl base_stack */
0x83,0xEC,0x0C, /* subl $12,%esp (RETVAL) */
0xB8,0,0,0,0, /* movl _bterp_handle_callbacks,%eax */
0xFF,0xD0, /* call *%eax */
0x8B,0x04,0x24, /* movl (%esp),%eax */
0x8B,0x54,0x24,0x04,/* movl 4(%esp),%edx */
0x8B,0x4C,0x24,0x08,/* movl 8(%esp),%ecx */
0xC9, /* leave */
0xC3 /* ret */
};
static char thunk386S[42] =
{/* THE EXTERNAL CALLBACK THUNK (Intel 386) */
0x55, /* pushl %ebp */
0x89,0xE5, /* movl %esp,%ebp */
0x68,0,0,0,0, /* pushl ft */
0x68,0,0,0,0, /* pushl iv */
0x68,0,0,0,0, /* pushl base_stack */
0x83,0xEC,0x0C, /* subl $12,%esp (RETVAL) */
0xB8,0,0,0,0, /* movl _bterp_handle_callbacks,%eax */
0xFF,0xD0, /* call *%eax */
0x8B,0x04,0x24, /* movl (%esp),%eax */
0x8B,0x54,0x24,0x04,/* movl 4(%esp),%edx */
0x8B,0x4C,0x24,0x08,/* movl 8(%esp),%ecx */
0xC9, /* leave */
0xC2,0x04 /* ret $4 (prune structret arg, GCC convention) */
};



/* ========================== INTERPRETER CODE =========================== */

static int
findswitch(Piv iv, unsigned long *key, void *result)
{
int bin;
NodePS node;
bin = (((~key[0] ^ key[1]) * 1103515245UL) + 12345) % SWITCHMOD;
if((node = iv->swtable[bin]))
{
do {
if(node->key[0] == key[0] && node->key[1] == key[1])
{
*((NodePS*)result) = node;
return 1;
}
} while((node = node->fptr));
}
return 0;
}
static void *
new_Snode(Piv iv)
{
void *p;

if(iv->chunksize < sizeof(NodeS))
{
iv->chunkbase = calloc(1, 4088);
*((void**)iv->chunkbase) = iv->chunklist;
iv->chunklist = iv->chunkbase;
iv->chunkbase += sizeof(void*);
iv->chunksize = 4088 - sizeof(void*);
}
p = iv->chunkbase;
iv->chunkbase += sizeof(NodeS);
iv->chunksize -= sizeof(NodeS);
return p;
}
static void
saveswitch(Piv iv, unsigned long *key, long value)
{
int bin;
NodePS node;

bin = (((~key[0] ^ key[1]) * 1103515245UL) + 12345) % SWITCHMOD;
node = new_Snode(iv);
node->key[0] = key[0];
node->key[1] = key[1];
node->value = value;
node->fptr = iv->swtable[bin];
iv->swtable[bin] = node;
}
static void
purge_allocas(Piv iv, void *last)
{
while(iv->allocalist && (iv->allocalist != last))
{
void *this = iv->allocalist;
iv->allocalist = *((void**)this);
free(this);
}
}

static void
_bterp_handle_callbacks(RV retval, char *base_stack, Piv iv, Pft ft,
int ebp, int pret, ...)
{/* Call to interpreted function from external function */
unsigned short fmods;
long stksiz, maxes, strucsiz, fs_size, argofs, es_beg, argsiz;
int hidden;
void *strret = 0;
void *argaddr, *e_stack, *lastalloca;
void *pes;
DATUM lastval;

fmods = ft->fmods;
argaddr = ((long*)&pret)+1;
if((hidden = (fmods & Fretstr)))
{/* return a struct or union */
strucsiz = ft->retsiz<<2;
strret = (void*) *(((long*)&pret)+1);
}
stksiz = ft->stksiz<<2;
maxes = ft->maxes;
argsiz = ft->argsiz<<2;

if(fmods & Fnested)
{/* callback to nested function */
argofs = ft->stkbeg+(stksiz-argsiz-hidden);
e_stack = ((PSB)base_stack)->cbes;
}
else
{/* callback to non-nested function */
if(fmods & Fellipsis)
argsiz += 128;
es_beg = stksiz+hidden+argsiz;
argofs = stksiz;
fs_size = es_beg + ((maxes+6)*SZ);

/* Create a stack for the called function */
base_stack = calloc(1, fs_size + sizeof(SB));
e_stack = base_stack + sizeof(SB) + es_beg;
((PSB)base_stack)->stksize = fs_size + sizeof(SB);
}

/* Copy the callers arguments */
memcpy(base_stack+argofs+sizeof(SB),argaddr,argsiz+hidden);

/* EVALUATE THE FUNCTION */
lastalloca = iv->allocalist;
pes = bterp_eval(iv, ft->funcaddr, base_stack, e_stack,
base_stack+((PSB)base_stack)->stksize);

/* Transfer the return value */
#if SUPPORT_LONG_DOUBLE
lastval.Ulongdouble = *((long double*)pes);
#else
lastval.Udouble = *((double*)pes);
#endif

/* Return to callers' stack */
if(fmods & Fretdbl)
{
asm ("fldl %0" :: "g"(lastval.Udouble));
}
else if(fmods & Fretflt)
{
asm ("flds %0" :: "g"(lastval.Ufloat));
}
else if(fmods & Fretldbl)
{
#if SUPPORT_LONG_DOUBLE
asm ("fstpt %0" :: "g"(lastval.Udouble));
#else
asm ("fldl %0" :: "g"(lastval.Udouble));
#endif
}
else if(strret)
{/* return pointer to struct */
retval.ptr = strret;
/* GCC needs this */
memcpy(&retval.p1, strret, MIN(8,strucsiz)); /* 8 bytes of struct */
}
else
{
retval.ptr = lastval.Upointer;
retval.p1 = lastval.lng.d[1];
retval.p2 = lastval.lng.d[2];
}
purge_allocas(iv, lastalloca);
if(fmods & Fnested)
{
#if 0
*((char**)pes) -= SZ;
#endif
ft->fmods &= ~Fthunked;
free(((PSB)base_stack)->thunkaddr);
}
else
{
free(base_stack);
}
}

static void *
make_callback_thunk(Piv iv, void *base_stack, Pft ft)
{
char *pth;

if(ft->fmods & Fretstr)
{
pth = malloc(sizeof(thunk386S));
memcpy(pth, thunk386S, sizeof(thunk386S));
}
else
{
pth = malloc(sizeof(thunk386));
memcpy(pth, thunk386, sizeof(thunk386));
}
*((long*)&pth[4]) = (long)ft;
*((long*)&pth[9]) = (long)iv;
*((long*)&pth[14]) = (long)base_stack;
*((long*)&pth[22]) = (long)_bterp_handle_callbacks;

return pth;
}
static void
ensure_strrets(Piv iv)
{
if(iv->strretcnt+1 >= iv->slcnt) {
iv->slcnt += 128;
iv->struclist = realloc(iv->struclist, iv->slcnt * sizeof(void *));
}
}
static void
prune_structs(Piv iv)
{
while(iv->strretcnt > 0)
{
free(iv->struclist[--iv->strretcnt]);
}
}
static int
mover(Piv iv, unsigned char *dp, int opcode, int size, char *src, char *dst)
{
char *s, *d;
int bump;

switch(opcode)
{
case S1|D1:
s = src+(G1(dp)<<2);
d = dst+(G1(dp+1)<<2);
bump = 3;
break;
case S1|D2:
s = src+(G1(dp)<<2);
d = dst+(G2(dp+1)<<2);
bump = 4;
break;
case S1|D3:
s = src+(G1(dp)<<2);
d = dst+(G3(dp+1)<<0);
bump = 5;
break;
case S1|D4:
s = src+(G1(dp)<<2);
d = (void*)G4(dp+1);
bump = 6;
break;
case S2|D1:
s = src+(G2(dp)<<2);
d = dst+G1(dp+2);
bump = 4;
break;
case S2|D2:
s = src+(G2(dp)<<2);
d = dst+(G2(dp+2)<<2);
bump = 5;
break;
case S2|D3:
s = src+(G2(dp)<<2);
d = dst+(G3(dp+2)<<0);
bump = 6;
break;
case S2|D4:
s = src+(G2(dp)<<2);
d = (void*)G4(dp+2);
bump = 7;
break;
case S3|D1:
s = src+(G3(dp)<<0);
d = dst+(G1(dp+3)<<2);
bump = 5;
break;
case S3|D2:
s = src+(G3(dp)<<0);
d = dst+(G2(dp+3)<<2);
bump = 6;
break;
case S3|D3:
s = src+(G3(dp)<<0);
d = dst+(G3(dp+3)<<0);
bump = 7;
break;
case S3|D4:
s = src+(G3(dp)<<0);
d = (void*)G4(dp+3);
bump = 8;
break;
case S4|D1:
s = (void*)G4(dp);
d = dst+(G1(dp+4)<<2);
bump = 6;
break;
case S4|D2:
s = (void*)G4(dp);
d = dst+(G2(dp+4)<<2);
bump = 7;
break;
case S4|D3:
s = (void*)G4(dp);
d = dst+(G3(dp+4)<<0);
bump = 8;
break;
case S4|D4:
s = (void*)G4(dp);
d = (void*)G4(dp+4);
bump = 9;
break;
default:
printf("bterp: BAD OPCODE for `mover' at pc=%lx\n",
((char*)dp - iv->text_base) - 1);
longjmp(iv->jb, 1);
}
if(size == B1)
*((char*)d) = *((char*)s);
else if(size == B2)
*((short*)d) = *((short*)s);
else if(size == B4)
*((long*)d) = *((long*)s);
else if(size == B8)
*((double*)d) = *((double*)s);
else
memcpy(d,s,XSZ);
return bump;
}
static void
load_efunc(Piv iv, Pft ft)
{
void *e_faddr;
if(!(e_faddr = oxlink_find_bare_func((void*)ft->funcaddr)))
{/* not in core, load the file */
if(!(e_faddr = oxlink_load_bare_symb((void*)ft->funcaddr, 1)))
{
printf("bterp: Can't load function `%s'\n", (char*)ft->funcaddr);
exit(1);
}
}
ft->funcaddr = (long)e_faddr;
ft->fmods |= Fthunked;
}
/* MOST OF THESE BUILTINS ARE UNNECESSARY DEMOS */
/* PUT ANYTHING THAT COULD BE CALLED THROUGH A FUNCPTR HERE */
static int
do_builtin(Piv iv, unsigned char code, char **pes)
{/* NOTE: builtins with no args and void return must leave a pseudo ret on stack */
char *es, *oes;
es = *pes;
oes = es-SZ;

switch(code)
{
case ALLOCA:
{
char *abuf = malloc(*((unsigned*)es)+sizeof(void*));
*((void**)es) = abuf+sizeof(void*);
*((void**)abuf) = iv->allocalist;
iv->allocalist = abuf;
return 1;
}
case STRLEN:
{
*((unsigned*)es) = strlen(*((const char**)es));
return 1;
}
case STRCPY:
{
*((void**)oes) = strcpy(*((char**)oes),*((const char**)es));
*pes = oes;
return 1;
}
case STRCAT:
{
*((void**)oes) = strcat(*((char**)oes),*((const char**)es));
*pes = oes;
return 1;
}
case MEMCPY:
{
*((void**)(oes-SZ)) = memcpy(*((void**)(oes-SZ)),*((const void**)oes),*((unsigned*)es));
*pes -= 2*SZ;
return 1;
}
case MEMMOVE:
{
*((void**)(oes-SZ)) = memmove(*((void**)(oes-SZ)),*((const void**)oes),*((unsigned*)es));
*pes -= 2*SZ;
return 1;
}
case MEMSET:
{
*((void**)(oes-SZ)) =
memset(*((void**)(oes-SZ)),*((int*)oes),*((long*)es));
*pes -= 2*SZ;
return 1;
}
case BZERO:
{
memset(*((void**)oes),0,*((unsigned*)es));
*pes = oes;
return 0;
}
case DEBUG:
{
iv->debug=1;
printf("DEBUG ON\n");
fflush(stdout);
*pes = es+SZ; /* pseudo ret */
return 0;
}
case NODEBUG:
{
iv->debug=0;
printf("DEBUG OFF\n");
fflush(stdout);
*pes = es+SZ; /* pseudo ret */
return 0;
}
case MALLOC:
{
*((void**)es) = malloc(*((unsigned*)es));
return 1;
}
case CALLOC:
{
*((void**)oes) = calloc(*((unsigned*)oes),*((unsigned*)es));
*pes = oes;
return 1;
}
case REALLOC:
{
*((void**)oes) = realloc(*((void**)oes),*((unsigned*)es));
*pes = oes;
return 1;
}
}
return 0;
}
static void *
bterp_eval(Piv iv, long pc_offset, void *base_stack, char *es, char *eb)
{
char *dd, *fs;
unsigned char *pc, *np;
char *oes, *nes, *bes;
long first_loc = -100;
long last_loc = 0;

dd = iv->dd;
fs = base_stack + sizeof(SB);
pc = iv->text_base + pc_offset;
bes = es;

if(iv->debug) {
printf("FUNCTION ofs=%lx pc=%p bs=%p fs=%p es=%p dd=%p eb=%p\n",
pc_offset, pc, base_stack, fs, es, dd, eb);
fflush(stdout);
}
for(;;++pc)
{
np = pc+1;
oes = es-SZ;
nes = es+SZ;

if(iv->debug) {
printf("ofs:%lx op=%x es=%p val=%lx oval=%lx nval=%lx\n",
((char*)pc) - iv->text_base, *pc, es,
*((long*)es), *((long*)oes), *((long*)nes));
fflush(stdout);
}
if(es < bes) {
printf("STACK UNDERFLOW ofs:%lx op=%x es=%p val=%lx oval=%lx nval=%lx\n",
((char*)pc) - iv->text_base, *pc, es, *((long*)es), *((long*)oes), *((long*)nes));
fflush(stdout);
longjmp(iv->jb, (int)es);
}
if(es >= eb) {
printf("STACK OVERFLOW ofs:%lx op=%x es=%p val=%lx oval=%lx nval=%lx\n",
((char*)pc) - iv->text_base, *pc, es, *((long*)es), *((long*)oes), *((long*)nes));
fflush(stdout);
longjmp(iv->jb, (int)es);
}
switch(*pc)
{
case LOCATE|J1:
{
last_loc = ((char*)(pc + GP1(np))) - iv->text_base;
if(first_loc == -100) first_loc = last_loc;
++pc;
break;
}
case LOCATE|J2:
{
last_loc = ((char*)(pc + GP2(np))) - iv->text_base;
if(first_loc == -100) first_loc = last_loc;
pc += 2;
break;
}
case LOCATE|J3:
{
last_loc = ((char*)(pc + GP3(np))) - iv->text_base;
if(first_loc == -100) first_loc = last_loc;
pc += 3;
break;
}
case LOCATE|J4:
{
last_loc = ((char*)(pc + GP4(np))) - iv->text_base;
if(first_loc == -100) first_loc = last_loc;
pc += 4;
break;
}
case LS|A1|B1:
LOADSTK1(char);
case LS|A1|B2:
LOADSTK1(short);
case LS|A1|B4:
LOADSTK1(long);
case LS|A1|B8:
LOADSTK1(double);
case LS|A2|B1:
LOADSTK2(char);
case LS|A2|B2:
LOADSTK2(short);
case LS|A2|B4:
LOADSTK2(long);
case LS|A2|B8:
LOADSTK2(double);
case LS|A3|B1:
LOADSTK3(char);
case LS|A3|B2:
LOADSTK3(short);
case LS|A3|B4:
LOADSTK3(long);
case LS|A3|B8:
LOADSTK3(double);

case NEG|BYTE:
NEG_ES(char);
case NEG|SHORT:
NEG_ES(short);
case NEG|LONG:
NEG_ES(long);
case NEG|UBYTE:
NEG_ES(unsigned char);
case NEG|USHORT:
NEG_ES(unsigned short);
case NEG|ULONG:
NEG_ES(unsigned long);
case NEG|FLOAT:
NEG_ES(float);
case NEG|DOUBLE:
NEG_ES(double);

case LM|A1|B1:
LOADMEM1(char);
case LM|A1|B2:
LOADMEM1(short);
case LM|A1|B4:
LOADMEM1(long);
case LM|A1|B8:
LOADMEM1(double);
case LM|A2|B1:
LOADMEM2(char);
case LM|A2|B2:
LOADMEM2(short);
case LM|A2|B4:
LOADMEM2(long);
case LM|A2|B8:
LOADMEM2(double);
case LM|A3|B1:
LOADMEM3(char);
case LM|A3|B2:
LOADMEM3(short);
case LM|A3|B4:
LOADMEM3(long);
case LM|A3|B8:
LOADMEM3(double);
case LM|A4|B1:
LOADMEM4(char);
case LM|A4|B2:
LOADMEM4(short);
case LM|A4|B4:
LOADMEM4(long);
case LM|A4|B8:
LOADMEM4(double);

case COMP|B1:
COMP_ES(char);
case COMP|B2:
COMP_ES(short);
case COMP|B4:
COMP_ES(long);
#if SUPPORT_LONG_LONG
case COMP|B8:
COMP_ES(long long);
#else
#endif
case JMP|J1:
pc += GP1(np)-1;
break;
case JMP|J2:
pc += GP2(np)-1;
break;
case JMP|J3:
pc += GP3(np)-1;
break;
case JMP|J4:
pc += GP4(np)-1;
break;

case LJMPT|J1:
if(*(es)) pc += GP1(np)-1;
else {pc += 1; es=oes;}
break;
case LJMPT|J2:
if(*(es)) pc += GP2(np)-1;
else {pc += 2; es=oes;}
break;
case LJMPT|J3:
if(*(es)) pc += GP3(np)-1;
else {pc += 3; es=oes;}
break;
case LJMPT|J4:
if(*(es)) pc += GP4(np)-1;
else {pc += 4; es=oes;}
break;

case JMPT|J1:
if(*(es)) pc += GP1(np)-1;
else pc += 1;
es = oes;
break;
case JMPT|J2:
if(*(es)) pc += GP2(np)-1;
else pc += 2;
es = oes;
break;
case JMPT|J3:
if(*(es)) pc += GP3(np)-1;
else pc += 3;
es = oes;
break;
case JMPT|J4:
if(*(es)) pc += GP4(np)-1;
else pc += 4;
es = oes;
break;

case LJMPF|J1:
if(!*(es)) pc += GP1(np)-1;
else {pc += 1; es=oes;}
break;
case LJMPF|J2:
if(!*(es)) pc += GP2(np)-1;
else {pc += 2; es=oes;};
break;
case LJMPF|J3:
if(!*(es)) pc += GP3(np)-1;
else {pc += 3; es=oes;}
break;
case LJMPF|J4:
if(!*(es)) pc += GP4(np)-1;
else {pc +=4; es=oes;}
break;

case JMPF|J1:
if(!*(es)) pc += GP1(np)-1;
else pc += 1;
es = oes;
break;
case JMPF|J2:
if(!*(es)) pc += GP2(np)-1;
else pc += 2;
es = oes;
break;
case JMPF|J3:
if(!*(es)) pc += GP3(np)-1;
else pc += 3;
es = oes;
break;
case JMPF|J4:
if(!*(es)) pc += GP4(np)-1;
else pc +=4;
es = oes;
break;

case NOT|B1:
NOT_ES(char);
case NOT|B2:
NOT_ES(short);
case NOT|B4: /* also FLOAT */
NOT_ES(long);
case NOT|B8: /* also DOUBLE */
#if SUPPORT_LONG_LONG
NOT_ES(long long);
#else
NOT_ES1;
#endif
case SS|A1|B1:
STORSTK1(char);
case SS|A1|B2:
STORSTK1(short);
case SS|A1|B4:
STORSTK1(long);
case SS|A1|B8:
STORSTK1(double);
case SS|A2|B1:
STORSTK2(char);
case SS|A2|B2:
STORSTK2(short);
case SS|A2|B4:
STORSTK2(long);
case SS|A2|B8:
STORSTK2(double);
case SS|A3|B1:
STORSTK3(char);
case SS|A3|B2:
STORSTK3(short);
case SS|A3|B4:
STORSTK3(long);
case SS|A3|B8:
STORSTK3(double);

case TRUTHOF|B2:
TRUTH_ES(short);
case TRUTHOF|B4: /* also FLOAT */
TRUTH_ES(long);
case TRUTHOF|B8: /* also DOUBLE */
#if SUPPORT_LONG_LONG
TRUTH_ES(long long);
#else
TRUTH_ES1;
#endif
case CVT:
{
++pc;
++np;
switch(*pc)
{
case SRC(BYTE)|SHORT:
*((short*)es) = *((char*)es);
break;
case SRC(BYTE)|LONG:
*((long*)es) = *((char*)es);
break;
case SRC(BYTE)|USHORT:
*((unsigned short*)es) = *((char*)es);
break;
case SRC(BYTE)|ULONG:
*((unsigned long*)es) = *((char*)es);
break;
case SRC(BYTE)|FLOAT:
*((float*)es) = *((char*)es);
break;
case SRC(BYTE)|DOUBLE:
*((double*)es) = *((char*)es);
break;
#if SUPPORT_LONG_LONG
case SRC(BYTE)|CLONGLONG:
*((long long*)es) = *((char*)es);
break;
case SRC(BYTE)|CULONGLONG:
*((unsigned long long*)es) = *((char*)es);
break;
#endif
#if SUPPORT_LONG_DOUBLE
case SRC(BYTE)|CLONGDOUBLE:
*((long double*)es) = *((char*)es);
break;
#endif
case SRC(SHORT)|LONG:
*((long*)es) = *((short*)es);
break;
case SRC(SHORT)|ULONG:
*((unsigned long*)es) = *((short*)es);
break;
case SRC(SHORT)|FLOAT:
*((float*)es) = *((short*)es);
break;
case SRC(SHORT)|DOUBLE:
*((double*)es) = *((short*)es);
break;
#if SUPPORT_LONG_LONG
case SRC(SHORT)|CLONGLONG:
*((long long*)es) = *((short*)es);
break;
case SRC(SHORT)|CULONGLONG:
*((unsigned long long*)es) = *((short*)es);
break;
#endif
#if SUPPORT_LONG_DOUBLE
case SRC(SHORT)|CLONGDOUBLE:
*((long double*)es) = *((short*)es);
break;
#endif
case SRC(LONG)|FLOAT:
*((float*)es) = *((long*)es);
break;
case SRC(LONG)|DOUBLE:
*((double*)es) = *((long*)es);
break;
#if SUPPORT_LONG_LONG
case SRC(LONG)|CLONGLONG:
*((long long*)es) = *((long*)es);
break;
case SRC(LONG)|CULONGLONG:
*((unsigned long long*)es) = *((long*)es);
break;
#endif
#if SUPPORT_LONG_DOUBLE
case SRC(LONG)|CLONGDOUBLE:
*((long double*)es) = *((long*)es);
break;
#endif
case SRC(UBYTE)|SHORT:
*((short*)es) = *((unsigned char*)es);
break;
case SRC(UBYTE)|LONG:
*((long*)es) = *((unsigned char*)es);
break;
case SRC(UBYTE)|USHORT:
*((unsigned short*)es) = *((unsigned char*)es);
break;
case SRC(UBYTE)|ULONG:
*((unsigned long*)es) = *((unsigned char*)es);
break;
case SRC(UBYTE)|FLOAT:
*((float*)es) = *((unsigned char*)es);
break;
case SRC(UBYTE)|DOUBLE:
*((double*)es) = *((unsigned char*)es);
break;
#if SUPPORT_LONG_LONG
case SRC(UBYTE)|CLONGLONG:
*((long long*)es) = *((unsigned char*)es);
break;
case SRC(UBYTE)|CULONGLONG:
*((unsigned long long*)es) = *((unsigned char*)es);
break;
#endif
#if SUPPORT_LONG_DOUBLE
case SRC(UBYTE)|CLONGDOUBLE:
*((long double*)es) = *((unsigned char*)es);
break;
#endif
case SRC(USHORT)|LONG:
*((long*)es) = *((unsigned short*)es);
break;
case SRC(USHORT)|ULONG:
*((unsigned long*)es) = *((unsigned short*)es);
break;
case SRC(USHORT)|FLOAT:
*((float*)es) = *((unsigned short*)es);
break;
case SRC(USHORT)|DOUBLE:
*((double*)es) = *((unsigned short*)es);
break;
#if SUPPORT_LONG_LONG
case SRC(USHORT)|CLONGLONG:
*((long long*)es) = *((unsigned short*)es);
break;
case SRC(USHORT)|CULONGLONG:
*((unsigned long long*)es) = *((unsigned short*)es);
break;
#endif
#if SUPPORT_LONG_DOUBLE
case SRC(USHORT)|CLONGDOUBLE:
*((long double*)es) = *((unsigned short*)es);
break;
#endif
case SRC(ULONG)|FLOAT:
*((float*)es) = *((unsigned long*)es);
break;
case SRC(ULONG)|DOUBLE:
*((double*)es) = *((unsigned long*)es);
break;
#if SUPPORT_LONG_LONG
case SRC(ULONG)|CLONGLONG:
*((long long*)es) = *((unsigned long*)es);
break;
case SRC(ULONG)|CULONGLONG:
*((unsigned long long*)es) = *((unsigned long*)es);
break;
#endif
#if SUPPORT_LONG_DOUBLE
case SRC(ULONG)|CLONGDOUBLE:
*((long double*)es) = *((unsigned long*)es);
break;
#endif
case SRC(FLOAT)|BYTE:
*((char*)es) = *((float*)es);
break;
case SRC(FLOAT)|SHORT:
*((short*)es) = *((float*)es);
break;
case SRC(FLOAT)|LONG:
*((long*)es) = *((float*)es);
break;
case SRC(FLOAT)|UBYTE:
*((unsigned char*)es) = *((float*)es);
break;
case SRC(FLOAT)|USHORT:
*((unsigned short*)es) = *((float*)es);
break;
case SRC(FLOAT)|ULONG:
*((unsigned long*)es) = *((float*)es);
break;
case SRC(FLOAT)|DOUBLE:
*((double*)es) = *((float*)es);
break;
#if SUPPORT_LONG_LONG
case SRC(FLOAT)|CLONGLONG:
*((long long*)es) = *((float*)es);
break;
case SRC(FLOAT)|CULONGLONG:
*((unsigned long long*)es) = *((float*)es);
break;
#endif
#if SUPPORT_LONG_DOUBLE
case SRC(FLOAT)|CLONGDOUBLE:
*((long double*)es) = *((float*)es);
break;
#endif
case SRC(DOUBLE)|BYTE:
*((char*)es) = *((double*)es);
break;
case SRC(DOUBLE)|SHORT:
*((short*)es) = *((double*)es);
break;
case SRC(DOUBLE)|LONG:
*((long*)es) = *((double*)es);
break;
case SRC(DOUBLE)|UBYTE:
*((unsigned char*)es) = *((double*)es);
break;
case SRC(DOUBLE)|USHORT:
*((unsigned short*)es) = *((double*)es);
break;
case SRC(DOUBLE)|ULONG:
*((unsigned long*)es) = *((double*)es);
break;
case SRC(DOUBLE)|FLOAT:
*((float*)es) = *((double*)es);
break;
#if SUPPORT_LONG_LONG
case SRC(DOUBLE)|CLONGLONG:
*((long long*)es) = *((double*)es);
break;
case SRC(DOUBLE)|CULONGLONG:
*((unsigned long long*)es) = *((double*)es);
break;
#endif
#if SUPPORT_LONG_DOUBLE
case SRC(DOUBLE)|CLONGDOUBLE:
*((long double*)es) = *((double*)es);
break;
#endif
#if SUPPORT_LONG_LONG
case SRC(CLONGLONG)|FLOAT:
*((float*)es) = *((long long*)es);
break;
case SRC(CLONGLONG)|DOUBLE:
*((double*)es) = *((long long*)es);
break;
#if SUPPORT_LONG_DOUBLE
case SRC(CLONGLONG)|CLONGDOUBLE:
*((long double*)es) = *((long long*)es);
break;
#endif
case SRC(CULONGLONG)|FLOAT:
*((float*)es) = *((unsigned long long*)es);
break;
case SRC(CULONGLONG)|DOUBLE:
*((double*)es) = *((unsigned long long*)es);
break;
#if SUPPORT_LONG_DOUBLE
case SRC(CULONGLONG)|CLONGDOUBLE:
*((long double*)es) = *((unsigned long long*)es);
break;
#endif
#endif
#if SUPPORT_LONG_DOUBLE
case SRC(CLONGDOUBLE)|BYTE:
*((char*)es) = *((long double*)es);
break;
case SRC(CLONGDOUBLE)|SHORT:
*((short*)es) = *((long double*)es);
break;
case SRC(CLONGDOUBLE)|LONG:
*((long*)es) = *((long double*)es);
break;
case SRC(CLONGDOUBLE)|UBYTE:
*((unsigned char*)es) = *((long double*)es);
break;
case SRC(CLONGDOUBLE)|USHORT:
*((unsigned short*)es) = *((long double*)es);
break;
case SRC(CLONGDOUBLE)|ULONG:
*((unsigned long*)es) = *((long double*)es);
break;
case SRC(CLONGDOUBLE)|FLOAT:
*((float*)es) = *((long double*)es);
break;
case SRC(CLONGDOUBLE)|DOUBLE:
*((double*)es) = *((long double*)es);
break;
#if SUPPORT_LONG_LONG
case SRC(CLONGDOUBLE)|CLONGLONG:
*((long long*)es) = *((long double*)es);
break;
case SRC(CLONGDOUBLE)|CULONGLONG:
*((unsigned long long*)es) = *((long double*)es);
break;
#endif
#endif
}
break;
}
case IMMED:
{
++pc;
++np;
switch(*pc)
{

case SMI|A1|B1:
STORMEMI1(char);
case SMI|A1|B2:
STORMEMI1(short);
case SMI|A1|B4:
STORMEMI1(long);
case SMI|A1|B8:
STORMEMI1(double);
case SMI|A2|B1:
STORMEMI2(char);
case SMI|A2|B2:
STORMEMI2(short);
case SMI|A2|B4:
STORMEMI2(long);
case SMI|A2|B8:
STORMEMI2(double);
case SMI|A3|B1:
STORMEMI3(char);
case SMI|A3|B2:
STORMEMI3(short);
case SMI|A3|B4:
STORMEMI3(long);
case SMI|A3|B8:
STORMEMI3(double);
case SMI|A4|B1:
STORMEMI4(char);
case SMI|A4|B2:
STORMEMI4(short);
case SMI|A4|B4:
STORMEMI4(long);
case SMI|A4|B8:
STORMEMI4(double);

case SSI|A1|B1:
STORSTKI1(char);
case SSI|A1|B2:
STORSTKI1(short);
case SSI|A1|B4:
STORSTKI1(long);
case SSI|A1|B8:
STORSTKI1(double);
case SSI|A2|B1:
STORSTKI2(char);
case SSI|A2|B2:
STORSTKI2(short);
case SSI|A2|B4:
STORSTKI2(long);
case SSI|A2|B8:
STORSTKI2(double);
case SSI|A3|B1:
STORSTKI3(char);
case SSI|A3|B2:
STORSTKI3(short);
case SSI|A3|B4:
STORSTKI3(long);
case SSI|A3|B8:
STORSTKI3(double);

case MODI|BYTE:
MODI_ES(char);
case MODI|SHORT:
MODI_ES(short);
case MODI|LONG:
MODI_ES(long);
case MODI|UBYTE:
MODI_ES(unsigned char);
case MODI|USHORT:
MODI_ES(unsigned short);
case MODI|ULONG:
MODI_ES(unsigned long);

case DEREF|BYTE:
DEREF_ES(char);
case DEREF|SHORT:
DEREF_ES(short);
case DEREF|LONG:
DEREF_ES(long);
case DEREF|UBYTE:
UDEREF_ES(unsigned char);
case DEREF|USHORT:
UDEREF_ES(unsigned short);
case DEREF|ULONG:
UDEREF_ES(unsigned long);
case DEREF|FLOAT:
FDEREF_ES(float);
case DEREF|DOUBLE:
FDEREF_ES(double);

case DEREF1|BYTE:
DEREF1_ES(char);
case DEREF1|SHORT:
DEREF1_ES(short);
case DEREF1|LONG:
DEREF1_ES(long);
case DEREF1|UBYTE:
UDEREF1_ES(unsigned char);
case DEREF1|USHORT:
UDEREF1_ES(unsigned short);
case DEREF1|ULONG:
UDEREF1_ES(unsigned long);
case DEREF1|FLOAT:
FDEREF1_ES(float);
case DEREF1|DOUBLE:
FDEREF1_ES(double);
}
break;
}
case LI|B1:
LOADI1();
case LI|B2:
LOADI2();
case LI|B4:
LOADI4();
case LI|B8:
LOADI8();
case LAI|D1:
LOADADDRI1();
case LAI|D2:
LOADADDRI2();
case LAI|D3:
LOADADDRI3();
case LAI|D4:
LOADADDRI4();

case LUI|B1:
LOADUI1();
case LUI|B2:
LOADUI2();
case LUI|B4:
LOADUI4();
case LUI|B8:
LOADI8();

case SM|A1|B1:
STORMEM1(char);
case SM|A1|B2:
STORMEM1(short);
case SM|A1|B4:
STORMEM1(long);
case SM|A1|B8:
STORMEM1(double);
case SM|A2|B1:
STORMEM2(char);
case SM|A2|B2:
STORMEM2(short);
case SM|A2|B4:
STORMEM2(long);
case SM|A2|B8:
STORMEM2(double);
case SM|A3|B1:
STORMEM3(char);
case SM|A3|B2:
STORMEM3(short);
case SM|A3|B4:
STORMEM3(long);
case SM|A3|B8:
STORMEM3(double);
case SM|A4|B1:
STORMEM4(char);
case SM|A4|B2:
STORMEM4(short);
case SM|A4|B4:
STORMEM4(long);
case SM|A4|B8:
STORMEM4(double);


case ADD|BYTE:
ADD_ES(char);
case ADD|SHORT:
ADD_ES(short);
case ADD|LONG:
ADD_ES(long);
case ADD|UBYTE:
ADD_ES(unsigned char);
case ADD|USHORT:
ADD_ES(unsigned short);
case ADD|ULONG:
ADD_ES(unsigned long);
case ADD|FLOAT:
ADD_ES(float);
case ADD|DOUBLE:
ADD_ES(double);

case SUB|BYTE:
SUB_ES(char);
case SUB|SHORT:
SUB_ES(short);
case SUB|LONG:
SUB_ES(long);
case SUB|UBYTE:
SUB_ES(unsigned char);
case SUB|USHORT:
SUB_ES(unsigned short);
case SUB|ULONG:
SUB_ES(unsigned long);
case SUB|FLOAT:
SUB_ES(float);
case SUB|DOUBLE:
SUB_ES(double);

case MUL|BYTE:
MUL_ES(char);
case MUL|SHORT:
MUL_ES(short);
case MUL|LONG:
MUL_ES(long);
case MUL|UBYTE:
MUL_ES(unsigned char);
case MUL|USHORT:
MUL_ES(unsigned short);
case MUL|ULONG:
MUL_ES(unsigned long);
case MUL|FLOAT:
MUL_ES(float);
case MUL|DOUBLE:
MUL_ES(double);

case DIV|BYTE:
DIV_ES(char);
case DIV|SHORT:
DIV_ES(short);
case DIV|LONG:
DIV_ES(long);
case DIV|UBYTE:
DIV_ES(unsigned char);
case DIV|USHORT:
DIV_ES(unsigned short);
case DIV|ULONG:
DIV_ES(unsigned long);
case DIV|FLOAT:
DIV_ES(float);
case DIV|DOUBLE:
DIV_ES(double);

case OR|B1:
OR_ES(unsigned char);
case OR|B2:
OR_ES(unsigned short);
case OR|B4:
OR_ES(unsigned long);

case XOR|B1:
XOR_ES(unsigned char);
case XOR|B2:
XOR_ES(unsigned short);
case XOR|B4:
XOR_ES(unsigned long);

case AND|B1:
AND_ES(unsigned char);
case AND|B2:
AND_ES(unsigned short);
case AND|B4:
AND_ES(unsigned long);

#if SUPPORT_LONG_LONG
case OR|B8:
OR_ES(unsigned long long);
case AND|B8:
AND_ES(unsigned long long);
case XOR|B8:
XOR_ES(unsigned long long);
#else
#endif

case MOD|BYTE:
MOD_ES(char);
case MOD|SHORT:
MOD_ES(short);
case MOD|LONG:
MOD_ES(long);
case MOD|UBYTE:
MOD_ES(unsigned char);
case MOD|USHORT:
MOD_ES(unsigned short);
case MOD|ULONG:
MOD_ES(unsigned long);

case XTD:
{
++pc;
++np;
switch(*pc)
{
case LSH|B1:
LSH_ES(char);
case LSH|B2:
LSH_ES(short);
case LSH|B4:
LSH_ES(long);
case LSH|B8:
LSH_ES(long long);

case LSHI|B1:
LSHI_ES(char);
case LSHI|B2:
LSHI_ES(short);
case LSHI|B4:
LSHI_ES(long);
case LSHI|B8:
LSHI_ES(long long);

case RSH|BYTE:
RSH_ES(char);
case RSH|SHORT:
RSH_ES(short);
case RSH|LONG:
RSH_ES(long);
case RSH|UBYTE:
RSH_ES(unsigned char);
case RSH|USHORT:
RSH_ES(unsigned short);
case RSH|ULONG:
RSH_ES(unsigned long);

case RSHI|BYTE:
RSHI_ES(char);
case RSHI|SHORT:
RSHI_ES(short);
case RSHI|LONG:
RSHI_ES(long);
case RSHI|UBYTE:
RSHI_ES(unsigned char);
case RSHI|USHORT:
RSHI_ES(unsigned short);
case RSHI|ULONG:
RSHI_ES(unsigned long);

case BUILTIN:
{
++pc;
++np;
switch(*pc)
{/* THESE BUILTINS CANNOT BE CALLED THROUGH A FUNCPTR */
case SETJMP:
{
long *jb;

jb = *((void**)es);
*((long*)es) = 0;

jb[0] = (long)iv->allocalist;
jb[1] = (long)pc;
if((jb = (long*)setjmp(((void*)&jb[4]))))
{
void *bs,*qs;
pc = (void*)jb[1];
*((long*)es) = jb[2];
bs = (void*)jb[3];
while(bs != base_stack)
{
qs = ((PSB)bs)->backlink;
free(bs);
bs = qs;
}
purge_allocas(iv, (void*)jb[0]);
prune_structs(iv);
}
break;
}
case LONGJMP:
{
long *jb;

jb = *((void**)oes);
jb[2] = *((long*)es);
jb[3] = (long)base_stack;
longjmp(((void*)&jb[4]), (long)jb);
break;
}
case ABORT:
printf("bterp: program called abort.\n");
case EXIT:
{
void *bs, *qs;
bs = base_stack;
while(bs != iv->base_stack)
{
qs = ((PSB)bs)->backlink;
free(bs);
bs = qs;
}
purge_allocas(iv, 0);
longjmp(iv->jb, (int)es);
break;
}
default:
do_builtin(iv, *pc, &es);
break;
}
break;
} /* END: XTD BUILTIN */
case CLRDAT:
{
memset(*((void**)oes), 0, *((long*)es));
es -= 2*SZ;
break;
}
case SWITCH:
{
unsigned long key[2];
unsigned char **result;

key[0] = *((unsigned short*)np)<<11;
key[1] = *((long*)es);
if(findswitch(iv, key, &result))
{
pc = *result - 1;
}
else
{
pc += 2;
}
es = oes;
break;
}
case CALLSETUP:
{
PCB cb = (PCB)es;
Pft ft = cb->loc;
int hidden;
long stksiz, maxes;
long argsiz, strucsiz;
int flags = 0;
if(ft->fmods & Fbuiltin)
{/* This only happens if the programmer uses a function
pointer which points to a builtin function. */
flags = 0x80;
}
cb->argsiz = argsiz = G4(np);

if((hidden = ft->fmods & Fretstr))
{/* function returning a structure */
strucsiz = ft->retsiz<<2;
}
stksiz = ft->stksiz<<2;
maxes = ft->maxes;

if(ft->fmods & Fnested)
{/* Calling nested function */
cb->argofs = (ft->stkbeg+(stksiz-(ft->argsiz<<2)-hidden)) >> 2;
if(ft->funcaddr >= first_loc && ft->funcaddr <= last_loc)
{/* call from enclosing function */
cb->base_stack = base_stack;
cb->es = es;
cb->flags = 0x10 + hidden;
}
else
{/* callback from another function */
PSB prev = (PSB)(fs - sizeof(SB));
long floc = prev->first_loc;
long lloc = prev->last_loc;

while((prev = prev->backlink))
{
if( ft->funcaddr >= floc
&& ft->funcaddr <= lloc)
{/* This is the container of the nested func */
cb->base_stack = (char*)prev;
cb->es = prev->cbes;
break;
}
floc = prev->first_loc;
lloc = prev->last_loc;
}
cb->flags = 0x20 + hidden;
}
}
else if(ft->fmods & Fextern)
{/* Calling external function */
/* Dynamic link it */
if(!(ft->fmods & Fthunked))
load_efunc(iv, ft);

cb->base_stack = calloc(1, sizeof(SB)+argsiz+hidden);
cb->argsiz = argsiz+hidden;
cb->argofs = 0;
cb->flags = 0x40 + hidden;
}
else
{/* Calling interpreted function */
if(flags & 0x80)
{
cb->flags = flags;
cb->es = cb->base_stack = calloc(1, 128);
}
else
{
long es_beg;
long fs_size;
PSB sp;
es_beg = stksiz+hidden+argsiz;
fs_size = es_beg + ((maxes+6)*SZ);
cb->base_stack = calloc(1, fs_size+sizeof(SB));
sp = (PSB)cb->base_stack;
cb->es = cb->base_stack + sizeof(SB) + es_beg;
cb->argofs = stksiz >> 2;
cb->flags = flags + hidden;
sp->first_loc = first_loc;
sp->last_loc = last_loc;
sp->backlink = base_stack;
sp->stksize = fs_size+sizeof(SB);
}
}
if(hidden)
{/* function returning a structure */
void *strucptr = malloc(strucsiz);
*((void**)(cb->base_stack+sizeof(SB)+(cb->argofs<<2))) = strucptr;
ensure_strrets(iv);
iv->struclist[iv->strretcnt++] = strucptr;
}
pc += 4;
break;
}
case RETSTRUCT:
{
long size = G2(np)<<2;
long offset = G2(np+2)<<2;
void *dst;

dst = fs + offset;
dst = *((void**)dst);
memcpy(dst, *((void**)es), size);
if(iv->debug) {
printf("RETSTRUCT ofs=%lx es=%p val=0x%lx\n", pc_offset, es, *((long*)es));
fflush(stdout);
}
return es;
}
case PRUNESTRUCT:
{
prune_structs(iv);
break;
}
case GETBITFIELD:
{
if(pc[1] + pc[2] <= 32)
{
*((long*)es) >>= pc[1];
*((long*)es) &= bfields[pc[2]];
if(pc[3])
{/* sign extend */
if(*((long*)es) & tsfields[pc[2]])
{
*((long*)es) |= sfields[pc[2]];
((long*)es)[1] = 0xffffffff;
}
else ((long*)es)[1] = 0;
}
}
else
{
#if SUPPORT_LONG_LONG
*((long long*)es) >>= pc[1];
*((long long*)es) &= lbfields[pc[2]];
if(pc[3])
{
if(*((long long*)es) & ltsfields[pc[2]])
*((long long*)es) |= lsfields[pc[2]];
}
#else
#endif
}
pc += 3;
break;
}
case PUTBITFIELD:
{
if(pc[1] + pc[2] <= 32)
{
unsigned long mask = bfields[pc[2]];
void *dst = *((void **)oes);
unsigned long dat = *((long*)es);
dat &= mask;
dat <<= pc[1];
mask <<= pc[1];
switch(pc[3])
{
case 1:
*((char*)dst) &= ~mask;
*((char*)dst) |= dat;
break;
case 2:
*((short*)dst) &= ~mask;
*((short*)dst) |= dat;
break;
case 4:
*((long*)dst) &= ~mask;
*((long*)dst) |= dat;
break;
default:
break;
}
}
else
{
#if SUPPORT_LONG_LONG
unsigned long long mask = lbfields[pc[2]];
void *dst = *((void **)oes);
unsigned long long dat = *((unsigned long long *)es);
dat &= mask;
dat <<= pc[1];
mask <<= pc[1];
switch(pc[3])
{
case 1:
*((char*)dst) &= ~mask;
*((char*)dst) |= dat;
break;
case 2:
*((short*)dst) &= ~mask;
*((short*)dst) |= dat;
break;
case 4:
*((long*)dst) &= ~mask;
*((long*)dst) |= dat;
break;
case 8:
*((long long*)dst) &= ~mask;
*((long long*)dst) |= dat;
break;
default:
break;
}
#else
#endif
}
pc += 3;
es -= 2*SZ;
break;
}
#if SUPPORT_LONG_DOUBLE
case LI:
LOADIX();
#endif
case IMMED:
{
++pc;
++np;
switch(*pc)
{
#if SUPPORT_LONG_DOUBLE

case SMI|A1:
STORMEMI1(long double);
case SMI|A2:
STORMEMI2(long double);
case SMI|A3:
STORMEMI3(long double);
case SMI|A4:
STORMEMI4(long double);

case SSI|A1:
STORSTKI1(long double);
case SSI|A2:
STORSTKI2(long double);
case SSI|A3:
STORSTKI3(long double);

case DEREF|LONGDOUBLE:
FDEREF_ES(long double);
case DEREF1|LONGDOUBLE:
FDEREF1_ES(long double);
#endif
#if SUPPORT_LONG_LONG
case DEREF|LONGLONG:
case DEREF|ULONGLONG:
FDEREF_ES(long long);

case DEREF1|LONGLONG:
case DEREF1|ULONGLONG:
FDEREF1_ES(long long);

case MODI|LONGLONG:
MODI_ES(long long);
case MODI|ULONGLONG:
MODI_ES(unsigned long long);
#endif
}
break;
}/* END: XTD IMMED */
#if SUPPORT_LONG_LONG

case ADD|LONGLONG:
ADD_ES(long long);
case ADD|ULONGLONG:
ADD_ES(unsigned long long);
case SUB|LONGLONG:
SUB_ES(long long);
case SUB|ULONGLONG:
SUB_ES(unsigned long long);
case MUL|LONGLONG:
MUL_ES(long long);
case MUL|ULONGLONG:
MUL_ES(unsigned long long);
case DIV|LONGLONG:
DIV_ES(long long);
case DIV|ULONGLONG:
DIV_ES(unsigned long long);
case NEG|LONGLONG:
NEG_ES(long long);
case NEG|ULONGLONG:
NEG_ES(unsigned long long);
case LT|LONGLONG:
LT_ES(long long);
case LT|ULONGLONG:
LT_ES(unsigned long long);
case GT|LONGLONG:
GT_ES(long long);
case GT|ULONGLONG:
GT_ES(unsigned long long);
case LE|LONGLONG:
LE_ES(long long);
case LE|ULONGLONG:
LE_ES(unsigned long long);
case GE|LONGLONG:
GE_ES(long long);
case GE|ULONGLONG:
GE_ES(unsigned long long);
case NE|LONGLONG:
NE_ES(long long);
case NE|ULONGLONG:
NE_ES(unsigned long long);
case EQ|LONGLONG:
EQ_ES(long long);
case EQ|ULONGLONG:
EQ_ES(unsigned long long);
case RSH|SLONGLONG:
RSH_ES(long long);
case RSH|SULONGLONG:
RSH_ES(unsigned long long);

case MOD|LONGLONG:
MODL_ES(long long);
case MOD|ULONGLONG:
MODL_ES(unsigned long long);


case RSHI|SLONGLONG:
RSHI_ES(long long);
case RSHI|SULONGLONG:
RSHI_ES(unsigned long long);
#endif

#if SUPPORT_LONG_DOUBLE

case ADD|LONGDOUBLE:
ADD_ES(long double);
case SUB|LONGDOUBLE:
SUB_ES(long double);
case MUL|LONGDOUBLE:
MUL_ES(long double);
case DIV|LONGDOUBLE:
DIV_ES(long double);
case TRUTHOF|BX:
TRUTH_ES(long double);
case NOT|BX:
NOT_ES(long double);
case NEG|LONGDOUBLE:
NEG_ES(long double);
case LT|LONGDOUBLE:
LT_ES(long double);
case GT|LONGDOUBLE:
GT_ES(long double);
case LE|LONGDOUBLE:
LE_ES(long double);
case GE|LONGDOUBLE:
GE_ES(long double);
case NE|LONGDOUBLE:
NE_ES(long double);
case EQ|LONGDOUBLE:
EQ_ES(long double);

case LS|A1:
LOADSTK1(long double);
case LS|A2:
LOADSTK2(long double);
case LS|A3:
LOADSTK3(long double);

case LM|A1:
LOADMEM1(long double);
case LM|A2:
LOADMEM2(long double);
case LM|A3:
LOADMEM3(long double);
case LM|A4:
LOADMEM4(long double);

case SS|A1:
STORSTK1(long double);
case SS|A2:
STORSTK2(long double);
case SS|A3:
STORSTK3(long double);

case SM|A1:
STORMEM1(long double);
case SM|A2:
STORMEM2(long double);
case SM|A3:
STORMEM3(long double);
case SM|A4:
STORMEM4(long double);

case MOVSS:
{
pc += mover(iv, np+1, *np, BX, fs, fs);
break;
}
case MOVSM:
{
pc += mover(iv, np+1, *np, BX, fs, dd);
break;
}
case MOVMS:
{
pc += mover(iv, np+1, *np, BX, dd, fs);
break;
}
case MOVMM:
{
pc += mover(iv, np+1, *np, BX, dd, dd);
break;
}
#endif /* SUPPORT_LONG_DOUBLE */
}
break;
}/* END: XTD */

case GT|BYTE:
GT_ES(char);
case GT|SHORT:
GT_ES(short);
case GT|LONG:
GT_ES(long);
case GT|UBYTE:
GT_ES(unsigned char);
case GT|USHORT:
GT_ES(unsigned short);
case GT|ULONG:
GT_ES(unsigned long);
case GT|FLOAT:
GT_ES(float);
case GT|DOUBLE:
GT_ES(double);

case LT|BYTE:
LT_ES(char);
case LT|SHORT:
LT_ES(short);
case LT|LONG:
LT_ES(long);
case LT|UBYTE:
LT_ES(unsigned char);
case LT|USHORT:
LT_ES(unsigned short);
case LT|ULONG:
LT_ES(unsigned long);
case LT|FLOAT:
LT_ES(float);
case LT|DOUBLE:
LT_ES(double);

case GE|BYTE:
GE_ES(char);
case GE|SHORT:
GE_ES(short);
case GE|LONG:
GE_ES(long);
case GE|UBYTE:
GE_ES(unsigned char);
case GE|USHORT:
GE_ES(unsigned short);
case GE|ULONG:
GE_ES(unsigned long);
case GE|FLOAT:
GE_ES(float);
case GE|DOUBLE:
GE_ES(double);

case LE|BYTE:
LE_ES(char);
case LE|SHORT:
LE_ES(short);
case LE|LONG:
LE_ES(long);
case LE|UBYTE:
LE_ES(unsigned char);
case LE|USHORT:
LE_ES(unsigned short);
case LE|ULONG:
LE_ES(unsigned long);
case LE|FLOAT:
LE_ES(float);
case LE|DOUBLE:
LE_ES(double);

case NE|BYTE:
NE_ES(char);
case NE|SHORT:
NE_ES(short);
case NE|LONG:
NE_ES(long);
case NE|UBYTE:
NE_ES(unsigned char);
case NE|USHORT:
NE_ES(unsigned short);
case NE|ULONG:
NE_ES(unsigned long);
case NE|FLOAT:
NE_ES(float);
case NE|DOUBLE:
NE_ES(double);

case EQ|BYTE:
EQ_ES(char);
case EQ|SHORT:
EQ_ES(short);
case EQ|LONG:
EQ_ES(long);
case EQ|UBYTE:
EQ_ES(unsigned char);
case EQ|USHORT:
EQ_ES(unsigned short);
case EQ|ULONG:
EQ_ES(unsigned long);
case EQ|FLOAT:
EQ_ES(float);
case EQ|DOUBLE:
EQ_ES(double);

case ARG:
case ARGA:
case ARGF:
{
PCB cb = (PCB)(es-(3*SZ));
long size = *((long*)es);
void *src = oes-SZ;
void *dst;
if(cb->flags & 0x80)
{/* arg to builtin func */
cb->es += SZ;
dst = cb->es;
}
else
{
dst = cb->base_stack+sizeof(SB)+(cb->argofs<<2)+*((long*)oes);
}
if(*pc == ARGA)
{/* dereference */
src = *((void**)src);
}
else if(*pc == ARGF)
{/* Passing address of function */
Pft ft = *((Pft*)src);

if(ft->fmods & Fnested)
{/* Record the current evaluation stack
the nested func will be called back */
((PSB)base_stack)->cbes = (void*)cb;
}
if(cb->flags & 0x40)
{/* To an external function */
if(!(ft->fmods & Fextern))
{/* Passing address of local function */
if(!(ft->fmods & Fthunked))
{
*((void**)src) = make_callback_thunk( iv,
base_stack,
ft);
ft->fmods |= Fthunked;
if(ft->fmods & Fnested)
{/* The thunk will be freed later */
((PSB)base_stack)->thunkaddr = *((void**)src);
}
}
}
}
}/* END: *pc == ARGF */
switch(size)
{
case 1:
*((char*)dst) = *((char*)src);
break;
case 2:
*((short*)dst) = *((short*)src);
break;
case 4:
*((long*)dst) = *((long*)src);
break;
case 8:
*((double*)dst) = *((double*)src);
break;
default:
memcpy(dst, src, size);
break;
}
es -= 3*SZ;
break;
}

case MOVSS|B1:
case MOVSS|B2:
case MOVSS|B4:
case MOVSS|B8:
{
pc += mover(iv, np+1, *np, *pc & 3, fs, fs);
break;
}
case MOVSM|B1:
case MOVSM|B2:
case MOVSM|B4:
case MOVSM|B8:
{
pc += mover(iv, np+1, *np, *pc & 3, fs, dd);
break;
}
case MOVMS|B1:
case MOVMS|B2:
case MOVMS|B4:
case MOVMS|B8:
{
pc += mover(iv, np+1, *np, *pc & 3, dd, fs);
break;
}
case MOVMM|B1:
case MOVMM|B2:
case MOVMM|B4:
case MOVMM|B8:
{
pc += mover(iv, np+1, *np, *pc & 3, dd, dd);
break;
}
case DUMP:
{
es = oes;
break;
}
case REGAIN:
{
es = nes;
break;
}
case CALL:
{
PCB cb = (PCB)es;
Pft ft = cb->loc;
if(cb->flags & 0x80)
{/* call builtin function through a function pointer */
char *pes = cb->es;

if(do_builtin(iv, (unsigned char)ft->funcaddr, &pes))
{/* builtin returned something */
#if SUPPORT_LONG_DOUBLE
*((long double*)es) = *((long double*)(pes));
#else
*((double*)es) = *((double*)pes);
#endif
}
free(cb->base_stack);
}
else if(cb->flags & 0x40)
{/* call external function */
unsigned short fmods = ft->fmods;
DATUM lastval;
if(fmods & Fretstr)
{
_ExternCallS( ft->funcaddr,
cb->base_stack+sizeof(SB),
cb->argsiz,
&lastval);
}
else
{
_ExternCall( ft->funcaddr,
cb->base_stack+sizeof(SB),
cb->argsiz,
&lastval);
}
if(fmods & Fretdbl)
{
asm ("fstpl %0" : "=g"(lastval.Udouble) :);
}
else if(fmods & Fretflt)
{
asm ("fstps %0" : "=g"(lastval.Ufloat) :);
}
else if(fmods & Fretldbl)
{
#if SUPPORT_LONG_DOUBLE
asm ("fstpt %0" : "=g"(lastval.Ulongdouble) :);
#else
asm ("fstpl %0" : "=g"(lastval.Udouble) :);
#endif
}
#if SUPPORT_LONG_DOUBLE
*((long double*)es) = lastval.Ulongdouble;
#else
*((double*)es) = lastval.Udouble;

#endif
free(cb->base_stack);
}/* END: call external func */
else
{ /* call internal function */
void *pes;
void *lastalloca = iv->allocalist;
pes = bterp_eval(iv, ft->funcaddr, cb->base_stack, cb->es,
cb->base_stack+((PSB)cb->base_stack)->stksize);
#if SUPPORT_LONG_DOUBLE
*((long double*)es) = *((long double*)pes);
#else
*((double*)es) = *((double*)pes);
#endif
if(cb->flags & 0x20)
{/* calledback a nested function */

}
else if(!(cb->flags & 0x10))
{/* called interpreted function */
free(cb->base_stack);
}
purge_allocas(iv, lastalloca);
}/* END: call internal function */
break;
}
case RET:
{
if(iv->debug) {
printf("RET ofs=%lx es=%p val=0x%lx\n", pc_offset, es, *((long*)es));
fflush(stdout);
}
return es;
}
case SWAP:
{
char t[SZ];
memcpy(t,es,SZ);
memcpy(es,oes,SZ);
memcpy(oes,t,SZ);
break;
}
case SWAP4:
{
long x;
x = *((long *)es);
*((long*)es) = *((long*)oes);
*((long*)oes) = x;
break;
}
case SWAP4DEEP:
{
long x;
x = *((long*)oes);
*((long*)oes) = *((long*)(oes-SZ));
*((long*)(oes-SZ)) = x;
break;
}
case DUP:
{
memcpy(nes,es,SZ);
es = nes;
break;
}
case DUP4:
{
*((long*)nes) = *((long*)es);
es = nes;
break;
}
case ABSMEM:
{
*((unsigned long*)es) += (unsigned long)dd;
break;
}
case ABSSTK:
{
*((unsigned long*)es) += (unsigned long)fs;
break;
}
case MOVDA1:
{
**((char**)(oes)) = *((char*)es);
es -= 2*SZ;
break;
}
case MOVDA2:
{
**((short**)(oes)) = *((short*)es);
es -= 2*SZ;
break;
}
case MOVDA4:
{
**((long**)(oes)) = *((long*)es);
es -= 2*SZ;
break;
}
case MOVDA8:
{
**((double**)(oes)) = *((double*)es);
es -= 2*SZ;
break;
}
case MOVDAX:
{
#if SUPPORT_LONG_DOUBLE
**((long double**)(oes)) = *((long double*)es);
#else
memcpy(*((void**)(oes)), es, XSZ);
#endif
es -= 2*SZ;
break;
}
case MOVAA1:
{
**((char**)(oes)) = **((char**)es);
es -= 2*SZ;
break;
}
case MOVAA2:
{
**((short**)(oes)) = **((short**)es);
es -= 2*SZ;
break;
}
case MOVAA4:
{
**((long**)(oes)) = **((long**)es);
es -= 2*SZ;
break;
}
case MOVAA8:
{
**((double**)(oes)) = **((double**)es);
es -= 2*SZ;
break;
}
case MOVAAX:
{
#if SUPPORT_LONG_DOUBLE
**((long double**)(oes)) = **((long double**)es);
#else
memcpy(*((void**)(oes)), *((void**)es), XSZ);
#endif
es -= 2*SZ;
break;
}
case MOVAAC:
{
memcpy(*((void**)(es-(2*SZ))), *((void**)(oes)), *((long*)(es)));
es -= 3*SZ;
break;
}
}
}/* END: for(;;++pc) */
/* NOT REACHED */
return 0;
}/* END: bterp_eval() */
/* ====================== END INTERPRETER CODE ===================== */

/* ================== INITIALIZATION CODE BELOW THIS POINT ================ */
static Piv tiv; /* temporary storage of iv whilst calling oxlink */

int
bterp_setup_functhunk(FE entry, struct nlist *nl)
{/* Called from the dynamic linker */
Pft ft;

ft = (void*)(entry->data_start_address + nl->n_value);

if(ft->fmods & Fextern)
{/* store a pointer to the function name string */
if(!(ft->fmods & Fthunked))
{
ft->funcaddr = (long)(entry->strings + nl->n_un.n_strx);
}
return 0;
}
else if(!(ft->fmods & Fthunked))
{/* export a useful address */
nl->n_value = (long)make_callback_thunk(tiv, 0, ft);
ft->fmods |= Fthunked;
}
return 1;
}
void
bterp_setup_switch(FE entry, struct nlist *nl)
{/* Called from the dynamic linker */
unsigned long key[2];
long value;

if(tiv->swtable == 0)
tiv->swtable = calloc(1, SWITCHMOD*sizeof(void*));

key[0] = nl->n_desc<<11;
key[1] = nl->n_un.n_strx;
value = (long)(entry->text_start_address + nl->n_value);
saveswitch(tiv, key, value);
}

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

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

for( ; i >= 0; --i)
if(path[i] == '/' || path[i] == '\\' || path[i] == ':')
ret = &path[i+1];
return ret;
}

static char *
propernameof(char *path)
{
int pathlen = strlen(path);
char *name = malloc(pathlen+8);
int i;

strcpy(name, path);
for(i = pathlen-1; i >= 0; --i)
{
if(name[i] == '/' || name[i] == '\\' || name[i] == ':')
break;
else if(name[i] == '.')
return name;
}
strcat(name, ".byt");
return name;
}
static char *
basenameof(char *filename)
{
char *name = malloc(strlen(filename)+8);
int i;
strcpy(name, filename);
for(i = 0; name[i]; ++i)
if(name[i] == '.')
name[i] = 0;
return name;
}
static void
setup_run_args(Piv iv, int argc, char **argv, char *startname)
{
int i;

if(!startname)
{
startname = basenameof(filenameof(argv[1]));
}
iv->run_argcnt = argc - 1;
if(iv->run_argcnt > MAX_RUNARGS)
iv->run_argcnt = MAX_RUNARGS;
iv->run_args[0] = startname;
for(i = 1; i < iv->run_argcnt; ++i)
{
iv->run_args[i] = argv[i+1];
}
}
static void
Usage()
{
puts(
"Usage: bterp [+Sd] file [args]...\n"
" +S name == start execution at function `name'\n"
" +d == print debug stmts\n"
" Default execution starts at function `file'\n"
);
}
#if USING_FRAMEWORK
int
PROG (int argc, char **argv)
#else
int
main(int argc, char **argv)
#endif
{
int i, j;
char *startname;
long *argptr;
long es_beg, fs_size;
int *pes, ret;
Piv iv;

iv = tiv = calloc(1, sizeof(struct _iv));
iv->piv = iv;

startname = 0;
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':
iv->debug = 1;
break;
case 'S':
if(argv[i][j+1]) {
startname = &argv[i][j+1];
}
else if(i < argc-1) {
startname = argv[i+1];
trimsize = 2;
} else {
printf("bterp: No starting fuction name\n");
Usage();
return 1;
}
goto trim;
break;
}
}
trim:
/* Trim switch */
for(j = i; j < argc-trimsize; ++j)
argv[j] = argv[j+trimsize];
argc -= trimsize;
--i; /* i will be bumped by for */
}
}
if(argc > 1)
{
PSB sp;
iv->filename = propernameof(argv[1]);
if(oxlink_load_object(iv->filename)) /* try library list */
{
oxlink_demand_noload();
if(oxlink_load_file(iv->filename)) /* try search path */
{
printf("bterp: file `%s' err:%s\n", iv->filename, oxlink_errstr());
exit(1);
}
oxlink_demand_load();
}
iv->entry = oxlink_get_entry_struct(iv->filename);
iv->text_base = iv->entry->text_start_address;
iv->dd = iv->entry->data_start_address;

setup_run_args(iv, argc, argv, startname);
if(!(iv->funcptr = oxlink_find_func("main")))
{
if(!(iv->funcptr = oxlink_find_func(iv->run_args[0])))
{
printf("bterp: function `%s' not found in file\n", iv->run_args[0]);
oxlink_unload_file(iv->filename, 0);
free(iv->filename);
free(iv->run_args[0]);
free(iv);
return 1;
}
}
iv->ft = *((Pft*)(&iv->funcptr[4]));
iv->funcaddr = iv->ft->funcaddr;
iv->stksiz = iv->ft->stksiz<<2;
iv->argsiz = iv->ft->argsiz<<2;
iv->maxes = iv->ft->maxes;

es_beg = iv->stksiz+iv->argsiz;
fs_size = es_beg + ((iv->maxes+6)*SZ);
iv->base_stack = calloc(1, fs_size + sizeof(SB));
iv->e_stack = iv->base_stack + sizeof(SB) + es_beg;

/* Fill in _stakblk */
sp = (PSB)iv->base_stack;
sp->first_loc = iv->funcaddr;
sp->last_loc = iv->dd - iv->text_base;
sp->stksize = fs_size + sizeof(SB);

/* Fill in the arguments */
argptr = (long*)(iv->base_stack + iv->stksiz + sizeof(SB));
if(iv->argsiz >= 4)
argptr[0] = iv->run_argcnt;
if(iv->argsiz >= 8)
argptr[1] = (long)iv->run_args;

if((pes = (void*)setjmp(iv->jb)))
goto done;

/* Call the starting function */
pes = bterp_eval(iv, iv->funcaddr, iv->base_stack, iv->e_stack,
iv->base_stack + (fs_size+sizeof(SB)));
done:
ret = *pes;
prune_structs(iv);
oxlink_unload_file(iv->filename, 0);
free(iv->filename);
free(iv->run_args[0]);
free(iv->base_stack);
if(iv->swtable)
{
void *p = iv->chunklist;
free(iv->swtable);
while(p)
{
void *q = p;
p = *((void**)p);
free(q);
}
}
free(iv);
return ret;
}
else
{
Usage();
return 1;
}
}
#if 0 /* used for testing */
int bterpcallback(int (*pfunc)())
{
return pfunc();
}
#endif