1 /*
2   Expression Evaluator Library (NS-EEL) v2
3   Copyright (C) 2004-2008 Cockos Incorporated
4   Copyright (C) 1999-2003 Nullsoft, Inc.
5 
6   nseel-compiler.c
7 
8   This software is provided 'as-is', without any express or implied
9   warranty.  In no event will the authors be held liable for any damages
10   arising from the use of this software.
11 
12   Permission is granted to anyone to use this software for any purpose,
13   including commercial applications, and to alter it and redistribute it
14   freely, subject to the following restrictions:
15 
16   1. The origin of this software must not be misrepresented; you must not
17      claim that you wrote the original software. If you use this software
18      in a product, an acknowledgment in the product documentation would be
19      appreciated but is not required.
20   2. Altered source versions must be plainly marked as such, and must not be
21      misrepresented as being the original software.
22   3. This notice may not be removed or altered from any source distribution.
23 */
24 
25 
26 // for VirtualProtect
27 
28 #include "ns-eel-int.h"
29 
30 
31 #include <string.h>
32 #include <math.h>
33 #include <stdio.h>
34 #include <ctype.h>
35 
36 #ifndef _WIN64
37   #ifndef __ppc__
38     #include <float.h>
39   #endif
40 #endif
41 
42 #ifdef __APPLE__
43   #ifdef __LP64__
44     #define EEL_USE_MPROTECT
45   #endif
46 #endif
47 
48 #ifdef EEL_USE_MPROTECT
49 #include <sys/mman.h>
50 #include <stdint.h>
51 #include <unistd.h>
52 #endif
53 
54 #ifdef NSEEL_EEL1_COMPAT_MODE
55 
56 #ifndef EEL_NO_CHANGE_FPFLAGS
57 #define EEL_NO_CHANGE_FPFLAGS
58 #endif
59 
60 #endif
61 
62 #ifndef _WIN64
63 #if !defined(_RC_CHOP) && !defined(EEL_NO_CHANGE_FPFLAGS)
64 
65 #include <fpu_control.h>
66 #define _RC_CHOP _FPU_RC_ZERO
67 #define _MCW_RC _FPU_RC_ZERO
_controlfp(unsigned int val,unsigned int mask)68 static unsigned int _controlfp(unsigned int val, unsigned int mask)
69 {
70    unsigned int ret;
71    _FPU_GETCW(ret);
72    if (mask)
73    {
74      ret&=~mask;
75      ret|=val;
76      _FPU_SETCW(ret);
77    }
78    return ret;
79 }
80 
81 #endif
82 #endif
83 
84 
85 #ifdef __ppc__
86 
87 #define GLUE_MOV_EAX_DIRECTVALUE_SIZE 8
GLUE_MOV_EAX_DIRECTVALUE_GEN(void * b,INT_PTR v)88 static void GLUE_MOV_EAX_DIRECTVALUE_GEN(void *b, INT_PTR v)
89 {
90     	unsigned int uv=(unsigned int)v;
91 	unsigned short *p=(unsigned short *)b;
92 
93         *p++ = 0x3C60; // addis r3, r0, hw
94 	*p++ = (uv>>16)&0xffff;
95         *p++ = 0x6063; // ori r3, r3, lw
96 	*p++ = uv&0xffff;
97 }
98 
99 
100 // mflr r5
101 // stwu r5, -4(r1)
102 const static unsigned int GLUE_FUNC_ENTER[2] = { 0x7CA802A6, 0x94A1FFFC };
103 
104 // lwz r5, 0(r1)
105 // addi r1, r1, 4
106 // mtlr r5
107 const static unsigned int GLUE_FUNC_LEAVE[3] = { 0x80A10000, 0x38210004, 0x7CA803A6 };
108 #define GLUE_FUNC_ENTER_SIZE sizeof(GLUE_FUNC_ENTER)
109 #define GLUE_FUNC_LEAVE_SIZE sizeof(GLUE_FUNC_LEAVE)
110 
111 const static unsigned int GLUE_RET[]={0x4E800020}; // blr
112 
113 const static unsigned int GLUE_MOV_ESI_EDI=0x7E308B78; // mr r16, r17
114 
GLUE_RESET_ESI(char * out,void * ptr)115 static int GLUE_RESET_ESI(char *out, void *ptr)
116 {
117   if (out) memcpy(out,&GLUE_MOV_ESI_EDI,sizeof(GLUE_MOV_ESI_EDI));
118   return sizeof(GLUE_MOV_ESI_EDI);
119 
120 }
121 
122 
123 
124 // stwu r3, -4(r1)
125 const static unsigned int GLUE_PUSH_EAX[1]={ 0x9461FFFC};
126 
127 // lwz r14, 0(r1)
128 // addi r1, r1, 4
129 const static unsigned int GLUE_POP_EBX[2]={ 0x81C10000, 0x38210004, };
130 
131 // lwz r15, 0(r1)
132 // addi r1, r1, 4
133 const static unsigned int GLUE_POP_ECX[2]={ 0x81E10000, 0x38210004 };
134 
135 
GLUE_CALL_CODE(INT_PTR bp,INT_PTR cp)136 static void GLUE_CALL_CODE(INT_PTR bp, INT_PTR cp)
137 {
138   __asm__(
139           "stmw r14, -80(r1)\n"
140           "mtctr %0\n"
141           "mr r17, %1\n"
142 	  "subi r17, r17, 8\n"
143           "mflr r5\n"
144           "stw r5, -84(r1)\n"
145           "subi r1, r1, 88\n"
146           "bctrl\n"
147           "addi r1, r1, 88\n"
148           "lwz r5, -84(r1)\n"
149           "lmw r14, -80(r1)\n"
150           "mtlr r5\n"
151             ::"r" (cp), "r" (bp));
152 };
153 
EEL_GLUE_set_immediate(void * _p,void * newv)154 INT_PTR *EEL_GLUE_set_immediate(void *_p, void *newv)
155 {
156 // todo 64 bit ppc will take some work
157   unsigned int *p=(unsigned int *)_p;
158   while ((p[0]&0x0000FFFF) != 0x0000dead &&
159          (p[1]&0x0000FFFF) != 0x0000beef) p++;
160   p[0] = (p[0]&0xFFFF0000) | (((unsigned int)newv)>>16);
161   p[1] = (p[1]&0xFFFF0000) | (((unsigned int)newv)&0xFFFF);
162 
163   return (INT_PTR*)++p;
164 }
165 
166 
167 #else
168 
169 //x86 specific code
170 
171 #define GLUE_FUNC_ENTER_SIZE 0
172 #define GLUE_FUNC_LEAVE_SIZE 0
173 const static unsigned int GLUE_FUNC_ENTER[1];
174 const static unsigned int GLUE_FUNC_LEAVE[1];
175 
176 #if defined(_WIN64) || defined(__LP64__)
177 #define GLUE_MOV_EAX_DIRECTVALUE_SIZE 10
GLUE_MOV_EAX_DIRECTVALUE_GEN(void * b,INT_PTR v)178 static void GLUE_MOV_EAX_DIRECTVALUE_GEN(void *b, INT_PTR v) {
179   unsigned short *bb = (unsigned short *)b;
180   *bb++ =0xB848;
181   *(INT_PTR *)bb = v;
182 }
183 const static unsigned char  GLUE_PUSH_EAX[2]={	   0x50,0x50}; // push rax ; push rax (push twice to preserve alignment)
184 const static unsigned char  GLUE_POP_EBX[2]={0x5F, 0x5f}; //pop rdi ; twice
185 const static unsigned char  GLUE_POP_ECX[2]={0x59, 0x59 }; // pop rcx ; twice
186 #else
187 #define GLUE_MOV_EAX_DIRECTVALUE_SIZE 5
GLUE_MOV_EAX_DIRECTVALUE_GEN(void * b,int v)188 static void GLUE_MOV_EAX_DIRECTVALUE_GEN(void *b, int v)
189 {
190   *((unsigned char *)b) =0xB8;
191   b= ((unsigned char *)b)+1;
192   *(int *)b = v;
193 }
194 const static unsigned char  GLUE_PUSH_EAX[4]={0x83, 0xEC, 12,   0x50}; // sub esp, 12, push eax
195 const static unsigned char  GLUE_POP_EBX[4]={0x5F, 0x83, 0xC4, 12}; //pop ebx, add esp, 12 // DI=5F, BX=0x5B;
196 const static unsigned char  GLUE_POP_ECX[4]={0x59, 0x83, 0xC4, 12}; // pop ecx, add esp, 12
197 
198 #endif
199 
200 //const static unsigned short GLUE_MOV_ESI_EDI=0xF78B;
201 const static unsigned char  GLUE_RET=0xC3;
202 
GLUE_RESET_ESI(unsigned char * out,void * ptr)203 static int GLUE_RESET_ESI(unsigned char *out, void *ptr)
204 {
205 #if defined(_WIN64) || defined(__LP64__)
206   if (out)
207   {
208 	  *out++ = 0x48;
209     *out++ = 0xBE; // mov rsi, constant64
210   	*(void **)out = ptr;
211     out+=sizeof(void *);
212   }
213   return 2+sizeof(void *);
214 #else
215   if (out)
216   {
217     *out++ = 0xBE; // mov esi, constant
218     memcpy(out,&ptr,sizeof(void *));
219     out+=sizeof(void *);
220   }
221   return 1+sizeof(void *);
222 #endif
223 }
224 
GLUE_CALL_CODE(INT_PTR bp,INT_PTR cp)225 static void GLUE_CALL_CODE(INT_PTR bp, INT_PTR cp)
226 {
227   #if defined(_WIN64) || defined(__LP64__)
228 	  extern void win64_callcode(INT_PTR code);
229 	  win64_callcode(cp);
230   #else // non-64 bit
231  #ifdef _MSC_VER
232     #ifndef EEL_NO_CHANGE_FPFLAGS
233       unsigned int old_v=_controlfp(0,0);
234       _controlfp(_RC_CHOP,_MCW_RC);
235     #endif
236 
237     __asm
238     {
239       mov eax, cp
240       pushad
241       call eax
242       popad
243     };
244 
245     #ifndef EEL_NO_CHANGE_FPFLAGS
246       _controlfp(old_v,_MCW_RC);
247     #endif
248 
249 #else // gcc x86
250   #ifndef EEL_NO_CHANGE_FPFLAGS
251     unsigned int old_v=_controlfp(0,0);
252     _controlfp(_RC_CHOP,_MCW_RC);
253   #endif
254   __asm__("call *%%eax"::"a" (cp): "%ecx","%edx","%esi","%edi");
255   #ifndef EEL_NO_CHANGE_FPFLAGS
256     _controlfp(old_v,_MCW_RC);
257   #endif
258     #endif //gcc x86
259   #endif // 32bit
260 }
261 
EEL_GLUE_set_immediate(void * _p,void * newv)262 INT_PTR *EEL_GLUE_set_immediate(void *_p, void *newv)
263 {
264   char *p=(char*)_p;
265   while (*(INT_PTR *)p != ~(INT_PTR)0) p++;
266   *(INT_PTR *)p = (INT_PTR)newv;
267   return ((INT_PTR*)p)+1;
268 }
269 
270 #endif
271 
272 
GLUE_realAddress(void * fn,void * fn_e,int * size)273 static void *GLUE_realAddress(void *fn, void *fn_e, int *size)
274 {
275 #if defined(_MSC_VER) || defined(__LP64__)
276 
277   unsigned char *p;
278 
279 #if defined(_DEBUG) && !defined(__LP64__)
280   if (*(unsigned char *)fn == 0xE9) // this means jump to the following address
281   {
282     fn = ((unsigned char *)fn) + *(int *)((char *)fn+1) + 5;
283   }
284 #endif
285 
286   // this may not work in debug mode
287   p=(unsigned char *)fn;
288   for (;;)
289   {
290     int a;
291     for (a=0;a<12;a++)
292     {
293       if (p[a] != (a?0x90:0x89)) break;
294     }
295     if (a>=12)
296     {
297       *size = (char *)p - (char *)fn;
298     //  if (*size<0) MessageBox(NULL,"expect poof","a",0);
299       return fn;
300     }
301     p++;
302   }
303 #else
304   char *p=(char *)fn_e - sizeof(GLUE_RET);
305   if (p <= (char *)fn) *size=0;
306   else
307   {
308     while (p > (char *)fn && memcmp(p,&GLUE_RET,sizeof(GLUE_RET))) p-=sizeof(GLUE_RET);
309     *size = p - (char *)fn;
310   }
311   return fn;
312 #endif
313 }
314 
315 
316 
317 static int nseel_evallib_stats[5]; // source bytes, static code bytes, call code bytes, data bytes, segments
NSEEL_getstats()318 int *NSEEL_getstats()
319 {
320   return nseel_evallib_stats;
321 }
NSEEL_getglobalregs()322 EEL_F *NSEEL_getglobalregs()
323 {
324   return nseel_globalregs;
325 }
326 
327 // this stuff almost works
findByteOffsetInSource(compileContext * ctx,int byteoffs,int * destoffs)328 static int findByteOffsetInSource(compileContext *ctx, int byteoffs,int *destoffs)
329 {
330 	int x;
331 	if (!ctx->compileLineRecs || !ctx->compileLineRecs_size) return *destoffs=0;
332 	if (byteoffs < ctx->compileLineRecs[0].destByteCount)
333 	{
334 		*destoffs=0;
335 		return 1;
336 	}
337 	for (x = 0; x < ctx->compileLineRecs_size-1; x ++)
338 	{
339 		if (byteoffs >= ctx->compileLineRecs[x].destByteCount &&
340 		    byteoffs < ctx->compileLineRecs[x+1].destByteCount) break;
341 	}
342 	*destoffs=ctx->compileLineRecs[(x&&x==ctx->compileLineRecs_size-1)?x-1:x].srcByteCount;
343 
344 	return x+2;
345 }
346 
347 
onCompileNewLine(compileContext * ctx,int srcBytes,int destBytes)348 static void onCompileNewLine(compileContext *ctx, int srcBytes, int destBytes)
349 {
350 	if (!ctx->compileLineRecs || ctx->compileLineRecs_size >= ctx->compileLineRecs_alloc)
351 	{
352 		ctx->compileLineRecs_alloc = ctx->compileLineRecs_size+1024;
353 		ctx->compileLineRecs = (lineRecItem *)realloc(ctx->compileLineRecs,sizeof(lineRecItem)*ctx->compileLineRecs_alloc);
354 	}
355 	if (ctx->compileLineRecs)
356 	{
357 		ctx->compileLineRecs[ctx->compileLineRecs_size].srcByteCount=srcBytes;
358 		ctx->compileLineRecs[ctx->compileLineRecs_size++].destByteCount=destBytes;
359 	}
360 }
361 
362 
363 
364 #define LLB_DSIZE (65536-64)
365 typedef struct _llBlock {
366 	struct _llBlock *next;
367   int sizeused;
368 	char block[LLB_DSIZE];
369 } llBlock;
370 
371 typedef struct _startPtr {
372   struct _startPtr *next;
373   void *startptr;
374 } startPtr;
375 
376 typedef struct {
377   void *workTable;
378 
379   llBlock *blocks;
380   void *code;
381   int code_stats[4];
382 } codeHandleType;
383 
384 #ifndef NSEEL_MAX_TEMPSPACE_ENTRIES
385 #define NSEEL_MAX_TEMPSPACE_ENTRIES 2048
386 #endif
387 
388 static void *__newBlock(llBlock **start,int size);
389 
390 #define newTmpBlock(x) __newTmpBlock((llBlock **)&ctx->tmpblocks_head,x)
391 #define newBlock(x,a) __newBlock_align(ctx,x,a)
392 
__newTmpBlock(llBlock ** start,int size)393 static void *__newTmpBlock(llBlock **start, int size)
394 {
395   void *p=__newBlock(start,size+4);
396   if (p && size>=0) *((int *)p) = size;
397   return p;
398 }
399 
__newBlock_align(compileContext * ctx,int size,int align)400 static void *__newBlock_align(compileContext *ctx, int size, int align) // makes sure block is aligned to 32 byte boundary, for code
401 {
402   int a1=align-1;
403   char *p=(char*)__newBlock((llBlock **)&ctx->blocks_head,size+a1);
404   return p+((align-(((INT_PTR)p)&a1))&a1);
405 }
406 
407 static void freeBlocks(llBlock **start);
408 
409 #define DECL_ASMFUNC(x)         \
410   void nseel_asm_##x(void);        \
411   void nseel_asm_##x##_end(void);    \
412 
413   DECL_ASMFUNC(sin)
DECL_ASMFUNC(cos)414   DECL_ASMFUNC(cos)
415   DECL_ASMFUNC(tan)
416   DECL_ASMFUNC(1pdd)
417   DECL_ASMFUNC(2pdd)
418   DECL_ASMFUNC(2pdds)
419   DECL_ASMFUNC(1pp)
420   DECL_ASMFUNC(2pp)
421   DECL_ASMFUNC(sqr)
422   DECL_ASMFUNC(sqrt)
423   DECL_ASMFUNC(log)
424   DECL_ASMFUNC(log10)
425   DECL_ASMFUNC(abs)
426   DECL_ASMFUNC(min)
427   DECL_ASMFUNC(max)
428   DECL_ASMFUNC(sig)
429   DECL_ASMFUNC(sign)
430   DECL_ASMFUNC(band)
431   DECL_ASMFUNC(bor)
432   DECL_ASMFUNC(bnot)
433   DECL_ASMFUNC(if)
434   DECL_ASMFUNC(repeat)
435   DECL_ASMFUNC(repeatwhile)
436   DECL_ASMFUNC(equal)
437   DECL_ASMFUNC(notequal)
438   DECL_ASMFUNC(below)
439   DECL_ASMFUNC(above)
440   DECL_ASMFUNC(beloweq)
441   DECL_ASMFUNC(aboveeq)
442   DECL_ASMFUNC(assign)
443   DECL_ASMFUNC(add)
444   DECL_ASMFUNC(sub)
445   DECL_ASMFUNC(add_op)
446   DECL_ASMFUNC(sub_op)
447   DECL_ASMFUNC(mul)
448   DECL_ASMFUNC(div)
449   DECL_ASMFUNC(mul_op)
450   DECL_ASMFUNC(div_op)
451   DECL_ASMFUNC(mod)
452   DECL_ASMFUNC(mod_op)
453   DECL_ASMFUNC(or)
454   DECL_ASMFUNC(and)
455   DECL_ASMFUNC(or_op)
456   DECL_ASMFUNC(and_op)
457   DECL_ASMFUNC(uplus)
458   DECL_ASMFUNC(uminus)
459   DECL_ASMFUNC(invsqrt)
460   DECL_ASMFUNC(exec2)
461 
462 static void NSEEL_PProc_GRAM(void *data, int data_size, compileContext *ctx)
463 {
464   if (data_size>0) EEL_GLUE_set_immediate(data, ctx->gram_blocks);
465 }
466 
467 
468 static EEL_F g_signs[2]={1.0,-1.0};
469 static EEL_F negativezeropointfive=-0.5f;
470 static EEL_F onepointfive=1.5f;
471 static EEL_F g_closefact = NSEEL_CLOSEFACTOR;
472 static const EEL_F eel_zero=0.0, eel_one=1.0;
473 
474 #if defined(_MSC_VER) && _MSC_VER >= 1400
__floor(double a)475 static double __floor(double a) { return floor(a); }
476 #endif
477 
eel1band(double a,double b)478 static double eel1band(double a, double b)
479 {
480   return (fabs(a)>g_closefact && fabs(b) > g_closefact) ? 1.0 : 0.0;
481 }
eel1bor(double a,double b)482 static double eel1bor(double a, double b)
483 {
484   return (fabs(a)>g_closefact || fabs(b) > g_closefact) ? 1.0 : 0.0;
485 }
486 
eel1sigmoid(double x,double constraint)487 static double eel1sigmoid(double x, double constraint)
488 {
489   double t = (1+exp(-x * (constraint)));
490   return fabs(t)>g_closefact ? 1.0/t : 0;
491 }
492 
493 
494 EEL_F NSEEL_CGEN_CALL nseel_int_rand(EEL_F *f);
495 
496 static functionType fnTable1[] = {
497   { "_if",     nseel_asm_if,nseel_asm_if_end,    3,  {&g_closefact} },
498   { "_and",   nseel_asm_band,nseel_asm_band_end,  2 } ,
499   { "_or",    nseel_asm_bor,nseel_asm_bor_end,   2 } ,
500   { "loop", nseel_asm_repeat,nseel_asm_repeat_end, 2 },
501   { "while", nseel_asm_repeatwhile,nseel_asm_repeatwhile_end, 1 },
502 
503 #ifdef __ppc__
504   { "_not",   nseel_asm_bnot,nseel_asm_bnot_end,  1, {&g_closefact,&eel_zero,&eel_one} } ,
505   { "_equal",  nseel_asm_equal,nseel_asm_equal_end, 2, {&g_closefact,&eel_zero, &eel_one} },
506   { "_noteq",  nseel_asm_notequal,nseel_asm_notequal_end, 2, {&g_closefact,&eel_one,&eel_zero} },
507   { "_below",  nseel_asm_below,nseel_asm_below_end, 2, {&eel_zero, &eel_one} },
508   { "_above",  nseel_asm_above,nseel_asm_above_end, 2, {&eel_zero, &eel_one}  },
509   { "_beleq",  nseel_asm_beloweq,nseel_asm_beloweq_end, 2, {&eel_zero, &eel_one}  },
510   { "_aboeq",  nseel_asm_aboveeq,nseel_asm_aboveeq_end, 2, {&eel_zero, &eel_one} },
511 #else
512   { "_not",   nseel_asm_bnot,nseel_asm_bnot_end,  1, {&g_closefact} } ,
513   { "_equal",  nseel_asm_equal,nseel_asm_equal_end, 2, {&g_closefact} },
514   { "_noteq",  nseel_asm_notequal,nseel_asm_notequal_end, 2, {&g_closefact} },
515   { "_below",  nseel_asm_below,nseel_asm_below_end, 2 },
516   { "_above",  nseel_asm_above,nseel_asm_above_end, 2 },
517   { "_beleq",  nseel_asm_beloweq,nseel_asm_beloweq_end, 2 },
518   { "_aboeq",  nseel_asm_aboveeq,nseel_asm_aboveeq_end, 2 },
519 #endif
520 
521   { "_set",nseel_asm_assign,nseel_asm_assign_end,2},
522   { "_mod",nseel_asm_mod,nseel_asm_mod_end,2},
523   { "_mulop",nseel_asm_mul_op,nseel_asm_mul_op_end,2},
524   { "_divop",nseel_asm_div_op,nseel_asm_div_op_end,2},
525   { "_orop",nseel_asm_or_op,nseel_asm_or_op_end,2},
526   { "_andop",nseel_asm_and_op,nseel_asm_and_op_end,2},
527   { "_addop",nseel_asm_add_op,nseel_asm_add_op_end,2},
528   { "_subop",nseel_asm_sub_op,nseel_asm_sub_op_end,2},
529   { "_modop",nseel_asm_mod_op,nseel_asm_mod_op_end,2},
530 
531 
532 #ifdef __ppc__
533    { "sin",   nseel_asm_1pdd,nseel_asm_1pdd_end,   1, {&sin} },
534    { "cos",    nseel_asm_1pdd,nseel_asm_1pdd_end,   1, {&cos} },
535    { "tan",    nseel_asm_1pdd,nseel_asm_1pdd_end,   1, {&tan}  },
536 #else
537    { "sin",   nseel_asm_sin,nseel_asm_sin_end,   1 },
538    { "cos",    nseel_asm_cos,nseel_asm_cos_end,   1 },
539    { "tan",    nseel_asm_tan,nseel_asm_tan_end,   1 },
540 #endif
541    { "asin",   nseel_asm_1pdd,nseel_asm_1pdd_end,  1, {&asin}, },
542    { "acos",   nseel_asm_1pdd,nseel_asm_1pdd_end,  1, {&acos}, },
543    { "atan",   nseel_asm_1pdd,nseel_asm_1pdd_end,  1, {&atan}, },
544    { "atan2",  nseel_asm_2pdd,nseel_asm_2pdd_end, 2, {&atan2}, },
545    { "sqr",    nseel_asm_sqr,nseel_asm_sqr_end,   1 },
546 #ifdef __ppc__
547    { "sqrt",   nseel_asm_1pdd,nseel_asm_1pdd_end,  1, {&sqrt}, },
548 #else
549    { "sqrt",   nseel_asm_sqrt,nseel_asm_sqrt_end,  1 },
550 #endif
551    { "pow",    nseel_asm_2pdd,nseel_asm_2pdd_end,   2, {&pow}, },
552    { "_powop",    nseel_asm_2pdds,nseel_asm_2pdds_end,   2, {&pow}, },
553    { "exp",    nseel_asm_1pdd,nseel_asm_1pdd_end,   1, {&exp}, },
554 #ifdef __ppc__
555    { "log",    nseel_asm_1pdd,nseel_asm_1pdd_end,   1, {&log} },
556    { "log10",  nseel_asm_1pdd,nseel_asm_1pdd_end, 1, {&log10} },
557 #else
558    { "log",    nseel_asm_log,nseel_asm_log_end,   1, },
559    { "log10",  nseel_asm_log10,nseel_asm_log10_end, 1, },
560 #endif
561    { "abs",    nseel_asm_abs,nseel_asm_abs_end,   1 },
562    { "min",    nseel_asm_min,nseel_asm_min_end,   2 },
563    { "max",    nseel_asm_max,nseel_asm_max_end,   2 },
564 #ifdef __ppc__
565    { "sign",   nseel_asm_sign,nseel_asm_sign_end,  1, {&eel_zero}} ,
566 #else
567    { "sign",   nseel_asm_sign,nseel_asm_sign_end,  1, {&g_signs}} ,
568 #endif
569 	 { "rand",   nseel_asm_1pp,nseel_asm_1pp_end,  1, {&nseel_int_rand}, } ,
570 
571 #if defined(_MSC_VER) && _MSC_VER >= 1400
572    { "floor",  nseel_asm_1pdd,nseel_asm_1pdd_end, 1, {&__floor} },
573 #else
574    { "floor",  nseel_asm_1pdd,nseel_asm_1pdd_end, 1, {&floor} },
575 #endif
576    { "ceil",   nseel_asm_1pdd,nseel_asm_1pdd_end,  1, {&ceil} },
577 #ifdef __ppc__
578    { "invsqrt",   nseel_asm_invsqrt,nseel_asm_invsqrt_end,  1,  },
579 #else
580    { "invsqrt",   nseel_asm_invsqrt,nseel_asm_invsqrt_end,  1, {&negativezeropointfive, &onepointfive} },
581 #endif
582 
583   { "sigmoid", nseel_asm_2pdd,nseel_asm_2pdd_end, 2, {&eel1sigmoid}, },
584 
585   // these differ from _and/_or, they always evaluate both...
586   { "band",  nseel_asm_2pdd,nseel_asm_2pdd_end, 2, {&eel1band}, },
587   { "bor",  nseel_asm_2pdd,nseel_asm_2pdd_end, 2, {&eel1bor}, },
588 
589   {"exec2",nseel_asm_exec2,nseel_asm_exec2_end,2},
590   {"exec3",nseel_asm_exec2,nseel_asm_exec2_end,3},
591    {"_mem",_asm_megabuf,_asm_megabuf_end,1,{&g_closefact,&__NSEEL_RAMAlloc},NSEEL_PProc_RAM},
592   {"_gmem",_asm_megabuf,_asm_megabuf_end,1,{&g_closefact,&__NSEEL_RAMAllocGMEM},NSEEL_PProc_GRAM},
593   {"freembuf",_asm_generic1parm,_asm_generic1parm_end,1,{&__NSEEL_RAM_MemFree},NSEEL_PProc_RAM},
594   {"memcpy",_asm_generic3parm,_asm_generic3parm_end,3,{&__NSEEL_RAM_MemCpy},NSEEL_PProc_RAM},
595   {"memset",_asm_generic3parm,_asm_generic3parm_end,3,{&__NSEEL_RAM_MemSet},NSEEL_PProc_RAM},
596 };
597 
598 static functionType *fnTableUser;
599 static int fnTableUser_size;
600 
nseel_getFunctionFromTable(int idx)601 functionType *nseel_getFunctionFromTable(int idx)
602 {
603   if (idx<0) return 0;
604   if (idx>=sizeof(fnTable1)/sizeof(fnTable1[0]))
605   {
606     idx -= sizeof(fnTable1)/sizeof(fnTable1[0]);
607     if (!fnTableUser || idx >= fnTableUser_size) return 0;
608     return fnTableUser+idx;
609   }
610   return fnTable1+idx;
611 }
612 
NSEEL_init()613 int NSEEL_init() // returns 0 on success
614 {
615   NSEEL_quit();
616   return 0;
617 }
618 
NSEEL_addfunctionex2(const char * name,int nparms,char * code_startaddr,int code_len,void * pproc,void * fptr,void * fptr2)619 void NSEEL_addfunctionex2(const char *name, int nparms, char *code_startaddr, int code_len, void *pproc, void *fptr, void *fptr2)
620 {
621   if (!fnTableUser || !(fnTableUser_size&7))
622   {
623     fnTableUser=(functionType *)realloc(fnTableUser,(fnTableUser_size+8)*sizeof(functionType));
624   }
625   if (fnTableUser)
626   {
627     memset(&fnTableUser[fnTableUser_size],0,sizeof(functionType));
628     fnTableUser[fnTableUser_size].nParams = nparms;
629     fnTableUser[fnTableUser_size].name = name;
630     fnTableUser[fnTableUser_size].afunc = code_startaddr;
631     fnTableUser[fnTableUser_size].func_e = code_startaddr + code_len;
632     fnTableUser[fnTableUser_size].pProc = (NSEEL_PPPROC) pproc;
633     fnTableUser[fnTableUser_size].replptrs[0]=fptr;
634     fnTableUser[fnTableUser_size].replptrs[1]=fptr2;
635     fnTableUser_size++;
636   }
637 }
638 
NSEEL_quit()639 void NSEEL_quit()
640 {
641   free(fnTableUser);
642   fnTableUser_size=0;
643   fnTableUser=0;
644 }
645 
646 //---------------------------------------------------------------------------------------------------------------
freeBlocks(llBlock ** start)647 static void freeBlocks(llBlock **start)
648 {
649   llBlock *s=*start;
650   *start=0;
651   while (s)
652   {
653     llBlock *llB = s->next;
654 #ifdef _WIN32
655 		VirtualFree(s, 0 /*LLB_DSIZE*/, MEM_RELEASE);
656 #else
657     free(s);
658 #endif
659     s=llB;
660   }
661 }
662 
663 //---------------------------------------------------------------------------------------------------------------
__newBlock(llBlock ** start,int size)664 static void *__newBlock(llBlock **start, int size)
665 {
666   llBlock *llb;
667   int alloc_size;
668   if (*start && (LLB_DSIZE - (*start)->sizeused) >= size)
669   {
670     void *t=(*start)->block+(*start)->sizeused;
671     (*start)->sizeused+=(size+7)&~7;
672     return t;
673   }
674 
675   alloc_size=sizeof(llBlock);
676   if ((int)size > LLB_DSIZE) alloc_size += size - LLB_DSIZE;
677 
678 #ifdef _WIN32
679 	llb = (llBlock *)VirtualAlloc(NULL, alloc_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
680 #else
681 	llb = (llBlock *)malloc(alloc_size); // grab bigger block if absolutely necessary (heh)
682 #endif
683 #if defined(EEL_USE_MPROTECT)
684   {
685     static int pagesize = 0;
686     if (!pagesize)
687     {
688       pagesize=sysconf(_SC_PAGESIZE);
689       if (!pagesize) pagesize=4096;
690     }
691     uintptr_t offs,eoffs;
692     offs=((uintptr_t)llb)&~(pagesize-1);
693     eoffs=((uintptr_t)llb + alloc_size + pagesize-1)&~(pagesize-1);
694     mprotect((void*)offs,eoffs-offs,PROT_WRITE|PROT_READ|PROT_EXEC);
695   }
696 #endif
697   llb->sizeused=(size+7)&~7;
698   llb->next = *start;
699   *start = llb;
700   return llb->block;
701 }
702 
703 
704 //---------------------------------------------------------------------------------------------------------------
nseel_createCompiledValue(compileContext * ctx,EEL_F value,EEL_F * addrValue)705 INT_PTR nseel_createCompiledValue(compileContext *ctx, EEL_F value, EEL_F *addrValue)
706 {
707   unsigned char *block;
708 
709   block=(unsigned char *)newTmpBlock(GLUE_MOV_EAX_DIRECTVALUE_SIZE);
710 
711   if (addrValue == NULL)
712   {
713     *(addrValue = (EEL_F *)newBlock(sizeof(EEL_F),sizeof(EEL_F))) = value;
714     ctx->l_stats[3]+=sizeof(EEL_F);
715   }
716 
717   GLUE_MOV_EAX_DIRECTVALUE_GEN(block+4,(INT_PTR)addrValue);
718 
719   return ((INT_PTR)(block));
720 
721 }
722 
723 //---------------------------------------------------------------------------------------------------------------
nseel_getFunctionAddress(int fntype,int fn,int * size,NSEEL_PPPROC * pProc,void *** replList)724 static void *nseel_getFunctionAddress(int fntype, int fn, int *size, NSEEL_PPPROC *pProc, void ***replList)
725 {
726   *replList=0;
727   switch (fntype)
728 	{
729   	case MATH_SIMPLE:
730 	  	switch (fn)
731 			{
732 			  case FN_ASSIGN:
733 				  return GLUE_realAddress(nseel_asm_assign,nseel_asm_assign_end,size);
734 			  case FN_ADD:
735 				  return GLUE_realAddress(nseel_asm_add,nseel_asm_add_end,size);
736 			  case FN_SUB:
737 				  return GLUE_realAddress(nseel_asm_sub,nseel_asm_sub_end,size);
738 			  case FN_MULTIPLY:
739 				  return GLUE_realAddress(nseel_asm_mul,nseel_asm_mul_end,size);
740 			  case FN_DIVIDE:
741 				  return GLUE_realAddress(nseel_asm_div,nseel_asm_div_end,size);
742 			  case FN_MODULO:
743 				  return GLUE_realAddress(nseel_asm_exec2,nseel_asm_exec2_end,size);
744 			  case FN_AND:
745 				  return GLUE_realAddress(nseel_asm_and,nseel_asm_and_end,size);
746 			  case FN_OR:
747 				  return GLUE_realAddress(nseel_asm_or,nseel_asm_or_end,size);
748 			  case FN_UPLUS:
749 				  return GLUE_realAddress(nseel_asm_uplus,nseel_asm_uplus_end,size);
750 			  case FN_UMINUS:
751 				  return GLUE_realAddress(nseel_asm_uminus,nseel_asm_uminus_end,size);
752 			}
753 	  case MATH_FN:
754       {
755         functionType *p=nseel_getFunctionFromTable(fn);
756 		    if (p)
757         {
758           *replList=p->replptrs;
759           *pProc=p->pProc;
760           return GLUE_realAddress(p->afunc,p->func_e,size);
761         }
762       }
763 	}
764 
765   *size=0;
766   return 0;
767 }
768 
769 
770 //---------------------------------------------------------------------------------------------------------------
nseel_createCompiledFunction3(compileContext * ctx,int fntype,INT_PTR fn,INT_PTR code1,INT_PTR code2,INT_PTR code3)771 INT_PTR nseel_createCompiledFunction3(compileContext *ctx, int fntype, INT_PTR fn, INT_PTR code1, INT_PTR code2, INT_PTR code3)
772 {
773   int sizes1=((int *)code1)[0];
774   int sizes2=((int *)code2)[0];
775   int sizes3=((int *)code3)[0];
776 
777   if (fntype == MATH_FN && fn == 0) // special case: IF
778   {
779     void *func3;
780     int size;
781     INT_PTR *ptr;
782     char *block;
783 
784     unsigned char *newblock2,*newblock3;
785     unsigned char *p;
786 
787     p=newblock2=newBlock(sizes2+sizeof(GLUE_RET)+GLUE_FUNC_ENTER_SIZE+GLUE_FUNC_LEAVE_SIZE,32);
788     memcpy(p,&GLUE_FUNC_ENTER,GLUE_FUNC_ENTER_SIZE); p+=GLUE_FUNC_ENTER_SIZE;
789     memcpy(p,(char*)code2+4,sizes2); p+=sizes2;
790     memcpy(p,&GLUE_FUNC_LEAVE,GLUE_FUNC_LEAVE_SIZE); p+=GLUE_FUNC_LEAVE_SIZE;
791     memcpy(p,&GLUE_RET,sizeof(GLUE_RET)); p+=sizeof(GLUE_RET);
792 
793     p=newblock3=newBlock(sizes3+sizeof(GLUE_RET)+GLUE_FUNC_ENTER_SIZE+GLUE_FUNC_LEAVE_SIZE,32);
794     memcpy(p,&GLUE_FUNC_ENTER,GLUE_FUNC_ENTER_SIZE); p+=GLUE_FUNC_ENTER_SIZE;
795     memcpy(p,(char*)code3+4,sizes3); p+=sizes3;
796     memcpy(p,&GLUE_FUNC_LEAVE,GLUE_FUNC_LEAVE_SIZE); p+=GLUE_FUNC_LEAVE_SIZE;
797     memcpy(p,&GLUE_RET,sizeof(GLUE_RET)); p+=sizeof(GLUE_RET);
798 
799     ctx->l_stats[2]+=sizes2+sizes3+sizeof(GLUE_RET)*2;
800 
801     func3 = GLUE_realAddress(nseel_asm_if,nseel_asm_if_end,&size);
802 
803     block=(char *)newTmpBlock(sizes1+size);
804 
805     memcpy(block+4,(char*)code1+4,sizes1);
806     ptr=(INT_PTR *)(block+4+sizes1);
807     memcpy(ptr,func3,size);
808 
809     ptr=EEL_GLUE_set_immediate(ptr,&g_closefact);
810     ptr=EEL_GLUE_set_immediate(ptr,newblock2);
811     EEL_GLUE_set_immediate(ptr,newblock3);
812 
813     ctx->computTableTop++;
814 
815     return (INT_PTR)block;
816 
817   }
818   else
819   {
820     int size2;
821     unsigned char *block;
822     unsigned char *outp;
823 
824     void *myfunc;
825     NSEEL_PPPROC preProc=0;
826     void **repl;
827 
828     myfunc = nseel_getFunctionAddress(fntype, fn, &size2, &preProc,&repl);
829 
830     block=(unsigned char *)newTmpBlock(size2+sizes1+sizes2+sizes3+
831       sizeof(GLUE_PUSH_EAX) +
832       sizeof(GLUE_PUSH_EAX) +
833       sizeof(GLUE_POP_EBX) +
834       sizeof(GLUE_POP_ECX));
835 
836     outp=block+4;
837     memcpy(outp,(char*)code1+4,sizes1);
838     outp+=sizes1;
839     memcpy(outp,&GLUE_PUSH_EAX,sizeof(GLUE_PUSH_EAX)); outp+=sizeof(GLUE_PUSH_EAX);
840     memcpy(outp,(char*)code2+4,sizes2);
841     outp+=sizes2;
842     memcpy(outp,&GLUE_PUSH_EAX,sizeof(GLUE_PUSH_EAX)); outp+=sizeof(GLUE_PUSH_EAX);
843     memcpy(outp,(char*)code3+4,sizes3);
844     outp+=sizes3;
845     memcpy(outp,&GLUE_POP_EBX,sizeof(GLUE_POP_EBX)); outp+=sizeof(GLUE_POP_EBX);
846     memcpy(outp,&GLUE_POP_ECX,sizeof(GLUE_POP_ECX)); outp+=sizeof(GLUE_POP_ECX);
847 
848     memcpy(outp,myfunc,size2);
849     if (preProc) preProc(outp,size2,ctx);
850     if (repl)
851     {
852       if (repl[0]) outp=(unsigned char *)EEL_GLUE_set_immediate(outp,repl[0]);
853       if (repl[1]) outp=(unsigned char *)EEL_GLUE_set_immediate(outp,repl[1]);
854       if (repl[2]) outp=(unsigned char *)EEL_GLUE_set_immediate(outp,repl[2]);
855       if (repl[3]) outp=(unsigned char *)EEL_GLUE_set_immediate(outp,repl[3]);
856     }
857 
858     ctx->computTableTop++;
859 
860     return ((INT_PTR)(block));
861   }
862 }
863 
864 //---------------------------------------------------------------------------------------------------------------
nseel_createCompiledFunction2(compileContext * ctx,int fntype,INT_PTR fn,INT_PTR code1,INT_PTR code2)865 INT_PTR nseel_createCompiledFunction2(compileContext *ctx, int fntype, INT_PTR fn, INT_PTR code1, INT_PTR code2)
866 {
867   int size2;
868   unsigned char *outp;
869   void *myfunc;
870   int sizes1=((int *)code1)[0];
871   int sizes2=((int *)code2)[0];
872   if (fntype == MATH_FN && (fn == 1 || fn == 2 || fn == 3)) // special case: LOOP/BOR/BAND
873   {
874     void *func3;
875     int size;
876     INT_PTR *ptr;
877     char *block;
878 
879     unsigned char *newblock2, *p;
880 
881     p=newblock2=newBlock(sizes2+sizeof(GLUE_RET)+GLUE_FUNC_ENTER_SIZE+GLUE_FUNC_LEAVE_SIZE,32);
882     memcpy(p,&GLUE_FUNC_ENTER,GLUE_FUNC_ENTER_SIZE); p+=GLUE_FUNC_ENTER_SIZE;
883     memcpy(p,(char*)code2+4,sizes2); p+=sizes2;
884     memcpy(p,&GLUE_FUNC_LEAVE,GLUE_FUNC_LEAVE_SIZE); p+=GLUE_FUNC_LEAVE_SIZE;
885     memcpy(p,&GLUE_RET,sizeof(GLUE_RET)); p+=sizeof(GLUE_RET);
886 
887     ctx->l_stats[2]+=sizes2+2;
888 
889     if (fn == 1) func3 = GLUE_realAddress(nseel_asm_band,nseel_asm_band_end,&size);
890     else if (fn == 3) func3 = GLUE_realAddress(nseel_asm_repeat,nseel_asm_repeat_end,&size);
891     else func3 = GLUE_realAddress(nseel_asm_bor,nseel_asm_bor_end,&size);
892 
893     block=(char *)newTmpBlock(sizes1+size);
894     memcpy(block+4,(char*)code1+4,sizes1);
895     ptr=(INT_PTR *)(block+4+sizes1);
896     memcpy(ptr,func3,size);
897 
898     if (fn!=3) ptr=EEL_GLUE_set_immediate(ptr,&g_closefact); // for or/and
899     ptr=EEL_GLUE_set_immediate(ptr,newblock2);
900     if (fn!=3) ptr=EEL_GLUE_set_immediate(ptr,&g_closefact); // for or/and
901 #ifdef __ppc__
902     if (fn!=3) // for or/and on ppc we need a one
903     {
904       ptr=EEL_GLUE_set_immediate(ptr,&eel_one);
905     }
906 #endif
907 
908     ctx->computTableTop++;
909     return (INT_PTR)block;
910   }
911 
912   {
913     NSEEL_PPPROC preProc=0;
914     unsigned char *block;
915     void **repl;
916     myfunc = nseel_getFunctionAddress(fntype, fn, &size2,&preProc,&repl);
917 
918     block=(unsigned char *)newTmpBlock(size2+sizes1+sizes2+sizeof(GLUE_PUSH_EAX)+sizeof(GLUE_POP_EBX));
919 
920     outp=block+4;
921     memcpy(outp,(char*)code1+4,sizes1);
922     outp+=sizes1;
923     memcpy(outp,&GLUE_PUSH_EAX,sizeof(GLUE_PUSH_EAX)); outp+=sizeof(GLUE_PUSH_EAX);
924     memcpy(outp,(char*)code2+4,sizes2);
925     outp+=sizes2;
926     memcpy(outp,&GLUE_POP_EBX,sizeof(GLUE_POP_EBX)); outp+=sizeof(GLUE_POP_EBX);
927 
928     memcpy(outp,myfunc,size2);
929     if (preProc) preProc(outp,size2,ctx);
930     if (repl)
931     {
932       if (repl[0]) outp=(unsigned char *)EEL_GLUE_set_immediate(outp,repl[0]);
933       if (repl[1]) outp=(unsigned char *)EEL_GLUE_set_immediate(outp,repl[1]);
934       if (repl[2]) outp=(unsigned char *)EEL_GLUE_set_immediate(outp,repl[2]);
935       if (repl[3]) outp=(unsigned char *)EEL_GLUE_set_immediate(outp,repl[3]);
936     }
937 
938     ctx->computTableTop++;
939 
940     return ((INT_PTR)(block));
941   }
942 }
943 
944 
945 //---------------------------------------------------------------------------------------------------------------
nseel_createCompiledFunction1(compileContext * ctx,int fntype,INT_PTR fn,INT_PTR code)946 INT_PTR nseel_createCompiledFunction1(compileContext *ctx, int fntype, INT_PTR fn, INT_PTR code)
947 {
948   NSEEL_PPPROC preProc=0;
949   int size,size2;
950   char *block;
951   void *myfunc;
952   void *func1;
953 
954   size =((int *)code)[0];
955   func1 = (void *)(code+4);
956 
957 
958   if (fntype == MATH_FN && fn == 4) // special case: while
959   {
960     void *func3;
961     INT_PTR *ptr;
962 
963     unsigned char *newblock2, *p;
964 
965     p=newblock2=newBlock(size+sizeof(GLUE_RET)+GLUE_FUNC_ENTER_SIZE+GLUE_FUNC_LEAVE_SIZE,32);
966     memcpy(p,&GLUE_FUNC_ENTER,GLUE_FUNC_ENTER_SIZE); p+=GLUE_FUNC_ENTER_SIZE;
967     memcpy(p,func1,size); p+=size;
968     memcpy(p,&GLUE_FUNC_LEAVE,GLUE_FUNC_LEAVE_SIZE); p+=GLUE_FUNC_LEAVE_SIZE;
969     memcpy(p,&GLUE_RET,sizeof(GLUE_RET)); p+=sizeof(GLUE_RET);
970 
971     ctx->l_stats[2]+=size+2;
972 
973     func3 = GLUE_realAddress(nseel_asm_repeatwhile,nseel_asm_repeatwhile_end,&size);
974 
975     block=(char *)newTmpBlock(size);
976   	ptr = (INT_PTR *)(block+4);
977     memcpy(ptr,func3,size);
978     ptr=EEL_GLUE_set_immediate(ptr,newblock2);
979     EEL_GLUE_set_immediate(ptr,&g_closefact);
980 
981     ctx->computTableTop++;
982     return (INT_PTR)block;
983   }
984 
985   {
986     void **repl;
987 	  myfunc = nseel_getFunctionAddress(fntype, fn, &size2,&preProc,&repl);
988 
989 	  block=(char *)newTmpBlock(size+size2);
990 
991 	  memcpy(block+4, func1, size);
992 	  memcpy(block+size+4,myfunc,size2);
993 	  if (preProc) preProc(block+size+4,size2,ctx);
994     if (repl)
995     {
996       unsigned char *outp=(unsigned char *)block+size+4;
997       if (repl[0]) outp=(unsigned char *)EEL_GLUE_set_immediate(outp,repl[0]);
998       if (repl[1]) outp=(unsigned char *)EEL_GLUE_set_immediate(outp,repl[1]);
999       if (repl[2]) outp=(unsigned char *)EEL_GLUE_set_immediate(outp,repl[2]);
1000       if (repl[3]) outp=(unsigned char *)EEL_GLUE_set_immediate(outp,repl[3]);
1001     }
1002 
1003 	  ctx->computTableTop++;
1004 
1005 	  return ((INT_PTR)(block));
1006   }
1007 }
1008 
1009 
preprocessCode(compileContext * ctx,char * expression)1010 static char *preprocessCode(compileContext *ctx, char *expression)
1011 {
1012   char *expression_start=expression;
1013   int len=0;
1014   int alloc_len=strlen(expression)+1+64;
1015   char *buf=(char *)malloc(alloc_len);
1016   int semicnt=0;
1017   // we need to call onCompileNewLine for each new line we get
1018 
1019   //onCompileNewLine(ctx,
1020 
1021   while (*expression)
1022   {
1023     if (len > alloc_len-64)
1024     {
1025       alloc_len = len+128;
1026       buf=(char*)realloc(buf,alloc_len);
1027     }
1028 
1029     if (expression[0] == '/')
1030     {
1031       if (expression[1] == '/')
1032       {
1033         expression+=2;
1034         while (expression[0] && expression[0] != '\n') expression++;
1035 	continue;
1036       }
1037       else if (expression[1] == '*')
1038       {
1039         expression+=2;
1040         while (expression[0] && (expression[0] != '*' || expression[1] != '/'))
1041 	{
1042 		if (expression[0] == '\n') onCompileNewLine(ctx,expression+1-expression_start,len);
1043 		expression++;
1044 	}
1045         if (expression[0]) expression+=2; // at this point we KNOW expression[0]=* and expression[1]=/
1046 	continue;
1047       }
1048     }
1049 
1050     if (expression[0] == '$')
1051     {
1052       if (toupper(expression[1]) == 'X')
1053       {
1054         char *p=expression+2;
1055         unsigned int v=strtoul(expression+2,&p,16);
1056         char tmp[64];
1057         expression=p;
1058 
1059         sprintf(tmp,"%u",v);
1060         memcpy(buf+len,tmp,strlen(tmp));
1061         len+=strlen(tmp);
1062         ctx->l_stats[0]+=strlen(tmp);
1063         continue;
1064 
1065       }
1066       if (expression[1]=='\'' && expression[2] && expression[3]=='\'')
1067       {
1068         char tmp[64];
1069         sprintf(tmp,"%u",((unsigned char *)expression)[2]);
1070         expression+=4;
1071 
1072         memcpy(buf+len,tmp,strlen(tmp));
1073         len+=strlen(tmp);
1074         ctx->l_stats[0]+=strlen(tmp);
1075         continue;
1076       }
1077       if (toupper(expression[1]) == 'P' && toupper(expression[2]) == 'I')
1078       {
1079         static char *str="3.141592653589793";
1080         expression+=3;
1081         memcpy(buf+len,str,17);
1082         len+=17; //strlen(str);
1083         ctx->l_stats[0]+=17;
1084 	      continue;
1085       }
1086       if (toupper(expression[1]) == 'E')
1087       {
1088         static char *str="2.71828183";
1089         expression+=2;
1090         memcpy(buf+len,str,10);
1091         len+=10; //strlen(str);
1092         ctx->l_stats[0]+=10;
1093   	    continue;
1094       }
1095       if (toupper(expression[1]) == 'P' && toupper(expression[2]) == 'H' && toupper(expression[3]) == 'I')
1096       {
1097         static char *str="1.61803399";
1098         expression+=4;
1099         memcpy(buf+len,str,10);
1100         len+=10; //strlen(str);
1101         ctx->l_stats[0]+=10;
1102 	      continue;
1103       }
1104 
1105     }
1106 
1107     {
1108       char c=*expression++;
1109 
1110       if (c == '\n') onCompileNewLine(ctx,expression-expression_start,len);
1111       if (isspace(c)) c=' ';
1112 
1113       if (c == '(') semicnt++;
1114       else if (c == ')') { semicnt--; if (semicnt < 0) semicnt=0; }
1115       else if (c == ';' && semicnt > 0)
1116       {
1117         // convert ; to % if next nonwhitespace char is alnum, otherwise convert to space
1118         int p=0;
1119         int nc;
1120 		int commentstate=0;
1121         	while ((nc=expression[p]))
1122 		{
1123 			if (!commentstate && nc == '/')
1124 			{
1125 				if (expression[p+1] == '/') commentstate=1;
1126 				else if (expression[p+1] == '*') commentstate=2;
1127 			}
1128 
1129 			if (commentstate == 1 && nc == '\n') commentstate=0;
1130 			else if (commentstate == 2 && nc == '*' && expression[p+1]=='/')
1131 			{
1132 				p++; // skip *
1133 				commentstate=0;
1134 			}
1135 			else if (!commentstate && !isspace(nc)) break;
1136 
1137 			p++;
1138 		}
1139 		// fucko, we should look for even more chars, me thinks
1140         if (nc && (isalnum(nc)
1141 #if 1
1142 				|| nc == '(' || nc == '_' || nc == '!' || nc == '$'
1143 #endif
1144 				)) c='%';
1145         else c = ' '; // stray ;
1146       }
1147 #if 0
1148       else if (semicnt > 0 && c == ',')
1149       {
1150         int p=0;
1151         int nc;
1152         while ((nc=expression[p]) && isspace(nc)) p++;
1153 		if (nc == ',' || nc == ')')
1154 		{
1155 			expression += p+1;
1156 			buf[len++]=',';
1157 			buf[len++]='0';
1158 			c=nc; // append this char
1159 		}
1160       }
1161 #endif
1162 	  // list of operators
1163 
1164 	  else if (!isspace(c) && !isalnum(c)) // check to see if this operator is ours
1165 	  {
1166 
1167 			static char *symbollists[]=
1168 			{
1169 				"", // or any control char that is not parenthed
1170 				":(,;?%",
1171 				",):?;", // or || or &&
1172 				",);", // jf> removed :? from this, for =
1173 				",);",
1174         "",  // only scans for a negative ] level
1175 
1176 			};
1177 
1178 
1179 			static struct
1180 			{
1181 			  char op[2];
1182 			  char lscan,rscan;
1183 			  char *func;
1184 			} preprocSymbols[] =
1185 			{
1186 				{{'+','='}, 0, 3, "_addop" },
1187 				{{'-','='}, 0, 3, "_subop" },
1188 				{{'%','='}, 0, 3, "_modop" },
1189 				{{'|','='}, 0, 3, "_orop" },
1190 				{{'&','='}, 0, 3, "_andop"},
1191 
1192 				{{'/','='}, 0, 3, "_divop"},
1193 				{{'*','='}, 0, 3, "_mulop"},
1194 				{{'^','='}, 0, 3, "_powop"},
1195 
1196 				{{'=','='}, 1, 2, "_equal" },
1197 				{{'<','='}, 1, 2, "_beleq" },
1198 				{{'>','='}, 1, 2, "_aboeq" },
1199 				{{'<',0  }, 1, 2, "_below" },
1200 				{{'>',0  }, 1, 2, "_above" },
1201 				{{'!','='}, 1, 2, "_noteq" },
1202 				{{'|','|'}, 1, 2, "_or" },
1203 				{{'&','&'}, 1, 2, "_and" },
1204 				{{'=',0  }, 0, 3, "_set" },
1205 				{{'%',0},   0, 0, "_mod" },
1206 				{{'^',0},   0, 0, "pow" },
1207 
1208 
1209         {{'[',0  }, 0, 5, },
1210 				{{'!',0  },-1, 0, }, // this should also ignore any leading +-
1211 				{{'?',0  }, 1, 4, },
1212 
1213 			};
1214 
1215 
1216 			int n;
1217 			int ns=sizeof(preprocSymbols)/sizeof(preprocSymbols[0]);
1218 			for (n = 0; n < ns; n++)
1219 			{
1220 				if (c == preprocSymbols[n].op[0] && (!preprocSymbols[n].op[1] || expression[0] == preprocSymbols[n].op[1]))
1221 				{
1222 					break;
1223 				}
1224 			}
1225 			if (n < ns)
1226 			{
1227 
1228 				int lscan=preprocSymbols[n].lscan;
1229 				int rscan=preprocSymbols[n].rscan;
1230 
1231 	       		// parse left side of =, scanning back for an unparenthed nonwhitespace nonalphanumeric nonparenth?
1232 	       		// so megabuf(x+y)= would be fine, x=, but +x= would do +set(x,)
1233        			char *l_ptr=0;
1234 				char *r_ptr=0;
1235 	       		if (lscan >= 0)
1236 				{
1237 					char *scan=symbollists[lscan];
1238 	       			int l_semicnt=0;
1239 					l_ptr=buf + len - 1;
1240 					while (l_ptr >= buf)
1241 					{
1242 						if (*l_ptr == ')') l_semicnt++;
1243 						else if (*l_ptr == '(')
1244 						{
1245 							l_semicnt--;
1246 							if (l_semicnt < 0) break;
1247 						}
1248 						else if (!l_semicnt)
1249 						{
1250 							if (!*scan)
1251 							{
1252 								if (!isspace(*l_ptr) && !isalnum(*l_ptr) && *l_ptr != '_' && *l_ptr != '.') break;
1253 							}
1254 							else
1255 							{
1256 								char *sc=scan;
1257 								if (lscan == 2 && ( // not currently used, even
1258 									(l_ptr[0]=='|' && l_ptr[1] == '|')||
1259 									(l_ptr[0]=='&' && l_ptr[1] == '&')
1260 									)
1261 								   ) break;
1262 								while (*sc && *l_ptr != *sc) sc++;
1263 								if (*sc) break;
1264 							}
1265 						}
1266 						l_ptr--;
1267 					}
1268 					buf[len]=0;
1269 
1270 					l_ptr++;
1271 
1272 					len = l_ptr - buf;
1273 
1274 					l_ptr = strdup(l_ptr); // doesn't need to be preprocessed since it just was
1275 	       		}
1276 				if (preprocSymbols[n].op[1]) expression++;
1277 
1278 				r_ptr=expression;
1279 				{
1280 					// scan forward to an uncommented,  unparenthed semicolon, comma, or )
1281 					int r_semicnt=0;
1282 					int r_qcnt=0;
1283 					char *scan=symbollists[rscan];
1284 					int commentstate=0;
1285 					int hashadch=0;
1286           int bracketcnt=0;
1287 					while (*r_ptr)
1288 					{
1289 						if (!commentstate && *r_ptr == '/')
1290 						{
1291 							if (r_ptr[1] == '/') commentstate=1;
1292 							else if (r_ptr[1] == '*') commentstate=2;
1293 						}
1294 						if (commentstate == 1 && *r_ptr == '\n') commentstate=0;
1295 						else if (commentstate == 2 && *r_ptr == '*' && r_ptr[1]=='/')
1296 						{
1297 							r_ptr++; // skip *
1298 							commentstate=0;
1299 						}
1300 						else if (!commentstate)
1301 						{
1302 							if (*r_ptr == '(') {hashadch=1; r_semicnt++; }
1303 							else if (*r_ptr == ')')
1304 							{
1305 								r_semicnt--;
1306 								if (r_semicnt < 0) break;
1307 							}
1308 							else if (!r_semicnt)
1309 							{
1310 								char *sc=scan;
1311 								if (*r_ptr == ';' || *r_ptr == ',') break;
1312 
1313 								if (!rscan)
1314 								{
1315 									if (*r_ptr == ':') break;
1316 									if (!isspace(*r_ptr) && !isalnum(*r_ptr) && *r_ptr != '_' && *r_ptr != '.' && hashadch) break;
1317 									if (isalnum(*r_ptr) || *r_ptr == '_')hashadch=1;
1318 								}
1319 								else if (rscan == 2 &&
1320 									((r_ptr[0]=='|' && r_ptr[1] == '|')||
1321 									(r_ptr[0]=='&' && r_ptr[1] == '&')
1322 									)
1323 								   ) break;
1324 
1325 								else if (rscan == 3 || rscan == 4)
1326 								{
1327 									if (*r_ptr == ':') r_qcnt--;
1328 									else if (*r_ptr == '?') r_qcnt++;
1329 
1330 									if (r_qcnt < 3-rscan) break;
1331 								}
1332                 else if (rscan == 5)
1333                 {
1334                   if (*r_ptr == '[') bracketcnt++;
1335                   else if (*r_ptr == ']') bracketcnt--;
1336                   if (bracketcnt < 0) break;
1337                 }
1338 
1339 								while (*sc && *r_ptr != *sc) sc++;
1340 								if (*sc) break;
1341 							}
1342 						}
1343 						r_ptr++;
1344 					}
1345 					// expression -> r_ptr is our string (not including r_ptr)
1346 
1347 					{
1348 						char *orp=r_ptr;
1349 
1350 						char rps=*orp;
1351 						*orp=0; // temporarily terminate
1352 
1353 						r_ptr=preprocessCode(ctx,expression);
1354 						expression=orp;
1355 
1356 						*orp = rps; // fix termination(restore string)
1357 					}
1358 
1359 				}
1360 
1361 				if (r_ptr)
1362 				{
1363 					int thisl = strlen(l_ptr?l_ptr:"") + strlen(r_ptr) + 32;
1364 
1365 	    			if (len+thisl > alloc_len-64)
1366     				{
1367       					alloc_len = len+thisl+128;
1368       					buf=(char*)realloc(buf,alloc_len);
1369     				}
1370 
1371 
1372           if (n == ns-3)
1373           {
1374             char *lp = l_ptr;
1375             char *rp = r_ptr;
1376       	    while (lp && *lp && isspace(*lp)) lp++;
1377       	    while (rp && *rp && isspace(*rp)) rp++;
1378             if (lp && !strncasecmp(lp,"gmem",4) && (!lp[4] || isspace(lp[4])))
1379             {
1380               len+=sprintf(buf+len,"_gmem(%s",r_ptr && *r_ptr ? r_ptr : "0");
1381               ctx->l_stats[0]+=strlen(l_ptr)+4;
1382             }
1383             else if (rp && *rp && strcmp(rp,"0"))
1384             {
1385   	      len+=sprintf(buf+len,"_mem((%s)+(%s)",lp,rp);
1386               ctx->l_stats[0]+=strlen(lp)+strlen(rp)+8;
1387             }
1388             else
1389             {
1390 	      len+=sprintf(buf+len,"_mem(%s",lp);
1391               ctx->l_stats[0]+=strlen(lp)+4;
1392             }
1393 
1394             // skip the ]
1395             if (*expression == ']') expression++;
1396 
1397           }
1398 					else if (n == ns-2)
1399 					{
1400 						len+=sprintf(buf+len,"_not(%s",
1401 							r_ptr);
1402 
1403 						ctx->l_stats[0]+=4;
1404 					}
1405 					else if (n == ns-1)// if (l_ptr,r_ptr1,r_ptr2)
1406 					{
1407 						char *rptr2=r_ptr;
1408 						char *tmp=r_ptr;
1409 						int parcnt=0;
1410 						int qcnt=1;
1411 						while (*rptr2)
1412 						{
1413 							if (*rptr2 == '?') qcnt++;
1414 							else if (*rptr2 == ':') qcnt--;
1415 							else if (*rptr2 == '(') parcnt++;
1416 							else if (*rptr2 == ')') parcnt--;
1417 							if (parcnt < 0) break;
1418 							if (!parcnt && !qcnt && *rptr2 == ':') break;
1419 							rptr2++;
1420 						}
1421 						if (*rptr2) *rptr2++=0;
1422 						while (isspace(*rptr2)) rptr2++;
1423 
1424 						while (isspace(*tmp)) tmp++;
1425 
1426 						len+=sprintf(buf+len,"_if(%s,%s,%s",l_ptr,*tmp?tmp:"0",*rptr2?rptr2:"0");
1427 						ctx->l_stats[0]+=6;
1428 					}
1429 					else
1430 					{
1431 						len+=sprintf(buf+len,"%s(%s,%s",preprocSymbols[n].func,l_ptr?l_ptr:"",r_ptr);
1432 						ctx->l_stats[0]+=strlen(preprocSymbols[n].func)+2;
1433 					}
1434 
1435 				}
1436 
1437 				free(r_ptr);
1438 				free(l_ptr);
1439 
1440 
1441 				c = ')'; // close parenth below
1442 		  }
1443 	  }
1444 
1445 //      if (c != ' ' || (len && buf[len-1] != ' ')) // don't bother adding multiple spaces
1446       {
1447       	buf[len++]=c;
1448       	if (c != ' ') ctx->l_stats[0]++;
1449       }
1450     }
1451   }
1452   buf[len]=0;
1453 
1454   return buf;
1455 }
1456 
1457 #ifdef PPROC_TEST
1458 
main(int argc,char * argv[])1459 int main(int argc, char* argv[])
1460 {
1461 	compileContext ctx={0};
1462 	char *p=preprocessCode(&ctx,argv[1]);
1463 	if (p)printf("%s\n",p);
1464 	free(p);
1465 	return 0;
1466 }
1467 
1468 #endif
1469 
1470 #if 0
1471 static void movestringover(char *str, int amount)
1472 {
1473   char tmp[1024+8];
1474 
1475   int l=(int)strlen(str);
1476   l=min(1024-amount-1,l);
1477 
1478   memcpy(tmp,str,l+1);
1479 
1480   while (l >= 0 && tmp[l]!='\n') l--;
1481   l++;
1482 
1483   tmp[l]=0;//ensure we null terminate
1484 
1485   memcpy(str+amount,tmp,l+1);
1486 }
1487 #endif
1488 
1489 //------------------------------------------------------------------------------
NSEEL_code_compile(NSEEL_VMCTX _ctx,char * _expression,int lineoffs)1490 NSEEL_CODEHANDLE NSEEL_code_compile(NSEEL_VMCTX _ctx, char *_expression, int lineoffs)
1491 {
1492   compileContext *ctx = (compileContext *)_ctx;
1493   char *expression,*expression_start;
1494   int computable_size=0;
1495   codeHandleType *handle;
1496   startPtr *scode=NULL;
1497   startPtr *startpts=NULL;
1498 
1499   if (!ctx) return 0;
1500 
1501   ctx->last_error_string[0]=0;
1502 
1503   if (!_expression || !*_expression) return 0;
1504 
1505   freeBlocks((llBlock **)&ctx->tmpblocks_head);  // free blocks
1506   freeBlocks((llBlock **)&ctx->blocks_head);  // free blocks
1507   memset(ctx->l_stats,0,sizeof(ctx->l_stats));
1508   free(ctx->compileLineRecs); ctx->compileLineRecs=0; ctx->compileLineRecs_size=0; ctx->compileLineRecs_alloc=0;
1509 
1510   handle = (codeHandleType*)newBlock(sizeof(codeHandleType),8);
1511 
1512   if (!handle)
1513   {
1514     return 0;
1515   }
1516 
1517   memset(handle,0,sizeof(codeHandleType));
1518 
1519   expression_start=expression=preprocessCode(ctx,_expression);
1520 
1521 
1522   while (*expression)
1523   {
1524 	void *startptr;
1525     char *expr;
1526     ctx->colCount=0;
1527 	ctx->computTableTop=0;
1528 
1529     // single out segment
1530     while (*expression == ';' || isspace(*expression)) expression++;
1531     if (!*expression) break;
1532     expr=expression;
1533 
1534     while (*expression && *expression != ';') expression++;
1535     if (*expression) *expression++ = 0;
1536 
1537     // parse
1538 
1539     startptr=nseel_compileExpression(ctx,expr);
1540 
1541     if (ctx->computTableTop > NSEEL_MAX_TEMPSPACE_ENTRIES- /* safety */ 16 - /* alignment */4 ||
1542         !startptr)
1543     {
1544       int byteoffs = expr - expression_start;
1545       int destoffs,linenumber;
1546       char buf[21], *p;
1547       int x,le;
1548 
1549 #ifdef NSEEL_EEL1_COMPAT_MODE
1550       if (!startptr) continue;
1551 #endif
1552       if (ctx->errVar > 0) byteoffs += ctx->errVar;
1553       linenumber=findByteOffsetInSource(ctx,byteoffs,&destoffs);
1554       if (destoffs < 0) destoffs=0;
1555 
1556       le=strlen(_expression);
1557       if (destoffs >= le) destoffs=le;
1558       p= _expression + destoffs;
1559       for (x = 0;x < 20; x ++)
1560       {
1561 	      if (!*p || *p == '\r' || *p == '\n') break;
1562 	      buf[x]=*p++;
1563       }
1564       buf[x]=0;
1565 
1566       sprintf(ctx->last_error_string,"Around line %d '%s'",linenumber+lineoffs,buf);
1567 
1568       ctx->last_error_string[sizeof(ctx->last_error_string)-1]=0;
1569       scode=NULL;
1570       break;
1571     }
1572     if (computable_size < ctx->computTableTop)
1573     {
1574       computable_size=ctx->computTableTop;
1575     }
1576 
1577     {
1578       startPtr *tmp=(startPtr*) __newBlock((llBlock **)&ctx->tmpblocks_head,sizeof(startPtr));
1579       if (!tmp) break;
1580 
1581       tmp->startptr = startptr;
1582     tmp->next=NULL;
1583     if (!scode) scode=startpts=tmp;
1584     else
1585     {
1586       scode->next=tmp;
1587       scode=tmp;
1588     }
1589   }
1590 }
1591   free(ctx->compileLineRecs); ctx->compileLineRecs=0; ctx->compileLineRecs_size=0; ctx->compileLineRecs_alloc=0;
1592 
1593   // check to see if failed on the first startingCode
1594   if (!scode)
1595   {
1596     handle=NULL;              // return NULL (after resetting blocks_head)
1597   }
1598   else
1599   {
1600     char *tabptr = (char *)(handle->workTable=calloc(computable_size+64,  sizeof(EEL_F)));
1601     unsigned char *writeptr;
1602     startPtr *p=startpts;
1603     int size=sizeof(GLUE_RET)+GLUE_FUNC_ENTER_SIZE+GLUE_FUNC_LEAVE_SIZE; // for ret at end :)
1604 
1605     if (((INT_PTR)tabptr)&31)
1606       tabptr += 32-(((INT_PTR)tabptr)&31);
1607 
1608     // now we build one big code segment out of our list of them, inserting a mov esi, computable before each item
1609     while (p)
1610     {
1611       size += GLUE_RESET_ESI(NULL,0);
1612       size+=*(int *)p->startptr;
1613       p=p->next;
1614     }
1615     handle->code = newBlock(size,32);
1616     if (handle->code)
1617     {
1618       writeptr=(unsigned char *)handle->code;
1619       memcpy(writeptr,&GLUE_FUNC_ENTER,GLUE_FUNC_ENTER_SIZE); writeptr += GLUE_FUNC_ENTER_SIZE;
1620       p=startpts;
1621       while (p)
1622       {
1623         int thissize=*(int *)p->startptr;
1624         writeptr+=GLUE_RESET_ESI(writeptr,tabptr);
1625         //memcpy(writeptr,&GLUE_MOV_ESI_EDI,sizeof(GLUE_MOV_ESI_EDI));
1626         //writeptr+=sizeof(GLUE_MOV_ESI_EDI);
1627         memcpy(writeptr,(char*)p->startptr + 4,thissize);
1628         writeptr += thissize;
1629 
1630         p=p->next;
1631       }
1632       memcpy(writeptr,&GLUE_FUNC_LEAVE,GLUE_FUNC_LEAVE_SIZE); writeptr += GLUE_FUNC_LEAVE_SIZE;
1633       memcpy(writeptr,&GLUE_RET,sizeof(GLUE_RET)); writeptr += sizeof(GLUE_RET);
1634       ctx->l_stats[1]=size;
1635     }
1636     handle->blocks = ctx->blocks_head;
1637     ctx->blocks_head=0;
1638 
1639   }
1640   freeBlocks((llBlock **)&ctx->tmpblocks_head);  // free blocks
1641   freeBlocks((llBlock **)&ctx->blocks_head);  // free blocks
1642 
1643   if (handle)
1644   {
1645     memcpy(handle->code_stats,ctx->l_stats,sizeof(ctx->l_stats));
1646     nseel_evallib_stats[0]+=ctx->l_stats[0];
1647     nseel_evallib_stats[1]+=ctx->l_stats[1];
1648     nseel_evallib_stats[2]+=ctx->l_stats[2];
1649     nseel_evallib_stats[3]+=ctx->l_stats[3];
1650     nseel_evallib_stats[4]++;
1651   }
1652   memset(ctx->l_stats,0,sizeof(ctx->l_stats));
1653 
1654   free(expression_start);
1655 
1656   return (NSEEL_CODEHANDLE)handle;
1657 }
1658 
1659 //------------------------------------------------------------------------------
NSEEL_code_execute(NSEEL_CODEHANDLE code)1660 void NSEEL_code_execute(NSEEL_CODEHANDLE code)
1661 {
1662   INT_PTR tabptr;
1663   INT_PTR codeptr;
1664   codeHandleType *h = (codeHandleType *)code;
1665   if (!h || !h->code) return;
1666 
1667   codeptr = (INT_PTR) h->code;
1668 #if 0
1669   {
1670 	unsigned int *p=(unsigned int *)codeptr;
1671 	while (*p != GLUE_RET[0])
1672 	{
1673 		printf("instr:%04X:%04X\n",*p>>16,*p&0xffff);
1674 		p++;
1675 	}
1676   }
1677 #endif
1678 
1679   tabptr=(INT_PTR)h->workTable;
1680   if (tabptr&31)
1681     tabptr += 32-((tabptr)&31);
1682   //printf("calling code!\n");
1683   GLUE_CALL_CODE(tabptr,codeptr);
1684 
1685 }
1686 
1687 
NSEEL_code_getcodeerror(NSEEL_VMCTX ctx)1688 char *NSEEL_code_getcodeerror(NSEEL_VMCTX ctx)
1689 {
1690   compileContext *c=(compileContext *)ctx;
1691   if (ctx && c->last_error_string[0]) return c->last_error_string;
1692   return 0;
1693 }
1694 
1695 //------------------------------------------------------------------------------
NSEEL_code_free(NSEEL_CODEHANDLE code)1696 void NSEEL_code_free(NSEEL_CODEHANDLE code)
1697 {
1698   codeHandleType *h = (codeHandleType *)code;
1699   if (h != NULL)
1700   {
1701     free(h->workTable);
1702     nseel_evallib_stats[0]-=h->code_stats[0];
1703     nseel_evallib_stats[1]-=h->code_stats[1];
1704     nseel_evallib_stats[2]-=h->code_stats[2];
1705     nseel_evallib_stats[3]-=h->code_stats[3];
1706     nseel_evallib_stats[4]--;
1707     freeBlocks(&h->blocks);
1708 
1709 
1710   }
1711 
1712 }
1713 
1714 
1715 //------------------------------------------------------------------------------
NSEEL_VM_resetvars(NSEEL_VMCTX _ctx)1716 void NSEEL_VM_resetvars(NSEEL_VMCTX _ctx)
1717 {
1718   if (_ctx)
1719   {
1720     compileContext *ctx=(compileContext *)_ctx;
1721     int x;
1722     if (ctx->varTable_Names || ctx->varTable_Values) for (x = 0; x < ctx->varTable_numBlocks; x ++)
1723     {
1724       if (ctx->varTable_Names) free(ctx->varTable_Names[x]);
1725       if (ctx->varTable_Values) free(ctx->varTable_Values[x]);
1726     }
1727 
1728     free(ctx->varTable_Values);
1729     free(ctx->varTable_Names);
1730     ctx->varTable_Values=0;
1731     ctx->varTable_Names=0;
1732 
1733     ctx->varTable_numBlocks=0;
1734   }
1735 }
1736 
1737 
NSEEL_VM_alloc()1738 NSEEL_VMCTX NSEEL_VM_alloc() // return a handle
1739 {
1740   compileContext *ctx=calloc(1,sizeof(compileContext));
1741   return ctx;
1742 }
1743 
NSEEL_VM_free(NSEEL_VMCTX _ctx)1744 void NSEEL_VM_free(NSEEL_VMCTX _ctx) // free when done with a VM and ALL of its code have been freed, as well
1745 {
1746 
1747   if (_ctx)
1748   {
1749     compileContext *ctx=(compileContext *)_ctx;
1750     NSEEL_VM_resetvars(_ctx);
1751     NSEEL_VM_freeRAM(_ctx);
1752 
1753     freeBlocks((llBlock **)&ctx->tmpblocks_head);  // free blocks
1754     freeBlocks((llBlock **)&ctx->blocks_head);  // free blocks
1755     free(ctx->compileLineRecs);
1756     free(ctx);
1757   }
1758 
1759 }
1760 
NSEEL_code_getstats(NSEEL_CODEHANDLE code)1761 int *NSEEL_code_getstats(NSEEL_CODEHANDLE code)
1762 {
1763   codeHandleType *h = (codeHandleType *)code;
1764   if (h)
1765   {
1766     return h->code_stats;
1767   }
1768   return 0;
1769 }
1770 
NSEEL_VM_SetCustomFuncThis(NSEEL_VMCTX ctx,void * thisptr)1771 void NSEEL_VM_SetCustomFuncThis(NSEEL_VMCTX ctx, void *thisptr)
1772 {
1773   if (ctx)
1774   {
1775     compileContext *c=(compileContext*)ctx;
1776     c->caller_this=thisptr;
1777   }
1778 }
1779 
1780 
1781 
1782 
1783 
NSEEL_PProc_RAM(void * data,int data_size,compileContext * ctx)1784 void NSEEL_PProc_RAM(void *data, int data_size, compileContext *ctx)
1785 {
1786   if (data_size>0) EEL_GLUE_set_immediate(data, &ctx->ram_blocks);
1787 }
NSEEL_PProc_THIS(void * data,int data_size,compileContext * ctx)1788 void NSEEL_PProc_THIS(void *data, int data_size, compileContext *ctx)
1789 {
1790   if (data_size>0) EEL_GLUE_set_immediate(data, ctx->caller_this);
1791 }
1792