mirror of https://github.com/cc65/cc65.git
250 lines
7.5 KiB
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 ();
|
|
}
|