1 /********************************************************************************
2 *                                                                               *
3 *                      E x p r e s s i o n   E v a l u a t o r                  *
4 *                                                                               *
5 *********************************************************************************
6 * Copyright (C) 1998,2020 by Jeroen van der Zijp.   All Rights Reserved.        *
7 *********************************************************************************
8 * This library is free software; you can redistribute it and/or modify          *
9 * it under the terms of the GNU Lesser General Public License as published by   *
10 * the Free Software Foundation; either version 3 of the License, or             *
11 * (at your option) any later version.                                           *
12 *                                                                               *
13 * This library is distributed in the hope that it will be useful,               *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of                *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                 *
16 * GNU Lesser General Public License for more details.                           *
17 *                                                                               *
18 * You should have received a copy of the GNU Lesser General Public License      *
19 * along with this program.  If not, see <http://www.gnu.org/licenses/>          *
20 ********************************************************************************/
21 #include "xincs.h"
22 #include "fxver.h"
23 #include "fxdefs.h"
24 #include "fxmath.h"
25 #include "fxascii.h"
26 #include "fxunicode.h"
27 #include "FXArray.h"
28 #include "FXHash.h"
29 #include "FXStream.h"
30 #include "FXElement.h"
31 #include "FXString.h"
32 #include "FXExpression.h"
33 
34 
35 /*
36   Notes:
37   - Old as night, but recently rediscovered ;-).
38   - Better treatment of identifiers needed [user-supplied names].
39   - Maintain stack-depth during compile phase for possible limit check.
40 */
41 
42 // Debugging expression code
43 //#define EXPRDEBUG 1
44 
45 #define MAXSTACKDEPTH 128
46 
47 // Access to argument
48 #if defined(__i386__) || defined(__x86_64__)            // No alignment limits on shorts
49 #define SETARG(p,val) (*((FXshort*)(p))=(val))
50 #define GETARG(p)     (*((FXshort*)(p)))
51 #elif (FOX_BIGENDIAN == 1)                              // Big-endian machines
52 #define SETARG(p,val) (*((p)+0)=(val)>>8,*((p)+1)=(val))
53 #define GETARG(p)     ((FXshort)((*((p)+0)<<8)+(*((p)+1))))
54 #else                                                   // Little-endian machines
55 #define SETARG(p,val) (*((p)+0)=(val),*((p)+1)=(val)>>8)
56 #define GETARG(p)     ((FXshort)((*((p)+0))+(*((p)+1)<<8)))
57 #endif
58 
59 using namespace FX;
60 
61 /*******************************************************************************/
62 
63 namespace FX {
64 
65 
66 // Furnish our own versions
67 extern FXAPI FXlong __strtoll(const FXchar *beg,const FXchar** end=NULL,FXint base=0,FXbool* ok=NULL);
68 extern FXAPI FXdouble __strtod(const FXchar *beg,const FXchar** end=NULL,FXbool* ok=NULL);
69 
70 
71 namespace {
72 
73 // Tokens
74 enum {
75   TK_EOF        = 0U,
76   TK_INT        = 1U,
77   TK_INT_HEX    = 2U,
78   TK_INT_BIN    = 3U,
79   TK_INT_OCT    = 4U,
80   TK_REAL       = 5U,
81   TK_PLUS       = 6U,
82   TK_MINUS      = 7U,
83   TK_TIMES      = 8U,
84   TK_DIVIDE     = 9U,
85   TK_MODULO     = 10U,
86   TK_POWER      = 11U,
87   TK_LPAR       = 12U,
88   TK_RPAR       = 13U,
89   TK_LESS       = 14U,
90   TK_GREATER    = 15U,
91   TK_LESSEQ     = 16U,
92   TK_GREATEREQ  = 17U,
93   TK_EQUAL      = 18U,
94   TK_NOTEQUAL   = 19U,
95   TK_AND        = 20U,
96   TK_OR         = 21U,
97   TK_XOR        = 22U,
98   TK_NOT        = 23U,
99   TK_SHIFTLEFT  = 24U,
100   TK_SHIFTRIGHT = 25U,
101   TK_COMMA      = 26U,
102   TK_QUEST      = 27U,
103   TK_COLON      = 28U,
104   TK_ERROR      = 29U,
105   TK_PI         = 2585U,
106   TK_EULER      = 69U,
107   TK_RTOD       = 3005613U,
108   TK_DTOR       = 2389741U,
109   TK_ABS        = 108848U,
110   TK_ACOS       = 3592862U,
111   TK_ACOSH      = 118564406U,
112   TK_ASIN       = 3610325U,
113   TK_ASINH      = 119140637U,
114   TK_ATAN       = 3615258U,
115   TK_ATANH      = 119303474U,
116   TK_CEIL       = 3523203U,
117   TK_COS        = 107103U,
118   TK_COSH       = 3534423U,
119   TK_EXP        = 114029U,
120   TK_FLOOR      = 122360152U,
121   TK_LOG        = 114052U,
122   TK_LOG10      = 124204261U,
123   TK_SIN        = 124308U,
124   TK_SINH       = 4102268U,
125   TK_SQR        = 123536U,
126   TK_CUB        = 107284U,
127   TK_SQRT       = 4076772U,
128   TK_CBRT       = 3520359U,
129   TK_ROUND      = 136616002U,
130   TK_TRUNC      = 133596670U,
131   TK_TAN        = 123227U,
132   TK_TANH       = 4066515U,
133   TK_MAX        = 121748U,
134   TK_MIN        = 121482U,
135   TK_POW        = 119176U,
136   TK_ATAN2      = 119303528U
137   };
138 
139 
140 // Opcodes
141 enum {
142   OP_END,
143 
144   OP_BRA,
145   OP_BRT,
146   OP_BRF,
147 
148   OP_NUM,
149   OP_VAR,
150 
151   OP_NOT,
152   OP_NEG,
153 
154   OP_MUL,
155   OP_DIV,
156   OP_MOD,
157   OP_ADD,
158   OP_SUB,
159   OP_AND,
160   OP_OR,
161   OP_XOR,
162   OP_SHL,
163   OP_SHR,
164   OP_LT,
165   OP_GT,
166   OP_LE,
167   OP_GE,
168   OP_EQ,
169   OP_NE,
170 
171   OP_ABS,
172   OP_ACOS,
173   OP_ACOSH,
174   OP_ASIN,
175   OP_ASINH,
176   OP_ATAN,
177   OP_ATANH,
178   OP_CEIL,
179   OP_COS,
180   OP_COSH,
181   OP_EXP,
182   OP_FLOOR,
183   OP_LOG,
184   OP_LOG10,
185   OP_SIN,
186   OP_SINH,
187   OP_SQR,
188   OP_CUB,
189   OP_SQRT,
190   OP_CBRT,
191   OP_ROUND,
192   OP_TRUNC,
193   OP_TAN,
194   OP_TANH,
195 
196   OP_MAX,
197   OP_MIN,
198   OP_POW,
199   OP_ATAN2
200   };
201 
202 
203 // Compile class
204 class FXCompile {
205   const FXchar *head;           // Start of token
206   const FXchar *tail;           // End of token + 1
207   const FXchar *vars;           // Variables
208   FXuchar      *code;           // Program code
209   FXuchar      *pc;             // Program counter
210   FXuint        token;          // Token
211 public:
212 
213   // Create compile engine
214   FXCompile(FXuchar *prog,const FXchar* ex,const FXchar* vs);
215 
216   // Return size of generated code
size() const217   FXival size() const { return pc-code; }
218 
219   // Get token
220   void gettok();
221 
222   // Parsing
223   FXExpression::Error compile();
224   FXExpression::Error expression();
225   FXExpression::Error altex();
226   FXExpression::Error compex();
227   FXExpression::Error shiftexp();
228   FXExpression::Error bitexp();
229   FXExpression::Error addexp();
230   FXExpression::Error mulexp();
231   FXExpression::Error powexp();
232   FXExpression::Error primary();
233   FXExpression::Error element();
234 
235   // Variable lookup
236   FXint lookup(const FXchar *list);
237 
238   // Code generation
239   FXuchar* opcode(FXuchar op);
240   FXuchar* offset(FXshort n);
241   FXuchar* number(FXdouble num);
242 
243   // Backpatch
244   void fix(FXuchar *ptr,FXshort val);
245   };
246 
247 
248 /*******************************************************************************/
249 
250 // Construct compile engine
FXCompile(FXuchar * prog,const FXchar * ex,const FXchar * vs)251 FXCompile::FXCompile(FXuchar *prog,const FXchar* ex,const FXchar* vs):head(ex),tail(ex),vars(vs),code(prog),pc(prog),token(TK_EOF){
252   }
253 
254 
255 // Compile expression
compile()256 FXExpression::Error FXCompile::compile(){
257   FXExpression::Error err;
258   FXuchar* at=pc;
259   gettok();
260   pc+=2;
261   if(token==TK_EOF) return FXExpression::ErrEmpty;
262   err=expression();
263   if(err!=FXExpression::ErrOK) return err;
264   if(token!=TK_EOF) return FXExpression::ErrToken;
265   opcode(OP_END);
266   fix(at,pc-code);
267   return FXExpression::ErrOK;
268   }
269 
270 
271 // Expression
expression()272 FXExpression::Error FXCompile::expression(){
273   FXExpression::Error err=altex();
274   if(err!=FXExpression::ErrOK) return err;
275   return FXExpression::ErrOK;
276   }
277 
278 
279 // Parse x?y:z
altex()280 FXExpression::Error FXCompile::altex(){
281   FXExpression::Error err=compex();
282   FXuchar *piff,*pels;
283   if(err!=FXExpression::ErrOK) return err;
284   if(token==TK_QUEST){
285     gettok();
286     opcode(OP_BRF);
287     piff=offset(0);
288     err=altex();
289     if(err!=FXExpression::ErrOK) return err;
290     if(token!=TK_COLON) return FXExpression::ErrColon;
291     opcode(OP_BRA);
292     pels=offset(0);
293     gettok();
294     fix(piff,pc-piff);
295     err=altex();
296     if(err!=FXExpression::ErrOK) return err;
297     fix(pels,pc-pels);
298     }
299   return FXExpression::ErrOK;
300   }
301 
302 
303 // Compare expression
compex()304 FXExpression::Error FXCompile::compex(){
305   FXExpression::Error err=shiftexp();
306   if(err!=FXExpression::ErrOK) return err;
307   if(TK_LESS<=token && token<=TK_NOTEQUAL){
308     FXuint t=token;
309     gettok();
310     err=shiftexp();
311     if(err!=FXExpression::ErrOK) return err;
312     if(t==TK_LESS) opcode(OP_LT);
313     else if(t==TK_LESSEQ) opcode(OP_LE);
314     else if(t==TK_GREATER) opcode(OP_GT);
315     else if(t==TK_GREATEREQ) opcode(OP_GE);
316     else if(t==TK_EQUAL) opcode(OP_EQ);
317     else opcode(OP_NE);
318     }
319   return FXExpression::ErrOK;
320   }
321 
322 
323 // Shift expression
shiftexp()324 FXExpression::Error FXCompile::shiftexp(){
325   FXExpression::Error err=bitexp();
326   if(err!=FXExpression::ErrOK) return err;
327   while(TK_SHIFTLEFT<=token && token<=TK_SHIFTRIGHT){
328     FXuint t=token;
329     gettok();
330     err=bitexp();
331     if(err!=FXExpression::ErrOK) return err;
332     if(t==TK_SHIFTLEFT) opcode(OP_SHL);
333     else opcode(OP_SHR);
334     }
335   return FXExpression::ErrOK;
336   }
337 
338 
339 // Bit expression
bitexp()340 FXExpression::Error FXCompile::bitexp(){
341   FXExpression::Error err=addexp();
342   if(err!=FXExpression::ErrOK) return err;
343   while(TK_AND<=token && token<=TK_XOR){
344     FXuint t=token;
345     gettok();
346     err=addexp();
347     if(err!=FXExpression::ErrOK) return err;
348     if(t==TK_AND) opcode(OP_AND);
349     else if(t==TK_OR) opcode(OP_OR);
350     else opcode(OP_XOR);
351     }
352   return FXExpression::ErrOK;
353   }
354 
355 
356 // Add expression
addexp()357 FXExpression::Error FXCompile::addexp(){
358   FXExpression::Error err=mulexp();
359   if(err!=FXExpression::ErrOK) return err;
360   while(TK_PLUS<=token && token<=TK_MINUS){
361     FXuint t=token;
362     gettok();
363     err=mulexp();
364     if(err!=FXExpression::ErrOK) return err;
365     if(t==TK_MINUS) opcode(OP_SUB);
366     else opcode(OP_ADD);
367     }
368   return FXExpression::ErrOK;
369   }
370 
371 
372 // Mul expression
mulexp()373 FXExpression::Error FXCompile::mulexp(){
374   FXExpression::Error err=powexp();
375   if(err!=FXExpression::ErrOK) return err;
376   while(TK_TIMES<=token && token<=TK_MODULO){
377     FXuint t=token;
378     gettok();
379     err=powexp();
380     if(err!=FXExpression::ErrOK) return err;
381     if(t==TK_TIMES) opcode(OP_MUL);
382     else if(t==TK_DIVIDE) opcode(OP_DIV);
383     else opcode(OP_MOD);
384     }
385   return FXExpression::ErrOK;
386   }
387 
388 
389 // Power expression
powexp()390 FXExpression::Error FXCompile::powexp(){
391   FXExpression::Error err=primary();
392   if(err!=FXExpression::ErrOK) return err;
393   if(token==TK_POWER){
394     gettok();
395     err=powexp();
396     if(err!=FXExpression::ErrOK) return err;
397     opcode(OP_POW);
398     }
399   return FXExpression::ErrOK;
400   }
401 
402 
403 // Primary
primary()404 FXExpression::Error FXCompile::primary(){
405   FXExpression::Error err;
406   if(token==TK_PLUS || token==TK_MINUS || token==TK_NOT){
407     FXuint t=token;
408     gettok();
409     err=primary();
410     if(err!=FXExpression::ErrOK) return err;
411     if(t==TK_MINUS) opcode(OP_NEG);
412     else if(t==TK_NOT) opcode(OP_NOT);
413     }
414   else{
415     err=element();
416     if(err!=FXExpression::ErrOK) return err;
417     }
418   return FXExpression::ErrOK;
419   }
420 
421 
422 // Element
element()423 FXExpression::Error FXCompile::element(){
424   FXExpression::Error err;
425   FXdouble num;
426   FXuchar op;
427   FXbool ok;
428   FXint v;
429   switch(token){
430     case TK_LPAR:
431       gettok();
432       err=expression();
433       if(err!=FXExpression::ErrOK) return err;
434       if(token!=TK_RPAR) return FXExpression::ErrParent;
435       break;
436     case TK_INT_HEX:
437       num=(FXdouble)__strtoll(head+2,NULL,16,&ok);
438       if(!ok) return FXExpression::ErrToken;
439       opcode(OP_NUM);
440       number(num);
441       break;
442     case TK_INT_BIN:
443       num=(FXdouble)__strtoll(head+2,NULL,2,&ok);
444       if(!ok) return FXExpression::ErrToken;
445       opcode(OP_NUM);
446       number(num);
447       break;
448     case TK_INT_OCT:
449       num=(FXdouble)__strtoll(head+1,NULL,8,&ok);
450       if(!ok) return FXExpression::ErrToken;
451       opcode(OP_NUM);
452       number(num);
453       break;
454     case TK_INT:
455       num=(FXdouble)__strtoll(head,NULL,10,&ok);
456       opcode(OP_NUM);
457       if(!ok) return FXExpression::ErrToken;
458       number(num);
459       break;
460     case TK_REAL:
461       num=__strtod(head,NULL,&ok);
462       if(!ok) return FXExpression::ErrToken;
463       opcode(OP_NUM);
464       number(num);
465       break;
466     case TK_PI:
467       opcode(OP_NUM);
468       number(PI);
469       break;
470     case TK_EULER:
471       opcode(OP_NUM);
472       number(EULER);
473       break;
474     case TK_RTOD:
475       opcode(OP_NUM);
476       number(RTOD);
477       break;
478     case TK_DTOR:
479       opcode(OP_NUM);
480       number(DTOR);
481       break;
482     case TK_MAX:
483       op=OP_MAX;
484       goto dyad;
485     case TK_MIN:
486       op=OP_MIN;
487       goto dyad;
488     case TK_POW:
489       op=OP_POW;
490       goto dyad;
491     case TK_ATAN2:
492       op=OP_ATAN2;
493 dyad: gettok();
494       if(token!=TK_LPAR) return FXExpression::ErrParent;
495       gettok();
496       err=expression();
497       if(err!=FXExpression::ErrOK) return err;
498       if(token!=TK_COMMA) return FXExpression::ErrComma;
499       gettok();
500       err=expression();
501       if(err!=FXExpression::ErrOK) return err;
502       if(token!=TK_RPAR) return FXExpression::ErrParent;
503       opcode(op);
504       break;
505     case TK_ABS:
506       op=OP_ABS;
507       goto mono;
508     case TK_ACOS:
509       op=OP_ACOS;
510       goto mono;
511     case TK_ACOSH:
512       op=OP_ACOS;
513       goto mono;
514     case TK_ASIN:
515       op=OP_ASIN;
516       goto mono;
517     case TK_ASINH:
518       op=OP_ASINH;
519       goto mono;
520     case TK_ATAN:
521       op=OP_ATAN;
522       goto mono;
523     case TK_ATANH:
524       op=OP_ATANH;
525       goto mono;
526     case TK_CEIL:
527       op=OP_CEIL;
528       goto mono;
529     case TK_COS:
530       op=OP_COS;
531       goto mono;
532     case TK_COSH:
533       op=OP_COSH;
534       goto mono;
535     case TK_EXP:
536       op=OP_EXP;
537       goto mono;
538     case TK_FLOOR:
539       op=OP_FLOOR;
540       goto mono;
541     case TK_LOG:
542       op=OP_LOG;
543       goto mono;
544     case TK_LOG10:
545       op=OP_LOG10;
546       goto mono;
547     case TK_SIN:
548       op=OP_SIN;
549       goto mono;
550     case TK_SINH:
551       op=OP_SINH;
552       goto mono;
553     case TK_SQR:
554       op=OP_SQR;
555       goto mono;
556     case TK_CUB:
557       op=OP_CUB;
558       goto mono;
559     case TK_SQRT:
560       op=OP_SQRT;
561       goto mono;
562     case TK_CBRT:
563       op=OP_CBRT;
564       goto mono;
565     case TK_ROUND:
566       op=OP_ROUND;
567       goto mono;
568     case TK_TRUNC:
569       op=OP_TRUNC;
570       goto mono;
571     case TK_TAN:
572       op=OP_TAN;
573       goto mono;
574     case TK_TANH:
575       op=OP_TANH;
576 mono: gettok();
577       if(token!=TK_LPAR) return FXExpression::ErrParent;
578       gettok();
579       err=expression();
580       if(err!=FXExpression::ErrOK) return err;
581       if(token!=TK_RPAR) return FXExpression::ErrParent;
582       opcode(op);
583       break;
584     default:
585       v=lookup(vars);
586       if(v<0) return FXExpression::ErrIdent;
587       opcode(OP_VAR);
588       opcode(v);
589       break;
590     case TK_EOF:
591     case TK_TIMES:
592     case TK_DIVIDE:
593     case TK_MODULO:
594     case TK_POWER:
595     case TK_RPAR:
596     case TK_LESS:
597     case TK_GREATER:
598     case TK_LESSEQ:
599     case TK_GREATEREQ:
600     case TK_EQUAL:
601     case TK_NOTEQUAL:
602     case TK_AND:
603     case TK_OR:
604     case TK_XOR:
605     case TK_SHIFTLEFT:
606     case TK_SHIFTRIGHT:
607     case TK_COMMA:
608     case TK_ERROR:
609     case TK_QUEST:
610     case TK_COLON:
611       return FXExpression::ErrToken;
612     }
613   gettok();
614   return FXExpression::ErrOK;
615   }
616 
617 
618 // Lookup current token in list
lookup(const FXchar * list)619 FXint FXCompile::lookup(const FXchar *list){
620   if(list){
621     FXint which=0;
622     while(*list){
623       const FXchar *q;
624       for(q=head; q<tail && *q==*list; q++,list++){}
625       if(q==tail && (*list=='\0' || *list==',')) return which;
626       while(*list && *list!=',') list++;
627       if(*list==','){ which++; list++; }
628       }
629     }
630   return -1;
631   }
632 
633 
634 // Obtain next token from input
gettok()635 void FXCompile::gettok(){
636   FXchar c;
637   head=tail;
638   while((c=*tail)!='\0'){
639     switch(c){
640       case ' ':
641       case '\b':
642       case '\t':
643       case '\v':
644       case '\f':
645       case '\r':
646       case '\n':
647         head=++tail;
648         break;
649       case '=':
650         token=TK_ERROR; tail++;
651         if(*tail=='='){ token=TK_EQUAL; tail++; }
652         return;
653       case '<':
654         token=TK_LESS; tail++;
655         if(*tail=='='){ token=TK_LESSEQ; tail++; }
656         else if(*tail=='<'){ token=TK_SHIFTLEFT; tail++; }
657         return;
658       case '>':
659         token=TK_GREATER;
660         tail++;
661         if(*tail=='='){ token=TK_GREATEREQ; tail++; }
662         else if(*tail=='>'){ token=TK_SHIFTRIGHT; tail++; }
663         return;
664       case '|':
665         token=TK_OR; tail++;
666         return;
667       case '&':
668         token=TK_AND; tail++;
669         return;
670       case '^':
671         token=TK_XOR; tail++;
672         return;
673       case '~':
674         token=TK_NOT; tail++;
675         return;
676       case '-':
677         token=TK_MINUS; tail++;
678         return;
679       case '+':
680         token=TK_PLUS; tail++;
681         return;
682       case '*':
683         token=TK_TIMES; tail++;
684         if(*tail=='*'){ token=TK_POWER; tail++; }
685         return;
686       case '/':
687         token=TK_DIVIDE; tail++;
688         return;
689       case '%':
690         token=TK_MODULO; tail++;
691         return;
692       case '!':
693         token=TK_ERROR; tail++;
694         if(*tail=='='){ token=TK_NOTEQUAL; tail++; }
695         return;
696       case '(':
697         token=TK_LPAR; tail++;
698         return;
699       case ')':
700         token=TK_RPAR; tail++;
701         return;
702       case ',':
703         token=TK_COMMA; tail++;
704         return;
705       case '?':
706         token=TK_QUEST; tail++;
707         return;
708       case ':':
709         token=TK_COLON; tail++;
710         return;
711       case '.':
712       case '0':
713       case '1':
714       case '2':
715       case '3':
716       case '4':
717       case '5':
718       case '6':
719       case '7':
720       case '8':
721       case '9':
722         token=TK_INT;
723         if(c=='0'){
724           tail++;
725           if(*tail=='x' || *tail=='X'){
726             tail++;
727             if(!Ascii::isHexDigit(*tail)){ token=TK_ERROR; return; }
728             tail++;
729             while(Ascii::isHexDigit(*tail)) tail++;
730             token=TK_INT_HEX;
731             return;
732             }
733           if(*tail=='b' || *tail=='B'){
734             tail++;
735             if(*tail!='0' && *tail!='1'){ token=TK_ERROR; return; }
736             tail++;
737             while(*tail=='0' || *tail=='1') tail++;
738             token=TK_INT_BIN;
739             return;
740             }
741           if('0'<=*tail && *tail<='7'){
742             tail++;
743             while('0'<=*tail && *tail<='7') tail++;
744             if('7'<=*tail && *tail<='9'){
745               token=TK_ERROR;
746               return;
747               }
748             token=TK_INT_OCT;
749             return;
750             }
751           }
752         while(Ascii::isDigit(*tail)) tail++;
753         if(*tail=='.'){
754           token=TK_REAL;
755           tail++;
756           while(Ascii::isDigit(*tail)) tail++;
757           }
758         if(*tail=='e' || *tail=='E'){
759           token=TK_REAL;
760           tail++;
761           if(*tail=='-' || *tail=='+') tail++;
762           if(!Ascii::isDigit(*tail)){ token=TK_ERROR; return; }
763           tail++;
764           while(Ascii::isDigit(*tail)) tail++;
765           }
766         return;
767       case 'a':
768       case 'b':
769       case 'c':
770       case 'd':
771       case 'e':
772       case 'f':
773       case 'g':
774       case 'h':
775       case 'i':
776       case 'j':
777       case 'k':
778       case 'l':
779       case 'm':
780       case 'n':
781       case 'o':
782       case 'p':
783       case 'q':
784       case 'r':
785       case 's':
786       case 't':
787       case 'u':
788       case 'v':
789       case 'w':
790       case 'x':
791       case 'y':
792       case 'z':
793       case 'A':
794       case 'B':
795       case 'C':
796       case 'D':
797       case 'E':
798       case 'F':
799       case 'G':
800       case 'H':
801       case 'I':
802       case 'J':
803       case 'K':
804       case 'L':
805       case 'M':
806       case 'N':
807       case 'O':
808       case 'P':
809       case 'Q':
810       case 'R':
811       case 'S':
812       case 'T':
813       case 'U':
814       case 'V':
815       case 'W':
816       case 'X':
817       case 'Y':
818       case 'Z':
819       case '_':
820         token=(FXuchar)*tail++;
821         while(Ascii::isWord(*tail)){
822           token=((token<<5)+token) ^ (FXuchar)*tail++;
823           }
824         //FXTRACE((1,"token=%u\n",token));
825         return;
826       default:
827         token=TK_ERROR;
828         return;
829       }
830     }
831   token=TK_EOF;
832   }
833 
834 
835 // Emit opcode
opcode(FXuchar op)836 FXuchar* FXCompile::opcode(FXuchar op){
837   FXuchar* result=pc;
838   if(code){
839     pc[0]=op;
840     }
841   pc++;
842   return result;
843   }
844 
845 
846 // Emit offset
offset(FXshort n)847 FXuchar* FXCompile::offset(FXshort n){
848   FXuchar* result=pc;
849   if(code){
850     SETARG(pc,n);
851     }
852   pc+=2;
853   return result;
854   }
855 
856 
857 // Emit double
number(FXdouble n)858 FXuchar* FXCompile::number(FXdouble n){
859   FXuchar* result=pc;
860   if(code){
861 #if defined(__i386__) || defined(__x86_64__)
862     ((FXdouble*)pc)[0]=n;
863 #else
864     pc[0]=((const FXuchar*)&n)[0];
865     pc[1]=((const FXuchar*)&n)[1];
866     pc[2]=((const FXuchar*)&n)[2];
867     pc[3]=((const FXuchar*)&n)[3];
868     pc[4]=((const FXuchar*)&n)[4];
869     pc[5]=((const FXuchar*)&n)[5];
870     pc[6]=((const FXuchar*)&n)[6];
871     pc[7]=((const FXuchar*)&n)[7];
872 #endif
873     }
874   pc+=8;
875   return result;
876   }
877 
878 
879 // Fix value
fix(FXuchar * ptr,FXshort val)880 void FXCompile::fix(FXuchar *ptr,FXshort val){
881   if(code && ptr){
882     SETARG(ptr,val);
883     }
884   }
885 
886 }
887 
888 /*******************************************************************************/
889 
890 #if (FOX_BIGENDIAN == 1)
891 const FXuchar FXExpression::initial[]={0,14,OP_NUM,0,0,0,0,0,0,0,0,OP_END};
892 #endif
893 #if (FOX_BIGENDIAN == 0)
894 const FXuchar FXExpression::initial[]={14,0,OP_NUM,0,0,0,0,0,0,0,0,OP_END};
895 #endif
896 
897 
898 // Error messages
899 const FXchar *const FXExpression::errors[]={
900   "OK",
901   "Empty expression",
902   "Out of memory",
903   "Unmatched parenthesis",
904   "Illegal token",
905   "Expected comma",
906   "Unknown identifier",
907   "Expected colon"
908   };
909 
910 
911 // Construct empty expression object
FXExpression()912 FXExpression::FXExpression():code((FXuchar*)(void*)initial){
913   }
914 
915 
916 // Copy regex object
FXExpression(const FXExpression & orig)917 FXExpression::FXExpression(const FXExpression& orig):code((FXuchar*)(void*)initial){
918   if(orig.code!=initial){
919     dupElms(code,orig.code,GETARG(orig.code));
920     }
921   }
922 
923 
924 // Compile expression from pattern; fail if error
FXExpression(const FXchar * expression,const FXchar * variables,FXExpression::Error * error)925 FXExpression::FXExpression(const FXchar* expression,const FXchar* variables,FXExpression::Error* error):code((FXuchar*)(void*)initial){
926   FXExpression::Error err=parse(expression,variables);
927   if(error){ *error=err; }
928   }
929 
930 
931 // Compile expression from pattern; fail if error
FXExpression(const FXString & expression,const FXString & variables,FXExpression::Error * error)932 FXExpression::FXExpression(const FXString& expression,const FXString& variables,FXExpression::Error* error):code((FXuchar*)(void*)initial){
933   FXExpression::Error err=parse(expression.text(),variables.text());
934   if(error){ *error=err; }
935   }
936 
937 
938 // Assignment
operator =(const FXExpression & orig)939 FXExpression& FXExpression::operator=(const FXExpression& orig){
940   if(code!=orig.code){
941     if(code!=initial) freeElms(code);
942     code=(FXuchar*)(void*)initial;
943     if(orig.code!=initial){
944       dupElms(code,orig.code,GETARG(orig.code));
945       }
946     }
947   return *this;
948   }
949 
950 /*******************************************************************************/
951 
952 #ifdef EXPRDEBUG
953 #include "fxexprdbg.h"
954 #endif
955 
956 
957 // Parse expression, return error code if syntax error is found
parse(const FXchar * expression,const FXchar * variables)958 FXExpression::Error FXExpression::parse(const FXchar* expression,const FXchar* variables){
959   FXExpression::Error err=FXExpression::ErrEmpty;
960 
961   // Free old code, if any
962   clear();
963 
964   // If not empty, parse expression
965   if(expression){
966 
967     // Create compile engine
968     FXCompile cs(NULL,expression,variables);
969 
970     // Parse to check syntax and determine size
971     if((err=cs.compile())==ErrOK){
972       FXuchar *prog;
973 
974       // Allocate new code
975       if(allocElms(prog,cs.size())){
976 
977         // Create compile engine
978         FXCompile gs(prog,expression,variables);
979 
980         // Now generate code for expression
981         if((err=gs.compile())==ErrOK){
982 
983           // Size still checking out?
984           FXASSERT(gs.size()==cs.size());
985 
986           // Install new program
987           code=prog;
988 
989 #ifdef EXPRDEBUG
990           if(fxTraceLevel>100) dump(code);
991 #endif
992 
993           // Report success
994           return ErrOK;
995           }
996         freeElms(prog);
997         }
998       }
999     }
1000   return err;
1001   }
1002 
1003 
1004 // Parse expression, return error code if syntax error is found
parse(const FXString & expression,const FXString & variables)1005 FXExpression::Error FXExpression::parse(const FXString& expression,const FXString& variables){
1006   return parse(expression.text(),variables.text());
1007   }
1008 
1009 
1010 // Evaluate expression
evaluate(const FXdouble * args) const1011 FXdouble FXExpression::evaluate(const FXdouble *args) const {
1012   FXdouble stack[MAXSTACKDEPTH];
1013   const FXuchar *pc=code+2;
1014   FXdouble *sp=stack;
1015   stack[0]=0.0;
1016   while(1){
1017     switch(*pc++){
1018       case OP_END:   return *sp;
1019       case OP_BRA:   pc+=GETARG(pc); break;
1020       case OP_BRF:   pc+=*sp-- ? 2 : GETARG(pc); break;
1021       case OP_BRT:   pc+=*sp-- ? GETARG(pc) : 2; break;
1022 #if defined(__i386__) || defined(__x86_64__) || defined(WIN32) || defined(__minix)
1023       case OP_NUM:   *++sp=*((FXdouble*)pc); pc+=8; break;
1024 #else
1025       case OP_NUM:   ++sp; ((FXuchar*)sp)[0]=*pc++; ((FXuchar*)sp)[1]=*pc++; ((FXuchar*)sp)[2]=*pc++; ((FXuchar*)sp)[3]=*pc++; ((FXuchar*)sp)[4]=*pc++; ((FXuchar*)sp)[5]=*pc++; ((FXuchar*)sp)[6]=*pc++; ((FXuchar*)sp)[7]=*pc++; break;
1026 #endif
1027       case OP_VAR:   *++sp=args[*pc++]; break;
1028       case OP_NOT:   *sp=(FXdouble)(~((FXlong)*sp)); break;
1029       case OP_NEG:   *sp=-*sp; break;
1030       case OP_SIN:   *sp=Math::sin(*sp); break;
1031       case OP_COS:   *sp=Math::cos(*sp); break;
1032       case OP_TAN:   *sp=Math::tan(*sp); break;
1033       case OP_ASIN:  *sp=Math::asin(*sp); break;
1034       case OP_ACOS:  *sp=Math::acos(*sp); break;
1035       case OP_ATAN:  *sp=Math::atan(*sp); break;
1036       case OP_SINH:  *sp=Math::sinh(*sp); break;
1037       case OP_COSH:  *sp=Math::cosh(*sp); break;
1038       case OP_TANH:  *sp=Math::tanh(*sp); break;
1039       case OP_ASINH: *sp=Math::asinh(*sp); break;
1040       case OP_ACOSH: *sp=Math::acosh(*sp); break;
1041       case OP_ATANH: *sp=Math::atanh(*sp); break;
1042       case OP_SQR:   *sp=Math::sqr(*sp); break;
1043       case OP_CUB:   *sp=Math::cub(*sp); break;
1044       case OP_SQRT:  *sp=Math::sqrt(*sp); break;
1045       case OP_CBRT:  *sp=Math::cbrt(*sp); break;
1046       case OP_ROUND: *sp=Math::round(*sp); break;
1047       case OP_TRUNC: *sp=Math::trunc(*sp); break;
1048       case OP_ABS:   *sp=Math::fabs(*sp); break;
1049       case OP_CEIL:  *sp=Math::ceil(*sp); break;
1050       case OP_FLOOR: *sp=Math::floor(*sp); break;
1051       case OP_EXP:   *sp=Math::exp(*sp); break;
1052       case OP_LOG:   *sp=Math::log(*sp); break;
1053       case OP_LOG10: *sp=Math::log10(*sp); break;
1054       case OP_MUL:   *(sp-1)=*(sp-1) * *sp; --sp; break;
1055       case OP_DIV:   *(sp-1)=*(sp-1) / *sp; --sp; break;
1056       case OP_MOD:   *(sp-1)=Math::fmod(*(sp-1),*sp); --sp; break;
1057       case OP_ADD:   *(sp-1)=*(sp-1) + *sp; --sp; break;
1058       case OP_SUB:   *(sp-1)=*(sp-1) - *sp; --sp; break;
1059       case OP_AND:   *(sp-1)=(FXdouble)(((FXlong)*(sp-1)) & ((FXlong)*sp)); --sp; break;
1060       case OP_OR:    *(sp-1)=(FXdouble)(((FXlong)*(sp-1)) | ((FXlong)*sp)); --sp; break;
1061       case OP_XOR:   *(sp-1)=(FXdouble)(((FXlong)*(sp-1)) ^ ((FXlong)*sp)); --sp; break;
1062       case OP_SHL:   *(sp-1)=(FXdouble)(((FXlong)*(sp-1)) << ((FXlong)*sp)); --sp; break;
1063       case OP_SHR:   *(sp-1)=(FXdouble)(((FXlong)*(sp-1)) >> ((FXlong)*sp)); --sp; break;
1064       case OP_LT:    *(sp-1)=(FXdouble)(*(sp-1) < *sp); --sp; break;
1065       case OP_GT:    *(sp-1)=(FXdouble)(*(sp-1) > *sp); --sp; break;
1066       case OP_LE:    *(sp-1)=(FXdouble)(*(sp-1) <= *sp); --sp; break;
1067       case OP_GE:    *(sp-1)=(FXdouble)(*(sp-1) >= *sp); --sp; break;
1068       case OP_EQ:    *(sp-1)=(FXdouble)(*(sp-1) == *sp); --sp; break;
1069       case OP_NE:    *(sp-1)=(FXdouble)(*(sp-1) != *sp); --sp; break;
1070       case OP_POW:   *(sp-1)=Math::pow(*(sp-1),*sp); --sp; break;
1071       case OP_MAX:   *(sp-1)=Math::fmax(*(sp-1),*sp); --sp; break;
1072       case OP_MIN:   *(sp-1)=Math::fmin(*(sp-1),*sp); --sp; break;
1073       case OP_ATAN2: *(sp-1)=Math::atan2(*(sp-1),*sp); --sp; break;
1074       }
1075     }
1076   return 0.0;
1077   }
1078 
1079 
1080 // Save
operator <<(FXStream & store,const FXExpression & s)1081 FXStream& operator<<(FXStream& store,const FXExpression& s){
1082   FXshort size=GETARG(s.code);
1083   store << size;
1084   store.save(s.code+2,size-2);
1085   return store;
1086   }
1087 
1088 
1089 // Load
operator >>(FXStream & store,FXExpression & s)1090 FXStream& operator>>(FXStream& store,FXExpression& s){
1091   FXshort size;
1092   store >> size;
1093   allocElms(s.code,size);
1094   store.load(s.code+2,size-2);
1095   SETARG(s.code,size);
1096   return store;
1097   }
1098 
1099 
1100 // Clear the expression
clear()1101 void FXExpression::clear(){
1102   if(code!=initial){
1103     freeElms(code);
1104     code=(FXuchar*)(void*)initial;
1105     }
1106   }
1107 
1108 
1109 // Clean up
~FXExpression()1110 FXExpression::~FXExpression(){
1111   clear();
1112   }
1113 
1114 }
1115