cc65/src/cc65/declattr.c

250 lines
7.5 KiB
C

/*****************************************************************************/
/* */
/* declattr.c */
/* */
/* Declarator 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 <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"
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* Forwards for attribute handlers */
static void NoReturnAttr (Declarator* D);
static void UnusedAttr (Declarator* D);
/* Attribute table */
typedef struct AttrDesc AttrDesc;
struct AttrDesc {
const char Name[15];
void (*Handler) (Declarator*);
};
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 (Declarator* D, DeclAttr* A)
/* Add an attribute to a declarator */
{
/* 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 (Declarator* D)
/* Parse the "noreturn" attribute */
{
/* Add the noreturn attribute */
AddAttr (D, NewDeclAttr (atNoReturn));
}
static void UnusedAttr (Declarator* D)
/* Parse the "unused" attribute */
{
/* Add the noreturn attribute */
AddAttr (D, NewDeclAttr (atUnused));
}
void ParseAttribute (Declarator* 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 ();
}