return res;
}
+static declaration_t *allocate_declaration_zero(void)
+{
+ declaration_t *declaration = allocate_ast_zero(sizeof(*allocate_declaration_zero()));
+ declaration->type = type_error_type;
+ return declaration;
+}
+
/**
* Returns the size of a statement node.
*
size_t size = get_expression_struct_size(kind);
expression_t *res = allocate_ast_zero(size);
- res->base.kind = kind;
+ res->base.kind = kind;
+ res->base.datatype = type_error_type;
return res;
}
expression->base.source_position, source_type, dest_type);
return expression;
+ case TYPE_COMPOUND_STRUCT:
+ case TYPE_COMPOUND_UNION:
+ case TYPE_ERROR:
+ return expression;
+
default:
panic("casting of non-atomic types not implemented yet");
}
}
/** Implements the rules from § 6.5.16.1 */
-static void semantic_assign(type_t *orig_type_left, expression_t **right,
+static type_t *semantic_assign(type_t *orig_type_left,
+ const expression_t *const right,
const char *context)
{
- type_t *orig_type_right = (*right)->base.datatype;
+ type_t *const orig_type_right = right->base.datatype;
- if(orig_type_right == NULL)
- return;
+ if (!is_type_valid(orig_type_right))
+ return orig_type_right;
type_t *const type_left = skip_typeref(orig_type_left);
type_t *const type_right = skip_typeref(orig_type_right);
if ((is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) ||
- (is_type_pointer(type_left) && is_null_pointer_constant(*right)) ||
+ (is_type_pointer(type_left) && is_null_pointer_constant(right)) ||
(is_type_atomic(type_left, ATOMIC_TYPE_BOOL)
&& is_type_pointer(type_right))) {
- *right = create_implicit_cast(*right, type_left);
- return;
+ return orig_type_left;
}
if (is_type_pointer(type_left) && is_type_pointer(type_right)) {
= points_to_right->base.qualifiers & ~points_to_left->base.qualifiers;
if(missing_qualifiers != 0) {
errorf(HERE, "destination type '%T' in %s from type '%T' lacks qualifiers '%Q' in pointed-to type", type_left, context, type_right, missing_qualifiers);
- return;
+ return orig_type_left;
}
points_to_left = get_unqualified_type(points_to_left);
if(!is_type_atomic(points_to_left, ATOMIC_TYPE_VOID)
&& !is_type_atomic(points_to_right, ATOMIC_TYPE_VOID)
&& !types_compatible(points_to_left, points_to_right)) {
- goto incompatible_assign_types;
+ return NULL;
}
- *right = create_implicit_cast(*right, type_left);
- return;
+ return orig_type_left;
}
- if (is_type_compound(type_left)
- && types_compatible(type_left, type_right)) {
- *right = create_implicit_cast(*right, type_left);
- return;
+ if (is_type_compound(type_left) && is_type_compound(type_right)) {
+ type_t *const unqual_type_left = get_unqualified_type(type_left);
+ type_t *const unqual_type_right = get_unqualified_type(type_right);
+ if (types_compatible(unqual_type_left, unqual_type_right)) {
+ return orig_type_left;
+ }
}
-incompatible_assign_types:
- /* TODO: improve error message */
- errorf(HERE, "incompatible types in %s: '%T' <- '%T'",
- context, orig_type_left, orig_type_right);
+ return NULL;
}
static expression_t *parse_constant_expression(void)
{
symbol_t *const symbol = symbol_table_insert(name);
- declaration_t *declaration = allocate_ast_zero(sizeof(declaration[0]));
+ declaration_t *const declaration = allocate_declaration_zero();
declaration->namespc = NAMESPACE_NORMAL;
declaration->storage_class = STORAGE_CLASS_TYPEDEF;
declaration->type = type;
return typedef_type;
}
-static const char *parse_string_literals(void)
+static string_t parse_string_literals(void)
{
assert(token.type == T_STRING_LITERAL);
- const char *result = token.v.string;
+ string_t result = token.v.string;
next_token();
- while(token.type == T_STRING_LITERAL) {
- result = concat_strings(result, token.v.string);
+ while (token.type == T_STRING_LITERAL) {
+ result = concat_strings(&result, &token.v.string);
next_token();
}
#endif
static initializer_t *initializer_from_string(array_type_t *type,
- const char *string)
+ const string_t *const string)
{
/* TODO: check len vs. size of array type */
(void) type;
initializer_t *initializer = allocate_initializer_zero(INITIALIZER_STRING);
- initializer->string.string = string;
+ initializer->string.string = *string;
return initializer;
}
case EXPR_STRING_LITERAL:
if (element_type->atomic.akind == ATOMIC_TYPE_CHAR) {
return initializer_from_string(array_type,
- expression->string.value);
+ &expression->string.value);
}
case EXPR_WIDE_STRING_LITERAL: {
}
}
- type_t *expression_type = skip_typeref(expression->base.datatype);
- if(is_type_scalar(type) || types_compatible(type, expression_type)) {
- semantic_assign(type, &expression, "initializer");
-
- initializer_t *result = allocate_initializer_zero(INITIALIZER_VALUE);
- result->value.value = expression;
+ type_t *const res_type = semantic_assign(type, expression, "initializer");
+ if (res_type == NULL)
+ return NULL;
- return result;
- }
+ initializer_t *const result = allocate_initializer_zero(INITIALIZER_VALUE);
+ result->value.value = create_implicit_cast(expression, res_type);
- return NULL;
+ return result;
}
static initializer_t *parse_sub_initializer(type_t *type,
return result;
}
-static initializer_t *parse_initializer(type_t *type)
+static initializer_t *parse_initializer(type_t *const orig_type)
{
initializer_t *result;
- type = skip_typeref(type);
+ type_t *const type = skip_typeref(orig_type);
if(token.type != '{') {
expression_t *expression = parse_assignment_expression();
+ if (expression->base.datatype == NULL) {
+ /* something bad happens, don't produce further errors */
+ return NULL;
+ }
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.datatype, type);
+ expression, expression->base.datatype, orig_type);
}
return initializer;
}
}
if(declaration == NULL) {
- declaration = allocate_ast_zero(sizeof(declaration[0]));
-
- if(is_struct) {
- declaration->namespc = NAMESPACE_STRUCT;
- } else {
- declaration->namespc = NAMESPACE_UNION;
- }
+ declaration = allocate_declaration_zero();
+ declaration->namespc =
+ (is_struct ? NAMESPACE_STRUCT : NAMESPACE_UNION);
declaration->source_position = token.source_position;
declaration->symbol = symbol;
declaration->parent_context = context;
return;
}
- declaration_t *const entry = allocate_ast_zero(sizeof(entry[0]));
+ declaration_t *const entry = allocate_declaration_zero();
entry->storage_class = STORAGE_CLASS_ENUM_ENTRY;
entry->type = enum_type;
entry->symbol = token.v.symbol;
}
if(declaration == NULL) {
- declaration = allocate_ast_zero(sizeof(declaration[0]));
-
- declaration->namespc = NAMESPACE_ENUM;
+ declaration = allocate_declaration_zero();
+ declaration->namespc = NAMESPACE_ENUM;
declaration->source_position = token.source_position;
declaration->symbol = symbol;
declaration->parent_context = context;
}
break;
- /* TODO: if type != NULL for the following rules should issue
+ /* TODO: if is_type_valid(type) for the following rules should issue
* an error */
case T_struct: {
type = allocate_type_zero(TYPE_COMPOUND_STRUCT);
declaration_t *declarations = NULL;
declaration_t *last_declaration = NULL;
do {
- declaration_t *declaration = allocate_ast_zero(sizeof(declaration[0]));
-
+ declaration_t *const declaration = allocate_declaration_zero();
declaration->source_position = token.source_position;
declaration->symbol = token.v.symbol;
next_token();
static declaration_t *parse_declarator(
const declaration_specifiers_t *specifiers, bool may_be_abstract)
{
- type_t *type = specifiers->type;
- declaration_t *declaration = allocate_ast_zero(sizeof(declaration[0]));
+ declaration_t *const declaration = allocate_declaration_zero();
declaration->storage_class = specifiers->storage_class;
declaration->modifiers = specifiers->decl_modifiers;
declaration->is_inline = specifiers->is_inline;
construct_type_t *construct_type
= parse_inner_declarator(declaration, may_be_abstract);
+ type_t *const type = specifiers->type;
declaration->type = construct_declarator_type(construct_type, type);
if(construct_type != NULL) {
errorf(declaration->source_position, "static declaration of '%Y' follows non-static declaration", symbol);
errorf(previous_declaration->source_position, "previous declaration of '%Y' was here", symbol);
} else {
- if (old_storage_class != STORAGE_CLASS_EXTERN) {
+ if (old_storage_class != STORAGE_CLASS_EXTERN && !is_function_definition) {
goto warn_redundant_declaration;
}
if (new_storage_class == STORAGE_CLASS_NONE) {
return append_declaration(declaration);
}
+/**
+ * Check if a given type is a vilid array type.
+ */
+static bool is_valid_array_type(const type_t *type) {
+ if (type->kind == TYPE_ARRAY) {
+ const array_type_t *array = &type->array;
+ const type_t *etype = skip_typeref(array->element_type);
+
+ if (! is_valid_array_type(etype))
+ return false;
+
+ if (etype->kind == TYPE_ATOMIC) {
+ const atomic_type_t *atype = &etype->atomic;
+
+ if (atype->akind == ATOMIC_TYPE_VOID) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
static declaration_t *record_declaration(declaration_t *declaration)
{
- return internal_record_declaration(declaration, false);
+ declaration = internal_record_declaration(declaration, false);
+ const type_t *type = skip_typeref(declaration->type);
+
+ /* check the type here for several not allowed combinations */
+ if (type->kind == TYPE_FUNCTION) {
+ const function_type_t* function_type = &type->function;
+ const type_t* ret_type = skip_typeref(function_type->return_type);
+
+ if (ret_type->kind == TYPE_FUNCTION) {
+ errorf(declaration->source_position, "'%Y' declared as function returning a function",
+ declaration->symbol);
+ declaration->type = type_error_type;
+ } else if (ret_type->kind == TYPE_ARRAY) {
+ errorf(declaration->source_position, "'%Y' declared as function returning an array",
+ declaration->symbol);
+ declaration->type = type_error_type;
+ }
+ }
+ if (! is_valid_array_type(type)) {
+ errorf(declaration->source_position, "declaration of '%Y' as array of voids",
+ declaration->symbol);
+ declaration->type = type_error_type;
+ }
+ return declaration;
}
static declaration_t *record_function_definition(declaration_t *const declaration)
eat('=');
type_t *orig_type = declaration->type;
- type_t *type = NULL;
- if(orig_type != NULL)
- type = skip_typeref(orig_type);
+ type_t *type = type = skip_typeref(orig_type);
if(declaration->init.initializer != NULL) {
parser_error_multiple_definition(declaration, token.source_position);
/* § 6.7.5 (22) array initializers for arrays with unknown size determine
* the array type size */
- if(type != NULL && is_type_array(type) && initializer != NULL) {
+ if(is_type_array(type) && initializer != NULL) {
array_type_t *array_type = &type->array;
if(array_type->size == NULL) {
case INITIALIZER_STRING: {
initializer_string_t *const string = &initializer->string;
- cnst->conste.v.int_value = strlen(string->string) + 1;
+ cnst->conste.v.int_value = string->string.size;
break;
}
}
}
- if(type != NULL && is_type_function(type)) {
+ if(is_type_function(type)) {
errorf(declaration->source_position,
"initializers not allowed for function types at declator '%Y' (type '%T')",
declaration->symbol, orig_type);
{
eat(';');
- declaration_t *declaration = allocate_ast_zero(sizeof(declaration[0]));
-
+ declaration_t *const declaration = allocate_declaration_zero();
declaration->type = specifiers->type;
declaration->storage_class = specifiers->storage_class;
declaration->source_position = specifiers->source_position;
type_t *orig_type = declaration->type;
type_t *type = skip_typeref(orig_type);
- if(type->kind != TYPE_FUNCTION && declaration->is_inline) {
+ if(is_type_valid(type) &&
+ type->kind != TYPE_FUNCTION && declaration->is_inline) {
warningf(declaration->source_position,
"variable '%Y' declared 'inline'\n", declaration->symbol);
}
type_t *type = make_bitfield_type(base_type, size);
- declaration = allocate_ast_zero(sizeof(declaration[0]));
-
+ declaration = allocate_declaration_zero();
declaration->namespc = NAMESPACE_NORMAL;
declaration->storage_class = STORAGE_CLASS_NONE;
declaration->source_position = token.source_position;
declaration->modifiers = specifiers->decl_modifiers;
declaration->type = type;
-
- record_declaration(declaration);
} else {
declaration = parse_declarator(specifiers,/*may_be_abstract=*/true);
return expression;
}
+/**
+ * Prints an error message if an expression was expected but not read
+ */
static expression_t *expected_expression_error(void)
{
- errorf(HERE, "expected expression, got token '%K'", &token);
-
+ /* skip the error message if the error token was read */
+ if (token.type != T_ERROR) {
+ errorf(HERE, "expected expression, got token '%K'", &token);
+ }
next_token();
return create_invalid_expression();
free_type(ntype);
}
- declaration_t *declaration = allocate_ast_zero(sizeof(declaration[0]));
-
+ declaration_t *const declaration = allocate_declaration_zero();
declaration->storage_class = STORAGE_CLASS_EXTERN;
declaration->type = type;
declaration->symbol = symbol;
expression->expression.kind = EXPR_FUNCTION;
expression->expression.datatype = type_string;
- expression->value = current_function->symbol->string;
return (expression_t*) expression;
}
expression->expression.kind = EXPR_PRETTY_FUNCTION;
expression->expression.datatype = type_string;
- expression->value = current_function->symbol->string;
return (expression_t*) expression;
}
type_t *base_type = skip_typeref(type);
if (base_type->base.kind == TYPE_ATOMIC) {
- if (base_type->atomic.akind == ATOMIC_TYPE_CHAR) {
+ switch (base_type->atomic.akind == ATOMIC_TYPE_CHAR) {
warningf(expression->base.source_position,
"array subscript has type '%T'", type);
}
function_type_t *function_type = NULL;
type_t *orig_type = expression->base.datatype;
- if(orig_type != NULL) {
+ if(is_type_valid(orig_type)) {
type_t *type = skip_typeref(orig_type);
if(is_type_pointer(type)) {
/* 6.5.15.2 */
type_t *condition_type_orig = expression->base.datatype;
- if(condition_type_orig != NULL) {
+ if(is_type_valid(condition_type_orig)) {
type_t *condition_type = skip_typeref(condition_type_orig);
- if(condition_type != NULL && !is_type_scalar(condition_type)) {
+ if(condition_type->kind != TYPE_ERROR && !is_type_scalar(condition_type)) {
type_error("expected a scalar type in conditional condition",
expression->base.source_position, condition_type_orig);
}
type_t *orig_true_type = true_expression->base.datatype;
type_t *orig_false_type = false_expression->base.datatype;
- if(orig_true_type == NULL || orig_false_type == NULL)
+ if(!is_type_valid(orig_true_type) || !is_type_valid(orig_false_type))
return result;
type_t *true_type = skip_typeref(orig_true_type);
static void semantic_incdec(unary_expression_t *expression)
{
type_t *orig_type = expression->value->base.datatype;
- if(orig_type == NULL)
+ if(!is_type_valid(orig_type))
return;
type_t *type = skip_typeref(orig_type);
static void semantic_unexpr_arithmetic(unary_expression_t *expression)
{
type_t *orig_type = expression->value->base.datatype;
- if(orig_type == NULL)
+ if(!is_type_valid(orig_type))
return;
type_t *type = skip_typeref(orig_type);
static void semantic_unexpr_scalar(unary_expression_t *expression)
{
type_t *orig_type = expression->value->base.datatype;
- if(orig_type == NULL)
+ if(!is_type_valid(orig_type))
return;
type_t *type = skip_typeref(orig_type);
static void semantic_unexpr_integer(unary_expression_t *expression)
{
type_t *orig_type = expression->value->base.datatype;
- if(orig_type == NULL)
+ if(!is_type_valid(orig_type))
return;
type_t *type = skip_typeref(orig_type);
static void semantic_dereference(unary_expression_t *expression)
{
type_t *orig_type = expression->value->base.datatype;
- if(orig_type == NULL)
+ if(!is_type_valid(orig_type))
return;
type_t *type = skip_typeref(orig_type);
value->base.datatype = revert_automatic_type_conversion(value);
type_t *orig_type = value->base.datatype;
- if(orig_type == NULL)
+ if(!is_type_valid(orig_type))
return;
if(value->kind == EXPR_REFERENCE) {
return;
}
- semantic_assign(orig_type_left, &expression->right, "assignment");
+ type_t *const res_type = semantic_assign(orig_type_left, expression->right,
+ "assignment");
+ if (res_type == NULL) {
+ errorf(expression->expression.source_position,
+ "cannot assign to '%T' from '%T'",
+ orig_type_left, expression->right->base.datatype);
+ } else {
+ expression->right = create_implicit_cast(expression->right, res_type);
+ }
expression->expression.datatype = orig_type_left;
}
}
/* otherwise we need to create a new one */
- declaration_t *declaration = allocate_ast_zero(sizeof(declaration[0]));
+ declaration_t *const declaration = allocate_declaration_zero();
declaration->namespc = NAMESPACE_LABEL;
declaration->symbol = symbol;
*/
static statement_t *parse_continue(void)
{
- statement_base_t *statement;
+ statement_t *statement;
if (current_loop == NULL) {
errorf(HERE, "continue statement not within loop");
statement = NULL;
} else {
- statement = allocate_ast_zero(sizeof(statement[0]));
- statement->kind = STATEMENT_CONTINUE;
- statement->source_position = token.source_position;
+ statement = allocate_statement_zero(STATEMENT_CONTINUE);
+
+ statement->base.source_position = token.source_position;
}
eat(T_continue);
expect(';');
- return (statement_t*)statement;
+ return statement;
}
/**
*/
static statement_t *parse_break(void)
{
- statement_base_t *statement;
+ statement_t *statement;
if (current_switch == NULL && current_loop == NULL) {
errorf(HERE, "break statement not within loop or switch");
statement = NULL;
} else {
- statement = allocate_ast_zero(sizeof(statement[0]));
- statement->kind = STATEMENT_BREAK;
- statement->source_position = token.source_position;
+ statement = allocate_statement_zero(STATEMENT_BREAK);
+
+ statement->base.source_position = token.source_position;
}
eat(T_break);
expect(';');
- return (statement_t*)statement;
+ return statement;
}
/**
"'return' with a value, in function returning void");
return_value = NULL;
} else {
- if(return_type != NULL) {
- semantic_assign(return_type, &return_value, "'return'");
+ if(is_type_valid(return_type)) {
+ if (return_value->base.datatype == NULL)
+ return (statement_t*)statement;
+
+ type_t *const res_type = semantic_assign(return_type,
+ return_value, "'return'");
+ if (res_type == NULL) {
+ errorf(statement->statement.source_position,
+ "cannot assign to '%T' from '%T'",
+ "cannot return something of type '%T' in function returning '%T'",
+ return_value->base.datatype, return_type);
+ } else {
+ return_value = create_implicit_cast(return_value, res_type);
+ }
}
}
/* check for returning address of a local var */