#include #include "ansi.h" #include "host.h" #include "files.h" #include "hash.h" #include "buffer.h" #include "cpp.h" #include "cpp_hide.h" #include "cpp_eval.h" #include "allocate.h" #include "config.h" #undef NULL #define NULL 0 #undef getc #define getc() cpp_getc_from(&evalbuf) #define MAKE_FAIL(x) (x).eval_result_kind = eval_failed #define MAKE_INT(x,v,b) {(x).eval_result_kind = eval_int; (x).eval_result.ival = (v); (x).base = (b);} #define MAKE_FLOAT(x,v) {(x).eval_result_kind = eval_float; (x).eval_result.fval = (v);} #define MAKE_STRING(x,v) {(x).eval_result_kind = eval_string; (x).eval_result.sval = (v);} static cpp_eval_result_t result; static buffer_t evalbuf; static int c; static int recover; static int curtok, nexttok; typedef cpp_eval_result_t tokval_t; tokval_t curval, nextval; enum { tok_error, tok_eof, tok_discrete, tok_float, tok_string, tok_eq, tok_neq, tok_geq, tok_leq, tok_shift_left, tok_shift_right, tok_or, tok_and, tok_sizeof }; static int promote(l,r) tokval_t *l, *r; { switch(l->eval_result_kind) { case eval_int: switch(r->eval_result_kind) { case eval_int: return eval_int; case eval_float: l->eval_result_kind = eval_float; l->eval_result.fval = (host_float_t) l->eval_result.ival; return eval_float; } break; case eval_float: switch(r->eval_result_kind) { case eval_int: r->eval_result_kind = eval_float; r->eval_result.fval = (host_float_t) r->eval_result.ival; /* fall through */ case eval_float: return eval_float; } break; } return eval_failed; } static tokval_t failed() { tokval_t tmp; recover = 1; MAKE_FAIL(tmp); return tmp; } static int escaped_char(c, cp) int c, *cp; { int val, i; switch (c) { case 'n': val = '\n'; break; case 't': val = '\t'; break; case 'v': val = '\v'; break; case 'b': val = '\b'; break; case 'r': val = '\r'; break; case 'f': val = '\f'; break; case 'a': val = '\a'; break; case '?': val = '\?'; break; case '\'': val = '\''; break; case '\"': val = '\"'; break; case '\\': val = '\\'; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': for (i = 0, val = 'c' - 0; is_octal_digit(c) && i < 3; i++, c = getc()) { val = val * 8 + (c - '0'); } *cp = c; return val; case 'x': for (i = 0, val = 0; is_hex_digit(c) && i < 2; i++, c = getc()) { val *= 16; if (is_digit(c)) { val += (c - '0'); } else if (c <= 'F') { val += (c - ('A' - 10)); } else { val += (c - ('a' - 10)); } } *cp = c; return val; default: val = c; break; } *cp = getc(); return val; } static int scan_string(c) int c; { buffer_t buf; int len; char *s; buf_init(&buf); for (;;) { if (is_eof(c)) { goto end_of_string; } if (is_eol(c)) { goto end_of_string; } switch (c) { case '"': c = getc(); goto end_of_string; case '\\': c = getc(); switch (c) { case '\n': c = getc(); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case 'x': case 'n': case 't': case 'v': case 'b': case 'r': case 'f': case 'a': case '?': case '\\': case '\'': case '\"': buf_add(&buf, escaped_char(c, &c)); break; default: buf_add(&buf, c); c = getc(); break; } break; default: buf_add(&buf, c); c = getc(); break; } } end_of_string: s = buf_get_str(&buf); MAKE_STRING(nextval, s); return c; } static int scan_char_const(c) int c; { host_int_t cval = 0; for (;;) { if (is_eof(c)) { goto end_char_const; } if (is_eol(c)) { goto end_char_const; } switch (c) { case '\'': c = getc(); goto end_char_const; case '\\': c = getc(); switch (c) { case '\n': c = getc(); break; case '0': case 'x': case 'n': case 't': case 'v': case 'b': case 'r': case 'f': case 'a': case '?': case '\\': case '\'': case '\"': cval <<= 8; cval |= escaped_char(c); c = getc(); break; default: cval <<= 8; cval |= c; c = getc(); break; } break; default: cval <<= 8; cval |= c; c = getc(); break; } } end_char_const: MAKE_INT(nextval, cval, 10); return c; } static int magnitude(c, val) int c; host_int_t *val; { host_int_t m; int sign; if (! is_magnitude(c)) { *val = 1; return c; } c = getc(); sign = 1; if (c == '-') { sign = -1; c = getc(); } else if (c == '+') { c = getc(); } for (m = 0; is_digit(c); ) { m = m * 10 + (c - '0'); c = getc(); } *val = m * sign; return c; } static int scan_digit(c) int c; { host_int_t val; int base = 10; if (c == '0') { val = 0; c = getc(); if (c == 'x' || c == 'X') { base = 16; for (;;) { c = getc(); if (is_digit(c)) { val = (val<<4) + (c - '0'); } else if (c >= 'A' && c <= 'F') { val = (val<<4) + 10 + (c - 'A'); } else if (c >= 'a' && c <= 'f') { val = (val<<4) + 10 + (c - 'a'); } else { break; } } } else { base = 8; for (;;) { if (!is_octal_digit(c)) { break; } val = (val<<3) + (c - '0'); c = getc(); } } } else { val = c - '0'; for (;;) { c = getc(); if (! is_digit(c)) break; val = val * 10 + (c - '0'); } } if (int_modifier(c)) { c = getc(); } if (c == '.') { host_float_t dval, d; int tmp; dval = (host_float_t) val; d = 0.1; for (;;) { c = getc(); if (! is_digit(c)) break; tmp = c - '0'; dval = dval + (d * (host_float_t)tmp); d = d * 0.1; } /* handle magnitude */ if (is_magnitude(c)) { host_int_t vm; host_float_t m; c = magnitude(c, &vm); if (vm > 0) { for (m = 1.0; vm; vm--) { m *= 10.0; } } else { for (m = 1.0; vm; vm++) { m /= 10.0; } } dval *= m; } if (float_modifier(c)) { c = getc(); } MAKE_FLOAT(nextval, dval); nexttok = tok_float; return c; } while (int_modifier(c)) { c = getc(); } MAKE_INT(nextval, val, base); nexttok = tok_discrete; return c; } static int skip_c_comment(c) int c; { for (;;) { if (c == BAD_INPUT) { return BAD_INPUT; } if (c == 0 || is_eof(c) || is_eol(c)) { return c; } switch (c) { case '\\': c = getc(); c = getc(); break; case '*': c = getc(); if (c == '/') { return getc(); } break; default: c = getc(); break; } } } static int skip_cpp_comment(c) int c; { for (;;) { if (c == BAD_INPUT) { return BAD_INPUT; } if ((c == 0) || is_eof(c)) return c; else if (is_eol(c)) return getc(); else c = getc(); } } static int advance() { curtok = nexttok; curval = nextval; for (;;) { if (c == BAD_INPUT) { nexttok = tok_error; break; } if (c == 0 || is_eof(c) || is_eol(c)) { nexttok = tok_eof; break; } if (is_white(c)) { c = getc(); continue; } if (is_digit(c)) { c = scan_digit(c); break; } if (is_alpha(c)) { nexttok = tok_error; break; } nexttok = c; c = getc(); switch (nexttok) { case '/': if (c == '*') { c = skip_c_comment(getc()); continue; } else if (c == '/') { c = skip_cpp_comment(getc()); continue; } break; case '\"': c = scan_string(c); nexttok = tok_string; break; case '\'': c = scan_char_const(c); nexttok = tok_discrete; break; case '<': if (c == '<') { c = getc(); nexttok = tok_shift_left; } else if (c == '=') { c = getc(); nexttok = tok_leq; } break; case '>': if (c == '>') { c = getc(); nexttok = tok_shift_right; } else if (c == '=') { c = getc(); nexttok = tok_geq; } break; case '=': if (c == '=') { c = getc(); nexttok = tok_eq; } break; case '!': if (c == '=') { c = getc(); nexttok = tok_neq; } break; case '|': if (c == '|') { c = getc(); nexttok = tok_or; } break; case '&': if (c == '&') { c = getc(); nexttok = tok_and; } break; } break; } end_of_subp: return curtok; } static int expect(tok) int tok; { if (curtok != tok) { recover = 1; return 0; } return 1; } static tokval_t eval(); static tokval_t term() { tokval_t val; char *p; switch (curtok) { case tok_discrete: case tok_float: case tok_string: val = curval; advance(); return val; case '-': advance(); val = term(); if (recover) { return val; } if (IS_EVAL_INT(val)) { EVAL_INT(val) = -EVAL_INT(val); return val; } if (IS_EVAL_FLOAT(val)) { EVAL_FLOAT(val) = -EVAL_FLOAT(val); return val; } MAKE_FAIL(val); return val; case '+': advance(); val = term(); if (recover) { return val; } MAKE_FAIL(val); return val; case '!': advance(); val = term(); if (recover) { return val; } if (IS_EVAL_INT(val)) { EVAL_INT(val) = !EVAL_INT(val); return val; } MAKE_FAIL(val); return val; case '~': advance(); val = term(); if (recover) { return val; } if (IS_EVAL_INT(val)) { EVAL_INT(val) = ~EVAL_INT(val); return val; } MAKE_FAIL(val); return val; case '(': advance(); val = eval(); if (recover) { return val; } if (expect(')')) { advance(); } else { MAKE_FAIL(val); } return val; default: return failed(); } } static tokval_t f10() { tokval_t l,r; int op; if (recover) { MAKE_FAIL(l); return l; } l = term(); if (recover) { return l; } for (;;) { switch (curtok) { case '*': case '/': case '%': op = curtok; break; default: return l; } advance(); r = term(); if (recover) { return r; } switch (promote(&l,&r)) { case eval_int: switch (op) { case '*': EVAL_INT(l) = EVAL_INT(l) * EVAL_INT(r); break; case '/': if (EVAL_INT(r) == 0) { return failed(); } EVAL_INT(l) = EVAL_INT(l) / EVAL_INT(r); break; case '%': if (EVAL_INT(r) == 0) { return failed(); } EVAL_INT(l) = EVAL_INT(l) % EVAL_INT(r); break; } break; case eval_float: switch (op) { case '*': EVAL_FLOAT(l) = EVAL_FLOAT(l) * EVAL_FLOAT(r); break; case '/': if (EVAL_FLOAT(r) == 0.0) { return failed(); } EVAL_FLOAT(l) = EVAL_FLOAT(l) / EVAL_FLOAT(r); break; case '%': if (EVAL_FLOAT(r) == 0.0) { return failed(); } EVAL_FLOAT(l) = EVAL_FLOAT(l) / EVAL_FLOAT(r); break; } break; default: return failed(); } } } static tokval_t f9() { tokval_t l,r; int op; if (recover) { MAKE_FAIL(l); return l; } l = f10(); if (recover) { return l; } for (;;) { switch (curtok) { case '+': case '-': op = curtok; break; default: return l; } advance(); r = f10(); if (recover) { return r; } switch (promote(&l,&r)) { case eval_int: switch (op) { case '+': EVAL_INT(l) = EVAL_INT(l) + EVAL_INT(r); break; case '-': EVAL_INT(l) = EVAL_INT(l) - EVAL_INT(r); break; } break; case eval_float: switch (op) { case '+': EVAL_FLOAT(l) = EVAL_FLOAT(l) + EVAL_FLOAT(r); break; case '-': EVAL_FLOAT(l) = EVAL_FLOAT(l) - EVAL_FLOAT(r); break; } break; default: return failed(); } } } static tokval_t f8() { tokval_t l,r; int op, tmp; if (recover) { MAKE_FAIL(l); return l; } l = f9(); if (recover) { return l; } for (;;) { switch (curtok) { case tok_shift_left: case tok_shift_right: op = curtok; break; default: return l; } advance(); r = f9(); if (recover) { return r; } if (IS_EVAL_INT(l) & IS_EVAL_INT(r)) { switch (op) { case tok_shift_left: EVAL_INT(l) = EVAL_INT(l) << EVAL_INT(r); break; case tok_shift_right: EVAL_INT(l) = EVAL_INT(l) >> EVAL_INT(r); break; } } else { return failed(); } } } static tokval_t f7() { tokval_t l,r; int op, tmp; if (recover) { MAKE_FAIL(l); return l; } l = f8(); if (recover) { return l; } for (;;) { switch (curtok) { case '>': case tok_geq: case '<': case tok_leq: op = curtok; break; default: return l; } advance(); r = f8(); if (recover) { return r; } switch (promote(&l,&r)) { case eval_int: switch (op) { case '>': EVAL_INT(l) = EVAL_INT(l) > EVAL_INT(r); break; case tok_geq: EVAL_INT(l) = EVAL_INT(l) >= EVAL_INT(r); break; case '<': EVAL_INT(l) = EVAL_INT(l) < EVAL_INT(r); break; case tok_leq: EVAL_INT(l) = EVAL_INT(l) <= EVAL_INT(r); break; } break; case eval_float: switch (op) { case '>': tmp = EVAL_FLOAT(l) > EVAL_FLOAT(r); break; case tok_geq: tmp = EVAL_FLOAT(l) >= EVAL_FLOAT(r); break; case '<': tmp = EVAL_FLOAT(l) < EVAL_FLOAT(r); break; case tok_leq: tmp = EVAL_FLOAT(l) <= EVAL_FLOAT(r); break; } MAKE_INT(l, tmp, 10); break; default: return failed(); } } } static tokval_t f6() { tokval_t l,r; int op, tmp; if (recover) { MAKE_FAIL(l); return l; } l = f7(); if (recover) { return l; } for (;;) { switch (curtok) { case tok_eq: case tok_neq: op = curtok; break; default: return l; } advance(); r = f7(); if (recover) { return r; } switch (promote(&l,&r)) { case eval_int: if (op == tok_eq) { EVAL_INT(l) = EVAL_INT(l) == EVAL_INT(r); } else { EVAL_INT(l) = EVAL_INT(l) != EVAL_INT(r); } break; case eval_float: if (op == tok_eq) { tmp = EVAL_FLOAT(l) == EVAL_FLOAT(r); } else { tmp = EVAL_FLOAT(l) != EVAL_FLOAT(r); } MAKE_INT(l, tmp, 10); break; default: return failed(); } } } static tokval_t f5() { tokval_t l,r; if (recover) { MAKE_FAIL(l); return l; } l = f6(); if (recover) { return l; } for (;;) { if (curtok != '&') { return l; } advance(); r = f6(); if (recover) { return r; } if (IS_EVAL_INT(l) & IS_EVAL_INT(r)) { EVAL_INT(l) = EVAL_INT(l) & EVAL_INT(r); } else { return failed(); } } } static tokval_t f4() { tokval_t l,r; if (recover) { MAKE_FAIL(l); return l; } l = f5(); if (recover) { return l; } for (;;) { if (curtok != '^') { return l; } advance(); r = f5(); if (recover) { return r; } if (IS_EVAL_INT(l) & IS_EVAL_INT(r)) { EVAL_INT(l) = EVAL_INT(l) ^ EVAL_INT(r); } else { return failed(); } } } static tokval_t f3() { tokval_t l,r; if (recover) { MAKE_FAIL(l); return l; } l = f4(); if (recover) { return l; } for (;;) { if (curtok != '|') { return l; } advance(); r = f4(); if (recover) { return r; } if (IS_EVAL_INT(l) && IS_EVAL_INT(r)) { EVAL_INT(l) = EVAL_INT(l) | EVAL_INT(r); } else { return failed(); } } } static tokval_t f2() { tokval_t l,r; if (recover) { MAKE_FAIL(l); return l; } l = f3(); if (recover) { return l; } for (;;) { if (curtok != tok_and) { return l; } advance(); r = f3(); if (recover) { return r; } if (IS_EVAL_INT(l) && IS_EVAL_INT(r)) { EVAL_INT(l) = EVAL_INT(l) && EVAL_INT(r); } else { return failed(); } } } static tokval_t f1() { tokval_t l,r; if (recover) { MAKE_FAIL(l); return l; } l = f2(); if (recover) { return l; } for (;;) { if (curtok != tok_or) { return l; } advance(); r = f2(); if (recover) { return r; } if (IS_EVAL_INT(l) && IS_EVAL_INT(r)) { EVAL_INT(l) = EVAL_INT(l) || EVAL_INT(r); } else { return failed(); } } } static tokval_t eval() { tokval_t cond,tru,fals,tmp; if (recover) { MAKE_FAIL(tmp); return tmp; } tmp = f1(); if (recover) { return tmp; } for (;;) { if (curtok != '?') { return tmp; } advance(); tru = eval(); if (recover) { return tru; } if (!expect(':')) { MAKE_FAIL(tmp); return tmp; } advance(); fals = eval(); if (recover) { return fals; } if (IS_EVAL_INT(cond)) { tmp = (EVAL_INT(cond) != 0) ? tru : fals; } else { return failed(); } } } cpp_eval_result_t cpp_eval(str) char *str; { scan_position_t *newpos; scan_position_t *savepos; cpp_control_state_t save_state; cpp_control_state_t new_state; assert(str != NULL); buf_init(&evalbuf); result.eval_result_kind = eval_int; result.eval_result.ival = 0; new_state.skip_else = 0; new_state.cur_scope = 0; new_state.gen_scope = 0; new_state._parsing = 1; newpos = (scan_position_t*) allocate(sizeof(scan_position_t)); newpos->scan_kind = scan_text; newpos->scan.text = str; cpp_set_state(newpos, &new_state, &savepos, &save_state); if (savepos != NULL) { newpos->scan_pos = savepos->scan_pos; } c = ' '; recover = 0; advance(); advance(); result = eval(); cpp_set_state(savepos, &save_state, &newpos, &new_state); if (curtok != tok_eof) { MAKE_FAIL(result); } return result; }