+ c_mode |= features_on;
+ c_mode &= ~features_off;
+}
+
+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)
+{
+ /* just here for gcc compatibility */
+ fprintf(out, "# 1 \"%s\"\n", unit->name);
+ fprintf(out, "# 1 \"<built-in>\"\n");
+ fprintf(out, "# 1 \"<command-line>\"\n");
+
+ 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];
+
+ 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 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;