diff options
author | Denys Vlasenko <dvlasenk@redhat.com> | 2010-09-13 11:11:40 +0200 |
---|---|---|
committer | Denys Vlasenko <dvlasenk@redhat.com> | 2010-09-13 11:11:40 +0200 |
commit | bd14770b0c8594ce5b0ab9b0b1249b72fc781dd3 (patch) | |
tree | 8907f85fa7657f613c50ac1e01ad6a3f2f855783 | |
parent | 51850c818cf909cde0e07091a8015532cc645b7a (diff) | |
download | busybox-w32-bd14770b0c8594ce5b0ab9b0b1249b72fc781dd3.tar.gz busybox-w32-bd14770b0c8594ce5b0ab9b0b1249b72fc781dd3.tar.bz2 busybox-w32-bd14770b0c8594ce5b0ab9b0b1249b72fc781dd3.zip |
shell/math.c: small code shrink; fixed incomprehensible comments
function old new delta
arith_apply 1334 1304 -30
Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
-rw-r--r-- | shell/math.c | 225 |
1 files changed, 113 insertions, 112 deletions
diff --git a/shell/math.c b/shell/math.c index c698a442b..a9fbc8910 100644 --- a/shell/math.c +++ b/shell/math.c | |||
@@ -52,17 +52,18 @@ | |||
52 | * than a comparable parser written in yacc. The supported operators are | 52 | * than a comparable parser written in yacc. The supported operators are |
53 | * listed in #defines below. Parens, order of operations, and error handling | 53 | * listed in #defines below. Parens, order of operations, and error handling |
54 | * are supported. This code is thread safe. The exact expression format should | 54 | * are supported. This code is thread safe. The exact expression format should |
55 | * be that which POSIX specifies for shells. */ | 55 | * be that which POSIX specifies for shells. |
56 | 56 | * | |
57 | /* The code uses a simple two-stack algorithm. See | 57 | * The code uses a simple two-stack algorithm. See |
58 | * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html | 58 | * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html |
59 | * for a detailed explanation of the infix-to-postfix algorithm on which | 59 | * for a detailed explanation of the infix-to-postfix algorithm on which |
60 | * this is based (this code differs in that it applies operators immediately | 60 | * this is based (this code differs in that it applies operators immediately |
61 | * to the stack instead of adding them to a queue to end up with an | 61 | * to the stack instead of adding them to a queue to end up with an |
62 | * expression). */ | 62 | * expression). |
63 | 63 | * | |
64 | /* To use the routine, call it with an expression string and error return | 64 | * To use the routine, call it with an expression string and error return |
65 | * pointer */ | 65 | * pointer |
66 | */ | ||
66 | 67 | ||
67 | /* | 68 | /* |
68 | * Aug 24, 2001 Manuel Novoa III | 69 | * Aug 24, 2001 Manuel Novoa III |
@@ -104,22 +105,21 @@ | |||
104 | * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru> | 105 | * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru> |
105 | * | 106 | * |
106 | * - allow access to variable, | 107 | * - allow access to variable, |
107 | * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6) | 108 | * use recursive value indirection: c="2*2"; a="c"; echo $((a+=2)) produce 6 |
108 | * - realize assign syntax (VAR=expr, +=, *= etc) | 109 | * - implement assign syntax (VAR=expr, +=, *= etc) |
109 | * - realize exponentiation (** operator) | 110 | * - implement exponentiation (** operator) |
110 | * - realize comma separated - expr, expr | 111 | * - implement comma separated - expr, expr |
111 | * - realise ++expr --expr expr++ expr-- | 112 | * - implement ++expr --expr expr++ expr-- |
112 | * - realise expr ? expr : expr (but, second expr calculate always) | 113 | * - implement expr ? expr : expr (but second expr is always calculated) |
113 | * - allow hexadecimal and octal numbers | 114 | * - allow hexadecimal and octal numbers |
114 | * - was restored loses XOR operator | 115 | * - restore lost XOR operator |
115 | * - remove one goto label, added three ;-) | 116 | * - protect $((num num)) as true zero expr (Manuel's error) |
116 | * - protect $((num num)) as true zero expr (Manuel`s error) | ||
117 | * - always use special isspace(), see comment from bash ;-) | 117 | * - always use special isspace(), see comment from bash ;-) |
118 | */ | 118 | */ |
119 | #include "libbb.h" | 119 | #include "libbb.h" |
120 | #include "math.h" | 120 | #include "math.h" |
121 | 121 | ||
122 | #define a_e_h_t arith_eval_hooks_t | 122 | #define a_e_h_t arith_eval_hooks_t |
123 | #define lookupvar (math_hooks->lookupvar) | 123 | #define lookupvar (math_hooks->lookupvar) |
124 | #define setvar (math_hooks->setvar ) | 124 | #define setvar (math_hooks->setvar ) |
125 | //#define endofname (math_hooks->endofname) | 125 | //#define endofname (math_hooks->endofname) |
@@ -130,103 +130,104 @@ typedef unsigned char operator; | |||
130 | * precedence, and 3 high bits are an ID unique across operators of that | 130 | * precedence, and 3 high bits are an ID unique across operators of that |
131 | * precedence. The ID portion is so that multiple operators can have the | 131 | * precedence. The ID portion is so that multiple operators can have the |
132 | * same precedence, ensuring that the leftmost one is evaluated first. | 132 | * same precedence, ensuring that the leftmost one is evaluated first. |
133 | * Consider * and /. */ | 133 | * Consider * and / |
134 | 134 | */ | |
135 | #define tok_decl(prec,id) (((id)<<5)|(prec)) | 135 | #define tok_decl(prec,id) (((id)<<5) | (prec)) |
136 | #define PREC(op) ((op) & 0x1F) | 136 | #define PREC(op) ((op) & 0x1F) |
137 | |||
138 | #define TOK_LPAREN tok_decl(0,0) | ||
139 | 137 | ||
140 | #define TOK_COMMA tok_decl(1,0) | 138 | #define TOK_LPAREN tok_decl(0,0) |
141 | 139 | ||
142 | #define TOK_ASSIGN tok_decl(2,0) | 140 | #define TOK_COMMA tok_decl(1,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 | 141 | ||
151 | #define TOK_MUL_ASSIGN tok_decl(3,0) | 142 | /* All assignments are right associative and have the same precedence, |
152 | #define TOK_DIV_ASSIGN tok_decl(3,1) | 143 | * but there are 11 of them, which doesn't fit into 3 bits for unique id. |
153 | #define TOK_REM_ASSIGN tok_decl(3,2) | 144 | * Abusing another precedence level: |
145 | */ | ||
146 | #define TOK_ASSIGN tok_decl(2,0) | ||
147 | #define TOK_AND_ASSIGN tok_decl(2,1) | ||
148 | #define TOK_OR_ASSIGN tok_decl(2,2) | ||
149 | #define TOK_XOR_ASSIGN tok_decl(2,3) | ||
150 | #define TOK_PLUS_ASSIGN tok_decl(2,4) | ||
151 | #define TOK_MINUS_ASSIGN tok_decl(2,5) | ||
152 | #define TOK_LSHIFT_ASSIGN tok_decl(2,6) | ||
153 | #define TOK_RSHIFT_ASSIGN tok_decl(2,7) | ||
154 | 154 | ||
155 | /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */ | 155 | #define TOK_MUL_ASSIGN tok_decl(3,0) |
156 | #define convert_prec_is_assign(prec) do { if (prec == 3) prec = 2; } while (0) | 156 | #define TOK_DIV_ASSIGN tok_decl(3,1) |
157 | #define TOK_REM_ASSIGN tok_decl(3,2) | ||
157 | 158 | ||
158 | /* conditional is right associativity too */ | 159 | #define fix_assignment_prec(prec) do { if (prec == 3) prec = 2; } while (0) |
159 | #define TOK_CONDITIONAL tok_decl(4,0) | ||
160 | #define TOK_CONDITIONAL_SEP tok_decl(4,1) | ||
161 | 160 | ||
162 | #define TOK_OR tok_decl(5,0) | 161 | /* ternary conditional operator is right associative too */ |
162 | #define TOK_CONDITIONAL tok_decl(4,0) | ||
163 | #define TOK_CONDITIONAL_SEP tok_decl(4,1) | ||
163 | 164 | ||
164 | #define TOK_AND tok_decl(6,0) | 165 | #define TOK_OR tok_decl(5,0) |
165 | 166 | ||
166 | #define TOK_BOR tok_decl(7,0) | 167 | #define TOK_AND tok_decl(6,0) |
167 | 168 | ||
168 | #define TOK_BXOR tok_decl(8,0) | 169 | #define TOK_BOR tok_decl(7,0) |
169 | 170 | ||
170 | #define TOK_BAND tok_decl(9,0) | 171 | #define TOK_BXOR tok_decl(8,0) |
171 | 172 | ||
172 | #define TOK_EQ tok_decl(10,0) | 173 | #define TOK_BAND tok_decl(9,0) |
173 | #define TOK_NE tok_decl(10,1) | ||
174 | 174 | ||
175 | #define TOK_LT tok_decl(11,0) | 175 | #define TOK_EQ tok_decl(10,0) |
176 | #define TOK_GT tok_decl(11,1) | 176 | #define TOK_NE tok_decl(10,1) |
177 | #define TOK_GE tok_decl(11,2) | ||
178 | #define TOK_LE tok_decl(11,3) | ||
179 | 177 | ||
180 | #define TOK_LSHIFT tok_decl(12,0) | 178 | #define TOK_LT tok_decl(11,0) |
181 | #define TOK_RSHIFT tok_decl(12,1) | 179 | #define TOK_GT tok_decl(11,1) |
180 | #define TOK_GE tok_decl(11,2) | ||
181 | #define TOK_LE tok_decl(11,3) | ||
182 | 182 | ||
183 | #define TOK_ADD tok_decl(13,0) | 183 | #define TOK_LSHIFT tok_decl(12,0) |
184 | #define TOK_SUB tok_decl(13,1) | 184 | #define TOK_RSHIFT tok_decl(12,1) |
185 | 185 | ||
186 | #define TOK_MUL tok_decl(14,0) | 186 | #define TOK_ADD tok_decl(13,0) |
187 | #define TOK_DIV tok_decl(14,1) | 187 | #define TOK_SUB tok_decl(13,1) |
188 | #define TOK_REM tok_decl(14,2) | ||
189 | 188 | ||
190 | /* exponent is right associativity */ | 189 | #define TOK_MUL tok_decl(14,0) |
191 | #define TOK_EXPONENT tok_decl(15,1) | 190 | #define TOK_DIV tok_decl(14,1) |
191 | #define TOK_REM tok_decl(14,2) | ||
192 | 192 | ||
193 | /* For now unary operators. */ | 193 | /* exponent is right associative */ |
194 | #define UNARYPREC 16 | 194 | #define TOK_EXPONENT tok_decl(15,1) |
195 | #define TOK_BNOT tok_decl(UNARYPREC,0) | ||
196 | #define TOK_NOT tok_decl(UNARYPREC,1) | ||
197 | 195 | ||
198 | #define TOK_UMINUS tok_decl(UNARYPREC+1,0) | 196 | /* unary operators */ |
199 | #define TOK_UPLUS tok_decl(UNARYPREC+1,1) | 197 | #define UNARYPREC 16 |
198 | #define TOK_BNOT tok_decl(UNARYPREC,0) | ||
199 | #define TOK_NOT tok_decl(UNARYPREC,1) | ||
200 | 200 | ||
201 | #define PREC_PRE (UNARYPREC+2) | 201 | #define TOK_UMINUS tok_decl(UNARYPREC+1,0) |
202 | #define TOK_UPLUS tok_decl(UNARYPREC+1,1) | ||
202 | 203 | ||
203 | #define TOK_PRE_INC tok_decl(PREC_PRE, 0) | 204 | #define PREC_PRE (UNARYPREC+2) |
204 | #define TOK_PRE_DEC tok_decl(PREC_PRE, 1) | ||
205 | 205 | ||
206 | #define PREC_POST (UNARYPREC+3) | 206 | #define TOK_PRE_INC tok_decl(PREC_PRE, 0) |
207 | #define TOK_PRE_DEC tok_decl(PREC_PRE, 1) | ||
207 | 208 | ||
208 | #define TOK_POST_INC tok_decl(PREC_POST, 0) | 209 | #define PREC_POST (UNARYPREC+3) |
209 | #define TOK_POST_DEC tok_decl(PREC_POST, 1) | ||
210 | 210 | ||
211 | #define SPEC_PREC (UNARYPREC+4) | 211 | #define TOK_POST_INC tok_decl(PREC_POST, 0) |
212 | #define TOK_POST_DEC tok_decl(PREC_POST, 1) | ||
212 | 213 | ||
213 | #define TOK_NUM tok_decl(SPEC_PREC, 0) | 214 | #define SPEC_PREC (UNARYPREC+4) |
214 | #define TOK_RPAREN tok_decl(SPEC_PREC, 1) | ||
215 | 215 | ||
216 | #define NUMPTR (*numstackptr) | 216 | #define TOK_NUM tok_decl(SPEC_PREC, 0) |
217 | #define TOK_RPAREN tok_decl(SPEC_PREC, 1) | ||
217 | 218 | ||
218 | static int | 219 | static int |
219 | tok_have_assign(operator op) | 220 | tok_have_assign(operator op) |
220 | { | 221 | { |
221 | operator prec = PREC(op); | 222 | operator prec = PREC(op); |
222 | 223 | ||
223 | convert_prec_is_assign(prec); | 224 | fix_assignment_prec(prec); |
224 | return (prec == PREC(TOK_ASSIGN) || | 225 | return (prec == PREC(TOK_ASSIGN) || |
225 | prec == PREC_PRE || prec == PREC_POST); | 226 | prec == PREC_PRE || prec == PREC_POST); |
226 | } | 227 | } |
227 | 228 | ||
228 | static int | 229 | static int |
229 | is_right_associativity(operator prec) | 230 | is_right_associative(operator prec) |
230 | { | 231 | { |
231 | return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) | 232 | return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) |
232 | || prec == PREC(TOK_CONDITIONAL)); | 233 | || prec == PREC(TOK_CONDITIONAL)); |
@@ -255,25 +256,25 @@ arith_lookup_val(v_n_t *t, a_e_h_t *math_hooks) | |||
255 | 256 | ||
256 | if (p) { | 257 | if (p) { |
257 | int errcode; | 258 | int errcode; |
258 | |||
259 | /* recursive try as expression */ | ||
260 | chk_var_recursive_looped_t *cur; | 259 | chk_var_recursive_looped_t *cur; |
261 | chk_var_recursive_looped_t cur_save; | 260 | chk_var_recursive_looped_t cur_save; |
262 | 261 | ||
262 | /* recursively try p as expression */ | ||
263 | |||
263 | for (cur = prev_chk_var_recursive; cur; cur = cur->next) { | 264 | for (cur = prev_chk_var_recursive; cur; cur = cur->next) { |
264 | if (strcmp(cur->var, t->var) == 0) { | 265 | if (strcmp(cur->var, t->var) == 0) { |
265 | /* expression recursion loop detected */ | 266 | /* expression recursion loop detected */ |
266 | return -5; | 267 | return -5; |
267 | } | 268 | } |
268 | } | 269 | } |
269 | /* save current lookuped var name */ | 270 | /* save current var name */ |
270 | cur = prev_chk_var_recursive; | 271 | cur = prev_chk_var_recursive; |
271 | cur_save.var = t->var; | 272 | cur_save.var = t->var; |
272 | cur_save.next = cur; | 273 | cur_save.next = cur; |
273 | prev_chk_var_recursive = &cur_save; | 274 | prev_chk_var_recursive = &cur_save; |
274 | 275 | ||
275 | t->val = arith (p, &errcode, math_hooks); | 276 | t->val = arith(p, &errcode, math_hooks); |
276 | /* restore previous ptr after recursiving */ | 277 | /* restore previous ptr after recursion */ |
277 | prev_chk_var_recursive = cur; | 278 | prev_chk_var_recursive = cur; |
278 | return errcode; | 279 | return errcode; |
279 | } | 280 | } |
@@ -283,21 +284,24 @@ arith_lookup_val(v_n_t *t, a_e_h_t *math_hooks) | |||
283 | return 0; | 284 | return 0; |
284 | } | 285 | } |
285 | 286 | ||
286 | /* "applying" a token means performing it on the top elements on the integer | 287 | /* "Applying" a token means performing it on the top elements on the integer |
287 | * stack. For a unary operator it will only change the top element, but a | 288 | * stack. For an unary operator it will only change the top element, but a |
288 | * binary operator will pop two arguments and push a result */ | 289 | * binary operator will pop two arguments and push the result */ |
289 | static NOINLINE int | 290 | static NOINLINE int |
290 | arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr, a_e_h_t *math_hooks) | 291 | arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr, a_e_h_t *math_hooks) |
291 | { | 292 | { |
293 | #define NUMPTR (*numstackptr) | ||
294 | |||
292 | v_n_t *numptr_m1; | 295 | v_n_t *numptr_m1; |
293 | arith_t numptr_val, rez; | 296 | arith_t numptr_val, rez; |
294 | int ret_arith_lookup_val; | 297 | int ret_arith_lookup_val; |
295 | 298 | ||
296 | /* There is no operator that can work without arguments */ | 299 | /* There is no operator that can work without arguments */ |
297 | if (NUMPTR == numstack) goto err; | 300 | if (NUMPTR == numstack) |
301 | goto err; | ||
298 | numptr_m1 = NUMPTR - 1; | 302 | numptr_m1 = NUMPTR - 1; |
299 | 303 | ||
300 | /* check operand is var with noninteger value */ | 304 | /* Check operand is var with noninteger value */ |
301 | ret_arith_lookup_val = arith_lookup_val(numptr_m1, math_hooks); | 305 | ret_arith_lookup_val = arith_lookup_val(numptr_m1, math_hooks); |
302 | if (ret_arith_lookup_val) | 306 | if (ret_arith_lookup_val) |
303 | return ret_arith_lookup_val; | 307 | return ret_arith_lookup_val; |
@@ -388,16 +392,13 @@ arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr, a_e_h_t *math_hoo | |||
388 | rez = rez ? | 392 | rez = rez ? |
389 | numptr_val : numptr_m1->contidional_second_val; | 393 | numptr_val : numptr_m1->contidional_second_val; |
390 | } else if (op == TOK_EXPONENT) { | 394 | } else if (op == TOK_EXPONENT) { |
395 | arith_t c; | ||
391 | if (numptr_val < 0) | 396 | if (numptr_val < 0) |
392 | return -3; /* exponent less than 0 */ | 397 | return -3; /* exponent less than 0 */ |
393 | else { | 398 | c = 1; |
394 | arith_t c = 1; | 399 | while (--numptr_val >= 0) |
395 | 400 | c *= rez; | |
396 | if (numptr_val) | 401 | rez = c; |
397 | while (numptr_val--) | ||
398 | c *= rez; | ||
399 | rez = c; | ||
400 | } | ||
401 | } else if (numptr_val==0) /* zero divisor check */ | 402 | } else if (numptr_val==0) /* zero divisor check */ |
402 | return -2; | 403 | return -2; |
403 | else if (op == TOK_DIV || op == TOK_DIV_ASSIGN) | 404 | else if (op == TOK_DIV || op == TOK_DIV_ASSIGN) |
@@ -422,11 +423,12 @@ arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr, a_e_h_t *math_hoo | |||
422 | rez++; | 423 | rez++; |
423 | } | 424 | } |
424 | numptr_m1->val = rez; | 425 | numptr_m1->val = rez; |
425 | /* protect geting var value, is number now */ | 426 | /* erase var name, it is just a number now */ |
426 | numptr_m1->var = NULL; | 427 | numptr_m1->var = NULL; |
427 | return 0; | 428 | return 0; |
428 | err: | 429 | err: |
429 | return -1; | 430 | return -1; |
431 | #undef NUMPTR | ||
430 | } | 432 | } |
431 | 433 | ||
432 | /* longest must be first */ | 434 | /* longest must be first */ |
@@ -473,7 +475,6 @@ static const char op_tokens[] ALIGN1 = { | |||
473 | '(', 0, TOK_LPAREN, | 475 | '(', 0, TOK_LPAREN, |
474 | 0 | 476 | 0 |
475 | }; | 477 | }; |
476 | /* ptr to ")" */ | ||
477 | #define ptr_to_rparen (&op_tokens[sizeof(op_tokens)-7]) | 478 | #define ptr_to_rparen (&op_tokens[sizeof(op_tokens)-7]) |
478 | 479 | ||
479 | const char* FAST_FUNC | 480 | const char* FAST_FUNC |
@@ -529,15 +530,15 @@ arith(const char *expr, int *perrcode, a_e_h_t *math_hooks) | |||
529 | * result on the integer stack */ | 530 | * result on the integer stack */ |
530 | 531 | ||
531 | if (expr != ptr_to_rparen + 1) { | 532 | if (expr != ptr_to_rparen + 1) { |
532 | /* If we haven't done so already, */ | 533 | /* If we haven't done so already, |
533 | /* append a closing right paren */ | 534 | * append a closing right paren |
535 | * and let the loop process it */ | ||
534 | expr = ptr_to_rparen; | 536 | expr = ptr_to_rparen; |
535 | /* and let the loop process it. */ | ||
536 | continue; | 537 | continue; |
537 | } | 538 | } |
538 | /* At this point, we're done with the expression. */ | 539 | /* At this point, we're done with the expression */ |
539 | if (numstackptr != numstack + 1) { | 540 | if (numstackptr != numstack + 1) { |
540 | /* ... but if there isn't, it's bad */ | 541 | /* ...but if there isn't, it's bad */ |
541 | goto err; | 542 | goto err; |
542 | } | 543 | } |
543 | if (numstack->var) { | 544 | if (numstack->var) { |
@@ -619,11 +620,11 @@ arith(const char *expr, int *perrcode, a_e_h_t *math_hooks) | |||
619 | /* We don't want an unary operator to cause recursive descent on the | 620 | /* We don't want an unary operator to cause recursive descent on the |
620 | * stack, because there can be many in a row and it could cause an | 621 | * stack, because there can be many in a row and it could cause an |
621 | * operator to be evaluated before its argument is pushed onto the | 622 | * operator to be evaluated before its argument is pushed onto the |
622 | * integer stack. */ | 623 | * integer stack. |
623 | /* But for binary operators, "apply" everything on the operator | 624 | * But for binary operators, "apply" everything on the operator |
624 | * stack until we find an operator with a lesser priority than the | 625 | * stack until we find an operator with a lesser priority than the |
625 | * one we have just extracted. */ | 626 | * one we have just extracted. |
626 | /* Left paren is given the lowest priority so it will never be | 627 | * Left paren is given the lowest priority so it will never be |
627 | * "applied" in this way. | 628 | * "applied" in this way. |
628 | * if associativity is right and priority eq, applied also skip | 629 | * if associativity is right and priority eq, applied also skip |
629 | */ | 630 | */ |
@@ -641,17 +642,17 @@ arith(const char *expr, int *perrcode, a_e_h_t *math_hooks) | |||
641 | * hit an open paren nor the bottom of the stack, pop | 642 | * hit an open paren nor the bottom of the stack, pop |
642 | * tokens and apply them */ | 643 | * tokens and apply them */ |
643 | if (prev_op == TOK_LPAREN) { | 644 | if (prev_op == TOK_LPAREN) { |
644 | /* Any operator directly after a */ | 645 | /* Any operator directly after a |
646 | * close paren should consider itself binary */ | ||
645 | lasttok = TOK_NUM; | 647 | lasttok = TOK_NUM; |
646 | /* close paren should consider itself binary */ | ||
647 | goto next; | 648 | goto next; |
648 | } | 649 | } |
649 | } else { | 650 | } else { |
650 | operator prev_prec = PREC(prev_op); | 651 | operator prev_prec = PREC(prev_op); |
651 | convert_prec_is_assign(prec); | 652 | fix_assignment_prec(prec); |
652 | convert_prec_is_assign(prev_prec); | 653 | fix_assignment_prec(prev_prec); |
653 | if (prev_prec < prec | 654 | if (prev_prec < prec |
654 | || (prev_prec == prec && is_right_associativity(prec)) | 655 | || (prev_prec == prec && is_right_associative(prec)) |
655 | ) { | 656 | ) { |
656 | stackptr++; | 657 | stackptr++; |
657 | break; | 658 | break; |