xref: /minix3/minix/lib/libmagicrt/magic_eval_lib.c (revision b2ed49a5d83e311ee0fa9e5ff613639b1bf77aaf)
1*b2ed49a5SDavid van Moolenbroek /* evaluate.c (C) 2000-2002 Kyzer/CSG. */
2*b2ed49a5SDavid van Moolenbroek /* Released under the terms of the GNU General Public Licence version 2. */
3*b2ed49a5SDavid van Moolenbroek 
4*b2ed49a5SDavid van Moolenbroek #include "magic_eval_lib.h"
5*b2ed49a5SDavid van Moolenbroek #include <ctype.h>
6*b2ed49a5SDavid van Moolenbroek #include <limits.h>
7*b2ed49a5SDavid van Moolenbroek #include <string.h>
8*b2ed49a5SDavid van Moolenbroek #include <stdio.h>
9*b2ed49a5SDavid van Moolenbroek #include <assert.h>
10*b2ed49a5SDavid van Moolenbroek 
11*b2ed49a5SDavid van Moolenbroek #if USE_MATH_LIB
12*b2ed49a5SDavid van Moolenbroek #include <math.h>
13*b2ed49a5SDavid van Moolenbroek #endif
14*b2ed49a5SDavid van Moolenbroek 
15*b2ed49a5SDavid van Moolenbroek #ifdef __MINIX
16*b2ed49a5SDavid van Moolenbroek /* FIXME: due to the current linker command line ordering, parts of lib(min)c
17*b2ed49a5SDavid van Moolenbroek  * that are used exclusively by libmagicrt end up not being instrumented, which
18*b2ed49a5SDavid van Moolenbroek  * then causes problems transferring pointers such as _ctype_tab_ and
19*b2ed49a5SDavid van Moolenbroek  * _tolower_tab_. As a temporary workaround, we redefine the macros that use
20*b2ed49a5SDavid van Moolenbroek  * those pointers. This code is currently never triggered so it is not
21*b2ed49a5SDavid van Moolenbroek  * performance critical; obviously there are a million better ways to do this.
22*b2ed49a5SDavid van Moolenbroek  */
23*b2ed49a5SDavid van Moolenbroek #undef isalpha
24*b2ed49a5SDavid van Moolenbroek #define isalpha(c) ((unsigned)(((c) & ~0x20) - 'A') <= ('Z' - 'A'))
25*b2ed49a5SDavid van Moolenbroek #undef isupper
26*b2ed49a5SDavid van Moolenbroek #define isupper(c) ((unsigned)((c) - 'A') <= ('Z' - 'A'))
27*b2ed49a5SDavid van Moolenbroek #undef islower
28*b2ed49a5SDavid van Moolenbroek #define islower(c) ((unsigned)((c) - 'a') <= ('z' - 'a'))
29*b2ed49a5SDavid van Moolenbroek #undef isdigit
30*b2ed49a5SDavid van Moolenbroek #define isdigit(c) ((unsigned)((c) - '0') <= ('9' - '0'))
__isxdigit(c)31*b2ed49a5SDavid van Moolenbroek static inline int __isxdigit(c) {
32*b2ed49a5SDavid van Moolenbroek     return isdigit(c) || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f');
33*b2ed49a5SDavid van Moolenbroek }
34*b2ed49a5SDavid van Moolenbroek #undef isxdigit
35*b2ed49a5SDavid van Moolenbroek #define isxdigit(c) (__isxdigit(c))
__isspace(c)36*b2ed49a5SDavid van Moolenbroek static inline int __isspace(c) {
37*b2ed49a5SDavid van Moolenbroek     switch (c) {
38*b2ed49a5SDavid van Moolenbroek     case ' ': case '\t': case '\n': case '\v': case '\f': case '\r': return 1;
39*b2ed49a5SDavid van Moolenbroek     default: return 0;
40*b2ed49a5SDavid van Moolenbroek     }
41*b2ed49a5SDavid van Moolenbroek }
42*b2ed49a5SDavid van Moolenbroek #undef isspace
43*b2ed49a5SDavid van Moolenbroek #define isspace(c) (__isspace(c))
__tolower(c)44*b2ed49a5SDavid van Moolenbroek static inline int __tolower(c) {
45*b2ed49a5SDavid van Moolenbroek     return isupper(c) ? (c | 0x20) : c;
46*b2ed49a5SDavid van Moolenbroek }
47*b2ed49a5SDavid van Moolenbroek #undef tolower
48*b2ed49a5SDavid van Moolenbroek #define tolower(c) (__tolower(c))
49*b2ed49a5SDavid van Moolenbroek #endif /* __MINIX */
50*b2ed49a5SDavid van Moolenbroek 
51*b2ed49a5SDavid van Moolenbroek /* a token structure */
52*b2ed49a5SDavid van Moolenbroek struct tok {
53*b2ed49a5SDavid van Moolenbroek     struct tok *next;
54*b2ed49a5SDavid van Moolenbroek     struct var *var;
55*b2ed49a5SDavid van Moolenbroek     char     token;
56*b2ed49a5SDavid van Moolenbroek     struct val val;
57*b2ed49a5SDavid van Moolenbroek     char     funcid, *name, *name_end;
58*b2ed49a5SDavid van Moolenbroek };
59*b2ed49a5SDavid van Moolenbroek #define REG_TOK_SIZE() offsetof(struct tok, val)
60*b2ed49a5SDavid van Moolenbroek #define VAL_TOK_SIZE() offsetof(struct tok, funcid)
61*b2ed49a5SDavid van Moolenbroek #define VAR_TOK_SIZE() sizeof(struct tok)
62*b2ed49a5SDavid van Moolenbroek 
63*b2ed49a5SDavid van Moolenbroek /* private memory header for tracked memory allocation */
64*b2ed49a5SDavid van Moolenbroek struct memh {
65*b2ed49a5SDavid van Moolenbroek     struct memh *next;
66*b2ed49a5SDavid van Moolenbroek     void *ptr;
67*b2ed49a5SDavid van Moolenbroek };
68*b2ed49a5SDavid van Moolenbroek 
69*b2ed49a5SDavid van Moolenbroek /* creates a new memory header for allocating memory */
70*b2ed49a5SDavid van Moolenbroek static struct memh *create_mem();
71*b2ed49a5SDavid van Moolenbroek 
72*b2ed49a5SDavid van Moolenbroek /* allocates memory using a particular header */
73*b2ed49a5SDavid van Moolenbroek static void *mem_alloc(struct memh *mh, size_t len);
74*b2ed49a5SDavid van Moolenbroek 
75*b2ed49a5SDavid van Moolenbroek /* frees all memory for a particular header */
76*b2ed49a5SDavid van Moolenbroek static void free_mem(struct memh *mh);
77*b2ed49a5SDavid van Moolenbroek 
78*b2ed49a5SDavid van Moolenbroek /* token types */
79*b2ed49a5SDavid van Moolenbroek enum {
80*b2ed49a5SDavid van Moolenbroek     /* parentheses */
81*b2ed49a5SDavid van Moolenbroek     TK_OPEN, TK_CLOSE,
82*b2ed49a5SDavid van Moolenbroek 
83*b2ed49a5SDavid van Moolenbroek     /* variables and values */
84*b2ed49a5SDavid van Moolenbroek     TK_VAR, TK_VARQUOTE, TK_VAL,
85*b2ed49a5SDavid van Moolenbroek 
86*b2ed49a5SDavid van Moolenbroek     /* binary operators */
87*b2ed49a5SDavid van Moolenbroek     TK_ADD, TK_SUB, TK_MUL, TK_MULI, TK_DIV,
88*b2ed49a5SDavid van Moolenbroek     TK_MOD, TK_POW, TK_AND, TK_OR, TK_BAND,
89*b2ed49a5SDavid van Moolenbroek     TK_BOR, TK_BXOR, TK_EQ, TK_NE, TK_LT, TK_GT,
90*b2ed49a5SDavid van Moolenbroek     TK_LE, TK_GE, TK_SHL, TK_SHR,
91*b2ed49a5SDavid van Moolenbroek 
92*b2ed49a5SDavid van Moolenbroek     /* unary operators */
93*b2ed49a5SDavid van Moolenbroek     TK_ASSN, TK_NEG, TK_FUNC, TK_NOT, TK_BNOT,
94*b2ed49a5SDavid van Moolenbroek 
95*b2ed49a5SDavid van Moolenbroek     /* special scan codes */
96*b2ed49a5SDavid van Moolenbroek     TK_BREAK, /* finish scanning, bring remainder of string forward */
97*b2ed49a5SDavid van Moolenbroek     TK_ERROR, /* abort scanning */
98*b2ed49a5SDavid van Moolenbroek     TK_SKIP     /* ignore the character */
99*b2ed49a5SDavid van Moolenbroek };
100*b2ed49a5SDavid van Moolenbroek 
101*b2ed49a5SDavid van Moolenbroek /* lookup table to do conversion [char -> token type] */
102*b2ed49a5SDavid van Moolenbroek char scantable[UCHAR_MAX+1];
103*b2ed49a5SDavid van Moolenbroek int scantable_ok = 0;
104*b2ed49a5SDavid van Moolenbroek 
105*b2ed49a5SDavid van Moolenbroek /* table of function names */
106*b2ed49a5SDavid van Moolenbroek const char *functable[] = {
107*b2ed49a5SDavid van Moolenbroek     "acos", "asin", "atan", "cos", "cosh", "exp", "ln", "log",
108*b2ed49a5SDavid van Moolenbroek     "sin", "sinh", "sqr", "sqrt", "tan", "tanh", NULL
109*b2ed49a5SDavid van Moolenbroek };
110*b2ed49a5SDavid van Moolenbroek 
111*b2ed49a5SDavid van Moolenbroek /* function ids (index to functable) */
112*b2ed49a5SDavid van Moolenbroek enum {
113*b2ed49a5SDavid van Moolenbroek     F_ACOS, F_ASIN, F_ATAN, F_COS, F_COSH, F_EXP, F_LN, F_LOG,
114*b2ed49a5SDavid van Moolenbroek     F_SIN, F_SINH, F_SQR, F_SQRT, F_TAN, F_TANH
115*b2ed49a5SDavid van Moolenbroek };
116*b2ed49a5SDavid van Moolenbroek 
117*b2ed49a5SDavid van Moolenbroek /* callbacks */
118*b2ed49a5SDavid van Moolenbroek static get_var_cb_t get_var_cb = NULL;
119*b2ed49a5SDavid van Moolenbroek static get_func_result_cb_t get_func_result_cb = NULL;
eval_set_cb_get_var(get_var_cb_t cb)120*b2ed49a5SDavid van Moolenbroek void eval_set_cb_get_var(get_var_cb_t cb) {
121*b2ed49a5SDavid van Moolenbroek         get_var_cb = cb;
122*b2ed49a5SDavid van Moolenbroek }
eval_set_cb_get_func_result(get_func_result_cb_t cb)123*b2ed49a5SDavid van Moolenbroek void eval_set_cb_get_func_result(get_func_result_cb_t cb) {
124*b2ed49a5SDavid van Moolenbroek         get_func_result_cb = cb;
125*b2ed49a5SDavid van Moolenbroek }
126*b2ed49a5SDavid van Moolenbroek 
127*b2ed49a5SDavid van Moolenbroek int same_str(const char *a, const char *b);
128*b2ed49a5SDavid van Moolenbroek int same_str_len(const char *a, const char *b, int len);
129*b2ed49a5SDavid van Moolenbroek 
130*b2ed49a5SDavid van Moolenbroek void init_scantable(void);
131*b2ed49a5SDavid van Moolenbroek int tokenize(struct memh *mh, char **string, struct tok **listptr);
132*b2ed49a5SDavid van Moolenbroek int scan_number(char **stringptr, struct val *valptr);
133*b2ed49a5SDavid van Moolenbroek int precedence(struct tok *t);
134*b2ed49a5SDavid van Moolenbroek int eval(struct memh *mh, struct tok *list, struct vartable *vt,
135*b2ed49a5SDavid van Moolenbroek     struct val *result);
136*b2ed49a5SDavid van Moolenbroek void prt_lst(struct tok *t);
137*b2ed49a5SDavid van Moolenbroek void prt_tok(struct tok *t);
138*b2ed49a5SDavid van Moolenbroek 
139*b2ed49a5SDavid van Moolenbroek /*** FRONT-END ***/
140*b2ed49a5SDavid van Moolenbroek 
evaluate(char * expr,struct val * result,struct vartable * vartable)141*b2ed49a5SDavid van Moolenbroek int evaluate(char *expr, struct val *result, struct vartable *vartable) {
142*b2ed49a5SDavid van Moolenbroek     struct memh *mh = NULL;
143*b2ed49a5SDavid van Moolenbroek     int error = RESULT_OK, madevar = 0;
144*b2ed49a5SDavid van Moolenbroek     struct tok *list;
145*b2ed49a5SDavid van Moolenbroek     char *str;
146*b2ed49a5SDavid van Moolenbroek 
147*b2ed49a5SDavid van Moolenbroek     /* ensure we have a variable table */
148*b2ed49a5SDavid van Moolenbroek     if (!vartable) madevar = 1, vartable = create_vartable();
149*b2ed49a5SDavid van Moolenbroek     if (!vartable) return ERROR_NOMEM;
150*b2ed49a5SDavid van Moolenbroek 
151*b2ed49a5SDavid van Moolenbroek     init_scantable();
152*b2ed49a5SDavid van Moolenbroek     result->type = T_INT;
153*b2ed49a5SDavid van Moolenbroek     result->ival = 0;
154*b2ed49a5SDavid van Moolenbroek 
155*b2ed49a5SDavid van Moolenbroek     if ((mh = create_mem())) {
156*b2ed49a5SDavid van Moolenbroek         if (expr && (str = (char *) mem_alloc(mh, strlen(expr)+1))) {
157*b2ed49a5SDavid van Moolenbroek             strcpy(str, expr);
158*b2ed49a5SDavid van Moolenbroek             while (*str) {
159*b2ed49a5SDavid van Moolenbroek     if ((error = tokenize(mh, &str, &list)) != RESULT_OK) break;
160*b2ed49a5SDavid van Moolenbroek     if ((error = eval(mh, list, vartable, result)) != RESULT_OK) break;
161*b2ed49a5SDavid van Moolenbroek             }
162*b2ed49a5SDavid van Moolenbroek         } else error = ERROR_NOMEM;
163*b2ed49a5SDavid van Moolenbroek     } else error = ERROR_NOMEM;
164*b2ed49a5SDavid van Moolenbroek 
165*b2ed49a5SDavid van Moolenbroek     if(mh) free_mem(mh);
166*b2ed49a5SDavid van Moolenbroek     if (madevar) free_vartable(vartable);
167*b2ed49a5SDavid van Moolenbroek     return error;
168*b2ed49a5SDavid van Moolenbroek }
169*b2ed49a5SDavid van Moolenbroek 
170*b2ed49a5SDavid van Moolenbroek 
171*b2ed49a5SDavid van Moolenbroek 
172*b2ed49a5SDavid van Moolenbroek 
173*b2ed49a5SDavid van Moolenbroek /**** TOKENIZATION ***/
174*b2ed49a5SDavid van Moolenbroek 
init_scantable(void)175*b2ed49a5SDavid van Moolenbroek void init_scantable(void) {
176*b2ed49a5SDavid van Moolenbroek     int i;
177*b2ed49a5SDavid van Moolenbroek 
178*b2ed49a5SDavid van Moolenbroek     if (scantable_ok) return;
179*b2ed49a5SDavid van Moolenbroek 
180*b2ed49a5SDavid van Moolenbroek     for (i = 0; i <= UCHAR_MAX; i++)
181*b2ed49a5SDavid van Moolenbroek         scantable[i] =
182*b2ed49a5SDavid van Moolenbroek             (isalpha(i) || i == '_') ? TK_VAR :
183*b2ed49a5SDavid van Moolenbroek          (isdigit(i) ? TK_VAL :
184*b2ed49a5SDavid van Moolenbroek          (isspace(i) ? TK_SKIP :
185*b2ed49a5SDavid van Moolenbroek                                      TK_ERROR));
186*b2ed49a5SDavid van Moolenbroek 
187*b2ed49a5SDavid van Moolenbroek     scantable['+'] = TK_ADD;
188*b2ed49a5SDavid van Moolenbroek     scantable['-'] = TK_SUB;
189*b2ed49a5SDavid van Moolenbroek     scantable['*'] = TK_MUL;    /* also '**' = TK_POW */
190*b2ed49a5SDavid van Moolenbroek     scantable['/'] = TK_DIV;
191*b2ed49a5SDavid van Moolenbroek     scantable['%'] = TK_MOD;
192*b2ed49a5SDavid van Moolenbroek     scantable['$'] = TK_VAL;    /* '$' starts a hexadecimal value */
193*b2ed49a5SDavid van Moolenbroek     scantable['.'] = TK_VAL;    /* '.' starts a fractional value */
194*b2ed49a5SDavid van Moolenbroek     scantable['('] = TK_OPEN;
195*b2ed49a5SDavid van Moolenbroek     scantable[')'] = TK_CLOSE;
196*b2ed49a5SDavid van Moolenbroek     scantable[';'] = TK_BREAK;
197*b2ed49a5SDavid van Moolenbroek     scantable['='] = TK_ASSN; /* also '==' = TK_EQ */
198*b2ed49a5SDavid van Moolenbroek     scantable['~'] = TK_BNOT;
199*b2ed49a5SDavid van Moolenbroek     scantable['^'] = TK_BXOR;
200*b2ed49a5SDavid van Moolenbroek     scantable['&'] = TK_BAND; /* also '&&' = TK_AND */
201*b2ed49a5SDavid van Moolenbroek     scantable['|'] = TK_BOR;    /* also '||' = TK_OR */
202*b2ed49a5SDavid van Moolenbroek     scantable['!'] = TK_NOT;    /* also '!=' = TK_NE */
203*b2ed49a5SDavid van Moolenbroek     scantable['<'] = TK_LT;     /* also '<<' = TK_SHL, '<=' = TK_LE */
204*b2ed49a5SDavid van Moolenbroek     scantable['>'] = TK_GT;     /* also '>>' = TK_SHR, '>=' = TK_GE */
205*b2ed49a5SDavid van Moolenbroek     scantable['\''] = TK_VARQUOTE;
206*b2ed49a5SDavid van Moolenbroek 
207*b2ed49a5SDavid van Moolenbroek     scantable_ok = 1;
208*b2ed49a5SDavid van Moolenbroek }
209*b2ed49a5SDavid van Moolenbroek 
210*b2ed49a5SDavid van Moolenbroek #if !MEM_LOW_FOOTPRINT
211*b2ed49a5SDavid van Moolenbroek 
tokenize(struct memh * mh,char ** string,struct tok ** listptr)212*b2ed49a5SDavid van Moolenbroek int tokenize(struct memh *mh, char **string, struct tok **listptr) {
213*b2ed49a5SDavid van Moolenbroek     struct tok *list;
214*b2ed49a5SDavid van Moolenbroek     int idx = 0, i, len;
215*b2ed49a5SDavid van Moolenbroek     char *s, *name, c, c2, nt;
216*b2ed49a5SDavid van Moolenbroek 
217*b2ed49a5SDavid van Moolenbroek     /* allocate a block of memory to hold the maximum amount of tokens */
218*b2ed49a5SDavid van Moolenbroek     i = strlen(*string) + 1;
219*b2ed49a5SDavid van Moolenbroek     list = (struct tok *) mem_alloc(mh, i * sizeof(struct tok));
220*b2ed49a5SDavid van Moolenbroek     if (!list) return ERROR_NOMEM;
221*b2ed49a5SDavid van Moolenbroek 
222*b2ed49a5SDavid van Moolenbroek     for (s = *string; *s; s++) {
223*b2ed49a5SDavid van Moolenbroek         /* get token type of character and store into list */
224*b2ed49a5SDavid van Moolenbroek         c = list[idx].token = scantable[* (unsigned char *) s];
225*b2ed49a5SDavid van Moolenbroek 
226*b2ed49a5SDavid van Moolenbroek #if TOKEN_DEBUG
227*b2ed49a5SDavid van Moolenbroek          printf("tokenize: token %p code %d string %s\n", &list[idx], list[idx].token, s);
228*b2ed49a5SDavid van Moolenbroek #endif
229*b2ed49a5SDavid van Moolenbroek 
230*b2ed49a5SDavid van Moolenbroek         /* break out of the for loop on TK_BREAK */
231*b2ed49a5SDavid van Moolenbroek         if (c == TK_BREAK) { s++; break; }
232*b2ed49a5SDavid van Moolenbroek 
233*b2ed49a5SDavid van Moolenbroek         switch (c) {
234*b2ed49a5SDavid van Moolenbroek         case TK_ERROR:
235*b2ed49a5SDavid van Moolenbroek             return ERROR_SYNTAX;
236*b2ed49a5SDavid van Moolenbroek 
237*b2ed49a5SDavid van Moolenbroek         case TK_SKIP:
238*b2ed49a5SDavid van Moolenbroek             break;
239*b2ed49a5SDavid van Moolenbroek 
240*b2ed49a5SDavid van Moolenbroek         /* most symbol-tokens fall under this one - nothing much to do */
241*b2ed49a5SDavid van Moolenbroek         case TK_OPEN: case TK_CLOSE: case TK_ADD: case TK_SUB:
242*b2ed49a5SDavid van Moolenbroek         case TK_MUL: case TK_DIV: case TK_MOD: case TK_BAND: case TK_BOR:
243*b2ed49a5SDavid van Moolenbroek         case TK_BXOR: case TK_BNOT: case TK_NOT: case TK_LT: case TK_GT:
244*b2ed49a5SDavid van Moolenbroek 
245*b2ed49a5SDavid van Moolenbroek             /* check for 'double character' tokens */
246*b2ed49a5SDavid van Moolenbroek             c2 = s[1];
247*b2ed49a5SDavid van Moolenbroek             nt = 0;
248*b2ed49a5SDavid van Moolenbroek             if (c == TK_MUL  && c2 == '*') nt = TK_POW;
249*b2ed49a5SDavid van Moolenbroek             if (c == TK_BAND && c2 == '&') nt = TK_AND;
250*b2ed49a5SDavid van Moolenbroek             if (c == TK_BOR  && c2 == '|') nt = TK_OR;
251*b2ed49a5SDavid van Moolenbroek             if (c == TK_NOT  && c2 == '=') nt = TK_NE;
252*b2ed49a5SDavid van Moolenbroek             if (c == TK_LT   && c2 == '=') nt = TK_LE;
253*b2ed49a5SDavid van Moolenbroek             if (c == TK_LT   && c2 == '<') nt = TK_SHL;
254*b2ed49a5SDavid van Moolenbroek             if (c == TK_GT   && c2 == '=') nt = TK_GE;
255*b2ed49a5SDavid van Moolenbroek             if (c == TK_GT   && c2 == '>') nt = TK_SHR;
256*b2ed49a5SDavid van Moolenbroek             if (nt) { list[idx].token = nt; s++; }
257*b2ed49a5SDavid van Moolenbroek 
258*b2ed49a5SDavid van Moolenbroek             idx++;
259*b2ed49a5SDavid van Moolenbroek             break;
260*b2ed49a5SDavid van Moolenbroek 
261*b2ed49a5SDavid van Moolenbroek         case TK_ASSN:
262*b2ed49a5SDavid van Moolenbroek             /* '=' = TK_ASSN, '==' = TK_EQ */
263*b2ed49a5SDavid van Moolenbroek             if (s[1] == '=') { list[idx++].token = TK_EQ; s++; break; }
264*b2ed49a5SDavid van Moolenbroek 
265*b2ed49a5SDavid van Moolenbroek             /* if the last token was a variable, change it to an assignment */
266*b2ed49a5SDavid van Moolenbroek             if (idx <= 0 || list[idx-1].token != TK_VAR) return ERROR_SYNTAX;
267*b2ed49a5SDavid van Moolenbroek             list[idx-1].token = TK_ASSN;
268*b2ed49a5SDavid van Moolenbroek             break;
269*b2ed49a5SDavid van Moolenbroek 
270*b2ed49a5SDavid van Moolenbroek         case TK_VAL:
271*b2ed49a5SDavid van Moolenbroek             if (!scan_number(&s, &list[idx++].val)) return ERROR_SYNTAX;
272*b2ed49a5SDavid van Moolenbroek             s--; /* wind back one for the loop's iterator */
273*b2ed49a5SDavid van Moolenbroek             break;
274*b2ed49a5SDavid van Moolenbroek 
275*b2ed49a5SDavid van Moolenbroek         case TK_VAR:
276*b2ed49a5SDavid van Moolenbroek         case TK_VARQUOTE:
277*b2ed49a5SDavid van Moolenbroek             if(c == TK_VAR) {
278*b2ed49a5SDavid van Moolenbroek                     list[idx].name = name = s;
279*b2ed49a5SDavid van Moolenbroek                     c2 = scantable[(int)s[1]];
280*b2ed49a5SDavid van Moolenbroek                     while (c2 == TK_VAR || c2 == TK_VAL) {
281*b2ed49a5SDavid van Moolenbroek                             s++; /* skip to end of string */
282*b2ed49a5SDavid van Moolenbroek                             c2 = scantable[(int)s[1]];
283*b2ed49a5SDavid van Moolenbroek                     }
284*b2ed49a5SDavid van Moolenbroek             }
285*b2ed49a5SDavid van Moolenbroek             else {
286*b2ed49a5SDavid van Moolenbroek                     if(!s[1] || scantable[(int)s[1]] == TK_VARQUOTE) {
287*b2ed49a5SDavid van Moolenbroek                             return ERROR_SYNTAX;
288*b2ed49a5SDavid van Moolenbroek                     }
289*b2ed49a5SDavid van Moolenbroek                     list[idx].token = TK_VAR;
290*b2ed49a5SDavid van Moolenbroek                     list[idx].name = name = ++s;
291*b2ed49a5SDavid van Moolenbroek                     while (s[1] && scantable[(int)s[1]] != TK_VARQUOTE) s++; /* skip to end of string */
292*b2ed49a5SDavid van Moolenbroek                     if(!s[1]) {
293*b2ed49a5SDavid van Moolenbroek                             return ERROR_SYNTAX;
294*b2ed49a5SDavid van Moolenbroek                     }
295*b2ed49a5SDavid van Moolenbroek             }
296*b2ed49a5SDavid van Moolenbroek             list[idx].name_end = s+1;
297*b2ed49a5SDavid van Moolenbroek             len = s+1 - name;
298*b2ed49a5SDavid van Moolenbroek             if(c == TK_VARQUOTE) {
299*b2ed49a5SDavid van Moolenbroek                     s++;
300*b2ed49a5SDavid van Moolenbroek             }
301*b2ed49a5SDavid van Moolenbroek 
302*b2ed49a5SDavid van Moolenbroek             if(scantable[(int)s[1]] == TK_OPEN) {
303*b2ed49a5SDavid van Moolenbroek                     list[idx].token  = TK_FUNC;
304*b2ed49a5SDavid van Moolenbroek                     list[idx].funcid = 0;
305*b2ed49a5SDavid van Moolenbroek                     /* look for matching function */
306*b2ed49a5SDavid van Moolenbroek                     for (i = 0; functable[i]; i++) {
307*b2ed49a5SDavid van Moolenbroek                         char *fname = functable[i];
308*b2ed49a5SDavid van Moolenbroek                         if (same_str_len(name, fname, len) && strlen(fname) == len) {
309*b2ed49a5SDavid van Moolenbroek                             list[idx].funcid = i+1;
310*b2ed49a5SDavid van Moolenbroek                             break;
311*b2ed49a5SDavid van Moolenbroek                         }
312*b2ed49a5SDavid van Moolenbroek                     }
313*b2ed49a5SDavid van Moolenbroek             }
314*b2ed49a5SDavid van Moolenbroek             idx++;
315*b2ed49a5SDavid van Moolenbroek             break;
316*b2ed49a5SDavid van Moolenbroek         }
317*b2ed49a5SDavid van Moolenbroek     }
318*b2ed49a5SDavid van Moolenbroek 
319*b2ed49a5SDavid van Moolenbroek     /* write back the final position of the tokenizer - either pointing at
320*b2ed49a5SDavid van Moolenbroek      * a null character, or the next expression to go */
321*b2ed49a5SDavid van Moolenbroek     *string = s;
322*b2ed49a5SDavid van Moolenbroek 
323*b2ed49a5SDavid van Moolenbroek     /* lace up the tokens and null-terminate the strings */
324*b2ed49a5SDavid van Moolenbroek     if (idx > 0) {
325*b2ed49a5SDavid van Moolenbroek         for (i = 0; i < idx; i++) {
326*b2ed49a5SDavid van Moolenbroek             list[i].next = &list[i+1];
327*b2ed49a5SDavid van Moolenbroek #if TOKEN_DEBUG
328*b2ed49a5SDavid van Moolenbroek             printf("tokenize: processed token %p code %d\n", &list[i], list[i].token);
329*b2ed49a5SDavid van Moolenbroek #endif
330*b2ed49a5SDavid van Moolenbroek             if (list[i].token == TK_VAR || list[i].token == TK_ASSN || list[i].token == TK_FUNC)
331*b2ed49a5SDavid van Moolenbroek                 *(list[i].name_end) = '\0';
332*b2ed49a5SDavid van Moolenbroek         }
333*b2ed49a5SDavid van Moolenbroek         list[idx-1].next = NULL;
334*b2ed49a5SDavid van Moolenbroek         *listptr = list;
335*b2ed49a5SDavid van Moolenbroek     }
336*b2ed49a5SDavid van Moolenbroek     else {
337*b2ed49a5SDavid van Moolenbroek         *listptr = NULL;
338*b2ed49a5SDavid van Moolenbroek     }
339*b2ed49a5SDavid van Moolenbroek 
340*b2ed49a5SDavid van Moolenbroek     return RESULT_OK;
341*b2ed49a5SDavid van Moolenbroek }
342*b2ed49a5SDavid van Moolenbroek 
343*b2ed49a5SDavid van Moolenbroek #else
344*b2ed49a5SDavid van Moolenbroek 
tokenize(struct memh * mh,char ** string,struct tok ** listptr)345*b2ed49a5SDavid van Moolenbroek int tokenize(struct memh *mh, char **string, struct tok **listptr) {
346*b2ed49a5SDavid van Moolenbroek     struct tok *tok = NULL, *last_tok = NULL;
347*b2ed49a5SDavid van Moolenbroek     int idx = 0, i, len;
348*b2ed49a5SDavid van Moolenbroek     char *s, *name, c, c2, nt;
349*b2ed49a5SDavid van Moolenbroek     int skip_alloc = 0;
350*b2ed49a5SDavid van Moolenbroek 
351*b2ed49a5SDavid van Moolenbroek     for (s = *string; *s; s++) {
352*b2ed49a5SDavid van Moolenbroek         /* get token type of character and store into list */
353*b2ed49a5SDavid van Moolenbroek         c = scantable[* (unsigned char *) s];
354*b2ed49a5SDavid van Moolenbroek 
355*b2ed49a5SDavid van Moolenbroek         /* break out of the for loop on TK_BREAK */
356*b2ed49a5SDavid van Moolenbroek         if(c == TK_BREAK) { s++; break; }
357*b2ed49a5SDavid van Moolenbroek         if(c == TK_ERROR) return ERROR_SYNTAX;
358*b2ed49a5SDavid van Moolenbroek 
359*b2ed49a5SDavid van Moolenbroek         if(c == TK_SKIP) continue;
360*b2ed49a5SDavid van Moolenbroek 
361*b2ed49a5SDavid van Moolenbroek         if(!skip_alloc) {
362*b2ed49a5SDavid van Moolenbroek                 size_t tok_size;
363*b2ed49a5SDavid van Moolenbroek                 last_tok = tok;
364*b2ed49a5SDavid van Moolenbroek                 switch(c) {
365*b2ed49a5SDavid van Moolenbroek                         case TK_VAL:
366*b2ed49a5SDavid van Moolenbroek                                 tok_size = VAL_TOK_SIZE();
367*b2ed49a5SDavid van Moolenbroek                         break;
368*b2ed49a5SDavid van Moolenbroek                         case TK_VAR:
369*b2ed49a5SDavid van Moolenbroek                         case TK_VARQUOTE:
370*b2ed49a5SDavid van Moolenbroek                         case TK_ASSN:
371*b2ed49a5SDavid van Moolenbroek                                 tok_size = VAR_TOK_SIZE();
372*b2ed49a5SDavid van Moolenbroek                         break;
373*b2ed49a5SDavid van Moolenbroek                         default:
374*b2ed49a5SDavid van Moolenbroek                                 tok_size = REG_TOK_SIZE();
375*b2ed49a5SDavid van Moolenbroek                         break;
376*b2ed49a5SDavid van Moolenbroek                 }
377*b2ed49a5SDavid van Moolenbroek                 tok = (struct tok *) mem_alloc(mh, tok_size);
378*b2ed49a5SDavid van Moolenbroek                 if(!tok) return ERROR_NOMEM;
379*b2ed49a5SDavid van Moolenbroek                 tok->next = NULL;
380*b2ed49a5SDavid van Moolenbroek                 if(last_tok) {
381*b2ed49a5SDavid van Moolenbroek                         last_tok->next = tok;
382*b2ed49a5SDavid van Moolenbroek                 }
383*b2ed49a5SDavid van Moolenbroek                 else {
384*b2ed49a5SDavid van Moolenbroek                         *listptr = tok;
385*b2ed49a5SDavid van Moolenbroek                 }
386*b2ed49a5SDavid van Moolenbroek         }
387*b2ed49a5SDavid van Moolenbroek         else {
388*b2ed49a5SDavid van Moolenbroek                 skip_alloc = 0;
389*b2ed49a5SDavid van Moolenbroek         }
390*b2ed49a5SDavid van Moolenbroek         tok->token = c;
391*b2ed49a5SDavid van Moolenbroek 
392*b2ed49a5SDavid van Moolenbroek #if TOKEN_DEBUG
393*b2ed49a5SDavid van Moolenbroek         printf("tokenize: token %p code %d string %s\n", tok, tok->token, s);
394*b2ed49a5SDavid van Moolenbroek #endif
395*b2ed49a5SDavid van Moolenbroek 
396*b2ed49a5SDavid van Moolenbroek         switch (c) {
397*b2ed49a5SDavid van Moolenbroek 
398*b2ed49a5SDavid van Moolenbroek         /* most symbol-tokens fall under this one - nothing much to do */
399*b2ed49a5SDavid van Moolenbroek         case TK_OPEN: case TK_CLOSE: case TK_ADD: case TK_SUB:
400*b2ed49a5SDavid van Moolenbroek         case TK_MUL: case TK_DIV: case TK_MOD: case TK_BAND: case TK_BOR:
401*b2ed49a5SDavid van Moolenbroek         case TK_BXOR: case TK_BNOT: case TK_NOT: case TK_LT: case TK_GT:
402*b2ed49a5SDavid van Moolenbroek 
403*b2ed49a5SDavid van Moolenbroek             /* check for 'double character' tokens */
404*b2ed49a5SDavid van Moolenbroek             c2 = s[1];
405*b2ed49a5SDavid van Moolenbroek             nt = 0;
406*b2ed49a5SDavid van Moolenbroek             if (c == TK_MUL  && c2 == '*') nt = TK_POW;
407*b2ed49a5SDavid van Moolenbroek             if (c == TK_BAND && c2 == '&') nt = TK_AND;
408*b2ed49a5SDavid van Moolenbroek             if (c == TK_BOR  && c2 == '|') nt = TK_OR;
409*b2ed49a5SDavid van Moolenbroek             if (c == TK_NOT  && c2 == '=') nt = TK_NE;
410*b2ed49a5SDavid van Moolenbroek             if (c == TK_LT   && c2 == '=') nt = TK_LE;
411*b2ed49a5SDavid van Moolenbroek             if (c == TK_LT   && c2 == '<') nt = TK_SHL;
412*b2ed49a5SDavid van Moolenbroek             if (c == TK_GT   && c2 == '=') nt = TK_GE;
413*b2ed49a5SDavid van Moolenbroek             if (c == TK_GT   && c2 == '>') nt = TK_SHR;
414*b2ed49a5SDavid van Moolenbroek             if (nt) { tok->token = nt; s++; }
415*b2ed49a5SDavid van Moolenbroek 
416*b2ed49a5SDavid van Moolenbroek             idx++;
417*b2ed49a5SDavid van Moolenbroek             break;
418*b2ed49a5SDavid van Moolenbroek 
419*b2ed49a5SDavid van Moolenbroek         case TK_ASSN:
420*b2ed49a5SDavid van Moolenbroek             /* '=' = TK_ASSN, '==' = TK_EQ */
421*b2ed49a5SDavid van Moolenbroek             if (s[1] == '=') { tok->token = TK_EQ; idx++; s++; break; }
422*b2ed49a5SDavid van Moolenbroek 
423*b2ed49a5SDavid van Moolenbroek             /* if the last token was a variable, change it to an assignment */
424*b2ed49a5SDavid van Moolenbroek             if (idx <= 0 || last_tok->token != TK_VAR) return ERROR_SYNTAX;
425*b2ed49a5SDavid van Moolenbroek             last_tok->token = TK_ASSN;
426*b2ed49a5SDavid van Moolenbroek             skip_alloc = 1;
427*b2ed49a5SDavid van Moolenbroek             break;
428*b2ed49a5SDavid van Moolenbroek 
429*b2ed49a5SDavid van Moolenbroek         case TK_VAL:
430*b2ed49a5SDavid van Moolenbroek             if (!scan_number(&s, &tok->val)) return ERROR_SYNTAX;
431*b2ed49a5SDavid van Moolenbroek             idx++;
432*b2ed49a5SDavid van Moolenbroek             s--; /* wind back one for the loop's iterator */
433*b2ed49a5SDavid van Moolenbroek             break;
434*b2ed49a5SDavid van Moolenbroek 
435*b2ed49a5SDavid van Moolenbroek         case TK_VAR:
436*b2ed49a5SDavid van Moolenbroek         case TK_VARQUOTE:
437*b2ed49a5SDavid van Moolenbroek             if(c == TK_VAR) {
438*b2ed49a5SDavid van Moolenbroek                     tok->name = name = s;
439*b2ed49a5SDavid van Moolenbroek                     c2 = scantable[(int)s[1]];
440*b2ed49a5SDavid van Moolenbroek                     while (c2 == TK_VAR || c2 == TK_VAL) {
441*b2ed49a5SDavid van Moolenbroek                             s++; /* skip to end of string */
442*b2ed49a5SDavid van Moolenbroek                             c2 = scantable[(int)s[1]];
443*b2ed49a5SDavid van Moolenbroek                     }
444*b2ed49a5SDavid van Moolenbroek             }
445*b2ed49a5SDavid van Moolenbroek             else {
446*b2ed49a5SDavid van Moolenbroek                     if(!s[1] || scantable[(int)s[1]] == TK_VARQUOTE) {
447*b2ed49a5SDavid van Moolenbroek                             return ERROR_SYNTAX;
448*b2ed49a5SDavid van Moolenbroek                     }
449*b2ed49a5SDavid van Moolenbroek                     tok->token = TK_VAR;
450*b2ed49a5SDavid van Moolenbroek                     tok->name = name = ++s;
451*b2ed49a5SDavid van Moolenbroek                     while (s[1] && scantable[(int)s[1]] != TK_VARQUOTE) s++; /* skip to end of string */
452*b2ed49a5SDavid van Moolenbroek                     if(!s[1]) {
453*b2ed49a5SDavid van Moolenbroek                             return ERROR_SYNTAX;
454*b2ed49a5SDavid van Moolenbroek                     }
455*b2ed49a5SDavid van Moolenbroek             }
456*b2ed49a5SDavid van Moolenbroek             tok->name_end = s+1;
457*b2ed49a5SDavid van Moolenbroek             len = s+1 - name;
458*b2ed49a5SDavid van Moolenbroek             if(c == TK_VARQUOTE) {
459*b2ed49a5SDavid van Moolenbroek                     s++;
460*b2ed49a5SDavid van Moolenbroek             }
461*b2ed49a5SDavid van Moolenbroek 
462*b2ed49a5SDavid van Moolenbroek             if(scantable[(int)s[1]] == TK_OPEN) {
463*b2ed49a5SDavid van Moolenbroek                     tok->token  = TK_FUNC;
464*b2ed49a5SDavid van Moolenbroek                     tok->funcid = 0;
465*b2ed49a5SDavid van Moolenbroek                     /* look for matching function */
466*b2ed49a5SDavid van Moolenbroek                     for (i = 0; functable[i]; i++) {
467*b2ed49a5SDavid van Moolenbroek                         const char *fname = functable[i];
468*b2ed49a5SDavid van Moolenbroek                         if (same_str_len(name, fname, len) && strlen(fname) == (size_t)len) {
469*b2ed49a5SDavid van Moolenbroek                             tok->funcid = i+1;
470*b2ed49a5SDavid van Moolenbroek                             break;
471*b2ed49a5SDavid van Moolenbroek                         }
472*b2ed49a5SDavid van Moolenbroek                     }
473*b2ed49a5SDavid van Moolenbroek             }
474*b2ed49a5SDavid van Moolenbroek             idx++;
475*b2ed49a5SDavid van Moolenbroek             break;
476*b2ed49a5SDavid van Moolenbroek         }
477*b2ed49a5SDavid van Moolenbroek     }
478*b2ed49a5SDavid van Moolenbroek 
479*b2ed49a5SDavid van Moolenbroek     /* write back the final position of the tokenizer - either pointing at
480*b2ed49a5SDavid van Moolenbroek      * a null character, or the next expression to go */
481*b2ed49a5SDavid van Moolenbroek     *string = s;
482*b2ed49a5SDavid van Moolenbroek 
483*b2ed49a5SDavid van Moolenbroek     /* lace up the tokens and null-terminate the strings */
484*b2ed49a5SDavid van Moolenbroek     if (idx > 0) {
485*b2ed49a5SDavid van Moolenbroek         tok = *listptr;
486*b2ed49a5SDavid van Moolenbroek         do {
487*b2ed49a5SDavid van Moolenbroek #if TOKEN_DEBUG
488*b2ed49a5SDavid van Moolenbroek             printf("tokenize: processed token %p code %d\n", tok, tok->token);
489*b2ed49a5SDavid van Moolenbroek #endif
490*b2ed49a5SDavid van Moolenbroek             if (tok->token == TK_VAR || tok->token == TK_ASSN || tok->token == TK_FUNC)
491*b2ed49a5SDavid van Moolenbroek                 *(tok->name_end) = '\0';
492*b2ed49a5SDavid van Moolenbroek             tok = tok->next;
493*b2ed49a5SDavid van Moolenbroek         } while(tok);
494*b2ed49a5SDavid van Moolenbroek     }
495*b2ed49a5SDavid van Moolenbroek     else {
496*b2ed49a5SDavid van Moolenbroek         *listptr = NULL;
497*b2ed49a5SDavid van Moolenbroek     }
498*b2ed49a5SDavid van Moolenbroek 
499*b2ed49a5SDavid van Moolenbroek     return RESULT_OK;
500*b2ed49a5SDavid van Moolenbroek }
501*b2ed49a5SDavid van Moolenbroek 
502*b2ed49a5SDavid van Moolenbroek #endif
503*b2ed49a5SDavid van Moolenbroek 
504*b2ed49a5SDavid van Moolenbroek /* scans some text into a value */
scan_number(char ** stringptr,struct val * valptr)505*b2ed49a5SDavid van Moolenbroek int scan_number(char **stringptr, struct val *valptr) {
506*b2ed49a5SDavid van Moolenbroek     struct val v = { T_INT, 0, 0.0 };
507*b2ed49a5SDavid van Moolenbroek     char *s = *stringptr;
508*b2ed49a5SDavid van Moolenbroek     int c;
509*b2ed49a5SDavid van Moolenbroek     double dp;
510*b2ed49a5SDavid van Moolenbroek 
511*b2ed49a5SDavid van Moolenbroek     /* test to see if it's a hex number */
512*b2ed49a5SDavid van Moolenbroek     if (s[0] == '$' || (s[0] == '0' && s[1] == 'x')) {
513*b2ed49a5SDavid van Moolenbroek         s += (s[1] == 'x') ? 2 : 1;
514*b2ed49a5SDavid van Moolenbroek         *stringptr = s;
515*b2ed49a5SDavid van Moolenbroek 
516*b2ed49a5SDavid van Moolenbroek         for (; isxdigit(c = (int) *s); s++)
517*b2ed49a5SDavid van Moolenbroek             v.ival = (v.ival << 4)
518*b2ed49a5SDavid van Moolenbroek                 + (isdigit(c) ? c-'0'            : 0)
519*b2ed49a5SDavid van Moolenbroek                 + (isupper(c) ? c-'A' + 10 : 0)
520*b2ed49a5SDavid van Moolenbroek                 + (islower(c) ? c-'a' + 10 : 0);
521*b2ed49a5SDavid van Moolenbroek     }
522*b2ed49a5SDavid van Moolenbroek 
523*b2ed49a5SDavid van Moolenbroek     /* must be a decimal integer or real */
524*b2ed49a5SDavid van Moolenbroek     else {
525*b2ed49a5SDavid van Moolenbroek         for (; isdigit(c = (int) *s); s++) v.ival = (v.ival * 10) + c-'0';
526*b2ed49a5SDavid van Moolenbroek         if (*s == '.') {
527*b2ed49a5SDavid van Moolenbroek             *stringptr = ++s;
528*b2ed49a5SDavid van Moolenbroek             v.type = T_REAL;
529*b2ed49a5SDavid van Moolenbroek             v.rval = (double) v.ival;
530*b2ed49a5SDavid van Moolenbroek             for (dp = 0.1; isdigit(c = (int) *s); s++, dp /= 10.0)
531*b2ed49a5SDavid van Moolenbroek                 v.rval += dp * (double) (c-'0');
532*b2ed49a5SDavid van Moolenbroek         }
533*b2ed49a5SDavid van Moolenbroek     }
534*b2ed49a5SDavid van Moolenbroek 
535*b2ed49a5SDavid van Moolenbroek     /* if no numeric chars have been read, it's a dud - return FAIL */
536*b2ed49a5SDavid van Moolenbroek     if (s == *stringptr) return 0;
537*b2ed49a5SDavid van Moolenbroek 
538*b2ed49a5SDavid van Moolenbroek     /* otherwise, update position and return SUCCESS */
539*b2ed49a5SDavid van Moolenbroek     *stringptr = s;
540*b2ed49a5SDavid van Moolenbroek     *valptr = v;
541*b2ed49a5SDavid van Moolenbroek     return 1;
542*b2ed49a5SDavid van Moolenbroek }
543*b2ed49a5SDavid van Moolenbroek 
544*b2ed49a5SDavid van Moolenbroek 
545*b2ed49a5SDavid van Moolenbroek /*** EVALUATION ***/
546*b2ed49a5SDavid van Moolenbroek 
547*b2ed49a5SDavid van Moolenbroek /* returns the precedence of a token */
precedence(struct tok * t)548*b2ed49a5SDavid van Moolenbroek int precedence(struct tok *t) {
549*b2ed49a5SDavid van Moolenbroek     switch (t->token) {
550*b2ed49a5SDavid van Moolenbroek     case TK_FUNC:                                                                                                   return 15;
551*b2ed49a5SDavid van Moolenbroek     case TK_MULI:                           return 14;
552*b2ed49a5SDavid van Moolenbroek     case TK_NEG:    case TK_NOT:    case TK_BNOT:           return 13;
553*b2ed49a5SDavid van Moolenbroek     case TK_POW:                            return 12;
554*b2ed49a5SDavid van Moolenbroek     case TK_MUL:    case TK_DIV:    case TK_MOD:            return 11;
555*b2ed49a5SDavid van Moolenbroek     case TK_ADD:    case TK_SUB:                    return 10;
556*b2ed49a5SDavid van Moolenbroek     case TK_SHL:    case TK_SHR:                    return 9;
557*b2ed49a5SDavid van Moolenbroek     case TK_LT: case TK_GT: case TK_LE: case TK_GE: return 8;
558*b2ed49a5SDavid van Moolenbroek     case TK_EQ: case TK_NE:                 return 7;
559*b2ed49a5SDavid van Moolenbroek     case TK_BAND:                           return 6;
560*b2ed49a5SDavid van Moolenbroek     case TK_BOR:    case TK_BXOR:                   return 5;
561*b2ed49a5SDavid van Moolenbroek     case TK_AND:    case TK_OR:                 return 4;
562*b2ed49a5SDavid van Moolenbroek     case TK_ASSN:                           return 3;
563*b2ed49a5SDavid van Moolenbroek     case TK_CLOSE:                                  return 2;
564*b2ed49a5SDavid van Moolenbroek     case TK_OPEN:                           return 1;
565*b2ed49a5SDavid van Moolenbroek     }
566*b2ed49a5SDavid van Moolenbroek     return 0;
567*b2ed49a5SDavid van Moolenbroek }
568*b2ed49a5SDavid van Moolenbroek 
569*b2ed49a5SDavid van Moolenbroek 
eval(struct memh * mh,struct tok * list,struct vartable * vt,struct val * result)570*b2ed49a5SDavid van Moolenbroek int eval(struct memh *mh, struct tok *list, struct vartable *vt,
571*b2ed49a5SDavid van Moolenbroek     struct val *result) {
572*b2ed49a5SDavid van Moolenbroek 
573*b2ed49a5SDavid van Moolenbroek     static struct val newval = { T_INT, 0, 0.0 };
574*b2ed49a5SDavid van Moolenbroek 
575*b2ed49a5SDavid van Moolenbroek     struct val tmp_val, *valstk, *x, *y;
576*b2ed49a5SDavid van Moolenbroek     struct tok open, close, *l, *r, *t, **opstk;
577*b2ed49a5SDavid van Moolenbroek     char lt, rt, token;
578*b2ed49a5SDavid van Moolenbroek     int vstk, ostk, vcnt = 0, ocnt = 0;
579*b2ed49a5SDavid van Moolenbroek     double xr, yr, rr = 0;
580*b2ed49a5SDavid van Moolenbroek     long xi, yi, ri = 0;
581*b2ed49a5SDavid van Moolenbroek #if VAR_FROM_ENV
582*b2ed49a5SDavid van Moolenbroek     char *envtxt;
583*b2ed49a5SDavid van Moolenbroek #endif
584*b2ed49a5SDavid van Moolenbroek 
585*b2ed49a5SDavid van Moolenbroek     /* clear result before we do anything - and no tokens is no result */
586*b2ed49a5SDavid van Moolenbroek     *result = newval;
587*b2ed49a5SDavid van Moolenbroek     if (!list) return RESULT_OK;
588*b2ed49a5SDavid van Moolenbroek 
589*b2ed49a5SDavid van Moolenbroek 
590*b2ed49a5SDavid van Moolenbroek     /* CONVERSION OF RAW TOKENS INTO COMPLETE INFIX EXPRESSION */
591*b2ed49a5SDavid van Moolenbroek 
592*b2ed49a5SDavid van Moolenbroek     /* wrap the token list in a pair of parentheses */
593*b2ed49a5SDavid van Moolenbroek     for (t = list; t->next; t = t->next)
594*b2ed49a5SDavid van Moolenbroek             ;
595*b2ed49a5SDavid van Moolenbroek     t->next = &close;
596*b2ed49a5SDavid van Moolenbroek     close.next = NULL; open.next = list; list = &open;
597*b2ed49a5SDavid van Moolenbroek     close.token = TK_CLOSE; open.token  = TK_OPEN;
598*b2ed49a5SDavid van Moolenbroek 
599*b2ed49a5SDavid van Moolenbroek     /* insert and change tokens as neccessary */
600*b2ed49a5SDavid van Moolenbroek     for (l=list, r=l->next; r->next; l=r, r=r->next) {
601*b2ed49a5SDavid van Moolenbroek         lt = l->token;
602*b2ed49a5SDavid van Moolenbroek         rt = r->token;
603*b2ed49a5SDavid van Moolenbroek 
604*b2ed49a5SDavid van Moolenbroek         /* convert TK_SUBs that should be unary into TK_NEGs */
605*b2ed49a5SDavid van Moolenbroek         if (rt == TK_SUB && lt != TK_CLOSE && lt != TK_VAR && lt != TK_VAL)
606*b2ed49a5SDavid van Moolenbroek             r->token = TK_NEG;
607*b2ed49a5SDavid van Moolenbroek 
608*b2ed49a5SDavid van Moolenbroek         /* insert implicit multiplication tokens */
609*b2ed49a5SDavid van Moolenbroek         if ((lt == TK_VAR || lt == TK_VAL || lt == TK_CLOSE)
610*b2ed49a5SDavid van Moolenbroek         && (rt == TK_VAR || rt == TK_VAL || rt == TK_OPEN || rt == TK_FUNC)) {
611*b2ed49a5SDavid van Moolenbroek             if (lt == rt) return ERROR_SYNTAX;
612*b2ed49a5SDavid van Moolenbroek             t = (struct tok *) mem_alloc(mh, sizeof(struct tok));
613*b2ed49a5SDavid van Moolenbroek             if (!t) return ERROR_NOMEM;
614*b2ed49a5SDavid van Moolenbroek             t->token = TK_MULI; l->next = t; t->next = r;
615*b2ed49a5SDavid van Moolenbroek         }
616*b2ed49a5SDavid van Moolenbroek     }
617*b2ed49a5SDavid van Moolenbroek 
618*b2ed49a5SDavid van Moolenbroek     /* VARIABLE CHECKING */
619*b2ed49a5SDavid van Moolenbroek 
620*b2ed49a5SDavid van Moolenbroek     vcnt = ocnt = 0;
621*b2ed49a5SDavid van Moolenbroek     for (t = list; t; t = t->next) {
622*b2ed49a5SDavid van Moolenbroek         lt = t->token;
623*b2ed49a5SDavid van Moolenbroek 
624*b2ed49a5SDavid van Moolenbroek         /* count the number of values and operators */
625*b2ed49a5SDavid van Moolenbroek         if (lt == TK_VAR || lt == TK_VAL) vcnt++; else ocnt++;
626*b2ed49a5SDavid van Moolenbroek 
627*b2ed49a5SDavid van Moolenbroek         /* if assigned variables don't exist, create a new blank one */
628*b2ed49a5SDavid van Moolenbroek         if (lt == TK_ASSN) {
629*b2ed49a5SDavid van Moolenbroek             if (!(t->var = get_var(vt, t->name)))
630*b2ed49a5SDavid van Moolenbroek                 if (!(t->var = put_var(vt, t->name, &newval)))
631*b2ed49a5SDavid van Moolenbroek                     return ERROR_NOMEM;
632*b2ed49a5SDavid van Moolenbroek         }
633*b2ed49a5SDavid van Moolenbroek 
634*b2ed49a5SDavid van Moolenbroek         /* try to get vars from vartable - if not, try the environment */
635*b2ed49a5SDavid van Moolenbroek         else if (lt == TK_VAR) {
636*b2ed49a5SDavid van Moolenbroek             int var_found = 0;
637*b2ed49a5SDavid van Moolenbroek             if ((t->var = get_var(vt, t->name))) {
638*b2ed49a5SDavid van Moolenbroek                     var_found = 1;
639*b2ed49a5SDavid van Moolenbroek             }
640*b2ed49a5SDavid van Moolenbroek #if VAR_FROM_ENV
641*b2ed49a5SDavid van Moolenbroek             if(!var_found && (envtxt = getenv(t->name))) {
642*b2ed49a5SDavid van Moolenbroek                     if (!scan_number(&envtxt, &tmp_val)) return ERROR_SYNTAX;
643*b2ed49a5SDavid van Moolenbroek                     if (!(t->var = put_var(vt, t->name, &tmp_val))) return ERROR_NOMEM;
644*b2ed49a5SDavid van Moolenbroek                     var_found = 1;
645*b2ed49a5SDavid van Moolenbroek             }
646*b2ed49a5SDavid van Moolenbroek #endif
647*b2ed49a5SDavid van Moolenbroek             if(!var_found && get_var_cb && (get_var_cb(t->name, &tmp_val))) {
648*b2ed49a5SDavid van Moolenbroek                     if (!(t->var = put_var(vt, t->name, &tmp_val))) return ERROR_NOMEM;
649*b2ed49a5SDavid van Moolenbroek                     var_found = 1;
650*b2ed49a5SDavid van Moolenbroek             }
651*b2ed49a5SDavid van Moolenbroek             if(!var_found) {
652*b2ed49a5SDavid van Moolenbroek                     return ERROR_VARNOTFOUND;
653*b2ed49a5SDavid van Moolenbroek             }
654*b2ed49a5SDavid van Moolenbroek         }
655*b2ed49a5SDavid van Moolenbroek     }
656*b2ed49a5SDavid van Moolenbroek 
657*b2ed49a5SDavid van Moolenbroek     /* ALLOCATE STACKS */
658*b2ed49a5SDavid van Moolenbroek 
659*b2ed49a5SDavid van Moolenbroek     /* allocate the operator stack and the value stack */
660*b2ed49a5SDavid van Moolenbroek     valstk = (struct val *)  mem_alloc(mh, vcnt * sizeof(struct val));
661*b2ed49a5SDavid van Moolenbroek     opstk  = (struct tok **) mem_alloc(mh, ocnt * sizeof(struct tok *));
662*b2ed49a5SDavid van Moolenbroek     if (!valstk || !opstk) return ERROR_NOMEM;
663*b2ed49a5SDavid van Moolenbroek 
664*b2ed49a5SDavid van Moolenbroek     /* set the stack pointers to '0 items on stack' */
665*b2ed49a5SDavid van Moolenbroek     /* (the stack pointers are always set at the topmost stack item) */
666*b2ed49a5SDavid van Moolenbroek     ostk = vstk = -1;
667*b2ed49a5SDavid van Moolenbroek 
668*b2ed49a5SDavid van Moolenbroek     /* MAIN EVALUATION LOOP */
669*b2ed49a5SDavid van Moolenbroek     prt_lst(list);
670*b2ed49a5SDavid van Moolenbroek     for (t = list; t; t=t->next) {
671*b2ed49a5SDavid van Moolenbroek         switch (t->token) {
672*b2ed49a5SDavid van Moolenbroek 
673*b2ed49a5SDavid van Moolenbroek         /* unary operators always wait until after what follows is evaluated */
674*b2ed49a5SDavid van Moolenbroek         /* also, open parentheses are pushed to match where close ones stop */
675*b2ed49a5SDavid van Moolenbroek         case TK_OPEN:
676*b2ed49a5SDavid van Moolenbroek         case TK_ASSN: case TK_NEG: case TK_FUNC: case TK_NOT: case TK_BNOT:
677*b2ed49a5SDavid van Moolenbroek             opstk[++ostk] = t; break;
678*b2ed49a5SDavid van Moolenbroek 
679*b2ed49a5SDavid van Moolenbroek         /* values go straight on the value stack */
680*b2ed49a5SDavid van Moolenbroek         case TK_VAL:
681*b2ed49a5SDavid van Moolenbroek             valstk[++vstk] = t->val;
682*b2ed49a5SDavid van Moolenbroek             break;
683*b2ed49a5SDavid van Moolenbroek 
684*b2ed49a5SDavid van Moolenbroek         /* variables go straight on the value stack */
685*b2ed49a5SDavid van Moolenbroek         case TK_VAR:
686*b2ed49a5SDavid van Moolenbroek             valstk[++vstk] = t->var->val;
687*b2ed49a5SDavid van Moolenbroek             break;
688*b2ed49a5SDavid van Moolenbroek 
689*b2ed49a5SDavid van Moolenbroek         /* this is where the action happens - all operations of a higher or same
690*b2ed49a5SDavid van Moolenbroek          * precedence are now executed. then, after that, we push the operator
691*b2ed49a5SDavid van Moolenbroek          * to the stack, or if it's a close paren, pull and expect an open paren
692*b2ed49a5SDavid van Moolenbroek          *
693*b2ed49a5SDavid van Moolenbroek          * it's assumed that all tokens in the token stream that aren't one of
694*b2ed49a5SDavid van Moolenbroek          * the previous cases must be the close bracket or a binary operator -
695*b2ed49a5SDavid van Moolenbroek          * that's why 'default' is used rather than all the names
696*b2ed49a5SDavid van Moolenbroek          */
697*b2ed49a5SDavid van Moolenbroek         default:
698*b2ed49a5SDavid van Moolenbroek             while (precedence(opstk[ostk]) >= precedence(t)) {
699*b2ed49a5SDavid van Moolenbroek                 struct tok *op = opstk[ostk--];
700*b2ed49a5SDavid van Moolenbroek #if EVAL_DEBUG
701*b2ed49a5SDavid van Moolenbroek                 printf("eval: "); prt_tok(op); printf("\n");
702*b2ed49a5SDavid van Moolenbroek #endif
703*b2ed49a5SDavid van Moolenbroek 
704*b2ed49a5SDavid van Moolenbroek                 /* there should always be at least a close bracket left here */
705*b2ed49a5SDavid van Moolenbroek                 if (ostk < 0) return ERROR_SYNTAX;
706*b2ed49a5SDavid van Moolenbroek 
707*b2ed49a5SDavid van Moolenbroek                 /* we assume that all operators require at least one value */
708*b2ed49a5SDavid van Moolenbroek                 /* on the stack, and check here */
709*b2ed49a5SDavid van Moolenbroek                 if (vstk < 0) return ERROR_SYNTAX;
710*b2ed49a5SDavid van Moolenbroek 
711*b2ed49a5SDavid van Moolenbroek                 /* now we actually perform evaluations */
712*b2ed49a5SDavid van Moolenbroek                 switch (token = op->token) {
713*b2ed49a5SDavid van Moolenbroek 
714*b2ed49a5SDavid van Moolenbroek                 /* binary (int/real) -> (int/real) */
715*b2ed49a5SDavid van Moolenbroek                 case TK_ADD: case TK_SUB: case TK_MUL: case TK_MULI:
716*b2ed49a5SDavid van Moolenbroek 
717*b2ed49a5SDavid van Moolenbroek                     /* pull two values from the stack, y then x, and push 'x op y' */
718*b2ed49a5SDavid van Moolenbroek                     if (vstk < 1) return ERROR_SYNTAX;
719*b2ed49a5SDavid van Moolenbroek                     y = &valstk[vstk--]; x = &valstk[vstk];
720*b2ed49a5SDavid van Moolenbroek 
721*b2ed49a5SDavid van Moolenbroek                     /* if both values are integer, do integer operations only */
722*b2ed49a5SDavid van Moolenbroek                     if (x->type == T_INT && y->type == T_INT) {
723*b2ed49a5SDavid van Moolenbroek                         xi = x->ival;
724*b2ed49a5SDavid van Moolenbroek                         yi = y->ival;
725*b2ed49a5SDavid van Moolenbroek                         switch (token) {
726*b2ed49a5SDavid van Moolenbroek                         case TK_MULI:
727*b2ed49a5SDavid van Moolenbroek                         case TK_MUL: ri = (xi * yi); break;
728*b2ed49a5SDavid van Moolenbroek                         case TK_ADD: ri = (xi + yi); break;
729*b2ed49a5SDavid van Moolenbroek                         case TK_SUB: ri = (xi - yi); break;
730*b2ed49a5SDavid van Moolenbroek                         }
731*b2ed49a5SDavid van Moolenbroek                         /* push int-value result to value stack */
732*b2ed49a5SDavid van Moolenbroek                         x->type = T_INT;
733*b2ed49a5SDavid van Moolenbroek                         x->ival = ri;
734*b2ed49a5SDavid van Moolenbroek                     }
735*b2ed49a5SDavid van Moolenbroek                     else {
736*b2ed49a5SDavid van Moolenbroek                         /* get real values - convert if neccessary */
737*b2ed49a5SDavid van Moolenbroek                         xr = (x->type == T_REAL) ? x->rval : (double) x->ival;
738*b2ed49a5SDavid van Moolenbroek                         yr = (y->type == T_REAL) ? y->rval : (double) y->ival;
739*b2ed49a5SDavid van Moolenbroek 
740*b2ed49a5SDavid van Moolenbroek                         switch (token) {
741*b2ed49a5SDavid van Moolenbroek                         case TK_MULI:
742*b2ed49a5SDavid van Moolenbroek                         case TK_MUL: rr = (xr * yr); break;
743*b2ed49a5SDavid van Moolenbroek                         case TK_ADD: rr = (xr + yr); break;
744*b2ed49a5SDavid van Moolenbroek                         case TK_SUB: rr = (xr - yr); break;
745*b2ed49a5SDavid van Moolenbroek                         }
746*b2ed49a5SDavid van Moolenbroek                         /* push real-value result to value stack */
747*b2ed49a5SDavid van Moolenbroek                         x->type = T_REAL;
748*b2ed49a5SDavid van Moolenbroek                         x->rval = rr;
749*b2ed49a5SDavid van Moolenbroek                     }
750*b2ed49a5SDavid van Moolenbroek                     break;
751*b2ed49a5SDavid van Moolenbroek 
752*b2ed49a5SDavid van Moolenbroek 
753*b2ed49a5SDavid van Moolenbroek 
754*b2ed49a5SDavid van Moolenbroek                 /* binary (int/real) -> int */
755*b2ed49a5SDavid van Moolenbroek                 case TK_EQ: case TK_NE: case TK_LT:
756*b2ed49a5SDavid van Moolenbroek                 case TK_GT: case TK_LE: case TK_GE:
757*b2ed49a5SDavid van Moolenbroek 
758*b2ed49a5SDavid van Moolenbroek                     if (vstk < 1) return ERROR_SYNTAX;
759*b2ed49a5SDavid van Moolenbroek                     y = &valstk[vstk--]; x = &valstk[vstk];
760*b2ed49a5SDavid van Moolenbroek 
761*b2ed49a5SDavid van Moolenbroek                     if (x->type == T_INT && y->type == T_INT) {
762*b2ed49a5SDavid van Moolenbroek                         xi = x->ival;
763*b2ed49a5SDavid van Moolenbroek                         yi = y->ival;
764*b2ed49a5SDavid van Moolenbroek                         switch (token) {
765*b2ed49a5SDavid van Moolenbroek                         case TK_EQ:  ri = (xi == yi); break;
766*b2ed49a5SDavid van Moolenbroek                         case TK_NE:  ri = (xi != yi); break;
767*b2ed49a5SDavid van Moolenbroek                         case TK_LT:  ri = (xi <  yi); break;
768*b2ed49a5SDavid van Moolenbroek                         case TK_GT:  ri = (xi >  yi); break;
769*b2ed49a5SDavid van Moolenbroek                         case TK_LE:  ri = (xi <= yi); break;
770*b2ed49a5SDavid van Moolenbroek                         case TK_GE:  ri = (xi >= yi); break;
771*b2ed49a5SDavid van Moolenbroek                         }
772*b2ed49a5SDavid van Moolenbroek                     }
773*b2ed49a5SDavid van Moolenbroek                     else {
774*b2ed49a5SDavid van Moolenbroek                         xr = (x->type == T_REAL) ? x->rval : (double) x->ival;
775*b2ed49a5SDavid van Moolenbroek                         yr = (y->type == T_REAL) ? y->rval : (double) y->ival;
776*b2ed49a5SDavid van Moolenbroek                         switch (token) {
777*b2ed49a5SDavid van Moolenbroek                         case TK_EQ:  ri = (xr == yr); break;
778*b2ed49a5SDavid van Moolenbroek                         case TK_NE:  ri = (xr != yr); break;
779*b2ed49a5SDavid van Moolenbroek                         case TK_LT:  ri = (xr <  yr); break;
780*b2ed49a5SDavid van Moolenbroek                         case TK_GT:  ri = (xr >  yr); break;
781*b2ed49a5SDavid van Moolenbroek                         case TK_LE:  ri = (xr <= yr); break;
782*b2ed49a5SDavid van Moolenbroek                         case TK_GE:  ri = (xr >= yr); break;
783*b2ed49a5SDavid van Moolenbroek                         }
784*b2ed49a5SDavid van Moolenbroek                     }
785*b2ed49a5SDavid van Moolenbroek                     x->type = T_INT;
786*b2ed49a5SDavid van Moolenbroek                     x->ival = ri;
787*b2ed49a5SDavid van Moolenbroek                     break;
788*b2ed49a5SDavid van Moolenbroek 
789*b2ed49a5SDavid van Moolenbroek 
790*b2ed49a5SDavid van Moolenbroek                 /* binary real -> real */
791*b2ed49a5SDavid van Moolenbroek                 case TK_DIV: case TK_POW:
792*b2ed49a5SDavid van Moolenbroek 
793*b2ed49a5SDavid van Moolenbroek                     if (vstk < 1) return ERROR_SYNTAX;
794*b2ed49a5SDavid van Moolenbroek                     y = &valstk[vstk--]; x = &valstk[vstk];
795*b2ed49a5SDavid van Moolenbroek                     xr = (x->type == T_REAL) ? x->rval : (double) x->ival;
796*b2ed49a5SDavid van Moolenbroek                     yr = (y->type == T_REAL) ? y->rval : (double) y->ival;
797*b2ed49a5SDavid van Moolenbroek 
798*b2ed49a5SDavid van Moolenbroek                     if (token == TK_DIV) {
799*b2ed49a5SDavid van Moolenbroek                         if (yr == 0) return ERROR_DIV0;
800*b2ed49a5SDavid van Moolenbroek                         x->rval = xr / yr;
801*b2ed49a5SDavid van Moolenbroek                     }
802*b2ed49a5SDavid van Moolenbroek                     else {
803*b2ed49a5SDavid van Moolenbroek #if USE_MATH_LIB
804*b2ed49a5SDavid van Moolenbroek                         x->rval = pow(xr, yr);
805*b2ed49a5SDavid van Moolenbroek #else
806*b2ed49a5SDavid van Moolenbroek                         x->rval = 0;
807*b2ed49a5SDavid van Moolenbroek #endif
808*b2ed49a5SDavid van Moolenbroek                     }
809*b2ed49a5SDavid van Moolenbroek                     x->type = T_REAL;
810*b2ed49a5SDavid van Moolenbroek         break;
811*b2ed49a5SDavid van Moolenbroek 
812*b2ed49a5SDavid van Moolenbroek 
813*b2ed49a5SDavid van Moolenbroek                 /* binary int -> int */
814*b2ed49a5SDavid van Moolenbroek                 case TK_MOD: case TK_AND: case TK_OR:
815*b2ed49a5SDavid van Moolenbroek                 case TK_BAND: case TK_BOR: case TK_BXOR:
816*b2ed49a5SDavid van Moolenbroek                 case TK_SHL: case TK_SHR:
817*b2ed49a5SDavid van Moolenbroek 
818*b2ed49a5SDavid van Moolenbroek                     if (vstk < 1) return ERROR_SYNTAX;
819*b2ed49a5SDavid van Moolenbroek                     y = &valstk[vstk--]; x = &valstk[vstk];
820*b2ed49a5SDavid van Moolenbroek                     xi = (x->type == T_INT) ? x->ival : (long) x->rval;
821*b2ed49a5SDavid van Moolenbroek                     yi = (y->type == T_INT) ? y->ival : (long) y->rval;
822*b2ed49a5SDavid van Moolenbroek 
823*b2ed49a5SDavid van Moolenbroek                     switch (token) {
824*b2ed49a5SDavid van Moolenbroek                     case TK_MOD:    if (yi == 0) return ERROR_DIV0;
825*b2ed49a5SDavid van Moolenbroek                                                 ri = (xi %  yi); break;
826*b2ed49a5SDavid van Moolenbroek                     case TK_AND:    ri = (xi && yi); break;
827*b2ed49a5SDavid van Moolenbroek                     case TK_OR:     ri = (xi || yi); break;
828*b2ed49a5SDavid van Moolenbroek                     case TK_BAND: ri = (xi &    yi); break;
829*b2ed49a5SDavid van Moolenbroek                     case TK_BOR:    ri = (xi |  yi); break;
830*b2ed49a5SDavid van Moolenbroek                     case TK_BXOR: ri = (xi ^    yi); break;
831*b2ed49a5SDavid van Moolenbroek                     case TK_SHL:    ri = (xi << yi); break;
832*b2ed49a5SDavid van Moolenbroek                     case TK_SHR:    ri = (xi >> yi); break;
833*b2ed49a5SDavid van Moolenbroek                     }
834*b2ed49a5SDavid van Moolenbroek 
835*b2ed49a5SDavid van Moolenbroek                     x->type = T_INT;
836*b2ed49a5SDavid van Moolenbroek                     x->ival = ri;
837*b2ed49a5SDavid van Moolenbroek                     break;
838*b2ed49a5SDavid van Moolenbroek 
839*b2ed49a5SDavid van Moolenbroek 
840*b2ed49a5SDavid van Moolenbroek 
841*b2ed49a5SDavid van Moolenbroek                 /* unary real -> real */
842*b2ed49a5SDavid van Moolenbroek                 case TK_FUNC:
843*b2ed49a5SDavid van Moolenbroek                     x = &valstk[vstk];
844*b2ed49a5SDavid van Moolenbroek                     if(op->funcid) {
845*b2ed49a5SDavid van Moolenbroek #if USE_MATH_LIB
846*b2ed49a5SDavid van Moolenbroek                             xr = (x->type == T_REAL) ? x->rval : (double) x->ival;
847*b2ed49a5SDavid van Moolenbroek                             switch (op->funcid-1) {
848*b2ed49a5SDavid van Moolenbroek                             case F_ACOS: xr =  acos(xr); break;
849*b2ed49a5SDavid van Moolenbroek                             case F_ASIN: xr =  asin(xr); break;
850*b2ed49a5SDavid van Moolenbroek                             case F_ATAN: xr =  atan(xr); break;
851*b2ed49a5SDavid van Moolenbroek                             case F_COS:  xr =       cos(xr); break;
852*b2ed49a5SDavid van Moolenbroek                             case F_COSH: xr =  cosh(xr); break;
853*b2ed49a5SDavid van Moolenbroek                             case F_EXP:  xr =       exp(xr); break;
854*b2ed49a5SDavid van Moolenbroek                             case F_LN:   xr =       log(xr); break;
855*b2ed49a5SDavid van Moolenbroek                             case F_LOG:  xr = log10(xr); break;
856*b2ed49a5SDavid van Moolenbroek                             case F_SIN:  xr =       sin(xr); break;
857*b2ed49a5SDavid van Moolenbroek                             case F_SINH: xr =  sinh(xr); break;
858*b2ed49a5SDavid van Moolenbroek                             case F_SQR:  xr =       xr * xr; break;
859*b2ed49a5SDavid van Moolenbroek                             case F_SQRT: xr =  sqrt(xr); break;
860*b2ed49a5SDavid van Moolenbroek                             case F_TAN:  xr =       tan(xr); break;
861*b2ed49a5SDavid van Moolenbroek                             case F_TANH: xr =  tanh(xr); break;
862*b2ed49a5SDavid van Moolenbroek                             default:         xr = 0;                 break;
863*b2ed49a5SDavid van Moolenbroek                             }
864*b2ed49a5SDavid van Moolenbroek #else
865*b2ed49a5SDavid van Moolenbroek                             xr = 0;
866*b2ed49a5SDavid van Moolenbroek #endif
867*b2ed49a5SDavid van Moolenbroek                             x->rval = xr;
868*b2ed49a5SDavid van Moolenbroek                             x->type = T_REAL;
869*b2ed49a5SDavid van Moolenbroek                     }
870*b2ed49a5SDavid van Moolenbroek                     else {
871*b2ed49a5SDavid van Moolenbroek                             if(!get_func_result_cb || !get_func_result_cb(op->name, x, x)) {
872*b2ed49a5SDavid van Moolenbroek                                     return ERROR_FUNCNOTFOUND;
873*b2ed49a5SDavid van Moolenbroek                             }
874*b2ed49a5SDavid van Moolenbroek                     }
875*b2ed49a5SDavid van Moolenbroek                     break;
876*b2ed49a5SDavid van Moolenbroek 
877*b2ed49a5SDavid van Moolenbroek 
878*b2ed49a5SDavid van Moolenbroek                 /* unary int -> int */
879*b2ed49a5SDavid van Moolenbroek                 case TK_BNOT: case TK_NOT:
880*b2ed49a5SDavid van Moolenbroek 
881*b2ed49a5SDavid van Moolenbroek                     x = &valstk[vstk];
882*b2ed49a5SDavid van Moolenbroek                     xi = (x->type == T_INT) ? x->ival : (long) x->rval;
883*b2ed49a5SDavid van Moolenbroek                     if (token == TK_BNOT) {
884*b2ed49a5SDavid van Moolenbroek                         x->ival = ~ xi;
885*b2ed49a5SDavid van Moolenbroek                     }
886*b2ed49a5SDavid van Moolenbroek                     else {
887*b2ed49a5SDavid van Moolenbroek                         x->ival = ! xi;
888*b2ed49a5SDavid van Moolenbroek                     }
889*b2ed49a5SDavid van Moolenbroek                     x->type = T_INT;
890*b2ed49a5SDavid van Moolenbroek                     break;
891*b2ed49a5SDavid van Moolenbroek 
892*b2ed49a5SDavid van Moolenbroek 
893*b2ed49a5SDavid van Moolenbroek                 /* unary (int/real) -> (int/real) */
894*b2ed49a5SDavid van Moolenbroek                 case TK_ASSN:
895*b2ed49a5SDavid van Moolenbroek                     op->var->val = valstk[vstk];
896*b2ed49a5SDavid van Moolenbroek                     break;
897*b2ed49a5SDavid van Moolenbroek 
898*b2ed49a5SDavid van Moolenbroek 
899*b2ed49a5SDavid van Moolenbroek                 /* unary (int/real) -> (int/real) */
900*b2ed49a5SDavid van Moolenbroek                 case TK_NEG:
901*b2ed49a5SDavid van Moolenbroek                     x = &valstk[vstk];
902*b2ed49a5SDavid van Moolenbroek                     if (x->type == T_INT)
903*b2ed49a5SDavid van Moolenbroek                         x->ival = - x->ival;
904*b2ed49a5SDavid van Moolenbroek                     else
905*b2ed49a5SDavid van Moolenbroek                         x->rval = - x->rval;
906*b2ed49a5SDavid van Moolenbroek                     break;
907*b2ed49a5SDavid van Moolenbroek 
908*b2ed49a5SDavid van Moolenbroek                 } /* end select (execution switch) */
909*b2ed49a5SDavid van Moolenbroek             } /* end while (precedence loop) */
910*b2ed49a5SDavid van Moolenbroek 
911*b2ed49a5SDavid van Moolenbroek             /* back to the postfixified */
912*b2ed49a5SDavid van Moolenbroek 
913*b2ed49a5SDavid van Moolenbroek             /* if we had a close paren, pull the matching open paren (error if
914*b2ed49a5SDavid van Moolenbroek              * we pull something else. otherwise push our new operator
915*b2ed49a5SDavid van Moolenbroek              */
916*b2ed49a5SDavid van Moolenbroek             if (t->token == TK_CLOSE) {
917*b2ed49a5SDavid van Moolenbroek                 if (opstk[ostk--]->token != TK_OPEN) return ERROR_SYNTAX;
918*b2ed49a5SDavid van Moolenbroek             }
919*b2ed49a5SDavid van Moolenbroek             else {
920*b2ed49a5SDavid van Moolenbroek                 opstk[++ostk] = t;
921*b2ed49a5SDavid van Moolenbroek             }
922*b2ed49a5SDavid van Moolenbroek         }
923*b2ed49a5SDavid van Moolenbroek     }
924*b2ed49a5SDavid van Moolenbroek 
925*b2ed49a5SDavid van Moolenbroek     /* there should be exactly one value and no operators left on the stacks */
926*b2ed49a5SDavid van Moolenbroek     if (vstk != 0 || ostk != -1) return ERROR_SYNTAX;
927*b2ed49a5SDavid van Moolenbroek 
928*b2ed49a5SDavid van Moolenbroek     /* return that value */
929*b2ed49a5SDavid van Moolenbroek     *result = valstk[0];
930*b2ed49a5SDavid van Moolenbroek     return RESULT_OK;
931*b2ed49a5SDavid van Moolenbroek }
932*b2ed49a5SDavid van Moolenbroek 
933*b2ed49a5SDavid van Moolenbroek 
934*b2ed49a5SDavid van Moolenbroek 
935*b2ed49a5SDavid van Moolenbroek 
936*b2ed49a5SDavid van Moolenbroek 
937*b2ed49a5SDavid van Moolenbroek /** debugging things **/
938*b2ed49a5SDavid van Moolenbroek #if EVAL_DEBUG
939*b2ed49a5SDavid van Moolenbroek /* expression printer */
prt_tok(struct tok * t)940*b2ed49a5SDavid van Moolenbroek void prt_tok(struct tok *t) {
941*b2ed49a5SDavid van Moolenbroek     switch(t->token)    {
942*b2ed49a5SDavid van Moolenbroek     case TK_OPEN:  printf("( ");    break;
943*b2ed49a5SDavid van Moolenbroek     case TK_CLOSE: printf(") ");    break;
944*b2ed49a5SDavid van Moolenbroek 
945*b2ed49a5SDavid van Moolenbroek     case TK_ADD:     printf("+ ");  break;
946*b2ed49a5SDavid van Moolenbroek     case TK_SUB:     printf("- ");  break;
947*b2ed49a5SDavid van Moolenbroek     case TK_MUL:     printf("* ");  break;
948*b2ed49a5SDavid van Moolenbroek     case TK_MULI:  printf("*i "); break;
949*b2ed49a5SDavid van Moolenbroek     case TK_POW:     printf("** "); break;
950*b2ed49a5SDavid van Moolenbroek     case TK_DIV:     printf("/ ");  break;
951*b2ed49a5SDavid van Moolenbroek     case TK_MOD:     printf("%% "); break;
952*b2ed49a5SDavid van Moolenbroek 
953*b2ed49a5SDavid van Moolenbroek     case TK_EQ:      printf("== "); break;
954*b2ed49a5SDavid van Moolenbroek     case TK_NE:      printf("!= "); break;
955*b2ed49a5SDavid van Moolenbroek     case TK_LT:      printf("< ");  break;
956*b2ed49a5SDavid van Moolenbroek     case TK_GT:      printf("> ");  break;
957*b2ed49a5SDavid van Moolenbroek     case TK_LE:      printf("<= "); break;
958*b2ed49a5SDavid van Moolenbroek     case TK_GE:      printf(">= "); break;
959*b2ed49a5SDavid van Moolenbroek 
960*b2ed49a5SDavid van Moolenbroek     case TK_AND:     printf("&& "); break;
961*b2ed49a5SDavid van Moolenbroek     case TK_BAND:  printf("& ");    break;
962*b2ed49a5SDavid van Moolenbroek     case TK_BNOT:  printf("~ ");    break;
963*b2ed49a5SDavid van Moolenbroek     case TK_BOR:     printf("| ");  break;
964*b2ed49a5SDavid van Moolenbroek     case TK_BXOR:  printf("^ ");    break;
965*b2ed49a5SDavid van Moolenbroek     case TK_NEG:     printf("_ ");  break;
966*b2ed49a5SDavid van Moolenbroek     case TK_NOT:     printf("! ");  break;
967*b2ed49a5SDavid van Moolenbroek     case TK_OR:      printf("|| "); break;
968*b2ed49a5SDavid van Moolenbroek     case TK_SHL:     printf("<< "); break;
969*b2ed49a5SDavid van Moolenbroek     case TK_SHR:     printf(">> "); break;
970*b2ed49a5SDavid van Moolenbroek 
971*b2ed49a5SDavid van Moolenbroek     case TK_ASSN:  printf("%s = ", t->name); break;
972*b2ed49a5SDavid van Moolenbroek     case TK_FUNC:  printf("%s() ", t->funcid ? functable[(int)t->funcid-1] : t->name); break;
973*b2ed49a5SDavid van Moolenbroek     case TK_VAL:     if (t->val.type == T_INT)
974*b2ed49a5SDavid van Moolenbroek                                      printf("%ld ", t->val.ival);
975*b2ed49a5SDavid van Moolenbroek                                  else
976*b2ed49a5SDavid van Moolenbroek                                      printf("%g ", t->val.rval);
977*b2ed49a5SDavid van Moolenbroek                                  break;
978*b2ed49a5SDavid van Moolenbroek 
979*b2ed49a5SDavid van Moolenbroek     case TK_VAR:     printf("%s ", t->name); break;
980*b2ed49a5SDavid van Moolenbroek     default:             printf("?? (%d)", t->token); break;
981*b2ed49a5SDavid van Moolenbroek     }
982*b2ed49a5SDavid van Moolenbroek }
983*b2ed49a5SDavid van Moolenbroek 
prt_lst(struct tok * t)984*b2ed49a5SDavid van Moolenbroek void prt_lst(struct tok *t) {
985*b2ed49a5SDavid van Moolenbroek     for (; t; t=t->next) prt_tok(t);
986*b2ed49a5SDavid van Moolenbroek     printf("\n");
987*b2ed49a5SDavid van Moolenbroek }
988*b2ed49a5SDavid van Moolenbroek 
989*b2ed49a5SDavid van Moolenbroek #else
prt_tok(struct tok * t)990*b2ed49a5SDavid van Moolenbroek void prt_tok(struct tok *t) {}
prt_lst(struct tok * t)991*b2ed49a5SDavid van Moolenbroek void prt_lst(struct tok *t) {}
992*b2ed49a5SDavid van Moolenbroek #endif
993*b2ed49a5SDavid van Moolenbroek 
994*b2ed49a5SDavid van Moolenbroek 
995*b2ed49a5SDavid van Moolenbroek 
996*b2ed49a5SDavid van Moolenbroek /*** UTILITY FUNCTIONS ***/
997*b2ed49a5SDavid van Moolenbroek 
998*b2ed49a5SDavid van Moolenbroek /* case-insensitive string comparison, TRUE or FALSE result */
same_str(const char * a,const char * b)999*b2ed49a5SDavid van Moolenbroek int same_str(const char *a, const char *b) {
1000*b2ed49a5SDavid van Moolenbroek     if (!a || !b) return 0; /* false even if a == b == null */
1001*b2ed49a5SDavid van Moolenbroek     if (a == b) return 1;
1002*b2ed49a5SDavid van Moolenbroek 
1003*b2ed49a5SDavid van Moolenbroek #ifdef HAVE_STRCASECMP
1004*b2ed49a5SDavid van Moolenbroek     return (strcasecmp(a, b) == 0);
1005*b2ed49a5SDavid van Moolenbroek #elif HAVE_STRCMPI
1006*b2ed49a5SDavid van Moolenbroek     return (strcmpi(a, b) == 0);
1007*b2ed49a5SDavid van Moolenbroek #else
1008*b2ed49a5SDavid van Moolenbroek     while ((tolower((int)*a) == tolower((int)*b))) {
1009*b2ed49a5SDavid van Moolenbroek         if (!*a) return 1; /* if end of both strings, return true */
1010*b2ed49a5SDavid van Moolenbroek         a++; b++;
1011*b2ed49a5SDavid van Moolenbroek     }
1012*b2ed49a5SDavid van Moolenbroek     return 0; /* mismatch before end of string - return false */
1013*b2ed49a5SDavid van Moolenbroek #endif
1014*b2ed49a5SDavid van Moolenbroek }
1015*b2ed49a5SDavid van Moolenbroek 
1016*b2ed49a5SDavid van Moolenbroek /* case-insensitive string comparison with maximum length */
same_str_len(const char * a,const char * b,int len)1017*b2ed49a5SDavid van Moolenbroek int same_str_len(const char *a, const char *b, int len) {
1018*b2ed49a5SDavid van Moolenbroek     if (!a || !b) return 0; /* false even if a == b == null */
1019*b2ed49a5SDavid van Moolenbroek     if (len == 0) return 0;
1020*b2ed49a5SDavid van Moolenbroek     if (a == b) return 1;
1021*b2ed49a5SDavid van Moolenbroek 
1022*b2ed49a5SDavid van Moolenbroek #ifdef HAVE_STRNCASECMP
1023*b2ed49a5SDavid van Moolenbroek     return (strncasecmp(a, b, len) == 0);
1024*b2ed49a5SDavid van Moolenbroek #elif HAVE_STRNCMPI
1025*b2ed49a5SDavid van Moolenbroek     return (strncmpi(a, b) == 0);
1026*b2ed49a5SDavid van Moolenbroek #else
1027*b2ed49a5SDavid van Moolenbroek     while (--len && (tolower((int)*a) == tolower((int)*b))) {
1028*b2ed49a5SDavid van Moolenbroek         if (!*a) return 1; /* true if both strings equal & end before len */
1029*b2ed49a5SDavid van Moolenbroek         a++; b++;
1030*b2ed49a5SDavid van Moolenbroek     }
1031*b2ed49a5SDavid van Moolenbroek     /* result based on last char of allowed length */
1032*b2ed49a5SDavid van Moolenbroek     return (tolower((int)*a) == tolower((int)*b)) ? 1 : 0;
1033*b2ed49a5SDavid van Moolenbroek #endif
1034*b2ed49a5SDavid van Moolenbroek }
1035*b2ed49a5SDavid van Moolenbroek 
1036*b2ed49a5SDavid van Moolenbroek #if EVAL_MALLOC
1037*b2ed49a5SDavid van Moolenbroek /* tracked memory allocation - create header */
create_mem()1038*b2ed49a5SDavid van Moolenbroek struct memh *create_mem() {
1039*b2ed49a5SDavid van Moolenbroek     struct memh *mh = (struct memh *) malloc(sizeof(struct memh));
1040*b2ed49a5SDavid van Moolenbroek     mh->next = NULL;
1041*b2ed49a5SDavid van Moolenbroek     mh->ptr  = NULL;
1042*b2ed49a5SDavid van Moolenbroek     return mh;
1043*b2ed49a5SDavid van Moolenbroek }
1044*b2ed49a5SDavid van Moolenbroek 
1045*b2ed49a5SDavid van Moolenbroek /* tracked memory allocation - allocate memory using header */
mem_alloc(struct memh * mh,size_t len)1046*b2ed49a5SDavid van Moolenbroek void *mem_alloc(struct memh *mh, size_t len) {
1047*b2ed49a5SDavid van Moolenbroek     struct memh *mem = (struct memh *) malloc(len + sizeof(struct memh));
1048*b2ed49a5SDavid van Moolenbroek     if (!mem) return NULL;
1049*b2ed49a5SDavid van Moolenbroek     mem->next = mh->next;
1050*b2ed49a5SDavid van Moolenbroek     mh->next = mem;
1051*b2ed49a5SDavid van Moolenbroek     return mem->ptr = (void *) &mem[1];
1052*b2ed49a5SDavid van Moolenbroek }
1053*b2ed49a5SDavid van Moolenbroek 
1054*b2ed49a5SDavid van Moolenbroek /* tracked memory allocation - free all memory in header */
free_mem(struct memh * mh)1055*b2ed49a5SDavid van Moolenbroek void free_mem(struct memh *mh) {
1056*b2ed49a5SDavid van Moolenbroek     struct memh *next;
1057*b2ed49a5SDavid van Moolenbroek     for (; mh; mh = next) {
1058*b2ed49a5SDavid van Moolenbroek         next = mh->next;
1059*b2ed49a5SDavid van Moolenbroek         free(mh);
1060*b2ed49a5SDavid van Moolenbroek     }
1061*b2ed49a5SDavid van Moolenbroek }
1062*b2ed49a5SDavid van Moolenbroek 
1063*b2ed49a5SDavid van Moolenbroek #else
1064*b2ed49a5SDavid van Moolenbroek #define MEM_BUFFER_LEN  4096
1065*b2ed49a5SDavid van Moolenbroek #define MAX_NUM_BUFFERS 2
1066*b2ed49a5SDavid van Moolenbroek char mem_buffer[MAX_NUM_BUFFERS][MEM_BUFFER_LEN];
1067*b2ed49a5SDavid van Moolenbroek struct memh mem_headers[MAX_NUM_BUFFERS];
1068*b2ed49a5SDavid van Moolenbroek int mem_idx[MAX_NUM_BUFFERS] = {0};
1069*b2ed49a5SDavid van Moolenbroek 
1070*b2ed49a5SDavid van Moolenbroek #define MEM_HEADER_TO_N(H) ((H)-mem_headers)
1071*b2ed49a5SDavid van Moolenbroek 
create_mem()1072*b2ed49a5SDavid van Moolenbroek struct memh *create_mem() {
1073*b2ed49a5SDavid van Moolenbroek     int n;
1074*b2ed49a5SDavid van Moolenbroek     struct memh *mh;
1075*b2ed49a5SDavid van Moolenbroek     for(n=0;n<MAX_NUM_BUFFERS;n++) {
1076*b2ed49a5SDavid van Moolenbroek             if(mem_idx[n] == 0) {
1077*b2ed49a5SDavid van Moolenbroek                     mem_idx[n] = 1;
1078*b2ed49a5SDavid van Moolenbroek                     break;
1079*b2ed49a5SDavid van Moolenbroek             }
1080*b2ed49a5SDavid van Moolenbroek     }
1081*b2ed49a5SDavid van Moolenbroek 
1082*b2ed49a5SDavid van Moolenbroek     if(n == MAX_NUM_BUFFERS) {
1083*b2ed49a5SDavid van Moolenbroek #if MEM_DEBUG
1084*b2ed49a5SDavid van Moolenbroek             printf("create_mem: out of buffers\n", n);
1085*b2ed49a5SDavid van Moolenbroek #endif
1086*b2ed49a5SDavid van Moolenbroek             return NULL;
1087*b2ed49a5SDavid van Moolenbroek     }
1088*b2ed49a5SDavid van Moolenbroek #if MEM_DEBUG
1089*b2ed49a5SDavid van Moolenbroek     printf("create_mem: n is %d\n", n);
1090*b2ed49a5SDavid van Moolenbroek #endif
1091*b2ed49a5SDavid van Moolenbroek     mh = &mem_headers[n];
1092*b2ed49a5SDavid van Moolenbroek     memset(mh, 0, sizeof(struct memh));
1093*b2ed49a5SDavid van Moolenbroek     return mh;
1094*b2ed49a5SDavid van Moolenbroek }
1095*b2ed49a5SDavid van Moolenbroek 
mem_alloc(struct memh * mh,size_t len)1096*b2ed49a5SDavid van Moolenbroek void *mem_alloc(struct memh *mh, size_t len) {
1097*b2ed49a5SDavid van Moolenbroek     int n = MEM_HEADER_TO_N(mh);
1098*b2ed49a5SDavid van Moolenbroek     int mem_idx_n;
1099*b2ed49a5SDavid van Moolenbroek     struct memh *mem = NULL;
1100*b2ed49a5SDavid van Moolenbroek     len += sizeof(struct memh);
1101*b2ed49a5SDavid van Moolenbroek     mem_idx_n = mem_idx[n]-1;
1102*b2ed49a5SDavid van Moolenbroek #if MEM_DEBUG
1103*b2ed49a5SDavid van Moolenbroek     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);
1104*b2ed49a5SDavid van Moolenbroek #endif
1105*b2ed49a5SDavid van Moolenbroek     if(mem_idx_n + len > MEM_BUFFER_LEN) {
1106*b2ed49a5SDavid van Moolenbroek #if MEM_DEBUG
1107*b2ed49a5SDavid van Moolenbroek             printf("mem_alloc: out of mem\n");
1108*b2ed49a5SDavid van Moolenbroek #endif
1109*b2ed49a5SDavid van Moolenbroek             return NULL;
1110*b2ed49a5SDavid van Moolenbroek     }
1111*b2ed49a5SDavid van Moolenbroek     mem = (struct memh *) &mem_buffer[n][mem_idx_n];
1112*b2ed49a5SDavid van Moolenbroek     mem_idx[n] += len;
1113*b2ed49a5SDavid van Moolenbroek     mem->next = mh->next;
1114*b2ed49a5SDavid van Moolenbroek     mh->next = mem;
1115*b2ed49a5SDavid van Moolenbroek     return mem->ptr = (void *) &mem[1];
1116*b2ed49a5SDavid van Moolenbroek }
1117*b2ed49a5SDavid van Moolenbroek 
free_mem(struct memh * mh)1118*b2ed49a5SDavid van Moolenbroek void free_mem(struct memh *mh) {
1119*b2ed49a5SDavid van Moolenbroek     int n = MEM_HEADER_TO_N(mh);
1120*b2ed49a5SDavid van Moolenbroek     mem_idx[n] = 0;
1121*b2ed49a5SDavid van Moolenbroek #if MEM_DEBUG
1122*b2ed49a5SDavid van Moolenbroek     printf("free_mem: n is %d\n", n);
1123*b2ed49a5SDavid van Moolenbroek #endif
1124*b2ed49a5SDavid van Moolenbroek }
1125*b2ed49a5SDavid van Moolenbroek 
1126*b2ed49a5SDavid van Moolenbroek #endif
1127*b2ed49a5SDavid van Moolenbroek 
1128*b2ed49a5SDavid van Moolenbroek /* creates an empty variable table */
create_vartable()1129*b2ed49a5SDavid van Moolenbroek struct vartable *create_vartable() {
1130*b2ed49a5SDavid van Moolenbroek     struct memh *mh = create_mem();
1131*b2ed49a5SDavid van Moolenbroek     struct vartable *vt;
1132*b2ed49a5SDavid van Moolenbroek     if(!mh) {
1133*b2ed49a5SDavid van Moolenbroek             return NULL;
1134*b2ed49a5SDavid van Moolenbroek     }
1135*b2ed49a5SDavid van Moolenbroek     vt = (struct vartable *) mem_alloc(mh, sizeof(struct vartable));
1136*b2ed49a5SDavid van Moolenbroek     if (mh && vt) vt->mh = mh, vt->first = NULL; else free_mem(mh);
1137*b2ed49a5SDavid van Moolenbroek     return vt;
1138*b2ed49a5SDavid van Moolenbroek }
1139*b2ed49a5SDavid van Moolenbroek 
1140*b2ed49a5SDavid van Moolenbroek /* frees a variable table */
free_vartable(struct vartable * vt)1141*b2ed49a5SDavid van Moolenbroek void free_vartable(struct vartable *vt) {
1142*b2ed49a5SDavid van Moolenbroek     free_mem(vt->mh);
1143*b2ed49a5SDavid van Moolenbroek }
1144*b2ed49a5SDavid van Moolenbroek 
1145*b2ed49a5SDavid van Moolenbroek /* gets a variable out of a variable table */
get_var(struct vartable * vt,char * name)1146*b2ed49a5SDavid van Moolenbroek struct var *get_var(struct vartable *vt, char *name) {
1147*b2ed49a5SDavid van Moolenbroek     struct var *v;
1148*b2ed49a5SDavid van Moolenbroek     if (!vt || !name) return NULL;
1149*b2ed49a5SDavid van Moolenbroek     for (v = vt->first; v; v = v->next) if (same_str(v->name, name)) return v;
1150*b2ed49a5SDavid van Moolenbroek     return NULL;
1151*b2ed49a5SDavid van Moolenbroek }
1152*b2ed49a5SDavid van Moolenbroek 
1153*b2ed49a5SDavid van Moolenbroek /* creates a new variable in a variable table */
put_var(struct vartable * vt,char * name,struct val * value)1154*b2ed49a5SDavid van Moolenbroek struct var *put_var(struct vartable *vt, char *name, struct val *value) {
1155*b2ed49a5SDavid van Moolenbroek     struct var *v;
1156*b2ed49a5SDavid van Moolenbroek     char *n;
1157*b2ed49a5SDavid van Moolenbroek 
1158*b2ed49a5SDavid van Moolenbroek     if (!vt || !name || !value) return NULL;
1159*b2ed49a5SDavid van Moolenbroek 
1160*b2ed49a5SDavid van Moolenbroek     if ((v = get_var(vt, name))) {
1161*b2ed49a5SDavid van Moolenbroek         v->val = *value;
1162*b2ed49a5SDavid van Moolenbroek         return v;
1163*b2ed49a5SDavid van Moolenbroek     }
1164*b2ed49a5SDavid van Moolenbroek 
1165*b2ed49a5SDavid van Moolenbroek     v = (struct var *) mem_alloc(vt->mh, sizeof(struct var));
1166*b2ed49a5SDavid van Moolenbroek     n = (char *) mem_alloc(vt->mh, strlen(name)+1);
1167*b2ed49a5SDavid van Moolenbroek     if (v && n) {
1168*b2ed49a5SDavid van Moolenbroek         strcpy(n, name);
1169*b2ed49a5SDavid van Moolenbroek         v->name = n;
1170*b2ed49a5SDavid van Moolenbroek         v->val  = *value;
1171*b2ed49a5SDavid van Moolenbroek         v->next = vt->first;
1172*b2ed49a5SDavid van Moolenbroek         vt->first = v;
1173*b2ed49a5SDavid van Moolenbroek         return v;
1174*b2ed49a5SDavid van Moolenbroek     }
1175*b2ed49a5SDavid van Moolenbroek     return NULL;
1176*b2ed49a5SDavid van Moolenbroek }
1177