void* __fastcall__ bsearch (const void* key, const void* base, size_t n,
size_t size, int (*cmp) (const void*, const void*));
div_t __fastcall__ div (int numer, int denom);
-void __fastcall__ exit (int ret);
+void __fastcall__ exit (int ret) __attribute__ ((noreturn));
char* __fastcall__ getenv (const char* name);
void __fastcall__ qsort (void* base, size_t count, size_t size,
int (*compare) (const void*, const void*));
while (CurTok.Tok != TOK_CEOF) {
DeclSpec Spec;
- Declaration Decl;
/* Check for empty statements */
if (CurTok.Tok == TOK_SEMI) {
comma = 0;
while (1) {
+ Declaration Decl;
+
/* Read the next declaration */
ParseDecl (&Spec, &Decl, DM_NEED_IDENT);
if (Decl.Ident[0] == '\0') {
/* Add an entry to the symbol table */
Entry = AddGlobalSym (Decl.Ident, Decl.Type, Decl.StorageClass);
+ /* Add declaration attributes */
+ SymUseAttributes (Entry, &Decl);
+
/* Reserve storage for the variable if we need to */
if (Decl.StorageClass & SC_STORAGE) {
strftime (TimeStr, sizeof (TimeStr), "\"%H:%M:%S\"", TM);
DefineTextMacro ("__DATE__", DateStr);
DefineTextMacro ("__TIME__", TimeStr);
-
+
/* Other standard macros */
/* DefineNumericMacro ("__STDC__", 1); <- not now */
DefineNumericMacro ("__STDC_HOSTED__", 1);
static void InitDeclaration (Declaration* D)
/* Initialize the Declaration struct for use */
{
- D->Ident[0] = '\0';
- D->Type[0].C = T_END;
- D->Index = 0;
+ D->Ident[0] = '\0';
+ D->Type[0].C = T_END;
+ D->Index = 0;
+ D->Attributes = 0;
}
DeclSpec Spec;
Declaration Decl;
- DeclAttr Attr;
/* Allow an ellipsis as last parameter */
if (CurTok.Tok == TOK_ELLIPSIS) {
Decl.StorageClass &= ~SC_DEF;
}
- /* Parse an attribute ### */
- ParseAttribute (&Decl, &Attr);
+ /* Parse attributes for this parameter */
+ ParseAttribute (&Decl);
/* Create a symbol table entry */
AddLocalSym (Decl.Ident, ParamTypeCvt (Decl.Type), Decl.StorageClass, 0);
/* Print an error if we have unnamed parameters and cc65 extensions
* are disabled.
*/
- if (IS_Get (&Standard) != STD_CC65 &&
- (F->Flags & FD_UNNAMED_PARAMS) != 0) {
+ if (IS_Get (&Standard) != STD_CC65 && (F->Flags & FD_UNNAMED_PARAMS)) {
Error ("Parameter name omitted");
}
}
-static FuncDesc* ParseFuncDecl (void)
+static FuncDesc* ParseFuncDecl (Declaration* D)
/* Parse the argument list of a function. */
{
unsigned Offs;
/* Parse params */
if ((F->Flags & FD_OLDSTYLE) == 0) {
+
/* New style function */
ParseAnsiParamList (F);
+
+ /* Allow attributes */
+ ParseAttribute (D);
+
+ /* Check if this is a function definition */
+ if (CurTok.Tok == TOK_LCURLY) {
+ /* Print an error if we have unnamed parameters and cc65 extensions
+ * are disabled.
+ */
+ if (IS_Get (&Standard) != STD_CC65 &&
+ (F->Flags & FD_UNNAMED_PARAMS)) {
+ Error ("Parameter name omitted");
+ }
+ }
+
} else {
/* Old style function */
ParseOldStyleParamList (F);
NextToken ();
/* Parse the function declaration */
- F = ParseFuncDecl ();
+ F = ParseFuncDecl (D);
/* We cannot specify fastcall for variadic functions */
if ((F->Flags & FD_VARIADIC) && (Qualifiers & T_QUAL_FASTCALL)) {
/* */
/* */
/* */
-/* (C) 1998-2008 Ullrich von Bassewitz */
-/* Roemerstrasse 52 */
-/* D-70794 Filderstadt */
-/* EMail: uz@cc65.org */
+/* (C) 1998-2009, Ullrich von Bassewitz */
+/* Roemerstrasse 52 */
+/* D-70794 Filderstadt */
+/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
+/* common */
+#include "coll.h"
+
/* cc65 */
#include "scanner.h"
#include "symtab.h"
/* Result of ParseDeclSpec */
typedef struct DeclSpec DeclSpec;
struct DeclSpec {
- unsigned StorageClass; /* One of the SC_xxx flags */
+ unsigned StorageClass; /* One of the SC_xxx flags */
Type Type[MAXTYPELEN]; /* Type of the declaration spec */
- unsigned Flags; /* Bitmapped flags */
+ unsigned Flags; /* Bitmapped flags */
};
/* Result of ParseDecl */
struct Declaration {
unsigned StorageClass; /* A set of SC_xxx flags */
Type Type[MAXTYPELEN]; /* The type */
- ident Ident; /* The identifier if any, else empty */
+ ident Ident; /* The identifier, if any*/
+ Collection* Attributes; /* Attributes if any */
/* Working variables */
- unsigned Index; /* Used to build Type */
+ unsigned Index; /* Used to build Type */
};
/* Modes for ParseDecl */
-typedef enum {
+typedef enum {
DM_NEED_IDENT, /* We must have an identifier */
DM_NO_IDENT, /* We won't read an identifier */
DM_ACCEPT_IDENT, /* We will accept an id if there is one */
/* */
/* */
/* */
-/* (C) 2000-2002 Ullrich von Bassewitz */
-/* Wacholderweg 14 */
-/* D-70597 Stuttgart */
-/* EMail: uz@musoftware.de */
+/* (C) 1998-2009, Ullrich von Bassewitz */
+/* Roemerstrasse 52 */
+/* D-70794 Filderstadt */
+/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
#include <string.h>
+/* common */
+#include "xmalloc.h"
+
/* cc65 */
+#include "declare.h"
+#include "declattr.h"
#include "error.h"
#include "scanner.h"
#include "symtab.h"
#include "typecmp.h"
-#include "declattr.h"
/* Forwards for attribute handlers */
-static void AliasAttr (const Declaration* D, DeclAttr* A);
-static void UnusedAttr (const Declaration* D, DeclAttr* A);
-static void ZeroPageAttr (const Declaration* D, DeclAttr* A);
+static void NoReturnAttr (Declaration* D);
/* Attribute table */
typedef struct AttrDesc AttrDesc;
struct AttrDesc {
- const char Name[12];
- void (*Handler) (const Declaration*, DeclAttr*);
+ const char Name[15];
+ void (*Handler) (Declaration*);
};
-static const AttrDesc AttrTable [atCount] = {
- { "alias", AliasAttr },
- { "unused", UnusedAttr },
- { "zeropage", ZeroPageAttr },
+static const AttrDesc AttrTable [] = {
+ { "__noreturn__", NoReturnAttr },
+ { "noreturn", NoReturnAttr },
};
/*****************************************************************************/
-/* Code */
+/* Struct DeclAttr */
+/*****************************************************************************/
+
+
+
+static DeclAttr* NewDeclAttr (DeclAttrType AttrType)
+/* Create a new DeclAttr struct and return it */
+{
+ /* Allocate memory */
+ DeclAttr* A = xmalloc (sizeof (DeclAttr));
+
+ /* Initialize the fields */
+ A->AttrType = AttrType;
+
+ /* Return the new struct */
+ return A;
+}
+
+
+
+/*****************************************************************************/
+/* Helper functions */
/*****************************************************************************/
unsigned A;
/* For now do a linear search */
- for (A = 0; A < atCount; ++A) {
+ for (A = 0; A < sizeof (AttrTable) / sizeof (AttrTable[0]); ++A) {
if (strcmp (Attr, AttrTable[A].Name) == 0) {
/* Found */
return AttrTable + A;
-static void AliasAttr (const Declaration* D, DeclAttr* A)
-/* Handle the "alias" attribute */
+static void ErrorSkip (void)
{
- SymEntry* Sym;
+ /* List of tokens to skip */
+ static const token_t SkipList[] = { TOK_RPAREN, TOK_SEMI };
- /* Comma expected */
- ConsumeComma ();
+ /* Skip until closing brace or semicolon */
+ SkipTokens (SkipList, sizeof (SkipList) / sizeof (SkipList[0]));
- /* The next identifier is the name of the alias symbol */
- if (CurTok.Tok != TOK_IDENT) {
- Error ("Identifier expected");
- return;
+ /* If we have a closing brace, read it, otherwise bail out */
+ if (CurTok.Tok == TOK_RPAREN) {
+ /* Read the two closing braces */
+ ConsumeRParen ();
+ ConsumeRParen ();
}
+}
- /* Lookup the symbol for this name, it must exist */
- Sym = FindSym (CurTok.Ident);
- if (Sym == 0) {
- Error ("Unknown identifier: `%s'", CurTok.Ident);
- NextToken ();
- return;
- }
- /* Since we have the symbol entry now, skip the name */
- NextToken ();
- /* Check if the types of the symbols are identical */
- if (TypeCmp (D->Type, Sym->Type) < TC_EQUAL) {
- /* Types are not identical */
- Error ("Incompatible types");
- return;
+static void AddAttr (Declaration* D, DeclAttr* A)
+/* Add an attribute to a declaration */
+{
+ /* Allocate the list if necessary, the add the attribute */
+ if (D->Attributes == 0) {
+ D->Attributes = NewCollection ();
}
-
- /* Attribute is verified, set the stuff in the attribute description */
- A->AttrType = atAlias;
- A->V.Sym = Sym;
+ CollAppend (D->Attributes, A);
}
-static void UnusedAttr (const Declaration* D attribute ((unused)), DeclAttr* A)
-/* Handle the "unused" attribute */
-{
- /* No parameters */
- A->AttrType = atUnused;
-}
+/*****************************************************************************/
+/* Attribute handling code */
+/*****************************************************************************/
-static void ZeroPageAttr (const Declaration* D attribute ((unused)), DeclAttr* A)
-/* Handle the "zeropage" attribute */
+void NoReturnAttr (Declaration* D)
+/* Parse the "noreturn" attribute */
{
- /* No parameters */
- A->AttrType = atZeroPage;
+ /* Add the noreturn attribute */
+ AddAttr (D, NewDeclAttr (atNoReturn));
}
-void ParseAttribute (const Declaration* D, DeclAttr* A)
+void ParseAttribute (Declaration* D)
/* Parse an additional __attribute__ modifier */
{
- ident AttrName;
- const AttrDesc* Attr;
-
- /* Initialize the attribute description with "no attribute" */
- A->AttrType = atNone;
-
/* Do we have an attribute? */
if (CurTok.Tok != TOK_ATTRIBUTE) {
/* No attribute, bail out */
ConsumeLParen ();
ConsumeLParen ();
- /* Identifier follows */
- if (CurTok.Tok != TOK_IDENT) {
- Error ("Identifier expected");
- /* We should *really* try to recover here, but for now: */
- return;
- }
+ /* Read a list of attributes */
+ while (1) {
- /* Map the attribute name to its id, then skip the identifier */
- strcpy (AttrName, CurTok.Ident);
- Attr = FindAttribute (AttrName);
- NextToken ();
+ ident AttrName;
+ const AttrDesc* Attr = 0;
- /* Did we find a valid attribute? */
- if (Attr) {
+ /* Identifier follows */
+ if (CurTok.Tok != TOK_IDENT) {
- /* Call the handler */
- Attr->Handler (D, A);
+ /* No attribute name */
+ Error ("Attribute name expected");
- /* Read the two closing braces */
- ConsumeRParen ();
- ConsumeRParen ();
+ /* Skip until end of attribute */
+ ErrorSkip ();
- } else {
- /* List of tokens to skip */
- static const token_t SkipList[] = { TOK_LPAREN, TOK_SEMI };
+ /* Bail out */
+ return;
+ }
- /* Attribute not known, maybe typo */
- Error ("Illegal attribute: `%s'", AttrName);
+ /* Map the attribute name to its id, then skip the identifier */
+ strcpy (AttrName, CurTok.Ident);
+ Attr = FindAttribute (AttrName);
+ NextToken ();
- /* Skip until closing brace or semicolon */
- SkipTokens (SkipList, sizeof (SkipList) / sizeof (SkipList[0]));
+ /* Did we find a valid attribute? */
+ if (Attr) {
- /* If we have a closing brace, read it, otherwise bail out */
- if (CurTok.Tok == TOK_LPAREN) {
- /* Read the two closing braces */
- ConsumeRParen ();
- ConsumeRParen ();
- }
+ /* Call the handler */
+ Attr->Handler (D);
+
+ } else {
+ /* Attribute not known, maybe typo */
+ Error ("Illegal attribute: `%s'", AttrName);
+
+ /* Skip until end of attribute */
+ ErrorSkip ();
+
+ /* Bail out */
+ return;
+ }
+
+ /* If a comma follows, there's a next attribute. Otherwise this is the
+ * end of the attribute list.
+ */
+ if (CurTok.Tok != TOK_COMMA) {
+ break;
+ }
+ NextToken ();
}
+
+ /* The declaration is terminated with two closing braces */
+ ConsumeRParen ();
+ ConsumeRParen ();
}
/* */
/* */
/* */
-/* (C) 2000-2002 Ullrich von Bassewitz */
-/* Wacholderweg 14 */
-/* D-70597 Stuttgart */
-/* EMail: uz@musoftware.de */
+/* (C) 1998-2009, Ullrich von Bassewitz */
+/* Roemerstrasse 52 */
+/* D-70794 Filderstadt */
+/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
-#include "declare.h"
-
-
-
/*****************************************************************************/
-/* Data */
+/* Data */
/*****************************************************************************/
+/* Forward */
+struct Declaration;
+
/* Supported attribute types */
typedef enum {
- atNone = -1, /* No attribute */
- atAlias, /* Alias declaration */
- atUnused, /* Variable is unused */
- atZeroPage, /* Zero page symbol */
+ atNone = -1, /* No attribute */
+ atNoReturn, /* Function does not return */
- atCount /* Number of attributes */
-} attrib_t;
+ atCount /* Number of attributes */
+} DeclAttrType;
/* An actual attribute description */
typedef struct DeclAttr DeclAttr;
struct DeclAttr {
- attrib_t AttrType; /* Type of attribute */
-
- union {
- struct SymEntry* Sym; /* Symbol for alias */
- } V;
+ DeclAttrType AttrType; /* Type of attribute */
};
/*****************************************************************************/
-/* Code */
+/* Code */
/*****************************************************************************/
-void ParseAttribute (const Declaration* D, DeclAttr* A);
+void ParseAttribute (struct Declaration* D);
/* Parse an additional __attribute__ modifier */
}
} else {
+ /* Check function attributes */
+ if (Expr->Sym && SymGetAttribute (Expr->Sym, atNoReturn)) {
+ /* For now, handle as if a return statement was encountered */
+ F_ReturnFound (CurrentFunc);
+ }
+
/* Check for known standard functions and inline them */
if (Expr->Name != 0) {
int StdFunc = FindStdFunc ((const char*) Expr->Name);
/* cc65 */
#include "anonname.h"
+#include "declare.h"
+#include "error.h"
#include "symentry.h"
E->Owner = 0;
E->Flags = Flags;
E->Type = 0;
+ E->Attr = 0;
E->AsmName = 0;
memcpy (E->Name, Name, Len+1);
+const DeclAttr* SymGetAttribute (const SymEntry* Sym, DeclAttrType AttrType)
+/* Return an attribute for this symbol or NULL if the attribute does not exist */
+{
+ /* Beware: We may not even have a collection */
+ if (Sym->Attr) {
+ unsigned I;
+ for (I = 0; I < CollCount (Sym->Attr); ++I) {
+
+ /* Get the next attribute */
+ const DeclAttr* A = CollConstAt (Sym->Attr, I);
+
+ /* If this is the one we're searching for, return it */
+ if (A->AttrType == AttrType) {
+ return A;
+ }
+ }
+ }
+
+ /* Not found */
+ return 0;
+}
+
+
+
+void SymUseAttributes (SymEntry* Sym, struct Declaration* D)
+/* Use the attributes from the declaration for this symbol */
+{
+ /* We cannot specify attributes twice */
+ if ((Sym->Flags & SC_HAVEATTR) != 0) {
+ if (D->Attributes != 0) {
+ Error ("Attributes must be specified in the first declaration");
+ }
+ return;
+ }
+
+ /* Move the attributes */
+ Sym->Attr = D->Attributes;
+ D->Attributes = 0;
+ Sym->Flags |= SC_HAVEATTR;
+}
+
+
+
void CvtRegVarToAuto (SymEntry* Sym)
/* Convert a register variable to an auto variable */
{
/* */
/* */
/* */
-/* (C) 2000-2009 Ullrich von Bassewitz */
-/* Roemerstrasse 52 */
-/* D-70794 Filderstadt */
-/* EMail: uz@cc65.org */
+/* (C) 2000-2009, Ullrich von Bassewitz */
+/* Roemerstrasse 52 */
+/* D-70794 Filderstadt */
+/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
#include <stdio.h>
/* common */
+#include "coll.h"
#include "inline.h"
/* cc65 */
#include "datatype.h"
+#include "declattr.h"
/* Storage classes and flags */
-#define SC_AUTO 0x0001U
-#define SC_REGISTER 0x0002U /* Register variable, is in static storage */
-#define SC_STATIC 0x0004U
-#define SC_EXTERN 0x0008U
+#define SC_AUTO 0x0001U /* Auto variable */
+#define SC_REGISTER 0x0002U /* Register variable */
+#define SC_STATIC 0x0004U /* Static */
+#define SC_EXTERN 0x0008U /* Extern linkage */
-#define SC_ENUM 0x0030U /* An enum (numeric constant) */
-#define SC_CONST 0x0020U /* A numeric constant with a type */
-#define SC_LABEL 0x0040U /* A goto label */
-#define SC_PARAM 0x0080U /* This is a function parameter */
-#define SC_FUNC 0x0100U /* Function entry */
+#define SC_ENUM 0x0030U /* An enum */
+#define SC_CONST 0x0020U /* A numeric constant with a type */
+#define SC_LABEL 0x0040U /* A goto label */
+#define SC_PARAM 0x0080U /* A function parameter */
+#define SC_FUNC 0x0100U /* A function */
-#define SC_DEFTYPE 0x0200U /* Parameter has default type (=int, old style) */
-#define SC_STORAGE 0x0400U /* Symbol with associated storage */
-#define SC_DEFAULT 0x0800U /* Flag: default storage class was used */
+#define SC_DEFTYPE 0x0200U /* Parameter has default type (=int, old style) */
+#define SC_STORAGE 0x0400U /* Symbol with associated storage */
+#define SC_DEFAULT 0x0800U /* Flag: default storage class was used */
-#define SC_DEF 0x1000U /* Symbol is defined */
-#define SC_REF 0x2000U /* Symbol is referenced */
+#define SC_DEF 0x1000U /* Symbol is defined */
+#define SC_REF 0x2000U /* Symbol is referenced */
-#define SC_TYPE 0x4000U /* This is a type, struct, typedef, etc. */
-#define SC_STRUCT 0x4001U /* Struct or union */
-#define SC_STRUCTFIELD 0x4002U /* Struct or union field */
-#define SC_BITFIELD 0x4004U /* A bit-field inside a struct or union */
-#define SC_TYPEDEF 0x4008U /* A typedef */
+#define SC_TYPE 0x4000U /* This is a type, struct, typedef, etc. */
+#define SC_STRUCT 0x4001U /* Struct or union */
+#define SC_STRUCTFIELD 0x4002U /* Struct or union field */
+#define SC_BITFIELD 0x4004U /* A bit-field inside a struct or union */
+#define SC_TYPEDEF 0x4008U /* A typedef */
-#define SC_ZEROPAGE 0x8000U /* Symbol marked as zeropage */
+#define SC_ZEROPAGE 0x8000U /* Symbol marked as zeropage */
+
+#define SC_HAVEATTR 0x10000U /* Symbol has attributes */
struct SymTable* Owner; /* Symbol table the symbol is in */
unsigned Flags; /* Symbol flags */
Type* Type; /* Symbol type */
+ Collection* Attr; /* Attribute list if any */
char* AsmName; /* Assembler name if any */
/* Data that differs for the different symbol types */
# define SymGetAsmName(Sym) ((Sym)->AsmName)
#endif
+const DeclAttr* SymGetAttribute (const SymEntry* Sym, DeclAttrType AttrType);
+/* Return an attribute for this symbol or NULL if the attribute does not exist */
+
+void SymUseAttributes (SymEntry* Sym, struct Declaration* D);
+/* Use the attributes from the declaration for this symbol */
+
void CvtRegVarToAuto (SymEntry* Sym);
/* Convert a register variable to an auto variable */
/* Undefined label */
Error ("Undefined label: `%s'", Entry->Name);
} else if (!SymIsRef (Entry)) {
- /* Defined but not used */
+ /* Defined but not used */
if (IS_Get (&WarnUnusedLabel)) {
Warning ("`%s' is defined but never used", Entry->Name);
}
TypeCmp (T + 1, EType + 1) < TC_EQUAL) {
/* Types not identical: Conflicting types */
Error ("Conflicting types for `%s'", Name);
- return Entry;
+ return Entry;
} else {
/* Check if we have a size in the existing definition */
if (ESize == UNSPECIFIED) {
/* New type must be identical */
if (TypeCmp (EType, T) < TC_EQUAL) {
Error ("Conflicting types for `%s'", Name);
- return Entry;
+ return Entry;
}
/* In case of a function, use the new type descriptor, since it
* empty parameter list.
*/
if (IsFunc) {
- /* Get the function descriptor from the new type */
- FuncDesc* F = GetFuncDesc (T);
- /* Use this new function descriptor if it doesn't contain
+ /* Get the function descriptor from the new type */
+ FuncDesc* F = GetFuncDesc (T);
+ /* Use this new function descriptor if it doesn't contain
* an empty parameter list.
*/
if ((F->Flags & FD_EMPTY) == 0) {