Use copy_triple only on non-flattened nodes.
[coreboot.git] / util / romcc / romcc.c
index 4b65357cb8001b9b537cc6fd94901371e1cd7c64..b6f68409be2b6fb4ca2fce029ae0fff8bce51db4 100644 (file)
@@ -3,8 +3,8 @@
 #undef RELEASE_DATE
 #undef VERSION
 #define VERSION_MAJOR "0"
-#define VERSION_MINOR "67"
-#define RELEASE_DATE "9 November 2004"
+#define VERSION_MINOR "72"
+#define RELEASE_DATE "10 February 2010"
 #define VERSION VERSION_MAJOR "." VERSION_MINOR
 
 #include <stdarg.h>
 #define MAX_CWD_SIZE 4096
 #define MAX_ALLOCATION_PASSES 100
 
+/* NOTE: Before you even start thinking to touch anything 
+ * in this code, set DEBUG_ROMCC_WARNINGS to 1 to get an
+ * insight on the original author's thoughts. We introduced 
+ * this switch as romcc was about the only thing producing
+ * massive warnings in our code..
+ */
+#define DEBUG_ROMCC_WARNINGS 0
+
 #define DEBUG_CONSISTENCY 1
 #define DEBUG_SDP_BLOCKS 0
 #define DEBUG_TRIPLE_COLOR 0
 
 #define DEBUG_EXPLICIT_CLOSURES 0
 
+#if DEBUG_ROMCC_WARNINGS
 #warning "FIXME give clear error messages about unused variables"
 #warning "FIXME properly handle multi dimensional arrays"
 #warning "FIXME handle multiple register sizes"
+#endif
 
 /*  Control flow graph of a loop without goto.
  * 
  * Where do I place phi functions and how do I make that decision.
  *   
  */
