X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=parser.c;h=3c1001362c37fd0f8ca179a1da1763e1e73ee011;hb=1cd9fac9d1a48d012cf3084c8edc4130e75a1ea5;hp=315d17c72499d4cd72f2722984bcc1e1b0a19c93;hpb=8c61b999e9291a7a30df929a2b8e0f829deaf10a;p=cparser diff --git a/parser.c b/parser.c index 315d17c..3c10013 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; @@ -315,6 +316,7 @@ static size_t get_expression_struct_size(expression_kind_t kind) [EXPR_VA_START] = sizeof(va_start_expression_t), [EXPR_VA_ARG] = sizeof(va_arg_expression_t), [EXPR_STATEMENT] = sizeof(statement_expression_t), + [EXPR_LABEL_ADDRESS] = sizeof(label_address_expression_t), }; if (kind >= EXPR_UNARY_FIRST && kind <= EXPR_UNARY_LAST) { return sizes[EXPR_UNARY_FIRST]; @@ -479,13 +481,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. */ @@ -764,6 +774,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); @@ -772,7 +787,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 */ @@ -782,6 +797,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 */ @@ -832,13 +858,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 @@ -848,6 +880,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; @@ -3076,6 +3120,95 @@ static declaration_t *create_error_declaration(symbol_t *symbol, storage_class_t return decl; } +/** + * Finish the construction of a struct type by calculating + * its size, offsets, alignment. + */ +static void finish_struct_type(compound_type_t *type) { + if (type->declaration == NULL) + return; + declaration_t *struct_decl = type->declaration; + 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; + + 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; + if (m_alignment > alignment) + alignment = m_alignment; + if (new_size > size) + need_pad = true; + entry->offset = new_size; + size = new_size + m_type->base.size; + } + if (type->base.alignment != 0) { + alignment = type->base.alignment; + } + + new_size = (size + alignment - 1) & -alignment; + if (new_size > size) + need_pad = true; + + if (warning.padded && need_pad) { + warningf(&struct_decl->source_position, + "'%#T' needs padding", type, struct_decl->symbol); + } + if (warning.packed && !need_pad) { + warningf(&struct_decl->source_position, + "superfluous packed attribute on '%#T'", + type, struct_decl->symbol); + } + + type->base.size = new_size; + type->base.alignment = alignment; +} + +/** + * Finish the construction of an union type by calculating + * its size and alignment. + */ +static void finish_union_type(compound_type_t *type) { + if (type->declaration == NULL) + return; + declaration_t *union_decl = type->declaration; + if (! union_decl->init.complete) + return; + + il_size_t size = 0; + il_alignment_t alignment = 1; + + declaration_t *entry = union_decl->scope.declarations; + for (; entry != NULL; entry = entry->next) { + if (entry->namespc != NAMESPACE_NORMAL) + continue; + + type_t *m_type = skip_typeref(entry->type); + + entry->offset = 0; + if (m_type->base.size > size) + size = m_type->base.size; + if (m_type->base.alignment > alignment) + alignment = m_type->base.alignment; + } + if (type->base.alignment != 0) { + alignment = type->base.alignment; + } + size = (size + alignment - 1) & -alignment; + type->base.size = size; + type->base.alignment = alignment; +} + static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) { type_t *type = NULL; @@ -3215,6 +3348,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) type = allocate_type_zero(TYPE_COMPOUND_STRUCT, HERE); type->compound.declaration = parse_compound_type_specifier(true); + finish_struct_type(&type->compound); break; } case T_union: { @@ -3223,6 +3357,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) if (type->compound.declaration->modifiers & DM_TRANSPARENT_UNION) modifiers |= TYPE_MODIFIER_TRANSPARENT_UNION; break; + finish_union_type(&type->compound); } case T_enum: type = parse_enum_specifier(); @@ -3897,8 +4032,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; @@ -4703,6 +4840,10 @@ static void check_labels(void) for (const goto_statement_t *goto_statement = goto_first; goto_statement != NULL; goto_statement = goto_statement->next) { + /* skip computed gotos */ + if (goto_statement->expression != NULL) + continue; + declaration_t *label = goto_statement->label; label->used = true; @@ -4908,9 +5049,16 @@ found_break_parent: } case STATEMENT_GOTO: - next = stmt->gotos.label->init.statement; - if (next == NULL) /* missing label */ - return; + if (stmt->gotos.expression) { + statement_t *parent = stmt->base.parent; + if (parent == NULL) /* top level goto */ + return; + next = parent; + } else { + next = stmt->gotos.label->init.statement; + if (next == NULL) /* missing label */ + return; + } break; case STATEMENT_LABEL: @@ -5404,12 +5552,12 @@ static void parse_compound_declarators(declaration_t *struct_declaration, { declaration_t *last_declaration = struct_declaration->scope.declarations; if (last_declaration != NULL) { - while(last_declaration->next != NULL) { + while (last_declaration->next != NULL) { last_declaration = last_declaration->next; } } - while(1) { + while (true) { declaration_t *declaration; if (token.type == ':') { @@ -5502,7 +5650,7 @@ static void parse_compound_type_entries(declaration_t *compound_declaration) eat('{'); add_anchor_token('}'); - while(token.type != '}' && token.type != T_EOF) { + while (token.type != '}' && token.type != T_EOF) { declaration_specifiers_t specifiers; memset(&specifiers, 0, sizeof(specifiers)); parse_declaration_specifiers(&specifiers); @@ -5848,7 +5996,10 @@ type_t *revert_automatic_type_conversion(const expression_t *expression) { switch (expression->kind) { case EXPR_REFERENCE: return expression->reference.declaration->type; - case EXPR_SELECT: return expression->select.compound_entry->type; + + case EXPR_SELECT: + return get_qualified_type(expression->select.compound_entry->type, + expression->base.type->base.qualifiers); case EXPR_UNARY_DEREFERENCE: { const expression_t *const value = expression->unary.value; @@ -6500,6 +6651,71 @@ end_error: return create_invalid_expression(); } +/** + * Return the declaration for a given label symbol or create a new one. + * + * @param symbol the symbol of the label + */ +static declaration_t *get_label(symbol_t *symbol) +{ + 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 + && candidate->parent_scope == ¤t_function->scope) { + return candidate; + } + + /* otherwise we need to create a new one */ + declaration_t *const declaration = allocate_declaration_zero(); + declaration->namespc = NAMESPACE_LABEL; + declaration->symbol = symbol; + + label_push(declaration); + + return declaration; +} + +/** + * Parses a GNU && label address expression. + */ +static expression_t *parse_label_address(void) +{ + source_position_t source_position = token.source_position; + eat(T_ANDAND); + if (token.type != T_IDENTIFIER) { + parse_error_expected("while parsing label address", T_IDENTIFIER, NULL); + goto end_error; + } + symbol_t *symbol = token.v.symbol; + next_token(); + + declaration_t *label = get_label(symbol); + + label->used = true; + label->address_taken = true; + + expression_t *expression = allocate_expression_zero(EXPR_LABEL_ADDRESS); + expression->base.source_position = source_position; + + /* label address is threaten as a void pointer */ + expression->base.type = type_void_ptr; + expression->label_address.declaration = label; + return expression; +end_error: + return create_invalid_expression(); +} + /** * Parse a microsoft __noop expression. */ @@ -6577,6 +6793,10 @@ static expression_t *parse_primary_expression(void) case T___builtin_constant_p: return parse_builtin_constant(); case T___builtin_prefetch: return parse_builtin_prefetch(); case T__assume: return parse_assume(); + case T_ANDAND: + if (c_mode & _GNUC) + return parse_label_address(); + break; case '(': return parse_parenthesized_expression(); case T___noop: return parse_noop_expression(); @@ -6746,24 +6966,23 @@ static expression_t *parse_select_expression(unsigned precedence, type_t *const orig_type = compound->base.type; type_t *const type = skip_typeref(orig_type); - type_t *type_left = type; + type_t *type_left; bool saw_error = false; if (is_type_pointer(type)) { if (!is_pointer) { errorf(HERE, "request for member '%Y' in something not a struct or union, but '%T'", - symbol, type_left); + symbol, orig_type); saw_error = true; } - type_left = type->pointer.points_to; - } else if (is_pointer) { - if (is_type_valid(type)) { + type_left = skip_typeref(type->pointer.points_to); + } else { + if (is_pointer && is_type_valid(type)) { errorf(HERE, "left hand side of '->' is not a pointer, but '%T'", orig_type); saw_error = true; } type_left = type; } - type_left = skip_typeref(type_left); declaration_t *entry; if (type_left->kind == TYPE_COMPOUND_STRUCT || @@ -6773,7 +6992,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); @@ -6793,11 +7012,15 @@ create_error_entry: } select->select.compound_entry = entry; + + type_t *const res_type = + get_qualified_type(entry->type, type_left->base.qualifiers); + /* we always do the auto-type conversions; the & and sizeof parser contains * code to revert this! */ - select->base.type = automatic_type_conversion(entry->type); + select->base.type = automatic_type_conversion(res_type); - type_t *skipped = skip_typeref(entry->type); + type_t *skipped = skip_typeref(res_type); if (skipped->kind == TYPE_BITFIELD) { select->base.type = skipped->bitfield.base_type; } @@ -7084,13 +7307,8 @@ static expression_t *parse_conditional_expression(unsigned precedence, to = type_void; } - type_t *const copy = duplicate_type(to); - copy->base.qualifiers = to1->base.qualifiers | to2->base.qualifiers; - - type_t *const type = typehash_insert(copy); - if (type != copy) - free_type(copy); - + type_t *const type = + get_qualified_type(to, to1->base.qualifiers | to2->base.qualifiers); result_type = make_pointer_type(type, TYPE_QUALIFIER_NONE); } else if (is_type_integer(other_type)) { warningf(&conditional->base.source_position, @@ -7284,7 +7502,7 @@ static void semantic_dereference(unary_expression_t *expression) if (!is_type_pointer(type)) { if (is_type_valid(type)) { errorf(&expression->base.source_position, - "Unary '*' needs pointer or arrray type, but type '%T' given", orig_type); + "Unary '*' needs pointer or array type, but type '%T' given", orig_type); } return; } @@ -7824,9 +8042,6 @@ static void semantic_binexpr_assign(binary_expression_t *expression) expression_t *left = expression->left; type_t *orig_type_left = left->base.type; - type_t *type_left = revert_automatic_type_conversion(left); - type_left = skip_typeref(orig_type_left); - if (!is_valid_assignment_lhs(left)) return; @@ -7861,6 +8076,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; @@ -8533,32 +8749,6 @@ end_error: return create_invalid_statement(); } -/** - * Return the declaration for a given label symbol or create a new one. - * - * @param symbol the symbol of the label - */ -static declaration_t *get_label(symbol_t *symbol) -{ - declaration_t *candidate = get_declaration(symbol, NAMESPACE_LABEL); - assert(current_function != NULL); - /* if we found a label in the same function, then we already created the - * declaration */ - if (candidate != NULL - && candidate->parent_scope == ¤t_function->scope) { - return candidate; - } - - /* otherwise we need to create a new one */ - declaration_t *const declaration = allocate_declaration_zero(); - declaration->namespc = NAMESPACE_LABEL; - declaration->symbol = symbol; - - label_push(declaration); - - return declaration; -} - /** * Parse a label statement. */ @@ -8576,9 +8766,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 { @@ -8896,22 +9086,47 @@ end_error: */ static statement_t *parse_goto(void) { + source_position_t source_position = token.source_position; eat(T_goto); - if (token.type != T_IDENTIFIER) { - parse_error_expected("while parsing goto", T_IDENTIFIER, NULL); - eat_statement(); - goto end_error; - } - symbol_t *symbol = token.v.symbol; - next_token(); + statement_t *statement; + if (c_mode & _GNUC && token.type == '*') { + next_token(); + expression_t *expression = parse_expression(); - declaration_t *label = get_label(symbol); + /* Argh: although documentation say the expression must be of type void *, + * gcc excepts anything that can be casted into void * without error */ + type_t *type = expression->base.type; - statement_t *statement = allocate_statement_zero(STATEMENT_GOTO); - statement->base.source_position = token.source_position; + if (type != type_error_type) { + if (!is_type_pointer(type) && !is_type_integer(type)) { + errorf(&source_position, "cannot convert to a pointer type"); + } else if (type != type_void_ptr) { + warningf(&source_position, + "type of computed goto expression should be 'void*' not '%T'", type); + } + expression = create_implicit_cast(expression, type_void_ptr); + } - statement->gotos.label = label; + statement = allocate_statement_zero(STATEMENT_GOTO); + statement->base.source_position = source_position; + statement->gotos.expression = expression; + } else { + if (token.type != T_IDENTIFIER) { + if (c_mode & _GNUC) + parse_error_expected("while parsing goto", T_IDENTIFIER, '*', NULL); + else + parse_error_expected("while parsing goto", T_IDENTIFIER, NULL); + eat_statement(); + goto end_error; + } + symbol_t *symbol = token.v.symbol; + next_token(); + + statement = allocate_statement_zero(STATEMENT_GOTO); + statement->base.source_position = source_position; + statement->gotos.label = get_label(symbol); + } /* remember the goto's in a list for later checking */ if (goto_last == NULL) { @@ -8969,7 +9184,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"); @@ -9197,6 +9412,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 @@ -9242,9 +9505,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; @@ -9303,6 +9570,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); @@ -9365,6 +9633,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; @@ -9491,6 +9760,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; @@ -9522,6 +9792,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; @@ -9531,7 +9802,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();