revert accidental commit
[cparser] / parser.c
index 531d07f..4e37812 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -104,6 +104,7 @@ static goto_statement_t   *goto_first        = NULL;
 static goto_statement_t   *goto_last         = NULL;
 static label_statement_t  *label_first       = NULL;
 static label_statement_t  *label_last        = NULL;
+static translation_unit_t *unit              = NULL;
 static struct obstack      temp_obst;
 
 static source_position_t null_position = { NULL, 0 };
@@ -1096,7 +1097,6 @@ static gnu_attribute_t *allocate_gnu_attribute(gnu_attribute_kind_t kind) {
        attribute->have_arguments  = false;
 
        return attribute;
-       return attribute;
 }
 
 /**
@@ -2187,6 +2187,9 @@ static initializer_t *parse_sub_initializer(type_path_t *path,
                                = allocate_initializer_zero(INITIALIZER_DESIGNATOR);
                        designator_initializer->designator.designator = designator;
                        ARR_APP1(initializer_t*, initializers, designator_initializer);
+
+                       orig_type = path->top_type;
+                       type      = orig_type != NULL ? skip_typeref(orig_type) : NULL;
                }
 
                initializer_t *sub;
@@ -2325,14 +2328,14 @@ error_parse_next:
               len * sizeof(initializers[0]));
 
        DEL_ARR_F(initializers);
-       ascend_to(path, top_path_level);
+       ascend_to(path, top_path_level+1);
 
        return result;
 
 end_error:
        skip_initializers();
        DEL_ARR_F(initializers);
-       ascend_to(path, top_path_level);
+       ascend_to(path, top_path_level+1);
        return NULL;
 }
 
@@ -3815,11 +3818,15 @@ static declaration_t *internal_record_declaration(
        const symbol_t *const symbol  = declaration->symbol;
        const namespace_t     namespc = (namespace_t)declaration->namespc;
 
+       assert(declaration->symbol != NULL);
+       declaration_t *previous_declaration = get_declaration(symbol, namespc);
+
        type_t *const orig_type = declaration->type;
        type_t *const type      = skip_typeref(orig_type);
        if (is_type_function(type) &&
                        type->function.unspecified_parameters &&
-                       warning.strict_prototypes) {
+                       warning.strict_prototypes &&
+                       previous_declaration == NULL) {
                warningf(&declaration->source_position,
                         "function declaration '%#T' is not a prototype",
                         orig_type, declaration->symbol);
@@ -3829,105 +3836,103 @@ static declaration_t *internal_record_declaration(
                check_type_of_main(declaration, &type->function);
        }
 
-       assert(declaration->symbol != NULL);
-       declaration_t *previous_declaration = get_declaration(symbol, namespc);
-
        assert(declaration != previous_declaration);
-       if (previous_declaration != NULL) {
-               if (previous_declaration->parent_scope == scope) {
-                       /* can happen for K&R style declarations */
-                       if(previous_declaration->type == NULL) {
-                               previous_declaration->type = declaration->type;
+       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;
+               }
+
+               const type_t *prev_type = skip_typeref(previous_declaration->type);
+               if (!types_compatible(type, prev_type)) {
+                       errorf(&declaration->source_position,
+                                  "declaration '%#T' is incompatible with '%#T' (declared %P)",
+                                  orig_type, symbol, previous_declaration->type, symbol,
+                                  &previous_declaration->source_position);
+               } else {
+                       unsigned old_storage_class = previous_declaration->storage_class;
+                       if (old_storage_class == STORAGE_CLASS_ENUM_ENTRY) {
+                               errorf(&declaration->source_position,
+                                          "redeclaration of enum entry '%Y' (declared %P)",
+                                          symbol, &previous_declaration->source_position);
+                               return previous_declaration;
                        }
 
-                       const type_t *prev_type = skip_typeref(previous_declaration->type);
-                       if (!types_compatible(type, prev_type)) {
-                               errorf(&declaration->source_position,
-                                      "declaration '%#T' is incompatible with '%#T' (declared %P)",
-                                      orig_type, symbol, previous_declaration->type, symbol,
-                                  &previous_declaration->source_position);
-                       } else {
-                               unsigned old_storage_class = previous_declaration->storage_class;
-                               if(old_storage_class == STORAGE_CLASS_ENUM_ENTRY) {
-                                       errorf(&declaration->source_position,
-                                              "redeclaration of enum entry '%Y' (declared %P)",
-                                              symbol, &previous_declaration->source_position);
-                                       return previous_declaration;
-                               }
+                       unsigned new_storage_class = declaration->storage_class;
 
-                               unsigned new_storage_class = declaration->storage_class;
+                       if (is_type_incomplete(prev_type)) {
+                               previous_declaration->type = type;
+                               prev_type                  = type;
+                       }
 
-                               if(is_type_incomplete(prev_type)) {
+                       /* pretend no storage class means extern for function
+                        * declarations (except if the previous declaration is neither
+                        * none nor extern) */
+                       if (is_type_function(type)) {
+                               if (prev_type->function.unspecified_parameters) {
                                        previous_declaration->type = type;
                                        prev_type                  = type;
                                }
 
-                               /* pretend no storage class means extern for function
-                                * declarations (except if the previous declaration is neither
-                                * none nor extern) */
-                               if (is_type_function(type)) {
-                                       switch (old_storage_class) {
-                                               case STORAGE_CLASS_NONE:
-                                                       old_storage_class = STORAGE_CLASS_EXTERN;
-
-                                               case STORAGE_CLASS_EXTERN:
-                                                       if (is_function_definition) {
-                                                               if (warning.missing_prototypes &&
-                                                                   prev_type->function.unspecified_parameters &&
-                                                                   !is_sym_main(symbol)) {
-                                                                       warningf(&declaration->source_position,
-                                                                                "no previous prototype for '%#T'",
-                                                                                orig_type, symbol);
-                                                               }
-                                                       } else if (new_storage_class == STORAGE_CLASS_NONE) {
-                                                               new_storage_class = STORAGE_CLASS_EXTERN;
-                                                       }
-                                                       break;
-
-                                               default: break;
+                               switch (old_storage_class) {
+                               case STORAGE_CLASS_NONE:
+                                       old_storage_class = STORAGE_CLASS_EXTERN;
+
+                               case STORAGE_CLASS_EXTERN:
+                                       if (is_function_definition) {
+                                               if (warning.missing_prototypes &&
+                                                       prev_type->function.unspecified_parameters &&
+                                                       !is_sym_main(symbol)) {
+                                                       warningf(&declaration->source_position,
+                                                                        "no previous prototype for '%#T'",
+                                                                        orig_type, symbol);
+                                               }
+                                       } else if (new_storage_class == STORAGE_CLASS_NONE) {
+                                               new_storage_class = STORAGE_CLASS_EXTERN;
                                        }
+                                       break;
+
+                               default:
+                                       break;
                                }
+                       }
 
-                               if (old_storage_class == STORAGE_CLASS_EXTERN &&
-                                               new_storage_class == STORAGE_CLASS_EXTERN) {
+                       if (old_storage_class == STORAGE_CLASS_EXTERN &&
+                                       new_storage_class == STORAGE_CLASS_EXTERN) {
 warn_redundant_declaration:
-                                       if (warning.redundant_decls) {
-                                               warningf(&declaration->source_position,
-                                                        "redundant declaration for '%Y' (declared %P)",
-                                                        symbol, &previous_declaration->source_position);
-                                       }
-                               } else if (current_function == NULL) {
-                                       if (old_storage_class != STORAGE_CLASS_STATIC &&
-                                                       new_storage_class == STORAGE_CLASS_STATIC) {
-                                               errorf(&declaration->source_position,
-                                                      "static declaration of '%Y' follows non-static declaration (declared %P)",
-                                                      symbol, &previous_declaration->source_position);
-                                       } else {
-                                               if (old_storage_class != STORAGE_CLASS_EXTERN && !is_function_definition) {
-                                                       goto warn_redundant_declaration;
-                                               }
-                                               if (new_storage_class == STORAGE_CLASS_NONE) {
-                                                       previous_declaration->storage_class = STORAGE_CLASS_NONE;
-                                                       previous_declaration->declared_storage_class = STORAGE_CLASS_NONE;
-                                               }
-                                       }
-                               } 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);
-                                       }
+                               if (warning.redundant_decls && strcmp(previous_declaration->source_position.input_name, "<builtin>") != 0) {
+                                       warningf(&declaration->source_position,
+                                                        "redundant declaration for '%Y' (declared %P)",
+                                                        symbol, &previous_declaration->source_position);
+                               }
+                       } else if (current_function == NULL) {
+                               if (old_storage_class != STORAGE_CLASS_STATIC &&
+                                               new_storage_class == STORAGE_CLASS_STATIC) {
+                                       errorf(&declaration->source_position,
+                                                  "static declaration of '%Y' follows non-static declaration (declared %P)",
+                                                  symbol, &previous_declaration->source_position);
+                               } else if (old_storage_class != STORAGE_CLASS_EXTERN
+                                               && !is_function_definition) {
+                                       goto warn_redundant_declaration;
+                               } else if (new_storage_class == STORAGE_CLASS_NONE) {
+                                               previous_declaration->storage_class = STORAGE_CLASS_NONE;
+                                               previous_declaration->declared_storage_class = STORAGE_CLASS_NONE;
                                }
+                       } 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);
                        }
-
-                       if (declaration->is_inline)
-                               previous_declaration->is_inline = true;
-                       return previous_declaration;
                }
