| File: | src/libexec/tradcpp/eval.c |
| Warning: | line 335, column 25 The result of the left shift is undefined due to shifting by '32', which is greater or equal to the width of type 'unsigned int' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /*- | |||
| 2 | * Copyright (c) 2010 The NetBSD Foundation, Inc. | |||
| 3 | * All rights reserved. | |||
| 4 | * | |||
| 5 | * This code is derived from software contributed to The NetBSD Foundation | |||
| 6 | * by David A. Holland. | |||
| 7 | * | |||
| 8 | * Redistribution and use in source and binary forms, with or without | |||
| 9 | * modification, are permitted provided that the following conditions | |||
| 10 | * are met: | |||
| 11 | * 1. Redistributions of source code must retain the above copyright | |||
| 12 | * notice, this list of conditions and the following disclaimer. | |||
| 13 | * 2. Redistributions in binary form must reproduce the above copyright | |||
| 14 | * notice, this list of conditions and the following disclaimer in the | |||
| 15 | * documentation and/or other materials provided with the distribution. | |||
| 16 | * | |||
| 17 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | |||
| 18 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |||
| 19 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |||
| 20 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |||
| 21 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |||
| 22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |||
| 23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |||
| 24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |||
| 25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |||
| 26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |||
| 27 | * POSSIBILITY OF SUCH DAMAGE. | |||
| 28 | */ | |||
| 29 | ||||
| 30 | #include <stdlib.h> | |||
| 31 | #include <string.h> | |||
| 32 | #include <limits.h> | |||
| 33 | #include <errno(*__errno()).h> | |||
| 34 | ||||
| 35 | //#define DEBUG | |||
| 36 | #ifdef DEBUG | |||
| 37 | #include <stdio.h> | |||
| 38 | #endif | |||
| 39 | ||||
| 40 | #include "utils.h" | |||
| 41 | #include "array.h" | |||
| 42 | #include "mode.h" | |||
| 43 | #include "place.h" | |||
| 44 | #include "eval.h" | |||
| 45 | ||||
| 46 | /* | |||
| 47 | * e ::= | |||
| 48 | * e1 ? e2 : e3 | |||
| 49 | * e1 || e2 | |||
| 50 | * e1 && e2 | |||
| 51 | * e1 | e2 | |||
| 52 | * e1 ^ e2 | |||
| 53 | * e1 & e2 | |||
| 54 | * e1 == e2 | e1 != e2 | |||
| 55 | * e1 < e2 | e1 <= e2 | e1 > e2 | e1 >= e2 | |||
| 56 | * e1 << e2 | e1 >> e2 | |||
| 57 | * e1 + e2 | e1 - e2 | |||
| 58 | * e1 * e2 | e1 / e2 | e1 % e2 | |||
| 59 | * !e | ~e | -e | +e | |||
| 60 | * ( e ) | ident | |||
| 61 | */ | |||
| 62 | ||||
| 63 | enum tokens { | |||
| 64 | T_EOF, /* end of input */ | |||
| 65 | T_VAL, /* value */ | |||
| 66 | T_LPAREN, /* parens */ | |||
| 67 | T_RPAREN, | |||
| 68 | T_PIPEPIPE, /* operators */ | |||
| 69 | T_AMPAMP, | |||
| 70 | T_EQEQ, | |||
| 71 | T_BANGEQ, | |||
| 72 | T_LTEQ, | |||
| 73 | T_GTEQ, | |||
| 74 | T_LTLT, | |||
| 75 | T_GTGT, | |||
| 76 | T_QUES, | |||
| 77 | T_COLON, | |||
| 78 | T_PIPE, | |||
| 79 | T_CARET, | |||
| 80 | T_AMP, | |||
| 81 | T_LT, | |||
| 82 | T_GT, | |||
| 83 | T_PLUS, | |||
| 84 | T_MINUS, | |||
| 85 | T_STAR, | |||
| 86 | T_SLASH, | |||
| 87 | T_PCT, | |||
| 88 | T_BANG, | |||
| 89 | T_TILDE, | |||
| 90 | }; | |||
| 91 | ||||
| 92 | static const struct { | |||
| 93 | char c1, c2; | |||
| 94 | enum tokens tok; | |||
| 95 | } tokens_2[] = { | |||
| 96 | { '|', '|', T_PIPEPIPE }, | |||
| 97 | { '&', '&', T_AMPAMP }, | |||
| 98 | { '=', '=', T_EQEQ }, | |||
| 99 | { '!', '=', T_BANGEQ }, | |||
| 100 | { '<', '=', T_LTEQ }, | |||
| 101 | { '>', '=', T_GTEQ }, | |||
| 102 | { '<', '<', T_LTLT }, | |||
| 103 | { '>', '>', T_GTGT }, | |||
| 104 | }; | |||
| 105 | static const unsigned num_tokens_2 = HOWMANY(tokens_2)(sizeof(tokens_2)/sizeof((tokens_2)[0])); | |||
| 106 | ||||
| 107 | static const struct { | |||
| 108 | char c1; | |||
| 109 | enum tokens tok; | |||
| 110 | } tokens_1[] = { | |||
| 111 | { '?', T_QUES }, | |||
| 112 | { ':', T_COLON }, | |||
| 113 | { '|', T_PIPE }, | |||
| 114 | { '^', T_CARET }, | |||
| 115 | { '&', T_AMP }, | |||
| 116 | { '<', T_LT }, | |||
| 117 | { '>', T_GT }, | |||
| 118 | { '+', T_PLUS }, | |||
| 119 | { '-', T_MINUS }, | |||
| 120 | { '*', T_STAR }, | |||
| 121 | { '/', T_SLASH }, | |||
| 122 | { '%', T_PCT }, | |||
| 123 | { '!', T_BANG }, | |||
| 124 | { '~', T_TILDE }, | |||
| 125 | { '(', T_LPAREN }, | |||
| 126 | { ')', T_RPAREN }, | |||
| 127 | }; | |||
| 128 | static const unsigned num_tokens_1 = HOWMANY(tokens_1)(sizeof(tokens_1)/sizeof((tokens_1)[0])); | |||
| 129 | ||||
| 130 | struct token { | |||
| 131 | struct place place; | |||
| 132 | enum tokens tok; | |||
| 133 | int val; | |||
| 134 | }; | |||
| 135 | DECLARRAY(token, static UNUSED)struct tokenarray { struct array arr; }; static __attribute__ ((__unused__)) struct tokenarray *tokenarray_create(void); static __attribute__((__unused__)) void tokenarray_destroy(struct tokenarray *a); static __attribute__((__unused__)) void tokenarray_init (struct tokenarray *a); static __attribute__((__unused__)) void tokenarray_cleanup(struct tokenarray *a); static __attribute__ ((__unused__)) unsigned tokenarray_num(const struct tokenarray *a); static __attribute__((__unused__)) struct token *tokenarray_get (const struct tokenarray *a, unsigned index_); static __attribute__ ((__unused__)) void tokenarray_set(struct tokenarray *a, unsigned index_, struct token *val); static __attribute__((__unused__ )) void tokenarray_setsize(struct tokenarray *a, unsigned num ); static __attribute__((__unused__)) void tokenarray_add(struct tokenarray *a, struct token *val, unsigned *index_ret); static __attribute__((__unused__)) void tokenarray_insert(struct tokenarray *a, unsigned index_); static __attribute__((__unused__)) void tokenarray_remove(struct tokenarray *a, unsigned index_); | |||
| 136 | DEFARRAY(token, static)static void tokenarray_init(struct tokenarray *a) { array_init (&a->arr); } static void tokenarray_cleanup(struct tokenarray *a) { array_cleanup(&a->arr); } static struct tokenarray *tokenarray_create(void) { struct tokenarray *a; a = domalloc (sizeof(*a)); tokenarray_init(a); return a; } static void tokenarray_destroy (struct tokenarray *a) { tokenarray_cleanup(a); dofree(a, sizeof (*a)); } static unsigned tokenarray_num(const struct tokenarray *a) { return array_num(&a->arr); } static struct token * tokenarray_get(const struct tokenarray *a, unsigned index_ ) { return (struct token *)array_get(&a->arr, index_); } static void tokenarray_set(struct tokenarray *a, unsigned index_ , struct token *val) { array_set(&a->arr, index_, (void *)val); } static void tokenarray_setsize(struct tokenarray * a, unsigned num) { array_setsize(&a->arr, num); } static void tokenarray_add(struct tokenarray *a, struct token *val, unsigned *ret) { array_add(&a->arr, (void *)val, ret) ; } static void tokenarray_insert(struct tokenarray *a, unsigned index_) { array_insert(&a->arr, index_); } static void tokenarray_remove(struct tokenarray *a, unsigned index_) { array_remove (&a->arr, index_); }; | |||
| 137 | ||||
| 138 | static struct tokenarray tokens; | |||
| 139 | ||||
| 140 | static | |||
| 141 | struct token * | |||
| 142 | token_create(const struct place *p, enum tokens tok, int val) | |||
| 143 | { | |||
| 144 | struct token *t; | |||
| 145 | ||||
| 146 | t = domalloc(sizeof(*t)); | |||
| 147 | t->place = *p; | |||
| 148 | t->tok = tok; | |||
| 149 | t->val = val; | |||
| 150 | return t; | |||
| 151 | } | |||
| 152 | ||||
| 153 | static | |||
| 154 | void | |||
| 155 | token_destroy(struct token *t) | |||
| 156 | { | |||
| 157 | dofree(t, sizeof(*t)); | |||
| 158 | } | |||
| 159 | ||||
| 160 | DESTROYALL_ARRAY(token, )void tokenarray_destroyall(struct tokenarray *arr); void tokenarray_destroyall (struct tokenarray *arr) { unsigned i, num; struct token *t; num = tokenarray_num(arr); for (i=0; i<num; i++) { t = tokenarray_get (arr, i); token_destroy(t); } tokenarray_setsize(arr, 0); }; | |||
| 161 | ||||
| 162 | #ifdef DEBUG | |||
| 163 | static | |||
| 164 | void | |||
| 165 | printtokens(void) | |||
| 166 | { | |||
| 167 | unsigned i, num; | |||
| 168 | struct token *t; | |||
| 169 | ||||
| 170 | fprintf(stderr, "tokens:"); | |||
| 171 | num = tokenarray_num(&tokens); | |||
| 172 | for (i=0; i<num; i++) { | |||
| 173 | t = tokenarray_get(&tokens, i); | |||
| 174 | switch (t->tok) { | |||
| 175 | case T_EOF: fprintf(stderr, " <eof>"); break; | |||
| 176 | case T_VAL: fprintf(stderr, " %d", t->val); break; | |||
| 177 | case T_LPAREN: fprintf(stderr, " ("); break; | |||
| 178 | case T_RPAREN: fprintf(stderr, " )"); break; | |||
| 179 | case T_PIPEPIPE: fprintf(stderr, " ||"); break; | |||
| 180 | case T_AMPAMP: fprintf(stderr, " &&"); break; | |||
| 181 | case T_EQEQ: fprintf(stderr, " =="); break; | |||
| 182 | case T_BANGEQ: fprintf(stderr, " !="); break; | |||
| 183 | case T_LTEQ: fprintf(stderr, " <="); break; | |||
| 184 | case T_GTEQ: fprintf(stderr, " >="); break; | |||
| 185 | case T_LTLT: fprintf(stderr, " <<"); break; | |||
| 186 | case T_GTGT: fprintf(stderr, " >>"); break; | |||
| 187 | case T_QUES: fprintf(stderr, " ?"); break; | |||
| 188 | case T_COLON: fprintf(stderr, " :"); break; | |||
| 189 | case T_PIPE: fprintf(stderr, " |"); break; | |||
| 190 | case T_CARET: fprintf(stderr, " ^"); break; | |||
| 191 | case T_AMP: fprintf(stderr, " &"); break; | |||
| 192 | case T_LT: fprintf(stderr, " <"); break; | |||
| 193 | case T_GT: fprintf(stderr, " >"); break; | |||
| 194 | case T_PLUS: fprintf(stderr, " +"); break; | |||
| 195 | case T_MINUS: fprintf(stderr, " -"); break; | |||
| 196 | case T_STAR: fprintf(stderr, " *"); break; | |||
| 197 | case T_SLASH: fprintf(stderr, " /"); break; | |||
| 198 | case T_PCT: fprintf(stderr, " %%"); break; | |||
| 199 | case T_BANG: fprintf(stderr, " !"); break; | |||
| 200 | case T_TILDE: fprintf(stderr, " ~"); break; | |||
| 201 | } | |||
| 202 | } | |||
| 203 | fprintf(stderr, "\n"); | |||
| 204 | } | |||
| 205 | #endif | |||
| 206 | ||||
| 207 | static | |||
| 208 | bool | |||
| 209 | isuop(enum tokens tok) | |||
| 210 | { | |||
| 211 | switch (tok) { | |||
| 212 | case T_BANG: | |||
| 213 | case T_TILDE: | |||
| 214 | case T_MINUS: | |||
| 215 | case T_PLUS: | |||
| 216 | return true1; | |||
| 217 | default: | |||
| 218 | break; | |||
| 219 | } | |||
| 220 | return false0; | |||
| 221 | } | |||
| 222 | ||||
| 223 | static | |||
| 224 | bool | |||
| 225 | isbop(enum tokens tok) | |||
| 226 | { | |||
| 227 | switch (tok) { | |||
| 228 | case T_EOF: | |||
| 229 | case T_VAL: | |||
| 230 | case T_LPAREN: | |||
| 231 | case T_RPAREN: | |||
| 232 | case T_COLON: | |||
| 233 | case T_QUES: | |||
| 234 | case T_BANG: | |||
| 235 | case T_TILDE: | |||
| 236 | return false0; | |||
| 237 | default: | |||
| 238 | break; | |||
| 239 | } | |||
| 240 | return true1; | |||
| 241 | } | |||
| 242 | ||||
| 243 | static | |||
| 244 | bool | |||
| 245 | isop(enum tokens tok) | |||
| 246 | { | |||
| 247 | switch (tok) { | |||
| 248 | case T_EOF: | |||
| 249 | case T_VAL: | |||
| 250 | case T_LPAREN: | |||
| 251 | case T_RPAREN: | |||
| 252 | return false0; | |||
| 253 | default: | |||
| 254 | break; | |||
| 255 | } | |||
| 256 | return true1; | |||
| 257 | } | |||
| 258 | ||||
| 259 | static | |||
| 260 | int | |||
| 261 | getprec(enum tokens tok) | |||
| 262 | { | |||
| 263 | switch (tok) { | |||
| 264 | case T_BANG: case T_TILDE: return -1; | |||
| 265 | case T_STAR: case T_SLASH: case T_PCT: return 0; | |||
| 266 | case T_PLUS: case T_MINUS: return 1; | |||
| 267 | case T_LTLT: case T_GTGT: return 2; | |||
| 268 | case T_LT: case T_LTEQ: case T_GT: case T_GTEQ: return 3; | |||
| 269 | case T_EQEQ: case T_BANGEQ: return 4; | |||
| 270 | case T_AMP: return 5; | |||
| 271 | case T_CARET: return 6; | |||
| 272 | case T_PIPE: return 7; | |||
| 273 | case T_AMPAMP: return 8; | |||
| 274 | case T_PIPEPIPE: return 9; | |||
| 275 | default: break; | |||
| 276 | } | |||
| 277 | return 10; | |||
| 278 | } | |||
| 279 | ||||
| 280 | static | |||
| 281 | bool | |||
| 282 | looser(enum tokens t1, enum tokens t2) | |||
| 283 | { | |||
| 284 | return getprec(t1) >= getprec(t2); | |||
| 285 | } | |||
| 286 | ||||
| 287 | static | |||
| 288 | int | |||
| 289 | eval_uop(enum tokens op, int val) | |||
| 290 | { | |||
| 291 | switch (op) { | |||
| 292 | case T_BANG: val = !val; break; | |||
| 293 | case T_TILDE: val = (int)~(unsigned)val; break; | |||
| 294 | case T_MINUS: val = -val; break; | |||
| 295 | case T_PLUS: break; | |||
| 296 | default: assert(0)((0) ? (void)0 : __assert2("/usr/src/libexec/tradcpp/eval.c", 296, __func__, "0")); break; | |||
| 297 | } | |||
| 298 | return val; | |||
| 299 | } | |||
| 300 | ||||
| 301 | static | |||
| 302 | int | |||
| 303 | eval_bop(struct place *p, int lv, enum tokens op, int rv) | |||
| 304 | { | |||
| 305 | unsigned mask; | |||
| 306 | ||||
| 307 | switch (op) { | |||
| 308 | case T_PIPEPIPE: return lv || rv; | |||
| 309 | case T_AMPAMP: return lv && rv; | |||
| 310 | case T_PIPE: return (int)((unsigned)lv | (unsigned)rv); | |||
| 311 | case T_CARET: return (int)((unsigned)lv ^ (unsigned)rv); | |||
| 312 | case T_AMP: return (int)((unsigned)lv & (unsigned)rv); | |||
| 313 | case T_EQEQ: return lv == rv; | |||
| 314 | case T_BANGEQ: return lv != rv; | |||
| 315 | case T_LT: return lv < rv; | |||
| 316 | case T_GT: return lv > rv; | |||
| 317 | case T_LTEQ: return lv <= rv; | |||
| 318 | case T_GTEQ: return lv >= rv; | |||
| 319 | ||||
| 320 | case T_LTLT: | |||
| 321 | case T_GTGT: | |||
| 322 | if (rv < 0) { | |||
| 323 | complain(p, "Negative bit-shift"); | |||
| 324 | complain_fail(); | |||
| 325 | rv = 0; | |||
| 326 | } | |||
| 327 | if ((unsigned)rv >= CHAR_BIT8 * sizeof(unsigned)) { | |||
| 328 | complain(p, "Bit-shift farther than type width"); | |||
| 329 | complain_fail(); | |||
| 330 | rv = 0; | |||
| 331 | } | |||
| 332 | if (op
| |||
| 333 | return (int)((unsigned)lv << (unsigned)rv); | |||
| 334 | } | |||
| 335 | mask = ((unsigned)-1) << (CHAR_BIT8 * sizeof(unsigned) - rv); | |||
| ||||
| 336 | lv = (int)(((unsigned)lv >> (unsigned)rv) | mask); | |||
| 337 | return lv; | |||
| 338 | ||||
| 339 | case T_MINUS: | |||
| 340 | if (rv == INT_MIN(-2147483647 -1)) { | |||
| 341 | if (lv == INT_MIN(-2147483647 -1)) { | |||
| 342 | return 0; | |||
| 343 | } | |||
| 344 | lv--; | |||
| 345 | rv++; | |||
| 346 | } | |||
| 347 | rv = -rv; | |||
| 348 | /* FALLTHROUGH */ | |||
| 349 | case T_PLUS: | |||
| 350 | if (rv > 0 && lv > (INT_MAX2147483647 - rv)) { | |||
| 351 | complain(p, "Integer overflow"); | |||
| 352 | complain_fail(); | |||
| 353 | return INT_MAX2147483647; | |||
| 354 | } | |||
| 355 | if (rv < 0 && lv < (INT_MIN(-2147483647 -1) - rv)) { | |||
| 356 | complain(p, "Integer underflow"); | |||
| 357 | complain_fail(); | |||
| 358 | return INT_MIN(-2147483647 -1); | |||
| 359 | } | |||
| 360 | return lv + rv; | |||
| 361 | ||||
| 362 | case T_STAR: | |||
| 363 | if (rv == 0) { | |||
| 364 | return 0; | |||
| 365 | } | |||
| 366 | if (rv == 1) { | |||
| 367 | return lv; | |||
| 368 | } | |||
| 369 | if (rv == -1 && lv == INT_MIN(-2147483647 -1)) { | |||
| 370 | lv++; | |||
| 371 | lv = -lv; | |||
| 372 | if (lv == INT_MAX2147483647) { | |||
| 373 | complain(p, "Integer overflow"); | |||
| 374 | complain_fail(); | |||
| 375 | return INT_MAX2147483647; | |||
| 376 | } | |||
| 377 | lv++; | |||
| 378 | return lv; | |||
| 379 | } | |||
| 380 | if (lv == INT_MIN(-2147483647 -1) && rv < 0) { | |||
| 381 | complain(p, "Integer overflow"); | |||
| 382 | complain_fail(); | |||
| 383 | return INT_MAX2147483647; | |||
| 384 | } | |||
| 385 | if (lv == INT_MIN(-2147483647 -1) && rv > 0) { | |||
| 386 | complain(p, "Integer underflow"); | |||
| 387 | complain_fail(); | |||
| 388 | return INT_MIN(-2147483647 -1); | |||
| 389 | } | |||
| 390 | if (rv < 0) { | |||
| 391 | rv = -rv; | |||
| 392 | lv = -lv; | |||
| 393 | } | |||
| 394 | if (lv > 0 && lv > INT_MAX2147483647 / rv) { | |||
| 395 | complain(p, "Integer overflow"); | |||
| 396 | complain_fail(); | |||
| 397 | return INT_MAX2147483647; | |||
| 398 | } | |||
| 399 | if (lv < 0 && lv < INT_MIN(-2147483647 -1) / rv) { | |||
| 400 | complain(p, "Integer underflow"); | |||
| 401 | complain_fail(); | |||
| 402 | return INT_MIN(-2147483647 -1); | |||
| 403 | } | |||
| 404 | return lv * rv; | |||
| 405 | ||||
| 406 | case T_SLASH: | |||
| 407 | if (rv == 0) { | |||
| 408 | complain(p, "Division by zero"); | |||
| 409 | complain_fail(); | |||
| 410 | return 0; | |||
| 411 | } | |||
| 412 | return lv / rv; | |||
| 413 | ||||
| 414 | case T_PCT: | |||
| 415 | if (rv == 0) { | |||
| 416 | complain(p, "Modulus by zero"); | |||
| 417 | complain_fail(); | |||
| 418 | return 0; | |||
| 419 | } | |||
| 420 | return lv % rv; | |||
| 421 | ||||
| 422 | default: assert(0)((0) ? (void)0 : __assert2("/usr/src/libexec/tradcpp/eval.c", 422, __func__, "0")); break; | |||
| 423 | } | |||
| 424 | return 0; | |||
| 425 | } | |||
| 426 | ||||
| 427 | static | |||
| 428 | void | |||
| 429 | tryreduce(void) | |||
| 430 | { | |||
| 431 | unsigned num; | |||
| 432 | struct token *t1, *t2, *t3, *t4, *t5, *t6; | |||
| 433 | ||||
| 434 | while (1) { | |||
| 435 | #ifdef DEBUG | |||
| 436 | printtokens(); | |||
| 437 | #endif | |||
| 438 | num = tokenarray_num(&tokens); | |||
| 439 | t1 = (num >= 1) ? tokenarray_get(&tokens, num-1) : NULL((void*)0); | |||
| 440 | t2 = (num >= 2) ? tokenarray_get(&tokens, num-2) : NULL((void*)0); | |||
| 441 | t3 = (num >= 3) ? tokenarray_get(&tokens, num-3) : NULL((void*)0); | |||
| 442 | ||||
| 443 | if (num
| |||
| 444 | t3->tok == T_LPAREN && | |||
| 445 | t2->tok == T_VAL && | |||
| 446 | t1->tok == T_RPAREN) { | |||
| 447 | /* (x) -> x */ | |||
| 448 | t2->place = t3->place; | |||
| 449 | token_destroy(t1); | |||
| 450 | token_destroy(t3); | |||
| 451 | tokenarray_remove(&tokens, num-1); | |||
| 452 | tokenarray_remove(&tokens, num-3); | |||
| 453 | continue; | |||
| 454 | } | |||
| 455 | ||||
| 456 | if (num
| |||
| 457 | (num
| |||
| 458 | isuop(t2->tok) && | |||
| 459 | t1->tok == T_VAL) { | |||
| 460 | /* unary operator */ | |||
| 461 | t1->val = eval_uop(t2->tok, t1->val); | |||
| 462 | t1->place = t2->place; | |||
| 463 | token_destroy(t2); | |||
| 464 | tokenarray_remove(&tokens, num-2); | |||
| 465 | continue; | |||
| 466 | } | |||
| 467 | if (num
| |||
| 468 | (num
| |||
| 469 | t2->tok != T_LPAREN && t2->tok != T_VAL && | |||
| 470 | t1->tok == T_VAL) { | |||
| 471 | complain(&t2->place, "Invalid unary operator"); | |||
| 472 | complain_fail(); | |||
| 473 | token_destroy(t2); | |||
| 474 | tokenarray_remove(&tokens, num-2); | |||
| 475 | continue; | |||
| 476 | } | |||
| 477 | ||||
| 478 | ||||
| 479 | t4 = (num >= 4) ? tokenarray_get(&tokens, num-4) : NULL((void*)0); | |||
| 480 | ||||
| 481 | if (num
| |||
| 482 | t4->tok == T_VAL && | |||
| 483 | isbop(t3->tok) && | |||
| 484 | t2->tok
| |||
| 485 | /* binary operator */ | |||
| 486 | if (looser(t1->tok, t3->tok)) { | |||
| 487 | t4->val = eval_bop(&t3->place, | |||
| 488 | t4->val, t3->tok, t2->val); | |||
| 489 | token_destroy(t2); | |||
| 490 | token_destroy(t3); | |||
| 491 | tokenarray_remove(&tokens, num-2); | |||
| 492 | tokenarray_remove(&tokens, num-3); | |||
| 493 | continue; | |||
| 494 | } | |||
| 495 | break; | |||
| 496 | } | |||
| 497 | ||||
| 498 | t5 = (num >= 5) ? tokenarray_get(&tokens, num-5) : NULL((void*)0); | |||
| 499 | t6 = (num >= 6) ? tokenarray_get(&tokens, num-6) : NULL((void*)0); | |||
| 500 | ||||
| 501 | if (num >= 6 && | |||
| 502 | t6->tok == T_VAL && | |||
| 503 | t5->tok == T_QUES && | |||
| 504 | t4->tok == T_VAL && | |||
| 505 | t3->tok == T_COLON && | |||
| 506 | t2->tok == T_VAL && | |||
| 507 | !isop(t1->tok)) { | |||
| 508 | /* conditional expression */ | |||
| 509 | t6->val = t6->val ? t4->val : t2->val; | |||
| 510 | token_destroy(t2); | |||
| 511 | token_destroy(t3); | |||
| 512 | token_destroy(t4); | |||
| 513 | token_destroy(t5); | |||
| 514 | tokenarray_remove(&tokens, num-2); | |||
| 515 | tokenarray_remove(&tokens, num-3); | |||
| 516 | tokenarray_remove(&tokens, num-4); | |||
| 517 | tokenarray_remove(&tokens, num-5); | |||
| 518 | continue; | |||
| 519 | } | |||
| 520 | ||||
| 521 | if (num >= 2 && | |||
| 522 | t2->tok == T_LPAREN && | |||
| 523 | t1->tok == T_RPAREN) { | |||
| 524 | complain(&t1->place, "Value expected within ()"); | |||
| 525 | complain_fail(); | |||
| 526 | t1->tok = T_VAL; | |||
| 527 | t1->val = 0; | |||
| 528 | token_destroy(t1); | |||
| 529 | tokenarray_remove(&tokens, num-1); | |||
| 530 | continue; | |||
| 531 | } | |||
| 532 | ||||
| 533 | if (num >= 2 && | |||
| 534 | t2->tok == T_VAL && | |||
| 535 | t1->tok == T_VAL) { | |||
| 536 | complain(&t1->place, "Operator expected"); | |||
| 537 | complain_fail(); | |||
| 538 | token_destroy(t1); | |||
| 539 | tokenarray_remove(&tokens, num-1); | |||
| 540 | continue; | |||
| 541 | } | |||
| 542 | ||||
| 543 | if (num >= 2 && | |||
| 544 | isop(t2->tok) && | |||
| 545 | t1->tok == T_EOF) { | |||
| 546 | complain(&t1->place, "Value expected after operator"); | |||
| 547 | complain_fail(); | |||
| 548 | token_destroy(t2); | |||
| 549 | tokenarray_remove(&tokens, num-2); | |||
| 550 | continue; | |||
| 551 | } | |||
| 552 | ||||
| 553 | if (num == 2 && | |||
| 554 | t2->tok == T_VAL && | |||
| 555 | t1->tok == T_RPAREN) { | |||
| 556 | complain(&t1->place, "Excess right parenthesis"); | |||
| 557 | complain_fail(); | |||
| 558 | token_destroy(t1); | |||
| 559 | tokenarray_remove(&tokens, num-1); | |||
| 560 | continue; | |||
| 561 | } | |||
| 562 | ||||
| 563 | if (num == 3 && | |||
| 564 | t3->tok == T_LPAREN && | |||
| 565 | t2->tok == T_VAL && | |||
| 566 | t1->tok == T_EOF) { | |||
| 567 | complain(&t1->place, "Unclosed left parenthesis"); | |||
| 568 | complain_fail(); | |||
| 569 | token_destroy(t3); | |||
| 570 | tokenarray_remove(&tokens, num-3); | |||
| 571 | continue; | |||
| 572 | } | |||
| 573 | ||||
| 574 | if (num == 2 && | |||
| 575 | t2->tok == T_VAL && | |||
| 576 | t1->tok == T_EOF) { | |||
| 577 | /* accepting state */ | |||
| 578 | break; | |||
| 579 | } | |||
| 580 | ||||
| 581 | if (num >= 1 && | |||
| 582 | t1->tok == T_EOF) { | |||
| 583 | /* any other configuration at eof is an error */ | |||
| 584 | complain(&t1->place, "Parse error"); | |||
| 585 | complain_fail(); | |||
| 586 | break; | |||
| 587 | } | |||
| 588 | ||||
| 589 | /* otherwise, wait for more input */ | |||
| 590 | break; | |||
| 591 | } | |||
| 592 | } | |||
| 593 | ||||
| 594 | static | |||
| 595 | void | |||
| 596 | token(struct place *p, enum tokens tok, int val) | |||
| 597 | { | |||
| 598 | struct token *t; | |||
| 599 | ||||
| 600 | t = token_create(p, tok, val); | |||
| 601 | ||||
| 602 | tokenarray_add(&tokens, t, NULL((void*)0)); | |||
| 603 | tryreduce(); | |||
| 604 | } | |||
| 605 | ||||
| 606 | static | |||
| 607 | int | |||
| 608 | wordval(struct place *p, char *word) | |||
| 609 | { | |||
| 610 | unsigned long val; | |||
| 611 | char *t; | |||
| 612 | ||||
| 613 | if (word[0] >= '0' && word[0] <= '9') { | |||
| 614 | errno(*__errno()) = 0; | |||
| 615 | val = strtoul(word, &t, 0); | |||
| 616 | if (errno(*__errno())) { | |||
| 617 | complain(p, "Invalid integer constant"); | |||
| 618 | complain_fail(); | |||
| 619 | return 0; | |||
| 620 | } | |||
| 621 | while (*t == 'U' || *t == 'L') { | |||
| 622 | t++; | |||
| 623 | } | |||
| 624 | if (*t != '\0') { | |||
| 625 | complain(p, "Trailing garbage after integer constant"); | |||
| 626 | complain_fail(); | |||
| 627 | return 0; | |||
| 628 | } | |||
| 629 | if (val > INT_MAX2147483647) { | |||
| 630 | complain(p, "Integer constant too large"); | |||
| 631 | complain_fail(); | |||
| 632 | return INT_MAX2147483647; | |||
| 633 | } | |||
| 634 | return val; | |||
| 635 | } | |||
| 636 | ||||
| 637 | /* if it's a symbol, warn and substitute 0. */ | |||
| 638 | if (warns.undef) { | |||
| 639 | complain(p, "Warning: value of undefined symbol %s is 0", | |||
| 640 | word); | |||
| 641 | if (mode.werror) { | |||
| 642 | complain_fail(); | |||
| 643 | } | |||
| 644 | } | |||
| 645 | debuglog(p, "Undefined symbol %s; substituting 0", word); | |||
| 646 | return 0; | |||
| 647 | } | |||
| 648 | ||||
| 649 | static | |||
| 650 | bool | |||
| 651 | check_word(struct place *p, char *expr, size_t pos, size_t *len_ret) | |||
| 652 | { | |||
| 653 | size_t len; | |||
| 654 | int val; | |||
| 655 | char tmp; | |||
| 656 | ||||
| 657 | if (!strchr(alnum, expr[pos])) { | |||
| 658 | return false0; | |||
| 659 | } | |||
| 660 | len = strspn(expr + pos, alnum); | |||
| 661 | tmp = expr[pos + len]; | |||
| 662 | expr[pos + len] = '\0'; | |||
| 663 | val = wordval(p, expr + pos); | |||
| 664 | expr[pos + len] = tmp; | |||
| 665 | token(p, T_VAL, val); | |||
| 666 | *len_ret = len; | |||
| 667 | return true1; | |||
| 668 | } | |||
| 669 | ||||
| 670 | static | |||
| 671 | bool | |||
| 672 | check_tokens_2(struct place *p, char *expr, size_t pos) | |||
| 673 | { | |||
| 674 | unsigned i; | |||
| 675 | ||||
| 676 | for (i=0; i<num_tokens_2; i++) { | |||
| 677 | if (expr[pos] == tokens_2[i].c1 && | |||
| 678 | expr[pos+1] == tokens_2[i].c2) { | |||
| 679 | token(p, tokens_2[i].tok, 0); | |||
| 680 | return true1; | |||
| 681 | } | |||
| 682 | } | |||
| 683 | return false0; | |||
| 684 | } | |||
| 685 | ||||
| 686 | static | |||
| 687 | bool | |||
| 688 | check_tokens_1(struct place *p, char *expr, size_t pos) | |||
| 689 | { | |||
| 690 | unsigned i; | |||
| 691 | ||||
| 692 | for (i=0; i<num_tokens_1; i++) { | |||
| 693 | if (expr[pos] == tokens_1[i].c1) { | |||
| 694 | token(p, tokens_1[i].tok, 0); | |||
| 695 | return true1; | |||
| 696 | } | |||
| 697 | } | |||
| 698 | return false0; | |||
| 699 | } | |||
| 700 | ||||
| 701 | static | |||
| 702 | void | |||
| 703 | tokenize(struct place *p, char *expr) | |||
| 704 | { | |||
| 705 | size_t pos, len; | |||
| 706 | ||||
| 707 | pos = 0; | |||
| 708 | while (expr[pos] != '\0') { | |||
| 709 | len = strspn(expr+pos, ws); | |||
| 710 | pos += len; | |||
| 711 | place_addcolumns(p, len); | |||
| 712 | /* trailing whitespace is supposed to have been pruned */ | |||
| 713 | assert(expr[pos] != '\0')((expr[pos] != '\0') ? (void)0 : __assert2("/usr/src/libexec/tradcpp/eval.c" , 713, __func__, "expr[pos] != '\\0'")); | |||
| 714 | if (check_word(p, expr, pos, &len)) { | |||
| 715 | pos += len; | |||
| 716 | place_addcolumns(p, len); | |||
| 717 | continue; | |||
| 718 | } | |||
| 719 | if (check_tokens_2(p, expr, pos)) { | |||
| 720 | pos += 2; | |||
| 721 | place_addcolumns(p, 2); | |||
| 722 | continue; | |||
| 723 | } | |||
| 724 | if (check_tokens_1(p, expr, pos)) { | |||
| 725 | pos++; | |||
| 726 | place_addcolumns(p, 1); | |||
| 727 | continue; | |||
| 728 | } | |||
| 729 | complain(p, "Invalid character %u in #if-expression", | |||
| 730 | (unsigned char)expr[pos]); | |||
| 731 | complain_fail(); | |||
| 732 | pos++; | |||
| 733 | place_addcolumns(p, 1); | |||
| 734 | } | |||
| 735 | token(p, T_EOF, 0); | |||
| 736 | } | |||
| 737 | ||||
| 738 | bool | |||
| 739 | eval(struct place *p, char *expr) | |||
| 740 | { | |||
| 741 | struct token *t1, *t2; | |||
| 742 | unsigned num; | |||
| 743 | bool result; | |||
| 744 | ||||
| 745 | #ifdef DEBUG | |||
| 746 | fprintf(stderr, "eval: %s\n", expr); | |||
| 747 | #endif | |||
| 748 | debuglog(p, "eval: %s", expr); | |||
| 749 | ||||
| 750 | tokenarray_init(&tokens); | |||
| 751 | tokenize(p, expr); | |||
| ||||
| 752 | ||||
| 753 | result = false0; | |||
| 754 | num = tokenarray_num(&tokens); | |||
| 755 | if (num == 2) { | |||
| 756 | t1 = tokenarray_get(&tokens, num-1); | |||
| 757 | t2 = tokenarray_get(&tokens, num-2); | |||
| 758 | if (t2->tok == T_VAL && | |||
| 759 | t1->tok == T_EOF) { | |||
| 760 | result = t2->val != 0; | |||
| 761 | } | |||
| 762 | } | |||
| 763 | ||||
| 764 | tokenarray_destroyall(&tokens); | |||
| 765 | tokenarray_cleanup(&tokens); | |||
| 766 | return result; | |||
| 767 | } |