1 /* -----------------------------------------------------------------------------
2 * This file is part of SWIG, which is licensed as a whole under version 3
3 * (or any later version) of the GNU General Public License. Some additional
4 * terms also apply to certain portions of SWIG. The full details of the SWIG
5 * license and copyrights can be found in the LICENSE and COPYRIGHT files
6 * included with the SWIG source code as distributed by the SWIG developers
7 * and at http://www.swig.org/legal.html.
8 *
9 * expr.c
10 *
11 * Integer arithmetic expression evaluator used to handle expressions
12 * encountered during preprocessing.
13 * ----------------------------------------------------------------------------- */
14
15 #include "swig.h"
16 #include "preprocessor.h"
17
18 static Scanner *scan = 0;
19
20 typedef struct {
21 int op;
22 long value;
23 String *svalue;
24 } exprval;
25
26 #define EXPR_TOP 1
27 #define EXPR_VALUE 2
28 #define EXPR_OP 3
29 #define EXPR_GROUP 4
30 #define EXPR_UMINUS 100
31
32 static exprval stack[256]; /* Parsing stack */
33 static int sp = 0; /* Stack pointer */
34 static int prec[256]; /* Precedence rules */
35 static int expr_init = 0; /* Initialization flag */
36 static const char *errmsg = 0; /* Parsing error */
37
38 /* Initialize the precedence table for various operators. Low values have higher precedence */
init_precedence()39 static void init_precedence() {
40 prec[SWIG_TOKEN_NOT] = 10;
41 prec[EXPR_UMINUS] = 10;
42 prec[SWIG_TOKEN_STAR] = 20;
43 prec[SWIG_TOKEN_SLASH] = 20;
44 prec[SWIG_TOKEN_PERCENT] = 20;
45 prec[SWIG_TOKEN_PLUS] = 30;
46 prec[SWIG_TOKEN_MINUS] = 30;
47 prec[SWIG_TOKEN_LSHIFT] = 40;
48 prec[SWIG_TOKEN_RSHIFT] = 40;
49 prec[SWIG_TOKEN_AND] = 50;
50 prec[SWIG_TOKEN_XOR] = 60;
51 prec[SWIG_TOKEN_OR] = 70;
52 prec[SWIG_TOKEN_EQUALTO] = 80;
53 prec[SWIG_TOKEN_NOTEQUAL] = 80;
54 prec[SWIG_TOKEN_LESSTHAN] = 80;
55 prec[SWIG_TOKEN_GREATERTHAN] = 80;
56 prec[SWIG_TOKEN_LTEQUAL] = 80;
57 prec[SWIG_TOKEN_GTEQUAL] = 80;
58 prec[SWIG_TOKEN_LNOT] = 90;
59 prec[SWIG_TOKEN_LAND] = 100;
60 prec[SWIG_TOKEN_LOR] = 110;
61 expr_init = 1;
62 }
63
64 #define UNARY_OP(token) (((token) == SWIG_TOKEN_NOT) || \
65 ((token) == SWIG_TOKEN_LNOT) || \
66 ((token) == EXPR_UMINUS))
67
68 /* Reduce a single operator on the stack */
69 /* return 0 on failure, 1 on success */
reduce_op()70 static int reduce_op() {
71 long op_token = stack[sp - 1].value;
72 assert(sp > 0);
73 assert(stack[sp - 1].op == EXPR_OP);
74 /* do some basic checking first: */
75 if (stack[sp].op != EXPR_VALUE) {
76 errmsg = "Right-hand side is not value";
77 return 0;
78 }
79 if (UNARY_OP(op_token)) {
80 if (stack[sp].svalue) {
81 errmsg = "Syntax error: attempt to apply unary operator to string";
82 return 0;
83 }
84 } else {
85 /* binary operator: */
86 if (sp == 1) {
87 /* top of stack: don't attempt to use sp-2! */
88 errmsg = "Missing left-hand side for binary operator";
89 return 0;
90 }
91 if (stack[sp].op != EXPR_VALUE) {
92 errmsg = "Left-hand side of binary operator is not a value";
93 return 0;
94 }
95 if ((!stack[sp - 2].svalue) != (!stack[sp].svalue)) {
96 errmsg = "Can't mix strings and integers in expression";
97 return 0;
98 }
99 }
100 if (stack[sp].svalue) {
101 /* A binary string expression */
102 switch (stack[sp - 1].value) {
103 case SWIG_TOKEN_EQUALTO:
104 stack[sp - 2].value = (Strcmp(stack[sp - 2].svalue, stack[sp].svalue) == 0);
105 Delete(stack[sp - 2].svalue);
106 Delete(stack[sp].svalue);
107 sp -= 2;
108 break;
109 case SWIG_TOKEN_NOTEQUAL:
110 stack[sp - 2].value = (Strcmp(stack[sp - 2].svalue, stack[sp].svalue) != 0);
111 Delete(stack[sp - 2].svalue);
112 Delete(stack[sp].svalue);
113 sp -= 2;
114 break;
115 default:
116 errmsg = "Syntax error: bad binary operator for strings";
117 return 0;
118 break;
119 }
120 } else {
121 switch (op_token) {
122 case SWIG_TOKEN_STAR:
123 stack[sp - 2].value = stack[sp - 2].value * stack[sp].value;
124 sp -= 2;
125 break;
126 case SWIG_TOKEN_EQUALTO:
127 stack[sp - 2].value = stack[sp - 2].value == stack[sp].value;
128 sp -= 2;
129 break;
130 case SWIG_TOKEN_NOTEQUAL:
131 stack[sp - 2].value = stack[sp - 2].value != stack[sp].value;
132 sp -= 2;
133 break;
134 case SWIG_TOKEN_PLUS:
135 stack[sp - 2].value = stack[sp - 2].value + stack[sp].value;
136 sp -= 2;
137 break;
138 case SWIG_TOKEN_MINUS:
139 stack[sp - 2].value = stack[sp - 2].value - stack[sp].value;
140 sp -= 2;
141 break;
142 case SWIG_TOKEN_AND:
143 stack[sp - 2].value = stack[sp - 2].value & stack[sp].value;
144 sp -= 2;
145 break;
146 case SWIG_TOKEN_LAND:
147 stack[sp - 2].value = stack[sp - 2].value && stack[sp].value;
148 sp -= 2;
149 break;
150 case SWIG_TOKEN_OR:
151 stack[sp - 2].value = stack[sp - 2].value | stack[sp].value;
152 sp -= 2;
153 break;
154 case SWIG_TOKEN_LOR:
155 stack[sp - 2].value = stack[sp - 2].value || stack[sp].value;
156 sp -= 2;
157 break;
158 case SWIG_TOKEN_XOR:
159 stack[sp - 2].value = stack[sp - 2].value ^ stack[sp].value;
160 sp -= 2;
161 break;
162 case SWIG_TOKEN_LESSTHAN:
163 stack[sp - 2].value = stack[sp - 2].value < stack[sp].value;
164 sp -= 2;
165 break;
166 case SWIG_TOKEN_GREATERTHAN:
167 stack[sp - 2].value = stack[sp - 2].value > stack[sp].value;
168 sp -= 2;
169 break;
170 case SWIG_TOKEN_LTEQUAL:
171 stack[sp - 2].value = stack[sp - 2].value <= stack[sp].value;
172 sp -= 2;
173 break;
174 case SWIG_TOKEN_GTEQUAL:
175 stack[sp - 2].value = stack[sp - 2].value >= stack[sp].value;
176 sp -= 2;
177 break;
178 case SWIG_TOKEN_NOT:
179 stack[sp - 1].value = ~stack[sp].value;
180 sp--;
181 break;
182 case SWIG_TOKEN_LNOT:
183 stack[sp - 1].value = !stack[sp].value;
184 sp--;
185 break;
186 case EXPR_UMINUS:
187 stack[sp - 1].value = -stack[sp].value;
188 sp--;
189 break;
190 case SWIG_TOKEN_SLASH:
191 if (stack[sp].value != 0) {
192 stack[sp - 2].value = stack[sp - 2].value / stack[sp].value;
193 sp -= 2;
194 } else {
195 errmsg = "Division by zero in expression";
196 return 0;
197 }
198 break;
199 case SWIG_TOKEN_PERCENT:
200 if (stack[sp].value != 0) {
201 stack[sp - 2].value = stack[sp - 2].value % stack[sp].value;
202 sp -= 2;
203 } else {
204 errmsg = "Modulo by zero in expression";
205 return 0;
206 }
207 break;
208 case SWIG_TOKEN_LSHIFT:
209 stack[sp - 2].value = stack[sp - 2].value << stack[sp].value;
210 sp -= 2;
211 break;
212 case SWIG_TOKEN_RSHIFT:
213 stack[sp - 2].value = stack[sp - 2].value >> stack[sp].value;
214 sp -= 2;
215 break;
216 default:
217 errmsg = "Syntax error: bad operator";
218 return 0;
219 break;
220 }
221 }
222 stack[sp].op = EXPR_VALUE;
223 stack[sp].svalue = 0; /* ensure it's not a string! */
224 return 1;
225 }
226
227 /* -----------------------------------------------------------------------------
228 * Preprocessor_expr_init()
229 *
230 * Initialize the expression evaluator
231 * ----------------------------------------------------------------------------- */
232
Preprocessor_expr_init(void)233 void Preprocessor_expr_init(void) {
234 if (!expr_init)
235 init_precedence();
236 if (!scan)
237 scan = NewScanner();
238 }
239
Preprocessor_expr_delete(void)240 void Preprocessor_expr_delete(void) {
241 DelScanner(scan);
242 }
243
244
245 /* -----------------------------------------------------------------------------
246 * Tokenizer
247 * ----------------------------------------------------------------------------- */
248
expr_token(Scanner * s)249 static int expr_token(Scanner * s) {
250 int t;
251 while (1) {
252 t = Scanner_token(s);
253 if (!((t == SWIG_TOKEN_BACKSLASH) || (t == SWIG_TOKEN_ENDLINE) || (t == SWIG_TOKEN_COMMENT)))
254 break;
255 }
256 return t;
257 }
258
259 /* -----------------------------------------------------------------------------
260 * Preprocessor_expr()
261 *
262 * Evaluates an arithmetic expression. Returns the result and sets an error code.
263 * ----------------------------------------------------------------------------- */
264
Preprocessor_expr(DOH * s,int * error)265 int Preprocessor_expr(DOH *s, int *error) {
266 int token = 0;
267 int op = 0;
268
269 sp = 0;
270 assert(s);
271 assert(scan);
272
273 Seek(s, 0, SEEK_SET);
274 /* Printf(stdout,"evaluating : '%s'\n", s); */
275 *error = 0;
276 Scanner_clear(scan);
277 Scanner_push(scan, s);
278
279 /* Put initial state onto the stack */
280 stack[sp].op = EXPR_TOP;
281 stack[sp].value = 0;
282
283 while (1) {
284 /* Look at the top of the stack */
285 switch (stack[sp].op) {
286 case EXPR_TOP:
287 /* An expression. Can be a number or another expression enclosed in parens */
288 token = expr_token(scan);
289 if (!token) {
290 errmsg = "Expected an expression";
291 *error = 1;
292 return 0;
293 }
294 if ((token == SWIG_TOKEN_INT) || (token == SWIG_TOKEN_UINT) || (token == SWIG_TOKEN_LONG) || (token == SWIG_TOKEN_ULONG)) {
295 /* A number. Reduce EXPR_TOP to an EXPR_VALUE */
296 char *c = Char(Scanner_text(scan));
297 stack[sp].value = (long) strtol(c, 0, 0);
298 stack[sp].svalue = 0;
299 /* stack[sp].value = (long) atol(Char(Scanner_text(scan))); */
300 stack[sp].op = EXPR_VALUE;
301 } else if (token == SWIG_TOKEN_PLUS) {
302 } else if ((token == SWIG_TOKEN_MINUS) || (token == SWIG_TOKEN_LNOT) || (token == SWIG_TOKEN_NOT)) {
303 if (token == SWIG_TOKEN_MINUS)
304 token = EXPR_UMINUS;
305 stack[sp].value = token;
306 stack[sp++].op = EXPR_OP;
307 stack[sp].op = EXPR_TOP;
308 stack[sp].svalue = 0;
309 } else if (token == SWIG_TOKEN_LPAREN) {
310 stack[sp++].op = EXPR_GROUP;
311 stack[sp].op = EXPR_TOP;
312 stack[sp].value = 0;
313 stack[sp].svalue = 0;
314 } else if (token == SWIG_TOKEN_ENDLINE) {
315 } else if (token == SWIG_TOKEN_STRING) {
316 stack[sp].svalue = NewString(Scanner_text(scan));
317 stack[sp].op = EXPR_VALUE;
318 } else if (token == SWIG_TOKEN_ID) {
319 stack[sp].value = 0;
320 stack[sp].svalue = 0;
321 stack[sp].op = EXPR_VALUE;
322 } else if ((token == SWIG_TOKEN_FLOAT) || (token == SWIG_TOKEN_DOUBLE)) {
323 errmsg = "Floating point constant in preprocessor expression";
324 *error = 1;
325 return 0;
326 } else
327 goto syntax_error;
328 break;
329 case EXPR_VALUE:
330 /* A value is on the stack. We may reduce or evaluate depending on what the next token is */
331 token = expr_token(scan);
332 if (!token) {
333 /* End of input. Might have to reduce if an operator is on stack */
334 while (sp > 0) {
335 if (stack[sp - 1].op == EXPR_OP) {
336 if (!reduce_op())
337 goto reduce_error;
338 } else if (stack[sp - 1].op == EXPR_GROUP) {
339 errmsg = "Missing \')\'";
340 *error = 1;
341 return 0;
342 } else
343 goto syntax_error;
344 }
345 return stack[sp].value;
346 }
347 /* Token must be an operator */
348 switch (token) {
349 case SWIG_TOKEN_STAR:
350 case SWIG_TOKEN_EQUALTO:
351 case SWIG_TOKEN_NOTEQUAL:
352 case SWIG_TOKEN_PLUS:
353 case SWIG_TOKEN_MINUS:
354 case SWIG_TOKEN_AND:
355 case SWIG_TOKEN_LAND:
356 case SWIG_TOKEN_OR:
357 case SWIG_TOKEN_LOR:
358 case SWIG_TOKEN_XOR:
359 case SWIG_TOKEN_LESSTHAN:
360 case SWIG_TOKEN_GREATERTHAN:
361 case SWIG_TOKEN_LTEQUAL:
362 case SWIG_TOKEN_GTEQUAL:
363 case SWIG_TOKEN_SLASH:
364 case SWIG_TOKEN_PERCENT:
365 case SWIG_TOKEN_LSHIFT:
366 case SWIG_TOKEN_RSHIFT:
367 if ((sp == 0) || (stack[sp - 1].op == EXPR_GROUP)) {
368 /* No possibility of reduce. Push operator and expression */
369 sp++;
370 stack[sp].op = EXPR_OP;
371 stack[sp].value = token;
372 sp++;
373 stack[sp].op = EXPR_TOP;
374 stack[sp].value = 0;
375 } else {
376 if (stack[sp - 1].op != EXPR_OP)
377 goto syntax_error_expected_operator;
378 op = stack[sp - 1].value; /* Previous operator */
379
380 /* Now, depending on the precedence relationship between the last operator and the current
381 we will reduce or push */
382
383 if (prec[op] <= prec[token]) {
384 /* Reduce the previous operator */
385 if (!reduce_op())
386 goto reduce_error;
387 }
388 sp++;
389 stack[sp].op = EXPR_OP;
390 stack[sp].value = token;
391 sp++;
392 stack[sp].op = EXPR_TOP;
393 stack[sp].value = 0;
394 }
395 break;
396 case SWIG_TOKEN_RPAREN:
397 if (sp == 0)
398 goto extra_rparen;
399
400 /* Might have to reduce operators first */
401 while ((sp > 0) && (stack[sp - 1].op == EXPR_OP)) {
402 if (!reduce_op())
403 goto reduce_error;
404 }
405 if ((sp == 0) || (stack[sp - 1].op != EXPR_GROUP))
406 goto extra_rparen;
407 stack[sp - 1].op = EXPR_VALUE;
408 stack[sp - 1].value = stack[sp].value;
409 sp--;
410 break;
411 default:
412 goto syntax_error_expected_operator;
413 break;
414 }
415 break;
416
417 default:
418 fprintf(stderr, "Internal error in expression evaluator.\n");
419 abort();
420 }
421 }
422
423 syntax_error:
424 errmsg = "Syntax error";
425 *error = 1;
426 return 0;
427
428 syntax_error_expected_operator:
429 errmsg = "Syntax error: expected operator";
430 *error = 1;
431 return 0;
432
433 reduce_error:
434 /* errmsg has been set by reduce_op */
435 *error = 1;
436 return 0;
437
438 extra_rparen:
439 errmsg = "Extra \')\'";
440 *error = 1;
441 return 0;
442 }
443
444 /* -----------------------------------------------------------------------------
445 * Preprocessor_expr_error()
446 *
447 * Return error message set by the evaluator (if any)
448 * ----------------------------------------------------------------------------- */
449
Preprocessor_expr_error()450 const char *Preprocessor_expr_error() {
451 return errmsg;
452 }
453