+
+               if (declaration->is_inline)
+                       previous_declaration->is_inline = true;
+               return previous_declaration;
        } else if (is_function_definition) {
                if (declaration->storage_class != STORAGE_CLASS_STATIC) {
                        if (warning.missing_prototypes && !is_sym_main(symbol)) {
@@ -4158,6 +4163,20 @@ static void parse_declaration(parsed_declaration_func finished_declaration)
        }
 }
 
+static type_t *get_default_promoted_type(type_t *orig_type)
+{
+       type_t *result = orig_type;
+
+       type_t *type = skip_typeref(orig_type);
+       if(is_type_integer(type)) {
+               result = promote_integer(type);
+       } else if(type == type_float) {
+               result = type_double;
+       }
+
+       return result;
+}
+
 static void parse_kr_declaration_list(declaration_t *declaration)
 {
        type_t *type = skip_typeref(declaration->type);
@@ -4216,6 +4235,11 @@ static void parse_kr_declaration_list(declaration_t *declaration)
                semantic_parameter(parameter_declaration);
                parameter_type = parameter_declaration->type;
 
+               /*
+                * we need the default promoted types for the function type
+                */
+               parameter_type = get_default_promoted_type(parameter_type);
+
                function_parameter_t *function_parameter
                        = obstack_alloc(type_obst, sizeof(function_parameter[0]));
                memset(function_parameter, 0, sizeof(function_parameter[0]));
@@ -4231,7 +4255,7 @@ static void parse_kr_declaration_list(declaration_t *declaration)
 
        /* ยง 6.9.1.7: A K&R style parameter list does NOT act as a function
         * prototype */
-       new_type->function.parameters = parameters;
+       new_type->function.parameters             = parameters;
        new_type->function.unspecified_parameters = true;
 
        type = typehash_insert(new_type);
@@ -4314,64 +4338,6 @@ static void check_declarations(void)
        }
 }
 
