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