/*****************************************************************************/ /* */ /* declattr.c */ /* */ /* Declaration attributes */ /* */ /* */ /* */ /* (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 */ /* warranty. In no event will the authors be held liable for any damages */ /* arising from the use of this software. */ /* */ /* Permission is granted to anyone to use this software for any purpose, */ /* including commercial applications, and to alter it and redistribute it */ /* freely, subject to the following restrictions: */ /* */ /* 1. The origin of this software must not be misrepresented; you must not */ /* claim that you wrote the original software. If you use this software */ /* in a product, an acknowledgment in the product documentation would be */ /* appreciated but is not required. */ /* 2. Altered source versions must be plainly marked as such, and must not */ /* be misrepresented as being the original software. */ /* 3. This notice may not be removed or altered from any source */ /* distribution. */ /* */ /*****************************************************************************/ #include /* common */ #include "xmalloc.h" /* cc65 */ #include "declare.h" #include "declattr.h" #include "error.h" #include "scanner.h" #include "symtab.h" #include "typecmp.h" /*****************************************************************************/ /* Data */ /*****************************************************************************/ /* Forwards for attribute handlers */ static void NoReturnAttr (Declaration* D); static void UnusedAttr (Declaration* D); /* Attribute table */ typedef struct AttrDesc AttrDesc; struct AttrDesc { const char Name[15]; void (*Handler) (Declaration*); }; static const AttrDesc AttrTable [] = { { "__noreturn__", NoReturnAttr }, { "__unused__", UnusedAttr }, { "noreturn", NoReturnAttr }, { "unused", UnusedAttr }, }; /*****************************************************************************/ /* 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 */ /*****************************************************************************/ static const AttrDesc* FindAttribute (const char* Attr) /* Search the attribute and return the corresponding attribute descriptor. * Return NULL if the attribute name is not known. */ { unsigned A; /* For now do a linear search */ for (A = 0; A < sizeof (AttrTable) / sizeof (AttrTable[0]); ++A) { if (strcmp (Attr, AttrTable[A].Name) == 0) { /* Found */ return AttrTable + A; } } /* Not found */ return 0; } static void ErrorSkip (void) { /* List of tokens to skip */ static const token_t SkipList[] = { TOK_RPAREN, TOK_SEMI }; /* 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_RPAREN) { /* Read the two closing braces */ ConsumeRParen (); ConsumeRParen (); } } 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 (); } CollAppend (D->Attributes, A); } /*****************************************************************************/ /* Attribute handling code */ /*****************************************************************************/ static void NoReturnAttr (Declaration* D) /* Parse the "noreturn" attribute */ { /* Add the noreturn attribute */ AddAttr (D, NewDeclAttr (atNoReturn)); } static void UnusedAttr (Declaration* D) /* Parse the "unused" attribute */ { /* Add the noreturn attribute */ AddAttr (D, NewDeclAttr (atUnused)); } void ParseAttribute (Declaration* D) /* Parse an additional __attribute__ modifier */ { /* Do we have an attribute? */ if (CurTok.Tok != TOK_ATTRIBUTE) { /* No attribute, bail out */ return; } /* Skip the attribute token */ NextToken (); /* Expect two(!) open braces */ ConsumeLParen (); ConsumeLParen (); /* 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 (); } /* The declaration is terminated with two closing braces */ ConsumeRParen (); ConsumeRParen (); }