/* 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) {
*/
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);
#include <string.h>
/* common */
+#include "addrsize.h"
#include "check.h"
+#include "mmodel.h"
#include "xmalloc.h"
/* cc65 */
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 */
/* 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;
/* 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 */
-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
* return T.
*/
{
- if (IsTypeFunc (T)) {
+ if (IsTypeFunc (T) || IsTypeArray (T)) {
return PointerTo (T);
- } else if (IsTypeArray (T)) {
- return ArrayToPtr (T);
} else {
return 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;
+ }
+}
+
+
/* 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,
# 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
* 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 */
/*****************************************************************************/
-/* 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;
}
NextToken ();
}
+Done:
/* Return the qualifiers read */
return Q;
}
-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 */
}
++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;
+ }
}
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) {
}
/* 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);
}
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);
-static unsigned FunctionModifierFlags (void)
-/* Parse __fastcall__, __near__ and __far__ and return the matching FD_ flags */
+static void Decl (const DeclSpec* Spec, Declaration* D, unsigned Mode)
+/* Recursively process declarators. Build a type array in reverse order. */
{
- /* 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;
-}
-
-
+ /* 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;
-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;
+ default:
+ Error ("Cannot specify more than one address size qualifier");
+ Qualifiers &= ~T_QUAL_ADDRSIZE;
}
- /* 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. */
-{
/* 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);
/* 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;
}
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");
+ }
}
/* 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)) {
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);
/*****************************************************************************/
-/* 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
/* 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;
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.
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 */
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
* 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
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 ();
/* 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) {
}
/* Result is an expression, no reference */
- ED_MakeRValExpr (Expr);
+ ED_MakeRValExpr (Expr);
}
/* Result is an expression, no reference */
ED_MakeRValExpr (Expr);
-}
+}
#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)
/* */
/* */
/* */
-/* (C) 2000-2006 Ullrich von Bassewitz */
-/* Römerstrasse 52 */
+/* (C) 2000-2008 Ullrich von Bassewitz */
+/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/* */
/* 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__");
}
}
/* 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;
/* Set a new result value if it is less than the existing one */
{
if (Val < *Result) {
+ /* printf ("SetResult = %d\n", Val); */
*Result = Val;
}
}
}
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);
* 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
/* 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");
} 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
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 {