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