update TODO, fox error33
[cparser] / main.c
diff --git a/main.c b/main.c
index a529a03..4eecd4c 100644 (file)
--- a/main.c
+++ b/main.c
@@ -1,3 +1,22 @@
+/*
+ * This file is part of cparser.
+ * Copyright (C) 2007-2008 Matthias Braun <matze@braunis.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
 #include <config.h>
 
 #define _GNU_SOURCE
@@ -60,7 +79,7 @@
 #include "warning.h"
 
 #ifndef PREPROCESSOR
-#define PREPROCESSOR "cpp -std=c99 -U__WCHAR_TYPE__ -D__WCHAR_TYPE__=int"
+#define PREPROCESSOR "cpp -std=c99 -U__WCHAR_TYPE__ -D__WCHAR_TYPE__=int -m32"
 #endif
 
 #ifndef LINKER
@@ -86,12 +105,19 @@ bool strict_mode = false;
 /* to switch on printing of implicit casts */
 extern bool print_implicit_casts;
 
-/* to switch on printing of  srenthesis to indicate operator precedence */
+/* to switch on printing of parenthesis to indicate operator precedence */
 extern bool print_parenthesis;
 
 static int            verbose;
 static struct obstack cppflags_obst, ldflags_obst;
 
+typedef struct file_list_entry_t file_list_entry_t;
+
+struct file_list_entry_t {
+       const char        *filename;
+       file_list_entry_t *next;
+};
+
 #if defined(_DEBUG) || defined(FIRM_DEBUG)
 /**
  * Debug printf implementation.
@@ -147,9 +173,9 @@ static void get_output_name(char *buf, size_t buflen, const char *inputname,
        memcpy(buf+last_dot, newext, extlen);
 }
 
-static translation_unit_t *do_parsing(FILE *const in, const char *const input)
+static translation_unit_t *do_parsing(FILE *const in, const char *const input_name)
 {
-       lexer_open_stream(in, input);
+       lexer_open_stream(in, input_name);
        translation_unit_t *unit = parse();
        return unit;
 }
@@ -165,7 +191,7 @@ static void lextest(FILE *in, const char *fname)
        } while(lexer_token.type != T_EOF);
 }
 
-static FILE* preprocess(FILE* in, const char *fname)
+static FILE *preprocess(FILE *in, const char *fname, bool to_stdout)
 {
        char buf[4096];
        obstack_1grow(&cppflags_obst, '\0');
@@ -181,12 +207,17 @@ static FILE* preprocess(FILE* in, const char *fname)
        if(verbose) {
                puts(buf);
        }
-       FILE* f = popen(buf, "r");
-       if (f == NULL) {
-               fprintf(stderr, "invoking preprocessor failed\n");
-               exit(1);
+       if(to_stdout) {
+               int res = system(buf);
+               exit(res);
+       } else {
+               FILE *f = popen(buf, "r");
+               if(f == NULL) {
+                       fprintf(stderr, "invoking preprocessor failed\n");
+                       exit(1);
+               }
+               return f;
        }
-       return f;
 }
 
 static void do_link(const char *out, const char *in)
@@ -319,6 +350,7 @@ void lower_compound_params(void)
 
 typedef enum compile_mode_t {
        BenchmarkParser,
+       PreprocessOnly,
        ParseOnly,
        Compile,
        CompileDump,
@@ -326,7 +358,8 @@ typedef enum compile_mode_t {
        CompileAssembleLink,
        LexTest,
        PrintAst,
-       PrintFluffy
+       PrintFluffy,
+       Link
 } compile_mode_t;
 
 static void usage(const char *argv0)
@@ -334,18 +367,42 @@ static void usage(const char *argv0)
        fprintf(stderr, "Usage %s input [-o output] [-c]\n", argv0);
 }
 
+static void print_cparser_version(void) {
+       firm_version_t ver;
+       firm_get_version(&ver);
+
+       printf("cparser (%s) using libFirm (%u.%u",
+               cparser_REVISION, ver.major, ver.minor);
+       if(ver.revision[0] != 0) {
+               putchar(' ');
+               fputs(ver.revision, stdout);
+       }
+       if(ver.build[0] != 0) {
+               putchar(' ');
+               fputs(ver.build, stdout);
+       }
+       puts(")\n");
+}
+
 int main(int argc, char **argv)
 {
        initialize_firm();
 
-       const char     *input        = NULL;
-       const char     *outname      = NULL;
-       const char     *dumpfunction = NULL;
-       compile_mode_t  mode         = CompileAssembleLink;
-       int             opt_level    = 1;
+       const char        *input        = NULL;
+       const char        *outname      = NULL;
+       const char        *dumpfunction = NULL;
+       compile_mode_t     mode         = CompileAssembleLink;
+       int                opt_level    = 1;
+       int                result       = EXIT_SUCCESS;
+       char               cpu_arch[16] = "ia32";
+       file_list_entry_t *c_files      = NULL;
+       file_list_entry_t *s_files      = NULL;
+       file_list_entry_t *o_files      = NULL;
+       struct obstack     file_obst;
 
        obstack_init(&cppflags_obst);
        obstack_init(&ldflags_obst);
+       obstack_init(&file_obst);
 
 #define GET_ARG_AFTER(def, args)                                             \
        def = &arg[sizeof(args)-1];                                              \
@@ -396,7 +453,6 @@ int main(int argc, char **argv)
                /* fallthrough */
        case 2:
                firm_option("inline");
