X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=parser.c;h=c4523d80034f1cee86be46589d7290717e28512c;hb=953a820405dfd857ff9f5e24f3b630b6103dad46;hp=f3674c1b084ec7ac6e1b3cdea4a3687ad4361cc8;hpb=75054c64100620c5b7ecac17b8fcf6dfe42e8f94;p=cparser diff --git a/parser.c b/parser.c index f3674c1..c4523d8 100644 --- a/parser.c +++ b/parser.c @@ -110,6 +110,7 @@ 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; +static stack_entry_t *local_label_stack = NULL; static scope_t *global_scope = NULL; static scope_t *scope = NULL; static declaration_t *last_declaration = NULL; @@ -133,6 +134,9 @@ static struct obstack temp_obst; static source_position_t null_position = { NULL, 0 }; +/** special symbol used for anonymous entities. */ +static const symbol_t *sym_anonymous = NULL; + /* symbols for Microsoft extended-decl-modifier */ static const symbol_t *sym_align = NULL; static const symbol_t *sym_allocate = NULL; @@ -480,13 +484,21 @@ static size_t environment_top(void) } /** - * Returns the index of the top element of the label stack. + * Returns the index of the top element of the global label stack. */ static size_t label_top(void) { return ARR_LEN(label_stack); } +/** + * Returns the index of the top element of the local label stack. + */ +static size_t local_label_top(void) +{ + return ARR_LEN(local_label_stack); +} + /** * Return the next token. */ @@ -765,6 +777,11 @@ static void stack_push(stack_entry_t **stack_ptr, declaration_t *declaration) ARR_APP1(stack_entry_t, *stack_ptr, entry); } +/** + * Push a declaration on the environment stack. + * + * @param declaration the declaration + */ static void environment_push(declaration_t *declaration) { assert(declaration->source_position.input_name != NULL); @@ -773,7 +790,7 @@ static void environment_push(declaration_t *declaration) } /** - * Push a declaration of the label stack. + * Push a declaration on the global label stack. * * @param declaration the declaration */ @@ -783,6 +800,17 @@ static void label_push(declaration_t *declaration) stack_push(&label_stack, declaration); } +/** + * Push a declaration of the local label stack. + * + * @param declaration the declaration + */ +static void local_label_push(declaration_t *declaration) +{ + assert(declaration->parent_scope != NULL); + stack_push(&local_label_stack, declaration); +} + /** * pops symbols from the environment stack until @p new_top is the top element */ @@ -833,13 +861,19 @@ static void stack_pop_to(stack_entry_t **stack_ptr, size_t new_top) ARR_SHRINKLEN(*stack_ptr, (int) new_top); } +/** + * Pop all entries from the environment stack until the new_top + * is reached. + * + * @param new_top the new stack top + */ static void environment_pop_to(size_t new_top) { stack_pop_to(&environment_stack, new_top); } /** - * Pop all entries on the label stack until the new_top + * Pop all entries from the global label stack until the new_top * is reached. * * @param new_top the new stack top @@ -849,6 +883,18 @@ static void label_pop_to(size_t new_top) stack_pop_to(&label_stack, new_top); } +/** + * Pop all entries from the local label stack until the new_top + * is reached. + * + * @param new_top the new stack top + */ +static void local_label_pop_to(size_t new_top) +{ + stack_pop_to(&local_label_stack, new_top); +} + + static int get_akind_rank(atomic_type_kind_t akind) { return (int) akind; @@ -987,7 +1033,7 @@ static void report_assign_error(assign_error_t error, type_t *orig_type_left, case ASSIGN_WARNING_POINTER_FROM_INT: warningf(source_position, - "%s makes integer '%T' from pointer '%T' without a cast", + "%s makes pointer '%T' from integer '%T' without a cast", context, orig_type_left, orig_type_right); return; @@ -2105,8 +2151,6 @@ static void descend_into_subtype(type_path_t *path) type_t *orig_top_type = path->top_type; type_t *top_type = skip_typeref(orig_top_type); - assert(is_type_compound(top_type) || is_type_array(top_type)); - type_path_entry_t *top = append_to_type_path(path); top->type = top_type; @@ -2120,11 +2164,11 @@ static void descend_into_subtype(type_path_t *path) } else { path->top_type = NULL; } - } else { - assert(is_type_array(top_type)); - + } else if (is_type_array(top_type)) { top->v.index = 0; path->top_type = top_type->array.element_type; + } else { + assert(!is_type_valid(top_type)); } } @@ -2653,7 +2697,6 @@ static declaration_t *parse_compound_type_specifier(bool is_struct) 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 != '{') { @@ -2668,18 +2711,17 @@ static declaration_t *parse_compound_type_specifier(bool is_struct) return NULL; } - if (declaration == NULL) { - declaration = allocate_declaration_zero(); - declaration->namespc = - (is_struct ? NAMESPACE_STRUCT : NAMESPACE_UNION); - declaration->source_position = token.source_position; - declaration->symbol = symbol; - declaration->parent_scope = scope; - if (symbol != NULL) { - environment_push(declaration); - } - append_declaration(declaration); + /* always create a new declaration, do NOT modify old one */ + declaration = allocate_declaration_zero(); + declaration->namespc = + (is_struct ? NAMESPACE_STRUCT : NAMESPACE_UNION); + declaration->source_position = token.source_position; + declaration->symbol = symbol; + declaration->parent_scope = scope; + if (symbol != NULL) { + environment_push(declaration); } + append_declaration(declaration); if (token.type == '{') { declaration->init.complete = true; @@ -2742,11 +2784,14 @@ end_error: ; } +/** + * Parse enum specifier and return the enum type or NULL on error. + */ static type_t *parse_enum_specifier(void) { - gnu_attribute_t *attributes = NULL; - declaration_t *declaration; - symbol_t *symbol; + gnu_attribute_t *attributes = NULL; + declaration_t *declaration = NULL; + symbol_t *symbol = NULL; eat(T_enum); if (token.type == T_IDENTIFIER) { @@ -2758,30 +2803,31 @@ static type_t *parse_enum_specifier(void) parse_error_expected("while parsing enum type specifier", T_IDENTIFIER, '{', NULL); return NULL; - } else { - declaration = NULL; - symbol = NULL; } - if (declaration == NULL) { - declaration = allocate_declaration_zero(); - declaration->namespc = NAMESPACE_ENUM; - declaration->source_position = token.source_position; - declaration->symbol = symbol; - declaration->parent_scope = scope; + if (token.type == '{' && declaration != NULL && declaration->init.complete) { + errorf(HERE, "multiple definitions of enum '%Y' (previous definition at %P)", + symbol, &declaration->source_position); } + declaration = allocate_declaration_zero(); + declaration->namespc = NAMESPACE_ENUM; + declaration->source_position = token.source_position; + declaration->symbol = symbol; + declaration->parent_scope = scope; + if (symbol != NULL) { + environment_push(declaration); + } + append_declaration(declaration); + type_t *const type = allocate_type_zero(TYPE_ENUM, &declaration->source_position); type->enumt.declaration = declaration; if (token.type == '{') { if (declaration->init.complete) { - errorf(HERE, "multiple definitions of enum %Y", symbol); - } - if (symbol != NULL) { - environment_push(declaration); + errorf(HERE, "multiple definitions of enum '%Y' (previous definition at %P)", + symbol, &declaration->source_position); } - append_declaration(declaration); declaration->init.complete = true; parse_enum_entries(type); @@ -3088,33 +3134,38 @@ static void finish_struct_type(compound_type_t *type) { if (! struct_decl->init.complete) return; - il_size_t size = 0; - il_size_t new_size; - il_alignment_t alignment = 1; - bool need_pad = false; + il_size_t size = 0; + il_size_t offset; + il_alignment_t alignment = 1; + bool need_pad = false; declaration_t *entry = struct_decl->scope.declarations; for (; entry != NULL; entry = entry->next) { if (entry->namespc != NAMESPACE_NORMAL) continue; - type_t *m_type = skip_typeref(entry->type); - il_alignment_t m_alignment = m_type->base.alignment; - - new_size = (size + m_alignment - 1) & -m_alignment; + type_t *m_type = skip_typeref(entry->type); + if (! is_type_valid(m_type)) { + /* simply ignore errors here */ + continue; + } + il_alignment_t m_alignment = m_type->base.alignment; if (m_alignment > alignment) alignment = m_alignment; - if (new_size > size) + + offset = (size + m_alignment - 1) & -m_alignment; + + if (offset > size) need_pad = true; - entry->offset = new_size; - size = new_size + m_type->base.size; + entry->offset = offset; + size = offset + m_type->base.size; } if (type->base.alignment != 0) { alignment = type->base.alignment; } - new_size = (size + alignment - 1) & -alignment; - if (new_size > size) + offset = (size + alignment - 1) & -alignment; + if (offset > size) need_pad = true; if (warning.padded && need_pad) { @@ -3127,7 +3178,7 @@ static void finish_struct_type(compound_type_t *type) { type, struct_decl->symbol); } - type->base.size = new_size; + type->base.size = offset; type->base.alignment = alignment; } @@ -3151,6 +3202,8 @@ static void finish_union_type(compound_type_t *type) { continue; type_t *m_type = skip_typeref(entry->type); + if (! is_type_valid(m_type)) + continue; entry->offset = 0; if (m_type->base.size > size) @@ -3989,8 +4042,10 @@ static construct_type_t *parse_inner_declarator(declaration_t *declaration, next_token(); add_anchor_token(')'); inner_types = parse_inner_declarator(declaration, may_be_abstract); - /* All later declarators only modify the return type, not declaration */ - declaration = NULL; + if (inner_types != NULL) { + /* All later declarators only modify the return type, not declaration */ + declaration = NULL; + } rem_anchor_token(')'); expect(')'); break; @@ -4407,8 +4462,9 @@ static declaration_t *record_declaration( if (old_storage_class == STORAGE_CLASS_EXTERN && new_storage_class == STORAGE_CLASS_EXTERN) { warn_redundant_declaration: - if (!is_definition && - warning.redundant_decls && + if (!is_definition && + warning.redundant_decls && + is_type_valid(prev_type) && strcmp(previous_declaration->source_position.input_name, "") != 0) { warningf(&declaration->source_position, "redundant declaration for '%Y' (declared %P)", @@ -4426,14 +4482,16 @@ warn_redundant_declaration: } else { goto warn_redundant_declaration; } - } else if (old_storage_class == new_storage_class) { - errorf(&declaration->source_position, - "redeclaration of '%Y' (declared %P)", - symbol, &previous_declaration->source_position); - } else { - errorf(&declaration->source_position, - "redeclaration of '%Y' with different linkage (declared %P)", - symbol, &previous_declaration->source_position); + } else if (is_type_valid(prev_type)) { + if (old_storage_class == new_storage_class) { + errorf(&declaration->source_position, + "redeclaration of '%Y' (declared %P)", + symbol, &previous_declaration->source_position); + } else { + errorf(&declaration->source_position, + "redeclaration of '%Y' with different linkage (declared %P)", + symbol, &previous_declaration->source_position); + } } } @@ -4545,24 +4603,26 @@ static void parse_anonymous_declaration_rest( { eat(';'); + if (specifiers->declared_storage_class != STORAGE_CLASS_NONE) { + warningf(&specifiers->source_position, + "useless storage class in empty declaration"); + } + +#ifdef RECORD_EMPTY_DECLARARTIONS 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; +#endif - if (declaration->declared_storage_class != STORAGE_CLASS_NONE) { - warningf(&declaration->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; @@ -4572,11 +4632,13 @@ static void parse_anonymous_declaration_rest( break; default: - warningf(&declaration->source_position, "empty declaration"); + warningf(&specifiers->source_position, "empty declaration"); break; } +#ifdef RECORD_EMPTY_DECLARARTIONS append_declaration(declaration); +#endif } static void parse_declaration_rest(declaration_t *ndeclaration, @@ -5465,12 +5527,40 @@ static void parse_external_declaration(void) } static type_t *make_bitfield_type(type_t *base_type, expression_t *size, - source_position_t *source_position) + source_position_t *source_position, + const symbol_t *symbol) { type_t *type = allocate_type_zero(TYPE_BITFIELD, source_position); - type->bitfield.base_type = base_type; - type->bitfield.size = size; + type->bitfield.base_type = base_type; + type->bitfield.size_expression = size; + + il_size_t bit_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); + bit_size = 0; + } else { + bit_size = skipped_type->base.size * 8; + } + + if (is_constant_expression(size)) { + long v = fold_constant(size); + + if (v < 0) { + errorf(source_position, "negative width in bit-field '%Y'", + symbol); + } else if (v == 0) { + errorf(source_position, "zero width for bit-field '%Y'", + symbol); + } else if (bit_size > 0 && (il_size_t)v > bit_size) { + errorf(source_position, "width of '%Y' exceeds its type", + symbol); + } else { + type->bitfield.bit_size = v; + } + } return type; } @@ -5522,12 +5612,8 @@ static void parse_compound_declarators(declaration_t *struct_declaration, type_t *base_type = specifiers->type; expression_t *size = parse_constant_expression(); - if (!is_type_integer(skip_typeref(base_type))) { - errorf(HERE, "bitfield base type '%T' is not an integer type", - base_type); - } - - type_t *type = make_bitfield_type(base_type, size, &source_position); + type_t *type = make_bitfield_type(base_type, size, + &source_position, sym_anonymous); declaration = allocate_declaration_zero(); declaration->namespc = NAMESPACE_NORMAL; @@ -5547,12 +5633,8 @@ static void parse_compound_declarators(declaration_t *struct_declaration, next_token(); expression_t *size = parse_constant_expression(); - if (!is_type_integer(type)) { - errorf(HERE, "bitfield base type '%T' is not an integer type", - orig_type); - } - - type_t *bitfield_type = make_bitfield_type(orig_type, size, &source_position); + type_t *bitfield_type = make_bitfield_type(orig_type, size, + &source_position, declaration->symbol); declaration->type = bitfield_type; } else { /* TODO we ignore arrays for now... what is missing is a check @@ -6003,21 +6085,15 @@ static expression_t *parse_reference(void) declaration_t *declaration = get_declaration(symbol, NAMESPACE_NORMAL); - source_position_t source_position = token.source_position; - next_token(); - if (declaration == NULL) { - if (token.type == '(') { + if (!strict_mode && look_ahead(1)->type == '(') { /* an implicitly declared function */ - if (strict_mode) { - errorf(HERE, "unknown symbol '%Y' found.", symbol); - } else if (warning.implicit_function_declaration) { + if (warning.implicit_function_declaration) { warningf(HERE, "implicit declaration of function '%Y'", symbol); } - declaration = create_implicit_function(symbol, - &source_position); + declaration = create_implicit_function(symbol, HERE); } else { errorf(HERE, "unknown symbol '%Y' found.", symbol); declaration = create_error_declaration(symbol, STORAGE_CLASS_NONE); @@ -6043,23 +6119,21 @@ static expression_t *parse_reference(void) "function" : "variable"; if (declaration->deprecated_string != NULL) { - warningf(&source_position, - "%s '%Y' is deprecated (declared %P): \"%s\"", prefix, - declaration->symbol, &declaration->source_position, + warningf(HERE, "%s '%Y' is deprecated (declared %P): \"%s\"", + prefix, declaration->symbol, &declaration->source_position, declaration->deprecated_string); } else { - warningf(&source_position, - "%s '%Y' is deprecated (declared %P)", prefix, + warningf(HERE, "%s '%Y' is deprecated (declared %P)", prefix, declaration->symbol, &declaration->source_position); } } if (warning.init_self && declaration == current_init_decl) { current_init_decl = NULL; - warningf(&source_position, - "variable '%#T' is initialized by itself", + warningf(HERE, "variable '%#T' is initialized by itself", declaration->type, declaration->symbol); } + next_token(); return expression; } @@ -6613,8 +6687,17 @@ end_error: */ static declaration_t *get_label(symbol_t *symbol) { - declaration_t *candidate = get_declaration(symbol, NAMESPACE_LABEL); + declaration_t *candidate; assert(current_function != NULL); + + candidate = get_declaration(symbol, NAMESPACE_LOCAL_LABEL); + /* if we found a local label, we already created the declaration */ + if (candidate != NULL) { + assert(candidate->parent_scope == scope); + return candidate; + } + + candidate = get_declaration(symbol, NAMESPACE_LABEL); /* if we found a label in the same function, then we already created the * declaration */ if (candidate != NULL @@ -6806,19 +6889,18 @@ static expression_t *parse_array_expression(unsigned precedence, orig_type_left, orig_type_inside); } return_type = type_error_type; - array_access->array_ref = create_invalid_expression(); + array_access->array_ref = left; + array_access->index = inside; } + expression->base.type = automatic_type_conversion(return_type); + rem_anchor_token(']'); - if (token.type != ']') { + if (token.type == ']') { + next_token(); + } else { parse_error_expected("Problem while parsing array access", ']', NULL); - return expression; } - next_token(); - - return_type = automatic_type_conversion(return_type); - expression->base.type = return_type; - return expression; } @@ -6938,7 +7020,7 @@ static expression_t *parse_select_expression(unsigned precedence, if (!declaration->init.complete) { errorf(HERE, "request for member '%Y' of incomplete type '%T'", symbol, type_left); - return create_invalid_expression(); + goto create_error_entry; } entry = find_compound_entry(declaration, symbol); @@ -7020,26 +7102,15 @@ static void check_call_argument(const function_parameter_t *parameter, snprintf(buf, sizeof(buf), "call argument %u", pos); report_assign_error(error, expected_type, arg_expr, buf, &arg_expr->base.source_position); - } else if (warning.traditional | warning.conversion) { - if ( - /* passing as integer instead of float or complex */ - (is_type_integer(expected_type) && - (is_type_float(arg_type) || is_type_complex(arg_type))) || - /* passing as complex instead of integer or float */ - (is_type_complex(expected_type) && - (is_type_integer(arg_type) || is_type_float(arg_type))) || - /* passing as float instead of integer or complex */ - (is_type_float(expected_type) && - (is_type_integer(arg_type) || is_type_complex(arg_type))) || - /* passing as float instead of double */ - (is_type_float(expected_type) && expected_type != type_double && - is_type_float(arg_type))) { + } else if (warning.traditional || warning.conversion) { + type_t *const promoted_type = get_default_promoted_type(arg_type); + if (!types_compatible(expected_type_skip, promoted_type) && + !types_compatible(expected_type_skip, type_void_ptr) && + !types_compatible(type_void_ptr, promoted_type)) { + /* Deliberately show the skipped types in this warning */ warningf(&arg_expr->base.source_position, "passing call argument %u as '%T' rather than '%T' due to prototype", - pos, expected_type, arg_type); - } - if (is_type_integer(expected_type) && is_type_integer(arg_type)) { - /* TODO check for size HERE */ + pos, expected_type_skip, promoted_type); } } } @@ -7560,6 +7631,9 @@ static type_t *semantic_arithmetic(type_t *type_left, type_t *type_right) { /* TODO: handle complex + imaginary types */ + type_left = get_unqualified_type(type_left); + type_right = get_unqualified_type(type_right); + /* § 6.3.1.8 Usual arithmetic conversions */ if (type_left == type_long_double || type_right == type_long_double) { return type_long_double; @@ -7646,10 +7720,15 @@ static void semantic_binexpr_arithmetic(binary_expression_t *expression) static void warn_div_by_zero(binary_expression_t const *const expression) { - if (warning.div_by_zero && - is_type_integer(expression->base.type) && - is_constant_expression(expression->right) && - fold_constant(expression->right) == 0) { + if (!warning.div_by_zero || + !is_type_integer(expression->base.type)) + return; + + expression_t const *const right = expression->right; + /* The type of the right operand can be different for /= */ + if (is_type_integer(right->base.type) && + is_constant_expression(right) && + fold_constant(right) == 0) { warningf(&expression->base.source_position, "division by zero"); } } @@ -8022,6 +8101,7 @@ static bool expression_has_effect(const expression_t *const expr) case EXPR_WIDE_CHARACTER_CONSTANT: return false; case EXPR_STRING_LITERAL: return false; case EXPR_WIDE_STRING_LITERAL: return false; + case EXPR_LABEL_ADDRESS: return false; case EXPR_CALL: { const call_expression_t *const call = &expr->call; @@ -8574,12 +8654,18 @@ static statement_t *parse_case_statement(void) source_position_t *const pos = &statement->base.source_position; *pos = token.source_position; - statement->case_label.expression = parse_expression(); - if (! is_constant_expression(statement->case_label.expression)) { - errorf(pos, "case label does not reduce to an integer constant"); + expression_t *const expression = parse_expression(); + statement->case_label.expression = expression; + if (!is_constant_expression(expression)) { + /* This check does not prevent the error message in all cases of an + * prior error while parsing the expression. At least it catches the + * common case of a mistyped enum entry. */ + if (is_type_valid(expression->base.type)) { + errorf(pos, "case label does not reduce to an integer constant"); + } statement->case_label.is_bad = true; } else { - long const val = fold_constant(statement->case_label.expression); + long const val = fold_constant(expression); statement->case_label.first_case = val; statement->case_label.last_case = val; } @@ -8587,16 +8673,22 @@ static statement_t *parse_case_statement(void) if (c_mode & _GNUC) { if (token.type == T_DOTDOTDOT) { next_token(); - statement->case_label.end_range = parse_expression(); - if (! is_constant_expression(statement->case_label.end_range)) { - errorf(pos, "case range does not reduce to an integer constant"); + expression_t *const end_range = parse_expression(); + statement->case_label.end_range = end_range; + if (!is_constant_expression(end_range)) { + /* This check does not prevent the error message in all cases of an + * prior error while parsing the expression. At least it catches the + * common case of a mistyped enum entry. */ + if (is_type_valid(end_range->base.type)) { + errorf(pos, "case range does not reduce to an integer constant"); + } statement->case_label.is_bad = true; } else { - long const val = fold_constant(statement->case_label.end_range); + long const val = fold_constant(end_range); statement->case_label.last_case = val; if (val < statement->case_label.first_case) { - statement->case_label.is_empty = true; + statement->case_label.is_empty_range = true; warningf(pos, "empty range specified"); } } @@ -8612,7 +8704,7 @@ static statement_t *parse_case_statement(void) /* Check for duplicate case values */ case_label_statement_t *c = &statement->case_label; for (case_label_statement_t *l = current_switch->first_case; l != NULL; l = l->next) { - if (l->is_bad || l->is_empty || l->expression == NULL) + if (l->is_bad || l->is_empty_range || l->expression == NULL) continue; if (c->last_case < l->first_case || c->first_case > l->last_case) @@ -8711,9 +8803,9 @@ static statement_t *parse_label_statement(void) PUSH_PARENT(statement); - /* if source position is already set then the label is defined twice, - * otherwise it was just mentioned in a goto so far */ - if (label->source_position.input_name != NULL) { + /* if statement is already set then the label is defined twice, + * otherwise it was just mentioned in a goto/local label declaration so far */ + if (label->init.statement != NULL) { errorf(HERE, "duplicate label '%Y' (declared %P)", symbol, &label->source_position); } else { @@ -9129,7 +9221,7 @@ end_error: /** * Parse a __leave statement. */ -static statement_t *parse_leave(void) +static statement_t *parse_leave_statement(void) { if (current_try == NULL) { errorf(HERE, "__leave statement not within __try"); @@ -9357,6 +9449,54 @@ static statement_t *parse_empty_statement(void) return statement; } +static statement_t *parse_local_label_declaration(void) { + statement_t *statement = allocate_statement_zero(STATEMENT_DECLARATION); + statement->base.source_position = token.source_position; + + eat(T___label__); + + declaration_t *begin = NULL, *end = NULL; + + while (true) { + if (token.type != T_IDENTIFIER) { + parse_error_expected("while parsing local label declaration", + T_IDENTIFIER, NULL); + goto end_error; + } + symbol_t *symbol = token.v.symbol; + declaration_t *declaration = get_declaration(symbol, NAMESPACE_LOCAL_LABEL); + if (declaration != NULL) { + errorf(HERE, "multiple definitions of '__label__ %Y' (previous definition at %P)", + symbol, &declaration->source_position); + } else { + declaration = allocate_declaration_zero(); + declaration->namespc = NAMESPACE_LOCAL_LABEL; + declaration->source_position = token.source_position; + declaration->symbol = symbol; + declaration->parent_scope = scope; + declaration->init.statement = NULL; + + if (end != NULL) + end->next = declaration; + end = declaration; + if (begin == NULL) + begin = declaration; + + local_label_push(declaration); + } + next_token(); + + if (token.type != ',') + break; + next_token(); + } + eat(';'); +end_error: + statement->declaration.declarations_begin = begin; + statement->declaration.declarations_end = end; + return statement; +} + /** * Parse a statement. * There's also parse_statement() which additionally checks for @@ -9376,13 +9516,18 @@ static statement_t *intern_parse_statement(void) } else if (is_typedef_symbol(token.v.symbol)) { statement = parse_declaration_statement(); } else switch (la1_type) { + case '*': + if (get_declaration(token.v.symbol, NAMESPACE_NORMAL) != NULL) + goto expression_statment; + /* FALLTHROUGH */ + DECLARATION_START case T_IDENTIFIER: - case '*': statement = parse_declaration_statement(); break; default: +expression_statment: statement = parse_expression_statement(); break; } @@ -9402,9 +9547,13 @@ static statement_t *intern_parse_statement(void) statement = parse_declaration_statement(); break; + case T___label__: + 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(); 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; @@ -9463,6 +9612,7 @@ static statement_t *parse_compound_statement(bool inside_expression_statement) add_anchor_token('}'); int top = environment_top(); + int top_local = local_label_top(); scope_t *last_scope = scope; set_scope(&statement->compound.scope); @@ -9525,6 +9675,7 @@ end_error: assert(scope == &statement->compound.scope); set_scope(last_scope); environment_pop_to(top); + local_label_pop_to(top_local); POP_PARENT; return statement; @@ -9651,6 +9802,7 @@ void start_parsing(void) { environment_stack = NEW_ARR_F(stack_entry_t, 0); label_stack = NEW_ARR_F(stack_entry_t, 0); + local_label_stack = NEW_ARR_F(stack_entry_t, 0); diagnostic_count = 0; error_count = 0; warning_count = 0; @@ -9682,6 +9834,7 @@ translation_unit_t *finish_parsing(void) DEL_ARR_F(environment_stack); DEL_ARR_F(label_stack); + DEL_ARR_F(local_label_stack); translation_unit_t *result = unit; unit = NULL; @@ -9691,7 +9844,7 @@ translation_unit_t *finish_parsing(void) void parse(void) { lookahead_bufpos = 0; - for(int i = 0; i < MAX_LOOKAHEAD + 2; ++i) { + for (int i = 0; i < MAX_LOOKAHEAD + 2; ++i) { next_token(); } parse_translation_unit(); @@ -9702,6 +9855,8 @@ void parse(void) */ void init_parser(void) { + sym_anonymous = symbol_table_insert(""); + if (c_mode & _MS) { /* add predefined symbols for extended-decl-modifier */ sym_align = symbol_table_insert("align");