1 /* evaluate.c (C) 2000-2002 Kyzer/CSG. */
2 /* Released under the terms of the GNU General Public Licence version 2. */
4 #include "magic_eval_lib.h"
16 /* FIXME: due to the current linker command line ordering, parts of lib(min)c
17 * that are used exclusively by libmagicrt end up not being instrumented, which
18 * then causes problems transferring pointers such as _ctype_tab_ and
19 * _tolower_tab_. As a temporary workaround, we redefine the macros that use
20 * those pointers. This code is currently never triggered so it is not
21 * performance critical; obviously there are a million better ways to do this.
24 #define isalpha(c) ((unsigned)(((c) & ~0x20) - 'A') <= ('Z' - 'A'))
26 #define isupper(c) ((unsigned)((c) - 'A') <= ('Z' - 'A'))
28 #define islower(c) ((unsigned)((c) - 'a') <= ('z' - 'a'))
30 #define isdigit(c) ((unsigned)((c) - '0') <= ('9' - '0'))
31 static inline int __isxdigit(c
) {
32 return isdigit(c
) || (c
>= 'A' && c
<= 'F') || (c
>= 'a' && c
<= 'f');
35 #define isxdigit(c) (__isxdigit(c))
36 static inline int __isspace(c
) {
38 case ' ': case '\t': case '\n': case '\v': case '\f': case '\r': return 1;
43 #define isspace(c) (__isspace(c))
44 static inline int __tolower(c
) {
45 return isupper(c
) ? (c
| 0x20) : c
;
48 #define tolower(c) (__tolower(c))
51 /* a token structure */
57 char funcid
, *name
, *name_end
;
59 #define REG_TOK_SIZE() offsetof(struct tok, val)
60 #define VAL_TOK_SIZE() offsetof(struct tok, funcid)
61 #define VAR_TOK_SIZE() sizeof(struct tok)
63 /* private memory header for tracked memory allocation */
69 /* creates a new memory header for allocating memory */
70 static struct memh
*create_mem();
72 /* allocates memory using a particular header */
73 static void *mem_alloc(struct memh
*mh
, size_t len
);
75 /* frees all memory for a particular header */
76 static void free_mem(struct memh
*mh
);
83 /* variables and values */
84 TK_VAR
, TK_VARQUOTE
, TK_VAL
,
86 /* binary operators */
87 TK_ADD
, TK_SUB
, TK_MUL
, TK_MULI
, TK_DIV
,
88 TK_MOD
, TK_POW
, TK_AND
, TK_OR
, TK_BAND
,
89 TK_BOR
, TK_BXOR
, TK_EQ
, TK_NE
, TK_LT
, TK_GT
,
90 TK_LE
, TK_GE
, TK_SHL
, TK_SHR
,
93 TK_ASSN
, TK_NEG
, TK_FUNC
, TK_NOT
, TK_BNOT
,
95 /* special scan codes */
96 TK_BREAK
, /* finish scanning, bring remainder of string forward */
97 TK_ERROR
, /* abort scanning */
98 TK_SKIP
/* ignore the character */
101 /* lookup table to do conversion [char -> token type] */
102 char scantable
[UCHAR_MAX
+1];
103 int scantable_ok
= 0;
105 /* table of function names */
106 const char *functable
[] = {
107 "acos", "asin", "atan", "cos", "cosh", "exp", "ln", "log",
108 "sin", "sinh", "sqr", "sqrt", "tan", "tanh", NULL
111 /* function ids (index to functable) */
113 F_ACOS
, F_ASIN
, F_ATAN
, F_COS
, F_COSH
, F_EXP
, F_LN
, F_LOG
,
114 F_SIN
, F_SINH
, F_SQR
, F_SQRT
, F_TAN
, F_TANH
118 static get_var_cb_t get_var_cb
= NULL
;
119 static get_func_result_cb_t get_func_result_cb
= NULL
;
120 void eval_set_cb_get_var(get_var_cb_t cb
) {
123 void eval_set_cb_get_func_result(get_func_result_cb_t cb
) {
124 get_func_result_cb
= cb
;
127 int same_str(const char *a
, const char *b
);
128 int same_str_len(const char *a
, const char *b
, int len
);
130 void init_scantable(void);
131 int tokenize(struct memh
*mh
, char **string
, struct tok
**listptr
);
132 int scan_number(char **stringptr
, struct val
*valptr
);
133 int precedence(struct tok
*t
);
134 int eval(struct memh
*mh
, struct tok
*list
, struct vartable
*vt
,
136 void prt_lst(struct tok
*t
);
137 void prt_tok(struct tok
*t
);
141 int evaluate(char *expr
, struct val
*result
, struct vartable
*vartable
) {
142 struct memh
*mh
= NULL
;
143 int error
= RESULT_OK
, madevar
= 0;
147 /* ensure we have a variable table */
148 if (!vartable
) madevar
= 1, vartable
= create_vartable();
149 if (!vartable
) return ERROR_NOMEM
;
152 result
->type
= T_INT
;
155 if ((mh
= create_mem())) {
156 if (expr
&& (str
= (char *) mem_alloc(mh
, strlen(expr
)+1))) {
159 if ((error
= tokenize(mh
, &str
, &list
)) != RESULT_OK
) break;
160 if ((error
= eval(mh
, list
, vartable
, result
)) != RESULT_OK
) break;
162 } else error
= ERROR_NOMEM
;
163 } else error
= ERROR_NOMEM
;
166 if (madevar
) free_vartable(vartable
);
173 /**** TOKENIZATION ***/
175 void init_scantable(void) {
178 if (scantable_ok
) return;
180 for (i
= 0; i
<= UCHAR_MAX
; i
++)
182 (isalpha(i
) || i
== '_') ? TK_VAR
:
183 (isdigit(i
) ? TK_VAL
:
184 (isspace(i
) ? TK_SKIP
:
187 scantable
['+'] = TK_ADD
;
188 scantable
['-'] = TK_SUB
;
189 scantable
['*'] = TK_MUL
; /* also '**' = TK_POW */
190 scantable
['/'] = TK_DIV
;
191 scantable
['%'] = TK_MOD
;
192 scantable
['$'] = TK_VAL
; /* '$' starts a hexadecimal value */
193 scantable
['.'] = TK_VAL
; /* '.' starts a fractional value */
194 scantable
['('] = TK_OPEN
;
195 scantable
[')'] = TK_CLOSE
;
196 scantable
[';'] = TK_BREAK
;
197 scantable
['='] = TK_ASSN
; /* also '==' = TK_EQ */
198 scantable
['~'] = TK_BNOT
;
199 scantable
['^'] = TK_BXOR
;
200 scantable
['&'] = TK_BAND
; /* also '&&' = TK_AND */
201 scantable
['|'] = TK_BOR
; /* also '||' = TK_OR */
202 scantable
['!'] = TK_NOT
; /* also '!=' = TK_NE */
203 scantable
['<'] = TK_LT
; /* also '<<' = TK_SHL, '<=' = TK_LE */
204 scantable
['>'] = TK_GT
; /* also '>>' = TK_SHR, '>=' = TK_GE */
205 scantable
['\''] = TK_VARQUOTE
;
210 #if !MEM_LOW_FOOTPRINT
212 int tokenize(struct memh
*mh
, char **string
, struct tok
**listptr
) {
215 char *s
, *name
, c
, c2
, nt
;
217 /* allocate a block of memory to hold the maximum amount of tokens */
218 i
= strlen(*string
) + 1;
219 list
= (struct tok
*) mem_alloc(mh
, i
* sizeof(struct tok
));
220 if (!list
) return ERROR_NOMEM
;
222 for (s
= *string
; *s
; s
++) {
223 /* get token type of character and store into list */
224 c
= list
[idx
].token
= scantable
[* (unsigned char *) s
];
227 printf("tokenize: token %p code %d string %s\n", &list
[idx
], list
[idx
].token
, s
);
230 /* break out of the for loop on TK_BREAK */
231 if (c
== TK_BREAK
) { s
++; break; }
240 /* most symbol-tokens fall under this one - nothing much to do */
241 case TK_OPEN
: case TK_CLOSE
: case TK_ADD
: case TK_SUB
:
242 case TK_MUL
: case TK_DIV
: case TK_MOD
: case TK_BAND
: case TK_BOR
:
243 case TK_BXOR
: case TK_BNOT
: case TK_NOT
: case TK_LT
: case TK_GT
:
245 /* check for 'double character' tokens */
248 if (c
== TK_MUL
&& c2
== '*') nt
= TK_POW
;
249 if (c
== TK_BAND
&& c2
== '&') nt
= TK_AND
;
250 if (c
== TK_BOR
&& c2
== '|') nt
= TK_OR
;
251 if (c
== TK_NOT
&& c2
== '=') nt
= TK_NE
;
252 if (c
== TK_LT
&& c2
== '=') nt
= TK_LE
;
253 if (c
== TK_LT
&& c2
== '<') nt
= TK_SHL
;
254 if (c
== TK_GT
&& c2
== '=') nt
= TK_GE
;
255 if (c
== TK_GT
&& c2
== '>') nt
= TK_SHR
;
256 if (nt
) { list
[idx
].token
= nt
; s
++; }
262 /* '=' = TK_ASSN, '==' = TK_EQ */
263 if (s
[1] == '=') { list
[idx
++].token
= TK_EQ
; s
++; break; }
265 /* if the last token was a variable, change it to an assignment */
266 if (idx
<= 0 || list
[idx
-1].token
!= TK_VAR
) return ERROR_SYNTAX
;
267 list
[idx
-1].token
= TK_ASSN
;
271 if (!scan_number(&s
, &list
[idx
++].val
)) return ERROR_SYNTAX
;
272 s
--; /* wind back one for the loop's iterator */
278 list
[idx
].name
= name
= s
;
279 c2
= scantable
[(int)s
[1]];
280 while (c2
== TK_VAR
|| c2
== TK_VAL
) {
281 s
++; /* skip to end of string */
282 c2
= scantable
[(int)s
[1]];
286 if(!s
[1] || scantable
[(int)s
[1]] == TK_VARQUOTE
) {
289 list
[idx
].token
= TK_VAR
;
290 list
[idx
].name
= name
= ++s
;
291 while (s
[1] && scantable
[(int)s
[1]] != TK_VARQUOTE
) s
++; /* skip to end of string */
296 list
[idx
].name_end
= s
+1;
298 if(c
== TK_VARQUOTE
) {
302 if(scantable
[(int)s
[1]] == TK_OPEN
) {
303 list
[idx
].token
= TK_FUNC
;
304 list
[idx
].funcid
= 0;
305 /* look for matching function */
306 for (i
= 0; functable
[i
]; i
++) {
307 char *fname
= functable
[i
];
308 if (same_str_len(name
, fname
, len
) && strlen(fname
) == len
) {
309 list
[idx
].funcid
= i
+1;
319 /* write back the final position of the tokenizer - either pointing at
320 * a null character, or the next expression to go */
323 /* lace up the tokens and null-terminate the strings */
325 for (i
= 0; i
< idx
; i
++) {
326 list
[i
].next
= &list
[i
+1];
328 printf("tokenize: processed token %p code %d\n", &list
[i
], list
[i
].token
);
330 if (list
[i
].token
== TK_VAR
|| list
[i
].token
== TK_ASSN
|| list
[i
].token
== TK_FUNC
)
331 *(list
[i
].name_end
) = '\0';
333 list
[idx
-1].next
= NULL
;
345 int tokenize(struct memh
*mh
, char **string
, struct tok
**listptr
) {
346 struct tok
*tok
= NULL
, *last_tok
= NULL
;
348 char *s
, *name
, c
, c2
, nt
;
351 for (s
= *string
; *s
; s
++) {
352 /* get token type of character and store into list */
353 c
= scantable
[* (unsigned char *) s
];
355 /* break out of the for loop on TK_BREAK */
356 if(c
== TK_BREAK
) { s
++; break; }
357 if(c
== TK_ERROR
) return ERROR_SYNTAX
;
359 if(c
== TK_SKIP
) continue;
366 tok_size
= VAL_TOK_SIZE();
371 tok_size
= VAR_TOK_SIZE();
374 tok_size
= REG_TOK_SIZE();
377 tok
= (struct tok
*) mem_alloc(mh
, tok_size
);
378 if(!tok
) return ERROR_NOMEM
;
381 last_tok
->next
= tok
;
393 printf("tokenize: token %p code %d string %s\n", tok
, tok
->token
, s
);
398 /* most symbol-tokens fall under this one - nothing much to do */
399 case TK_OPEN
: case TK_CLOSE
: case TK_ADD
: case TK_SUB
:
400 case TK_MUL
: case TK_DIV
: case TK_MOD
: case TK_BAND
: case TK_BOR
:
401 case TK_BXOR
: case TK_BNOT
: case TK_NOT
: case TK_LT
: case TK_GT
:
403 /* check for 'double character' tokens */
406 if (c
== TK_MUL
&& c2
== '*') nt
= TK_POW
;
407 if (c
== TK_BAND
&& c2
== '&') nt
= TK_AND
;
408 if (c
== TK_BOR
&& c2
== '|') nt
= TK_OR
;
409 if (c
== TK_NOT
&& c2
== '=') nt
= TK_NE
;
410 if (c
== TK_LT
&& c2
== '=') nt
= TK_LE
;
411 if (c
== TK_LT
&& c2
== '<') nt
= TK_SHL
;
412 if (c
== TK_GT
&& c2
== '=') nt
= TK_GE
;
413 if (c
== TK_GT
&& c2
== '>') nt
= TK_SHR
;
414 if (nt
) { tok
->token
= nt
; s
++; }
420 /* '=' = TK_ASSN, '==' = TK_EQ */
421 if (s
[1] == '=') { tok
->token
= TK_EQ
; idx
++; s
++; break; }
423 /* if the last token was a variable, change it to an assignment */
424 if (idx
<= 0 || last_tok
->token
!= TK_VAR
) return ERROR_SYNTAX
;
425 last_tok
->token
= TK_ASSN
;
430 if (!scan_number(&s
, &tok
->val
)) return ERROR_SYNTAX
;
432 s
--; /* wind back one for the loop's iterator */
438 tok
->name
= name
= s
;
439 c2
= scantable
[(int)s
[1]];
440 while (c2
== TK_VAR
|| c2
== TK_VAL
) {
441 s
++; /* skip to end of string */
442 c2
= scantable
[(int)s
[1]];
446 if(!s
[1] || scantable
[(int)s
[1]] == TK_VARQUOTE
) {
450 tok
->name
= name
= ++s
;
451 while (s
[1] && scantable
[(int)s
[1]] != TK_VARQUOTE
) s
++; /* skip to end of string */
458 if(c
== TK_VARQUOTE
) {
462 if(scantable
[(int)s
[1]] == TK_OPEN
) {
463 tok
->token
= TK_FUNC
;
465 /* look for matching function */
466 for (i
= 0; functable
[i
]; i
++) {
467 const char *fname
= functable
[i
];
468 if (same_str_len(name
, fname
, len
) && strlen(fname
) == (size_t)len
) {
479 /* write back the final position of the tokenizer - either pointing at
480 * a null character, or the next expression to go */
483 /* lace up the tokens and null-terminate the strings */
488 printf("tokenize: processed token %p code %d\n", tok
, tok
->token
);
490 if (tok
->token
== TK_VAR
|| tok
->token
== TK_ASSN
|| tok
->token
== TK_FUNC
)
491 *(tok
->name_end
) = '\0';
504 /* scans some text into a value */
505 int scan_number(char **stringptr
, struct val
*valptr
) {
506 struct val v
= { T_INT
, 0, 0.0 };
507 char *s
= *stringptr
;
511 /* test to see if it's a hex number */
512 if (s
[0] == '$' || (s
[0] == '0' && s
[1] == 'x')) {
513 s
+= (s
[1] == 'x') ? 2 : 1;
516 for (; isxdigit(c
= (int) *s
); s
++)
517 v
.ival
= (v
.ival
<< 4)
518 + (isdigit(c
) ? c
-'0' : 0)
519 + (isupper(c
) ? c
-'A' + 10 : 0)
520 + (islower(c
) ? c
-'a' + 10 : 0);
523 /* must be a decimal integer or real */
525 for (; isdigit(c
= (int) *s
); s
++) v
.ival
= (v
.ival
* 10) + c
-'0';
529 v
.rval
= (double) v
.ival
;
530 for (dp
= 0.1; isdigit(c
= (int) *s
); s
++, dp
/= 10.0)
531 v
.rval
+= dp
* (double) (c
-'0');
535 /* if no numeric chars have been read, it's a dud - return FAIL */
536 if (s
== *stringptr
) return 0;
538 /* otherwise, update position and return SUCCESS */
547 /* returns the precedence of a token */
548 int precedence(struct tok
*t
) {
550 case TK_FUNC
: return 15;
551 case TK_MULI
: return 14;
552 case TK_NEG
: case TK_NOT
: case TK_BNOT
: return 13;
553 case TK_POW
: return 12;
554 case TK_MUL
: case TK_DIV
: case TK_MOD
: return 11;
555 case TK_ADD
: case TK_SUB
: return 10;
556 case TK_SHL
: case TK_SHR
: return 9;
557 case TK_LT
: case TK_GT
: case TK_LE
: case TK_GE
: return 8;
558 case TK_EQ
: case TK_NE
: return 7;
559 case TK_BAND
: return 6;
560 case TK_BOR
: case TK_BXOR
: return 5;
561 case TK_AND
: case TK_OR
: return 4;
562 case TK_ASSN
: return 3;
563 case TK_CLOSE
: return 2;
564 case TK_OPEN
: return 1;
570 int eval(struct memh
*mh
, struct tok
*list
, struct vartable
*vt
,
571 struct val
*result
) {
573 static struct val newval
= { T_INT
, 0, 0.0 };
575 struct val tmp_val
, *valstk
, *x
, *y
;
576 struct tok open
, close
, *l
, *r
, *t
, **opstk
;
578 int vstk
, ostk
, vcnt
= 0, ocnt
= 0;
579 double xr
, yr
, rr
= 0;
585 /* clear result before we do anything - and no tokens is no result */
587 if (!list
) return RESULT_OK
;
590 /* CONVERSION OF RAW TOKENS INTO COMPLETE INFIX EXPRESSION */
592 /* wrap the token list in a pair of parentheses */
593 for (t
= list
; t
->next
; t
= t
->next
)
596 close
.next
= NULL
; open
.next
= list
; list
= &open
;
597 close
.token
= TK_CLOSE
; open
.token
= TK_OPEN
;
599 /* insert and change tokens as neccessary */
600 for (l
=list
, r
=l
->next
; r
->next
; l
=r
, r
=r
->next
) {
604 /* convert TK_SUBs that should be unary into TK_NEGs */
605 if (rt
== TK_SUB
&& lt
!= TK_CLOSE
&& lt
!= TK_VAR
&& lt
!= TK_VAL
)
608 /* insert implicit multiplication tokens */
609 if ((lt
== TK_VAR
|| lt
== TK_VAL
|| lt
== TK_CLOSE
)
610 && (rt
== TK_VAR
|| rt
== TK_VAL
|| rt
== TK_OPEN
|| rt
== TK_FUNC
)) {
611 if (lt
== rt
) return ERROR_SYNTAX
;
612 t
= (struct tok
*) mem_alloc(mh
, sizeof(struct tok
));
613 if (!t
) return ERROR_NOMEM
;
614 t
->token
= TK_MULI
; l
->next
= t
; t
->next
= r
;
618 /* VARIABLE CHECKING */
621 for (t
= list
; t
; t
= t
->next
) {
624 /* count the number of values and operators */
625 if (lt
== TK_VAR
|| lt
== TK_VAL
) vcnt
++; else ocnt
++;
627 /* if assigned variables don't exist, create a new blank one */
629 if (!(t
->var
= get_var(vt
, t
->name
)))
630 if (!(t
->var
= put_var(vt
, t
->name
, &newval
)))
634 /* try to get vars from vartable - if not, try the environment */
635 else if (lt
== TK_VAR
) {
637 if ((t
->var
= get_var(vt
, t
->name
))) {
641 if(!var_found
&& (envtxt
= getenv(t
->name
))) {
642 if (!scan_number(&envtxt
, &tmp_val
)) return ERROR_SYNTAX
;
643 if (!(t
->var
= put_var(vt
, t
->name
, &tmp_val
))) return ERROR_NOMEM
;
647 if(!var_found
&& get_var_cb
&& (get_var_cb(t
->name
, &tmp_val
))) {
648 if (!(t
->var
= put_var(vt
, t
->name
, &tmp_val
))) return ERROR_NOMEM
;
652 return ERROR_VARNOTFOUND
;
657 /* ALLOCATE STACKS */
659 /* allocate the operator stack and the value stack */
660 valstk
= (struct val
*) mem_alloc(mh
, vcnt
* sizeof(struct val
));
661 opstk
= (struct tok
**) mem_alloc(mh
, ocnt
* sizeof(struct tok
*));
662 if (!valstk
|| !opstk
) return ERROR_NOMEM
;
664 /* set the stack pointers to '0 items on stack' */
665 /* (the stack pointers are always set at the topmost stack item) */
668 /* MAIN EVALUATION LOOP */
670 for (t
= list
; t
; t
=t
->next
) {
673 /* unary operators always wait until after what follows is evaluated */
674 /* also, open parentheses are pushed to match where close ones stop */
676 case TK_ASSN
: case TK_NEG
: case TK_FUNC
: case TK_NOT
: case TK_BNOT
:
677 opstk
[++ostk
] = t
; break;
679 /* values go straight on the value stack */
681 valstk
[++vstk
] = t
->val
;
684 /* variables go straight on the value stack */
686 valstk
[++vstk
] = t
->var
->val
;
689 /* this is where the action happens - all operations of a higher or same
690 * precedence are now executed. then, after that, we push the operator
691 * to the stack, or if it's a close paren, pull and expect an open paren
693 * it's assumed that all tokens in the token stream that aren't one of
694 * the previous cases must be the close bracket or a binary operator -
695 * that's why 'default' is used rather than all the names
698 while (precedence(opstk
[ostk
]) >= precedence(t
)) {
699 struct tok
*op
= opstk
[ostk
--];
701 printf("eval: "); prt_tok(op
); printf("\n");
704 /* there should always be at least a close bracket left here */
705 if (ostk
< 0) return ERROR_SYNTAX
;
707 /* we assume that all operators require at least one value */
708 /* on the stack, and check here */
709 if (vstk
< 0) return ERROR_SYNTAX
;
711 /* now we actually perform evaluations */
712 switch (token
= op
->token
) {
714 /* binary (int/real) -> (int/real) */
715 case TK_ADD
: case TK_SUB
: case TK_MUL
: case TK_MULI
:
717 /* pull two values from the stack, y then x, and push 'x op y' */
718 if (vstk
< 1) return ERROR_SYNTAX
;
719 y
= &valstk
[vstk
--]; x
= &valstk
[vstk
];
721 /* if both values are integer, do integer operations only */
722 if (x
->type
== T_INT
&& y
->type
== T_INT
) {
727 case TK_MUL
: ri
= (xi
* yi
); break;
728 case TK_ADD
: ri
= (xi
+ yi
); break;
729 case TK_SUB
: ri
= (xi
- yi
); break;
731 /* push int-value result to value stack */
736 /* get real values - convert if neccessary */
737 xr
= (x
->type
== T_REAL
) ? x
->rval
: (double) x
->ival
;
738 yr
= (y
->type
== T_REAL
) ? y
->rval
: (double) y
->ival
;
742 case TK_MUL
: rr
= (xr
* yr
); break;
743 case TK_ADD
: rr
= (xr
+ yr
); break;
744 case TK_SUB
: rr
= (xr
- yr
); break;
746 /* push real-value result to value stack */
754 /* binary (int/real) -> int */
755 case TK_EQ
: case TK_NE
: case TK_LT
:
756 case TK_GT
: case TK_LE
: case TK_GE
:
758 if (vstk
< 1) return ERROR_SYNTAX
;
759 y
= &valstk
[vstk
--]; x
= &valstk
[vstk
];
761 if (x
->type
== T_INT
&& y
->type
== T_INT
) {
765 case TK_EQ
: ri
= (xi
== yi
); break;
766 case TK_NE
: ri
= (xi
!= yi
); break;
767 case TK_LT
: ri
= (xi
< yi
); break;
768 case TK_GT
: ri
= (xi
> yi
); break;
769 case TK_LE
: ri
= (xi
<= yi
); break;
770 case TK_GE
: ri
= (xi
>= yi
); break;
774 xr
= (x
->type
== T_REAL
) ? x
->rval
: (double) x
->ival
;
775 yr
= (y
->type
== T_REAL
) ? y
->rval
: (double) y
->ival
;
777 case TK_EQ
: ri
= (xr
== yr
); break;
778 case TK_NE
: ri
= (xr
!= yr
); break;
779 case TK_LT
: ri
= (xr
< yr
); break;
780 case TK_GT
: ri
= (xr
> yr
); break;
781 case TK_LE
: ri
= (xr
<= yr
); break;
782 case TK_GE
: ri
= (xr
>= yr
); break;
790 /* binary real -> real */
791 case TK_DIV
: case TK_POW
:
793 if (vstk
< 1) return ERROR_SYNTAX
;
794 y
= &valstk
[vstk
--]; x
= &valstk
[vstk
];
795 xr
= (x
->type
== T_REAL
) ? x
->rval
: (double) x
->ival
;
796 yr
= (y
->type
== T_REAL
) ? y
->rval
: (double) y
->ival
;
798 if (token
== TK_DIV
) {
799 if (yr
== 0) return ERROR_DIV0
;
804 x
->rval
= pow(xr
, yr
);
813 /* binary int -> int */
814 case TK_MOD
: case TK_AND
: case TK_OR
:
815 case TK_BAND
: case TK_BOR
: case TK_BXOR
:
816 case TK_SHL
: case TK_SHR
:
818 if (vstk
< 1) return ERROR_SYNTAX
;
819 y
= &valstk
[vstk
--]; x
= &valstk
[vstk
];
820 xi
= (x
->type
== T_INT
) ? x
->ival
: (long) x
->rval
;
821 yi
= (y
->type
== T_INT
) ? y
->ival
: (long) y
->rval
;
824 case TK_MOD
: if (yi
== 0) return ERROR_DIV0
;
825 ri
= (xi
% yi
); break;
826 case TK_AND
: ri
= (xi
&& yi
); break;
827 case TK_OR
: ri
= (xi
|| yi
); break;
828 case TK_BAND
: ri
= (xi
& yi
); break;
829 case TK_BOR
: ri
= (xi
| yi
); break;
830 case TK_BXOR
: ri
= (xi
^ yi
); break;
831 case TK_SHL
: ri
= (xi
<< yi
); break;
832 case TK_SHR
: ri
= (xi
>> yi
); break;
841 /* unary real -> real */
846 xr
= (x
->type
== T_REAL
) ? x
->rval
: (double) x
->ival
;
847 switch (op
->funcid
-1) {
848 case F_ACOS
: xr
= acos(xr
); break;
849 case F_ASIN
: xr
= asin(xr
); break;
850 case F_ATAN
: xr
= atan(xr
); break;
851 case F_COS
: xr
= cos(xr
); break;
852 case F_COSH
: xr
= cosh(xr
); break;
853 case F_EXP
: xr
= exp(xr
); break;
854 case F_LN
: xr
= log(xr
); break;
855 case F_LOG
: xr
= log10(xr
); break;
856 case F_SIN
: xr
= sin(xr
); break;
857 case F_SINH
: xr
= sinh(xr
); break;
858 case F_SQR
: xr
= xr
* xr
; break;
859 case F_SQRT
: xr
= sqrt(xr
); break;
860 case F_TAN
: xr
= tan(xr
); break;
861 case F_TANH
: xr
= tanh(xr
); break;
862 default: xr
= 0; break;
871 if(!get_func_result_cb
|| !get_func_result_cb(op
->name
, x
, x
)) {
872 return ERROR_FUNCNOTFOUND
;
878 /* unary int -> int */
879 case TK_BNOT
: case TK_NOT
:
882 xi
= (x
->type
== T_INT
) ? x
->ival
: (long) x
->rval
;
883 if (token
== TK_BNOT
) {
893 /* unary (int/real) -> (int/real) */
895 op
->var
->val
= valstk
[vstk
];
899 /* unary (int/real) -> (int/real) */
902 if (x
->type
== T_INT
)
908 } /* end select (execution switch) */
909 } /* end while (precedence loop) */
911 /* back to the postfixified */
913 /* if we had a close paren, pull the matching open paren (error if
914 * we pull something else. otherwise push our new operator
916 if (t
->token
== TK_CLOSE
) {
917 if (opstk
[ostk
--]->token
!= TK_OPEN
) return ERROR_SYNTAX
;
925 /* there should be exactly one value and no operators left on the stacks */
926 if (vstk
!= 0 || ostk
!= -1) return ERROR_SYNTAX
;
928 /* return that value */
937 /** debugging things **/
939 /* expression printer */
940 void prt_tok(struct tok
*t
) {
942 case TK_OPEN
: printf("( "); break;
943 case TK_CLOSE
: printf(") "); break;
945 case TK_ADD
: printf("+ "); break;
946 case TK_SUB
: printf("- "); break;
947 case TK_MUL
: printf("* "); break;
948 case TK_MULI
: printf("*i "); break;
949 case TK_POW
: printf("** "); break;
950 case TK_DIV
: printf("/ "); break;
951 case TK_MOD
: printf("%% "); break;
953 case TK_EQ
: printf("== "); break;
954 case TK_NE
: printf("!= "); break;
955 case TK_LT
: printf("< "); break;
956 case TK_GT
: printf("> "); break;
957 case TK_LE
: printf("<= "); break;
958 case TK_GE
: printf(">= "); break;
960 case TK_AND
: printf("&& "); break;
961 case TK_BAND
: printf("& "); break;
962 case TK_BNOT
: printf("~ "); break;
963 case TK_BOR
: printf("| "); break;
964 case TK_BXOR
: printf("^ "); break;
965 case TK_NEG
: printf("_ "); break;
966 case TK_NOT
: printf("! "); break;
967 case TK_OR
: printf("|| "); break;
968 case TK_SHL
: printf("<< "); break;
969 case TK_SHR
: printf(">> "); break;
971 case TK_ASSN
: printf("%s = ", t
->name
); break;
972 case TK_FUNC
: printf("%s() ", t
->funcid
? functable
[(int)t
->funcid
-1] : t
->name
); break;
973 case TK_VAL
: if (t
->val
.type
== T_INT
)
974 printf("%ld ", t
->val
.ival
);
976 printf("%g ", t
->val
.rval
);
979 case TK_VAR
: printf("%s ", t
->name
); break;
980 default: printf("?? (%d)", t
->token
); break;
984 void prt_lst(struct tok
*t
) {
985 for (; t
; t
=t
->next
) prt_tok(t
);
990 void prt_tok(struct tok
*t
) {}
991 void prt_lst(struct tok
*t
) {}
996 /*** UTILITY FUNCTIONS ***/
998 /* case-insensitive string comparison, TRUE or FALSE result */
999 int same_str(const char *a
, const char *b
) {
1000 if (!a
|| !b
) return 0; /* false even if a == b == null */
1001 if (a
== b
) return 1;
1003 #ifdef HAVE_STRCASECMP
1004 return (strcasecmp(a
, b
) == 0);
1006 return (strcmpi(a
, b
) == 0);
1008 while ((tolower((int)*a
) == tolower((int)*b
))) {
1009 if (!*a
) return 1; /* if end of both strings, return true */
1012 return 0; /* mismatch before end of string - return false */
1016 /* case-insensitive string comparison with maximum length */
1017 int same_str_len(const char *a
, const char *b
, int len
) {
1018 if (!a
|| !b
) return 0; /* false even if a == b == null */
1019 if (len
== 0) return 0;
1020 if (a
== b
) return 1;
1022 #ifdef HAVE_STRNCASECMP
1023 return (strncasecmp(a
, b
, len
) == 0);
1025 return (strncmpi(a
, b
) == 0);
1027 while (--len
&& (tolower((int)*a
) == tolower((int)*b
))) {
1028 if (!*a
) return 1; /* true if both strings equal & end before len */
1031 /* result based on last char of allowed length */
1032 return (tolower((int)*a
) == tolower((int)*b
)) ? 1 : 0;
1037 /* tracked memory allocation - create header */
1038 struct memh
*create_mem() {
1039 struct memh
*mh
= (struct memh
*) malloc(sizeof(struct memh
));
1045 /* tracked memory allocation - allocate memory using header */
1046 void *mem_alloc(struct memh
*mh
, size_t len
) {
1047 struct memh
*mem
= (struct memh
*) malloc(len
+ sizeof(struct memh
));
1048 if (!mem
) return NULL
;
1049 mem
->next
= mh
->next
;
1051 return mem
->ptr
= (void *) &mem
[1];
1054 /* tracked memory allocation - free all memory in header */
1055 void free_mem(struct memh
*mh
) {
1057 for (; mh
; mh
= next
) {
1064 #define MEM_BUFFER_LEN 4096
1065 #define MAX_NUM_BUFFERS 2
1066 char mem_buffer
[MAX_NUM_BUFFERS
][MEM_BUFFER_LEN
];
1067 struct memh mem_headers
[MAX_NUM_BUFFERS
];
1068 int mem_idx
[MAX_NUM_BUFFERS
] = {0};
1070 #define MEM_HEADER_TO_N(H) ((H)-mem_headers)
1072 struct memh
*create_mem() {
1075 for(n
=0;n
<MAX_NUM_BUFFERS
;n
++) {
1076 if(mem_idx
[n
] == 0) {
1082 if(n
== MAX_NUM_BUFFERS
) {
1084 printf("create_mem: out of buffers\n", n
);
1089 printf("create_mem: n is %d\n", n
);
1091 mh
= &mem_headers
[n
];
1092 memset(mh
, 0, sizeof(struct memh
));
1096 void *mem_alloc(struct memh
*mh
, size_t len
) {
1097 int n
= MEM_HEADER_TO_N(mh
);
1099 struct memh
*mem
= NULL
;
1100 len
+= sizeof(struct memh
);
1101 mem_idx_n
= mem_idx
[n
]-1;
1103 printf("mem_alloc: len is %d, buffer num is %d, buffer idx is %d, buffer len is %d\n", len
, n
, mem_idx_n
, MEM_BUFFER_LEN
);
1105 if(mem_idx_n
+ len
> MEM_BUFFER_LEN
) {
1107 printf("mem_alloc: out of mem\n");
1111 mem
= (struct memh
*) &mem_buffer
[n
][mem_idx_n
];
1113 mem
->next
= mh
->next
;
1115 return mem
->ptr
= (void *) &mem
[1];
1118 void free_mem(struct memh
*mh
) {
1119 int n
= MEM_HEADER_TO_N(mh
);
1122 printf("free_mem: n is %d\n", n
);
1128 /* creates an empty variable table */
1129 struct vartable
*create_vartable() {
1130 struct memh
*mh
= create_mem();
1131 struct vartable
*vt
;
1135 vt
= (struct vartable
*) mem_alloc(mh
, sizeof(struct vartable
));
1136 if (mh
&& vt
) vt
->mh
= mh
, vt
->first
= NULL
; else free_mem(mh
);
1140 /* frees a variable table */
1141 void free_vartable(struct vartable
*vt
) {
1145 /* gets a variable out of a variable table */
1146 struct var
*get_var(struct vartable
*vt
, char *name
) {
1148 if (!vt
|| !name
) return NULL
;
1149 for (v
= vt
->first
; v
; v
= v
->next
) if (same_str(v
->name
, name
)) return v
;
1153 /* creates a new variable in a variable table */
1154 struct var
*put_var(struct vartable
*vt
, char *name
, struct val
*value
) {
1158 if (!vt
|| !name
|| !value
) return NULL
;
1160 if ((v
= get_var(vt
, name
))) {
1165 v
= (struct var
*) mem_alloc(vt
->mh
, sizeof(struct var
));
1166 n
= (char *) mem_alloc(vt
->mh
, strlen(name
)+1);
1171 v
->next
= vt
->first
;