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