next up previous
Next: Associating types with identifiers Up: The C type system Previous: Conversions


Constraints on operators

Many of the subsections of Section 6.3 of the standard describe constraints on the types of operands that a given operator can have. This section formalizes those constraints, defining each C operator by an INDICATION. The constraints are described by a set of OPERators, each with a specific type signature. Each INDICATION is associated with a comma-separated list of the OPERators that satisfy the standard's constraints on that C operator.

Operators[19]:

INDICATION
  Subscript_Indication: Subscript_Op, Array_Subscript_Op, IndexString;
This macro is defined in definitions 19, 20, 21, 22, 23, 24, 25, 26, 27, and 28.
This macro is invoked in definition 4.

Distinct subscripting operations are defined for each array type and each pointer type other than TypeIs_VoidPointer. The second operand is specified to be a TypeIs_unsigned_long, although the standard specifies that it has integral type. Any integral type can be converted to TypeIs_unsigned_long by means of implicit conversions, so this specification is equivalent to that of the standard. The main reason for using TypeIs_unsigned_long is that OIL does not permit sets as operand specifications within a class definition, but a secondary reason is that this approach reduces the total number of operators in the compiler's database.

Operators[20]:

INDICATION
  Plus_Plus_Indication:   Increment_Op, Ptr_Inc_Op;
  Minus_Minus_Indication: Decrement_Op, Ptr_Dec_Op;

OPER
  Increment_Op, Decrement_Op(TypeIs_Arithmetic): TypeIs_Arithmetic;
This macro is defined in definitions 19, 20, 21, 22, 23, 24, 25, 26, 27, and 28.
This macro is invoked in definition 4.

Operators[21]:

INDICATION
  Star_Indication:  Ptr_Deref_Op, DerefString;
  Amper_Indication: Ptr_Ref_Op;
This macro is defined in definitions 19, 20, 21, 22, 23, 24, 25, 26, 27, and 28.
This macro is invoked in definition 4.

Operators[22]:

INDICATION
  Plus_Indication:   Plus_Op;
  Minus_Indication:  Minus_Op;
  Tilde_Indication:  Bitwise_Not_Op;
  Bang_Indication:   Logical_Not_Op;
  Sizeof_Indication: Sizeof_op;
  Cast_Indication:   Cast_Op, Cast_IntegraltoPtr, Cast_VoidPtrtoPtr,
                     Cast_VoidVoid, CScalartoVoid;

SET TypeIs_CastResult = TypeIs_Scalar;

OPER
  Plus_Op, Minus_Op(TypeIs_ArithPromoted):    TypeIs_ArithPromoted;
  Bitwise_Not_Op   (TypeIs_IntegralPromoted): TypeIs_IntegralPromoted;
  Logical_Not_Op   (TypeIs_Scalar):           TypeIs_int;
/* FIXME: sizeof is more constrained than this.  Also, it has different
  semantics in that the operand is not evaluated.  May need another kind
  of operator.
*/
  Sizeof_op        (TypeIs_void):             TypeIs_int;
  Cast_Op          (TypeIs_Scalar):           TypeIs_CastResult;
  Cast_VoidVoid    (TypeIs_void):             TypeIs_void;
This macro is defined in definitions 19, 20, 21, 22, 23, 24, 25, 26, 27, and 28.
This macro is invoked in definition 4.

By defining TypeIs_CastResult as being equal to TypeIs_Scalar and then using these two set identifiers in defining Cast_Op, the specification defines a cast from every element of TypeIs_Scalar to every other element of TypeIs_Scalar. If Cast_Op were defined with the signature (TypeIs_Scalar): TypeIs_Scalar then the operand and result would be constrained to be identical.

The definition of Cast_Op allows any pointer type to be cast to any integral type: There is an implicit conversion from any pointer type to TypeIs_VoidPointer, which is an element of TypeIs_Scalar, and every integral type is an element of TypeIs_CastResult.

Distinct cast operators are defined for each pointer type other than TypeIs_VoidPointer to handle casts from arbitrary integers and from TypeIs_VoidPointer to that pointer type. The operand of the former is specified to be a TypeIs_unsigned_long, although the standard specifies that it has integral type. Any integral type can be converted to TypeIs_unsigned_long by means of implicit conversions, so this specification is equivalent to that of the standard. The main reason for using TypeIs_unsigned_long is that OIL does not permit sets as operand specifications within a class definition, but a secondary reason is that this approach reduces the total number of operators in the compiler's database.

The implicit conversion from any pointer type to TypeIs_VoidPointer, combined with Cast_VoidPtrtoPtr, allows any pointer type to be cast to any other pointer type. (This includes pointers to function types.)

Operators[23]:

INDICATION
  Star_Indication:    MulOp;
  Slash_Indication:   DivOp;
  Percent_Indication: ModOp;
  Plus_Indication:    AddOp,
                      Void_Ptr_Add_Op, Void_Ptr_Rev_Add_Op,
                      Ptr_Add_Op,      Ptr_Rev_Add_Op;
  Minus_Indication:   SubOp,
                      Void_Ptr_Sub_Op, Ptr_Sub_Op, Ptr_Ptr_Sub_Op;

OPER
  MulOp, DivOp,
  AddOp, SubOp   (TypeIs_Arithmetic, TypeIs_Arithmetic): TypeIs_Arithmetic;
  ModOp          (TypeIs_Integral, TypeIs_Integral):     TypeIs_Integral;
  Void_Ptr_Add_Op,
  Void_Ptr_Sub_Op(TypeIs_VoidPointer, TypeIs_unsigned_long): TypeIs_VoidPointer;
  Void_Ptr_Rev_Add_Op
                 (TypeIs_unsigned_long, TypeIs_VoidPointer): TypeIs_VoidPointer;
