fixed some warnings
[cparser] / parser.c
index eedba78..fa8ad94 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -705,6 +705,27 @@ static expression_t *create_implicit_cast(expression_t *expression,
        panic("casting of non-atomic types not implemented yet");
 }
 
+static bool is_atomic_type(const type_t *type, atomic_type_type_t atype)
+{
+       if(type->type != TYPE_ATOMIC)
+               return false;
+       const atomic_type_t *atomic_type = (const atomic_type_t*) type;
+
+       return atomic_type->atype == atype;
+}
+
+static bool is_pointer(const type_t *type)
+{
+       return type->type == TYPE_POINTER;
+}
+
+static bool is_compound_type(const type_t *type)
+{
+       return type->type == TYPE_COMPOUND_STRUCT
+               || type->type == TYPE_COMPOUND_UNION;
+}
+
+/** Implements the rules from ยง 6.5.16.1 */
 static void semantic_assign(type_t *orig_type_left, expression_t **right,
                             const char *context)
 {
@@ -716,40 +737,52 @@ static void semantic_assign(type_t *orig_type_left, expression_t **right,
        type_t *const type_left  = skip_typeref(orig_type_left);
        type_t *const type_right = skip_typeref(orig_type_right);
 
-       if (type_left == type_right) {
-               return;
-       }
-
        if ((is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) ||
-           (type_left->type == TYPE_POINTER && is_null_expression(*right)) ||
-           (type_left->type == TYPE_POINTER && type_right->type == TYPE_POINTER)) {
+           (is_pointer(type_left) && is_null_expression(*right)) ||
+           (is_atomic_type(type_left, ATOMIC_TYPE_BOOL)
+               && is_pointer(type_right))) {
                *right = create_implicit_cast(*right, type_left);
                return;
        }
 
-       if (type_left->type == TYPE_POINTER) {
-               switch (type_right->type) {
-                       case TYPE_FUNCTION: {
-                               pointer_type_t *const ptr_type = (pointer_type_t*)type_left;
-                               if (ptr_type->points_to == type_right) {
-                                       return;
-                               }
-                               break;
-                       }
+       if (is_pointer(type_left) && is_pointer(type_right)) {
+               pointer_type_t *pointer_type_left  = (pointer_type_t*) type_left;
+               pointer_type_t *pointer_type_right = (pointer_type_t*) type_right;
+               type_t         *points_to_left     = pointer_type_left->points_to;
+               type_t         *points_to_right    = pointer_type_right->points_to;
 
-                       case TYPE_ARRAY: {
-                               pointer_type_t *const ptr_type = (pointer_type_t*)type_left;
-                               array_type_t   *const arr_type = (array_type_t*)type_right;
-                               if (ptr_type->points_to == arr_type->element_type) {
-                                       return;
-                               }
-                               break;
-                       }
+               if(!is_atomic_type(points_to_left, ATOMIC_TYPE_VOID)
+                               && !is_atomic_type(points_to_right, ATOMIC_TYPE_VOID)
+                               && !types_compatible(points_to_left, points_to_right)) {
+                       goto incompatible_assign_types;
+               }
 
-                       default: break;
+               /* the left type has all qualifiers from the right type */
+               unsigned missing_qualifiers
+                       = points_to_right->qualifiers & ~points_to_left->qualifiers;
+               if(missing_qualifiers != 0) {
+                       parser_print_error_prefix();
+                       fprintf(stderr, "destination type ");
+                       print_type_quoted(type_left);
+                       fprintf(stderr, " in %s from type ", context);
+                       print_type_quoted(type_right);
+                       fprintf(stderr, " lacks qualifiers '");
+                       print_type_qualifiers(missing_qualifiers);
+                       fprintf(stderr, "' in pointed-to type\n");
+                       return;
                }
+
+               *right = create_implicit_cast(*right, type_left);
+               return;
        }
 
+       if (is_compound_type(type_left)
+                       && types_compatible(type_left, type_right)) {
+               *right = create_implicit_cast(*right, type_left);
+               return;
+       }
+
+incompatible_assign_types:
        /* TODO: improve error message */
        parser_print_error_prefix();
        fprintf(stderr, "incompatible types in %s\n", context);
@@ -894,10 +927,24 @@ static designator_t *parse_designation(void)
 }
 #endif
 
+static initializer_t *initializer_from_string(array_type_t *type,
+                                              const char *string)
+{
+       /* TODO: check len vs. size of array type */
+       (void) type;
+
+       initializer_string_t *initializer
+               = allocate_ast_zero(sizeof(initializer[0]));
+
+       initializer->initializer.type = INITIALIZER_STRING;
+       initializer->string           = string;
+
+       return (initializer_t*) initializer;
+}
+
 static initializer_t *initializer_from_expression(type_t *type,
                                                   expression_t *expression)
 {
-       initializer_value_t *result = allocate_ast_zero(sizeof(result[0]));
 
        /* TODO check that expression is a constant expression */
 
@@ -914,15 +961,16 @@ static initializer_t *initializer_from_expression(type_t *type,
                        if(atype == ATOMIC_TYPE_CHAR
                                        || atype == ATOMIC_TYPE_SCHAR
                                        || atype == ATOMIC_TYPE_UCHAR) {
-                               /* it's fine TODO: check for length of string array... */
-                               goto initializer_from_expression_finished;
+
+                               string_literal_t *literal = (string_literal_t*) expression;
+                               return initializer_from_string(array_type, literal->value);
                        }
                }
        }
 
        semantic_assign(type, &expression, "initializer");
 
-initializer_from_expression_finished:
+       initializer_value_t *result = allocate_ast_zero(sizeof(result[0]));
        result->initializer.type = INITIALIZER_VALUE;
        result->value            = expression;
 
@@ -1024,6 +1072,8 @@ static initializer_t *parse_sub_initializer(type_t *type,
                        if(token.type == '}')
                                break;
                        expect_block(',');
+                       if(token.type == '}')
+                               break;
 
                        initializer_t *sub
                                = parse_sub_initializer(element_type, NULL, NULL);
@@ -2162,9 +2212,6 @@ static void parse_init_declarators(const declaration_specifiers_t *specifiers)
                        initializer_t *initializer = parse_initializer(type);
 
                        if(type->type == TYPE_ARRAY && initializer != NULL) {
-                               assert(initializer->type == INITIALIZER_LIST);
-
-                               initializer_list_t *list = (initializer_list_t*) initializer;
                                array_type_t       *array_type = (array_type_t*) type;
 
                                if(array_type->size == NULL) {
@@ -2172,7 +2219,17 @@ static void parse_init_declarators(const declaration_specifiers_t *specifiers)
 
                                        cnst->expression.type     = EXPR_CONST;
                                        cnst->expression.datatype = type_size_t;
-                                       cnst->v.int_value         = list->len;
+
+                                       if(initializer->type == INITIALIZER_LIST) {
+                                               initializer_list_t *list
+                                                       = (initializer_list_t*) initializer;
+                                               cnst->v.int_value = list->len;
+                                       } else {
+                                               assert(initializer->type == INITIALIZER_STRING);
+                                               initializer_string_t *string
+                                                       = (initializer_string_t*) initializer;
+                                               cnst->v.int_value = strlen(string->string) + 1;
+                                       }
 
                                        array_type->size = (expression_t*) cnst;
                                }
@@ -3605,19 +3662,31 @@ static void semantic_logical_op(binary_expression_t *expression)
 
 static void semantic_binexpr_assign(binary_expression_t *expression)
 {
-       expression_t *left       = expression->left;
-       type_t       *type_left  = left->datatype;
+       expression_t *left           = expression->left;
+       type_t       *orig_type_left = left->datatype;
 
-       if(type_left == NULL)
+       if(orig_type_left == NULL)
                return;
 
+       type_t *type_left = skip_typeref(orig_type_left);
+
        if (type_left->type == TYPE_ARRAY) {
                parse_error("Cannot assign to arrays.");
-       } else if (type_left != NULL) {
-               semantic_assign(type_left, &expression->right, "assignment");
+               return;
        }
 
-       expression->expression.datatype = type_left;
+       if(type_left->qualifiers & TYPE_QUALIFIER_CONST) {
+               parser_print_error_prefix();
+               fprintf(stderr, "assignment to readonly location '");
+               print_expression(left);
+               fprintf(stderr, "' (type ");
+               print_type_quoted(orig_type_left);
+               fprintf(stderr, ")\n");
+       }
+
+       semantic_assign(orig_type_left, &expression->right, "assignment");
+
+       expression->expression.datatype = orig_type_left;
 }
 
 static void semantic_comma(binary_expression_t *expression)