X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=parser.c;h=3c1001362c37fd0f8ca179a1da1763e1e73ee011;hb=1cd9fac9d1a48d012cf3084c8edc4130e75a1ea5;hp=c11906c89ded7c990d0558eba51a1baffe456cf0;hpb=5ba6c59ce75fd069dfbfac1ce4d9a261c99251f6;p=cparser diff --git a/parser.c b/parser.c index c11906c..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; @@ -3988,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; @@ -4794,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; @@ -4999,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: @@ -6594,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. */ @@ -6671,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(); @@ -6866,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); @@ -7376,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; } @@ -7950,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; @@ -8622,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. */ @@ -8665,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 { @@ -8985,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) { @@ -9058,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"); @@ -9286,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 @@ -9331,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; @@ -9392,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); @@ -9454,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; @@ -9580,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; @@ -9611,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; @@ -9620,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();