This macro is defined in definitions 19, 20, 21, 22, 23, 24, 25, 26, 27, and 28.
This macro is invoked in definition 4.

Operators[24]:

INDICATION
  Less_Less_Indication:       Bit_Shift_Left_Op;
  Greater_Greater_Indication: Bit_Shift_Right_Op;
  Less_Indication:            LessThan_Op,       Ptr_LT_Op;
  Greater_Indication:         Greater_Op,        Ptr_GT_Op;
  Less_Equal_Indication:      LessThan_Equal_Op, Ptr_LTE_Op;
  Greater_Equal_Indication:   Greater_Equal_Op,  Ptr_GTE_Op;

SET TypeIs_ShiftCount = TypeIs_IntegralPromoted;

OPER
  Bit_Shift_Right_Op,
  Bit_Shift_Left_Op
    (TypeIs_IntegralPromoted, TypeIs_ShiftCount): TypeIs_IntegralPromoted;

  Greater_Op, LessThan_Op, Greater_Equal_Op,
  LessThan_Equal_Op(TypeIs_Scalar, TypeIs_Scalar): TypeIs_int;
This macro is defined in definitions 19, 20, 21, 22, 23, 24, 25, 26, 27, and 28.
This macro is invoked in definition 4.

Operators[25]:

INDICATION
  Equal_Equal_Indication: Equality_Op,  Ptr_Eq_Op;
  Bang_Equal_Indication:  Not_Equal_Op, Ptr_NEq_Op;

OPER
  Equality_Op, Not_Equal_Op(TypeIs_Scalar, TypeIs_Scalar): TypeIs_int;
This macro is defined in definitions 19, 20, 21, 22, 23, 24, 25, 26, 27, and 28.
This macro is invoked in definition 4.

Operators[26]:

INDICATION
  Amper_Indication:       Bitwise_And_Op;
  Caret_Indication:       Bitwise_XOr_Op;
  Bar_Indication:         Bitwise_Or_Op;
  Amper_Amper_Indication: Logical_And_Op;
  Bar_Bar_Indication:     Logical_Or_Op;  
  Conditional_Indication: Arith_Cond_Op, Void_Cond_Op, Ptr_Cond_Op;

SET TypeIs_RHS_Scalar = TypeIs_Scalar;

OPER
  Bitwise_And_Op, Bitwise_XOr_Op,
  Bitwise_Or_Op(TypeIs_Integral, TypeIs_Integral): TypeIs_Integral;
  Logical_And_Op,
  Logical_Or_Op(TypeIs_Scalar, TypeIs_RHS_Scalar): TypeIs_int;
  Arith_Cond_Op(TypeIs_Scalar,TypeIs_Arithmetic,TypeIs_Arithmetic): TypeIs_Arithmetic;
  Void_Cond_Op (TypeIs_Scalar,TypeIs_Void,TypeIs_Void): TypeIs_Void;
This macro is defined in definitions 19, 20, 21, 22, 23, 24, 25, 26, 27, and 28.
This macro is invoked in definition 4.

FIXME: The standard allows balancing of two compatible struct or union types. The best way to handle this is probably to have a common type that all such types can be coerced to, followed by more stringent testing.

Operators[27]:

INDICATION
   Equal_Indication:
     Assign_Op, Ptr_Assign_Op, Enum_Assign_Op,
     Struct_Assign_Op, Union_Assign_Op, Ptr_Void_Assign_Op,
     Ptr_Void_Void_Assign_Op;

SET TypeIs_RHS_Arithmetic = TypeIs_Arithmetic;

OPER
  Assign_Op(TypeIs_Arithmetic, TypeIs_RHS_Arithmetic): TypeIs_Arithmetic;
  Ptr_Void_Void_Assign_Op
    (TypeIs_VoidPointer, TypeIs_VoidPointer): TypeIs_VoidPointer;
This macro is defined in definitions 19, 20, 21, 22, 23, 24, 25, 26, 27, and 28.
This macro is invoked in definition 4.

Operators[28]:

INDICATION
  Star_Equal_Indication:            Mult_Eq_Op;
  Slash_Equal_Indication:           Div_Eq_Op;
  Percent_Equal_Indication:         Mod_Eq_Op;
  Plus_Equal_Indication:            Plus_Eq_Op,  Ptr_Plus_Eq_Op;  
  Minus_Equal_Indication:           Minus_Eq_Op, Ptr_Minus_Eq_Op;  
  Less_Less_Equal_Indication:       Bitwise_Shift_Left_Eq_Op;
  Greater_Greater_Equal_Indication: Bitwise_Shift_Right_Eq_Op;
  Amper_Equal_Indication:           Bitwise_And_Eq_Op;
  Caret_Equal_Indication:           Bitwise_XOr_Eq_Op;
  Bar_Equal_Indication:             Bitwise_Or_Eq_Op;

SET TypeIs_RHS_Integral = TypeIs_Integral;

OPER
  Mult_Eq_Op, Div_Eq_Op, Plus_Eq_Op,
  Minus_Eq_Op( TypeIs_Arithmetic, TypeIs_RHS_Arithmetic ) : TypeIs_Arithmetic;
  Mod_Eq_Op, Bitwise_Shift_Left_Eq_Op, Bitwise_Shift_Right_Eq_Op,
  Bitwise_And_Eq_Op, Bitwise_XOr_Eq_Op,
  Bitwise_Or_Eq_Op( TypeIs_Integral, TypeIs_RHS_Integral ) : TypeIs_Integral;
This macro is defined in definitions 19, 20, 21, 22, 23, 24, 25, 26, 27, and 28.
This macro is invoked in definition 4.


next up previous
Next: Associating types with identifiers Up: The C type system Previous: Conversions
2008-08-30