-               firm_option("no-strength-red");
                firm_option("deconv");
                firm_be_option("omitfp");
                break;
@@ -414,8 +470,12 @@ int main(int argc, char **argv)
                                GET_ARG_AFTER(outname, "-o");
                        } else if(option[0] == 'g') {
                                firm_be_option("stabs=yes");
+                               firm_be_option("omitfp=no");
+                               firm_be_option("ia32-nooptcc=yes");
                        } else if(SINGLE_OPTION('c')) {
                                mode = CompileAssemble;
+                       } else if(SINGLE_OPTION('E')) {
+                               mode = PreprocessOnly;
                        } else if(SINGLE_OPTION('S')) {
                                mode = Compile;
                        } else if(option[0] == 'O') {
@@ -475,23 +535,85 @@ int main(int argc, char **argv)
                                        argument_errors = true;
                                } else if (res == -1) {
                                        help_displayed = true;
+                               } else {
+                                       if (strncmp(opt, "isa=", 4) == 0)
+                                               strncpy(cpu_arch, opt, sizeof(cpu_arch));
                                }
                        } else if(option[0] == 'W') {
                                set_warning_opt(&option[1]);
                        } else if(option[0] == 'm') {
+                               /* -m options */
                                const char *opt;
+                               char arch_opt[64];
+
                                GET_ARG_AFTER(opt, "-m");
-                               char *endptr;
-                               long int value = strtol(opt, &endptr, 10);
-                               if (*endptr != '\0') {
-                                       fprintf(stderr, "error: wrong option '-m %s'\n",  opt);
-                                       argument_errors = true;
-                               }
-                               if (value != 16 && value != 32 && value != 64) {
-                                       fprintf(stderr, "error: option -m supports only 16, 32 or 64\n");
-                                       argument_errors = true;
+                               if(strncmp(opt, "arch=", 5) == 0) {
+                                       GET_ARG_AFTER(opt, "-march=");
+                                       snprintf(arch_opt, sizeof(arch_opt), "%s-arch=%s", cpu_arch, opt);
+                                       int res = firm_be_option(arch_opt);
+                                       if (res == 0)
+                                               argument_errors = true;
+                                       else {
+                                               snprintf(arch_opt, sizeof(arch_opt), "%s-opt=%s", cpu_arch, opt);
+                                               int res = firm_be_option(arch_opt);
+                                               if (res == 0)
+                                                       argument_errors = true;
+                                       }
+                               } else if(strncmp(opt, "tune=", 5) == 0) {
+                                       GET_ARG_AFTER(opt, "-mtune=");
+                                       snprintf(arch_opt, sizeof(arch_opt), "%s-opt=%s", cpu_arch, opt);
+                                       int res = firm_be_option(arch_opt);
+                                       if (res == 0)
+                                               argument_errors = true;
+                               } else if(strncmp(opt, "cpu=", 4) == 0) {
+                                       GET_ARG_AFTER(opt, "-mcpu=");
+                                       snprintf(arch_opt, sizeof(arch_opt), "%s-arch=%s", cpu_arch, opt);
+                                       int res = firm_be_option(arch_opt);
+                                       if (res == 0)
+                                               argument_errors = true;
+                               } else if(strncmp(opt, "fpmath=", 7) == 0) {
+                                       GET_ARG_AFTER(opt, "-mfpmath=");
+                                       if(strcmp(opt, "387") == 0)
+                                               opt = "x87";
+                                       else if(strcmp(opt, "sse") == 0)
+                                               opt = "sse2";
+                                       else {
+                                               fprintf(stderr, "error: option -mfpumath supports only 387 or sse\n");
+                                               argument_errors = true;
+                                       }
+                                       if(!argument_errors) {
+                                               snprintf(arch_opt, sizeof(arch_opt), "%s-fpunit=%s", cpu_arch, opt);
+                                               int res = firm_be_option(arch_opt);
+                                               if (res == 0)
+                                                       argument_errors = true;
+                                       }
+                               } else if(strncmp(opt, "preferred-stack-boundary=", 25) == 0) {
+                                       GET_ARG_AFTER(opt, "-mpreferred-stack-boundary=");
+                                       snprintf(arch_opt, sizeof(arch_opt), "%s-stackalign=%s", cpu_arch, opt);
+                                       int res = firm_be_option(arch_opt);
+                                       if (res == 0)
+                                               argument_errors = true;
+                               } else if(strcmp(opt, "omit-leaf-frame-pointer") == 0) {
+                                       int res = firm_be_option("omitleaffp=1");
+                                       if (res == 0)
+                                               argument_errors = true;
+                               } else if(strcmp(opt, "no-omit-leaf-frame-pointer") == 0) {
+                                       int res = firm_be_option("omitleaffp=0");
+                                       if (res == 0)
+                                               argument_errors = true;
                                } else {
-                                       machine_size = (unsigned int)value;
+                                       char *endptr;
+                                       long int value = strtol(opt, &endptr, 10);
+                                       if (*endptr != '\0') {
+                                               fprintf(stderr, "error: wrong option '-m %s'\n",  opt);
+                                               argument_errors = true;
+                                       }
+                                       if (value != 16 && value != 32 && value != 64) {
+                                               fprintf(stderr, "error: option -m supports only 16, 32 or 64\n");
+                                               argument_errors = true;
+                                       } else {
+                                               machine_size = (unsigned int)value;
+                                       }
                                }
                        } else if (option[0] == '\0') {
                                if(input != NULL) {
@@ -500,10 +622,24 @@ int main(int argc, char **argv)
                                } else {
                                        input = arg;
                                }
+                       } else if(strcmp(option, "pg") == 0) {
+                               firm_be_option("-b gprof");
+                               obstack_printf(&ldflags_obst, " -pg");
                        } else if(strcmp(option, "pedantic") == 0) {
                                fprintf(stderr, "warning: ignoring gcc option '%s'\n", arg);
                        } else if(strncmp(option, "std=", 4) == 0) {
-                               fprintf(stderr, "warning: ignoring gcc option '%s'\n", arg);
+                               if(strcmp(&option[4], "c99") == 0) {
+                                       c_mode = _C89|_C99;
+                               } else if(strcmp(&option[4], "c89") == 0) {
+                                       c_mode = _C89;
+                               } else if(strcmp(&option[4], "gnu99") == 0) {
+                                       c_mode = _C89|_C99|_GNUC;
+                               } else if(strcmp(&option[4], "microsoft") == 0) {
+                                       c_mode = _C89|_C99|_MS;
+                               } else
+                                       fprintf(stderr, "warning: ignoring gcc option '%s'\n", arg);
+                       } else if(strcmp(option, "version") == 0) {
+                               print_cparser_version();
                        } else if (option[0] == '-') {
                                /* double dash option */
                                ++option;
@@ -534,18 +670,7 @@ int main(int argc, char **argv)
                                } else if(strcmp(option, "print-fluffy") == 0) {
                                        mode = PrintFluffy;
                                } else if(strcmp(option, "version") == 0) {
-                                       firm_version_t ver;
-                                       firm_get_version(&ver);
-                                       printf("cparser (%d.%d %s) using libFirm (%u.%u", 0, 1, cparser_REVISION, ver.major, ver.minor);
-                                       if(ver.revision[0] != 0) {
-                                               putchar(' ');
-                                               fputs(ver.revision, stdout);
-                                       }
-                                       if(ver.build[0] != 0) {
-                                               putchar(' ');
-                                               fputs(ver.build, stdout);
-                                       }
-                                       puts(")\n");
+                                       print_cparser_version();
                                        exit(EXIT_SUCCESS);
                                } else if(strcmp(option, "dump-function") == 0) {
                                        ++i;
@@ -566,22 +691,47 @@ int main(int argc, char **argv)
                                argument_errors = true;
                        }
                } else {
-                       if(input != NULL) {
-                               fprintf(stderr, "error: multiple input files specified\n");
-                               argument_errors = true;
+
+                       size_t len = strlen(arg);
+                       if (len < 2) {
+                               fprintf(stderr, "'%s': file format not recognized\n", input);
+                               continue;
+                       }
+
+                       file_list_entry_t *entry
+                               = obstack_alloc(&file_obst, sizeof(entry[0]));
+                       entry->filename = arg;
+                       if (strcmp(arg+len-2, ".c") == 0) {
+                               entry->next = c_files;
+                               c_files     = entry;
+                       } else if (strcmp(arg+len-2, ".s") == 0) {
+                               entry->next = s_files;
+                               s_files     = entry;
+                       } else if (strcmp(arg+len-2, ".o") == 0) {
+                               entry->next = o_files;
+                               o_files     = entry;
                        } else {
-                               input = arg;
+                               fprintf(stderr, "'%s': file format not recognized\n", input);
                        }
                }
        }
 
