diagnostic: Use errorf(NULL, "[...]") instead of fprintf(stderr, "error: [...]\n").
[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                 source_position_t const pos = { unit->name, 0, 0, 0 };
398                 errorf(&pos, "invoking preprocessor failed");
399                 return false;
400         }
401         /* we do not really need that anymore */
402         obstack_free(&cppflags_obst, commandline);
403
404         unit->input         = f;
405         unit->input_is_pipe = true;
406         switch (unit->type) {
407         case COMPILATION_UNIT_ASSEMBLER:
408                 unit->type = COMPILATION_UNIT_PREPROCESSED_ASSEMBLER;
409                 break;
410         case COMPILATION_UNIT_C:
411                 unit->type = COMPILATION_UNIT_PREPROCESSED_C;
412                 break;
413         case COMPILATION_UNIT_CXX:
414                 unit->type = COMPILATION_UNIT_PREPROCESSED_CXX;
415                 break;
416         default:
417                 unit->type = COMPILATION_UNIT_UNKNOWN;
418                 break;
419         }
420
421         return true;
422 }
423
424 static void assemble(const char *out, const char *in)
425 {
426         obstack_1grow(&asflags_obst, '\0');
427         const char *flags = obstack_finish(&asflags_obst);
428
429         const char *assembler = getenv("CPARSER_AS");
430         if (assembler != NULL) {
431                 obstack_printf(&asflags_obst, "%s", assembler);
432         } else {
433                 if (target_triple != NULL)
434                         obstack_printf(&asflags_obst, "%s-", target_triple);
435                 obstack_printf(&asflags_obst, "%s", ASSEMBLER);
436         }
437         if (flags[0] != '\0')
438                 obstack_printf(&asflags_obst, " %s", flags);
439
440         obstack_printf(&asflags_obst, " %s -o %s", in, out);
441         obstack_1grow(&asflags_obst, '\0');
442
443         char *commandline = obstack_finish(&asflags_obst);
444         if (verbose) {
445                 puts(commandline);
446         }
447         int err = system(commandline);
448         if (err != EXIT_SUCCESS) {
449                 source_position_t const pos = { in, 0, 0, 0 };
450                 errorf(&pos, "assembler reported an error");
451                 exit(EXIT_FAILURE);
452         }
453         obstack_free(&asflags_obst, commandline);
454 }
455
456 static void print_file_name(const char *file)
457 {
458         add_flag(&ldflags_obst, "-print-file-name=%s", file);
459
460         obstack_1grow(&ldflags_obst, '\0');
461         const char *flags = obstack_finish(&ldflags_obst);
462
463         /* construct commandline */
464         const char *linker = getenv("CPARSER_LINK");
465         if (linker != NULL) {
466                 obstack_printf(&ldflags_obst, "%s ", linker);
467         } else {
468                 if (target_triple != NULL)
469                         obstack_printf(&ldflags_obst, "%s-", target_triple);
470                 obstack_printf(&ldflags_obst, "%s ", LINKER);
471         }
472         obstack_printf(&ldflags_obst, "%s ", linker);
473         obstack_printf(&ldflags_obst, "%s", flags);
474         obstack_1grow(&ldflags_obst, '\0');
475
476         char *commandline = obstack_finish(&ldflags_obst);
477         if (verbose) {
478                 puts(commandline);
479         }
480         int err = system(commandline);
481         if (err != EXIT_SUCCESS) {
482                 source_position_t const pos = { file, 0, 0, 0 };
483                 errorf(&pos, "linker reported an error");
484                 exit(EXIT_FAILURE);
485         }
486         obstack_free(&ldflags_obst, commandline);
487 }
488
489 static const char *try_dir(const char *dir)
490 {
491         if (dir == NULL)
492                 return dir;
493         if (access(dir, R_OK | W_OK | X_OK) == 0)
494                 return dir;
495         return NULL;
496 }
497
498 static const char *get_tempdir(void)
499 {
500         static const char *tmpdir = NULL;
501
502         if (tmpdir != NULL)
503                 return tmpdir;
504
505         if (tmpdir == NULL)
506                 tmpdir = try_dir(getenv("TMPDIR"));
507         if (tmpdir == NULL)
508                 tmpdir = try_dir(getenv("TMP"));
509         if (tmpdir == NULL)
510                 tmpdir = try_dir(getenv("TEMP"));
511
512 #ifdef P_tmpdir
513         if (tmpdir == NULL)
514                 tmpdir = try_dir(P_tmpdir);
515 #endif
516
517         if (tmpdir == NULL)
518                 tmpdir = try_dir("/var/tmp");
519         if (tmpdir == NULL)
520                 tmpdir = try_dir("/usr/tmp");
521         if (tmpdir == NULL)
522                 tmpdir = try_dir("/tmp");
523
524         if (tmpdir == NULL)
525                 tmpdir = ".";
526
527         return tmpdir;
528 }
529
530 #ifndef HAVE_MKSTEMP
531 /* cheap and nasty mkstemp replacement */
532 static int mkstemp(char *templ)
533 {
534         mktemp(templ);
535         return open(templ, O_RDWR|O_CREAT|O_EXCL|O_BINARY, 0600);
536 }
537 #endif
538
539 /**
540  * custom version of tmpnam, which: writes to an obstack, emits no warnings
541  * during linking (like glibc/gnu ld do for tmpnam)...
542  */
543 static FILE *make_temp_file(const char *prefix, const char **name_result)
544 {
545         const char *tempdir = get_tempdir();
546         assert(obstack_object_size(&file_obst) == 0);
547         obstack_printf(&file_obst, "%s/%sXXXXXX", tempdir, prefix);
548         obstack_1grow(&file_obst, '\0');
549
550         char *name = obstack_finish(&file_obst);
551         int fd = mkstemp(name);
552         if (fd == -1) {
553                 source_position_t const pos = { name, 0, 0, 0 };
554                 errorf(&pos, "could not create temporary file: %s", strerror(errno));
555                 return NULL;
556         }
557         FILE *out = fdopen(fd, "w");
558         if (out == NULL) {
559                 source_position_t const pos = { name, 0, 0, 0 };
560                 errorf(&pos, "could not open temporary file as FILE*");
561                 return NULL;
562         }
563
564         ARR_APP1(char*, temp_files, name);
565         *name_result = name;
566         return out;
567 }
568
569 static void free_temp_files(void)
570 {
571         if (temp_files == NULL)
572                 return;
573
574         size_t n_temp_files = ARR_LEN(temp_files);
575         size_t i;
576         for (i = 0; i < n_temp_files; ++i) {
577                 char *file = temp_files[i];
578                 unlink(file);
579         }
580         DEL_ARR_F(temp_files);
581         temp_files = NULL;
582 }
583
584 typedef enum compile_mode_t {
585         BenchmarkParser,
586         PreprocessOnly,
587         ParseOnly,
588         Compile,
589         CompileDump,
590         CompileExportIR,
591         CompileAssemble,
592         CompileAssembleLink,
593         PrintAst,
594         PrintFluffy,
595         PrintJna,
596         PrintCompoundSizes,
597 } compile_mode_t;
598
599 static void usage(const char *argv0)
600 {
601         fprintf(stderr, "Usage %s [options] input [-o output]\n", argv0);
602 }
603
604 static void print_cparser_version(void)
605 {
606         printf("cparser (%s) using libFirm (%u.%u",
607                cparser_REVISION, ir_get_version_major(),
608                ir_get_version_minor());
609
610         const char *revision = ir_get_version_revision();
611         if (revision[0] != 0) {
612                 putchar('-');
613                 fputs(revision, stdout);
614         }
615
616         const char *build = ir_get_version_build();
617         if (build[0] != 0) {
618                 putchar(' ');
619                 fputs(build, stdout);
620         }
621         puts(")");
622         puts("This is free software; see the source for copying conditions.  There is NO\n"
623              "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
624 }
625
626 static void print_cparser_version_short(void)
627 {
628         puts(cparser_REVISION);
629 }
630
631 static void print_help_basic(const char *argv0)
632 {
633         usage(argv0);
634         puts("");
635         put_help("--help",                   "Display this information");
636         put_help("--version",                "Display compiler version");
637         put_help("--help-parser",            "Display information about parser options");
638         put_help("--help-warnings",          "Display information about warning options");
639         put_help("--help-codegen",           "Display information about code-generation options");
640         put_help("--help-optimization",      "Display information about optimization options");
641         put_help("--help-linker",            "Display information about linker options");
642         put_help("--help-language-tools",    "Display information about language tools options");
643         put_help("--help-debug",             "Display information about compiler debugging options");
644         put_help("--help-firm",              "Display information about direct firm options");
645         put_help("--help-all",               "Display information about all options");
646         put_help("-c",                       "Compile and assemble but do not link");
647         put_help("-E",                       "Preprocess only");
648         put_help("-S",                       "Compile but do not assembler or link");
649         put_help("-o",                       "Specify output file");
650         put_help("-v",                       "Verbose output (show invocation of sub-processes)");
651         put_help("-x",                       "Force input language:");
652         put_choice("c",                      "C");
653         put_choice("c++",                    "C++");
654         put_choice("assembler",              "Assembler (no preprocessing)");
655         put_choice("assembler-with-cpp",     "Assembler with preprocessing");
656         put_choice("none",                   "Autodetection");
657         put_help("-pipe",                    "Ignored (gcc compatibility)");
658 }
659
660 static void print_help_preprocessor(void)
661 {
662         put_help("-nostdinc",                "Do not search standard system include directories");
663         put_help("-trigraphs",               "Support ISO C trigraphs");
664         put_help("-isystem",                 "");
665         put_help("-include",                 "");
666         put_help("-I PATH",                  "");
667         put_help("-D SYMBOL[=value]",        "");
668         put_help("-U SYMBOL",                "");
669         put_help("-Wp,OPTION",               "Pass option directly to preprocessor");
670         put_help("-M",                       "");
671         put_help("-MD",                      "");
672         put_help("-MMD",                     "");
673         put_help("-MM",                      "");
674         put_help("-MP",                      "");
675         put_help("-MT",                      "");
676         put_help("-MQ",                      "");
677         put_help("-MF",                      "");
678 }
679
680 static void print_help_parser(void)
681 {
682         put_help("-finput-charset=CHARSET",  "Select encoding of input files");
683         put_help("-fmessage-length=LEN",     "Ignored (gcc compatibility)");
684         put_help("-fshort-wchar",            "Type \"wchar_t\" is unsigned short instead of int");
685         put_help("-fshow-column",            "Show the column number in diagnostic messages");
686         put_help("-fsigned-char",            "Type \"char\" is a signed type");
687         put_help("-funsigned-char",          "Type \"char\" is an unsigned type");
688         put_help("--ms",                     "Enable msvc extensions");
689         put_help("--no-ms",                  "Disable msvc extensions");
690         put_help("--gcc",                    "Enable gcc extensions");
691         put_help("--no-gcc",                 "Disable gcc extensions");
692         put_help("-std=STANDARD",            "Specify language standard:");
693         put_choice("c99",                    "ISO C99 standard");
694         put_choice("c89",                    "ISO C89 standard");
695         put_choice("c90",                    "Same as -std=c89");
696         put_choice("c11",                    "ISO C11 standard");
697         put_choice("c9x",                    "Deprecated");
698         put_choice("c++",                    "ISO C++ 98");
699         put_choice("c++98",                  "ISO C++ 98");
700         put_choice("gnu99",                  "ISO C99 + GNU extensions (default)");
701         put_choice("gnu89",                  "ISO C89 + GNU extensions");
702         put_choice("gnu11",                  "ISO C11 + GNU extensions");
703         put_choice("gnu9x",                  "Deprecated");
704         put_choice("iso9899:1990",           "ISO C89");
705         put_choice("iso9899:199409",         "ISO C90");
706         put_choice("iso9899:1999",           "ISO C99");
707         put_choice("iso9899:199x",           "Deprecated");
708         put_help("-pedantic",                "Ignored (gcc compatibility)");
709         put_help("-ansi",                    "-std=c90 (for C) or -std=c++98 (for C++)");
710         put_help("--strict",                 "Enable strict conformance checking");
711 }
712
713 static void print_help_warnings(void)
714 {
715         put_help("-f[no-]diagnostics-show-option", "Show the switch, which controls a warning, after each warning");
716         put_help("-w",                             "Disable all warnings");
717         put_help("-Wno-trigraphs",                 "Warn if input contains trigraphs");
718         put_help("-Wundef",                        "Warn if an undefined macro is used in an #if");
719         put_help("-Wmissing-include-dirs",         "Warn about missing user-specified include directories");
720         put_help("-Wendif-labels",                 "Warn about stray text after #elif and #endif");
721         put_help("-Winit-self",                    "Ignored (gcc compatibility)");
722         put_help("-Wformat-y2k",                   "Ignored (gcc compatibility)");
723         put_help("-Wformat-security",              "Ignored (gcc compatibility)");
724         put_help("-Wold-style-declaration",        "Ignored (gcc compatibility)");
725         put_help("-Wtype-limits",                  "Ignored (gcc compatibility)");
726         print_warning_opt_help();
727 }
728
729 static void print_help_optimization(void)
730 {
731         put_help("-O LEVEL",                 "Select optimization level (0-4)");
732         firm_option_help(put_help);
733         put_help("-fexpensive-optimizations","Ignored (gcc compatibility)");
734 }
735
736 static void print_help_codegeneration(void)
737 {
738         put_help("-g",                       "Generate debug information");
739         put_help("-pg",                      "Instrument code for gnu gprof");
740         put_help("-fomit-frame-pointer",     "Produce code without frame pointer where possible");
741         put_help("-ffreestanding",           "Compile in freestanding mode (see ISO C standard)");
742         put_help("-fhosted",                 "Compile in hosted (not freestanding) mode");
743         put_help("-fprofile-generate",       "Generate instrumented code to collect profile information");
744         put_help("-fprofile-use",            "Use profile information generated by instrumented binaries");
745         put_help("-ffp-precise",             "Precise floating point model");
746         put_help("-ffp-fast",                "Imprecise floating point model");
747         put_help("-ffp-strict",              "Strict floating point model");
748         put_help("-pthread",                 "Use pthread threading library");
749         put_help("-mtarget=TARGET",          "Specify target architecture as CPU-manufacturer-OS triple");
750         put_help("-mtriple=TARGET",          "Alias for -mtarget (clang compatibility)");
751         put_help("-march=ARCH",              "");
752         put_help("-mtune=ARCH",              "");
753         put_help("-mcpu=CPU",                "");
754         put_help("-mfpmath=",                "");
755         put_help("-mpreferred-stack-boundary=", "");
756         put_help("-mrtd",                    "");
757         put_help("-mregparm=",               "Not supported yet");
758         put_help("-msoft-float",             "Not supported yet");
759         put_help("-m32",                     "Generate 32bit code");
760         put_help("-m64",                     "Generate 64bit code");
761         put_help("-fverbose-asm",            "Ignored (gcc compatibility)");
762         put_help("-fjump-tables",            "Ignored (gcc compatibility)");
763         put_help("-fcommon",                 "Ignored (gcc compatibility)");
764         put_help("-foptimize-sibling-calls", "Ignored (gcc compatibility)");
765         put_help("-falign-loops",            "Ignored (gcc compatibility)");
766         put_help("-falign-jumps",            "Ignored (gcc compatibility)");
767         put_help("-falign-functions",        "Ignored (gcc compatibility)");
768         put_help("-fPIC",                    "Ignored (gcc compatibility)");
769         put_help("-ffast-math",              "Same as -ffp-fast (gcc compatibility)");
770         puts("");
771         puts("\tMost of these options can be used with a no- prefix to disable them");
772         puts("\te.g. -fno-omit-frame-pointer");
773 }
774
775 static void print_help_linker(void)
776 {
777         put_help("-l LIBRARY",               "");
778         put_help("-L PATH",                  "");
779         put_help("-s",                       "Do not produce symbol table and relocation information");
780         put_help("-shared",                  "Produce a shared library");
781         put_help("-static",                  "Produce statically linked binary");
782         put_help("-Wl,OPTION",               "Pass option directly to linker");
783 }
784
785 static void print_help_debug(void)
786 {
787         put_help("--print-ast",              "Preprocess, parse and print AST");
788         put_help("--print-implicit-cast",    "");
789         put_help("--print-parenthesis",      "");
790         put_help("--benchmark",              "Preprocess and parse, produces no output");
791         put_help("--time",                   "Measure time of compiler passes");
792         put_help("--statev",                 "Produce statev output");
793         put_help("--filtev=filter",          "Set statev filter regex");
794         put_help("--dump-function func",     "Preprocess, parse and output vcg graph of func");
795         put_help("--export-ir",              "Preprocess, parse and output compiler intermediate representation");
796 }
797
798 static void print_help_language_tools(void)
799 {
800         put_help("--print-fluffy",           "Preprocess, parse and generate declarations for the fluffy language");
801         put_help("--print-jna",              "Preprocess, parse and generate declarations for JNA");
802         put_help("--jna-limit filename",     "");
803         put_help("--jna-libname name",       "");
804 }
805
806 static void print_help_firm(void)
807 {
808         put_help("-bOPTION",                 "Directly pass option to libFirm backend");
809         int res = be_parse_arg("help");
810         (void) res;
811         assert(res);
812 }
813
814 typedef enum {
815         HELP_NONE          = 0,
816         HELP_BASIC         = 1 << 0,
817         HELP_PREPROCESSOR  = 1 << 1,
818         HELP_PARSER        = 1 << 2,
819         HELP_WARNINGS      = 1 << 3,
820         HELP_OPTIMIZATION  = 1 << 4,
821         HELP_CODEGEN       = 1 << 5,
822         HELP_LINKER        = 1 << 6,
823         HELP_LANGUAGETOOLS = 1 << 7,
824         HELP_DEBUG         = 1 << 8,
825         HELP_FIRM          = 1 << 9,
826
827         HELP_ALL           = -1
828 } help_sections_t;
829
830 static void print_help(const char *argv0, help_sections_t sections)
831 {
832         if (sections & HELP_BASIC)         print_help_basic(argv0);
833         if (sections & HELP_PREPROCESSOR)  print_help_preprocessor();
834         if (sections & HELP_PARSER)        print_help_parser();
835         if (sections & HELP_WARNINGS)      print_help_warnings();
836         if (sections & HELP_OPTIMIZATION)  print_help_optimization();
837         if (sections & HELP_CODEGEN)       print_help_codegeneration();
838         if (sections & HELP_LINKER)        print_help_linker();
839         if (sections & HELP_LANGUAGETOOLS) print_help_language_tools();
840         if (sections & HELP_DEBUG)         print_help_debug();
841         if (sections & HELP_FIRM)          print_help_firm();
842 }
843
844 static void set_be_option(const char *arg)
845 {
846         int res = be_parse_arg(arg);
847         (void) res;
848         assert(res);
849 }
850
851 static compilation_unit_type_t get_unit_type_from_string(const char *string)
852 {
853         if (streq(string, "c") || streq(string, "c-header"))
854                 return COMPILATION_UNIT_C;
855         if (streq(string, "c++") || streq(string, "c++-header"))
856                 return COMPILATION_UNIT_CXX;
857         if (streq(string, "assembler"))
858                 return COMPILATION_UNIT_PREPROCESSED_ASSEMBLER;
859         if (streq(string, "assembler-with-cpp"))
860                 return COMPILATION_UNIT_ASSEMBLER;
861         if (streq(string, "none"))
862                 return COMPILATION_UNIT_AUTODETECT;
863
864         return COMPILATION_UNIT_UNKNOWN;
865 }
866
867 static bool init_os_support(void)
868 {
869         wchar_atomic_kind         = ATOMIC_TYPE_INT;
870         enable_main_collect2_hack = false;
871         define_intmax_types       = false;
872
873         if (firm_is_unixish_os(target_machine)) {
874                 set_create_ld_ident(create_name_linux_elf);
875         } else if (firm_is_darwin_os(target_machine)) {
876                 set_create_ld_ident(create_name_macho);
877                 define_intmax_types = true;
878         } else if (firm_is_windows_os(target_machine)) {
879                 wchar_atomic_kind         = ATOMIC_TYPE_USHORT;
880                 enable_main_collect2_hack = true;
881                 set_create_ld_ident(create_name_win32);
882         } else {
883                 return false;
884         }
885
886         return true;
887 }
888
889 static bool parse_target_triple(const char *arg)
890 {
891         machine_triple_t *triple = firm_parse_machine_triple(arg);
892         if (triple == NULL) {
893                 errorf(NULL, "target-triple '%s' is not in the form 'cpu_type-manufacturer-operating_system'", arg);
894                 return false;
895         }
896         target_machine = triple;
897         return true;
898 }
899
900 static unsigned decide_modulo_shift(unsigned type_size)
901 {
902         if (architecture_modulo_shift == 0)
903                 return 0;
904         if (type_size < architecture_modulo_shift)
905                 return architecture_modulo_shift;
906         return type_size;
907 }
908
909 static bool is_ia32_cpu(const char *architecture)
910 {
911         return streq(architecture, "i386")
912             || streq(architecture, "i486")
913             || streq(architecture, "i586")
914             || streq(architecture, "i686")
915             || streq(architecture, "i786");
916 }
917
918 static const char *setup_isa_from_tripel(const machine_triple_t *machine)
919 {
920         const char *cpu = machine->cpu_type;
921
922         if (is_ia32_cpu(cpu)) {
923                 return "ia32";
924         } else if (streq(cpu, "x86_64")) {
925                 return "amd64";
926         } else if (streq(cpu, "sparc")) {
927                 return "sparc";
928         } else if (streq(cpu, "arm")) {
929                 return "arm";
930         } else {
931                 errorf(NULL, "unknown cpu '%s' in target-triple", cpu);
932                 return NULL;
933         }
934 }
935
936 static const char *setup_target_machine(void)
937 {
938         if (!setup_firm_for_machine(target_machine))
939                 exit(1);
940
941         const char *isa = setup_isa_from_tripel(target_machine);
942
943         if (isa == NULL)
944                 exit(1);
945
946         init_os_support();
947
948         return isa;
949 }
950
951 /**
952  * initialize cparser type properties based on a firm type
953  */
954 static void set_typeprops_type(atomic_type_properties_t* props, ir_type *type)
955 {
956         props->size             = get_type_size_bytes(type);
957         props->alignment        = get_type_alignment_bytes(type);
958         props->struct_alignment = props->alignment;
959 }
960
961 /**
962  * Copy atomic type properties except the integer conversion rank
963  */
964 static void copy_typeprops(atomic_type_properties_t *dest,
965                            const atomic_type_properties_t *src)
966 {
967         dest->size             = src->size;
968         dest->alignment        = src->alignment;
969         dest->struct_alignment = src->struct_alignment;
970         dest->flags            = src->flags;
971 }
972
973 static void init_types_and_adjust(void)
974 {
975         const backend_params *be_params = be_get_backend_param();
976         unsigned machine_size = be_params->machine_size;
977         init_types(machine_size);
978
979         atomic_type_properties_t *props = atomic_type_properties;
980
981         /* adjust types as requested by target architecture */
982         ir_type *type_long_double = be_params->type_long_double;
983         if (type_long_double != NULL) {
984                 set_typeprops_type(&props[ATOMIC_TYPE_LONG_DOUBLE], type_long_double);
985                 atomic_modes[ATOMIC_TYPE_LONG_DOUBLE] = get_type_mode(type_long_double);
986         }
987
988         ir_type *type_long_long = be_params->type_long_long;
989         if (type_long_long != NULL)
990                 set_typeprops_type(&props[ATOMIC_TYPE_LONGLONG], type_long_long);
991
992         ir_type *type_unsigned_long_long = be_params->type_unsigned_long_long;
993         if (type_unsigned_long_long != NULL)
994                 set_typeprops_type(&props[ATOMIC_TYPE_ULONGLONG], type_unsigned_long_long);
995
996         /* operating system ABI specifics */
997         if (firm_is_darwin_os(target_machine)) {
998                 if (is_ia32_cpu(target_machine->cpu_type)) {
999                         props[ATOMIC_TYPE_LONGLONG].struct_alignment    =  4;
1000                         props[ATOMIC_TYPE_ULONGLONG].struct_alignment   =  4;
1001                         props[ATOMIC_TYPE_DOUBLE].struct_alignment      =  4;
1002                         props[ATOMIC_TYPE_LONG_DOUBLE].size             = 16;
1003                         props[ATOMIC_TYPE_LONG_DOUBLE].alignment        = 16;
1004                         props[ATOMIC_TYPE_LONG_DOUBLE].struct_alignment = 16;
1005                 }
1006         } else if (firm_is_windows_os(target_machine)) {
1007                 if (is_ia32_cpu(target_machine->cpu_type)) {
1008                         props[ATOMIC_TYPE_LONGLONG].struct_alignment    =  8;
1009                         props[ATOMIC_TYPE_ULONGLONG].struct_alignment   =  8;
1010                         props[ATOMIC_TYPE_DOUBLE].struct_alignment      =  8;
1011                 } else if (machine_size == 64) {
1012                         /* to ease porting of old c-code microsoft decided to use 32bits
1013                          * even for long */
1014                         props[ATOMIC_TYPE_LONG]  = props[ATOMIC_TYPE_INT];
1015                         props[ATOMIC_TYPE_ULONG] = props[ATOMIC_TYPE_UINT];
1016                 }
1017
1018                 /* on windows long double is not supported */
1019                 props[ATOMIC_TYPE_LONG_DOUBLE] = props[ATOMIC_TYPE_DOUBLE];
1020         } else if (firm_is_unixish_os(target_machine)) {
1021                 if (is_ia32_cpu(target_machine->cpu_type)) {
1022                         props[ATOMIC_TYPE_DOUBLE].struct_alignment    = 4;
1023                         props[ATOMIC_TYPE_LONGLONG].struct_alignment  = 4;
1024                         props[ATOMIC_TYPE_ULONGLONG].struct_alignment = 4;
1025                 }
1026         }
1027
1028         /* stuff decided after processing operating system specifics and
1029          * commandline flags */
1030         if (char_is_signed) {
1031                 props[ATOMIC_TYPE_CHAR].flags |= ATOMIC_TYPE_FLAG_SIGNED;
1032         } else {
1033                 props[ATOMIC_TYPE_CHAR].flags &= ~ATOMIC_TYPE_FLAG_SIGNED;
1034         }
1035         /* copy over wchar_t properties (including rank) */
1036         props[ATOMIC_TYPE_WCHAR_T] = props[wchar_atomic_kind];
1037
1038         /* initialize defaults for unsupported types */
1039         if (type_long_long == NULL) {
1040                 copy_typeprops(&props[ATOMIC_TYPE_LONGLONG], &props[ATOMIC_TYPE_LONG]);
1041         }
1042         if (type_unsigned_long_long == NULL) {
1043                 copy_typeprops(&props[ATOMIC_TYPE_ULONGLONG],
1044                                &props[ATOMIC_TYPE_ULONG]);
1045         }
1046         if (type_long_double == NULL) {
1047                 copy_typeprops(&props[ATOMIC_TYPE_LONG_DOUBLE],
1048                                &props[ATOMIC_TYPE_DOUBLE]);
1049         }
1050
1051         /* initialize firm pointer modes */
1052         char               name[64];
1053         unsigned           bit_size     = machine_size;
1054         unsigned           modulo_shift = decide_modulo_shift(bit_size);
1055
1056         snprintf(name, sizeof(name), "p%u", machine_size);
1057         ir_mode *ptr_mode = new_reference_mode(name, irma_twos_complement, bit_size, modulo_shift);
1058
1059         if (machine_size == 16) {
1060                 set_reference_mode_signed_eq(ptr_mode, mode_Hs);
1061                 set_reference_mode_unsigned_eq(ptr_mode, mode_Hu);
1062         } else if (machine_size == 32) {
1063                 set_reference_mode_signed_eq(ptr_mode, mode_Is);
1064                 set_reference_mode_unsigned_eq(ptr_mode, mode_Iu);
1065         } else if (machine_size == 64) {
1066                 set_reference_mode_signed_eq(ptr_mode, mode_Ls);
1067                 set_reference_mode_unsigned_eq(ptr_mode, mode_Lu);
1068         } else {
1069                 panic("strange machine_size when determining pointer modes");
1070         }
1071
1072         /* Hmm, pointers should be machine size */
1073         set_modeP_data(ptr_mode);
1074         set_modeP_code(ptr_mode);
1075
1076         byte_order_big_endian = be_params->byte_order_big_endian;
1077         if (be_params->modulo_shift_efficient) {
1078                 architecture_modulo_shift = machine_size;
1079         } else {
1080                 architecture_modulo_shift = 0;
1081         }
1082 }
1083
1084 static void setup_cmode(const compilation_unit_t *unit)
1085 {
1086         compilation_unit_type_t type     = unit->type;
1087         lang_standard_t         standard = unit->standard;
1088         if (type == COMPILATION_UNIT_PREPROCESSED_C || type == COMPILATION_UNIT_C) {
1089                 switch (standard) {
1090                 case STANDARD_C89:     c_mode = _C89;                       break;
1091                                                            /* TODO determine difference between these two */
1092                 case STANDARD_C89AMD1: c_mode = _C89;                       break;
1093                 case STANDARD_C99:     c_mode = _C89 | _C99;                break;
1094                 case STANDARD_C11:     c_mode = _C89 | _C99 | _C11;         break;
1095                 case STANDARD_GNU89:   c_mode = _C89 |               _GNUC; break;
1096                 case STANDARD_GNU11:   c_mode = _C89 | _C99 | _C11 | _GNUC; break;
1097
1098                 case STANDARD_ANSI:
1099                 case STANDARD_CXX98:
1100                 case STANDARD_GNUXX98:
1101                 case STANDARD_DEFAULT:
1102                         fprintf(stderr, "warning: command line option \"-std=%s\" is not valid for C\n", str_lang_standard(standard));
1103                         /* FALLTHROUGH */
1104                 case STANDARD_GNU99:   c_mode = _C89 | _C99 | _GNUC; break;
1105                 }
1106         } else if (type == COMPILATION_UNIT_PREPROCESSED_CXX
1107                    || type == COMPILATION_UNIT_CXX) {
1108                 switch (standard) {
1109                 case STANDARD_CXX98: c_mode = _CXX; break;
1110
1111                 case STANDARD_ANSI:
1112                 case STANDARD_C89:
1113                 case STANDARD_C89AMD1:
1114                 case STANDARD_C99:
1115                 case STANDARD_C11:
1116                 case STANDARD_GNU89:
1117                 case STANDARD_GNU99:
1118                 case STANDARD_GNU11:
1119                 case STANDARD_DEFAULT:
1120                         fprintf(stderr, "warning: command line option \"-std=%s\" is not valid for C++\n", str_lang_standard(standard));
1121                         /* FALLTHROUGH */
1122                 case STANDARD_GNUXX98: c_mode = _CXX | _GNUC; break;
1123                 }
1124         }
1125
1126         c_mode |= features_on;
1127         c_mode &= ~features_off;
1128 }
1129
1130 static void determine_unit_standard(compilation_unit_t *unit,
1131                                     lang_standard_t standard)
1132 {
1133         unit->standard = standard;
1134         switch (standard) {
1135         case STANDARD_ANSI:
1136                 switch (unit->type) {
1137                 case COMPILATION_UNIT_C:
1138                 case COMPILATION_UNIT_PREPROCESSED_C:
1139                         unit->standard = STANDARD_C89;
1140                         break;
1141                 case COMPILATION_UNIT_CXX:
1142                 case COMPILATION_UNIT_PREPROCESSED_CXX:
1143                         unit->standard = STANDARD_CXX98;
1144                         break;
1145                 default:
1146                         break;
1147                 }
1148                 break;
1149
1150         case STANDARD_DEFAULT:
1151                 switch (unit->type) {
1152                 case COMPILATION_UNIT_C:
1153                 case COMPILATION_UNIT_PREPROCESSED_C:
1154                         unit->standard = STANDARD_GNU99;
1155                         break;
1156                 case COMPILATION_UNIT_CXX:
1157                 case COMPILATION_UNIT_PREPROCESSED_CXX:
1158                         unit->standard = STANDARD_GNUXX98;
1159                         break;
1160                 default:
1161                         break;
1162                 }
1163                 break;
1164
1165         default:
1166                 break;
1167         }
1168 }
1169
1170 static bool output_preprocessor_tokens(compilation_unit_t *unit, FILE *out)
1171 {
1172         /* just here for gcc compatibility */
1173         fprintf(out, "# 1 \"%s\"\n", unit->name);
1174         fprintf(out, "# 1 \"<built-in>\"\n");
1175         fprintf(out, "# 1 \"<command-line>\"\n");
1176
1177         set_preprocessor_output(out);
1178         switch_pp_input(unit->input, unit->name, NULL, false);
1179
1180         for (;;) {
1181                 next_preprocessing_token();
1182                 if (pp_token.kind == T_EOF)
1183                         break;
1184                 emit_pp_token();
1185         }
1186
1187         fputc('\n', out);
1188         check_unclosed_conditionals();
1189         close_pp_input();
1190         print_error_summary();
1191         set_preprocessor_output(NULL);
1192
1193         if (unit->type == COMPILATION_UNIT_C) {
1194                 unit->type = COMPILATION_UNIT_PREPROCESSED_C;
1195         } else if (unit->type == COMPILATION_UNIT_CXX) {
1196                 unit->type = COMPILATION_UNIT_PREPROCESSED_CXX;
1197         }
1198         bool res = close_input(unit);
1199         return res && error_count == 0;
1200 }
1201
1202 static bool open_input(compilation_unit_t *unit)
1203 {
1204         /* input already available as FILE? */
1205         if (unit->input != NULL)
1206                 return true;
1207
1208         const char *const inputname = unit->name;
1209         unit->input_is_pipe = false;
1210         if (streq(inputname, "-")) {
1211                 unit->input   = stdin;
1212         } else {
1213                 unit->input = fopen(inputname, "r");
1214                 if (unit->input == NULL) {
1215                         source_position_t const pos = { inputname, 0, 0, 0 };
1216                         errorf(&pos, "could not open: %s", strerror(errno));
1217                         return false;
1218                 }
1219         }
1220         return true;
1221 }
1222
1223 static void node_counter(ir_node *node, void *env)
1224 {
1225         (void)node;
1226         unsigned long long *count = (unsigned long long*)env;
1227         ++(*count);
1228 }
1229
1230 static unsigned long long count_firm_nodes(void)
1231 {
1232         unsigned long long count = 0;
1233
1234         int n_irgs = get_irp_n_irgs();
1235         for (int i = 0; i < n_irgs; ++i) {
1236                 ir_graph *irg = get_irp_irg(i);
1237                 irg_walk_graph(irg, node_counter, NULL, &count);
1238         }
1239         return count;
1240 }
1241
1242 static int compilation_loop(compile_mode_t mode, compilation_unit_t *units,
1243                                                         lang_standard_t standard, FILE *out)
1244 {
1245         int  result                   = EXIT_SUCCESS;
1246         bool already_constructed_firm = false;
1247         for (compilation_unit_t *unit = units; unit != NULL; unit = unit->next) {
1248                 const char *const inputname = unit->name;
1249
1250                 determine_unit_standard(unit, standard);
1251                 setup_cmode(unit);
1252
1253                 stat_ev_ctx_push_str("compilation_unit", inputname);
1254
1255 again:
1256                 switch (unit->type) {
1257                 case COMPILATION_UNIT_IR: {
1258                         bool res = open_input(unit);
1259                         if (!res) {
1260                                 result = EXIT_FAILURE;
1261                                 break;
1262                         }
1263                         res = !ir_import_file(unit->input, unit->name);
1264                         if (!res) {
1265                                 source_position_t const pos = { inputname, 0, 0, 0 };
1266                                 errorf(&pos, "import of firm graph failed");
1267                                 result = EXIT_FAILURE;
1268                                 break;
1269                         }
1270                         unit->type = COMPILATION_UNIT_INTERMEDIATE_REPRESENTATION;
1271                         goto again;
1272                 }
1273                 case COMPILATION_UNIT_ASSEMBLER:
1274                         panic("TODO: preprocess for assembler");
1275                 case COMPILATION_UNIT_C:
1276                 case COMPILATION_UNIT_CXX:
1277                         if (external_preprocessor != NULL) {
1278                                 bool res = run_external_preprocessor(unit);
1279                                 if (!res) {
1280                                         result = EXIT_FAILURE;
1281                                         break;
1282                                 }
1283                                 goto again;
1284                         }
1285                         /* FALLTHROUGH */
1286
1287                 case COMPILATION_UNIT_PREPROCESSED_C:
1288                 case COMPILATION_UNIT_PREPROCESSED_CXX: {
1289                         bool res = open_input(unit);
1290                         if (!res) {
1291                                 result = EXIT_FAILURE;
1292                                 break;
1293                         }
1294                         init_tokens();
1295
1296                         if (mode == PreprocessOnly) {
1297                                 bool res = output_preprocessor_tokens(unit, out);
1298                                 if (!res) {
1299                                         result = EXIT_FAILURE;
1300                                         break;
1301                                 }
1302                                 break;
1303                         }
1304
1305                         /* do the actual parsing */
1306                         do_parsing(unit);
1307                         goto again;
1308                 }
1309                 case COMPILATION_UNIT_AST:
1310                         /* prints the AST even if errors occurred */
1311                         if (mode == PrintAst) {
1312                                 print_to_file(out);
1313                                 print_ast(unit->ast);
1314                         }
1315                         if (unit->parse_errors) {
1316                                 result = EXIT_FAILURE;
1317                                 break;
1318                         }
1319
1320                         if (mode == BenchmarkParser) {
1321                                 break;
1322                         } else if (mode == PrintFluffy) {
1323                                 write_fluffy_decls(out, unit->ast);
1324                                 break;
1325                         } else if (mode == PrintJna) {
1326                                 write_jna_decls(out, unit->ast);
1327                                 break;
1328                         } else if (mode == PrintCompoundSizes) {
1329                                 write_compoundsizes(out, unit->ast);
1330                                 break;
1331                         }
1332
1333                         /* build the firm graph */
1334                         ir_timer_t *t_construct = ir_timer_new();
1335                         timer_register(t_construct, "Frontend: Graph construction");
1336                         timer_start(t_construct);
1337                         if (already_constructed_firm) {
1338                                 panic("compiling multiple files/translation units not possible");
1339                         }
1340                         init_implicit_optimizations();
1341                         translation_unit_to_firm(unit->ast);
1342                         already_constructed_firm = true;
1343                         timer_stop(t_construct);
1344                         if (stat_ev_enabled) {
1345                                 stat_ev_dbl("time_graph_construction", ir_timer_elapsed_sec(t_construct));
1346                                 stat_ev_int("size_graph_construction", count_firm_nodes());
1347                         }
1348                         unit->type = COMPILATION_UNIT_INTERMEDIATE_REPRESENTATION;
1349                         goto again;
1350
1351                 case COMPILATION_UNIT_INTERMEDIATE_REPRESENTATION:
1352                         if (mode == ParseOnly)
1353                                 break;
1354
1355                         if (mode == CompileDump) {
1356                                 /* find irg */
1357                                 ident    *id     = new_id_from_str(dumpfunction);
1358                                 ir_graph *irg    = NULL;
1359                                 int       n_irgs = get_irp_n_irgs();
1360                                 for (int i = 0; i < n_irgs; ++i) {
1361                                         ir_graph *tirg   = get_irp_irg(i);
1362                                         ident    *irg_id = get_entity_ident(get_irg_entity(tirg));
1363                                         if (irg_id == id) {
1364                                                 irg = tirg;
1365                                                 break;
1366                                         }
1367                                 }
1368
1369                                 if (irg == NULL) {
1370                                         errorf(NULL, "no graph for function '%s' found", dumpfunction);
1371                                         return EXIT_FAILURE;
1372                                 }
1373
1374                                 dump_ir_graph_file(out, irg);
1375                                 fclose(out);
1376                                 return EXIT_SUCCESS;
1377                         }
1378
1379                         if (mode == CompileExportIR) {
1380                                 ir_export_file(out);
1381                                 if (ferror(out) != 0) {
1382                                         errorf(NULL, "writing to output failed");
1383                                         return EXIT_FAILURE;
1384                                 }
1385                                 return EXIT_SUCCESS;
1386                         }
1387
1388                         FILE *asm_out;
1389                         if (mode == Compile) {
1390                                 asm_out = out;
1391                         } else {
1392                                 asm_out = make_temp_file("ccs", &unit->name);
1393                         }
1394                         ir_timer_t *t_opt_codegen = ir_timer_new();
1395                         timer_register(t_opt_codegen, "Optimization and Codegeneration");
1396                         timer_start(t_opt_codegen);
1397                         generate_code(asm_out, inputname);
1398                         timer_stop(t_opt_codegen);
1399                         if (stat_ev_enabled) {
1400                                 stat_ev_dbl("time_opt_codegen", ir_timer_elapsed_sec(t_opt_codegen));
1401                         }
1402                         if (asm_out != out) {
1403                                 fclose(asm_out);
1404                         }
1405                         unit->type = COMPILATION_UNIT_PREPROCESSED_ASSEMBLER;
1406                         goto again;
1407                 case COMPILATION_UNIT_PREPROCESSED_ASSEMBLER:
1408                         if (mode != CompileAssemble && mode != CompileAssembleLink)
1409                                 break;
1410
1411                         /* assemble */
1412                         const char *input = unit->name;
1413                         if (mode == CompileAssemble) {
1414                                 fclose(out);
1415                                 unit->name = outname;
1416                         } else {
1417                                 FILE *tempf = make_temp_file("cco", &unit->name);
1418                                 /* hackish... */
1419                                 fclose(tempf);
1420                         }
1421
1422                         assemble(unit->name, input);
1423
1424                         unit->type = COMPILATION_UNIT_OBJECT;
1425                         goto again;
1426                 case COMPILATION_UNIT_UNKNOWN:
1427                 case COMPILATION_UNIT_AUTODETECT:
1428                 case COMPILATION_UNIT_OBJECT:
1429                         break;
1430                 }
1431
1432                 stat_ev_ctx_pop("compilation_unit");
1433         }
1434         return result;
1435 }
1436
1437 static int link_program(compilation_unit_t *units)
1438 {
1439         obstack_1grow(&ldflags_obst, '\0');
1440         const char *flags = obstack_finish(&ldflags_obst);
1441
1442         /* construct commandline */
1443         const char *linker = getenv("CPARSER_LINK");
1444         if (linker != NULL) {
1445                 obstack_printf(&file_obst, "%s ", linker);
1446         } else {
1447                 if (target_triple != NULL)
1448                         obstack_printf(&file_obst, "%s-", target_triple);
1449                 obstack_printf(&file_obst, "%s ", LINKER);
1450         }
1451
1452         for (compilation_unit_t *unit = units; unit != NULL; unit = unit->next) {
1453                 if (unit->type != COMPILATION_UNIT_OBJECT)
1454                         continue;
1455
1456                 add_flag(&file_obst, "%s", unit->name);
1457         }
1458
1459         add_flag(&file_obst, "-o");
1460         add_flag(&file_obst, outname);
1461         obstack_printf(&file_obst, "%s", flags);
1462         obstack_1grow(&file_obst, '\0');
1463
1464         char *commandline = obstack_finish(&file_obst);
1465
1466         if (verbose) {
1467                 puts(commandline);
1468         }
1469         int err = system(commandline);
1470         if (err != EXIT_SUCCESS) {
1471                 errorf(NULL, "linker reported an error");
1472                 return EXIT_FAILURE;
1473         }
1474         return EXIT_SUCCESS;
1475 }
1476
1477 int main(int argc, char **argv)
1478 {
1479         const char         *print_file_name_file = NULL;
1480         compile_mode_t      mode                 = CompileAssembleLink;
1481         int                 opt_level            = 1;
1482         char                cpu_arch[16]         = "ia32";
1483         compilation_unit_t *units                = NULL;
1484         compilation_unit_t *last_unit            = NULL;
1485         bool                construct_dep_target = false;
1486         bool                produce_statev       = false;
1487         const char         *filtev               = NULL;
1488         bool                profile_generate     = false;
1489         bool                profile_use          = false;
1490         bool                do_timing            = false;
1491         bool                print_timing         = false;
1492
1493         /* hack for now... */
1494         if (strstr(argv[0], "pptest") != NULL) {
1495                 extern int pptest_main(int argc, char **argv);
1496                 return pptest_main(argc, argv);
1497         }
1498
1499         temp_files = NEW_ARR_F(char*, 0);
1500         atexit(free_temp_files);
1501
1502         obstack_init(&cppflags_obst);
1503         obstack_init(&ldflags_obst);
1504         obstack_init(&asflags_obst);
1505         obstack_init(&file_obst);
1506         init_include_paths();
1507
1508 #define GET_ARG_AFTER(def, args)                                             \
1509         do {                                                                     \
1510         def = &arg[sizeof(args)-1];                                              \
1511         if (def[0] == '\0') {                                                    \
1512                 ++i;                                                                 \
1513                 if (i >= argc) {                                                     \
1514                         errorf(NULL, "expected argument after '" args "'"); \
1515                         argument_errors = true;                                          \
1516                         break;                                                           \
1517                 }                                                                    \
1518                 def = argv[i];                                                       \
1519                 if (def[0] == '-' && def[1] != '\0') {                               \
1520                         errorf(NULL, "expected argument after '" args "'"); \
1521                         argument_errors = true;                                          \
1522                         continue;                                                        \
1523                 }                                                                    \
1524         }                                                                        \
1525         } while (0)
1526
1527 #define SINGLE_OPTION(ch) (option[0] == (ch) && option[1] == '\0')
1528
1529         /* initialize this early because it has to parse options */
1530         gen_firm_init();
1531
1532         /* early options parsing (find out optimization level and OS) */
1533         for (int i = 1; i < argc; ++i) {
1534                 const char *arg = argv[i];
1535                 if (arg[0] != '-')
1536                         continue;
1537
1538                 const char *option = &arg[1];
1539                 if (option[0] == 'O') {
1540                         sscanf(&option[1], "%d", &opt_level);
1541                 }
1542         }
1543
1544         if (target_machine == NULL) {
1545                 target_machine = firm_get_host_machine();
1546         }
1547         choose_optimization_pack(opt_level);
1548         setup_target_machine();
1549
1550         /* parse rest of options */
1551         lang_standard_t         standard        = STANDARD_DEFAULT;
1552         compilation_unit_type_t forced_unittype = COMPILATION_UNIT_AUTODETECT;
1553         help_sections_t         help            = HELP_NONE;
1554         bool                    argument_errors = false;
1555         for (int i = 1; i < argc; ++i) {
1556                 const char *arg = argv[i];
1557                 if (arg[0] == '-' && arg[1] != '\0') {
1558                         /* an option */
1559                         const char *option = &arg[1];
1560                         if (option[0] == 'o') {
1561                                 GET_ARG_AFTER(outname, "-o");
1562                         } else if (option[0] == 'g') {
1563                                 /* TODO: parse -gX with 0<=x<=3... */
1564                                 set_be_option("debug=frameinfo");
1565                                 set_be_option("ia32-nooptcc=yes");
1566                         } else if (SINGLE_OPTION('c')) {
1567                                 mode = CompileAssemble;
1568                         } else if (SINGLE_OPTION('E')) {
1569                                 mode = PreprocessOnly;
1570                         } else if (SINGLE_OPTION('s')) {
1571                                 add_flag(&ldflags_obst, "-s");
1572                         } else if (SINGLE_OPTION('S')) {
1573                                 mode = Compile;
1574                         } else if (option[0] == 'O') {
1575                                 continue;
1576                         } else if (option[0] == 'I') {
1577                                 const char *opt;
1578                                 GET_ARG_AFTER(opt, "-I");
1579                                 add_flag(&cppflags_obst, "-I%s", opt);
1580                                 append_include_path(&bracket_searchpath, opt);
1581                         } else if (option[0] == 'D') {
1582                                 const char *opt;
1583                                 GET_ARG_AFTER(opt, "-D");
1584                                 add_flag(&cppflags_obst, "-D%s", opt);
1585                         } else if (option[0] == 'U') {
1586                                 const char *opt;
1587                                 GET_ARG_AFTER(opt, "-U");
1588                                 add_flag(&cppflags_obst, "-U%s", opt);
1589                         } else if (option[0] == 'l') {
1590                                 const char *opt;
1591                                 GET_ARG_AFTER(opt, "-l");
1592                                 add_flag(&ldflags_obst, "-l%s", opt);
1593                         } else if (option[0] == 'L') {
1594                                 const char *opt;
1595                                 GET_ARG_AFTER(opt, "-L");
1596                                 add_flag(&ldflags_obst, "-L%s", opt);
1597                         } else if (SINGLE_OPTION('v')) {
1598                                 verbose = 1;
1599                         } else if (SINGLE_OPTION('w')) {
1600                                 add_flag(&cppflags_obst, "-w");
1601                                 disable_all_warnings();
1602                         } else if (option[0] == 'x') {
1603                                 const char *opt;
1604                                 GET_ARG_AFTER(opt, "-x");
1605                                 forced_unittype = get_unit_type_from_string(opt);
1606                                 if (forced_unittype == COMPILATION_UNIT_UNKNOWN) {
1607                                         errorf(NULL, "unknown language '%s'", opt);
1608                                         argument_errors = true;
1609                                 }
1610                         } else if (streq(option, "M")) {
1611                                 mode = PreprocessOnly;
1612                                 add_flag(&cppflags_obst, "-M");
1613                         } else if (streq(option, "MMD") ||
1614                                    streq(option, "MD")) {
1615                             construct_dep_target = true;
1616                                 add_flag(&cppflags_obst, "-%s", option);
1617                         } else if (streq(option, "MM")  ||
1618                                    streq(option, "MP")) {
1619                                 add_flag(&cppflags_obst, "-%s", option);
1620                         } else if (streq(option, "MT") ||
1621                                    streq(option, "MQ") ||
1622                                    streq(option, "MF")) {
1623                                 const char *opt;
1624                                 GET_ARG_AFTER(opt, "-MT");
1625                                 add_flag(&cppflags_obst, "-%s", option);
1626                                 add_flag(&cppflags_obst, "%s", opt);
1627                         } else if (streq(option, "include")) {
1628                                 const char *opt;
1629                                 GET_ARG_AFTER(opt, "-include");
1630                                 add_flag(&cppflags_obst, "-include");
1631                                 add_flag(&cppflags_obst, "%s", opt);
1632                         } else if (streq(option, "idirafter")) {
1633                                 const char *opt;
1634                                 GET_ARG_AFTER(opt, "-idirafter");
1635                                 add_flag(&cppflags_obst, "-idirafter");
1636                                 add_flag(&cppflags_obst, "%s", opt);
1637                                 append_include_path(&after_searchpath, opt);
1638                         } else if (streq(option, "isystem")) {
1639                                 const char *opt;
1640                                 GET_ARG_AFTER(opt, "-isystem");
1641                                 add_flag(&cppflags_obst, "-isystem");
1642                                 add_flag(&cppflags_obst, "%s", opt);
1643                                 append_include_path(&system_searchpath, opt);
1644                         } else if (streq(option, "iquote")) {
1645                                 const char *opt;
1646                                 GET_ARG_AFTER(opt, "-iquote");
1647                                 add_flag(&cppflags_obst, "-iquote");
1648                                 add_flag(&cppflags_obst, "%s", opt);
1649                                 append_include_path(&quote_searchpath, opt);
1650                         } else if (streq(option, "pthread")) {
1651                                 /* set flags for the preprocessor */
1652                                 add_flag(&cppflags_obst, "-D_REENTRANT");
1653                                 /* set flags for the linker */
1654                                 add_flag(&ldflags_obst, "-lpthread");
1655                         } else if (streq(option, "nostdinc")
1656                                         || streq(option, "trigraphs")) {
1657                                 /* pass these through to the preprocessor */
1658                                 add_flag(&cppflags_obst, "%s", arg);
1659                         } else if (streq(option, "pipe")) {
1660                                 /* here for gcc compatibility */
1661                         } else if (streq(option, "static")) {
1662                                 add_flag(&ldflags_obst, "-static");
1663                         } else if (streq(option, "shared")) {
1664                                 add_flag(&ldflags_obst, "-shared");
1665                         } else if (option[0] == 'f') {
1666                                 char const *orig_opt;
1667                                 GET_ARG_AFTER(orig_opt, "-f");
1668
1669                                 if (strstart(orig_opt, "input-charset=")) {
1670                                         char const* const encoding = strchr(orig_opt, '=') + 1;
1671                                         input_encoding = encoding;
1672                                 } else if (strstart(orig_opt, "align-loops=") ||
1673                                            strstart(orig_opt, "align-jumps=") ||
1674                                            strstart(orig_opt, "align-functions=")) {
1675                                         fprintf(stderr, "ignoring gcc option '-f%s'\n", orig_opt);
1676                                 } else if (strstart(orig_opt, "visibility=")) {
1677                                         const char *val = strchr(orig_opt, '=')+1;
1678                                         elf_visibility_tag_t visibility
1679                                                 = get_elf_visibility_from_string(val);
1680                                         if (visibility == ELF_VISIBILITY_ERROR) {
1681                                                 errorf(NULL, "invalid visibility '%s' specified", val);
1682                                                 argument_errors = true;
1683                                         } else {
1684                                                 set_default_visibility(visibility);
1685                                         }
1686                                 } else if (strstart(orig_opt, "message-length=")) {
1687                                         /* ignore: would only affect error message format */
1688                                 } else if (streq(orig_opt, "fast-math") ||
1689                                            streq(orig_opt, "fp-fast")) {
1690                                         firm_fp_model = fp_model_fast;
1691                                 } else if (streq(orig_opt, "fp-precise")) {
1692                                         firm_fp_model = fp_model_precise;
1693                                 } else if (streq(orig_opt, "fp-strict")) {
1694                                         firm_fp_model = fp_model_strict;
1695                                 } else if (streq(orig_opt, "help")) {
1696                                         fprintf(stderr, "warning: -fhelp is deprecated\n");
1697                                         help |= HELP_OPTIMIZATION;
1698                                 } else {
1699                                         /* -f options which have an -fno- variant */
1700                                         char const *opt         = orig_opt;
1701                                         bool        truth_value = true;
1702                                         if (opt[0] == 'n' && opt[1] == 'o' && opt[2] == '-') {
1703                                                 truth_value = false;
1704                                                 opt += 3;
1705                                         }
1706
1707                                         if (streq(opt, "diagnostics-show-option")) {
1708                                                 diagnostics_show_option = truth_value;
1709                                         } else if (streq(opt, "dollars-in-identifiers")) {
1710                                                 allow_dollar_in_symbol = truth_value;
1711                                         } else if (streq(opt, "omit-frame-pointer")) {
1712                                                 set_be_option(truth_value ? "omitfp" : "omitfp=no");
1713                                         } else if (streq(opt, "short-wchar")) {
1714                                                 wchar_atomic_kind = truth_value ? ATOMIC_TYPE_USHORT
1715                                                         : ATOMIC_TYPE_INT;
1716                                         } else if (streq(opt, "show-column")) {
1717                                                 show_column = truth_value;
1718                                         } else if (streq(opt, "signed-char")) {
1719                                                 char_is_signed = truth_value;
1720                                         } else if (streq(opt, "strength-reduce")) {
1721                                                 /* does nothing, for gcc compatibility (even gcc does
1722                                                  * nothing for this switch anymore) */
1723                                         } else if (streq(opt, "syntax-only")) {
1724                                                 mode = truth_value ? ParseOnly : CompileAssembleLink;
1725                                         } else if (streq(opt, "unsigned-char")) {
1726                                                 char_is_signed = !truth_value;
1727                                         } else if (streq(opt, "freestanding")) {
1728                                                 freestanding = truth_value;
1729                                         } else if (streq(opt, "hosted")) {
1730                                                 freestanding = !truth_value;
1731                                         } else if (streq(opt, "profile-generate")) {
1732                                                 profile_generate = truth_value;
1733                                         } else if (streq(opt, "profile-use")) {
1734                                                 profile_use = truth_value;
1735                                         } else if (!truth_value &&
1736                                                    streq(opt, "asynchronous-unwind-tables")) {
1737                                             /* nothing todo, a gcc feature which we do not support
1738                                              * anyway was deactivated */
1739                                         } else if (streq(opt, "verbose-asm")) {
1740                                                 /* ignore: we always print verbose assembler */
1741                                         } else if (streq(opt, "jump-tables")             ||
1742                                                    streq(opt, "expensive-optimizations") ||
1743                                                    streq(opt, "common")                  ||
1744                                                    streq(opt, "optimize-sibling-calls")  ||
1745                                                    streq(opt, "align-loops")             ||
1746                                                    streq(opt, "align-jumps")             ||
1747                                                    streq(opt, "align-functions")         ||
1748                                                    streq(opt, "PIC")                     ||
1749                                                    streq(opt, "stack-protector")         ||
1750                                                    streq(opt, "stack-protector-all")) {
1751                                                 fprintf(stderr, "ignoring gcc option '-f%s'\n", orig_opt);
1752                                         } else {
1753                                                 int res = firm_option(orig_opt);
1754                                                 if (res == 0) {
1755                                                         errorf(NULL, "unknown Firm option '-f%s'", orig_opt);
1756                                                         argument_errors = true;
1757                                                         continue;
1758                                                 }
1759                                         }
1760                                 }
1761                         } else if (option[0] == 'b') {
1762                                 const char *opt;
1763                                 GET_ARG_AFTER(opt, "-b");
1764
1765                                 if (streq(opt, "help")) {
1766                                         fprintf(stderr, "warning: -bhelp is deprecated (use --help-firm)\n");
1767                                         help |= HELP_FIRM;
1768                                 } else {
1769                                         int res = be_parse_arg(opt);
1770                                         if (res == 0) {
1771                                                 errorf(NULL, "unknown Firm backend option '-b %s'", 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                                                 errorf(NULL, "unknown architecture '%s'", 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                                                 errorf(NULL, "option -mfpmath supports only 387 or sse");
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                                         errorf(NULL, "regparm convention not supported yet");
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                                                 errorf(NULL, "wrong option '-m %s'",  opt);
1890                                                 argument_errors = true;
1891                                         } else if (value != 16 && value != 32 && value != 64) {
1892                                                 errorf(NULL, "option -m supports only 16, 32 or 64");
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                                                 errorf(NULL, "expected argument after '--jna-limit'");
1976                                                 argument_errors = true;
1977                                                 break;
1978                                         }
1979                                         jna_limit_output(argv[i]);
1980                                 } else if (streq(option, "jna-libname")) {
1981                                         ++i;
1982                                         if (i >= argc) {
1983                                                 errorf(NULL, "expected argument after '--jna-libname'");
1984                                                 argument_errors = true;
1985                                                 break;
1986                                         }
1987                                         jna_set_libname(argv[i]);
1988                                 } else if (streq(option, "external-pp")) {
1989                                         if (i+1 < argc && argv[i+1][0] != '-') {
1990                                                 ++i;
1991                                                 external_preprocessor = argv[i+1];
1992                                         } else {
1993                                                 external_preprocessor = PREPROCESSOR;
1994                                         }
1995                                 } else if (streq(option, "no-external-pp")) {
1996                                         external_preprocessor = NULL;
1997                                 } else if (streq(option, "time")) {
1998                                         do_timing    = true;
1999                                         print_timing = true;
2000                                 } else if (streq(option, "statev")) {
2001                                         do_timing      = true;
2002                                         produce_statev = true;
2003                                 } else if (strstart(option, "filtev=")) {
2004                                         GET_ARG_AFTER(filtev, "--filtev=");
2005                                 } else if (streq(option, "version")) {
2006                                         print_cparser_version();
2007                                         return EXIT_SUCCESS;
2008                                 } else if (streq(option, "help")) {
2009                                         help |= HELP_BASIC;
2010                                 } else if (streq(option, "help-parser")) {
2011                                         help |= HELP_PARSER;
2012                                 } else if (streq(option, "help-warnings")) {
2013                                         help |= HELP_WARNINGS;
2014                                 } else if (streq(option, "help-codegen")) {
2015                                         help |= HELP_CODEGEN;
2016                                 } else if (streq(option, "help-linker")) {
2017                                         help |= HELP_LINKER;
2018                                 } else if (streq(option, "help-optimization")) {
2019                                         help |= HELP_OPTIMIZATION;
2020                                 } else if (streq(option, "help-language-tools")) {
2021                                         help |= HELP_LANGUAGETOOLS;
2022                                 } else if (streq(option, "help-debug")) {
2023                                         help |= HELP_DEBUG;
2024                                 } else if (streq(option, "help-firm")) {
2025                                         help |= HELP_FIRM;
2026                                 } else if (streq(option, "help-all")) {
2027                                         help |= HELP_ALL;
2028                                 } else if (streq(option, "dump-function")) {
2029                                         ++i;
2030                                         if (i >= argc) {
2031                                                 errorf(NULL, "expected argument after '--dump-function'");
2032                                                 argument_errors = true;
2033                                                 break;
2034                                         }
2035                                         dumpfunction = argv[i];
2036                                         mode         = CompileDump;
2037                                 } else if (streq(option, "export-ir")) {
2038                                         mode = CompileExportIR;
2039                                 } else if (streq(option, "unroll-loops")) {
2040                                         /* ignore (gcc compatibility) */
2041                                 } else {
2042                                         errorf(NULL, "unknown argument '%s'", arg);
2043                                         argument_errors = true;
2044                                 }
2045                         } else {
2046                                 errorf(NULL, "unknown argument '%s'", arg);
2047                                 argument_errors = true;
2048                         }
2049                 } else {
2050                         compilation_unit_type_t type = forced_unittype;
2051                         if (type == COMPILATION_UNIT_AUTODETECT) {
2052                                 if (streq(arg, "-")) {
2053                                         /* - implicitly means C source file */
2054                                         type = COMPILATION_UNIT_C;
2055                                 } else {
2056                                         const char *suffix = strrchr(arg, '.');
2057                                         /* Ensure there is at least one char before the suffix */
2058                                         if (suffix != NULL && suffix != arg) {
2059                                                 ++suffix;
2060                                                 type =
2061                                                         streq(suffix, "S")   ? COMPILATION_UNIT_ASSEMBLER              :
2062                                                         streq(suffix, "a")   ? COMPILATION_UNIT_OBJECT                 :
2063                                                         streq(suffix, "c")   ? COMPILATION_UNIT_C                      :
2064                                                         streq(suffix, "i")   ? COMPILATION_UNIT_PREPROCESSED_C         :
2065                                                         streq(suffix, "C")   ? COMPILATION_UNIT_CXX                    :
2066                                                         streq(suffix, "cc")  ? COMPILATION_UNIT_CXX                    :
2067                                                         streq(suffix, "cp")  ? COMPILATION_UNIT_CXX                    :
2068                                                         streq(suffix, "cpp") ? COMPILATION_UNIT_CXX                    :
2069                                                         streq(suffix, "CPP") ? COMPILATION_UNIT_CXX                    :
2070                                                         streq(suffix, "cxx") ? COMPILATION_UNIT_CXX                    :
2071                                                         streq(suffix, "c++") ? COMPILATION_UNIT_CXX                    :
2072                                                         streq(suffix, "ii")  ? COMPILATION_UNIT_PREPROCESSED_CXX       :
2073                                                         streq(suffix, "h")   ? COMPILATION_UNIT_C                      :
2074                                                         streq(suffix, "ir")  ? COMPILATION_UNIT_IR                     :
2075                                                         streq(suffix, "o")   ? COMPILATION_UNIT_OBJECT                 :
2076                                                         streq(suffix, "s")   ? COMPILATION_UNIT_PREPROCESSED_ASSEMBLER :
2077                                                         streq(suffix, "so")  ? COMPILATION_UNIT_OBJECT                 :
2078                                                         COMPILATION_UNIT_OBJECT; /* gcc behavior: unknown file extension means object file */
2079                                         }
2080                                 }
2081                         }
2082
2083                         compilation_unit_t *entry = OALLOCZ(&file_obst, compilation_unit_t);
2084                         entry->name = arg;
2085                         entry->type = type;
2086
2087                         if (last_unit != NULL) {
2088                                 last_unit->next = entry;
2089                         } else {
2090                                 units = entry;
2091                         }
2092                         last_unit = entry;
2093                 }
2094         }
2095
2096         if (help != HELP_NONE) {
2097                 print_help(argv[0], help);
2098                 return !argument_errors;
2099         }
2100
2101         if (print_file_name_file != NULL) {
2102                 print_file_name(print_file_name_file);
2103                 return EXIT_SUCCESS;
2104         }
2105         if (units == NULL) {
2106                 errorf(NULL, "no input files specified");
2107                 argument_errors = true;
2108         }
2109
2110         if (argument_errors) {
2111                 usage(argv[0]);
2112                 return EXIT_FAILURE;
2113         }
2114
2115         /* apply some effects from switches */
2116         c_mode |= features_on;
2117         c_mode &= ~features_off;
2118         if (profile_generate) {
2119                 add_flag(&ldflags_obst, "-lfirmprof");
2120                 set_be_option("profilegenerate");
2121         }
2122         if (profile_use) {
2123                 set_be_option("profileuse");
2124         }
2125
2126         init_symbol_table();
2127         init_types_and_adjust();
2128         init_typehash();
2129         init_basic_types();
2130         if (c_mode & _CXX) {
2131                 init_wchar_types(ATOMIC_TYPE_WCHAR_T);
2132         } else {
2133                 init_wchar_types(wchar_atomic_kind);
2134         }
2135         init_preprocessor();
2136         init_ast();
2137         init_parser();
2138         init_ast2firm();
2139         init_mangle();
2140
2141         if (do_timing)
2142                 timer_init();
2143
2144         if (construct_dep_target) {
2145                 if (outname != 0 && strlen(outname) >= 2) {
2146                         get_output_name(dep_target, sizeof(dep_target), outname, ".d");
2147                 } else {
2148                         get_output_name(dep_target, sizeof(dep_target), units->name, ".d");
2149                 }
2150         } else {
2151                 dep_target[0] = '\0';
2152         }
2153
2154         char outnamebuf[4096];
2155         if (outname == NULL) {
2156                 const char *filename = units->name;
2157
2158                 switch(mode) {
2159                 case BenchmarkParser:
2160                 case PrintAst:
2161                 case PrintFluffy:
2162                 case PrintJna:
2163                 case PrintCompoundSizes:
2164                 case PreprocessOnly:
2165                 case ParseOnly:
2166                         outname = "-";
2167                         break;
2168                 case Compile:
2169                         get_output_name(outnamebuf, sizeof(outnamebuf), filename, ".s");
2170                         outname = outnamebuf;
2171                         break;
2172                 case CompileAssemble:
2173                         get_output_name(outnamebuf, sizeof(outnamebuf), filename, ".o");
2174                         outname = outnamebuf;
2175                         break;
2176                 case CompileDump:
2177                         get_output_name(outnamebuf, sizeof(outnamebuf), dumpfunction,
2178                                         ".vcg");
2179                         outname = outnamebuf;
2180                         break;
2181                 case CompileExportIR:
2182                         get_output_name(outnamebuf, sizeof(outnamebuf), filename, ".ir");
2183                         outname = outnamebuf;
2184                         break;
2185                 case CompileAssembleLink:
2186                         if (firm_is_windows_os(target_machine)) {
2187                                 outname = "a.exe";
2188                         } else {
2189                                 outname = "a.out";
2190                         }
2191                         break;
2192                 }
2193         }
2194
2195         assert(outname != NULL);
2196
2197         FILE *out;
2198         if (streq(outname, "-")) {
2199                 out = stdout;
2200         } else {
2201                 out = fopen(outname, "w");
2202                 if (out == NULL) {
2203                         source_position_t const pos = { outname, 0, 0, 0 };
2204                         errorf(&pos, "could not open for writing: %s", strerror(errno));
2205                         return EXIT_FAILURE;
2206                 }
2207         }
2208
2209         if (produce_statev && units != NULL) {
2210                 /* attempt to guess a good name for the file */
2211                 const char *first_cup = units->name;
2212                 if (first_cup != NULL) {
2213                         const char *dot = strrchr(first_cup, '.');
2214                         const char *pos = dot ? dot : first_cup + strlen(first_cup);
2215                         char        buf[pos-first_cup+1];
2216                         strncpy(buf, first_cup, pos-first_cup);
2217                         buf[pos-first_cup] = '\0';
2218
2219                         stat_ev_begin(buf, filtev);
2220                 }
2221         }
2222
2223         int result = compilation_loop(mode, units, standard, out);
2224         if (stat_ev_enabled) {
2225                 stat_ev_end();
2226         }
2227
2228         if (result != EXIT_SUCCESS) {
2229                 if (out != stdout)
2230                         unlink(outname);
2231                 return result;
2232         }
2233
2234         /* link program file */
2235         if (mode == CompileAssembleLink) {
2236                 int result = link_program(units);
2237                 if (result != EXIT_SUCCESS) {
2238                         if (out != stdout)
2239                                 unlink(outname);
2240                         return result;
2241                 }
2242         }
2243
2244         if (do_timing)
2245                 timer_term(print_timing ? stderr : NULL);
2246
2247         free_temp_files();
2248         obstack_free(&cppflags_obst, NULL);
2249         obstack_free(&ldflags_obst, NULL);
2250         obstack_free(&asflags_obst, NULL);
2251         obstack_free(&file_obst, NULL);
2252
2253         gen_firm_finish();
2254         exit_mangle();
2255         exit_ast2firm();
2256         exit_parser();
2257         exit_ast();
2258         exit_preprocessor();
2259         exit_typehash();
2260         exit_types();
2261         exit_tokens();
2262         exit_symbol_table();
2263         return EXIT_SUCCESS;
2264 }