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