diff options
| author | Denys Vlasenko <dvlasenk@redhat.com> | 2010-09-16 11:50:46 +0200 |
|---|---|---|
| committer | Denys Vlasenko <dvlasenk@redhat.com> | 2010-09-16 11:50:46 +0200 |
| commit | bed7c81ea24e9e9ba2a897e233de2abefe611e8b (patch) | |
| tree | b18a4559e60300fecd7275c0088f8942441072a2 /shell/math.c | |
| parent | 063847d6bd23e184c409f37645ba90fa4d039ada (diff) | |
| download | busybox-w32-bed7c81ea24e9e9ba2a897e233de2abefe611e8b.tar.gz busybox-w32-bed7c81ea24e9e9ba2a897e233de2abefe611e8b.tar.bz2 busybox-w32-bed7c81ea24e9e9ba2a897e233de2abefe611e8b.zip | |
shell/math: deconvolute and explain ?: handling. Give better error message
function old new delta
arith_apply 1271 1283 +12
Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
Diffstat (limited to 'shell/math.c')
| -rw-r--r-- | shell/math.c | 243 |
1 files changed, 135 insertions, 108 deletions
diff --git a/shell/math.c b/shell/math.c index 871c06c3e..9d3b912a7 100644 --- a/shell/math.c +++ b/shell/math.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * arithmetic code ripped out of ash shell for code sharing | 2 | * Arithmetic code ripped out of ash shell for code sharing. |
| 3 | * | 3 | * |
| 4 | * This code is derived from software contributed to Berkeley by | 4 | * This code is derived from software contributed to Berkeley by |
| 5 | * Kenneth Almquist. | 5 | * Kenneth Almquist. |
| @@ -154,7 +154,7 @@ typedef unsigned char operator; | |||
| 154 | 154 | ||
| 155 | #define fix_assignment_prec(prec) do { if (prec == 3) prec = 2; } while (0) | 155 | #define fix_assignment_prec(prec) do { if (prec == 3) prec = 2; } while (0) |
| 156 | 156 | ||
| 157 | /* ternary conditional operator is right associative too */ | 157 | /* Ternary conditional operator is right associative too */ |
| 158 | #define TOK_CONDITIONAL tok_decl(4,0) | 158 | #define TOK_CONDITIONAL tok_decl(4,0) |
| 159 | #define TOK_CONDITIONAL_SEP tok_decl(4,1) | 159 | #define TOK_CONDITIONAL_SEP tok_decl(4,1) |
| 160 | 160 | ||
| @@ -186,10 +186,10 @@ typedef unsigned char operator; | |||
| 186 | #define TOK_DIV tok_decl(14,1) | 186 | #define TOK_DIV tok_decl(14,1) |
| 187 | #define TOK_REM tok_decl(14,2) | 187 | #define TOK_REM tok_decl(14,2) |
| 188 | 188 | ||
| 189 | /* exponent is right associative */ | 189 | /* Exponent is right associative */ |
| 190 | #define TOK_EXPONENT tok_decl(15,1) | 190 | #define TOK_EXPONENT tok_decl(15,1) |
| 191 | 191 | ||
| 192 | /* unary operators */ | 192 | /* Unary operators */ |
| 193 | #define UNARYPREC 16 | 193 | #define UNARYPREC 16 |
| 194 | #define TOK_BNOT tok_decl(UNARYPREC,0) | 194 | #define TOK_BNOT tok_decl(UNARYPREC,0) |
| 195 | #define TOK_NOT tok_decl(UNARYPREC,1) | 195 | #define TOK_NOT tok_decl(UNARYPREC,1) |
| @@ -213,30 +213,37 @@ typedef unsigned char operator; | |||
| 213 | #define TOK_RPAREN tok_decl(SPEC_PREC, 1) | 213 | #define TOK_RPAREN tok_decl(SPEC_PREC, 1) |
| 214 | 214 | ||
| 215 | static int | 215 | static int |
| 216 | tok_have_assign(operator op) | 216 | is_assign_op(operator op) |
| 217 | { | 217 | { |
| 218 | operator prec = PREC(op); | 218 | operator prec = PREC(op); |
| 219 | |||
| 220 | fix_assignment_prec(prec); | 219 | fix_assignment_prec(prec); |
| 221 | return (prec == PREC(TOK_ASSIGN) || | 220 | return prec == PREC(TOK_ASSIGN) |
| 222 | prec == PREC_PRE || prec == PREC_POST); | 221 | || prec == PREC_PRE |
| 222 | || prec == PREC_POST; | ||
| 223 | } | 223 | } |
| 224 | 224 | ||
| 225 | static int | 225 | static int |
| 226 | is_right_associative(operator prec) | 226 | is_right_associative(operator prec) |
| 227 | { | 227 | { |
| 228 | return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) | 228 | return prec == PREC(TOK_ASSIGN) |
| 229 | || prec == PREC(TOK_CONDITIONAL)); | 229 | || prec == PREC(TOK_EXPONENT) |
| 230 | || prec == PREC(TOK_CONDITIONAL); | ||
| 230 | } | 231 | } |
| 231 | 232 | ||
| 232 | 233 | ||
| 233 | typedef struct { | 234 | typedef struct { |
| 234 | arith_t val; | 235 | arith_t val; |
| 235 | arith_t contidional_second_val; | 236 | /* We acquire second_val only when "expr1 : expr2" part |
| 236 | char contidional_second_val_initialized; | 237 | * of ternary ?: op is evaluated. |
| 237 | char *var; /* if NULL then is regular number, | 238 | * We treat ?: as two binary ops: (expr ? (expr1 : expr2)). |
| 238 | else is variable name */ | 239 | * ':' produces a new value which has two parts, val and second_val; |
| 239 | } v_n_t; | 240 | * then '?' selects one of them based on its left side. |
| 241 | */ | ||
| 242 | arith_t second_val; | ||
| 243 | char second_val_present; | ||
| 244 | /* If NULL then it's just a number, else it's a named variable */ | ||
| 245 | char *var; | ||
| 246 | } var_or_num_t; | ||
| 240 | 247 | ||
| 241 | typedef struct remembered_name { | 248 | typedef struct remembered_name { |
| 242 | struct remembered_name *next; | 249 | struct remembered_name *next; |
| @@ -248,7 +255,7 @@ static arith_t FAST_FUNC | |||
| 248 | evaluate_string(arith_state_t *math_state, const char *expr); | 255 | evaluate_string(arith_state_t *math_state, const char *expr); |
| 249 | 256 | ||
| 250 | static const char* | 257 | static const char* |
| 251 | arith_lookup_val(arith_state_t *math_state, v_n_t *t) | 258 | arith_lookup_val(arith_state_t *math_state, var_or_num_t *t) |
| 252 | { | 259 | { |
| 253 | if (t->var) { | 260 | if (t->var) { |
| 254 | const char *p = lookupvar(t->var); | 261 | const char *p = lookupvar(t->var); |
| @@ -290,27 +297,28 @@ arith_lookup_val(arith_state_t *math_state, v_n_t *t) | |||
| 290 | * stack. For an unary operator it will only change the top element, but a | 297 | * stack. For an unary operator it will only change the top element, but a |
| 291 | * binary operator will pop two arguments and push the result */ | 298 | * binary operator will pop two arguments and push the result */ |
| 292 | static NOINLINE const char* | 299 | static NOINLINE const char* |
| 293 | arith_apply(arith_state_t *math_state, operator op, v_n_t *numstack, v_n_t **numstackptr) | 300 | arith_apply(arith_state_t *math_state, operator op, var_or_num_t *numstack, var_or_num_t **numstackptr) |
| 294 | { | 301 | { |
| 295 | #define NUMPTR (*numstackptr) | 302 | #define NUMPTR (*numstackptr) |
| 296 | 303 | ||
| 297 | v_n_t *numptr_m1; | 304 | var_or_num_t *top_of_stack; |
| 298 | arith_t numptr_val, rez; | 305 | arith_t rez; |
| 299 | const char *err; | 306 | const char *err; |
| 300 | 307 | ||
| 301 | /* There is no operator that can work without arguments */ | 308 | /* There is no operator that can work without arguments */ |
| 302 | if (NUMPTR == numstack) | 309 | if (NUMPTR == numstack) |
| 303 | goto err; | 310 | goto err; |
| 304 | numptr_m1 = NUMPTR - 1; | ||
| 305 | 311 | ||
| 306 | /* Check operand is var with noninteger value */ | 312 | top_of_stack = NUMPTR - 1; |
| 307 | err = arith_lookup_val(math_state, numptr_m1); | 313 | |
| 314 | /* Resolve name to value, if needed */ | ||
| 315 | err = arith_lookup_val(math_state, top_of_stack); | ||
| 308 | if (err) | 316 | if (err) |
| 309 | return err; | 317 | return err; |
| 310 | 318 | ||
| 311 | rez = numptr_m1->val; | 319 | rez = top_of_stack->val; |
| 312 | if (op == TOK_UMINUS) | 320 | if (op == TOK_UMINUS) |
| 313 | rez *= -1; | 321 | rez = -rez; |
| 314 | else if (op == TOK_NOT) | 322 | else if (op == TOK_NOT) |
| 315 | rez = !rez; | 323 | rez = !rez; |
| 316 | else if (op == TOK_BNOT) | 324 | else if (op == TOK_BNOT) |
| @@ -321,112 +329,119 @@ arith_apply(arith_state_t *math_state, operator op, v_n_t *numstack, v_n_t **num | |||
| 321 | rez--; | 329 | rez--; |
| 322 | else if (op != TOK_UPLUS) { | 330 | else if (op != TOK_UPLUS) { |
| 323 | /* Binary operators */ | 331 | /* Binary operators */ |
| 332 | arith_t right_side_val; | ||
| 333 | char bad_second_val; | ||
| 324 | 334 | ||
| 325 | /* check and binary operators need two arguments */ | 335 | /* Binary operators need two arguments */ |
| 326 | if (numptr_m1 == numstack) goto err; | 336 | if (top_of_stack == numstack) |
| 327 | |||
| 328 | /* ... and they pop one */ | ||
| 329 | --NUMPTR; | ||
| 330 | numptr_val = rez; | ||
| 331 | if (op == TOK_CONDITIONAL) { | ||
| 332 | if (!numptr_m1->contidional_second_val_initialized) { | ||
| 333 | /* protect $((expr1 ? expr2)) without ": expr" */ | ||
| 334 | goto err; | ||
| 335 | } | ||
| 336 | rez = numptr_m1->contidional_second_val; | ||
| 337 | } else if (numptr_m1->contidional_second_val_initialized) { | ||
| 338 | /* protect $((expr1 : expr2)) without "expr ? " */ | ||
| 339 | goto err; | 337 | goto err; |
| 338 | /* ...and they pop one */ | ||
| 339 | NUMPTR = top_of_stack; /* this decrements NUMPTR */ | ||
| 340 | |||
| 341 | bad_second_val = top_of_stack->second_val_present; | ||
| 342 | if (op == TOK_CONDITIONAL) { /* ? operation */ | ||
| 343 | /* Make next if (...) protect against | ||
| 344 | * $((expr1 ? expr2)) - that is, missing ": expr" */ | ||
| 345 | bad_second_val = !bad_second_val; | ||
| 346 | } | ||
| 347 | if (bad_second_val) { | ||
| 348 | /* Protect against $((expr <not_?_op> expr1 : expr2)) */ | ||
| 349 | return "malformed ?: operator"; | ||
| 340 | } | 350 | } |
| 341 | numptr_m1 = NUMPTR - 1; | 351 | |
| 352 | top_of_stack--; /* now points to left side */ | ||
| 353 | |||
| 342 | if (op != TOK_ASSIGN) { | 354 | if (op != TOK_ASSIGN) { |
| 343 | /* check operand is var with noninteger value for not '=' */ | 355 | /* Resolve left side value (unless the op is '=') */ |
| 344 | err = arith_lookup_val(math_state, numptr_m1); | 356 | err = arith_lookup_val(math_state, top_of_stack); |
| 345 | if (err) | 357 | if (err) |
| 346 | return err; | 358 | return err; |
| 347 | } | 359 | } |
| 348 | if (op == TOK_CONDITIONAL) { | 360 | |
| 349 | numptr_m1->contidional_second_val = rez; | 361 | right_side_val = rez; |
| 362 | rez = top_of_stack->val; | ||
| 363 | if (op == TOK_CONDITIONAL) /* ? operation */ | ||
| 364 | rez = (rez ? right_side_val : top_of_stack[1].second_val); | ||
| 365 | else if (op == TOK_CONDITIONAL_SEP) { /* : operation */ | ||
| 366 | if (top_of_stack == numstack) { | ||
| 367 | /* Protect against $((expr : expr)) */ | ||
| 368 | return "malformed ?: operator"; | ||
| 369 | } | ||
| 370 | top_of_stack->second_val_present = op; | ||
| 371 | top_of_stack->second_val = right_side_val; | ||
| 350 | } | 372 | } |
| 351 | rez = numptr_m1->val; | 373 | else if (op == TOK_BOR || op == TOK_OR_ASSIGN) |
| 352 | if (op == TOK_BOR || op == TOK_OR_ASSIGN) | 374 | rez |= right_side_val; |
| 353 | rez |= numptr_val; | ||
| 354 | else if (op == TOK_OR) | 375 | else if (op == TOK_OR) |
| 355 | rez = numptr_val || rez; | 376 | rez = right_side_val || rez; |
| 356 | else if (op == TOK_BAND || op == TOK_AND_ASSIGN) | 377 | else if (op == TOK_BAND || op == TOK_AND_ASSIGN) |
| 357 | rez &= numptr_val; | 378 | rez &= right_side_val; |
| 358 | else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN) | 379 | else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN) |
| 359 | rez ^= numptr_val; | 380 | rez ^= right_side_val; |
| 360 | else if (op == TOK_AND) | 381 | else if (op == TOK_AND) |
| 361 | rez = rez && numptr_val; | 382 | rez = rez && right_side_val; |
| 362 | else if (op == TOK_EQ) | 383 | else if (op == TOK_EQ) |
| 363 | rez = (rez == numptr_val); | 384 | rez = (rez == right_side_val); |
| 364 | else if (op == TOK_NE) | 385 | else if (op == TOK_NE) |
| 365 | rez = (rez != numptr_val); | 386 | rez = (rez != right_side_val); |
| 366 | else if (op == TOK_GE) | 387 | else if (op == TOK_GE) |
| 367 | rez = (rez >= numptr_val); | 388 | rez = (rez >= right_side_val); |
| 368 | else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN) | 389 | else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN) |
| 369 | rez >>= numptr_val; | 390 | rez >>= right_side_val; |
| 370 | else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN) | 391 | else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN) |
| 371 | rez <<= numptr_val; | 392 | rez <<= right_side_val; |
| 372 | else if (op == TOK_GT) | 393 | else if (op == TOK_GT) |
| 373 | rez = (rez > numptr_val); | 394 | rez = (rez > right_side_val); |
| 374 | else if (op == TOK_LT) | 395 | else if (op == TOK_LT) |
| 375 | rez = (rez < numptr_val); | 396 | rez = (rez < right_side_val); |
| 376 | else if (op == TOK_LE) | 397 | else if (op == TOK_LE) |
| 377 | rez = (rez <= numptr_val); | 398 | rez = (rez <= right_side_val); |
| 378 | else if (op == TOK_MUL || op == TOK_MUL_ASSIGN) | 399 | else if (op == TOK_MUL || op == TOK_MUL_ASSIGN) |
| 379 | rez *= numptr_val; | 400 | rez *= right_side_val; |
| 380 | else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN) | 401 | else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN) |
| 381 | rez += numptr_val; | 402 | rez += right_side_val; |
| 382 | else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN) | 403 | else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN) |
| 383 | rez -= numptr_val; | 404 | rez -= right_side_val; |
| 384 | else if (op == TOK_ASSIGN || op == TOK_COMMA) | 405 | else if (op == TOK_ASSIGN || op == TOK_COMMA) |
| 385 | rez = numptr_val; | 406 | rez = right_side_val; |
| 386 | else if (op == TOK_CONDITIONAL_SEP) { | 407 | else if (op == TOK_EXPONENT) { |
| 387 | if (numptr_m1 == numstack) { | ||
| 388 | /* protect $((expr : expr)) without "expr ? " */ | ||
| 389 | goto err; | ||
| 390 | } | ||
| 391 | numptr_m1->contidional_second_val_initialized = op; | ||
| 392 | numptr_m1->contidional_second_val = numptr_val; | ||
| 393 | } else if (op == TOK_CONDITIONAL) { | ||
| 394 | rez = rez ? | ||
| 395 | numptr_val : numptr_m1->contidional_second_val; | ||
| 396 | } else if (op == TOK_EXPONENT) { | ||
| 397 | arith_t c; | 408 | arith_t c; |
| 398 | if (numptr_val < 0) | 409 | if (right_side_val < 0) |
| 399 | return "exponent less than 0"; | 410 | return "exponent less than 0"; |
| 400 | c = 1; | 411 | c = 1; |
| 401 | while (--numptr_val >= 0) | 412 | while (--right_side_val >= 0) |
| 402 | c *= rez; | 413 | c *= rez; |
| 403 | rez = c; | 414 | rez = c; |
| 404 | } else if (numptr_val == 0) | 415 | } |
| 416 | else if (right_side_val == 0) | ||
| 405 | return "divide by zero"; | 417 | return "divide by zero"; |
| 406 | else if (op == TOK_DIV || op == TOK_DIV_ASSIGN) | 418 | else if (op == TOK_DIV || op == TOK_DIV_ASSIGN) |
| 407 | rez /= numptr_val; | 419 | rez /= right_side_val; |
| 408 | else if (op == TOK_REM || op == TOK_REM_ASSIGN) | 420 | else if (op == TOK_REM || op == TOK_REM_ASSIGN) |
| 409 | rez %= numptr_val; | 421 | rez %= right_side_val; |
| 410 | } | 422 | } |
| 411 | if (tok_have_assign(op)) { | 423 | |
| 424 | if (is_assign_op(op)) { | ||
| 412 | char buf[sizeof(arith_t)*3 + 2]; | 425 | char buf[sizeof(arith_t)*3 + 2]; |
| 413 | 426 | ||
| 414 | if (numptr_m1->var == NULL) { | 427 | if (top_of_stack->var == NULL) { |
| 415 | /* Hmm, 1=2 ? */ | 428 | /* Hmm, 1=2 ? */ |
| 429 | //TODO: actually, bash allows ++7 but for some reason it evals to 7, not 8 | ||
| 416 | goto err; | 430 | goto err; |
| 417 | } | 431 | } |
| 418 | /* save to shell variable */ | 432 | /* Save to shell variable */ |
| 419 | sprintf(buf, arith_t_fmt, rez); | 433 | sprintf(buf, ARITH_FMT, rez); |
| 420 | setvar(numptr_m1->var, buf); | 434 | setvar(top_of_stack->var, buf); |
| 421 | /* after saving, make previous value for v++ or v-- */ | 435 | /* After saving, make previous value for v++ or v-- */ |
| 422 | if (op == TOK_POST_INC) | 436 | if (op == TOK_POST_INC) |
| 423 | rez--; | 437 | rez--; |
| 424 | else if (op == TOK_POST_DEC) | 438 | else if (op == TOK_POST_DEC) |
| 425 | rez++; | 439 | rez++; |
| 426 | } | 440 | } |
| 427 | numptr_m1->val = rez; | 441 | |
| 428 | /* erase var name, it is just a number now */ | 442 | top_of_stack->val = rez; |
| 429 | numptr_m1->var = NULL; | 443 | /* Erase var name, it is just a number now */ |
| 444 | top_of_stack->var = NULL; | ||
| 430 | return NULL; | 445 | return NULL; |
| 431 | err: | 446 | err: |
| 432 | return "arithmetic syntax error"; | 447 | return "arithmetic syntax error"; |
| @@ -499,16 +514,17 @@ evaluate_string(arith_state_t *math_state, const char *expr) | |||
| 499 | const char *start_expr = expr = skip_whitespace(expr); | 514 | const char *start_expr = expr = skip_whitespace(expr); |
| 500 | unsigned expr_len = strlen(expr) + 2; | 515 | unsigned expr_len = strlen(expr) + 2; |
| 501 | /* Stack of integers */ | 516 | /* Stack of integers */ |
| 502 | /* The proof that there can be no more than strlen(startbuf)/2+1 integers | 517 | /* The proof that there can be no more than strlen(startbuf)/2+1 |
| 503 | * in any given correct or incorrect expression is left as an exercise to | 518 | * integers in any given correct or incorrect expression |
| 504 | * the reader. */ | 519 | * is left as an exercise to the reader. */ |
| 505 | v_n_t *const numstack = alloca((expr_len / 2) * sizeof(numstack[0])); | 520 | var_or_num_t *const numstack = alloca((expr_len / 2) * sizeof(numstack[0])); |
| 506 | v_n_t *numstackptr = numstack; | 521 | var_or_num_t *numstackptr = numstack; |
| 507 | /* Stack of operator tokens */ | 522 | /* Stack of operator tokens */ |
| 508 | operator *const stack = alloca(expr_len * sizeof(stack[0])); | 523 | operator *const stack = alloca(expr_len * sizeof(stack[0])); |
| 509 | operator *stackptr = stack; | 524 | operator *stackptr = stack; |
| 510 | 525 | ||
| 511 | *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */ | 526 | /* Start with a left paren */ |
| 527 | *stackptr++ = lasttok = TOK_LPAREN; | ||
| 512 | errmsg = NULL; | 528 | errmsg = NULL; |
| 513 | 529 | ||
| 514 | while (1) { | 530 | while (1) { |
| @@ -521,7 +537,7 @@ evaluate_string(arith_state_t *math_state, const char *expr) | |||
| 521 | arithval = *expr; | 537 | arithval = *expr; |
| 522 | if (arithval == '\0') { | 538 | if (arithval == '\0') { |
| 523 | if (expr == start_expr) { | 539 | if (expr == start_expr) { |
| 524 | /* Null expression. */ | 540 | /* Null expression */ |
| 525 | numstack->val = 0; | 541 | numstack->val = 0; |
| 526 | goto ret; | 542 | goto ret; |
| 527 | } | 543 | } |
| @@ -558,7 +574,7 @@ evaluate_string(arith_state_t *math_state, const char *expr) | |||
| 558 | safe_strncpy(numstackptr->var, expr, var_name_size); | 574 | safe_strncpy(numstackptr->var, expr, var_name_size); |
| 559 | expr = p; | 575 | expr = p; |
| 560 | num: | 576 | num: |
| 561 | numstackptr->contidional_second_val_initialized = 0; | 577 | numstackptr->second_val_present = 0; |
| 562 | numstackptr++; | 578 | numstackptr++; |
| 563 | lasttok = TOK_NUM; | 579 | lasttok = TOK_NUM; |
| 564 | continue; | 580 | continue; |
| @@ -577,21 +593,32 @@ evaluate_string(arith_state_t *math_state, const char *expr) | |||
| 577 | /* Should be an operator */ | 593 | /* Should be an operator */ |
| 578 | p = op_tokens; | 594 | p = op_tokens; |
| 579 | while (1) { | 595 | while (1) { |
| 580 | const char *e = expr; | 596 | // TODO: bash allows 7+++v, treats it as 7 + ++v |
| 597 | // we treat it as 7++ + v and reject | ||
| 581 | /* Compare expr to current op_tokens[] element */ | 598 | /* Compare expr to current op_tokens[] element */ |
| 582 | while (*p && *e == *p) | 599 | const char *e = expr; |
| 583 | p++, e++; | 600 | while (1) { |
| 584 | if (*p == '\0') { /* match: operator is found */ | 601 | if (*p == '\0') { |
| 585 | expr = e; | 602 | /* Match: operator is found */ |
| 586 | break; | 603 | expr = e; |
| 604 | goto tok_found; | ||
| 605 | } | ||
| 606 | if (*p != *e) | ||
| 607 | break; | ||
| 608 | p++; | ||
| 609 | e++; | ||
| 587 | } | 610 | } |
| 588 | /* Go to next element of op_tokens[] */ | 611 | /* No match, go to next element of op_tokens[] */ |
| 589 | while (*p) | 612 | while (*p) |
| 590 | p++; | 613 | p++; |
| 591 | p += 2; /* skip NUL and TOK_foo bytes */ | 614 | p += 2; /* skip NUL and TOK_foo bytes */ |
| 592 | if (*p == '\0') /* no next element, operator not found */ | 615 | if (*p == '\0') { |
| 616 | /* No next element, operator not found */ | ||
| 617 | //math_state->syntax_error_at = expr; | ||
| 593 | goto err; | 618 | goto err; |
| 619 | } | ||
| 594 | } | 620 | } |
| 621 | tok_found: | ||
| 595 | op = p[1]; /* fetch TOK_foo value */ | 622 | op = p[1]; /* fetch TOK_foo value */ |
| 596 | /* NB: expr now points past the operator */ | 623 | /* NB: expr now points past the operator */ |
| 597 | 624 | ||
| @@ -662,21 +689,21 @@ evaluate_string(arith_state_t *math_state, const char *expr) | |||
| 662 | } | 689 | } |
| 663 | errmsg = arith_apply(math_state, prev_op, numstack, &numstackptr); | 690 | errmsg = arith_apply(math_state, prev_op, numstack, &numstackptr); |
| 664 | if (errmsg) | 691 | if (errmsg) |
| 665 | goto ret; | 692 | goto err_with_custom_msg; |
| 666 | } | 693 | } |
| 667 | if (op == TOK_RPAREN) { | 694 | if (op == TOK_RPAREN) |
| 668 | goto err; | 695 | goto err; |
| 669 | } | ||
| 670 | } | 696 | } |
| 671 | 697 | ||
| 672 | /* Push this operator to the stack and remember it. */ | 698 | /* Push this operator to the stack and remember it */ |
| 673 | *stackptr++ = lasttok = op; | 699 | *stackptr++ = lasttok = op; |
| 674 | next: ; | 700 | next: ; |
| 675 | } /* while (1) */ | 701 | } /* while (1) */ |
| 676 | 702 | ||
| 677 | err: | 703 | err: |
| 678 | numstack->val = -1; | ||
| 679 | errmsg = "arithmetic syntax error"; | 704 | errmsg = "arithmetic syntax error"; |
| 705 | err_with_custom_msg: | ||
| 706 | numstack->val = -1; | ||
| 680 | ret: | 707 | ret: |
| 681 | math_state->errmsg = errmsg; | 708 | math_state->errmsg = errmsg; |
| 682 | return numstack->val; | 709 | return numstack->val; |
