X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=parser.c;h=fd17b0a74069ce49af2c3dee6bebc067780a8c93;hb=6929ad2bb7092e642261858a1ff5a709597f46c0;hp=5aef89d1b8f3ba9b09e82c61494194113bc93093;hpb=0ed4fc7c3c09aeef9892fcd94508547484f0e4d1;p=cparser diff --git a/parser.c b/parser.c index 5aef89d..fd17b0a 100644 --- a/parser.c +++ b/parser.c @@ -105,8 +105,11 @@ typedef struct parse_initializer_env_t { typedef declaration_t* (*parsed_declaration_func) (declaration_t *declaration, bool is_definition); +/** The current token. */ static token_t token; +/** The lookahead ring-buffer. */ static token_t lookahead_buffer[MAX_LOOKAHEAD]; +/** Position of the next token in the lookahead buffer. */ static int lookahead_bufpos; static stack_entry_t *environment_stack = NULL; static stack_entry_t *label_stack = NULL; @@ -124,9 +127,15 @@ static goto_statement_t *goto_first = NULL; static goto_statement_t *goto_last = NULL; static label_statement_t *label_first = NULL; static label_statement_t *label_last = NULL; +/** current translation unit. */ static translation_unit_t *unit = NULL; +/** 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. */ +static bool in_gcc_extension = false; static struct obstack temp_obst; + #define PUSH_PARENT(stmt) \ statement_t *const prev_parent = current_parent; \ current_parent = (stmt); @@ -163,6 +172,9 @@ static unsigned char token_anchor_set[T_LAST_TOKEN]; /** The current source position. */ #define HERE (&token.source_position) +/** true if we are in GCC mode. */ +#define GNU_MODE ((c_mode & _GNUC) || in_gcc_extension) + static type_t *type_valist; static statement_t *parse_compound_statement(bool inside_expression_statement); @@ -643,16 +655,6 @@ static void eat_block(void) next_token(); } -/** - * eat all token until a ';' is reached or a stop token is found. - */ -static void eat_statement(void) -{ - eat_until_matching_token(';'); - if (token.type == ';') - next_token(); -} - #define eat(token_type) do { assert(token.type == token_type); next_token(); } while (0) /** @@ -2863,16 +2865,16 @@ static type_t *parse_typeof(void) expression_t *expression = NULL; -restart: - switch(token.type) { - case T___extension__: - /* This can be a prefix to a typename or an expression. We simply eat - * it now. */ - do { - next_token(); - } while (token.type == T___extension__); - goto restart; + bool old_type_prop = in_type_prop; + bool old_gcc_extension = in_gcc_extension; + in_type_prop = true; + while (token.type == T___extension__) { + /* This can be a prefix to a typename or an expression. */ + next_token(); + in_gcc_extension = true; + } + switch (token.type) { case T_IDENTIFIER: if (is_typedef_symbol(token.v.symbol)) { type = parse_typename(); @@ -2891,6 +2893,8 @@ restart: type = expression->base.type; break; } + in_type_prop = old_type_prop; + in_gcc_extension = old_gcc_extension; rem_anchor_token(')'); expect(')'); @@ -2963,7 +2967,7 @@ static bool check_alignment_value(long long intvalue) return false; } unsigned v = (unsigned)intvalue; - for(unsigned i = 1; i <= 8192; i += i) { + for (unsigned i = 1; i <= 8192; i += i) { if (i == v) return true; } @@ -3034,7 +3038,7 @@ static void parse_microsoft_extended_decl_modifier(declaration_specifiers_t *spe } else if (symbol == sym_property) { next_token(); expect('('); - for(;;) { + for (;;) { bool is_get = false; if (token.type != T_IDENTIFIER) goto end_error; @@ -3224,12 +3228,13 @@ static void finish_union_type(compound_type_t *type) { static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) { - type_t *type = NULL; - type_qualifiers_t qualifiers = TYPE_QUALIFIER_NONE; - type_modifiers_t modifiers = TYPE_MODIFIER_NONE; - unsigned type_specifiers = 0; - bool newtype = false; - bool saw_error = false; + type_t *type = NULL; + type_qualifiers_t qualifiers = TYPE_QUALIFIER_NONE; + type_modifiers_t modifiers = TYPE_MODIFIER_NONE; + unsigned type_specifiers = 0; + bool newtype = false; + bool saw_error = false; + bool old_gcc_extension = in_gcc_extension; specifiers->source_position = token.source_position; @@ -3239,7 +3244,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) if (specifiers->modifiers & DM_TRANSPARENT_UNION) modifiers |= TYPE_MODIFIER_TRANSPARENT_UNION; - switch(token.type) { + switch (token.type) { /* storage class */ #define MATCH_STORAGE_CLASS(token, class) \ @@ -3304,8 +3309,8 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) MATCH_TYPE_QUALIFIER(T___sptr, TYPE_QUALIFIER_SPTR); case T___extension__: - /* TODO */ next_token(); + in_gcc_extension = true; break; /* type specifiers */ @@ -3450,6 +3455,8 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) } finish_specifiers: + in_gcc_extension = old_gcc_extension; + if (type == NULL || (saw_error && type_specifiers != 0)) { atomic_type_kind_t atomic_type; @@ -4054,13 +4061,7 @@ static construct_type_t *parse_inner_declarator(declaration_t *declaration, if (may_be_abstract) break; parse_error_expected("while parsing declarator", T_IDENTIFIER, '(', NULL); - /* avoid a loop in the outermost scope, because eat_statement doesn't - * eat '}' */ - if (token.type == '}' && current_function == NULL) { - next_token(); - } else { - eat_statement(); - } + eat_until_anchor(); return NULL; } @@ -4378,7 +4379,7 @@ static declaration_t *record_declaration( previous_declaration == NULL) { warningf(&declaration->source_position, "function declaration '%#T' is not a prototype", - orig_type, declaration->symbol); + orig_type, symbol); } if (warning.main && is_type_function(type) && is_sym_main(symbol)) { @@ -4546,7 +4547,7 @@ static void parser_error_multiple_definition(declaration_t *declaration, static bool is_declaration_specifier(const token_t *token, bool only_specifiers_qualifiers) { - switch(token->type) { + switch (token->type) { TYPE_SPECIFIERS TYPE_QUALIFIERS return true; @@ -4609,24 +4610,17 @@ static void parse_anonymous_declaration_rest( { eat(';'); - declaration_t *const declaration = allocate_declaration_zero(); - declaration->type = specifiers->type; - declaration->declared_storage_class = specifiers->declared_storage_class; - declaration->source_position = specifiers->source_position; - declaration->modifiers = specifiers->modifiers; - - if (declaration->declared_storage_class != STORAGE_CLASS_NONE) { - warningf(&declaration->source_position, + if (specifiers->declared_storage_class != STORAGE_CLASS_NONE) { + warningf(&specifiers->source_position, "useless storage class in empty declaration"); } - declaration->storage_class = STORAGE_CLASS_NONE; - type_t *type = declaration->type; + type_t *type = specifiers->type; switch (type->kind) { case TYPE_COMPOUND_STRUCT: case TYPE_COMPOUND_UNION: { if (type->compound.declaration->symbol == NULL) { - warningf(&declaration->source_position, + warningf(&specifiers->source_position, "unnamed struct/union that defines no instances"); } break; @@ -4636,11 +4630,20 @@ static void parse_anonymous_declaration_rest( break; default: - warningf(&declaration->source_position, "empty declaration"); + warningf(&specifiers->source_position, "empty declaration"); break; } +#ifdef RECORD_EMPTY_DECLARATIONS + declaration_t *const declaration = allocate_declaration_zero(); + declaration->type = specifiers->type; + declaration->declared_storage_class = specifiers->declared_storage_class; + declaration->source_position = specifiers->source_position; + declaration->modifiers = specifiers->modifiers; + declaration->storage_class = STORAGE_CLASS_NONE; + append_declaration(declaration); +#endif } static void parse_declaration_rest(declaration_t *ndeclaration, @@ -4648,7 +4651,6 @@ static void parse_declaration_rest(declaration_t *ndeclaration, parsed_declaration_func finished_declaration) { add_anchor_token(';'); - add_anchor_token('='); add_anchor_token(','); while(true) { declaration_t *declaration = @@ -4672,13 +4674,14 @@ static void parse_declaration_rest(declaration_t *ndeclaration, break; eat(','); + add_anchor_token('='); ndeclaration = parse_declarator(specifiers, /*may_be_abstract=*/false); + rem_anchor_token('='); } expect(';'); end_error: rem_anchor_token(';'); - rem_anchor_token('='); rem_anchor_token(','); } @@ -4721,7 +4724,10 @@ static void parse_declaration(parsed_declaration_func finished_declaration) { declaration_specifiers_t specifiers; memset(&specifiers, 0, sizeof(specifiers)); + + add_anchor_token(';'); parse_declaration_specifiers(&specifiers); + rem_anchor_token(';'); if (token.type == ';') { parse_anonymous_declaration_rest(&specifiers); @@ -5829,8 +5835,7 @@ static expression_t *parse_character_constant(void) cnst->conste.v.character = token.v.string; if (cnst->conste.v.character.size != 1) { - if (warning.multichar && (c_mode & _GNUC)) { - /* TODO */ + if (warning.multichar && GNU_MODE) { warningf(HERE, "multi-character character constant"); } else { errorf(HERE, "more than 1 characters in character constant"); @@ -5853,8 +5858,7 @@ static expression_t *parse_wide_character_constant(void) cnst->conste.v.wide_character = token.v.wide_string; if (cnst->conste.v.wide_character.size != 1) { - if (warning.multichar && (c_mode & _GNUC)) { - /* TODO */ + if (warning.multichar && GNU_MODE) { warningf(HERE, "multi-character character constant"); } else { errorf(HERE, "more than 1 characters in character constant"); @@ -6129,7 +6133,7 @@ static expression_t *parse_reference(void) declaration->symbol, &declaration->source_position); } } - if (warning.init_self && declaration == current_init_decl) { + if (warning.init_self && declaration == current_init_decl && !in_type_prop) { current_init_decl = NULL; warningf(HERE, "variable '%#T' is initialized by itself", declaration->type, declaration->symbol); @@ -6825,7 +6829,7 @@ static expression_t *parse_primary_expression(void) case T___builtin_prefetch: return parse_builtin_prefetch(); case T__assume: return parse_assume(); case T_ANDAND: - if (c_mode & _GNUC) + if (GNU_MODE) return parse_label_address(); break; @@ -6916,10 +6920,9 @@ static expression_t *parse_typeprop(expression_kind_t const kind, char const* const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof"; - /* we only refer to a type property, not the value, so do not warn - * when using current_init_decl */ - declaration_t *old = current_init_decl; - current_init_decl = NULL; + /* we only refer to a type property, mark this case */ + bool old = in_type_prop; + in_type_prop = true; if (token.type == '(' && is_declaration_specifier(look_ahead(1), true)) { next_token(); add_anchor_token(')'); @@ -6960,7 +6963,7 @@ static expression_t *parse_typeprop(expression_kind_t const kind, } end_error: - current_init_decl = old; + in_type_prop = old; return tp_expression; } @@ -7258,7 +7261,7 @@ static expression_t *parse_conditional_expression(unsigned precedence, expression_t *true_expression = expression; bool gnu_cond = false; - if ((c_mode & _GNUC) && token.type == ':') { + if (GNU_MODE && token.type == ':') { gnu_cond = true; } else true_expression = parse_expression(); @@ -7369,9 +7372,10 @@ static expression_t *parse_extension(unsigned precedence) { eat(T___extension__); - /* TODO enable extensions */ + bool old_gcc_extension = in_gcc_extension; + in_gcc_extension = true; expression_t *expression = parse_sub_expression(precedence); - /* TODO disable extensions */ + in_gcc_extension = old_gcc_extension; return expression; } @@ -7405,7 +7409,7 @@ static bool check_pointer_arithmetic(const source_position_t *source_position, points_to = skip_typeref(points_to); if (is_type_incomplete(points_to)) { - if (!(c_mode & _GNUC) || !is_type_atomic(points_to, ATOMIC_TYPE_VOID)) { + if (!GNU_MODE || !is_type_atomic(points_to, ATOMIC_TYPE_VOID)) { errorf(source_position, "arithmetic with pointer to incomplete type '%T' not allowed", orig_pointer_type); @@ -7416,7 +7420,7 @@ static bool check_pointer_arithmetic(const source_position_t *source_position, orig_pointer_type); } } else if (is_type_function(points_to)) { - if (!(c_mode && _GNUC)) { + if (!GNU_MODE) { errorf(source_position, "arithmetic with pointer to function type '%T' not allowed", orig_pointer_type); @@ -8675,7 +8679,7 @@ static statement_t *parse_case_statement(void) statement->case_label.last_case = val; } - if (c_mode & _GNUC) { + if (GNU_MODE) { if (token.type == T_DOTDOTDOT) { next_token(); expression_t *const end_range = parse_expression(); @@ -9132,7 +9136,7 @@ static statement_t *parse_goto(void) eat(T_goto); statement_t *statement; - if (c_mode & _GNUC && token.type == '*') { + if (GNU_MODE && token.type == '*') { next_token(); expression_t *expression = parse_expression(); @@ -9155,11 +9159,11 @@ static statement_t *parse_goto(void) statement->gotos.expression = expression; } else { if (token.type != T_IDENTIFIER) { - if (c_mode & _GNUC) + if (GNU_MODE) parse_error_expected("while parsing goto", T_IDENTIFIER, '*', NULL); else parse_error_expected("while parsing goto", T_IDENTIFIER, NULL); - eat_statement(); + eat_until_anchor(); goto end_error; } symbol_t *symbol = token.v.symbol; @@ -9367,7 +9371,10 @@ static statement_t *parse_declaration_statement(void) statement->base.source_position = token.source_position; declaration_t *before = last_declaration; - parse_declaration(record_declaration); + if (GNU_MODE) + parse_external_declaration(); + else + parse_declaration(record_declaration); if (before == NULL) { statement->declaration.declarations_begin = scope->declarations; @@ -9545,7 +9552,10 @@ expression_statment: do { next_token(); } while (token.type == T___extension__); + bool old_gcc_extension = in_gcc_extension; + in_gcc_extension = true; statement = parse_statement(); + in_gcc_extension = false; break; DECLARATION_START @@ -9823,13 +9833,18 @@ static void parse_translation_unit(void) for (;;) { #ifndef NDEBUG bool anchor_leak = false; - for (token_type_t i = 0; i != T_LAST_TOKEN; ++i) { + for (int i = 0; i != T_LAST_TOKEN; ++i) { unsigned char count = token_anchor_set[i]; if (count != 0) { errorf(HERE, "Leaked anchor token %k %d times", i, count); anchor_leak = true; } } + if (in_gcc_extension) { + errorf(HERE, "Leaked __extension__"); + anchor_leak = true; + } + if (anchor_leak) abort(); #endif