34ee11b45f2c370343a1ffea02423946431cdd1f
[cparser] / main.c
1 #include <config.h>
2
3 #define _GNU_SOURCE
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <stdbool.h>
8 #include <errno.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include <assert.h>
12
13 #ifndef WITH_LIBCORE
14 #define WITH_LIBCORE
15 #endif
16
17 #include <libfirm/firm.h>
18 #include <libfirm/be.h>
19
20 #include "lexer.h"
21 #include "token_t.h"
22 #include "type_hash.h"
23 #include "parser.h"
24 #include "ast2firm.h"
25 #include "adt/error.h"
26 #include "write_fluffy.h"
27
28 #ifndef PREPROCESSOR
29 #define PREPROCESSOR "cpp -std=c99 -U__WCHAR_TYPE__ -D__WCHAR_TYPE__=int"
30 #endif
31
32 #ifndef LINKER
33 #define LINKER       "gcc"
34 #endif
35
36 #ifndef ASSEMBLER
37 #define ASSEMBLER "as"
38 #endif
39
40 #ifdef _WIN32
41 /* remap some names */
42 #define popen(cmd, mode)  _popen(cmd, mode)
43 #define pclose(file)      _pclose(file)
44 #endif /* _WIN32 */
45
46 static int  verbose;
47 static bool do_dump;
48
49 static const ir_settings_if_conv_t *if_conv_info = NULL;
50 static const backend_params        *be_params    = NULL;
51
52 static void initialize_firm(void)
53 {
54         be_opt_register();
55         firm_init_options(NULL, 0, NULL);
56
57         firm_parameter_t params;
58         memset(&params, 0, sizeof(params));
59
60         params.size = sizeof(params);
61         params.enable_statistics = 0;
62         params.initialize_local_func = uninitialized_local_var;
63         params.cc_mask = 0;
64         params.builtin_dbg = NULL;
65
66         /* initialize backend */
67         be_params = be_init();
68         ir_set_debug_retrieve(retrieve_dbg);
69         params.arch_op_settings = be_params->arch_op_settings;
70         if_conv_info            = be_params->if_conv_info;
71
72         (void) if_conv_info; /* avoid unused warning */
73
74         /* intialize firm itself */
75         init_firm(&params);
76         dbg_init(NULL, NULL, dbg_snprint);
77
78         set_opt_constant_folding(1);
79         set_opt_unreachable_code(1);
80         set_opt_control_flow_straightening(1);
81         set_opt_control_flow_weak_simplification(1);
82         set_opt_control_flow_strong_simplification(1);
83         set_opt_dyn_meth_dispatch(1);
84         set_opt_normalize(1);
85         set_opt_precise_exc_context(0);
86         set_opt_strength_red(0);
87         set_opt_fragile_ops(0);
88         set_opt_optimize_class_casts(0);
89         set_opt_suppress_downcast_optimization(0);
90         set_opt_remove_confirm(1);
91         set_opt_scalar_replacement(1);
92         set_opt_ldst_only_null_ptr_exceptions(1);
93         set_opt_alias_analysis(1);
94
95         dump_consts_local(1);
96         dump_keepalive_edges(1);
97 }
98
99 static void dump(ir_graph *irg, const char *suffix)
100 {
101         if(do_dump) {
102                 dump_ir_block_graph(irg, suffix);
103         }
104 }
105
106 static void get_output_name(char *buf, size_t buflen, const char *inputname,
107                             const char *newext)
108 {
109         size_t last_dot = 0xffffffff;
110         size_t i = 0;
111
112         if(inputname == NULL) {
113                 snprintf(buf, buflen, "a%s", newext);
114                 return;
115         }
116
117         for(const char *c = inputname; *c != 0; ++c) {
118                 if(*c == '.')
119                         last_dot = i;
120                 ++i;
121         }
122         if(last_dot == 0xffffffff)
123                 last_dot = i;
124
125         if(last_dot >= buflen)
126                 panic("filename too long");
127         memcpy(buf, inputname, last_dot);
128
129         size_t extlen = strlen(newext) + 1;
130         if(extlen + last_dot >= buflen)
131                 panic("filename too long");
132         memcpy(buf+last_dot, newext, extlen);
133 }
134
135 static translation_unit_t *do_parsing(FILE *const in, const char *const input)
136 {
137         lexer_open_stream(in, input);
138         translation_unit_t *unit = parse();
139         return unit;
140 }
141
142 static void lextest(FILE *in, const char *fname)
143 {
144         lexer_open_stream(in, fname);
145
146         do {
147                 lexer_next_preprocessing_token();
148                 print_token(stdout, &lexer_token);
149                 puts("");
150         } while(lexer_token.type != T_EOF);
151 }
152
153 static void emit(FILE *out, const char *input_name)
154 {
155         be_main(out, input_name);
156 }
157
158 static FILE* preprocess(FILE* in, const char *fname)
159 {
160         char buf[4096];
161
162         if(in != stdin) {
163                 snprintf(buf, sizeof(buf), PREPROCESSOR " %s", fname);
164         } else {
165                 /* read from stdin */
166                 snprintf(buf, sizeof(buf), PREPROCESSOR " -");
167         }
168
169         if(verbose) {
170                 puts(buf);
171         }
172         FILE* f = popen(buf, "r");
173         if (f == NULL) {
174                 fprintf(stderr, "invoking preprocessor failed\n");
175                 exit(1);
176         }
177         return f;
178 }
179
180 static void do_link(const char *out, const char *in)
181 {
182         char buf[4096];
183
184         snprintf(buf, sizeof(buf), "%s %s -o %s", LINKER, in, out);
185         if(verbose) {
186                 puts(buf);
187         }
188         int err = system(buf);
189         if(err != 0) {
190                 fprintf(stderr, "linker reported an error\n");
191                 exit(1);
192         }
193 }
194
195 static void assemble(const char *out, const char *in)
196 {
197         char buf[4096];
198
199         snprintf(buf, sizeof(buf), "%s %s -o %s", ASSEMBLER, in, out);
200         if(verbose) {
201                 puts(buf);
202         }
203
204         int err = system(buf);
205         if(err != 0) {
206                 fprintf(stderr, "assembler reported an error\n");
207                 exit(1);
208         }
209 }
210
211 static const char *try_dir(const char *dir)
212 {
213         if(dir == NULL)
214                 return dir;
215         if(access(dir, R_OK | W_OK | X_OK) == 0)
216                 return dir;
217         return NULL;
218 }
219
220 static const char *get_tempdir(void)
221 {
222         static const char *tmpdir = NULL;
223
224         if(tmpdir != NULL)
225                 return tmpdir;
226
227         if(tmpdir == NULL)
228                 tmpdir = try_dir(getenv("TMPDIR"));
229         if(tmpdir == NULL)
230                 tmpdir = try_dir(getenv("TMP"));
231         if(tmpdir == NULL)
232                 tmpdir = try_dir(getenv("TEMP"));
233
234 #ifdef P_tmpdir
235         if(tmpdir == NULL)
236                 tmpdir = try_dir(P_tmpdir);
237 #endif
238
239         if(tmpdir == NULL)
240                 tmpdir = try_dir("/var/tmp");
241         if(tmpdir == NULL)
242                 tmpdir = try_dir("/usr/tmp");
243         if(tmpdir == NULL)
244                 tmpdir = try_dir("/tmp");
245
246         if(tmpdir == NULL)
247                 tmpdir = ".";
248
249         return tmpdir;
250 }
251
252 /**
253  * an own version of tmpnam, which: writes in a buffer, appends a user specified
254  * suffix, emits no warnings during linking (like glibc/gnu ld do for tmpnam)...
255  */
256 static FILE *make_temp_file(char *buffer, size_t buflen,
257                             const char *prefix, const char *suffix)
258 {
259         const char *tempdir = get_tempdir();
260
261         /* oh well... mkstemp doesn't accept a suffix after XXXXXX... */
262         (void) suffix;
263         suffix = "";
264
265         snprintf(buffer, buflen, "%s/%sXXXXXX%s", tempdir, prefix, suffix);
266
267         int fd = mkstemp(buffer);
268         if(fd == -1) {
269                 fprintf(stderr, "couldn't create temporary file: %s\n",
270                         strerror(errno));
271                 exit(1);
272         }
273         FILE *out = fdopen(fd, "w");
274         if(out == NULL) {
275                 fprintf(stderr, "couldn't create temporary file FILE*\n");
276                 exit(1);
277         }
278
279         return out;
280 }
281
282 static void create_firm_prog(translation_unit_t *unit)
283 {
284         translation_unit_to_firm(unit);
285
286         //dump_globals_as_text(dump_verbosity_max, "-globals");
287
288         int n_irgs = get_irp_n_irgs();
289         for(int i = 0; i < n_irgs; ++i) {
290                 ir_graph *const irg = get_irp_irg(i);
291                 dump(irg, "-start");
292         }
293
294         lower_params_t params;
295
296         params.def_ptr_alignment    = 4;
297         params.flags                = LF_COMPOUND_RETURN | LF_RETURN_HIDDEN;
298         params.hidden_params        = ADD_HIDDEN_ALWAYS_IN_FRONT;
299         params.find_pointer_type    = NULL;
300         params.ret_compound_in_regs = NULL;
301         lower_calls_with_compounds(&params);
302
303         lower_highlevel();
304
305         for(int i = 0; i < n_irgs; ++i) {
306                 ir_graph *const irg = get_irp_irg(i);
307                 dump(irg, "-lower");
308         }
309 }
310
311 static void optimize(void)
312 {
313         int         arr_len;
314         ir_entity **keep_methods;
315
316         cgana(&arr_len, &keep_methods);
317         gc_irgs(arr_len, keep_methods);
318         free(keep_methods);
319
320         optimize_funccalls(0);
321
322         lwrdw_param_t lwrdw_param = {
323                 1,
324                 1,
325                 mode_Ls, mode_Lu,
326                 mode_Is, mode_Iu,
327                 def_create_intrinsic_fkt,
328                 NULL
329         };
330         if (be_params->arch_create_intrinsic_fkt) {
331                 lwrdw_param.create_intrinsic = be_params->arch_create_intrinsic_fkt;
332                 lwrdw_param.ctx              = be_params->create_intrinsic_ctx;
333         }
334
335         for(int i = 0; i < get_irp_n_irgs(); ++i) {
336                 ir_graph *irg = get_irp_irg(i);
337
338                 optimize_graph_df(irg);
339                 dump(irg, "-01-localopt");
340                 place_code(irg);
341                 dump(irg, "-02-place");
342                 optimize_cf(irg);
343                 dump(irg, "-03-cf");
344                 lower_dw_ops(&lwrdw_param);
345                 dump(irg, "-04-dw");
346                 optimize_graph_df(irg);
347                 dump(irg, "-05-localopt");
348                 optimize_cf(irg);
349                 dump(irg, "-06-cf");
350         }
351 }
352
353 typedef enum compile_mode_t {
354         Compile,
355         CompileAssemble,
356         CompileAssembleLink,
357         LexTest,
358         PrintAst,
359         PrintFluffy
360 } compile_mode_t;
361
362 static void usage(const char *argv0)
363 {
364         fprintf(stderr, "Usage %s input [-o output] [-c]\n", argv0);
365 }
366
367 int main(int argc, char **argv)
368 {
369         initialize_firm();
370
371         init_symbol_table();
372         init_tokens();
373         init_types();
374         init_typehash();
375         init_lexer();
376         init_ast();
377         init_parser();
378         init_ast2firm();
379
380         const char *input   = NULL;
381         const char *outname = NULL;
382         compile_mode_t mode = CompileAssembleLink;
383
384         for(int i = 1; i < argc; ++i) {
385                 const char *arg = argv[i];
386                 if(strcmp(arg, "-o") == 0) {
387                         ++i;
388                         if(i >= argc) {
389                                 usage(argv[0]);
390                                 return 1;
391                         }
392                         outname = argv[i];
393                 } else if(strcmp(arg, "-c") == 0) {
394                         mode = CompileAssemble;
395                 } else if(strcmp(arg, "-S") == 0) {
396                         mode = Compile;
397                 } else if(strcmp(arg, "--lextest") == 0) {
398                         mode = LexTest;
399                 } else if(strcmp(arg, "--print-ast") == 0) {
400                         mode = PrintAst;
401                 } else if(strcmp(arg, "--print-fluffy") == 0) {
402                         mode = PrintFluffy;
403                 } else if(strcmp(arg, "--dump") == 0) {
404                         do_dump = true;
405                 } else if(strcmp(arg, "-v") == 0) {
406                         verbose = 1;
407                 } else if(arg[0] == '-' && arg[1] == 'f') {
408                         const char *opt = &arg[2];
409                         if(opt[0] == 0) {
410                                 ++i;
411                                 if(i >= argc) {
412                                         usage(argv[0]);
413                                         return 1;
414                                 }
415                                 opt = argv[i];
416                                 if(opt[0] == '-') {
417                                         usage(argv[0]);
418                                         return 1;
419                                 }
420                         }
421                         //firm_option(opt);
422                 } else if(arg[0] == '-' && arg[1] == 'b') {
423                         const char *opt = &arg[2];
424                         if(opt[0] == 0) {
425                                 ++i;
426                                 if(i >= argc) {
427                                         usage(argv[0]);
428                                         return 1;
429                                 }
430                                 opt = argv[i];
431                                 if(opt[0] == '-') {
432                                         usage(argv[0]);
433                                         return 1;
434                                 }
435                         }
436                         //be_parse_arg(opt);
437                 } else if(arg[0] == '-') {
438                         if (arg[1] == '\0') {
439                                 input = "-";
440                         } else if (arg[1] == 'D' ||
441                                         arg[1] == 'O' ||
442                                         arg[1] == 'f' ||
443                                         arg[1] == 'W' ||
444                                         arg[1] == 'g' ||
445                                         strncmp(arg + 1, "std=", 4) == 0) {
446                                 fprintf(stderr, "Warning: Ignoring option '%s'\n", arg);
447                         } else {
448                                 usage(argv[0]);
449                                 return 1;
450                         }
451                 } else {
452                         if(input != NULL) {
453                                 fprintf(stderr, "Error: multiple input files specified\n");
454                                 usage(argv[0]);
455                                 return 1;
456                         } else {
457                                 input = arg;
458                         }
459                 }
460         }
461
462         FILE *out;
463         char  outnamebuf[4096];
464         if(outname == NULL) {
465                 switch(mode) {
466                 case PrintAst:
467                 case PrintFluffy:
468                 case LexTest:
469                         break;
470                 case Compile:
471                         get_output_name(outnamebuf, sizeof(outnamebuf), input, ".s");
472                         outname = outnamebuf;
473                         break;
474                 case CompileAssemble:
475                         get_output_name(outnamebuf, sizeof(outnamebuf), input, ".o");
476                         outname = outnamebuf;
477                         break;
478                 case CompileAssembleLink:
479                         outname = "a.out";
480                         break;
481                 }
482                 assert(outname != NULL);
483         }
484
485         if(strcmp(outname, "-") == 0) {
486                 out = stdout;
487         } else {
488                 out = fopen(outname, "w");
489                 if(out == NULL) {
490                         fprintf(stderr, "Couldn't open '%s' for writing: %s\n", outname,
491                                 strerror(errno));
492                         return 1;
493                 }
494         }
495
496         FILE *in;
497         if(input == NULL) {
498                 fprintf(stderr, "%s: no input files\n", argv[0]);
499                 return 1;
500         } else if(strcmp(input, "-") == 0) {
501                 in    = stdin;
502                 input = "<stdin>";
503         } else {
504                 in = fopen(input, "r");
505                 if(in == NULL) {
506                         fprintf(stderr, "Couldn't open '%s': %s\n", input, strerror(errno));
507                         return 1;
508                 }
509         }
510
511         if(mode == LexTest) {
512                 lextest(in, input);
513                 fclose(in);
514                 return 0;
515         }
516
517         FILE *preprocessed_in = preprocess(in, input);
518         translation_unit_t *const unit = do_parsing(preprocessed_in, input);
519         pclose(preprocessed_in);
520         if(unit == NULL)
521                 return 1;
522
523         if(mode == PrintAst) {
524                 ast_set_output(out);
525                 print_ast(unit);
526                 return 0;
527         }
528         if(mode == PrintFluffy) {
529                 write_fluffy_decls(out, unit);
530         }
531
532         FILE *asm_out;
533         char  asm_tempfile[1024];
534         if(mode == Compile) {
535                 asm_out = out;
536         } else {
537                 asm_out
538                         = make_temp_file(asm_tempfile, sizeof(asm_tempfile), "cc", ".s");
539         }
540
541         create_firm_prog(unit);
542         optimize();
543         emit(asm_out, input);
544         fclose(asm_out);
545
546         char obj_tfile[1024];
547         if(mode == CompileAssemble || mode == CompileAssembleLink) {
548                 const char *obj_outfile;
549                 if(mode == CompileAssemble) {
550                         fclose(out);
551                         obj_outfile = outname;
552                 } else {
553                         FILE *tempf
554                                 = make_temp_file(obj_tfile, sizeof(obj_tfile), "cc", ".o");
555                         fclose(tempf);
556                         obj_outfile = obj_tfile;
557                 }
558
559                 assemble(obj_outfile, asm_tempfile);
560         }
561
562         if(mode == CompileAssembleLink) {
563                 do_link(outname, obj_tfile);
564         }
565
566         exit_ast2firm();
567         exit_parser();
568         exit_ast();
569         exit_lexer();
570         exit_typehash();
571         exit_types();
572         exit_tokens();
573         exit_symbol_table();
574         return 0;
575 }