crude -g implementation
[cparser] / parser.c
index bb29247..6715131 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -31,7 +31,7 @@ typedef struct {
 typedef struct declaration_specifiers_t  declaration_specifiers_t;
 struct declaration_specifiers_t {
        source_position_t  source_position;
-       unsigned char      storage_class;
+       unsigned char      declared_storage_class;
        bool               is_inline;
        decl_modifiers_t   decl_modifiers;
        type_t            *type;
@@ -809,11 +809,12 @@ static type_t *make_global_typedef(const char *name, type_t *type)
        symbol_t *const symbol       = symbol_table_insert(name);
 
        declaration_t *const declaration = allocate_declaration_zero();
-       declaration->namespc         = NAMESPACE_NORMAL;
-       declaration->storage_class   = STORAGE_CLASS_TYPEDEF;
-       declaration->type            = type;
-       declaration->symbol          = symbol;
-       declaration->source_position = builtin_source_position;
+       declaration->namespc                = NAMESPACE_NORMAL;
+       declaration->storage_class          = STORAGE_CLASS_TYPEDEF;
+       declaration->declared_storage_class = STORAGE_CLASS_TYPEDEF;
+       declaration->type                   = type;
+       declaration->symbol                 = symbol;
+       declaration->source_position        = builtin_source_position;
 
        record_declaration(declaration);
 
@@ -1003,7 +1004,14 @@ static initializer_t *initializer_from_expression(type_t *orig_type,
        return result;
 }
 
-static initializer_t *parse_scalar_initializer(type_t *type)
+static bool is_initializer_constant(const expression_t *expression)
+{
+       return is_constant_expression(expression)
+               || is_address_constant(expression);
+}
+
+static initializer_t *parse_scalar_initializer(type_t *type,
+                                               bool must_be_constant)
 {
        /* there might be extra {} hierarchies */
        int braces = 0;
@@ -1015,7 +1023,13 @@ static initializer_t *parse_scalar_initializer(type_t *type)
                braces++;
        }
 
-       expression_t  *expression  = parse_assignment_expression();
+       expression_t *expression = parse_assignment_expression();
+       if(must_be_constant && !is_initializer_constant(expression)) {
+               errorf(expression->base.source_position,
+                      "Initialisation expression '%E' is not constant\n",
+                      expression);
+       }
+
        initializer_t *initializer = initializer_from_expression(type, expression);
 
        if(initializer == NULL) {
@@ -1056,11 +1070,13 @@ struct type_path_entry_t {
 typedef struct type_path_t type_path_t;
 struct type_path_t {
        type_path_entry_t *path;
-       type_t            *top_type;
+       type_t            *top_type;     /**< type of the element the path points */
+       size_t             max_index;    /**< largest index in outermost array */
        bool               invalid;
 };
 
-static __attribute__((unused)) void debug_print_type_path(const type_path_t *path)
+static __attribute__((unused)) void debug_print_type_path(
+               const type_path_t *path)
 {
        size_t len = ARR_LEN(path->path);
 
@@ -1304,7 +1320,7 @@ static void skip_initializers(void)
 }
 
 static initializer_t *parse_sub_initializer(type_path_t *path,
-               type_t *outer_type, size_t top_path_level)
+               type_t *outer_type, size_t top_path_level, bool must_be_constant)
 {
        type_t *orig_type = path->top_type;
        type_t *type      = skip_typeref(orig_type);
@@ -1340,12 +1356,13 @@ static initializer_t *parse_sub_initializer(type_path_t *path,
 
                if(token.type == '{') {
                        if(is_type_scalar(type)) {
-                               sub = parse_scalar_initializer(type);
+                               sub = parse_scalar_initializer(type, must_be_constant);
                        } else {
                                eat('{');
                                descend_into_subtype(path);
 
-                               sub = parse_sub_initializer(path, orig_type, top_path_level+1);
+                               sub = parse_sub_initializer(path, orig_type, top_path_level+1,
+                                                           must_be_constant);
 
                                ascend_from_subtype(path);
 
@@ -1355,6 +1372,12 @@ static initializer_t *parse_sub_initializer(type_path_t *path,
                        /* must be an expression */
                        expression_t *expression = parse_assignment_expression();
 
+                       if(must_be_constant && !is_initializer_constant(expression)) {
+                               errorf(expression->base.source_position,
+                                      "Initialisation expression '%E' is not constant\n",
+                                      expression);
+                       }
+
                        /* handle { "string" } special case */
                        if((expression->kind == EXPR_STRING_LITERAL
                                        || expression->kind == EXPR_WIDE_STRING_LITERAL)
@@ -1395,6 +1418,18 @@ static initializer_t *parse_sub_initializer(type_path_t *path,
                                descend_into_subtype(path);
                        }
                }
+
+               /* update largest index of top array */
+               const type_path_entry_t *first      = &path->path[0];
+               type_t                  *first_type = first->type;
+               first_type                          = skip_typeref(first_type);
+               if(is_type_array(first_type)) {
+                       size_t index = first->v.index;
+                       if(index > path->max_index)
+                               path->max_index = index;
+               }
+
+               /* append to initializers list */
                ARR_APP1(initializer_t*, initializers, sub);
 
                if(token.type == '}') {
@@ -1404,7 +1439,10 @@ static initializer_t *parse_sub_initializer(type_path_t *path,
                if(token.type == '}') {
                        break;
                }
+
                advance_current_object(path, top_path_level);
+               orig_type = path->top_type;
+               type      = skip_typeref(orig_type);
        }
 
        size_t len  = ARR_LEN(initializers);
@@ -1417,8 +1455,6 @@ static initializer_t *parse_sub_initializer(type_path_t *path,
 
        ascend_to(path, top_path_level);
 
-       /* TODO: if(is_global && !is_constant(...)) { error } */
-
        return result;
 
 end_error:
@@ -1428,52 +1464,81 @@ end_error:
        return NULL;
 }
 
-static initializer_t *parse_initializer(type_t *const orig_type)
-{
-       initializer_t *result;
-
-       type_t *const type = skip_typeref(orig_type);
+typedef struct parse_initializer_env_t {
+       type_t        *type;        /* the type of the initializer. In case of an
+                                      array type with unspecified size this gets
+                                      adjusted to the actual size. */
+       initializer_t *initializer; /* initializer will be filled in here */
+       bool           must_be_constant;
+} parse_initializer_env_t;
 
-       if(token.type != '{') {
-               expression_t  *expression  = parse_assignment_expression();
-               initializer_t *initializer = initializer_from_expression(type, expression);
-               if(initializer == NULL) {
-                       errorf(HERE,
-                               "initializer expression '%E' of type '%T' is incompatible with type '%T'",
-                               expression, expression->base.type, orig_type);
-               }
-               return initializer;
-       }
+static void parse_initializer(parse_initializer_env_t *env)
+{
+       type_t        *type   = skip_typeref(env->type);
+       initializer_t *result = NULL;
+       size_t         max_index;
 
        if(is_type_scalar(type)) {
                /* TODO: § 6.7.8.11; eat {} without warning */
-
-               result = parse_scalar_initializer(type);
-
-               if(token.type == ',')
-                       next_token();
-
-               return result;
+               result = parse_scalar_initializer(type, env->must_be_constant);
        } else if(token.type == '{') {
-               next_token();
+               eat('{');
 
                type_path_t path;
                memset(&path, 0, sizeof(path));
-               path.top_type = orig_type;
+               path.top_type = env->type;
                path.path     = NEW_ARR_F(type_path_entry_t, 0);
 
                descend_into_subtype(&path);
 
-               result = parse_sub_initializer(&path, orig_type, 1);
+               result = parse_sub_initializer(&path, env->type, 1,
+                                              env->must_be_constant);
 
+               max_index = path.max_index;
                DEL_ARR_F(path.path);
 
-               expect('}');
+               expect_void('}');
        } else {
-               /* TODO ... */
+               /* parse_scalar_initializer also works in this case: we simply
+                * have an expression without {} around it */
+               result = parse_scalar_initializer(type, env->must_be_constant);
        }
 
-       return result;
+       /* § 6.7.5 (22)  array initializers for arrays with unknown size determine
+        * the array type size */
+       if(is_type_array(type) && type->array.size_expression == NULL
+                       && result != NULL) {
+               size_t size;
+               switch (result->kind) {
+               case INITIALIZER_LIST:
+                       size = max_index + 1;
+                       break;
+
+               case INITIALIZER_STRING:
+                       size = result->string.string.size;
+                       break;
+
+               case INITIALIZER_WIDE_STRING:
+                       size = result->wide_string.string.size;
+                       break;
+
+               default:
+                       panic("invalid initializer type");
+               }
+
+               expression_t *cnst       = allocate_expression_zero(EXPR_CONST);
+               cnst->base.type          = type_size_t;
+               cnst->conste.v.int_value = size;
+
+               type_t *new_type = duplicate_type(type);
+
+               new_type->array.size_expression = cnst;
+               new_type->array.size_constant   = true;
+               new_type->array.size            = size;
+               env->type = new_type;
+       }
+
+       env->initializer = result;
 }
 
 static declaration_t *append_declaration(declaration_t *declaration);
@@ -1570,7 +1635,10 @@ static void parse_enum_entries(type_t *const enum_type)
 
                if(token.type == '=') {
                        next_token();
-                       entry->init.enum_value = parse_constant_expression();
+                       expression_t *value = parse_constant_expression();
+
+                       value = create_implicit_cast(value, enum_type);
+                       entry->init.enum_value = value;
 
                        /* TODO semantic */
                }
@@ -1753,13 +1821,13 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                switch(token.type) {
 
                /* storage class */
-#define MATCH_STORAGE_CLASS(token, class)                                \
-               case token:                                                      \
-                       if(specifiers->storage_class != STORAGE_CLASS_NONE) {        \
+#define MATCH_STORAGE_CLASS(token, class)                                  \
+               case token:                                                        \
+                       if(specifiers->declared_storage_class != STORAGE_CLASS_NONE) { \
                                errorf(HERE, "multiple storage classes in declaration specifiers"); \
-                       }                                                            \
-                       specifiers->storage_class = class;                           \
-                       next_token();                                                \
+                       }                                                              \
+                       specifiers->declared_storage_class = class;                    \
+                       next_token();                                                  \
                        break;
 
                MATCH_STORAGE_CLASS(T_typedef,  STORAGE_CLASS_TYPEDEF)
@@ -1769,22 +1837,22 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                MATCH_STORAGE_CLASS(T_register, STORAGE_CLASS_REGISTER)
 
                case T___thread:
-                       switch (specifiers->storage_class) {
-                               case STORAGE_CLASS_NONE:
-                                       specifiers->storage_class = STORAGE_CLASS_THREAD;
-                                       break;
+                       switch (specifiers->declared_storage_class) {
+                       case STORAGE_CLASS_NONE:
+                               specifiers->declared_storage_class = STORAGE_CLASS_THREAD;
+                               break;
 
-                               case STORAGE_CLASS_EXTERN:
-                                       specifiers->storage_class = STORAGE_CLASS_THREAD_EXTERN;
-                                       break;
+                       case STORAGE_CLASS_EXTERN:
+                               specifiers->declared_storage_class = STORAGE_CLASS_THREAD_EXTERN;
+                               break;
 
-                               case STORAGE_CLASS_STATIC:
-                                       specifiers->storage_class = STORAGE_CLASS_THREAD_STATIC;
-                                       break;
+                       case STORAGE_CLASS_STATIC:
+                               specifiers->declared_storage_class = STORAGE_CLASS_THREAD_STATIC;
+                               break;
 
-                               default:
-                                       errorf(HERE, "multiple storage classes in declaration specifiers");
-                                       break;
+                       default:
+                               errorf(HERE, "multiple storage classes in declaration specifiers");
+                               break;
                        }
                        next_token();
                        break;
@@ -2078,10 +2146,10 @@ static void semantic_parameter(declaration_t *declaration)
 {
        /* TODO: improve error messages */
 
-       if(declaration->storage_class == STORAGE_CLASS_TYPEDEF) {
+       if(declaration->declared_storage_class == STORAGE_CLASS_TYPEDEF) {
                errorf(HERE, "typedef not allowed in parameter list");
-       } else if(declaration->storage_class != STORAGE_CLASS_NONE
-                       && declaration->storage_class != STORAGE_CLASS_REGISTER) {
+       } else if(declaration->declared_storage_class != STORAGE_CLASS_NONE
+                       && declaration->declared_storage_class != STORAGE_CLASS_REGISTER) {
                errorf(HERE, "parameter may only have none or register storage class");
        }
 
@@ -2476,10 +2544,16 @@ static type_t *construct_declarator_type(construct_type_t *construct_list,
 static declaration_t *parse_declarator(
                const declaration_specifiers_t *specifiers, bool may_be_abstract)
 {
-       declaration_t *const declaration = allocate_declaration_zero();
-       declaration->storage_class  = specifiers->storage_class;
-       declaration->modifiers      = specifiers->decl_modifiers;
-       declaration->is_inline      = specifiers->is_inline;
+       declaration_t *const declaration    = allocate_declaration_zero();
+       declaration->declared_storage_class = specifiers->declared_storage_class;
+       declaration->modifiers              = specifiers->decl_modifiers;
+       declaration->is_inline              = specifiers->is_inline;
+
+       declaration->storage_class          = specifiers->declared_storage_class;
+       if(declaration->storage_class == STORAGE_CLASS_NONE
+                       && scope != global_scope) {
+               declaration->storage_class = STORAGE_CLASS_AUTO;
+       }
 
        construct_type_t *construct_type
                = parse_inner_declarator(declaration, may_be_abstract);
@@ -2671,6 +2745,7 @@ 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 {
@@ -2761,52 +2836,28 @@ static void parse_init_declarator_rest(declaration_t *declaration)
        eat('=');
 
        type_t *orig_type = declaration->type;
-       type_t *type      = type = skip_typeref(orig_type);
+       type_t *type      = skip_typeref(orig_type);
 
        if(declaration->init.initializer != NULL) {
                parser_error_multiple_definition(declaration, token.source_position);
        }
 
-       initializer_t *initializer = parse_initializer(type);
-
-       /* § 6.7.5 (22)  array initializers for arrays with unknown size determine
-        * the array type size */
-       if(is_type_array(type) && initializer != NULL) {
-               array_type_t *array_type = &type->array;
-
-               if(array_type->size_expression == NULL) {
-                       size_t size;
-                       switch (initializer->kind) {
-                               case INITIALIZER_LIST: {
-                                       /* TODO */
-                                       size = initializer->list.len;
-                                       break;
-                               }
-
-                               case INITIALIZER_STRING: {
-                                       size = initializer->string.string.size;
-                                       break;
-                               }
-
-                               case INITIALIZER_WIDE_STRING: {
-                                       size = initializer->wide_string.string.size;
-                                       break;
-                               }
-
-                               default: {
-                                       panic("invalid initializer type");
-                                       break;
-                               }
-                       }
+       bool must_be_constant = false;
+       if(declaration->storage_class == STORAGE_CLASS_STATIC
+                       || declaration->storage_class == STORAGE_CLASS_THREAD_STATIC
+                       || declaration->parent_scope == global_scope) {
+               must_be_constant = true;
+       }
 
-                       expression_t *cnst       = allocate_expression_zero(EXPR_CONST);
-                       cnst->base.type          = type_size_t;
-                       cnst->conste.v.int_value = size;
+       parse_initializer_env_t env;
+       env.type             = orig_type;
+       env.must_be_constant = must_be_constant;
+       parse_initializer(&env);
 
-                       array_type->size_expression = cnst;
-                       array_type->size_constant   = true;
-                       array_type->size            = size;
-               }
+       if(env.type != orig_type) {
+               orig_type         = env.type;
+               type              = skip_typeref(orig_type);
+               declaration->type = env.type;
        }
 
        if(is_type_function(type)) {
@@ -2814,7 +2865,7 @@ static void parse_init_declarator_rest(declaration_t *declaration)
                       "initializers not allowed for function types at declator '%Y' (type '%T')",
                       declaration->symbol, orig_type);
        } else {
-               declaration->init.initializer = initializer;
+               declaration->init.initializer = env.initializer;
        }
 }
 
@@ -2825,14 +2876,15 @@ static void parse_anonymous_declaration_rest(
 {
        eat(';');
 
-       declaration_t *const declaration = allocate_declaration_zero();
-       declaration->type            = specifiers->type;
-       declaration->storage_class   = specifiers->storage_class;
-       declaration->source_position = specifiers->source_position;
+       declaration_t *const declaration    = allocate_declaration_zero();
+       declaration->type                   = specifiers->type;
+       declaration->declared_storage_class = specifiers->declared_storage_class;
+       declaration->source_position        = specifiers->source_position;
 
-       if (declaration->storage_class != STORAGE_CLASS_NONE) {
+       if (declaration->declared_storage_class != STORAGE_CLASS_NONE) {
                warningf(declaration->source_position, "useless storage class in empty declaration");
        }
+       declaration->storage_class = STORAGE_CLASS_NONE;
 
        type_t *type = declaration->type;
        switch (type->kind) {
@@ -2907,6 +2959,7 @@ static declaration_t *finished_kr_declaration(declaration_t *declaration)
 
        if(previous_declaration->type == NULL) {
                previous_declaration->type          = declaration->type;
+               previous_declaration->declared_storage_class = declaration->declared_storage_class;
                previous_declaration->storage_class = declaration->storage_class;
                previous_declaration->parent_scope  = scope;
                return previous_declaration;
@@ -3252,12 +3305,13 @@ static void parse_compound_declarators(declaration_t *struct_declaration,
 
                        type_t *type = make_bitfield_type(base_type, size, source_position);
 
-                       declaration                  = allocate_declaration_zero();
-                       declaration->namespc         = NAMESPACE_NORMAL;
-                       declaration->storage_class   = STORAGE_CLASS_NONE;
-                       declaration->source_position = source_position;
-                       declaration->modifiers       = specifiers->decl_modifiers;
-                       declaration->type            = type;
+                       declaration                         = allocate_declaration_zero();
+                       declaration->namespc                = NAMESPACE_NORMAL;
+                       declaration->declared_storage_class = STORAGE_CLASS_NONE;
+                       declaration->storage_class          = STORAGE_CLASS_NONE;
+                       declaration->source_position        = source_position;
+                       declaration->modifiers              = specifiers->decl_modifiers;
+                       declaration->type                   = type;
                } else {
                        declaration = parse_declarator(specifiers,/*may_be_abstract=*/true);
 
@@ -3342,7 +3396,7 @@ static type_t *parse_typename(void)
        declaration_specifiers_t specifiers;
        memset(&specifiers, 0, sizeof(specifiers));
        parse_declaration_specifiers(&specifiers);
-       if(specifiers.storage_class != STORAGE_CLASS_NONE) {
+       if(specifiers.declared_storage_class != STORAGE_CLASS_NONE) {
                /* TODO: improve error message, user does probably not know what a
                 * storage class is...
                 */
@@ -3410,6 +3464,9 @@ static expression_t *parse_string_const(void)
                }
                if (token.type != T_WIDE_STRING_LITERAL) {
                        expression_t *const cnst = allocate_expression_zero(EXPR_STRING_LITERAL);
+                       /* note: that we use type_char_ptr here, which is already the
+                        * automatic converted type. revert_automatic_type_conversion
+                        * will construct the array type */
                        cnst->base.type    = type_char_ptr;
                        cnst->string.value = res;
                        return cnst;
@@ -3507,12 +3564,13 @@ static declaration_t *create_implicit_function(symbol_t *symbol,
                free_type(ntype);
        }
 
-       declaration_t *const declaration = allocate_declaration_zero();
-       declaration->storage_class   = STORAGE_CLASS_EXTERN;
-       declaration->type            = type;
-       declaration->symbol          = symbol;
-       declaration->source_position = source_position;
-       declaration->parent_scope  = global_scope;
+       declaration_t *const declaration    = allocate_declaration_zero();
+       declaration->storage_class          = STORAGE_CLASS_EXTERN;
+       declaration->declared_storage_class = STORAGE_CLASS_EXTERN;
+       declaration->type                   = type;
+       declaration->symbol                 = symbol;
+       declaration->source_position        = source_position;
+       declaration->parent_scope           = global_scope;
 
        scope_t *old_scope = scope;
        set_scope(global_scope);
@@ -3629,6 +3687,19 @@ type_t *revert_automatic_type_conversion(const expression_t *expression)
                        return type_left->pointer.points_to;
                }
 
+               case EXPR_STRING_LITERAL: {
+                       size_t size = expression->string.value.size;
+                       return make_array_type(type_char, size, TYPE_QUALIFIER_NONE);
+               }
+
+               case EXPR_WIDE_STRING_LITERAL: {
+                       size_t size = expression->wide_string.value.size;
+                       return make_array_type(type_wchar_t, size, TYPE_QUALIFIER_NONE);
+               }
+
+               case EXPR_COMPOUND_LITERAL:
+                       return expression->compound_literal.type;
+
                default: break;
        }
 
@@ -3689,8 +3760,14 @@ static expression_t *parse_compound_literal(type_t *type)
 {
        expression_t *expression = allocate_expression_zero(EXPR_COMPOUND_LITERAL);
 
+       parse_initializer_env_t env;
+       env.type             = type;
+       env.must_be_constant = false;
+       parse_initializer(&env);
+       type = env.type;
+
        expression->compound_literal.type        = type;
-       expression->compound_literal.initializer = parse_initializer(type);
+       expression->compound_literal.initializer = env.initializer;
        expression->base.type                    = automatic_type_conversion(type);
 
        return expression;
@@ -5878,7 +5955,6 @@ static statement_t *parse_break(void)
  */
 static bool is_local_var_declaration(const declaration_t *declaration) {
        switch ((storage_class_tag_t) declaration->storage_class) {
-       case STORAGE_CLASS_NONE:
        case STORAGE_CLASS_AUTO:
        case STORAGE_CLASS_REGISTER: {
                const type_t *type = skip_typeref(declaration->type);
@@ -5897,25 +5973,11 @@ static bool is_local_var_declaration(const declaration_t *declaration) {
  * Check if a given declaration represents a variable.
  */
 static bool is_var_declaration(const declaration_t *declaration) {
-       switch ((storage_class_tag_t) declaration->storage_class) {
-       case STORAGE_CLASS_NONE:
-       case STORAGE_CLASS_EXTERN:
-       case STORAGE_CLASS_STATIC:
-       case STORAGE_CLASS_AUTO:
-       case STORAGE_CLASS_REGISTER:
-       case STORAGE_CLASS_THREAD:
-       case STORAGE_CLASS_THREAD_EXTERN:
-       case STORAGE_CLASS_THREAD_STATIC: {
-               const type_t *type = skip_typeref(declaration->type);
-               if(is_type_function(type)) {
-                       return false;
-               } else {
-                       return true;
-               }
-       }
-       default:
+       if(declaration->storage_class == STORAGE_CLASS_TYPEDEF)
                return false;
-       }
+
+       const type_t *type = skip_typeref(declaration->type);
+       return !is_type_function(type);
 }
 
 /**