-/**
- * check all returns vor matching type.
- */
-static bool search_return_statements(statement_t *statement) {
-       switch(statement->kind) {
-       case STATEMENT_RETURN:
-               /* ok, found a return */
-               return true;
-       case STATEMENT_IF: {
-               /* return must be found on then and else */
-               if_statement_t *if_stat = &statement->ifs;
-               if(if_stat->true_statement != NULL && if_stat->false_statement != NULL) {
-                       return search_return_statements(if_stat->true_statement) &&
-                              search_return_statements(if_stat->false_statement);
-               }
-               break;
-       }
-       case STATEMENT_DO_WHILE: {
-               do_while_statement_t *do_stmt = &statement->do_while;
-               if(do_stmt->body != NULL) {
-                       if (search_return_statements(do_stmt->body))
-                               return true;
-               }
-               break;
-       }
-       case STATEMENT_COMPOUND: {
-               /* search the last statement */
-               compound_statement_t *compound = &statement->compound;
-               statement_t *statement = compound->statements;
-               if(statement == NULL)
-                       return false;
-               for( ; statement != NULL; statement = statement->base.next) {
-                       if (search_return_statements(statement))
-                               return true;
-               }
-               break;
-       }
-       default:
-               break;
-       }
-       return false;
-}
-
-/**
- * Check returns of a function.
- */
-static void check_return_type(declaration_t *declaration) {
-       function_type_t *function_type = &declaration->type->function;
-       type_t          *ret_type      = function_type->return_type;
-
-       if (ret_type != type_void) {
-               if (! search_return_statements(declaration->init.statement)) {
-                       warningf(HERE, "missing return statement at end of non-void function '%Y'",
-                                       declaration->symbol);
-               }
-       }
-}
-
 static void parse_external_declaration(void)
 {
        /* function-definitions and declarations both start with declaration
@@ -4483,7 +4449,6 @@ static void parse_external_declaration(void)
                assert(current_function == declaration);
                current_function = old_current_function;
                label_pop_to(label_stack_top);
-               check_return_type(declaration);
        }
 
 end_of_parse_external_declaration:
@@ -5898,17 +5863,20 @@ static expression_t *parse_call_expression(unsigned precedence,
        rem_anchor_token(')');
        expect(')');
 
-       if(function_type != NULL) {
-               function_parameter_t *parameter = function_type->parameters;
-               call_argument_t      *argument  = call->arguments;
+       if(function_type == NULL)
+               return result;
+
+       function_parameter_t *parameter = function_type->parameters;
+       call_argument_t      *argument  = call->arguments;
+       if (!function_type->unspecified_parameters) {
                for( ; parameter != NULL && argument != NULL;
                                parameter = parameter->next, argument = argument->next) {
                        type_t *expected_type = parameter->type;
                        /* TODO report scope in error messages */
                        expression_t *const arg_expr = argument->expression;
                        type_t       *const res_type = semantic_assign(expected_type, arg_expr,
-                                                                      "function call",
-                                                                      &arg_expr->base.source_position);
+                                                                                                                  "function call",
+                                                                                                                  &arg_expr->base.source_position);
                        if (res_type == NULL) {
                                /* TODO improve error message */
                                errorf(&arg_expr->base.source_position,
@@ -5918,37 +5886,26 @@ static expression_t *parse_call_expression(unsigned precedence,
                                argument->expression = create_implicit_cast(argument->expression, expected_type);
                        }
                }
-               /* too few parameters */
-               if(parameter != NULL) {
+
+               if (parameter != NULL) {
                        errorf(HERE, "too few arguments to function '%E'", expression);
-               } else if(argument != NULL) {
-                       /* too many parameters */
-                       if(!function_type->variadic
-                                       && !function_type->unspecified_parameters) {
-                               errorf(HERE, "too many arguments to function '%E'", expression);
-                       } else {
-                               /* do default promotion */
-                               for( ; argument != NULL; argument = argument->next) {
-                                       type_t *type = argument->expression->base.type;
-
-                                       type = skip_typeref(type);
-                                       if(is_type_integer(type)) {
-                                               type = promote_integer(type);
-                                       } else if(type == type_float) {
-                                               type = type_double;
-                                       }
+               } else if (argument != NULL && !function_type->variadic) {
+                       errorf(HERE, "too many arguments to function '%E'", expression);
+               }
+       }
 
-                                       argument->expression
-                                               = create_implicit_cast(argument->expression, type);
-                               }
+       /* do default promotion */
+       for( ; argument != NULL; argument = argument->next) {
+               type_t *type = argument->expression->base.type;
 
-                               check_format(&result->call);
-                       }
-               } else {
-                       check_format(&result->call);
-               }
+               type = get_default_promoted_type(type);
+
+               argument->expression
+                       = create_implicit_cast(argument->expression, type);
        }
 
