1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116#include "libbb.h"
117#include "math.h"
118
119#define lookupvar (math_state->lookupvar)
120#define setvar (math_state->setvar )
121
122
123typedef unsigned char operator;
124
125
126
127
128
129
130
131#define tok_decl(prec,id) (((id)<<5) | (prec))
132#define PREC(op) ((op) & 0x1F)
133
134#define TOK_LPAREN tok_decl(0,0)
135
136#define TOK_COMMA tok_decl(1,0)
137
138
139
140
141
142#define TOK_ASSIGN tok_decl(2,0)
143#define TOK_AND_ASSIGN tok_decl(2,1)
144#define TOK_OR_ASSIGN tok_decl(2,2)
145#define TOK_XOR_ASSIGN tok_decl(2,3)
146#define TOK_PLUS_ASSIGN tok_decl(2,4)
147#define TOK_MINUS_ASSIGN tok_decl(2,5)
148#define TOK_LSHIFT_ASSIGN tok_decl(2,6)
149#define TOK_RSHIFT_ASSIGN tok_decl(2,7)
150
151#define TOK_MUL_ASSIGN tok_decl(3,0)
152#define TOK_DIV_ASSIGN tok_decl(3,1)
153#define TOK_REM_ASSIGN tok_decl(3,2)
154
155#define fix_assignment_prec(prec) do { if (prec == 3) prec = 2; } while (0)
156
157
158#define TOK_CONDITIONAL tok_decl(4,0)
159#define TOK_CONDITIONAL_SEP tok_decl(4,1)
160
161#define TOK_OR tok_decl(5,0)
162
163#define TOK_AND tok_decl(6,0)
164
165#define TOK_BOR tok_decl(7,0)
166
167#define TOK_BXOR tok_decl(8,0)
168
169#define TOK_BAND tok_decl(9,0)
170
171#define TOK_EQ tok_decl(10,0)
172#define TOK_NE tok_decl(10,1)
173
174#define TOK_LT tok_decl(11,0)
175#define TOK_GT tok_decl(11,1)
176#define TOK_GE tok_decl(11,2)
177#define TOK_LE tok_decl(11,3)
178
179#define TOK_LSHIFT tok_decl(12,0)
180#define TOK_RSHIFT tok_decl(12,1)
181
182#define TOK_ADD tok_decl(13,0)
183#define TOK_SUB tok_decl(13,1)
184
185#define TOK_MUL tok_decl(14,0)
186#define TOK_DIV tok_decl(14,1)
187#define TOK_REM tok_decl(14,2)
188
189
190#define TOK_EXPONENT tok_decl(15,1)
191
192
193#define UNARYPREC 16
194#define TOK_BNOT tok_decl(UNARYPREC,0)
195#define TOK_NOT tok_decl(UNARYPREC,1)
196
197#define TOK_UMINUS tok_decl(UNARYPREC+1,0)
198#define TOK_UPLUS tok_decl(UNARYPREC+1,1)
199
200#define PREC_PRE (UNARYPREC+2)
201
202#define TOK_PRE_INC tok_decl(PREC_PRE, 0)
203#define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
204
205#define PREC_POST (UNARYPREC+3)
206
207#define TOK_POST_INC tok_decl(PREC_POST, 0)
208#define TOK_POST_DEC tok_decl(PREC_POST, 1)
209
210#define SPEC_PREC (UNARYPREC+4)
211
212#define TOK_NUM tok_decl(SPEC_PREC, 0)
213#define TOK_RPAREN tok_decl(SPEC_PREC, 1)
214
215static int
216is_assign_op(operator op)
217{
218 operator prec = PREC(op);
219 fix_assignment_prec(prec);
220 return prec == PREC(TOK_ASSIGN)
221 || prec == PREC_PRE
222 || prec == PREC_POST;
223}
224
225static int
226is_right_associative(operator prec)
227{
228 return prec == PREC(TOK_ASSIGN)
229 || prec == PREC(TOK_EXPONENT)
230 || prec == PREC(TOK_CONDITIONAL);
231}
232
233
234typedef struct {
235 arith_t val;
236
237
238
239
240
241
242 arith_t second_val;
243 char second_val_present;
244
245 char *var;
246} var_or_num_t;
247
248typedef struct remembered_name {
249 struct remembered_name *next;
250 const char *var;
251} remembered_name;
252
253
254static arith_t FAST_FUNC
255evaluate_string(arith_state_t *math_state, const char *expr);
256
257static const char*
258arith_lookup_val(arith_state_t *math_state, var_or_num_t *t)
259{
260 if (t->var) {
261 const char *p = lookupvar(t->var);
262 if (p) {
263 remembered_name *cur;
264 remembered_name cur_save;
265
266
267
268
269 for (cur = math_state->list_of_recursed_names; cur; cur = cur->next) {
270 if (strcmp(cur->var, t->var) == 0) {
271
272 return "expression recursion loop detected";
273 }
274 }
275
276
277 cur = math_state->list_of_recursed_names;
278 cur_save.var = t->var;
279 cur_save.next = cur;
280 math_state->list_of_recursed_names = &cur_save;
281
282
283 t->val = evaluate_string(math_state, p);
284
285
286 math_state->list_of_recursed_names = cur;
287
288 return math_state->errmsg;
289 }
290
291 t->val = 0;
292 }
293 return 0;
294}
295
296
297
298
299static NOINLINE const char*
300arith_apply(arith_state_t *math_state, operator op, var_or_num_t *numstack, var_or_num_t **numstackptr)
301{
302#define NUMPTR (*numstackptr)
303
304 var_or_num_t *top_of_stack;
305 arith_t rez;
306 const char *err;
307
308
309 if (NUMPTR == numstack)
310 goto err;
311
312 top_of_stack = NUMPTR - 1;
313
314
315 err = arith_lookup_val(math_state, top_of_stack);
316 if (err)
317 return err;
318
319 rez = top_of_stack->val;
320 if (op == TOK_UMINUS)
321 rez = -rez;
322 else if (op == TOK_NOT)
323 rez = !rez;
324 else if (op == TOK_BNOT)
325 rez = ~rez;
326 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
327 rez++;
328 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
329 rez--;
330 else if (op != TOK_UPLUS) {
331
332 arith_t right_side_val;
333 char bad_second_val;
334
335
336 if (top_of_stack == numstack)
337 goto err;
338
339 NUMPTR = top_of_stack;
340
341 bad_second_val = top_of_stack->second_val_present;
342 if (op == TOK_CONDITIONAL) {
343
344
345 bad_second_val = !bad_second_val;
346 }
347 if (bad_second_val) {
348
349 return "malformed ?: operator";
350 }
351
352 top_of_stack--;
353
354 if (op != TOK_ASSIGN) {
355
356 err = arith_lookup_val(math_state, top_of_stack);
357 if (err)
358 return err;
359 }
360
361 right_side_val = rez;
362 rez = top_of_stack->val;
363 if (op == TOK_CONDITIONAL)
364 rez = (rez ? right_side_val : top_of_stack[1].second_val);
365 else if (op == TOK_CONDITIONAL_SEP) {
366 if (top_of_stack == numstack) {
367
368 return "malformed ?: operator";
369 }
370 top_of_stack->second_val_present = op;
371 top_of_stack->second_val = right_side_val;
372 }
373 else if (op == TOK_BOR || op == TOK_OR_ASSIGN)
374 rez |= right_side_val;
375 else if (op == TOK_OR)
376 rez = right_side_val || rez;
377 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
378 rez &= right_side_val;
379 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
380 rez ^= right_side_val;
381 else if (op == TOK_AND)
382 rez = rez && right_side_val;
383 else if (op == TOK_EQ)
384 rez = (rez == right_side_val);
385 else if (op == TOK_NE)
386 rez = (rez != right_side_val);
387 else if (op == TOK_GE)
388 rez = (rez >= right_side_val);
389 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
390 rez >>= right_side_val;
391 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
392 rez <<= right_side_val;
393 else if (op == TOK_GT)
394 rez = (rez > right_side_val);
395 else if (op == TOK_LT)
396 rez = (rez < right_side_val);
397 else if (op == TOK_LE)
398 rez = (rez <= right_side_val);
399 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
400 rez *= right_side_val;
401 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
402 rez += right_side_val;
403 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
404 rez -= right_side_val;
405 else if (op == TOK_ASSIGN || op == TOK_COMMA)
406 rez = right_side_val;
407 else if (op == TOK_EXPONENT) {
408 arith_t c;
409 if (right_side_val < 0)
410 return "exponent less than 0";
411 c = 1;
412 while (--right_side_val >= 0)
413 c *= rez;
414 rez = c;
415 }
416 else if (right_side_val == 0)
417 return "divide by zero";
418 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
419 rez /= right_side_val;
420 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
421 rez %= right_side_val;
422 }
423
424 if (is_assign_op(op)) {
425 char buf[sizeof(arith_t)*3 + 2];
426
427 if (top_of_stack->var == NULL) {
428
429
430 goto err;
431 }
432
433 sprintf(buf, ARITH_FMT, rez);
434 setvar(top_of_stack->var, buf);
435
436 if (op == TOK_POST_INC)
437 rez--;
438 else if (op == TOK_POST_DEC)
439 rez++;
440 }
441
442 top_of_stack->val = rez;
443
444 top_of_stack->var = NULL;
445 return NULL;
446 err:
447 return "arithmetic syntax error";
448#undef NUMPTR
449}
450
451
452static const char op_tokens[] ALIGN1 = {
453 '<','<','=',0, TOK_LSHIFT_ASSIGN,
454 '>','>','=',0, TOK_RSHIFT_ASSIGN,
455 '<','<', 0, TOK_LSHIFT,
456 '>','>', 0, TOK_RSHIFT,
457 '|','|', 0, TOK_OR,
458 '&','&', 0, TOK_AND,
459 '!','=', 0, TOK_NE,
460 '<','=', 0, TOK_LE,
461 '>','=', 0, TOK_GE,
462 '=','=', 0, TOK_EQ,
463 '|','=', 0, TOK_OR_ASSIGN,
464 '&','=', 0, TOK_AND_ASSIGN,
465 '*','=', 0, TOK_MUL_ASSIGN,
466 '/','=', 0, TOK_DIV_ASSIGN,
467 '%','=', 0, TOK_REM_ASSIGN,
468 '+','=', 0, TOK_PLUS_ASSIGN,
469 '-','=', 0, TOK_MINUS_ASSIGN,
470 '-','-', 0, TOK_POST_DEC,
471 '^','=', 0, TOK_XOR_ASSIGN,
472 '+','+', 0, TOK_POST_INC,
473 '*','*', 0, TOK_EXPONENT,
474 '!', 0, TOK_NOT,
475 '<', 0, TOK_LT,
476 '>', 0, TOK_GT,
477 '=', 0, TOK_ASSIGN,
478 '|', 0, TOK_BOR,
479 '&', 0, TOK_BAND,
480 '*', 0, TOK_MUL,
481 '/', 0, TOK_DIV,
482 '%', 0, TOK_REM,
483 '+', 0, TOK_ADD,
484 '-', 0, TOK_SUB,
485 '^', 0, TOK_BXOR,
486
487 '~', 0, TOK_BNOT,
488 ',', 0, TOK_COMMA,
489 '?', 0, TOK_CONDITIONAL,
490 ':', 0, TOK_CONDITIONAL_SEP,
491 ')', 0, TOK_RPAREN,
492 '(', 0, TOK_LPAREN,
493 0
494};
495#define ptr_to_rparen (&op_tokens[sizeof(op_tokens)-7])
496
497const char* FAST_FUNC
498endofname(const char *name)
499{
500 if (!is_name(*name))
501 return name;
502 while (*++name) {
503 if (!is_in_name(*name))
504 break;
505 }
506 return name;
507}
508
509static arith_t FAST_FUNC
510evaluate_string(arith_state_t *math_state, const char *expr)
511{
512 operator lasttok;
513 const char *errmsg;
514 const char *start_expr = expr = skip_whitespace(expr);
515 unsigned expr_len = strlen(expr) + 2;
516
517
518
519
520 var_or_num_t *const numstack = alloca((expr_len / 2) * sizeof(numstack[0]));
521 var_or_num_t *numstackptr = numstack;
522
523 operator *const stack = alloca(expr_len * sizeof(stack[0]));
524 operator *stackptr = stack;
525
526
527 *stackptr++ = lasttok = TOK_LPAREN;
528 errmsg = NULL;
529
530 while (1) {
531 const char *p;
532 operator op;
533 operator prec;
534 char arithval;
535
536 expr = skip_whitespace(expr);
537 arithval = *expr;
538 if (arithval == '\0') {
539 if (expr == start_expr) {
540
541 numstack->val = 0;
542 goto ret;
543 }
544
545
546
547
548
549
550 if (expr != ptr_to_rparen + 1) {
551
552
553
554 expr = ptr_to_rparen;
555 continue;
556 }
557
558 if (numstackptr != numstack + 1) {
559
560 goto err;
561 }
562 if (numstack->var) {
563
564 errmsg = arith_lookup_val(math_state, numstack);
565 }
566 goto ret;
567 }
568
569 p = endofname(expr);
570 if (p != expr) {
571
572 size_t var_name_size = (p-expr) + 1;
573 numstackptr->var = alloca(var_name_size);
574 safe_strncpy(numstackptr->var, expr, var_name_size);
575 expr = p;
576 num:
577 numstackptr->second_val_present = 0;
578 numstackptr++;
579 lasttok = TOK_NUM;
580 continue;
581 }
582
583 if (isdigit(arithval)) {
584
585 numstackptr->var = NULL;
586 errno = 0;
587 numstackptr->val = strto_arith_t(expr, (char**) &expr, 0);
588 if (errno)
589 numstackptr->val = 0;
590 goto num;
591 }
592
593
594 p = op_tokens;
595 while (1) {
596
597
598
599 const char *e = expr;
600 while (1) {
601 if (*p == '\0') {
602
603 expr = e;
604 goto tok_found;
605 }
606 if (*p != *e)
607 break;
608 p++;
609 e++;
610 }
611
612 while (*p)
613 p++;
614 p += 2;
615 if (*p == '\0') {
616
617
618 goto err;
619 }
620 }
621 tok_found:
622 op = p[1];
623
624
625
626 if (lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
627 lasttok = TOK_NUM;
628
629
630
631
632
633 if (lasttok != TOK_NUM) {
634 switch (op) {
635 case TOK_ADD:
636 op = TOK_UPLUS;
637 break;
638 case TOK_SUB:
639 op = TOK_UMINUS;
640 break;
641 case TOK_POST_INC:
642 op = TOK_PRE_INC;
643 break;
644 case TOK_POST_DEC:
645 op = TOK_PRE_DEC;
646 break;
647 }
648 }
649
650
651
652
653
654
655
656
657
658
659
660 prec = PREC(op);
661 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
662
663 if (lasttok != TOK_NUM) {
664
665 goto err;
666 }
667 while (stackptr != stack) {
668 operator prev_op = *--stackptr;
669 if (op == TOK_RPAREN) {
670
671
672
673 if (prev_op == TOK_LPAREN) {
674
675
676 lasttok = TOK_NUM;
677 goto next;
678 }
679 } else {
680 operator prev_prec = PREC(prev_op);
681 fix_assignment_prec(prec);
682 fix_assignment_prec(prev_prec);
683 if (prev_prec < prec
684 || (prev_prec == prec && is_right_associative(prec))
685 ) {
686 stackptr++;
687 break;
688 }
689 }
690 errmsg = arith_apply(math_state, prev_op, numstack, &numstackptr);
691 if (errmsg)
692 goto err_with_custom_msg;
693 }
694 if (op == TOK_RPAREN)
695 goto err;
696 }
697
698
699 *stackptr++ = lasttok = op;
700 next: ;
701 }
702
703 err:
704 errmsg = "arithmetic syntax error";
705 err_with_custom_msg:
706 numstack->val = -1;
707 ret:
708 math_state->errmsg = errmsg;
709 return numstack->val;
710}
711
712arith_t FAST_FUNC
713arith(arith_state_t *math_state, const char *expr)
714{
715 math_state->errmsg = NULL;
716 math_state->list_of_recursed_names = NULL;
717 return evaluate_string(math_state, expr);
718}
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751