2 test programs I had lying around here
[cparser] / parser.c
index 24f0a18..0e45442 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -50,6 +50,7 @@ static declaration_t  *last_declaration  = NULL;
 static declaration_t  *current_function  = NULL;
 static struct obstack  temp_obst;
 
+/** The current source position. */
 #define HERE token.source_position
 
 static type_t *type_valist;
@@ -627,7 +628,7 @@ static int get_rank(const type_t *type)
 
        assert(type->kind == TYPE_ATOMIC);
        const atomic_type_t *atomic_type = &type->atomic;
-       atomic_type_type_t   atype       = atomic_type->atype;
+       atomic_type_kind_t   atype       = atomic_type->akind;
        return atype;
 }
 
@@ -1007,7 +1008,7 @@ static initializer_t *initializer_from_expression(type_t *type,
                if (element_type->kind == TYPE_ATOMIC) {
                        switch (expression->kind) {
                                case EXPR_STRING_LITERAL:
-                                       if (element_type->atomic.atype == ATOMIC_TYPE_CHAR) {
+                                       if (element_type->atomic.akind == ATOMIC_TYPE_CHAR) {
                                                return initializer_from_string(array_type,
                                                        expression->string.value);
                                        }
@@ -1280,7 +1281,7 @@ static initializer_t *parse_initializer(type_t *type)
        return result;
 }
 
-
+static declaration_t *append_declaration(declaration_t *declaration);
 
 static declaration_t *parse_compound_type_specifier(bool is_struct)
 {
@@ -1329,7 +1330,11 @@ static declaration_t *parse_compound_type_specifier(bool is_struct)
                }
                declaration->source_position = token.source_position;
                declaration->symbol          = symbol;
-               record_declaration(declaration);
+               declaration->parent_context  = context;
+               if (symbol != NULL) {
+                       environment_push(declaration);
+               }
+               append_declaration(declaration);
        }
 
        if(token.type == '{') {
@@ -1424,6 +1429,7 @@ static type_t *parse_enum_specifier(void)
                declaration->namespc       = NAMESPACE_ENUM;
                declaration->source_position = token.source_position;
                declaration->symbol          = symbol;
+               declaration->parent_context  = context;
        }
 
        type_t *const type      = allocate_type_zero(TYPE_ENUM);
@@ -1433,7 +1439,10 @@ static type_t *parse_enum_specifier(void)
                if(declaration->init.is_defined) {
                        errorf(HERE, "multiple definitions of enum %Y", symbol);
                }
-               record_declaration(declaration);
+               if (symbol != NULL) {
+                       environment_push(declaration);
+               }
+               append_declaration(declaration);
                declaration->init.is_defined = 1;
 
                parse_enum_entries(&type->enumt);
@@ -1708,7 +1717,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
 finish_specifiers:
 
        if(type == NULL) {
-               atomic_type_type_t atomic_type;
+               atomic_type_kind_t atomic_type;
 
                /* match valid basic types */
                switch(type_specifiers) {
@@ -1819,7 +1828,7 @@ finish_specifiers:
                }
 
                type               = allocate_type_zero(TYPE_ATOMIC);
-               type->atomic.atype = atomic_type;
+               type->atomic.akind = atomic_type;
                newtype            = 1;
        } else {
                if(type_specifiers != 0) {
@@ -2314,6 +2323,11 @@ static declaration_t *internal_record_declaration(
        assert(declaration != previous_declaration);
        if (previous_declaration != NULL
                        && previous_declaration->parent_context == context) {
+               /* can happen for K&R style declarations */
+               if(previous_declaration->type == NULL) {
+                       previous_declaration->type = declaration->type;
+               }
+
                const type_t *const prev_type = skip_typeref(previous_declaration->type);
                if (!types_compatible(type, prev_type)) {
                        errorf(declaration->source_position,
@@ -2549,11 +2563,32 @@ static void parse_declaration_rest(declaration_t *ndeclaration,
 
 static declaration_t *finished_kr_declaration(declaration_t *declaration)
 {
-       /* TODO: check that it was actually a parameter that gets a type */
+       symbol_t *symbol  = declaration->symbol;
+       if(symbol == NULL) {
+               errorf(HERE, "anonymous declaration not valid as function parameter");
+               return declaration;
+       }
+       namespace_t namespc = (namespace_t) declaration->namespc;
+       if(namespc != NAMESPACE_NORMAL) {
+               return record_declaration(declaration);
+       }
+
+       declaration_t *previous_declaration = get_declaration(symbol, namespc);
+       if(previous_declaration == NULL ||
+                       previous_declaration->parent_context != context) {
+               errorf(HERE, "expected declaration of a function parameter, found '%Y'",
+                      symbol);
+               return declaration;
+       }
 
-       /* we should have a declaration for the parameter in the current
-        * scope */
-       return record_declaration(declaration);
+       if(previous_declaration->type == NULL) {
+               previous_declaration->type           = declaration->type;
+               previous_declaration->storage_class  = declaration->storage_class;
+               previous_declaration->parent_context = context;
+               return previous_declaration;
+       } else {
+               return record_declaration(declaration);
+       }
 }
 
 static void parse_declaration(parsed_declaration_func finished_declaration)
@@ -2690,7 +2725,8 @@ static void parse_external_declaration(void)
        /* note that we don't skip typerefs: the standard doesn't allow them here
         * (so we can't use is_type_function here) */
        if(type->kind != TYPE_FUNCTION) {
-               errorf(HERE, "declarator '%#T' has a body but is not a function type", type, ndeclaration->symbol);
+               errorf(HERE, "declarator '%#T' has a body but is not a function type",
+                      type, ndeclaration->symbol);
                eat_block();
                return;
        }
@@ -2721,7 +2757,11 @@ static void parse_external_declaration(void)
 
        declaration_t *parameter = declaration->context.declarations;
        for( ; parameter != NULL; parameter = parameter->next) {
-               assert(parameter->parent_context == NULL || parameter->parent_context == context);
+               if(parameter->parent_context == &ndeclaration->context) {
+                       parameter->parent_context = context;
+               }
+               assert(parameter->parent_context == NULL
+                               || parameter->parent_context == context);
                parameter->parent_context = context;
                environment_push(parameter);
        }
@@ -2943,10 +2983,17 @@ static declaration_t *create_implicit_function(symbol_t *symbol,
        declaration->source_position = source_position;
        declaration->parent_context  = global_context;
 
+       context_t *old_context = context;
+       set_context(global_context);
+
        environment_push(declaration);
+       /* prepend the declaration to the global declarations list */
        declaration->next     = context->declarations;
        context->declarations = declaration;
 
+       assert(context == global_context);
+       set_context(old_context);
+
        return declaration;
 }
 
@@ -3545,6 +3592,21 @@ static expression_t *parse_primary_expression(void)
        return create_invalid_expression();
 }
 
+/**
+ * Check if the expression has the character type and issue a warning then.
+ */
+static void check_for_char_index_type(const expression_t *expression) {
+       type_t *type      = expression->base.datatype;
+       type_t *base_type = skip_typeref(type);
+
+       if (base_type->base.kind == TYPE_ATOMIC) {
+               if (base_type->atomic.akind == ATOMIC_TYPE_CHAR) {
+                       warningf(expression->base.source_position,
+                               "array subscript has type '%T'", type);
+               }
+       }
+}
+
 static expression_t *parse_array_expression(unsigned precedence,
                                             expression_t *left)
 {
@@ -3572,12 +3634,14 @@ static expression_t *parse_array_expression(unsigned precedence,
                        return_type             = pointer->points_to;
                        array_access->array_ref = left;
                        array_access->index     = inside;
+                       check_for_char_index_type(inside);
                } else if(is_type_pointer(type_inside)) {
                        pointer_type_t *pointer = &type_inside->pointer;
                        return_type             = pointer->points_to;
                        array_access->array_ref = inside;
                        array_access->index     = left;
                        array_access->flipped   = true;
+                       check_for_char_index_type(left);
                } else {
                        errorf(HERE, "array access on object with non-pointer types '%T', '%T'", type_left, type_inside);
                }
@@ -4008,6 +4072,9 @@ static void semantic_dereference(unary_expression_t *expression)
        expression->expression.datatype = result_type;
 }
 
+/**
+ * Check the semantic of the address taken expression.
+ */
 static void semantic_take_addr(unary_expression_t *expression)
 {
        expression_t *value  = expression->value;
@@ -4021,6 +4088,11 @@ static void semantic_take_addr(unary_expression_t *expression)
                reference_expression_t *reference   = (reference_expression_t*) value;
                declaration_t          *declaration = reference->declaration;
                if(declaration != NULL) {
+                       if (declaration->storage_class == STORAGE_CLASS_REGISTER) {
+                               errorf(expression->expression.source_position,
+                                       "address of register variable '%Y' requested",
+                                       declaration->symbol);
+                       }
                        declaration->address_taken = 1;
                }
        }
@@ -4032,13 +4104,14 @@ static void semantic_take_addr(unary_expression_t *expression)
 static expression_t *parse_##unexpression_type(unsigned precedence)            \
 {                                                                              \
        eat(token_type);                                                           \
-                                                                               \
+                                                                                  \
        expression_t *unary_expression                                             \
                = allocate_expression_zero(unexpression_type);                         \
+       unary_expression->base.source_position = HERE;                             \
        unary_expression->unary.value = parse_sub_expression(precedence);          \
                                                                                   \
        sfunc(&unary_expression->unary);                                           \
-                                                                               \
+                                                                                  \
        return unary_expression;                                                   \
 }
 
@@ -4896,7 +4969,9 @@ static statement_t *parse_switch(void)
        statement->statement.source_position = token.source_position;
 
        expect('(');
-       statement->expression = parse_expression();
+       expression_t *const expr = parse_expression();
+       type_t       *const type = promote_integer(skip_typeref(expr->base.datatype));
+       statement->expression = create_implicit_cast(expr, type);
        expect(')');
        statement->body = parse_statement();
 
@@ -5047,6 +5122,38 @@ static statement_t *parse_break(void)
        return statement;
 }
 
+/**
+ * Check if a given declaration represents a local variable.
+ */
+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);
+               if(is_type_function(type)) {
+                       return false;
+               } else {
+                       return true;
+               }
+       }
+       default:
+               return false;
+       }
+}
+
+/**
+ * Check if a given expression represents a local variable.
+ */
+static bool is_local_variable(const expression_t *expression)
+{
+       if (expression->base.kind != EXPR_REFERENCE) {
+               return false;
+       }
+       const declaration_t *declaration = expression->reference.declaration;
+       return is_local_var_declaration(declaration);
+}
+
 /**
  * Parse a return statement.
  */
@@ -5081,16 +5188,26 @@ static statement_t *parse_return(void)
 
                if(is_type_atomic(return_type, ATOMIC_TYPE_VOID)
                                && !is_type_atomic(return_value_type, ATOMIC_TYPE_VOID)) {
-                       warningf(HERE, "'return' with a value, in function returning void");
+                       warningf(statement->statement.source_position,
+                               "'return' with a value, in function returning void");
                        return_value = NULL;
                } else {
                        if(return_type != NULL) {
                                semantic_assign(return_type, &return_value, "'return'");
                        }
                }
+               /* check for returning address of a local var */
+               if (return_value->base.kind == EXPR_UNARY_TAKE_ADDRESS) {
+                       const expression_t *expression = return_value->unary.value;
+                       if (is_local_variable(expression)) {
+                               warningf(statement->statement.source_position,
+                                       "function returns address of local variable");
+                       }
+               }
        } else {
                if(!is_type_atomic(return_type, ATOMIC_TYPE_VOID)) {
-                       warningf(HERE, "'return' without value, in function returning non-void");
+                       warningf(statement->statement.source_position,
+                               "'return' without value, in function returning non-void");
                }
        }
        statement->return_value = return_value;