+       if (c_files == NULL && s_files == NULL && o_files != NULL) {
+               mode = Link;
+       } else if (c_files != NULL && c_files->next == NULL) {
+               input = c_files->filename;
+       } else {
+               fprintf(stderr, "error: multiple input files specified\n");
+               argument_errors = true;
+       }
+
        /* we do the lowering in ast2firm */
        firm_opt.lower_bitfields = FALSE;
 
-       if(help_displayed) {
+       if (help_displayed) {
                return !argument_errors;
        }
-       if(argument_errors) {
+       if (argument_errors) {
                usage(argv[0]);
                return 1;
        }
@@ -608,6 +758,8 @@ int main(int argc, char **argv)
                        if(outname == NULL)
                                outname = "-";
                        break;
+               case PreprocessOnly:
+                       break;
                case ParseOnly:
                        break;
                case Compile:
@@ -623,12 +775,43 @@ int main(int argc, char **argv)
                                        ".vcg");
                        outname = outnamebuf;
                        break;
+               case Link:
                case CompileAssembleLink:
+#ifdef _WIN32
+                       /* Windows compiler typically derive the output name from
+                          the first source file */
+                       get_output_name(outnamebuf, sizeof(outnamebuf), input, ".exe");
+                       outname = outnamebuf;
+#else
                        outname = "a.out";
+#endif
                        break;
                }
        }
 