+       check_format(&result->call);
+
        return result;
 end_error:
        return create_invalid_expression();
@@ -6972,13 +6929,13 @@ static void init_expression_parsers(void)
        register_infix_parser(parse_EXPR_UNARY_POSTFIX_DECREMENT,
                                                              T_MINUSMINUS,     30);
 
-       register_infix_parser(parse_EXPR_BINARY_MUL,          '*',              16);
-       register_infix_parser(parse_EXPR_BINARY_DIV,          '/',              16);
-       register_infix_parser(parse_EXPR_BINARY_MOD,          '%',              16);
-       register_infix_parser(parse_EXPR_BINARY_SHIFTLEFT,    T_LESSLESS,       16);
-       register_infix_parser(parse_EXPR_BINARY_SHIFTRIGHT,   T_GREATERGREATER, 16);
-       register_infix_parser(parse_EXPR_BINARY_ADD,          '+',              15);
-       register_infix_parser(parse_EXPR_BINARY_SUB,          '-',              15);
+       register_infix_parser(parse_EXPR_BINARY_MUL,          '*',              17);
+       register_infix_parser(parse_EXPR_BINARY_DIV,          '/',              17);
+       register_infix_parser(parse_EXPR_BINARY_MOD,          '%',              17);
+       register_infix_parser(parse_EXPR_BINARY_ADD,          '+',              16);
+       register_infix_parser(parse_EXPR_BINARY_SUB,          '-',              16);
+       register_infix_parser(parse_EXPR_BINARY_SHIFTLEFT,    T_LESSLESS,       15);
+       register_infix_parser(parse_EXPR_BINARY_SHIFTRIGHT,   T_GREATERGREATER, 15);
        register_infix_parser(parse_EXPR_BINARY_LESS,         '<',              14);
        register_infix_parser(parse_EXPR_BINARY_GREATER,      '>',              14);
        register_infix_parser(parse_EXPR_BINARY_LESSEQUAL,    T_LESSEQUAL,      14);
