From 02f47f268839c472e23095ac0025e5ccbb5ed70a Mon Sep 17 00:00:00 2001 From: Matthias Braun Date: Fri, 14 Nov 2008 15:34:32 +0000 Subject: [PATCH] More work for C++ mode: * Can parse (but not produce usefull code) for namespace now * mangle function names according to Itanium C++ ABI * Parse custom linkage for function types [r23661] --- Makefile | 1 + ast.c | 35 ++++- ast2firm.c | 146 +++++++++--------- ast2firm.h | 1 + ast_t.h | 12 +- driver/firm_opt.c | 56 +------ entity.h | 1 + entity_t.h | 26 +++- main.c | 9 +- mangle.c | 263 ++++++++++++++++++++++++++++++++ mangle.h | 33 ++++ parser.c | 378 ++++++++++++++++++++++++++++++++-------------- preprocessor.c | 2 +- tokens.inc | 166 ++++++++++---------- type.c | 14 +- type_hash.c | 4 +- type_t.h | 2 +- types.c | 2 - 18 files changed, 799 insertions(+), 352 deletions(-) create mode 100644 mangle.c create mode 100644 mangle.h diff --git a/Makefile b/Makefile index f7f50ca..8a75c20 100644 --- a/Makefile +++ b/Makefile @@ -34,6 +34,7 @@ SOURCES := \ format_check.c \ lexer.c \ main.c \ + mangle.c \ walk_statements.c \ symbol_table.c \ token.c \ diff --git a/ast.c b/ast.c index 201039e..164c864 100644 --- a/ast.c +++ b/ast.c @@ -1477,6 +1477,34 @@ static void print_ms_modifiers(const declaration_t *declaration) fputs(") ", out); } +static void print_scope(const scope_t *scope) +{ + const entity_t *entity = scope->entities; + for ( ; entity != NULL; entity = entity->base.next) { + print_indent(); + print_entity(entity); + fputs("\n", out); + } +} + +static void print_namespace(const namespace_t *namespace) +{ + fputs("namespace ", out); + if (namespace->base.symbol != NULL) { + fputs(namespace->base.symbol->string, out); + fputc(' ', out); + } + + fputs("{\n", out); + ++indent; + + print_scope(&namespace->members); + + --indent; + print_indent(); + fputs("}\n", out); +} + /** * Print a variable or function declaration */ @@ -1543,10 +1571,12 @@ void print_entity(const entity_t *entity) switch ((entity_kind_tag_t) entity->kind) { case ENTITY_VARIABLE: - case ENTITY_FUNCTION: case ENTITY_COMPOUND_MEMBER: print_declaration(entity); return; + case ENTITY_FUNCTION: + print_declaration(entity); + return; case ENTITY_TYPEDEF: print_typedef(entity); return; @@ -1575,6 +1605,9 @@ void print_entity(const entity_t *entity) print_enum_definition(&entity->enume); fputc(';', out); return; + case ENTITY_NAMESPACE: + print_namespace(&entity->namespacee); + return; case ENTITY_LABEL: case ENTITY_ENUM_VALUE: case ENTITY_LOCAL_LABEL: diff --git a/ast2firm.c b/ast2firm.c index 09d7592..25725f8 100644 --- a/ast2firm.c +++ b/ast2firm.c @@ -41,16 +41,14 @@ #include "diagnostic.h" #include "lang_features.h" #include "types.h" +#include "type_hash.h" +#include "mangle.h" #include "walk_statements.h" #include "warning.h" #include "entitymap_t.h" #include "driver/firm_opt.h" #include "driver/firm_cmdline.h" -/* some idents needed for name mangling */ -static ident *id_underscore; -static ident *id_imp; - static ir_type *ir_type_const_char; static ir_type *ir_type_wchar_t; static ir_type *ir_type_void; @@ -65,6 +63,7 @@ static label_t **all_labels; static entity_t **inner_functions; static ir_node *ijmp_list; static bool constant_folding; +static symbol_t *sym_C; extern bool have_const_functions; @@ -73,6 +72,7 @@ static ir_node *current_function_name; static ir_node *current_funcsig; static switch_statement_t *current_switch; static ir_graph *current_function; +static translation_unit_t *current_translation_unit; static entitymap_t entitymap; @@ -89,7 +89,7 @@ typedef enum declaration_kind_t { DECLARATION_KIND_INNER_FUNCTION } declaration_kind_t; -static ir_type *get_ir_type(type_t *type); +static ir_mode *get_ir_mode(type_t *type); static ir_type *get_ir_type_incomplete(type_t *type); static void enqueue_inner_function(entity_t *entity) @@ -151,7 +151,6 @@ static ir_mode *mode_int, *mode_uint; static ir_node *_expression_to_firm(const expression_t *expression); static ir_node *expression_to_firm(const expression_t *expression); -static inline ir_mode *get_ir_mode(type_t *type); static void create_local_declaration(entity_t *entity); static ir_mode *init_atomic_ir_mode(atomic_type_kind_t kind) @@ -399,6 +398,8 @@ static ir_type *create_method_type(const function_type_t *function_type) set_method_variadicity(irtype, variadicity_variadic); } +#if 0 + /* TODO: revive this with linkage stuff */ unsigned cc = get_method_calling_convention(irtype); switch (function_type->calling_convention) { case CC_DEFAULT: /* unspecified calling convention, equal to one of the other, typically cdecl */ @@ -426,6 +427,8 @@ is_cdecl: /* Hmm, leave default, not accepted by the parser yet. */ break; } +#endif + return irtype; } @@ -497,7 +500,7 @@ static ir_type *get_signed_int_type_for_bit_size(ir_type *base_tp, snprintf(name, sizeof(name), "I%u", size); ident *id = new_id_from_str(name); dbg_info *dbgi = get_dbg_info(&builtin_source_position); - res = new_d_type_primitive(mangle_u(get_type_ident(base_tp), id), mode, dbgi); + res = new_d_type_primitive(id_mangle_u(get_type_ident(base_tp), id), mode, dbgi); set_primitive_base_type(res, base_tp); return res; @@ -533,7 +536,7 @@ static ir_type *get_unsigned_int_type_for_bit_size(ir_type *base_tp, snprintf(name, sizeof(name), "U%u", size); ident *id = new_id_from_str(name); dbg_info *dbgi = get_dbg_info(&builtin_source_position); - res = new_d_type_primitive(mangle_u(get_type_ident(base_tp), id), mode, dbgi); + res = new_d_type_primitive(id_mangle_u(get_type_ident(base_tp), id), mode, dbgi); set_primitive_base_type(res, base_tp); return res; @@ -803,7 +806,7 @@ static ir_type *get_ir_type_incomplete(type_t *type) } } -static ir_type *get_ir_type(type_t *type) +ir_type *get_ir_type(type_t *type) { assert(type != NULL); @@ -868,7 +871,7 @@ static ir_type *get_ir_type(type_t *type) return firm_type; } -static inline ir_mode *get_ir_mode(type_t *type) +ir_mode *get_ir_mode(type_t *type) { ir_type *irtype = get_ir_type(type); @@ -966,59 +969,8 @@ static const struct { static ident *rts_idents[sizeof(rts_data) / sizeof(rts_data[0])]; -/** - * Mangles an entity linker (ld) name for win32 usage. - * - * @param ent the entity to be mangled - * @param declaration the declaration - */ -static ident *create_ld_ident_win32(ir_entity *irentity, entity_t *entity) -{ - ident *id; - - if (is_Method_type(get_entity_type(irentity))) - id = decorate_win32_c_fkt(irentity, get_entity_ident(irentity)); - else { - /* always add an underscore in win32 */ - id = mangle(id_underscore, get_entity_ident(irentity)); - } - - assert(is_declaration(entity)); - decl_modifiers_t decl_modifiers = entity->declaration.modifiers; - if (decl_modifiers & DM_DLLIMPORT) { - /* add prefix for imported symbols */ - id = mangle(id_imp, id); - } - return id; -} - -/** - * Mangles an entity linker (ld) name for Linux ELF usage. - * - * @param ent the entity to be mangled - * @param declaration the declaration - */ -static ident *create_ld_ident_linux_elf(ir_entity *irentity, entity_t *entity) -{ - (void) entity; - return get_entity_ident(irentity); -} - -/** - * Mangles an entity linker (ld) name for Mach-O usage. - * - * @param ent the entity to be mangled - * @param declaration the declaration - */ -static ident *create_ld_ident_macho(ir_entity *irentity, entity_t *entity) -{ - (void) entity; - ident *id = mangle(id_underscore, get_entity_ident(irentity)); - return id; -} - -typedef ident* (*create_ld_ident_func)(ir_entity *irentity, entity_t *entity); -create_ld_ident_func create_ld_ident = create_ld_ident_linux_elf; +typedef ident* (*create_ld_ident_func)(entity_t *entity); +create_ld_ident_func create_ld_ident = create_name_linux_elf; /** * Handle GNU attributes for entities @@ -1046,6 +998,22 @@ static void handle_gnu_attributes_ent(ir_entity *irentity, entity_t *entity) } } +static bool is_main(entity_t *entity) +{ + static symbol_t *sym_main = NULL; + if (sym_main == NULL) { + sym_main = symbol_table_insert("main"); + } + + if (entity->base.symbol != sym_main) + return false; + /* must be in outermost scope */ + if (entity->base.parent_scope != ¤t_translation_unit->scope) + return false; + + return true; +} + /** * Creates an entity representing a function. * @@ -1058,6 +1026,27 @@ static ir_entity *get_function_entity(entity_t *entity) return entity->function.entity; } + if (is_main(entity)) { + /* force main to C linkage */ + type_t *type = entity->declaration.type; + assert(is_type_function(type)); + if (type->function.linkage != NULL && type->function.linkage != sym_C) { + errorf(&entity->base.source_position, + "main must have \"C\" linkage"); + } + + if (type->function.linkage == NULL || type->function.linkage != sym_C) { + type_t *new_type = duplicate_type(type); + new_type->function.linkage = sym_C; + + type = typehash_insert(new_type); + if (type != new_type) { + obstack_free(type_obst, new_type); + } + entity->declaration.type = type; + } + } + symbol_t *symbol = entity->base.symbol; ident *id = new_id_from_str(symbol->string); @@ -1077,7 +1066,7 @@ static ir_entity *get_function_entity(entity_t *entity) dbg_info *const dbgi = get_dbg_info(&entity->base.source_position); irentity = new_d_entity(global_type, id, ir_type_method, dbgi); - set_entity_ld_ident(irentity, create_ld_ident(irentity, entity)); + set_entity_ld_ident(irentity, create_ld_ident(entity)); handle_gnu_attributes_ent(irentity, entity); @@ -3270,7 +3259,7 @@ static void create_variable_entity(entity_t *variable, variable->declaration.kind = (unsigned char) declaration_kind; variable->variable.v.entity = irentity; set_entity_variability(irentity, variability_uninitialized); - set_entity_ld_ident(irentity, create_ld_ident(irentity, variable)); + set_entity_ld_ident(irentity, create_ld_ident(variable)); if (parent_type == get_tls_type()) set_entity_allocation(irentity, allocation_automatic); else if (declaration_kind == DECLARATION_KIND_GLOBAL_VARIABLE) @@ -4028,7 +4017,7 @@ static void create_local_static_variable(entity_t *entity) entity->declaration.kind = DECLARATION_KIND_GLOBAL_VARIABLE; entity->variable.v.entity = irentity; - set_entity_ld_ident(irentity, create_ld_ident(irentity, entity)); + set_entity_ld_ident(irentity, id); set_entity_variability(irentity, variability_uninitialized); set_entity_visibility(irentity, visibility_local); set_entity_allocation(irentity, allocation_static); @@ -5305,7 +5294,7 @@ static void create_function(entity_t *entity) ir_node *in[1]; /* §5.1.2.2.3 main implicitly returns 0 */ - if (strcmp(entity->base.symbol->string, "main") == 0) { + if (is_main(entity)) { in[0] = new_Const(mode, get_mode_null(mode)); } else { in[0] = new_Unknown(mode); @@ -5416,20 +5405,19 @@ void init_ast2firm(void) obstack_init(&asm_obst); init_atomic_modes(); - id_underscore = new_id_from_chars("_", 1); - id_imp = new_id_from_chars("__imp_", 6); - /* OS option must be set to the backend */ switch (firm_opt.os_support) { case OS_SUPPORT_MINGW: - create_ld_ident = create_ld_ident_win32; + create_ld_ident = create_name_win32; break; case OS_SUPPORT_LINUX: - create_ld_ident = create_ld_ident_linux_elf; + create_ld_ident = create_name_linux_elf; break; case OS_SUPPORT_MACHO: - create_ld_ident = create_ld_ident_macho; + create_ld_ident = create_name_macho; break; + default: + panic("unexpected OS support mode"); } /* create idents for all known runtime functions */ @@ -5437,6 +5425,8 @@ void init_ast2firm(void) rts_idents[i] = new_id_from_str(rts_data[i].name); } + sym_C = symbol_table_insert("C"); + entitymap_init(&entitymap); } @@ -5479,9 +5469,10 @@ static void global_asm_to_firm(statement_t *s) void translation_unit_to_firm(translation_unit_t *unit) { /* just to be sure */ - continue_label = NULL; - break_label = NULL; - current_switch_cond = NULL; + continue_label = NULL; + break_label = NULL; + current_switch_cond = NULL; + current_translation_unit = unit; init_ir_types(); inner_functions = NEW_ARR_F(entity_t *, 0); @@ -5492,5 +5483,6 @@ void translation_unit_to_firm(translation_unit_t *unit) DEL_ARR_F(inner_functions); inner_functions = NULL; - current_ir_graph = NULL; + current_ir_graph = NULL; + current_translation_unit = NULL; } diff --git a/ast2firm.h b/ast2firm.h index 0112cf8..2314ab3 100644 --- a/ast2firm.h +++ b/ast2firm.h @@ -30,5 +30,6 @@ void init_ast2firm(void); void exit_ast2firm(void); ir_mode *get_atomic_mode(atomic_type_kind_t kind); +ir_type *get_ir_type(type_t *type); #endif diff --git a/ast_t.h b/ast_t.h index eefd350..332cc85 100644 --- a/ast_t.h +++ b/ast_t.h @@ -27,7 +27,7 @@ #include "symbol.h" #include "token_t.h" #include "type.h" -#include "entity.h" +#include "entity_t.h" #include "adt/obst.h" /** The AST obstack contains all data that must stay in the AST. */ @@ -228,16 +228,6 @@ typedef enum funcname_kind_t { EXPR_UNARY_CASES_MANDATORY \ EXPR_UNARY_CASES_OPTIONAL -/** - * A scope containing declarations. - */ -struct scope_t { - entity_t *entities; /**< List of declarations in this scope. */ - entity_t *last_entity; /**< last declaration in this scope. */ - scope_t *parent; /**< points to the parent scope. */ - unsigned depth; /**< while parsing, the depth of this scope in the scope stack. */ -}; - struct expression_base_t { expression_kind_t kind; type_t *type; diff --git a/driver/firm_opt.c b/driver/firm_opt.c index eb75247..7b0e3a6 100644 --- a/driver/firm_opt.c +++ b/driver/firm_opt.c @@ -538,12 +538,6 @@ static void do_firm_optimizations(const char *input_filename) for (i = 0; i < get_irp_n_irgs(); i++) { ir_graph *irg = get_irp_irg(i); -#ifdef FIRM_EXT_GRS - /* If SIMD optimization is on, make sure we have only 1 return */ - if (firm_ext_grs.create_pattern || firm_ext_grs.simd_opt) - do_irg_opt("onereturn"); -#endif - do_irg_opt(irg, "scalar"); do_irg_opt(irg, "local"); do_irg_opt(irg, "reassoc"); @@ -915,13 +909,6 @@ void gen_firm_init(void) params.cc_mask = 0; /* no regparam, cdecl */ params.builtin_dbg = NULL; - #ifdef FIRM_EXT_GRS - /* Activate Graph rewriting if SIMD optimization is turned on */ - /* This has to be done before init_firm() is called! */ - if (firm_ext_grs.simd_opt) - ext_grs_activate(); -#endif - init_firm(¶ms); if (firm_be_opt.selection == BE_FIRM_BE) { @@ -939,23 +926,9 @@ void gen_firm_init(void) if (be_params->has_imm_fp_mode) firm_imm_fp_mode = be_params->imm_fp_mode; } - /* OS option must be set to the backend */ - switch (firm_opt.os_support) { - case OS_SUPPORT_MINGW: - firm_be_option("ia32-gasmode=mingw"); - break; - case OS_SUPPORT_MACHO: - firm_be_option("ia32-gasmode=macho"); - break; - case OS_SUPPORT_LINUX: - default: - firm_be_option("ia32-gasmode=linux"); - break; - } dbg_init(NULL, NULL, dbg_snprint); edges_init_dbg(firm_opt.vrfy_edges); - //cbackend_set_debug_retrieve(dbg_retrieve); set_opt_precise_exc_context(firm_opt.precise_exc); set_opt_fragile_ops(firm_opt.fragile_ops); @@ -1090,23 +1063,6 @@ void gen_firm_finish(FILE *out, const char *input_filename, int c_mode, int new_ for (i = get_irp_n_irgs() - 1; i >= 0; --i) set_irg_phase_low(get_irp_irg(i)); - -#ifdef FIRM_EXT_GRS - /** SIMD Optimization Extensions **/ - - /* Pattern creation step. No code has to be generated, so - exit after pattern creation */ - if (firm_ext_grs.create_pattern) { - ext_grs_create_pattern(); - exit(0); - } - - /* SIMD optimization step. Uses graph patterns to find - rich instructions and rewrite */ - if (firm_ext_grs.simd_opt) - ext_grs_simd_opt(); -#endif - if (firm_dump.statistic & STAT_FINAL_IR) stat_dump_snapshot(input_filename, "final-ir"); @@ -1116,18 +1072,14 @@ void gen_firm_finish(FILE *out, const char *input_filename, int c_mode, int new_ if (firm_dump.statistic & STAT_FINAL) stat_dump_snapshot(input_filename, "final"); - -#if 0 - if (firm_opt.ycomp_dbg) - firm_finish_ycomp_debugger(); -#endif -} /* gen_firm_finish */ +} /** * Do very early initializations */ -void firm_early_init(void) { +void firm_early_init(void) +{ /* arg: need this here for command line options */ be_opt_register(); firm_init_options(NULL, 0, NULL); -} /* firm_early_init */ +} diff --git a/entity.h b/entity.h index f7d4375..ee0db10 100644 --- a/entity.h +++ b/entity.h @@ -27,6 +27,7 @@ typedef struct compound_t compound_t; typedef struct enum_t enum_t; typedef struct enum_value_t enum_value_t; typedef struct label_t label_t; +typedef struct namespace_t namespace_t; typedef struct declaration_t declaration_t; typedef struct typedef_t typedef_t; typedef struct variable_t variable_t; diff --git a/entity_t.h b/entity_t.h index d6002f9..c9e2294 100644 --- a/entity_t.h +++ b/entity_t.h @@ -20,6 +20,8 @@ #ifndef ENTITY_T_H #define ENTITY_T_H +#include "lexer.h" +#include "symbol.h" #include "entity.h" typedef enum { @@ -33,7 +35,8 @@ typedef enum { ENTITY_ENUM, ENTITY_ENUM_VALUE, ENTITY_LABEL, - ENTITY_LOCAL_LABEL + ENTITY_LOCAL_LABEL, + ENTITY_NAMESPACE } entity_kind_tag_t; typedef unsigned char entity_kind_t; @@ -45,7 +48,7 @@ typedef enum namespace_tag_t { NAMESPACE_ENUM, NAMESPACE_LABEL } namespace_tag_t; -typedef unsigned char namespace_t; +typedef unsigned char entity_namespace_t; typedef enum storage_class_tag_t { STORAGE_CLASS_NONE, @@ -91,13 +94,24 @@ typedef enum decl_modifier_t { typedef unsigned decl_modifiers_t; +/** + * A scope containing entities. + */ +struct scope_t { + entity_t *entities; + entity_t *last_entity; + scope_t *parent; /**< points to the parent scope. */ + unsigned depth; /**< while parsing, the depth of this scope in the + scope stack. */ +}; + /** * a named entity is something which can be referenced by its name * (a symbol) */ struct entity_base_t { entity_kind_t kind; - namespace_t namespc; + entity_namespace_t namespc; symbol_t *symbol; source_position_t source_position; scope_t *parent_scope; /**< The parent scope where this declaration lives. */ @@ -147,6 +161,11 @@ struct label_t { ir_node *block; }; +struct namespace_t { + entity_base_t base; + scope_t members; +}; + struct typedef_t { entity_base_t base; decl_modifiers_t modifiers; @@ -217,6 +236,7 @@ union entity_t { enum_t enume; enum_value_t enum_value; label_t label; + namespace_t namespacee; typedef_t typedefe; declaration_t declaration; variable_t variable; diff --git a/main.c b/main.c index 9d60894..8e0c7d8 100644 --- a/main.c +++ b/main.c @@ -56,10 +56,6 @@ #define HAVE_MKSTEMP #endif -#ifndef WITH_LIBCORE -#define WITH_LIBCORE -#endif - #include #include @@ -79,6 +75,7 @@ #include "write_caml.h" #include "revision.h" #include "warning.h" +#include "mangle.h" #ifndef PREPROCESSOR #ifdef __APPLE__ @@ -118,6 +115,8 @@ bool use_builtins = false; /** we have extern function with const attribute. */ bool have_const_functions = false; +atomic_type_kind_t wchar_atomic_kind = ATOMIC_TYPE_INT; + /* to switch on printing of implicit casts */ extern bool print_implicit_casts; @@ -1053,6 +1052,7 @@ int main(int argc, char **argv) init_ast(); init_parser(); init_ast2firm(); + init_mangle(); if (construct_dep_target) { if (outname != 0 && strlen(outname) >= 2) { @@ -1371,6 +1371,7 @@ do_parsing: obstack_free(&ldflags_obst, NULL); obstack_free(&file_obst, NULL); + exit_mangle(); exit_ast2firm(); exit_parser(); exit_ast(); diff --git a/mangle.c b/mangle.c new file mode 100644 index 0000000..b4149c6 --- /dev/null +++ b/mangle.c @@ -0,0 +1,263 @@ +/* + * This file is part of cparser. + * Copyright (C) 2007-2008 Matthias Braun + * + * 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. + */ +#include + +#include +#include + +#include "entity_t.h" +#include "type_t.h" +#include "symbol_t.h" +#include "mangle.h" +#include "diagnostic.h" +#include "ast2firm.h" +#include "lang_features.h" +#include "adt/error.h" + +static ident *id_underscore; +static ident *id_imp; +static symbol_t *sym_C; +static symbol_t *sym_stdcall; +static struct obstack obst; + +static void mangle_type(type_t *type); + +static const char *get_atomic_type_mangle(atomic_type_kind_t kind) +{ + switch (kind) { + case ATOMIC_TYPE_INVALID: break; + case ATOMIC_TYPE_VOID: return "v"; + case ATOMIC_TYPE_BOOL: return "b"; + case ATOMIC_TYPE_CHAR: return "c"; + case ATOMIC_TYPE_SCHAR: return "a"; + case ATOMIC_TYPE_UCHAR: return "h"; + case ATOMIC_TYPE_INT: return "i"; + case ATOMIC_TYPE_UINT: return "j"; + case ATOMIC_TYPE_SHORT: return "s"; + case ATOMIC_TYPE_USHORT: return "t"; + case ATOMIC_TYPE_LONG: return "l"; + case ATOMIC_TYPE_ULONG: return "m"; + case ATOMIC_TYPE_LONGLONG: return "x"; + case ATOMIC_TYPE_ULONGLONG: return "y"; + case ATOMIC_TYPE_LONG_DOUBLE: return "e"; + case ATOMIC_TYPE_FLOAT: return "f"; + case ATOMIC_TYPE_DOUBLE: return "d"; + } + panic("invalid atomic type in mangler"); +} + +static void mangle_atomic_type(const atomic_type_t *type) +{ + obstack_printf(&obst, "%s", get_atomic_type_mangle(type->akind)); +} + +static void mangle_pointer_type(const pointer_type_t *type) +{ + obstack_printf(&obst, "P"); + mangle_type(type->points_to); +} + +static void mangle_function_type(const function_type_t *type) +{ + obstack_printf(&obst, "F"); + if (type->linkage == sym_C) { + obstack_printf(&obst, "Y"); + } + + mangle_type(type->return_type); + + function_parameter_t *parameter = type->parameters; + for ( ; parameter != NULL; parameter = parameter->next) { + mangle_type(parameter->type); + } + if (type->variadic) { + obstack_printf(&obst, "z"); + } + if (type->unspecified_parameters) + panic("can't mangle unspecified parameter types"); + if (type->kr_style_parameters) + panic("can't mangle kr_style_parameters type"); + + obstack_printf(&obst, "E"); +} + +static void mangle_qualifiers(type_qualifiers_t qualifiers) +{ + if (qualifiers & TYPE_QUALIFIER_CONST) + obstack_printf(&obst, "K"); + if (qualifiers & TYPE_QUALIFIER_VOLATILE) + obstack_printf(&obst, "V"); + if (qualifiers & TYPE_QUALIFIER_RESTRICT) + obstack_printf(&obst, "r"); + + /* handle MS extended qualifiers? */ +} + +static void mangle_type(type_t *orig_type) +{ + type_t *type = skip_typeref(orig_type); + + mangle_qualifiers(type->base.qualifiers); + + switch (type->kind) { + case TYPE_ATOMIC: + mangle_atomic_type(&type->atomic); + return; + case TYPE_POINTER: + mangle_pointer_type(&type->pointer); + return; + case TYPE_FUNCTION: + mangle_function_type(&type->function); + return; + case TYPE_INVALID: + panic("invalid type encountered while mangling"); + case TYPE_ERROR: + panic("error type encountered while mangling"); + case TYPE_BUILTIN: + case TYPE_TYPEDEF: + case TYPE_TYPEOF: + panic("typeref not resolved while manging?!?"); + + case TYPE_BITFIELD: + case TYPE_COMPLEX: + case TYPE_IMAGINARY: + case TYPE_COMPOUND_STRUCT: + case TYPE_COMPOUND_UNION: + case TYPE_ENUM: + case TYPE_ARRAY: + panic("no mangling for this type implemented yet"); + break; + } + panic("invalid type encountered while mangling"); +} + + +/** + * Mangles an entity linker (ld) name for win32 usage. + * + * @param ent the entity to be mangled + * @param declaration the declaration + */ +ident *create_name_win32(entity_t *entity) +{ + ident *id = new_id_from_str(entity->base.symbol->string); + + if (entity->kind == ENTITY_FUNCTION) { + if (entity->declaration.type->function.linkage == sym_stdcall) { + char buf[16]; + ir_type *irtype = get_ir_type(entity->declaration.type); + size_t size = 0; + for (int i = get_method_n_params(irtype) - 1; i >= 0; --i) { + size += get_type_size_bytes(get_method_param_type(irtype, i)); + } + + snprintf(buf, sizeof(buf), "@%d", size); + return id_mangle3("_", id, buf); + } + } else { + /* always add an underscore in win32 */ + id = id_mangle(id_underscore, id); + } + + assert(is_declaration(entity)); + decl_modifiers_t decl_modifiers = entity->declaration.modifiers; + if (decl_modifiers & DM_DLLIMPORT) { + /* add prefix for imported symbols */ + id = id_mangle(id_imp, id); + } + return id; +} + +static void mangle_entity(entity_t *entity) +{ + assert(obstack_object_size(&obst) == 0); + obstack_printf(&obst, "_Z"); + + /* TODO: mangle scope */ + + symbol_t *symbol = entity->base.symbol; + obstack_printf(&obst, "%u%s", strlen(symbol->string), symbol->string); + + if (entity->kind == ENTITY_FUNCTION) { + mangle_type(entity->declaration.type); + } +} + +/** + * Mangles an entity linker (ld) name for Linux ELF usage. + * + * @param ent the entity to be mangled + * @param declaration the declaration + */ +ident *create_name_linux_elf(entity_t *entity) +{ + bool needs_mangling = false; + + if (entity->kind == ENTITY_FUNCTION && (c_mode & _CXX)) { + symbol_t *linkage = entity->declaration.type->function.linkage; + + if (linkage == NULL) { + needs_mangling = true; + } else if (linkage != sym_C) { + errorf(&entity->base.source_position, + "Unknown linkage type \"%Y\" found\n", linkage); + } + } + + if (needs_mangling) { + mangle_entity(entity); + obstack_1grow(&obst, '\0'); + char *str = obstack_finish(&obst); + + ident *id = new_id_from_str(str); + obstack_free(&obst, str); + + return id; + } + + return new_id_from_str(entity->base.symbol->string); +} + +/** + * Mangles an entity linker (ld) name for Mach-O usage. + * + * @param ent the entity to be mangled + * @param declaration the declaration + */ +ident *create_name_macho(entity_t *entity) +{ + ident *id = new_id_from_str(entity->base.symbol->string); + return id_mangle(id_underscore, id); +} + +void init_mangle(void) +{ + id_underscore = new_id_from_chars("_", 1); + id_imp = new_id_from_chars("__imp_", 6); + sym_C = symbol_table_insert("C"); + sym_stdcall = symbol_table_insert("stdcall"); + + obstack_init(&obst); +} + +void exit_mangle(void) +{ + obstack_free(&obst, NULL); +} diff --git a/mangle.h b/mangle.h new file mode 100644 index 0000000..6f576de --- /dev/null +++ b/mangle.h @@ -0,0 +1,33 @@ +/* + * This file is part of cparser. + * Copyright (C) 2007-2008 Matthias Braun + * + * 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. + */ +#ifndef MANGLE_H +#define MANGLE_H + +#include "entity.h" +#include + +ident *create_name_linux_elf(entity_t *entity); +ident *create_name_macho(entity_t *entity); +ident *create_name_win32(entity_t *entity); + +void init_mangle(void); +void exit_mangle(void); + +#endif diff --git a/parser.c b/parser.c index 13f2cbb..b6deeef 100644 --- a/parser.c +++ b/parser.c @@ -45,9 +45,9 @@ #define MAX_LOOKAHEAD 2 typedef struct { - entity_t *old_entity; - symbol_t *symbol; - namespace_t namespc; + entity_t *old_entity; + symbol_t *symbol; + entity_namespace_t namespc; } stack_entry_t; typedef struct argument_list_t argument_list_t; @@ -107,10 +107,8 @@ static token_t lookahead_buffer[MAX_LOOKAHEAD]; static int lookahead_bufpos; static stack_entry_t *environment_stack = NULL; static stack_entry_t *label_stack = NULL; -/** The global file scope. */ static scope_t *file_scope = NULL; -/** The current scope. */ -static scope_t *scope = NULL; +static scope_t *current_scope = NULL; /** Point to the current function declaration if inside a function. */ static function_t *current_function = NULL; static entity_t *current_init_decl = NULL; @@ -118,6 +116,7 @@ static switch_statement_t *current_switch = NULL; static statement_t *current_loop = NULL; static statement_t *current_parent = NULL; static ms_try_statement_t *current_try = NULL; +static symbol_t *current_linkage = NULL; static goto_statement_t *goto_first = NULL; static goto_statement_t *goto_last = NULL; static label_statement_t *label_first = NULL; @@ -176,6 +175,8 @@ static statement_t *parse_statement(void); static expression_t *parse_sub_expression(precedence_t); static expression_t *parse_expression(void); static type_t *parse_typename(void); +static void parse_externals(void); +static void parse_external(void); static void parse_compound_type_entries(compound_t *compound_declaration); static entity_t *parse_declarator(const declaration_specifiers_t *specifiers, @@ -193,6 +194,13 @@ static void semantic_comparison(binary_expression_t *expression); case T_register: \ case T___thread: +#define STORAGE_CLASSES_NO_EXTERN \ + case T_typedef: \ + case T_static: \ + case T_auto: \ + case T_register: \ + case T___thread: + #define TYPE_QUALIFIERS \ case T_const: \ case T_restrict: \ @@ -232,6 +240,11 @@ static void semantic_comparison(binary_expression_t *expression); TYPE_QUALIFIERS \ TYPE_SPECIFIERS +#define DECLARATION_START_NO_EXTERN \ + STORAGE_CLASSES_NO_EXTERN \ + TYPE_QUALIFIERS \ + TYPE_SPECIFIERS + #define TYPENAME_START \ TYPE_QUALIFIERS \ TYPE_SPECIFIERS @@ -312,7 +325,8 @@ static size_t get_entity_struct_size(entity_kind_t kind) [ENTITY_ENUM] = sizeof(enum_t), [ENTITY_ENUM_VALUE] = sizeof(enum_value_t), [ENTITY_LABEL] = sizeof(label_t), - [ENTITY_LOCAL_LABEL] = sizeof(label_t) + [ENTITY_LOCAL_LABEL] = sizeof(label_t), + [ENTITY_NAMESPACE] = sizeof(namespace_t) }; assert(kind < sizeof(sizes) / sizeof(sizes[0])); assert(sizes[kind] != 0); @@ -761,22 +775,23 @@ static void type_error_incompatible(const char *msg, static void scope_push(scope_t *new_scope) { - if (scope != NULL) { - new_scope->depth = scope->depth + 1; + if (current_scope != NULL) { + new_scope->depth = current_scope->depth + 1; } - new_scope->parent = scope; - scope = new_scope; + new_scope->parent = current_scope; + current_scope = new_scope; } static void scope_pop(void) { - scope = scope->parent; + current_scope = current_scope->parent; } /** * Search an entity by its symbol in a given namespace. */ -static entity_t *get_entity(const symbol_t *const symbol, namespace_t namespc) +static entity_t *get_entity(const symbol_t *const symbol, + namespace_tag_t namespc) { entity_t *entity = symbol->entity; for( ; entity != NULL; entity = entity->base.symbol_next) { @@ -793,8 +808,8 @@ static entity_t *get_entity(const symbol_t *const symbol, namespace_t namespc) */ static void stack_push(stack_entry_t **stack_ptr, entity_t *entity) { - symbol_t *symbol = entity->base.symbol; - namespace_t namespc = entity->base.namespc; + symbol_t *symbol = entity->base.symbol; + entity_namespace_t namespc = entity->base.namespc; assert(namespc != NAMESPACE_INVALID); /* replace/add entity into entity list of the symbol */ @@ -859,9 +874,9 @@ static void stack_pop_to(stack_entry_t **stack_ptr, size_t new_top) for(i = top; i > new_top; --i) { stack_entry_t *entry = &stack[i - 1]; - entity_t *old_entity = entry->old_entity; - symbol_t *symbol = entry->symbol; - namespace_t namespc = entry->namespc; + entity_t *old_entity = entry->old_entity; + symbol_t *symbol = entry->symbol; + entity_namespace_t namespc = entry->namespc; /* replace with old_entity/remove */ entity_t **anchor; @@ -2941,13 +2956,13 @@ static compound_t *parse_compound_type_specifier(bool is_struct) symbol = token.v.symbol; next_token(); - namespace_t const namespc = + namespace_tag_t const namespc = is_struct ? NAMESPACE_STRUCT : NAMESPACE_UNION; entity_t *entity = get_entity(symbol, namespc); if (entity != NULL) { assert(entity->kind == (is_struct ? ENTITY_STRUCT : ENTITY_UNION)); compound = &entity->compound; - if (compound->base.parent_scope != scope && + if (compound->base.parent_scope != current_scope && (token.type == '{' || token.type == ';')) { /* we're in an inner scope and have a definition. Override existing definition in outer scope */ @@ -2982,11 +2997,11 @@ static compound_t *parse_compound_type_specifier(bool is_struct) (is_struct ? NAMESPACE_STRUCT : NAMESPACE_UNION); compound->base.source_position = token.source_position; compound->base.symbol = symbol; - compound->base.parent_scope = scope; + compound->base.parent_scope = current_scope; if (symbol != NULL) { environment_push(entity); } - append_entity(scope, entity); + append_entity(current_scope, entity); } if (token.type == '{') { @@ -3076,7 +3091,7 @@ static type_t *parse_enum_specifier(void) entity->base.namespc = NAMESPACE_ENUM; entity->base.source_position = token.source_position; entity->base.symbol = symbol; - entity->base.parent_scope = scope; + entity->base.parent_scope = current_scope; } type_t *const type = allocate_type_zero(TYPE_ENUM); @@ -3090,7 +3105,7 @@ static type_t *parse_enum_specifier(void) if (symbol != NULL) { environment_push(entity); } - append_entity(scope, entity); + append_entity(current_scope, entity); entity->enume.complete = true; parse_enum_entries(type); @@ -4190,6 +4205,8 @@ static construct_type_t *parse_function_declarator(scope_t *scope) { type_t *type = allocate_type_zero(TYPE_FUNCTION); + type->function.linkage = current_linkage; + /* TODO: revive this... once we know exactly how to do it */ #if 0 decl_modifiers_t modifiers = entity->declaration.modifiers; @@ -4576,7 +4593,8 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers, storage_class_t storage_class = specifiers->storage_class; entity->declaration.declared_storage_class = storage_class; - if (storage_class == STORAGE_CLASS_NONE && scope != file_scope) { + if (storage_class == STORAGE_CLASS_NONE + && current_scope != file_scope) { storage_class = STORAGE_CLASS_AUTO; } entity->declaration.storage_class = storage_class; @@ -4668,6 +4686,34 @@ static bool is_sym_main(const symbol_t *const sym) return strcmp(sym->string, "main") == 0; } +static const char *get_entity_kind_name(entity_kind_t kind) +{ + switch ((entity_kind_tag_t) kind) { + case ENTITY_FUNCTION: return "function"; + case ENTITY_VARIABLE: return "variable"; + case ENTITY_COMPOUND_MEMBER: return "compound type member"; + case ENTITY_STRUCT: return "struct"; + case ENTITY_UNION: return "union"; + case ENTITY_ENUM: return "enum"; + case ENTITY_ENUM_VALUE: return "enum value"; + case ENTITY_LABEL: return "label"; + case ENTITY_LOCAL_LABEL: return "local label"; + case ENTITY_TYPEDEF: return "typedef"; + case ENTITY_NAMESPACE: return "namespace"; + case ENTITY_INVALID: break; + } + + panic("Invalid entity kind encountered in get_entity_kind_name"); +} + +static void error_redefined_as_different_kind(const source_position_t *pos, + const entity_t *old, entity_kind_t new_kind) +{ + errorf(pos, "redeclaration of %s '%Y' as %s (declared %P)", + get_entity_kind_name(old->kind), old->base.symbol, new_kind, + &old->base.source_position); +} + /** * record entities for the NAMESPACE_NORMAL, and produce error messages/warnings * for various problems that occur for multiple definitions @@ -4675,7 +4721,7 @@ static bool is_sym_main(const symbol_t *const sym) static entity_t *record_entity(entity_t *entity, const bool is_definition) { const symbol_t *const symbol = entity->base.symbol; - const namespace_t namespc = entity->base.namespc; + const namespace_tag_t namespc = entity->base.namespc; const source_position_t *pos = &entity->base.source_position; assert(symbol != NULL); @@ -4695,7 +4741,8 @@ static entity_t *record_entity(entity_t *entity, const bool is_definition) orig_type, symbol); } - if (warning.main && scope == file_scope && is_sym_main(symbol)) { + if (warning.main && current_scope == file_scope + && is_sym_main(symbol)) { check_type_of_main(entity); } } @@ -4703,7 +4750,7 @@ static entity_t *record_entity(entity_t *entity, const bool is_definition) if (is_declaration(entity)) { if (warning.nested_externs && entity->declaration.storage_class == STORAGE_CLASS_EXTERN - && scope != file_scope) { + && current_scope != file_scope) { warningf(pos, "nested extern declaration of '%#T'", entity->declaration.type, symbol); } @@ -4711,7 +4758,7 @@ static entity_t *record_entity(entity_t *entity, const bool is_definition) if (previous_entity != NULL && previous_entity->base.parent_scope == ¤t_function->parameters - && scope->depth == previous_entity->base.parent_scope->depth + 1) { + && current_scope->depth == previous_entity->base.parent_scope->depth+1){ assert(previous_entity->kind == ENTITY_VARIABLE); errorf(pos, @@ -4723,12 +4770,11 @@ static entity_t *record_entity(entity_t *entity, const bool is_definition) } if (previous_entity != NULL - && previous_entity->base.parent_scope == scope) { + && previous_entity->base.parent_scope == current_scope) { if (previous_entity->kind != entity->kind) { - errorf(pos, - "redeclaration of '%Y' as different kind of symbol (declared %P)", - symbol, &previous_entity->base.source_position); + error_redefined_as_different_kind(pos, previous_entity, + entity->kind); goto finish; } if (previous_entity->kind == ENTITY_ENUM_VALUE) { @@ -4885,7 +4931,7 @@ error_redeclaration: } } else if (warning.missing_declarations && entity->kind == ENTITY_VARIABLE - && scope == file_scope) { + && current_scope == file_scope) { declaration_t *declaration = &entity->declaration; if (declaration->storage_class == STORAGE_CLASS_NONE || declaration->storage_class == STORAGE_CLASS_THREAD) { @@ -4896,12 +4942,12 @@ error_redeclaration: finish: assert(entity->base.parent_scope == NULL); - assert(scope != NULL); + assert(current_scope != NULL); - entity->base.parent_scope = scope; + entity->base.parent_scope = current_scope; entity->base.namespc = NAMESPACE_NORMAL; environment_push(entity); - append_entity(scope, entity); + append_entity(current_scope, entity); return entity; } @@ -5050,7 +5096,7 @@ static entity_t *finished_kr_declaration(entity_t *entity, bool is_definition) assert(entity->base.namespc == NAMESPACE_NORMAL); entity_t *previous_entity = get_entity(symbol, NAMESPACE_NORMAL); if (previous_entity == NULL - || previous_entity->base.parent_scope != scope) { + || previous_entity->base.parent_scope != current_scope) { errorf(HERE, "expected declaration of a function parameter, found '%Y'", symbol); return entity; @@ -5114,7 +5160,7 @@ static void parse_kr_declaration_list(entity_t *entity) entity_t *parameter = entity->function.parameters.entities; for ( ; parameter != NULL; parameter = parameter->base.next) { assert(parameter->base.parent_scope == NULL); - parameter->base.parent_scope = scope; + parameter->base.parent_scope = current_scope; environment_push(parameter); } @@ -5124,7 +5170,7 @@ static void parse_kr_declaration_list(entity_t *entity) } /* pop function parameters */ - assert(scope == &entity->function.parameters); + assert(current_scope == &entity->function.parameters); scope_pop(); environment_pop_to(top); @@ -5843,11 +5889,9 @@ static void parse_external_declaration(void) } assert(is_declaration(ndeclaration)); - type_t *type = ndeclaration->declaration.type; + type_t *type = skip_typeref(ndeclaration->declaration.type); - /* note that we don't skip typerefs: the standard doesn't allow them here - * (so we can't use is_type_function here) */ - if (type->kind != TYPE_FUNCTION) { + if (!is_type_function(type)) { if (is_type_valid(type)) { errorf(HERE, "declarator '%#T' has a body but is not a function type", type, ndeclaration->base.symbol); @@ -5903,11 +5947,11 @@ static void parse_external_declaration(void) entity_t *parameter = function->parameters.entities; for( ; parameter != NULL; parameter = parameter->base.next) { if (parameter->base.parent_scope == &ndeclaration->function.parameters) { - parameter->base.parent_scope = scope; + parameter->base.parent_scope = current_scope; } assert(parameter->base.parent_scope == NULL - || parameter->base.parent_scope == scope); - parameter->base.parent_scope = scope; + || parameter->base.parent_scope == current_scope); + parameter->base.parent_scope = current_scope; if (parameter->base.symbol == NULL) { errorf(¶meter->base.source_position, "parameter name omitted"); continue; @@ -5953,7 +5997,7 @@ static void parse_external_declaration(void) label_pop_to(label_stack_top); } - assert(scope == &function->parameters); + assert(current_scope == &function->parameters); scope_pop(); environment_pop_to(top); } @@ -7182,8 +7226,8 @@ static label_t *get_label(symbol_t *symbol) label = get_entity(symbol, NAMESPACE_LABEL); /* if we found a local label, we already created the declaration */ if (label != NULL && label->kind == ENTITY_LOCAL_LABEL) { - if (label->base.parent_scope != scope) { - assert(label->base.parent_scope->depth < scope->depth); + if (label->base.parent_scope != current_scope) { + assert(label->base.parent_scope->depth < current_scope->depth); current_function->goto_to_outer = true; } return &label->label; @@ -9736,7 +9780,7 @@ static statement_t *parse_for(void) rem_anchor_token(')'); statement->fors.body = parse_loop_body(statement); - assert(scope == &statement->fors.scope); + assert(current_scope == &statement->fors.scope); scope_pop(); environment_pop_to(top); @@ -9746,7 +9790,7 @@ static statement_t *parse_for(void) end_error: POP_PARENT; rem_anchor_token(')'); - assert(scope == &statement->fors.scope); + assert(current_scope == &statement->fors.scope); scope_pop(); environment_pop_to(top); @@ -9932,7 +9976,7 @@ static statement_t *parse_return(void) mark_vars_read(return_value, NULL); } - const type_t *const func_type = current_function->base.type; + const type_t *const func_type = skip_typeref(current_function->base.type); assert(is_type_function(func_type)); type_t *const return_type = skip_typeref(func_type->function.return_type); @@ -9980,18 +10024,18 @@ static statement_t *parse_declaration_statement(void) { statement_t *statement = allocate_statement_zero(STATEMENT_DECLARATION); - entity_t *before = scope->last_entity; + entity_t *before = current_scope->last_entity; if (GNU_MODE) parse_external_declaration(); else parse_declaration(record_entity); if (before == NULL) { - statement->declaration.declarations_begin = scope->entities; + statement->declaration.declarations_begin = current_scope->entities; } else { statement->declaration.declarations_begin = before->base.next; } - statement->declaration.declarations_end = scope->last_entity; + statement->declaration.declarations_end = current_scope->last_entity; return statement; } @@ -10087,13 +10131,13 @@ static statement_t *parse_local_label_declaration(void) } symbol_t *symbol = token.v.symbol; entity_t *entity = get_entity(symbol, NAMESPACE_LABEL); - if (entity != NULL && entity->base.parent_scope == scope) { + if (entity != NULL && entity->base.parent_scope == current_scope) { errorf(HERE, "multiple definitions of '__label__ %Y' (previous definition %P)", symbol, &entity->base.source_position); } else { entity = allocate_entity_zero(ENTITY_LOCAL_LABEL); - entity->base.parent_scope = scope; + entity->base.parent_scope = current_scope; entity->base.namespc = NAMESPACE_LABEL; entity->base.source_position = token.source_position; entity->base.symbol = symbol; @@ -10119,6 +10163,55 @@ end_error: return statement; } +static void parse_namespace_definition(void) +{ + eat(T_namespace); + + entity_t *entity = NULL; + symbol_t *symbol = NULL; + + if (token.type == T_IDENTIFIER) { + symbol = token.v.symbol; + next_token(); + + entity = get_entity(symbol, NAMESPACE_NORMAL); + if (entity != NULL && entity->kind != ENTITY_NAMESPACE + && entity->base.parent_scope == current_scope) { + error_redefined_as_different_kind(&token.source_position, + entity, ENTITY_NAMESPACE); + entity = NULL; + } + } + + if (entity == NULL) { + entity = allocate_entity_zero(ENTITY_NAMESPACE); + entity->base.symbol = symbol; + entity->base.source_position = token.source_position; + entity->base.namespc = NAMESPACE_NORMAL; + entity->base.parent_scope = current_scope; + } + + if (token.type == '=') { + /* TODO: parse namespace alias */ + panic("namespace alias definition not supported yet"); + } + + environment_push(entity); + append_entity(current_scope, entity); + + size_t const top = environment_top(); + scope_push(&entity->namespacee.members); + + expect('{'); + parse_externals(); + expect('}'); + +end_error: + assert(current_scope == &entity->namespacee.members); + scope_pop(); + environment_pop_to(top); +} + /** * Parse a statement. * There's also parse_statement() which additionally checks for @@ -10182,22 +10275,22 @@ expression_statment: statement = parse_local_label_declaration(); break; - case ';': statement = parse_empty_statement(); break; - case '{': statement = parse_compound_statement(false); break; - case T___leave: statement = parse_leave_statement(); break; - case T___try: statement = parse_ms_try_statment(); break; - case T_asm: statement = parse_asm_statement(); break; - case T_break: statement = parse_break(); break; - case T_case: statement = parse_case_statement(); break; - case T_continue: statement = parse_continue(); break; - case T_default: statement = parse_default_statement(); break; - case T_do: statement = parse_do(); break; - case T_for: statement = parse_for(); break; - case T_goto: statement = parse_goto(); break; - case T_if: statement = parse_if(); break; - case T_return: statement = parse_return(); break; - case T_switch: statement = parse_switch(); break; - case T_while: statement = parse_while(); break; + case ';': statement = parse_empty_statement(); break; + case '{': statement = parse_compound_statement(false); break; + case T___leave: statement = parse_leave_statement(); break; + case T___try: statement = parse_ms_try_statment(); break; + case T_asm: statement = parse_asm_statement(); break; + case T_break: statement = parse_break(); break; + case T_case: statement = parse_case_statement(); break; + case T_continue: statement = parse_continue(); break; + case T_default: statement = parse_default_statement(); break; + case T_do: statement = parse_do(); break; + case T_for: statement = parse_for(); break; + case T_goto: statement = parse_goto(); break; + case T_if: statement = parse_if(); break; + case T_return: statement = parse_return(); break; + case T_switch: statement = parse_switch(); break; + case T_while: statement = parse_while(); break; EXPRESSION_START statement = parse_expression_statement(); @@ -10309,7 +10402,7 @@ static statement_t *parse_compound_statement(bool inside_expression_statement) end_error: rem_anchor_token('}'); - assert(scope == &statement->compound.scope); + assert(current_scope == &statement->compound.scope); scope_pop(); environment_pop_to(top); @@ -10371,18 +10464,88 @@ static void parse_global_asm(void) end_error:; } -/** - * Parse a translation unit. - */ -static void parse_translation_unit(void) +static void parse_linkage_specification(void) { + eat(T_extern); + assert(token.type == T_STRING_LITERAL); + + string_t linkage = parse_string_literals(); + /* convert to symbol for easier handling... */ + symbol_t *symbol = symbol_table_insert(linkage.begin); + + + symbol_t *old_linkage = current_linkage; + current_linkage = symbol; + + if (token.type == '{') { + next_token(); + parse_externals(); + expect('}'); + } else { + parse_external(); + } + +end_error: + assert(current_linkage == symbol); + current_linkage = old_linkage; +} + +static void parse_external(void) +{ + switch (token.type) { + DECLARATION_START_NO_EXTERN + case T_IDENTIFIER: + case T___extension__: + case '(': /* for function declarations with implicit return type and + * parenthesized declarator, i.e. (f)(void); */ + parse_external_declaration(); + return; + + case T_extern: + if (look_ahead(1)->type == T_STRING_LITERAL) { + parse_linkage_specification(); + } else { + parse_external_declaration(); + } + return; + + case T_asm: + parse_global_asm(); + return; + + case T_namespace: + parse_namespace_definition(); + return; + + case ';': + if (!strict_mode) { + if (warning.other) + warningf(HERE, "stray ';' outside of function"); + next_token(); + return; + } + /* FALLTHROUGH */ + + default: + errorf(HERE, "stray %K outside of function", &token); + if (token.type == '(' || token.type == '{' || token.type == '[') + eat_until_matching_token(token.type); + next_token(); + return; + } +} + +static void parse_externals(void) +{ + add_anchor_token('}'); add_anchor_token(T_EOF); #ifndef NDEBUG unsigned char token_anchor_copy[T_LAST_TOKEN]; memcpy(token_anchor_copy, token_anchor_set, sizeof(token_anchor_copy)); #endif - for (;;) { + + while (token.type != T_EOF && token.type != '}') { #ifndef NDEBUG bool anchor_leak = false; for (int i = 0; i != T_LAST_TOKEN; ++i) { @@ -10401,39 +10564,30 @@ static void parse_translation_unit(void) abort(); #endif - switch (token.type) { - DECLARATION_START - case T_IDENTIFIER: - case T___extension__: - case '(': /* for function declarations with implicit return type and - * parenthesized declarator, i.e. (f)(void); */ - parse_external_declaration(); - break; + parse_external(); + } - case T_asm: - parse_global_asm(); - break; + rem_anchor_token(T_EOF); + rem_anchor_token('}'); +} - case T_EOF: - rem_anchor_token(T_EOF); - return; +/** + * Parse a translation unit. + */ +static void parse_translation_unit(void) +{ + add_anchor_token(T_EOF); - case ';': - if (!strict_mode) { - if (warning.other) - warningf(HERE, "stray ';' outside of function"); - next_token(); - break; - } - /* FALLTHROUGH */ + while (true) { + parse_externals(); - default: - errorf(HERE, "stray %K outside of function", &token); - if (token.type == '(' || token.type == '{' || token.type == '[') - eat_until_matching_token(token.type); - next_token(); - break; - } + if (token.type == T_EOF) + break; + + errorf(HERE, "stray %K outside of function", &token); + if (token.type == '(' || token.type == '{' || token.type == '[') + eat_until_matching_token(token.type); + next_token(); } } @@ -10459,15 +10613,15 @@ void start_parsing(void) assert(file_scope == NULL); file_scope = &unit->scope; - assert(scope == NULL); + assert(current_scope == NULL); scope_push(&unit->scope); } translation_unit_t *finish_parsing(void) { /* do NOT use scope_pop() here, this will crash, will it by hand */ - assert(scope == &unit->scope); - scope = NULL; + assert(current_scope == &unit->scope); + current_scope = NULL; assert(file_scope == &unit->scope); check_unused_globals(); diff --git a/preprocessor.c b/preprocessor.c index f56a182..39b2bb7 100644 --- a/preprocessor.c +++ b/preprocessor.c @@ -1264,7 +1264,7 @@ static void print_line_directive(const source_position_t *pos, const char *add) static void print_spaces(void) { - if (counted_newlines >= 8) { + if (counted_newlines >= 9) { if (input.had_non_space) { fputc('\n', out); } diff --git a/tokens.inc b/tokens.inc index 11f4a7f..bca37bb 100644 --- a/tokens.inc +++ b/tokens.inc @@ -140,91 +140,91 @@ S(_MS, __FUNCDNAME__) #endif #define S(mode, x, val) T(mode, x, #x, val) -S(_ANSI|_C99, signed, ) -S(_ALL, __signed, = T_signed) -S(_ALL, __signed__, = T_signed) -S(_C99|_GNUC, _Complex, ) -S(_ALL, __complex__, = T__Complex) -S(_ALL, __complex, = T__Complex) -S(_C99|_GNUC, _Imaginary, ) -S(_ALL, __real__, ) -S(_ALL, __real, = T___real__) -S(_ALL, __imag__, ) -S(_ALL, __imag, = T___imag__) -S(_ALL, __alignof__, ) -S(_ALL, __alignof, = T___alignof__) -S(_MS, _alignof, = T___alignof__) -S(_ANSI|_C99, const, ) -S(_ALL, __const, = T_const) -S(_ALL, __const__, = T_const) -S(_C99, restrict, ) -S(_ALL, __restrict__, = T_restrict) -S(_ALL, __restrict, = T_restrict) -S(_MS, _restrict, = T_restrict) -S(_ALL, asm, ) -S(_ALL, __asm__, = T_asm) -S(_MS, _asm, = T_asm) -S(_ALL, __asm, = T_asm) -S(_ANSI|_C99, volatile, ) -S(_ALL, __volatile, = T_volatile) -S(_ALL, __volatile__, = T_volatile) -S(_C99|_CXX, inline, ) -S(_ALL, __inline, = T_inline) -S(_ALL, __inline__, = T_inline) -S(_GNUC, typeof, ) -S(_ALL, __typeof, = T_typeof) -S(_ALL, __typeof__, = T_typeof) -S(_ALL, __attribute__, ) +S(_ANSI|_C99|_CXX, signed, ) +S(_ALL, __signed, = T_signed) +S(_ALL, __signed__, = T_signed) +S(_C99|_GNUC, _Complex, ) +S(_ALL, __complex__, = T__Complex) +S(_ALL, __complex, = T__Complex) +S(_C99|_GNUC, _Imaginary, ) +S(_ALL, __real__, ) +S(_ALL, __real, = T___real__) +S(_ALL, __imag__, ) +S(_ALL, __imag, = T___imag__) +S(_ALL, __alignof__, ) +S(_ALL, __alignof, = T___alignof__) +S(_MS, _alignof, = T___alignof__) +S(_ANSI|_C99|_CXX, const, ) +S(_ALL, __const, = T_const) +S(_ALL, __const__, = T_const) +S(_C99, restrict, ) +S(_ALL, __restrict__, = T_restrict) +S(_ALL, __restrict, = T_restrict) +S(_MS, _restrict, = T_restrict) +S(_ALL, asm, ) +S(_ALL, __asm__, = T_asm) +S(_MS, _asm, = T_asm) +S(_ALL, __asm, = T_asm) +S(_ANSI|_C99|_CXX, volatile, ) +S(_ALL, __volatile, = T_volatile) +S(_ALL, __volatile__, = T_volatile) +S(_C99|_CXX, inline, ) +S(_ALL, __inline, = T_inline) +S(_ALL, __inline__, = T_inline) +S(_GNUC, typeof, ) +S(_ALL, __typeof, = T_typeof) +S(_ALL, __typeof__, = T_typeof) +S(_ALL, __attribute__, ) -S(_ALL, __builtin_va_start, ) -S(_ALL, __builtin_stdarg_start, = T___builtin_va_start) +S(_ALL, __builtin_va_start, ) +S(_ALL, __builtin_stdarg_start, = T___builtin_va_start) -S(_MS, _near, ) -S(_MS, __near, = T__near) -S(_MS, _far, ) -S(_MS, __far, = T__far) -S(_MS, cdecl, ) -S(_MS, _cdecl, = T_cdecl) -S(_MS, __cdecl, = T_cdecl) -S(_MS, _stdcall, ) -S(_MS, __stdcall, = T__stdcall) -S(_MS, _fastcall, ) -S(_MS, __fastcall, = T__fastcall) -S(_MS, __thiscall, ) -S(_MS, _forceinline, ) -S(_MS, __forceinline, = T__forceinline) -S(_MS, __unaligned, ) -S(_MS, _assume, ) -S(_MS, __assume, = T__assume) -S(_MS, _try, ) -S(_MS, __try, = T__try) -S(_MS, _finally, ) -S(_MS, __finally, = T__finally) -S(_MS, _leave, ) -S(_MS, __leave, = T__leave) -S(_MS, _except, ) -S(_MS, __except, = T__except) -S(_MS, _declspec, ) -S(_MS, __declspec, = T__declspec) -S(_MS, _based, ) -S(_MS, __based, = T__based) -S(_MS, __noop, ) +S(_MS, _near, ) +S(_MS, __near, = T__near) +S(_MS, _far, ) +S(_MS, __far, = T__far) +S(_MS, cdecl, ) +S(_MS, _cdecl, = T_cdecl) +S(_MS, __cdecl, = T_cdecl) +S(_MS, _stdcall, ) +S(_MS, __stdcall, = T__stdcall) +S(_MS, _fastcall, ) +S(_MS, __fastcall, = T__fastcall) +S(_MS, __thiscall, ) +S(_MS, _forceinline, ) +S(_MS, __forceinline, = T__forceinline) +S(_MS, __unaligned, ) +S(_MS, _assume, ) +S(_MS, __assume, = T__assume) +S(_MS, _try, ) +S(_MS, __try, = T__try) +S(_MS, _finally, ) +S(_MS, __finally, = T__finally) +S(_MS, _leave, ) +S(_MS, __leave, = T__leave) +S(_MS, _except, ) +S(_MS, __except, = T__except) +S(_MS, _declspec, ) +S(_MS, __declspec, = T__declspec) +S(_MS, _based, ) +S(_MS, __based, = T__based) +S(_MS, __noop, ) -S(_MS, __ptr32, ) -S(_MS, __ptr64, ) -S(_MS, __sptr, ) -S(_MS, __uptr, ) -S(_MS, _w64, ) -S(_MS, __w64, = T__w64) +S(_MS, __ptr32, ) +S(_MS, __ptr64, ) +S(_MS, __sptr, ) +S(_MS, __uptr, ) +S(_MS, _w64, ) +S(_MS, __w64, = T__w64) -S(_MS, _int8, ) -S(_MS, __int8, = T__int8) -S(_MS, _int16, ) -S(_MS, __int16, = T__int16) -S(_MS, _int32, ) -S(_MS, __int32, = T__int32) -S(_MS, _int64, ) -S(_MS, __int64, = T__int64) -S(_MS, _int128, ) -S(_MS, __int128, = T__int128) +S(_MS, _int8, ) +S(_MS, __int8, = T__int8) +S(_MS, _int16, ) +S(_MS, __int16, = T__int16) +S(_MS, _int32, ) +S(_MS, __int32, = T__int32) +S(_MS, _int64, ) +S(_MS, __int64, = T__int64) +S(_MS, _int128, ) +S(_MS, __int128, = T__int128) #undef S diff --git a/type.c b/type.c index ce14faa..204d6f0 100644 --- a/type.c +++ b/type.c @@ -295,14 +295,21 @@ void print_imaginary_type(const imaginary_type_t *type) */ static void print_function_type_pre(const function_type_t *type, bool top) { + if (type->linkage != NULL) { + fputs("extern \"", out); + fputs(type->linkage->string, out); + fputs("\" ", out); + } + print_type_qualifiers(type->base.qualifiers); if (type->base.qualifiers != 0) fputc(' ', out); - intern_print_type_pre(type->return_type, false); - switch (type->calling_convention) { +#if 0 + /* TODO: revive with linkage */ + switch (type->linkage) { case CC_CDECL: fputs("__cdecl ", out); break; @@ -318,6 +325,7 @@ static void print_function_type_pre(const function_type_t *type, bool top) case CC_DEFAULT: break; } +#endif /* don't emit parenthesis if we're the toplevel type... */ if (!top) @@ -1029,7 +1037,7 @@ static bool function_types_compatible(const function_type_t *func1, if (!types_compatible(ret1, ret2)) return false; - if (func1->calling_convention != func2->calling_convention) + if (func1->linkage != func2->linkage) return false; /* can parameters be compared? */ diff --git a/type_hash.c b/type_hash.c index d20759f..88de01c 100644 --- a/type_hash.c +++ b/type_hash.c @@ -98,7 +98,7 @@ static unsigned hash_function_type(const function_type_t *type) result ^= hash_ptr(parameter->type); parameter = parameter->next; } - result += type->calling_convention; + result ^= hash_ptr(type->linkage); return result; } @@ -208,7 +208,7 @@ static bool function_types_equal(const function_type_t *type1, return false; if (type1->kr_style_parameters != type2->kr_style_parameters) return false; - if (type1->calling_convention != type2->calling_convention) + if (type1->linkage != type2->linkage) return false; function_parameter_t *param1 = type1->parameters; diff --git a/type_t.h b/type_t.h index 5fed59d..0773f70 100644 --- a/type_t.h +++ b/type_t.h @@ -132,7 +132,7 @@ struct function_type_t { type_base_t base; type_t *return_type; /**< The return type. */ function_parameter_t *parameters; /**< A list of the parameter types. */ - cc_kind_t calling_convention; /**< The specified calling convention. */ + symbol_t *linkage; bool variadic : 1; bool unspecified_parameters : 1; bool kr_style_parameters : 1; diff --git a/types.c b/types.c index 98e75ce..586b95b 100644 --- a/types.c +++ b/types.c @@ -22,8 +22,6 @@ #include "lang_features.h" #include "entity_t.h" -atomic_type_kind_t wchar_atomic_kind = ATOMIC_TYPE_INT; - /** The error type. */ type_t *type_error_type; -- 2.20.1