Use strstart() instead of strncmp().
[cparser] / main.c
diff --git a/main.c b/main.c
index dc75056..85964f0 100644 (file)
--- a/main.c
+++ b/main.c
 #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 | _ANSI | _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 machine_triple_t *target_machine;
 static const char       *target_triple;
@@ -117,6 +117,7 @@ static struct obstack    asflags_obst;
 static char              dep_target[1024];
 static const char       *outname;
 static bool              define_intmax_types;
+static const char       *input_encoding;
 
 typedef enum lang_standard_t {
        STANDARD_DEFAULT, /* gnu99 (for C, GCC does gnu89) or gnu++98 (for C++) */
@@ -182,22 +183,26 @@ static translation_unit_t *do_parsing(FILE *const in, const char *const input_na
 {
        start_parsing();
 
-       lexer_open_stream(in, input_name);
+       input_t *input = input_from_stream(in, input_encoding);
+       lexer_switch_input(input, input_name);
        parse();
-
        translation_unit_t *unit = finish_parsing();
+       input_free(input);
+
        return unit;
 }
 
 static void lextest(FILE *in, const char *fname)
 {
-       lexer_open_stream(in, fname);
+       input_t *input = input_from_stream(in, input_encoding);
+       lexer_switch_input(input, fname);
 
        do {
                lexer_next_preprocessing_token();
                print_token(stdout, &lexer_token);
                putchar('\n');
        } while (lexer_token.kind != T_EOF);
+       input_free(input);
 }
 
 static void add_flag(struct obstack *obst, const char *format, ...)
@@ -630,7 +635,13 @@ static void print_help_warnings(void)
        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();
 }
 
@@ -684,6 +695,7 @@ static void print_help_linker(void)
 {
        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("-Wl,OPTION",               "Pass option directly to linker");
@@ -798,6 +810,22 @@ static filetype_t get_filetype_from_string(const char *string)
        return FILETYPE_UNKNOWN;
 }
 
+static bool is_windows_os(const char *os)
+{
+       return strstr(os, "mingw") != NULL || streq(os, "win32");
+}
+
+static bool is_unixish_os(const char *os)
+{
+       return strstr(os, "linux") != NULL || strstr(os, "bsd") != NULL
+              || streq(os, "solaris");
+}
+
+static bool is_darwin_os(const char *os)
+{
+       return streq(os, "darwin");
+}
+
 static bool init_os_support(void)
 {
        const char *os = target_machine->operating_system;
@@ -805,14 +833,12 @@ static bool init_os_support(void)
        enable_main_collect2_hack = false;
        define_intmax_types       = false;
 
-       if (strstr(os, "linux") != NULL || strstr(os, "bsd") != NULL
-                       || streq(os, "solaris")) {
+       if (is_unixish_os(os)) {
                set_create_ld_ident(create_name_linux_elf);
-       } else if (streq(os, "darwin")) {
-               long_double_size = 16;
+       } else if (is_darwin_os(os)) {
                set_create_ld_ident(create_name_macho);
                define_intmax_types = true;
-       } else if (strstr(os, "mingw") != NULL || streq(os, "win32")) {
+       } else if (is_windows_os(os)) {
                wchar_atomic_kind         = ATOMIC_TYPE_USHORT;
                enable_main_collect2_hack = true;
                set_create_ld_ident(create_name_win32);
@@ -834,22 +860,189 @@ static bool parse_target_triple(const char *arg)
        return true;
 }
 
-static void setup_target_machine(void)
+static unsigned decide_modulo_shift(unsigned type_size)
+{
+       if (architecture_modulo_shift == 0)
+               return 0;
+       if (type_size < architecture_modulo_shift)
+               return architecture_modulo_shift;
+       return type_size;
+}
+
+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 {
+               fprintf(stderr, "Unknown cpu '%s' in target-triple\n", 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 *type_long_double = be_params->type_long_double;
+       if (type_long_double != NULL)
+               set_typeprops_type(&props[ATOMIC_TYPE_LONG_DOUBLE], type_long_double);
+
+       ir_type *type_long_long = be_params->type_long_long;
+       if (type_long_long != NULL)
+               set_typeprops_type(&props[ATOMIC_TYPE_LONGLONG], type_long_long);
+
+       ir_type *type_unsigned_long_long = be_params->type_unsigned_long_long;
+       if (type_unsigned_long_long != NULL)
+               set_typeprops_type(&props[ATOMIC_TYPE_ULONGLONG], type_unsigned_long_long);
+
+       /* operating system ABI specifics */
+       const char *os = target_machine->operating_system;
+       if (is_darwin_os(os)) {
+               if (machine_size == 32) {
+                       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 (is_windows_os(os)) {
+               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 (is_unixish_os(os)) {
+               if (is_ia32_cpu(target_machine->cpu_type)) {
+                       /* System V has a broken alignment for double so we have to add
+                        * a hack here */
+                       props[ATOMIC_TYPE_DOUBLE].struct_alignment    = 4;
+                       props[ATOMIC_TYPE_LONGLONG].struct_alignment  = 4;
+                       props[ATOMIC_TYPE_ULONGLONG].struct_alignment = 4;
+               }
        }
 
-       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;
+       /* 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];
 
-       init_os_support();
+       /* initialize defaults for unsupported types */
+       if (type_long_long == NULL) {
+               copy_typeprops(&props[ATOMIC_TYPE_LONGLONG], &props[ATOMIC_TYPE_LONG]);
+       }
+       if (type_unsigned_long_long == NULL) {
+               copy_typeprops(&props[ATOMIC_TYPE_ULONGLONG],
+                              &props[ATOMIC_TYPE_ULONG]);
+       }
+       if (type_long_double == NULL) {
+               copy_typeprops(&props[ATOMIC_TYPE_LONG_DOUBLE],
+                              &props[ATOMIC_TYPE_DOUBLE]);
+       }
+
+       /* initialize firm pointer modes */
+       char               name[64];
+       ir_mode_sort       sort         = irms_reference;
+       unsigned           bit_size     = machine_size;
+       bool               is_signed    = 0;
+       ir_mode_arithmetic arithmetic   = irma_twos_complement;
+       unsigned           modulo_shift = decide_modulo_shift(bit_size);
+
+       snprintf(name, sizeof(name), "p%u", machine_size);
+       ir_mode *ptr_mode = new_ir_mode(name, sort, bit_size, is_signed, arithmetic,
+                                       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;
+       if (be_params->modulo_shift_efficient) {
+               architecture_modulo_shift = machine_size;
+       } else {
+               architecture_modulo_shift = 0;
+       }
 }
 
 int main(int argc, char **argv)
@@ -947,6 +1140,8 @@ int main(int argc, char **argv)
                                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') {
@@ -974,6 +1169,7 @@ int main(int argc, char **argv)
                        } 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;
@@ -1033,7 +1229,7 @@ int main(int argc, char **argv)
 
                                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=")) {
@@ -1111,7 +1307,9 @@ int main(int argc, char **argv)
                                                   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);
@@ -1152,10 +1350,17 @@ int main(int argc, char **argv)
                                        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 (gcc compatibility) */
+                                       /* 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]);
                                }
@@ -1170,7 +1375,8 @@ int main(int argc, char **argv)
                                        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=")) {
@@ -1178,7 +1384,8 @@ int main(int argc, char **argv)
                                        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=")) {
@@ -1232,8 +1439,11 @@ int main(int argc, char **argv)
                                        fprintf(stderr, "error: regparm convention not supported yet\n");
                                        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);
+                                       int res = be_parse_arg(arch_opt);
+                                       if (res == 0)
+                                               argument_errors = true;
                                } else {
                                        long int value = strtol(opt, NULL, 10);
                                        if (value == 0) {
@@ -1243,10 +1453,11 @@ int main(int argc, char **argv)
                                                fprintf(stderr, "error: option -m supports only 16, 32 or 64\n");
                                                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 (streq(option, "pg")) {
@@ -1451,9 +1662,15 @@ int main(int argc, char **argv)
 
        gen_firm_init();
        init_symbol_table();
-       init_types();
+       init_types_and_adjust();
        init_typehash();
        init_basic_types();
+       if (wchar_atomic_kind == ATOMIC_TYPE_INT)
+               init_wchar_types(type_int);
+       else if (wchar_atomic_kind == ATOMIC_TYPE_SHORT)
+               init_wchar_types(type_short);
+       else
+               panic("unexpected wchar type");
        init_lexer();
        init_ast();
        init_parser();