+
+struct filelist {
+       const char *filename;
+       struct filelist *next;
+};
+
+struct filelist *include_filelist = NULL;
+
 static void die(char *fmt, ...)
 {
        va_list args;
@@ -209,11 +227,10 @@ static int exists(const char *dirname, const char *filename)
 static char *slurp_file(const char *dirname, const char *filename, off_t *r_size)
 {
        char cwd[MAX_CWD_SIZE];
-       int fd;
        char *buf;
        off_t size, progress;
        ssize_t result;
-       struct stat stats;
+       FILE* file;
        
        if (!filename) {
                *r_size = 0;
@@ -223,25 +240,22 @@ static char *slurp_file(const char *dirname, const char *filename, off_t *r_size
                die("cwd buffer to small");
        }
        xchdir(dirname);
-       fd = open(filename, O_RDONLY);
+       file = fopen(filename, "rb");
        xchdir(cwd);
-       if (fd < 0) {
+       if (file == NULL) {
                die("Cannot open '%s' : %s\n",
                        filename, strerror(errno));
        }
-       result = fstat(fd, &stats);
-       if (result < 0) {
-               die("Cannot stat: %s: %s\n",
-                       filename, strerror(errno));
-       }
-       size = stats.st_size;
+       fseek(file, 0, SEEK_END);
+       size = ftell(file);
+       fseek(file, 0, SEEK_SET);
        *r_size = size +1;
        buf = xmalloc(size +2, filename);
        buf[size] = '\n'; /* Make certain the file is newline terminated */
        buf[size+1] = '\0'; /* Null terminate the file for good measure */
        progress = 0;
        while(progress < size) {
-               result = read(fd, buf + progress, size - progress);
+               result = fread(buf + progress, 1, size - progress, file);
                if (result < 0) {
                        if ((errno == EINTR) || (errno == EAGAIN))
                                continue;
@@ -250,16 +264,14 @@ static char *slurp_file(const char *dirname, const char *filename, off_t *r_size
                }
                progress += result;
        }
-       result = close(fd);
-       if (result < 0) {
-               die("Close of %s failed: %s\n",
-                       filename, strerror(errno));
-       }
+       fclose(file);
        return buf;
 }
 
 /* Types on the destination platform */
+#if DEBUG_ROMCC_WARNINGS
 #warning "FIXME this assumes 32bit x86 is the destination"
+#endif
 typedef int8_t   schar_t;
 typedef uint8_t  uchar_t;
 typedef int8_t   char_t;
@@ -268,7 +280,7 @@ typedef uint16_t ushort_t;
 typedef int32_t  int_t;
 typedef uint32_t uint_t;
 typedef int32_t  long_t;
-typedef uint32_t ulong_t;
+#define ulong_t uint32_t
 
 #define SCHAR_T_MIN (-128)
 #define SCHAR_T_MAX 127
@@ -328,7 +340,7 @@ struct file_state {
        struct file_state *prev;
        const char *basename;
        char *dirname;
-       char *buf;
+       const char *buf;
        off_t size;
        const char *pos;
        int line;
@@ -336,12 +348,15 @@ struct file_state {
        int report_line;
        const char *report_name;
        const char *report_dir;
-       int macro : 1;
+       int macro      : 1;
+       int trigraphs  : 1;
+       int join_lines : 1;
 };
 struct hash_entry;
 struct token {
        int tok;
        struct hash_entry *ident;
+       const char *pos;
        int str_len;
        union {
                ulong_t integer;
@@ -797,7 +812,9 @@ static const struct op_info table_ops[] = {
 [OP_ADDRCONST  ] = OP( 0,  0, 1, 0, PURE | DEF, "addrconst"),
 [OP_UNKNOWNVAL ] = OP( 0,  0, 0, 0, PURE | DEF, "unknown"),
 
+#if DEBUG_ROMCC_WARNINGS
 #warning "FIXME is it correct for OP_WRITE to be a def?  I currently use it as one..."
+#endif
 [OP_WRITE      ] = OP( 0,  1, 1, 0, PURE | DEF | BLOCK, "write"),
 [OP_READ       ] = OP( 0,  1, 0, 0, PURE | DEF | BLOCK, "read"),
 [OP_COPY       ] = OP( 0,  1, 0, 0, PURE | DEF | BLOCK, "copy"),
@@ -1003,9 +1020,8 @@ struct macro_arg {
 };
 struct macro {
        struct hash_entry *ident;
-       char *buf;
+       const char *buf;
        int buf_len;
-       int buf_off;
        struct macro_arg *args;
        int argc;
 };
@@ -1048,7 +1064,7 @@ struct basic_blocks {
        struct block *first_block, *last_block;
        int last_vertex;
 };
-#define MAX_CPP_IF_DEPTH 63
+#define MAX_PP_IF_DEPTH 63
 struct compile_state {
        struct compiler_state *compiler;
        struct arch_state *arch;
@@ -1067,6 +1083,7 @@ struct compile_state {
        struct hash_entry *i_break;
        struct hash_entry *i_default;
        struct hash_entry *i_return;
+       struct hash_entry *i_noreturn;
        /* Additional hash entries for predefined macros */
        struct hash_entry *i_defined;
        struct hash_entry *i___VA_ARGS__;
@@ -1078,10 +1095,9 @@ struct compile_state {
        struct hash_entry *i_noinline;
        struct hash_entry *i_always_inline;
        int scope_depth;
-       unsigned char if_bytes[(MAX_CPP_IF_DEPTH + CHAR_BIT -1)/CHAR_BIT];
+       unsigned char if_bytes[(MAX_PP_IF_DEPTH + CHAR_BIT -1)/CHAR_BIT];
        int if_depth;
        int eat_depth, eat_targ;
-       int macro_line;
        struct file_state *macro_file;
        struct triple *functions;
        struct triple *main_function;
@@ -1300,7 +1316,10 @@ static struct triple *transform_to_arch_instruction(
        struct compile_state *state, struct triple *ins);
 static struct triple *flatten(
        struct compile_state *state, struct triple *first, struct triple *ptr);
-
+static void print_dominators(struct compile_state *state,
+       FILE *fp, struct basic_blocks *bb);
+static void print_dominance_frontiers(struct compile_state *state,
+       FILE *fp, struct basic_blocks *bb);
 
 
 
@@ -1376,9 +1395,11 @@ static struct triple *flatten(
 #define COMPILER_SIMPLIFY_LOGICAL          0x00004000
 #define COMPILER_SIMPLIFY_BITFIELD         0x00008000
 
-#define COMPILER_CPP_ONLY                  0x80000000
+#define COMPILER_TRIGRAPHS                 0x40000000
+#define COMPILER_PP_ONLY                   0x80000000
 
 #define COMPILER_DEFAULT_FLAGS ( \
+       COMPILER_TRIGRAPHS | \
        COMPILER_ELIMINATE_INEFECTUAL_CODE | \
        COMPILER_INLINE_DEFAULTON | \
        COMPILER_SIMPLIFY_OP | \
@@ -1558,7 +1579,8 @@ static int append_undef(struct compiler_state *compiler, const char *str)
 }
 
 static const struct compiler_flag romcc_flags[] = {
-       { "cpp-only",                  COMPILER_CPP_ONLY },
+       { "trigraphs",                 COMPILER_TRIGRAPHS },
+       { "pp-only",                   COMPILER_PP_ONLY },
        { "eliminate-inefectual-code", COMPILER_ELIMINATE_INEFECTUAL_CODE },
        { "simplify",                  COMPILER_SIMPLIFY },
        { "scc-transform",             COMPILER_SCC_TRANSFORM },
@@ -1590,7 +1612,7 @@ static const struct compiler_arg romcc_args[] = {
 static const struct compiler_flag romcc_opt_flags[] = {
        { "-O",  COMPILER_SIMPLIFY },
        { "-O2", COMPILER_SIMPLIFY | COMPILER_SCC_TRANSFORM },
-       { "-E",  COMPILER_CPP_ONLY },
+       { "-E",  COMPILER_PP_ONLY },
        { 0, 0, },
 };
 static const struct compiler_flag romcc_debug_flags[] = {
@@ -1747,7 +1769,7 @@ static void loc(FILE *fp, struct compile_state *state, struct triple *triple)
                state->file->report_name, state->file->report_line, col);
 }
 
-static void internal_error(struct compile_state *state, struct triple *ptr, 
+static void __attribute__ ((noreturn)) internal_error(struct compile_state *state, struct triple *ptr, 
        const char *fmt, ...)
 {
        FILE *fp = state->errout;
@@ -1785,7 +1807,7 @@ static void internal_warning(struct compile_state *state, struct triple *ptr,
 
 
 
-static void error(struct compile_state *state, struct triple *ptr, 
+static void __attribute__ ((noreturn)) error(struct compile_state *state, struct triple *ptr, 
        const char *fmt, ...)
 {
        FILE *fp = state->errout;
@@ -1840,6 +1862,7 @@ static void valid_ins(struct compile_state *state, struct triple *ptr)
        valid_op(state, ptr->op);
 }
 
+#if DEBUG_ROMCC_WARNING
 static void valid_param_count(struct compile_state *state, struct triple *ins)
 {
        int lhs, rhs, misc, targ;
@@ -1862,66 +1885,7 @@ static void valid_param_count(struct compile_state *state, struct triple *ins)
                internal_error(state, ins, "Bad targ count");
        }
 }
-
-static void process_trigraphs(struct compile_state *state)
-{
-       char *src, *dest, *end;
-       struct file_state *file;
-       file = state->file;
-       src = dest = file->buf;
-       end = file->buf + file->size;
-       while((end - src) >= 3) {
-               if ((src[0] == '?') && (src[1] == '?')) {
-                       int c = -1;
-                       switch(src[2]) {
-                       case '=': c = '#'; break;
-                       case '/': c = '\\'; break;
-                       case '\'': c = '^'; break;
-                       case '(': c = '['; break;
-                       case ')': c = ']'; break;
-                       case '!': c = '!'; break;
-                       case '<': c = '{'; break;
-                       case '>': c = '}'; break;
-                       case '-': c = '~'; break;
-                       }
-                       if (c != -1) {
-                               *dest++ = c;
-                               src += 3;
-                       }
-                       else {
-                               *dest++ = *src++;
-                       }
-               }
-               else {
-                       *dest++ = *src++;
-               }
-       }
-       while(src != end) {
-               *dest++ = *src++;
-       }
-       file->size = dest - file->buf;
-}
-
-static void splice_lines(struct compile_state *state)
-{
-       char *src, *dest, *end;
-       struct file_state *file;
-       file = state->file;
-       src = dest = file->buf;
-       end = file->buf + file->size;
-       while((end - src) >= 2) {
-               if ((src[0] == '\\') && (src[1] == '\n')) {
-                       src += 2;
-               }
-               else {
-                       *dest++ = *src++;
-               }
-       }
-       while(src != end) {
-               *dest++ = *src++;
-       }
-       file->size = dest - file->buf;
-}
+#endif
 
 static struct type void_type;
 static struct type unknown_type;
@@ -1932,12 +1896,16 @@ static void use_triple(struct triple *used, struct triple *user)
                return;
        if (!user)
                return;
-       ptr = &used->use;
-       while(*ptr) {
-               if ((*ptr)->member == user) {
-                       return;
+       if (used->use == (void*)-1)
+               used->use = 0;
+       if (used->use) {
+               ptr = &used->use;
+               while(*ptr) {
+                       if ((*ptr)->member == user) {
+                               return;
+                       }
+                       ptr = &(*ptr)->next;
                }
-               ptr = &(*ptr)->next;
        }
        /* Append new to the head of the list, 
         * copy_func and rename_block_variables
@@ -2696,13 +2664,15 @@ static int triple_is_ret(struct compile_state *state, struct triple *ins)
        /* Is this triple a return instruction? */
        return triple_is_branch_type(state, ins, RETBRANCH);
 }
-
+#if DEBUG_ROMCC_WARNING
 static int triple_is_simple_ubranch(struct compile_state *state, struct triple *ins)
 {
        /* Is this triple an unconditional branch and not a call or a
         * return? */
        return triple_is_branch_type(state, ins, UBRANCH);
 }
+#endif
 
 static int triple_is_end(struct compile_state *state, struct triple *ins)
 {
@@ -2978,7 +2948,10 @@ static int find_rhs_use(struct compile_state *state,
        struct triple **param;
        int size, i;
        verify_use(state, user, used);
+
+#if DEBUG_ROMCC_WARNINGS
 #warning "AUDIT ME ->rhs"
+#endif
        size = user->rhs;
        param = &RHS(user, 0);
        for(i = 0; i < size; i++) {
@@ -3087,128 +3060,128 @@ static void release_triple(struct compile_state *state, struct triple *ptr)
 static void print_triples(struct compile_state *state);
 static void print_blocks(struct compile_state *state, const char *func, FILE *fp);
 
-#define TOK_UNKNOWN     0
-#define TOK_SPACE       1
-#define TOK_SEMI        2
-#define TOK_LBRACE      3
-#define TOK_RBRACE      4
-#define TOK_COMMA       5
-#define TOK_EQ          6
-#define TOK_COLON       7
-#define TOK_LBRACKET    8
-#define TOK_RBRACKET    9
-#define TOK_LPAREN      10
-#define TOK_RPAREN      11
-#define TOK_STAR        12
-#define TOK_DOTS        13
-#define TOK_MORE        14
-#define TOK_LESS        15
-#define TOK_TIMESEQ     16
-#define TOK_DIVEQ       17
-#define TOK_MODEQ       18
-#define TOK_PLUSEQ      19
-#define TOK_MINUSEQ     20
-#define TOK_SLEQ        21
-#define TOK_SREQ        22
-#define TOK_ANDEQ       23
-#define TOK_XOREQ       24
-#define TOK_OREQ        25
-#define TOK_EQEQ        26
-#define TOK_NOTEQ       27
-#define TOK_QUEST       28
-#define TOK_LOGOR       29
-#define TOK_LOGAND      30
-#define TOK_OR          31
-#define TOK_AND         32
-#define TOK_XOR         33
-#define TOK_LESSEQ      34
-#define TOK_MOREEQ      35
-#define TOK_SL          36
-#define TOK_SR          37
-#define TOK_PLUS        38
-#define TOK_MINUS       39
-#define TOK_DIV         40
-#define TOK_MOD         41
-#define TOK_PLUSPLUS    42
-#define TOK_MINUSMINUS  43
-#define TOK_BANG        44
-#define TOK_ARROW       45
-#define TOK_DOT         46
-#define TOK_TILDE       47
-#define TOK_LIT_STRING  48
-#define TOK_LIT_CHAR    49
-#define TOK_LIT_INT     50
-#define TOK_LIT_FLOAT   51
-#define TOK_MACRO       52
-#define TOK_CONCATENATE 53
-
-#define TOK_IDENT       54
-#define TOK_STRUCT_NAME 55
-#define TOK_ENUM_CONST  56
-#define TOK_TYPE_NAME   57
-
-#define TOK_AUTO        58
-#define TOK_BREAK       59
-#define TOK_CASE        60
-#define TOK_CHAR        61
-#define TOK_CONST       62
-#define TOK_CONTINUE    63
-#define TOK_DEFAULT     64
-#define TOK_DO          65
-#define TOK_DOUBLE      66
-#define TOK_ELSE        67
-#define TOK_ENUM        68
-#define TOK_EXTERN      69
-#define TOK_FLOAT       70
-#define TOK_FOR         71
-#define TOK_GOTO        72
-#define TOK_IF          73
-#define TOK_INLINE      74
-#define TOK_INT         75
-#define TOK_LONG        76
-#define TOK_REGISTER    77
-#define TOK_RESTRICT    78
-#define TOK_RETURN      79
-#define TOK_SHORT       80
-#define TOK_SIGNED      81
-#define TOK_SIZEOF      82
-#define TOK_STATIC      83
-#define TOK_STRUCT      84
-#define TOK_SWITCH      85
-#define TOK_TYPEDEF     86
-#define TOK_UNION       87
-#define TOK_UNSIGNED    88
-#define TOK_VOID        89
-#define TOK_VOLATILE    90
-#define TOK_WHILE       91
-#define TOK_ASM         92
-#define TOK_ATTRIBUTE   93
-#define TOK_ALIGNOF     94
+#define TOK_UNKNOWN       0
+#define TOK_SPACE         1
+#define TOK_SEMI          2
+#define TOK_LBRACE        3
+#define TOK_RBRACE        4
+#define TOK_COMMA         5
+#define TOK_EQ            6
+#define TOK_COLON         7
+#define TOK_LBRACKET      8
+#define TOK_RBRACKET      9
+#define TOK_LPAREN        10
+#define TOK_RPAREN        11
+#define TOK_STAR          12
+#define TOK_DOTS          13
+#define TOK_MORE          14
+#define TOK_LESS          15
+#define TOK_TIMESEQ       16
+#define TOK_DIVEQ         17
+#define TOK_MODEQ         18
+#define TOK_PLUSEQ        19
+#define TOK_MINUSEQ       20
+#define TOK_SLEQ          21
+#define TOK_SREQ          22
+#define TOK_ANDEQ         23
+#define TOK_XOREQ         24
+#define TOK_OREQ          25
+#define TOK_EQEQ          26
+#define TOK_NOTEQ         27
+#define TOK_QUEST         28
+#define TOK_LOGOR         29
+#define TOK_LOGAND        30
+#define TOK_OR            31
+#define TOK_AND           32
+#define TOK_XOR           33
+#define TOK_LESSEQ        34
+#define TOK_MOREEQ        35
+#define TOK_SL            36
+#define TOK_SR            37
+#define TOK_PLUS          38
+#define TOK_MINUS         39
+#define TOK_DIV           40
+#define TOK_MOD           41
+#define TOK_PLUSPLUS      42
+#define TOK_MINUSMINUS    43
+#define TOK_BANG          44
+#define TOK_ARROW         45
+#define TOK_DOT           46
+#define TOK_TILDE         47
+#define TOK_LIT_STRING    48
+#define TOK_LIT_CHAR      49
+#define TOK_LIT_INT       50
+#define TOK_LIT_FLOAT     51
+#define TOK_MACRO         52
+#define TOK_CONCATENATE   53
+
+#define TOK_IDENT         54
+#define TOK_STRUCT_NAME   55
+#define TOK_ENUM_CONST    56
+#define TOK_TYPE_NAME     57
+
+#define TOK_AUTO          58
+#define TOK_BREAK         59
+#define TOK_CASE          60
+#define TOK_CHAR          61
+#define TOK_CONST         62
+#define TOK_CONTINUE      63
+#define TOK_DEFAULT       64
+#define TOK_DO            65
+#define TOK_DOUBLE        66
+#define TOK_ELSE          67
+#define TOK_ENUM          68
+#define TOK_EXTERN        69
+#define TOK_FLOAT         70
+#define TOK_FOR           71
+#define TOK_GOTO          72
+#define TOK_IF            73
+#define TOK_INLINE        74
+#define TOK_INT           75
+#define TOK_LONG          76
+#define TOK_REGISTER      77
+#define TOK_RESTRICT      78
+#define TOK_RETURN        79
+#define TOK_SHORT         80
+#define TOK_SIGNED        81
+#define TOK_SIZEOF        82
+#define TOK_STATIC        83
+#define TOK_STRUCT        84
+#define TOK_SWITCH        85
+#define TOK_TYPEDEF       86
+#define TOK_UNION         87
+#define TOK_UNSIGNED      88
+#define TOK_VOID          89
+#define TOK_VOLATILE      90
+#define TOK_WHILE         91
+#define TOK_ASM           92
+#define TOK_ATTRIBUTE     93
+#define TOK_ALIGNOF       94
 #define TOK_FIRST_KEYWORD TOK_AUTO
 #define TOK_LAST_KEYWORD  TOK_ALIGNOF
 
-#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_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_MIF         112
-#define TOK_MELSE       113
-#define TOK_MIDENT      114
+#define TOK_MIF           112
+#define TOK_MELSE         113
+#define TOK_MIDENT        114
 
-#define TOK_EOL                115
-#define TOK_EOF         116
+#define TOK_EOL                  115
+#define TOK_EOF           116
 
 static const char *tokens[] = {
 [TOK_UNKNOWN     ] = ":unknown:",
@@ -3575,47 +3548,64 @@ static void undef_macro(struct compile_state *state, struct hash_entry *ident)
        }
 }
 
-static void define_macro(
-       struct compile_state *state,
-       struct hash_entry *ident, 
-       const char *value, int value_len, int value_off, 
-       struct macro_arg *args)
+static void do_define_macro(struct compile_state *state, 
+       struct hash_entry *ident, const char *body, 
+       int argc, struct macro_arg *args)
 {
        struct macro *macro;
        struct macro_arg *arg;
+       size_t body_len;
+
+       /* Find the length of the body */
+       body_len = strlen(body);
        macro = ident->sym_define;
        if (macro != 0) {
-               /* Explicitly allow identical redefinitions of the same macro */
-               if ((macro->buf_len == value_len) &&
-                       (memcmp(macro->buf, value, value_len) == 0)) {
+               int identical_bodies, identical_args;
+               struct macro_arg *oarg;
+               /* Explicitly allow identical redfinitions of the same macro */
+               identical_bodies = 
+                       (macro->buf_len == body_len) &&
+                       (memcmp(macro->buf, body, body_len) == 0);
+               identical_args = macro->argc == argc;
+               oarg = macro->args;
+               arg = args;
+               while(identical_args && arg) {
+                       identical_args = oarg->ident == arg->ident;
+                       arg = arg->next;
+                       oarg = oarg->next;
+               }
+               if (identical_bodies && identical_args) {
+                       xfree(body);
                        return;
                }
                error(state, 0, "macro %s already defined\n", ident->name);
        }
 #if 0
-       fprintf(state->errout, "%s: `%*.*s'\n",
-               ident->name,
-               value_len - value_off,
-               value_len - value_off,
-               value + value_off);
+       fprintf(state->errout, "#define %s: `%*.*s'\n",
+               ident->name, body_len, body_len, body);
 #endif
        macro = xmalloc(sizeof(*macro), "macro");
-       macro->ident = ident;
-       macro->buf_len = value_len;
-       macro->buf_off = value_off;
+       macro->ident   = ident;
+       macro->buf     = body;
+       macro->buf_len = body_len;
        macro->args    = args;
-       macro->buf = xmalloc(macro->buf_len + 1, "macro buf");
-
-       macro->argc = 0;
-       for(arg = args; arg; arg = arg->next) {
-               macro->argc += 1;
-       }      
-
-       memcpy(macro->buf, value, macro->buf_len);
-       macro->buf[macro->buf_len] = '\0';
+       macro->argc    = argc;
 
        ident->sym_define = macro;
 }
+       
+static void define_macro(
+       struct compile_state *state,
+       struct hash_entry *ident,
+       const char *body, int body_len,
+       int argc, struct macro_arg *args)
+{
+       char *buf;
+       buf = xmalloc(body_len + 1, "macro buf");
+       memcpy(buf, body, body_len);
+       buf[body_len] = '\0';
+       do_define_macro(state, ident, buf, argc, args);
+}
 
 static void register_builtin_macro(struct compile_state *state,
        const char *name, const char *value)
@@ -3626,7 +3616,7 @@ static void register_builtin_macro(struct compile_state *state,
                internal_error(state, 0, "Builtin macros with arguments not supported");
        }
        ident = lookup(state, name, strlen(name));
-       define_macro(state, ident, value, strlen(value), 0, 0);
+       define_macro(state, ident, value, strlen(value), -1, 0);
 }
 
 static void register_builtin_macros(struct compile_state *state)
@@ -3675,7 +3665,7 @@ static void process_cmdline_macros(struct compile_state *state)
                        body++;
                }
                ident = lookup(state, name, name_len);
-               define_macro(state, ident, body, strlen(body), 0, 0);
+               define_macro(state, ident, body, strlen(body), -1, 0);
        }
        for(macro = state->compiler->undefs; (name = *macro); macro++) {
                ident = lookup(state, name, strlen(name));
@@ -3698,17 +3688,6 @@ static int spacep(int c)
        return ret;
 }
 
-static int eolp(int c)
-{
-       int ret = 0;
-       switch(c) {
-       case '\n':
-               ret = 1;
-               break;
-       }
-       return ret;
-}
-
 static int digitp(int c)
 {
        int ret = 0;
@@ -3861,56 +3840,183 @@ static int char_value(struct compile_state *state,
        return c;
 }
 
-static const char *after_digits(const char *ptr, const char *end)
+static const char *next_char(struct file_state *file, const char *pos, int index)
 {
-       while((ptr < end) && digitp(*ptr)) {
-               ptr++;
+       const char *end = file->buf + file->size;
+       while(pos < end) {
+               /* Lookup the character */
+               int size = 1;
+               int c = *pos;
+               /* Is this a trigraph? */
+               if (file->trigraphs &&
+                       (c == '?') && ((end - pos) >= 3) && (pos[1] == '?')) 
+               {
+                       switch(pos[2]) {
+                       case '=': c = '#'; break;
+                       case '/': c = '\\'; break;
+                       case '\'': c = '^'; break;
+                       case '(': c = '['; break;
+                       case ')': c = ']'; break;
+                       case '!': c = '!'; break;
+                       case '<': c = '{'; break;
+                       case '>': c = '}'; break;
+                       case '-': c = '~'; break;
+                       }
+                       if (c != '?') {
+                               size = 3;
+                       }
+               }
+               /* Is this an escaped newline? */
+               if (file->join_lines &&
+                       (c == '\\') && (pos + size < end) && ((pos[1] == '\n') || ((pos[1] == '\r') && (pos[2] == '\n'))))
+               {
+                       int cr_offset = ((pos[1] == '\r') && (pos[2] == '\n'))?1:0;
+                       /* At the start of a line just eat it */
+                       if (pos == file->pos) {
+                               file->line++;
+                               file->report_line++;
+                               file->line_start = pos + size + 1 + cr_offset;
+                       }
+                       pos += size + 1 + cr_offset;
+               }
+               /* Do I need to ga any farther? */
+               else if (index == 0) {
+                       break;
+               }
+               /* Process a normal character */
+               else {
+                       pos += size;
+                       index -= 1;
+               }
+       }
+       return pos;
+}
+
+static int get_char(struct file_state *file, const char *pos)
+{
+       const char *end = file->buf + file->size;
+       int c;
+       c = -1;
+       pos = next_char(file, pos, 0);
+       if (pos < end) {
+               /* Lookup the character */
+               c = *pos;
+               /* If it is a trigraph get the trigraph value */
+               if (file->trigraphs &&
+                       (c == '?') && ((end - pos) >= 3) && (pos[1] == '?')) 
+               {
+                       switch(pos[2]) {
+                       case '=': c = '#'; break;
+                       case '/': c = '\\'; break;
+                       case '\'': c = '^'; break;
+                       case '(': c = '['; break;
+                       case ')': c = ']'; break;
+                       case '!': c = '!'; break;
+                       case '<': c = '{'; break;
+                       case '>': c = '}'; break;
+                       case '-': c = '~'; break;
+                       }
+               }
+       }
+       return c;
+}
+
+static void eat_chars(struct file_state *file, const char *targ)
+{
+       const char *pos = file->pos;
+       while(pos < targ) {
+               /* Do we have a newline? */
+               if (pos[0] == '\n') {
+                       file->line++;
+                       file->report_line++;
+                       file->line_start = pos + 1;
+               }
+               pos++;
+       }
+       file->pos = pos;
+}
+
+
+static size_t char_strlen(struct file_state *file, const char *src, const char *end)
+{
+       size_t len;
+       len = 0;
+       while(src < end) {
+               src = next_char(file, src, 1);
+               len++;
+       }
+       return len;
+}
+
+static void char_strcpy(char *dest, 
+       struct file_state *file, const char *src, const char *end)
+{
+       while(src < end) {
+               int c;
+               c = get_char(file, src);
+               src = next_char(file, src, 1);
+               *dest++ = c;
+       }
+}
+
+static char *char_strdup(struct file_state *file, 
+       const char *start, const char *end, const char *id)
+{
+       char *str;
+       size_t str_len;
+       str_len = char_strlen(file, start, end);
+       str = xcmalloc(str_len + 1, id);
+       char_strcpy(str, file, start, end);
+       str[str_len] = '\0';
+       return str;
+}
+
+static const char *after_digits(struct file_state *file, const char *ptr)
+{
+       while(digitp(get_char(file, ptr))) {
+               ptr = next_char(file, ptr, 1);
        }
        return ptr;
 }
 
-static const char *after_octdigits(const char *ptr, const char *end)
+static const char *after_octdigits(struct file_state *file, const char *ptr)
 {
-       while((ptr < end) && octdigitp(*ptr)) {
-               ptr++;
+       while(octdigitp(get_char(file, ptr))) {
+               ptr = next_char(file, ptr, 1);
        }
        return ptr;
 }
 
-static const char *after_hexdigits(const char *ptr, const char *end)
+static const char *after_hexdigits(struct file_state *file, const char *ptr)
 {
-       while((ptr < end) && hexdigitp(*ptr)) {
-               ptr++;
+       while(hexdigitp(get_char(file, ptr))) {
+               ptr = next_char(file, ptr, 1);
        }
        return ptr;
 }
 
-static void save_string(struct compile_state *state, 
+static const char *after_alnums(struct file_state *file, const char *ptr)
+{
+       int c;
+       c = get_char(file, ptr);
+       while(letterp(c) || digitp(c)) {
+               ptr = next_char(file, ptr, 1);
+               c = get_char(file, ptr);
+       }
+       return ptr;
+}
+
+static void save_string(struct file_state *file,
        struct token *tk, const char *start, const char *end, const char *id)
 {
        char *str;
-       int str_len;
+
        /* Create a private copy of the string */
-       str_len = end - start + 1;
-       str = xmalloc(str_len + 1, id);
-       memcpy(str, start, str_len);
-       str[str_len] = '\0';
+       str = char_strdup(file, start, end, id);
 
        /* Store the copy in the token */
        tk->val.str = str;
-       tk->str_len = str_len;
-}
-
-static int lparen_peek(struct compile_state *state, struct file_state *file)
-{
-       const char *tokp, *end;
-       /* Is the next token going to be an lparen? 
-        * Whitespace tokens are significant for seeing if a macro
-        * should be expanded.
-        */
-       tokp = file->pos;
-       end = file->buf + file->size;
-       return (tokp < end) && (*tokp == '(');
+       tk->str_len = strlen(str);
 }
 
 static void raw_next_token(struct compile_state *state, 
@@ -3918,108 +4024,81 @@ static void raw_next_token(struct compile_state *state,
 {
        const char *token;
        int c, c1, c2, c3;
-       const char *tokp, *end;
+       const char *tokp;
+       int eat;
        int tok;
 
        tk->str_len = 0;
        tk->ident = 0;
-       token = tokp = file->pos;
-       end = file->buf + file->size;
+       token = tokp = next_char(file, file->pos, 0);
        tok = TOK_UNKNOWN;
-       c = -1;
-       if (tokp < end) {
-               c = *tokp;
-       }
-       c1 = -1;
-       if ((tokp + 1) < end) {
-               c1 = tokp[1];
-       }
-       c2 = -1;
-       if ((tokp + 2) < end) {
-               c2 = tokp[2];
-       }
-       c3 = -1;
-       if ((tokp + 3) < end) {
-               c3 = tokp[3];
-       }
-       if (tokp >= end) {
+       c  = get_char(file, tokp);
+       tokp = next_char(file, tokp, 1);
+       eat = 0;
+       c1 = get_char(file, tokp);
+       c2 = get_char(file, next_char(file, tokp, 1));
+       c3 = get_char(file, next_char(file, tokp, 2));
+
+       /* The end of the file */
+       if (c == -1) {
                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)) {
-                       c = *(++tokp);
-               }
-               if (!spacep(c)) {
-                       tokp--;
+               while (spacep(get_char(file, tokp))) {
+                       tokp = next_char(file, tokp, 1);
                }
        }
        /* EOL Comments */
        else if ((c == '/') && (c1 == '/')) {
                tok = TOK_SPACE;
-               for(tokp += 2; tokp < end; tokp++) {
-                       c = *tokp;
+               tokp = next_char(file, tokp, 1);
+               while((c = get_char(file, tokp)) != -1) {
+                       /* Advance to the next character only after we verify
+                        * the current character is not a newline.  
+                        * EOL is special to the preprocessor so we don't
+                        * want to loose any.
+                        */
                        if (c == '\n') {
-                               tokp--;
                                break;
                        }
+                       tokp = next_char(file, tokp, 1);
                }
        }
        /* Comments */
        else if ((c == '/') && (c1 == '*')) {
-               int line;
-               const char *line_start;
-               line = file->line;
-               line_start = file->line_start;
-               for(tokp += 2; (end - tokp) >= 2; tokp++) {
-                       c = *tokp;
-                       if (c == '\n') {
-                               line++;
-                               line_start = tokp +1;
-                       }
-                       else if ((c == '*') && (tokp[1] == '/')) {
+               tokp = next_char(file, tokp, 2);
+               c = c2;
+               while((c1 = get_char(file, tokp)) != -1) {
+                       tokp = next_char(file, tokp, 1);
+                       if ((c == '*') && (c1 == '/')) {
                                tok = TOK_SPACE;
-                               tokp += 1;
                                break;
                        }
+                       c = c1;
                }
                if (tok == TOK_UNKNOWN) {
                        error(state, 0, "unterminated comment");
                }
-               file->report_line += line - file->line;
-               file->line = line;
-               file->line_start = line_start;
        }
        /* string constants */
-       else if ((c == '"') ||
-               ((c == 'L') && (c1 == '"'))) {
-               int line;
-               const char *line_start;
-               int wchar;
-               line = file->line;
-               line_start = file->line_start;
+       else if ((c == '"') || ((c == 'L') && (c1 == '"'))) {
+               int wchar, multiline;
+
                wchar = 0;
+               multiline = 0;
                if (c == 'L') {
                        wchar = 1;
-                       tokp++;
+                       tokp = next_char(file, tokp, 1);
                }
-               for(tokp += 1; tokp < end; tokp++) {
-                       c = *tokp;
+               while((c = get_char(file, tokp)) != -1) {
+                       tokp = next_char(file, tokp, 1);
                        if (c == '\n') {
-                               line++;
-                               line_start = tokp + 1;
+                               multiline = 1;
                        }
-                       else if ((c == '\\') && (tokp +1 < end)) {
-                               tokp++;
+                       else if (c == '\\') {
+                               tokp = next_char(file, tokp, 1);
                        }
                        else if (c == '"') {
                                tok = TOK_LIT_STRING;
@@ -4029,37 +4108,30 @@ static void raw_next_token(struct compile_state *state,
                if (tok == TOK_UNKNOWN) {
                        error(state, 0, "unterminated string constant");
                }
-               if (line != file->line) {
+               if (multiline) {
                        warning(state, 0, "multiline string constant");
                }
-               file->report_line += line - file->line;
-               file->line = line;
-               file->line_start = line_start;
 
                /* Save the string value */
-               save_string(state, tk, token, tokp, "literal string");
+               save_string(file, tk, token, tokp, "literal string");
        }
        /* character constants */
-       else if ((c == '\'') ||
-               ((c == 'L') && (c1 == '\''))) {
-               int line;
-               const char *line_start;
-               int wchar;
-               line = file->line;
-               line_start = file->line_start;
+       else if ((c == '\'') || ((c == 'L') && (c1 == '\''))) {
+               int wchar, multiline;
+
                wchar = 0;
+               multiline = 0;
                if (c == 'L') {
                        wchar = 1;
-                       tokp++;
+                       tokp = next_char(file, tokp, 1);
                }
-               for(tokp += 1; tokp < end; tokp++) {
-                       c = *tokp;
+               while((c = get_char(file, tokp)) != -1) {
+                       tokp = next_char(file, tokp, 1);
                        if (c == '\n') {
-                               line++;
-                               line_start = tokp + 1;
+                               multiline = 1;
                        }
-                       else if ((c == '\\') && (tokp +1 < end)) {
-                               tokp++;
+                       else if (c == '\\') {
+                               tokp = next_char(file, tokp, 1);
                        }
                        else if (c == '\'') {
                                tok = TOK_LIT_CHAR;
@@ -4069,15 +4141,12 @@ static void raw_next_token(struct compile_state *state,
                if (tok == TOK_UNKNOWN) {
                        error(state, 0, "unterminated character constant");
                }
-               if (line != file->line) {
+               if (multiline) {
                        warning(state, 0, "multiline character constant");
                }
-               file->report_line += line - file->line;
-               file->line = line;
-               file->line_start = line_start;
 
                /* Save the character value */
-               save_string(state, tk, token, tokp, "literal character");
+               save_string(file, tk, token, tokp, "literal character");
        }
        /* integer and floating constants 
         * Integer Constants
@@ -4092,122 +4161,140 @@ static void raw_next_token(struct compile_state *state,
         * .{digits}[Ee][+-]?{digits}
         * .{digits}
         */
-       
        else if (digitp(c) || ((c == '.') && (digitp(c1)))) {
-               const char *next, *new;
+               const char *next;
                int is_float;
+               int cn;
                is_float = 0;
                if (c != '.') {
-                       next = after_digits(tokp, end);
+                       next = after_digits(file, tokp);
                }
                else {
-                       next = tokp;
-               }
-               if (next[0] == '.') {
-                       new = after_digits(next, end);
-                       is_float = (new != next);
-                       next = new;
-               }
-               if ((next[0] == 'e') || (next[0] == 'E')) {
-                       if (((next + 1) < end) && 
-                               ((next[1] == '+') || (next[1] == '-'))) {
-                               next++;
-                       }
-                       new = after_digits(next, end);
-                       is_float = (new != next);
+                       next = token;
+               }
+               cn = get_char(file, next);
+               if (cn == '.') {
+                       next = next_char(file, next, 1);
+                       next = after_digits(file, next);
+                       is_float = 1;
+               }
+               cn = get_char(file, next);
+               if ((cn == 'e') || (cn == 'E')) {
+                       const char *new;
+                       next = next_char(file, next, 1);
+                       cn = get_char(file, next);
+                       if ((cn == '+') || (cn == '-')) {
+                               next = next_char(file, next, 1);
+                       }
+                       new = after_digits(file, next);
+                       is_float |= (new != next);
                        next = new;
                }
                if (is_float) {
                        tok = TOK_LIT_FLOAT;
-                       if ((next < end) && (
-                               (next[0] == 'f') ||
-                               (next[0] == 'F') ||
-                               (next[0] == 'l') ||
-                               (next[0] == 'L'))
-                               ) {
-                               next++;
+                       cn = get_char(file, next);
+                       if ((cn  == 'f') || (cn == 'F') || (cn == 'l') || (cn == 'L')) {
+                               next = next_char(file, next, 1);
                        }
                }
                if (!is_float && digitp(c)) {
                        tok = TOK_LIT_INT;
                        if ((c == '0') && ((c1 == 'x') || (c1 == 'X'))) {
-                               next = after_hexdigits(tokp + 2, end);
+                               next = next_char(file, tokp, 1);
+                               next = after_hexdigits(file, next);
                        }
                        else if (c == '0') {
-                               next = after_octdigits(tokp, end);
+                               next = after_octdigits(file, tokp);
                        }
                        else {
-                               next = after_digits(tokp, end);
+                               next = after_digits(file, tokp);
                        }
                        /* crazy integer suffixes */
-                       if ((next < end) && 
-                               ((next[0] == 'u') || (next[0] == 'U'))) { 
-                               next++;
-                               if ((next < end) &&
-                                       ((next[0] == 'l') || (next[0] == 'L'))) {
-                                       next++;
+                       cn = get_char(file, next);
+                       if ((cn == 'u') || (cn == 'U')) {
+                               next = next_char(file, next, 1);
+                               cn = get_char(file, next);
+                               if ((cn == 'l') || (cn == 'L')) {
+                                       next = next_char(file, next, 1);
+                                       cn = get_char(file, next);
+                               }
+                               if ((cn == 'l') || (cn == 'L')) {
+                                       next = next_char(file, next, 1);
                                }
                        }
-                       else if ((next < end) &&
-                               ((next[0] == 'l') || (next[0] == 'L'))) {
-                               next++;
-                               if ((next < end) && 
-                                       ((next[0] == 'u') || (next[0] == 'U'))) { 
-                                       next++;
+                       else if ((cn == 'l') || (cn == 'L')) {
+                               next = next_char(file, next, 1);
+                               cn = get_char(file, next);
+                               if ((cn == 'l') || (cn == 'L')) {
+                                       next = next_char(file, next, 1);
+                                       cn = get_char(file, next);
+                               }
+                               if ((cn == 'u') || (cn == 'U')) {
+                                       next = next_char(file, next, 1);
                                }
                        }
                }
-               tokp = next - 1;
+               tokp = next;
 
                /* Save the integer/floating point value */
-               save_string(state, tk, token, tokp, "literal number");
+               save_string(file, tk, token, tokp, "literal number");
        }
        /* identifiers */
        else if (letterp(c)) {
                tok = TOK_IDENT;
-               tokp = identifier(tokp, end);
-               tokp -= 1;
-               tk->ident = lookup(state, token, tokp +1 - token);
+
+               /* Find and save the identifier string */
+               tokp = after_alnums(file, tokp);
+               save_string(file, tk, token, tokp, "identifier");
+
+               /* Look up to see which identifier it is */
+               tk->ident = lookup(state, tk->val.str, tk->str_len);
+
+               /* Free the identifier string */
+               tk->str_len = 0;
+               xfree(tk->val.str);
+
                /* See if this identifier can be macro expanded */
                tk->val.notmacro = 0;
-               if ((tokp < end) && (tokp[1] == '$')) {
-                       tokp++;
+               c = get_char(file, tokp);
+               if (c == '$') {
+                       tokp = next_char(file, tokp, 1);
                        tk->val.notmacro = 1;
                }
        }
        /* C99 alternate macro characters */
        else if ((c == '%') && (c1 == ':') && (c2 == '%') && (c3 == ':')) { 
-               tokp += 3; 
+               eat += 3;
                tok = TOK_CONCATENATE; 
        }
-       else if ((c == '.') && (c1 == '.') && (c2 == '.')) { tokp += 2; tok = TOK_DOTS; }
-       else if ((c == '<') && (c1 == '<') && (c2 == '=')) { tokp += 2; tok = TOK_SLEQ; }
-       else if ((c == '>') && (c1 == '>') && (c2 == '=')) { tokp += 2; tok = TOK_SREQ; }
-       else if ((c == '*') && (c1 == '=')) { tokp += 1; tok = TOK_TIMESEQ; }
-       else if ((c == '/') && (c1 == '=')) { tokp += 1; tok = TOK_DIVEQ; }
-       else if ((c == '%') && (c1 == '=')) { tokp += 1; tok = TOK_MODEQ; }
-       else if ((c == '+') && (c1 == '=')) { tokp += 1; tok = TOK_PLUSEQ; }
-       else if ((c == '-') && (c1 == '=')) { tokp += 1; tok = TOK_MINUSEQ; }
-       else if ((c == '&') && (c1 == '=')) { tokp += 1; tok = TOK_ANDEQ; }
-       else if ((c == '^') && (c1 == '=')) { tokp += 1; tok = TOK_XOREQ; }
-       else if ((c == '|') && (c1 == '=')) { tokp += 1; tok = TOK_OREQ; }
-       else if ((c == '=') && (c1 == '=')) { tokp += 1; tok = TOK_EQEQ; }
-       else if ((c == '!') && (c1 == '=')) { tokp += 1; tok = TOK_NOTEQ; }
-       else if ((c == '|') && (c1 == '|')) { tokp += 1; tok = TOK_LOGOR; }
-       else if ((c == '&') && (c1 == '&')) { tokp += 1; tok = TOK_LOGAND; }
-       else if ((c == '<') && (c1 == '=')) { tokp += 1; tok = TOK_LESSEQ; }
-       else if ((c == '>') && (c1 == '=')) { tokp += 1; tok = TOK_MOREEQ; }
-       else if ((c == '<') && (c1 == '<')) { tokp += 1; tok = TOK_SL; }
-       else if ((c == '>') && (c1 == '>')) { tokp += 1; tok = TOK_SR; }
-       else if ((c == '+') && (c1 == '+')) { tokp += 1; tok = TOK_PLUSPLUS; }
-       else if ((c == '-') && (c1 == '-')) { tokp += 1; tok = TOK_MINUSMINUS; }
-       else if ((c == '-') && (c1 == '>')) { tokp += 1; tok = TOK_ARROW; }
-       else if ((c == '<') && (c1 == ':')) { tokp += 1; tok = TOK_LBRACKET; }
-       else if ((c == ':') && (c1 == '>')) { tokp += 1; tok = TOK_RBRACKET; }
-       else if ((c == '<') && (c1 == '%')) { tokp += 1; tok = TOK_LBRACE; }
-       else if ((c == '%') && (c1 == '>')) { tokp += 1; tok = TOK_RBRACE; }
-       else if ((c == '%') && (c1 == ':')) { tokp += 1; tok = TOK_MACRO; }
-       else if ((c == '#') && (c1 == '#')) { tokp += 1; tok = TOK_CONCATENATE; }
+       else if ((c == '.') && (c1 == '.') && (c2 == '.')) { eat += 2; tok = TOK_DOTS; }
+       else if ((c == '<') && (c1 == '<') && (c2 == '=')) { eat += 2; tok = TOK_SLEQ; }
+       else if ((c == '>') && (c1 == '>') && (c2 == '=')) { eat += 2; tok = TOK_SREQ; }
+       else if ((c == '*') && (c1 == '=')) { eat += 1; tok = TOK_TIMESEQ; }
+       else if ((c == '/') && (c1 == '=')) { eat += 1; tok = TOK_DIVEQ; }
+       else if ((c == '%') && (c1 == '=')) { eat += 1; tok = TOK_MODEQ; }
+       else if ((c == '+') && (c1 == '=')) { eat += 1; tok = TOK_PLUSEQ; }
+       else if ((c == '-') && (c1 == '=')) { eat += 1; tok = TOK_MINUSEQ; }
+       else if ((c == '&') && (c1 == '=')) { eat += 1; tok = TOK_ANDEQ; }
+       else if ((c == '^') && (c1 == '=')) { eat += 1; tok = TOK_XOREQ; }
+       else if ((c == '|') && (c1 == '=')) { eat += 1; tok = TOK_OREQ; }
+       else if ((c == '=') && (c1 == '=')) { eat += 1; tok = TOK_EQEQ; }
+       else if ((c == '!') && (c1 == '=')) { eat += 1; tok = TOK_NOTEQ; }
+       else if ((c == '|') && (c1 == '|')) { eat += 1; tok = TOK_LOGOR; }
+       else if ((c == '&') && (c1 == '&')) { eat += 1; tok = TOK_LOGAND; }
+       else if ((c == '<') && (c1 == '=')) { eat += 1; tok = TOK_LESSEQ; }
+       else if ((c == '>') && (c1 == '=')) { eat += 1; tok = TOK_MOREEQ; }
+       else if ((c == '<') && (c1 == '<')) { eat += 1; tok = TOK_SL; }
+       else if ((c == '>') && (c1 == '>')) { eat += 1; tok = TOK_SR; }
+       else if ((c == '+') && (c1 == '+')) { eat += 1; tok = TOK_PLUSPLUS; }
+       else if ((c == '-') && (c1 == '-')) { eat += 1; tok = TOK_MINUSMINUS; }
+       else if ((c == '-') && (c1 == '>')) { eat += 1; tok = TOK_ARROW; }
+       else if ((c == '<') && (c1 == ':')) { eat += 1; tok = TOK_LBRACKET; }
+       else if ((c == ':') && (c1 == '>')) { eat += 1; tok = TOK_RBRACKET; }
+       else if ((c == '<') && (c1 == '%')) { eat += 1; tok = TOK_LBRACE; }
+       else if ((c == '%') && (c1 == '>')) { eat += 1; tok = TOK_RBRACE; }
+       else if ((c == '%') && (c1 == ':')) { eat += 1; tok = TOK_MACRO; }
+       else if ((c == '#') && (c1 == '#')) { eat += 1; tok = TOK_CONCATENATE; }
        else if (c == ';') { tok = TOK_SEMI; }
        else if (c == '{') { tok = TOK_LBRACE; }
        else if (c == '}') { tok = TOK_RBRACE; }
@@ -4233,38 +4320,12 @@ static void raw_next_token(struct compile_state *state,
        else if (c == '.') { tok = TOK_DOT; }
        else if (c == '~') { tok = TOK_TILDE; }
        else if (c == '#') { tok = TOK_MACRO; }
+       else if (c == '\n') { tok = TOK_EOL; }
 
-       file->pos = tokp + 1;
+       tokp = next_char(file, tokp, eat);
+       eat_chars(file, tokp);
        tk->tok = tok;
-       if (tok == TOK_IDENT) {
-               if (state->token_base == 0) {
-                       ident_to_keyword(state, tk);
-               } else {
-                       ident_to_macro(state, tk);
-               }
-       }
-}
-
-static void next_token(struct compile_state *state, struct token *tk)
-{
-       struct file_state *file;
-       file = state->file;
-       /* Don't return space tokens. */
-       do {
-               raw_next_token(state, file, tk);
-               if (tk->tok == TOK_MACRO) {
-                       /* Only match preprocessor directives at the start of a line */
-                       const char *ptr;
-                       for(ptr = file->line_start; spacep(*ptr); ptr++)
-                               ;
-                       if (ptr != file->pos - 1) {
-                               tk->tok = TOK_UNKNOWN;
-                       }
-               }
-               if (tk->tok == TOK_UNKNOWN) {
-                       error(state, 0, "unknown token");
-               }
-       } while(tk->tok == TOK_SPACE);
+       tk->pos = token;
 }
 
 static void check_tok(struct compile_state *state, struct token *tk, int tok)
@@ -4283,7 +4344,7 @@ static void check_tok(struct compile_state *state, struct token *tk, int tok)
 
 struct macro_arg_value {
        struct hash_entry *ident;
-       unsigned char *value;
+       char *value;
        size_t len;
 };
 static struct macro_arg_value *read_macro_args(
@@ -4299,7 +4360,7 @@ static struct macro_arg_value *read_macro_args(
                do {
                        raw_next_token(state, file, tk);
                } while(tk->tok == TOK_SPACE);
-               return 0;
+               return NULL;
        }
        argv = xcmalloc(sizeof(*argv) * macro->argc, "macro args");
        for(i = 0, arg = macro->args; arg; arg = arg->next, i++) {
@@ -4340,11 +4401,11 @@ static struct macro_arg_value *read_macro_args(
                if (tk->tok == TOK_EOF) {
                        error(state, 0, "End of file encountered while parsing macro arguments");
                }
-               
-               len = file->pos - start;
+
+               len = char_strlen(file, start, file->pos);
                argv[i].value = xrealloc(
                        argv[i].value, argv[i].len + len, "macro args");
-               memcpy(argv[i].value + argv[i].len, start, len);
+               char_strcpy((char *)argv[i].value + argv[i].len, file, start, file->pos);
                argv[i].len += len;
        }
        if (i != macro->argc -1) {
@@ -4369,22 +4430,44 @@ struct macro_buf {
        size_t len, pos;
 };
 
+static void grow_macro_buf(struct compile_state *state,
+       const char *id, struct macro_buf *buf,
+       size_t grow)
+{
+       if ((buf->pos + grow) >= buf->len) {
+               buf->str = xrealloc(buf->str, buf->len + grow, id);
+               buf->len += grow;
+       }
+}
+
 static void append_macro_text(struct compile_state *state,
-       struct macro *macro, struct macro_buf *buf, 
+       const char *id, struct macro_buf *buf,
        const char *fstart, size_t flen)
 {
+       grow_macro_buf(state, id, buf, flen);
+       memcpy(buf->str + buf->pos, fstart, flen);
 #if 0
        fprintf(state->errout, "append: `%*.*s' `%*.*s'\n",
                buf->pos, buf->pos, buf->str,
-               flen, flen, fstart);
+               flen, flen, buf->str + buf->pos);
+#endif
+       buf->pos += flen;
+}
+
+
+static void append_macro_chars(struct compile_state *state,
+       const char *id, struct macro_buf *buf,
+       struct file_state *file, const char *start, const char *end)
+{
+       size_t flen;
+       flen = char_strlen(file, start, end);
+       grow_macro_buf(state, id, buf, flen);
+       char_strcpy(buf->str + buf->pos, file, start, end);
+#if 0
+       fprintf(state->errout, "append: `%*.*s' `%*.*s'\n",
+               buf->pos, buf->pos, buf->str,
+               flen, flen, buf->str + buf->pos);
 #endif
-       if ((buf->pos + flen) < buf->len) {
-               memcpy(buf->str + buf->pos, fstart, flen);
-       } else {
-               buf->str = xrealloc(buf->str, buf->len + flen, macro->ident->name);
-               memcpy(buf->str + buf->pos, fstart, flen);
-               buf->len += flen;
-       }
        buf->pos += flen;
 }
 
@@ -4394,25 +4477,26 @@ static int compile_macro(struct compile_state *state,
 static void macro_expand_args(struct compile_state *state, 
        struct macro *macro, struct macro_arg_value *argv, struct token *tk)
 {
-       size_t i;
+       int i;
        
        for(i = 0; i < macro->argc; i++) {
                struct file_state fmacro, *file;
                struct macro_buf buf;
-               const char *fstart;
-               size_t flen;
 
+               fmacro.prev        = 0;
                fmacro.basename    = argv[i].ident->name;
                fmacro.dirname     = "";
+               fmacro.buf         = (char *)argv[i].value;
                fmacro.size        = argv[i].len;
-               fmacro.buf         = argv[i].value;
                fmacro.pos         = fmacro.buf;
-               fmacro.line_start  = fmacro.buf;
                fmacro.line        = 1;
+               fmacro.line_start  = fmacro.buf;
                fmacro.report_line = 1;
                fmacro.report_name = fmacro.basename;
                fmacro.report_dir  = fmacro.dirname;
-               fmacro.prev        = 0;
+               fmacro.macro       = 1;
+               fmacro.trigraphs   = 0;
+               fmacro.join_lines  = 0;
 
                buf.len = argv[i].len;
                buf.str = xmalloc(buf.len, argv[i].ident->name);
@@ -4420,10 +4504,11 @@ static void macro_expand_args(struct compile_state *state,
 
                file = &fmacro;
                for(;;) {
-                       fstart = file->pos;
                        raw_next_token(state, file, tk);
-                       flen = file->pos - fstart;
                        
+                       /* If we have recursed into another macro body
+                        * get out of it.
+                        */
                        if (tk->tok == TOK_EOF) {
                                struct file_state *old;
                                old = file;
@@ -4443,8 +4528,8 @@ static void macro_expand_args(struct compile_state *state,
                                }
                        }
 
-                       append_macro_text(state, macro, &buf,
-                               fstart, flen);
+                       append_macro_chars(state, macro->ident->name, &buf,
+                               file, tk->pos, file->pos);
                }
                        
                xfree(argv[i].value);
@@ -4462,19 +4547,25 @@ static void expand_macro(struct compile_state *state,
        const char space[] = " ";
        const char *fstart;
        size_t flen;
-       size_t i, j;
-       fmacro.basename = macro->ident->name;
-       fmacro.dirname  = "";
-       fmacro.size = macro->buf_len - macro->buf_off;;
-       fmacro.buf  = macro->buf + macro->buf_off;
-       fmacro.pos  = fmacro.buf;
-       fmacro.line_start = fmacro.buf;
-       fmacro.line = 1;
+       int i, j;
+
+       /* Place the macro body in a dummy file */
+       fmacro.prev        = 0;
+       fmacro.basename    = macro->ident->name;
+       fmacro.dirname     = "";
+       fmacro.buf         = macro->buf;
+       fmacro.size        = macro->buf_len;
+       fmacro.pos         = fmacro.buf;
+       fmacro.line        = 1;
+       fmacro.line_start  = fmacro.buf;
        fmacro.report_line = 1;
        fmacro.report_name = fmacro.basename;
        fmacro.report_dir  = fmacro.dirname;
-       fmacro.prev = 0;
+       fmacro.macro       = 1;
+       fmacro.trigraphs   = 0;
+       fmacro.join_lines  = 0;
        
+       /* Allocate a buffer to hold the macro expansion */
        buf->len = macro->buf_len + 3;
        buf->str = xmalloc(buf->len, macro->ident->name);
        buf->pos = 0;
@@ -4498,7 +4589,7 @@ static void expand_macro(struct compile_state *state,
                        flen   = argv[i].len;
                        break;
                case TOK_MACRO:
-                       if (!macro->buf_off) {
+                       if (macro->argc < 0) {
                                break;
                        }
                        do {
@@ -4515,7 +4606,7 @@ static void expand_macro(struct compile_state *state,
                                        tk->ident->name);
                        }
                        /* Stringize token */
-                       append_macro_text(state, macro, buf, "\"", 1);
+                       append_macro_text(state, macro->ident->name, buf, "\"", 1);
                        for(j = 0; j < argv[i].len; j++) {
                                char *str = argv[i].value + j;
                                size_t len = 1;
@@ -4527,9 +4618,9 @@ static void expand_macro(struct compile_state *state,
                                        str = "\\\"";
                                        len = 2;
                                }
-                               append_macro_text(state, macro, buf, str, len);
+                               append_macro_text(state, macro->ident->name, buf, str, len);
                        }
-                       append_macro_text(state, macro, buf, "\"", 1);
+                       append_macro_text(state, macro->ident->name, buf, "\"", 1);
                        fstart = 0;
                        flen   = 0;
                        break;
@@ -4563,7 +4654,7 @@ static void expand_macro(struct compile_state *state,
                        break;
                }
 
-               append_macro_text(state, macro, buf, fstart, flen);
+               append_macro_text(state, macro->ident->name, buf, fstart, flen);
                
                fstart = fmacro.pos;
                raw_next_token(state, &fmacro, tk);
@@ -4580,18 +4671,24 @@ static void tag_macro_name(struct compile_state *state,
        struct file_state fmacro;
        const char *fstart;
        size_t flen;
-       fmacro.basename = macro->ident->name;
-       fmacro.dirname  = "";
-       fmacro.size = buf->pos;
-       fmacro.buf  = buf->str;
-       fmacro.pos  = fmacro.buf;
-       fmacro.line_start = fmacro.buf;
-       fmacro.line = 1;
+
+       /* Put the old macro expansion buffer in a file */
+       fmacro.prev        = 0;
+       fmacro.basename    = macro->ident->name;
+       fmacro.dirname     = "";
+       fmacro.buf         = buf->str;
+       fmacro.size        = buf->pos;
+       fmacro.pos         = fmacro.buf;
+       fmacro.line        = 1;
+       fmacro.line_start  = fmacro.buf;
        fmacro.report_line = 1;
        fmacro.report_name = fmacro.basename;
        fmacro.report_dir  = fmacro.dirname;
-       fmacro.prev = 0;
+       fmacro.macro       = 1;
+       fmacro.trigraphs   = 0;
+       fmacro.join_lines  = 0;
        
+       /* Allocate a new macro expansion buffer */
        buf->len = macro->buf_len + 3;
        buf->str = xmalloc(buf->len, macro->ident->name);
        buf->pos = 0;
@@ -4602,20 +4699,21 @@ static void tag_macro_name(struct compile_state *state,
                flen = fmacro.pos - fstart;
                if ((tk->tok == TOK_IDENT) &&
                        (tk->ident == macro->ident) &&
-                       (tk->val.notmacro == 0)) {
-                       append_macro_text(state, macro, buf, fstart, flen);
+                       (tk->val.notmacro == 0)) 
+               {
+                       append_macro_text(state, macro->ident->name, buf, fstart, flen);
                        fstart = "$";
                        flen   = 1;
                }
 
-               append_macro_text(state, macro, buf, fstart, flen);
+               append_macro_text(state, macro->ident->name, buf, fstart, flen);
                
                fstart = fmacro.pos;
                raw_next_token(state, &fmacro, tk);
        }
        xfree(fmacro.buf);
 }
-       
+
 static int compile_macro(struct compile_state *state, 
        struct file_state **filep, struct token *tk)
 {
@@ -4638,13 +4736,13 @@ static int compile_macro(struct compile_state *state,
        /* If I am a function like macro and the identifier is not followed
         * by a left parenthesis, do nothing.
         */
-       if ((macro->buf_off != 0) && !lparen_peek(state, *filep)) {
+       if ((macro->argc >= 0) && (get_char(*filep, (*filep)->pos) != '(')) {
                return 0;
        }
 
        /* Read in the macro arguments */
        argv = 0;
-       if (macro->buf_off) {
+       if (macro->argc >= 0) {
                raw_next_token(state, *filep, tk);
                check_tok(state, tk, TOK_LPAREN);
 
@@ -4677,7 +4775,6 @@ static int compile_macro(struct compile_state *state,
         * be regonized as a canidate for macro expansion.
         */
        tag_macro_name(state, macro, &buf, tk);
-       append_macro_text(state, macro, &buf, "\n\0", 2);
 
 #if 0
        fprintf(state->errout, "%s: %d -> `%*.*s'\n",
@@ -4687,18 +4784,20 @@ static int compile_macro(struct compile_state *state,
        free_macro_args(macro, argv);
 
        file = xmalloc(sizeof(*file), "file_state");
-       file->basename = xstrdup(ident->name);
-       file->dirname = xstrdup("");
-       file->buf = buf.str;
-       file->size = buf.pos - 2;
-       file->pos = file->buf;
-       file->line_start = file->pos;
-       file->line = 1;
+       file->prev        = *filep;
+       file->basename    = xstrdup(ident->name);
+       file->dirname     = xstrdup("");
+       file->buf         = buf.str;
+       file->size        = buf.pos;
+       file->pos         = file->buf;
+       file->line        = 1;
+       file->line_start  = file->pos;
        file->report_line = 1;
        file->report_name = file->basename;
        file->report_dir  = file->dirname;
        file->macro       = 1;
-       file->prev = *filep;
+       file->trigraphs   = 0;
+       file->join_lines  = 0;
        *filep = file;
        return 1;
 }
@@ -4742,7 +4841,7 @@ static void in_if(struct compile_state *state, const char *name)
 static void enter_if(struct compile_state *state)
 {
        state->if_depth += 1;
-       if (state->if_depth > MAX_CPP_IF_DEPTH) {
+       if (state->if_depth > MAX_PP_IF_DEPTH) {
                error(state, 0, "#if depth too great");
        }
 }
@@ -4774,61 +4873,101 @@ static void exit_if(struct compile_state *state, const char *name)
        state->if_depth -= 1;
 }
 
-static void cpp_token(struct compile_state *state, struct token *tk)
+static void raw_token(struct compile_state *state, struct token *tk)
 {
        struct file_state *file;
        int rescan;
 
-       next_token(state, tk);
+       file = state->file;
+       raw_next_token(state, file, 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) &&
-                       file->prev) 
+                       (file != state->macro_file) && file->prev) 
                {
                        state->file = file->prev;
                        /* file->basename is used keep it */
                        xfree(file->dirname);
                        xfree(file->buf);
                        xfree(file);
-                       next_token(state, tk);
+                       file = 0;
+                       raw_next_token(state, state->file, tk);
                        rescan = 1;
                }
        } while(rescan);
 }
 
+static void pp_token(struct compile_state *state, struct token *tk)
+{
+       struct file_state *file;
+       int rescan;
+
+       raw_token(state, tk);
+       do {
+               rescan = 0;
+               file = state->file;
+               if (tk->tok == TOK_SPACE) {
+                       raw_token(state, tk);
+                       rescan = 1;
+               }
+               else if (tk->tok == TOK_IDENT) {
+                       if (state->token_base == 0) {
+                               ident_to_keyword(state, tk);
+                       } else {
+                               ident_to_macro(state, tk);
+                       }
+               }
+       } while(rescan);
+}
+
 static void preprocess(struct compile_state *state, struct token *tk);
 
 static void token(struct compile_state *state, struct token *tk)
 {
        int rescan;
-       cpp_token(state, tk);
+       pp_token(state, tk);
        do {
                rescan = 0;
                /* Process a macro directive */
                if (tk->tok == TOK_MACRO) {
-                       preprocess(state, tk);
-                       rescan = 1;
+                       /* Only match preprocessor directives at the start of a line */
+                       const char *ptr;
+                       ptr = state->file->line_start;
+                       while((ptr < tk->pos)
+                               && spacep(get_char(state->file, ptr)))
+                       {
+                               ptr = next_char(state->file, ptr, 1);
+                       }
+                       if (ptr == tk->pos) {
+                               preprocess(state, tk);
+                               rescan = 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);
+                               pp_token(state, tk);
                        }
                }
-               /* Eat tokens disabled by the preprocessor (Unless we are parsing a preprocessor directive */
+               /* Eat tokens disabled by the preprocessor 
+                * (Unless we are parsing a preprocessor directive 
+                */
                else if (if_eat(state) && (state->token_base == 0)) {
-                       cpp_token(state, tk);
+                       pp_token(state, tk);
                        rescan = 1;
                }
                /* Make certain EOL only shows up in preprocessor directives */
                else if ((tk->tok == TOK_EOL) && (state->token_base == 0)) {
-                       cpp_token(state, tk);
+                       pp_token(state, tk);
                        rescan = 1;
                }
+               /* Error on unknown tokens */
+               else if (tk->tok == TOK_UNKNOWN) {
+                       error(state, 0, "unknown token");
+               }
        } while(rescan);
 }
 
@@ -4867,19 +5006,35 @@ static struct token *do_eat_token(struct compile_state *state, int tok)
        return tk;
 }
 
-static int cpp_peek(struct compile_state *state)
+static int raw_peek(struct compile_state *state)
 {
        struct token *tk1;
        tk1 = get_token(state, 1);
        if (tk1->tok == -1) {
-               cpp_token(state, tk1);
+               raw_token(state, tk1);
        }
        return tk1->tok;
 }
 
-static struct token *cpp_eat(struct compile_state *state, int tok)
+static struct token *raw_eat(struct compile_state *state, int tok)
 {
-       cpp_peek(state);
+       raw_peek(state);
+       return do_eat_token(state, tok);
+}
+
+static int pp_peek(struct compile_state *state)
+{
+       struct token *tk1;
+       tk1 = get_token(state, 1);
+       if (tk1->tok == -1) {
+               pp_token(state, tk1);
+       }
+       return tk1->tok;
+}
+
+static struct token *pp_eat(struct compile_state *state, int tok)
+{
+       pp_peek(state);
        return do_eat_token(state, tok);
 }
 
@@ -4939,7 +5094,7 @@ static void compile_file(struct compile_state *state, const char *filename, int
        if (getcwd(cwd, sizeof(cwd)) == 0) {
                die("cwd buffer to small");
        }
-       if (subdir[0] == '/') {
+       if ((subdir[0] == '/') || ((subdir[1] == ':') && ((subdir[2] == '/') || (subdir[2] == '\\')))) {
                file->dirname = xmalloc(subdir_len + 1, "dirname");
                memcpy(file->dirname, subdir, subdir_len);
                file->dirname[subdir_len] = '\0';
@@ -4962,7 +5117,7 @@ static void compile_file(struct compile_state *state, const char *filename, int
                        }
                }
                if (!dir) {
-                       error(state, 0, "Cannot find `%s'\n", filename);
+                       error(state, 0, "Cannot open `%s'\n", filename);
                }
                dirlen = strlen(dir);
                file->dirname = xmalloc(dirlen + 1 + subdir_len + 1, "dirname");
@@ -4981,12 +5136,11 @@ static void compile_file(struct compile_state *state, const char *filename, int
        file->report_name = file->basename;
        file->report_dir  = file->dirname;
        file->macro       = 0;
+       file->trigraphs   = (state->compiler->flags & COMPILER_TRIGRAPHS)? 1: 0;
+       file->join_lines  = 1;
 
        file->prev = state->file;
        state->file = file;
-       
-       process_trigraphs(state);
-       splice_lines(state);
 }
 
 static struct triple *constant_expr(struct compile_state *state);
@@ -5009,32 +5163,28 @@ static void preprocess(struct compile_state *state, struct token *current_token)
         * a parser and a major restructuring.
         * Postpone that for later.
         */
-       struct file_state *file;
        int old_token_base;
-       int line;
        int tok;
        
-       file = state->file;
-       state->macro_line = line = file->line;
-       state->macro_file = file;
+       state->macro_file = state->file;
 
        old_token_base = state->token_base;
        state->token_base = current_token - state->token;
 
-       tok = cpp_peek(state);
-       switch(tok) {
+       tok = pp_peek(state);
+       switch(tok) {
        case TOK_LIT_INT:
        {
                struct token *tk;
                int override_line;
-               tk = cpp_eat(state, TOK_LIT_INT);
+               tk = pp_eat(state, TOK_LIT_INT);
                override_line = strtoul(tk->val.str, 0, 10);
-               /* I have a cpp line marker parse it */
-               if (cpp_peek(state) == TOK_LIT_STRING) {
+               /* I have a preprocessor  line marker parse it */
+               if (pp_peek(state) == TOK_LIT_STRING) {
                        const char *token, *base;
                        char *name, *dir;
                        int name_len, dir_len;
-                       tk = cpp_eat(state, TOK_LIT_STRING);
+                       tk = pp_eat(state, TOK_LIT_STRING);
                        name = xmalloc(tk->str_len, "report_name");
                        token = tk->val.str + 1;
                        base = strrchr(token, '/');
@@ -5052,24 +5202,24 @@ static void preprocess(struct compile_state *state, struct token *current_token)
                        dir = xmalloc(dir_len + 1, "report_dir");
                        memcpy(dir, token, dir_len);
                        dir[dir_len] = '\0';
-                       file->report_line = override_line - 1;
-                       file->report_name = name;
-                       file->report_dir = dir;
-                       file->macro      = 0;
+                       state->file->report_line = override_line - 1;
+                       state->file->report_name = name;
+                       state->file->report_dir = dir;
+                       state->file->macro      = 0;
                }
                break;
        }
        case TOK_MLINE:
        {
                struct token *tk;
-               cpp_eat(state, TOK_MLINE);
+               pp_eat(state, TOK_MLINE);
                tk = eat(state, TOK_LIT_INT);
-               file->report_line = strtoul(tk->val.str, 0, 10) -1;
-               if (cpp_peek(state) == TOK_LIT_STRING) {
+               state->file->report_line = strtoul(tk->val.str, 0, 10) -1;
+               if (pp_peek(state) == TOK_LIT_STRING) {
                        const char *token, *base;
                        char *name, *dir;
                        int name_len, dir_len;
-                       tk = cpp_eat(state, TOK_LIT_STRING);
+                       tk = pp_eat(state, TOK_LIT_STRING);
                        name = xmalloc(tk->str_len, "report_name");
                        token = tk->val.str + 1;
                        base = strrchr(token, '/');
@@ -5087,32 +5237,32 @@ static void preprocess(struct compile_state *state, struct token *current_token)
                        dir = xmalloc(dir_len + 1, "report_dir");
                        memcpy(dir, token, dir_len);
                        dir[dir_len] = '\0';
-                       file->report_name = name;
-                       file->report_dir = dir;
-                       file->macro      = 0;
+                       state->file->report_name = name;
+                       state->file->report_dir = dir;
+                       state->file->macro      = 0;
                }
                break;
        }
        case TOK_MUNDEF:
        {
                struct hash_entry *ident;
-               cpp_eat(state, TOK_MUNDEF);
+               pp_eat(state, TOK_MUNDEF);
                if (if_eat(state))  /* quit early when #if'd out */
                        break;
                
-               ident = cpp_eat(state, TOK_MIDENT)->ident;
+               ident = pp_eat(state, TOK_MIDENT)->ident;
 
                undef_macro(state, ident);
                break;
        }
        case TOK_MPRAGMA:
-               cpp_eat(state, TOK_MPRAGMA);
+               pp_eat(state, TOK_MPRAGMA);
                if (if_eat(state))  /* quit early when #if'd out */
                        break;
                warning(state, 0, "Ignoring pragma"); 
                break;
        case TOK_MELIF:
-               cpp_eat(state, TOK_MELIF);
+               pp_eat(state, TOK_MELIF);
                reenter_if(state, "#elif");
                if (if_eat(state))   /* quit early when #if'd out */
                        break;
@@ -5131,7 +5281,7 @@ static void preprocess(struct compile_state *state, struct token *current_token)
                }
                break;
        case TOK_MIF:
-               cpp_eat(state, TOK_MIF);
+               pp_eat(state, TOK_MIF);
                enter_if(state);
                if (if_eat(state))  /* quit early when #if'd out */
                        break;
@@ -5144,11 +5294,11 @@ static void preprocess(struct compile_state *state, struct token *current_token)
        {
                struct hash_entry *ident;
 
-               cpp_eat(state, TOK_MIFNDEF);
+               pp_eat(state, TOK_MIFNDEF);
                enter_if(state);
                if (if_eat(state))  /* quit early when #if'd out */
                        break;
-               ident = cpp_eat(state, TOK_MIDENT)->ident;
+               ident = pp_eat(state, TOK_MIDENT)->ident;
                set_if_value(state, ident->sym_define == 0);
                if (!if_value(state)) {
                        eat_tokens(state, TOK_MELSE);
@@ -5158,11 +5308,11 @@ static void preprocess(struct compile_state *state, struct token *current_token)
        case TOK_MIFDEF:
        {
                struct hash_entry *ident;
-               cpp_eat(state, TOK_MIFDEF);
+               pp_eat(state, TOK_MIFDEF);
                enter_if(state);
                if (if_eat(state))  /* quit early when #if'd out */
                        break;
-               ident = cpp_eat(state, TOK_MIDENT)->ident;
+               ident = pp_eat(state, TOK_MIDENT)->ident;
                set_if_value(state, ident->sym_define != 0);
                if (!if_value(state)) {
                        eat_tokens(state, TOK_MELSE);
@@ -5170,69 +5320,51 @@ static void preprocess(struct compile_state *state, struct token *current_token)
                break;
        }
        case TOK_MELSE:
-               cpp_eat(state, TOK_MELSE);
+               pp_eat(state, TOK_MELSE);
                enter_else(state, "#else");
                if (!if_eat(state) && if_value(state)) {
                        eat_tokens(state, TOK_MENDIF);
                }
                break;
        case TOK_MENDIF:
-               cpp_eat(state, TOK_MENDIF);
+               pp_eat(state, TOK_MENDIF);
                exit_if(state, "#endif");
                break;
        case TOK_MDEFINE:
        {
                struct hash_entry *ident;
                struct macro_arg *args, **larg;
-               const char *start, *mstart, *ptr;
+               const char *mstart, *mend;
+               int argc;
 
-               cpp_eat(state, TOK_MDEFINE);
+               pp_eat(state, TOK_MDEFINE);
                if (if_eat(state))  /* quit early when #if'd out */
                        break;
-
-               ident = cpp_eat(state, TOK_MIDENT)->ident;
+               ident = pp_eat(state, TOK_MIDENT)->ident;
+               argc = -1;
                args = 0;
                larg = &args;
 
-               /* Remember the start of the macro */
-               start = file->pos;
-
-               /* Find the end of the line. */
-               for(ptr = start; *ptr != '\n'; ptr++)  
-                       ;
-
-               /* remove the trailing whitespace */
-               ptr-=1;
-               while(spacep(*ptr)) {
-                       ptr--;
-               }
-
-               /* Remove leading whitespace */
-               while(spacep(*start) && (start < ptr)) {
-                       start++;
-               }
-               /* Remember where the macro starts */
-               mstart = start;
-
                /* Parse macro parameters */
-               if (lparen_peek(state, state->file)) {
-                       cpp_eat(state, TOK_LPAREN);
-                       
+               if (raw_peek(state) == TOK_LPAREN) {
+                       raw_eat(state, TOK_LPAREN);
+                       argc += 1;
+
                        for(;;) {
                                struct macro_arg *narg, *arg;
                                struct hash_entry *aident;
                                int tok;
 
-                               tok = cpp_peek(state);
+                               tok = pp_peek(state);
                                if (!args && (tok == TOK_RPAREN)) {
                                        break;
                                }
                                else if (tok == TOK_DOTS) {
-                                       cpp_eat(state, TOK_DOTS);
+                                       pp_eat(state, TOK_DOTS);
                                        aident = state->i___VA_ARGS__;
                                } 
                                else {
-                                       aident = cpp_eat(state, TOK_MIDENT)->ident;
+                                       aident = pp_eat(state, TOK_MIDENT)->ident;
                                }
                                
                                narg = xcmalloc(sizeof(*arg), "macro arg");
@@ -5248,57 +5380,82 @@ static void preprocess(struct compile_state *state, struct token *current_token)
                                /* Add the new argument to the end of the list */
                                *larg = narg;
                                larg = &narg->next;
+                               argc += 1;
 
                                if ((aident == state->i___VA_ARGS__) ||
-                                       (cpp_peek(state) != TOK_COMMA)) {
+                                       (pp_peek(state) != TOK_COMMA)) {
                                        break;
                                }
-                               cpp_eat(state, TOK_COMMA);
+                               pp_eat(state, TOK_COMMA);
                        }
-                       cpp_eat(state, TOK_RPAREN);
+                       pp_eat(state, TOK_RPAREN);
+               }
+               /* Remove leading whitespace */
+               while(raw_peek(state) == TOK_SPACE) {
+                       raw_eat(state, TOK_SPACE);
+               }
 
-                       /* Get the start of the macro body */
-                       mstart = file->pos;
+               /* Remember the start of the macro body */
+               tok = raw_peek(state);
+               mend = mstart = get_token(state, 1)->pos;
 
-                       /* Remove leading whitespace */
-                       while(spacep(*mstart) && (mstart < ptr)) {
-                               mstart++;
+               /* Find the end of the macro */
+               for(tok = raw_peek(state); tok != TOK_EOL; tok = raw_peek(state)) {
+                       raw_eat(state, tok);
+                       /* Remember the end of the last non space token */
+                       raw_peek(state);
+                       if (tok != TOK_SPACE) {
+                               mend = get_token(state, 1)->pos;
                        }
                }
-               define_macro(state, ident, start, ptr - start + 1, 
-                       mstart - start, args);
+               
+               /* Now that I have found the body defined the token */
+               do_define_macro(state, ident,
+                       char_strdup(state->file, mstart, mend, "macro buf"),
+                       argc, args);
                break;
        }
        case TOK_MERROR:
        {
-               const char *end;
+               const char *start, *end;
                int len;
                
-               cpp_eat(state, TOK_MERROR);
+               pp_eat(state, TOK_MERROR);
+               /* Find the start of the line */
+               raw_peek(state);
+               start = get_token(state, 1)->pos;
+
                /* Find the end of the line */
-               for(end = file->pos; *end != '\n'; end++)
-                       ;
-               len = (end - file->pos);
+               while((tok = raw_peek(state)) != TOK_EOL) {
+                       raw_eat(state, tok);
+               }
+               end = get_token(state, 1)->pos;
+               len = end - start;
                if (!if_eat(state)) {
-                       error(state, 0, "%*.*s", len, len, file->pos);
+                       error(state, 0, "%*.*s", len, len, start);
                }
-               file->pos = end;
                break;
        }
        case TOK_MWARNING:
        {
-               const char *end;
+               const char *start, *end;
                int len;
                
-               cpp_eat(state, TOK_MWARNING);
+               pp_eat(state, TOK_MWARNING);
+
+               /* Find the start of the line */
+               raw_peek(state);
+               start = get_token(state, 1)->pos;
+                
                /* Find the end of the line */
-               for(end = file->pos; *end != '\n'; end++)
-                       ;
-               len = (end - file->pos);
+               while((tok = raw_peek(state)) != TOK_EOL) {
+                       raw_eat(state, tok);
+               }
+               end = get_token(state, 1)->pos;
+               len = end - start;
                if (!if_eat(state)) {
-                       warning(state, 0, "%*.*s", len, len, file->pos);
+                       warning(state, 0, "%*.*s", len, len, start);
                }
-               file->pos = end;
                break;
        }
        case TOK_MINCLUDE:
@@ -5308,7 +5465,14 @@ static void preprocess(struct compile_state *state, struct token *current_token)
                local = 0;
                name = 0;
 
-               cpp_eat(state, TOK_MINCLUDE);
+               pp_eat(state, TOK_MINCLUDE);
+               if (if_eat(state)) {
+                       /* Find the end of the line */
+                       while((tok = raw_peek(state)) != TOK_EOL) {
+                               raw_eat(state, tok);
+                       }
+                       break;
+               }
                tok = peek(state);
                if (tok == TOK_LIT_STRING) {
                        struct token *tk;
@@ -5327,29 +5491,36 @@ static void preprocess(struct compile_state *state, struct token *current_token)
                        local = 1;
                }
                else if (tok == TOK_LESS) {
-                       const char *start, *end;
+                       struct macro_buf buf;
                        eat(state, TOK_LESS);
-                       start = file->pos;
-                       for(end = start; *end != '\n'; end++) {
-                               if (*end == '>') {
-                                       break;
-                               }
-                       }
-                       if (*end == '\n') {
+
+                       buf.len = 40;
+                       buf.str = xmalloc(buf.len, "include");
+                       buf.pos = 0;
+
+                       tok = peek(state);
+                       while((tok != TOK_MORE) &&
+                               (tok != TOK_EOL) && (tok != TOK_EOF))
+                       {
+                               struct token *tk;
+                               tk = eat(state, tok);
+                               append_macro_chars(state, "include", &buf,
+                                       state->file, tk->pos, state->file->pos);
+                               tok = peek(state);
+                       }
+                       append_macro_text(state, "include", &buf, "\0", 1);
+                       if (peek(state) != TOK_MORE) {
                                error(state, 0, "Unterminated include directive");
                        }
-                       name = xmalloc(end - start + 1, "include");
-                       memcpy(name, start, end - start);
-                       name[end - start] = '\0';
-                       file->pos = end;
-                       local = 0;
                        eat(state, TOK_MORE);
+                       local = 0;
+                       name = buf.str;
                }
                else {
                        error(state, 0, "Invalid include directive");
                }
                /* Error if there are any tokens after the include */
-               if (cpp_peek(state) != TOK_EOL) {
+               if (pp_peek(state) != TOK_EOL) {
                        error(state, 0, "garbage after include directive");
                }
                if (!if_eat(state)) {
@@ -5376,10 +5547,11 @@ static void preprocess(struct compile_state *state, struct token *current_token)
        }
        /* Consume the rest of the macro line */
        do {
-               tok = cpp_peek(state);
-               cpp_eat(state, tok);
+               tok = pp_peek(state);
+               pp_eat(state, tok);
        } while((tok != TOK_EOF) && (tok != TOK_EOL));
        state->token_base = old_token_base;
+       state->macro_file = NULL;
        return;
 }
 
@@ -5487,7 +5659,7 @@ static struct type *invalid_type(struct compile_state *state, struct type *type)
 static inline ulong_t mask_uint(ulong_t x)
 {
        if (SIZEOF_INT < SIZEOF_LONG) {
-               ulong_t mask = (((ulong_t)1) << ((ulong_t)(SIZEOF_INT))) -1;
+               ulong_t mask = (1ULL << ((ulong_t)(SIZEOF_INT))) -1;
                x &= mask;
        }
        return x;
@@ -5498,7 +5670,9 @@ static inline ulong_t mask_uint(ulong_t x)
 static struct type void_type    = { .type  = TYPE_VOID };
 static struct type char_type    = { .type  = TYPE_CHAR };
 static struct type uchar_type   = { .type  = TYPE_UCHAR };
+#if DEBUG_ROMCC_WARNING
 static struct type short_type   = { .type  = TYPE_SHORT };
+#endif
 static struct type ushort_type  = { .type  = TYPE_USHORT };
 static struct type int_type     = { .type  = TYPE_INT };
 static struct type uint_type    = { .type  = TYPE_UINT };
@@ -5511,11 +5685,13 @@ static struct type void_ptr_type  = {
        .left = &void_type,
 };
 
+#if DEBUG_ROMCC_WARNING
 static struct type void_func_type = { 
        .type  = TYPE_FUNCTION,
        .left  = &void_type,
        .right = &void_type,
 };
+#endif
 
 static size_t bits_to_bytes(size_t size)
 {
@@ -7256,7 +7432,9 @@ static struct triple *read_expr(struct compile_state *state, struct triple *def)
        if  (!def) {
                return 0;
        }
+#if DEBUG_ROMCC_WARNINGS
 #warning "CHECK_ME is this the only place I need to do lvalue conversions?"
+#endif
        /* Transform lvalues into something we can read */
        def = lvalue_conversion(state, def);
        if (!is_lvalue(state, def)) {
@@ -7494,7 +7672,7 @@ static struct triple *mkland_expr(
        val = read_expr(state, var);
 
        /* Generate the prog for a logical and */
-       def = mkprog(state, var, lstore, jmp, mid, rstore, end, val, 0);
+       def = mkprog(state, var, lstore, jmp, mid, rstore, end, val, 0UL);
        
        return def;
 }
@@ -7523,7 +7701,7 @@ static struct triple *mklor_expr(
        val = read_expr(state, var);
 
        /* Generate the prog for a logical or */
-       def = mkprog(state, var, left, jmp, mid, right, end, val, 0);
+       def = mkprog(state, var, left, jmp, mid, right, end, val, 0UL);
 
        return def;
 }
@@ -7589,7 +7767,7 @@ static struct triple *mkcond_expr(
        val = read_expr(state, var);
 
        /* Generate the prog for a conditional expression */
-       def = mkprog(state, var, jmp1, top, left, jmp2, mid, right, end, val, 0);
+       def = mkprog(state, var, jmp1, top, left, jmp2, mid, right, end, val, 0UL);
 
        return def;
 }
@@ -7597,7 +7775,9 @@ static struct triple *mkcond_expr(
 
 static int expr_depth(struct compile_state *state, struct triple *ins)
 {
+#if DEBUG_ROMCC_WARNINGS
 #warning "FIXME move optimal ordering of subexpressions into the optimizer"
+#endif
        int count;
        count = 0;
        if (!ins || (ins->id & TRIPLE_FLAG_FLATTENED)) {
@@ -8211,6 +8391,7 @@ static int is_one(struct triple *ins)
        return is_simple_const(ins) && (ins->u.cval == 1);
 }
 
+#if DEBUG_ROMCC_WARNING
 static long_t bit_count(ulong_t value)
 {
        int count;
@@ -8227,6 +8408,8 @@ static long_t bit_count(ulong_t value)
        return count;
        
 }
+#endif
+
 static long_t bsr(ulong_t value)
 {
        int i;
@@ -8255,14 +8438,14 @@ static long_t bsf(ulong_t value)
        return -1;
 }
 
-static long_t log2(ulong_t value)
+static long_t ilog2(ulong_t value)
 {
        return bsr(value);
 }
 
 static long_t tlog2(struct triple *ins)
 {
-       return log2(ins->u.cval);
+       return ilog2(ins->u.cval);
 }
 
 static int is_pow2(struct triple *ins)
@@ -8273,7 +8456,7 @@ static int is_pow2(struct triple *ins)
                return 0;
        }
        value = ins->u.cval;
-       log = log2(value);
+       log = ilog2(value);
        if (log == -1) {
                return 0;
        }
@@ -8444,6 +8627,7 @@ static void unuse_lhs(struct compile_state *state, struct triple *ins)
        }
 }
 
+#if DEBUG_ROMCC_WARNING
 static void unuse_misc(struct compile_state *state, struct triple *ins)
 {
        struct triple **expr;
@@ -8474,6 +8658,7 @@ static void check_lhs(struct compile_state *state, struct triple *ins)
        }
        
 }
+#endif
 
 static void check_misc(struct compile_state *state, struct triple *ins)
 {
@@ -8511,6 +8696,7 @@ static void wipe_ins(struct compile_state *state, struct triple *ins)
        ins->targ = 0;
 }
 
+#if DEBUG_ROMCC_WARNING
 static void wipe_branch(struct compile_state *state, struct triple *ins)
 {
        /* Becareful which instructions you replace the wiped
@@ -8526,6 +8712,7 @@ static void wipe_branch(struct compile_state *state, struct triple *ins)
        ins->misc = 0;
        ins->targ = 0;
 }
+#endif
 
 static void mkcopy(struct compile_state *state, 
        struct triple *ins, struct triple *rhs)
@@ -10498,7 +10685,9 @@ static struct type *declarator(
        struct hash_entry **ident, int need_ident);
 static void decl(struct compile_state *state, struct triple *first);
 static struct type *specifier_qualifier_list(struct compile_state *state);
+#if DEBUG_ROMCC_WARNING
 static int isdecl_specifier(int tok);
+#endif
 static struct type *decl_specifiers(struct compile_state *state);
 static int istype(int tok);
 static struct triple *expr(struct compile_state *state);
@@ -10564,7 +10753,7 @@ static struct triple *character_constant(struct compile_state *state)
        int c;
        int str_len;
        tk = eat(state, TOK_LIT_CHAR);
-       str = tk->val.str + 1;
+       str = (signed char *)tk->val.str + 1;
        str_len = tk->str_len - 2;
        if (str_len <= 0) {
                error(state, 0, "empty character constant");
@@ -10593,11 +10782,14 @@ static struct triple *string_constant(struct compile_state *state)
        /* The while loop handles string concatenation */
        do {
                tk = eat(state, TOK_LIT_STRING);
-               str = tk->val.str + 1;
+               str = (signed char *)tk->val.str + 1;
                str_len = tk->str_len - 2;
                if (str_len < 0) {
                        error(state, 0, "negative string constant length");
                }
+               /* ignore empty string tokens */
+               if ('"' == *str && 0 == str[1])
+                       continue;
                end = str + str_len;
                ptr = buf;
                buf = xmalloc(type->elements + str_len + 1, "string_constant");
@@ -10897,11 +11089,11 @@ static struct triple *unary_expr(struct compile_state *state)
                int parens;
                eat(state, TOK_MDEFINED);
                parens = 0;
-               if (cpp_peek(state) == TOK_LPAREN) {
-                       cpp_eat(state, TOK_LPAREN);
+               if (pp_peek(state) == TOK_LPAREN) {
+                       pp_eat(state, TOK_LPAREN);
                        parens = 1;
                }
-               ident = cpp_eat(state, TOK_MIDENT)->ident;
+               ident = pp_eat(state, TOK_MIDENT)->ident;
                if (parens) {
                        eat(state, TOK_RPAREN);
                }
@@ -10944,7 +11136,8 @@ static struct triple *mult_expr(struct compile_state *state)
                struct type *result_type;
                int tok, op, sign;
                done = 0;
-               switch(tok = (peek(state))) {
+               tok = peek(state);
+               switch(tok) {
                case TOK_STAR:
                case TOK_DIV:
                case TOK_MOD:
@@ -11035,7 +11228,9 @@ static struct triple *shift_expr(struct compile_state *state)
 
 static struct triple *relational_expr(struct compile_state *state)
 {
+#if DEBUG_ROMCC_WARNINGS
 #warning "Extend relational exprs to work on more than arithmetic types"
+#endif
        struct triple *def;
        int done;
        def = shift_expr(state);
@@ -11078,7 +11273,9 @@ static struct triple *relational_expr(struct compile_state *state)
 
 static struct triple *equality_expr(struct compile_state *state)
 {
+#if DEBUG_ROMCC_WARNINGS
 #warning "Extend equality exprs to work on more than arithmetic types"
+#endif
        struct triple *def;
        int done;
        def = relational_expr(state);
@@ -11360,7 +11557,7 @@ static struct triple *constant_expr(struct compile_state *state)
 
 static struct triple *assignment_expr(struct compile_state *state)
 {
-       struct triple *def, *left, *right;
+       struct triple *def, *left, *left2, *right;
        int tok, op, sign;
        /* The C grammer in K&R shows assignment expressions
         * only taking unary expressions as input on their
@@ -11381,6 +11578,9 @@ static struct triple *assignment_expr(struct compile_state *state)
         */
        def = conditional_expr(state);
        left = def;
+       left2 = left;
+       if (!(left2->id & TRIPLE_FLAG_FLATTENED))
+               left2 = copy_triple(state, left2);
        switch((tok = peek(state))) {
        case TOK_EQ:
                lvalue(state, left);
@@ -11406,19 +11606,19 @@ static struct triple *assignment_expr(struct compile_state *state)
                }
                def = write_expr(state, left,
                        triple(state, op, left->type, 
-                               read_expr(state, left), right));
+                               read_expr(state, left2), right));
                break;
        case TOK_PLUSEQ:
                lvalue(state, left);
                eat(state, TOK_PLUSEQ);
                def = write_expr(state, left,
-                       mk_add_expr(state, left, assignment_expr(state)));
+                       mk_add_expr(state, left2, assignment_expr(state)));
                break;
        case TOK_MINUSEQ:
                lvalue(state, left);
                eat(state, TOK_MINUSEQ);
                def = write_expr(state, left,
-                       mk_sub_expr(state, left, assignment_expr(state)));
+                       mk_sub_expr(state, left2, assignment_expr(state)));
                break;
        case TOK_SLEQ:
        case TOK_SREQ:
@@ -11442,7 +11642,7 @@ static struct triple *assignment_expr(struct compile_state *state)
                }
                def = write_expr(state, left,
                        triple(state, op, left->type, 
-                               read_expr(state, left), right));
+                               read_expr(state, left2), right));
                break;
        }
        return def;
@@ -11454,7 +11654,7 @@ static struct triple *expr(struct compile_state *state)
        def = assignment_expr(state);
        while(peek(state) == TOK_COMMA) {
                eat(state, TOK_COMMA);
-               def = mkprog(state, def, assignment_expr(state), 0);
+               def = mkprog(state, def, assignment_expr(state), 0UL);
        }
        return def;
 }
@@ -11639,7 +11839,9 @@ static void return_statement(struct compile_state *state, struct triple *first)
        int last;
        eat(state, TOK_RETURN);
 
+#if DEBUG_ROMCC_WARNINGS
 #warning "FIXME implement a more general excess branch elimination"
+#endif
        val = 0;
        /* If we have a return value do some more work */
        if (peek(state) != TOK_SEMI) {
@@ -12564,6 +12766,9 @@ static unsigned int attrib(struct compile_state *state, unsigned int attributes)
                        }
                        attributes |= ATTRIB_ALWAYS_INLINE;
                }
+               else if (ident == state->i_noreturn) {
+                       // attribute((noreturn)) does nothing (yet?)
+               }
                else {
                        error(state, 0, "Unknown attribute:%s", ident->name);
                }
@@ -12814,6 +13019,7 @@ static struct type *specifier_qualifier_list(struct compile_state *state)
        return type;
 }
 
+#if DEBUG_ROMCC_WARNING
 static int isdecl_specifier(int tok)
 {
        switch(tok) {
@@ -12851,6 +13057,7 @@ static int isdecl_specifier(int tok)
                return 0;
        }
 }
+#endif
 
 static struct type *decl_specifiers(struct compile_state *state)
 {
@@ -12933,7 +13140,9 @@ static struct triple *initializer(
        struct compile_state *state, struct type *type)
 {
        struct triple *result;
+#if DEBUG_ROMCC_WARNINGS
 #warning "FIXME more consistent initializer handling (where should eval_const_expr go?"
+#endif
        if (peek(state) != TOK_LBRACE) {
                result = assignment_expr(state);
                if (((type->type & TYPE_MASK) == TYPE_ARRAY) &&
@@ -13381,8 +13590,10 @@ static struct reg_block *compute_variable_lifetimes(
        struct compile_state *state, struct basic_blocks *bb);
 static void free_variable_lifetimes(struct compile_state *state, 
        struct basic_blocks *bb, struct reg_block *blocks);
+#if DEBUG_EXPLICIT_CLOSURES
 static void print_live_variables(struct compile_state *state, 
        struct basic_blocks *bb, struct reg_block *rb, FILE *fp);
+#endif
 
 
 static struct triple *call(struct compile_state *state,
@@ -14959,7 +15170,9 @@ static void free_basic_block(struct compile_state *state, struct block *block)
                }
        }
        memset(block, -1, sizeof(*block));
+#ifndef WIN32
        xfree(block);
+#endif
 }
 
 static void free_basic_blocks(struct compile_state *state, 
@@ -15162,8 +15375,6 @@ static void romcc_print_blocks(struct compile_state *state, FILE *fp)
 }
 static void print_blocks(struct compile_state *state, const char *func, FILE *fp)
 {
-       static void print_dominators(struct compile_state *state, FILE *fp, struct basic_blocks *bb);
-       static void print_dominance_frontiers(struct compile_state *state, FILE *fp, struct basic_blocks *bb);
        if (state->compiler->debug & DEBUG_BASIC_BLOCKS) {
                fprintf(fp, "After %s\n", func);
                romcc_print_blocks(state, fp);
@@ -17175,19 +17386,24 @@ static int in_triple(struct reg_block *rb, struct triple *in)
 {
        return do_triple_set(&rb->in, in, 0);
 }
+
+#if DEBUG_ROMCC_WARNING
 static void unin_triple(struct reg_block *rb, struct triple *unin)
 {
        do_triple_unset(&rb->in, unin);
 }
+#endif
 
 static int out_triple(struct reg_block *rb, struct triple *out)
 {
        return do_triple_set(&rb->out, out, 0);
 }
+#if DEBUG_ROMCC_WARNING
 static void unout_triple(struct reg_block *rb, struct triple *unout)
 {
        do_triple_unset(&rb->out, unout);
 }
+#endif
 
 static int initialize_regblock(struct reg_block *blocks,
        struct block *block, int vertex)
@@ -17353,7 +17569,9 @@ static int use_in(struct compile_state *state, struct reg_block *rb)
        /* Find the variables we use but don't define and add
         * it to the current blocks input set.
         */
+#if DEBUG_ROMCC_WARNINGS
 #warning "FIXME is this O(N^2) algorithm bad?"
+#endif
        struct block *block;
        struct triple *ptr;
        int done;
@@ -17524,6 +17742,7 @@ struct print_live_variable_info {
        struct reg_block *rb;
        FILE *fp;
 };
+#if DEBUG_EXPLICIT_CLOSURES
 static void print_live_variables_block(
        struct compile_state *state, struct block *block, void *arg)
 
@@ -17605,7 +17824,7 @@ static void print_live_variables(struct compile_state *state,
        walk_blocks(state, bb, print_live_variables_block, &info);
 
 }
-
+#endif
 
 static int count_triples(struct compile_state *state)
 {
@@ -17776,7 +17995,10 @@ static void eliminate_inefectual_code(struct compile_state *state)
                        struct triple *last;
                        last = user->member->last;
                        while((last->op == OP_NOOP) && (last != user->member->first)) {
-                               internal_warning(state, last, "awakening noop?");
+#if DEBUG_ROMCC_WARNINGS
+#warning "Should we bring the awakening noops back?"
+#endif
+                               // internal_warning(state, last, "awakening noop?");
                                last = last->prev;
                        }
                        awaken(state, dtriple, &last, &work_list_tail);
@@ -18399,6 +18621,7 @@ static void transfer_live_edges(struct reg_state *rstate,
  *
  */
 
+#if DEBUG_ROMCC_WARNING
 static void different_colored(
        struct compile_state *state, struct reg_state *rstate, 
        struct triple *parent, struct triple *ins)
@@ -18418,7 +18641,7 @@ static void different_colored(
                }
        }
 }
-
+#endif
 
 static struct live_range *coalesce_ranges(
        struct compile_state *state, struct reg_state *rstate,
@@ -18506,7 +18729,9 @@ static struct live_range *coalesce_ranges(
 #endif
        
        /* Append lr2 onto lr1 */
+#if DEBUG_ROMCC_WARNINGS
 #warning "FIXME should this be a merge instead of a splice?"
+#endif
        /* This FIXME item applies to the correctness of live_range_end 
         * and to the necessity of making multiple passes of coalesce_live_ranges.
         * A failure to find some coalesce opportunities in coaleace_live_ranges
@@ -18743,6 +18968,7 @@ static void graph_ins(
        return;
 }
 
+#if DEBUG_CONSISTENCY > 1
 static struct live_range *get_verify_live_range(
        struct compile_state *state, struct reg_state *rstate, struct triple *ins)
 {
@@ -18821,7 +19047,7 @@ static void verify_graph_ins(
        }
        return;
 }
-
+#endif
 
 static void print_interference_ins(
        struct compile_state *state, 
@@ -19058,7 +19284,9 @@ static void replace_block_use(struct compile_state *state,
        struct reg_block *blocks, struct triple *orig, struct triple *new)
 {
        int i;
+#if DEBUG_ROMCC_WARNINGS
 #warning "WISHLIST visit just those blocks that need it *"
+#endif
        for(i = 1; i <= state->bb.last_vertex; i++) {
                struct reg_block *rb;
                rb = &blocks[i];
@@ -19111,7 +19339,9 @@ static struct triple *resolve_tangle(
        struct triple_set *set, *next;
        struct triple *copy;
 
+#if DEBUG_ROMCC_WARNINGS
 #warning "WISHLIST recalculate all affected instructions colors"
+#endif
        info = find_lhs_color(state, tangle, 0);
        for(set = tangle->use; set; set = next) {
                struct triple *user;
@@ -19250,7 +19480,9 @@ struct triple *find_constrained_def(
                 * Then a triple is not constrained.
                 * FIXME handle this case!
                 */
+#if DEBUG_ROMCC_WARNINGS
 #warning "FIXME ignore cases that cannot be fixed (a definition followed by a use)"
+#endif
                
 
                /* Of the constrained live ranges deal with the
@@ -19286,7 +19518,9 @@ static int split_constrained_ranges(
        for(edge = range->edges; edge; edge = edge->next) {
                constrained = find_constrained_def(state, edge->node, constrained);
        }
+#if DEBUG_ROMCC_WARNINGS
 #warning "FIXME should I call find_constrained_def here only if no previous constrained def was found?"
+#endif
        if (!constrained) {
                constrained = find_constrained_def(state, range, constrained);
        }
@@ -19330,7 +19564,9 @@ static int split_ranges(
         * it would be useful to have.
         *
         */
+#if DEBUG_ROMCC_WARNINGS
 #warning "WISHLIST implement live range splitting..."
+#endif
        
        if (!split && (state->compiler->debug & DEBUG_RANGE_CONFLICTS2)) {
                FILE *fp = state->errout;
@@ -20128,8 +20364,8 @@ static void scc_add_sedge(struct compile_state *state, struct scc_state *scc,
        struct ssa_edge *sedge)
 {
        if (state->compiler->debug & DEBUG_SCC_TRANSFORM2) {
-               fprintf(state->errout, "adding sedge: %5d (%4d -> %5d)\n",
-                       sedge - scc->ssa_edges,
+               fprintf(state->errout, "adding sedge: %5ld (%4d -> %5d)\n",
+                       (long)(sedge - scc->ssa_edges),
                        sedge->src->def->id,
                        sedge->dst->def->id);
        }
@@ -20138,8 +20374,8 @@ static void scc_add_sedge(struct compile_state *state, struct scc_state *scc,
                (sedge->work_prev != sedge)) {
 
                if (state->compiler->debug & DEBUG_SCC_TRANSFORM2) {
-                       fprintf(state->errout, "dupped sedge: %5d\n",
-                               sedge - scc->ssa_edges);
+                       fprintf(state->errout, "dupped sedge: %5ld\n",
+                               (long)(sedge - scc->ssa_edges));
                }
                return;
        }
@@ -20495,7 +20731,9 @@ static int compute_lnode_val(struct compile_state *state, struct scc_state *scc,
                scratch->next = lnode->def->next;
        }
        /* Recompute the value */
+#if DEBUG_ROMCC_WARNINGS
 #warning "FIXME see if simplify does anything bad"
+#endif
        /* So far it looks like only the strength reduction
         * optimization are things I need to worry about.
         */
@@ -20559,7 +20797,9 @@ static int compute_lnode_val(struct compile_state *state, struct scc_state *scc,
                ((      !triple_is_def(state, lnode->def)  &&
                        !triple_is_cbranch(state, lnode->def)) ||
                        (lnode->def->op == OP_PIECE))) {
+#if DEBUG_ROMCC_WARNINGS
 #warning "FIXME constant propogate through expressions with multiple left hand sides"
+#endif
                if (changed) {
                        internal_warning(state, lnode->def, "non def changes value?");
                }
@@ -20880,8 +21120,8 @@ static void scc_transform(struct compile_state *state)
                        fblock = lnode->fblock;
 
                        if (state->compiler->debug & DEBUG_SCC_TRANSFORM) {
-                               fprintf(state->errout, "sedge: %5d (%5d -> %5d)\n",
-                                       sedge - scc.ssa_edges,
+                               fprintf(state->errout, "sedge: %5ld (%5d -> %5d)\n",
+                                       (unsigned long)sedge - (unsigned long)scc.ssa_edges,
                                        sedge->src->def->id,
                                        sedge->dst->def->id);
                        }
@@ -21387,8 +21627,10 @@ static void optimize(struct compile_state *state)
        /* Propogate constants throughout the code */
        scc_transform(state);
        verify_consistency(state);
+#if DEBUG_ROMCC_WARNINGS
 #warning "WISHLIST implement single use constants (least possible register pressure)"
 #warning "WISHLIST implement induction variable elimination"
+#endif
        /* Select architecture instructions and an initial partial
         * coloring based on architecture constraints.
         */
@@ -21573,7 +21815,11 @@ static void print_op_asm(struct compile_state *state,
 #define REG_XMM7   44
 #define REGC_XMM_FIRST REG_XMM0
 #define REGC_XMM_LAST  REG_XMM7
+
+#if DEBUG_ROMCC_WARNINGS
 #warning "WISHLIST figure out how to use pinsrw and pextrw to better use extended regs"
+#endif
+
 #define LAST_REG   REG_XMM7
 
 #define REGC_GPR32_8_FIRST REG_EAX
@@ -22151,7 +22397,10 @@ static int arch_select_free_register(
 
 static unsigned arch_type_to_regcm(struct compile_state *state, struct type *type) 
 {
+
+#if DEBUG_ROMCC_WARNINGS
 #warning "FIXME force types smaller (if legal) before I get here"
+#endif
        unsigned mask;
        mask = 0;
        switch(type->type & TYPE_MASK) {
@@ -22211,7 +22460,10 @@ static unsigned arch_type_to_regcm(struct compile_state *state, struct type *typ
 
 static int is_imm32(struct triple *imm)
 {
-       return ((imm->op == OP_INTCONST) && (imm->u.cval <= 0xffffffffUL)) ||
+       // second condition commented out to prevent compiler warning:
+       // imm->u.cval is always 32bit unsigned, so the comparison is
+       // always true.
+       return ((imm->op == OP_INTCONST) /* && (imm->u.cval <= 0xffffffffUL) */ ) ||
                (imm->op == OP_ADDRCONST);
        
 }
@@ -23618,12 +23870,12 @@ static long get_const_pool_ref(
        long ref;
        ref = next_label(state);
        fprintf(fp, ".section \"" DATA_SECTION "\"\n");
-       fprintf(fp, ".balign %d\n", align_of_in_bytes(state, ins->type));
+       fprintf(fp, ".balign %ld\n", (long int)align_of_in_bytes(state, ins->type));
        fprintf(fp, "L%s%lu:\n", state->compiler->label_prefix, ref);
        print_const(state, ins, fp);
        fill_bytes = bits_to_bytes(size - size_of(state, ins->type));
        if (fill_bytes) {
-               fprintf(fp, ".fill %d, 1, 0\n", fill_bytes);
+               fprintf(fp, ".fill %ld, 1, 0\n", (long int)fill_bytes);
        }
        fprintf(fp, ".section \"" TEXT_SECTION "\"\n");
        return ref;
@@ -24326,7 +24578,9 @@ static void print_op_branch(struct compile_state *state,
                        (RHS(branch, 0)->op != OP_TEST)) {
                        internal_error(state, branch, "bad branch test");
                }
+#if DEBUG_ROMCC_WARNINGS
 #warning "FIXME I have observed instructions between the test and branch instructions"
+#endif
                ptr = RHS(branch, 0);
                for(ptr = RHS(branch, 0)->next; ptr != branch; ptr = ptr->next) {
                        if (ptr->op != OP_COPY) {
@@ -24430,7 +24684,7 @@ static void print_sdecl(struct compile_state *state,
        struct triple *ins, FILE *fp)
 {
        fprintf(fp, ".section \"" DATA_SECTION "\"\n");
-       fprintf(fp, ".balign %d\n", align_of_in_bytes(state, ins->type));
+       fprintf(fp, ".balign %ld\n", (long int)align_of_in_bytes(state, ins->type));
        fprintf(fp, "L%s%lu:\n", 
                state->compiler->label_prefix, (unsigned long)(ins->u.cval));
        print_const(state, MISC(ins, 0), fp);
@@ -24592,8 +24846,8 @@ static void print_instructions(struct compile_state *state)
                        last_occurance != ins->occurance) {
                        if (!ins->occurance->parent) {
                                fprintf(fp, "\t/* %s,%s:%d.%d */\n",
-                                       ins->occurance->function,
-                                       ins->occurance->filename,
+                                       ins->occurance->function?ins->occurance->function:"(null)",
+                                       ins->occurance->filename?ins->occurance->filename:"(null)",
                                        ins->occurance->line,
                                        ins->occurance->col);
                        }
@@ -24660,7 +24914,6 @@ static void print_preprocessed_tokens(struct compile_state *state)
                        tk->ident ? tk->ident->name :
                        tk->str_len ? tk->val.str :
                        tokens[tk->tok];
-               
 
                file = state->file;
                while(file->macro && file->prev) {
@@ -24699,12 +24952,13 @@ static void print_preprocessed_tokens(struct compile_state *state)
        }
 }
 
-static void compile(const char *filename, 
+static void compile(const char *filename,
        struct compiler_state *compiler, struct arch_state *arch)
 {
        int i;
        struct compile_state state;
        struct triple *ptr;
+       struct filelist *includes = include_filelist;
        memset(&state, 0, sizeof(state));
        state.compiler = compiler;
        state.arch     = arch;
@@ -24751,6 +25005,7 @@ static void compile(const char *filename,
        /* Memorize where some attribute keywords are. */
        state.i_noinline      = lookup(&state, "noinline", 8);
        state.i_always_inline = lookup(&state, "always_inline", 13);
+       state.i_noreturn      = lookup(&state, "noreturn", 8);
 
        /* Process the command line macros */
        process_cmdline_macros(&state);
@@ -24772,10 +25027,16 @@ static void compile(const char *filename,
        /* Enter the globl definition scope */
        start_scope(&state);
        register_builtins(&state);
+
        compile_file(&state, filename, 1);
+       
+       while (includes) {
+               compile_file(&state, includes->filename, 1);
+               includes=includes->next;
+       }
 
        /* Stop if all we want is preprocessor output */
-       if (state.compiler->flags & COMPILER_CPP_ONLY) {
+       if (state.compiler->flags & COMPILER_PP_ONLY) {
                print_preprocessed_tokens(&state);
                return;
        }
@@ -24888,6 +25149,18 @@ int main(int argc, char **argv)
                        else if (strncmp(argv[1], "-m", 2) == 0) {
                                result = arch_encode_flag(&arch, argv[1]+2);
                        }
+                       else if (strncmp(argv[1], "-include", 10) == 0) {
+                               struct filelist *old_head = include_filelist;
+                               include_filelist = malloc(sizeof(struct filelist));
+                               if (!include_filelist) {
+                                       die("Out of memory.\n");
+                               }
+                               argv++;
+                               argc--;
+                               include_filelist->filename = argv[1];
+                               include_filelist->next = old_head;
+                               result = 0;
+                       }
                        if (result < 0) {
                                arg_error("Invalid option specified: %s\n",
                                        argv[1]);