1792 lines
48 KiB
C
1792 lines
48 KiB
C
/*
|
|
Expression Evaluator Library (NS-EEL) v2
|
|
Copyright (C) 2004-2008 Cockos Incorporated
|
|
Copyright (C) 1999-2003 Nullsoft, Inc.
|
|
|
|
nseel-compiler.c
|
|
|
|
This software is provided 'as-is', without any express or implied
|
|
warranty. In no event will the authors be held liable for any damages
|
|
arising from the use of this software.
|
|
|
|
Permission is granted to anyone to use this software for any purpose,
|
|
including commercial applications, and to alter it and redistribute it
|
|
freely, subject to the following restrictions:
|
|
|
|
1. The origin of this software must not be misrepresented; you must not
|
|
claim that you wrote the original software. If you use this software
|
|
in a product, an acknowledgment in the product documentation would be
|
|
appreciated but is not required.
|
|
2. Altered source versions must be plainly marked as such, and must not be
|
|
misrepresented as being the original software.
|
|
3. This notice may not be removed or altered from any source distribution.
|
|
*/
|
|
|
|
|
|
// for VirtualProtect
|
|
|
|
#include "ns-eel-int.h"
|
|
|
|
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
|
|
#ifndef _WIN64
|
|
#ifndef __ppc__
|
|
#include <float.h>
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef __APPLE__
|
|
#ifdef __LP64__
|
|
#define EEL_USE_MPROTECT
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef EEL_USE_MPROTECT
|
|
#include <sys/mman.h>
|
|
#include <stdint.h>
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#ifdef NSEEL_EEL1_COMPAT_MODE
|
|
|
|
#ifndef EEL_NO_CHANGE_FPFLAGS
|
|
#define EEL_NO_CHANGE_FPFLAGS
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#ifndef _WIN64
|
|
#if !defined(_RC_CHOP) && !defined(EEL_NO_CHANGE_FPFLAGS)
|
|
|
|
#include <fpu_control.h>
|
|
#define _RC_CHOP _FPU_RC_ZERO
|
|
#define _MCW_RC _FPU_RC_ZERO
|
|
static unsigned int _controlfp(unsigned int val, unsigned int mask)
|
|
{
|
|
unsigned int ret;
|
|
_FPU_GETCW(ret);
|
|
if (mask)
|
|
{
|
|
ret&=~mask;
|
|
ret|=val;
|
|
_FPU_SETCW(ret);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
#endif
|
|
#endif
|
|
|
|
|
|
#ifdef __ppc__
|
|
|
|
#define GLUE_MOV_EAX_DIRECTVALUE_SIZE 8
|
|
static void GLUE_MOV_EAX_DIRECTVALUE_GEN(void *b, INT_PTR v)
|
|
{
|
|
unsigned int uv=(unsigned int)v;
|
|
unsigned short *p=(unsigned short *)b;
|
|
|
|
*p++ = 0x3C60; // addis r3, r0, hw
|
|
*p++ = (uv>>16)&0xffff;
|
|
*p++ = 0x6063; // ori r3, r3, lw
|
|
*p++ = uv&0xffff;
|
|
}
|
|
|
|
|
|
// mflr r5
|
|
// stwu r5, -4(r1)
|
|
const static unsigned int GLUE_FUNC_ENTER[2] = { 0x7CA802A6, 0x94A1FFFC };
|
|
|
|
// lwz r5, 0(r1)
|
|
// addi r1, r1, 4
|
|
// mtlr r5
|
|
const static unsigned int GLUE_FUNC_LEAVE[3] = { 0x80A10000, 0x38210004, 0x7CA803A6 };
|
|
#define GLUE_FUNC_ENTER_SIZE sizeof(GLUE_FUNC_ENTER)
|
|
#define GLUE_FUNC_LEAVE_SIZE sizeof(GLUE_FUNC_LEAVE)
|
|
|
|
const static unsigned int GLUE_RET[]={0x4E800020}; // blr
|
|
|
|
const static unsigned int GLUE_MOV_ESI_EDI=0x7E308B78; // mr r16, r17
|
|
|
|
static int GLUE_RESET_ESI(char *out, void *ptr)
|
|
{
|
|
if (out) memcpy(out,&GLUE_MOV_ESI_EDI,sizeof(GLUE_MOV_ESI_EDI));
|
|
return sizeof(GLUE_MOV_ESI_EDI);
|
|
|
|
}
|
|
|
|
|
|
|
|
// stwu r3, -4(r1)
|
|
const static unsigned int GLUE_PUSH_EAX[1]={ 0x9461FFFC};
|
|
|
|
// lwz r14, 0(r1)
|
|
// addi r1, r1, 4
|
|
const static unsigned int GLUE_POP_EBX[2]={ 0x81C10000, 0x38210004, };
|
|
|
|
// lwz r15, 0(r1)
|
|
// addi r1, r1, 4
|
|
const static unsigned int GLUE_POP_ECX[2]={ 0x81E10000, 0x38210004 };
|
|
|
|
|
|
static void GLUE_CALL_CODE(INT_PTR bp, INT_PTR cp)
|
|
{
|
|
__asm__(
|
|
"stmw r14, -80(r1)\n"
|
|
"mtctr %0\n"
|
|
"mr r17, %1\n"
|
|
"subi r17, r17, 8\n"
|
|
"mflr r5\n"
|
|
"stw r5, -84(r1)\n"
|
|
"subi r1, r1, 88\n"
|
|
"bctrl\n"
|
|
"addi r1, r1, 88\n"
|
|
"lwz r5, -84(r1)\n"
|
|
"lmw r14, -80(r1)\n"
|
|
"mtlr r5\n"
|
|
::"r" (cp), "r" (bp));
|
|
};
|
|
|
|
INT_PTR *EEL_GLUE_set_immediate(void *_p, void *newv)
|
|
{
|
|
// todo 64 bit ppc will take some work
|
|
unsigned int *p=(unsigned int *)_p;
|
|
while ((p[0]&0x0000FFFF) != 0x0000dead &&
|
|
(p[1]&0x0000FFFF) != 0x0000beef) p++;
|
|
p[0] = (p[0]&0xFFFF0000) | (((unsigned int)newv)>>16);
|
|
p[1] = (p[1]&0xFFFF0000) | (((unsigned int)newv)&0xFFFF);
|
|
|
|
return (INT_PTR*)++p;
|
|
}
|
|
|
|
|
|
#else
|
|
|
|
//x86 specific code
|
|
|
|
#define GLUE_FUNC_ENTER_SIZE 0
|
|
#define GLUE_FUNC_LEAVE_SIZE 0
|
|
const static unsigned int GLUE_FUNC_ENTER[1];
|
|
const static unsigned int GLUE_FUNC_LEAVE[1];
|
|
|
|
#if defined(_WIN64) || defined(__LP64__)
|
|
#define GLUE_MOV_EAX_DIRECTVALUE_SIZE 10
|
|
static void GLUE_MOV_EAX_DIRECTVALUE_GEN(void *b, INT_PTR v) {
|
|
unsigned short *bb = (unsigned short *)b;
|
|
*bb++ =0xB848;
|
|
*(INT_PTR *)bb = v;
|
|
}
|
|
const static unsigned char GLUE_PUSH_EAX[2]={ 0x50,0x50}; // push rax ; push rax (push twice to preserve alignment)
|
|
const static unsigned char GLUE_POP_EBX[2]={0x5F, 0x5f}; //pop rdi ; twice
|
|
const static unsigned char GLUE_POP_ECX[2]={0x59, 0x59 }; // pop rcx ; twice
|
|
#else
|
|
#define GLUE_MOV_EAX_DIRECTVALUE_SIZE 5
|
|
static void GLUE_MOV_EAX_DIRECTVALUE_GEN(void *b, int v)
|
|
{
|
|
*((unsigned char *)b) =0xB8;
|
|
b= ((unsigned char *)b)+1;
|
|
*(int *)b = v;
|
|
}
|
|
const static unsigned char GLUE_PUSH_EAX[4]={0x83, 0xEC, 12, 0x50}; // sub esp, 12, push eax
|
|
const static unsigned char GLUE_POP_EBX[4]={0x5F, 0x83, 0xC4, 12}; //pop ebx, add esp, 12 // DI=5F, BX=0x5B;
|
|
const static unsigned char GLUE_POP_ECX[4]={0x59, 0x83, 0xC4, 12}; // pop ecx, add esp, 12
|
|
|
|
#endif
|
|
|
|
//const static unsigned short GLUE_MOV_ESI_EDI=0xF78B;
|
|
const static unsigned char GLUE_RET=0xC3;
|
|
|
|
static int GLUE_RESET_ESI(unsigned char *out, void *ptr)
|
|
{
|
|
#if defined(_WIN64) || defined(__LP64__)
|
|
if (out)
|
|
{
|
|
*out++ = 0x48;
|
|
*out++ = 0xBE; // mov rsi, constant64
|
|
*(void **)out = ptr;
|
|
out+=sizeof(void *);
|
|
}
|
|
return 2+sizeof(void *);
|
|
#else
|
|
if (out)
|
|
{
|
|
*out++ = 0xBE; // mov esi, constant
|
|
memcpy(out,&ptr,sizeof(void *));
|
|
out+=sizeof(void *);
|
|
}
|
|
return 1+sizeof(void *);
|
|
#endif
|
|
}
|
|
|
|
static void GLUE_CALL_CODE(INT_PTR bp, INT_PTR cp)
|
|
{
|
|
#if defined(_WIN64) || defined(__LP64__)
|
|
extern void win64_callcode(INT_PTR code);
|
|
win64_callcode(cp);
|
|
#else // non-64 bit
|
|
#ifdef _MSC_VER
|
|
#ifndef EEL_NO_CHANGE_FPFLAGS
|
|
unsigned int old_v=_controlfp(0,0);
|
|
_controlfp(_RC_CHOP,_MCW_RC);
|
|
#endif
|
|
|
|
__asm
|
|
{
|
|
mov eax, cp
|
|
pushad
|
|
call eax
|
|
popad
|
|
};
|
|
|
|
#ifndef EEL_NO_CHANGE_FPFLAGS
|
|
_controlfp(old_v,_MCW_RC);
|
|
#endif
|
|
|
|
#else // gcc x86
|
|
#ifndef EEL_NO_CHANGE_FPFLAGS
|
|
unsigned int old_v=_controlfp(0,0);
|
|
_controlfp(_RC_CHOP,_MCW_RC);
|
|
#endif
|
|
__asm__("call *%%eax"::"a" (cp): "%ecx","%edx","%esi","%edi");
|
|
#ifndef EEL_NO_CHANGE_FPFLAGS
|
|
_controlfp(old_v,_MCW_RC);
|
|
#endif
|
|
#endif //gcc x86
|
|
#endif // 32bit
|
|
}
|
|
|
|
INT_PTR *EEL_GLUE_set_immediate(void *_p, void *newv)
|
|
{
|
|
char *p=(char*)_p;
|
|
while (*(INT_PTR *)p != ~(INT_PTR)0) p++;
|
|
*(INT_PTR *)p = (INT_PTR)newv;
|
|
return ((INT_PTR*)p)+1;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
static void *GLUE_realAddress(void *fn, void *fn_e, int *size)
|
|
{
|
|
#if defined(_MSC_VER) || defined(__LP64__)
|
|
|
|
unsigned char *p;
|
|
|
|
#if defined(_DEBUG) && !defined(__LP64__)
|
|
if (*(unsigned char *)fn == 0xE9) // this means jump to the following address
|
|
{
|
|
fn = ((unsigned char *)fn) + *(int *)((char *)fn+1) + 5;
|
|
}
|
|
#endif
|
|
|
|
// this may not work in debug mode
|
|
p=(unsigned char *)fn;
|
|
for (;;)
|
|
{
|
|
int a;
|
|
for (a=0;a<12;a++)
|
|
{
|
|
if (p[a] != (a?0x90:0x89)) break;
|
|
}
|
|
if (a>=12)
|
|
{
|
|
*size = (char *)p - (char *)fn;
|
|
// if (*size<0) MessageBox(NULL,"expect poof","a",0);
|
|
return fn;
|
|
}
|
|
p++;
|
|
}
|
|
#else
|
|
char *p=(char *)fn_e - sizeof(GLUE_RET);
|
|
if (p <= (char *)fn) *size=0;
|
|
else
|
|
{
|
|
while (p > (char *)fn && memcmp(p,&GLUE_RET,sizeof(GLUE_RET))) p-=sizeof(GLUE_RET);
|
|
*size = p - (char *)fn;
|
|
}
|
|
return fn;
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
static int nseel_evallib_stats[5]; // source bytes, static code bytes, call code bytes, data bytes, segments
|
|
int *NSEEL_getstats()
|
|
{
|
|
return nseel_evallib_stats;
|
|
}
|
|
EEL_F *NSEEL_getglobalregs()
|
|
{
|
|
return nseel_globalregs;
|
|
}
|
|
|
|
// this stuff almost works
|
|
static int findByteOffsetInSource(compileContext *ctx, int byteoffs,int *destoffs)
|
|
{
|
|
int x;
|
|
if (!ctx->compileLineRecs || !ctx->compileLineRecs_size) return *destoffs=0;
|
|
if (byteoffs < ctx->compileLineRecs[0].destByteCount)
|
|
{
|
|
*destoffs=0;
|
|
return 1;
|
|
}
|
|
for (x = 0; x < ctx->compileLineRecs_size-1; x ++)
|
|
{
|
|
if (byteoffs >= ctx->compileLineRecs[x].destByteCount &&
|
|
byteoffs < ctx->compileLineRecs[x+1].destByteCount) break;
|
|
}
|
|
*destoffs=ctx->compileLineRecs[(x&&x==ctx->compileLineRecs_size-1)?x-1:x].srcByteCount;
|
|
|
|
return x+2;
|
|
}
|
|
|
|
|
|
static void onCompileNewLine(compileContext *ctx, int srcBytes, int destBytes)
|
|
{
|
|
if (!ctx->compileLineRecs || ctx->compileLineRecs_size >= ctx->compileLineRecs_alloc)
|
|
{
|
|
ctx->compileLineRecs_alloc = ctx->compileLineRecs_size+1024;
|
|
ctx->compileLineRecs = (lineRecItem *)realloc(ctx->compileLineRecs,sizeof(lineRecItem)*ctx->compileLineRecs_alloc);
|
|
}
|
|
if (ctx->compileLineRecs)
|
|
{
|
|
ctx->compileLineRecs[ctx->compileLineRecs_size].srcByteCount=srcBytes;
|
|
ctx->compileLineRecs[ctx->compileLineRecs_size++].destByteCount=destBytes;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
#define LLB_DSIZE (65536-64)
|
|
typedef struct _llBlock {
|
|
struct _llBlock *next;
|
|
int sizeused;
|
|
char block[LLB_DSIZE];
|
|
} llBlock;
|
|
|
|
typedef struct _startPtr {
|
|
struct _startPtr *next;
|
|
void *startptr;
|
|
} startPtr;
|
|
|
|
typedef struct {
|
|
void *workTable;
|
|
|
|
llBlock *blocks;
|
|
void *code;
|
|
int code_stats[4];
|
|
} codeHandleType;
|
|
|
|
#ifndef NSEEL_MAX_TEMPSPACE_ENTRIES
|
|
#define NSEEL_MAX_TEMPSPACE_ENTRIES 2048
|
|
#endif
|
|
|
|
static void *__newBlock(llBlock **start,int size);
|
|
|
|
#define newTmpBlock(x) __newTmpBlock((llBlock **)&ctx->tmpblocks_head,x)
|
|
#define newBlock(x,a) __newBlock_align(ctx,x,a)
|
|
|
|
static void *__newTmpBlock(llBlock **start, int size)
|
|
{
|
|
void *p=__newBlock(start,size+4);
|
|
if (p && size>=0) *((int *)p) = size;
|
|
return p;
|
|
}
|
|
|
|
static void *__newBlock_align(compileContext *ctx, int size, int align) // makes sure block is aligned to 32 byte boundary, for code
|
|
{
|
|
int a1=align-1;
|
|
char *p=(char*)__newBlock((llBlock **)&ctx->blocks_head,size+a1);
|
|
return p+((align-(((INT_PTR)p)&a1))&a1);
|
|
}
|
|
|
|
static void freeBlocks(llBlock **start);
|
|
|
|
#define DECL_ASMFUNC(x) \
|
|
void nseel_asm_##x(void); \
|
|
void nseel_asm_##x##_end(void); \
|
|
|
|
DECL_ASMFUNC(sin)
|
|
DECL_ASMFUNC(cos)
|
|
DECL_ASMFUNC(tan)
|
|
DECL_ASMFUNC(1pdd)
|
|
DECL_ASMFUNC(2pdd)
|
|
DECL_ASMFUNC(2pdds)
|
|
DECL_ASMFUNC(1pp)
|
|
DECL_ASMFUNC(2pp)
|
|
DECL_ASMFUNC(sqr)
|
|
DECL_ASMFUNC(sqrt)
|
|
DECL_ASMFUNC(log)
|
|
DECL_ASMFUNC(log10)
|
|
DECL_ASMFUNC(abs)
|
|
DECL_ASMFUNC(min)
|
|
DECL_ASMFUNC(max)
|
|
DECL_ASMFUNC(sig)
|
|
DECL_ASMFUNC(sign)
|
|
DECL_ASMFUNC(band)
|
|
DECL_ASMFUNC(bor)
|
|
DECL_ASMFUNC(bnot)
|
|
DECL_ASMFUNC(if)
|
|
DECL_ASMFUNC(repeat)
|
|
DECL_ASMFUNC(repeatwhile)
|
|
DECL_ASMFUNC(equal)
|
|
DECL_ASMFUNC(notequal)
|
|
DECL_ASMFUNC(below)
|
|
DECL_ASMFUNC(above)
|
|
DECL_ASMFUNC(beloweq)
|
|
DECL_ASMFUNC(aboveeq)
|
|
DECL_ASMFUNC(assign)
|
|
DECL_ASMFUNC(add)
|
|
DECL_ASMFUNC(sub)
|
|
DECL_ASMFUNC(add_op)
|
|
DECL_ASMFUNC(sub_op)
|
|
DECL_ASMFUNC(mul)
|
|
DECL_ASMFUNC(div)
|
|
DECL_ASMFUNC(mul_op)
|
|
DECL_ASMFUNC(div_op)
|
|
DECL_ASMFUNC(mod)
|
|
DECL_ASMFUNC(mod_op)
|
|
DECL_ASMFUNC(or)
|
|
DECL_ASMFUNC(and)
|
|
DECL_ASMFUNC(or_op)
|
|
DECL_ASMFUNC(and_op)
|
|
DECL_ASMFUNC(uplus)
|
|
DECL_ASMFUNC(uminus)
|
|
DECL_ASMFUNC(invsqrt)
|
|
DECL_ASMFUNC(exec2)
|
|
|
|
static void NSEEL_PProc_GRAM(void *data, int data_size, compileContext *ctx)
|
|
{
|
|
if (data_size>0) EEL_GLUE_set_immediate(data, ctx->gram_blocks);
|
|
}
|
|
|
|
|
|
static EEL_F g_signs[2]={1.0,-1.0};
|
|
static EEL_F negativezeropointfive=-0.5f;
|
|
static EEL_F onepointfive=1.5f;
|
|
static EEL_F g_closefact = NSEEL_CLOSEFACTOR;
|
|
static const EEL_F eel_zero=0.0, eel_one=1.0;
|
|
|
|
//#if defined(_MSC_VER) && _MSC_VER >= 1400
|
|
//static double __floor(double a) { return floor(a); }
|
|
//#endif
|
|
|
|
static double eel1band(double a, double b)
|
|
{
|
|
return (fabs(a)>g_closefact && fabs(b) > g_closefact) ? 1.0 : 0.0;
|
|
}
|
|
static double eel1bor(double a, double b)
|
|
{
|
|
return (fabs(a)>g_closefact || fabs(b) > g_closefact) ? 1.0 : 0.0;
|
|
}
|
|
|
|
static double eel1sigmoid(double x, double constraint)
|
|
{
|
|
double t = (1+exp(-x * (constraint)));
|
|
return fabs(t)>g_closefact ? 1.0/t : 0;
|
|
}
|
|
|
|
|
|
EEL_F NSEEL_CGEN_CALL nseel_int_rand(EEL_F *f);
|
|
|
|
static functionType fnTable1[] = {
|
|
{ "_if", nseel_asm_if,nseel_asm_if_end, 3, {&g_closefact} },
|
|
{ "_and", nseel_asm_band,nseel_asm_band_end, 2 } ,
|
|
{ "_or", nseel_asm_bor,nseel_asm_bor_end, 2 } ,
|
|
{ "loop", nseel_asm_repeat,nseel_asm_repeat_end, 2 },
|
|
{ "while", nseel_asm_repeatwhile,nseel_asm_repeatwhile_end, 1 },
|
|
|
|
#ifdef __ppc__
|
|
{ "_not", nseel_asm_bnot,nseel_asm_bnot_end, 1, {&g_closefact,&eel_zero,&eel_one} } ,
|
|
{ "_equal", nseel_asm_equal,nseel_asm_equal_end, 2, {&g_closefact,&eel_zero, &eel_one} },
|
|
{ "_noteq", nseel_asm_notequal,nseel_asm_notequal_end, 2, {&g_closefact,&eel_one,&eel_zero} },
|
|
{ "_below", nseel_asm_below,nseel_asm_below_end, 2, {&eel_zero, &eel_one} },
|
|
{ "_above", nseel_asm_above,nseel_asm_above_end, 2, {&eel_zero, &eel_one} },
|
|
{ "_beleq", nseel_asm_beloweq,nseel_asm_beloweq_end, 2, {&eel_zero, &eel_one} },
|
|
{ "_aboeq", nseel_asm_aboveeq,nseel_asm_aboveeq_end, 2, {&eel_zero, &eel_one} },
|
|
#else
|
|
{ "_not", nseel_asm_bnot,nseel_asm_bnot_end, 1, {&g_closefact} } ,
|
|
{ "_equal", nseel_asm_equal,nseel_asm_equal_end, 2, {&g_closefact} },
|
|
{ "_noteq", nseel_asm_notequal,nseel_asm_notequal_end, 2, {&g_closefact} },
|
|
{ "_below", nseel_asm_below,nseel_asm_below_end, 2 },
|
|
{ "_above", nseel_asm_above,nseel_asm_above_end, 2 },
|
|
{ "_beleq", nseel_asm_beloweq,nseel_asm_beloweq_end, 2 },
|
|
{ "_aboeq", nseel_asm_aboveeq,nseel_asm_aboveeq_end, 2 },
|
|
#endif
|
|
|
|
{ "_set",nseel_asm_assign,nseel_asm_assign_end,2},
|
|
{ "_mod",nseel_asm_mod,nseel_asm_mod_end,2},
|
|
{ "_mulop",nseel_asm_mul_op,nseel_asm_mul_op_end,2},
|
|
{ "_divop",nseel_asm_div_op,nseel_asm_div_op_end,2},
|
|
{ "_orop",nseel_asm_or_op,nseel_asm_or_op_end,2},
|
|
{ "_andop",nseel_asm_and_op,nseel_asm_and_op_end,2},
|
|
{ "_addop",nseel_asm_add_op,nseel_asm_add_op_end,2},
|
|
{ "_subop",nseel_asm_sub_op,nseel_asm_sub_op_end,2},
|
|
{ "_modop",nseel_asm_mod_op,nseel_asm_mod_op_end,2},
|
|
|
|
|
|
#ifdef __ppc__
|
|
{ "sin", nseel_asm_1pdd,nseel_asm_1pdd_end, 1, {&sin} },
|
|
{ "cos", nseel_asm_1pdd,nseel_asm_1pdd_end, 1, {&cos} },
|
|
{ "tan", nseel_asm_1pdd,nseel_asm_1pdd_end, 1, {&tan} },
|
|
#else
|
|
{ "sin", nseel_asm_sin,nseel_asm_sin_end, 1 },
|
|
{ "cos", nseel_asm_cos,nseel_asm_cos_end, 1 },
|
|
{ "tan", nseel_asm_tan,nseel_asm_tan_end, 1 },
|
|
#endif
|
|
{ "asin", nseel_asm_1pdd,nseel_asm_1pdd_end, 1, {&asin}, },
|
|
{ "acos", nseel_asm_1pdd,nseel_asm_1pdd_end, 1, {&acos}, },
|
|
{ "atan", nseel_asm_1pdd,nseel_asm_1pdd_end, 1, {&atan}, },
|
|
{ "atan2", nseel_asm_2pdd,nseel_asm_2pdd_end, 2, {&atan2}, },
|
|
{ "sqr", nseel_asm_sqr,nseel_asm_sqr_end, 1 },
|
|
#ifdef __ppc__
|
|
{ "sqrt", nseel_asm_1pdd,nseel_asm_1pdd_end, 1, {&sqrt}, },
|
|
#else
|
|
{ "sqrt", nseel_asm_sqrt,nseel_asm_sqrt_end, 1 },
|
|
#endif
|
|
{ "pow", nseel_asm_2pdd,nseel_asm_2pdd_end, 2, {&pow}, },
|
|
{ "_powop", nseel_asm_2pdds,nseel_asm_2pdds_end, 2, {&pow}, },
|
|
{ "exp", nseel_asm_1pdd,nseel_asm_1pdd_end, 1, {&exp}, },
|
|
#ifdef __ppc__
|
|
{ "log", nseel_asm_1pdd,nseel_asm_1pdd_end, 1, {&log} },
|
|
{ "log10", nseel_asm_1pdd,nseel_asm_1pdd_end, 1, {&log10} },
|
|
#else
|
|
{ "log", nseel_asm_log,nseel_asm_log_end, 1, },
|
|
{ "log10", nseel_asm_log10,nseel_asm_log10_end, 1, },
|
|
#endif
|
|
{ "abs", nseel_asm_abs,nseel_asm_abs_end, 1 },
|
|
{ "min", nseel_asm_min,nseel_asm_min_end, 2 },
|
|
{ "max", nseel_asm_max,nseel_asm_max_end, 2 },
|
|
#ifdef __ppc__
|
|
{ "sign", nseel_asm_sign,nseel_asm_sign_end, 1, {&eel_zero}} ,
|
|
#else
|
|
{ "sign", nseel_asm_sign,nseel_asm_sign_end, 1, {&g_signs}} ,
|
|
#endif
|
|
{ "rand", nseel_asm_1pp,nseel_asm_1pp_end, 1, {&nseel_int_rand}, } ,
|
|
|
|
//#if defined(_MSC_VER) && _MSC_VER >= 1400
|
|
// { "floor", nseel_asm_1pdd,nseel_asm_1pdd_end, 1, {&__floor} },
|
|
//#else
|
|
// { "floor", nseel_asm_1pdd,nseel_asm_1pdd_end, 1, {&floor} },
|
|
//#endif
|
|
{ "ceil", nseel_asm_1pdd,nseel_asm_1pdd_end, 1, {&ceil} },
|
|
#ifdef __ppc__
|
|
{ "invsqrt", nseel_asm_invsqrt,nseel_asm_invsqrt_end, 1, },
|
|
#else
|
|
{ "invsqrt", nseel_asm_invsqrt,nseel_asm_invsqrt_end, 1, {&negativezeropointfive, &onepointfive} },
|
|
#endif
|
|
|
|
{ "sigmoid", nseel_asm_2pdd,nseel_asm_2pdd_end, 2, {&eel1sigmoid}, },
|
|
|
|
// these differ from _and/_or, they always evaluate both...
|
|
{ "band", nseel_asm_2pdd,nseel_asm_2pdd_end, 2, {&eel1band}, },
|
|
{ "bor", nseel_asm_2pdd,nseel_asm_2pdd_end, 2, {&eel1bor}, },
|
|
|
|
{"exec2",nseel_asm_exec2,nseel_asm_exec2_end,2},
|
|
{"exec3",nseel_asm_exec2,nseel_asm_exec2_end,3},
|
|
{"_mem",_asm_megabuf,_asm_megabuf_end,1,{&g_closefact,&__NSEEL_RAMAlloc},NSEEL_PProc_RAM},
|
|
{"_gmem",_asm_megabuf,_asm_megabuf_end,1,{&g_closefact,&__NSEEL_RAMAllocGMEM},NSEEL_PProc_GRAM},
|
|
{"freembuf",_asm_generic1parm,_asm_generic1parm_end,1,{&__NSEEL_RAM_MemFree},NSEEL_PProc_RAM},
|
|
{"memcpy",_asm_generic3parm,_asm_generic3parm_end,3,{&__NSEEL_RAM_MemCpy},NSEEL_PProc_RAM},
|
|
{"memset",_asm_generic3parm,_asm_generic3parm_end,3,{&__NSEEL_RAM_MemSet},NSEEL_PProc_RAM},
|
|
};
|
|
|
|
static functionType *fnTableUser;
|
|
static int fnTableUser_size;
|
|
|
|
functionType *nseel_getFunctionFromTable(int idx)
|
|
{
|
|
if (idx<0) return 0;
|
|
if (idx>=sizeof(fnTable1)/sizeof(fnTable1[0]))
|
|
{
|
|
idx -= sizeof(fnTable1)/sizeof(fnTable1[0]);
|
|
if (!fnTableUser || idx >= fnTableUser_size) return 0;
|
|
return fnTableUser+idx;
|
|
}
|
|
return fnTable1+idx;
|
|
}
|
|
|
|
int NSEEL_init() // returns 0 on success
|
|
{
|
|
NSEEL_quit();
|
|
return 0;
|
|
}
|
|
|
|
void NSEEL_addfunctionex2(const char *name, int nparms, char *code_startaddr, int code_len, void *pproc, void *fptr, void *fptr2)
|
|
{
|
|
if (!fnTableUser || !(fnTableUser_size&7))
|
|
{
|
|
fnTableUser=(functionType *)realloc(fnTableUser,(fnTableUser_size+8)*sizeof(functionType));
|
|
}
|
|
if (fnTableUser)
|
|
{
|
|
memset(&fnTableUser[fnTableUser_size],0,sizeof(functionType));
|
|
fnTableUser[fnTableUser_size].nParams = nparms;
|
|
fnTableUser[fnTableUser_size].name = name;
|
|
fnTableUser[fnTableUser_size].afunc = code_startaddr;
|
|
fnTableUser[fnTableUser_size].func_e = code_startaddr + code_len;
|
|
fnTableUser[fnTableUser_size].pProc = (NSEEL_PPPROC) pproc;
|
|
fnTableUser[fnTableUser_size].replptrs[0]=fptr;
|
|
fnTableUser[fnTableUser_size].replptrs[1]=fptr2;
|
|
fnTableUser_size++;
|
|
}
|
|
}
|
|
|
|
void NSEEL_quit()
|
|
{
|
|
free(fnTableUser);
|
|
fnTableUser_size=0;
|
|
fnTableUser=0;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------------------------------------
|
|
static void freeBlocks(llBlock **start)
|
|
{
|
|
llBlock *s=*start;
|
|
*start=0;
|
|
while (s)
|
|
{
|
|
llBlock *llB = s->next;
|
|
#ifdef _WIN32
|
|
VirtualFree(s, 0 /*LLB_DSIZE*/, MEM_RELEASE);
|
|
#else
|
|
free(s);
|
|
#endif
|
|
s=llB;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------------------------------------
|
|
static void *__newBlock(llBlock **start, int size)
|
|
{
|
|
llBlock *llb;
|
|
int alloc_size;
|
|
if (*start && (LLB_DSIZE - (*start)->sizeused) >= size)
|
|
{
|
|
void *t=(*start)->block+(*start)->sizeused;
|
|
(*start)->sizeused+=(size+7)&~7;
|
|
return t;
|
|
}
|
|
|
|
alloc_size=sizeof(llBlock);
|
|
if ((int)size > LLB_DSIZE) alloc_size += size - LLB_DSIZE;
|
|
|
|
#ifdef _WIN32
|
|
llb = (llBlock *)VirtualAlloc(NULL, alloc_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
|
#else
|
|
llb = (llBlock *)malloc(alloc_size); // grab bigger block if absolutely necessary (heh)
|
|
#endif
|
|
#if defined(EEL_USE_MPROTECT)
|
|
{
|
|
static int pagesize = 0;
|
|
if (!pagesize)
|
|
{
|
|
pagesize=sysconf(_SC_PAGESIZE);
|
|
if (!pagesize) pagesize=4096;
|
|
}
|
|
uintptr_t offs,eoffs;
|
|
offs=((uintptr_t)llb)&~(pagesize-1);
|
|
eoffs=((uintptr_t)llb + alloc_size + pagesize-1)&~(pagesize-1);
|
|
mprotect((void*)offs,eoffs-offs,PROT_WRITE|PROT_READ|PROT_EXEC);
|
|
}
|
|
#endif
|
|
llb->sizeused=(size+7)&~7;
|
|
llb->next = *start;
|
|
*start = llb;
|
|
return llb->block;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------
|
|
INT_PTR nseel_createCompiledValue(compileContext *ctx, EEL_F value, EEL_F *addrValue)
|
|
{
|
|
unsigned char *block;
|
|
|
|
block=(unsigned char *)newTmpBlock(GLUE_MOV_EAX_DIRECTVALUE_SIZE);
|
|
|
|
if (addrValue == NULL)
|
|
{
|
|
*(addrValue = (EEL_F *)newBlock(sizeof(EEL_F),sizeof(EEL_F))) = value;
|
|
ctx->l_stats[3]+=sizeof(EEL_F);
|
|
}
|
|
|
|
GLUE_MOV_EAX_DIRECTVALUE_GEN(block+4,(INT_PTR)addrValue);
|
|
|
|
return ((INT_PTR)(block));
|
|
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------------------------------------
|
|
static void *nseel_getFunctionAddress(int fntype, int fn, int *size, NSEEL_PPPROC *pProc, void ***replList)
|
|
{
|
|
*replList=0;
|
|
switch (fntype)
|
|
{
|
|
case MATH_SIMPLE:
|
|
switch (fn)
|
|
{
|
|
case FN_ASSIGN:
|
|
return GLUE_realAddress(nseel_asm_assign,nseel_asm_assign_end,size);
|
|
case FN_ADD:
|
|
return GLUE_realAddress(nseel_asm_add,nseel_asm_add_end,size);
|
|
case FN_SUB:
|
|
return GLUE_realAddress(nseel_asm_sub,nseel_asm_sub_end,size);
|
|
case FN_MULTIPLY:
|
|
return GLUE_realAddress(nseel_asm_mul,nseel_asm_mul_end,size);
|
|
case FN_DIVIDE:
|
|
return GLUE_realAddress(nseel_asm_div,nseel_asm_div_end,size);
|
|
case FN_MODULO:
|
|
return GLUE_realAddress(nseel_asm_exec2,nseel_asm_exec2_end,size);
|
|
case FN_AND:
|
|
return GLUE_realAddress(nseel_asm_and,nseel_asm_and_end,size);
|
|
case FN_OR:
|
|
return GLUE_realAddress(nseel_asm_or,nseel_asm_or_end,size);
|
|
case FN_UPLUS:
|
|
return GLUE_realAddress(nseel_asm_uplus,nseel_asm_uplus_end,size);
|
|
case FN_UMINUS:
|
|
return GLUE_realAddress(nseel_asm_uminus,nseel_asm_uminus_end,size);
|
|
}
|
|
case MATH_FN:
|
|
{
|
|
functionType *p=nseel_getFunctionFromTable(fn);
|
|
if (p)
|
|
{
|
|
*replList=p->replptrs;
|
|
*pProc=p->pProc;
|
|
return GLUE_realAddress(p->afunc,p->func_e,size);
|
|
}
|
|
}
|
|
}
|
|
|
|
*size=0;
|
|
return 0;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------
|
|
INT_PTR nseel_createCompiledFunction3(compileContext *ctx, int fntype, INT_PTR fn, INT_PTR code1, INT_PTR code2, INT_PTR code3)
|
|
{
|
|
int sizes1=((int *)code1)[0];
|
|
int sizes2=((int *)code2)[0];
|
|
int sizes3=((int *)code3)[0];
|
|
|
|
if (fntype == MATH_FN && fn == 0) // special case: IF
|
|
{
|
|
void *func3;
|
|
int size;
|
|
INT_PTR *ptr;
|
|
char *block;
|
|
|
|
unsigned char *newblock2,*newblock3;
|
|
unsigned char *p;
|
|
|
|
p=newblock2=newBlock(sizes2+sizeof(GLUE_RET)+GLUE_FUNC_ENTER_SIZE+GLUE_FUNC_LEAVE_SIZE,32);
|
|
memcpy(p,&GLUE_FUNC_ENTER,GLUE_FUNC_ENTER_SIZE); p+=GLUE_FUNC_ENTER_SIZE;
|
|
memcpy(p,(char*)code2+4,sizes2); p+=sizes2;
|
|
memcpy(p,&GLUE_FUNC_LEAVE,GLUE_FUNC_LEAVE_SIZE); p+=GLUE_FUNC_LEAVE_SIZE;
|
|
memcpy(p,&GLUE_RET,sizeof(GLUE_RET)); p+=sizeof(GLUE_RET);
|
|
|
|
p=newblock3=newBlock(sizes3+sizeof(GLUE_RET)+GLUE_FUNC_ENTER_SIZE+GLUE_FUNC_LEAVE_SIZE,32);
|
|
memcpy(p,&GLUE_FUNC_ENTER,GLUE_FUNC_ENTER_SIZE); p+=GLUE_FUNC_ENTER_SIZE;
|
|
memcpy(p,(char*)code3+4,sizes3); p+=sizes3;
|
|
memcpy(p,&GLUE_FUNC_LEAVE,GLUE_FUNC_LEAVE_SIZE); p+=GLUE_FUNC_LEAVE_SIZE;
|
|
memcpy(p,&GLUE_RET,sizeof(GLUE_RET)); p+=sizeof(GLUE_RET);
|
|
|
|
ctx->l_stats[2]+=sizes2+sizes3+sizeof(GLUE_RET)*2;
|
|
|
|
func3 = GLUE_realAddress(nseel_asm_if,nseel_asm_if_end,&size);
|
|
|
|
block=(char *)newTmpBlock(sizes1+size);
|
|
|
|
memcpy(block+4,(char*)code1+4,sizes1);
|
|
ptr=(INT_PTR *)(block+4+sizes1);
|
|
memcpy(ptr,func3,size);
|
|
|
|
ptr=EEL_GLUE_set_immediate(ptr,&g_closefact);
|
|
ptr=EEL_GLUE_set_immediate(ptr,newblock2);
|
|
EEL_GLUE_set_immediate(ptr,newblock3);
|
|
|
|
ctx->computTableTop++;
|
|
|
|
return (INT_PTR)block;
|
|
|
|
}
|
|
else
|
|
{
|
|
int size2;
|
|
unsigned char *block;
|
|
unsigned char *outp;
|
|
|
|
void *myfunc;
|
|
NSEEL_PPPROC preProc=0;
|
|
void **repl;
|
|
|
|
myfunc = nseel_getFunctionAddress(fntype, fn, &size2, &preProc,&repl);
|
|
|
|
block=(unsigned char *)newTmpBlock(size2+sizes1+sizes2+sizes3+
|
|
sizeof(GLUE_PUSH_EAX) +
|
|
sizeof(GLUE_PUSH_EAX) +
|
|
sizeof(GLUE_POP_EBX) +
|
|
sizeof(GLUE_POP_ECX));
|
|
|
|
outp=block+4;
|
|
memcpy(outp,(char*)code1+4,sizes1);
|
|
outp+=sizes1;
|
|
memcpy(outp,&GLUE_PUSH_EAX,sizeof(GLUE_PUSH_EAX)); outp+=sizeof(GLUE_PUSH_EAX);
|
|
memcpy(outp,(char*)code2+4,sizes2);
|
|
outp+=sizes2;
|
|
memcpy(outp,&GLUE_PUSH_EAX,sizeof(GLUE_PUSH_EAX)); outp+=sizeof(GLUE_PUSH_EAX);
|
|
memcpy(outp,(char*)code3+4,sizes3);
|
|
outp+=sizes3;
|
|
memcpy(outp,&GLUE_POP_EBX,sizeof(GLUE_POP_EBX)); outp+=sizeof(GLUE_POP_EBX);
|
|
memcpy(outp,&GLUE_POP_ECX,sizeof(GLUE_POP_ECX)); outp+=sizeof(GLUE_POP_ECX);
|
|
|
|
memcpy(outp,myfunc,size2);
|
|
if (preProc) preProc(outp,size2,ctx);
|
|
if (repl)
|
|
{
|
|
if (repl[0]) outp=(unsigned char *)EEL_GLUE_set_immediate(outp,repl[0]);
|
|
if (repl[1]) outp=(unsigned char *)EEL_GLUE_set_immediate(outp,repl[1]);
|
|
if (repl[2]) outp=(unsigned char *)EEL_GLUE_set_immediate(outp,repl[2]);
|
|
if (repl[3]) outp=(unsigned char *)EEL_GLUE_set_immediate(outp,repl[3]);
|
|
}
|
|
|
|
ctx->computTableTop++;
|
|
|
|
return ((INT_PTR)(block));
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------------------------------------
|
|
INT_PTR nseel_createCompiledFunction2(compileContext *ctx, int fntype, INT_PTR fn, INT_PTR code1, INT_PTR code2)
|
|
{
|
|
int size2;
|
|
unsigned char *outp;
|
|
void *myfunc;
|
|
int sizes1=((int *)code1)[0];
|
|
int sizes2=((int *)code2)[0];
|
|
if (fntype == MATH_FN && (fn == 1 || fn == 2 || fn == 3)) // special case: LOOP/BOR/BAND
|
|
{
|
|
void *func3;
|
|
int size;
|
|
INT_PTR *ptr;
|
|
char *block;
|
|
|
|
unsigned char *newblock2, *p;
|
|
|
|
p=newblock2=newBlock(sizes2+sizeof(GLUE_RET)+GLUE_FUNC_ENTER_SIZE+GLUE_FUNC_LEAVE_SIZE,32);
|
|
memcpy(p,&GLUE_FUNC_ENTER,GLUE_FUNC_ENTER_SIZE); p+=GLUE_FUNC_ENTER_SIZE;
|
|
memcpy(p,(char*)code2+4,sizes2); p+=sizes2;
|
|
memcpy(p,&GLUE_FUNC_LEAVE,GLUE_FUNC_LEAVE_SIZE); p+=GLUE_FUNC_LEAVE_SIZE;
|
|
memcpy(p,&GLUE_RET,sizeof(GLUE_RET)); p+=sizeof(GLUE_RET);
|
|
|
|
ctx->l_stats[2]+=sizes2+2;
|
|
|
|
if (fn == 1) func3 = GLUE_realAddress(nseel_asm_band,nseel_asm_band_end,&size);
|
|
else if (fn == 3) func3 = GLUE_realAddress(nseel_asm_repeat,nseel_asm_repeat_end,&size);
|
|
else func3 = GLUE_realAddress(nseel_asm_bor,nseel_asm_bor_end,&size);
|
|
|
|
block=(char *)newTmpBlock(sizes1+size);
|
|
memcpy(block+4,(char*)code1+4,sizes1);
|
|
ptr=(INT_PTR *)(block+4+sizes1);
|
|
memcpy(ptr,func3,size);
|
|
|
|
if (fn!=3) ptr=EEL_GLUE_set_immediate(ptr,&g_closefact); // for or/and
|
|
ptr=EEL_GLUE_set_immediate(ptr,newblock2);
|
|
if (fn!=3) ptr=EEL_GLUE_set_immediate(ptr,&g_closefact); // for or/and
|
|
#ifdef __ppc__
|
|
if (fn!=3) // for or/and on ppc we need a one
|
|
{
|
|
ptr=EEL_GLUE_set_immediate(ptr,&eel_one);
|
|
}
|
|
#endif
|
|
|
|
ctx->computTableTop++;
|
|
return (INT_PTR)block;
|
|
}
|
|
|
|
{
|
|
NSEEL_PPPROC preProc=0;
|
|
unsigned char *block;
|
|
void **repl;
|
|
myfunc = nseel_getFunctionAddress(fntype, fn, &size2,&preProc,&repl);
|
|
|
|
block=(unsigned char *)newTmpBlock(size2+sizes1+sizes2+sizeof(GLUE_PUSH_EAX)+sizeof(GLUE_POP_EBX));
|
|
|
|
outp=block+4;
|
|
memcpy(outp,(char*)code1+4,sizes1);
|
|
outp+=sizes1;
|
|
memcpy(outp,&GLUE_PUSH_EAX,sizeof(GLUE_PUSH_EAX)); outp+=sizeof(GLUE_PUSH_EAX);
|
|
memcpy(outp,(char*)code2+4,sizes2);
|
|
outp+=sizes2;
|
|
memcpy(outp,&GLUE_POP_EBX,sizeof(GLUE_POP_EBX)); outp+=sizeof(GLUE_POP_EBX);
|
|
|
|
memcpy(outp,myfunc,size2);
|
|
if (preProc) preProc(outp,size2,ctx);
|
|
if (repl)
|
|
{
|
|
if (repl[0]) outp=(unsigned char *)EEL_GLUE_set_immediate(outp,repl[0]);
|
|
if (repl[1]) outp=(unsigned char *)EEL_GLUE_set_immediate(outp,repl[1]);
|
|
if (repl[2]) outp=(unsigned char *)EEL_GLUE_set_immediate(outp,repl[2]);
|
|
if (repl[3]) outp=(unsigned char *)EEL_GLUE_set_immediate(outp,repl[3]);
|
|
}
|
|
|
|
ctx->computTableTop++;
|
|
|
|
return ((INT_PTR)(block));
|
|
}
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------------------------------------------
|
|
INT_PTR nseel_createCompiledFunction1(compileContext *ctx, int fntype, INT_PTR fn, INT_PTR code)
|
|
{
|
|
NSEEL_PPPROC preProc=0;
|
|
int size,size2;
|
|
char *block;
|
|
void *myfunc;
|
|
void *func1;
|
|
|
|
size =((int *)code)[0];
|
|
func1 = (void *)(code+4);
|
|
|
|
|
|
if (fntype == MATH_FN && fn == 4) // special case: while
|
|
{
|
|
void *func3;
|
|
INT_PTR *ptr;
|
|
|
|
unsigned char *newblock2, *p;
|
|
|
|
p=newblock2=newBlock(size+sizeof(GLUE_RET)+GLUE_FUNC_ENTER_SIZE+GLUE_FUNC_LEAVE_SIZE,32);
|
|
memcpy(p,&GLUE_FUNC_ENTER,GLUE_FUNC_ENTER_SIZE); p+=GLUE_FUNC_ENTER_SIZE;
|
|
memcpy(p,func1,size); p+=size;
|
|
memcpy(p,&GLUE_FUNC_LEAVE,GLUE_FUNC_LEAVE_SIZE); p+=GLUE_FUNC_LEAVE_SIZE;
|
|
memcpy(p,&GLUE_RET,sizeof(GLUE_RET)); p+=sizeof(GLUE_RET);
|
|
|
|
ctx->l_stats[2]+=size+2;
|
|
|
|
func3 = GLUE_realAddress(nseel_asm_repeatwhile,nseel_asm_repeatwhile_end,&size);
|
|
|
|
block=(char *)newTmpBlock(size);
|
|
ptr = (INT_PTR *)(block+4);
|
|
memcpy(ptr,func3,size);
|
|
ptr=EEL_GLUE_set_immediate(ptr,newblock2);
|
|
EEL_GLUE_set_immediate(ptr,&g_closefact);
|
|
|
|
ctx->computTableTop++;
|
|
return (INT_PTR)block;
|
|
}
|
|
|
|
{
|
|
void **repl;
|
|
myfunc = nseel_getFunctionAddress(fntype, fn, &size2,&preProc,&repl);
|
|
|
|
block=(char *)newTmpBlock(size+size2);
|
|
|
|
memcpy(block+4, func1, size);
|
|
memcpy(block+size+4,myfunc,size2);
|
|
if (preProc) preProc(block+size+4,size2,ctx);
|
|
if (repl)
|
|
{
|
|
unsigned char *outp=(unsigned char *)block+size+4;
|
|
if (repl[0]) outp=(unsigned char *)EEL_GLUE_set_immediate(outp,repl[0]);
|
|
if (repl[1]) outp=(unsigned char *)EEL_GLUE_set_immediate(outp,repl[1]);
|
|
if (repl[2]) outp=(unsigned char *)EEL_GLUE_set_immediate(outp,repl[2]);
|
|
if (repl[3]) outp=(unsigned char *)EEL_GLUE_set_immediate(outp,repl[3]);
|
|
}
|
|
|
|
ctx->computTableTop++;
|
|
|
|
return ((INT_PTR)(block));
|
|
}
|
|
}
|
|
|
|
|
|
static char *preprocessCode(compileContext *ctx, char *expression)
|
|
{
|
|
char *expression_start=expression;
|
|
int len=0;
|
|
int alloc_len=strlen(expression)+1+64;
|
|
char *buf=(char *)malloc(alloc_len);
|
|
int semicnt=0;
|
|
// we need to call onCompileNewLine for each new line we get
|
|
|
|
//onCompileNewLine(ctx,
|
|
|
|
while (*expression)
|
|
{
|
|
if (len > alloc_len-64)
|
|
{
|
|
alloc_len = len+128;
|
|
buf=(char*)realloc(buf,alloc_len);
|
|
}
|
|
|
|
if (expression[0] == '/')
|
|
{
|
|
if (expression[1] == '/')
|
|
{
|
|
expression+=2;
|
|
while (expression[0] && expression[0] != '\n') expression++;
|
|
continue;
|
|
}
|
|
else if (expression[1] == '*')
|
|
{
|
|
expression+=2;
|
|
while (expression[0] && (expression[0] != '*' || expression[1] != '/'))
|
|
{
|
|
if (expression[0] == '\n') onCompileNewLine(ctx,expression+1-expression_start,len);
|
|
expression++;
|
|
}
|
|
if (expression[0]) expression+=2; // at this point we KNOW expression[0]=* and expression[1]=/
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (expression[0] == '$')
|
|
{
|
|
if (toupper(expression[1]) == 'X')
|
|
{
|
|
char *p=expression+2;
|
|
unsigned int v=strtoul(expression+2,&p,16);
|
|
char tmp[64];
|
|
expression=p;
|
|
|
|
sprintf(tmp,"%u",v);
|
|
memcpy(buf+len,tmp,strlen(tmp));
|
|
len+=strlen(tmp);
|
|
ctx->l_stats[0]+=strlen(tmp);
|
|
continue;
|
|
|
|
}
|
|
if (expression[1]=='\'' && expression[2] && expression[3]=='\'')
|
|
{
|
|
char tmp[64];
|
|
sprintf(tmp,"%u",((unsigned char *)expression)[2]);
|
|
expression+=4;
|
|
|
|
memcpy(buf+len,tmp,strlen(tmp));
|
|
len+=strlen(tmp);
|
|
ctx->l_stats[0]+=strlen(tmp);
|
|
continue;
|
|
}
|
|
if (toupper(expression[1]) == 'P' && toupper(expression[2]) == 'I')
|
|
{
|
|
static char *str="3.141592653589793";
|
|
expression+=3;
|
|
memcpy(buf+len,str,17);
|
|
len+=17; //strlen(str);
|
|
ctx->l_stats[0]+=17;
|
|
continue;
|
|
}
|
|
if (toupper(expression[1]) == 'E')
|
|
{
|
|
static char *str="2.71828183";
|
|
expression+=2;
|
|
memcpy(buf+len,str,10);
|
|
len+=10; //strlen(str);
|
|
ctx->l_stats[0]+=10;
|
|
continue;
|
|
}
|
|
if (toupper(expression[1]) == 'P' && toupper(expression[2]) == 'H' && toupper(expression[3]) == 'I')
|
|
{
|
|
static char *str="1.61803399";
|
|
expression+=4;
|
|
memcpy(buf+len,str,10);
|
|
len+=10; //strlen(str);
|
|
ctx->l_stats[0]+=10;
|
|
continue;
|
|
}
|
|
|
|
}
|
|
|
|
{
|
|
char c=*expression++;
|
|
|
|
if (c == '\n') onCompileNewLine(ctx,expression-expression_start,len);
|
|
if (isspace(c)) c=' ';
|
|
|
|
if (c == '(') semicnt++;
|
|
else if (c == ')') { semicnt--; if (semicnt < 0) semicnt=0; }
|
|
else if (c == ';' && semicnt > 0)
|
|
{
|
|
// convert ; to % if next nonwhitespace char is alnum, otherwise convert to space
|
|
int p=0;
|
|
int nc;
|
|
int commentstate=0;
|
|
while ((nc=expression[p]))
|
|
{
|
|
if (!commentstate && nc == '/')
|
|
{
|
|
if (expression[p+1] == '/') commentstate=1;
|
|
else if (expression[p+1] == '*') commentstate=2;
|
|
}
|
|
|
|
if (commentstate == 1 && nc == '\n') commentstate=0;
|
|
else if (commentstate == 2 && nc == '*' && expression[p+1]=='/')
|
|
{
|
|
p++; // skip *
|
|
commentstate=0;
|
|
}
|
|
else if (!commentstate && !isspace(nc)) break;
|
|
|
|
p++;
|
|
}
|
|
// fucko, we should look for even more chars, me thinks
|
|
if (nc && (isalnum(nc)
|
|
#if 1
|
|
|| nc == '(' || nc == '_' || nc == '!' || nc == '$'
|
|
#endif
|
|
)) c='%';
|
|
else c = ' '; // stray ;
|
|
}
|
|
#if 0
|
|
else if (semicnt > 0 && c == ',')
|
|
{
|
|
int p=0;
|
|
int nc;
|
|
while ((nc=expression[p]) && isspace(nc)) p++;
|
|
if (nc == ',' || nc == ')')
|
|
{
|
|
expression += p+1;
|
|
buf[len++]=',';
|
|
buf[len++]='0';
|
|
c=nc; // append this char
|
|
}
|
|
}
|
|
#endif
|
|
// list of operators
|
|
|
|
else if (!isspace(c) && !isalnum(c)) // check to see if this operator is ours
|
|
{
|
|
|
|
static char *symbollists[]=
|
|
{
|
|
"", // or any control char that is not parenthed
|
|
":(,;?%",
|
|
",):?;", // or || or &&
|
|
",);", // jf> removed :? from this, for =
|
|
",);",
|
|
"", // only scans for a negative ] level
|
|
|
|
};
|
|
|
|
|
|
static struct
|
|
{
|
|
char op[2];
|
|
char lscan,rscan;
|
|
char *func;
|
|
} preprocSymbols[] =
|
|
{
|
|
{{'+','='}, 0, 3, "_addop" },
|
|
{{'-','='}, 0, 3, "_subop" },
|
|
{{'%','='}, 0, 3, "_modop" },
|
|
{{'|','='}, 0, 3, "_orop" },
|
|
{{'&','='}, 0, 3, "_andop"},
|
|
|
|
{{'/','='}, 0, 3, "_divop"},
|
|
{{'*','='}, 0, 3, "_mulop"},
|
|
{{'^','='}, 0, 3, "_powop"},
|
|
|
|
{{'=','='}, 1, 2, "_equal" },
|
|
{{'<','='}, 1, 2, "_beleq" },
|
|
{{'>','='}, 1, 2, "_aboeq" },
|
|
{{'<',0 }, 1, 2, "_below" },
|
|
{{'>',0 }, 1, 2, "_above" },
|
|
{{'!','='}, 1, 2, "_noteq" },
|
|
{{'|','|'}, 1, 2, "_or" },
|
|
{{'&','&'}, 1, 2, "_and" },
|
|
{{'=',0 }, 0, 3, "_set" },
|
|
{{'%',0}, 0, 0, "_mod" },
|
|
{{'^',0}, 0, 0, "pow" },
|
|
|
|
|
|
{{'[',0 }, 0, 5, },
|
|
{{'!',0 },-1, 0, }, // this should also ignore any leading +-
|
|
{{'?',0 }, 1, 4, },
|
|
|
|
};
|
|
|
|
|
|
int n;
|
|
int ns=sizeof(preprocSymbols)/sizeof(preprocSymbols[0]);
|
|
for (n = 0; n < ns; n++)
|
|
{
|
|
if (c == preprocSymbols[n].op[0] && (!preprocSymbols[n].op[1] || expression[0] == preprocSymbols[n].op[1]))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (n < ns)
|
|
{
|
|
|
|
int lscan=preprocSymbols[n].lscan;
|
|
int rscan=preprocSymbols[n].rscan;
|
|
|
|
// parse left side of =, scanning back for an unparenthed nonwhitespace nonalphanumeric nonparenth?
|
|
// so megabuf(x+y)= would be fine, x=, but +x= would do +set(x,)
|
|
char *l_ptr=0;
|
|
char *r_ptr=0;
|
|
if (lscan >= 0)
|
|
{
|
|
char *scan=symbollists[lscan];
|
|
int l_semicnt=0;
|
|
l_ptr=buf + len - 1;
|
|
while (l_ptr >= buf)
|
|
{
|
|
if (*l_ptr == ')') l_semicnt++;
|
|
else if (*l_ptr == '(')
|
|
{
|
|
l_semicnt--;
|
|
if (l_semicnt < 0) break;
|
|
}
|
|
else if (!l_semicnt)
|
|
{
|
|
if (!*scan)
|
|
{
|
|
if (!isspace(*l_ptr) && !isalnum(*l_ptr) && *l_ptr != '_' && *l_ptr != '.') break;
|
|
}
|
|
else
|
|
{
|
|
char *sc=scan;
|
|
if (lscan == 2 && ( // not currently used, even
|
|
(l_ptr[0]=='|' && l_ptr[1] == '|')||
|
|
(l_ptr[0]=='&' && l_ptr[1] == '&')
|
|
)
|
|
) break;
|
|
while (*sc && *l_ptr != *sc) sc++;
|
|
if (*sc) break;
|
|
}
|
|
}
|
|
l_ptr--;
|
|
}
|
|
buf[len]=0;
|
|
|
|
l_ptr++;
|
|
|
|
len = l_ptr - buf;
|
|
|
|
l_ptr = strdup(l_ptr); // doesn't need to be preprocessed since it just was
|
|
}
|
|
if (preprocSymbols[n].op[1]) expression++;
|
|
|
|
r_ptr=expression;
|
|
{
|
|
// scan forward to an uncommented, unparenthed semicolon, comma, or )
|
|
int r_semicnt=0;
|
|
int r_qcnt=0;
|
|
char *scan=symbollists[rscan];
|
|
int commentstate=0;
|
|
int hashadch=0;
|
|
int bracketcnt=0;
|
|
while (*r_ptr)
|
|
{
|
|
if (!commentstate && *r_ptr == '/')
|
|
{
|
|
if (r_ptr[1] == '/') commentstate=1;
|
|
else if (r_ptr[1] == '*') commentstate=2;
|
|
}
|
|
if (commentstate == 1 && *r_ptr == '\n') commentstate=0;
|
|
else if (commentstate == 2 && *r_ptr == '*' && r_ptr[1]=='/')
|
|
{
|
|
r_ptr++; // skip *
|
|
commentstate=0;
|
|
}
|
|
else if (!commentstate)
|
|
{
|
|
if (*r_ptr == '(') {hashadch=1; r_semicnt++; }
|
|
else if (*r_ptr == ')')
|
|
{
|
|
r_semicnt--;
|
|
if (r_semicnt < 0) break;
|
|
}
|
|
else if (!r_semicnt)
|
|
{
|
|
char *sc=scan;
|
|
if (*r_ptr == ';' || *r_ptr == ',') break;
|
|
|
|
if (!rscan)
|
|
{
|
|
if (*r_ptr == ':') break;
|
|
if (!isspace(*r_ptr) && !isalnum(*r_ptr) && *r_ptr != '_' && *r_ptr != '.' && hashadch) break;
|
|
if (isalnum(*r_ptr) || *r_ptr == '_')hashadch=1;
|
|
}
|
|
else if (rscan == 2 &&
|
|
((r_ptr[0]=='|' && r_ptr[1] == '|')||
|
|
(r_ptr[0]=='&' && r_ptr[1] == '&')
|
|
)
|
|
) break;
|
|
|
|
else if (rscan == 3 || rscan == 4)
|
|
{
|
|
if (*r_ptr == ':') r_qcnt--;
|
|
else if (*r_ptr == '?') r_qcnt++;
|
|
|
|
if (r_qcnt < 3-rscan) break;
|
|
}
|
|
else if (rscan == 5)
|
|
{
|
|
if (*r_ptr == '[') bracketcnt++;
|
|
else if (*r_ptr == ']') bracketcnt--;
|
|
if (bracketcnt < 0) break;
|
|
}
|
|
|
|
while (*sc && *r_ptr != *sc) sc++;
|
|
if (*sc) break;
|
|
}
|
|
}
|
|
r_ptr++;
|
|
}
|
|
// expression -> r_ptr is our string (not including r_ptr)
|
|
|
|
{
|
|
char *orp=r_ptr;
|
|
|
|
char rps=*orp;
|
|
*orp=0; // temporarily terminate
|
|
|
|
r_ptr=preprocessCode(ctx,expression);
|
|
expression=orp;
|
|
|
|
*orp = rps; // fix termination(restore string)
|
|
}
|
|
|
|
}
|
|
|
|
if (r_ptr)
|
|
{
|
|
int thisl = strlen(l_ptr?l_ptr:"") + strlen(r_ptr) + 32;
|
|
|
|
if (len+thisl > alloc_len-64)
|
|
{
|
|
alloc_len = len+thisl+128;
|
|
buf=(char*)realloc(buf,alloc_len);
|
|
}
|
|
|
|
|
|
if (n == ns-3)
|
|
{
|
|
char *lp = l_ptr;
|
|
char *rp = r_ptr;
|
|
while (lp && *lp && isspace(*lp)) lp++;
|
|
while (rp && *rp && isspace(*rp)) rp++;
|
|
if (lp && !strncasecmp(lp,"gmem",4) && (!lp[4] || isspace(lp[4])))
|
|
{
|
|
len+=sprintf(buf+len,"_gmem(%s",r_ptr && *r_ptr ? r_ptr : "0");
|
|
ctx->l_stats[0]+=strlen(l_ptr)+4;
|
|
}
|
|
else if (rp && *rp && strcmp(rp,"0"))
|
|
{
|
|
len+=sprintf(buf+len,"_mem((%s)+(%s)",lp,rp);
|
|
ctx->l_stats[0]+=strlen(lp)+strlen(rp)+8;
|
|
}
|
|
else
|
|
{
|
|
len+=sprintf(buf+len,"_mem(%s",lp);
|
|
ctx->l_stats[0]+=strlen(lp)+4;
|
|
}
|
|
|
|
// skip the ]
|
|
if (*expression == ']') expression++;
|
|
|
|
}
|
|
else if (n == ns-2)
|
|
{
|
|
len+=sprintf(buf+len,"_not(%s",
|
|
r_ptr);
|
|
|
|
ctx->l_stats[0]+=4;
|
|
}
|
|
else if (n == ns-1)// if (l_ptr,r_ptr1,r_ptr2)
|
|
{
|
|
char *rptr2=r_ptr;
|
|
char *tmp=r_ptr;
|
|
int parcnt=0;
|
|
int qcnt=1;
|
|
while (*rptr2)
|
|
{
|
|
if (*rptr2 == '?') qcnt++;
|
|
else if (*rptr2 == ':') qcnt--;
|
|
else if (*rptr2 == '(') parcnt++;
|
|
else if (*rptr2 == ')') parcnt--;
|
|
if (parcnt < 0) break;
|
|
if (!parcnt && !qcnt && *rptr2 == ':') break;
|
|
rptr2++;
|
|
}
|
|
if (*rptr2) *rptr2++=0;
|
|
while (isspace(*rptr2)) rptr2++;
|
|
|
|
while (isspace(*tmp)) tmp++;
|
|
|
|
len+=sprintf(buf+len,"_if(%s,%s,%s",l_ptr,*tmp?tmp:"0",*rptr2?rptr2:"0");
|
|
ctx->l_stats[0]+=6;
|
|
}
|
|
else
|
|
{
|
|
len+=sprintf(buf+len,"%s(%s,%s",preprocSymbols[n].func,l_ptr?l_ptr:"",r_ptr);
|
|
ctx->l_stats[0]+=strlen(preprocSymbols[n].func)+2;
|
|
}
|
|
|
|
}
|
|
|
|
free(r_ptr);
|
|
free(l_ptr);
|
|
|
|
|
|
c = ')'; // close parenth below
|
|
}
|
|
}
|
|
|
|
// if (c != ' ' || (len && buf[len-1] != ' ')) // don't bother adding multiple spaces
|
|
{
|
|
buf[len++]=c;
|
|
if (c != ' ') ctx->l_stats[0]++;
|
|
}
|
|
}
|
|
}
|
|
buf[len]=0;
|
|
|
|
return buf;
|
|
}
|
|
|
|
#ifdef PPROC_TEST
|
|
|
|
int main(int argc, char* argv[])
|
|
{
|
|
compileContext ctx={0};
|
|
char *p=preprocessCode(&ctx,argv[1]);
|
|
if (p)printf("%s\n",p);
|
|
free(p);
|
|
return 0;
|
|
}
|
|
|
|
#endif
|
|
|
|
#if 0
|
|
static void movestringover(char *str, int amount)
|
|
{
|
|
char tmp[1024+8];
|
|
|
|
int l=(int)strlen(str);
|
|
l=min(1024-amount-1,l);
|
|
|
|
memcpy(tmp,str,l+1);
|
|
|
|
while (l >= 0 && tmp[l]!='\n') l--;
|
|
l++;
|
|
|
|
tmp[l]=0;//ensure we null terminate
|
|
|
|
memcpy(str+amount,tmp,l+1);
|
|
}
|
|
#endif
|
|
|
|
//------------------------------------------------------------------------------
|
|
NSEEL_CODEHANDLE NSEEL_code_compile(NSEEL_VMCTX _ctx, char *_expression, int lineoffs)
|
|
{
|
|
compileContext *ctx = (compileContext *)_ctx;
|
|
char *expression,*expression_start;
|
|
int computable_size=0;
|
|
codeHandleType *handle;
|
|
startPtr *scode=NULL;
|
|
startPtr *startpts=NULL;
|
|
|
|
if (!ctx) return 0;
|
|
|
|
ctx->last_error_string[0]=0;
|
|
|
|
if (!_expression || !*_expression) return 0;
|
|
|
|
freeBlocks((llBlock **)&ctx->tmpblocks_head); // free blocks
|
|
freeBlocks((llBlock **)&ctx->blocks_head); // free blocks
|
|
memset(ctx->l_stats,0,sizeof(ctx->l_stats));
|
|
free(ctx->compileLineRecs); ctx->compileLineRecs=0; ctx->compileLineRecs_size=0; ctx->compileLineRecs_alloc=0;
|
|
|
|
handle = (codeHandleType*)newBlock(sizeof(codeHandleType),8);
|
|
|
|
if (!handle)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
memset(handle,0,sizeof(codeHandleType));
|
|
|
|
expression_start=expression=preprocessCode(ctx,_expression);
|
|
|
|
|
|
while (*expression)
|
|
{
|
|
void *startptr;
|
|
char *expr;
|
|
ctx->colCount=0;
|
|
ctx->computTableTop=0;
|
|
|
|
// single out segment
|
|
while (*expression == ';' || isspace(*expression)) expression++;
|
|
if (!*expression) break;
|
|
expr=expression;
|
|
|
|
while (*expression && *expression != ';') expression++;
|
|
if (*expression) *expression++ = 0;
|
|
|
|
// parse
|
|
|
|
startptr=nseel_compileExpression(ctx,expr);
|
|
|
|
if (ctx->computTableTop > NSEEL_MAX_TEMPSPACE_ENTRIES- /* safety */ 16 - /* alignment */4 ||
|
|
!startptr)
|
|
{
|
|
int byteoffs = expr - expression_start;
|
|
int destoffs,linenumber;
|
|
char buf[21], *p;
|
|
int x,le;
|
|
|
|
#ifdef NSEEL_EEL1_COMPAT_MODE
|
|
if (!startptr) continue;
|
|
#endif
|
|
if (ctx->errVar > 0) byteoffs += ctx->errVar;
|
|
linenumber=findByteOffsetInSource(ctx,byteoffs,&destoffs);
|
|
if (destoffs < 0) destoffs=0;
|
|
|
|
le=strlen(_expression);
|
|
if (destoffs >= le) destoffs=le;
|
|
p= _expression + destoffs;
|
|
for (x = 0;x < 20; x ++)
|
|
{
|
|
if (!*p || *p == '\r' || *p == '\n') break;
|
|
buf[x]=*p++;
|
|
}
|
|
buf[x]=0;
|
|
|
|
sprintf(ctx->last_error_string,"Around line %d '%s'",linenumber+lineoffs,buf);
|
|
|
|
ctx->last_error_string[sizeof(ctx->last_error_string)-1]=0;
|
|
scode=NULL;
|
|
break;
|
|
}
|
|
if (computable_size < ctx->computTableTop)
|
|
{
|
|
computable_size=ctx->computTableTop;
|
|
}
|
|
|
|
{
|
|
startPtr *tmp=(startPtr*) __newBlock((llBlock **)&ctx->tmpblocks_head,sizeof(startPtr));
|
|
if (!tmp) break;
|
|
|
|
tmp->startptr = startptr;
|
|
tmp->next=NULL;
|
|
if (!scode) scode=startpts=tmp;
|
|
else
|
|
{
|
|
scode->next=tmp;
|
|
scode=tmp;
|
|
}
|
|
}
|
|
}
|
|
free(ctx->compileLineRecs); ctx->compileLineRecs=0; ctx->compileLineRecs_size=0; ctx->compileLineRecs_alloc=0;
|
|
|
|
// check to see if failed on the first startingCode
|
|
if (!scode)
|
|
{
|
|
handle=NULL; // return NULL (after resetting blocks_head)
|
|
}
|
|
else
|
|
{
|
|
char *tabptr = (char *)(handle->workTable=calloc(computable_size+64, sizeof(EEL_F)));
|
|
unsigned char *writeptr;
|
|
startPtr *p=startpts;
|
|
int size=sizeof(GLUE_RET)+GLUE_FUNC_ENTER_SIZE+GLUE_FUNC_LEAVE_SIZE; // for ret at end :)
|
|
|
|
if (((INT_PTR)tabptr)&31)
|
|
tabptr += 32-(((INT_PTR)tabptr)&31);
|
|
|
|
// now we build one big code segment out of our list of them, inserting a mov esi, computable before each item
|
|
while (p)
|
|
{
|
|
size += GLUE_RESET_ESI(NULL,0);
|
|
size+=*(int *)p->startptr;
|
|
p=p->next;
|
|
}
|
|
handle->code = newBlock(size,32);
|
|
if (handle->code)
|
|
{
|
|
writeptr=(unsigned char *)handle->code;
|
|
memcpy(writeptr,&GLUE_FUNC_ENTER,GLUE_FUNC_ENTER_SIZE); writeptr += GLUE_FUNC_ENTER_SIZE;
|
|
p=startpts;
|
|
while (p)
|
|
{
|
|
int thissize=*(int *)p->startptr;
|
|
writeptr+=GLUE_RESET_ESI(writeptr,tabptr);
|
|
//memcpy(writeptr,&GLUE_MOV_ESI_EDI,sizeof(GLUE_MOV_ESI_EDI));
|
|
//writeptr+=sizeof(GLUE_MOV_ESI_EDI);
|
|
memcpy(writeptr,(char*)p->startptr + 4,thissize);
|
|
writeptr += thissize;
|
|
|
|
p=p->next;
|
|
}
|
|
memcpy(writeptr,&GLUE_FUNC_LEAVE,GLUE_FUNC_LEAVE_SIZE); writeptr += GLUE_FUNC_LEAVE_SIZE;
|
|
memcpy(writeptr,&GLUE_RET,sizeof(GLUE_RET)); writeptr += sizeof(GLUE_RET);
|
|
ctx->l_stats[1]=size;
|
|
}
|
|
handle->blocks = ctx->blocks_head;
|
|
ctx->blocks_head=0;
|
|
|
|
}
|
|
freeBlocks((llBlock **)&ctx->tmpblocks_head); // free blocks
|
|
freeBlocks((llBlock **)&ctx->blocks_head); // free blocks
|
|
|
|
if (handle)
|
|
{
|
|
memcpy(handle->code_stats,ctx->l_stats,sizeof(ctx->l_stats));
|
|
nseel_evallib_stats[0]+=ctx->l_stats[0];
|
|
nseel_evallib_stats[1]+=ctx->l_stats[1];
|
|
nseel_evallib_stats[2]+=ctx->l_stats[2];
|
|
nseel_evallib_stats[3]+=ctx->l_stats[3];
|
|
nseel_evallib_stats[4]++;
|
|
}
|
|
memset(ctx->l_stats,0,sizeof(ctx->l_stats));
|
|
|
|
free(expression_start);
|
|
|
|
return (NSEEL_CODEHANDLE)handle;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
void NSEEL_code_execute(NSEEL_CODEHANDLE code)
|
|
{
|
|
INT_PTR tabptr;
|
|
INT_PTR codeptr;
|
|
codeHandleType *h = (codeHandleType *)code;
|
|
if (!h || !h->code) return;
|
|
|
|
codeptr = (INT_PTR) h->code;
|
|
#if 0
|
|
{
|
|
unsigned int *p=(unsigned int *)codeptr;
|
|
while (*p != GLUE_RET[0])
|
|
{
|
|
printf("instr:%04X:%04X\n",*p>>16,*p&0xffff);
|
|
p++;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
tabptr=(INT_PTR)h->workTable;
|
|
if (tabptr&31)
|
|
tabptr += 32-((tabptr)&31);
|
|
//printf("calling code!\n");
|
|
GLUE_CALL_CODE(tabptr,codeptr);
|
|
|
|
}
|
|
|
|
|
|
char *NSEEL_code_getcodeerror(NSEEL_VMCTX ctx)
|
|
{
|
|
compileContext *c=(compileContext *)ctx;
|
|
if (ctx && c->last_error_string[0]) return c->last_error_string;
|
|
return 0;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
void NSEEL_code_free(NSEEL_CODEHANDLE code)
|
|
{
|
|
codeHandleType *h = (codeHandleType *)code;
|
|
if (h != NULL)
|
|
{
|
|
free(h->workTable);
|
|
nseel_evallib_stats[0]-=h->code_stats[0];
|
|
nseel_evallib_stats[1]-=h->code_stats[1];
|
|
nseel_evallib_stats[2]-=h->code_stats[2];
|
|
nseel_evallib_stats[3]-=h->code_stats[3];
|
|
nseel_evallib_stats[4]--;
|
|
freeBlocks(&h->blocks);
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
void NSEEL_VM_resetvars(NSEEL_VMCTX _ctx)
|
|
{
|
|
if (_ctx)
|
|
{
|
|
compileContext *ctx=(compileContext *)_ctx;
|
|
int x;
|
|
if (ctx->varTable_Names || ctx->varTable_Values) for (x = 0; x < ctx->varTable_numBlocks; x ++)
|
|
{
|
|
if (ctx->varTable_Names) free(ctx->varTable_Names[x]);
|
|
if (ctx->varTable_Values) free(ctx->varTable_Values[x]);
|
|
}
|
|
|
|
free(ctx->varTable_Values);
|
|
free(ctx->varTable_Names);
|
|
ctx->varTable_Values=0;
|
|
ctx->varTable_Names=0;
|
|
|
|
ctx->varTable_numBlocks=0;
|
|
}
|
|
}
|
|
|
|
|
|
NSEEL_VMCTX NSEEL_VM_alloc() // return a handle
|
|
{
|
|
compileContext *ctx=calloc(1,sizeof(compileContext));
|
|
return ctx;
|
|
}
|
|
|
|
void NSEEL_VM_free(NSEEL_VMCTX _ctx) // free when done with a VM and ALL of its code have been freed, as well
|
|
{
|
|
|
|
if (_ctx)
|
|
{
|
|
compileContext *ctx=(compileContext *)_ctx;
|
|
NSEEL_VM_resetvars(_ctx);
|
|
NSEEL_VM_freeRAM(_ctx);
|
|
|
|
freeBlocks((llBlock **)&ctx->tmpblocks_head); // free blocks
|
|
freeBlocks((llBlock **)&ctx->blocks_head); // free blocks
|
|
free(ctx->compileLineRecs);
|
|
free(ctx);
|
|
}
|
|
|
|
}
|
|
|
|
int *NSEEL_code_getstats(NSEEL_CODEHANDLE code)
|
|
{
|
|
codeHandleType *h = (codeHandleType *)code;
|
|
if (h)
|
|
{
|
|
return h->code_stats;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void NSEEL_VM_SetCustomFuncThis(NSEEL_VMCTX ctx, void *thisptr)
|
|
{
|
|
if (ctx)
|
|
{
|
|
compileContext *c=(compileContext*)ctx;
|
|
c->caller_this=thisptr;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void NSEEL_PProc_RAM(void *data, int data_size, compileContext *ctx)
|
|
{
|
|
if (data_size>0) EEL_GLUE_set_immediate(data, &ctx->ram_blocks);
|
|
}
|
|
void NSEEL_PProc_THIS(void *data, int data_size, compileContext *ctx)
|
|
{
|
|
if (data_size>0) EEL_GLUE_set_immediate(data, ctx->caller_this);
|
|
}
|