X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=parser.c;h=f42ad8e4f2fddb57b397280988670e46b1dce931;hb=0c1c8650276b582c47dad917668dc0d3612b1427;hp=f1adb8ee5f68bd17140f9b284cba76aa82ed8b2f;hpb=c1c1d9984582dc6c6118e274ce0dba5f3f2b8101;p=cparser diff --git a/parser.c b/parser.c index f1adb8e..f42ad8e 100644 --- a/parser.c +++ b/parser.c @@ -526,14 +526,14 @@ static void eat_until_matching_token(int type) { unsigned parenthesis_count = 0; unsigned brace_count = 0; unsigned bracket_count = 0; - int end_token = type; - if (type == '(') - end_token = ')'; - else if (type == '{') - end_token = '}'; - else if (type == '[') - end_token = ']'; + int end_token; + switch (type) { + case '(': end_token = ')'; break; + case '{': end_token = '}'; break; + case '[': end_token = ']'; break; + default: end_token = type; break; + } while(token.type != end_token || (parenthesis_count > 0 || brace_count > 0 || bracket_count > 0)) { @@ -1293,13 +1293,16 @@ static void parse_gnu_attribute_mode_arg(gnu_attribute_t *attribute) /* This isn't really correct, the backend should provide a list of machine * specific modes (according to gcc philosophy that is...) */ const char *symbol_str = token.v.symbol->string; - if(strcmp_underscore("QI", symbol_str) == 0) { + if (strcmp_underscore("QI", symbol_str) == 0 || + strcmp_underscore("byte", symbol_str) == 0) { attribute->u.akind = ATOMIC_TYPE_CHAR; } else if (strcmp_underscore("HI", symbol_str) == 0) { attribute->u.akind = ATOMIC_TYPE_SHORT; - } else if(strcmp_underscore("SI", symbol_str) == 0) { + } else if (strcmp_underscore("SI", symbol_str) == 0 + || strcmp_underscore("word", symbol_str) == 0 + || strcmp_underscore("pointer", symbol_str) == 0) { attribute->u.akind = ATOMIC_TYPE_INT; - } else if(strcmp_underscore("DI", symbol_str) == 0) { + } else if (strcmp_underscore("DI", symbol_str) == 0) { attribute->u.akind = ATOMIC_TYPE_LONGLONG; } else { warningf(HERE, "ignoring unknown mode '%s'", symbol_str); @@ -1541,9 +1544,6 @@ static decl_modifiers_t parse_gnu_attribute(gnu_attribute_t **attributes) switch(kind) { case GNU_AK_CONST: case GNU_AK_VOLATILE: - case GNU_AK_CDECL: - case GNU_AK_STDCALL: - case GNU_AK_FASTCALL: case GNU_AK_DEPRECATED: case GNU_AK_NAKED: case GNU_AK_MALLOC: @@ -1552,7 +1552,6 @@ static decl_modifiers_t parse_gnu_attribute(gnu_attribute_t **attributes) case GNU_AK_NOCOMMON: case GNU_AK_SHARED: case GNU_AK_NOTSHARED: - case GNU_AK_USED: case GNU_AK_UNUSED: case GNU_AK_NO_INSTRUMENT_FUNCTION: case GNU_AK_WARN_UNUSED_RESULT: @@ -1577,63 +1576,23 @@ static decl_modifiers_t parse_gnu_attribute(gnu_attribute_t **attributes) case GNU_AK_MAY_ALIAS: case GNU_AK_MS_STRUCT: case GNU_AK_GCC_STRUCT: - check_no_argument(attribute, name); - break; - - case GNU_AK_PURE: - check_no_argument(attribute, name); - modifiers |= DM_PURE; - break; - - case GNU_AK_ALWAYS_INLINE: - check_no_argument(attribute, name); - modifiers |= DM_FORCEINLINE; - break; - - case GNU_AK_DLLIMPORT: - check_no_argument(attribute, name); - modifiers |= DM_DLLIMPORT; - break; - - case GNU_AK_DLLEXPORT: - check_no_argument(attribute, name); - modifiers |= DM_DLLEXPORT; - break; - - case GNU_AK_PACKED: - check_no_argument(attribute, name); - modifiers |= DM_PACKED; - break; - - case GNU_AK_NOINLINE: - check_no_argument(attribute, name); - modifiers |= DM_NOINLINE; - break; - - case GNU_AK_NORETURN: - check_no_argument(attribute, name); - modifiers |= DM_NORETURN; - break; - - case GNU_AK_NOTHROW: - check_no_argument(attribute, name); - modifiers |= DM_NOTHROW; - break; - - case GNU_AK_TRANSPARENT_UNION: - check_no_argument(attribute, name); - modifiers |= DM_TRANSPARENT_UNION; - break; - - case GNU_AK_CONSTRUCTOR: - check_no_argument(attribute, name); - modifiers |= DM_CONSTRUCTOR; - break; - - case GNU_AK_DESTRUCTOR: - check_no_argument(attribute, name); - modifiers |= DM_DESTRUCTOR; - break; + goto no_arg; + + case GNU_AK_CDECL: modifiers |= DM_CDECL; goto no_arg; + case GNU_AK_FASTCALL: modifiers |= DM_FASTCALL; goto no_arg; + case GNU_AK_STDCALL: modifiers |= DM_STDCALL; goto no_arg; + case GNU_AK_USED: modifiers |= DM_USED; goto no_arg; + case GNU_AK_PURE: modifiers |= DM_PURE; goto no_arg; + case GNU_AK_ALWAYS_INLINE: modifiers |= DM_FORCEINLINE; goto no_arg; + case GNU_AK_DLLIMPORT: modifiers |= DM_DLLIMPORT; goto no_arg; + case GNU_AK_DLLEXPORT: modifiers |= DM_DLLEXPORT; goto no_arg; + case GNU_AK_PACKED: modifiers |= DM_PACKED; goto no_arg; + case GNU_AK_NOINLINE: modifiers |= DM_NOINLINE; goto no_arg; + case GNU_AK_NORETURN: modifiers |= DM_NORETURN; goto no_arg; + case GNU_AK_NOTHROW: modifiers |= DM_NOTHROW; goto no_arg; + case GNU_AK_TRANSPARENT_UNION: modifiers |= DM_TRANSPARENT_UNION; goto no_arg; + case GNU_AK_CONSTRUCTOR: modifiers |= DM_CONSTRUCTOR; goto no_arg; + case GNU_AK_DESTRUCTOR: modifiers |= DM_DESTRUCTOR; goto no_arg; case GNU_AK_ALIGNED: /* __align__ may be used without an argument */ @@ -1722,6 +1681,9 @@ static decl_modifiers_t parse_gnu_attribute(gnu_attribute_t **attributes) case GNU_AK_LAST: /* already handled */ break; + +no_arg: + check_no_argument(attribute, name); } } if (attribute != NULL) { @@ -1757,7 +1719,7 @@ static decl_modifiers_t parse_attributes(gnu_attribute_t **attributes) switch(token.type) { case T___attribute__: modifiers |= parse_gnu_attribute(attributes); - break; + continue; case T_asm: next_token(); @@ -1771,25 +1733,23 @@ static decl_modifiers_t parse_attributes(gnu_attribute_t **attributes) parse_string_literals(); } expect(')'); - break; + continue; + + case T_cdecl: modifiers |= DM_CDECL; break; + case T__fastcall: modifiers |= DM_FASTCALL; break; + case T__stdcall: modifiers |= DM_STDCALL; break; - case T_cdecl: - case T__fastcall: - case T__stdcall: case T___thiscall: /* TODO record modifier */ warningf(HERE, "Ignoring declaration modifier %K", &token); - next_token(); break; - default: - goto attributes_finished; +end_error: + default: return modifiers; } - } -attributes_finished: -end_error: - return modifiers; + next_token(); + } } static designator_t *parse_designation(void) @@ -2590,10 +2550,21 @@ static declaration_t *parse_compound_type_specifier(bool is_struct) symbol = token.v.symbol; next_token(); - if (is_struct) { - declaration = get_declaration(symbol, NAMESPACE_STRUCT); - } else { - declaration = get_declaration(symbol, NAMESPACE_UNION); + namespace_t const namespc = + is_struct ? NAMESPACE_STRUCT : NAMESPACE_UNION; + declaration = get_declaration(symbol, namespc); + if (declaration != NULL) { + if (declaration->parent_scope != scope && + (token.type == '{' || token.type == ';')) { + declaration = NULL; + } else if (declaration->init.complete && + token.type == '{') { + assert(symbol != NULL); + errorf(HERE, "multiple definitions of '%s %Y' (previous definition at %P)", + is_struct ? "struct" : "union", symbol, + &declaration->source_position); + declaration->scope.declarations = NULL; + } } } else if (token.type != '{') { if (is_struct) { @@ -2621,13 +2592,6 @@ static declaration_t *parse_compound_type_specifier(bool is_struct) } if (token.type == '{') { - if (declaration->init.complete) { - assert(symbol != NULL); - errorf(HERE, "multiple definitions of '%s %Y' (previous definition at %P)", - is_struct ? "struct" : "union", symbol, - &declaration->source_position); - declaration->scope.declarations = NULL; - } declaration->init.complete = true; parse_compound_type_entries(declaration); @@ -3019,6 +2983,11 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) specifiers->source_position = token.source_position; while(true) { + specifiers->modifiers + |= parse_attributes(&specifiers->gnu_attributes); + if (specifiers->modifiers & DM_TRANSPARENT_UNION) + modifiers |= TYPE_MODIFIER_TRANSPARENT_UNION; + switch(token.type) { /* storage class */ @@ -3160,13 +3129,6 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) next_token(); break; - case T___attribute__: - specifiers->modifiers - |= parse_attributes(&specifiers->gnu_attributes); - if (specifiers->modifiers & DM_TRANSPARENT_UNION) - modifiers |= TYPE_MODIFIER_TRANSPARENT_UNION; - break; - case T_IDENTIFIER: { /* only parse identifier if we haven't found a type yet */ if (type != NULL || type_specifiers != 0) @@ -3425,6 +3387,8 @@ static declaration_t *parse_identifier_list(void) return declarations; } +static type_t *automatic_type_conversion(type_t *orig_type); + static void semantic_parameter(declaration_t *declaration) { /* TODO: improve error messages */ @@ -3437,19 +3401,15 @@ static void semantic_parameter(declaration_t *declaration) } type_t *const orig_type = declaration->type; - type_t * type = skip_typeref(orig_type); - - /* Array as last part of a parameter type is just syntactic sugar. Turn it - * into a pointer. § 6.7.5.3 (7) */ - if (is_type_array(type)) { - type_t *const element_type = type->array.element_type; - - type = make_pointer_type(element_type, type->base.qualifiers); - - declaration->type = type; - } + /* §6.7.5.3(7): Array as last part of a parameter type is just syntactic + * sugar. Turn it into a pointer. + * §6.7.5.3(8): A declaration of a parameter as ``function returning type'' + * shall be adjusted to ``pointer to function returning type'', as in 6.3.2.1. + */ + type_t *const type = automatic_type_conversion(orig_type); + declaration->type = type; - if (is_type_incomplete(type)) { + if (is_type_incomplete(skip_typeref(type))) { errorf(HERE, "incomplete type '%T' not allowed for parameter '%Y'", orig_type, declaration->symbol); } @@ -8411,7 +8371,9 @@ static void check_unused_globals(void) return; for (const declaration_t *decl = global_scope->declarations; decl != NULL; decl = decl->next) { - if (decl->used || decl->storage_class != STORAGE_CLASS_STATIC) + if (decl->used || + decl->modifiers & DM_USED || + decl->storage_class != STORAGE_CLASS_STATIC) continue; type_t *const type = decl->type; @@ -8433,18 +8395,43 @@ static void check_unused_globals(void) } } +static void parse_global_asm(void) +{ + eat(T_asm); + expect('('); + + statement_t *statement = allocate_statement_zero(STATEMENT_ASM); + statement->base.source_position = token.source_position; + statement->asms.asm_text = parse_string_literals(); + statement->base.next = unit->global_asm; + unit->global_asm = statement; + + expect(')'); + expect(';'); + +end_error:; +} + /** * Parse a translation unit. */ static void parse_translation_unit(void) { while(token.type != T_EOF) { - if (token.type == ';') { - /* TODO error in strict mode */ - warningf(HERE, "stray ';' outside of function"); - next_token(); - } else { - parse_external_declaration(); + switch (token.type) { + case ';': + /* TODO error in strict mode */ + warningf(HERE, "stray ';' outside of function"); + next_token(); + break; + + case T_asm: + parse_global_asm(); + break; + + default: + parse_external_declaration(); + break; } } }