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