X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;ds=sidebyside;f=parser.c;h=502dcc6026d2fd28e032184142c4dcdd8b292232;hb=979fce13621246b706781035786b5d11a8e2f608;hp=293630f756df02e819032d6853db49db9c0aac0b;hpb=187f82e4c1cbff67189e4ef40a1305dbe447b9cf;p=cparser diff --git a/parser.c b/parser.c index 293630f..502dcc6 100644 --- a/parser.c +++ b/parser.c @@ -1,6 +1,6 @@ /* * This file is part of cparser. - * Copyright (C) 2007-2008 Matthias Braun + * Copyright (C) 2007-2009 Matthias Braun * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -38,6 +38,7 @@ #include "lang_features.h" #include "walk_statements.h" #include "warning.h" +#include "printer.h" #include "adt/bitfiddle.h" #include "adt/error.h" #include "adt/array.h" @@ -87,6 +88,7 @@ static scope_t *file_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_entity = NULL; static entity_t *current_init_decl = NULL; static switch_statement_t *current_switch = NULL; static statement_t *current_loop = NULL; @@ -99,9 +101,9 @@ static label_statement_t *label_first = NULL; static label_statement_t **label_anchor = NULL; /** current translation unit. */ static translation_unit_t *unit = NULL; -/** true if we are in a type property context (evaluation only for type. */ +/** true if we are in a type property context (evaluation only for type) */ static bool in_type_prop = false; -/** true in we are in a __extension__ context. */ +/** true if we are in an __extension__ context. */ static bool in_gcc_extension = false; static struct obstack temp_obst; static entity_t *anonymous_entity; @@ -114,7 +116,7 @@ static declaration_t **incomplete_arrays; #define POP_PARENT ((void)(current_parent = prev_parent)) /** special symbol used for anonymous entities. */ -static const symbol_t *sym_anonymous = NULL; +static symbol_t *sym_anonymous = NULL; /** The token anchor set */ static unsigned char token_anchor_set[T_LAST_TOKEN]; @@ -149,13 +151,8 @@ typedef enum declarator_flags_t { static entity_t *parse_declarator(const declaration_specifiers_t *specifiers, declarator_flags_t flags); -static entity_t *record_entity(entity_t *entity, bool is_definition); - static void semantic_comparison(binary_expression_t *expression); -static void create_gnu_builtins(void); -static void create_microsoft_intrinsics(void); - #define STORAGE_CLASSES \ STORAGE_CLASSES_NO_EXTERN \ case T_extern: @@ -264,57 +261,6 @@ static void create_microsoft_intrinsics(void); case T_throw: \ case T_true: -/** - * Allocate an AST node with given size and - * initialize all fields with zero. - */ -static void *allocate_ast_zero(size_t size) -{ - void *res = allocate_ast(size); - memset(res, 0, size); - return res; -} - -/** - * Returns the size of an entity node. - * - * @param kind the entity kind - */ -static size_t get_entity_struct_size(entity_kind_t kind) -{ - static const size_t sizes[] = { - [ENTITY_VARIABLE] = sizeof(variable_t), - [ENTITY_PARAMETER] = sizeof(parameter_t), - [ENTITY_COMPOUND_MEMBER] = sizeof(compound_member_t), - [ENTITY_FUNCTION] = sizeof(function_t), - [ENTITY_TYPEDEF] = sizeof(typedef_t), - [ENTITY_STRUCT] = sizeof(compound_t), - [ENTITY_UNION] = sizeof(compound_t), - [ENTITY_ENUM] = sizeof(enum_t), - [ENTITY_ENUM_VALUE] = sizeof(enum_value_t), - [ENTITY_LABEL] = sizeof(label_t), - [ENTITY_LOCAL_LABEL] = sizeof(label_t), - [ENTITY_NAMESPACE] = sizeof(namespace_t) - }; - assert(kind < lengthof(sizes)); - assert(sizes[kind] != 0); - return sizes[kind]; -} - -/** - * Allocate an entity of given kind and initialize all - * fields with zero. - * - * @param kind the kind of the entity to allocate - */ -static entity_t *allocate_entity_zero(entity_kind_t kind) -{ - size_t size = get_entity_struct_size(kind); - entity_t *entity = allocate_ast_zero(size); - entity->kind = kind; - return entity; -} - /** * Returns the size of a statement node. * @@ -453,53 +399,10 @@ static statement_t *create_empty_statement(void) return allocate_statement_zero(STATEMENT_EMPTY); } -/** - * Returns the size of a type node. - * - * @param kind the type kind - */ -static size_t get_type_struct_size(type_kind_t kind) -{ - static const size_t sizes[] = { - [TYPE_ATOMIC] = sizeof(atomic_type_t), - [TYPE_COMPLEX] = sizeof(complex_type_t), - [TYPE_IMAGINARY] = sizeof(imaginary_type_t), - [TYPE_BITFIELD] = sizeof(bitfield_type_t), - [TYPE_COMPOUND_STRUCT] = sizeof(compound_type_t), - [TYPE_COMPOUND_UNION] = sizeof(compound_type_t), - [TYPE_ENUM] = sizeof(enum_type_t), - [TYPE_FUNCTION] = sizeof(function_type_t), - [TYPE_POINTER] = sizeof(pointer_type_t), - [TYPE_ARRAY] = sizeof(array_type_t), - [TYPE_BUILTIN] = sizeof(builtin_type_t), - [TYPE_TYPEDEF] = sizeof(typedef_type_t), - [TYPE_TYPEOF] = sizeof(typeof_type_t), - }; - assert(lengthof(sizes) == (int)TYPE_TYPEOF + 1); - assert(kind <= TYPE_TYPEOF); - assert(sizes[kind] != 0); - return sizes[kind]; -} - -/** - * Allocate a type node of given kind and initialize all - * fields with zero. - * - * @param kind type kind to allocate - */ -static type_t *allocate_type_zero(type_kind_t kind) -{ - size_t size = get_type_struct_size(kind); - type_t *res = obstack_alloc(type_obst, size); - memset(res, 0, size); - res->base.kind = kind; - - return res; -} - static function_parameter_t *allocate_parameter(type_t *const type) { - function_parameter_t *const param = obstack_alloc(type_obst, sizeof(*param)); + function_parameter_t *const param + = obstack_alloc(type_obst, sizeof(*param)); memset(param, 0, sizeof(*param)); param->type = type; return param; @@ -569,6 +472,16 @@ static inline void next_token(void) #endif } +static inline bool next_if(int const type) +{ + if (token.type == type) { + next_token(); + return true; + } else { + return false; + } +} + /** * Return the next token with a given lookahead. */ @@ -702,8 +615,7 @@ static void eat_until_anchor(void) static void eat_block(void) { eat_until_matching_token('{'); - if (token.type == '}') - next_token(); + next_if('}'); } #define eat(token_type) (assert(token.type == (token_type)), next_token()) @@ -747,8 +659,7 @@ static void type_error_incompatible(const char *msg, parse_error_expected(NULL, (expected), NULL); \ add_anchor_token(expected); \ eat_until_anchor(); \ - if (token.type == expected) \ - next_token(); \ + next_if((expected)); \ rem_anchor_token(expected); \ goto error_label; \ } \ @@ -796,7 +707,7 @@ static entity_t *get_entity(const symbol_t *const symbol, /* §6.2.3:1 24) There is only one name space for tags even though three are * possible. */ static entity_t *get_tag(symbol_t const *const symbol, - entity_kind_tag_t const kind) + entity_kind_tag_t const kind) { entity_t *entity = get_entity(symbol, NAMESPACE_TAG); if (entity != NULL && entity->kind != kind) { @@ -1242,12 +1153,9 @@ static attribute_t *allocate_attribute_zero(attribute_kind_t kind) */ static attribute_argument_t *parse_attribute_arguments(void) { - if (token.type == ')') - return NULL; - - attribute_argument_t *first = NULL; - attribute_argument_t *last = NULL; - while (true) { + attribute_argument_t *first = NULL; + attribute_argument_t **anchor = &first; + if (token.type != ')') do { attribute_argument_t *argument = allocate_ast_zero(sizeof(*argument)); /* is it an identifier */ @@ -1266,20 +1174,10 @@ static attribute_argument_t *parse_attribute_arguments(void) } /* append argument */ - if (last == NULL) { - first = argument; - } else { - last->next = argument; - } - last = argument; - - if (token.type == ',') { - next_token(); - continue; - } - expect(')', end_error); - break; - } + *anchor = argument; + anchor = &argument->next; + } while (next_if(',')); + expect(')', end_error); return first; @@ -1373,10 +1271,8 @@ static attribute_t *parse_attribute_gnu_single(void) attribute_t *attribute = allocate_attribute_zero(kind); /* parse arguments */ - if (token.type == '(') { - next_token(); + if (next_if('(')) attribute->a.arguments = parse_attribute_arguments(); - } return attribute; @@ -1386,37 +1282,22 @@ end_error: static attribute_t *parse_attribute_gnu(void) { - attribute_t *first = NULL; - attribute_t *last = NULL; + attribute_t *first = NULL; + attribute_t **anchor = &first; eat(T___attribute__); expect('(', end_error); expect('(', end_error); - if (token.type == ')') { - next_token(); - expect(')', end_error); - return first; - } - - while (true) { + if (token.type != ')') do { attribute_t *attribute = parse_attribute_gnu_single(); if (attribute == NULL) goto end_error; - if (last == NULL) { - first = attribute; - } else { - last->next = attribute; - } - last = attribute; - - if (token.type == ')') { - next_token(); - break; - } - expect(',', end_error); - } + *anchor = attribute; + anchor = &attribute->next; + } while (next_if(',')); + expect(')', end_error); expect(')', end_error); end_error: @@ -1426,12 +1307,10 @@ end_error: /** Parse attributes. */ static attribute_t *parse_attributes(attribute_t *first) { - attribute_t *last = first; - while (true) { - if (last != NULL) { - while (last->next != NULL) - last = last->next; - } + attribute_t **anchor = &first; + for (;;) { + while (*anchor != NULL) + anchor = &(*anchor)->next; attribute_t *attribute; switch (token.type) { @@ -1475,12 +1354,8 @@ static attribute_t *parse_attributes(attribute_t *first) return first; } - if (last == NULL) { - first = attribute; - } else { - last->next = attribute; - } - last = attribute; + *anchor = attribute; + anchor = &attribute->next; } } @@ -1721,10 +1596,10 @@ unary: static designator_t *parse_designation(void) { - designator_t *result = NULL; - designator_t *last = NULL; + designator_t *result = NULL; + designator_t **anchor = &result; - while (true) { + for (;;) { designator_t *designator; switch (token.type) { case '[': @@ -1754,12 +1629,8 @@ static designator_t *parse_designation(void) } assert(designator != NULL); - if (last != NULL) { - last->next = designator; - } else { - result = designator; - } - last = designator; + *anchor = designator; + anchor = &designator->next; } end_error: return NULL; @@ -1840,11 +1711,6 @@ static initializer_t *initializer_from_expression(type_t *orig_type, &expression->base.source_position); initializer_t *const result = allocate_initializer_zero(INITIALIZER_VALUE); -#if 0 - if (type->kind == TYPE_BITFIELD) { - type = type->bitfield.base_type; - } -#endif result->value.value = create_implicit_cast(expression, type); return result; @@ -1869,20 +1735,19 @@ static initializer_t *parse_scalar_initializer(type_t *type, { /* there might be extra {} hierarchies */ int braces = 0; - if (token.type == '{') { + if (next_if('{')) { if (warning.other) warningf(HERE, "extra curly braces around scalar initializer"); do { ++braces; - next_token(); - } while (token.type == '{'); + } while (next_if('{')); } expression_t *expression = parse_assignment_expression(); mark_vars_read(expression, NULL); if (must_be_constant && !is_initializer_constant(expression)) { errorf(&expression->base.source_position, - "Initialisation expression '%E' is not constant", + "initialisation expression '%E' is not constant", expression); } @@ -1898,9 +1763,7 @@ static initializer_t *parse_scalar_initializer(type_t *type, bool additional_warning_displayed = false; while (braces > 0) { - if (token.type == ',') { - next_token(); - } + next_if(','); if (token.type != '}') { if (!additional_warning_displayed && warning.other) { warningf(HERE, "additional elements in scalar initializer"); @@ -2198,8 +2061,7 @@ static void advance_current_object(type_path_t *path, size_t top_path_level) */ static void skip_initializers(void) { - if (token.type == '{') - next_token(); + next_if('{'); while (token.type != '}') { if (token.type == T_EOF) @@ -2316,6 +2178,8 @@ finish_designator: if (type == NULL) { /* we are already outside, ... */ + if (outer_type == NULL) + goto error_parse_next; type_t *const outer_type_skip = skip_typeref(outer_type); if (is_type_compound(outer_type_skip) && !outer_type_skip->compound.compound->complete) { @@ -2330,9 +2194,7 @@ finish_designator: && outer_type != NULL) { sub = initializer_from_expression(outer_type, expression); if (sub != NULL) { - if (token.type == ',') { - next_token(); - } + next_if(','); if (token.type != '}' && warning.other) { warningf(HERE, "excessive elements in initializer for type '%T'", orig_type); @@ -2382,10 +2244,10 @@ finish_designator: error_excess: if (warning.other) { if (env->entity != NULL) { - warningf(HERE, "excess elements in struct initializer for '%Y'", - env->entity->base.symbol); + warningf(HERE, "excess elements in initializer for '%Y'", + env->entity->base.symbol); } else { - warningf(HERE, "excess elements in struct initializer"); + warningf(HERE, "excess elements in initializer"); } } } @@ -2520,17 +2382,14 @@ static void append_entity(scope_t *scope, entity_t *entity) } else { scope->entities = entity; } - scope->last_entity = entity; + entity->base.parent_entity = current_entity; + scope->last_entity = entity; } static compound_t *parse_compound_type_specifier(bool is_struct) { - if (is_struct) { - eat(T_struct); - } else { - eat(T_union); - } + eat(is_struct ? T_struct : T_union); symbol_t *symbol = NULL; compound_t *compound = NULL; @@ -2632,8 +2491,7 @@ static void parse_enum_entries(type_t *const enum_type) entity->base.source_position = token.source_position; next_token(); - if (token.type == '=') { - next_token(); + if (next_if('=')) { expression_t *value = parse_constant_expression(); value = create_implicit_cast(value, enum_type); @@ -2643,11 +2501,7 @@ static void parse_enum_entries(type_t *const enum_type) } record_entity(entity, false); - - if (token.type != ',') - break; - next_token(); - } while (token.type != '}'); + } while (next_if(',') && token.type != '}'); rem_anchor_token('}'); expect('}', end_error); @@ -2658,33 +2512,38 @@ end_error: static type_t *parse_enum_specifier(void) { - entity_t *entity; - symbol_t *symbol; + entity_t *entity; + symbol_t *symbol; eat(T_enum); - if (token.type == T_IDENTIFIER) { - symbol = token.v.symbol; - next_token(); + switch (token.type) { + case T_IDENTIFIER: + symbol = token.v.symbol; + next_token(); - entity = get_tag(symbol, ENTITY_ENUM); - if (entity != NULL) { - if (entity->base.parent_scope != current_scope && - (token.type == '{' || token.type == ';')) { - /* we're in an inner scope and have a definition. Shadow - * existing definition in outer scope */ - entity = NULL; - } else if (entity->enume.complete && token.type == '{') { - errorf(HERE, "multiple definitions of 'enum %Y' (previous definition %P)", - symbol, &entity->base.source_position); + entity = get_tag(symbol, ENTITY_ENUM); + if (entity != NULL) { + if (entity->base.parent_scope != current_scope && + (token.type == '{' || token.type == ';')) { + /* we're in an inner scope and have a definition. Shadow + * existing definition in outer scope */ + entity = NULL; + } else if (entity->enume.complete && token.type == '{') { + errorf(HERE, "multiple definitions of 'enum %Y' (previous definition %P)", + symbol, &entity->base.source_position); + } } - } - } else if (token.type != '{') { - parse_error_expected("while parsing enum type specifier", - T_IDENTIFIER, '{', NULL); - return NULL; - } else { - entity = NULL; - symbol = NULL; + break; + + case '{': + entity = NULL; + symbol = NULL; + break; + + default: + parse_error_expected("while parsing enum type specifier", + T_IDENTIFIER, '{', NULL); + return NULL; } if (entity == NULL) { @@ -2746,9 +2605,8 @@ static type_t *parse_typeof(void) bool old_gcc_extension = in_gcc_extension; in_type_prop = true; - while (token.type == T___extension__) { + while (next_if(T___extension__)) { /* This can be a prefix to a typename or an expression. */ - next_token(); in_gcc_extension = true; } switch (token.type) { @@ -2835,7 +2693,7 @@ static attribute_t *parse_attribute_ms_property(attribute_t *attribute) attribute_property_argument_t *property = allocate_ast_zero(sizeof(*property)); - while (true) { + do { if (token.type != T_IDENTIFIER) { parse_error_expected("while parsing property declspec", T_IDENTIFIER, NULL); @@ -2865,10 +2723,7 @@ static attribute_t *parse_attribute_ms_property(attribute_t *attribute) property->get_symbol = token.v.symbol; } next_token(); - if (token.type == ')') - break; - expect(',', end_error); - } + } while (next_if(',')); attribute->a.property = property; @@ -2881,9 +2736,8 @@ end_error: static attribute_t *parse_microsoft_extended_decl_modifier_single(void) { attribute_kind_t kind = ATTRIBUTE_UNKNOWN; - if (token.type == T_restrict) { + if (next_if(T_restrict)) { kind = ATTRIBUTE_MS_RESTRICT; - next_token(); } else if (token.type == T_IDENTIFIER) { const char *name = token.v.symbol->string; next_token(); @@ -2911,10 +2765,8 @@ static attribute_t *parse_microsoft_extended_decl_modifier_single(void) } /* parse arguments */ - if (token.type == '(') { - next_token(); + if (next_if('(')) attribute->a.arguments = parse_attribute_arguments(); - } return attribute; } @@ -2925,37 +2777,24 @@ static attribute_t *parse_microsoft_extended_decl_modifier(attribute_t *first) expect('(', end_error); - if (token.type == ')') { - next_token(); + if (next_if(')')) return NULL; - } add_anchor_token(')'); - attribute_t *last = first; - while (true) { - if (last != NULL) { - while (last->next != NULL) - last = last->next; - } + attribute_t **anchor = &first; + do { + while (*anchor != NULL) + anchor = &(*anchor)->next; attribute_t *attribute = parse_microsoft_extended_decl_modifier_single(); if (attribute == NULL) goto end_error; - if (last == NULL) { - first = attribute; - } else { - last->next = attribute; - } - last = attribute; - - if (token.type == ')') { - break; - } - expect(',', end_error); - } + *anchor = attribute; + anchor = &attribute->next; + } while (next_if(',')); rem_anchor_token(')'); expect(')', end_error); @@ -3417,7 +3256,6 @@ warn_about_long_long: end_error: specifiers->type = type_error_type; - return; } static type_qualifiers_t parse_type_qualifiers(void) @@ -3458,12 +3296,7 @@ static void parse_identifier_list(scope_t *scope) if (scope != NULL) append_entity(scope, entity); - - if (token.type != ',') { - break; - } - next_token(); - } while (token.type == T_IDENTIFIER); + } while (next_if(',') && token.type == T_IDENTIFIER); } static entity_t *parse_parameter(void) @@ -3529,8 +3362,7 @@ static void parse_parameters(function_type_t *type, scope_t *scope) !is_typedef_symbol(token.v.symbol)) { token_type_t la1_type = (token_type_t)look_ahead(1)->type; if (la1_type == ',' || la1_type == ')') { - type->kr_style_parameters = true; - type->unspecified_parameters = true; + type->kr_style_parameters = true; parse_identifier_list(scope); goto parameters_finished; } @@ -3545,7 +3377,7 @@ static void parse_parameters(function_type_t *type, scope_t *scope) if (has_parameters()) { function_parameter_t **anchor = &type->parameters; - for (;;) { + do { switch (token.type) { case T_DOTDOTDOT: next_token(); @@ -3581,11 +3413,7 @@ static void parse_parameters(function_type_t *type, scope_t *scope) default: goto parameters_finished; } - if (token.type != ',') { - goto parameters_finished; - } - next_token(); - } + } while (next_if(',')); } @@ -3679,18 +3507,12 @@ static construct_type_t *parse_array_declarator(void) memset(array, 0, sizeof(*array)); cons->kind = CONSTRUCT_ARRAY; - if (token.type == T_static) { + if (next_if(T_static)) array->is_static = true; - next_token(); - } type_qualifiers_t type_qualifiers = parse_type_qualifiers(); - if (type_qualifiers != 0) { - if (token.type == T_static) { + if (type_qualifiers != 0 && next_if(T_static)) array->is_static = true; - next_token(); - } - } array->type_qualifiers = type_qualifiers; if (token.type == '*' && look_ahead(1)->type == ']') { @@ -3725,7 +3547,7 @@ static construct_type_t *parse_function_declarator(scope_t *scope) function_type_t *ftype = &type->function; ftype->linkage = current_linkage; - ftype->calling_convention = CC_CDECL; + ftype->calling_convention = CC_DEFAULT; parse_parameters(ftype, scope); @@ -3768,26 +3590,7 @@ static construct_type_t *parse_inner_declarator(parse_declarator_env_t *env) break; case T__based: { -#if 0 - source_position_t const pos = *HERE; - next_token(); - expect('(', end_error); - add_anchor_token(')'); - based = parse_microsoft_based(); - rem_anchor_token(')'); - expect(')', end_error); - if (token.type != '*') { - if (token.type == T__based) { - errorf(&pos, "__based type modifier specified more than once"); - } else if (warning.other) { - warningf(&pos, - "__based does not precede a pointer declarator, ignored"); - } - continue; - } -#else - panic("based currently disabled"); -#endif + panic("based not supported anymore"); /* FALLTHROUGH */ } @@ -3807,11 +3610,6 @@ static construct_type_t *parse_inner_declarator(parse_declarator_env_t *env) } ptr_operator_end: ; -#if 0 - modifiers |= env->modifiers; - env->modifiers = modifiers; -#endif - construct_type_t *inner_types = NULL; switch (token.type) { @@ -3886,7 +3684,8 @@ end_error: return NULL; } -static type_t *construct_declarator_type(construct_type_t *construct_list, type_t *type) +static type_t *construct_declarator_type(construct_type_t *construct_list, + type_t *type) { construct_type_t *iter = construct_list; for (; iter != NULL; iter = iter->base.next) { @@ -4045,15 +3844,11 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers, attribute_t *attributes = parse_attributes(env.attributes); /* append (shared) specifier attribute behind attributes of this - declarator */ - if (attributes != NULL) { - attribute_t *last = attributes; - while (last->next != NULL) - last = last->next; - last->next = specifiers->attributes; - } else { - attributes = specifiers->attributes; - } + * declarator */ + attribute_t **anchor = &attributes; + while (*anchor != NULL) + anchor = &(*anchor)->next; + *anchor = specifiers->attributes; entity_t *entity; if (specifiers->storage_class == STORAGE_CLASS_TYPEDEF) { @@ -4164,7 +3959,7 @@ 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 && current_scope != file_scope) + if (storage_class == STORAGE_CLASS_NONE && current_function != NULL) storage_class = STORAGE_CLASS_AUTO; entity->declaration.storage_class = storage_class; } @@ -4281,11 +4076,52 @@ static bool is_error_entity(entity_t *const ent) return false; } +static bool contains_attribute(const attribute_t *list, const attribute_t *attr) +{ + for (const attribute_t *tattr = list; tattr != NULL; tattr = tattr->next) { + if (attributes_equal(tattr, attr)) + return true; + } + return false; +} + +/** + * test wether new_list contains any attributes not included in old_list + */ +static bool has_new_attributes(const attribute_t *old_list, + const attribute_t *new_list) +{ + for (const attribute_t *attr = new_list; attr != NULL; attr = attr->next) { + if (!contains_attribute(old_list, attr)) + return true; + } + return false; +} + +/** + * Merge in attributes from an attribute list (probably from a previous + * declaration with the same name). Warning: destroys the old structure + * of the attribute list - don't reuse attributes after this call. + */ +static void merge_in_attributes(declaration_t *decl, attribute_t *attributes) +{ + attribute_t *next; + for (attribute_t *attr = attributes; attr != NULL; attr = next) { + next = attr->next; + if (contains_attribute(decl->attributes, attr)) + continue; + + /* move attribute to new declarations attributes list */ + attr->next = decl->attributes; + decl->attributes = attr; + } +} + /** * record entities for the NAMESPACE_NORMAL, and produce error messages/warnings * for various problems that occur for multiple definitions */ -static entity_t *record_entity(entity_t *entity, const bool is_definition) +entity_t *record_entity(entity_t *entity, const bool is_definition) { const symbol_t *const symbol = entity->base.symbol; const namespace_tag_t namespc = (namespace_tag_t)entity->base.namespc; @@ -4386,6 +4222,7 @@ static entity_t *record_entity(entity_t *entity, const bool is_definition) &previous_entity->base.source_position); } else { unsigned old_storage_class = prev_decl->storage_class; + if (warning.redundant_decls && is_definition && !prev_decl->used && @@ -4434,22 +4271,28 @@ static entity_t *record_entity(entity_t *entity, const bool is_definition) if (old_storage_class == STORAGE_CLASS_EXTERN && new_storage_class == STORAGE_CLASS_EXTERN) { -warn_redundant_declaration: - if (!is_definition && + +warn_redundant_declaration: ; + bool has_new_attrs + = has_new_attributes(prev_decl->attributes, + decl->attributes); + if (has_new_attrs) { + merge_in_attributes(decl, prev_decl->attributes); + } else if (!is_definition && warning.redundant_decls && is_type_valid(prev_type) && strcmp(previous_entity->base.source_position.input_name, "") != 0) { warningf(pos, - "redundant declaration for '%Y' (declared %P)", - symbol, &previous_entity->base.source_position); + "redundant declaration for '%Y' (declared %P)", + symbol, &previous_entity->base.source_position); } } else if (current_function == NULL) { if (old_storage_class != STORAGE_CLASS_STATIC && new_storage_class == STORAGE_CLASS_STATIC) { errorf(pos, - "static declaration of '%Y' follows non-static declaration (declared %P)", - symbol, &previous_entity->base.source_position); + "static declaration of '%Y' follows non-static declaration (declared %P)", + symbol, &previous_entity->base.source_position); } else if (old_storage_class == STORAGE_CLASS_EXTERN) { prev_decl->storage_class = STORAGE_CLASS_NONE; prev_decl->declared_storage_class = STORAGE_CLASS_NONE; @@ -4683,9 +4526,8 @@ static void parse_declaration_rest(entity_t *ndeclaration, check_variable_type_complete(entity); - if (token.type != ',') + if (!next_if(',')) break; - eat(','); add_anchor_token('='); ndeclaration = parse_declarator(specifiers, flags); @@ -4766,7 +4608,6 @@ static void parse_kr_declaration_list(entity_t *entity) if (!type->function.kr_style_parameters) return; - add_anchor_token('{'); /* push function parameters */ @@ -4808,8 +4649,30 @@ decl_list_end: function_parameter_t *parameters = NULL; function_parameter_t **anchor = ¶meters; + /* did we have an earlier prototype? */ + entity_t *proto_type = get_entity(entity->base.symbol, NAMESPACE_NORMAL); + if (proto_type != NULL && proto_type->kind != ENTITY_FUNCTION) + proto_type = NULL; + + function_parameter_t *proto_parameter = NULL; + if (proto_type != NULL) { + type_t *proto_type_type = proto_type->declaration.type; + proto_parameter = proto_type_type->function.parameters; + /* If a K&R function definition has a variadic prototype earlier, then + * make the function definition variadic, too. This should conform to + * §6.7.5.3:15 and §6.9.1:8. */ + new_type->function.variadic = proto_type_type->function.variadic; + } else { + /* §6.9.1.7: A K&R style parameter list does NOT act as a function + * prototype */ + new_type->function.unspecified_parameters = true; + } + + bool need_incompatible_warning = false; parameter = entity->function.parameters.entities; - for (; parameter != NULL; parameter = parameter->base.next) { + for (; parameter != NULL; parameter = parameter->base.next, + proto_parameter = + proto_parameter == NULL ? NULL : proto_parameter->next) { if (parameter->kind != ENTITY_PARAMETER) continue; @@ -4831,25 +4694,42 @@ decl_list_end: semantic_parameter_incomplete(parameter); - /* - * we need the default promoted types for the function type - */ - parameter_type = get_default_promoted_type(parameter_type); - - function_parameter_t *const parameter = - allocate_parameter(parameter_type); + /* we need the default promoted types for the function type */ + type_t *not_promoted = parameter_type; + parameter_type = get_default_promoted_type(parameter_type); + + /* gcc special: if the type of the prototype matches the unpromoted + * type don't promote */ + if (!strict_mode && proto_parameter != NULL) { + type_t *proto_p_type = skip_typeref(proto_parameter->type); + type_t *promo_skip = skip_typeref(parameter_type); + type_t *param_skip = skip_typeref(not_promoted); + if (!types_compatible(proto_p_type, promo_skip) + && types_compatible(proto_p_type, param_skip)) { + /* don't promote */ + need_incompatible_warning = true; + parameter_type = not_promoted; + } + } + function_parameter_t *const parameter + = allocate_parameter(parameter_type); *anchor = parameter; anchor = ¶meter->next; } - /* §6.9.1.7: A K&R style parameter list does NOT act as a function - * prototype */ - new_type->function.parameters = parameters; - new_type->function.unspecified_parameters = true; - + new_type->function.parameters = parameters; new_type = identify_new_type(new_type); + if (warning.other && need_incompatible_warning) { + type_t *proto_type_type = proto_type->declaration.type; + warningf(HERE, + "declaration '%#T' is incompatible with '%#T' (declared %P)", + proto_type_type, proto_type->base.symbol, + new_type, entity->base.symbol, + &proto_type->base.source_position); + } + entity->declaration.type = new_type; rem_anchor_token('{'); @@ -5236,9 +5116,8 @@ static void check_reachable(statement_t *const stmt) break; } - case STATEMENT_CONTINUE: { - statement_t *parent = stmt; - for (;;) { + case STATEMENT_CONTINUE: + for (statement_t *parent = stmt;;) { parent = parent->base.parent; if (parent == NULL) /* continue not within loop */ return; @@ -5252,11 +5131,9 @@ static void check_reachable(statement_t *const stmt) default: break; } } - } - case STATEMENT_BREAK: { - statement_t *parent = stmt; - for (;;) { + case STATEMENT_BREAK: + for (statement_t *parent = stmt;;) { parent = parent->base.parent; if (parent == NULL) /* break not within loop/switch */ return; @@ -5275,7 +5152,6 @@ static void check_reachable(statement_t *const stmt) } found_break_parent: break; - } case STATEMENT_GOTO: if (stmt->gotos.expression) { @@ -5671,8 +5547,7 @@ static void parse_external_declaration(void) /* §6.7.5.3:14 a function definition with () means no * parameters (and not unspecified parameters) */ if (type->function.unspecified_parameters && - type->function.parameters == NULL && - !type->function.kr_style_parameters) { + type->function.parameters == NULL) { type_t *copy = duplicate_type(type); copy->function.unspecified_parameters = false; type = identify_new_type(copy); @@ -5717,7 +5592,9 @@ static void parse_external_declaration(void) /* parse function body */ int label_stack_top = label_top(); function_t *old_current_function = current_function; + entity_t *old_current_entity = current_entity; current_function = function; + current_entity = (entity_t*) function; current_parent = NULL; goto_first = NULL; @@ -5749,6 +5626,8 @@ static void parse_external_declaration(void) assert(current_parent == NULL); assert(current_function == function); + assert(current_entity == (entity_t*) function); + current_entity = old_current_entity; current_function = old_current_function; label_pop_to(label_stack_top); } @@ -5771,7 +5650,7 @@ static type_t *make_bitfield_type(type_t *base_type, expression_t *size, type_t *skipped_type = skip_typeref(base_type); if (!is_type_integer(skipped_type)) { errorf(HERE, "bitfield base type '%T' is not an integer type", - base_type); + base_type); bit_size = 0; } else { bit_size = get_type_size(base_type) * 8; @@ -5917,7 +5796,7 @@ static expression_t *find_create_select(const source_position_t *pos, static void parse_compound_declarators(compound_t *compound, const declaration_specifiers_t *specifiers) { - while (true) { + do { entity_t *entity; if (token.type == ':') { @@ -5930,15 +5809,11 @@ static void parse_compound_declarators(compound_t *compound, type_t *type = make_bitfield_type(base_type, size, &source_position, NULL); - attribute_t *attributes = parse_attributes(NULL); - if (attributes != NULL) { - attribute_t *last = attributes; - while (last->next != NULL) - last = last->next; - last->next = specifiers->attributes; - } else { - attributes = specifiers->attributes; - } + attribute_t *attributes = parse_attributes(NULL); + attribute_t **anchor = &attributes; + while (*anchor != NULL) + anchor = &(*anchor)->next; + *anchor = specifiers->attributes; entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER); entity->base.namespc = NAMESPACE_NORMAL; @@ -5989,7 +5864,7 @@ static void parse_compound_declarators(compound_t *compound, type_t *type = skip_typeref(orig_type); if (is_type_function(type)) { errorf(&entity->base.source_position, - "compound member '%Y' must not have function type '%T'", + "compound member '%Y' must not have function type '%T'", entity->base.symbol, orig_type); } else if (is_type_incomplete(type)) { /* §6.7.2.1:16 flexible array member */ @@ -5997,7 +5872,7 @@ static void parse_compound_declarators(compound_t *compound, token.type != ';' || look_ahead(1)->type != '}') { errorf(&entity->base.source_position, - "compound member '%Y' has incomplete type '%T'", + "compound member '%Y' has incomplete type '%T'", entity->base.symbol, orig_type); } } @@ -6006,11 +5881,7 @@ static void parse_compound_declarators(compound_t *compound, append_entity(&compound->members, entity); } } - - if (token.type != ',') - break; - next_token(); - } + } while (next_if(',')); expect(';', end_error); end_error: @@ -6045,8 +5916,8 @@ static type_t *parse_typename(void) declaration_specifiers_t specifiers; memset(&specifiers, 0, sizeof(specifiers)); parse_declaration_specifiers(&specifiers); - if (specifiers.storage_class != STORAGE_CLASS_NONE || - specifiers.thread_local) { + if (specifiers.storage_class != STORAGE_CLASS_NONE + || specifiers.thread_local) { /* TODO: improve error message, user does probably not know what a * storage class is... */ @@ -6248,79 +6119,6 @@ static entity_t *create_implicit_function(symbol_t *symbol, return entity; } -/** - * Creates a return_type (func)(argument_type) function type if not - * already exists. - */ -static type_t *make_function_2_type(type_t *return_type, type_t *argument_type1, - type_t *argument_type2) -{ - function_parameter_t *const parameter2 = allocate_parameter(argument_type2); - function_parameter_t *const parameter1 = allocate_parameter(argument_type1); - parameter1->next = parameter2; - - type_t *type = allocate_type_zero(TYPE_FUNCTION); - type->function.return_type = return_type; - type->function.parameters = parameter1; - - return identify_new_type(type); -} - -/** - * Creates a return_type (func)(argument_type) function type if not - * already exists. - * - * @param return_type the return type - * @param argument_type the argument type - */ -static type_t *make_function_1_type(type_t *return_type, type_t *argument_type) -{ - function_parameter_t *const parameter = allocate_parameter(argument_type); - - type_t *type = allocate_type_zero(TYPE_FUNCTION); - type->function.return_type = return_type; - type->function.parameters = parameter; - - return identify_new_type(type); -} - -static type_t *make_function_1_type_variadic(type_t *return_type, type_t *argument_type) -{ - type_t *res = make_function_1_type(return_type, argument_type); - res->function.variadic = 1; - return res; -} - -/** - * Creates a return_type (func)(void) function type if not - * already exists. - * - * @param return_type the return type - */ -static type_t *make_function_0_type(type_t *return_type) -{ - type_t *type = allocate_type_zero(TYPE_FUNCTION); - type->function.return_type = return_type; - type->function.parameters = NULL; - - return identify_new_type(type); -} - -/** - * Creates a NO_RETURN return_type (func)(void) function type if not - * already exists. - * - * @param return_type the return type - */ -static type_t *make_function_0_type_noreturn(type_t *return_type) -{ - type_t *type = allocate_type_zero(TYPE_FUNCTION); - type->function.return_type = return_type; - type->function.parameters = NULL; - type->function.modifiers |= DM_NORETURN; - return identify_new_type(type); -} - /** * Performs automatic type cast as described in §6.3.2.1. * @@ -6404,30 +6202,100 @@ type_t *revert_automatic_type_conversion(const expression_t *expression) } } -static expression_t *parse_reference(void) +/** + * Find an entity matching a symbol in a scope. + * Uses current scope if scope is NULL + */ +static entity_t *lookup_entity(const scope_t *scope, symbol_t *symbol, + namespace_tag_t namespc) { - symbol_t *const symbol = token.v.symbol; + if (scope == NULL) { + return get_entity(symbol, namespc); + } - entity_t *entity = get_entity(symbol, NAMESPACE_NORMAL); + /* we should optimize here, if scope grows above a certain size we should + construct a hashmap here... */ + entity_t *entity = scope->entities; + for ( ; entity != NULL; entity = entity->base.next) { + if (entity->base.symbol == symbol && entity->base.namespc == namespc) + break; + } + + return entity; +} + +static entity_t *parse_qualified_identifier(void) +{ + /* namespace containing the symbol */ + symbol_t *symbol; + source_position_t pos; + const scope_t *lookup_scope = NULL; + + if (next_if(T_COLONCOLON)) + lookup_scope = &unit->scope; + + entity_t *entity; + while (true) { + if (token.type != T_IDENTIFIER) { + parse_error_expected("while parsing identifier", T_IDENTIFIER, NULL); + return create_error_entity(sym_anonymous, ENTITY_VARIABLE); + } + symbol = token.v.symbol; + pos = *HERE; + next_token(); + + /* lookup entity */ + entity = lookup_entity(lookup_scope, symbol, NAMESPACE_NORMAL); + + if (!next_if(T_COLONCOLON)) + break; + + switch (entity->kind) { + case ENTITY_NAMESPACE: + lookup_scope = &entity->namespacee.members; + break; + case ENTITY_STRUCT: + case ENTITY_UNION: + case ENTITY_CLASS: + lookup_scope = &entity->compound.members; + break; + default: + errorf(&pos, "'%Y' must be a namespace, class, struct or union (but is a %s)", + symbol, get_entity_kind_name(entity->kind)); + goto end_error; + } + } if (entity == NULL) { - if (!strict_mode && look_ahead(1)->type == '(') { + if (!strict_mode && token.type == '(') { /* an implicitly declared function */ if (warning.error_implicit_function_declaration) { - errorf(HERE, "implicit declaration of function '%Y'", symbol); + errorf(&pos, "implicit declaration of function '%Y'", symbol); } else if (warning.implicit_function_declaration) { - warningf(HERE, "implicit declaration of function '%Y'", symbol); + warningf(&pos, "implicit declaration of function '%Y'", symbol); } - entity = create_implicit_function(symbol, HERE); + entity = create_implicit_function(symbol, &pos); } else { - errorf(HERE, "unknown identifier '%Y' found.", symbol); + errorf(&pos, "unknown identifier '%Y' found.", symbol); entity = create_error_entity(symbol, ENTITY_VARIABLE); } } - type_t *orig_type; + return entity; + +end_error: + /* skip further qualifications */ + while (next_if(T_IDENTIFIER) && next_if(T_COLONCOLON)) {} + + return create_error_entity(sym_anonymous, ENTITY_VARIABLE); +} + +static expression_t *parse_reference(void) +{ + entity_t *entity = parse_qualified_identifier(); + type_t *orig_type; if (is_declaration(entity)) { orig_type = entity->declaration.type; } else if (entity->kind == ENTITY_ENUM_VALUE) { @@ -6454,8 +6322,9 @@ static expression_t *parse_reference(void) } if (entity->base.parent_scope != file_scope - && (current_function != NULL && entity->base.parent_scope->depth < current_function->parameters.depth) - && is_type_valid(orig_type) && !is_type_function(orig_type)) { + && (current_function != NULL + && entity->base.parent_scope->depth < current_function->parameters.depth) + && (entity->kind == ENTITY_VARIABLE || entity->kind == ENTITY_PARAMETER)) { if (entity->kind == ENTITY_VARIABLE) { /* access of a variable from an outer function */ entity->variable.address_taken = true; @@ -6474,7 +6343,6 @@ static expression_t *parse_reference(void) entity->declaration.type, entity->base.symbol); } - next_token(); return expression; } @@ -6721,8 +6589,7 @@ static designator_t *parse_designator(void) designator_t *last_designator = result; while (true) { - if (token.type == '.') { - next_token(); + if (next_if('.')) { if (token.type != T_IDENTIFIER) { parse_error_expected("while parsing member designator", T_IDENTIFIER, NULL); @@ -6737,8 +6604,7 @@ static designator_t *parse_designator(void) last_designator = designator; continue; } - if (token.type == '[') { - next_token(); + if (next_if('[')) { add_anchor_token(']'); designator_t *designator = allocate_ast_zero(sizeof(result[0])); designator->source_position = *HERE; @@ -6819,9 +6685,12 @@ static expression_t *parse_va_start(void) expression_t *const expr = parse_assignment_expression(); if (expr->kind == EXPR_REFERENCE) { entity_t *const entity = expr->reference.entity; - if (entity->base.parent_scope != ¤t_function->parameters - || entity->base.next != NULL - || entity->kind != ENTITY_PARAMETER) { + if (!current_function->base.type->function.variadic) { + errorf(&expr->base.source_position, + "'va_start' used in non-variadic function"); + } else if (entity->base.parent_scope != ¤t_function->parameters || + entity->base.next != NULL || + entity->kind != ENTITY_PARAMETER) { errorf(&expr->base.source_position, "second argument of 'va_start' must be last parameter of the current function"); } else { @@ -6991,31 +6860,6 @@ end_error: return create_invalid_expression(); } -#if 0 -/** - * Parses a __builtin_expect(, end_error) expression. - */ -static expression_t *parse_builtin_expect(void, end_error) -{ - expression_t *expression - = allocate_expression_zero(EXPR_BINARY_BUILTIN_EXPECT); - - eat(T___builtin_expect); - - expect('(', end_error); - expression->binary.left = parse_assignment_expression(); - expect(',', end_error); - expression->binary.right = parse_constant_expression(); - expect(')', end_error); - - expression->base.type = expression->binary.left->base.type; - - return expression; -end_error: - return create_invalid_expression(); -} -#endif - /** * Parses a MS assume() expression. */ @@ -7123,14 +6967,9 @@ static expression_t *parse_noop_expression(void) add_anchor_token(')'); add_anchor_token(','); - if (token.type != ')') { - while (true) { - (void)parse_assignment_expression(); - if (token.type != ',') - break; - next_token(); - } - } + if (token.type != ')') do { + (void)parse_assignment_expression(); + } while (next_if(',')); } rem_anchor_token(','); rem_anchor_token(')'); @@ -7181,6 +7020,8 @@ static expression_t *parse_primary_expression(void) case T___noop: return parse_noop_expression(); /* Gracefully handle type names while parsing expressions. */ + case T_COLONCOLON: + return parse_reference(); case T_IDENTIFIER: if (!is_typedef_symbol(token.v.symbol)) { return parse_reference(); @@ -7528,17 +7369,13 @@ static expression_t *parse_call_expression(expression_t *expression) if (token.type != ')') { call_argument_t **anchor = &call->arguments; - for (;;) { + do { call_argument_t *argument = allocate_ast_zero(sizeof(*argument)); argument->expression = parse_assignment_expression(); *anchor = argument; anchor = &argument->next; - - if (token.type != ',') - break; - next_token(); - } + } while (next_if(',')); } rem_anchor_token(','); rem_anchor_token(')'); @@ -7854,8 +7691,7 @@ static expression_t *parse_delete(void) eat(T_delete); - if (token.type == '[') { - next_token(); + if (next_if('[')) { result->kind = EXPR_UNARY_DELETE_ARRAY; expect(']', end_error); end_error:; @@ -7963,14 +7799,14 @@ static bool is_lvalue(const expression_t *expression) return true; default: { - type_t *type = skip_typeref(expression->base.type); - return - /* ISO/IEC 14882:1998(E) §3.10:3 */ - is_type_reference(type) || - /* Claim it is an lvalue, if the type is invalid. There was a parse - * error before, which maybe prevented properly recognizing it as - * lvalue. */ - !is_type_valid(type); + type_t *type = skip_typeref(expression->base.type); + return + /* ISO/IEC 14882:1998(E) §3.10:3 */ + is_type_reference(type) || + /* Claim it is an lvalue, if the type is invalid. There was a parse + * error before, which maybe prevented properly recognizing it as + * lvalue. */ + !is_type_valid(type); } } } @@ -9132,8 +8968,7 @@ static asm_argument_t *parse_asm_arguments(bool is_out) asm_argument_t *argument = allocate_ast_zero(sizeof(argument[0])); memset(argument, 0, sizeof(argument[0])); - if (token.type == '[') { - eat('['); + if (next_if('[')) { if (token.type != T_IDENTIFIER) { parse_error_expected("while parsing asm argument", T_IDENTIFIER, NULL); @@ -9212,9 +9047,8 @@ static asm_argument_t *parse_asm_arguments(bool is_out) *anchor = argument; anchor = &argument->next; - if (token.type != ',') + if (!next_if(',')) break; - eat(','); } return result; @@ -9227,23 +9061,18 @@ end_error: */ static asm_clobber_t *parse_asm_clobbers(void) { - asm_clobber_t *result = NULL; - asm_clobber_t *last = NULL; + asm_clobber_t *result = NULL; + asm_clobber_t **anchor = &result; while (token.type == T_STRING_LITERAL) { asm_clobber_t *clobber = allocate_ast_zero(sizeof(clobber[0])); clobber->clobber = parse_string_literals(); - if (last != NULL) { - last->next = clobber; - } else { - result = clobber; - } - last = clobber; + *anchor = clobber; + anchor = &clobber->next; - if (token.type != ',') + if (!next_if(',')) break; - eat(','); } return result; @@ -9259,36 +9088,31 @@ static statement_t *parse_asm_statement(void) eat(T_asm); - if (token.type == T_volatile) { - next_token(); + if (next_if(T_volatile)) asm_statement->is_volatile = true; - } expect('(', end_error); add_anchor_token(')'); add_anchor_token(':'); asm_statement->asm_text = parse_string_literals(); - if (token.type != ':') { + if (!next_if(':')) { rem_anchor_token(':'); goto end_of_asm; } - eat(':'); asm_statement->outputs = parse_asm_arguments(true); - if (token.type != ':') { + if (!next_if(':')) { rem_anchor_token(':'); goto end_of_asm; } - eat(':'); asm_statement->inputs = parse_asm_arguments(false); - if (token.type != ':') { + if (!next_if(':')) { rem_anchor_token(':'); goto end_of_asm; } rem_anchor_token(':'); - eat(':'); asm_statement->clobbers = parse_asm_clobbers(); @@ -9335,8 +9159,7 @@ static statement_t *parse_case_statement(void) } if (GNU_MODE) { - if (token.type == T_DOTDOTDOT) { - next_token(); + if (next_if(T_DOTDOTDOT)) { expression_t *const end_range = parse_expression(); statement->case_label.end_range = end_range; if (!is_constant_expression(end_range)) { @@ -9539,8 +9362,7 @@ end_error: statement->ifs.true_statement = true_stmt; rem_anchor_token(T_else); - if (token.type == T_else) { - next_token(); + if (next_if(T_else)) { statement->ifs.false_statement = parse_statement(); } else if (warning.parentheses && true_stmt->kind == STATEMENT_IF && @@ -9743,13 +9565,11 @@ static statement_t *parse_for(void) scope_t *old_scope = scope_push(&statement->fors.scope); bool old_gcc_extension = in_gcc_extension; - while (token.type == T___extension__) { - next_token(); + while (next_if(T___extension__)) { in_gcc_extension = true; } - if (token.type == ';') { - next_token(); + if (next_if(';')) { } else if (is_declaration_specifier(&token, false)) { parse_declaration(record_entity, DECL_FLAGS_NONE); } else { @@ -9817,8 +9637,7 @@ static statement_t *parse_goto(void) statement_t *statement = allocate_statement_zero(STATEMENT_GOTO); eat(T_goto); - if (GNU_MODE && token.type == '*') { - next_token(); + if (GNU_MODE && next_if('*')) { expression_t *expression = parse_expression(); mark_vars_read(expression, NULL); @@ -10101,8 +9920,7 @@ static statement_t *parse_ms_try_statment(void) POP_PARENT; - if (token.type == T___except) { - eat(T___except); + if (next_if(T___except)) { expect('(', end_error); add_anchor_token(')'); expression_t *const expr = parse_expression(); @@ -10119,8 +9937,7 @@ static statement_t *parse_ms_try_statment(void) rem_anchor_token(')'); expect(')', end_error); statement->ms_try.final_statement = parse_compound_statement(false); - } else if (token.type == T__finally) { - eat(T___finally); + } else if (next_if(T__finally)) { statement->ms_try.final_statement = parse_compound_statement(false); } else { parse_error_expected("while parsing __try statement", T___except, T___finally, NULL); @@ -10149,7 +9966,7 @@ static statement_t *parse_local_label_declaration(void) entity_t *begin = NULL, *end = NULL; - while (true) { + do { if (token.type != T_IDENTIFIER) { parse_error_expected("while parsing local label declaration", T_IDENTIFIER, NULL); @@ -10177,11 +9994,7 @@ static statement_t *parse_local_label_declaration(void) environment_push(entity); } next_token(); - - if (token.type != ',') - break; - next_token(); - } + } while (next_if(',')); eat(';'); end_error: statement->declaration.declarations_begin = begin; @@ -10201,9 +10014,9 @@ static void parse_namespace_definition(void) next_token(); entity = get_entity(symbol, NAMESPACE_NORMAL); - if (entity != NULL && - entity->kind != ENTITY_NAMESPACE && - entity->base.parent_scope == current_scope) { + if (entity != NULL + && entity->kind != ENTITY_NAMESPACE + && entity->base.parent_scope == current_scope) { if (!is_error_entity(entity)) { error_redefined_as_different_kind(&token.source_position, entity, ENTITY_NAMESPACE); @@ -10231,12 +10044,17 @@ static void parse_namespace_definition(void) size_t const top = environment_top(); scope_t *old_scope = scope_push(&entity->namespacee.members); + entity_t *old_current_entity = current_entity; + current_entity = entity; + expect('{', end_error); parse_externals(); expect('}', end_error); end_error: assert(current_scope == &entity->namespacee.members); + assert(current_entity == entity); + current_entity = old_current_entity; scope_pop(old_scope); environment_pop_to(top); } @@ -10288,9 +10106,7 @@ expression_statment: case T___extension__: /* This can be a prefix to a declaration or an expression statement. * We simply eat it now and parse the rest with tail recursion. */ - do { - next_token(); - } while (token.type == T___extension__); + while (next_if(T___extension__)) {} bool old_gcc_extension = in_gcc_extension; in_gcc_extension = true; statement = intern_parse_statement(); @@ -10687,8 +10503,7 @@ static void parse_linkage_specification(void) } current_linkage = new_linkage; - if (token.type == '{') { - next_token(); + if (next_if('{')) { parse_externals(); expect('}', end_error); } else { @@ -10817,8 +10632,7 @@ void start_parsing(void) error_count = 0; warning_count = 0; - type_set_output(stderr); - ast_set_output(stderr); + print_to_file(stderr); assert(unit == NULL); unit = allocate_ast_zero(sizeof(unit[0])); @@ -10925,104 +10739,6 @@ void parse(void) incomplete_arrays = NULL; } -/** - * create a builtin function. - */ -static entity_t *create_builtin_function(builtin_kind_t kind, const char *name, type_t *function_type) -{ - symbol_t *symbol = symbol_table_insert(name); - entity_t *entity = allocate_entity_zero(ENTITY_FUNCTION); - entity->declaration.storage_class = STORAGE_CLASS_EXTERN; - entity->declaration.declared_storage_class = STORAGE_CLASS_EXTERN; - entity->declaration.type = function_type; - entity->declaration.implicit = true; - entity->base.symbol = symbol; - entity->base.source_position = builtin_source_position; - - entity->function.btk = kind; - - record_entity(entity, /*is_definition=*/false); - return entity; -} - - -/** - * Create predefined gnu builtins. - */ -static void create_gnu_builtins(void) -{ -#define GNU_BUILTIN(a, b) create_builtin_function(bk_gnu_builtin_##a, "__builtin_" #a, b) - - GNU_BUILTIN(alloca, make_function_1_type(type_void_ptr, type_size_t)); - GNU_BUILTIN(huge_val, make_function_0_type(type_double)); - GNU_BUILTIN(inf, make_function_0_type(type_double)); - GNU_BUILTIN(inff, make_function_0_type(type_float)); - GNU_BUILTIN(infl, make_function_0_type(type_long_double)); - GNU_BUILTIN(nan, make_function_1_type(type_double, type_char_ptr)); - GNU_BUILTIN(nanf, make_function_1_type(type_float, type_char_ptr)); - GNU_BUILTIN(nanl, make_function_1_type(type_long_double, type_char_ptr)); - GNU_BUILTIN(va_end, make_function_1_type(type_void, type_valist)); - GNU_BUILTIN(expect, make_function_2_type(type_long, type_long, type_long)); - GNU_BUILTIN(return_address, make_function_1_type(type_void_ptr, type_unsigned_int)); - GNU_BUILTIN(frame_address, make_function_1_type(type_void_ptr, type_unsigned_int)); - GNU_BUILTIN(ffs, make_function_1_type(type_int, type_unsigned_int)); - GNU_BUILTIN(clz, make_function_1_type(type_int, type_unsigned_int)); - GNU_BUILTIN(ctz, make_function_1_type(type_int, type_unsigned_int)); - GNU_BUILTIN(popcount, make_function_1_type(type_int, type_unsigned_int)); - GNU_BUILTIN(parity, make_function_1_type(type_int, type_unsigned_int)); - GNU_BUILTIN(prefetch, make_function_1_type_variadic(type_float, type_void_ptr)); - GNU_BUILTIN(trap, make_function_0_type_noreturn(type_void)); - -#undef GNU_BUILTIN -} - -/** - * Create predefined MS intrinsics. - */ -static void create_microsoft_intrinsics(void) -{ -#define MS_BUILTIN(a, b) create_builtin_function(bk_ms##a, #a, b) - - /* intrinsics for all architectures */ - MS_BUILTIN(_rotl, make_function_2_type(type_unsigned_int, type_unsigned_int, type_int)); - MS_BUILTIN(_rotr, make_function_2_type(type_unsigned_int, type_unsigned_int, type_int)); - MS_BUILTIN(_rotl64, make_function_2_type(type_unsigned_int64, type_unsigned_int64, type_int)); - MS_BUILTIN(_rotr64, make_function_2_type(type_unsigned_int64, type_unsigned_int64, type_int)); - MS_BUILTIN(_byteswap_ushort, make_function_1_type(type_unsigned_short, type_unsigned_short)); - MS_BUILTIN(_byteswap_ulong, make_function_1_type(type_unsigned_long, type_unsigned_long)); - MS_BUILTIN(_byteswap_uint64, make_function_1_type(type_unsigned_int64, type_unsigned_int64)); - - MS_BUILTIN(__debugbreak, make_function_0_type(type_void)); - MS_BUILTIN(_ReturnAddress, make_function_0_type(type_void_ptr)); - MS_BUILTIN(_AddressOfReturnAddress, make_function_0_type(type_void_ptr)); - MS_BUILTIN(__popcount, make_function_1_type(type_unsigned_int, type_unsigned_int)); - - /* x86/x64 only */ - MS_BUILTIN(_enable, make_function_0_type(type_void)); - MS_BUILTIN(_disable, make_function_0_type(type_void)); - MS_BUILTIN(__inbyte, make_function_1_type(type_unsigned_char, type_unsigned_short)); - MS_BUILTIN(__inword, make_function_1_type(type_unsigned_short, type_unsigned_short)); - MS_BUILTIN(__indword, make_function_1_type(type_unsigned_long, type_unsigned_short)); - MS_BUILTIN(__outbyte, make_function_2_type(type_void, type_unsigned_short, type_unsigned_char)); - MS_BUILTIN(__outword, make_function_2_type(type_void, type_unsigned_short, type_unsigned_short)); - MS_BUILTIN(__outdword, make_function_2_type(type_void, type_unsigned_short, type_unsigned_long)); - MS_BUILTIN(__ud2, make_function_0_type_noreturn(type_void)); - MS_BUILTIN(_BitScanForward, make_function_2_type(type_unsigned_char, type_unsigned_long_ptr, type_unsigned_long)); - MS_BUILTIN(_BitScanReverse, make_function_2_type(type_unsigned_char, type_unsigned_long_ptr, type_unsigned_long)); - MS_BUILTIN(_InterlockedExchange, make_function_2_type(type_long, type_long_ptr, type_long)); - MS_BUILTIN(_InterlockedExchange64, make_function_2_type(type_int64, type_int64_ptr, type_int64)); - - if (machine_size <= 32) { - MS_BUILTIN(__readeflags, make_function_0_type(type_unsigned_int)); - MS_BUILTIN(__writeeflags, make_function_1_type(type_void, type_unsigned_int)); - } else { - MS_BUILTIN(__readeflags, make_function_0_type(type_unsigned_int64)); - MS_BUILTIN(__writeeflags, make_function_1_type(type_void, type_unsigned_int64)); - } - -#undef MS_BUILTIN -} - /** * Initialize the parser. */