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