- Romcc preprocessor bug fixes, (The code size went down about 350 lines.. :)
authorEric Biederman <ebiederm@xmission.com>
Mon, 8 Nov 2004 09:31:09 +0000 (09:31 +0000)
committerEric Biederman <ebiederm@xmission.com>
Mon, 8 Nov 2004 09:31:09 +0000 (09:31 +0000)
- 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

util/romcc/romcc.c

index e03bb6b41b69ec1872b399c3a63fbfde5163b7e2..1b2d5e832bbdb77605bb537fc30640a550b71ab3 100644 (file)
@@ -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 <stdarg.h>
@@ -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);