diff --git a/src/cc65/datatype.c b/src/cc65/datatype.c index 90bf892ba..6465c27a6 100644 --- a/src/cc65/datatype.c +++ b/src/cc65/datatype.c @@ -546,14 +546,14 @@ unsigned long GetIntegerTypeMax (const Type* Type) -static unsigned TypeOfBySize (const Type* Type) +static unsigned TypeOfBySize (unsigned Size) /* Get the code generator replacement type of the object by its size */ { unsigned NewType; /* If the size is less than or equal to that of a a long, we will copy ** the struct using the primary register, otherwise we use memcpy. */ - switch (SizeOf (Type)) { + switch (Size) { case 1: NewType = CF_CHAR; break; case 2: NewType = CF_INT; break; case 3: /* FALLTHROUGH */ @@ -566,125 +566,6 @@ static unsigned TypeOfBySize (const Type* Type) -Type* NewPointerTo (const Type* T) -/* Return a type string that is "pointer to T". The type string is allocated -** on the heap and may be freed after use. -*/ -{ - /* Get the size of the type string including the terminator */ - unsigned Size = TypeLen (T) + 1; - - /* Allocate the new type string */ - Type* P = TypeAlloc (Size + 1); - - /* Create the return type... */ - P[0].C = T_PTR | (T[0].C & T_QUAL_ADDRSIZE); - memcpy (P+1, T, Size * sizeof (Type)); - - /* ...and return it */ - return P; -} - - - -void PrintType (FILE* F, const Type* T) -/* Print fulle name of the type */ -{ - StrBuf Buf = AUTO_STRBUF_INITIALIZER; - fprintf (F, "%s", SB_GetConstBuf (GetFullTypeNameBuf (&Buf, T))); - SB_Done (&Buf); -} - - - -void PrintFuncSig (FILE* F, const char* Name, const Type* T) -/* Print a function signature */ -{ - StrBuf Buf = AUTO_STRBUF_INITIALIZER; - StrBuf ParamList = AUTO_STRBUF_INITIALIZER; - StrBuf East = AUTO_STRBUF_INITIALIZER; - StrBuf West = AUTO_STRBUF_INITIALIZER; - - /* Get the function descriptor used in definition */ - const FuncDesc* D = GetFuncDefinitionDesc (T); - - /* Get the parameter list string. Start from the first parameter */ - SymEntry* Param = D->SymTab->SymHead; - unsigned I; - for (I = 0; I < D->ParamCount; ++I) { - CHECK (Param != 0 && (Param->Flags & SC_PARAM) != 0); - if (I > 0) { - SB_AppendStr (&ParamList, ", "); - } - if (SymIsRegVar (Param)) { - SB_AppendStr (&ParamList, "register "); - } - if (!HasAnonName (Param)) { - SB_AppendStr (&Buf, Param->Name); - } - SB_AppendStr (&ParamList, SB_GetConstBuf (GetFullTypeNameBuf (&Buf, Param->Type))); - SB_Clear (&Buf); - /* Next argument */ - Param = Param->NextSym; - } - if ((D->Flags & FD_VARIADIC) == 0) { - if (D->ParamCount == 0 && (D->Flags & FD_EMPTY) == 0) { - SB_AppendStr (&ParamList, "void"); - } - } else { - if (D->ParamCount > 0) { - SB_AppendStr (&ParamList, ", ..."); - } else { - SB_AppendStr (&ParamList, "..."); - } - } - SB_Terminate (&ParamList); - - /* Get the function qualifiers */ - if (GetQualifierTypeCodeNameBuf (&Buf, T->C, T_QUAL_NONE) > 0) { - /* Append a space between the qualifiers and the name */ - SB_AppendChar (&Buf, ' '); - } - SB_Terminate (&Buf); - - /* Get the signature string without the return type */ - SB_Printf (&West, "%s%s (%s)", SB_GetConstBuf (&Buf), Name, SB_GetConstBuf (&ParamList)); - SB_Done (&Buf); - SB_Done (&ParamList); - - /* Complete with the return type */ - GetFullTypeNameWestEast (&West, &East, GetFuncReturn (T)); - SB_Append (&West, &East); - SB_Terminate (&West); - - /* Output */ - fprintf (F, "%s", SB_GetConstBuf (&West)); - SB_Done (&East); - SB_Done (&West); -} - - - -void PrintRawType (FILE* F, const Type* T) -/* Print a type string in raw hex format (for debugging) */ -{ - while (T->C != T_END) { - fprintf (F, "%04lX ", T->C); - ++T; - } - fprintf (F, "\n"); -} - - - -int TypeHasAttr (const Type* T) -/* Return true if the given type has attribute data */ -{ - return IsClassStruct (T) || IsTypeArray (T) || IsClassFunc (T); -} - - - const Type* GetUnderlyingType (const Type* Type) /* Get the underlying type of an enum or other integer class type */ { @@ -906,7 +787,7 @@ unsigned TypeOf (const Type* T) case T_STRUCT: case T_UNION: - NewType = TypeOfBySize (T); + NewType = TypeOfBySize (SizeOf (T)); if (NewType != CF_NONE) { return NewType; } @@ -968,6 +849,48 @@ Type* IndirectModifiable (Type* T) +Type* NewPointerTo (const Type* T) +/* Return a type string that is "pointer to T". The type string is allocated +** on the heap and may be freed after use. +*/ +{ + /* Get the size of the type string including the terminator */ + unsigned Size = TypeLen (T) + 1; + + /* Allocate the new type string */ + Type* P = TypeAlloc (Size + 1); + + /* Create the return type... */ + P[0].C = T_PTR | (T[0].C & T_QUAL_ADDRSIZE); + memcpy (P+1, T, Size * sizeof (Type)); + + /* ...and return it */ + return P; +} + + + +const Type* AddressOf (const Type* T) +/* Return a type string that is "address of T". The type string is allocated +** on the heap and may be freed after use. +*/ +{ + /* Get the size of the type string including the terminator */ + unsigned Size = TypeLen (T) + 1; + + /* Allocate the new type string */ + Type* P = TypeAlloc (Size + 1); + + /* Create the return type... */ + P[0].C = T_PTR | (T[0].C & T_QUAL_ADDRSIZE) | T_QUAL_CONST; + memcpy (P+1, T, Size * sizeof (Type)); + + /* ...and return it */ + return P; +} + + + Type* ArrayToPtr (const Type* T) /* Convert an array to a pointer to it's first element */ { @@ -977,6 +900,165 @@ Type* ArrayToPtr (const Type* T) +const Type* PtrConversion (const Type* T) +/* If the type is a function, convert it to pointer to function. If the +** expression is an array, convert it to pointer to first element. Otherwise +** return T. +*/ +{ + if (IsTypeFunc (T)) { + return AddressOf (T); + } else if (IsTypeArray (T)) { + return AddressOf (GetElementType (T)); + } else { + return T; + } +} + + + +const Type* IntPromotion (const Type* T) +/* Apply the integer promotions to T and return the result. The returned type +** string may be T if there is no need to change it. +*/ +{ + /* We must have an int to apply int promotions */ + PRECONDITION (IsClassInt (T)); + + /* https://port70.net/~nsz/c/c89/c89-draft.html#3.2.1.1 + ** A char, a short int, or an int bit-field, or their signed or unsigned varieties, or + ** an object that has enumeration type, may be used in an expression wherever an int or + ** unsigned int may be used. If an int can represent all values of the original type, + ** the value is converted to an int; otherwise it is converted to an unsigned int. + ** These are called the integral promotions. + */ + + if (IsTypeChar (T)) { + /* An integer can represent all values from either signed or unsigned char, so convert + ** chars to int. + */ + return type_int; + } else if (IsTypeShort (T)) { + /* An integer cannot represent all values from unsigned short, so convert unsigned short + ** to unsigned int. + */ + return IsSignUnsigned (T) ? type_uint : type_int; + } else if (!IsIncompleteESUType (T)) { + /* The type is a complete type not smaller than int, so leave it alone. */ + return T; + } else { + /* Otherwise, this is an incomplete enum, and there is expceted to be an error already. + ** Assume int to avoid further errors. + */ + return type_int; + } +} + + + +const Type* ArithmeticConvert (const Type* lhst, const Type* rhst) +/* Perform the usual arithmetic conversions for binary operators. */ +{ + /* https://port70.net/~nsz/c/c89/c89-draft.html#3.2.1.5 + ** Many binary operators that expect operands of arithmetic type cause conversions and yield + ** result types in a similar way. The purpose is to yield a common type, which is also the type + ** of the result. This pattern is called the usual arithmetic conversions. + */ + + /* There are additional rules for floating point types that we don't bother with, since + ** floating point types are not (yet) supported. + ** The integral promotions are performed on both operands. + */ + lhst = IntPromotion (lhst); + rhst = IntPromotion (rhst); + + /* If either operand has type unsigned long int, the other operand is converted to + ** unsigned long int. + */ + if ((IsTypeLong (lhst) && IsSignUnsigned (lhst)) || + (IsTypeLong (rhst) && IsSignUnsigned (rhst))) { + return type_ulong; + } + + /* Otherwise, if one operand has type long int and the other has type unsigned int, + ** if a long int can represent all values of an unsigned int, the operand of type unsigned int + ** is converted to long int ; if a long int cannot represent all the values of an unsigned int, + ** both operands are converted to unsigned long int. + */ + if ((IsTypeLong (lhst) && IsTypeInt (rhst) && IsSignUnsigned (rhst)) || + (IsTypeLong (rhst) && IsTypeInt (lhst) && IsSignUnsigned (lhst))) { + /* long can represent all unsigneds, so we are in the first sub-case. */ + return type_long; + } + + /* Otherwise, if either operand has type long int, the other operand is converted to long int. + */ + if (IsTypeLong (lhst) || IsTypeLong (rhst)) { + return type_long; + } + + /* Otherwise, if either operand has type unsigned int, the other operand is converted to + ** unsigned int. + */ + if ((IsTypeInt (lhst) && IsSignUnsigned (lhst)) || + (IsTypeInt (rhst) && IsSignUnsigned (rhst))) { + return type_uint; + } + + /* Otherwise, both operands have type int. */ + CHECK (IsTypeInt (lhst)); + CHECK (IsSignSigned (lhst)); + CHECK (IsTypeInt (rhst)); + CHECK (IsSignSigned (rhst)); + return type_int; +} + + + +const Type* SignedType (const Type* T) +/* Get signed counterpart of the integral type */ +{ + switch (GetUnderlyingTypeCode (T) & T_MASK_TYPE) { + case T_TYPE_CHAR: + return type_schar; + + case T_TYPE_INT: + case T_TYPE_SHORT: + return type_int; + + case T_TYPE_LONG: + return type_long; + + default: + Internal ("Unknown type code: %lX", GetUnderlyingTypeCode (T)); + return T; + } +} + + + +const Type* UnsignedType (const Type* T) +/* Get unsigned counterpart of the integral type */ +{ + switch (GetUnderlyingTypeCode (T) & T_MASK_TYPE) { + case T_TYPE_CHAR: + return type_uchar; + + case T_TYPE_INT: + case T_TYPE_SHORT: + return type_uint; + + case T_TYPE_LONG: + return type_ulong; + + default: + Internal ("Unknown type code: %lX", GetUnderlyingTypeCode (T)); + return T; + } +} + + + int IsClassObject (const Type* T) /* Return true if this is a fully described object type */ { @@ -1266,62 +1348,6 @@ void SetESUSymEntry (Type* T, struct SymEntry* S) -const Type* IntPromotion (const Type* T) -/* Apply the integer promotions to T and return the result. The returned type -** string may be T if there is no need to change it. -*/ -{ - /* We must have an int to apply int promotions */ - PRECONDITION (IsClassInt (T)); - - /* https://port70.net/~nsz/c/c89/c89-draft.html#3.2.1.1 - ** A char, a short int, or an int bit-field, or their signed or unsigned varieties, or an - ** object that has enumeration type, may be used in an expression wherever an int or - ** unsigned int may be used. If an int can represent all values of the original type, the value - ** is converted to an int; otherwise it is converted to an unsigned int. - ** These are called the integral promotions. - */ - - if (IsTypeChar (T)) { - /* An integer can represent all values from either signed or unsigned char, so convert - ** chars to int. - */ - return type_int; - } else if (IsTypeShort (T)) { - /* An integer cannot represent all values from unsigned short, so convert unsigned short - ** to unsigned int. - */ - return IsSignUnsigned (T) ? type_uint : type_int; - } else if (!IsIncompleteESUType (T)) { - /* The type is a complete type not smaller than int, so leave it alone. */ - return T; - } else { - /* Otherwise, this is an incomplete enum, and there is expceted to be an error already. - ** Assume int to avoid further errors. - */ - return type_int; - } -} - - - -const Type* PtrConversion (const Type* T) -/* If the type is a function, convert it to pointer to function. If the -** expression is an array, convert it to pointer to first element. Otherwise -** return T. -*/ -{ - if (IsTypeFunc (T)) { - return NewPointerTo (T); - } else if (IsTypeArray (T)) { - return ArrayToPtr (T); - } else { - return T; - } -} - - - TypeCode AddrSizeQualifier (unsigned AddrSize) /* Return T_QUAL_NEAR or T_QUAL_FAR depending on the address size */ { @@ -1339,3 +1365,101 @@ TypeCode AddrSizeQualifier (unsigned AddrSize) } } + + + +int TypeHasAttr (const Type* T) +/* Return true if the given type has attribute data */ +{ + return IsClassStruct (T) || IsTypeArray (T) || IsClassFunc (T); +} + + + +void PrintType (FILE* F, const Type* T) +/* Print fulle name of the type */ +{ + StrBuf Buf = AUTO_STRBUF_INITIALIZER; + fprintf (F, "%s", SB_GetConstBuf (GetFullTypeNameBuf (&Buf, T))); + SB_Done (&Buf); +} + + + +void PrintFuncSig (FILE* F, const char* Name, const Type* T) +/* Print a function signature */ +{ + StrBuf Buf = AUTO_STRBUF_INITIALIZER; + StrBuf ParamList = AUTO_STRBUF_INITIALIZER; + StrBuf East = AUTO_STRBUF_INITIALIZER; + StrBuf West = AUTO_STRBUF_INITIALIZER; + + /* Get the function descriptor used in definition */ + const FuncDesc* D = GetFuncDefinitionDesc (T); + + /* Get the parameter list string. Start from the first parameter */ + SymEntry* Param = D->SymTab->SymHead; + unsigned I; + for (I = 0; I < D->ParamCount; ++I) { + CHECK (Param != 0 && (Param->Flags & SC_PARAM) != 0); + if (I > 0) { + SB_AppendStr (&ParamList, ", "); + } + if (SymIsRegVar (Param)) { + SB_AppendStr (&ParamList, "register "); + } + if (!HasAnonName (Param)) { + SB_AppendStr (&Buf, Param->Name); + } + SB_AppendStr (&ParamList, SB_GetConstBuf (GetFullTypeNameBuf (&Buf, Param->Type))); + SB_Clear (&Buf); + /* Next argument */ + Param = Param->NextSym; + } + if ((D->Flags & FD_VARIADIC) == 0) { + if (D->ParamCount == 0 && (D->Flags & FD_EMPTY) == 0) { + SB_AppendStr (&ParamList, "void"); + } + } else { + if (D->ParamCount > 0) { + SB_AppendStr (&ParamList, ", ..."); + } else { + SB_AppendStr (&ParamList, "..."); + } + } + SB_Terminate (&ParamList); + + /* Get the function qualifiers */ + if (GetQualifierTypeCodeNameBuf (&Buf, T->C, T_QUAL_NONE) > 0) { + /* Append a space between the qualifiers and the name */ + SB_AppendChar (&Buf, ' '); + } + SB_Terminate (&Buf); + + /* Get the signature string without the return type */ + SB_Printf (&West, "%s%s (%s)", SB_GetConstBuf (&Buf), Name, SB_GetConstBuf (&ParamList)); + SB_Done (&Buf); + SB_Done (&ParamList); + + /* Complete with the return type */ + GetFullTypeNameWestEast (&West, &East, GetFuncReturn (T)); + SB_Append (&West, &East); + SB_Terminate (&West); + + /* Output */ + fprintf (F, "%s", SB_GetConstBuf (&West)); + SB_Done (&East); + SB_Done (&West); +} + + + +void PrintRawType (FILE* F, const Type* T) +/* Print a type string in raw hex format (for debugging) */ +{ + while (T->C != T_END) { + fprintf (F, "%04lX ", T->C); + ++T; + } + fprintf (F, "\n"); +} diff --git a/src/cc65/datatype.h b/src/cc65/datatype.h index af1c6b8e4..4729284bd 100644 --- a/src/cc65/datatype.h +++ b/src/cc65/datatype.h @@ -288,33 +288,6 @@ unsigned long GetIntegerTypeMax (const Type* Type); ** The type must have a known size. */ -Type* NewPointerTo (const Type* T); -/* Return a type string that is "pointer to T". The type string is allocated -** on the heap and may be freed after use. -*/ - -void PrintType (FILE* F, const Type* T); -/* Print fulle name of the type */ - -void PrintFuncSig (FILE* F, const char* Name, const Type* T); -/* Print a function signature */ - -void PrintRawType (FILE* F, const Type* T); -/* Print a type string in raw hex format (for debugging) */ - -int TypeHasAttr (const Type* T); -/* Return true if the given type has attribute data */ - -#if defined(HAVE_INLINE) -INLINE void CopyTypeAttr (const Type* Src, Type* Dest) -/* Copy attribute data from Src to Dest */ -{ - Dest->A = Src->A; -} -#else -# define CopyTypeAttr(Src, Dest) ((Dest)->A = (Src)->A) -#endif - #if defined(HAVE_INLINE) INLINE TypeCode UnqualifiedType (TypeCode T) /* Return the unqalified type code */ @@ -366,9 +339,39 @@ Type* IndirectModifiable (Type* T); ** given type points to. */ +Type* NewPointerTo (const Type* T); +/* Return a type string that is "pointer to T". The type string is allocated +** on the heap and may be freed after use. +*/ + +const Type* AddressOf (const Type* T); +/* Return a type string that is "address of T". The type string is allocated +** on the heap and may be freed after use. +*/ + Type* ArrayToPtr (const Type* T); /* Convert an array to a pointer to it's first element */ +const Type* PtrConversion (const Type* T); +/* If the type is a function, convert it to pointer to function. If the +** expression is an array, convert it to pointer to first element. Otherwise +** return T. +*/ + +const Type* IntPromotion (const Type* T); +/* Apply the integer promotions to T and return the result. The returned type +** string may be T if there is no need to change it. +*/ + +const Type* ArithmeticConvert (const Type* lhst, const Type* rhst); +/* Perform the usual arithmetic conversions for binary operators. */ + +const Type* SignedType (const Type* T); +/* Get signed counterpart of the integral type */ + +const Type* UnsignedType (const Type* T); +/* Get unsigned counterpart of the integral type */ + #if defined(HAVE_INLINE) INLINE TypeCode GetRawType (const Type* T) /* Get the raw type */ @@ -892,17 +895,6 @@ struct SymEntry* GetESUSymEntry (const Type* T) attribute ((const)); void SetESUSymEntry (Type* T, struct SymEntry* S); /* Set the SymEntry pointer for an enum/struct/union type */ -const Type* IntPromotion (const Type* T); -/* Apply the integer promotions to T and return the result. The returned type -** string may be T if there is no need to change it. -*/ - -const Type* PtrConversion (const Type* T); -/* If the type is a function, convert it to pointer to function. If the -** expression is an array, convert it to pointer to first element. Otherwise -** return T. -*/ - TypeCode AddrSizeQualifier (unsigned AddrSize); /* Return T_QUAL_NEAR or T_QUAL_FAR depending on the address size */ @@ -926,6 +918,28 @@ INLINE TypeCode DataAddrSizeQualifier (void) # define DataAddrSizeQualifier() (AddrSizeQualifier (DataAddrSize)) #endif +int TypeHasAttr (const Type* T); +/* Return true if the given type has attribute data */ + +#if defined(HAVE_INLINE) +INLINE void CopyTypeAttr (const Type* Src, Type* Dest) +/* Copy attribute data from Src to Dest */ +{ + Dest->A = Src->A; +} +#else +# define CopyTypeAttr(Src, Dest) ((Dest)->A = (Src)->A) +#endif + +void PrintType (FILE* F, const Type* T); +/* Print fulle name of the type */ + +void PrintFuncSig (FILE* F, const char* Name, const Type* T); +/* Print a function signature */ + +void PrintRawType (FILE* F, const Type* T); +/* Print a type string in raw hex format (for debugging) */ + /* End of datatype.h */ diff --git a/src/cc65/expr.c b/src/cc65/expr.c index b68b3abbb..729b26942 100644 --- a/src/cc65/expr.c +++ b/src/cc65/expr.c @@ -153,65 +153,6 @@ void MarkedExprWithCheck (void (*Func) (ExprDesc*), ExprDesc* Expr) -static const Type* ArithmeticConvert (const Type* lhst, const Type* rhst) -/* Perform the usual arithmetic conversions for binary operators. */ -{ - /* https://port70.net/~nsz/c/c89/c89-draft.html#3.2.1.5 - ** Many binary operators that expect operands of arithmetic type cause conversions and yield - ** result types in a similar way. The purpose is to yield a common type, which is also the type - ** of the result. This pattern is called the usual arithmetic conversions. - */ - - /* There are additional rules for floating point types that we don't bother with, since - ** floating point types are not (yet) supported. - ** The integral promotions are performed on both operands. - */ - lhst = IntPromotion (lhst); - rhst = IntPromotion (rhst); - - /* If either operand has type unsigned long int, the other operand is converted to - ** unsigned long int. - */ - if ((IsTypeLong (lhst) && IsSignUnsigned (lhst)) || - (IsTypeLong (rhst) && IsSignUnsigned (rhst))) { - return type_ulong; - } - - /* Otherwise, if one operand has type long int and the other has type unsigned int, - ** if a long int can represent all values of an unsigned int, the operand of type unsigned int - ** is converted to long int ; if a long int cannot represent all the values of an unsigned int, - ** both operands are converted to unsigned long int. - */ - if ((IsTypeLong (lhst) && IsTypeInt (rhst) && IsSignUnsigned (rhst)) || - (IsTypeLong (rhst) && IsTypeInt (lhst) && IsSignUnsigned (lhst))) { - /* long can represent all unsigneds, so we are in the first sub-case. */ - return type_long; - } - - /* Otherwise, if either operand has type long int, the other operand is converted to long int. - */ - if (IsTypeLong (lhst) || IsTypeLong (rhst)) { - return type_long; - } - - /* Otherwise, if either operand has type unsigned int, the other operand is converted to - ** unsigned int. - */ - if ((IsTypeInt (lhst) && IsSignUnsigned (lhst)) || - (IsTypeInt (rhst) && IsSignUnsigned (rhst))) { - return type_uint; - } - - /* Otherwise, both operands have type int. */ - CHECK (IsTypeInt (lhst)); - CHECK (IsSignSigned (lhst)); - CHECK (IsTypeInt (rhst)); - CHECK (IsSignSigned (rhst)); - return type_int; -} - - - static unsigned typeadjust (ExprDesc* lhs, const ExprDesc* rhs, int NoPush) /* Adjust the two values for a binary operation. lhs is expected on stack or ** to be constant, rhs is expected to be in the primary register or constant. @@ -263,7 +204,7 @@ static unsigned typeadjust (ExprDesc* lhs, const ExprDesc* rhs, int NoPush) -static void LimitExprValue (ExprDesc* Expr) +void LimitExprValue (ExprDesc* Expr) /* Limit the constant value of the expression to the range of its type */ { switch (GetUnderlyingTypeCode (Expr->Type)) { diff --git a/src/cc65/expr.h b/src/cc65/expr.h index 02f9f7a5f..4909815ee 100644 --- a/src/cc65/expr.h +++ b/src/cc65/expr.h @@ -44,6 +44,9 @@ void MarkedExprWithCheck (void (*Func) (ExprDesc*), ExprDesc* Expr); ** generated code. */ +void LimitExprValue (ExprDesc* Expr); +/* Limit the constant value of the expression to the range of its type */ + void PushAddr (const ExprDesc* Expr); /* If the expression contains an address that was somehow evaluated, ** push this address on the stack. This is a helper function for all