static expr *parse_primary(void) { switch(tok_cur){ case tok_ident: tok_next(); return expr_ident(); case tok_num: tok_next(); return expr_num(tok_cur_num); case tok_lparen: { expr *e; tok_next(); e = parse(); if(tok_cur != tok_rparen) CPP_DIE("close paren expected"); tok_next(); return e; } case tok_not: case tok_bnot: case tok_minus: { const e_op op = tok_cur; tok_next(); return expr_new_uop(op, parse_primary()); } default: break; } { char s[2]; *s = tok_cur, s[1] = '\0'; CPP_DIE("expression expected (got %s)", tok_cur == tok_eof ? "eof" : s); } }
void preproc_push(FILE *f, const char *fname, int is_sysh) { if(file_stack_idx >= 0) file_stack[file_stack_idx].line_no = current_line; /* save state */ file_stack_idx++; if(file_stack_idx == countof(file_stack)) CPP_DIE("too many includes"); #ifdef DO_CHDIR char *wd; curwdfd = open(".", O_RDONLY); if(curwdfd == -1) ppdie(p, "open(\".\"): %s", strerror(errno)); /* make sure everything is relative to the file */ wd = udirname(p->fname); if(chdir(wd)) ppdie(p, "chdir(\"%s\"): %s (for %s)", wd, strerror(errno), p->fname); free(wd); #endif /* setup new state */ set_current_fname(fname); file_stack[file_stack_idx].file = f; file_stack[file_stack_idx].fname = ustrdup(fname); file_stack[file_stack_idx].line_no = current_line = 1; file_stack[file_stack_idx].is_sysh = is_sysh; preproc_emit_line_info_top(LINEINFO_START_OF_FILE); }
void preprocess(void) { char *line; int eof = 0; preproc_push(stdin, current_fname, /*sysh:*/0); while(!eof && (line = splice_lines(&eof))){ debug_push_line(line); if(option_digraphs) line = expand_digraphs(line); line = strip_comment(line); switch(strip_in_block){ case NOT_IN_BLOCK: case IN_BLOCK_BEGIN: case IN_BLOCK_END: line = filter_macros(line); case IN_BLOCK_FULL: /* no thanks */ break; } debug_pop_line(); if(line){ if(!no_output) puts(line); free(line); } } switch(strip_in_block){ case NOT_IN_BLOCK: case IN_BLOCK_END: break; case IN_BLOCK_BEGIN: case IN_BLOCK_FULL: CPP_DIE("no terminating block comment"); } parse_end_validate(); }
static expr *parse_rhs(expr *lhs, int priority) { for(;;){ int this_pri, next_pri; e_op op; expr *rhs; op = tok_cur; if(!is_op(op)) return lhs; /* eof, rparen and colon covered here */ this_pri = PRECEDENCE(op); if(this_pri > priority) return lhs; /* eat the op */ tok_next(); /* special case for ternary */ if(op == tok_question){ expr *if_t = parse(); if(tok_cur != tok_colon) CPP_DIE("colon expected for ternary-? operator"); tok_next(); rhs = parse(); lhs = expr_new_top(lhs, if_t, rhs); }else{ rhs = parse_primary(); /* now on the next op, or eof (in which case, precedence returns -1 */ next_pri = PRECEDENCE(tok_cur); if(next_pri < this_pri) { /* next is tighter, give it our rhs as its lhs */ rhs = parse_rhs(rhs, next_pri); } lhs = expr_op(op, lhs, rhs); } } }
expr *expr_parse(char *str) { expr *e; expr_init(); debug_push_line(str); tok_begin(str); tok_next(); e = parse(); if(tok_cur != tok_eof) CPP_DIE("'%s' at end of expression", tok_last()); debug_pop_line(); return e; }
/* eval */ expr_n expr_eval(expr *e_, int *had_ident) { const expr ke = *e_; free(e_); switch(ke.type){ case E_IDENT: *had_ident = 1; return 0; /* identifiers are zero */ case E_NUM: return ke.bits.num; case E_UOP: { expr_n n = expr_eval(ke.bits.uop.e, had_ident); switch(ke.bits.op.op){ #define UNARY(ch, o) case ch: return o n UNARY('-', -); UNARY('!', !); UNARY('~', ~); default: break; } ICE("bad op"); } case E_OP: { expr_n nums[2]; nums[0] = expr_eval(ke.bits.op.lhs, had_ident); nums[1] = expr_eval(ke.bits.op.rhs, had_ident); switch(ke.bits.op.op){ case '*': case '/': if(nums[1] == 0) CPP_DIE("%s by zero", ke.bits.op.op == '/' ? "division" : "modulo"); default: break; } switch(ke.bits.op.op){ #define OP(ty, op) case tok_ ## ty: return nums[0] op nums[1] OP(divide, /); OP(modulus, %); OP(multiply, *); OP(plus, +); OP(minus, -); OP(xor, ^); OP(or, |); OP(and, &); OP(orsc, ||); OP(andsc, &&); OP(shiftl, <<); OP(shiftr, >>); OP(eq, ==); OP(ne, !=); OP(le, <=); OP(lt, <); OP(ge, >=); OP(gt, >); #undef OP default: break; } ICE("bad op"); } case E_TOP: { expr_n a, b, c; /* must evaluate all - free the expressions */ a = expr_eval(ke.bits.top.e, had_ident); b = expr_eval(ke.bits.top.if_true, had_ident); c = expr_eval(ke.bits.top.if_false, had_ident); return a ? b : c; } } ICE("bad expr type"); }