@@ -7544,7 +7501,7 @@ static statement_t *parse_goto(void)
        if(token.type != T_IDENTIFIER) {
                parse_error_expected("while parsing goto", T_IDENTIFIER, NULL);
                eat_statement();
-               return NULL;
+               goto end_error;
        }
        symbol_t *symbol = token.v.symbol;
        next_token();
@@ -7737,7 +7694,8 @@ static statement_t *parse_return(void)
                        }
                }
                /* check for returning address of a local var */
-               if (return_value->base.kind == EXPR_UNARY_TAKE_ADDRESS) {
+               if (return_value != NULL &&
+                               return_value->base.kind == EXPR_UNARY_TAKE_ADDRESS) {
                        const expression_t *expression = return_value->unary.value;
                        if (is_local_variable(expression)) {
                                warningf(&statement->base.source_position,
@@ -8109,18 +8067,8 @@ static void check_unused_globals(void)
 /**
  * Parse a translation unit.
  */
-static translation_unit_t *parse_translation_unit(void)
+static void parse_translation_unit(void)
 {
-       translation_unit_t *unit = allocate_ast_zero(sizeof(unit[0]));
-
-       assert(global_scope == NULL);
-       global_scope = &unit->scope;
-
-       assert(scope == NULL);
-       set_scope(&unit->scope);
-
-       initialize_builtin_types();
-
        while(token.type != T_EOF) {
                if (token.type == ';') {
                        /* TODO error in strict mode */
@@ -8130,16 +8078,6 @@ static translation_unit_t *parse_translation_unit(void)
                        parse_external_declaration();
                }
        }
-
-       assert(scope == &unit->scope);
-       scope          = NULL;
-       last_declaration = NULL;
-
-       assert(global_scope == &unit->scope);
-       check_unused_globals();
-       global_scope = NULL;
-
-       return unit;
 }
 
 /**
@@ -8147,7 +8085,7 @@ static translation_unit_t *parse_translation_unit(void)
  *
  * @return  the translation unit or NULL if errors occurred.
  */
-translation_unit_t *parse(void)
+void start_parsing(void)
 {
        environment_stack = NEW_ARR_F(stack_entry_t, 0);
        label_stack       = NEW_ARR_F(stack_entry_t, 0);
@@ -8158,16 +8096,43 @@ translation_unit_t *parse(void)
        type_set_output(stderr);
        ast_set_output(stderr);
 
-       lookahead_bufpos = 0;
-       for(int i = 0; i < MAX_LOOKAHEAD + 2; ++i) {
-               next_token();
-       }
-       translation_unit_t *unit = parse_translation_unit();
+       assert(unit == NULL);
+       unit = allocate_ast_zero(sizeof(unit[0]));
+
+       assert(global_scope == NULL);
+       global_scope = &unit->scope;
+
+       assert(scope == NULL);
+       set_scope(&unit->scope);
+
+       initialize_builtin_types();
+}
+
+translation_unit_t *finish_parsing(void)
+{
+       assert(scope == &unit->scope);
+       scope          = NULL;
+       last_declaration = NULL;
+
+       assert(global_scope == &unit->scope);
+       check_unused_globals();
+       global_scope = NULL;
 
        DEL_ARR_F(environment_stack);
        DEL_ARR_F(label_stack);
 
-       return unit;
+       translation_unit_t *result = unit;
+       unit = NULL;
+       return result;
+}
+
+void parse(void)
+{
+       lookahead_bufpos = 0;
+       for(int i = 0; i < MAX_LOOKAHEAD + 2; ++i) {
+               next_token();
+       }
+       parse_translation_unit();
 }
 
 /**