#ifndef WONKY_EXPRESSION_CONSTRAINTS_C
#define WONKY_EXPRESSION_CONSTRAINTS_C WONKY_EXPRESSION_CONSTRAINTS_C
#include <expression_constraints.h>
/*the operands of % shall both have an integer type 6.5.5*/
_Bool constraint_check_modulo_expression(struct AST_Expression *left,struct AST_Expression *right,struct Translation_Data *translation_data)
{
struct Type *left_type;
struct Type *right_type;
if(left->type==ERROR || right->type==ERROR)
return 0;
left_type=extract_expresion_value_type(left->value);
right_type=extract_expresion_value_type(right->value);
if(!type_is_integer_type(left_type))
{
push_translation_error("expected integer type in right operand of modulo operation",translation_data);
return 0;
}
if(!type_is_integer_type(right_type))
{
push_translation_error("expected integer type in right operand of modulo operation",translation_data);
return 0;
}
return 1;
}
/*constraints only on modulo operation 6.5.5*/
_Bool constraint_check_multiplicative_expression(struct AST_Expression *left,struct AST_Expression *right,enum AST_Type operation,struct Translation_Data *translation_data)
{
if(left->type==ERROR || right->type==ERROR)
return 0;
if(operation==OP_REMAINDER)
{
return constraint_check_modulo_expression(left,right,translation_data);
}else
{
struct Type *left_type;
struct Type *right_type;
left_type=extract_expresion_value_type(left->value);
right_type=extract_expresion_value_type(right->value);
if(type_is_arithmetic(left_type) && type_is_arithmetic(right_type))
{
return 1;
}else
{
push_translation_error("constraint check violation in multiplicative expression",translation_data);
return 0;
}
}
wonky_assert(SHOULD_NOT_REACH_HERE);
}
/*for addition both operands shall have arithmetic type, or one operand shall be of pointer type and the other of integer type.
* for subtraction one of the following shall hold
* both operands shall have arihtmetic type
* both operands are pointers to qualified or unqualified versions of compatible object types
* left operand is a pointer to an object type and the right operand has integer type*/
_Bool constraint_check_additive_expression(struct AST_Expression *left,struct AST_Expression *right,enum AST_Type operation,struct Translation_Data *translation_data)
{
struct Type *left_type;
struct Type *right_type;
if(left->type==ERROR || right->type==ERROR)
return 0;
wonky_assert(operation==OP_SUBTRACTION || operation==OP_ADDITION);
left_type=extract_expresion_value_type(left->value);
right_type=extract_expresion_value_type(right->value);
if(operation==OP_ADDITION) // operation is '+'
{
if(type_is_arithmetic(left_type))
{
if(type_is_arithmetic(right_type))
{
return 1;
}else if(type_is_pointer_to_object(right_type))
{
return 1;
}else
{
push_translation_error("unexpected type of right operand of addition",translation_data);
return 0;
}
}else if(type_is_pointer_to_object(left_type))
{
if(type_is_arithmetic(right_type))
{
return 1;
}else
{
push_translation_error("unexpected type of right operand of addition",translation_data);
return 0;
}
}else
{
push_translation_error("unexpected type of left operand of addition",translation_data);
return 0;
}
}else // operation is '-'
{
if(type_is_arithmetic(left_type) && type_is_arithmetic(right_type))
{
return 1;
}else if(type_is_pointer_to_object(left_type))
{
if(type_is_integer_type(right_type) || type_is_pointer_to_object(right_type))
{
return 1;
}else
{
push_translation_error("unexpected type of right operand of addition",translation_data);
return 0;
}
}else
{
push_translation_error("unexpected type of left operand of addition",translation_data);
return 0;
}
}
}
/*each of the operands shall have integer type 6.5.7*/
_Bool constraint_check_shift_expression(struct AST_Expression *left,struct AST_Expression *right,enum AST_Type operation,struct Translation_Data *translation_data)
{
struct Type *left_type;
struct Type *right_type;
if(left->type==ERROR || right->type==ERROR)
return 0;
left_type=extract_expresion_value_type(left->value);
right_type=extract_expresion_value_type(right->value);
if(type_is_integer_type(left_type) && type_is_integer_type(right_type))
{
return 1;
}else
{
push_translation_error("both operands of shift operation must be of integer type",translation_data);
return 0;
}
}
_Bool constraint_check_bitwise_expression(struct AST_Expression *left,struct AST_Expression *right,enum AST_Type operation,struct Translation_Data *translation_data)
{
if(left->type==ERROR || right->type==ERROR)
return 0;
return 1;
}
/*
* One of the following shall hold:
* both operands have real type
* both operands are pointers to qualified or unqualified versions of compatible object types
* both operands are pointers to qualified or unqualified versions of compatible incomplete type
*
* */
_Bool constraint_check_relational_operation(struct AST_Expression *left,struct AST_Expression *right,enum AST_Type operation,struct Translation_Data *translation_data)
{
if(left->type==ERROR || right->type==ERROR)
return 0;
return 1;
}
/* One of the following shall hold:
* both operands have arithmetic type
* both operands are pointers to qualified or unqualified versions of compatible types
* one operand is a pointer to object or incomplete type and the other is a pointer to a qualified or unqualified version of void
* one operand is a pointer and the other is a null pointer constant*/
_Bool constraint_check_equality_expression(struct AST_Expression *left,struct AST_Expression *right,struct Translation_Data *translation_data)
{
struct Type *left_type;
struct Type *right_type;
if(left->type==ERROR || right->type==ERROR)
return 0;
left_type=extract_expresion_value_type(left->value);
right_type=extract_expresion_value_type(right->value);
if(type_is_arithmetic(left_type) && type_is_arithmetic(right_type))
{
return 1;
}else if(type_is_pointer_to_object(left_type))
{
if(type_is_pointer_to_object(right_type))
{
if(types_are_compatible(left_type,right_type))
{
return 1;
}else
{
push_translation_error("checking for equality between pointers of incompatible types",translation_data);
return 0;
}
}else if(ast_is_null_pointer_constant((struct AST*)right) || type_is_pointer_to_void(right_type))
{
return 1;
}else
{
push_translation_error("rhs is not a pointer",translation_data);
return 0;
}
}else if(type_is_pointer_to_object(right_type))
{
if(ast_is_null_pointer_constant((struct AST*)left) || type_is_pointer_to_void(left_type))
return 1;
else
{
push_translation_error("lhs is not a pointer",translation_data);
return 0;
}
}else if(type_is_pointer_to_incomplete_type(left_type))
{
if(type_is_pointer_to_void(right_type) || ast_is_null_pointer_constant((struct AST*)right))
{
return 1;
}else
{
push_translation_error("rhs is not a pointer",translation_data);
return 0;
}
}else if(type_is_pointer_to_incomplete_type(right_type))
{
if(type_is_pointer_to_void(left_type) || ast_is_null_pointer_constant((struct AST*)left))
{
return 1;
}
else
{
push_translation_error("lhs is not a pointer",translation_data);
return 0;
}
}else if(left_type->specifier==TS_POINTER)
{
if(ast_is_null_pointer_constant((struct AST*)right))
{
return 1;
}else
{
push_translation_error("rhs is not a null constant",translation_data);
return 0;
}
}else if(right_type->specifier==TS_POINTER)
{
if(ast_is_null_pointer_constant((struct AST*)left))
{
return 1;
}else
{
push_translation_error("lhs is not a null constant",translation_data);
return 0;
}
}
}
/*each of the operands shall have scallar type 6.5.13 6.5.14*/
_Bool constraint_check_logical_expression(struct AST_Expression *left,struct AST_Expression *right,enum AST_Type operation,struct Translation_Data *translation_data)
{
struct Type *left_type;
struct Type *right_type;
if(left->type==ERROR || right->type==ERROR)
return 0;
left_type=extract_expresion_value_type(left->value);
right_type=extract_expresion_value_type(right->value);
if(type_is_scalar(left_type) && type_is_scalar(right_type))
{
return 1;
}else
{
push_translation_error("both operands of logical expression must be of scallar type",translation_data);
return 0;
}
}
/*
left operand is a modifiable lvalue
One of the following shall hold:
1. Left operand has qualified or unqualified arithmetic type and the
right has arithmetic type
2. The left operand has a qualified or unqualified version of a
structure or union type compatible with the type of the right
3. Both operands are pointers to qualified or unqualified versions
of compatible types, and the type pointed ot by the left has all
the qualifiers of the type pointed by the right
4. One operand is a pointer to an object to or incomplete type and the
other is a pointer to a qualified or unqualified version of void,
and the type pointed to by the left has all the qualifiers of the
type pointed to by the right
5. The left operand is a pointer and the right is a null pointer
constant
6. The left operand has type _Bool and
the right is a pointer
6.5.16.1
* */
_Bool constraint_check_simple_assignment_expression(struct AST_Expression *left,struct AST_Expression *right,struct Translation_Data *translation_data)
{
struct Type *left_type;
struct Type *right_type;
if(left->type==ERROR || right->type==ERROR)
return 0;
if(!expression_value_is_modifiable(left->value))
{
push_translation_error("left operand of assignment operator must be modifiable",translation_data);
return 0;
}
left_type=extract_expresion_value_type(left->value);
right_type=extract_expresion_value_type(right->value);
if(type_is_arithmetic(left_type) && type_is_arithmetic(right_type))
{
return 1;
}else if(type_is_struct_union(left_type) && types_are_compatible_unqualified(left_type,right_type))
{
return 1;
}else if(left_type->specifier==TS_POINTER && types_are_compatible_unqualified(left_type,right_type))
{
return 1;
}else if(left_type->specifier==TS_POINTER && ast_is_null_pointer_constant((struct AST*)right))
{
return 1;
}else
{
push_translation_error("cannot assign %T to %T in simple assignment",translation_data,right_type,left_type);
return 0;
}
//TODO ADD _BOOL TS
}
/*
left operand is a modifiable lvalue
if += or -=
1. left operand shall be a pointer to an object and the right operand shall be of integer type
2. left operand shall be qualified or unqualified arithmetic type and the right shall be an arithmetic type
else
each operand shall have arithmetic type consistent with those allowed by the corresponding binary operator
6.5.16.2
*/
_Bool constraint_check_compound_assignment_expression(struct AST_Expression *left,struct AST_Expression *right,enum AST_Type operation,struct Translation_Data *translation_data)
{
struct Type *left_type;
struct Type *right_type;
if(left->type==ERROR || right->type==ERROR)
return 0;
if(!expression_value_is_modifiable(left->value))
{
push_translation_error("left operand of assignment operator must be modifiable",translation_data);
return 0;
}
switch(operation)
{
case OP_ADD_ASSIGN:
case OP_SUBTRACT_ASSIGN:
left_type=extract_expresion_value_type(left->value);
right_type=extract_expresion_value_type(right->value);
if(left_type->specifier==TS_POINTER && type_is_integer_type(right_type))
{
return 1;
}else if(type_is_arithmetic(left_type) && type_is_arithmetic(right_type))
{
return 1;
}else
{
push_translation_error("constraint check violation in compound assignment expression",translation_data);
return 0;
}
wonky_assert(SHOULD_NOT_REACH_HERE);
case OP_MULTIPLY_ASSIGN:
case OP_DIV_ASSIGN:
case OP_REMAINDER_ASSIGN:
return constraint_check_multiplicative_expression(left,right,operation,translation_data);
case OP_SHIFT_RIGHT_ASSIGN:
case OP_SHIFT_LEFT_ASSIGN:
return constraint_check_shift_expression(left,right,operation,translation_data);
case OP_AND_ASSIGN:
case OP_XOR_ASSIGN:
case OP_PIPE_ASSIGN:
return constraint_check_bitwise_expression(left,right,operation,translation_data);
default:
wonky_assert(SHOULD_NOT_REACH_HERE);
}
}
/*
none that I could see
*/
_Bool constraint_check_comma_expression(struct AST_Expression *left,struct AST_Expression *right,struct Translation_Data *translation_data)
{
if(left->type==ERROR || right->type==ERROR)
return 0;
return 1;
}
/*
one of the expressions shall have type pointer to object the other shall have integer
*/
_Bool constraint_check_array_subscript_expression(struct AST_Expression *left,struct AST_Expression *right,struct Translation_Data *translation_data)
{
struct Type *left_type;
struct Type *right_type;
if(left->type==ERROR || right->type==ERROR)
return 0;
left_type=extract_expresion_value_type(left->value);
right_type=extract_expresion_value_type(right->value);
if(type_is_pointer(left_type) && type_is_integer_type(right_type))
{
return 1;
}else if(type_is_pointer(right_type) && type_is_integer_type(left_type))
{
return 1;
}else
{
push_translation_error("constraint check violation in array subscript expression",translation_data);
return 0;
}
}
/*
left is (un)qualified struct or union, second is an id of a memeber of the struct or union
NOTE: we don't check if id is a member of the struct or union here
*/
_Bool constraint_check_struct_union_member_expression(struct AST_Expression *left,struct identifier *id,struct Translation_Data *translation_data)
{
struct Type *left_type;
if(left->type==ERROR)
return 0;
left_type=extract_expresion_value_type(left->value);
if(!type_is_struct_union(left_type))
{
push_translation_error("trying get struct/union member of non a %T type",translation_data,left_type);
}else
{
return 1;
}
}
/*
see above
*/
_Bool constraint_check_struct_union_member_trough_ptr_expression(struct AST_Expression *left,struct identifier *id,struct Translation_Data *translation_data)
{
struct Type *left_type;
if(left->type==ERROR)
return 0;
left_type=extract_expresion_value_type(left->value);
if(type_is_pointer_to_object(left_type))
{
left_type=((struct Type_Pointer*)left_type)->points_to;
return type_is_struct_union(left_type);
}else
{
push_translation_error("constraint check violation in member access expression",translation_data);
return 0;
}
}
/*
First operand shall have scaller type
One of the following shall hold for the second and third operands
both operands have arithmetic type
both operands have the same structure or union type
both operands have void type
both operands are pointers of (un)qualified versions of compatible types
one operand is a pointer and the other is a null pointer constant
one operand is a pointer to an object or incomplete type and the other is a pointer to a (un)qualified version of void
*/
_Bool constraint_check_conditional_expression(struct AST_Expression *left,struct AST_Expression *center,struct AST_Expression *right,struct Translation_Data *translation_data)
{
struct Type *left_type;
if(left->type==ERROR || center->type==ERROR || right->type==ERROR)
return 0;
left_type=extract_expresion_value_type(left->value);
if(!type_is_arithmetic(left_type))
{
push_translation_error("first operand of conditional expression must be of arithmetic type",translation_data);
return 0;
}else
{
struct Type *center_type;
struct Type *right_type;
right_type=extract_expresion_value_type(right->value);
center_type=extract_expresion_value_type(center->value);
if(type_is_arithmetic(right_type) && type_is_arithmetic(center_type))
{
return 1;
}else if(type_is_struct_union(center_type) && types_are_compatible(center_type,right_type))
{
return 1;
}else if(center_type->specifier==TS_VOID && right_type->specifier==TS_VOID)
{
return 1;
}else if(type_is_pointer(center_type) && types_are_compatible(center_type,right_type))
{
return 1;
}else if(type_is_pointer(center_type) && ast_is_null_pointer_constant((struct AST*)right))
{
return 1;
}else if(type_is_pointer(right_type) && ast_is_null_pointer_constant((struct AST*)center))
{
return 1;
}else if( (type_is_pointer_to_object(center_type) || type_is_pointer_to_incomplete_type(center_type)) && type_is_pointer_to_void(right_type))
{
return 1;
}else if( (type_is_pointer_to_object(center_type) || type_is_pointer_to_incomplete_type(center_type)) && type_is_pointer_to_void(right_type))
{
return 1;
}else
{
push_translation_error("constraint check violation in member contitional expression",translation_data);
return 0;
}
}
}
_Bool constraint_check_function_expression(struct AST_Function_Expression *proposed_function,struct Translation_Data *translation_data)
{
struct Type *expected_argument_type;
struct Type *given_argument_type;
struct Type_Pointer *proposed_function_pointer_type;
struct Type_Function *proposed_function_type;
size_t i;
if(proposed_function->type==ERROR || proposed_function->id->type==ERROR)
return 0;
proposed_function_pointer_type=(struct Type_Pointer*)extract_expresion_value_type(proposed_function->id->value);
if(proposed_function_pointer_type->specifier!=TS_POINTER)
{
push_translation_error("%T is not a pointer to function",translation_data,proposed_function_pointer_type);
return 0;
}
proposed_function_type=(struct Type_Function*)proposed_function_pointer_type->points_to;
if(proposed_function_pointer_type->specifier!=TS_POINTER)
{
push_translation_error("%T is not a function type",translation_data,proposed_function_type);
return 0;
}
if(proposed_function_type->is_variadic)
{
if(proposed_function_type->number_of_arguments>proposed_function->number_of_arguments)
{
push_translation_error("to little arguments given for variadic function",translation_data);
return 0;
}
}else if(proposed_function_type->number_of_arguments!=proposed_function->number_of_arguments)
{
push_translation_error("mismatching number of arguments",translation_data);
return 0;
}
for(i=0;i<proposed_function_type->number_of_arguments;++i)
{
if(proposed_function->arg_list[i]->type==ERROR)
return 0;
expected_argument_type=proposed_function_type->arguments[i]->object->type;
given_argument_type=extract_expresion_value_type(proposed_function->arg_list[i]->value);
if(!types_are_compatible_unqualified(expected_argument_type,given_argument_type))
{
push_translation_error("incompatible types of arguments",translation_data);
push_translation_note("expected %T, but got %T",translation_data,expected_argument_type,given_argument_type);
return 0;
}
}
return 1;
}
_Bool constraint_check_indirection_expression(struct AST_Expression *operand,struct Translation_Data *translation_data)
{
struct Type *operand_type;
if(operand->type==ERROR)
return 0;
operand_type=extract_expresion_value_type(operand->value);
if(operand_type->specifier==TS_POINTER)
{
return 1;
}else
{
push_translation_error("needs pointer type got %T instead",translation_data,operand_type);
return 0;
}
}
_Bool constraint_check_address_expression(struct AST_Expression *operand,struct Translation_Data *translation_data)
{
struct Type *operand_type;
if(operand->type==ERROR)
return 0;
operand_type=extract_expresion_value_type(operand->value);
if(operand->value->type==VALUE_FUNCTION_DESIGNATOR || operand->type==OP_ARR_SUBSCRIPT || operand->type==OP_DEREFERENCE)
{
return 1;
}else if(operand->value->type==VALUE_LVALUE)
{
struct Object *hold_operand_object;
hold_operand_object=((struct Expression_Value_LValue*)operand->value)->object;
if(hold_operand_object->kind==OBJECT_KIND_BITFIELD || hold_operand_object->storage_class==SCS_REGISTER)
{
push_translation_error("can't get the address of such an operand",translation_data);
return 0;
}else
{
return 1;
}
}else
{
push_translation_error("cast type needs to be of scalar type",translation_data);
return 0;
}
}
_Bool constraint_check_sizeof_by_type(struct Type *type)
{
if(type->specifier==TS_ERROR)
return 0;
else
return 1;
}
_Bool constraint_check_sizeof_expression(struct AST_Expression *expression,struct Translation_Data *translation_data)
{
if(expression->type==ERROR)
return 0;
else
return 1;
}
/*
* operand shall have arithmetic type
*/
_Bool constraint_check_unary_plus_minus(struct AST_Expression *operand,enum AST_Type operation,struct Translation_Data *translation_data)
{
struct Type *operand_type;
if(operand->type==ERROR)
return 0;
operand_type=extract_expresion_value_type(operand->value);
if(type_is_arithmetic(operand_type))
{
return 1;
}else
{
push_translation_error("operan of unary +/- must be of arithmetic type",translation_data);
return 0;
}
}
/*
* operand shall have integer type
*/
_Bool constraint_check_unary_bitwise_not(struct AST_Expression *operand,struct Translation_Data *translation_data)
{
struct Type *operand_type;
if(operand->type==ERROR)
return 0;
operand_type=extract_expresion_value_type(operand->value);
if(type_is_integer_type(operand_type))
{
return 1;
}else
{
push_translation_error("operand of unary ~ must be of integer type",translation_data);
return 0;
}
}
/*
* operand shall have scalar type
*/
_Bool constraint_check_unary_logical_not(struct AST_Expression *operand,struct Translation_Data *translation_data)
{
struct Type *operand_type;
if(operand->type==ERROR)
return 0;
operand_type=extract_expresion_value_type(operand->value);
if(type_is_scalar(operand_type))
{
return 1;
}else
{
push_translation_error("operand of unary ! operand must be of scallar type",translation_data);
return 0;
}
}
/*
operand is a modifiable lvalue and has a (un)qualified real or pointer type
* */
_Bool constraint_check_postfix_inc_dec_expression(struct AST_Expression *operand,enum AST_Type operation,struct Translation_Data *translation_data)
{
struct Type *operand_type;
if(operand->type==ERROR)
return 0;
if(!expression_value_is_modifiable(operand->value))
{
push_translation_error("expected modifiable lvalue as operand to the ++/-- operator",translation_data);
return 0;
}
operand_type=extract_expresion_value_type(operand->value);
if(type_is_real(operand_type) || type_is_pointer(operand_type))
{
return 1;
}else
{
push_translation_error("expected real or pointer type as the type of the operand in the ++/-- operator",translation_data);
return 0;
}
}
/*
operand is a modifiable lvalue and has a (un)qualified real or pointer type
* */
_Bool constraint_check_prefix_inc_dec_expression(struct AST_Expression *operand,enum AST_Type operation,struct Translation_Data *translation_data)
{
if(operand->type==ERROR)
return 0;
return constraint_check_postfix_inc_dec_expression(operand,operation,translation_data);
}
_Bool constraint_check_cast_expression(struct Type *type,struct AST_Expression *expression,struct Translation_Data *translation_data)
{
if(expression->type==ERROR || type->specifier==TS_ERROR)
return 0;
return 1;
}
#endif