+       if (mode == Link) {
+               obstack_1grow(&ldflags_obst, '\0');
+               const char *flags = obstack_finish(&ldflags_obst);
+
+               obstack_printf(&file_obst, LINKER " %s -o %s", flags, outname);
+
+               for (file_list_entry_t *entry = o_files; entry != NULL;
+                               entry = entry->next) {
+                       obstack_printf(&file_obst, " %s", entry->filename);
+               }
+               char *buf = obstack_finish(&file_obst);
+
+               if(verbose) {
+                       puts(buf);
+               }
+               int err = system(buf);
+               if(err != 0) {
+                       fprintf(stderr, "linker reported an error\n");
+                       exit(1);
+               }
+               return 0;
+       }
+
        if(outname != NULL) {
                if(strcmp(outname, "-") == 0) {
                        out = stdout;
@@ -663,31 +846,37 @@ int main(int argc, char **argv)
                return 0;
        }
 
-       FILE *preprocessed_in = preprocess(in, input);
+       FILE *preprocessed_in = preprocess(in, input, mode == PreprocessOnly);
        translation_unit_t *const unit = do_parsing(preprocessed_in, input);
-       int result = pclose(preprocessed_in);
-       if(result != 0) {
-               return result;
+       int res = pclose(preprocessed_in);
+       if(res != 0) {
+               return res;
        }
-       if(unit == NULL) {
+
+       if(error_count > 0) {
                /* parsing failed because of errors */
                fprintf(stderr, "%u error(s), %u warning(s)\n", error_count, warning_count);
-               return EXIT_FAILURE;
-       }
-       if (warning_count > 0) {
+               result = EXIT_FAILURE;
+       } else if(warning_count > 0) {
                fprintf(stderr, "%u warning(s)\n", warning_count);
        }
 
        if(mode == BenchmarkParser) {
-               return 0;
+               return result;
        }
 
+       /* prints the AST even if errors occurred */
        if(mode == PrintAst) {
                type_set_output(out);
                ast_set_output(out);
                print_ast(unit);
-               return 0;
+               return result;
        }
+
+       /* cannot handle other modes with errors */
+       if(result != EXIT_SUCCESS)
+               return result;
+
        if(mode == PrintFluffy) {
                type_set_output(out);
                ast_set_output(out);
@@ -763,6 +952,7 @@ int main(int argc, char **argv)
 
        obstack_free(&cppflags_obst, NULL);
        obstack_free(&ldflags_obst, NULL);
+       obstack_free(&file_obst, NULL);
 
        exit_ast2firm();
        exit_parser();