X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;ds=sidebyside;f=parser.c;h=73b02095bff093a58e1fbbfb5b4976e57a2b7e74;hb=09964a9e87be1ddf585aef762a0042feff30ce87;hp=6d1a9591875eba6c7a6fab737cceac86cd3fc1d8;hpb=c8a74a89b4428528d5d7947b440c3ec5a0a65e0f;p=cparser diff --git a/parser.c b/parser.c index 6d1a959..73b0209 100644 --- a/parser.c +++ b/parser.c @@ -284,25 +284,26 @@ static void semantic_comparison(binary_expression_t *expression); static size_t get_statement_struct_size(statement_kind_t kind) { static const size_t sizes[] = { - [STATEMENT_ERROR] = sizeof(statement_base_t), - [STATEMENT_EMPTY] = sizeof(statement_base_t), - [STATEMENT_COMPOUND] = sizeof(compound_statement_t), - [STATEMENT_RETURN] = sizeof(return_statement_t), - [STATEMENT_DECLARATION] = sizeof(declaration_statement_t), - [STATEMENT_IF] = sizeof(if_statement_t), - [STATEMENT_SWITCH] = sizeof(switch_statement_t), - [STATEMENT_EXPRESSION] = sizeof(expression_statement_t), - [STATEMENT_CONTINUE] = sizeof(statement_base_t), - [STATEMENT_BREAK] = sizeof(statement_base_t), - [STATEMENT_GOTO] = sizeof(goto_statement_t), - [STATEMENT_LABEL] = sizeof(label_statement_t), - [STATEMENT_CASE_LABEL] = sizeof(case_label_statement_t), - [STATEMENT_WHILE] = sizeof(while_statement_t), - [STATEMENT_DO_WHILE] = sizeof(do_while_statement_t), - [STATEMENT_FOR] = sizeof(for_statement_t), - [STATEMENT_ASM] = sizeof(asm_statement_t), - [STATEMENT_MS_TRY] = sizeof(ms_try_statement_t), - [STATEMENT_LEAVE] = sizeof(leave_statement_t) + [STATEMENT_ERROR] = sizeof(statement_base_t), + [STATEMENT_EMPTY] = sizeof(statement_base_t), + [STATEMENT_COMPOUND] = sizeof(compound_statement_t), + [STATEMENT_RETURN] = sizeof(return_statement_t), + [STATEMENT_DECLARATION] = sizeof(declaration_statement_t), + [STATEMENT_IF] = sizeof(if_statement_t), + [STATEMENT_SWITCH] = sizeof(switch_statement_t), + [STATEMENT_EXPRESSION] = sizeof(expression_statement_t), + [STATEMENT_CONTINUE] = sizeof(statement_base_t), + [STATEMENT_BREAK] = sizeof(statement_base_t), + [STATEMENT_COMPUTED_GOTO] = sizeof(computed_goto_statement_t), + [STATEMENT_GOTO] = sizeof(goto_statement_t), + [STATEMENT_LABEL] = sizeof(label_statement_t), + [STATEMENT_CASE_LABEL] = sizeof(case_label_statement_t), + [STATEMENT_WHILE] = sizeof(while_statement_t), + [STATEMENT_DO_WHILE] = sizeof(do_while_statement_t), + [STATEMENT_FOR] = sizeof(for_statement_t), + [STATEMENT_ASM] = sizeof(asm_statement_t), + [STATEMENT_MS_TRY] = sizeof(ms_try_statement_t), + [STATEMENT_LEAVE] = sizeof(leave_statement_t) }; assert((size_t)kind < lengthof(sizes)); assert(sizes[kind] != 0); @@ -1521,7 +1522,7 @@ unary: determine_lhs_ent(expr->va_starte.ap, lhs_ent); return; - EXPR_LITERAL_CASES + case EXPR_LITERAL_CASES: case EXPR_ERROR: case EXPR_STRING_LITERAL: case EXPR_WIDE_STRING_LITERAL: @@ -1665,15 +1666,6 @@ static initializer_t *initializer_from_expression(type_t *orig_type, return result; } -/** - * Checks if a given expression can be used as a constant initializer. - */ -static bool is_initializer_constant(const expression_t *expression) -{ - return is_constant_expression(expression) != EXPR_CLASS_VARIABLE || - is_linker_constant(expression) != EXPR_CLASS_VARIABLE; -} - /** * Parses an scalar initializer. * @@ -1694,7 +1686,7 @@ static initializer_t *parse_scalar_initializer(type_t *type, expression_t *expression = parse_assignment_expression(); mark_vars_read(expression, NULL); - if (must_be_constant && !is_initializer_constant(expression)) { + if (must_be_constant && !is_linker_constant(expression)) { errorf(&expression->base.source_position, "initialisation expression '%E' is not constant", expression); @@ -2114,7 +2106,7 @@ finish_designator: expression_t *expression = parse_assignment_expression(); mark_vars_read(expression, NULL); - if (env->must_be_constant && !is_initializer_constant(expression)) { + if (env->must_be_constant && !is_linker_constant(expression)) { errorf(&expression->base.source_position, "Initialisation expression '%E' is not constant", expression); @@ -2611,9 +2603,9 @@ static attribute_t *parse_attribute_ms_property(attribute_t *attribute) symbol_t **prop; symbol_t *symbol = token.identifier.symbol; - if (strcmp(symbol->string, "put") == 0) { + if (streq(symbol->string, "put")) { prop = &property->put_symbol; - } else if (strcmp(symbol->string, "get") == 0) { + } else if (streq(symbol->string, "get")) { prop = &property->get_symbol; } else { errorf(HERE, "expected put or get in property declspec"); @@ -2649,7 +2641,7 @@ static attribute_t *parse_microsoft_extended_decl_modifier_single(void) for (attribute_kind_t k = ATTRIBUTE_MS_FIRST; k <= ATTRIBUTE_MS_LAST; ++k) { const char *attribute_name = get_attribute_name(k); - if (attribute_name != NULL && strcmp(attribute_name, name) == 0) { + if (attribute_name != NULL && streq(attribute_name, name)) { kind = k; break; } @@ -3966,7 +3958,7 @@ warn_arg_count: */ static bool is_sym_main(const symbol_t *const sym) { - return strcmp(sym->string, "main") == 0; + return streq(sym->string, "main"); } static void error_redefined_as_different_kind(const source_position_t *pos, @@ -4629,10 +4621,6 @@ 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; - label_t *label = goto_statement->label; if (label->base.source_position.input_name == NULL) { print_in_function(); @@ -4732,10 +4720,12 @@ static bool expression_returns(expression_t const *const expr) switch (expr->kind) { case EXPR_CALL: { expression_t const *const func = expr->call.function; - if (func->kind == EXPR_REFERENCE) { - entity_t *entity = func->reference.entity; - if (entity->kind == ENTITY_FUNCTION - && entity->declaration.modifiers & DM_NORETURN) + type_t const *const type = skip_typeref(func->base.type); + if (type->kind == TYPE_POINTER) { + type_t const *const points_to + = skip_typeref(type->pointer.points_to); + if (points_to->kind == TYPE_FUNCTION + && points_to->function.modifiers & DM_NORETURN) return false; } @@ -4752,7 +4742,7 @@ static bool expression_returns(expression_t const *const expr) case EXPR_REFERENCE: case EXPR_REFERENCE_ENUM_VALUE: - EXPR_LITERAL_CASES + case EXPR_LITERAL_CASES: case EXPR_STRING_LITERAL: case EXPR_WIDE_STRING_LITERAL: case EXPR_COMPOUND_LITERAL: // TODO descend into initialisers @@ -4805,13 +4795,13 @@ static bool expression_returns(expression_t const *const expr) case EXPR_VA_COPY: return expression_returns(expr->va_copye.src); - EXPR_UNARY_CASES_MANDATORY + case EXPR_UNARY_CASES_MANDATORY: return expression_returns(expr->unary.value); case EXPR_UNARY_THROW: return false; - EXPR_BINARY_CASES + case EXPR_BINARY_CASES: // TODO handle constant lhs of && and || return expression_returns(expr->binary.left) && @@ -5010,20 +5000,21 @@ static void check_reachable(statement_t *const stmt) found_break_parent: break; - case STATEMENT_GOTO: - if (stmt->gotos.expression) { - if (!expression_returns(stmt->gotos.expression)) - return; + case STATEMENT_COMPUTED_GOTO: { + if (!expression_returns(stmt->computed_goto.expression)) + return; - statement_t *parent = stmt->base.parent; - if (parent == NULL) /* top level goto */ - return; - next = parent; - } else { - next = stmt->gotos.label->statement; - if (next == NULL) /* missing label */ - return; - } + statement_t *parent = stmt->base.parent; + if (parent == NULL) /* top level goto */ + return; + next = parent; + break; + } + + case STATEMENT_GOTO: + next = stmt->gotos.label->statement; + if (next == NULL) /* missing label */ + return; break; case STATEMENT_LABEL: @@ -5138,6 +5129,7 @@ found_break_parent: case STATEMENT_RETURN: case STATEMENT_CONTINUE: case STATEMENT_BREAK: + case STATEMENT_COMPUTED_GOTO: case STATEMENT_GOTO: case STATEMENT_LEAVE: panic("invalid control flow in function"); @@ -5321,6 +5313,22 @@ warn_unreachable: } } +static bool is_main(entity_t *entity) +{ + static symbol_t *sym_main = NULL; + if (sym_main == NULL) { + sym_main = symbol_table_insert("main"); + } + + if (entity->base.symbol != sym_main) + return false; + /* must be in outermost scope */ + if (entity->base.parent_scope != file_scope) + return false; + + return true; +} + static void parse_external_declaration(void) { /* function-definitions and declarations both start with declaration @@ -5470,6 +5478,9 @@ static void parse_external_declaration(void) } } + if (is_main(entity) && enable_main_collect2_hack) + prepare_main_collect2(entity); + POP_PARENT(); assert(current_function == function); assert(current_entity == entity); @@ -5705,6 +5716,8 @@ static void parse_compound_declarators(compound_t *compound, token.kind != ';' || look_ahead(1)->kind != '}') { errorf(pos, "'%N' has incomplete type '%T'", entity, orig_type); + } else if (compound->members.entities == NULL) { + errorf(pos, "flexible array member in otherwise empty struct"); } } } @@ -6855,9 +6868,10 @@ static expression_t *parse_noop_expression(void) if (token.kind != ')') do { (void)parse_assignment_expression(); } while (next_if(',')); + + rem_anchor_token(','); + rem_anchor_token(')'); } - rem_anchor_token(','); - rem_anchor_token(')'); expect(')', end_error); end_error: @@ -9082,7 +9096,22 @@ static statement_t *parse_case_statement(void) eat(T_case); - expression_t *const expression = parse_expression(); + expression_t *expression = parse_expression(); + type_t *expression_type = expression->base.type; + type_t *skipped = skip_typeref(expression_type); + if (!is_type_integer(skipped) && is_type_valid(skipped)) { + errorf(pos, "case expression '%E' must have integer type but has type '%T'", + expression, expression_type); + } + + type_t *type = expression_type; + if (current_switch != NULL) { + type_t *switch_type = current_switch->expression->base.type; + if (is_type_valid(switch_type)) { + expression = create_implicit_cast(expression, switch_type); + } + } + statement->case_label.expression = expression; expression_classification_t const expr_class = is_constant_expression(expression); if (expr_class != EXPR_CLASS_CONSTANT) { @@ -9098,7 +9127,15 @@ static statement_t *parse_case_statement(void) if (GNU_MODE) { if (next_if(T_DOTDOTDOT)) { - expression_t *const end_range = parse_expression(); + expression_t *end_range = parse_expression(); + expression_type = expression->base.type; + skipped = skip_typeref(expression_type); + if (!is_type_integer(skipped) && is_type_valid(skipped)) { + errorf(pos, "case expression '%E' must have integer type but has type '%T'", + expression, expression_type); + } + + end_range = create_implicit_cast(end_range, type); statement->case_label.end_range = end_range; expression_classification_t const end_class = is_constant_expression(end_range); if (end_class != EXPR_CLASS_CONSTANT) { @@ -9542,10 +9579,12 @@ end_error1: */ static statement_t *parse_goto(void) { - statement_t *statement = allocate_statement_zero(STATEMENT_GOTO); - eat(T_goto); + statement_t *statement; + if (GNU_MODE && look_ahead(1)->kind == '*') { + statement = allocate_statement_zero(STATEMENT_COMPUTED_GOTO); + eat(T_goto); + eat('*'); - if (GNU_MODE && next_if('*')) { expression_t *expression = parse_expression(); mark_vars_read(expression, NULL); @@ -9563,24 +9602,28 @@ static statement_t *parse_goto(void) expression = create_implicit_cast(expression, type_void_ptr); } - statement->gotos.expression = expression; - } else if (token.kind == T_IDENTIFIER) { - label_t *const label = get_label(); - label->used = true; - statement->gotos.label = label; + statement->computed_goto.expression = expression; } else { - if (GNU_MODE) - parse_error_expected("while parsing goto", T_IDENTIFIER, '*', NULL); - else - parse_error_expected("while parsing goto", T_IDENTIFIER, NULL); - eat_until_anchor(); - return create_error_statement(); + statement = allocate_statement_zero(STATEMENT_GOTO); + eat(T_goto); + if (token.kind == T_IDENTIFIER) { + label_t *const label = get_label(); + label->used = true; + statement->gotos.label = label; + + /* remember the goto's in a list for later checking */ + *goto_anchor = &statement->gotos; + goto_anchor = &statement->gotos.next; + } else { + if (GNU_MODE) + parse_error_expected("while parsing goto", T_IDENTIFIER, '*', NULL); + else + parse_error_expected("while parsing goto", T_IDENTIFIER, NULL); + eat_until_anchor(); + return create_error_statement(); + } } - /* remember the goto's in a list for later checking */ - *goto_anchor = &statement->gotos; - goto_anchor = &statement->gotos.next; - expect(';', end_error); end_error: @@ -10371,9 +10414,9 @@ static void parse_linkage_specification(void) linkage_kind_t old_linkage = current_linkage; linkage_kind_t new_linkage; - if (strcmp(linkage, "C") == 0) { + if (streq(linkage, "C")) { new_linkage = LINKAGE_C; - } else if (strcmp(linkage, "C++") == 0) { + } else if (streq(linkage, "C++")) { new_linkage = LINKAGE_CXX; } else { errorf(&pos, "linkage string \"%s\" not recognized", linkage); @@ -10571,6 +10614,8 @@ static void complete_incomplete_arrays(void) void prepare_main_collect2(entity_t *entity) { + PUSH_SCOPE(&entity->function.statement->compound.scope); + // create call to __main symbol_t *symbol = symbol_table_insert("__main"); entity_t *subsubmain_ent @@ -10597,6 +10642,8 @@ void prepare_main_collect2(entity_t *entity) expr_statement->base.next = compounds->statements; compounds->statements = expr_statement; + + POP_SCOPE(); } void parse(void)