Merged changes r1927-r1963 from the trunk into multiarch branch.

svn path=/branches/multiarch/; revision=1964
diff --git a/frontends/yasm/yasm.c b/frontends/yasm/yasm.c
index acbf6ab..9397615 100644
--- a/frontends/yasm/yasm.c
+++ b/frontends/yasm/yasm.c
@@ -220,7 +220,7 @@
 static constcharparam_head preproc_options;
 
 static int
-do_preproc_only(FILE *in)
+do_preproc_only()
 {
     yasm_linemap *linemap;
     char *preproc_buf = yasm_xmalloc(PREPROC_BUF_SIZE);
@@ -241,7 +241,7 @@
         /* determine the object filename if not specified, but we need a
             file name for the makefile rule */
         if (generate_make_dependencies && !obj_filename) {
-            if (in == stdin)
+            if (in_filename == NULL)
                 /* Default to yasm.out if no obj filename specified */
                 obj_filename = yasm__xstrdup("yasm.out");
             else {
@@ -264,7 +264,7 @@
     }
 
     /* Pre-process until done */
-    cur_preproc = yasm_preproc_create(cur_preproc_module, in, in_filename,
+    cur_preproc = yasm_preproc_create(cur_preproc_module, in_filename,
                                       linemap, errwarns);
 
     apply_preproc_builtins();
@@ -293,9 +293,6 @@
             fwrite(preproc_buf, got, 1, out);
     }
 
-    if (in != stdin)
-        fclose(in);
-
     if (out != stdout)
         fclose(out);
 
@@ -321,7 +318,7 @@
 }
 
 static int
-do_assemble(FILE *in)
+do_assemble()
 {
     yasm_object *object;
     const char *base_filename;
@@ -337,7 +334,7 @@
 
     /* determine the object filename if not specified */
     if (!obj_filename) {
-        if (in == stdin)
+        if (in_filename == NULL)
             /* Default to yasm.out if no obj filename specified */
             obj_filename = yasm__xstrdup("yasm.out");
         else {
@@ -366,9 +363,8 @@
                 yasm__xstrdup(cur_arch_module->default_machine_keyword);
     }
 
-    cur_arch = cur_arch_module->create(machine_name,
-                                       cur_parser_module->keyword,
-                                       &arch_error);
+    cur_arch = yasm_arch_create(cur_arch_module, machine_name,
+                                cur_parser_module->keyword, &arch_error);
     if (!cur_arch) {
         switch (arch_error) {
             case YASM_ARCH_CREATE_BAD_MACHINE:
@@ -402,8 +398,6 @@
         yasm_xfree(estr);
         yasm_xfree(xrefstr);
 
-        if (in != stdin)
-            fclose(in);
         cleanup(object);
         return EXIT_FAILURE;
     }
@@ -423,14 +417,12 @@
         print_error(_("%s: `%s' is not a valid %s for %s `%s'"), _("FATAL"),
                     cur_preproc_module->keyword, _("preprocessor"),
                     _("parser"), cur_parser_module->keyword);
-        if (in != stdin)
-            fclose(in);
         cleanup(object);
         return EXIT_FAILURE;
     }
 
-    cur_preproc = cur_preproc_module->create(in, in_filename, linemap,
-                                             errwarns);
+    cur_preproc = yasm_preproc_create(cur_preproc_module, in_filename,
+                                      linemap, errwarns);
 
     apply_preproc_builtins();
     apply_preproc_saved_options();
@@ -444,13 +436,9 @@
     yasm_arch_set_var(cur_arch, "force_strict", force_strict);
 
     /* Parse! */
-    cur_parser_module->do_parse(object, cur_preproc, in, list_filename != NULL,
+    cur_parser_module->do_parse(object, cur_preproc, list_filename != NULL,
                                 linemap, errwarns);
 
-    /* Close input file */
-    if (in != stdin)
-        fclose(in);
-
     check_errors(errwarns, object, linemap);
 
     /* Finalize parse */
@@ -576,7 +564,7 @@
     /* Initialize intnum and floatnum */
     yasm_intnum_initialize();
     yasm_floatnum_initialize();
-    
+
     /* If not already specified, default to bin as the object format. */
     if (!cur_objfmt_module) {
         if (!objfmt_keyword)
@@ -638,20 +626,6 @@
     if (!in_filename) {
         print_error(_("No input files specified"));
         return EXIT_FAILURE;
-    } else if (strcmp(in_filename, "-") != 0) {
-        /* Open the input file (if not standard input) */
-        in = fopen(in_filename, "rt");
-        if (!in) {
-            print_error(_("%s: could not open file `%s'"), _("FATAL"),
-                        in_filename);
-            yasm_xfree(in_filename);
-            if (obj_filename)
-                yasm_xfree(obj_filename);
-            return EXIT_FAILURE;
-        }
-    } else {
-        /* Filename was "-", read stdin */
-        in = stdin;
     }
 
     /* handle preproc-only case here */
@@ -1086,7 +1060,7 @@
     /* Also set preproc_only to 1, we don't want to generate code */
     preproc_only = 1;
     generate_make_dependencies = 1;
-    
+
     return 0;
 }
 
diff --git a/libyasm/file.c b/libyasm/file.c
index cd2e002..48cb6f2 100644
--- a/libyasm/file.c
+++ b/libyasm/file.c
@@ -518,6 +518,23 @@
     STAILQ_INIT(&incpaths);
 }
 
+const char *
+yasm_get_include_dir(void **iter)
+{
+    incpath *p = (incpath *)*iter;
+
+    if (!p)
+        p = STAILQ_FIRST(&incpaths);
+    else
+        p = STAILQ_NEXT(p, link);
+
+    *iter = p;
+    if (p)
+        return p->path;
+    else
+        return NULL;
+}
+
 void
 yasm_add_include_path(const char *path)
 {
diff --git a/libyasm/file.h b/libyasm/file.h
index c706994..21676cd 100644
--- a/libyasm/file.h
+++ b/libyasm/file.h
@@ -210,6 +210,10 @@
  */
 void yasm_delete_include_paths(void);
 
+/** Iterate through include paths.
+*/
+const char * yasm_get_include_dir(void **iter);
+
 /** Add an include path for use by yasm_fopen_include().
  * If path is relative, it is treated by yasm_fopen_include() as relative to
  * the current working directory.
diff --git a/libyasm/parser.h b/libyasm/parser.h
index 2ed5ce1..fcbb20c 100644
--- a/libyasm/parser.h
+++ b/libyasm/parser.h
@@ -54,7 +54,6 @@
     /** Parse a source file into an object.
      * \param object    object to parse into (already created)
      * \param pp        preprocessor
-     * \param f         initial starting file
      * \param save_input        nonzero if the parser should save the original
      *                          lines of source into the object's linemap (via
      *                          yasm_linemap_add_data()).
@@ -62,7 +61,7 @@
      * \note Parse errors and warnings are stored into errwarns.
      */
     void (*do_parse)
-        (yasm_object *object, yasm_preproc *pp, FILE *f, int save_input,
+        (yasm_object *object, yasm_preproc *pp, int save_input,
          yasm_linemap *linemap, yasm_errwarns *errwarns);
 } yasm_parser_module;
 
diff --git a/libyasm/preproc.h b/libyasm/preproc.h
index f93a838..98f56e8 100644
--- a/libyasm/preproc.h
+++ b/libyasm/preproc.h
@@ -56,15 +56,15 @@
      * Module-level implementation of yasm_preproc_create().
      * Call yasm_preproc_create() instead of calling this function.
      *
-     * \param f                 initial starting file
-     * \param in_filename       initial starting filename
+     * \param in_filename       initial starting filename, or "-" to read from
+     *                          stdin
      * \param lm                line mapping repository
      * \param errwarns          error/warnning set.
      * \return New preprocessor.
      *
      * \note Any preprocessor errors and warnings are stored into errwarns.
      */
-    /*@only@*/ yasm_preproc * (*create) (FILE *f, const char *in_filename,
+    /*@only@*/ yasm_preproc * (*create) (const char *in_filename,
                                          yasm_linemap *lm,
                                          yasm_errwarns *errwarns);
 
@@ -110,15 +110,14 @@
  * The preprocessor needs access to the object format module to find out
  * any output format specific macros.
  * \param module        preprocessor module
- * \param f             initial starting file
- * \param in_filename   initial starting file filename
+ * \param in_filename   initial starting filename, or "-" to read from stdin
  * \param lm            line mapping repository
  * \param errwarns      error/warning set
  * \return New preprocessor.
  * \note Errors/warnings are stored into errwarns.
  */
 /*@only@*/ yasm_preproc *yasm_preproc_create
-    (yasm_preproc_module *module, FILE *f, const char *in_filename,
+    (yasm_preproc_module *module, const char *in_filename,
      yasm_linemap *lm, yasm_errwarns *errwarns);
 
 /** Cleans up any allocated preproc memory.
@@ -176,8 +175,8 @@
 
 /* Inline macro implementations for preproc functions */
 
-#define yasm_preproc_create(module, f, in_filename, lm, ews) \
-    module->create(f, in_filename, lm, ews)
+#define yasm_preproc_create(module, in_filename, lm, ews) \
+    module->create(in_filename, lm, ews)
 
 #define yasm_preproc_destroy(preproc) \
     ((yasm_preproc_base *)preproc)->module->destroy(preproc)
diff --git a/modules/parsers/gas/gas-parse.c b/modules/parsers/gas/gas-parse.c
index ef64c16..2c402f1 100644
--- a/modules/parsers/gas/gas-parse.c
+++ b/modules/parsers/gas/gas-parse.c
@@ -44,6 +44,7 @@
     enum gas_parser_state newstate;
 } dir_lookup;
 
+static yasm_bytecode * cpp_line_marker(yasm_parser_gas *parser_gas);
 static yasm_bytecode *parse_instr(yasm_parser_gas *parser_gas);
 static int parse_dirvals(yasm_parser_gas *parser_gas, yasm_valparamhead *vps);
 static int parse_datavals(yasm_parser_gas *parser_gas, yasm_datavalhead *dvs);
@@ -85,7 +86,7 @@
 {
     char savech = parser_gas->tokch;
     if (parser_gas->peek_token != NONE)
-        yasm_internal_error(N_("only can have one token of lookahead"));
+        yasm_internal_error(N_("can only have one token of lookahead"));
     parser_gas->peek_token =
         gas_parser_lex(&parser_gas->peek_tokval, parser_gas);
     parser_gas->peek_tokch = parser_gas->tokch;
@@ -247,6 +248,9 @@
             define_label(parser_gas, LABEL_val, 0);
             get_next_token(); /* LABEL */
             return parse_line(parser_gas);
+        case LINE_MARKER:
+            get_next_token();
+            return cpp_line_marker(parser_gas);
         default:
             yasm_error_set(YASM_ERROR_SYNTAX,
                 N_("label or instruction expected at start of line"));
@@ -254,6 +258,110 @@
     }
 }
 
+/*
+    Handle line markers generated by cpp.
+
+    We expect a positive integer (line) followed by a string (filename). If we
+    fail to find either of these, we treat the line as a comment. There is a
+    possibility of false positives (mistaking a comment for a line marker, when
+    the comment is not intended as a line marker) but this cannot be avoided
+    without adding a filter to the input before passing it to cpp.
+
+    This function is only called if the preprocessor was 'cpp', since the
+    LINE_MARKER token isn't generated for any other preprocessor. With any other
+    preprocessor, anything after a '#' is always treated as a comment.
+*/
+static yasm_bytecode *
+cpp_line_marker(yasm_parser_gas *parser_gas)
+{
+    yasm_valparamhead vps;
+    yasm_valparam *vp;
+    unsigned long line;
+    char *filename;
+
+    /* Line number. */
+    if (curtok != INTNUM) {
+        /* Skip over a comment. */
+        while (curtok != '\n')
+            get_next_token();
+
+        return NULL;
+    }
+
+    if (yasm_intnum_sign(INTNUM_val) < 0) {
+        get_next_token(); /* INTNUM */
+        yasm_error_set(YASM_ERROR_SYNTAX,
+                       N_("line number is negative"));
+        return NULL;
+    }
+
+    line = yasm_intnum_get_uint(INTNUM_val);
+
+    /*
+        Set to (line - 1) since the directive indicates that the *next* line
+        will have the number given.
+
+        cpp should never produce line=0, but the if keeps us safe just incase.
+    */
+    if (line != 0)
+        line--;
+
+    yasm_intnum_destroy(INTNUM_val);
+    get_next_token(); /* INTNUM */
+
+    /* File name, in quotes. */
+    if (curtok != STRING) {
+        /* Skip over a comment. */
+        while (curtok != '\n')
+            get_next_token();
+
+        return NULL;
+    }
+
+    filename = STRING_val.contents;
+    get_next_token();
+
+    /* Set linemap. */
+    yasm_linemap_set(parser_gas->linemap, filename, line, 1);
+
+    /*
+        The first line marker in the file (which should be on the first line
+        of the file) will give us the name of the source file. This information
+        needs to be passed on to the debug format module.
+    */
+    if (parser_gas->seen_line_marker == 0) {
+        parser_gas->seen_line_marker = 1;
+
+        yasm_vps_initialize(&vps);
+        vp = yasm_vp_create_string(NULL, filename);
+        yasm_vps_append(&vps, vp);
+
+        yasm_object_directive(p_object, ".file", "gas", &vps, NULL, cur_line);
+
+        yasm_vps_delete(&vps);
+    }
+
+    /* Skip flags. */
+    while (1) {
+        switch (curtok) {
+            case INTNUM:
+                break;
+
+            case '\n':
+                return NULL;
+
+            default:
+                yasm_error_set(YASM_ERROR_SYNTAX,
+                    N_("junk at end of cpp line marker"));
+                return NULL;
+        }
+        get_next_token();
+    }
+
+    /* Never reached. */
+    return NULL;
+}
+
 /* Line directive */
 static yasm_bytecode *
 dir_line(yasm_parser_gas *parser_gas, unsigned int param)
@@ -1516,7 +1624,7 @@
 
     while (get_next_token() != 0) {
         yasm_bytecode *bc = NULL, *temp_bc;
-        
+
         if (!is_eol()) {
             bc = parse_line(parser_gas);
             demand_eol();
diff --git a/modules/parsers/gas/gas-parser.c b/modules/parsers/gas/gas-parser.c
index 9cc6138..521851c 100644
--- a/modules/parsers/gas/gas-parser.c
+++ b/modules/parsers/gas/gas-parser.c
@@ -36,7 +36,7 @@
 
 
 static void
-gas_parser_do_parse(yasm_object *object, yasm_preproc *pp, FILE *f,
+gas_parser_do_parse(yasm_object *object, yasm_preproc *pp,
                     int save_input, yasm_linemap *linemap,
                     yasm_errwarns *errwarns)
 {
@@ -46,14 +46,13 @@
     parser_gas.object = object;
     parser_gas.linemap = linemap;
 
-    parser_gas.in = f;
-
     parser_gas.locallabel_base = (char *)NULL;
     parser_gas.locallabel_base_len = 0;
 
     parser_gas.dir_fileline = 0;
     parser_gas.dir_file = NULL;
     parser_gas.dir_line = 0;
+    parser_gas.seen_line_marker = 0;
 
     parser_gas.preproc = pp;
     parser_gas.errwarns = errwarns;
@@ -112,6 +111,7 @@
 /* Define valid preprocessors to use with this parser */
 static const char *gas_parser_preproc_keywords[] = {
     "raw",
+    "cpp",
     NULL
 };
 
diff --git a/modules/parsers/gas/gas-parser.h b/modules/parsers/gas/gas-parser.h
index 8d683e0..eece2a2 100644
--- a/modules/parsers/gas/gas-parser.h
+++ b/modules/parsers/gas/gas-parser.h
@@ -48,6 +48,7 @@
     RIGHT_OP,
     ID,
     LABEL,
+    LINE_MARKER,
     NONE
 };
 
@@ -93,7 +94,6 @@
 };
 
 typedef struct yasm_parser_gas {
-    FILE *in;
     int debug;
 
     /*@only@*/ yasm_object *object;
@@ -107,6 +107,9 @@
     /*@null@*/ char *dir_file;
     unsigned long dir_line;
 
+    /* Have we seen a line marker? */
+    int seen_line_marker;
+
     /*@dependent@*/ yasm_preproc *preproc;
     /*@dependent@*/ yasm_errwarns *errwarns;
 
diff --git a/modules/parsers/gas/gas-token.re b/modules/parsers/gas/gas-token.re
index c3b19e9..1251225 100644
--- a/modules/parsers/gas/gas-token.re
+++ b/modules/parsers/gas/gas-token.re
@@ -42,8 +42,8 @@
 #define YYMARKER        (s->ptr)
 #define YYFILL(n)       {cursor = fill(parser_gas, cursor);}
 
-#define RETURN(i)       {s->cur = cursor; parser_gas->tokch = s->tok[0]; \
-                         return i;}
+#define RETURN(i)       do {s->cur = cursor; parser_gas->tokch = s->tok[0]; \
+                         return i;} while (0)
 
 #define SCANINIT()      {s->tok = cursor;}
 
@@ -445,7 +445,14 @@
         }
 
         "/*"                    { parser_gas->state = COMMENT; goto comment; }
-        "#" (any \ [\n])*       { goto scan; }
+        "#"                     {
+            if (strcmp(((yasm_preproc_base*)parser_gas->preproc)->module->keyword,
+                 "cpp") == 0)
+            {
+                RETURN(LINE_MARKER);
+            } else
+                goto line_comment;
+        }
 
         ws+                     { goto scan; }
 
@@ -485,6 +492,12 @@
         }
     */
 
+    /* Single line comment. */
+line_comment:
+    /*!re2c
+        (any \ [\n])*   { goto scan; }
+    */
+
     /* .section directive (the section name portion thereof) */
 section_directive:
     SCANINIT();
diff --git a/modules/parsers/nasm/nasm-parser.c b/modules/parsers/nasm/nasm-parser.c
index 8cdc63a..7138c9d 100644
--- a/modules/parsers/nasm/nasm-parser.c
+++ b/modules/parsers/nasm/nasm-parser.c
@@ -33,7 +33,7 @@
 
 
 static void
-nasm_parser_do_parse(yasm_object *object, yasm_preproc *pp, FILE *f,
+nasm_parser_do_parse(yasm_object *object, yasm_preproc *pp,
                      int save_input, yasm_linemap *linemap,
                      yasm_errwarns *errwarns)
 {
@@ -42,8 +42,6 @@
     parser_nasm.object = object;
     parser_nasm.linemap = linemap;
 
-    parser_nasm.in = f;
-
     parser_nasm.locallabel_base = (char *)NULL;
     parser_nasm.locallabel_base_len = 0;
 
diff --git a/modules/parsers/nasm/nasm-parser.h b/modules/parsers/nasm/nasm-parser.h
index 4c8de41..2f14522 100644
--- a/modules/parsers/nasm/nasm-parser.h
+++ b/modules/parsers/nasm/nasm-parser.h
@@ -81,7 +81,6 @@
 #define YYSTYPE yystype
 
 typedef struct yasm_parser_nasm {
-    FILE *in;
     int debug;
 
     /*@only@*/ yasm_object *object;
diff --git a/modules/preprocs/Makefile.inc b/modules/preprocs/Makefile.inc
index 0414558..8d3f7cf 100644
--- a/modules/preprocs/Makefile.inc
+++ b/modules/preprocs/Makefile.inc
@@ -2,6 +2,8 @@
 
 EXTRA_DIST += modules/preprocs/nasm/Makefile.inc
 EXTRA_DIST += modules/preprocs/raw/Makefile.inc
+EXTRA_DIST += modules/preprocs/cpp/Makefile.inc
 
 include modules/preprocs/nasm/Makefile.inc
 include modules/preprocs/raw/Makefile.inc
+include modules/preprocs/cpp/Makefile.inc
diff --git a/modules/preprocs/cpp/Makefile.inc b/modules/preprocs/cpp/Makefile.inc
new file mode 100644
index 0000000..30bd24b
--- /dev/null
+++ b/modules/preprocs/cpp/Makefile.inc
@@ -0,0 +1,6 @@
+# Makefile for cpp module.
+# Copied from raw preprocessor module.
+
+libyasm_a_SOURCES += modules/preprocs/cpp/cpp-preproc.c
+
+YASM_MODULES += preproc_cpp
diff --git a/modules/preprocs/cpp/cpp-preproc.c b/modules/preprocs/cpp/cpp-preproc.c
new file mode 100644
index 0000000..c28e6e6
--- /dev/null
+++ b/modules/preprocs/cpp/cpp-preproc.c
@@ -0,0 +1,356 @@
+/*
+ * Invoke an external C preprocessor
+ *
+ *  Copyright (C) 2007       Paul Barker
+ *  Copyright (C) 2001-2007  Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <util.h>
+#include <libyasm.h>
+
+/* TODO: Use autoconf to get the limit on the command line length. */
+#define CMDLINE_SIZE 32770
+
+/* Pre-declare the preprocessor module object. */
+yasm_preproc_module yasm_cpp_LTX_preproc;
+
+/*******************************************************************************
+    Structures.
+*******************************************************************************/
+
+/* An entry in a list of arguments to pass to cpp. */
+typedef struct cpp_arg_entry {
+    TAILQ_ENTRY(cpp_arg_entry) entry;
+
+    /*
+        The operator (eg "-I") and the parameter (eg "include/"). op is expected
+        to point to a string literal, whereas param is expected to be a copy of
+        the parameter which is free'd when no-longer needed (in
+        cpp_preproc_destroy()).
+    */
+    const char *op;
+    char *param;
+} cpp_arg_entry;
+
+typedef struct yasm_preproc_cpp {
+    yasm_preproc_base preproc;   /* base structure */
+
+    /* List of arguments to pass to cpp. */
+    TAILQ_HEAD(, cpp_arg_entry) cpp_args;
+
+    char *filename;
+    FILE *f, *f_deps;
+    yasm_linemap *cur_lm;
+    yasm_errwarns *errwarns;
+
+    int flags;
+} yasm_preproc_cpp;
+
+/* Flag values for yasm_preproc_cpp->flags. */
+#define CPP_HAS_BEEN_INVOKED        0x01
+#define CPP_HAS_GENERATED_DEPS      0x02
+
+/*******************************************************************************
+    Internal functions and helpers.
+*******************************************************************************/
+
+/*
+    Append a string to the command line, ensuring that we don't overflow the
+    buffer.
+*/
+#define APPEND(s) do {                              \
+    size_t _len = strlen(s);                        \
+    if (p + _len >= limit)                          \
+        yasm__fatal(N_("command line too long!"));  \
+    strcpy(p, s);                                   \
+    p += _len;                                      \
+} while (0)
+
+/*
+    Put all the options together into a command line that can be used to invoke
+    cpp.
+*/
+static char *
+cpp_build_cmdline(yasm_preproc_cpp *pp, const char *extra)
+{
+    char *cmdline, *p, *limit;
+    cpp_arg_entry *arg;
+
+    /*
+        Initialize command line. We can assume there will be enough space to
+        store "cpp".
+    */
+    cmdline = p = yasm_xmalloc(CMDLINE_SIZE);
+    limit = p + CMDLINE_SIZE;
+    strcpy(p, "cpp");
+    p += 3;
+
+    arg = TAILQ_FIRST(&pp->cpp_args);
+
+    /* Append arguments from the list. */
+    while ( arg ) {
+        APPEND(" ");
+        APPEND(arg->op);
+        APPEND(" ");
+        APPEND(arg->param);
+
+        arg = TAILQ_NEXT(arg, entry);
+    }
+
+    /* Append extra arguments. */
+    if (extra) {
+        APPEND(" ");
+        APPEND(extra);
+    }
+    /* Append final arguments. */
+    APPEND(" -x assembler-with-cpp ");
+    APPEND(pp->filename);
+
+    return cmdline;
+}
+
+/* Invoke the c preprocessor. */
+static void
+cpp_invoke(yasm_preproc_cpp *pp)
+{
+    char *cmdline;
+
+    cmdline = cpp_build_cmdline(pp, NULL);
+
+    pp->f = popen(cmdline, "r");
+    if (!pp->f)
+        yasm__fatal( N_("Failed to execute preprocessor") );
+
+    yasm_xfree(cmdline);
+}
+
+/* Free memory used by the list of arguments. */
+static void
+cpp_destroy_args(yasm_preproc_cpp *pp)
+{
+    cpp_arg_entry *arg;
+
+    while ( (arg = TAILQ_FIRST(&pp->cpp_args)) ) {
+        TAILQ_REMOVE(&pp->cpp_args, arg, entry);
+        yasm_xfree(arg->param);
+        yasm_xfree(arg);
+    }
+}
+
+/* Invoke the c preprocessor to generate dependency info. */
+static void
+cpp_generate_deps(yasm_preproc_cpp *pp)
+{
+    char *cmdline;
+
+    cmdline = cpp_build_cmdline(pp, "-M");
+
+    pp->f_deps = popen(cmdline, "r");
+    if (!pp->f_deps)
+        yasm__fatal( N_("Failed to execute preprocessor") );
+
+    yasm_xfree(cmdline);
+}
+
+/*******************************************************************************
+    Interface functions.
+*******************************************************************************/
+static yasm_preproc *
+cpp_preproc_create(const char *in, yasm_linemap *lm, yasm_errwarns *errwarns)
+{
+    yasm_preproc_cpp *pp = yasm_xmalloc(sizeof(yasm_preproc_cpp));
+    void * iter;
+    const char * inc_dir;
+
+    pp->preproc.module = &yasm_cpp_LTX_preproc;
+    pp->f = pp->f_deps = NULL;
+    pp->cur_lm = lm;
+    pp->errwarns = errwarns;
+    pp->flags = 0;
+    pp->filename = yasm__xstrdup(in);
+
+    TAILQ_INIT(&pp->cpp_args);
+
+    /* Iterate through the list of include dirs. */
+    iter = NULL;
+    while ((inc_dir = yasm_get_include_dir(&iter)) != NULL) {
+        cpp_arg_entry *arg = yasm_xmalloc(sizeof(cpp_arg_entry));
+        arg->op = "-I";
+        arg->param = yasm__xstrdup(inc_dir);
+
+        TAILQ_INSERT_TAIL(&pp->cpp_args, arg, entry);
+    }
+
+    return (yasm_preproc *)pp;
+}
+
+static void
+cpp_preproc_destroy(yasm_preproc *preproc)
+{
+    yasm_preproc_cpp *pp = (yasm_preproc_cpp *)preproc;
+
+    if (pp->f) {
+        if (pclose(pp->f) != 0)
+            yasm__fatal( N_("Preprocessor exited with failure") );
+    }
+
+    cpp_destroy_args(pp);
+
+    yasm_xfree(pp->filename);
+    yasm_xfree(pp);
+}
+
+static size_t
+cpp_preproc_input(yasm_preproc *preproc, char *buf, size_t max_size)
+{
+    size_t n;
+    yasm_preproc_cpp *pp = (yasm_preproc_cpp *)preproc;
+
+    if (! (pp->flags & CPP_HAS_BEEN_INVOKED) ) {
+        pp->flags |= CPP_HAS_BEEN_INVOKED;
+
+        cpp_invoke(pp);
+    }
+
+    /*
+        Once the preprocessor has been run, we're just dealing with a normal
+        file.
+    */
+    if (((n = fread(buf, 1, max_size, pp->f)) == 0) &&
+               ferror(pp->f)) {
+        yasm_error_set(YASM_ERROR_IO, N_("error reading from pipe"));
+        yasm_errwarn_propagate(pp->errwarns,
+                               yasm_linemap_get_current(pp->cur_lm));
+    }
+
+    return n;
+}
+
+static size_t
+cpp_preproc_get_included_file(yasm_preproc *preproc, char *buf,
+                              size_t max_size)
+{
+    char *p = buf;
+    int ch = '\0';
+    size_t n = 0;
+    yasm_preproc_cpp *pp = (yasm_preproc_cpp *)preproc;
+
+    if (! (pp->flags & CPP_HAS_GENERATED_DEPS) ) {
+        pp->flags |= CPP_HAS_GENERATED_DEPS;
+
+        cpp_generate_deps(pp);
+
+        /* Skip target name and first dependency. */
+        while (ch != ':')
+            ch = fgetc(pp->f_deps);
+
+        fgetc(pp->f_deps);      /* Discard space after colon. */
+
+        while (ch != ' ' && ch != EOF)
+            ch = fgetc(pp->f_deps);
+
+        if (ch == EOF)
+            return 0;
+    }
+
+    while (n < max_size) {
+        ch = fgetc(pp->f_deps);
+
+        if (ch == ' ' || ch == EOF) {
+            *p = '\0';
+            return n;
+        }
+
+        /* Eat any silly characters. */
+        if (ch < ' ')
+            continue;
+
+        *p++ = ch;
+        n++;
+    }
+
+    /* Ensure the buffer is null-terminated. */
+    *(p - 1) = '\0';
+    return n;
+}
+
+static void
+cpp_preproc_add_include_file(yasm_preproc *preproc, const char *filename)
+{
+    yasm_preproc_cpp *pp = (yasm_preproc_cpp *)preproc;
+
+    cpp_arg_entry *arg = yasm_xmalloc(sizeof(cpp_arg_entry));
+    arg->op = "-include";
+    arg->param = yasm__xstrdup(filename);
+
+    TAILQ_INSERT_TAIL(&pp->cpp_args, arg, entry);
+}
+
+static void
+cpp_preproc_predefine_macro(yasm_preproc *preproc, const char *macronameval)
+{
+    yasm_preproc_cpp *pp = (yasm_preproc_cpp *)preproc;
+
+    cpp_arg_entry *arg = yasm_xmalloc(sizeof(cpp_arg_entry));
+    arg->op = "-D";
+    arg->param = yasm__xstrdup(macronameval);
+
+    TAILQ_INSERT_TAIL(&pp->cpp_args, arg, entry);
+}
+
+static void
+cpp_preproc_undefine_macro(yasm_preproc *preproc, const char *macroname)
+{
+    yasm_preproc_cpp *pp = (yasm_preproc_cpp *)preproc;
+
+    cpp_arg_entry *arg = yasm_xmalloc(sizeof(cpp_arg_entry));
+    arg->op = "-U";
+    arg->param = yasm__xstrdup(macroname);
+
+    TAILQ_INSERT_TAIL(&pp->cpp_args, arg, entry);
+}
+
+static void
+cpp_preproc_define_builtin(yasm_preproc *preproc, const char *macronameval)
+{
+    /* Handle a builtin as if it were a predefine. */
+    cpp_preproc_predefine_macro(preproc, macronameval);
+}
+
+/*******************************************************************************
+    Preprocessor module object.
+*******************************************************************************/
+
+yasm_preproc_module yasm_cpp_LTX_preproc = {
+    "Run input through enternal C preprocessor",
+    "cpp",
+    cpp_preproc_create,
+    cpp_preproc_destroy,
+    cpp_preproc_input,
+    cpp_preproc_get_included_file,
+    cpp_preproc_add_include_file,
+    cpp_preproc_predefine_macro,
+    cpp_preproc_undefine_macro,
+    cpp_preproc_define_builtin
+};
diff --git a/modules/preprocs/nasm/nasm-preproc.c b/modules/preprocs/nasm/nasm-preproc.c
index 9670026..78993b5 100644
--- a/modules/preprocs/nasm/nasm-preproc.c
+++ b/modules/preprocs/nasm/nasm-preproc.c
@@ -128,13 +128,22 @@
 }
 
 static yasm_preproc *
-nasm_preproc_create(FILE *f, const char *in_filename, yasm_linemap *lm,
+nasm_preproc_create(const char *in_filename, yasm_linemap *lm,
                     yasm_errwarns *errwarns)
 {
+    FILE *f;
     yasm_preproc_nasm *preproc_nasm = yasm_xmalloc(sizeof(yasm_preproc_nasm));
 
     preproc_nasm->preproc.module = &yasm_nasm_LTX_preproc;
 
+    if (strcmp(in_filename, "-") != 0) {
+        f = fopen(in_filename, "r");
+        if (!f)
+            yasm__fatal( N_("Could not open input file") );
+    }
+    else
+        f = stdin;
+
     preproc_nasm->in = f;
     cur_lm = lm;
     cur_errwarns = errwarns;
diff --git a/modules/preprocs/raw/raw-preproc.c b/modules/preprocs/raw/raw-preproc.c
index 4e80cff..869cbec 100644
--- a/modules/preprocs/raw/raw-preproc.c
+++ b/modules/preprocs/raw/raw-preproc.c
@@ -44,11 +44,20 @@
 int isatty(int);
 
 static yasm_preproc *
-raw_preproc_create(FILE *f, const char *in_filename, yasm_linemap *lm,
+raw_preproc_create(const char *in_filename, yasm_linemap *lm,
                    yasm_errwarns *errwarns)
 {
+    FILE *f;
     yasm_preproc_raw *preproc_raw = yasm_xmalloc(sizeof(yasm_preproc_raw));
 
+    if (strcmp(in_filename, "-") != 0) {
+        f = fopen(in_filename, "r");
+        if (!f)
+            yasm__fatal( N_("Could not open input file") );
+    }
+    else
+        f = stdin;
+
     preproc_raw->preproc.module = &yasm_raw_LTX_preproc;
     preproc_raw->in = f;
     preproc_raw->cur_lm = lm;
diff --git a/modules/preprocs/yapp/yapp-preproc.c b/modules/preprocs/yapp/yapp-preproc.c
index c775644..e1215a7 100644
--- a/modules/preprocs/yapp/yapp-preproc.c
+++ b/modules/preprocs/yapp/yapp-preproc.c
@@ -241,11 +241,20 @@
 expand_token_list(struct source_head *paramexp, struct source_head *to_head, source **to_tail);
 
 static yasm_preproc *
-yapp_preproc_create(FILE *f, const char *in_filename, yasm_linemap *lm,
+yapp_preproc_create(const char *in_filename, yasm_linemap *lm,
                     yasm_errwarns *errwarns)
 {
+    FILE *f;
     yasm_preproc_yapp *preproc_yapp = yasm_xmalloc(sizeof(yasm_preproc_yapp));
 
+    if (strcmp(in_filename, "-") != 0) {
+        f = fopen(in_filename, "r");
+        if (!f)
+            yasm__fatal( N_("Could not open input file") );
+    }
+    else
+        f = stdin;
+
     preproc_yapp->preproc.module = &yasm_yapp_LTX_preproc;
 
     yapp_preproc_linemap = lm;
@@ -468,7 +477,7 @@
             return 0;
         append_token(token, to_head, to_tail);
         token = yapp_preproc_lex();
-    } 
+    }
     return '\n';
 }
 
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 4dc46a9..34438fa 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -6,7 +6,6 @@
 
 frontends/yasm/yasm-options.c
 frontends/yasm/yasm.c
-#lc3bid.c
 libyasm/bc-align.c
 libyasm/bc-data.c
 libyasm/bc-incbin.c
@@ -23,10 +22,11 @@
 libyasm/intnum.c
 libyasm/section.c
 libyasm/symrec.c
+libyasm/valparam.c
 libyasm/value.c
 libyasm/xmalloc.c
-#modules/arch/lc3b/lc3barch.c
-#modules/arch/lc3b/lc3bbc.c
+modules/arch/lc3b/lc3barch.c
+modules/arch/lc3b/lc3bbc.c
 modules/arch/x86/x86arch.c
 modules/arch/x86/x86bc.c
 modules/arch/x86/x86expr.c
@@ -54,5 +54,8 @@
 modules/parsers/gas/gas-token.re
 modules/parsers/nasm/nasm-parse.c
 modules/parsers/nasm/nasm-token.re
+modules/preprocs/cpp/cpp-preproc.c
+modules/preprocs/yapp/yapp-preproc.c
+modules/preprocs/nasm/nasm-preproc.c
 modules/preprocs/nasm/nasm-pp.c
 modules/preprocs/raw/raw-preproc.c