/*
* This file is part of cparser.
- * Copyright (C) 2007-2009 Matthias Braun <matze@braunis.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
+ * Copyright (C) 2012 Matthias Braun <matze@braunis.de>
*/
#include <config.h>
#include <libfirm/firm.h>
#include <libfirm/be.h>
+#include <libfirm/statev.h>
-#include "lexer.h"
+#include "adt/util.h"
+#include "ast_t.h"
+#include "preprocessor.h"
#include "token_t.h"
#include "types.h"
#include "type_hash.h"
#include "driver/firm_machine.h"
#include "adt/error.h"
#include "adt/strutil.h"
+#include "adt/array.h"
+#include "symbol_table.h"
#include "wrappergen/write_fluffy.h"
#include "wrappergen/write_jna.h"
+#include "wrappergen/write_compoundsizes.h"
#include "revision.h"
#include "warning.h"
#include "help.h"
#ifndef PREPROCESSOR
#ifndef __WIN32__
-#define PREPROCESSOR "gcc -E -U__STRICT_ANSI__"
+#define PREPROCESSOR "gcc -E -U__STRICT_ANSI__ -U__BLOCKS__"
#else
#define PREPROCESSOR "cpp -U__STRICT_ANSI__"
#endif
#define ASSEMBLER "gcc -c -xassembler"
#endif
-unsigned int c_mode = _C89 | _ANSI | _C99 | _GNUC;
-unsigned int machine_size = 32;
-bool byte_order_big_endian = false;
-bool char_is_signed = true;
-bool strict_mode = false;
-atomic_type_kind_t wchar_atomic_kind = ATOMIC_TYPE_INT;
-unsigned long_double_size = 0;
-bool enable_main_collect2_hack = false;
-bool freestanding = false;
+unsigned int c_mode = _C89 | _C99 | _GNUC;
+bool byte_order_big_endian = false;
+bool strict_mode = false;
+bool enable_main_collect2_hack = false;
+bool freestanding = false;
+unsigned architecture_modulo_shift = 0;
+
+static bool char_is_signed = true;
+static atomic_type_kind_t wchar_atomic_kind = ATOMIC_TYPE_INT;
+static unsigned features_on = 0;
+static unsigned features_off = 0;
+static const char *dumpfunction = NULL;
+static struct obstack file_obst;
+static const char *external_preprocessor = PREPROCESSOR;
static machine_triple_t *target_machine;
static const char *target_triple;
static int verbose;
-static bool use_builtins;
static struct obstack cppflags_obst;
static struct obstack ldflags_obst;
static struct obstack asflags_obst;
-static char dep_target[1024];
static const char *outname;
static bool define_intmax_types;
+static const char *input_encoding;
+static bool construct_dep_target;
typedef enum lang_standard_t {
STANDARD_DEFAULT, /* gnu99 (for C, GCC does gnu89) or gnu++98 (for C++) */
- STANDARD_ANSI, /* c89 (for C) or c++98 (for C++) */
+ STANDARD_ANSI, /* ISO C90 (for C) or ISO C++ 1998 (for C++) */
STANDARD_C89, /* ISO C90 (sic) */
- STANDARD_C90, /* ISO C90 as modified in amendment 1 */
+ STANDARD_C89AMD1, /* ISO C90 as modified in amendment 1 */
STANDARD_C99, /* ISO C99 */
+ STANDARD_C11, /* ISO C11 */
STANDARD_GNU89, /* ISO C90 plus GNU extensions (including some C99) */
STANDARD_GNU99, /* ISO C99 plus GNU extensions */
+ STANDARD_GNU11, /* ISO C11 plus GNU extensions */
STANDARD_CXX98, /* ISO C++ 1998 plus amendments */
STANDARD_GNUXX98 /* ISO C++ 1998 plus amendments and GNU extensions */
} lang_standard_t;
-static lang_standard_t standard;
-
-typedef struct file_list_entry_t file_list_entry_t;
-
-typedef enum filetype_t {
- FILETYPE_AUTODETECT,
- FILETYPE_C,
- FILETYPE_PREPROCESSED_C,
- FILETYPE_CXX,
- FILETYPE_PREPROCESSED_CXX,
- FILETYPE_ASSEMBLER,
- FILETYPE_PREPROCESSED_ASSEMBLER,
- FILETYPE_OBJECT,
- FILETYPE_IR,
- FILETYPE_UNKNOWN
-} filetype_t;
-
-struct file_list_entry_t {
- const char *name; /**< filename or NULL for stdin */
- filetype_t type;
- file_list_entry_t *next;
+typedef enum compilation_unit_type_t {
+ COMPILATION_UNIT_AUTODETECT,
+ COMPILATION_UNIT_C,
+ COMPILATION_UNIT_PREPROCESSED_C,
+ COMPILATION_UNIT_CXX,
+ COMPILATION_UNIT_PREPROCESSED_CXX,
+ COMPILATION_UNIT_AST,
+ COMPILATION_UNIT_INTERMEDIATE_REPRESENTATION,
+ COMPILATION_UNIT_ASSEMBLER,
+ COMPILATION_UNIT_PREPROCESSED_ASSEMBLER,
+ COMPILATION_UNIT_OBJECT,
+ COMPILATION_UNIT_IR,
+ COMPILATION_UNIT_UNKNOWN
+} compilation_unit_type_t;
+
+typedef struct compilation_unit_t compilation_unit_t;
+struct compilation_unit_t {
+ const char *name; /**< filename or "-" for stdin */
+ FILE *input; /**< input (NULL if not opened yet) */
+ bool input_is_pipe;
+ compilation_unit_type_t type;
+ lang_standard_t standard;
+ translation_unit_t *ast;
+ bool parse_errors;
+ compilation_unit_t *next;
};
-static file_list_entry_t *temp_files;
+static char **temp_files;
static void get_output_name(char *buf, size_t buflen, const char *inputname,
const char *newext)
panic("filename too long");
}
-#include "gen_builtins.h"
-
-static translation_unit_t *do_parsing(FILE *const in, const char *const input_name)
+static bool close_input(compilation_unit_t *unit)
{
- start_parsing();
-
- if (use_builtins) {
- lexer_open_buffer(builtins, sizeof(builtins)-1, "<builtin>");
- parse();
+ assert(unit->input);
+ bool res;
+ if (unit->input == stdin) {
+ res = true;
+ } else if (unit->input_is_pipe) {
+ res = pclose(unit->input) == EXIT_SUCCESS;
+ } else {
+ fclose(unit->input);
+ res = true;
}
+ unit->input = NULL;
+ unit->name = NULL;
+ return res;
+}
- lexer_open_stream(in, input_name);
- parse();
-
- translation_unit_t *unit = finish_parsing();
- return unit;
+static void print_error_summary(void)
+{
+ if (error_count > 0) {
+ /* parsing failed because of errors */
+ fprintf(stderr, "%u error(s), %u warning(s)\n", error_count,
+ warning_count);
+ } else if (warning_count > 0) {
+ fprintf(stderr, "%u warning(s)\n", warning_count);
+ }
}
-static void lextest(FILE *in, const char *fname)
+static void do_parsing(compilation_unit_t *unit)
{
- lexer_open_stream(in, fname);
+ ir_timer_t *t_parsing = ir_timer_new();
+ timer_register(t_parsing, "Frontend: Parsing");
+ timer_start(t_parsing);
+
+ start_parsing();
- do {
- lexer_next_preprocessing_token();
- print_token(stdout, &lexer_token);
- putchar('\n');
- } while (lexer_token.type != T_EOF);
+ switch_pp_input(unit->input, unit->name, NULL, false);
+ parse();
+ unit->ast = finish_parsing();
+ check_unclosed_conditionals();
+ close_pp_input();
+ bool res = close_input(unit);
+
+ print_error_summary();
+
+ unit->type = COMPILATION_UNIT_AST;
+ unit->parse_errors = error_count > 0 || !res;
+ timer_stop(t_parsing);
+ if (stat_ev_enabled) {
+ stat_ev_dbl("time_parsing", ir_timer_elapsed_sec(t_parsing));
+ }
}
static void add_flag(struct obstack *obst, const char *format, ...)
#else
/* escape stuff... */
for (char *c = buf; *c != '\0'; ++c) {
- switch(*c) {
+ switch (*c) {
case ' ':
case '"':
case '$':
return get_atomic_kind_name(type->atomic.akind);
}
-static FILE *preprocess(const char *fname, filetype_t filetype)
+static char const* str_lang_standard(lang_standard_t const standard)
+{
+ switch (standard) {
+ case STANDARD_C89: return "c89";
+ case STANDARD_C89AMD1: return "iso9899:199409";
+ case STANDARD_C99: return "c99";
+ case STANDARD_C11: return "c11";
+ case STANDARD_GNU89: return "gnu89";
+ case STANDARD_GNU99: return "gnu99";
+ case STANDARD_GNU11: return "gnu11";
+ case STANDARD_CXX98: return "c++98";
+ case STANDARD_GNUXX98: return "gnu++98";
+ case STANDARD_ANSI: break;
+ case STANDARD_DEFAULT: break;
+ }
+ panic("invalid standard");
+}
+
+static bool run_external_preprocessor(compilation_unit_t *unit)
{
- static const char *common_flags = NULL;
+ obstack_1grow(&cppflags_obst, '\0');
+ const char *flags = obstack_finish(&cppflags_obst);
+
+ const char *preprocessor = getenv("CPARSER_PP");
+ if (preprocessor != NULL) {
+ obstack_printf(&cppflags_obst, "%s ", preprocessor);
+ } else {
+ if (target_triple != NULL)
+ obstack_printf(&cppflags_obst, "%s-", target_triple);
+ obstack_printf(&cppflags_obst, "%s", external_preprocessor);
+ }
+
+ char const *lang;
+ switch (unit->type) {
+ case COMPILATION_UNIT_C: lang = "c"; break;
+ case COMPILATION_UNIT_CXX: lang = "c++"; break;
+ case COMPILATION_UNIT_ASSEMBLER: lang = "assembler-with-cpp"; break;
+ default: lang = NULL; break;
+ }
+ if (lang)
+ add_flag(&cppflags_obst, "-x%s", lang);
- if (common_flags == NULL) {
- obstack_1grow(&cppflags_obst, '\0');
- const char *flags = obstack_finish(&cppflags_obst);
+ if (unit->type == COMPILATION_UNIT_C
+ || unit->type == COMPILATION_UNIT_CXX) {
+ add_flag(&cppflags_obst, "-std=%s", str_lang_standard(unit->standard));
/* setup default defines */
add_flag(&cppflags_obst, "-U__WCHAR_TYPE__");
add_flag(&cppflags_obst, "-U__UINTMAX_TYPE__");
add_flag(&cppflags_obst, "-D__UINTMAX_TYPE__=%s", type_to_string(type_uintmax_t));
}
-
- if (flags[0] != '\0') {
- size_t len = strlen(flags);
- obstack_1grow(&cppflags_obst, ' ');
- obstack_grow(&cppflags_obst, flags, len);
- }
- obstack_1grow(&cppflags_obst, '\0');
- common_flags = obstack_finish(&cppflags_obst);
- }
-
- assert(obstack_object_size(&cppflags_obst) == 0);
-
- const char *preprocessor = getenv("CPARSER_PP");
- if (preprocessor != NULL) {
- obstack_printf(&cppflags_obst, "%s ", preprocessor);
- } else {
- if (target_triple != NULL)
- obstack_printf(&cppflags_obst, "%s-", target_triple);
- obstack_printf(&cppflags_obst, PREPROCESSOR);
}
-
- switch (filetype) {
- case FILETYPE_C:
- add_flag(&cppflags_obst, "-std=c99");
- break;
- case FILETYPE_CXX:
- add_flag(&cppflags_obst, "-std=c++98");
- break;
- case FILETYPE_ASSEMBLER:
- add_flag(&cppflags_obst, "-x");
- add_flag(&cppflags_obst, "assembler-with-cpp");
- break;
- default:
- break;
+ if (flags[0] != '\0') {
+ size_t len = strlen(flags);
+ obstack_1grow(&cppflags_obst, ' ');
+ obstack_grow(&cppflags_obst, flags, len);
}
- obstack_printf(&cppflags_obst, "%s", common_flags);
/* handle dependency generation */
- if (dep_target[0] != '\0') {
+ if (construct_dep_target) {
+ static char dep_target[4096];
+ if (outname != 0) {
+ size_t len = strlen(outname);
+ if (len > sizeof(dep_target)-4) /* leave room for .d extension */
+ len = sizeof(dep_target)-4;
+ memcpy(dep_target, outname, len);
+ /* replace extension with .d if found */
+ char *dot = &dep_target[len-1];
+ for ( ; dot >= dep_target && *dot != '/'; --dot) {
+ if (*dot == '.') {
+ dot[1] = 'd';
+ len = (dot-dep_target)+2;
+ break;
+ }
+ }
+ dep_target[len] = '\0';
+ } else {
+ get_output_name(dep_target, sizeof(dep_target), unit->name, ".d");
+ }
+
add_flag(&cppflags_obst, "-MF");
add_flag(&cppflags_obst, dep_target);
- if (outname != NULL) {
- add_flag(&cppflags_obst, "-MQ");
- add_flag(&cppflags_obst, outname);
- }
}
- add_flag(&cppflags_obst, fname);
+ assert(unit->input == NULL);
+ add_flag(&cppflags_obst, unit->name);
obstack_1grow(&cppflags_obst, '\0');
char *commandline = obstack_finish(&cppflags_obst);
}
FILE *f = popen(commandline, "r");
if (f == NULL) {
- fprintf(stderr, "invoking preprocessor failed\n");
- exit(EXIT_FAILURE);
+ position_t const pos = { unit->name, 0, 0, 0 };
+ errorf(&pos, "invoking preprocessor failed");
+ return false;
}
/* we do not really need that anymore */
obstack_free(&cppflags_obst, commandline);
- return f;
+ unit->input = f;
+ unit->input_is_pipe = true;
+ switch (unit->type) {
+ case COMPILATION_UNIT_ASSEMBLER:
+ unit->type = COMPILATION_UNIT_PREPROCESSED_ASSEMBLER;
+ break;
+ case COMPILATION_UNIT_C:
+ unit->type = COMPILATION_UNIT_PREPROCESSED_C;
+ break;
+ case COMPILATION_UNIT_CXX:
+ unit->type = COMPILATION_UNIT_PREPROCESSED_CXX;
+ break;
+ default:
+ unit->type = COMPILATION_UNIT_UNKNOWN;
+ break;
+ }
+
+ return true;
}
static void assemble(const char *out, const char *in)
}
int err = system(commandline);
if (err != EXIT_SUCCESS) {
- fprintf(stderr, "assembler reported an error\n");
+ position_t const pos = { in, 0, 0, 0 };
+ errorf(&pos, "assembler reported an error");
exit(EXIT_FAILURE);
}
obstack_free(&asflags_obst, commandline);
}
int err = system(commandline);
if (err != EXIT_SUCCESS) {
- fprintf(stderr, "linker reported an error\n");
+ position_t const pos = { file, 0, 0, 0 };
+ errorf(&pos, "linker reported an error");
exit(EXIT_FAILURE);
}
obstack_free(&ldflags_obst, commandline);
#endif
/**
- * an own version of tmpnam, which: writes in a buffer, emits no warnings
+ * custom version of tmpnam, which: writes to an obstack, emits no warnings
* during linking (like glibc/gnu ld do for tmpnam)...
*/
-static FILE *make_temp_file(char *buffer, size_t buflen, const char *prefix)
+static FILE *make_temp_file(const char *prefix, const char **name_result)
{
const char *tempdir = get_tempdir();
+ assert(obstack_object_size(&file_obst) == 0);
+ obstack_printf(&file_obst, "%s/%sXXXXXX", tempdir, prefix);
+ obstack_1grow(&file_obst, '\0');
- snprintf(buffer, buflen, "%s/%sXXXXXX", tempdir, prefix);
-
- int fd = mkstemp(buffer);
+ char *name = obstack_finish(&file_obst);
+ int fd = mkstemp(name);
if (fd == -1) {
- fprintf(stderr, "could not create temporary file: %s\n",
- strerror(errno));
- exit(EXIT_FAILURE);
+ position_t const pos = { name, 0, 0, 0 };
+ errorf(&pos, "could not create temporary file: %s", strerror(errno));
+ return NULL;
}
FILE *out = fdopen(fd, "w");
if (out == NULL) {
- fprintf(stderr, "could not create temporary file FILE*\n");
- exit(EXIT_FAILURE);
+ position_t const pos = { name, 0, 0, 0 };
+ errorf(&pos, "could not open temporary file as FILE*");
+ return NULL;
}
- file_list_entry_t *entry = xmalloc(sizeof(*entry));
- memset(entry, 0, sizeof(*entry));
-
- size_t name_len = strlen(buffer) + 1;
- char *name = malloc(name_len);
- memcpy(name, buffer, name_len);
- entry->name = name;
-
- entry->next = temp_files;
- temp_files = entry;
-
+ ARR_APP1(char*, temp_files, name);
+ *name_result = name;
return out;
}
static void free_temp_files(void)
{
- file_list_entry_t *entry = temp_files;
- file_list_entry_t *next;
- for ( ; entry != NULL; entry = next) {
- next = entry->next;
-
- unlink(entry->name);
- free((char*) entry->name);
- free(entry);
+ if (temp_files == NULL)
+ return;
+
+ size_t n_temp_files = ARR_LEN(temp_files);
+ size_t i;
+ for (i = 0; i < n_temp_files; ++i) {
+ char *file = temp_files[i];
+ unlink(file);
}
+ DEL_ARR_F(temp_files);
temp_files = NULL;
}
CompileExportIR,
CompileAssemble,
CompileAssembleLink,
- LexTest,
PrintAst,
PrintFluffy,
- PrintJna
+ PrintJna,
+ PrintCompoundSizes,
} compile_mode_t;
static void usage(const char *argv0)
const char *revision = ir_get_version_revision();
if (revision[0] != 0) {
- putchar(' ');
+ putchar('-');
fputs(revision, stdout);
}
"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
}
+static void print_cparser_version_short(void)
+{
+ puts(cparser_REVISION);
+}
+
static void print_help_basic(const char *argv0)
{
usage(argv0);
put_help("-D SYMBOL[=value]", "");
put_help("-U SYMBOL", "");
put_help("-Wp,OPTION", "Pass option directly to preprocessor");
+ put_help("-Xpreprocessor OPTION", "Pass option directly to preprocessor");
put_help("-M", "");
put_help("-MD", "");
put_help("-MMD", "");
put_help("-std=STANDARD", "Specify language standard:");
put_choice("c99", "ISO C99 standard");
put_choice("c89", "ISO C89 standard");
+ put_choice("c90", "Same as -std=c89");
+ put_choice("c11", "ISO C11 standard");
put_choice("c9x", "Deprecated");
put_choice("c++", "ISO C++ 98");
put_choice("c++98", "ISO C++ 98");
put_choice("gnu99", "ISO C99 + GNU extensions (default)");
put_choice("gnu89", "ISO C89 + GNU extensions");
+ put_choice("gnu11", "ISO C11 + GNU extensions");
put_choice("gnu9x", "Deprecated");
put_choice("iso9899:1990", "ISO C89");
put_choice("iso9899:199409", "ISO C90");
put_choice("iso9899:1999", "ISO C99");
put_choice("iso9899:199x", "Deprecated");
put_help("-pedantic", "Ignored (gcc compatibility)");
- put_help("-ansi", "Ignored (gcc compatibility)");
+ put_help("-ansi", "-std=c90 (for C) or -std=c++98 (for C++)");
put_help("--strict", "Enable strict conformance checking");
}
put_help("-w", "Disable all warnings");
put_help("-Wno-trigraphs", "Warn if input contains trigraphs");
put_help("-Wundef", "Warn if an undefined macro is used in an #if");
+ put_help("-Wmissing-include-dirs", "Warn about missing user-specified include directories");
+ put_help("-Wendif-labels", "Warn about stray text after #elif and #endif");
+ put_help("-Winit-self", "Ignored (gcc compatibility)");
+ put_help("-Wformat-y2k", "Ignored (gcc compatibility)");
+ put_help("-Wformat-security", "Ignored (gcc compatibility)");
+ put_help("-Wold-style-declaration", "Ignored (gcc compatibility)");
+ put_help("-Wtype-limits", "Ignored (gcc compatibility)");
print_warning_opt_help();
}
{
put_help("-l LIBRARY", "");
put_help("-L PATH", "");
+ put_help("-s", "Do not produce symbol table and relocation information");
put_help("-shared", "Produce a shared library");
put_help("-static", "Produce statically linked binary");
+ put_help("-Wa,OPTION", "Pass option directly to assembler");
+ put_help("-Xassembler OPTION", "Pass option directly to assembler");
put_help("-Wl,OPTION", "Pass option directly to linker");
+ put_help("-Xlinker OPTION", "Pass option directly to linker");
}
static void print_help_debug(void)
{
- put_help("--lextest", "Preprocess and tokenize only");
put_help("--print-ast", "Preprocess, parse and print AST");
put_help("--print-implicit-cast", "");
put_help("--print-parenthesis", "");
put_help("--benchmark", "Preprocess and parse, produces no output");
put_help("--time", "Measure time of compiler passes");
+ put_help("--statev", "Produce statev output");
+ put_help("--filtev=filter", "Set statev filter regex");
put_help("--dump-function func", "Preprocess, parse and output vcg graph of func");
put_help("--export-ir", "Preprocess, parse and output compiler intermediate representation");
}
typedef enum {
HELP_NONE = 0,
- HELP_BASIC = 1u << 0,
- HELP_PREPROCESSOR = 1u << 1,
- HELP_PARSER = 1u << 2,
- HELP_WARNINGS = 1u << 3,
- HELP_OPTIMIZATION = 1u << 4,
- HELP_CODEGEN = 1u << 5,
- HELP_LINKER = 1u << 6,
- HELP_LANGUAGETOOLS = 1u << 7,
- HELP_DEBUG = 1u << 8,
- HELP_FIRM = 1u << 9,
-
- HELP_ALL = (unsigned)-1
+ HELP_BASIC = 1 << 0,
+ HELP_PREPROCESSOR = 1 << 1,
+ HELP_PARSER = 1 << 2,
+ HELP_WARNINGS = 1 << 3,
+ HELP_OPTIMIZATION = 1 << 4,
+ HELP_CODEGEN = 1 << 5,
+ HELP_LINKER = 1 << 6,
+ HELP_LANGUAGETOOLS = 1 << 7,
+ HELP_DEBUG = 1 << 8,
+ HELP_FIRM = 1 << 9,
+
+ HELP_ALL = -1
} help_sections_t;
static void print_help(const char *argv0, help_sections_t sections)
assert(res);
}
-static void copy_file(FILE *dest, FILE *input)
-{
- char buf[16384];
-
- while (!feof(input) && !ferror(dest)) {
- size_t read = fread(buf, 1, sizeof(buf), input);
- if (fwrite(buf, 1, read, dest) != read) {
- perror("could not write output");
- }
- }
-}
-
-static FILE *open_file(const char *filename)
-{
- if (streq(filename, "-")) {
- return stdin;
- }
-
- FILE *in = fopen(filename, "r");
- if (in == NULL) {
- fprintf(stderr, "Could not open '%s': %s\n", filename,
- strerror(errno));
- exit(EXIT_FAILURE);
- }
-
- return in;
-}
-
-static filetype_t get_filetype_from_string(const char *string)
+static compilation_unit_type_t get_unit_type_from_string(const char *string)
{
if (streq(string, "c") || streq(string, "c-header"))
- return FILETYPE_C;
+ return COMPILATION_UNIT_C;
if (streq(string, "c++") || streq(string, "c++-header"))
- return FILETYPE_CXX;
+ return COMPILATION_UNIT_CXX;
if (streq(string, "assembler"))
- return FILETYPE_PREPROCESSED_ASSEMBLER;
+ return COMPILATION_UNIT_PREPROCESSED_ASSEMBLER;
if (streq(string, "assembler-with-cpp"))
- return FILETYPE_ASSEMBLER;
+ return COMPILATION_UNIT_ASSEMBLER;
if (streq(string, "none"))
- return FILETYPE_AUTODETECT;
+ return COMPILATION_UNIT_AUTODETECT;
- return FILETYPE_UNKNOWN;
+ return COMPILATION_UNIT_UNKNOWN;
}
static bool init_os_support(void)
{
- const char *os = target_machine->operating_system;
wchar_atomic_kind = ATOMIC_TYPE_INT;
enable_main_collect2_hack = false;
define_intmax_types = false;
- if (strstr(os, "linux") != NULL || strstr(os, "bsd") != NULL
- || streq(os, "solaris")) {
+ if (firm_is_unixish_os(target_machine)) {
set_create_ld_ident(create_name_linux_elf);
- } else if (streq(os, "darwin")) {
- long_double_size = 16;
+ } else if (firm_is_darwin_os(target_machine)) {
set_create_ld_ident(create_name_macho);
define_intmax_types = true;
- } else if (strstr(os, "mingw") != NULL || streq(os, "win32")) {
+ } else if (firm_is_windows_os(target_machine)) {
wchar_atomic_kind = ATOMIC_TYPE_USHORT;
enable_main_collect2_hack = true;
set_create_ld_ident(create_name_win32);
{
machine_triple_t *triple = firm_parse_machine_triple(arg);
if (triple == NULL) {
- fprintf(stderr, "Target-triple is not in the form 'cpu_type-manufacturer-operating_system'\n");
+ errorf(NULL, "target-triple '%s' is not in the form 'cpu_type-manufacturer-operating_system'", arg);
return false;
}
target_machine = triple;
return true;
}
-static void setup_target_machine(void)
+static unsigned decide_modulo_shift(unsigned type_size)
+{
+ if (architecture_modulo_shift == 0)
+ return 0;
+ return MAX(type_size, architecture_modulo_shift);
+}
+
+static bool is_ia32_cpu(const char *architecture)
+{
+ return streq(architecture, "i386")
+ || streq(architecture, "i486")
+ || streq(architecture, "i586")
+ || streq(architecture, "i686")
+ || streq(architecture, "i786");
+}
+
+static const char *setup_isa_from_tripel(const machine_triple_t *machine)
+{
+ const char *cpu = machine->cpu_type;
+
+ if (is_ia32_cpu(cpu)) {
+ return "ia32";
+ } else if (streq(cpu, "x86_64")) {
+ return "amd64";
+ } else if (streq(cpu, "sparc")) {
+ return "sparc";
+ } else if (streq(cpu, "arm")) {
+ return "arm";
+ } else {
+ errorf(NULL, "unknown cpu '%s' in target-triple", cpu);
+ return NULL;
+ }
+}
+
+static const char *setup_target_machine(void)
{
if (!setup_firm_for_machine(target_machine))
exit(1);
- const backend_params *be_params = be_get_backend_param();
- if (be_params->long_double_size % 8 != 0) {
- fprintf(stderr, "firm-target long double size is not a multiple of 8, cannot handle this\n");
+ const char *isa = setup_isa_from_tripel(target_machine);
+
+ if (isa == NULL)
exit(1);
+
+ init_os_support();
+
+ return isa;
+}
+
+/**
+ * initialize cparser type properties based on a firm type
+ */
+static void set_typeprops_type(atomic_type_properties_t* props, ir_type *type)
+{
+ props->size = get_type_size_bytes(type);
+ props->alignment = get_type_alignment_bytes(type);
+ props->struct_alignment = props->alignment;
+}
+
+/**
+ * Copy atomic type properties except the integer conversion rank
+ */
+static void copy_typeprops(atomic_type_properties_t *dest,
+ const atomic_type_properties_t *src)
+{
+ dest->size = src->size;
+ dest->alignment = src->alignment;
+ dest->struct_alignment = src->struct_alignment;
+ dest->flags = src->flags;
+}
+
+static void init_types_and_adjust(void)
+{
+ const backend_params *be_params = be_get_backend_param();
+ unsigned machine_size = be_params->machine_size;
+ init_types(machine_size);
+
+ atomic_type_properties_t *props = atomic_type_properties;
+
+ /* adjust types as requested by target architecture */
+ ir_type *const type_ld = be_params->type_long_double;
+ if (type_ld) {
+ set_typeprops_type(&props[ATOMIC_TYPE_LONG_DOUBLE], type_ld);
+ atomic_modes[ATOMIC_TYPE_LONG_DOUBLE] = get_type_mode(type_ld);
+ }
+
+ ir_type *const type_ll = be_params->type_long_long;
+ if (type_ll)
+ set_typeprops_type(&props[ATOMIC_TYPE_LONGLONG], type_ll);
+
+ ir_type *const type_ull = be_params->type_unsigned_long_long;
+ if (type_ull)
+ set_typeprops_type(&props[ATOMIC_TYPE_ULONGLONG], type_ull);
+
+ /* operating system ABI specifics */
+ if (firm_is_darwin_os(target_machine)) {
+ if (is_ia32_cpu(target_machine->cpu_type)) {
+ props[ATOMIC_TYPE_LONGLONG].struct_alignment = 4;
+ props[ATOMIC_TYPE_ULONGLONG].struct_alignment = 4;
+ props[ATOMIC_TYPE_DOUBLE].struct_alignment = 4;
+ props[ATOMIC_TYPE_LONG_DOUBLE].size = 16;
+ props[ATOMIC_TYPE_LONG_DOUBLE].alignment = 16;
+ props[ATOMIC_TYPE_LONG_DOUBLE].struct_alignment = 16;
+ }
+ } else if (firm_is_windows_os(target_machine)) {
+ if (is_ia32_cpu(target_machine->cpu_type)) {
+ props[ATOMIC_TYPE_LONGLONG].struct_alignment = 8;
+ props[ATOMIC_TYPE_ULONGLONG].struct_alignment = 8;
+ props[ATOMIC_TYPE_DOUBLE].struct_alignment = 8;
+ } else if (machine_size == 64) {
+ /* to ease porting of old c-code microsoft decided to use 32bits
+ * even for long */
+ props[ATOMIC_TYPE_LONG] = props[ATOMIC_TYPE_INT];
+ props[ATOMIC_TYPE_ULONG] = props[ATOMIC_TYPE_UINT];
+ }
+
+ /* on windows long double is not supported */
+ props[ATOMIC_TYPE_LONG_DOUBLE] = props[ATOMIC_TYPE_DOUBLE];
+ } else if (firm_is_unixish_os(target_machine)) {
+ if (is_ia32_cpu(target_machine->cpu_type)) {
+ props[ATOMIC_TYPE_DOUBLE].struct_alignment = 4;
+ props[ATOMIC_TYPE_LONGLONG].struct_alignment = 4;
+ props[ATOMIC_TYPE_ULONGLONG].struct_alignment = 4;
+ }
+ }
+
+ /* stuff decided after processing operating system specifics and
+ * commandline flags */
+ if (char_is_signed) {
+ props[ATOMIC_TYPE_CHAR].flags |= ATOMIC_TYPE_FLAG_SIGNED;
+ } else {
+ props[ATOMIC_TYPE_CHAR].flags &= ~ATOMIC_TYPE_FLAG_SIGNED;
+ }
+ /* copy over wchar_t properties (including rank) */
+ props[ATOMIC_TYPE_WCHAR_T] = props[wchar_atomic_kind];
+
+ /* initialize defaults for unsupported types */
+ if (!type_ll) {
+ copy_typeprops(&props[ATOMIC_TYPE_LONGLONG], &props[ATOMIC_TYPE_LONG]);
}
+ if (!type_ull) {
+ copy_typeprops(&props[ATOMIC_TYPE_ULONGLONG],
+ &props[ATOMIC_TYPE_ULONG]);
+ }
+ if (!type_ld) {
+ copy_typeprops(&props[ATOMIC_TYPE_LONG_DOUBLE],
+ &props[ATOMIC_TYPE_DOUBLE]);
+ }
+
+ /* initialize firm pointer modes */
+ char name[64];
+ unsigned bit_size = machine_size;
+ unsigned modulo_shift = decide_modulo_shift(bit_size);
+
+ snprintf(name, sizeof(name), "p%u", machine_size);
+ ir_mode *ptr_mode = new_reference_mode(name, irma_twos_complement, bit_size, modulo_shift);
+
+ if (machine_size == 16) {
+ set_reference_mode_signed_eq(ptr_mode, mode_Hs);
+ set_reference_mode_unsigned_eq(ptr_mode, mode_Hu);
+ } else if (machine_size == 32) {
+ set_reference_mode_signed_eq(ptr_mode, mode_Is);
+ set_reference_mode_unsigned_eq(ptr_mode, mode_Iu);
+ } else if (machine_size == 64) {
+ set_reference_mode_signed_eq(ptr_mode, mode_Ls);
+ set_reference_mode_unsigned_eq(ptr_mode, mode_Lu);
+ } else {
+ panic("strange machine_size when determining pointer modes");
+ }
+
+ /* Hmm, pointers should be machine size */
+ set_modeP_data(ptr_mode);
+ set_modeP_code(ptr_mode);
byte_order_big_endian = be_params->byte_order_big_endian;
- machine_size = be_params->machine_size;
- long_double_size = be_params->long_double_size / 8;
+ if (be_params->modulo_shift_efficient) {
+ architecture_modulo_shift = machine_size;
+ } else {
+ architecture_modulo_shift = 0;
+ }
+}
- init_os_support();
+static void setup_cmode(const compilation_unit_t *unit)
+{
+ compilation_unit_type_t type = unit->type;
+ lang_standard_t standard = unit->standard;
+ if (type == COMPILATION_UNIT_PREPROCESSED_C || type == COMPILATION_UNIT_C) {
+ switch (standard) {
+ case STANDARD_C89: c_mode = _C89; break;
+ /* TODO determine difference between these two */
+ case STANDARD_C89AMD1: c_mode = _C89; break;
+ case STANDARD_C99: c_mode = _C89 | _C99; break;
+ case STANDARD_C11: c_mode = _C89 | _C99 | _C11; break;
+ case STANDARD_GNU89: c_mode = _C89 | _GNUC; break;
+ case STANDARD_GNU11: c_mode = _C89 | _C99 | _C11 | _GNUC; break;
+
+ case STANDARD_ANSI:
+ case STANDARD_CXX98:
+ case STANDARD_GNUXX98:
+ case STANDARD_DEFAULT:
+ fprintf(stderr, "warning: command line option \"-std=%s\" is not valid for C\n", str_lang_standard(standard));
+ /* FALLTHROUGH */
+ case STANDARD_GNU99: c_mode = _C89 | _C99 | _GNUC; break;
+ }
+ } else if (type == COMPILATION_UNIT_PREPROCESSED_CXX
+ || type == COMPILATION_UNIT_CXX) {
+ switch (standard) {
+ case STANDARD_CXX98: c_mode = _CXX; break;
+
+ case STANDARD_ANSI:
+ case STANDARD_C89:
+ case STANDARD_C89AMD1:
+ case STANDARD_C99:
+ case STANDARD_C11:
+ case STANDARD_GNU89:
+ case STANDARD_GNU99:
+ case STANDARD_GNU11:
+ case STANDARD_DEFAULT:
+ fprintf(stderr, "warning: command line option \"-std=%s\" is not valid for C++\n", str_lang_standard(standard));
+ /* FALLTHROUGH */
+ case STANDARD_GNUXX98: c_mode = _CXX | _GNUC; break;
+ }
+ }
+
+ c_mode |= features_on;
+ c_mode &= ~features_off;
}
-int main(int argc, char **argv)
+static void determine_unit_standard(compilation_unit_t *unit,
+ lang_standard_t standard)
+{
+ unit->standard = standard;
+ switch (standard) {
+ case STANDARD_ANSI:
+ switch (unit->type) {
+ case COMPILATION_UNIT_C:
+ case COMPILATION_UNIT_PREPROCESSED_C:
+ unit->standard = STANDARD_C89;
+ break;
+ case COMPILATION_UNIT_CXX:
+ case COMPILATION_UNIT_PREPROCESSED_CXX:
+ unit->standard = STANDARD_CXX98;
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case STANDARD_DEFAULT:
+ switch (unit->type) {
+ case COMPILATION_UNIT_C:
+ case COMPILATION_UNIT_PREPROCESSED_C:
+ unit->standard = STANDARD_GNU99;
+ break;
+ case COMPILATION_UNIT_CXX:
+ case COMPILATION_UNIT_PREPROCESSED_CXX:
+ unit->standard = STANDARD_GNUXX98;
+ break;
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+static bool output_preprocessor_tokens(compilation_unit_t *unit, FILE *out)
{
- firm_early_init();
-
- const char *dumpfunction = NULL;
- const char *print_file_name_file = NULL;
- compile_mode_t mode = CompileAssembleLink;
- int opt_level = 1;
- int result = EXIT_SUCCESS;
- char cpu_arch[16] = "ia32";
- file_list_entry_t *files = NULL;
- file_list_entry_t *last_file = NULL;
- bool construct_dep_target = false;
- bool do_timing = false;
- bool profile_generate = false;
- bool profile_use = false;
- struct obstack file_obst;
+ /* just here for gcc compatibility */
+ fprintf(out, "# 1 \"%s\"\n", unit->name);
+ fprintf(out, "# 1 \"<built-in>\"\n");
+ fprintf(out, "# 1 \"<command-line>\"\n");
- atexit(free_temp_files);
+ set_preprocessor_output(out);
+ switch_pp_input(unit->input, unit->name, NULL, false);
+
+ for (;;) {
+ next_preprocessing_token();
+ if (pp_token.kind == T_EOF)
+ break;
+ emit_pp_token();
+ }
+
+ fputc('\n', out);
+ check_unclosed_conditionals();
+ close_pp_input();
+ print_error_summary();
+ set_preprocessor_output(NULL);
+
+ if (unit->type == COMPILATION_UNIT_C) {
+ unit->type = COMPILATION_UNIT_PREPROCESSED_C;
+ } else if (unit->type == COMPILATION_UNIT_CXX) {
+ unit->type = COMPILATION_UNIT_PREPROCESSED_CXX;
+ }
+ bool res = close_input(unit);
+ return res && error_count == 0;
+}
+
+static void copy_file(FILE *dest, FILE *input)
+{
+ char buf[16384];
+
+ for (;;) {
+ size_t read = fread(buf, 1, sizeof(buf), input);
+ if (read == 0)
+ break;
+ if (fwrite(buf, 1, read, dest) != read) {
+ perror("could not write output");
+ }
+ }
+}
+
+static bool open_input(compilation_unit_t *unit)
+{
+ /* input already available as FILE? */
+ if (unit->input != NULL)
+ return true;
+
+ const char *const inputname = unit->name;
+ unit->input_is_pipe = false;
+ if (streq(inputname, "-")) {
+ unit->input = stdin;
+ } else {
+ unit->input = fopen(inputname, "r");
+ if (unit->input == NULL) {
+ position_t const pos = { inputname, 0, 0, 0 };
+ errorf(&pos, "could not open: %s", strerror(errno));
+ return false;
+ }
+ }
+ return true;
+}
+
+static void node_counter(ir_node *node, void *env)
+{
+ (void)node;
+ unsigned long long *count = (unsigned long long*)env;
+ ++(*count);
+}
+
+static unsigned long long count_firm_nodes(void)
+{
+ unsigned long long count = 0;
+
+ int n_irgs = get_irp_n_irgs();
+ for (int i = 0; i < n_irgs; ++i) {
+ ir_graph *irg = get_irp_irg(i);
+ irg_walk_graph(irg, node_counter, NULL, &count);
+ }
+ return count;
+}
+
+static int compilation_loop(compile_mode_t mode, compilation_unit_t *units,
+ lang_standard_t standard, FILE *out)
+{
+ int result = EXIT_SUCCESS;
+ bool already_constructed_firm = false;
+ for (compilation_unit_t *unit = units; unit != NULL; unit = unit->next) {
+ const char *const inputname = unit->name;
+
+ determine_unit_standard(unit, standard);
+ setup_cmode(unit);
+
+ stat_ev_ctx_push_str("compilation_unit", inputname);
+
+again:
+ switch (unit->type) {
+ case COMPILATION_UNIT_IR: {
+ if (!open_input(unit)) {
+ result = EXIT_FAILURE;
+ break;
+ }
+ if (ir_import_file(unit->input, unit->name)) {
+ position_t const pos = { inputname, 0, 0, 0 };
+ errorf(&pos, "import of firm graph failed");
+ result = EXIT_FAILURE;
+ break;
+ }
+ unit->type = COMPILATION_UNIT_INTERMEDIATE_REPRESENTATION;
+ goto again;
+ }
+ case COMPILATION_UNIT_ASSEMBLER: {
+ if (external_preprocessor == NULL) {
+ panic("preprocessed assembler not possible with internal preprocessor yet");
+ }
+ if (!run_external_preprocessor(unit)) {
+ result = EXIT_FAILURE;
+ break;
+ }
+ /* write file to output... */
+ FILE *asm_out;
+ if (mode == PreprocessOnly) {
+ asm_out = out;
+ } else {
+ asm_out = make_temp_file("ccs", &unit->name);
+ }
+ assert(unit->input != NULL);
+ assert(unit->input_is_pipe);
+ copy_file(asm_out, unit->input);
+ if (asm_out != out)
+ fclose(asm_out);
+ unit->type = COMPILATION_UNIT_PREPROCESSED_ASSEMBLER;
+ goto again;
+ }
+ case COMPILATION_UNIT_C:
+ case COMPILATION_UNIT_CXX:
+ if (external_preprocessor != NULL) {
+ if (!run_external_preprocessor(unit)) {
+ result = EXIT_FAILURE;
+ break;
+ }
+ goto again;
+ }
+ /* FALLTHROUGH */
+
+ case COMPILATION_UNIT_PREPROCESSED_C:
+ case COMPILATION_UNIT_PREPROCESSED_CXX: {
+ if (!open_input(unit)) {
+ result = EXIT_FAILURE;
+ break;
+ }
+ init_tokens();
+
+ if (mode == PreprocessOnly) {
+ if (!output_preprocessor_tokens(unit, out)) {
+ result = EXIT_FAILURE;
+ break;
+ }
+ break;
+ }
+
+ /* do the actual parsing */
+ do_parsing(unit);
+ goto again;
+ }
+ case COMPILATION_UNIT_AST:
+ /* prints the AST even if errors occurred */
+ if (mode == PrintAst) {
+ print_to_file(out);
+ print_ast(unit->ast);
+ }
+ if (unit->parse_errors) {
+ result = EXIT_FAILURE;
+ break;
+ }
+
+ if (mode == BenchmarkParser) {
+ break;
+ } else if (mode == PrintFluffy) {
+ write_fluffy_decls(out, unit->ast);
+ break;
+ } else if (mode == PrintJna) {
+ write_jna_decls(out, unit->ast);
+ break;
+ } else if (mode == PrintCompoundSizes) {
+ write_compoundsizes(out, unit->ast);
+ break;
+ }
+
+ /* build the firm graph */
+ ir_timer_t *t_construct = ir_timer_new();
+ timer_register(t_construct, "Frontend: Graph construction");
+ timer_start(t_construct);
+ if (already_constructed_firm) {
+ panic("compiling multiple files/translation units not possible");
+ }
+ init_implicit_optimizations();
+ translation_unit_to_firm(unit->ast);
+ already_constructed_firm = true;
+ timer_stop(t_construct);
+ if (stat_ev_enabled) {
+ stat_ev_dbl("time_graph_construction", ir_timer_elapsed_sec(t_construct));
+ stat_ev_int("size_graph_construction", count_firm_nodes());
+ }
+ unit->type = COMPILATION_UNIT_INTERMEDIATE_REPRESENTATION;
+ goto again;
+
+ case COMPILATION_UNIT_INTERMEDIATE_REPRESENTATION:
+ if (mode == ParseOnly)
+ break;
+
+ if (mode == CompileDump) {
+ /* find irg */
+ ident *id = new_id_from_str(dumpfunction);
+ ir_graph *irg = NULL;
+ int n_irgs = get_irp_n_irgs();
+ for (int i = 0; i < n_irgs; ++i) {
+ ir_graph *tirg = get_irp_irg(i);
+ ident *irg_id = get_entity_ident(get_irg_entity(tirg));
+ if (irg_id == id) {
+ irg = tirg;
+ break;
+ }
+ }
+
+ if (irg == NULL) {
+ errorf(NULL, "no graph for function '%s' found", dumpfunction);
+ return EXIT_FAILURE;
+ }
+
+ dump_ir_graph_file(out, irg);
+ fclose(out);
+ return EXIT_SUCCESS;
+ }
+
+ if (mode == CompileExportIR) {
+ ir_export_file(out);
+ if (ferror(out) != 0) {
+ errorf(NULL, "writing to output failed");
+ return EXIT_FAILURE;
+ }
+ return EXIT_SUCCESS;
+ }
+
+ FILE *asm_out;
+ if (mode == Compile) {
+ asm_out = out;
+ } else {
+ asm_out = make_temp_file("ccs", &unit->name);
+ }
+ ir_timer_t *t_opt_codegen = ir_timer_new();
+ timer_register(t_opt_codegen, "Optimization and Codegeneration");
+ timer_start(t_opt_codegen);
+ generate_code(asm_out, inputname);
+ timer_stop(t_opt_codegen);
+ if (stat_ev_enabled) {
+ stat_ev_dbl("time_opt_codegen", ir_timer_elapsed_sec(t_opt_codegen));
+ }
+ if (asm_out != out) {
+ fclose(asm_out);
+ }
+ unit->type = COMPILATION_UNIT_PREPROCESSED_ASSEMBLER;
+ goto again;
+ case COMPILATION_UNIT_PREPROCESSED_ASSEMBLER:
+ if (mode != CompileAssemble && mode != CompileAssembleLink)
+ break;
+
+ /* assemble */
+ const char *input = unit->name;
+ if (mode == CompileAssemble) {
+ fclose(out);
+ unit->name = outname;
+ } else {
+ FILE *tempf = make_temp_file("cco", &unit->name);
+ /* hackish... */
+ fclose(tempf);
+ }
+
+ assemble(unit->name, input);
+
+ unit->type = COMPILATION_UNIT_OBJECT;
+ goto again;
+ case COMPILATION_UNIT_UNKNOWN:
+ case COMPILATION_UNIT_AUTODETECT:
+ case COMPILATION_UNIT_OBJECT:
+ break;
+ }
+
+ stat_ev_ctx_pop("compilation_unit");
+ }
+ return result;
+}
+
+static int link_program(compilation_unit_t *units)
+{
+ obstack_1grow(&ldflags_obst, '\0');
+ const char *flags = obstack_finish(&ldflags_obst);
+
+ /* construct commandline */
+ const char *linker = getenv("CPARSER_LINK");
+ if (linker != NULL) {
+ obstack_printf(&file_obst, "%s ", linker);
+ } else {
+ if (target_triple != NULL)
+ obstack_printf(&file_obst, "%s-", target_triple);
+ obstack_printf(&file_obst, "%s ", LINKER);
+ }
+
+ for (compilation_unit_t *unit = units; unit != NULL; unit = unit->next) {
+ if (unit->type != COMPILATION_UNIT_OBJECT)
+ continue;
+
+ add_flag(&file_obst, "%s", unit->name);
+ }
+
+ add_flag(&file_obst, "-o");
+ add_flag(&file_obst, outname);
+ obstack_printf(&file_obst, "%s", flags);
+ obstack_1grow(&file_obst, '\0');
+
+ char *commandline = obstack_finish(&file_obst);
+
+ if (verbose) {
+ puts(commandline);
+ }
+ int err = system(commandline);
+ if (err != EXIT_SUCCESS) {
+ errorf(NULL, "linker reported an error");
+ return EXIT_FAILURE;
+ }
+ return EXIT_SUCCESS;
+}
+
+int main(int argc, char **argv)
+{
+ const char *print_file_name_file = NULL;
+ compile_mode_t mode = CompileAssembleLink;
+ int opt_level = 1;
+ char cpu_arch[16] = "ia32";
+ compilation_unit_t *units = NULL;
+ compilation_unit_t *last_unit = NULL;
+ bool produce_statev = false;
+ const char *filtev = NULL;
+ bool profile_generate = false;
+ bool profile_use = false;
+ bool do_timing = false;
+ bool print_timing = false;
/* hack for now... */
if (strstr(argv[0], "pptest") != NULL) {
return pptest_main(argc, argv);
}
+ temp_files = NEW_ARR_F(char*, 0);
+ atexit(free_temp_files);
+
obstack_init(&cppflags_obst);
obstack_init(&ldflags_obst);
obstack_init(&asflags_obst);
obstack_init(&file_obst);
+ init_include_paths();
#define GET_ARG_AFTER(def, args) \
do { \
if (def[0] == '\0') { \
++i; \
if (i >= argc) { \
- fprintf(stderr, "error: expected argument after '" args "'\n"); \
+ errorf(NULL, "expected argument after '" args "'"); \
argument_errors = true; \
break; \
} \
def = argv[i]; \
if (def[0] == '-' && def[1] != '\0') { \
- fprintf(stderr, "error: expected argument after '" args "'\n"); \
+ errorf(NULL, "expected argument after '" args "'"); \
argument_errors = true; \
continue; \
} \
#define SINGLE_OPTION(ch) (option[0] == (ch) && option[1] == '\0')
+ /* initialize this early because it has to parse options */
+ gen_firm_init();
+
/* early options parsing (find out optimization level and OS) */
for (int i = 1; i < argc; ++i) {
const char *arg = argv[i];
}
}
- const char *target = getenv("TARGET");
- if (target != NULL)
- parse_target_triple(target);
if (target_machine == NULL) {
target_machine = firm_get_host_machine();
}
setup_target_machine();
/* parse rest of options */
- standard = STANDARD_DEFAULT;
- unsigned features_on = 0;
- unsigned features_off = 0;
- filetype_t forced_filetype = FILETYPE_AUTODETECT;
- help_sections_t help = HELP_NONE;
- bool argument_errors = false;
+ lang_standard_t standard = STANDARD_DEFAULT;
+ compilation_unit_type_t forced_unittype = COMPILATION_UNIT_AUTODETECT;
+ help_sections_t help = HELP_NONE;
+ bool argument_errors = false;
for (int i = 1; i < argc; ++i) {
const char *arg = argv[i];
if (arg[0] == '-' && arg[1] != '\0') {
if (option[0] == 'o') {
GET_ARG_AFTER(outname, "-o");
} else if (option[0] == 'g') {
- set_be_option("debuginfo=stabs");
- set_be_option("omitfp=no");
- set_be_option("ia32-nooptcc=yes");
+ /* TODO: parse -gX with 0<=X<=3... */
+ set_be_option("debug=frameinfo");
+ set_be_option("ia32-optcc=false");
} else if (SINGLE_OPTION('c')) {
mode = CompileAssemble;
} else if (SINGLE_OPTION('E')) {
mode = PreprocessOnly;
+ } else if (SINGLE_OPTION('s')) {
+ add_flag(&ldflags_obst, "-s");
} else if (SINGLE_OPTION('S')) {
mode = Compile;
} else if (option[0] == 'O') {
const char *opt;
GET_ARG_AFTER(opt, "-I");
add_flag(&cppflags_obst, "-I%s", opt);
+ append_include_path(&bracket_searchpath, opt);
} else if (option[0] == 'D') {
const char *opt;
GET_ARG_AFTER(opt, "-D");
} else if (SINGLE_OPTION('v')) {
verbose = 1;
} else if (SINGLE_OPTION('w')) {
+ add_flag(&cppflags_obst, "-w");
disable_all_warnings();
} else if (option[0] == 'x') {
const char *opt;
GET_ARG_AFTER(opt, "-x");
- forced_filetype = get_filetype_from_string(opt);
- if (forced_filetype == FILETYPE_UNKNOWN) {
- fprintf(stderr, "Unknown language '%s'\n", opt);
+ forced_unittype = get_unit_type_from_string(opt);
+ if (forced_unittype == COMPILATION_UNIT_UNKNOWN) {
+ errorf(NULL, "unknown language '%s'", opt);
argument_errors = true;
}
- } else if (streq(option, "M")) {
+ } else if (SINGLE_OPTION('M')) {
mode = PreprocessOnly;
add_flag(&cppflags_obst, "-M");
} else if (streq(option, "MMD") ||
streq(option, "MD")) {
- construct_dep_target = true;
+ construct_dep_target = true;
add_flag(&cppflags_obst, "-%s", option);
} else if (streq(option, "MM") ||
streq(option, "MP")) {
GET_ARG_AFTER(opt, "-include");
add_flag(&cppflags_obst, "-include");
add_flag(&cppflags_obst, "%s", opt);
+ } else if (streq(option, "idirafter")) {
+ const char *opt;
+ GET_ARG_AFTER(opt, "-idirafter");
+ add_flag(&cppflags_obst, "-idirafter");
+ add_flag(&cppflags_obst, "%s", opt);
+ append_include_path(&after_searchpath, opt);
} else if (streq(option, "isystem")) {
const char *opt;
GET_ARG_AFTER(opt, "-isystem");
add_flag(&cppflags_obst, "-isystem");
add_flag(&cppflags_obst, "%s", opt);
-#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__CYGWIN__)
+ append_include_path(&system_searchpath, opt);
+ } else if (streq(option, "iquote")) {
+ const char *opt;
+ GET_ARG_AFTER(opt, "-iquote");
+ add_flag(&cppflags_obst, "-iquote");
+ add_flag(&cppflags_obst, "%s", opt);
+ append_include_path("e_searchpath, opt);
} else if (streq(option, "pthread")) {
/* set flags for the preprocessor */
add_flag(&cppflags_obst, "-D_REENTRANT");
/* set flags for the linker */
add_flag(&ldflags_obst, "-lpthread");
-#endif
} else if (streq(option, "nostdinc")
|| streq(option, "trigraphs")) {
/* pass these through to the preprocessor */
if (strstart(orig_opt, "input-charset=")) {
char const* const encoding = strchr(orig_opt, '=') + 1;
- select_input_encoding(encoding);
+ input_encoding = encoding;
} else if (strstart(orig_opt, "align-loops=") ||
strstart(orig_opt, "align-jumps=") ||
strstart(orig_opt, "align-functions=")) {
elf_visibility_tag_t visibility
= get_elf_visibility_from_string(val);
if (visibility == ELF_VISIBILITY_ERROR) {
- fprintf(stderr, "invalid visibility '%s' specified\n",
- val);
+ errorf(NULL, "invalid visibility '%s' specified", val);
argument_errors = true;
} else {
set_default_visibility(visibility);
}
} else if (strstart(orig_opt, "message-length=")) {
/* ignore: would only affect error message format */
- } else if (strstart(orig_opt, "fast-math") ||
- strstart(orig_opt, "fp-fast")) {
+ } else if (streq(orig_opt, "fast-math") ||
+ streq(orig_opt, "fp-fast")) {
firm_fp_model = fp_model_fast;
- } else if (strstart(orig_opt, "fp-precise")) {
+ } else if (streq(orig_opt, "fp-precise")) {
firm_fp_model = fp_model_precise;
- } else if (strstart(orig_opt, "fp-strict")) {
+ } else if (streq(orig_opt, "fp-strict")) {
firm_fp_model = fp_model_strict;
- } else if (streq(opt, "help")) {
+ } else if (streq(orig_opt, "help")) {
fprintf(stderr, "warning: -fhelp is deprecated\n");
help |= HELP_OPTIMIZATION;
} else {
opt += 3;
}
- if (streq(opt, "builtins")) {
- use_builtins = truth_value;
- } else if (streq(opt, "diagnostics-show-option")) {
+ if (streq(opt, "diagnostics-show-option")) {
diagnostics_show_option = truth_value;
} else if (streq(opt, "dollars-in-identifiers")) {
allow_dollar_in_symbol = truth_value;
streq(opt, "align-loops") ||
streq(opt, "align-jumps") ||
streq(opt, "align-functions") ||
- streq(opt, "PIC")) {
+ streq(opt, "PIC") ||
+ streq(opt, "stack-protector") ||
+ streq(opt, "stack-protector-all")) {
fprintf(stderr, "ignoring gcc option '-f%s'\n", orig_opt);
} else {
- int res = firm_option(orig_opt);
- if (res == 0) {
- fprintf(stderr, "error: unknown Firm option '-f%s'\n",
- orig_opt);
+ if (firm_option(orig_opt) == 0) {
+ errorf(NULL, "unknown Firm option '-f%s'", orig_opt);
argument_errors = true;
continue;
}
fprintf(stderr, "warning: -bhelp is deprecated (use --help-firm)\n");
help |= HELP_FIRM;
} else {
- int res = be_parse_arg(opt);
- if (res == 0) {
- fprintf(stderr, "error: unknown Firm backend option '-b %s'\n",
- opt);
+ if (be_parse_arg(opt) == 0) {
+ errorf(NULL, "unknown Firm backend option '-b %s'", opt);
argument_errors = true;
} else if (strstart(opt, "isa=")) {
strncpy(cpu_arch, opt, sizeof(cpu_arch));
}
}
} else if (option[0] == 'W') {
- if (strstart(option + 1, "p,")) {
+ if (strstart(option + 1, "a,")) {
+ const char *opt;
+ GET_ARG_AFTER(opt, "-Wa,");
+ add_flag(&asflags_obst, "-Wa,%s", opt);
+ } else if (strstart(option + 1, "p,")) {
// pass options directly to the preprocessor
const char *opt;
GET_ARG_AFTER(opt, "-Wp,");
GET_ARG_AFTER(opt, "-Wl,");
add_flag(&ldflags_obst, "-Wl,%s", opt);
} else if (streq(option + 1, "no-trigraphs")
- || streq(option + 1, "undef")) {
+ || streq(option + 1, "undef")
+ || streq(option + 1, "missing-include-dirs")
+ || streq(option + 1, "endif-labels")) {
add_flag(&cppflags_obst, "%s", arg);
+ } else if (streq(option+1, "init-self")) {
+ /* ignored (same as gcc does) */
+ } else if (streq(option+1, "format-y2k")
+ || streq(option+1, "format-security")
+ || streq(option+1, "old-style-declaration")
+ || streq(option+1, "type-limits")) {
+ /* ignore (gcc compatibility) */
} else {
set_warning_opt(&option[1]);
}
if (!parse_target_triple(opt)) {
argument_errors = true;
} else {
- setup_target_machine();
+ const char *isa = setup_target_machine();
+ strncpy(cpu_arch, isa, sizeof(cpu_arch));
target_triple = opt;
}
} else if (strstart(opt, "triple=")) {
if (!parse_target_triple(opt)) {
argument_errors = true;
} else {
- setup_target_machine();
+ const char *isa = setup_target_machine();
+ strncpy(cpu_arch, isa, sizeof(cpu_arch));
target_triple = opt;
}
} else if (strstart(opt, "arch=")) {
res &= be_parse_arg(arch_opt);
if (res == 0) {
- fprintf(stderr, "Unknown architecture '%s'\n", arch_opt);
+ errorf(NULL, "unknown architecture '%s'", arch_opt);
argument_errors = true;
}
} else if (strstart(opt, "tune=")) {
GET_ARG_AFTER(opt, "-mtune=");
snprintf(arch_opt, sizeof(arch_opt), "%s-opt=%s", cpu_arch, opt);
- int res = be_parse_arg(arch_opt);
- if (res == 0)
+ if (be_parse_arg(arch_opt) == 0)
argument_errors = true;
} else if (strstart(opt, "cpu=")) {
GET_ARG_AFTER(opt, "-mcpu=");
snprintf(arch_opt, sizeof(arch_opt), "%s-arch=%s", cpu_arch, opt);
- int res = be_parse_arg(arch_opt);
- if (res == 0)
+ if (be_parse_arg(arch_opt) == 0)
argument_errors = true;
} else if (strstart(opt, "fpmath=")) {
GET_ARG_AFTER(opt, "-mfpmath=");
else if (streq(opt, "sse"))
opt = "sse2";
else {
- fprintf(stderr, "error: option -mfpmath supports only 387 or sse\n");
+ errorf(NULL, "option -mfpmath supports only 387 or sse");
argument_errors = true;
}
if (!argument_errors) {
snprintf(arch_opt, sizeof(arch_opt), "%s-fpunit=%s", cpu_arch, opt);
- int res = be_parse_arg(arch_opt);
- if (res == 0)
+ if (be_parse_arg(arch_opt) == 0)
argument_errors = true;
}
} else if (strstart(opt, "preferred-stack-boundary=")) {
GET_ARG_AFTER(opt, "-mpreferred-stack-boundary=");
snprintf(arch_opt, sizeof(arch_opt), "%s-stackalign=%s", cpu_arch, opt);
- int res = be_parse_arg(arch_opt);
- if (res == 0)
+ if (be_parse_arg(arch_opt) == 0)
argument_errors = true;
} else if (streq(opt, "rtd")) {
default_calling_convention = CC_STDCALL;
} else if (strstart(opt, "regparm=")) {
- fprintf(stderr, "error: regparm convention not supported yet\n");
+ errorf(NULL, "regparm convention not supported yet");
argument_errors = true;
} else if (streq(opt, "soft-float")) {
- fprintf(stderr, "error: software floatingpoint not supported yet\n");
- argument_errors = true;
+ add_flag(&ldflags_obst, "-msoft-float");
+ snprintf(arch_opt, sizeof(arch_opt), "%s-fpunit=softfloat", cpu_arch);
+ if (be_parse_arg(arch_opt) == 0)
+ argument_errors = true;
+ } else if (streq(opt, "sse2")) {
+ /* ignore for now, our x86 backend always uses sse when
+ * sse is requested */
} else {
long int value = strtol(opt, NULL, 10);
if (value == 0) {
- fprintf(stderr, "error: wrong option '-m %s'\n", opt);
+ errorf(NULL, "wrong option '-m %s'", opt);
argument_errors = true;
} else if (value != 16 && value != 32 && value != 64) {
- fprintf(stderr, "error: option -m supports only 16, 32 or 64\n");
+ errorf(NULL, "option -m supports only 16, 32 or 64");
argument_errors = true;
} else {
+ unsigned machine_size = (unsigned)value;
+ /* TODO: choose/change backend based on this */
add_flag(&cppflags_obst, "-m%u", machine_size);
add_flag(&asflags_obst, "-m%u", machine_size);
add_flag(&ldflags_obst, "-m%u", machine_size);
- /* TODO: choose/change backend based on this */
}
}
+ } else if (option[0] == 'X') {
+ if (streq(option + 1, "assembler")) {
+ const char *opt;
+ GET_ARG_AFTER(opt, "-Xassembler");
+ add_flag(&asflags_obst, "-Xassembler");
+ add_flag(&asflags_obst, opt);
+ } else if (streq(option + 1, "preprocessor")) {
+ const char *opt;
+ GET_ARG_AFTER(opt, "-Xpreprocessor");
+ add_flag(&cppflags_obst, "-Xpreprocessor");
+ add_flag(&cppflags_obst, opt);
+ } else if (streq(option + 1, "linker")) {
+ const char *opt;
+ GET_ARG_AFTER(opt, "-Xlinker");
+ add_flag(&ldflags_obst, "-Xlinker");
+ add_flag(&ldflags_obst, opt);
+ }
} else if (streq(option, "pg")) {
set_be_option("gprof");
add_flag(&ldflags_obst, "-pg");
- } else if (streq(option, "pedantic") ||
- streq(option, "ansi")) {
+ } else if (streq(option, "ansi")) {
+ standard = STANDARD_ANSI;
+ } else if (streq(option, "pedantic")) {
fprintf(stderr, "warning: ignoring gcc option '%s'\n", arg);
} else if (strstart(option, "std=")) {
const char *const o = &option[4];
standard =
streq(o, "c++") ? STANDARD_CXX98 :
streq(o, "c++98") ? STANDARD_CXX98 :
+ streq(o, "c11") ? STANDARD_C11 :
+ streq(o, "c1x") ? STANDARD_C11 : // deprecated
streq(o, "c89") ? STANDARD_C89 :
+ streq(o, "c90") ? STANDARD_C89 :
streq(o, "c99") ? STANDARD_C99 :
streq(o, "c9x") ? STANDARD_C99 : // deprecated
streq(o, "gnu++98") ? STANDARD_GNUXX98 :
+ streq(o, "gnu11") ? STANDARD_GNU11 :
+ streq(o, "gnu1x") ? STANDARD_GNU11 : // deprecated
streq(o, "gnu89") ? STANDARD_GNU89 :
streq(o, "gnu99") ? STANDARD_GNU99 :
streq(o, "gnu9x") ? STANDARD_GNU99 : // deprecated
streq(o, "iso9899:1990") ? STANDARD_C89 :
- streq(o, "iso9899:199409") ? STANDARD_C90 :
+ streq(o, "iso9899:199409") ? STANDARD_C89AMD1 :
streq(o, "iso9899:1999") ? STANDARD_C99 :
streq(o, "iso9899:199x") ? STANDARD_C99 : // deprecated
+ streq(o, "iso9899:2011") ? STANDARD_C11 :
(fprintf(stderr, "warning: ignoring gcc option '%s'\n", arg), standard);
} else if (streq(option, "version")) {
print_cparser_version();
+ return EXIT_SUCCESS;
+ } else if (streq(option, "dumpversion")) {
+ /* gcc compatibility option */
+ print_cparser_version_short();
+ return EXIT_SUCCESS;
} else if (strstart(option, "print-file-name=")) {
GET_ARG_AFTER(print_file_name_file, "-print-file-name=");
} else if (option[0] == '-') {
features_off |= _MS;
} else if (streq(option, "strict")) {
strict_mode = true;
- } else if (streq(option, "lextest")) {
- mode = LexTest;
} else if (streq(option, "benchmark")) {
mode = BenchmarkParser;
} else if (streq(option, "print-ast")) {
print_parenthesis = true;
} else if (streq(option, "print-fluffy")) {
mode = PrintFluffy;
+ } else if (streq(option, "print-compound-sizes")) {
+ mode = PrintCompoundSizes;
} else if (streq(option, "print-jna")) {
mode = PrintJna;
} else if (streq(option, "jna-limit")) {
++i;
if (i >= argc) {
- fprintf(stderr, "error: "
- "expected argument after '--jna-limit'\n");
+ errorf(NULL, "expected argument after '--jna-limit'");
argument_errors = true;
break;
}
} else if (streq(option, "jna-libname")) {
++i;
if (i >= argc) {
- fprintf(stderr, "error: "
- "expected argument after '--jna-libname'\n");
+ errorf(NULL, "expected argument after '--jna-libname'");
argument_errors = true;
break;
}
jna_set_libname(argv[i]);
+ } else if (streq(option, "external-pp")) {
+ if (i+1 < argc && argv[i+1][0] != '-') {
+ ++i;
+ external_preprocessor = argv[i+1];
+ } else {
+ external_preprocessor = PREPROCESSOR;
+ }
+ } else if (streq(option, "no-external-pp")) {
+ external_preprocessor = NULL;
} else if (streq(option, "time")) {
- do_timing = true;
+ do_timing = true;
+ print_timing = true;
+ } else if (streq(option, "statev")) {
+ do_timing = true;
+ produce_statev = true;
+ } else if (strstart(option, "filtev=")) {
+ GET_ARG_AFTER(filtev, "--filtev=");
} else if (streq(option, "version")) {
print_cparser_version();
return EXIT_SUCCESS;
} else if (streq(option, "dump-function")) {
++i;
if (i >= argc) {
- fprintf(stderr, "error: "
- "expected argument after '--dump-function'\n");
+ errorf(NULL, "expected argument after '--dump-function'");
argument_errors = true;
break;
}
mode = CompileDump;
} else if (streq(option, "export-ir")) {
mode = CompileExportIR;
+ } else if (streq(option, "unroll-loops")) {
+ /* ignore (gcc compatibility) */
} else {
- fprintf(stderr, "error: unknown argument '%s'\n", arg);
+ errorf(NULL, "unknown argument '%s'", arg);
argument_errors = true;
}
} else {
- fprintf(stderr, "error: unknown argument '%s'\n", arg);
+ errorf(NULL, "unknown argument '%s'", arg);
argument_errors = true;
}
} else {
- filetype_t type = forced_filetype;
- if (type == FILETYPE_AUTODETECT) {
+ compilation_unit_type_t type = forced_unittype;
+ if (type == COMPILATION_UNIT_AUTODETECT) {
if (streq(arg, "-")) {
/* - implicitly means C source file */
- type = FILETYPE_C;
+ type = COMPILATION_UNIT_C;
} else {
const char *suffix = strrchr(arg, '.');
/* Ensure there is at least one char before the suffix */
if (suffix != NULL && suffix != arg) {
++suffix;
type =
- streq(suffix, "S") ? FILETYPE_ASSEMBLER :
- streq(suffix, "a") ? FILETYPE_OBJECT :
- streq(suffix, "c") ? FILETYPE_C :
- streq(suffix, "i") ? FILETYPE_PREPROCESSED_C :
- streq(suffix, "C") ? FILETYPE_CXX :
- streq(suffix, "cc") ? FILETYPE_CXX :
- streq(suffix, "cp") ? FILETYPE_CXX :
- streq(suffix, "cpp") ? FILETYPE_CXX :
- streq(suffix, "CPP") ? FILETYPE_CXX :
- streq(suffix, "cxx") ? FILETYPE_CXX :
- streq(suffix, "c++") ? FILETYPE_CXX :
- streq(suffix, "ii") ? FILETYPE_PREPROCESSED_CXX :
- streq(suffix, "h") ? FILETYPE_C :
- streq(suffix, "ir") ? FILETYPE_IR :
- streq(suffix, "o") ? FILETYPE_OBJECT :
- streq(suffix, "s") ? FILETYPE_PREPROCESSED_ASSEMBLER :
- streq(suffix, "so") ? FILETYPE_OBJECT :
- FILETYPE_OBJECT; /* gcc behavior: unknown file extension means object file */
+ streq(suffix, "S") ? COMPILATION_UNIT_ASSEMBLER :
+ streq(suffix, "a") ? COMPILATION_UNIT_OBJECT :
+ streq(suffix, "c") ? COMPILATION_UNIT_C :
+ streq(suffix, "i") ? COMPILATION_UNIT_PREPROCESSED_C :
+ streq(suffix, "C") ? COMPILATION_UNIT_CXX :
+ streq(suffix, "cc") ? COMPILATION_UNIT_CXX :
+ streq(suffix, "cp") ? COMPILATION_UNIT_CXX :
+ streq(suffix, "cpp") ? COMPILATION_UNIT_CXX :
+ streq(suffix, "CPP") ? COMPILATION_UNIT_CXX :
+ streq(suffix, "cxx") ? COMPILATION_UNIT_CXX :
+ streq(suffix, "c++") ? COMPILATION_UNIT_CXX :
+ streq(suffix, "ii") ? COMPILATION_UNIT_PREPROCESSED_CXX :
+ streq(suffix, "h") ? COMPILATION_UNIT_C :
+ streq(suffix, "ir") ? COMPILATION_UNIT_IR :
+ streq(suffix, "o") ? COMPILATION_UNIT_OBJECT :
+ streq(suffix, "s") ? COMPILATION_UNIT_PREPROCESSED_ASSEMBLER :
+ streq(suffix, "so") ? COMPILATION_UNIT_OBJECT :
+ COMPILATION_UNIT_OBJECT; /* gcc behavior: unknown file extension means object file */
}
}
}
- file_list_entry_t *entry
- = obstack_alloc(&file_obst, sizeof(entry[0]));
- memset(entry, 0, sizeof(entry[0]));
+ compilation_unit_t *entry = OALLOCZ(&file_obst, compilation_unit_t);
entry->name = arg;
entry->type = type;
- if (last_file != NULL) {
- last_file->next = entry;
+ if (last_unit != NULL) {
+ last_unit->next = entry;
} else {
- files = entry;
+ units = entry;
}
- last_file = entry;
+ last_unit = entry;
}
}
print_file_name(print_file_name_file);
return EXIT_SUCCESS;
}
- if (files == NULL) {
- fprintf(stderr, "error: no input files specified\n");
+ if (units == NULL) {
+ errorf(NULL, "no input files specified");
argument_errors = true;
}
set_be_option("profileuse");
}
- gen_firm_init();
init_symbol_table();
- init_types();
+ init_types_and_adjust();
init_typehash();
init_basic_types();
- init_lexer();
+ if (c_mode & _CXX) {
+ init_wchar_types(ATOMIC_TYPE_WCHAR_T);
+ } else {
+ init_wchar_types(wchar_atomic_kind);
+ }
+ init_preprocessor();
init_ast();
init_parser();
init_ast2firm();
if (do_timing)
timer_init();
- if (construct_dep_target) {
- if (outname != 0 && strlen(outname) >= 2) {
- get_output_name(dep_target, sizeof(dep_target), outname, ".d");
- } else {
- get_output_name(dep_target, sizeof(dep_target), files->name, ".d");
- }
- } else {
- dep_target[0] = '\0';
- }
-
char outnamebuf[4096];
if (outname == NULL) {
- const char *filename = files->name;
+ const char *filename = units->name;
- switch(mode) {
+ switch (mode) {
case BenchmarkParser:
case PrintAst:
case PrintFluffy:
case PrintJna:
- case LexTest:
+ case PrintCompoundSizes:
case PreprocessOnly:
case ParseOnly:
outname = "-";
outname = outnamebuf;
break;
case CompileAssembleLink:
-#ifdef _WIN32
- outname = "a.exe";
-#else
- outname = "a.out";
-#endif
+ if (firm_is_windows_os(target_machine)) {
+ outname = "a.exe";
+ } else {
+ outname = "a.out";
+ }
break;
}
}
} else {
out = fopen(outname, "w");
if (out == NULL) {
- fprintf(stderr, "Could not open '%s' for writing: %s\n", outname,
- strerror(errno));
+ position_t const pos = { outname, 0, 0, 0 };
+ errorf(&pos, "could not open for writing: %s", strerror(errno));
return EXIT_FAILURE;
}
}
- file_list_entry_t *file;
- bool already_constructed_firm = false;
- for (file = files; file != NULL; file = file->next) {
- char asm_tempfile[1024];
- const char *filename = file->name;
- filetype_t filetype = file->type;
-
- if (filetype == FILETYPE_OBJECT)
- continue;
-
- FILE *in = NULL;
- if (mode == LexTest) {
- if (in == NULL)
- in = open_file(filename);
- lextest(in, filename);
- fclose(in);
- return EXIT_SUCCESS;
- }
-
- FILE *preprocessed_in = NULL;
- filetype_t next_filetype = filetype;
- switch (filetype) {
- case FILETYPE_C:
- next_filetype = FILETYPE_PREPROCESSED_C;
- goto preprocess;
- case FILETYPE_CXX:
- next_filetype = FILETYPE_PREPROCESSED_CXX;
- goto preprocess;
- case FILETYPE_ASSEMBLER:
- next_filetype = FILETYPE_PREPROCESSED_ASSEMBLER;
- goto preprocess;
-preprocess:
- /* no support for input on FILE* yet */
- if (in != NULL)
- panic("internal compiler error: in for preprocessor != NULL");
-
- preprocessed_in = preprocess(filename, filetype);
- if (mode == PreprocessOnly) {
- copy_file(out, preprocessed_in);
- int pp_result = pclose(preprocessed_in);
- fclose(out);
- /* remove output file in case of error */
- if (out != stdout && pp_result != EXIT_SUCCESS) {
- unlink(outname);
- }
- return pp_result;
- }
-
- in = preprocessed_in;
- filetype = next_filetype;
- break;
-
- default:
- break;
- }
-
- FILE *asm_out;
- if (mode == Compile) {
- asm_out = out;
- } else {
- asm_out = make_temp_file(asm_tempfile, sizeof(asm_tempfile), "ccs");
- }
-
- if (in == NULL)
- in = open_file(filename);
-
- /* preprocess and compile */
- if (filetype == FILETYPE_PREPROCESSED_C) {
- char const* invalid_mode;
- switch (standard) {
- case STANDARD_ANSI:
- case STANDARD_C89: c_mode = _C89; break;
- /* TODO determine difference between these two */
- case STANDARD_C90: c_mode = _C89; break;
- case STANDARD_C99: c_mode = _C89 | _C99; break;
- case STANDARD_GNU89: c_mode = _C89 | _GNUC; break;
-
-default_c_warn:
- fprintf(stderr,
- "warning: command line option \"-std=%s\" is not valid for C\n",
- invalid_mode);
- /* FALLTHROUGH */
- case STANDARD_DEFAULT:
- case STANDARD_GNU99: c_mode = _C89 | _C99 | _GNUC; break;
-
- case STANDARD_CXX98: invalid_mode = "c++98"; goto default_c_warn;
- case STANDARD_GNUXX98: invalid_mode = "gnu98"; goto default_c_warn;
- }
- goto do_parsing;
- } else if (filetype == FILETYPE_PREPROCESSED_CXX) {
- char const* invalid_mode;
- switch (standard) {
- case STANDARD_C89: invalid_mode = "c89"; goto default_cxx_warn;
- case STANDARD_C90: invalid_mode = "c90"; goto default_cxx_warn;
- case STANDARD_C99: invalid_mode = "c99"; goto default_cxx_warn;
- case STANDARD_GNU89: invalid_mode = "gnu89"; goto default_cxx_warn;
- case STANDARD_GNU99: invalid_mode = "gnu99"; goto default_cxx_warn;
-
- case STANDARD_ANSI:
- case STANDARD_CXX98: c_mode = _CXX; break;
-
-default_cxx_warn:
- fprintf(stderr,
- "warning: command line option \"-std=%s\" is not valid for C++\n",
- invalid_mode);
- case STANDARD_DEFAULT:
- case STANDARD_GNUXX98: c_mode = _CXX | _GNUC; break;
- }
-
-do_parsing:
- c_mode |= features_on;
- c_mode &= ~features_off;
-
- /* do the actual parsing */
- ir_timer_t *t_parsing = ir_timer_new();
- timer_register(t_parsing, "Frontend: Parsing");
- timer_push(t_parsing);
- init_tokens();
- translation_unit_t *const unit = do_parsing(in, filename);
- timer_pop(t_parsing);
-
- /* prints the AST even if errors occurred */
- if (mode == PrintAst) {
- print_to_file(out);
- print_ast(unit);
- }
-
- if (error_count > 0) {
- /* parsing failed because of errors */
- fprintf(stderr, "%u error(s), %u warning(s)\n", error_count,
- warning_count);
- result = EXIT_FAILURE;
- continue;
- } else if (warning_count > 0) {
- fprintf(stderr, "%u warning(s)\n", warning_count);
- }
-
- if (in == preprocessed_in) {
- int pp_result = pclose(preprocessed_in);
- if (pp_result != EXIT_SUCCESS) {
- /* remove output file */
- if (out != stdout)
- unlink(outname);
- return EXIT_FAILURE;
- }
- }
-
- if (mode == BenchmarkParser) {
- return result;
- } else if (mode == PrintFluffy) {
- write_fluffy_decls(out, unit);
- continue;
- } else if (mode == PrintJna) {
- write_jna_decls(out, unit);
- continue;
- }
-
- /* build the firm graph */
- ir_timer_t *t_construct = ir_timer_new();
- timer_register(t_construct, "Frontend: Graph construction");
- timer_push(t_construct);
- if (already_constructed_firm) {
- panic("compiling multiple files/translation units not possible");
- }
- translation_unit_to_firm(unit);
- already_constructed_firm = true;
- timer_pop(t_construct);
-
-graph_built:
- if (mode == ParseOnly) {
- continue;
- }
-
- if (mode == CompileDump) {
- /* find irg */
- ident *id = new_id_from_str(dumpfunction);
- ir_graph *irg = NULL;
- int n_irgs = get_irp_n_irgs();
- for (int i = 0; i < n_irgs; ++i) {
- ir_graph *tirg = get_irp_irg(i);
- ident *irg_id = get_entity_ident(get_irg_entity(tirg));
- if (irg_id == id) {
- irg = tirg;
- break;
- }
- }
-
- if (irg == NULL) {
- fprintf(stderr, "No graph for function '%s' found\n",
- dumpfunction);
- return EXIT_FAILURE;
- }
-
- dump_ir_graph_file(out, irg);
- fclose(out);
- return EXIT_SUCCESS;
- }
-
- if (mode == CompileExportIR) {
- fclose(out);
- ir_export(outname);
- return EXIT_SUCCESS;
- }
-
- gen_firm_finish(asm_out, filename);
- if (asm_out != out) {
- fclose(asm_out);
- }
- } else if (filetype == FILETYPE_IR) {
- fclose(in);
- ir_import(filename);
- goto graph_built;
- } else if (filetype == FILETYPE_PREPROCESSED_ASSEMBLER) {
- copy_file(asm_out, in);
- if (in == preprocessed_in) {
- int pp_result = pclose(preprocessed_in);
- if (pp_result != EXIT_SUCCESS) {
- /* remove output in error case */
- if (out != stdout)
- unlink(outname);
- return pp_result;
- }
- }
- if (asm_out != out) {
- fclose(asm_out);
- }
- }
-
- if (mode == Compile)
- continue;
-
- /* if we're here then we have preprocessed assembly */
- filename = asm_tempfile;
- filetype = FILETYPE_PREPROCESSED_ASSEMBLER;
-
- /* assemble */
- if (filetype == FILETYPE_PREPROCESSED_ASSEMBLER) {
- char temp[1024];
- const char *filename_o;
- if (mode == CompileAssemble) {
- fclose(out);
- filename_o = outname;
- } else {
- FILE *tempf = make_temp_file(temp, sizeof(temp), "cco");
- fclose(tempf);
- filename_o = temp;
- }
-
- assemble(filename_o, filename);
-
- size_t len = strlen(filename_o) + 1;
- filename = obstack_copy(&file_obst, filename_o, len);
- filetype = FILETYPE_OBJECT;
+ if (produce_statev && units != NULL) {
+ /* attempt to guess a good name for the file */
+ const char *first_cup = units->name;
+ if (first_cup != NULL) {
+ const char *dot = strrchr(first_cup, '.');
+ const char *pos = dot ? dot : first_cup + strlen(first_cup);
+ char buf[pos-first_cup+1];
+ strncpy(buf, first_cup, pos-first_cup);
+ buf[pos-first_cup] = '\0';
+
+ stat_ev_begin(buf, filtev);
}
+ }
- /* ok we're done here, process next file */
- file->name = filename;
- file->type = filetype;
+ int result = compilation_loop(mode, units, standard, out);
+ if (stat_ev_enabled) {
+ stat_ev_end();
}
if (result != EXIT_SUCCESS) {
/* link program file */
if (mode == CompileAssembleLink) {
- obstack_1grow(&ldflags_obst, '\0');
- const char *flags = obstack_finish(&ldflags_obst);
-
- /* construct commandline */
- const char *linker = getenv("CPARSER_LINK");
- if (linker != NULL) {
- obstack_printf(&file_obst, "%s ", linker);
- } else {
- if (target_triple != NULL)
- obstack_printf(&file_obst, "%s-", target_triple);
- obstack_printf(&file_obst, "%s ", LINKER);
- }
-
- for (file_list_entry_t *entry = files; entry != NULL;
- entry = entry->next) {
- if (entry->type != FILETYPE_OBJECT)
- continue;
-
- add_flag(&file_obst, "%s", entry->name);
- }
-
- add_flag(&file_obst, "-o");
- add_flag(&file_obst, outname);
- obstack_printf(&file_obst, "%s", flags);
- obstack_1grow(&file_obst, '\0');
-
- char *commandline = obstack_finish(&file_obst);
-
- if (verbose) {
- puts(commandline);
- }
- int err = system(commandline);
- if (err != EXIT_SUCCESS) {
- fprintf(stderr, "linker reported an error\n");
- return EXIT_FAILURE;
+ int const link_result = link_program(units);
+ if (link_result != EXIT_SUCCESS) {
+ if (out != stdout)
+ unlink(outname);
+ return link_result;
}
}
if (do_timing)
- timer_term(stderr);
+ timer_term(print_timing ? stderr : NULL);
+ free_temp_files();
obstack_free(&cppflags_obst, NULL);
obstack_free(&ldflags_obst, NULL);
obstack_free(&asflags_obst, NULL);
obstack_free(&file_obst, NULL);
+ gen_firm_finish();
exit_mangle();
exit_ast2firm();
exit_parser();
exit_ast();
- exit_lexer();
+ exit_preprocessor();
exit_typehash();
exit_types();
exit_tokens();