diff --git a/src/cc65/codeinfo.c b/src/cc65/codeinfo.c index fb6bea667..1eec54964 100644 --- a/src/cc65/codeinfo.c +++ b/src/cc65/codeinfo.c @@ -340,14 +340,15 @@ void GetFuncInfo (const char* Name, unsigned short* Use, unsigned short* Chg) /* Did we find it in the top level table? */ if (E && IsTypeFunc (E->Type)) { + FuncDesc* D = E->V.F.Func; + /* A function may use the A or A/X registers if it is a fastcall * function. If it is not a fastcall function but a variadic one, * it will use the Y register (the parameter size is passed here). * In all other cases, no registers are used. However, we assume * that any function will destroy all registers. */ - FuncDesc* D = E->V.F.Func; - if ((D->Flags & FD_FASTCALL) != 0 && D->ParamCount > 0) { + if (IsQualFastcall (E->Type) && D->ParamCount > 0) { /* Will use registers depending on the last param */ unsigned LastParamSize = CheckedSizeOf (D->LastParam->Type); if (LastParamSize == 1) { diff --git a/src/cc65/codeseg.c b/src/cc65/codeseg.c index 0b90a73fc..ad1b3aeb7 100644 --- a/src/cc65/codeseg.c +++ b/src/cc65/codeseg.c @@ -1241,12 +1241,11 @@ void CS_OutputPrologue (const CodeSeg* S, FILE* F) */ if (Func) { /* Get the function descriptor */ - const FuncDesc* D = GetFuncDesc (Func->Type); CS_PrintFunctionHeader (S, F); fprintf (F, ".segment\t\"%s\"\n\n.proc\t_%s", S->SegName, Func->Name); - if (D->Flags & FD_NEAR) { + if (IsQualNear (Func->Type)) { fputs (": near", F); - } else if (D->Flags & FD_FAR) { + } else if (IsQualFar (Func->Type)) { fputs (": far", F); } fputs ("\n\n", F); diff --git a/src/cc65/datatype.c b/src/cc65/datatype.c index 738a8afaa..fc71d3df2 100644 --- a/src/cc65/datatype.c +++ b/src/cc65/datatype.c @@ -36,7 +36,9 @@ #include /* common */ +#include "addrsize.h" #include "check.h" +#include "mmodel.h" #include "xmalloc.h" /* cc65 */ @@ -208,7 +210,7 @@ Type* PointerTo (const Type* T) Type* P = TypeAlloc (Size + 1); /* Create the return type... */ - P[0].C = T_PTR; + P[0].C = T_PTR | (T[0].C & T_QUAL_ADDRSIZE); memcpy (P+1, T, Size * sizeof (Type)); /* ...and return it */ @@ -240,69 +242,72 @@ void PrintType (FILE* F, const Type* T) /* Get the type code */ TypeCode C = T->C; - /* Print any qualifiers */ + /* Print any qualifiers */ C = PrintTypeComp (F, C, T_QUAL_CONST, "const"); - C = PrintTypeComp (F, C, T_QUAL_VOLATILE, "volatile"); + C = PrintTypeComp (F, C, T_QUAL_VOLATILE, "volatile"); C = PrintTypeComp (F, C, T_QUAL_RESTRICT, "restrict"); + C = PrintTypeComp (F, C, T_QUAL_NEAR, "__near__"); + C = PrintTypeComp (F, C, T_QUAL_FAR, "__far__"); + C = PrintTypeComp (F, C, T_QUAL_FASTCALL, "__fastcall__"); - /* Signedness. Omit the signedness specifier for long and int */ + /* Signedness. Omit the signedness specifier for long and int */ if ((C & T_MASK_TYPE) != T_TYPE_INT && (C & T_MASK_TYPE) != T_TYPE_LONG) { - C = PrintTypeComp (F, C, T_SIGN_SIGNED, "signed"); - } - C = PrintTypeComp (F, C, T_SIGN_UNSIGNED, "unsigned"); + C = PrintTypeComp (F, C, T_SIGN_SIGNED, "signed"); + } + C = PrintTypeComp (F, C, T_SIGN_UNSIGNED, "unsigned"); - /* Now check the real type */ + /* Now check the real type */ switch (C & T_MASK_TYPE) { - case T_TYPE_CHAR: - fprintf (F, "char"); - break; - case T_TYPE_SHORT: - fprintf (F, "short"); - break; - case T_TYPE_INT: - fprintf (F, "int"); - break; - case T_TYPE_LONG: - fprintf (F, "long"); - break; - case T_TYPE_LONGLONG: - fprintf (F, "long long"); - break; - case T_TYPE_FLOAT: - fprintf (F, "float"); - break; - case T_TYPE_DOUBLE: - fprintf (F, "double"); - break; + case T_TYPE_CHAR: + fprintf (F, "char"); + break; + case T_TYPE_SHORT: + fprintf (F, "short"); + break; + case T_TYPE_INT: + fprintf (F, "int"); + break; + case T_TYPE_LONG: + fprintf (F, "long"); + break; + case T_TYPE_LONGLONG: + fprintf (F, "long long"); + break; + case T_TYPE_FLOAT: + fprintf (F, "float"); + break; + case T_TYPE_DOUBLE: + fprintf (F, "double"); + break; case T_TYPE_VOID: fprintf (F, "void"); - break; - case T_TYPE_STRUCT: - fprintf (F, "struct %s", ((SymEntry*) T->A.P)->Name); - break; - case T_TYPE_UNION: - fprintf (F, "union %s", ((SymEntry*) T->A.P)->Name); - break; - case T_TYPE_ARRAY: - /* Recursive call */ - PrintType (F, T + 1); - if (T->A.L == UNSPECIFIED) { - fprintf (F, "[]"); - } else { - fprintf (F, "[%ld]", T->A.L); - } - return; - case T_TYPE_PTR: - /* Recursive call */ - PrintType (F, T + 1); - fprintf (F, "*"); - return; - case T_TYPE_FUNC: - fprintf (F, "function returning "); - break; - default: - fprintf (F, "unknown type: %04lX", T->C); - } + break; + case T_TYPE_STRUCT: + fprintf (F, "struct %s", ((SymEntry*) T->A.P)->Name); + break; + case T_TYPE_UNION: + fprintf (F, "union %s", ((SymEntry*) T->A.P)->Name); + break; + case T_TYPE_ARRAY: + /* Recursive call */ + PrintType (F, T + 1); + if (T->A.L == UNSPECIFIED) { + fprintf (F, "[]"); + } else { + fprintf (F, "[%ld]", T->A.L); + } + return; + case T_TYPE_PTR: + /* Recursive call */ + PrintType (F, T + 1); + fprintf (F, "*"); + return; + case T_TYPE_FUNC: + fprintf (F, "function returning "); + break; + default: + fprintf (F, "unknown type: %04lX", T->C); + } /* Next element */ ++T; @@ -319,33 +324,33 @@ void PrintFuncSig (FILE* F, const char* Name, Type* T) /* Print a comment with the function signature */ PrintType (F, GetFuncReturn (T)); - if (D->Flags & FD_NEAR) { + if (IsQualNear (T)) { fprintf (F, " __near__"); } - if (D->Flags & FD_FAR) { + if (IsQualFar (T)) { fprintf (F, " __far__"); } - if (D->Flags & FD_FASTCALL) { + if (IsQualFastcall (T)) { fprintf (F, " __fastcall__"); } fprintf (F, " %s (", Name); /* Parameters */ if (D->Flags & FD_VOID_PARAM) { - fprintf (F, "void"); + fprintf (F, "void"); } else { - unsigned I; - SymEntry* E = D->SymTab->SymHead; - for (I = 0; I < D->ParamCount; ++I) { - if (I > 0) { - fprintf (F, ", "); - } + unsigned I; + SymEntry* E = D->SymTab->SymHead; + for (I = 0; I < D->ParamCount; ++I) { + if (I > 0) { + fprintf (F, ", "); + } if (SymIsRegVar (E)) { fprintf (F, "register "); } - PrintType (F, E->Type); - E = E->NextSym; - } + PrintType (F, E->Type); + E = E->NextSym; + } } /* End of parameter list */ @@ -555,31 +560,6 @@ Type* ArrayToPtr (const Type* T) -TypeCode GetQualifier (const Type* T) -/* Get the qualifier from the given type string */ -{ - /* If this is an array, look at the element type, otherwise look at the - * type itself. - */ - if (IsTypeArray (T)) { - ++T; - } - return (T->C & T_MASK_QUAL); -} - - - -int IsFastCallFunc (const Type* T) -/* Return true if this is a function type or pointer to function with - * __fastcall__ calling conventions - */ -{ - FuncDesc* F = GetFuncDesc (T); - return (F->Flags & FD_FASTCALL) != 0; -} - - - int IsVariadicFunc (const Type* T) /* Return true if this is a function type or pointer to function type with * variable parameter list @@ -723,10 +703,8 @@ Type* PtrConversion (Type* T) * return T. */ { - if (IsTypeFunc (T)) { + if (IsTypeFunc (T) || IsTypeArray (T)) { return PointerTo (T); - } else if (IsTypeArray (T)) { - return ArrayToPtr (T); } else { return T; } @@ -734,4 +712,27 @@ Type* PtrConversion (Type* T) +TypeCode CodeAddrSizeQualifier (void) +/* Return T_QUAL_NEAR or T_QUAL_FAR depending on the code address size */ +{ + if (CodeAddrSize == ADDR_SIZE_FAR) { + return T_QUAL_FAR; + } else { + return T_QUAL_NEAR; + } +} + + + +TypeCode DataAddrSizeQualifier (void) +/* Return T_QUAL_NEAR or T_QUAL_FAR depending on the data address size */ +{ + if (DataAddrSize == ADDR_SIZE_FAR) { + return T_QUAL_FAR; + } else { + return T_QUAL_NEAR; + } +} + + diff --git a/src/cc65/datatype.h b/src/cc65/datatype.h index 3b5b99245..84155f305 100644 --- a/src/cc65/datatype.h +++ b/src/cc65/datatype.h @@ -58,54 +58,58 @@ /* Basic data types */ enum { - T_END = 0x0000, + T_END = 0x000000, /* Basic types */ - T_TYPE_NONE = 0x0000, - T_TYPE_CHAR = 0x0001, - T_TYPE_SHORT = 0x0002, - T_TYPE_INT = 0x0003, - T_TYPE_LONG = 0x0004, - T_TYPE_LONGLONG = 0x0005, - T_TYPE_ENUM = 0x0006, - T_TYPE_FLOAT = 0x0007, - T_TYPE_DOUBLE = 0x0008, - T_TYPE_VOID = 0x0009, - T_TYPE_STRUCT = 0x000A, - T_TYPE_UNION = 0x000B, - T_TYPE_ARRAY = 0x000C, - T_TYPE_PTR = 0x000D, - T_TYPE_FUNC = 0x000E, - T_MASK_TYPE = 0x001F, + T_TYPE_NONE = 0x000000, + T_TYPE_CHAR = 0x000001, + T_TYPE_SHORT = 0x000002, + T_TYPE_INT = 0x000003, + T_TYPE_LONG = 0x000004, + T_TYPE_LONGLONG = 0x000005, + T_TYPE_ENUM = 0x000006, + T_TYPE_FLOAT = 0x000007, + T_TYPE_DOUBLE = 0x000008, + T_TYPE_VOID = 0x000009, + T_TYPE_STRUCT = 0x00000A, + T_TYPE_UNION = 0x00000B, + T_TYPE_ARRAY = 0x00000C, + T_TYPE_PTR = 0x00000D, + T_TYPE_FUNC = 0x00000E, + T_MASK_TYPE = 0x00000F, /* Type classes */ - T_CLASS_NONE = 0x0000, - T_CLASS_INT = 0x0020, - T_CLASS_FLOAT = 0x0040, - T_CLASS_PTR = 0x0060, - T_CLASS_STRUCT = 0x0080, - T_CLASS_FUNC = 0x00A0, - T_MASK_CLASS = 0x00E0, + T_CLASS_NONE = 0x000000, + T_CLASS_INT = 0x000010, + T_CLASS_FLOAT = 0x000020, + T_CLASS_PTR = 0x000030, + T_CLASS_STRUCT = 0x000040, + T_CLASS_FUNC = 0x000050, + T_MASK_CLASS = 0x000070, /* Type signedness */ - T_SIGN_NONE = 0x0000, - T_SIGN_UNSIGNED = 0x0100, - T_SIGN_SIGNED = 0x0200, - T_MASK_SIGN = 0x0300, + T_SIGN_NONE = 0x000000, + T_SIGN_UNSIGNED = 0x000080, + T_SIGN_SIGNED = 0x000100, + T_MASK_SIGN = 0x000180, /* Type size modifiers */ - T_SIZE_NONE = 0x0000, - T_SIZE_SHORT = 0x0400, - T_SIZE_LONG = 0x0800, - T_SIZE_LONGLONG = 0x0C00, - T_MASK_SIZE = 0x0C00, + T_SIZE_NONE = 0x000000, + T_SIZE_SHORT = 0x000200, + T_SIZE_LONG = 0x000400, + T_SIZE_LONGLONG = 0x000600, + T_MASK_SIZE = 0x000600, /* Type qualifiers */ - T_QUAL_NONE = 0x0000, - T_QUAL_CONST = 0x1000, - T_QUAL_VOLATILE = 0x2000, - T_QUAL_RESTRICT = 0x4000, - T_MASK_QUAL = 0x7000, + T_QUAL_NONE = 0x000000, + T_QUAL_CONST = 0x000800, + T_QUAL_VOLATILE = 0x001000, + T_QUAL_RESTRICT = 0x002000, + T_QUAL_NEAR = 0x004000, + T_QUAL_FAR = 0x008000, + T_QUAL_ADDRSIZE = T_QUAL_NEAR | T_QUAL_FAR, + T_QUAL_FASTCALL = 0x010000, + T_MASK_QUAL = 0x01F800, /* Types */ T_CHAR = T_TYPE_CHAR | T_CLASS_INT | T_SIGN_UNSIGNED | T_SIZE_NONE, @@ -506,43 +510,75 @@ INLINE int IsSignSigned (const Type* T) # define IsSignSigned(T) (GetSignedness (T) == T_SIGN_SIGNED) #endif -TypeCode GetQualifier (const Type* T) attribute ((const)); +#if defined(HAVE_INLINE) +INLINE TypeCode GetQualifier (const Type* T) /* Get the qualifier from the given type string */ +{ + return (T->C & T_MASK_QUAL); +} +#else +# define GetQualifier(T) ((T)->C & T_MASK_QUAL) +#endif #if defined(HAVE_INLINE) INLINE int IsQualConst (const Type* T) /* Return true if the given type has a const memory image */ { - return (GetQualifier (T) & T_QUAL_CONST) != 0; + return (T->C & T_QUAL_CONST) != 0; } #else -# define IsQualConst(T) ((GetQualifier (T) & T_QUAL_CONST) != 0) +# define IsQualConst(T) ((T->C & T_QUAL_CONST) != 0) #endif #if defined(HAVE_INLINE) INLINE int IsQualVolatile (const Type* T) /* Return true if the given type has a volatile type qualifier */ { - return (GetQualifier (T) & T_QUAL_VOLATILE) != 0; + return (T->C & T_QUAL_VOLATILE) != 0; } #else -# define IsQualVolatile(T) ((GetQualifier (T) & T_QUAL_VOLATILE) != 0) +# define IsQualVolatile(T) (T->C & T_QUAL_VOLATILE) != 0) #endif #if defined(HAVE_INLINE) INLINE int IsQualRestrict (const Type* T) /* Return true if the given type has a restrict qualifier */ { - return (GetQualifier (T) & T_QUAL_RESTRICT) != 0; + return (T->C & T_QUAL_RESTRICT) != 0; } #else -# define IsQualRestrict(T) ((GetQualifier (T) & T_QUAL_RESTRICT) != 0) +# define IsQualRestrict(T) (T->C & T_QUAL_RESTRICT) != 0) #endif -int IsFastCallFunc (const Type* T) attribute ((const)); -/* Return true if this is a function type or pointer to function with - * __fastcall__ calling conventions - */ +#if defined(HAVE_INLINE) +INLINE int IsQualNear (const Type* T) +/* Return true if the given type has a near qualifier */ +{ + return (T->C & T_QUAL_NEAR) != 0; +} +#else +# define IsQualNear(T) (T->C & T_QUAL_NEAR) != 0) +#endif + +#if defined(HAVE_INLINE) +INLINE int IsQualFar (const Type* T) +/* Return true if the given type has a far qualifier */ +{ + return (T->C & T_QUAL_FAR) != 0; +} +#else +# define IsQualFar(T) (T->C & T_QUAL_FAR) != 0) +#endif + +#if defined(HAVE_INLINE) +INLINE int IsQualFastcall (const Type* T) +/* Return true if the given type has a fastcall qualifier */ +{ + return (T->C & T_QUAL_FASTCALL) != 0; +} +#else +# define IsQualFastcall(T) (T->C & T_QUAL_FASTCALL) != 0) +#endif int IsVariadicFunc (const Type* T) attribute ((const)); /* Return true if this is a function type or pointer to function type with @@ -598,6 +634,12 @@ Type* PtrConversion (Type* T); * return T. */ +TypeCode CodeAddrSizeQualifier (void); +/* Return T_QUAL_NEAR or T_QUAL_FAR depending on the code address size */ + +TypeCode DataAddrSizeQualifier (void); +/* Return T_QUAL_NEAR or T_QUAL_FAR depending on the data address size */ + /* End of datatype.h */ diff --git a/src/cc65/declare.c b/src/cc65/declare.c index cf3521f8f..640a04f69 100644 --- a/src/cc65/declare.c +++ b/src/cc65/declare.c @@ -77,41 +77,94 @@ static unsigned ParseInitInternal (Type* T, int AllowFlexibleMembers); /*****************************************************************************/ -/* internal functions */ +/* internal functions */ /*****************************************************************************/ -static TypeCode OptionalQualifiers (TypeCode Q) +static void DuplicateQualifier (const char* Name) +/* Print an error message */ +{ + Warning ("Duplicate qualifier: `%s'", Name); +} + + + +static TypeCode OptionalQualifiers (TypeCode Q, TypeCode Allowed) /* Read type qualifiers if we have any */ { - while (TokIsTypeQual (&CurTok)) { + while (1) { - switch (CurTok.Tok) { + switch (CurTok.Tok) { - case TOK_CONST: - if (Q & T_QUAL_CONST) { - Error ("Duplicate qualifier: `const'"); - } - Q |= T_QUAL_CONST; - break; + case TOK_CONST: + if (Allowed & T_QUAL_CONST) { + if (Q & T_QUAL_CONST) { + DuplicateQualifier ("const"); + } + Q |= T_QUAL_CONST; + } else { + goto Done; + } + break; case TOK_VOLATILE: - if (Q & T_QUAL_VOLATILE) { - Error ("Duplicate qualifier: `volatile'"); - } - Q |= T_QUAL_VOLATILE; - break; + if (Allowed & T_QUAL_VOLATILE) { + if (Q & T_QUAL_VOLATILE) { + DuplicateQualifier ("volatile"); + } + Q |= T_QUAL_VOLATILE; + } else { + goto Done; + } + break; case TOK_RESTRICT: - if (Q & T_QUAL_RESTRICT) { - Error ("Duplicate qualifier: `restrict'"); + if (Allowed & T_QUAL_RESTRICT) { + if (Q & T_QUAL_RESTRICT) { + DuplicateQualifier ("restrict"); + } + Q |= T_QUAL_RESTRICT; + } else { + goto Done; + } + break; + + case TOK_NEAR: + if (Allowed & T_QUAL_NEAR) { + if (Q & T_QUAL_NEAR) { + DuplicateQualifier ("near"); + } + Q |= T_QUAL_NEAR; + } else { + goto Done; + } + break; + + case TOK_FAR: + if (Allowed & T_QUAL_FAR) { + if (Q & T_QUAL_FAR) { + DuplicateQualifier ("far"); + } + Q |= T_QUAL_FAR; + } else { + goto Done; + } + break; + + case TOK_FASTCALL: + if (Allowed & T_QUAL_FASTCALL) { + if (Q & T_QUAL_FASTCALL) { + DuplicateQualifier ("fastcall"); + } + Q |= T_QUAL_FASTCALL; + } else { + goto Done; } - Q |= T_QUAL_RESTRICT; break; default: - Internal ("Unexpected type qualifier token: %d", CurTok.Tok); + goto Done; } @@ -119,6 +172,7 @@ static TypeCode OptionalQualifiers (TypeCode Q) NextToken (); } +Done: /* Return the qualifiers read */ return Q; } @@ -190,35 +244,18 @@ static void AddTypeToDeclaration (Declaration* D, TypeCode T) -static void AddFuncTypeToDeclaration (Declaration* D, FuncDesc* F) -/* Add a function type plus function descriptor to the type of a declaration */ +static void FixQualifiers (Type* DataType) +/* Apply several fixes to qualifiers */ { - NeedTypeSpace (D, 1); - D->Type[D->Index].C = T_FUNC; - SetFuncDesc (D->Type + D->Index, F); - ++D->Index; -} + Type* T; + TypeCode Q; - - -static void AddArrayToDeclaration (Declaration* D, long Size) -/* Add an array type plus size to the type of a declaration */ -{ - NeedTypeSpace (D, 1); - D->Type[D->Index].C = T_ARRAY; - D->Type[D->Index].A.L = Size; - ++D->Index; -} - - - -static void FixArrayQualifiers (Type* T) -/* Using typedefs, it is possible to generate declarations that have - * type qualifiers attached to an array, not the element type. Go and - * fix these here. - */ -{ - TypeCode Q = T_QUAL_NONE; + /* Using typedefs, it is possible to generate declarations that have + * type qualifiers attached to an array, not the element type. Go and + * fix these here. + */ + T = DataType; + Q = T_QUAL_NONE; while (T->C != T_END) { if (IsTypeArray (T)) { /* Extract any type qualifiers */ @@ -231,9 +268,69 @@ static void FixArrayQualifiers (Type* T) } ++T; } - /* Q must be empty now */ CHECK (Q == T_QUAL_NONE); + + /* Do some fixes on pointers and functions. */ + T = DataType; + while (T->C != T_END) { + if (IsTypePtr (T)) { + + /* Fastcall qualifier on the pointer? */ + if (IsQualFastcall (T)) { + /* Pointer to function which is not fastcall? */ + if (IsTypeFunc (T+1) && !IsQualFastcall (T+1)) { + /* Move the fastcall qualifier from the pointer to + * the function. + */ + T[0].C &= ~T_QUAL_FASTCALL; + T[1].C |= T_QUAL_FASTCALL; + } else { + Error ("Invalid `_fastcall__' qualifier for pointer"); + } + } + + /* Apply the default far and near qualifiers if none are given */ + Q = (T[0].C & T_QUAL_ADDRSIZE); + if (Q == T_QUAL_NONE) { + /* No address size qualifiers specified */ + if (IsTypeFunc (T+1)) { + /* Pointer to function. Use the qualifier from the function + * or the default if the function don't has one. + */ + Q = (T[1].C & T_QUAL_ADDRSIZE); + if (Q == T_QUAL_NONE) { + Q = CodeAddrSizeQualifier (); + } + } else { + Q = DataAddrSizeQualifier (); + } + T[0].C |= Q; + } else { + /* We have address size qualifiers. If followed by a function, + * apply these also to the function. + */ + if (IsTypeFunc (T+1)) { + TypeCode FQ = (T[1].C & T_QUAL_ADDRSIZE); + if (FQ == T_QUAL_NONE) { + T[1].C |= Q; + } else if (FQ != Q) { + Error ("Address size qualifier mismatch"); + T[1].C = (T[1].C & ~T_QUAL_ADDRSIZE) | Q; + } + } + } + + } else if (IsTypeFunc (T)) { + + /* Apply the default far and near qualifiers if none are given */ + if ((T[0].C & T_QUAL_ADDRSIZE) == 0) { + T[0].C |= CodeAddrSizeQualifier (); + } + + } + ++T; + } } @@ -458,7 +555,7 @@ static void ParseTypeSpec (DeclSpec* D, long Default, TypeCode Qualifiers) D->Flags &= ~DS_DEF_TYPE; /* Read type qualifiers if we have any */ - Qualifiers = OptionalQualifiers (Qualifiers); + Qualifiers = OptionalQualifiers (Qualifiers, T_QUAL_CONST | T_QUAL_VOLATILE); /* Look at the data type */ switch (CurTok.Tok) { @@ -666,7 +763,7 @@ static void ParseTypeSpec (DeclSpec* D, long Default, TypeCode Qualifiers) } /* There may also be qualifiers *after* the initial type */ - D->Type[0].C |= OptionalQualifiers (Qualifiers); + D->Type[0].C |= OptionalQualifiers (Qualifiers, T_QUAL_CONST | T_QUAL_VOLATILE); } @@ -924,13 +1021,6 @@ static FuncDesc* ParseFuncDecl (void) Sym = Sym->PrevSym; } - /* Add the default address size for the function */ - if (CodeAddrSize == ADDR_SIZE_FAR) { - F->Flags |= FD_FAR; - } else { - F->Flags |= FD_NEAR; - } - /* Leave the lexical level remembering the symbol tables */ RememberFunctionLevel (F); @@ -940,111 +1030,48 @@ static FuncDesc* ParseFuncDecl (void) -static unsigned FunctionModifierFlags (void) -/* Parse __fastcall__, __near__ and __far__ and return the matching FD_ flags */ -{ - /* Read the flags */ - unsigned Flags = FD_NONE; - while (CurTok.Tok == TOK_FASTCALL || CurTok.Tok == TOK_NEAR || CurTok.Tok == TOK_FAR) { - - /* Get the flag bit for the next token */ - unsigned F = FD_NONE; - switch (CurTok.Tok) { - case TOK_FASTCALL: F = FD_FASTCALL; break; - case TOK_NEAR: F = FD_NEAR; break; - case TOK_FAR: F = FD_FAR; break; - default: Internal ("Unexpected token: %d", CurTok.Tok); - } - - /* Remember the flag for this modifier */ - if (Flags & F) { - Error ("Duplicate modifier"); - } - Flags |= F; - - /* Skip the token */ - NextToken (); - } - - /* Sanity check */ - if ((Flags & (FD_NEAR | FD_FAR)) == (FD_NEAR | FD_FAR)) { - Error ("Cannot specify both, `__near__' and `__far__' modifiers"); - Flags &= ~(FD_NEAR | FD_FAR); - } - - /* Return the flags read */ - return Flags; -} - - - -static void ApplyFunctionModifiers (Type* T, unsigned Flags) -/* Apply a set of function modifier flags to a function */ -{ - /* Get the function descriptor */ - FuncDesc* F = GetFuncDesc (T); - - /* Special check for __fastcall__ */ - if ((Flags & FD_FASTCALL) != 0 && IsVariadicFunc (T)) { - Error ("Cannot apply `__fastcall__' to functions with " - "variable parameter list"); - Flags &= ~FD_FASTCALL; - } - - /* Remove the default function address size modifiers */ - F->Flags &= ~(FD_NEAR | FD_FAR); - - /* Add the new modifers */ - F->Flags |= Flags; -} - - - static void Decl (const DeclSpec* Spec, Declaration* D, unsigned Mode) /* Recursively process declarators. Build a type array in reverse order. */ { + /* Read optional function or pointer qualifiers. These modify the + * identifier or token to the right. For convenience, we allow the fastcall + * qualifier also for pointers here. If it is a pointer-to-function, the + * qualifier will later be transfered to the function itself. If it's a + * pointer to something else, it will be flagged as an error. + */ + TypeCode Qualifiers = + OptionalQualifiers (T_QUAL_NONE, T_QUAL_ADDRSIZE | T_QUAL_FASTCALL); + + /* We cannot have more than one address size far qualifier */ + switch (Qualifiers & T_QUAL_ADDRSIZE) { + + case T_QUAL_NONE: + case T_QUAL_NEAR: + case T_QUAL_FAR: + break; + + default: + Error ("Cannot specify more than one address size qualifier"); + Qualifiers &= ~T_QUAL_ADDRSIZE; + } + /* Pointer to something */ if (CurTok.Tok == TOK_STAR) { - TypeCode C; - /* Skip the star */ NextToken (); - /* Allow optional const or volatile qualifiers */ - C = T_PTR | OptionalQualifiers (T_QUAL_NONE); + /* Allow optional pointer qualifiers */ + Qualifiers = OptionalQualifiers (Qualifiers, T_QUAL_CONST | T_QUAL_VOLATILE); /* Parse the type, the pointer points to */ Decl (Spec, D, Mode); /* Add the type */ - AddTypeToDeclaration (D, C); + AddTypeToDeclaration (D, T_PTR | Qualifiers); return; } - /* Function modifiers */ - if (CurTok.Tok == TOK_FASTCALL || CurTok.Tok == TOK_NEAR || CurTok.Tok == TOK_FAR) { - - /* Remember the current type pointer */ - Type* T = D->Type + D->Index; - - /* Read the flags */ - unsigned Flags = FunctionModifierFlags (); - - /* Parse the function */ - Decl (Spec, D, Mode); - - /* Check that we have a function */ - if (!IsTypeFunc (T) && !IsTypeFuncPtr (T)) { - Error ("Function modifier applied to non function"); - } else { - ApplyFunctionModifiers (T, Flags); - } - - /* Done */ - return; - } - if (CurTok.Tok == TOK_LPAREN) { NextToken (); Decl (Spec, D, Mode); @@ -1078,17 +1105,41 @@ static void Decl (const DeclSpec* Spec, Declaration* D, unsigned Mode) /* Function declaration */ FuncDesc* F; + + /* Skip the opening paren */ NextToken (); /* Parse the function declaration */ F = ParseFuncDecl (); + /* We cannot specify fastcall for variadic functions */ + if ((F->Flags & FD_VARIADIC) && (Qualifiers & T_QUAL_FASTCALL)) { + Error ("Variadic functions cannot be `__fastcall'"); + Qualifiers &= ~T_QUAL_FASTCALL; + } + /* Add the function type. Be sure to bounds check the type buffer */ - AddFuncTypeToDeclaration (D, F); + NeedTypeSpace (D, 1); + D->Type[D->Index].C = T_FUNC | Qualifiers; + D->Type[D->Index].A.P = F; + ++D->Index; + + /* Qualifiers now used */ + Qualifiers = T_QUAL_NONE; + } else { - /* Array declaration */ + /* Array declaration. */ long Size = UNSPECIFIED; + + /* We cannot have any qualifiers for an array */ + if (Qualifiers != T_QUAL_NONE) { + Error ("Invalid qualifiers for array"); + Qualifiers = T_QUAL_NONE; + } + + /* Skip the left bracket */ NextToken (); + /* Read the size if it is given */ if (CurTok.Tok != TOK_RBRACK) { ExprDesc Expr; @@ -1103,12 +1154,28 @@ static void Decl (const DeclSpec* Spec, Declaration* D, unsigned Mode) } Size = Expr.IVal; } + + /* Skip the right bracket */ ConsumeRBrack (); - /* Add the array type with the size */ - AddArrayToDeclaration (D, Size); + /* Add the array type with the size to the type */ + NeedTypeSpace (D, 1); + D->Type[D->Index].C = T_ARRAY; + D->Type[D->Index].A.L = Size; + ++D->Index; } } + + /* If we have remaining qualifiers, flag them as invalid */ + if (Qualifiers & T_QUAL_NEAR) { + Error ("Invalid `__near__' qualifier"); + } + if (Qualifiers & T_QUAL_FAR) { + Error ("Invalid `__far__' qualifier"); + } + if (Qualifiers & T_QUAL_FASTCALL) { + Error ("Invalid `__fastcall__' qualifier"); + } } @@ -1157,8 +1224,8 @@ void ParseDecl (const DeclSpec* Spec, Declaration* D, unsigned Mode) /* Use the storage class from the declspec */ D->StorageClass = Spec->StorageClass; - /* Fix any type qualifiers attached to an array type */ - FixArrayQualifiers (D->Type); + /* Do several fixes on qualifiers */ + FixQualifiers (D->Type); /* If we have a function, add a special storage class */ if (IsTypeFunc (D->Type)) { @@ -1243,7 +1310,7 @@ void ParseDeclSpec (DeclSpec* D, unsigned DefStorage, long DefType) InitDeclSpec (D); /* There may be qualifiers *before* the storage class specifier */ - Qualifiers = OptionalQualifiers (T_QUAL_NONE); + Qualifiers = OptionalQualifiers (T_QUAL_NONE, T_QUAL_CONST | T_QUAL_VOLATILE); /* Now get the storage class specifier for this declaration */ ParseStorageClass (D, DefStorage); diff --git a/src/cc65/expr.c b/src/cc65/expr.c index 052e26423..6fb2d5e27 100644 --- a/src/cc65/expr.c +++ b/src/cc65/expr.c @@ -242,12 +242,12 @@ void PushAddr (const ExprDesc* Expr) /*****************************************************************************/ -/* code */ +/* code */ /*****************************************************************************/ -static unsigned FunctionParamList (FuncDesc* Func) +static unsigned FunctionParamList (FuncDesc* Func, int IsFastcall) /* Parse a function parameter list and pass the parameters to the called * function. Depending on several criteria this may be done by just pushing * each parameter separately, or creating the parameter frame once and then @@ -284,7 +284,7 @@ static unsigned FunctionParamList (FuncDesc* Func) /* Calculate the number and size of the parameters */ FrameParams = Func->ParamCount; FrameSize = Func->ParamSize; - if (FrameParams > 0 && (Func->Flags & FD_FASTCALL) != 0) { + if (FrameParams > 0 && IsFastcall) { /* Last parameter is not pushed */ FrameSize -= CheckedSizeOf (Func->LastParam->Type); --FrameParams; @@ -371,7 +371,7 @@ static unsigned FunctionParamList (FuncDesc* Func) Flags |= TypeOf (Expr.Type); /* If this is a fastcall function, don't push the last argument */ - if (ParamCount != Func->ParamCount || (Func->Flags & FD_FASTCALL) == 0) { + if (ParamCount != Func->ParamCount || !IsFastcall) { unsigned ArgSize = sizeofarg (Flags); if (FrameSize > 0) { /* We have the space already allocated, store in the frame. @@ -430,7 +430,7 @@ static void FunctionCall (ExprDesc* Expr) unsigned ParamSize; /* Number of parameter bytes */ CodeMark Mark; int PtrOffs = 0; /* Offset of function pointer on stack */ - int IsFastCall = 0; /* True if it's a fast call function */ + int IsFastcall = 0; /* True if it's a fast call function */ int PtrOnStack = 0; /* True if a pointer copy is on stack */ /* Skip the left paren */ @@ -444,7 +444,7 @@ static void FunctionCall (ExprDesc* Expr) if (IsFuncPtr) { /* Check wether it's a fastcall function that has parameters */ - IsFastCall = IsFastCallFunc (Expr->Type + 1) && (Func->ParamCount > 0); + IsFastcall = IsQualFastcall (Expr->Type + 1) && (Func->ParamCount > 0); /* Things may be difficult, depending on where the function pointer * resides. If the function pointer is an expression of some sort @@ -454,7 +454,7 @@ static void FunctionCall (ExprDesc* Expr) * For fastcall functions we do also need to place a copy of the * pointer on stack, since we cannot use a/x. */ - PtrOnStack = IsFastCall || !ED_IsConst (Expr); + PtrOnStack = IsFastcall || !ED_IsConst (Expr); if (PtrOnStack) { /* Not a global or local variable, or a fastcall function. Load @@ -471,18 +471,23 @@ static void FunctionCall (ExprDesc* Expr) PtrOffs = StackPtr; } - /* Check for known standard functions and inline them */ - } else if (Expr->Name != 0) { - int StdFunc = FindStdFunc ((const char*) Expr->Name); - if (StdFunc >= 0) { - /* Inline this function */ - HandleStdFunc (StdFunc, Func, Expr); - return; + } else { + /* Check for known standard functions and inline them */ + if (Expr->Name != 0) { + int StdFunc = FindStdFunc ((const char*) Expr->Name); + if (StdFunc >= 0) { + /* Inline this function */ + HandleStdFunc (StdFunc, Func, Expr); + return; + } } + + /* If we didn't inline the function, get fastcall info */ + IsFastcall = IsQualFastcall (Expr->Type); } /* Parse the parameter list */ - ParamSize = FunctionParamList (Func); + ParamSize = FunctionParamList (Func, IsFastcall); /* We need the closing paren here */ ConsumeRParen (); @@ -493,7 +498,7 @@ static void FunctionCall (ExprDesc* Expr) /* If the function is not a fastcall function, load the pointer to * the function into the primary. */ - if (!IsFastCall) { + if (!IsFastcall) { /* Not a fastcall function - we may use the primary */ if (PtrOnStack) { @@ -1290,7 +1295,7 @@ static void PreInc (ExprDesc* Expr) } /* Result is an expression, no reference */ - ED_MakeRValExpr (Expr); + ED_MakeRValExpr (Expr); } @@ -1367,7 +1372,7 @@ static void PreDec (ExprDesc* Expr) /* Result is an expression, no reference */ ED_MakeRValExpr (Expr); -} +} diff --git a/src/cc65/funcdesc.h b/src/cc65/funcdesc.h index 56da848a1..7186c3ee8 100644 --- a/src/cc65/funcdesc.h +++ b/src/cc65/funcdesc.h @@ -49,12 +49,9 @@ #define FD_EMPTY 0x0001U /* Function with empty param list */ #define FD_VOID_PARAM 0x0002U /* Function with a void param list */ #define FD_VARIADIC 0x0004U /* Function with variable param list */ -#define FD_FASTCALL 0x0010U /* __fastcall__ function */ -#define FD_FAR 0x0020U /* __far__ function */ -#define FD_NEAR 0x0040U /* __near__ function */ -#define FD_OLDSTYLE 0x0100U /* Old style (K&R) function */ -#define FD_OLDSTYLE_INTRET 0x0200U /* K&R func has implicit int return */ -#define FD_UNNAMED_PARAMS 0x0400U /* Function has unnamed params */ +#define FD_OLDSTYLE 0x0010U /* Old style (K&R) function */ +#define FD_OLDSTYLE_INTRET 0x0020U /* K&R func has implicit int return */ +#define FD_UNNAMED_PARAMS 0x0040U /* Function has unnamed params */ /* Bits that must be ignored when comparing funcs */ #define FD_IGNORE (FD_OLDSTYLE | FD_OLDSTYLE_INTRET | FD_UNNAMED_PARAMS) diff --git a/src/cc65/function.c b/src/cc65/function.c index 6a2a76912..d278fc63a 100644 --- a/src/cc65/function.c +++ b/src/cc65/function.c @@ -6,8 +6,8 @@ /* */ /* */ /* */ -/* (C) 2000-2006 Ullrich von Bassewitz */ -/* Römerstrasse 52 */ +/* (C) 2000-2008 Ullrich von Bassewitz */ +/* Roemerstrasse 52 */ /* D-70794 Filderstadt */ /* EMail: uz@cc65.org */ /* */ @@ -370,7 +370,7 @@ void NewFunc (SymEntry* Func) /* Special handling for main() */ if (strcmp (Func->Name, "main") == 0) { /* Main cannot be a fastcall function */ - if (IsFastCallFunc (Func->Type)) { + if (IsQualFastcall (Func->Type)) { Error ("`main' cannot be declared as __fastcall__"); } @@ -391,7 +391,7 @@ void NewFunc (SymEntry* Func) } /* If this is a fastcall function, push the last parameter onto the stack */ - if (IsFastCallFunc (Func->Type) && D->ParamCount > 0) { + if (IsQualFastcall (Func->Type) && D->ParamCount > 0) { unsigned Flags; diff --git a/src/cc65/typecmp.c b/src/cc65/typecmp.c index 0752d60ba..6afc6698f 100644 --- a/src/cc65/typecmp.c +++ b/src/cc65/typecmp.c @@ -52,6 +52,7 @@ static void SetResult (typecmp_t* Result, typecmp_t Val) /* Set a new result value if it is less than the existing one */ { if (Val < *Result) { + /* printf ("SetResult = %d\n", Val); */ *Result = Val; } } @@ -246,13 +247,14 @@ static void DoCompare (const Type* lhs, const Type* rhs, typecmp_t* Result) } if (LeftQual != RightQual) { /* On the first indirection level, different qualifiers mean - * that the types are still compatible. On the second level, - * this is a (maybe minor) error, so we create a special - * return code, since a qualifier is dropped from a pointer. - * Starting from the next level, the types are incompatible - * if the qualifiers differ. - */ - switch (Indirections) { + * that the types are still compatible. On the second level, + * this is a (maybe minor) error, so we create a special + * return code, since a qualifier is dropped from a pointer. + * Starting from the next level, the types are incompatible + * if the qualifiers differ. + */ + /* printf ("Ind = %d %06X != %06X\n", Indirections, LeftQual, RightQual); */ + switch (Indirections) { case 0: SetResult (Result, TC_STRICT_COMPATIBLE); diff --git a/src/cc65/typeconv.c b/src/cc65/typeconv.c index 7ef1e63ee..57313457d 100644 --- a/src/cc65/typeconv.c +++ b/src/cc65/typeconv.c @@ -168,11 +168,6 @@ void TypeConversion (ExprDesc* Expr, Type* NewType) * impossible. */ { - /* Get the type of the right hand side. Treat function types as - * pointer-to-function - */ - Expr->Type = PtrConversion (Expr->Type); - /* First, do some type checking */ if (IsTypeVoid (NewType) || IsTypeVoid (Expr->Type)) { /* If one of the sides are of type void, output a more apropriate @@ -192,7 +187,10 @@ void TypeConversion (ExprDesc* Expr, Type* NewType) /* Handle conversions to int type */ if (IsClassPtr (Expr->Type)) { - /* Pointer -> int conversion */ + /* Pointer -> int conversion. Convert array to pointer */ + if (IsTypeArray (Expr->Type)) { + Expr->Type = ArrayToPtr (Expr->Type); + } Warning ("Converting pointer to integer without a cast"); } else if (!IsClassInt (Expr->Type) && !IsClassFloat (Expr->Type)) { Error ("Incompatible types"); @@ -207,7 +205,13 @@ void TypeConversion (ExprDesc* Expr, Type* NewType) } else if (IsClassPtr (NewType)) { /* Handle conversions to pointer type */ - if (IsClassPtr (Expr->Type)) { + if (IsClassPtr (Expr->Type)) { + + /* Convert array to pointer */ + if (IsTypeArray (Expr->Type)) { + Expr->Type = ArrayToPtr (Expr->Type); + } + /* Pointer to pointer assignment is valid, if: * - both point to the same types, or * - the rhs pointer is a void pointer, or @@ -230,16 +234,20 @@ void TypeConversion (ExprDesc* Expr, Type* NewType) break; } } + } else if (IsClassInt (Expr->Type)) { /* Int to pointer assignment is valid only for constant zero */ if (!ED_IsConstAbsInt (Expr) || Expr->IVal != 0) { Warning ("Converting integer to pointer without a cast"); } } else if (IsTypeFuncPtr (NewType) && IsTypeFunc(Expr->Type)) { + /* Function -> Function pointer. First convert rhs to pointer */ + Expr->Type = PointerTo (Expr->Type); + /* Assignment of function to function pointer is allowed, provided * that both functions have the same parameter list. */ - if (TypeCmp (Indirect (NewType), Expr->Type) < TC_EQUAL) { + if (TypeCmp (NewType, Expr->Type) < TC_EQUAL) { Error ("Incompatible types"); } } else {