mirror of
https://github.com/cc65/cc65.git
synced 2025-02-05 20:31:53 +00:00
Moved ArithmeticConvert() from cc65/expr.c to cc65/datatype.c.
Reorganized a few functions in cc65/datatype.c. Added SignedType() and UnsignedType() for future usage. Made LimitExprValue() external so that it can be used more often.
This commit is contained in:
parent
09862e7ce9
commit
dcacba472a
@ -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");
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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)) {
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user