X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=parser.c;h=14a84c45a6702c26f96a95cdd58e75d43d90dc70;hb=a59c61b5fa0c601030faec6aea663be9c76f2414;hp=83f51e04d9461d014dd6ce3fb4ff5b2351cf2a38;hpb=84b0c7d487744836ad5c80fba4f481d9eed12920;p=cparser diff --git a/parser.c b/parser.c index 83f51e0..14a84c4 100644 --- a/parser.c +++ b/parser.c @@ -114,9 +114,12 @@ 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; +/** The global file scope. */ +static scope_t *file_scope = NULL; +/** The current scope. */ static scope_t *scope = NULL; static declaration_t *last_declaration = NULL; +/** Point to the current function declaration if inside a function. */ static declaration_t *current_function = NULL; static declaration_t *current_init_decl = NULL; static switch_statement_t *current_switch = NULL; @@ -637,13 +640,9 @@ check_stop: */ static void eat_until_anchor(void) { - if (token.type == T_EOF) - return; while (token_anchor_set[token.type] == 0) { if (token.type == '(' || token.type == '{' || token.type == '[') eat_until_matching_token(token.type); - if (token.type == T_EOF) - break; next_token(); } } @@ -713,16 +712,25 @@ static void type_error_incompatible(const char *msg, next_token(); \ } while (0) -static void set_scope(scope_t *new_scope) +static void scope_push(scope_t *new_scope) { if (scope != NULL) { scope->last_declaration = last_declaration; + new_scope->depth = scope->depth + 1; } - scope = new_scope; + new_scope->parent = scope; + scope = new_scope; last_declaration = new_scope->last_declaration; } +static void scope_pop(void) +{ + scope->last_declaration = last_declaration; + scope = scope->parent; + last_declaration = scope->last_declaration; +} + /** * Search a symbol in a given namespace and returns its declaration or * NULL if this symbol was not found. @@ -749,28 +757,20 @@ static void stack_push(stack_entry_t **stack_ptr, declaration_t *declaration) namespace_t namespc = (namespace_t) declaration->namespc; /* replace/add declaration into declaration list of the symbol */ - declaration_t *iter = symbol->declaration; - if (iter == NULL) { - symbol->declaration = declaration; - } else { - declaration_t *iter_last = NULL; - for( ; iter != NULL; iter_last = iter, iter = iter->symbol_next) { - /* replace an entry? */ - if (iter->namespc == namespc) { - if (iter_last == NULL) { - symbol->declaration = declaration; - } else { - iter_last->symbol_next = declaration; - } - declaration->symbol_next = iter->symbol_next; - break; - } - } - if (iter == NULL) { - assert(iter_last->symbol_next == NULL); - iter_last->symbol_next = declaration; + declaration_t **anchor; + declaration_t *iter; + for (anchor = &symbol->declaration;; anchor = &iter->symbol_next) { + iter = *anchor; + if (iter == NULL) + break; + + /* replace an entry? */ + if (iter->namespc == namespc) { + declaration->symbol_next = iter->symbol_next; + break; } } + *anchor = declaration; /* remember old declaration */ stack_entry_t entry; @@ -835,30 +835,20 @@ static void stack_pop_to(stack_entry_t **stack_ptr, size_t new_top) namespace_t namespc = (namespace_t)entry->namespc; /* replace/remove declaration */ - declaration_t *declaration = symbol->declaration; - assert(declaration != NULL); - if (declaration->namespc == namespc) { - if (old_declaration == NULL) { - symbol->declaration = declaration->symbol_next; - } else { - symbol->declaration = old_declaration; - } - } else { - declaration_t *iter_last = declaration; - declaration_t *iter = declaration->symbol_next; - for( ; iter != NULL; iter_last = iter, iter = iter->symbol_next) { - /* replace an entry? */ - if (iter->namespc == namespc) { - assert(iter_last != NULL); - iter_last->symbol_next = old_declaration; - if (old_declaration != NULL) { - old_declaration->symbol_next = iter->symbol_next; - } - break; - } - } + declaration_t **anchor; + declaration_t *iter; + for (anchor = &symbol->declaration;; anchor = &iter->symbol_next) { + iter = *anchor; assert(iter != NULL); + /* replace an entry? */ + if (iter->namespc == namespc) + break; } + + /* Because of scopes and appending other namespaces to the end of + * the list, this must hold. */ + assert((old_declaration != NULL ? old_declaration->symbol_next : NULL) == iter->symbol_next); + *anchor = old_declaration; } ARR_SHRINKLEN(*stack_ptr, (int) new_top); @@ -3122,7 +3112,7 @@ static declaration_t *create_error_declaration(symbol_t *symbol, storage_class_t decl->source_position = *HERE; decl->declared_storage_class = storage_class; decl->storage_class = - storage_class != STORAGE_CLASS_NONE || scope == global_scope ? + storage_class != STORAGE_CLASS_NONE || scope == file_scope ? storage_class : STORAGE_CLASS_AUTO; decl->symbol = symbol; decl->implicit = true; @@ -3374,8 +3364,8 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) type->compound.declaration = parse_compound_type_specifier(false); if (type->compound.declaration->modifiers & DM_TRANSPARENT_UNION) modifiers |= TYPE_MODIFIER_TRANSPARENT_UNION; - break; finish_union_type(&type->compound); + break; } case T_enum: type = parse_enum_specifier(); @@ -3674,7 +3664,13 @@ static type_qualifiers_t parse_type_qualifiers(void) } } -static declaration_t *parse_identifier_list(void) +/** + * Parses an K&R identifier list and return a list of declarations. + * + * @param last points to the last declaration in the list + * @return the list of declarations + */ +static declaration_t *parse_identifier_list(declaration_t **last) { declaration_t *declarations = NULL; declaration_t *last_declaration = NULL; @@ -3698,6 +3694,7 @@ static declaration_t *parse_identifier_list(void) next_token(); } while (token.type == T_IDENTIFIER); + *last = last_declaration; return declarations; } @@ -3750,7 +3747,13 @@ static declaration_t *parse_parameter(void) return declaration; } -static declaration_t *parse_parameters(function_type_t *type) +/** + * Parses a function type parameter list and return a list of declarations. + * + * @param last point to the last element of the list + * @return the parameter list + */ +static declaration_t *parse_parameters(function_type_t *type, declaration_t **last) { declaration_t *declarations = NULL; @@ -3763,7 +3766,7 @@ static declaration_t *parse_parameters(function_type_t *type) token_type_t la1_type = (token_type_t)look_ahead(1)->type; if (la1_type == ',' || la1_type == ')') { type->kr_style_parameters = true; - declarations = parse_identifier_list(); + declarations = parse_identifier_list(last); goto parameters_finished; } } @@ -3829,10 +3832,12 @@ parameters_finished: expect(')'); restore_anchor_state(',', saved_comma_state); + *last = last_declaration; return declarations; end_error: restore_anchor_state(',', saved_comma_state); + *last = NULL; return NULL; } @@ -3968,9 +3973,12 @@ static construct_type_t *parse_function_declarator(declaration_t *declaration) type = allocate_type_zero(TYPE_FUNCTION, HERE); } - declaration_t *parameters = parse_parameters(&type->function); + declaration_t *last; + declaration_t *parameters = parse_parameters(&type->function, &last); if (declaration != NULL) { - declaration->scope.declarations = parameters; + declaration->scope.declarations = parameters; + declaration->scope.last_declaration = last; + declaration->scope.is_parameter = true; } construct_function_type_t *construct_function_type = @@ -4251,8 +4259,8 @@ static declaration_t *parse_declarator( declaration->is_inline = specifiers->is_inline; declaration->storage_class = specifiers->declared_storage_class; - if (declaration->storage_class == STORAGE_CLASS_NONE - && scope != global_scope) { + if (declaration->storage_class == STORAGE_CLASS_NONE && + scope != file_scope) { declaration->storage_class = STORAGE_CLASS_AUTO; } @@ -4388,14 +4396,23 @@ static declaration_t *record_declaration( if (warning.nested_externs && declaration->storage_class == STORAGE_CLASS_EXTERN && - scope != global_scope) { + scope != file_scope) { warningf(&declaration->source_position, "nested extern declaration of '%#T'", declaration->type, symbol); } assert(declaration != previous_declaration); - if (previous_declaration != NULL - && previous_declaration->parent_scope == scope) { + if (previous_declaration != NULL && + previous_declaration->parent_scope->is_parameter && + scope->depth == previous_declaration->parent_scope->depth + 1) { + errorf(&declaration->source_position, + "declaration '%#T' redeclares the parameter '%#T' (declared %P)", + orig_type, symbol, previous_declaration->type, symbol, + &previous_declaration->source_position); + goto finish; + } + if (previous_declaration != NULL && + previous_declaration->parent_scope == scope) { /* can happen for K&R style declarations */ if (previous_declaration->type == NULL) { previous_declaration->type = declaration->type; @@ -4519,7 +4536,7 @@ warn_redundant_declaration: } } else { if (warning.missing_declarations && - scope == global_scope && ( + scope == file_scope && ( declaration->storage_class == STORAGE_CLASS_NONE || declaration->storage_class == STORAGE_CLASS_THREAD )) { @@ -4527,7 +4544,7 @@ warn_redundant_declaration: "no previous declaration for '%#T'", orig_type, symbol); } } - +finish: assert(declaration->parent_scope == NULL); assert(scope != NULL); @@ -4575,9 +4592,9 @@ static void parse_init_declarator_rest(declaration_t *declaration) } bool must_be_constant = false; - if (declaration->storage_class == STORAGE_CLASS_STATIC - || declaration->storage_class == STORAGE_CLASS_THREAD_STATIC - || declaration->parent_scope == global_scope) { + if (declaration->storage_class == STORAGE_CLASS_STATIC || + declaration->storage_class == STORAGE_CLASS_THREAD_STATIC || + declaration->parent_scope == file_scope) { must_be_constant = true; } @@ -4760,10 +4777,11 @@ static void parse_kr_declaration_list(declaration_t *declaration) if (!type->function.kr_style_parameters) return; + add_anchor_token('{'); + /* push function parameters */ - int top = environment_top(); - scope_t *last_scope = scope; - set_scope(&declaration->scope); + size_t const top = environment_top(); + scope_push(&declaration->scope); declaration_t *parameter = declaration->scope.declarations; for ( ; parameter != NULL; parameter = parameter->next) { @@ -4779,7 +4797,7 @@ static void parse_kr_declaration_list(declaration_t *declaration) /* pop function parameters */ assert(scope == &declaration->scope); - set_scope(last_scope); + scope_pop(); environment_pop_to(top); /* update function type */ @@ -4838,6 +4856,8 @@ static void parse_kr_declaration_list(declaration_t *declaration) } declaration->type = type; + + rem_anchor_token('{'); } static bool first_err = true; @@ -5475,9 +5495,8 @@ static void parse_external_declaration(void) type = skip_typeref(declaration->type); /* push function parameters and switch scope */ - int top = environment_top(); - scope_t *last_scope = scope; - set_scope(&declaration->scope); + size_t const top = environment_top(); + scope_push(&declaration->scope); declaration_t *parameter = declaration->scope.declarations; for( ; parameter != NULL; parameter = parameter->next) { @@ -5532,7 +5551,7 @@ static void parse_external_declaration(void) } assert(scope == &declaration->scope); - set_scope(last_scope); + scope_pop(); environment_pop_to(top); } @@ -5697,7 +5716,11 @@ static void parse_compound_type_entries(declaration_t *compound_declaration) eat('{'); add_anchor_token('}'); - while (token.type != '}' && token.type != T_EOF) { + while (token.type != '}') { + if (token.type == T_EOF) { + errorf(HERE, "EOF while parsing struct"); + break; + } declaration_specifiers_t specifiers; memset(&specifiers, 0, sizeof(specifiers)); parse_declaration_specifiers(&specifiers); @@ -5705,10 +5728,6 @@ static void parse_compound_type_entries(declaration_t *compound_declaration) parse_compound_declarators(compound_declaration, &specifiers); } rem_anchor_token('}'); - - if (token.type == T_EOF) { - errorf(HERE, "EOF while parsing struct"); - } next_token(); } @@ -6108,11 +6127,11 @@ static expression_t *parse_reference(void) } } - type_t *type = declaration->type; + type_t *orig_type = declaration->type; /* we always do the auto-type conversions; the & and sizeof parser contains * code to revert this! */ - type = automatic_type_conversion(type); + type_t *type = automatic_type_conversion(orig_type); ref->declaration = declaration; ref->base.type = type; @@ -6120,6 +6139,15 @@ static expression_t *parse_reference(void) /* this declaration is used */ declaration->used = true; + if (declaration->parent_scope != file_scope && + declaration->parent_scope->depth < current_function->scope.depth && + is_type_valid(orig_type) && !is_type_function(orig_type)) { + /* access of a variable from an outer function */ + declaration->address_taken = true; + ref->is_outer_ref = true; + current_function->need_closure = true; + } + /* check for deprecated functions */ if (warning.deprecated_declarations && declaration->modifiers & DM_DEPRECATED) { @@ -6611,7 +6639,6 @@ static expression_t *parse_compare_builtin(void) break; default: internal_errorf(HERE, "invalid compare builtin found"); - break; } expression->base.source_position = *HERE; next_token(); @@ -6701,7 +6728,10 @@ static declaration_t *get_label(symbol_t *symbol) 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); + if (candidate->parent_scope != scope) { + assert(candidate->parent_scope->depth < scope->depth); + current_function->goto_to_outer = true; + } return candidate; } @@ -7496,6 +7526,46 @@ static void semantic_unexpr_plus(unary_expression_t *expression) "traditional C rejects the unary plus operator"); } +static expression_t const *get_reference_address(expression_t const *expr) +{ + bool regular_take_address = true; + for (;;) { + if (expr->kind == EXPR_UNARY_TAKE_ADDRESS) { + expr = expr->unary.value; + } else { + regular_take_address = false; + } + + if (expr->kind != EXPR_UNARY_DEREFERENCE) + break; + + expr = expr->unary.value; + } + + if (expr->kind != EXPR_REFERENCE) + return NULL; + + if (!regular_take_address && + !is_type_function(skip_typeref(expr->reference.declaration->type))) { + return NULL; + } + + return expr; +} + +static void warn_function_address_as_bool(expression_t const* expr) +{ + if (!warning.address) + return; + + expr = get_reference_address(expr); + if (expr != NULL) { + warningf(&expr->base.source_position, + "the address of '%Y' will always evaluate as 'true'", + expr->reference.declaration->symbol); + } +} + static void semantic_not(unary_expression_t *expression) { type_t *const orig_type = expression->value->base.type; @@ -7505,6 +7575,8 @@ static void semantic_not(unary_expression_t *expression) "operand of ! must be of scalar type"); } + warn_function_address_as_bool(expression->value); + expression->base.type = type_int; } @@ -7852,6 +7924,22 @@ static void semantic_sub(binary_expression_t *expression) } } +static void warn_string_literal_address(expression_t const* expr) +{ + while (expr->kind == EXPR_UNARY_TAKE_ADDRESS) { + expr = expr->unary.value; + if (expr->kind != EXPR_UNARY_DEREFERENCE) + return; + expr = expr->unary.value; + } + + if (expr->kind == EXPR_STRING_LITERAL || + expr->kind == EXPR_WIDE_STRING_LITERAL) { + warningf(&expr->base.source_position, + "comparison with string literal results in unspecified behaviour"); + } +} + /** * Check the semantics of comparison expressions. * @@ -7859,13 +7947,32 @@ static void semantic_sub(binary_expression_t *expression) */ static void semantic_comparison(binary_expression_t *expression) { - expression_t *left = expression->left; - expression_t *right = expression->right; - type_t *orig_type_left = left->base.type; - type_t *orig_type_right = right->base.type; + expression_t *left = expression->left; + expression_t *right = expression->right; - type_t *type_left = skip_typeref(orig_type_left); - type_t *type_right = skip_typeref(orig_type_right); + if (warning.address) { + warn_string_literal_address(left); + warn_string_literal_address(right); + + expression_t const* const func_left = get_reference_address(left); + if (func_left != NULL && is_null_pointer_constant(right)) { + warningf(&expression->base.source_position, + "the address of '%Y' will never be NULL", + func_left->reference.declaration->symbol); + } + + expression_t const* const func_right = get_reference_address(right); + if (func_right != NULL && is_null_pointer_constant(right)) { + warningf(&expression->base.source_position, + "the address of '%Y' will never be NULL", + func_right->reference.declaration->symbol); + } + } + + type_t *orig_type_left = left->base.type; + type_t *orig_type_right = right->base.type; + type_t *type_left = skip_typeref(orig_type_left); + type_t *type_right = skip_typeref(orig_type_right); /* TODO non-arithmetic types */ if (is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) { @@ -8058,6 +8165,9 @@ static void semantic_logical_op(binary_expression_t *expression) type_t *const type_left = skip_typeref(orig_type_left); type_t *const type_right = skip_typeref(orig_type_right); + warn_function_address_as_bool(left); + warn_function_address_as_bool(right); + if (!is_type_scalar(type_left) || !is_type_scalar(type_right)) { /* TODO: improve error message */ if (is_type_valid(type_left) && is_type_valid(type_right)) { @@ -9069,9 +9179,8 @@ static statement_t *parse_for(void) PUSH_PARENT(statement); - int top = environment_top(); - scope_t *last_scope = scope; - set_scope(&statement->fors.scope); + size_t const top = environment_top(); + scope_push(&statement->fors.scope); expect('('); add_anchor_token(')'); @@ -9113,7 +9222,7 @@ static statement_t *parse_for(void) statement->fors.body = parse_loop_body(statement); assert(scope == &statement->fors.scope); - set_scope(last_scope); + scope_pop(); environment_pop_to(top); POP_PARENT; @@ -9123,7 +9232,7 @@ end_error: POP_PARENT; rem_anchor_token(')'); assert(scope == &statement->fors.scope); - set_scope(last_scope); + scope_pop(); environment_pop_to(top); return create_invalid_statement(); @@ -9174,6 +9283,10 @@ static statement_t *parse_goto(void) statement = allocate_statement_zero(STATEMENT_GOTO); statement->base.source_position = source_position; statement->gotos.label = get_label(symbol); + + if (statement->gotos.label->parent_scope->depth < current_function->scope.depth) { + statement->gotos.outer_fkt_jmp = true; + } } /* remember the goto's in a list for later checking */ @@ -9679,14 +9792,18 @@ static statement_t *parse_compound_statement(bool inside_expression_statement) eat('{'); add_anchor_token('}'); - int top = environment_top(); - int top_local = local_label_top(); - scope_t *last_scope = scope; - set_scope(&statement->compound.scope); + size_t const top = environment_top(); + size_t const top_local = local_label_top(); + scope_push(&statement->compound.scope); statement_t **anchor = &statement->compound.statements; bool only_decls_so_far = true; - while (token.type != '}' && token.type != T_EOF) { + while (token.type != '}') { + if (token.type == T_EOF) { + errorf(&statement->base.source_position, + "EOF while parsing compound statement"); + break; + } statement_t *sub_statement = intern_parse_statement(); if (is_invalid_statement(sub_statement)) { /* an error occurred. if we are at an anchor, return */ @@ -9711,13 +9828,7 @@ static statement_t *parse_compound_statement(bool inside_expression_statement) anchor = &sub_statement->base.next; } - - if (token.type == '}') { - next_token(); - } else { - errorf(&statement->base.source_position, - "end of file while looking for closing '}'"); - } + next_token(); /* look over all statements again to produce no effect warnings */ if (warning.unused_value) { @@ -9741,7 +9852,7 @@ static statement_t *parse_compound_statement(bool inside_expression_statement) end_error: rem_anchor_token('}'); assert(scope == &statement->compound.scope); - set_scope(last_scope); + scope_pop(); environment_pop_to(top); local_label_pop_to(top_local); @@ -9784,7 +9895,7 @@ static void check_unused_globals(void) if (!warning.unused_function && !warning.unused_variable) return; - for (const declaration_t *decl = global_scope->declarations; decl != NULL; decl = decl->next) { + for (const declaration_t *decl = file_scope->declarations; decl != NULL; decl = decl->next) { if (decl->used || decl->modifiers & DM_UNUSED || decl->modifiers & DM_USED || @@ -9832,11 +9943,17 @@ end_error:; */ static void parse_translation_unit(void) { + add_anchor_token(T_EOF); + +#ifndef NDEBUG + unsigned char token_anchor_copy[T_LAST_TOKEN]; + memcpy(token_anchor_copy, token_anchor_set, sizeof(token_anchor_copy)); +#endif for (;;) { #ifndef NDEBUG bool anchor_leak = false; for (int i = 0; i != T_LAST_TOKEN; ++i) { - unsigned char count = token_anchor_set[i]; + unsigned char count = token_anchor_set[i] - token_anchor_copy[i]; if (count != 0) { errorf(HERE, "Leaked anchor token %k %d times", i, count); anchor_leak = true; @@ -9863,6 +9980,7 @@ static void parse_translation_unit(void) break; case T_EOF: + rem_anchor_token(T_EOF); return; case ';': @@ -9901,24 +10019,25 @@ void start_parsing(void) assert(unit == NULL); unit = allocate_ast_zero(sizeof(unit[0])); - assert(global_scope == NULL); - global_scope = &unit->scope; + assert(file_scope == NULL); + file_scope = &unit->scope; assert(scope == NULL); - set_scope(&unit->scope); + scope_push(&unit->scope); initialize_builtin_types(); } translation_unit_t *finish_parsing(void) { + /* do NOT use scope_pop() here, this will crash, will it by hand */ assert(scope == &unit->scope); - scope = NULL; + scope = NULL; last_declaration = NULL; - assert(global_scope == &unit->scope); + assert(file_scope == &unit->scope); check_unused_globals(); - global_scope = NULL; + file_scope = NULL; DEL_ARR_F(environment_stack); DEL_ARR_F(label_stack);