1
0
mirror of https://github.com/cc65/cc65.git synced 2024-06-26 05:29:30 +00:00

Fixed the existing but unused attribute parsing code. Added

__attribute__((noexit)) that may be used to mark functions that won't return.
Added this attribute to the exit() function in stdlib.h.


git-svn-id: svn://svn.cc65.org/cc65/trunk@4372 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
uz 2009-10-18 18:31:02 +00:00
parent 0ce362a69b
commit 5a00b38aab
10 changed files with 270 additions and 173 deletions

View File

@ -109,7 +109,7 @@ int __fastcall__ atexit (void (*exitfunc) (void));
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*));

View File

@ -83,7 +83,6 @@ static void Parse (void)
while (CurTok.Tok != TOK_CEOF) {
DeclSpec Spec;
Declaration Decl;
/* Check for empty statements */
if (CurTok.Tok == TOK_SEMI) {
@ -128,6 +127,8 @@ static void Parse (void)
comma = 0;
while (1) {
Declaration Decl;
/* Read the next declaration */
ParseDecl (&Spec, &Decl, DM_NEED_IDENT);
if (Decl.Ident[0] == '\0') {
@ -168,6 +169,9 @@ static void Parse (void)
/* 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) {
@ -334,7 +338,7 @@ void Compile (const char* FileName)
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);

View File

@ -249,9 +249,10 @@ static void InitDeclSpec (DeclSpec* D)
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;
}
@ -1123,7 +1124,6 @@ static void ParseAnsiParamList (FuncDesc* F)
DeclSpec Spec;
Declaration Decl;
DeclAttr Attr;
/* Allow an ellipsis as last parameter */
if (CurTok.Tok == TOK_ELLIPSIS) {
@ -1161,8 +1161,8 @@ static void ParseAnsiParamList (FuncDesc* F)
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);
@ -1195,8 +1195,7 @@ static void ParseAnsiParamList (FuncDesc* F)
/* 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");
}
}
@ -1204,7 +1203,7 @@ static void ParseAnsiParamList (FuncDesc* F)
static FuncDesc* ParseFuncDecl (void)
static FuncDesc* ParseFuncDecl (Declaration* D)
/* Parse the argument list of a function. */
{
unsigned Offs;
@ -1238,8 +1237,24 @@ static FuncDesc* ParseFuncDecl (void)
/* 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);
@ -1344,7 +1359,7 @@ static void Declarator (const DeclSpec* Spec, Declaration* D, declmode_t Mode)
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)) {

View File

@ -6,10 +6,10 @@
/* */
/* */
/* */
/* (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 */
@ -38,6 +38,9 @@
/* common */
#include "coll.h"
/* cc65 */
#include "scanner.h"
#include "symtab.h"
@ -58,9 +61,9 @@
/* 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 */
@ -68,14 +71,15 @@ typedef struct Declaration Declaration;
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 */

View File

@ -6,10 +6,10 @@
/* */
/* */
/* */
/* (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 */
@ -35,12 +35,16 @@
#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"
@ -51,28 +55,46 @@
/* 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 */
/*****************************************************************************/
@ -85,7 +107,7 @@ static const AttrDesc* FindAttribute (const char* Attr)
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;
@ -98,72 +120,54 @@ static const AttrDesc* FindAttribute (const char* Attr)
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;
}
/* Attribute is verified, set the stuff in the attribute description */
A->AttrType = atAlias;
A->V.Sym = Sym;
}
static void UnusedAttr (const Declaration* D attribute ((unused)), DeclAttr* A)
/* Handle the "unused" attribute */
static void AddAttr (Declaration* D, DeclAttr* A)
/* Add an attribute to a declaration */
{
/* No parameters */
A->AttrType = atUnused;
/* Allocate the list if necessary, the add the attribute */
if (D->Attributes == 0) {
D->Attributes = NewCollection ();
}
CollAppend (D->Attributes, A);
}
static void ZeroPageAttr (const Declaration* D attribute ((unused)), DeclAttr* A)
/* Handle the "zeropage" attribute */
/*****************************************************************************/
/* Attribute handling code */
/*****************************************************************************/
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 */
@ -177,45 +181,59 @@ void ParseAttribute (const Declaration* D, DeclAttr* A)
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) {
ident AttrName;
const AttrDesc* Attr = 0;
/* Identifier follows */
if (CurTok.Tok != TOK_IDENT) {
/* No attribute name */
Error ("Attribute name expected");
/* Skip until end of attribute */
ErrorSkip ();
/* Bail out */
return;
}
/* Map the attribute name to its id, then skip the identifier */
strcpy (AttrName, CurTok.Ident);
Attr = FindAttribute (AttrName);
NextToken ();
/* Did we find a valid attribute? */
if (Attr) {
/* 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 ();
}
/* Map the attribute name to its id, then skip the identifier */
strcpy (AttrName, CurTok.Ident);
Attr = FindAttribute (AttrName);
NextToken ();
/* Did we find a valid attribute? */
if (Attr) {
/* Call the handler */
Attr->Handler (D, A);
/* Read the two closing braces */
ConsumeRParen ();
ConsumeRParen ();
} else {
/* List of tokens to skip */
static const token_t SkipList[] = { TOK_LPAREN, TOK_SEMI };
/* Attribute not known, maybe typo */
Error ("Illegal attribute: `%s'", AttrName);
/* Skip until closing brace or semicolon */
SkipTokens (SkipList, sizeof (SkipList) / sizeof (SkipList[0]));
/* If we have a closing brace, read it, otherwise bail out */
if (CurTok.Tok == TOK_LPAREN) {
/* Read the two closing braces */
ConsumeRParen ();
ConsumeRParen ();
}
}
/* The declaration is terminated with two closing braces */
ConsumeRParen ();
ConsumeRParen ();
}

View File

@ -6,10 +6,10 @@
/* */
/* */
/* */
/* (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 */
@ -38,45 +38,38 @@
#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 */

View File

@ -486,6 +486,12 @@ static void FunctionCall (ExprDesc* Expr)
}
} 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);

View File

@ -40,6 +40,8 @@
/* cc65 */
#include "anonname.h"
#include "declare.h"
#include "error.h"
#include "symentry.h"
@ -67,6 +69,7 @@ SymEntry* NewSymEntry (const char* Name, unsigned Flags)
E->Owner = 0;
E->Flags = Flags;
E->Type = 0;
E->Attr = 0;
E->AsmName = 0;
memcpy (E->Name, Name, Len+1);
@ -150,6 +153,49 @@ void DumpSymEntry (FILE* F, const SymEntry* E)
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 */
{

View File

@ -6,10 +6,10 @@
/* */
/* */
/* */
/* (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 */
@ -41,10 +41,12 @@
#include <stdio.h>
/* common */
#include "coll.h"
#include "inline.h"
/* cc65 */
#include "datatype.h"
#include "declattr.h"
@ -65,31 +67,33 @@ struct Segments;
/* 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 */
@ -103,6 +107,7 @@ struct SymEntry {
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 */
@ -226,6 +231,12 @@ INLINE const char* SymGetAsmName (const SymEntry* Sym)
# 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 */

View File

@ -181,7 +181,7 @@ static void CheckSymTable (SymTable* Tab)
/* 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);
}
@ -768,7 +768,7 @@ SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags)
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) {
@ -781,7 +781,7 @@ SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags)
/* 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
@ -791,9 +791,9 @@ SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags)
* 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) {