From: Eric Biederman Date: Mon, 8 Nov 2004 09:31:09 +0000 (+0000) Subject: - Romcc preprocessor bug fixes, (The code size went down about 350 lines.. :) X-Git-Url: http://wien.tomnetworks.com/gitweb/?p=coreboot.git;a=commitdiff_plain;h=41203d9b779d6f1c82de292b839793216f9199e7 - Romcc preprocessor bug fixes, (The code size went down about 350 lines.. :) - Preprocessor constant expression evaluation is no long a special case so unsigned long values can not be used. - Undefined macros are not converted to 0. But a big warning is printed. - Garbage at the of an #include directive is now done in tokens instead of in characters. This allows comments after an #include directive. - Repaired a previously unnoticed regression in constant expression evaluation. Logical expressions can now be evaluated again. git-svn-id: svn://svn.coreboot.org/coreboot/trunk@1767 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1 --- diff --git a/util/romcc/romcc.c b/util/romcc/romcc.c index e03bb6b41..1b2d5e832 100644 --- a/util/romcc/romcc.c +++ b/util/romcc/romcc.c @@ -3,8 +3,8 @@ #undef RELEASE_DATE #undef VERSION #define VERSION_MAJOR "0" -#define VERSION_MINOR "64" -#define RELEASE_DATE "28 June 2004" +#define VERSION_MINOR "65" +#define RELEASE_DATE "8 November 2004" #define VERSION VERSION_MAJOR "." VERSION_MINOR #include @@ -582,7 +582,7 @@ struct token { #define OP_CBRANCH 82 /* a conditional branch */ /* For conditional branch instructions * RHS(0) holds the branch condition. - * TARG(1) holds the branch target. + * TARG(0) holds the branch target. * ->next holds where to branch to if the branch is not taken. * The branch target can only be a label */ @@ -1057,7 +1057,8 @@ struct compile_state { struct file_state *file; struct occurance *last_occurance; const char *function; - struct token token[4]; + int token_base; + struct token token[6]; struct hash_entry *hash_table[HASH_TABLE_SIZE]; struct hash_entry *i_switch; struct hash_entry *i_case; @@ -2199,6 +2200,15 @@ struct triple *dup_triple(struct compile_state *state, struct triple *src) return dup; } +static struct triple *copy_triple(struct compile_state *state, struct triple *src) +{ + struct triple *copy; + copy = dup_triple(state, src); + copy->use = 0; + copy->next = copy->prev = copy; + return copy; +} + static struct triple *new_triple(struct compile_state *state, int op, struct type *type, int lhs, int rhs) { @@ -3176,26 +3186,31 @@ static void print_blocks(struct compile_state *state, const char *func, FILE *fp #define TOK_FIRST_KEYWORD TOK_AUTO #define TOK_LAST_KEYWORD TOK_ALIGNOF -#define TOK_DEFINE 100 -#define TOK_UNDEF 101 -#define TOK_INCLUDE 102 -#define TOK_LINE 103 -#define TOK_ERROR 104 -#define TOK_WARNING 105 -#define TOK_PRAGMA 106 -#define TOK_IFDEF 107 -#define TOK_IFNDEF 108 -#define TOK_ELIF 109 -#define TOK_ENDIF 110 - -#define TOK_FIRST_MACRO TOK_DEFINE -#define TOK_LAST_MACRO TOK_ENDIF +#define TOK_MDEFINE 100 +#define TOK_MDEFINED 101 +#define TOK_MUNDEF 102 +#define TOK_MINCLUDE 103 +#define TOK_MLINE 104 +#define TOK_MERROR 105 +#define TOK_MWARNING 106 +#define TOK_MPRAGMA 107 +#define TOK_MIFDEF 108 +#define TOK_MIFNDEF 109 +#define TOK_MELIF 110 +#define TOK_MENDIF 111 + +#define TOK_FIRST_MACRO TOK_MDEFINE +#define TOK_LAST_MACRO TOK_MENDIF -#define TOK_DEFINED 111 -#define TOK_EOF 112 +#define TOK_MIF 112 +#define TOK_MELSE 113 +#define TOK_MIDENT 114 + +#define TOK_EOL 115 +#define TOK_EOF 116 static const char *tokens[] = { -[TOK_UNKNOWN ] = "unknown", +[TOK_UNKNOWN ] = ":unknown:", [TOK_SPACE ] = ":space:", [TOK_SEMI ] = ";", [TOK_LBRACE ] = "{", @@ -3290,19 +3305,23 @@ static const char *tokens[] = { [TOK_ATTRIBUTE ] = "__attribute__", [TOK_ALIGNOF ] = "__alignof__", -[TOK_DEFINE ] = "define", -[TOK_UNDEF ] = "undef", -[TOK_INCLUDE ] = "include", -[TOK_LINE ] = "line", -[TOK_ERROR ] = "error", -[TOK_WARNING ] = "warning", -[TOK_PRAGMA ] = "pragma", -[TOK_IFDEF ] = "ifdef", -[TOK_IFNDEF ] = "ifndef", -[TOK_ELIF ] = "elif", -[TOK_ENDIF ] = "endif", - -[TOK_DEFINED ] = "defined", +[TOK_MDEFINE ] = "#define", +[TOK_MDEFINED ] = "#defined", +[TOK_MUNDEF ] = "#undef", +[TOK_MINCLUDE ] = "#include", +[TOK_MLINE ] = "#line", +[TOK_MERROR ] = "#error", +[TOK_MWARNING ] = "#warning", +[TOK_MPRAGMA ] = "#pragma", +[TOK_MIFDEF ] = "#ifdef", +[TOK_MIFNDEF ] = "#ifndef", +[TOK_MELIF ] = "#elif", +[TOK_MENDIF ] = "#endif", + +[TOK_MIF ] = "#if", +[TOK_MELSE ] = "#else", +[TOK_MIDENT ] = "#:ident:", +[TOK_EOL ] = "EOL", [TOK_EOF ] = "EOF", }; @@ -3366,11 +3385,20 @@ static void ident_to_macro(struct compile_state *state, struct token *tk) { struct hash_entry *entry; entry = tk->ident; - if (entry && - (entry->tok >= TOK_FIRST_MACRO) && - (entry->tok <= TOK_LAST_MACRO)) { + if (!entry) + return; + if ((entry->tok >= TOK_FIRST_MACRO) && (entry->tok <= TOK_LAST_MACRO)) { tk->tok = entry->tok; } + else if (entry->tok == TOK_IF) { + tk->tok = TOK_MIF; + } + else if (entry->tok == TOK_ELSE) { + tk->tok = TOK_MELSE; + } + else { + tk->tok = TOK_MIDENT; + } } static void hash_keyword( @@ -3507,17 +3535,18 @@ static void register_keywords(struct compile_state *state) static void register_macro_keywords(struct compile_state *state) { - hash_keyword(state, "define", TOK_DEFINE); - hash_keyword(state, "undef", TOK_UNDEF); - hash_keyword(state, "include", TOK_INCLUDE); - hash_keyword(state, "line", TOK_LINE); - hash_keyword(state, "error", TOK_ERROR); - hash_keyword(state, "warning", TOK_WARNING); - hash_keyword(state, "pragma", TOK_PRAGMA); - hash_keyword(state, "ifdef", TOK_IFDEF); - hash_keyword(state, "ifndef", TOK_IFNDEF); - hash_keyword(state, "elif", TOK_ELIF); - hash_keyword(state, "endif", TOK_ENDIF); + hash_keyword(state, "define", TOK_MDEFINE); + hash_keyword(state, "defined", TOK_MDEFINED); + hash_keyword(state, "undef", TOK_MUNDEF); + hash_keyword(state, "include", TOK_MINCLUDE); + hash_keyword(state, "line", TOK_MLINE); + hash_keyword(state, "error", TOK_MERROR); + hash_keyword(state, "warning", TOK_MWARNING); + hash_keyword(state, "pragma", TOK_MPRAGMA); + hash_keyword(state, "ifdef", TOK_MIFDEF); + hash_keyword(state, "ifndef", TOK_MIFNDEF); + hash_keyword(state, "elif", TOK_MELIF); + hash_keyword(state, "endif", TOK_MENDIF); } @@ -3574,7 +3603,7 @@ static void define_macro( macro->buf_len = value_len; macro->buf_off = value_off; macro->args = args; - macro->buf = xmalloc(macro->buf_len + 2, "macro buf"); + macro->buf = xmalloc(macro->buf_len + 1, "macro buf"); macro->argc = 0; for(arg = args; arg; arg = arg->next) { @@ -3582,8 +3611,7 @@ static void define_macro( } memcpy(macro->buf, value, macro->buf_len); - macro->buf[macro->buf_len] = '\n'; - macro->buf[macro->buf_len+1] = '\0'; + macro->buf[macro->buf_len] = '\0'; ident->sym_define = macro; } @@ -3663,6 +3691,16 @@ static int spacep(int c) case '\f': case '\v': case '\r': + ret = 1; + break; + } + return ret; +} + +static int eolp(int c) +{ + int ret = 0; + switch(c) { case '\n': ret = 1; break; @@ -3907,15 +3945,17 @@ static void raw_next_token(struct compile_state *state, tok = TOK_EOF; tokp = end; } + /* End of Line */ + else if (eolp(c)) { + tok = TOK_EOL; + file->line++; + file->report_line++; + file->line_start = tokp + 1; + } /* Whitespace */ else if (spacep(c)) { tok = TOK_SPACE; while ((tokp < end) && spacep(c)) { - if (c == '\n') { - file->line++; - file->report_line++; - file->line_start = tokp + 1; - } c = *(++tokp); } if (!spacep(c)) { @@ -3928,9 +3968,7 @@ static void raw_next_token(struct compile_state *state, for(tokp += 2; tokp < end; tokp++) { c = *tokp; if (c == '\n') { - file->line++; - file->report_line++; - file->line_start = tokp +1; + tokp--; break; } } @@ -3956,6 +3994,10 @@ static void raw_next_token(struct compile_state *state, if (tok == TOK_UNKNOWN) { error(state, 0, "unterminated comment"); } + if (state->token_base && (line != file->line)) { + error(state, 0, + "multiline comment in preprocessor directive"); + } file->report_line += line - file->line; file->line = line; file->line_start = line_start; @@ -3991,7 +4033,12 @@ static void raw_next_token(struct compile_state *state, error(state, 0, "unterminated string constant"); } if (line != file->line) { - warning(state, 0, "multiline string constant"); + if (state->token_base) { + /* Preprocessor directives cannot span lines */ + error(state, 0, "multiline string constant"); + } else { + warning(state, 0, "multiline string constant"); + } } file->report_line += line - file->line; file->line = line; @@ -4031,7 +4078,12 @@ static void raw_next_token(struct compile_state *state, error(state, 0, "unterminated character constant"); } if (line != file->line) { - warning(state, 0, "multiline character constant"); + if (state->token_base) { + /* Preprocessor directives cannot span lines */ + error(state, 0, "multiline character constant"); + } else { + warning(state, 0, "multiline character constant"); + } } file->report_line += line - file->line; file->line = line; @@ -4198,7 +4250,11 @@ static void raw_next_token(struct compile_state *state, file->pos = tokp + 1; tk->tok = tok; if (tok == TOK_IDENT) { - ident_to_keyword(state, tk); + if (state->token_base == 0) { + ident_to_keyword(state, tk); + } else { + ident_to_macro(state, tk); + } } } @@ -4230,7 +4286,7 @@ static void check_tok(struct compile_state *state, struct token *tk, int tok) const char *name1, *name2; name1 = tokens[tk->tok]; name2 = ""; - if (tk->tok == TOK_IDENT) { + if ((tk->tok == TOK_IDENT) || (tk->tok == TOK_MIDENT)) { name2 = tk->ident->name; } error(state, 0, "\tfound %s %s expected %s", @@ -4659,92 +4715,93 @@ static int compile_macro(struct compile_state *state, return 1; } +static void eat_tokens(struct compile_state *state, int targ_tok) +{ + if (state->eat_depth > 0) { + internal_error(state, 0, "Already eating..."); + } + state->eat_depth = state->if_depth; + state->eat_targ = targ_tok; +} +static int if_eat(struct compile_state *state) +{ + return state->eat_depth > 0; +} +static int if_value(struct compile_state *state) +{ + int index, offset; + index = state->if_depth / CHAR_BIT; + offset = state->if_depth % CHAR_BIT; + return !!(state->if_bytes[index] & (1 << (offset))); +} +static void set_if_value(struct compile_state *state, int value) +{ + int index, offset; + index = state->if_depth / CHAR_BIT; + offset = state->if_depth % CHAR_BIT; -static int mpeek(struct compile_state *state, int index) + state->if_bytes[index] &= ~(1 << offset); + if (value) { + state->if_bytes[index] |= (1 << offset); + } +} +static void in_if(struct compile_state *state, const char *name) { - struct token *tk; - int rescan; - tk = &state->token[index + 1]; - if (tk->tok == -1) { - do { - raw_next_token(state, state->file, tk); - } while(tk->tok == TOK_SPACE); + if (state->if_depth <= 0) { + error(state, 0, "%s without #if", name); } - do { - rescan = 0; - if ((tk->tok == TOK_EOF) && - (state->file != state->macro_file) && - (state->file->prev)) { - struct file_state *file = state->file; - state->file = file->prev; - /* file->basename is used keep it */ - if (file->report_dir != file->dirname) { - xfree(file->report_dir); - } - xfree(file->dirname); - xfree(file->buf); - xfree(file); - next_token(state, tk); - rescan = 1; - } - else if (tk->ident && tk->ident->sym_define) { - rescan = compile_macro(state, &state->file, tk); - if (rescan) { - next_token(state, tk); - } - - } - } while(rescan); - /* Don't show the token on the next line */ - if (state->macro_line < state->macro_file->line) { - return TOK_EOF; +} +static void enter_if(struct compile_state *state) +{ + state->if_depth += 1; + if (state->if_depth > MAX_CPP_IF_DEPTH) { + error(state, 0, "#if depth too great"); } - return tk->tok; } - -static void meat(struct compile_state *state, int index, int tok) +static void reenter_if(struct compile_state *state, const char *name) { - int i; - int next_tok; - next_tok = mpeek(state, index); - if (next_tok != tok) { - check_tok(state, &state->token[index + 1], tok); + in_if(state, name); + if ((state->eat_depth == state->if_depth) && + (state->eat_targ == TOK_MELSE)) { + state->eat_depth = 0; + state->eat_targ = 0; } - - /* Free the old token value */ - if (state->token[index].str_len) { - memset((void *)(state->token[index].val.str), -1, - state->token[index].str_len); - xfree(state->token[index].val.str); +} +static void enter_else(struct compile_state *state, const char *name) +{ + in_if(state, name); + if ((state->eat_depth == state->if_depth) && + (state->eat_targ == TOK_MELSE)) { + state->eat_depth = 0; + state->eat_targ = 0; } - for(i = index; i < sizeof(state->token)/sizeof(state->token[0]) - 1; i++) { - state->token[i] = state->token[i + 1]; +} +static void exit_if(struct compile_state *state, const char *name) +{ + in_if(state, name); + if (state->eat_depth == state->if_depth) { + state->eat_depth = 0; + state->eat_targ = 0; } - memset(&state->token[i], 0, sizeof(state->token[i])); - state->token[i].tok = -1; + state->if_depth -= 1; } -static int mpeek_raw(struct compile_state *state, int index) +static void cpp_token(struct compile_state *state, struct token *tk) { - struct token *tk; + struct file_state *file; int rescan; - tk = &state->token[index + 1]; - if (tk->tok == -1) { - do { - raw_next_token(state, state->file, tk); - } while(tk->tok == TOK_SPACE); - } + + next_token(state, tk); do { rescan = 0; + file = state->file; + /* Exit out of an include directive or macro call */ if ((tk->tok == TOK_EOF) && - (state->file != state->macro_file) && - (state->file->prev)) { - struct file_state *file = state->file; + (state->file && state->macro_file) && + file->prev) + { state->file = file->prev; /* file->basename is used keep it */ - if (file->report_dir != file->dirname) { - xfree(file->report_dir); - } xfree(file->dirname); xfree(file->buf); xfree(file); @@ -4752,450 +4809,243 @@ static int mpeek_raw(struct compile_state *state, int index) rescan = 1; } } while(rescan); - /* Don't show the token on the next line */ - if (state->macro_line < state->macro_file->line) { - return TOK_EOF; - } - return tk->tok; } -static void meat_raw(struct compile_state *state, int index, int tok) -{ - int next_tok; - int i; - next_tok = mpeek_raw(state, index); - if (next_tok != tok) { - check_tok(state, &state->token[index + 1], tok); - } +static void preprocess(struct compile_state *state, struct token *tk); - /* Free the old token value */ - if (state->token[index].str_len) { - memset((void *)(state->token[index].val.str), -1, - state->token[index].str_len); - xfree(state->token[index].val.str); - } - for(i = index; i < sizeof(state->token)/sizeof(state->token[0]) - 1; i++) { - state->token[i] = state->token[i + 1]; - } - memset(&state->token[i], 0, sizeof(state->token[i])); - state->token[i].tok = -1; -} - -static long_t mcexpr(struct compile_state *state, int index); - -static long_t mprimary_expr(struct compile_state *state, int index) +static void token(struct compile_state *state, struct token *tk) { - long_t val; - int tok; - tok = mpeek(state, index); - switch(tok) { - case TOK_LPAREN: - meat(state, index, TOK_LPAREN); - val = mcexpr(state, index); - meat(state, index, TOK_RPAREN); - break; - case TOK_LIT_INT: - { - long lval; - char *end; - meat(state, index, TOK_LIT_INT); - errno = 0; - lval = strtol(state->token[index].val.str, &end, 0); - if ((lval > LONG_T_MAX) || (lval < LONG_T_MIN) || - (((lval == LONG_MIN) || (lval == LONG_MAX)) && - (errno == ERANGE))) { - error(state, 0, "Integer constant `%s' to large", state->token[index].val.str); + int rescan; + cpp_token(state, tk); + do { + rescan = 0; + /* Process a macro directive */ + if (tk->tok == TOK_MACRO) { + preprocess(state, tk); + rescan = 1; } - val = lval; - break; - } - default: - meat(state, index, TOK_LIT_INT); - val = 0; - } - return val; -} -static long_t munary_expr(struct compile_state *state, int index) -{ - long_t val; - int tok; - tok = mpeek(state, index); - if ((tok == TOK_IDENT) && - (state->token[index + 1].ident == state->i_defined)) { - tok = TOK_DEFINED; - } - switch(tok) { - case TOK_PLUS: - meat(state, index, TOK_PLUS); - val = munary_expr(state, index); - val = + val; - break; - case TOK_MINUS: - meat(state, index, TOK_MINUS); - val = munary_expr(state, index); - val = - val; - break; - case TOK_TILDE: - meat(state, index, TOK_BANG); - val = munary_expr(state, index); - val = ~ val; - break; - case TOK_BANG: - meat(state, index, TOK_BANG); - val = munary_expr(state, index); - val = ! val; - break; - case TOK_DEFINED: - { - struct hash_entry *ident; - int parens; - meat(state, index, TOK_IDENT); - parens = 0; - if (mpeek_raw(state, index) == TOK_LPAREN) { - meat(state, index, TOK_LPAREN); - parens = 1; + /* Expand a macro call */ + else if (tk->ident && tk->ident->sym_define) { + rescan = compile_macro(state, &state->file, tk); + if (rescan) { + cpp_token(state, tk); + } } - meat_raw(state, index, TOK_IDENT); - ident = state->token[index].ident; - val = ident->sym_define != 0; - if (parens) { - meat(state, index, TOK_RPAREN); + /* Eat tokens disabled by the preprocessor */ + else if (if_eat(state)) { + cpp_token(state, tk); + rescan = 1; } - break; - } - default: - val = mprimary_expr(state, index); - break; - } - return val; - -} -static long_t mmul_expr(struct compile_state *state, int index) -{ - long_t val; - int done; - val = munary_expr(state, index); - do { - long_t right; - done = 0; - switch(mpeek(state, index)) { - case TOK_STAR: - meat(state, index, TOK_STAR); - right = munary_expr(state, index); - val = val * right; - break; - case TOK_DIV: - meat(state, index, TOK_DIV); - right = munary_expr(state, index); - val = val / right; - break; - case TOK_MOD: - meat(state, index, TOK_MOD); - right = munary_expr(state, index); - val = val % right; - break; - default: - done = 1; - break; + /* When not in macro context hide EOL */ + else if ((tk->tok == TOK_EOL) && (state->token_base == 0)) { + next_token(state, tk); + rescan = 1; } - } while(!done); - - return val; + } while(rescan); } -static long_t madd_expr(struct compile_state *state, int index) -{ - long_t val; - int done; - val = mmul_expr(state, index); - do { - long_t right; - done = 0; - switch(mpeek(state, index)) { - case TOK_PLUS: - meat(state, index, TOK_PLUS); - right = mmul_expr(state, index); - val = val + right; - break; - case TOK_MINUS: - meat(state, index, TOK_MINUS); - right = mmul_expr(state, index); - val = val - right; - break; - default: - done = 1; - break; - } - } while(!done); - - return val; -} -static long_t mshift_expr(struct compile_state *state, int index) +static inline struct token *get_token(struct compile_state *state, int offset) { - long_t val; - int done; - val = madd_expr(state, index); - do { - long_t right; - done = 0; - switch(mpeek(state, index)) { - case TOK_SL: - meat(state, index, TOK_SL); - right = madd_expr(state, index); - val = val << right; - break; - case TOK_SR: - meat(state, index, TOK_SR); - right = madd_expr(state, index); - val = val >> right; - break; - default: - done = 1; - break; - } - } while(!done); - - return val; + int index; + index = state->token_base + offset; + if (index >= sizeof(state->token)/sizeof(state->token[0])) { + internal_error(state, 0, "token array to small"); + } + return &state->token[index]; } -static long_t mrel_expr(struct compile_state *state, int index) +static struct token *do_eat_token(struct compile_state *state, int tok) { - long_t val; - int done; - val = mshift_expr(state, index); - do { - long_t right; - done = 0; - switch(mpeek(state, index)) { - case TOK_LESS: - meat(state, index, TOK_LESS); - right = mshift_expr(state, index); - val = val < right; - break; - case TOK_MORE: - meat(state, index, TOK_MORE); - right = mshift_expr(state, index); - val = val > right; - break; - case TOK_LESSEQ: - meat(state, index, TOK_LESSEQ); - right = mshift_expr(state, index); - val = val <= right; - break; - case TOK_MOREEQ: - meat(state, index, TOK_MOREEQ); - right = mshift_expr(state, index); - val = val >= right; - break; - default: - done = 1; - break; - } - } while(!done); - return val; -} + struct token *tk; + int i; + check_tok(state, get_token(state, 1), tok); + + /* Free the old token value */ + tk = get_token(state, 0); + if (tk->str_len) { + memset((void *)tk->val.str, -1, tk->str_len); + xfree(tk->val.str); + } + /* Overwrite the old token with newer tokens */ + for(i = state->token_base; i < sizeof(state->token)/sizeof(state->token[0]) - 1; i++) { + state->token[i] = state->token[i + 1]; + } + /* Clear the last token */ + memset(&state->token[i], 0, sizeof(state->token[i])); + state->token[i].tok = -1; -static long_t meq_expr(struct compile_state *state, int index) -{ - long_t val; - int done; - val = mrel_expr(state, index); - do { - long_t right; - done = 0; - switch(mpeek(state, index)) { - case TOK_EQEQ: - meat(state, index, TOK_EQEQ); - right = mrel_expr(state, index); - val = val == right; - break; - case TOK_NOTEQ: - meat(state, index, TOK_NOTEQ); - right = mrel_expr(state, index); - val = val != right; - break; - default: - done = 1; - break; - } - } while(!done); - return val; + /* Return the token */ + return tk; } -static long_t mand_expr(struct compile_state *state, int index) +static int cpp_peek(struct compile_state *state) { - long_t val; - val = meq_expr(state, index); - while (mpeek(state, index) == TOK_AND) { - long_t right; - meat(state, index, TOK_AND); - right = meq_expr(state, index); - val = val & right; + struct token *tk1; + tk1 = get_token(state, 1); + if (tk1->tok == -1) { + cpp_token(state, tk1); } - return val; + return tk1->tok; } -static long_t mxor_expr(struct compile_state *state, int index) +static struct token *cpp_eat(struct compile_state *state, int tok) { - long_t val; - val = mand_expr(state, index); - while (mpeek(state, index) == TOK_XOR) { - long_t right; - meat(state, index, TOK_XOR); - right = mand_expr(state, index); - val = val ^ right; - } - return val; + cpp_peek(state); + return do_eat_token(state, tok); } -static long_t mor_expr(struct compile_state *state, int index) +static int peek(struct compile_state *state) { - long_t val; - val = mxor_expr(state, index); - while (mpeek(state, index) == TOK_OR) { - long_t right; - meat(state, index, TOK_OR); - right = mxor_expr(state, index); - val = val | right; + struct token *tk1; + tk1 = get_token(state, 1); + if (tk1->tok == -1) { + token(state, tk1); } - return val; + return tk1->tok; } -static long_t mland_expr(struct compile_state *state, int index) +static int peek2(struct compile_state *state) { - long_t val; - val = mor_expr(state, index); - while (mpeek(state, index) == TOK_LOGAND) { - long_t right; - meat(state, index, TOK_LOGAND); - right = mor_expr(state, index); - val = val && right; + struct token *tk1, *tk2; + tk1 = get_token(state, 1); + tk2 = get_token(state, 2); + if (tk1->tok == -1) { + token(state, tk1); } - return val; -} -static long_t mlor_expr(struct compile_state *state, int index) -{ - long_t val; - val = mland_expr(state, index); - while (mpeek(state, index) == TOK_LOGOR) { - long_t right; - meat(state, index, TOK_LOGOR); - right = mland_expr(state, index); - val = val || right; + if (tk2->tok == -1) { + token(state, tk2); } - return val; + return tk2->tok; } -static long_t mcexpr(struct compile_state *state, int index) +static struct token *eat(struct compile_state *state, int tok) { - return mlor_expr(state, index); + peek(state); + return do_eat_token(state, tok); } -static void eat_tokens(struct compile_state *state, int targ_tok) -{ - if (state->eat_depth > 0) { - internal_error(state, 0, "Already eating..."); - } - state->eat_depth = state->if_depth; - state->eat_targ = targ_tok; -} -static int if_eat(struct compile_state *state) -{ - return state->eat_depth > 0; -} -static int if_value(struct compile_state *state) -{ - int index, offset; - index = state->if_depth / CHAR_BIT; - offset = state->if_depth % CHAR_BIT; - return !!(state->if_bytes[index] & (1 << (offset))); -} -static void set_if_value(struct compile_state *state, int value) +static void compile_file(struct compile_state *state, const char *filename, int local) { - int index, offset; - index = state->if_depth / CHAR_BIT; - offset = state->if_depth % CHAR_BIT; + char cwd[MAX_CWD_SIZE]; + const char *subdir, *base; + int subdir_len; + struct file_state *file; + char *basename; + file = xmalloc(sizeof(*file), "file_state"); - state->if_bytes[index] &= ~(1 << offset); - if (value) { - state->if_bytes[index] |= (1 << offset); + base = strrchr(filename, '/'); + subdir = filename; + if (base != 0) { + subdir_len = base - filename; + base++; } -} -static void in_if(struct compile_state *state, const char *name) -{ - if (state->if_depth <= 0) { - error(state, 0, "%s without #if", name); + else { + base = filename; + subdir_len = 0; } -} -static void enter_if(struct compile_state *state) -{ - state->if_depth += 1; - if (state->if_depth > MAX_CPP_IF_DEPTH) { - error(state, 0, "#if depth too great"); + basename = xmalloc(strlen(base) +1, "basename"); + strcpy(basename, base); + file->basename = basename; + + if (getcwd(cwd, sizeof(cwd)) == 0) { + die("cwd buffer to small"); } -} -static void reenter_if(struct compile_state *state, const char *name) -{ - in_if(state, name); - if ((state->eat_depth == state->if_depth) && - (state->eat_targ == TOK_ELSE)) { - state->eat_depth = 0; - state->eat_targ = 0; + if (subdir[0] == '/') { + file->dirname = xmalloc(subdir_len + 1, "dirname"); + memcpy(file->dirname, subdir, subdir_len); + file->dirname[subdir_len] = '\0'; } -} -static void enter_else(struct compile_state *state, const char *name) -{ - in_if(state, name); - if ((state->eat_depth == state->if_depth) && - (state->eat_targ == TOK_ELSE)) { - state->eat_depth = 0; - state->eat_targ = 0; + else { + const char *dir; + int dirlen; + const char **path; + /* Find the appropriate directory... */ + dir = 0; + if (!state->file && exists(cwd, filename)) { + dir = cwd; + } + if (local && state->file && exists(state->file->dirname, filename)) { + dir = state->file->dirname; + } + for(path = state->compiler->include_paths; !dir && *path; path++) { + if (exists(*path, filename)) { + dir = *path; + } + } + if (!dir) { + error(state, 0, "Cannot find `%s'\n", filename); + } + dirlen = strlen(dir); + file->dirname = xmalloc(dirlen + 1 + subdir_len + 1, "dirname"); + memcpy(file->dirname, dir, dirlen); + file->dirname[dirlen] = '/'; + memcpy(file->dirname + dirlen + 1, subdir, subdir_len); + file->dirname[dirlen + 1 + subdir_len] = '\0'; } + file->buf = slurp_file(file->dirname, file->basename, &file->size); + + file->pos = file->buf; + file->line_start = file->pos; + file->line = 1; + + file->report_line = 1; + file->report_name = file->basename; + file->report_dir = file->dirname; + + file->prev = state->file; + state->file = file; + + process_trigraphs(state); + splice_lines(state); } -static void exit_if(struct compile_state *state, const char *name) + +static struct triple *constant_expr(struct compile_state *state); +static void integral(struct compile_state *state, struct triple *def); + +static int mcexpr(struct compile_state *state) { - in_if(state, name); - if (state->eat_depth == state->if_depth) { - state->eat_depth = 0; - state->eat_targ = 0; + struct triple *cvalue; + cvalue = constant_expr(state); + integral(state, cvalue); + if (cvalue->op != OP_INTCONST) { + error(state, 0, "integer constant expected"); } - state->if_depth -= 1; + return cvalue->u.cval != 0; } -static void preprocess(struct compile_state *state, int index) +static void preprocess(struct compile_state *state, struct token *current_token) { /* Doing much more with the preprocessor would require * a parser and a major restructuring. * Postpone that for later. */ struct file_state *file; - struct token *tk; + int old_token_base; int line; int tok; file = state->file; - tk = &state->token[index]; state->macro_line = line = file->line; state->macro_file = file; - next_token(state, tk); - ident_to_macro(state, tk); - if (tk->tok == TOK_IDENT) { - error(state, 0, "undefined preprocessing directive `%s'", - tk->ident->name); - } - switch(tk->tok) { + old_token_base = state->token_base; + state->token_base = current_token - state->token; + + tok = cpp_peek(state); + switch(tok) { case TOK_LIT_INT: { + struct token *tk; int override_line; + tk = cpp_eat(state, TOK_LIT_INT); override_line = strtoul(tk->val.str, 0, 10); - next_token(state, tk); /* I have a cpp line marker parse it */ - if (tk->tok == TOK_LIT_STRING) { + if (cpp_peek(state) == TOK_LIT_STRING) { const char *token, *base; char *name, *dir; int name_len, dir_len; + tk = cpp_eat(state, TOK_LIT_STRING); name = xmalloc(tk->str_len, "report_name"); token = tk->val.str + 1; base = strrchr(token, '/'); @@ -5219,14 +5069,17 @@ static void preprocess(struct compile_state *state, int index) } break; } - case TOK_LINE: - meat(state, index, TOK_LIT_INT); + case TOK_MLINE: + { + struct token *tk; + cpp_eat(state, TOK_MLINE); + tk = eat(state, TOK_LIT_INT); file->report_line = strtoul(tk->val.str, 0, 10) -1; - if (mpeek(state, index) == TOK_LIT_STRING) { + if (cpp_peek(state) == TOK_LIT_STRING) { const char *token, *base; char *name, *dir; int name_len, dir_len; - meat(state, index, TOK_LIT_STRING); + tk = cpp_eat(state, TOK_LIT_STRING); name = xmalloc(tk->str_len, "report_name"); token = tk->val.str + 1; base = strrchr(token, '/'); @@ -5248,97 +5101,105 @@ static void preprocess(struct compile_state *state, int index) file->report_dir = dir; } break; - case TOK_UNDEF: + } + case TOK_MUNDEF: { struct hash_entry *ident; + cpp_eat(state, TOK_MUNDEF); if (if_eat(state)) /* quit early when #if'd out */ break; - - meat_raw(state, index, TOK_IDENT); - ident = tk->ident; + + ident = cpp_eat(state, TOK_MIDENT)->ident; undef_macro(state, ident); break; } - case TOK_PRAGMA: + case TOK_MPRAGMA: + cpp_eat(state, TOK_MPRAGMA); if (if_eat(state)) /* quit early when #if'd out */ break; - warning(state, 0, "Ignoring preprocessor directive: %s", - tk->ident->name); + warning(state, 0, "Ignoring pragma"); break; - case TOK_ELIF: + case TOK_MELIF: + cpp_eat(state, TOK_MELIF); reenter_if(state, "#elif"); if (if_eat(state)) /* quit early when #if'd out */ break; /* If the #if was taken the #elif just disables the following code */ if (if_value(state)) { - eat_tokens(state, TOK_ENDIF); + eat_tokens(state, TOK_MENDIF); } /* If the previous #if was not taken see if the #elif enables the * trailing code. */ else { - set_if_value(state, mcexpr(state, index) != 0); + set_if_value(state, mcexpr(state)); if (!if_value(state)) { - eat_tokens(state, TOK_ELSE); + eat_tokens(state, TOK_MELSE); } } break; - case TOK_IF: + case TOK_MIF: + cpp_eat(state, TOK_MIF); enter_if(state); if (if_eat(state)) /* quit early when #if'd out */ break; - set_if_value(state, mcexpr(state, index) != 0); + set_if_value(state, mcexpr(state)); if (!if_value(state)) { - eat_tokens(state, TOK_ELSE); + eat_tokens(state, TOK_MELSE); } break; - case TOK_IFNDEF: + case TOK_MIFNDEF: + { + struct hash_entry *ident; + + cpp_eat(state, TOK_MIFNDEF); enter_if(state); if (if_eat(state)) /* quit early when #if'd out */ break; - next_token(state, tk); - if ((line != file->line) || (tk->tok != TOK_IDENT)) { - error(state, 0, "Invalid macro name"); - } - set_if_value(state, tk->ident->sym_define == 0); + ident = cpp_eat(state, TOK_MIDENT)->ident; + set_if_value(state, ident->sym_define == 0); if (!if_value(state)) { - eat_tokens(state, TOK_ELSE); + eat_tokens(state, TOK_MELSE); } break; - case TOK_IFDEF: + } + case TOK_MIFDEF: + { + struct hash_entry *ident; + cpp_eat(state, TOK_MIFDEF); enter_if(state); if (if_eat(state)) /* quit early when #if'd out */ break; - next_token(state, tk); - if ((line != file->line) || (tk->tok != TOK_IDENT)) { - error(state, 0, "Invalid macro name"); - } - set_if_value(state, tk->ident->sym_define != 0); + ident = cpp_eat(state, TOK_MIDENT)->ident; + set_if_value(state, ident->sym_define != 0); if (!if_value(state)) { - eat_tokens(state, TOK_ELSE); + eat_tokens(state, TOK_MELSE); } break; - case TOK_ELSE: + } + case TOK_MELSE: + cpp_eat(state, TOK_MELSE); enter_else(state, "#else"); if (!if_eat(state) && if_value(state)) { - eat_tokens(state, TOK_ENDIF); + eat_tokens(state, TOK_MENDIF); } break; - case TOK_ENDIF: + case TOK_MENDIF: + cpp_eat(state, TOK_MENDIF); exit_if(state, "#endif"); break; - case TOK_DEFINE: + case TOK_MDEFINE: { struct hash_entry *ident; struct macro_arg *args, **larg; const char *start, *mstart, *ptr; + cpp_eat(state, TOK_MDEFINE); if (if_eat(state)) /* quit early when #if'd out */ break; - meat_raw(state, index, TOK_IDENT); - ident = tk->ident; + ident = cpp_eat(state, TOK_MIDENT)->ident; args = 0; larg = &args; @@ -5350,6 +5211,7 @@ static void preprocess(struct compile_state *state, int index) ; /* remove the trailing whitespace */ + ptr-=1; while(spacep(*ptr)) { ptr--; } @@ -5363,24 +5225,23 @@ static void preprocess(struct compile_state *state, int index) /* Parse macro parameters */ if (lparen_peek(state, state->file)) { - meat_raw(state, index, TOK_LPAREN); + cpp_eat(state, TOK_LPAREN); for(;;) { struct macro_arg *narg, *arg; struct hash_entry *aident; int tok; - tok = mpeek_raw(state, index); + tok = cpp_peek(state); if (!args && (tok == TOK_RPAREN)) { break; } else if (tok == TOK_DOTS) { - meat_raw(state, index, TOK_DOTS); + cpp_eat(state, TOK_DOTS); aident = state->i___VA_ARGS__; } else { - meat_raw(state, index, TOK_IDENT); - aident = tk->ident; + aident = cpp_eat(state, TOK_MIDENT)->ident; } narg = xcmalloc(sizeof(*arg), "macro arg"); @@ -5398,12 +5259,12 @@ static void preprocess(struct compile_state *state, int index) larg = &narg->next; if ((aident == state->i___VA_ARGS__) || - (mpeek(state, index) != TOK_COMMA)) { + (cpp_peek(state) != TOK_COMMA)) { break; } - meat_raw(state, index, TOK_COMMA); + cpp_eat(state, TOK_COMMA); } - meat_raw(state, index, TOK_RPAREN); + cpp_eat(state, TOK_RPAREN); /* Get the start of the macro body */ mstart = file->pos; @@ -5417,11 +5278,12 @@ static void preprocess(struct compile_state *state, int index) mstart - start, args); break; } - case TOK_ERROR: + case TOK_MERROR: { const char *end; int len; + cpp_eat(state, TOK_MERROR); /* Find the end of the line */ for(end = file->pos; *end != '\n'; end++) ; @@ -5432,11 +5294,12 @@ static void preprocess(struct compile_state *state, int index) file->pos = end; break; } - case TOK_WARNING: + case TOK_MWARNING: { const char *end; int len; + cpp_eat(state, TOK_MWARNING); /* Find the end of the line */ for(end = file->pos; *end != '\n'; end++) ; @@ -5447,17 +5310,20 @@ static void preprocess(struct compile_state *state, int index) file->pos = end; break; } - case TOK_INCLUDE: + case TOK_MINCLUDE: { char *name; - const char *ptr; int local; local = 0; name = 0; - next_token(state, tk); - if (tk->tok == TOK_LIT_STRING) { + + cpp_eat(state, TOK_MINCLUDE); + tok = peek(state); + if (tok == TOK_LIT_STRING) { + struct token *tk; const char *token; int name_len; + tk = eat(state, TOK_LIT_STRING); name = xmalloc(tk->str_len, "include"); token = tk->val.str +1; name_len = tk->str_len -2; @@ -5469,8 +5335,9 @@ static void preprocess(struct compile_state *state, int index) name[name_len] = '\0'; local = 1; } - else if (tk->tok == TOK_LESS) { + else if (tok == TOK_LESS) { const char *start, *end; + eat(state, TOK_LESS); start = file->pos; for(end = start; *end != '\n'; end++) { if (*end == '>') { @@ -5478,199 +5345,53 @@ static void preprocess(struct compile_state *state, int index) } } if (*end == '\n') { - error(state, 0, "Unterminated included directive"); + error(state, 0, "Unterminated include directive"); } name = xmalloc(end - start + 1, "include"); memcpy(name, start, end - start); name[end - start] = '\0'; - file->pos = end +1; + file->pos = end; local = 0; + eat(state, TOK_MORE); } else { error(state, 0, "Invalid include directive"); } - /* Error if there are any characters after the include */ - for(ptr = file->pos; *ptr != '\n'; ptr++) { - switch(*ptr) { - case ' ': - case '\t': - case '\v': - break; - default: - error(state, 0, "garbage after include directive"); - } + /* Error if there are any tokens after the include */ + if (cpp_peek(state) != TOK_EOL) { + error(state, 0, "garbage after include directive"); } if (!if_eat(state)) { compile_file(state, name, local); } xfree(name); - next_token(state, tk); - return; + break; } + case TOK_EOL: + /* Ignore # without a follwing ident */ + break; default: - /* Ignore # without a following ident */ - if (tk->tok == TOK_IDENT) { - error(state, 0, "Invalid preprocessor directive: %s", - tk->ident->name); + { + const char *name1, *name2; + name1 = tokens[tok]; + name2 = ""; + if (tok == TOK_MIDENT) { + name2 = get_token(state, 1)->ident->name; } + error(state, 0, "Invalid preprocessor directive: %s %s", + name1, name2); break; } + } /* Consume the rest of the macro line */ do { - tok = mpeek_raw(state, index); - meat_raw(state, index, tok); - } while(tok != TOK_EOF); + tok = cpp_peek(state); + cpp_eat(state, tok); + } while((tok != TOK_EOF) && (tok != TOK_EOL)); + state->token_base = old_token_base; return; } -static void token(struct compile_state *state, int index) -{ - struct file_state *file; - struct token *tk; - int rescan; - - tk = &state->token[index]; - next_token(state, tk); - do { - rescan = 0; - file = state->file; - if (tk->tok == TOK_EOF && file->prev) { - state->file = file->prev; - /* file->basename is used keep it */ - xfree(file->dirname); - xfree(file->buf); - xfree(file); - next_token(state, tk); - rescan = 1; - } - else if (tk->tok == TOK_MACRO) { - preprocess(state, index); - rescan = 1; - } - else if (tk->ident && tk->ident->sym_define) { - rescan = compile_macro(state, &state->file, tk); - if (rescan) { - next_token(state, tk); - } - } - else if (if_eat(state)) { - next_token(state, tk); - rescan = 1; - } - } while(rescan); -} - -static int peek(struct compile_state *state) -{ - if (state->token[1].tok == -1) { - token(state, 1); - } - return state->token[1].tok; -} - -static int peek2(struct compile_state *state) -{ - if (state->token[1].tok == -1) { - token(state, 1); - } - if (state->token[2].tok == -1) { - token(state, 2); - } - return state->token[2].tok; -} - -static void eat(struct compile_state *state, int tok) -{ - int i; - peek(state); - check_tok(state, &state->token[1], tok); - - /* Free the old token value */ - if (state->token[0].str_len) { - xfree((void *)(state->token[0].val.str)); - } - for(i = 0; i < sizeof(state->token)/sizeof(state->token[0]) - 1; i++) { - state->token[i] = state->token[i + 1]; - } - memset(&state->token[i], 0, sizeof(state->token[i])); - state->token[i].tok = -1; -} - -static void compile_file(struct compile_state *state, const char *filename, int local) -{ - char cwd[MAX_CWD_SIZE]; - const char *subdir, *base; - int subdir_len; - struct file_state *file; - char *basename; - file = xmalloc(sizeof(*file), "file_state"); - - base = strrchr(filename, '/'); - subdir = filename; - if (base != 0) { - subdir_len = base - filename; - base++; - } - else { - base = filename; - subdir_len = 0; - } - basename = xmalloc(strlen(base) +1, "basename"); - strcpy(basename, base); - file->basename = basename; - - if (getcwd(cwd, sizeof(cwd)) == 0) { - die("cwd buffer to small"); - } - if (subdir[0] == '/') { - file->dirname = xmalloc(subdir_len + 1, "dirname"); - memcpy(file->dirname, subdir, subdir_len); - file->dirname[subdir_len] = '\0'; - } - else { - const char *dir; - int dirlen; - const char **path; - /* Find the appropriate directory... */ - dir = 0; - if (!state->file && exists(cwd, filename)) { - dir = cwd; - } - if (local && state->file && exists(state->file->dirname, filename)) { - dir = state->file->dirname; - } - for(path = state->compiler->include_paths; !dir && *path; path++) { - if (exists(*path, filename)) { - dir = *path; - } - } - if (!dir) { - error(state, 0, "Cannot find `%s'\n", filename); - } - dirlen = strlen(dir); - file->dirname = xmalloc(dirlen + 1 + subdir_len + 1, "dirname"); - memcpy(file->dirname, dir, dirlen); - file->dirname[dirlen] = '/'; - memcpy(file->dirname + dirlen + 1, subdir, subdir_len); - file->dirname[dirlen + 1 + subdir_len] = '\0'; - } - file->buf = slurp_file(file->dirname, file->basename, &file->size); - - file->pos = file->buf; - file->line_start = file->pos; - file->line = 1; - - file->report_line = 1; - file->report_name = file->basename; - file->report_dir = file->dirname; - - file->prev = state->file; - state->file = file; - - process_trigraphs(state); - splice_lines(state); -} - /* Type helper functions */ static struct type *new_type( @@ -7761,13 +7482,14 @@ static struct triple *mkland_expr( struct triple *left, struct triple *right) { struct triple *def, *val, *var, *jmp, *mid, *end; + struct triple *lstore, *rstore; /* Generate some intermediate triples */ end = label(state); var = variable(state, &int_type); /* Store the left hand side value */ - left = write_expr(state, var, left); + lstore = write_expr(state, var, left); /* Jump if the value is false */ jmp = branch(state, end, @@ -7775,13 +7497,13 @@ static struct triple *mkland_expr( mid = label(state); /* Store the right hand side value */ - right = write_expr(state, var, right); + rstore = write_expr(state, var, right); /* An expression for the computed value */ val = read_expr(state, var); /* Generate the prog for a logical and */ - def = mkprog(state, var, left, jmp, mid, right, end, val, 0); + def = mkprog(state, var, lstore, jmp, mid, rstore, end, val, 0); return def; } @@ -10850,8 +10572,7 @@ static struct triple *character_constant(struct compile_state *state) const signed char *str, *end; int c; int str_len; - eat(state, TOK_LIT_CHAR); - tk = &state->token[0]; + tk = eat(state, TOK_LIT_CHAR); str = tk->val.str + 1; str_len = tk->str_len - 2; if (str_len <= 0) { @@ -10880,8 +10601,7 @@ static struct triple *string_constant(struct compile_state *state) type->elements = 0; /* The while loop handles string concatenation */ do { - eat(state, TOK_LIT_STRING); - tk = &state->token[0]; + tk = eat(state, TOK_LIT_STRING); str = tk->val.str + 1; str_len = tk->str_len - 2; if (str_len < 0) { @@ -10915,8 +10635,7 @@ static struct triple *integer_constant(struct compile_state *state) int u, l, decimal; struct type *type; - eat(state, TOK_LIT_INT); - tk = &state->token[0]; + tk = eat(state, TOK_LIT_INT); errno = 0; decimal = (tk->val.str[0] != '0'); val = strtoul(tk->val.str, &end, 0); @@ -10983,8 +10702,7 @@ static struct triple *primary_expr(struct compile_state *state) * a varable name * a function name */ - eat(state, TOK_IDENT); - ident = state->token[0].ident; + ident = eat(state, TOK_IDENT)->ident; if (!ident->sym_ident) { error(state, 0, "%s undeclared", ident->name); } @@ -10995,14 +10713,22 @@ static struct triple *primary_expr(struct compile_state *state) { struct hash_entry *ident; /* Here ident is an enumeration constant */ - eat(state, TOK_ENUM_CONST); - ident = state->token[0].ident; + ident = eat(state, TOK_ENUM_CONST)->ident; if (!ident->sym_ident) { error(state, 0, "%s undeclared", ident->name); } def = ident->sym_ident->def; break; } + case TOK_MIDENT: + { + struct hash_entry *ident; + ident = eat(state, TOK_MIDENT)->ident; + warning(state, 0, "Replacing undefined macro: %s with 0", + ident->name); + def = int_const(state, &int_type, 0); + break; + } case TOK_LPAREN: eat(state, TOK_LPAREN); def = expr(state); @@ -11053,8 +10779,7 @@ static struct triple *postfix_expr(struct compile_state *state) { struct hash_entry *field; eat(state, TOK_DOT); - eat(state, TOK_IDENT); - field = state->token[0].ident; + field = eat(state, TOK_IDENT)->ident; def = deref_field(state, def, field); break; } @@ -11062,8 +10787,7 @@ static struct triple *postfix_expr(struct compile_state *state) { struct hash_entry *field; eat(state, TOK_ARROW); - eat(state, TOK_IDENT); - field = state->token[0].ident; + field = eat(state, TOK_IDENT)->ident; def = mk_deref_expr(state, read_expr(state, def)); def = deref_field(state, def, field); break; @@ -11175,6 +10899,24 @@ static struct triple *unary_expr(struct compile_state *state) def = int_const(state, &ulong_type, align_of_in_bytes(state, type)); break; } + case TOK_MDEFINED: + { + /* We only come here if we are called from the preprocessor */ + struct hash_entry *ident; + int parens; + eat(state, TOK_MDEFINED); + parens = 0; + if (cpp_peek(state) == TOK_LPAREN) { + cpp_eat(state, TOK_LPAREN); + parens = 1; + } + ident = cpp_eat(state, TOK_MIDENT)->ident; + if (parens) { + eat(state, TOK_RPAREN); + } + def = int_const(state, &int_type, ident->sym_define != 0); + break; + } default: def = postfix_expr(state); break; @@ -11482,35 +11224,141 @@ static struct triple *conditional_expr(struct compile_state *state) return def; } +struct cv_triple { + struct triple *val; + int id; +}; + +static void set_cv(struct compile_state *state, struct cv_triple *cv, + struct triple *dest, struct triple *val) +{ + if (cv[dest->id].val) { + free_triple(state, cv[dest->id].val); + } + cv[dest->id].val = val; +} +static struct triple *get_cv(struct compile_state *state, struct cv_triple *cv, + struct triple *src) +{ + return cv[src->id].val; +} + static struct triple *eval_const_expr( struct compile_state *state, struct triple *expr) { struct triple *def; if (is_const(expr)) { def = expr; - } + } else { /* If we don't start out as a constant simplify into one */ struct triple *head, *ptr; + struct cv_triple *cv; + int i, count; head = label(state); /* dummy initial triple */ flatten(state, head, expr); + count = 1; + for(ptr = head->next; ptr != head; ptr = ptr->next) { + count++; + } + cv = xcmalloc(sizeof(struct cv_triple)*count, "const value vector"); + i = 1; for(ptr = head->next; ptr != head; ptr = ptr->next) { - simplify(state, ptr); + cv[i].val = 0; + cv[i].id = ptr->id; + ptr->id = i; + i++; } - /* Remove the constant value the tail of the list */ - def = head->prev; - def->prev->next = def->next; - def->next->prev = def->prev; - def->next = def->prev = def; - if (!is_const(def)) { - error(state, 0, "Not a constant expression"); + ptr = head->next; + do { + valid_ins(state, ptr); + if ((ptr->op == OP_PHI) || (ptr->op == OP_LIST)) { + internal_error(state, ptr, + "unexpected %s in constant expression", + tops(ptr->op)); + } + else if (ptr->op == OP_LIST) { + } + else if (triple_is_structural(state, ptr)) { + ptr = ptr->next; + } + else if (triple_is_ubranch(state, ptr)) { + ptr = TARG(ptr, 0); + } + else if (triple_is_cbranch(state, ptr)) { + struct triple *cond_val; + cond_val = get_cv(state, cv, RHS(ptr, 0)); + if (!cond_val || !is_const(cond_val) || + (cond_val->op != OP_INTCONST)) + { + internal_error(state, ptr, "bad branch condition"); + } + if (cond_val->u.cval == 0) { + ptr = ptr->next; + } else { + ptr = TARG(ptr, 0); + } + } + else if (triple_is_branch(state, ptr)) { + error(state, ptr, "bad branch type in constant expression"); + } + else if (ptr->op == OP_WRITE) { + struct triple *val; + val = get_cv(state, cv, RHS(ptr, 0)); + + set_cv(state, cv, MISC(ptr, 0), + copy_triple(state, val)); + set_cv(state, cv, ptr, + copy_triple(state, val)); + ptr = ptr->next; + } + else if (ptr->op == OP_READ) { + set_cv(state, cv, ptr, + copy_triple(state, + get_cv(state, cv, RHS(ptr, 0)))); + ptr = ptr->next; + } + else if (triple_is_pure(state, ptr, cv[ptr->id].id)) { + struct triple *val, **rhs; + val = copy_triple(state, ptr); + rhs = triple_rhs(state, val, 0); + for(; rhs; rhs = triple_rhs(state, val, rhs)) { + if (!*rhs) { + internal_error(state, ptr, "Missing rhs"); + } + *rhs = get_cv(state, cv, *rhs); + } + simplify(state, val); + set_cv(state, cv, ptr, val); + ptr = ptr->next; + } + else { + error(state, ptr, "impure operation in constant expression"); + } + + } while(ptr != head); + + /* Get the result value */ + def = get_cv(state, cv, head->prev); + cv[head->prev->id].val = 0; + + /* Free the temporary values */ + for(i = 0; i < count; i++) { + if (cv[i].val) { + free_triple(state, cv[i].val); + cv[i].val = 0; + } } + xfree(cv); /* Free the intermediate expressions */ while(head->next != head) { release_triple(state, head->next); } free_triple(state, head); } + if (!is_const(def)) { + error(state, expr, "Not a constant expression"); + } return def; } @@ -11864,8 +11712,7 @@ static void goto_statement(struct compile_state *state, struct triple *first) { struct hash_entry *ident; eat(state, TOK_GOTO); - eat(state, TOK_IDENT); - ident = state->token[0].ident; + ident = eat(state, TOK_IDENT)->ident; if (!ident->sym_label) { /* If this is a forward branch allocate the label now, * it will be flattend in the appropriate location later. @@ -11883,9 +11730,8 @@ static void labeled_statement(struct compile_state *state, struct triple *first) { struct triple *ins; struct hash_entry *ident; - eat(state, TOK_IDENT); - ident = state->token[0].ident; + ident = eat(state, TOK_IDENT)->ident; if (ident->sym_label && ident->sym_label->def) { ins = ident->sym_label->def; put_occurance(ins->occurance); @@ -12376,24 +12222,25 @@ static struct type *type_name(struct compile_state *state) static struct type *direct_declarator( struct compile_state *state, struct type *type, - struct hash_entry **ident, int need_ident) + struct hash_entry **pident, int need_ident) { + struct hash_entry *ident; struct type *outer; int op; outer = 0; arrays_complete(state, type); switch(peek(state)) { case TOK_IDENT: - eat(state, TOK_IDENT); + ident = eat(state, TOK_IDENT)->ident; if (!ident) { error(state, 0, "Unexpected identifier found"); } /* The name of what we are declaring */ - *ident = state->token[0].ident; + *pident = ident; break; case TOK_LPAREN: eat(state, TOK_LPAREN); - outer = declarator(state, type, ident, need_ident); + outer = declarator(state, type, pident, need_ident); eat(state, TOK_RPAREN); break; default: @@ -12453,13 +12300,13 @@ static struct type *direct_declarator( static struct type *declarator( struct compile_state *state, struct type *type, - struct hash_entry **ident, int need_ident) + struct hash_entry **pident, int need_ident) { while(peek(state) == TOK_STAR) { eat(state, TOK_STAR); type = new_type(TYPE_POINTER | (type->type & STOR_MASK), type, 0); } - type = direct_declarator(state, type, ident, need_ident); + type = direct_declarator(state, type, pident, need_ident); return type; } @@ -12468,8 +12315,7 @@ static struct type *typedef_name( { struct hash_entry *ident; struct type *type; - eat(state, TOK_TYPE_NAME); - ident = state->token[0].ident; + ident = eat(state, TOK_TYPE_NAME)->ident; type = ident->sym_ident->type; specifiers |= type->type & QUAL_MASK; if ((specifiers & (STOR_MASK | QUAL_MASK)) != @@ -12491,9 +12337,7 @@ static struct type *enum_specifier( eat(state, TOK_ENUM); tok = peek(state); if ((tok == TOK_IDENT) || (tok == TOK_ENUM_CONST) || (tok == TOK_TYPE_NAME)) { - eat(state, tok); - ident = state->token[0].ident; - + ident = eat(state, tok)->ident; } base = 0; if (!ident || (peek(state) == TOK_LBRACE)) { @@ -12506,8 +12350,7 @@ static struct type *enum_specifier( struct hash_entry *eident; struct triple *value; struct type *entry; - eat(state, TOK_IDENT); - eident = state->token[0].ident; + eident = eat(state, TOK_IDENT)->ident; if (eident->sym_ident) { error(state, 0, "%s already declared", eident->name); @@ -12601,8 +12444,7 @@ static struct type *struct_or_union_specifier( } tok = peek(state); if ((tok == TOK_IDENT) || (tok == TOK_ENUM_CONST) || (tok == TOK_TYPE_NAME)) { - eat(state, tok); - ident = state->token[0].ident; + ident = eat(state, tok)->ident; } if (!ident || (peek(state) == TOK_LBRACE)) { ulong_t elements; @@ -12717,8 +12559,7 @@ static unsigned int attrib(struct compile_state *state, unsigned int attributes) case TOK_TYPE_NAME: { struct hash_entry *ident; - eat(state, TOK_IDENT); - ident = state->token[0].ident; + ident = eat(state, TOK_IDENT)->ident; if (ident == state->i_noinline) { if (attributes & ATTRIB_ALWAYS_INLINE) { @@ -12799,8 +12640,9 @@ static struct type *type_specifier( struct compile_state *state, unsigned int spec) { struct type *type; + int tok; type = 0; - switch(peek(state)) { + switch((tok = peek(state))) { case TOK_VOID: eat(state, TOK_VOID); type = new_type(TYPE_VOID | spec, 0, 0); @@ -12935,7 +12777,7 @@ static struct type *type_specifier( break; default: error(state, 0, "bad type specifier %s", - tokens[peek(state)]); + tokens[tok]); break; } return type; @@ -13082,8 +12924,7 @@ static struct field_info designator(struct compile_state *state, struct type *ty error(state, 0, "Struct designator not in struct initializer"); } eat(state, TOK_DOT); - eat(state, TOK_IDENT); - field = state->token[0].ident; + field = eat(state, TOK_IDENT)->ident; info.offset = field_offset(state, type, field); info.type = field_type(state, type, field); break; @@ -14724,6 +14565,10 @@ static void join_functions(struct compile_state *state) state->file = &file; state->function = ""; + if (!state->main_function) { + error(state, 0, "No functions to compile\n"); + } + /* The type of arguments */ args_type = state->main_function->type->right; /* The return type without any specifiers */ @@ -20237,9 +20082,6 @@ static int is_lattice_lo(struct compile_state *state, struct lattice_node *lnode return (lnode->val != lnode->def) && !is_scc_const(state, lnode->val); } - - - static void scc_add_fedge(struct compile_state *state, struct scc_state *scc, struct flow_edge *fedge) { @@ -20342,7 +20184,6 @@ static struct ssa_edge *scc_next_sedge( return sedge; } - static void initialize_scc_state( struct compile_state *state, struct scc_state *scc) { @@ -21529,7 +21370,7 @@ static void optimize(struct compile_state *state) print_triples(state); verify_consistency(state); - /* Analize the intermediate code */ + /* Analyze the intermediate code */ state->bb.first = state->first; analyze_basic_blocks(state, &state->bb); @@ -24808,22 +24649,21 @@ static void generate_code(struct compile_state *state) static void print_preprocessed_tokens(struct compile_state *state) { - struct token *tk; int tok; FILE *fp; int line; const char *filename; fp = state->output; - tk = &state->token[0]; filename = 0; line = 0; for(;;) { + struct token *tk; const char *token_str; tok = peek(state); if (tok == TOK_EOF) { break; } - eat(state, tok); + tk = eat(state, tok); token_str = tk->ident ? tk->ident->name : tk->str_len ? tk->val.str : @@ -24905,7 +24745,6 @@ static void compile(const char *filename, state.i_default = lookup(&state, "default", 7); state.i_return = lookup(&state, "return", 6); /* Memorize where predefined macros are. */ - state.i_defined = lookup(&state, "defined", 7); state.i___VA_ARGS__ = lookup(&state, "__VA_ARGS__", 11); state.i___FILE__ = lookup(&state, "__FILE__", 8); state.i___LINE__ = lookup(&state, "__LINE__", 8);