use statev in cparser
[cparser] / main.c
1 /*
2  * This file is part of cparser.
3  * Copyright (C) 2007-2009 Matthias Braun <matze@braunis.de>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
18  * 02111-1307, USA.
19  */
20 #include <config.h>
21
22 #define _GNU_SOURCE
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <stdbool.h>
27 #include <errno.h>
28 #include <string.h>
29 #include <assert.h>
30
31 #ifdef _WIN32
32
33 #include <fcntl.h>
34 #include <io.h>
35
36 /* no eXecute on Win32 */
37 #define X_OK 0
38 #define W_OK 2
39 #define R_OK 4
40
41 #define O_RDWR          _O_RDWR
42 #define O_CREAT         _O_CREAT
43 #define O_EXCL          _O_EXCL
44 #define O_BINARY        _O_BINARY
45
46 /* remap some names, we are not in the POSIX world */
47 #define access(fname, mode)      _access(fname, mode)
48 #define mktemp(tmpl)             _mktemp(tmpl)
49 #define open(fname, oflag, mode) _open(fname, oflag, mode)
50 #define fdopen(fd, mode)         _fdopen(fd, mode)
51 #define popen(cmd, mode)         _popen(cmd, mode)
52 #define pclose(file)             _pclose(file)
53 #define unlink(filename)         _unlink(filename)
54
55 #else
56 #include <unistd.h>
57 #define HAVE_MKSTEMP
58 #endif
59
60 #include <libfirm/firm.h>
61 #include <libfirm/be.h>
62 #include <libfirm/statev.h>
63
64 #include "preprocessor.h"
65 #include "token_t.h"
66 #include "types.h"
67 #include "type_hash.h"
68 #include "parser.h"
69 #include "type_t.h"
70 #include "ast2firm.h"
71 #include "diagnostic.h"
72 #include "lang_features.h"
73 #include "driver/firm_opt.h"
74 #include "driver/firm_timing.h"
75 #include "driver/firm_machine.h"
76 #include "adt/error.h"
77 #include "adt/strutil.h"
78 #include "adt/array.h"
79 #include "wrappergen/write_fluffy.h"
80 #include "wrappergen/write_jna.h"
81 #include "wrappergen/write_compoundsizes.h"
82 #include "revision.h"
83 #include "warning.h"
84 #include "help.h"
85 #include "mangle.h"
86 #include "printer.h"
87
88 #ifndef PREPROCESSOR
89 #ifndef __WIN32__
90 #define PREPROCESSOR "gcc -E -U__STRICT_ANSI__ -U__BLOCKS__"
91 #else
92 #define PREPROCESSOR "cpp -U__STRICT_ANSI__"
93 #endif
94 #endif
95
96 #ifndef LINKER
97 #define LINKER    "gcc"
98 #endif
99
100 #ifndef ASSEMBLER
101 #define ASSEMBLER "gcc -c -xassembler"
102 #endif
103
104 unsigned int        c_mode                    = _C89 | _C99 | _GNUC;
105 bool                byte_order_big_endian     = false;
106 bool                strict_mode               = false;
107 bool                enable_main_collect2_hack = false;
108 bool                freestanding              = false;
109 unsigned            architecture_modulo_shift = 0;
110
111 static bool               char_is_signed      = true;
112 static atomic_type_kind_t wchar_atomic_kind   = ATOMIC_TYPE_INT;
113 static unsigned           features_on         = 0;
114 static unsigned           features_off        = 0;
115 static const char        *dumpfunction        = NULL;
116 static struct obstack     file_obst;
117 static const char        *external_preprocessor = PREPROCESSOR;
118
119 static machine_triple_t *target_machine;
120 static const char       *target_triple;
121 static int               verbose;
122 static struct obstack    cppflags_obst;
123 static struct obstack    ldflags_obst;
124 static struct obstack    asflags_obst;
125 static char              dep_target[1024];
126 static const char       *outname;
127 static bool              define_intmax_types;
128 static const char       *input_encoding;
129
130 typedef enum lang_standard_t {
131         STANDARD_DEFAULT, /* gnu99 (for C, GCC does gnu89) or gnu++98 (for C++) */
132         STANDARD_ANSI,    /* ISO C90 (for C) or ISO C++ 1998 (for C++) */
133         STANDARD_C89,     /* ISO C90 (sic) */
134         STANDARD_C89AMD1, /* ISO C90 as modified in amendment 1 */
135         STANDARD_C99,     /* ISO C99 */
136         STANDARD_C11,     /* ISO C11 */
137         STANDARD_GNU89,   /* ISO C90 plus GNU extensions (including some C99) */
138         STANDARD_GNU99,   /* ISO C99 plus GNU extensions */
139         STANDARD_GNU11,   /* ISO C11 plus GNU extensions */
140         STANDARD_CXX98,   /* ISO C++ 1998 plus amendments */
141         STANDARD_GNUXX98  /* ISO C++ 1998 plus amendments and GNU extensions */
142 } lang_standard_t;
143
144 typedef enum compilation_unit_type_t {
145         COMPILATION_UNIT_AUTODETECT,
146         COMPILATION_UNIT_C,
147         COMPILATION_UNIT_PREPROCESSED_C,
148         COMPILATION_UNIT_CXX,
149         COMPILATION_UNIT_PREPROCESSED_CXX,
150         COMPILATION_UNIT_AST,
151         COMPILATION_UNIT_INTERMEDIATE_REPRESENTATION,
152         COMPILATION_UNIT_ASSEMBLER,
153         COMPILATION_UNIT_PREPROCESSED_ASSEMBLER,
154         COMPILATION_UNIT_OBJECT,
155         COMPILATION_UNIT_IR,
156         COMPILATION_UNIT_UNKNOWN
157 } compilation_unit_type_t;
158
159 typedef struct compilation_unit_t compilation_unit_t;
160 struct compilation_unit_t {
161         const char             *name;  /**< filename or "-" for stdin */
162         FILE                   *input; /**< input (NULL if not opened yet) */
163         bool                    input_is_pipe;
164         compilation_unit_type_t type;
165         lang_standard_t         standard;
166         translation_unit_t     *ast;
167         bool                    parse_errors;
168         compilation_unit_t     *next;
169 };
170
171 static char **temp_files;
172
173 static void get_output_name(char *buf, size_t buflen, const char *inputname,
174                             const char *newext)
175 {
176         if (inputname == NULL)
177                 inputname = "a";
178
179         char const *const last_slash = strrchr(inputname, '/');
180         char const *const filename   =
181                 last_slash != NULL ? last_slash + 1 : inputname;
182         char const *const last_dot   = strrchr(filename, '.');
183         char const *const name_end   =
184                 last_dot != NULL ? last_dot : strchr(filename, '\0');
185
186         int const len = snprintf(buf, buflen, "%.*s%s",
187                         (int)(name_end - filename), filename, newext);
188 #ifdef _WIN32
189         if (len < 0 || buflen <= (size_t)len)
190 #else
191         if (buflen <= (size_t)len)
192 #endif
193                 panic("filename too long");
194 }
195
196 static bool close_input(compilation_unit_t *unit)
197 {
198         assert(unit->input);
199         bool res;
200         if (unit->input == stdin) {
201                 res = true;
202         } else if (unit->input_is_pipe) {
203                 res = pclose(unit->input) == EXIT_SUCCESS;
204         } else {
205                 fclose(unit->input);
206                 res = true;
207         }
208         unit->input = NULL;
209         unit->name  = NULL;
210         return res;
211 }
212
213 static void print_error_summary(void)
214 {
215         if (error_count > 0) {
216                 /* parsing failed because of errors */
217                 fprintf(stderr, "%u error(s), %u warning(s)\n", error_count,
218                                 warning_count);
219         } else if (warning_count > 0) {
220                 fprintf(stderr, "%u warning(s)\n", warning_count);
221         }
222 }
223
224 static void do_parsing(compilation_unit_t *unit)
225 {
226         ir_timer_t *t_parsing = ir_timer_new();
227         timer_register(t_parsing, "Frontend: Parsing");
228         timer_start(t_parsing);
229
230         start_parsing();
231
232         switch_pp_input(unit->input, unit->name, NULL, false);
233         parse();
234         unit->ast = finish_parsing();
235         check_unclosed_conditionals();
236         close_pp_input();
237         bool res = close_input(unit);
238
239         print_error_summary();
240
241         unit->type         = COMPILATION_UNIT_AST;
242         unit->parse_errors = error_count > 0 || !res;
243         timer_stop(t_parsing);
244         if (stat_ev_enabled) {
245                 stat_ev_dbl("time_parsing", ir_timer_elapsed_sec(t_parsing));
246         }
247 }
248
249 static void add_flag(struct obstack *obst, const char *format, ...)
250 {
251         char buf[65536];
252         va_list ap;
253
254         va_start(ap, format);
255 #ifdef _WIN32
256         int len =
257 #endif
258                 vsnprintf(buf, sizeof(buf), format, ap);
259         va_end(ap);
260
261         obstack_1grow(obst, ' ');
262 #ifdef _WIN32
263         obstack_1grow(obst, '"');
264         obstack_grow(obst, buf, len);
265         obstack_1grow(obst, '"');
266 #else
267         /* escape stuff... */
268         for (char *c = buf; *c != '\0'; ++c) {
269                 switch(*c) {
270                 case ' ':
271                 case '"':
272                 case '$':
273                 case '&':
274                 case '(':
275                 case ')':
276                 case ';':
277                 case '<':
278                 case '>':
279                 case '\'':
280                 case '\\':
281                 case '\n':
282                 case '\r':
283                 case '\t':
284                 case '`':
285                 case '|':
286                         obstack_1grow(obst, '\\');
287                         /* FALLTHROUGH */
288                 default:
289                         obstack_1grow(obst, *c);
290                         break;
291                 }
292         }
293 #endif
294 }
295
296 static const char *type_to_string(type_t *type)
297 {
298         assert(type->kind == TYPE_ATOMIC);
299         return get_atomic_kind_name(type->atomic.akind);
300 }
301
302 static char const* str_lang_standard(lang_standard_t const standard)
303 {
304         switch (standard) {
305         case STANDARD_C89:     return "c89";
306         case STANDARD_C89AMD1: return "iso9899:199409";
307         case STANDARD_C99:     return "c99";
308         case STANDARD_C11:     return "c11";
309         case STANDARD_GNU89:   return "gnu89";
310         case STANDARD_GNU99:   return "gnu99";
311         case STANDARD_GNU11:   return "gnu11";
312         case STANDARD_CXX98:   return "c++98";
313         case STANDARD_GNUXX98: return "gnu++98";
314         case STANDARD_ANSI:    break;
315         case STANDARD_DEFAULT: break;
316         }
317         panic("invalid standard");
318 }
319
320 static bool run_external_preprocessor(compilation_unit_t *unit)
321 {
322         static const char *common_flags = NULL;
323
324         if (common_flags == NULL) {
325                 obstack_1grow(&cppflags_obst, '\0');
326                 const char *flags = obstack_finish(&cppflags_obst);
327
328                 /* setup default defines */
329                 add_flag(&cppflags_obst, "-U__WCHAR_TYPE__");
330                 add_flag(&cppflags_obst, "-D__WCHAR_TYPE__=%s", type_to_string(type_wchar_t));
331                 add_flag(&cppflags_obst, "-U__SIZE_TYPE__");
332                 add_flag(&cppflags_obst, "-D__SIZE_TYPE__=%s", type_to_string(type_size_t));
333
334                 add_flag(&cppflags_obst, "-U__VERSION__");
335                 add_flag(&cppflags_obst, "-D__VERSION__=\"%s\"", cparser_REVISION);
336
337                 if (define_intmax_types) {
338                         add_flag(&cppflags_obst, "-U__INTMAX_TYPE__");
339                         add_flag(&cppflags_obst, "-D__INTMAX_TYPE__=%s", type_to_string(type_intmax_t));
340                         add_flag(&cppflags_obst, "-U__UINTMAX_TYPE__");
341                         add_flag(&cppflags_obst, "-D__UINTMAX_TYPE__=%s", type_to_string(type_uintmax_t));
342                 }
343
344                 if (flags[0] != '\0') {
345                         size_t len = strlen(flags);
346                         obstack_1grow(&cppflags_obst, ' ');
347                         obstack_grow(&cppflags_obst, flags, len);
348                 }
349                 obstack_1grow(&cppflags_obst, '\0');
350                 common_flags = obstack_finish(&cppflags_obst);
351         }
352
353         assert(obstack_object_size(&cppflags_obst) == 0);
354
355         const char *preprocessor = getenv("CPARSER_PP");
356         if (preprocessor != NULL) {
357                 obstack_printf(&cppflags_obst, "%s ", preprocessor);
358         } else {
359                 if (target_triple != NULL)
360                         obstack_printf(&cppflags_obst, "%s-", target_triple);
361                 obstack_printf(&cppflags_obst, "%s", external_preprocessor);
362         }
363
364         char const *lang;
365         switch (unit->type) {
366         case COMPILATION_UNIT_C:         lang = "c";                  break;
367         case COMPILATION_UNIT_CXX:       lang = "c++";                break;
368         case COMPILATION_UNIT_ASSEMBLER: lang = "assembler-with-cpp"; break;
369         default:                         lang = NULL;                 break;
370         }
371         if (lang)
372                 add_flag(&cppflags_obst, "-x%s", lang);
373
374         add_flag(&cppflags_obst, "-std=%s", str_lang_standard(unit->standard));
375
376         obstack_printf(&cppflags_obst, "%s", common_flags);
377
378         /* handle dependency generation */
379         if (dep_target[0] != '\0') {
380                 add_flag(&cppflags_obst, "-MF");
381                 add_flag(&cppflags_obst, dep_target);
382                 if (outname != NULL) {
383                         add_flag(&cppflags_obst, "-MQ");
384                         add_flag(&cppflags_obst, outname);
385                 }
386         }
387         assert(unit->input == NULL);
388         add_flag(&cppflags_obst, unit->name);
389         obstack_1grow(&cppflags_obst, '\0');
390
391         char *commandline = obstack_finish(&cppflags_obst);
392         if (verbose) {
393                 puts(commandline);
394         }
395         FILE *f = popen(commandline, "r");
396         if (f == NULL) {
397                 fprintf(stderr, "invoking preprocessor failed\n");
398                 return false;
399         }
400         /* we do not really need that anymore */
401         obstack_free(&cppflags_obst, commandline);
402
403         unit->input         = f;
404         unit->input_is_pipe = true;
405         switch (unit->type) {
406         case COMPILATION_UNIT_ASSEMBLER:
407                 unit->type = COMPILATION_UNIT_PREPROCESSED_ASSEMBLER;
408                 break;
409         case COMPILATION_UNIT_C:
410                 unit->type = COMPILATION_UNIT_PREPROCESSED_C;
411                 break;
412         case COMPILATION_UNIT_CXX:
413                 unit->type = COMPILATION_UNIT_PREPROCESSED_CXX;
414                 break;
415         default:
416                 unit->type = COMPILATION_UNIT_UNKNOWN;
417                 break;
418         }
419
420         return true;
421 }
422
423 static void assemble(const char *out, const char *in)
424 {
425         obstack_1grow(&asflags_obst, '\0');
426         const char *flags = obstack_finish(&asflags_obst);
427
428         const char *assembler = getenv("CPARSER_AS");
429         if (assembler != NULL) {
430                 obstack_printf(&asflags_obst, "%s", assembler);
431         } else {
432                 if (target_triple != NULL)
433                         obstack_printf(&asflags_obst, "%s-", target_triple);
434                 obstack_printf(&asflags_obst, "%s", ASSEMBLER);
435         }
436         if (flags[0] != '\0')
437                 obstack_printf(&asflags_obst, " %s", flags);
438
439         obstack_printf(&asflags_obst, " %s -o %s", in, out);
440         obstack_1grow(&asflags_obst, '\0');
441
442         char *commandline = obstack_finish(&asflags_obst);
443         if (verbose) {
444                 puts(commandline);
445         }
446         int err = system(commandline);
447         if (err != EXIT_SUCCESS) {
448                 fprintf(stderr, "assembler reported an error\n");
449                 exit(EXIT_FAILURE);
450         }
451         obstack_free(&asflags_obst, commandline);
452 }
453
454 static void print_file_name(const char *file)
455 {
456         add_flag(&ldflags_obst, "-print-file-name=%s", file);
457
458         obstack_1grow(&ldflags_obst, '\0');
459         const char *flags = obstack_finish(&ldflags_obst);
460
461         /* construct commandline */
462         const char *linker = getenv("CPARSER_LINK");
463         if (linker != NULL) {
464                 obstack_printf(&ldflags_obst, "%s ", linker);
465         } else {
466                 if (target_triple != NULL)
467                         obstack_printf(&ldflags_obst, "%s-", target_triple);
468                 obstack_printf(&ldflags_obst, "%s ", LINKER);
469         }
470         obstack_printf(&ldflags_obst, "%s ", linker);
471         obstack_printf(&ldflags_obst, "%s", flags);
472         obstack_1grow(&ldflags_obst, '\0');
473
474         char *commandline = obstack_finish(&ldflags_obst);
475         if (verbose) {
476                 puts(commandline);
477         }
478         int err = system(commandline);
479         if (err != EXIT_SUCCESS) {
480                 fprintf(stderr, "linker reported an error\n");
481                 exit(EXIT_FAILURE);
482         }
483         obstack_free(&ldflags_obst, commandline);
484 }
485
486 static const char *try_dir(const char *dir)
487 {
488         if (dir == NULL)
489                 return dir;
490         if (access(dir, R_OK | W_OK | X_OK) == 0)
491                 return dir;
492         return NULL;
493 }
494
495 static const char *get_tempdir(void)
496 {
497         static const char *tmpdir = NULL;
498
499         if (tmpdir != NULL)
500                 return tmpdir;
501
502         if (tmpdir == NULL)
503                 tmpdir = try_dir(getenv("TMPDIR"));
504         if (tmpdir == NULL)
505                 tmpdir = try_dir(getenv("TMP"));
506         if (tmpdir == NULL)
507                 tmpdir = try_dir(getenv("TEMP"));
508
509 #ifdef P_tmpdir
510         if (tmpdir == NULL)
511                 tmpdir = try_dir(P_tmpdir);
512 #endif
513
514         if (tmpdir == NULL)
515                 tmpdir = try_dir("/var/tmp");
516         if (tmpdir == NULL)
517                 tmpdir = try_dir("/usr/tmp");
518         if (tmpdir == NULL)
519                 tmpdir = try_dir("/tmp");
520
521         if (tmpdir == NULL)
522                 tmpdir = ".";
523
524         return tmpdir;
525 }
526
527 #ifndef HAVE_MKSTEMP
528 /* cheap and nasty mkstemp replacement */
529 static int mkstemp(char *templ)
530 {
531         mktemp(templ);
532         return open(templ, O_RDWR|O_CREAT|O_EXCL|O_BINARY, 0600);
533 }
534 #endif
535
536 /**
537  * custom version of tmpnam, which: writes to an obstack, emits no warnings
538  * during linking (like glibc/gnu ld do for tmpnam)...
539  */
540 static FILE *make_temp_file(const char *prefix, const char **name_result)
541 {
542         const char *tempdir = get_tempdir();
543         assert(obstack_object_size(&file_obst) == 0);
544         obstack_printf(&file_obst, "%s/%sXXXXXX", tempdir, prefix);
545         obstack_1grow(&file_obst, '\0');
546
547         char *name = obstack_finish(&file_obst);
548         int fd = mkstemp(name);
549         if (fd == -1) {
550                 fprintf(stderr, "could not create temporary file: %s\n",
551                         strerror(errno));
552                 return NULL;
553         }
554         FILE *out = fdopen(fd, "w");
555         if (out == NULL) {
556                 fprintf(stderr, "could not open temporary file as FILE*\n");
557                 return NULL;
558         }
559
560         ARR_APP1(char*, temp_files, name);
561         *name_result = name;
562         return out;
563 }
564
565 static void free_temp_files(void)
566 {
567         if (temp_files == NULL)
568                 return;
569
570         size_t n_temp_files = ARR_LEN(temp_files);
571         size_t i;
572         for (i = 0; i < n_temp_files; ++i) {
573                 char *file = temp_files[i];
574                 unlink(file);
575         }
576         DEL_ARR_F(temp_files);
577         temp_files = NULL;
578 }
579
580 typedef enum compile_mode_t {
581         BenchmarkParser,
582         PreprocessOnly,
583         ParseOnly,
584         Compile,
585         CompileDump,
586         CompileExportIR,
587         CompileAssemble,
588         CompileAssembleLink,
589         PrintAst,
590         PrintFluffy,
591         PrintJna,
592         PrintCompoundSizes,
593 } compile_mode_t;
594
595 static void usage(const char *argv0)
596 {
597         fprintf(stderr, "Usage %s [options] input [-o output]\n", argv0);
598 }
599
600 static void print_cparser_version(void)
601 {
602         printf("cparser (%s) using libFirm (%u.%u",
603                cparser_REVISION, ir_get_version_major(),
604                ir_get_version_minor());
605
606         const char *revision = ir_get_version_revision();
607         if (revision[0] != 0) {
608                 putchar('-');
609                 fputs(revision, stdout);
610         }
611
612         const char *build = ir_get_version_build();
613         if (build[0] != 0) {
614                 putchar(' ');
615                 fputs(build, stdout);
616         }
617         puts(")");
618         puts("This is free software; see the source for copying conditions.  There is NO\n"
619              "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
620 }
621
622 static void print_cparser_version_short(void)
623 {
624         puts(cparser_REVISION);
625 }
626
627 static void print_help_basic(const char *argv0)
628 {
629         usage(argv0);
630         puts("");
631         put_help("--help",                   "Display this information");
632         put_help("--version",                "Display compiler version");
633         put_help("--help-parser",            "Display information about parser options");
634         put_help("--help-warnings",          "Display information about warning options");
635         put_help("--help-codegen",           "Display information about code-generation options");
636         put_help("--help-optimization",      "Display information about optimization options");
637         put_help("--help-linker",            "Display information about linker options");
638         put_help("--help-language-tools",    "Display information about language tools options");
639         put_help("--help-debug",             "Display information about compiler debugging options");
640         put_help("--help-firm",              "Display information about direct firm options");
641         put_help("--help-all",               "Display information about all options");
642         put_help("-c",                       "Compile and assemble but do not link");
643         put_help("-E",                       "Preprocess only");
644         put_help("-S",                       "Compile but do not assembler or link");
645         put_help("-o",                       "Specify output file");
646         put_help("-v",                       "Verbose output (show invocation of sub-processes)");
647         put_help("-x",                       "Force input language:");
648         put_choice("c",                      "C");
649         put_choice("c++",                    "C++");
650         put_choice("assembler",              "Assembler (no preprocessing)");
651         put_choice("assembler-with-cpp",     "Assembler with preprocessing");
652         put_choice("none",                   "Autodetection");
653         put_help("-pipe",                    "Ignored (gcc compatibility)");
654 }
655
656 static void print_help_preprocessor(void)
657 {
658         put_help("-nostdinc",                "Do not search standard system include directories");
659         put_help("-trigraphs",               "Support ISO C trigraphs");
660         put_help("-isystem",                 "");
661         put_help("-include",                 "");
662         put_help("-I PATH",                  "");
663         put_help("-D SYMBOL[=value]",        "");
664         put_help("-U SYMBOL",                "");
665         put_help("-Wp,OPTION",               "Pass option directly to preprocessor");
666         put_help("-M",                       "");
667         put_help("-MD",                      "");
668         put_help("-MMD",                     "");
669         put_help("-MM",                      "");
670         put_help("-MP",                      "");
671         put_help("-MT",                      "");
672         put_help("-MQ",                      "");
673         put_help("-MF",                      "");
674 }
675
676 static void print_help_parser(void)
677 {
678         put_help("-finput-charset=CHARSET",  "Select encoding of input files");
679         put_help("-fmessage-length=LEN",     "Ignored (gcc compatibility)");
680         put_help("-fshort-wchar",            "Type \"wchar_t\" is unsigned short instead of int");
681         put_help("-fshow-column",            "Show the column number in diagnostic messages");
682         put_help("-fsigned-char",            "Type \"char\" is a signed type");
683         put_help("-funsigned-char",          "Type \"char\" is an unsigned type");
684         put_help("--ms",                     "Enable msvc extensions");
685         put_help("--no-ms",                  "Disable msvc extensions");
686         put_help("--gcc",                    "Enable gcc extensions");
687         put_help("--no-gcc",                 "Disable gcc extensions");
688         put_help("-std=STANDARD",            "Specify language standard:");
689         put_choice("c99",                    "ISO C99 standard");
690         put_choice("c89",                    "ISO C89 standard");
691         put_choice("c90",                    "Same as -std=c89");
692         put_choice("c11",                    "ISO C11 standard");
693         put_choice("c9x",                    "Deprecated");
694         put_choice("c++",                    "ISO C++ 98");
695         put_choice("c++98",                  "ISO C++ 98");
696         put_choice("gnu99",                  "ISO C99 + GNU extensions (default)");
697         put_choice("gnu89",                  "ISO C89 + GNU extensions");
698         put_choice("gnu11",                  "ISO C11 + GNU extensions");
699         put_choice("gnu9x",                  "Deprecated");
700         put_choice("iso9899:1990",           "ISO C89");
701         put_choice("iso9899:199409",         "ISO C90");
702         put_choice("iso9899:1999",           "ISO C99");
703         put_choice("iso9899:199x",           "Deprecated");
704         put_help("-pedantic",                "Ignored (gcc compatibility)");
705         put_help("-ansi",                    "-std=c90 (for C) or -std=c++98 (for C++)");
706         put_help("--strict",                 "Enable strict conformance checking");
707 }
708
709 static void print_help_warnings(void)
710 {
711         put_help("-f[no-]diagnostics-show-option", "Show the switch, which controls a warning, after each warning");
712         put_help("-w",                             "Disable all warnings");
713         put_help("-Wno-trigraphs",                 "Warn if input contains trigraphs");
714         put_help("-Wundef",                        "Warn if an undefined macro is used in an #if");
715         put_help("-Wmissing-include-dirs",         "Warn about missing user-specified include directories");
716         put_help("-Wendif-labels",                 "Warn about stray text after #elif and #endif");
717         put_help("-Winit-self",                    "Ignored (gcc compatibility)");
718         put_help("-Wformat-y2k",                   "Ignored (gcc compatibility)");
719         put_help("-Wformat-security",              "Ignored (gcc compatibility)");
720         put_help("-Wold-style-declaration",        "Ignored (gcc compatibility)");
721         put_help("-Wtype-limits",                  "Ignored (gcc compatibility)");
722         print_warning_opt_help();
723 }
724
725 static void print_help_optimization(void)
726 {
727         put_help("-O LEVEL",                 "Select optimization level (0-4)");
728         firm_option_help(put_help);
729         put_help("-fexpensive-optimizations","Ignored (gcc compatibility)");
730 }
731
732 static void print_help_codegeneration(void)
733 {
734         put_help("-g",                       "Generate debug information");
735         put_help("-pg",                      "Instrument code for gnu gprof");
736         put_help("-fomit-frame-pointer",     "Produce code without frame pointer where possible");
737         put_help("-ffreestanding",           "Compile in freestanding mode (see ISO C standard)");
738         put_help("-fhosted",                 "Compile in hosted (not freestanding) mode");
739         put_help("-fprofile-generate",       "Generate instrumented code to collect profile information");
740         put_help("-fprofile-use",            "Use profile information generated by instrumented binaries");
741         put_help("-ffp-precise",             "Precise floating point model");
742         put_help("-ffp-fast",                "Imprecise floating point model");
743         put_help("-ffp-strict",              "Strict floating point model");
744         put_help("-pthread",                 "Use pthread threading library");
745         put_help("-mtarget=TARGET",          "Specify target architecture as CPU-manufacturer-OS triple");
746         put_help("-mtriple=TARGET",          "Alias for -mtarget (clang compatibility)");
747         put_help("-march=ARCH",              "");
748         put_help("-mtune=ARCH",              "");
749         put_help("-mcpu=CPU",                "");
750         put_help("-mfpmath=",                "");
751         put_help("-mpreferred-stack-boundary=", "");
752         put_help("-mrtd",                    "");
753         put_help("-mregparm=",               "Not supported yet");
754         put_help("-msoft-float",             "Not supported yet");
755         put_help("-m32",                     "Generate 32bit code");
756         put_help("-m64",                     "Generate 64bit code");
757         put_help("-fverbose-asm",            "Ignored (gcc compatibility)");
758         put_help("-fjump-tables",            "Ignored (gcc compatibility)");
759         put_help("-fcommon",                 "Ignored (gcc compatibility)");
760         put_help("-foptimize-sibling-calls", "Ignored (gcc compatibility)");
761         put_help("-falign-loops",            "Ignored (gcc compatibility)");
762         put_help("-falign-jumps",            "Ignored (gcc compatibility)");
763         put_help("-falign-functions",        "Ignored (gcc compatibility)");
764         put_help("-fPIC",                    "Ignored (gcc compatibility)");
765         put_help("-ffast-math",              "Same as -ffp-fast (gcc compatibility)");
766         puts("");
767         puts("\tMost of these options can be used with a no- prefix to disable them");
768         puts("\te.g. -fno-omit-frame-pointer");
769 }
770
771 static void print_help_linker(void)
772 {
773         put_help("-l LIBRARY",               "");
774         put_help("-L PATH",                  "");
775         put_help("-s",                       "Do not produce symbol table and relocation information");
776         put_help("-shared",                  "Produce a shared library");
777         put_help("-static",                  "Produce statically linked binary");
778         put_help("-Wl,OPTION",               "Pass option directly to linker");
779 }
780
781 static void print_help_debug(void)
782 {
783         put_help("--print-ast",              "Preprocess, parse and print AST");
784         put_help("--print-implicit-cast",    "");
785         put_help("--print-parenthesis",      "");
786         put_help("--benchmark",              "Preprocess and parse, produces no output");
787         put_help("--time",                   "Measure time of compiler passes");
788         put_help("--statev",                 "Produce statev output");
789         put_help("--filtev=filter",          "Set statev filter regex");
790         put_help("--dump-function func",     "Preprocess, parse and output vcg graph of func");
791         put_help("--export-ir",              "Preprocess, parse and output compiler intermediate representation");
792 }
793
794 static void print_help_language_tools(void)
795 {
796         put_help("--print-fluffy",           "Preprocess, parse and generate declarations for the fluffy language");
797         put_help("--print-jna",              "Preprocess, parse and generate declarations for JNA");
798         put_help("--jna-limit filename",     "");
799         put_help("--jna-libname name",       "");
800 }
801
802 static void print_help_firm(void)
803 {
804         put_help("-bOPTION",                 "Directly pass option to libFirm backend");
805         int res = be_parse_arg("help");
806         (void) res;
807         assert(res);
808 }
809
810 typedef enum {
811         HELP_NONE          = 0,
812         HELP_BASIC         = 1 << 0,
813         HELP_PREPROCESSOR  = 1 << 1,
814         HELP_PARSER        = 1 << 2,
815         HELP_WARNINGS      = 1 << 3,
816         HELP_OPTIMIZATION  = 1 << 4,
817         HELP_CODEGEN       = 1 << 5,
818         HELP_LINKER        = 1 << 6,
819         HELP_LANGUAGETOOLS = 1 << 7,
820         HELP_DEBUG         = 1 << 8,
821         HELP_FIRM          = 1 << 9,
822
823         HELP_ALL           = -1
824 } help_sections_t;
825
826 static void print_help(const char *argv0, help_sections_t sections)
827 {
828         if (sections & HELP_BASIC)         print_help_basic(argv0);
829         if (sections & HELP_PREPROCESSOR)  print_help_preprocessor();
830         if (sections & HELP_PARSER)        print_help_parser();
831         if (sections & HELP_WARNINGS)      print_help_warnings();
832         if (sections & HELP_OPTIMIZATION)  print_help_optimization();
833         if (sections & HELP_CODEGEN)       print_help_codegeneration();
834         if (sections & HELP_LINKER)        print_help_linker();
835         if (sections & HELP_LANGUAGETOOLS) print_help_language_tools();
836         if (sections & HELP_DEBUG)         print_help_debug();
837         if (sections & HELP_FIRM)          print_help_firm();
838 }
839
840 static void set_be_option(const char *arg)
841 {
842         int res = be_parse_arg(arg);
843         (void) res;
844         assert(res);
845 }
846
847 static compilation_unit_type_t get_unit_type_from_string(const char *string)
848 {
849         if (streq(string, "c") || streq(string, "c-header"))
850                 return COMPILATION_UNIT_C;
851         if (streq(string, "c++") || streq(string, "c++-header"))
852                 return COMPILATION_UNIT_CXX;
853         if (streq(string, "assembler"))
854                 return COMPILATION_UNIT_PREPROCESSED_ASSEMBLER;
855         if (streq(string, "assembler-with-cpp"))
856                 return COMPILATION_UNIT_ASSEMBLER;
857         if (streq(string, "none"))
858                 return COMPILATION_UNIT_AUTODETECT;
859
860         return COMPILATION_UNIT_UNKNOWN;
861 }
862
863 static bool init_os_support(void)
864 {
865         wchar_atomic_kind         = ATOMIC_TYPE_INT;
866         enable_main_collect2_hack = false;
867         define_intmax_types       = false;
868
869         if (firm_is_unixish_os(target_machine)) {
870                 set_create_ld_ident(create_name_linux_elf);
871         } else if (firm_is_darwin_os(target_machine)) {
872                 set_create_ld_ident(create_name_macho);
873                 define_intmax_types = true;
874         } else if (firm_is_windows_os(target_machine)) {
875                 wchar_atomic_kind         = ATOMIC_TYPE_USHORT;
876                 enable_main_collect2_hack = true;
877                 set_create_ld_ident(create_name_win32);
878         } else {
879                 return false;
880         }
881
882         return true;
883 }
884
885 static bool parse_target_triple(const char *arg)
886 {
887         machine_triple_t *triple = firm_parse_machine_triple(arg);
888         if (triple == NULL) {
889                 fprintf(stderr, "Target-triple is not in the form 'cpu_type-manufacturer-operating_system'\n");
890                 return false;
891         }
892         target_machine = triple;
893         return true;
894 }
895
896 static unsigned decide_modulo_shift(unsigned type_size)
897 {
898         if (architecture_modulo_shift == 0)
899                 return 0;
900         if (type_size < architecture_modulo_shift)
901                 return architecture_modulo_shift;
902         return type_size;
903 }
904
905 static bool is_ia32_cpu(const char *architecture)
906 {
907         return streq(architecture, "i386")
908             || streq(architecture, "i486")
909             || streq(architecture, "i586")
910             || streq(architecture, "i686")
911             || streq(architecture, "i786");
912 }
913
914 static const char *setup_isa_from_tripel(const machine_triple_t *machine)
915 {
916         const char *cpu = machine->cpu_type;
917
918         if (is_ia32_cpu(cpu)) {
919                 return "ia32";
920         } else if (streq(cpu, "x86_64")) {
921                 return "amd64";
922         } else if (streq(cpu, "sparc")) {
923                 return "sparc";
924         } else if (streq(cpu, "arm")) {
925                 return "arm";
926         } else {
927                 fprintf(stderr, "Unknown cpu '%s' in target-triple\n", cpu);
928                 return NULL;
929         }
930 }
931
932 static const char *setup_target_machine(void)
933 {
934         if (!setup_firm_for_machine(target_machine))
935                 exit(1);
936
937         const char *isa = setup_isa_from_tripel(target_machine);
938
939         if (isa == NULL)
940                 exit(1);
941
942         init_os_support();
943
944         return isa;
945 }
946
947 /**
948  * initialize cparser type properties based on a firm type
949  */
950 static void set_typeprops_type(atomic_type_properties_t* props, ir_type *type)
951 {
952         props->size             = get_type_size_bytes(type);
953         props->alignment        = get_type_alignment_bytes(type);
954         props->struct_alignment = props->alignment;
955 }
956
957 /**
958  * Copy atomic type properties except the integer conversion rank
959  */
960 static void copy_typeprops(atomic_type_properties_t *dest,
961                            const atomic_type_properties_t *src)
962 {
963         dest->size             = src->size;
964         dest->alignment        = src->alignment;
965         dest->struct_alignment = src->struct_alignment;
966         dest->flags            = src->flags;
967 }
968
969 static void init_types_and_adjust(void)
970 {
971         const backend_params *be_params = be_get_backend_param();
972         unsigned machine_size = be_params->machine_size;
973         init_types(machine_size);
974
975         atomic_type_properties_t *props = atomic_type_properties;
976
977         /* adjust types as requested by target architecture */
978         ir_type *type_long_double = be_params->type_long_double;
979         if (type_long_double != NULL) {
980                 set_typeprops_type(&props[ATOMIC_TYPE_LONG_DOUBLE], type_long_double);
981                 atomic_modes[ATOMIC_TYPE_LONG_DOUBLE] = get_type_mode(type_long_double);
982         }
983
984         ir_type *type_long_long = be_params->type_long_long;
985         if (type_long_long != NULL)
986                 set_typeprops_type(&props[ATOMIC_TYPE_LONGLONG], type_long_long);
987
988         ir_type *type_unsigned_long_long = be_params->type_unsigned_long_long;
989         if (type_unsigned_long_long != NULL)
990                 set_typeprops_type(&props[ATOMIC_TYPE_ULONGLONG], type_unsigned_long_long);
991
992         /* operating system ABI specifics */
993         if (firm_is_darwin_os(target_machine)) {
994                 if (is_ia32_cpu(target_machine->cpu_type)) {
995                         props[ATOMIC_TYPE_LONGLONG].struct_alignment    =  4;
996                         props[ATOMIC_TYPE_ULONGLONG].struct_alignment   =  4;
997                         props[ATOMIC_TYPE_DOUBLE].struct_alignment      =  4;
998                         props[ATOMIC_TYPE_LONG_DOUBLE].size             = 16;
999                         props[ATOMIC_TYPE_LONG_DOUBLE].alignment        = 16;
1000                         props[ATOMIC_TYPE_LONG_DOUBLE].struct_alignment = 16;
1001                 }
1002         } else if (firm_is_windows_os(target_machine)) {
1003                 if (is_ia32_cpu(target_machine->cpu_type)) {
1004                         props[ATOMIC_TYPE_LONGLONG].struct_alignment    =  8;
1005                         props[ATOMIC_TYPE_ULONGLONG].struct_alignment   =  8;
1006                         props[ATOMIC_TYPE_DOUBLE].struct_alignment      =  8;
1007                 } else if (machine_size == 64) {
1008                         /* to ease porting of old c-code microsoft decided to use 32bits
1009                          * even for long */
1010                         props[ATOMIC_TYPE_LONG]  = props[ATOMIC_TYPE_INT];
1011                         props[ATOMIC_TYPE_ULONG] = props[ATOMIC_TYPE_UINT];
1012                 }
1013
1014                 /* on windows long double is not supported */
1015                 props[ATOMIC_TYPE_LONG_DOUBLE] = props[ATOMIC_TYPE_DOUBLE];
1016         } else if (firm_is_unixish_os(target_machine)) {
1017                 if (is_ia32_cpu(target_machine->cpu_type)) {
1018                         props[ATOMIC_TYPE_DOUBLE].struct_alignment    = 4;
1019                         props[ATOMIC_TYPE_LONGLONG].struct_alignment  = 4;
1020                         props[ATOMIC_TYPE_ULONGLONG].struct_alignment = 4;
1021                 }
1022         }
1023
1024         /* stuff decided after processing operating system specifics and
1025          * commandline flags */
1026         if (char_is_signed) {
1027                 props[ATOMIC_TYPE_CHAR].flags |= ATOMIC_TYPE_FLAG_SIGNED;
1028         } else {
1029                 props[ATOMIC_TYPE_CHAR].flags &= ~ATOMIC_TYPE_FLAG_SIGNED;
1030         }
1031         /* copy over wchar_t properties (including rank) */
1032         props[ATOMIC_TYPE_WCHAR_T] = props[wchar_atomic_kind];
1033
1034         /* initialize defaults for unsupported types */
1035         if (type_long_long == NULL) {
1036                 copy_typeprops(&props[ATOMIC_TYPE_LONGLONG], &props[ATOMIC_TYPE_LONG]);
1037         }
1038         if (type_unsigned_long_long == NULL) {
1039                 copy_typeprops(&props[ATOMIC_TYPE_ULONGLONG],
1040                                &props[ATOMIC_TYPE_ULONG]);
1041         }
1042         if (type_long_double == NULL) {
1043                 copy_typeprops(&props[ATOMIC_TYPE_LONG_DOUBLE],
1044                                &props[ATOMIC_TYPE_DOUBLE]);
1045         }
1046
1047         /* initialize firm pointer modes */
1048         char               name[64];
1049         unsigned           bit_size     = machine_size;
1050         unsigned           modulo_shift = decide_modulo_shift(bit_size);
1051
1052         snprintf(name, sizeof(name), "p%u", machine_size);
1053         ir_mode *ptr_mode = new_reference_mode(name, irma_twos_complement, bit_size, modulo_shift);
1054
1055         if (machine_size == 16) {
1056                 set_reference_mode_signed_eq(ptr_mode, mode_Hs);
1057                 set_reference_mode_unsigned_eq(ptr_mode, mode_Hu);
1058         } else if (machine_size == 32) {
1059                 set_reference_mode_signed_eq(ptr_mode, mode_Is);
1060                 set_reference_mode_unsigned_eq(ptr_mode, mode_Iu);
1061         } else if (machine_size == 64) {
1062                 set_reference_mode_signed_eq(ptr_mode, mode_Ls);
1063                 set_reference_mode_unsigned_eq(ptr_mode, mode_Lu);
1064         } else {
1065                 panic("strange machine_size when determining pointer modes");
1066         }
1067
1068         /* Hmm, pointers should be machine size */
1069         set_modeP_data(ptr_mode);
1070         set_modeP_code(ptr_mode);
1071
1072         byte_order_big_endian = be_params->byte_order_big_endian;
1073         if (be_params->modulo_shift_efficient) {
1074                 architecture_modulo_shift = machine_size;
1075         } else {
1076                 architecture_modulo_shift = 0;
1077         }
1078 }
1079
1080 static void setup_cmode(const compilation_unit_t *unit)
1081 {
1082         compilation_unit_type_t type     = unit->type;
1083         lang_standard_t         standard = unit->standard;
1084         if (type == COMPILATION_UNIT_PREPROCESSED_C || type == COMPILATION_UNIT_C) {
1085                 switch (standard) {
1086                 case STANDARD_C89:     c_mode = _C89;                       break;
1087                                                            /* TODO determine difference between these two */
1088                 case STANDARD_C89AMD1: c_mode = _C89;                       break;
1089                 case STANDARD_C99:     c_mode = _C89 | _C99;                break;
1090                 case STANDARD_C11:     c_mode = _C89 | _C99 | _C11;         break;
1091                 case STANDARD_GNU89:   c_mode = _C89 |               _GNUC; break;
1092                 case STANDARD_GNU11:   c_mode = _C89 | _C99 | _C11 | _GNUC; break;
1093
1094                 case STANDARD_ANSI:
1095                 case STANDARD_CXX98:
1096                 case STANDARD_GNUXX98:
1097                 case STANDARD_DEFAULT:
1098                         fprintf(stderr, "warning: command line option \"-std=%s\" is not valid for C\n", str_lang_standard(standard));
1099                         /* FALLTHROUGH */
1100                 case STANDARD_GNU99:   c_mode = _C89 | _C99 | _GNUC; break;
1101                 }
1102         } else if (type == COMPILATION_UNIT_PREPROCESSED_CXX
1103                    || type == COMPILATION_UNIT_CXX) {
1104                 switch (standard) {
1105                 case STANDARD_CXX98: c_mode = _CXX; break;
1106
1107                 case STANDARD_ANSI:
1108                 case STANDARD_C89:
1109                 case STANDARD_C89AMD1:
1110                 case STANDARD_C99:
1111                 case STANDARD_C11:
1112                 case STANDARD_GNU89:
1113                 case STANDARD_GNU99:
1114                 case STANDARD_GNU11:
1115                 case STANDARD_DEFAULT:
1116                         fprintf(stderr, "warning: command line option \"-std=%s\" is not valid for C++\n", str_lang_standard(standard));
1117                         /* FALLTHROUGH */
1118                 case STANDARD_GNUXX98: c_mode = _CXX | _GNUC; break;
1119                 }
1120         }
1121
1122         c_mode |= features_on;
1123         c_mode &= ~features_off;
1124 }
1125
1126 static void determine_unit_standard(compilation_unit_t *unit,
1127                                     lang_standard_t standard)
1128 {
1129         unit->standard = standard;
1130         switch (standard) {
1131         case STANDARD_ANSI:
1132                 switch (unit->type) {
1133                 case COMPILATION_UNIT_C:
1134                 case COMPILATION_UNIT_PREPROCESSED_C:
1135                         unit->standard = STANDARD_C89;
1136                         break;
1137                 case COMPILATION_UNIT_CXX:
1138                 case COMPILATION_UNIT_PREPROCESSED_CXX:
1139                         unit->standard = STANDARD_CXX98;
1140                         break;
1141                 default:
1142                         break;
1143                 }
1144                 break;
1145
1146         case STANDARD_DEFAULT:
1147                 switch (unit->type) {
1148                 case COMPILATION_UNIT_C:
1149                 case COMPILATION_UNIT_PREPROCESSED_C:
1150                         unit->standard = STANDARD_GNU99;
1151                         break;
1152                 case COMPILATION_UNIT_CXX:
1153                 case COMPILATION_UNIT_PREPROCESSED_CXX:
1154                         unit->standard = STANDARD_GNUXX98;
1155                         break;
1156                 default:
1157                         break;
1158                 }
1159                 break;
1160
1161         default:
1162                 break;
1163         }
1164 }
1165
1166 static bool output_preprocessor_tokens(compilation_unit_t *unit, FILE *out)
1167 {
1168         /* just here for gcc compatibility */
1169         fprintf(out, "# 1 \"%s\"\n", unit->name);
1170         fprintf(out, "# 1 \"<built-in>\"\n");
1171         fprintf(out, "# 1 \"<command-line>\"\n");
1172
1173         set_preprocessor_output(out);
1174         switch_pp_input(unit->input, unit->name, NULL, false);
1175
1176         for (;;) {
1177                 next_preprocessing_token();
1178                 if (pp_token.kind == T_EOF)
1179                         break;
1180                 emit_pp_token();
1181         }
1182
1183         fputc('\n', out);
1184         check_unclosed_conditionals();
1185         close_pp_input();
1186         print_error_summary();
1187         set_preprocessor_output(NULL);
1188
1189         if (unit->type == COMPILATION_UNIT_C) {
1190                 unit->type = COMPILATION_UNIT_PREPROCESSED_C;
1191         } else if (unit->type == COMPILATION_UNIT_CXX) {
1192                 unit->type = COMPILATION_UNIT_PREPROCESSED_CXX;
1193         }
1194         bool res = close_input(unit);
1195         return res && error_count == 0;
1196 }
1197
1198 static bool open_input(compilation_unit_t *unit)
1199 {
1200         /* input already available as FILE? */
1201         if (unit->input != NULL)
1202                 return true;
1203
1204         const char *const inputname = unit->name;
1205         unit->input_is_pipe = false;
1206         if (streq(inputname, "-")) {
1207                 unit->input   = stdin;
1208         } else {
1209                 unit->input = fopen(inputname, "r");
1210                 if (unit->input == NULL) {
1211                         fprintf(stderr, "Could not open '%s': %s\n", inputname,
1212                                         strerror(errno));
1213                         return false;
1214                 }
1215         }
1216         return true;
1217 }
1218
1219 static void node_counter(ir_node *node, void *env)
1220 {
1221         (void)node;
1222         unsigned long long *count = (unsigned long long*)env;
1223         ++(*count);
1224 }
1225
1226 static unsigned long long count_firm_nodes(void)
1227 {
1228         unsigned long long count = 0;
1229
1230         int n_irgs = get_irp_n_irgs();
1231         for (int i = 0; i < n_irgs; ++i) {
1232                 ir_graph *irg = get_irp_irg(i);
1233                 irg_walk_graph(irg, node_counter, NULL, &count);
1234         }
1235         return count;
1236 }
1237
1238 static int compilation_loop(compile_mode_t mode, compilation_unit_t *units,
1239                                                         lang_standard_t standard, FILE *out)
1240 {
1241         int  result                   = EXIT_SUCCESS;
1242         bool already_constructed_firm = false;
1243         for (compilation_unit_t *unit = units; unit != NULL; unit = unit->next) {
1244                 const char *const inputname = unit->name;
1245
1246                 determine_unit_standard(unit, standard);
1247                 setup_cmode(unit);
1248
1249                 stat_ev_ctx_push_str("compilation_unit", inputname);
1250
1251 again:
1252                 switch (unit->type) {
1253                 case COMPILATION_UNIT_IR: {
1254                         bool res = open_input(unit);
1255                         if (!res) {
1256                                 result = EXIT_FAILURE;
1257                                 break;
1258                         }
1259                         res = !ir_import_file(unit->input, unit->name);
1260                         if (!res) {
1261                                 fprintf(stderr, "Import of firm graph from '%s' failed\n",
1262                                         inputname);
1263                                 result = EXIT_FAILURE;
1264                                 break;
1265                         }
1266                         unit->type = COMPILATION_UNIT_INTERMEDIATE_REPRESENTATION;
1267                         goto again;
1268                 }
1269                 case COMPILATION_UNIT_ASSEMBLER:
1270                         panic("TODO: preprocess for assembler");
1271                 case COMPILATION_UNIT_C:
1272                 case COMPILATION_UNIT_CXX:
1273                         if (external_preprocessor != NULL) {
1274                                 bool res = run_external_preprocessor(unit);
1275                                 if (!res) {
1276                                         result = EXIT_FAILURE;
1277                                         break;
1278                                 }
1279                                 goto again;
1280                         }
1281                         /* FALLTHROUGH */
1282
1283                 case COMPILATION_UNIT_PREPROCESSED_C:
1284                 case COMPILATION_UNIT_PREPROCESSED_CXX: {
1285                         bool res = open_input(unit);
1286                         if (!res) {
1287                                 result = EXIT_FAILURE;
1288                                 break;
1289                         }
1290                         init_tokens();
1291
1292                         if (mode == PreprocessOnly) {
1293                                 bool res = output_preprocessor_tokens(unit, out);
1294                                 if (!res) {
1295                                         result = EXIT_FAILURE;
1296                                         break;
1297                                 }
1298                                 break;
1299                         }
1300
1301                         /* do the actual parsing */
1302                         do_parsing(unit);
1303                         goto again;
1304                 }
1305                 case COMPILATION_UNIT_AST:
1306                         /* prints the AST even if errors occurred */
1307                         if (mode == PrintAst) {
1308                                 print_to_file(out);
1309                                 print_ast(unit->ast);
1310                         }
1311                         if (unit->parse_errors) {
1312                                 result = EXIT_FAILURE;
1313                                 break;
1314                         }
1315
1316                         if (mode == BenchmarkParser) {
1317                                 break;
1318                         } else if (mode == PrintFluffy) {
1319                                 write_fluffy_decls(out, unit->ast);
1320                                 break;
1321                         } else if (mode == PrintJna) {
1322                                 write_jna_decls(out, unit->ast);
1323                                 break;
1324                         } else if (mode == PrintCompoundSizes) {
1325                                 write_compoundsizes(out, unit->ast);
1326                                 break;
1327                         }
1328
1329                         /* build the firm graph */
1330                         ir_timer_t *t_construct = ir_timer_new();
1331                         timer_register(t_construct, "Frontend: Graph construction");
1332                         timer_start(t_construct);
1333                         if (already_constructed_firm) {
1334                                 panic("compiling multiple files/translation units not possible");
1335                         }
1336                         init_implicit_optimizations();
1337                         translation_unit_to_firm(unit->ast);
1338                         already_constructed_firm = true;
1339                         timer_stop(t_construct);
1340                         if (stat_ev_enabled) {
1341                                 stat_ev_dbl("time_graph_construction", ir_timer_elapsed_sec(t_construct));
1342                                 stat_ev_int("size_graph_construction", count_firm_nodes());
1343                         }
1344                         unit->type = COMPILATION_UNIT_INTERMEDIATE_REPRESENTATION;
1345                         goto again;
1346
1347                 case COMPILATION_UNIT_INTERMEDIATE_REPRESENTATION:
1348                         if (mode == ParseOnly)
1349                                 break;
1350
1351                         if (mode == CompileDump) {
1352                                 /* find irg */
1353                                 ident    *id     = new_id_from_str(dumpfunction);
1354                                 ir_graph *irg    = NULL;
1355                                 int       n_irgs = get_irp_n_irgs();
1356                                 for (int i = 0; i < n_irgs; ++i) {
1357                                         ir_graph *tirg   = get_irp_irg(i);
1358                                         ident    *irg_id = get_entity_ident(get_irg_entity(tirg));
1359                                         if (irg_id == id) {
1360                                                 irg = tirg;
1361                                                 break;
1362                                         }
1363                                 }
1364
1365                                 if (irg == NULL) {
1366                                         fprintf(stderr, "No graph for function '%s' found\n",
1367                                                 dumpfunction);
1368                                         return EXIT_FAILURE;
1369                                 }
1370
1371                                 dump_ir_graph_file(out, irg);
1372                                 fclose(out);
1373                                 return EXIT_SUCCESS;
1374                         }
1375
1376                         if (mode == CompileExportIR) {
1377                                 ir_export_file(out);
1378                                 if (ferror(out) != 0) {
1379                                         fprintf(stderr, "Error while writing to output\n");
1380                                         return EXIT_FAILURE;
1381                                 }
1382                                 return EXIT_SUCCESS;
1383                         }
1384
1385                         FILE *asm_out;
1386                         if (mode == Compile) {
1387                                 asm_out = out;
1388                         } else {
1389                                 asm_out = make_temp_file("ccs", &unit->name);
1390                         }
1391                         ir_timer_t *t_opt_codegen = ir_timer_new();
1392                         timer_register(t_opt_codegen, "Optimization and Codegeneration");
1393                         timer_start(t_opt_codegen);
1394                         generate_code(asm_out, inputname);
1395                         timer_stop(t_opt_codegen);
1396                         if (stat_ev_enabled) {
1397                                 stat_ev_dbl("time_opt_codegen", ir_timer_elapsed_sec(t_opt_codegen));
1398                         }
1399                         if (asm_out != out) {
1400                                 fclose(asm_out);
1401                         }
1402                         unit->type = COMPILATION_UNIT_PREPROCESSED_ASSEMBLER;
1403                         goto again;
1404                 case COMPILATION_UNIT_PREPROCESSED_ASSEMBLER:
1405                         if (mode != CompileAssemble && mode != CompileAssembleLink)
1406                                 break;
1407
1408                         /* assemble */
1409                         const char *input = unit->name;
1410                         if (mode == CompileAssemble) {
1411                                 fclose(out);
1412                                 unit->name = outname;
1413                         } else {
1414                                 FILE *tempf = make_temp_file("cco", &unit->name);
1415                                 /* hackish... */
1416                                 fclose(tempf);
1417                         }
1418
1419                         assemble(unit->name, input);
1420
1421                         unit->type = COMPILATION_UNIT_OBJECT;
1422                         goto again;
1423                 case COMPILATION_UNIT_UNKNOWN:
1424                 case COMPILATION_UNIT_AUTODETECT:
1425                 case COMPILATION_UNIT_OBJECT:
1426                         break;
1427                 }
1428
1429                 stat_ev_ctx_pop("compilation_unit");
1430         }
1431         return result;
1432 }
1433
1434 static int link_program(compilation_unit_t *units)
1435 {
1436         obstack_1grow(&ldflags_obst, '\0');
1437         const char *flags = obstack_finish(&ldflags_obst);
1438
1439         /* construct commandline */
1440         const char *linker = getenv("CPARSER_LINK");
1441         if (linker != NULL) {
1442                 obstack_printf(&file_obst, "%s ", linker);
1443         } else {
1444                 if (target_triple != NULL)
1445                         obstack_printf(&file_obst, "%s-", target_triple);
1446                 obstack_printf(&file_obst, "%s ", LINKER);
1447         }
1448
1449         for (compilation_unit_t *unit = units; unit != NULL; unit = unit->next) {
1450                 if (unit->type != COMPILATION_UNIT_OBJECT)
1451                         continue;
1452
1453                 add_flag(&file_obst, "%s", unit->name);
1454         }
1455
1456         add_flag(&file_obst, "-o");
1457         add_flag(&file_obst, outname);
1458         obstack_printf(&file_obst, "%s", flags);
1459         obstack_1grow(&file_obst, '\0');
1460
1461         char *commandline = obstack_finish(&file_obst);
1462
1463         if (verbose) {
1464                 puts(commandline);
1465         }
1466         int err = system(commandline);
1467         if (err != EXIT_SUCCESS) {
1468                 fprintf(stderr, "linker reported an error\n");
1469                 return EXIT_FAILURE;
1470         }
1471         return EXIT_SUCCESS;
1472 }
1473
1474 int main(int argc, char **argv)
1475 {
1476         const char         *print_file_name_file = NULL;
1477         compile_mode_t      mode                 = CompileAssembleLink;
1478         int                 opt_level            = 1;
1479         char                cpu_arch[16]         = "ia32";
1480         compilation_unit_t *units                = NULL;
1481         compilation_unit_t *last_unit            = NULL;
1482         bool                construct_dep_target = false;
1483         bool                produce_statev       = false;
1484         const char         *filtev               = NULL;
1485         bool                profile_generate     = false;
1486         bool                profile_use          = false;
1487         bool                do_timing            = false;
1488         bool                print_timing         = false;
1489
1490         /* hack for now... */
1491         if (strstr(argv[0], "pptest") != NULL) {
1492                 extern int pptest_main(int argc, char **argv);
1493                 return pptest_main(argc, argv);
1494         }
1495
1496         temp_files = NEW_ARR_F(char*, 0);
1497         atexit(free_temp_files);
1498
1499         obstack_init(&cppflags_obst);
1500         obstack_init(&ldflags_obst);
1501         obstack_init(&asflags_obst);
1502         obstack_init(&file_obst);
1503         init_include_paths();
1504
1505 #define GET_ARG_AFTER(def, args)                                             \
1506         do {                                                                     \
1507         def = &arg[sizeof(args)-1];                                              \
1508         if (def[0] == '\0') {                                                    \
1509                 ++i;                                                                 \
1510                 if (i >= argc) {                                                     \
1511                         fprintf(stderr, "error: expected argument after '" args "'\n");  \
1512                         argument_errors = true;                                          \
1513                         break;                                                           \
1514                 }                                                                    \
1515                 def = argv[i];                                                       \
1516                 if (def[0] == '-' && def[1] != '\0') {                               \
1517                         fprintf(stderr, "error: expected argument after '" args "'\n");  \
1518                         argument_errors = true;                                          \
1519                         continue;                                                        \
1520                 }                                                                    \
1521         }                                                                        \
1522         } while (0)
1523
1524 #define SINGLE_OPTION(ch) (option[0] == (ch) && option[1] == '\0')
1525
1526         /* initialize this early because it has to parse options */
1527         gen_firm_init();
1528
1529         /* early options parsing (find out optimization level and OS) */
1530         for (int i = 1; i < argc; ++i) {
1531                 const char *arg = argv[i];
1532                 if (arg[0] != '-')
1533                         continue;
1534
1535                 const char *option = &arg[1];
1536                 if (option[0] == 'O') {
1537                         sscanf(&option[1], "%d", &opt_level);
1538                 }
1539         }
1540
1541         if (target_machine == NULL) {
1542                 target_machine = firm_get_host_machine();
1543         }
1544         choose_optimization_pack(opt_level);
1545         setup_target_machine();
1546
1547         /* parse rest of options */
1548         lang_standard_t         standard        = STANDARD_DEFAULT;
1549         compilation_unit_type_t forced_unittype = COMPILATION_UNIT_AUTODETECT;
1550         help_sections_t         help            = HELP_NONE;
1551         bool                    argument_errors = false;
1552         for (int i = 1; i < argc; ++i) {
1553                 const char *arg = argv[i];
1554                 if (arg[0] == '-' && arg[1] != '\0') {
1555                         /* an option */
1556                         const char *option = &arg[1];
1557                         if (option[0] == 'o') {
1558                                 GET_ARG_AFTER(outname, "-o");
1559                         } else if (option[0] == 'g') {
1560                                 /* TODO: parse -gX with 0<=x<=3... */
1561                                 set_be_option("debug=frameinfo");
1562                                 set_be_option("ia32-nooptcc=yes");
1563                         } else if (SINGLE_OPTION('c')) {
1564                                 mode = CompileAssemble;
1565                         } else if (SINGLE_OPTION('E')) {
1566                                 mode = PreprocessOnly;
1567                         } else if (SINGLE_OPTION('s')) {
1568                                 add_flag(&ldflags_obst, "-s");
1569                         } else if (SINGLE_OPTION('S')) {
1570                                 mode = Compile;
1571                         } else if (option[0] == 'O') {
1572                                 continue;
1573                         } else if (option[0] == 'I') {
1574                                 const char *opt;
1575                                 GET_ARG_AFTER(opt, "-I");
1576                                 add_flag(&cppflags_obst, "-I%s", opt);
1577                                 append_include_path(&bracket_searchpath, opt);
1578                         } else if (option[0] == 'D') {
1579                                 const char *opt;
1580                                 GET_ARG_AFTER(opt, "-D");
1581                                 add_flag(&cppflags_obst, "-D%s", opt);
1582                         } else if (option[0] == 'U') {
1583                                 const char *opt;
1584                                 GET_ARG_AFTER(opt, "-U");
1585                                 add_flag(&cppflags_obst, "-U%s", opt);
1586                         } else if (option[0] == 'l') {
1587                                 const char *opt;
1588                                 GET_ARG_AFTER(opt, "-l");
1589                                 add_flag(&ldflags_obst, "-l%s", opt);
1590                         } else if (option[0] == 'L') {
1591                                 const char *opt;
1592                                 GET_ARG_AFTER(opt, "-L");
1593                                 add_flag(&ldflags_obst, "-L%s", opt);
1594                         } else if (SINGLE_OPTION('v')) {
1595                                 verbose = 1;
1596                         } else if (SINGLE_OPTION('w')) {
1597                                 add_flag(&cppflags_obst, "-w");
1598                                 disable_all_warnings();
1599                         } else if (option[0] == 'x') {
1600                                 const char *opt;
1601                                 GET_ARG_AFTER(opt, "-x");
1602                                 forced_unittype = get_unit_type_from_string(opt);
1603                                 if (forced_unittype == COMPILATION_UNIT_UNKNOWN) {
1604                                         fprintf(stderr, "Unknown language '%s'\n", opt);
1605                                         argument_errors = true;
1606                                 }
1607                         } else if (streq(option, "M")) {
1608                                 mode = PreprocessOnly;
1609                                 add_flag(&cppflags_obst, "-M");
1610                         } else if (streq(option, "MMD") ||
1611                                    streq(option, "MD")) {
1612                             construct_dep_target = true;
1613                                 add_flag(&cppflags_obst, "-%s", option);
1614                         } else if (streq(option, "MM")  ||
1615                                    streq(option, "MP")) {
1616                                 add_flag(&cppflags_obst, "-%s", option);
1617                         } else if (streq(option, "MT") ||
1618                                    streq(option, "MQ") ||
1619                                    streq(option, "MF")) {
1620                                 const char *opt;
1621                                 GET_ARG_AFTER(opt, "-MT");
1622                                 add_flag(&cppflags_obst, "-%s", option);
1623                                 add_flag(&cppflags_obst, "%s", opt);
1624                         } else if (streq(option, "include")) {
1625                                 const char *opt;
1626                                 GET_ARG_AFTER(opt, "-include");
1627                                 add_flag(&cppflags_obst, "-include");
1628                                 add_flag(&cppflags_obst, "%s", opt);
1629                         } else if (streq(option, "idirafter")) {
1630                                 const char *opt;
1631                                 GET_ARG_AFTER(opt, "-idirafter");
1632                                 add_flag(&cppflags_obst, "-idirafter");
1633                                 add_flag(&cppflags_obst, "%s", opt);
1634                                 append_include_path(&after_searchpath, opt);
1635                         } else if (streq(option, "isystem")) {
1636                                 const char *opt;
1637                                 GET_ARG_AFTER(opt, "-isystem");
1638                                 add_flag(&cppflags_obst, "-isystem");
1639                                 add_flag(&cppflags_obst, "%s", opt);
1640                                 append_include_path(&system_searchpath, opt);
1641                         } else if (streq(option, "iquote")) {
1642                                 const char *opt;
1643                                 GET_ARG_AFTER(opt, "-iquote");
1644                                 add_flag(&cppflags_obst, "-iquote");
1645                                 add_flag(&cppflags_obst, "%s", opt);
1646                                 append_include_path(&quote_searchpath, opt);
1647                         } else if (streq(option, "pthread")) {
1648                                 /* set flags for the preprocessor */
1649                                 add_flag(&cppflags_obst, "-D_REENTRANT");
1650                                 /* set flags for the linker */
1651                                 add_flag(&ldflags_obst, "-lpthread");
1652                         } else if (streq(option, "nostdinc")
1653                                         || streq(option, "trigraphs")) {
1654                                 /* pass these through to the preprocessor */
1655                                 add_flag(&cppflags_obst, "%s", arg);
1656                         } else if (streq(option, "pipe")) {
1657                                 /* here for gcc compatibility */
1658                         } else if (streq(option, "static")) {
1659                                 add_flag(&ldflags_obst, "-static");
1660                         } else if (streq(option, "shared")) {
1661                                 add_flag(&ldflags_obst, "-shared");
1662                         } else if (option[0] == 'f') {
1663                                 char const *orig_opt;
1664                                 GET_ARG_AFTER(orig_opt, "-f");
1665
1666                                 if (strstart(orig_opt, "input-charset=")) {
1667                                         char const* const encoding = strchr(orig_opt, '=') + 1;
1668                                         input_encoding = encoding;
1669                                 } else if (strstart(orig_opt, "align-loops=") ||
1670                                            strstart(orig_opt, "align-jumps=") ||
1671                                            strstart(orig_opt, "align-functions=")) {
1672                                         fprintf(stderr, "ignoring gcc option '-f%s'\n", orig_opt);
1673                                 } else if (strstart(orig_opt, "visibility=")) {
1674                                         const char *val = strchr(orig_opt, '=')+1;
1675                                         elf_visibility_tag_t visibility
1676                                                 = get_elf_visibility_from_string(val);
1677                                         if (visibility == ELF_VISIBILITY_ERROR) {
1678                                                 fprintf(stderr, "invalid visibility '%s' specified\n",
1679                                                         val);
1680                                                 argument_errors = true;
1681                                         } else {
1682                                                 set_default_visibility(visibility);
1683                                         }
1684                                 } else if (strstart(orig_opt, "message-length=")) {
1685                                         /* ignore: would only affect error message format */
1686                                 } else if (streq(orig_opt, "fast-math") ||
1687                                            streq(orig_opt, "fp-fast")) {
1688                                         firm_fp_model = fp_model_fast;
1689                                 } else if (streq(orig_opt, "fp-precise")) {
1690                                         firm_fp_model = fp_model_precise;
1691                                 } else if (streq(orig_opt, "fp-strict")) {
1692                                         firm_fp_model = fp_model_strict;
1693                                 } else if (streq(orig_opt, "help")) {
1694                                         fprintf(stderr, "warning: -fhelp is deprecated\n");
1695                                         help |= HELP_OPTIMIZATION;
1696                                 } else {
1697                                         /* -f options which have an -fno- variant */
1698                                         char const *opt         = orig_opt;
1699                                         bool        truth_value = true;
1700                                         if (opt[0] == 'n' && opt[1] == 'o' && opt[2] == '-') {
1701                                                 truth_value = false;
1702                                                 opt += 3;
1703                                         }
1704
1705                                         if (streq(opt, "diagnostics-show-option")) {
1706                                                 diagnostics_show_option = truth_value;
1707                                         } else if (streq(opt, "dollars-in-identifiers")) {
1708                                                 allow_dollar_in_symbol = truth_value;
1709                                         } else if (streq(opt, "omit-frame-pointer")) {
1710                                                 set_be_option(truth_value ? "omitfp" : "omitfp=no");
1711                                         } else if (streq(opt, "short-wchar")) {
1712                                                 wchar_atomic_kind = truth_value ? ATOMIC_TYPE_USHORT
1713                                                         : ATOMIC_TYPE_INT;
1714                                         } else if (streq(opt, "show-column")) {
1715                                                 show_column = truth_value;
1716                                         } else if (streq(opt, "signed-char")) {
1717                                                 char_is_signed = truth_value;
1718                                         } else if (streq(opt, "strength-reduce")) {
1719                                                 /* does nothing, for gcc compatibility (even gcc does
1720                                                  * nothing for this switch anymore) */
1721                                         } else if (streq(opt, "syntax-only")) {
1722                                                 mode = truth_value ? ParseOnly : CompileAssembleLink;
1723                                         } else if (streq(opt, "unsigned-char")) {
1724                                                 char_is_signed = !truth_value;
1725                                         } else if (streq(opt, "freestanding")) {
1726                                                 freestanding = truth_value;
1727                                         } else if (streq(opt, "hosted")) {
1728                                                 freestanding = !truth_value;
1729                                         } else if (streq(opt, "profile-generate")) {
1730                                                 profile_generate = truth_value;
1731                                         } else if (streq(opt, "profile-use")) {
1732                                                 profile_use = truth_value;
1733                                         } else if (!truth_value &&
1734                                                    streq(opt, "asynchronous-unwind-tables")) {
1735                                             /* nothing todo, a gcc feature which we do not support
1736                                              * anyway was deactivated */
1737                                         } else if (streq(opt, "verbose-asm")) {
1738                                                 /* ignore: we always print verbose assembler */
1739                                         } else if (streq(opt, "jump-tables")             ||
1740                                                    streq(opt, "expensive-optimizations") ||
1741                                                    streq(opt, "common")                  ||
1742                                                    streq(opt, "optimize-sibling-calls")  ||
1743                                                    streq(opt, "align-loops")             ||
1744                                                    streq(opt, "align-jumps")             ||
1745                                                    streq(opt, "align-functions")         ||
1746                                                    streq(opt, "PIC")                     ||
1747                                                    streq(opt, "stack-protector")         ||
1748                                                    streq(opt, "stack-protector-all")) {
1749                                                 fprintf(stderr, "ignoring gcc option '-f%s'\n", orig_opt);
1750                                         } else {
1751                                                 int res = firm_option(orig_opt);
1752                                                 if (res == 0) {
1753                                                         fprintf(stderr, "error: unknown Firm option '-f%s'\n",
1754                                                                 orig_opt);
1755                                                         argument_errors = true;
1756                                                         continue;
1757                                                 }
1758                                         }
1759                                 }
1760                         } else if (option[0] == 'b') {
1761                                 const char *opt;
1762                                 GET_ARG_AFTER(opt, "-b");
1763
1764                                 if (streq(opt, "help")) {
1765                                         fprintf(stderr, "warning: -bhelp is deprecated (use --help-firm)\n");
1766                                         help |= HELP_FIRM;
1767                                 } else {
1768                                         int res = be_parse_arg(opt);
1769                                         if (res == 0) {
1770                                                 fprintf(stderr, "error: unknown Firm backend option '-b %s'\n",
1771                                                                 opt);
1772                                                 argument_errors = true;
1773                                         } else if (strstart(opt, "isa=")) {
1774                                                 strncpy(cpu_arch, opt, sizeof(cpu_arch));
1775                                         }
1776                                 }
1777                         } else if (option[0] == 'W') {
1778                                 if (strstart(option + 1, "p,")) {
1779                                         // pass options directly to the preprocessor
1780                                         const char *opt;
1781                                         GET_ARG_AFTER(opt, "-Wp,");
1782                                         add_flag(&cppflags_obst, "-Wp,%s", opt);
1783                                 } else if (strstart(option + 1, "l,")) {
1784                                         // pass options directly to the linker
1785                                         const char *opt;
1786                                         GET_ARG_AFTER(opt, "-Wl,");
1787                                         add_flag(&ldflags_obst, "-Wl,%s", opt);
1788                                 } else if (streq(option + 1, "no-trigraphs")
1789                                                         || streq(option + 1, "undef")
1790                                                         || streq(option + 1, "missing-include-dirs")
1791                                                         || streq(option + 1, "endif-labels")) {
1792                                         add_flag(&cppflags_obst, "%s", arg);
1793                                 } else if (streq(option+1, "init-self")) {
1794                                         /* ignored (same as gcc does) */
1795                                 } else if (streq(option+1, "format-y2k")
1796                                            || streq(option+1, "format-security")
1797                                            || streq(option+1, "old-style-declaration")
1798                                            || streq(option+1, "type-limits")) {
1799                                     /* ignore (gcc compatibility) */
1800                                 } else {
1801                                         set_warning_opt(&option[1]);
1802                                 }
1803                         } else if (option[0] == 'm') {
1804                                 /* -m options */
1805                                 const char *opt;
1806                                 char arch_opt[64];
1807
1808                                 GET_ARG_AFTER(opt, "-m");
1809                                 if (strstart(opt, "target=")) {
1810                                         GET_ARG_AFTER(opt, "-mtarget=");
1811                                         if (!parse_target_triple(opt)) {
1812                                                 argument_errors = true;
1813                                         } else {
1814                                                 const char *isa = setup_target_machine();
1815                                                 strncpy(cpu_arch, isa, sizeof(cpu_arch));
1816                                                 target_triple = opt;
1817                                         }
1818                                 } else if (strstart(opt, "triple=")) {
1819                                         GET_ARG_AFTER(opt, "-mtriple=");
1820                                         if (!parse_target_triple(opt)) {
1821                                                 argument_errors = true;
1822                                         } else {
1823                                                 const char *isa = setup_target_machine();
1824                                                 strncpy(cpu_arch, isa, sizeof(cpu_arch));
1825                                                 target_triple = opt;
1826                                         }
1827                                 } else if (strstart(opt, "arch=")) {
1828                                         GET_ARG_AFTER(opt, "-march=");
1829                                         snprintf(arch_opt, sizeof(arch_opt), "%s-arch=%s", cpu_arch, opt);
1830                                         int res = be_parse_arg(arch_opt);
1831                                         snprintf(arch_opt, sizeof(arch_opt), "%s-opt=%s", cpu_arch, opt);
1832                                         res &= be_parse_arg(arch_opt);
1833
1834                                         if (res == 0) {
1835                                                 fprintf(stderr, "Unknown architecture '%s'\n", arch_opt);
1836                                                 argument_errors = true;
1837                                         }
1838                                 } else if (strstart(opt, "tune=")) {
1839                                         GET_ARG_AFTER(opt, "-mtune=");
1840                                         snprintf(arch_opt, sizeof(arch_opt), "%s-opt=%s", cpu_arch, opt);
1841                                         int res = be_parse_arg(arch_opt);
1842                                         if (res == 0)
1843                                                 argument_errors = true;
1844                                 } else if (strstart(opt, "cpu=")) {
1845                                         GET_ARG_AFTER(opt, "-mcpu=");
1846                                         snprintf(arch_opt, sizeof(arch_opt), "%s-arch=%s", cpu_arch, opt);
1847                                         int res = be_parse_arg(arch_opt);
1848                                         if (res == 0)
1849                                                 argument_errors = true;
1850                                 } else if (strstart(opt, "fpmath=")) {
1851                                         GET_ARG_AFTER(opt, "-mfpmath=");
1852                                         if (streq(opt, "387"))
1853                                                 opt = "x87";
1854                                         else if (streq(opt, "sse"))
1855                                                 opt = "sse2";
1856                                         else {
1857                                                 fprintf(stderr, "error: option -mfpmath supports only 387 or sse\n");
1858                                                 argument_errors = true;
1859                                         }
1860                                         if (!argument_errors) {
1861                                                 snprintf(arch_opt, sizeof(arch_opt), "%s-fpunit=%s", cpu_arch, opt);
1862                                                 int res = be_parse_arg(arch_opt);
1863                                                 if (res == 0)
1864                                                         argument_errors = true;
1865                                         }
1866                                 } else if (strstart(opt, "preferred-stack-boundary=")) {
1867                                         GET_ARG_AFTER(opt, "-mpreferred-stack-boundary=");
1868                                         snprintf(arch_opt, sizeof(arch_opt), "%s-stackalign=%s", cpu_arch, opt);
1869                                         int res = be_parse_arg(arch_opt);
1870                                         if (res == 0)
1871                                                 argument_errors = true;
1872                                 } else if (streq(opt, "rtd")) {
1873                                         default_calling_convention = CC_STDCALL;
1874                                 } else if (strstart(opt, "regparm=")) {
1875                                         fprintf(stderr, "error: regparm convention not supported yet\n");
1876                                         argument_errors = true;
1877                                 } else if (streq(opt, "soft-float")) {
1878                                         add_flag(&ldflags_obst, "-msoft-float");
1879                                         snprintf(arch_opt, sizeof(arch_opt), "%s-fpunit=softfloat", cpu_arch);
1880                                         int res = be_parse_arg(arch_opt);
1881                                         if (res == 0)
1882                                                 argument_errors = true;
1883                                 } else if (streq(opt, "sse2")) {
1884                                         /* ignore for now, our x86 backend always uses sse when
1885                                          * sse is requested */
1886                                 } else {
1887                                         long int value = strtol(opt, NULL, 10);
1888                                         if (value == 0) {
1889                                                 fprintf(stderr, "error: wrong option '-m %s'\n",  opt);
1890                                                 argument_errors = true;
1891                                         } else if (value != 16 && value != 32 && value != 64) {
1892                                                 fprintf(stderr, "error: option -m supports only 16, 32 or 64\n");
1893                                                 argument_errors = true;
1894                                         } else {
1895                                                 unsigned machine_size = (unsigned)value;
1896                                                 /* TODO: choose/change backend based on this */
1897                                                 add_flag(&cppflags_obst, "-m%u", machine_size);
1898                                                 add_flag(&asflags_obst, "-m%u", machine_size);
1899                                                 add_flag(&ldflags_obst, "-m%u", machine_size);
1900                                         }
1901                                 }
1902                         } else if (streq(option, "pg")) {
1903                                 set_be_option("gprof");
1904                                 add_flag(&ldflags_obst, "-pg");
1905                         } else if (streq(option, "ansi")) {
1906                                 standard = STANDARD_ANSI;
1907                         } else if (streq(option, "pedantic")) {
1908                                 fprintf(stderr, "warning: ignoring gcc option '%s'\n", arg);
1909                         } else if (strstart(option, "std=")) {
1910                                 const char *const o = &option[4];
1911                                 standard =
1912                                         streq(o, "c++")            ? STANDARD_CXX98   :
1913                                         streq(o, "c++98")          ? STANDARD_CXX98   :
1914                                         streq(o, "c11")            ? STANDARD_C11     :
1915                                         streq(o, "c1x")            ? STANDARD_C11     : // deprecated
1916                                         streq(o, "c89")            ? STANDARD_C89     :
1917                                         streq(o, "c90")            ? STANDARD_C89     :
1918                                         streq(o, "c99")            ? STANDARD_C99     :
1919                                         streq(o, "c9x")            ? STANDARD_C99     : // deprecated
1920                                         streq(o, "gnu++98")        ? STANDARD_GNUXX98 :
1921                                         streq(o, "gnu11")          ? STANDARD_GNU11   :
1922                                         streq(o, "gnu1x")          ? STANDARD_GNU11   : // deprecated
1923                                         streq(o, "gnu89")          ? STANDARD_GNU89   :
1924                                         streq(o, "gnu99")          ? STANDARD_GNU99   :
1925                                         streq(o, "gnu9x")          ? STANDARD_GNU99   : // deprecated
1926                                         streq(o, "iso9899:1990")   ? STANDARD_C89     :
1927                                         streq(o, "iso9899:199409") ? STANDARD_C89AMD1 :
1928                                         streq(o, "iso9899:1999")   ? STANDARD_C99     :
1929                                         streq(o, "iso9899:199x")   ? STANDARD_C99     : // deprecated
1930                                         streq(o, "iso9899:2011")   ? STANDARD_C11     :
1931                                         (fprintf(stderr, "warning: ignoring gcc option '%s'\n", arg), standard);
1932                         } else if (streq(option, "version")) {
1933                                 print_cparser_version();
1934                                 return EXIT_SUCCESS;
1935                         } else if (streq(option, "dumpversion")) {
1936                                 /* gcc compatibility option */
1937                                 print_cparser_version_short();
1938                                 return EXIT_SUCCESS;
1939                         } else if (strstart(option, "print-file-name=")) {
1940                                 GET_ARG_AFTER(print_file_name_file, "-print-file-name=");
1941                         } else if (option[0] == '-') {
1942                                 /* double dash option */
1943                                 ++option;
1944                                 if (streq(option, "gcc")) {
1945                                         features_on  |=  _GNUC;
1946                                         features_off &= ~_GNUC;
1947                                 } else if (streq(option, "no-gcc")) {
1948                                         features_on  &= ~_GNUC;
1949                                         features_off |=  _GNUC;
1950                                 } else if (streq(option, "ms")) {
1951                                         features_on  |=  _MS;
1952                                         features_off &= ~_MS;
1953                                 } else if (streq(option, "no-ms")) {
1954                                         features_on  &= ~_MS;
1955                                         features_off |=  _MS;
1956                                 } else if (streq(option, "strict")) {
1957                                         strict_mode = true;
1958                                 } else if (streq(option, "benchmark")) {
1959                                         mode = BenchmarkParser;
1960                                 } else if (streq(option, "print-ast")) {
1961                                         mode = PrintAst;
1962                                 } else if (streq(option, "print-implicit-cast")) {
1963                                         print_implicit_casts = true;
1964                                 } else if (streq(option, "print-parenthesis")) {
1965                                         print_parenthesis = true;
1966                                 } else if (streq(option, "print-fluffy")) {
1967                                         mode = PrintFluffy;
1968                                 } else if (streq(option, "print-compound-sizes")) {
1969                                         mode = PrintCompoundSizes;
1970                                 } else if (streq(option, "print-jna")) {
1971                                         mode = PrintJna;
1972                                 } else if (streq(option, "jna-limit")) {
1973                                         ++i;
1974                                         if (i >= argc) {
1975                                                 fprintf(stderr, "error: "
1976                                                         "expected argument after '--jna-limit'\n");
1977                                                 argument_errors = true;
1978                                                 break;
1979                                         }
1980                                         jna_limit_output(argv[i]);
1981                                 } else if (streq(option, "jna-libname")) {
1982                                         ++i;
1983                                         if (i >= argc) {
1984                                                 fprintf(stderr, "error: "
1985                                                         "expected argument after '--jna-libname'\n");
1986                                                 argument_errors = true;
1987                                                 break;
1988                                         }
1989                                         jna_set_libname(argv[i]);
1990                                 } else if (streq(option, "external-pp")) {
1991                                         if (i+1 < argc && argv[i+1][0] != '-') {
1992                                                 ++i;
1993                                                 external_preprocessor = argv[i+1];
1994                                         } else {
1995                                                 external_preprocessor = PREPROCESSOR;
1996                                         }
1997                                 } else if (streq(option, "no-external-pp")) {
1998                                         external_preprocessor = NULL;
1999                                 } else if (streq(option, "time")) {
2000                                         do_timing    = true;
2001                                         print_timing = true;
2002                                 } else if (streq(option, "statev")) {
2003                                         do_timing      = true;
2004                                         produce_statev = true;
2005                                 } else if (strstart(option, "filtev=")) {
2006                                         GET_ARG_AFTER(filtev, "--filtev=");
2007                                 } else if (streq(option, "version")) {
2008                                         print_cparser_version();
2009                                         return EXIT_SUCCESS;
2010                                 } else if (streq(option, "help")) {
2011                                         help |= HELP_BASIC;
2012                                 } else if (streq(option, "help-parser")) {
2013                                         help |= HELP_PARSER;
2014                                 } else if (streq(option, "help-warnings")) {
2015                                         help |= HELP_WARNINGS;
2016                                 } else if (streq(option, "help-codegen")) {
2017                                         help |= HELP_CODEGEN;
2018                                 } else if (streq(option, "help-linker")) {
2019                                         help |= HELP_LINKER;
2020                                 } else if (streq(option, "help-optimization")) {
2021                                         help |= HELP_OPTIMIZATION;
2022                                 } else if (streq(option, "help-language-tools")) {
2023                                         help |= HELP_LANGUAGETOOLS;
2024                                 } else if (streq(option, "help-debug")) {
2025                                         help |= HELP_DEBUG;
2026                                 } else if (streq(option, "help-firm")) {
2027                                         help |= HELP_FIRM;
2028                                 } else if (streq(option, "help-all")) {
2029                                         help |= HELP_ALL;
2030                                 } else if (streq(option, "dump-function")) {
2031                                         ++i;
2032                                         if (i >= argc) {
2033                                                 fprintf(stderr, "error: "
2034                                                         "expected argument after '--dump-function'\n");
2035                                                 argument_errors = true;
2036                                                 break;
2037                                         }
2038                                         dumpfunction = argv[i];
2039                                         mode         = CompileDump;
2040                                 } else if (streq(option, "export-ir")) {
2041                                         mode = CompileExportIR;
2042                                 } else if (streq(option, "unroll-loops")) {
2043                                         /* ignore (gcc compatibility) */
2044                                 } else {
2045                                         fprintf(stderr, "error: unknown argument '%s'\n", arg);
2046                                         argument_errors = true;
2047                                 }
2048                         } else {
2049                                 fprintf(stderr, "error: unknown argument '%s'\n", arg);
2050                                 argument_errors = true;
2051                         }
2052                 } else {
2053                         compilation_unit_type_t type = forced_unittype;
2054                         if (type == COMPILATION_UNIT_AUTODETECT) {
2055                                 if (streq(arg, "-")) {
2056                                         /* - implicitly means C source file */
2057                                         type = COMPILATION_UNIT_C;
2058                                 } else {
2059                                         const char *suffix = strrchr(arg, '.');
2060                                         /* Ensure there is at least one char before the suffix */
2061                                         if (suffix != NULL && suffix != arg) {
2062                                                 ++suffix;
2063                                                 type =
2064                                                         streq(suffix, "S")   ? COMPILATION_UNIT_ASSEMBLER              :
2065                                                         streq(suffix, "a")   ? COMPILATION_UNIT_OBJECT                 :
2066                                                         streq(suffix, "c")   ? COMPILATION_UNIT_C                      :
2067                                                         streq(suffix, "i")   ? COMPILATION_UNIT_PREPROCESSED_C         :
2068                                                         streq(suffix, "C")   ? COMPILATION_UNIT_CXX                    :
2069                                                         streq(suffix, "cc")  ? COMPILATION_UNIT_CXX                    :
2070                                                         streq(suffix, "cp")  ? COMPILATION_UNIT_CXX                    :
2071                                                         streq(suffix, "cpp") ? COMPILATION_UNIT_CXX                    :
2072                                                         streq(suffix, "CPP") ? COMPILATION_UNIT_CXX                    :
2073                                                         streq(suffix, "cxx") ? COMPILATION_UNIT_CXX                    :
2074                                                         streq(suffix, "c++") ? COMPILATION_UNIT_CXX                    :
2075                                                         streq(suffix, "ii")  ? COMPILATION_UNIT_PREPROCESSED_CXX       :
2076                                                         streq(suffix, "h")   ? COMPILATION_UNIT_C                      :
2077                                                         streq(suffix, "ir")  ? COMPILATION_UNIT_IR                     :
2078                                                         streq(suffix, "o")   ? COMPILATION_UNIT_OBJECT                 :
2079                                                         streq(suffix, "s")   ? COMPILATION_UNIT_PREPROCESSED_ASSEMBLER :
2080                                                         streq(suffix, "so")  ? COMPILATION_UNIT_OBJECT                 :
2081                                                         COMPILATION_UNIT_OBJECT; /* gcc behavior: unknown file extension means object file */
2082                                         }
2083                                 }
2084                         }
2085
2086                         compilation_unit_t *entry = OALLOCZ(&file_obst, compilation_unit_t);
2087                         entry->name = arg;
2088                         entry->type = type;
2089
2090                         if (last_unit != NULL) {
2091                                 last_unit->next = entry;
2092                         } else {
2093                                 units = entry;
2094                         }
2095                         last_unit = entry;
2096                 }
2097         }
2098
2099         if (help != HELP_NONE) {
2100                 print_help(argv[0], help);
2101                 return !argument_errors;
2102         }
2103
2104         if (print_file_name_file != NULL) {
2105                 print_file_name(print_file_name_file);
2106                 return EXIT_SUCCESS;
2107         }
2108         if (units == NULL) {
2109                 fprintf(stderr, "error: no input files specified\n");
2110                 argument_errors = true;
2111         }
2112
2113         if (argument_errors) {
2114                 usage(argv[0]);
2115                 return EXIT_FAILURE;
2116         }
2117
2118         /* apply some effects from switches */
2119         c_mode |= features_on;
2120         c_mode &= ~features_off;
2121         if (profile_generate) {
2122                 add_flag(&ldflags_obst, "-lfirmprof");
2123                 set_be_option("profilegenerate");
2124         }
2125         if (profile_use) {
2126                 set_be_option("profileuse");
2127         }
2128
2129         init_symbol_table();
2130         init_types_and_adjust();
2131         init_typehash();
2132         init_basic_types();
2133         if (c_mode & _CXX) {
2134                 init_wchar_types(ATOMIC_TYPE_WCHAR_T);
2135         } else {
2136                 init_wchar_types(wchar_atomic_kind);
2137         }
2138         init_preprocessor();
2139         init_ast();
2140         init_parser();
2141         init_ast2firm();
2142         init_mangle();
2143
2144         if (do_timing)
2145                 timer_init();
2146
2147         if (construct_dep_target) {
2148                 if (outname != 0 && strlen(outname) >= 2) {
2149                         get_output_name(dep_target, sizeof(dep_target), outname, ".d");
2150                 } else {
2151                         get_output_name(dep_target, sizeof(dep_target), units->name, ".d");
2152                 }
2153         } else {
2154                 dep_target[0] = '\0';
2155         }
2156
2157         char outnamebuf[4096];
2158         if (outname == NULL) {
2159                 const char *filename = units->name;
2160
2161                 switch(mode) {
2162                 case BenchmarkParser:
2163                 case PrintAst:
2164                 case PrintFluffy:
2165                 case PrintJna:
2166                 case PrintCompoundSizes:
2167                 case PreprocessOnly:
2168                 case ParseOnly:
2169                         outname = "-";
2170                         break;
2171                 case Compile:
2172                         get_output_name(outnamebuf, sizeof(outnamebuf), filename, ".s");
2173                         outname = outnamebuf;
2174                         break;
2175                 case CompileAssemble:
2176                         get_output_name(outnamebuf, sizeof(outnamebuf), filename, ".o");
2177                         outname = outnamebuf;
2178                         break;
2179                 case CompileDump:
2180                         get_output_name(outnamebuf, sizeof(outnamebuf), dumpfunction,
2181                                         ".vcg");
2182                         outname = outnamebuf;
2183                         break;
2184                 case CompileExportIR:
2185                         get_output_name(outnamebuf, sizeof(outnamebuf), filename, ".ir");
2186                         outname = outnamebuf;
2187                         break;
2188                 case CompileAssembleLink:
2189                         if (firm_is_windows_os(target_machine)) {
2190                                 outname = "a.exe";
2191                         } else {
2192                                 outname = "a.out";
2193                         }
2194                         break;
2195                 }
2196         }
2197
2198         assert(outname != NULL);
2199
2200         FILE *out;
2201         if (streq(outname, "-")) {
2202                 out = stdout;
2203         } else {
2204                 out = fopen(outname, "w");
2205                 if (out == NULL) {
2206                         fprintf(stderr, "Could not open '%s' for writing: %s\n", outname,
2207                                         strerror(errno));
2208                         return EXIT_FAILURE;
2209                 }
2210         }
2211
2212         if (produce_statev && units != NULL) {
2213                 /* attempt to guess a good name for the file */
2214                 const char *first_cup = units->name;
2215                 if (first_cup != NULL) {
2216                         const char *dot = strrchr(first_cup, '.');
2217                         const char *pos = dot ? dot : first_cup + strlen(first_cup);
2218                         char        buf[pos-first_cup+1];
2219                         strncpy(buf, first_cup, pos-first_cup);
2220                         buf[pos-first_cup] = '\0';
2221
2222                         stat_ev_begin(buf, filtev);
2223                 }
2224         }
2225
2226         int result = compilation_loop(mode, units, standard, out);
2227         if (stat_ev_enabled) {
2228                 stat_ev_end();
2229         }
2230
2231         if (result != EXIT_SUCCESS) {
2232                 if (out != stdout)
2233                         unlink(outname);
2234                 return result;
2235         }
2236
2237         /* link program file */
2238         if (mode == CompileAssembleLink) {
2239                 int result = link_program(units);
2240                 if (result != EXIT_SUCCESS) {
2241                         if (out != stdout)
2242                                 unlink(outname);
2243                         return result;
2244                 }
2245         }
2246
2247         if (do_timing)
2248                 timer_term(print_timing ? stderr : NULL);
2249
2250         free_temp_files();
2251         obstack_free(&cppflags_obst, NULL);
2252         obstack_free(&ldflags_obst, NULL);
2253         obstack_free(&asflags_obst, NULL);
2254         obstack_free(&file_obst, NULL);
2255
2256         gen_firm_finish();
2257         exit_mangle();
2258         exit_ast2firm();
2259         exit_parser();
2260         exit_ast();
2261         exit_preprocessor();
2262         exit_typehash();
2263         exit_types();
2264         exit_tokens();
2265         exit_symbol_table();
2266         return EXIT_SUCCESS;
2267 }