mirror of
https://github.com/cc65/cc65.git
synced 2025-04-01 02:31:56 +00:00
Fixed compiling with pragmas in the middle of declarations or statements.
This commit is contained in:
parent
6222cd9115
commit
20c3e994c6
@ -111,12 +111,6 @@ static void Parse (void)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check for a #pragma */
|
||||
if (CurTok.Tok == TOK_PRAGMA) {
|
||||
DoPragma ();
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check for a _Static_assert */
|
||||
if (CurTok.Tok == TOK_STATIC_ASSERT) {
|
||||
ParseStaticAssert ();
|
||||
|
@ -41,12 +41,11 @@
|
||||
#include "chartype.h"
|
||||
#include "segnames.h"
|
||||
#include "tgttrans.h"
|
||||
#include "xmalloc.h"
|
||||
|
||||
/* cc65 */
|
||||
#include "codegen.h"
|
||||
#include "error.h"
|
||||
#include "expr.h"
|
||||
#include "funcdesc.h"
|
||||
#include "global.h"
|
||||
#include "litpool.h"
|
||||
#include "scanner.h"
|
||||
@ -58,7 +57,7 @@
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* data */
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
@ -142,6 +141,21 @@ typedef enum {
|
||||
PP_ERROR,
|
||||
} PushPopResult;
|
||||
|
||||
/* Effective scope of the pragma.
|
||||
** This talks about how far the pragma has effects on whenever it shows up,
|
||||
** even in the middle of an expression, statement or something.
|
||||
*/
|
||||
typedef enum {
|
||||
PES_NONE,
|
||||
PES_IMM, /* No way back */
|
||||
PES_EXPR, /* Current expression/declarator */
|
||||
PES_STMT, /* Current statement/declaration */
|
||||
PES_SCOPE, /* Current scope */
|
||||
PES_FUNC, /* Current function */
|
||||
PES_FILE, /* Current file */
|
||||
PES_ALL, /* All */
|
||||
} pragma_scope_t;
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
@ -339,7 +353,7 @@ static void PushInt (IntStack* S, long Val)
|
||||
|
||||
|
||||
|
||||
static int BoolKeyword (StrBuf* Ident)
|
||||
static int IsBoolKeyword (StrBuf* Ident)
|
||||
/* Check if the identifier in Ident is a keyword for a boolean value. Currently
|
||||
** accepted are true/false/on/off.
|
||||
*/
|
||||
@ -364,17 +378,92 @@ static int BoolKeyword (StrBuf* Ident)
|
||||
|
||||
|
||||
|
||||
static void ApplyPragma (int PushPop, IntStack* Stack, long Val)
|
||||
/* Apply a pragma immediately */
|
||||
{
|
||||
if (PushPop > 0) {
|
||||
/* Push the new value */
|
||||
PushInt (Stack, Val);
|
||||
} else if (PushPop < 0) {
|
||||
/* Pop the old value */
|
||||
PopInt (Stack);
|
||||
} else {
|
||||
/* Set the new value */
|
||||
IS_Set (Stack, Val);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void ApplySegNamePragma (pragma_t Token, int PushPop, const char* Name, unsigned char AddrSize)
|
||||
/* Process a segname pragma */
|
||||
{
|
||||
segment_t Seg = SEG_CODE;
|
||||
|
||||
switch (Token) {
|
||||
case PRAGMA_CODE_NAME:
|
||||
case PRAGMA_CODESEG:
|
||||
Seg = SEG_CODE;
|
||||
break;
|
||||
|
||||
case PRAGMA_RODATA_NAME:
|
||||
case PRAGMA_RODATASEG:
|
||||
Seg = SEG_RODATA;
|
||||
break;
|
||||
|
||||
case PRAGMA_DATA_NAME:
|
||||
case PRAGMA_DATASEG:
|
||||
Seg = SEG_DATA;
|
||||
break;
|
||||
|
||||
case PRAGMA_BSS_NAME:
|
||||
case PRAGMA_BSSSEG:
|
||||
Seg = SEG_BSS;
|
||||
break;
|
||||
|
||||
default:
|
||||
Internal ("Unknown segment name pragma: %02X", Token);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Set the new name */
|
||||
if (PushPop > 0) {
|
||||
PushSegName (Seg, Name);
|
||||
} else if (PushPop < 0) {
|
||||
PopSegName (Seg);
|
||||
} else {
|
||||
SetSegName (Seg, Name);
|
||||
}
|
||||
|
||||
/* Set the optional address size for the segment if valid */
|
||||
if (PushPop >= 0 && AddrSize != ADDR_SIZE_INVALID) {
|
||||
SetSegAddrSize (Name, AddrSize);
|
||||
}
|
||||
|
||||
/* BSS variables are output at the end of the compilation. Don't
|
||||
** bother to change their segment, now.
|
||||
*/
|
||||
if (Seg != SEG_BSS) {
|
||||
g_segname (Seg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Pragma handling functions */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static void StringPragma (StrBuf* B, void (*Func) (const char*))
|
||||
static void StringPragma (pragma_scope_t Scope, StrBuf* B, void (*Func) (const char*))
|
||||
/* Handle a pragma that expects a string parameter */
|
||||
{
|
||||
StrBuf S = AUTO_STRBUF_INITIALIZER;
|
||||
|
||||
/* Only PES_IMM is supported */
|
||||
CHECK (Scope == PES_IMM);
|
||||
|
||||
/* We expect a string here */
|
||||
if (GetString (B, &S)) {
|
||||
/* Call the given function with the string argument */
|
||||
@ -387,14 +476,17 @@ static void StringPragma (StrBuf* B, void (*Func) (const char*))
|
||||
|
||||
|
||||
|
||||
static void SegNamePragma (StrBuf* B, segment_t Seg)
|
||||
static void SegNamePragma (pragma_scope_t Scope, pragma_t Token, StrBuf* B)
|
||||
/* Handle a pragma that expects a segment name parameter */
|
||||
{
|
||||
const char* Name;
|
||||
unsigned char AddrSize = ADDR_SIZE_INVALID;
|
||||
StrBuf S = AUTO_STRBUF_INITIALIZER;
|
||||
StrBuf A = AUTO_STRBUF_INITIALIZER;
|
||||
int Push = 0;
|
||||
int PushPop = 0;
|
||||
|
||||
/* Unused at the moment */
|
||||
(void)Scope;
|
||||
|
||||
/* Check for the "push" or "pop" keywords */
|
||||
switch (ParsePushPop (B)) {
|
||||
@ -403,19 +495,12 @@ static void SegNamePragma (StrBuf* B, segment_t Seg)
|
||||
break;
|
||||
|
||||
case PP_PUSH:
|
||||
Push = 1;
|
||||
PushPop = 1;
|
||||
break;
|
||||
|
||||
case PP_POP:
|
||||
/* Pop the old value and output it */
|
||||
PopSegName (Seg);
|
||||
|
||||
/* BSS variables are output at the end of the compilation. Don't
|
||||
** bother to change their segment, now.
|
||||
*/
|
||||
if (Seg != SEG_BSS) {
|
||||
g_segname (Seg);
|
||||
}
|
||||
ApplySegNamePragma (Token, -1, 0, 0);
|
||||
|
||||
/* Done */
|
||||
goto ExitPoint;
|
||||
@ -454,27 +539,14 @@ static void SegNamePragma (StrBuf* B, segment_t Seg)
|
||||
/* Get the address size for the segment */
|
||||
AddrSize = AddrSizeFromStr (SB_GetConstBuf (&A));
|
||||
|
||||
/* Set the address size for the segment if valid */
|
||||
if (AddrSize != ADDR_SIZE_INVALID) {
|
||||
SetSegAddrSize (Name, AddrSize);
|
||||
} else {
|
||||
Warning ("Invalid address size for segment!");
|
||||
/* Check the address size for the segment */
|
||||
if (AddrSize == ADDR_SIZE_INVALID) {
|
||||
Warning ("Invalid address size for segment");
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the new name and optionally address size */
|
||||
if (Push) {
|
||||
PushSegName (Seg, Name);
|
||||
} else {
|
||||
SetSegName (Seg, Name);
|
||||
}
|
||||
|
||||
/* BSS variables are output at the end of the compilation. Don't
|
||||
** bother to change their segment, now.
|
||||
*/
|
||||
if (Seg != SEG_BSS) {
|
||||
g_segname (Seg);
|
||||
}
|
||||
ApplySegNamePragma (Token, PushPop, Name, AddrSize);
|
||||
|
||||
} else {
|
||||
|
||||
@ -484,13 +556,15 @@ static void SegNamePragma (StrBuf* B, segment_t Seg)
|
||||
}
|
||||
|
||||
ExitPoint:
|
||||
|
||||
/* Call the string buf destructor */
|
||||
SB_Done (&S);
|
||||
SB_Done (&A);
|
||||
}
|
||||
|
||||
|
||||
static void WrappedCallPragma (StrBuf* B)
|
||||
|
||||
static void WrappedCallPragma (pragma_scope_t Scope, StrBuf* B)
|
||||
/* Handle the wrapped-call pragma */
|
||||
{
|
||||
StrBuf S = AUTO_STRBUF_INITIALIZER;
|
||||
@ -498,6 +572,9 @@ static void WrappedCallPragma (StrBuf* B)
|
||||
long Val;
|
||||
SymEntry *Entry;
|
||||
|
||||
/* Only PES_IMM is supported */
|
||||
CHECK (Scope == PES_IMM);
|
||||
|
||||
/* Check for the "push" or "pop" keywords */
|
||||
switch (ParsePushPop (B)) {
|
||||
|
||||
@ -573,11 +650,14 @@ ExitPoint:
|
||||
|
||||
|
||||
|
||||
static void CharMapPragma (StrBuf* B)
|
||||
static void CharMapPragma (pragma_scope_t Scope, StrBuf* B)
|
||||
/* Change the character map */
|
||||
{
|
||||
long Index, C;
|
||||
|
||||
/* Only PES_IMM is supported */
|
||||
CHECK (Scope == PES_IMM);
|
||||
|
||||
/* Read the character index */
|
||||
if (!GetNumber (B, &Index)) {
|
||||
return;
|
||||
@ -619,7 +699,7 @@ static void CharMapPragma (StrBuf* B)
|
||||
|
||||
|
||||
|
||||
static void WarnPragma (StrBuf* B)
|
||||
static void WarnPragma (pragma_scope_t Scope, StrBuf* B)
|
||||
/* Enable/disable warnings */
|
||||
{
|
||||
long Val;
|
||||
@ -627,6 +707,10 @@ static void WarnPragma (StrBuf* B)
|
||||
|
||||
/* A warning name must follow */
|
||||
IntStack* S = GetWarning (B);
|
||||
|
||||
/* Only PES_IMM is supported */
|
||||
CHECK (Scope == PES_IMM);
|
||||
|
||||
if (S == 0) {
|
||||
return;
|
||||
}
|
||||
@ -680,48 +764,47 @@ static void WarnPragma (StrBuf* B)
|
||||
|
||||
|
||||
|
||||
static void FlagPragma (StrBuf* B, IntStack* Stack)
|
||||
static void FlagPragma (pragma_scope_t Scope, pragma_t Token, StrBuf* B, IntStack* Stack)
|
||||
/* Handle a pragma that expects a boolean parameter */
|
||||
{
|
||||
StrBuf Ident = AUTO_STRBUF_INITIALIZER;
|
||||
long Val;
|
||||
int Push;
|
||||
int PushPop = 0;
|
||||
|
||||
/* Unused at the moment */
|
||||
(void)Scope;
|
||||
(void)Token;
|
||||
|
||||
/* Try to read an identifier */
|
||||
int IsIdent = SB_GetSym (B, &Ident, 0);
|
||||
|
||||
/* Check if we have a first argument named "pop" */
|
||||
if (IsIdent && SB_CompareStr (&Ident, "pop") == 0) {
|
||||
PopInt (Stack);
|
||||
/* Pop the old value and bail out */
|
||||
ApplyPragma (-1, Stack, 0);
|
||||
|
||||
/* No other arguments allowed */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if we have a first argument named "push" */
|
||||
if (IsIdent && SB_CompareStr (&Ident, "push") == 0) {
|
||||
Push = 1;
|
||||
PushPop = 1;
|
||||
if (!GetComma (B)) {
|
||||
goto ExitPoint;
|
||||
}
|
||||
IsIdent = SB_GetSym (B, &Ident, 0);
|
||||
} else {
|
||||
Push = 0;
|
||||
}
|
||||
|
||||
/* Boolean argument follows */
|
||||
if (IsIdent) {
|
||||
Val = BoolKeyword (&Ident);
|
||||
Val = IsBoolKeyword (&Ident);
|
||||
} else if (!GetNumber (B, &Val)) {
|
||||
goto ExitPoint;
|
||||
}
|
||||
|
||||
/* Set/push the new value */
|
||||
if (Push) {
|
||||
PushInt (Stack, Val);
|
||||
} else {
|
||||
IS_Set (Stack, Val);
|
||||
}
|
||||
/* Add this pragma and apply it whenever appropriately */
|
||||
ApplyPragma (PushPop, Stack, Val);
|
||||
|
||||
ExitPoint:
|
||||
/* Free the identifier */
|
||||
@ -730,12 +813,16 @@ ExitPoint:
|
||||
|
||||
|
||||
|
||||
static void IntPragma (StrBuf* B, IntStack* Stack, long Low, long High)
|
||||
static void IntPragma (pragma_scope_t Scope, pragma_t Token, StrBuf* B, IntStack* Stack, long Low, long High)
|
||||
/* Handle a pragma that expects an int parameter */
|
||||
{
|
||||
long Val;
|
||||
int Push;
|
||||
|
||||
/* Unused at the moment */
|
||||
(void)Scope;
|
||||
(void)Token;
|
||||
|
||||
/* Check for the "push" or "pop" keywords */
|
||||
switch (ParsePushPop (B)) {
|
||||
|
||||
@ -749,7 +836,7 @@ static void IntPragma (StrBuf* B, IntStack* Stack, long Low, long High)
|
||||
|
||||
case PP_POP:
|
||||
/* Pop the old value and bail out */
|
||||
PopInt (Stack);
|
||||
ApplyPragma (-1, Stack, 0);
|
||||
return;
|
||||
|
||||
case PP_ERROR:
|
||||
@ -772,31 +859,32 @@ static void IntPragma (StrBuf* B, IntStack* Stack, long Low, long High)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set/push the new value */
|
||||
if (Push) {
|
||||
PushInt (Stack, Val);
|
||||
} else {
|
||||
IS_Set (Stack, Val);
|
||||
}
|
||||
/* Add this pragma and apply it whenever appropriately */
|
||||
ApplyPragma (Push, Stack, Val);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void MakeMessage (const char* Message)
|
||||
static void NoteMessagePragma (const char* Message)
|
||||
/* Wrapper for printf-like Note() function protected from user-provided format
|
||||
** specifiers.
|
||||
*/
|
||||
{
|
||||
Note ("%s", Message);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void ParsePragma (void)
|
||||
/* Parse the contents of the _Pragma statement */
|
||||
static void ParsePragmaString (void)
|
||||
/* Parse the contents of _Pragma */
|
||||
{
|
||||
pragma_t Pragma;
|
||||
StrBuf Ident = AUTO_STRBUF_INITIALIZER;
|
||||
|
||||
/* Create a string buffer from the string literal */
|
||||
StrBuf B = AUTO_STRBUF_INITIALIZER;
|
||||
|
||||
|
||||
SB_Append (&B, GetLiteralStrBuf (CurTok.SVal));
|
||||
|
||||
/* Skip the string token */
|
||||
@ -837,111 +925,130 @@ static void ParsePragma (void)
|
||||
switch (Pragma) {
|
||||
|
||||
case PRAGMA_ALIGN:
|
||||
IntPragma (&B, &DataAlignment, 1, 4096);
|
||||
/* TODO: PES_EXPR (PES_DECL) */
|
||||
IntPragma (PES_STMT, Pragma, &B, &DataAlignment, 1, 4096);
|
||||
break;
|
||||
|
||||
case PRAGMA_ALLOW_EAGER_INLINE:
|
||||
FlagPragma (&B, &EagerlyInlineFuncs);
|
||||
FlagPragma (PES_STMT, Pragma, &B, &EagerlyInlineFuncs);
|
||||
break;
|
||||
|
||||
case PRAGMA_BSSSEG:
|
||||
Warning ("#pragma bssseg is obsolete, please use #pragma bss-name instead");
|
||||
/* FALLTHROUGH */
|
||||
case PRAGMA_BSS_NAME:
|
||||
SegNamePragma (&B, SEG_BSS);
|
||||
/* TODO: PES_STMT or even PES_EXPR (PES_DECL) maybe? */
|
||||
SegNamePragma (PES_FUNC, PRAGMA_BSS_NAME, &B);
|
||||
break;
|
||||
|
||||
case PRAGMA_CHARMAP:
|
||||
CharMapPragma (&B);
|
||||
CharMapPragma (PES_IMM, &B);
|
||||
break;
|
||||
|
||||
case PRAGMA_CHECKSTACK:
|
||||
Warning ("#pragma checkstack is obsolete, please use #pragma check-stack instead");
|
||||
/* FALLTHROUGH */
|
||||
case PRAGMA_CHECK_STACK:
|
||||
FlagPragma (&B, &CheckStack);
|
||||
/* TODO: PES_SCOPE maybe? */
|
||||
FlagPragma (PES_FUNC, Pragma, &B, &CheckStack);
|
||||
break;
|
||||
|
||||
case PRAGMA_CODESEG:
|
||||
Warning ("#pragma codeseg is obsolete, please use #pragma code-name instead");
|
||||
/* FALLTHROUGH */
|
||||
case PRAGMA_CODE_NAME:
|
||||
SegNamePragma (&B, SEG_CODE);
|
||||
/* PES_FUNC is the only sensible option so far */
|
||||
SegNamePragma (PES_FUNC, PRAGMA_CODE_NAME, &B);
|
||||
break;
|
||||
|
||||
case PRAGMA_CODESIZE:
|
||||
IntPragma (&B, &CodeSizeFactor, 10, 1000);
|
||||
/* PES_EXPR would be optimization nightmare */
|
||||
IntPragma (PES_STMT, Pragma, &B, &CodeSizeFactor, 10, 1000);
|
||||
break;
|
||||
|
||||
case PRAGMA_DATASEG:
|
||||
Warning ("#pragma dataseg is obsolete, please use #pragma data-name instead");
|
||||
/* FALLTHROUGH */
|
||||
case PRAGMA_DATA_NAME:
|
||||
SegNamePragma (&B, SEG_DATA);
|
||||
/* TODO: PES_STMT or even PES_EXPR (PES_DECL) maybe? */
|
||||
SegNamePragma (PES_FUNC, PRAGMA_DATA_NAME, &B);
|
||||
break;
|
||||
|
||||
case PRAGMA_INLINE_STDFUNCS:
|
||||
FlagPragma (&B, &InlineStdFuncs);
|
||||
/* TODO: PES_EXPR maybe? */
|
||||
FlagPragma (PES_STMT, Pragma, &B, &InlineStdFuncs);
|
||||
break;
|
||||
|
||||
case PRAGMA_LOCAL_STRINGS:
|
||||
FlagPragma (&B, &LocalStrings);
|
||||
/* TODO: PES_STMT or even PES_EXPR */
|
||||
FlagPragma (PES_FUNC, Pragma, &B, &LocalStrings);
|
||||
break;
|
||||
|
||||
case PRAGMA_MESSAGE:
|
||||
StringPragma (&B, MakeMessage);
|
||||
/* PES_IMM is the only sensible option */
|
||||
StringPragma (PES_IMM, &B, NoteMessagePragma);
|
||||
break;
|
||||
|
||||
case PRAGMA_OPTIMIZE:
|
||||
FlagPragma (&B, &Optimize);
|
||||
/* TODO: PES_STMT or even PES_EXPR maybe? */
|
||||
FlagPragma (PES_STMT, Pragma, &B, &Optimize);
|
||||
break;
|
||||
|
||||
case PRAGMA_REGVARADDR:
|
||||
FlagPragma (&B, &AllowRegVarAddr);
|
||||
/* TODO: PES_STMT or even PES_EXPR maybe? */
|
||||
FlagPragma (PES_FUNC, Pragma, &B, &AllowRegVarAddr);
|
||||
break;
|
||||
|
||||
case PRAGMA_REGVARS:
|
||||
Warning ("#pragma regvars is obsolete, please use #pragma register-vars instead");
|
||||
/* FALLTHROUGH */
|
||||
case PRAGMA_REGISTER_VARS:
|
||||
FlagPragma (&B, &EnableRegVars);
|
||||
/* TODO: PES_STMT or even PES_EXPR (PES_DECL) maybe? */
|
||||
FlagPragma (PES_FUNC, Pragma, &B, &EnableRegVars);
|
||||
break;
|
||||
|
||||
case PRAGMA_RODATASEG:
|
||||
Warning ("#pragma rodataseg is obsolete, please use #pragma rodata-name instead");
|
||||
/* FALLTHROUGH */
|
||||
case PRAGMA_RODATA_NAME:
|
||||
SegNamePragma (&B, SEG_RODATA);
|
||||
/* TODO: PES_STMT or even PES_EXPR maybe? */
|
||||
SegNamePragma (PES_FUNC, PRAGMA_RODATA_NAME, &B);
|
||||
break;
|
||||
|
||||
case PRAGMA_SIGNEDCHARS:
|
||||
Warning ("#pragma signedchars is obsolete, please use #pragma signed-chars instead");
|
||||
/* FALLTHROUGH */
|
||||
case PRAGMA_SIGNED_CHARS:
|
||||
FlagPragma (&B, &SignedChars);
|
||||
/* TODO: PES_STMT or even PES_EXPR maybe? */
|
||||
FlagPragma (PES_FUNC, Pragma, &B, &SignedChars);
|
||||
break;
|
||||
|
||||
case PRAGMA_STATICLOCALS:
|
||||
Warning ("#pragma staticlocals is obsolete, please use #pragma static-locals instead");
|
||||
/* FALLTHROUGH */
|
||||
case PRAGMA_STATIC_LOCALS:
|
||||
FlagPragma (&B, &StaticLocals);
|
||||
/* TODO: PES_STMT or even PES_EXPR (PES_DECL) maybe? */
|
||||
FlagPragma (PES_FUNC, Pragma, &B, &StaticLocals);
|
||||
break;
|
||||
|
||||
case PRAGMA_WRAPPED_CALL:
|
||||
WrappedCallPragma(&B);
|
||||
/* PES_IMM is the only sensible option */
|
||||
WrappedCallPragma (PES_IMM, &B);
|
||||
break;
|
||||
|
||||
case PRAGMA_WARN:
|
||||
WarnPragma (&B);
|
||||
/* PES_IMM is the only sensible option */
|
||||
WarnPragma (PES_IMM, &B);
|
||||
break;
|
||||
|
||||
case PRAGMA_WRITABLE_STRINGS:
|
||||
FlagPragma (&B, &WritableStrings);
|
||||
/* TODO: PES_STMT or even PES_EXPR maybe? */
|
||||
FlagPragma (PES_FUNC, Pragma, &B, &WritableStrings);
|
||||
break;
|
||||
|
||||
case PRAGMA_ZPSYM:
|
||||
StringPragma (&B, MakeZPSym);
|
||||
/* PES_IMM is the only sensible option */
|
||||
StringPragma (PES_IMM, &B, MakeZPSym);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -975,10 +1082,18 @@ ExitPoint:
|
||||
|
||||
|
||||
|
||||
void DoPragma (void)
|
||||
/* Handle pragmas. These come always in form of the new C99 _Pragma() operator. */
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
void ConsumePragma (void)
|
||||
/* Parse a pragma. The pragma comes always in the form of the new C99 _Pragma()
|
||||
** operator.
|
||||
*/
|
||||
{
|
||||
/* Skip the token itself */
|
||||
/* Skip the _Pragma token */
|
||||
NextToken ();
|
||||
|
||||
/* We expect an opening paren */
|
||||
@ -988,7 +1103,6 @@ void DoPragma (void)
|
||||
|
||||
/* String literal */
|
||||
if (CurTok.Tok != TOK_SCONST) {
|
||||
|
||||
/* Print a diagnostic */
|
||||
Error ("String literal expected");
|
||||
|
||||
@ -996,11 +1110,9 @@ void DoPragma (void)
|
||||
** enclosing paren, or a semicolon.
|
||||
*/
|
||||
PragmaErrorSkip ();
|
||||
|
||||
} else {
|
||||
|
||||
/* Parse the _Pragma statement */
|
||||
ParsePragma ();
|
||||
/* Parse the pragma */
|
||||
ParsePragmaString ();
|
||||
}
|
||||
|
||||
/* Closing paren needed */
|
||||
|
@ -44,8 +44,10 @@
|
||||
|
||||
|
||||
|
||||
void DoPragma (void);
|
||||
/* Handle pragmas. These come always in form of the new C99 _Pragma() operator. */
|
||||
void ConsumePragma (void);
|
||||
/* Parse a pragma. The pragma comes always in the form of the new C99 _Pragma()
|
||||
** operator.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
@ -56,6 +56,7 @@
|
||||
#include "ident.h"
|
||||
#include "input.h"
|
||||
#include "litpool.h"
|
||||
#include "pragma.h"
|
||||
#include "preproc.h"
|
||||
#include "scanner.h"
|
||||
#include "standard.h"
|
||||
@ -800,36 +801,30 @@ static void NumericConst (void)
|
||||
|
||||
|
||||
|
||||
void NextToken (void)
|
||||
static void GetNextInputToken (void)
|
||||
/* Get next token from input stream */
|
||||
{
|
||||
ident token;
|
||||
|
||||
/* We have to skip white space here before shifting tokens, since the
|
||||
** tokens and the current line info is invalid at startup and will get
|
||||
** initialized by reading the first time from the file. Remember if
|
||||
** we were at end of input and handle that later.
|
||||
** initialized by reading the first time from the file. Remember if we
|
||||
** were at end of input and handle that later.
|
||||
*/
|
||||
int GotEOF = (SkipWhite() == 0);
|
||||
int GotEOF = (SkipWhite () == 0);
|
||||
|
||||
/* Current token is the lookahead token */
|
||||
if (CurTok.LI) {
|
||||
ReleaseLineInfo (CurTok.LI);
|
||||
}
|
||||
CurTok = NextTok;
|
||||
|
||||
/* When reading the first time from the file, the line info in NextTok,
|
||||
** which was copied to CurTok is invalid. Since the information from
|
||||
** the token is used for error messages, we must make it valid.
|
||||
*/
|
||||
if (CurTok.LI == 0) {
|
||||
CurTok.LI = UseLineInfo (GetCurLineInfo ());
|
||||
}
|
||||
/* Get the current token */
|
||||
CurTok = NextTok;
|
||||
|
||||
/* Remember the starting position of the next token */
|
||||
NextTok.LI = UseLineInfo (GetCurLineInfo ());
|
||||
|
||||
/* Now handle end of input. */
|
||||
/* Now handle end of input */
|
||||
if (GotEOF) {
|
||||
/* End of file reached */
|
||||
NextTok.Tok = TOK_CEOF;
|
||||
@ -859,7 +854,8 @@ void NextToken (void)
|
||||
|
||||
if (!PPParserRunning) {
|
||||
/* Check for a keyword */
|
||||
if ((NextTok.Tok = FindKey (token)) != TOK_IDENT) {
|
||||
NextTok.Tok = FindKey (token);
|
||||
if (NextTok.Tok != TOK_IDENT) {
|
||||
/* Reserved word found */
|
||||
return;
|
||||
}
|
||||
@ -1117,7 +1113,31 @@ void NextToken (void)
|
||||
UnknownChar (CurC);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void NextToken (void)
|
||||
/* Get next non-pragma token from input stream consuming any pragmas
|
||||
** encountered. Adjacent string literal tokens will be concatenated.
|
||||
*/
|
||||
{
|
||||
/* When reading the first time from the file, the line info in NextTok,
|
||||
** which will be copied to CurTok is invalid. Since the information from
|
||||
** the token is used for error messages, we must make it valid.
|
||||
*/
|
||||
if (NextTok.LI == 0) {
|
||||
NextTok.LI = UseLineInfo (GetCurLineInfo ());
|
||||
}
|
||||
|
||||
/* Read the next token from the file */
|
||||
GetNextInputToken ();
|
||||
|
||||
/* Consume all pragmas at hand, including those nested in a _Pragma() */
|
||||
if (CurTok.Tok == TOK_PRAGMA) {
|
||||
/* Repeated and/or nested _Pragma()'s will be handled recursively */
|
||||
ConsumePragma ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -299,7 +299,9 @@ void CopyPPNumber (StrBuf* Target);
|
||||
/* Copy a pp-number from the input to Target */
|
||||
|
||||
void NextToken (void);
|
||||
/* Get next token from input stream */
|
||||
/* Get next non-pragma token from input stream consuming any pragmas
|
||||
** encountered. Adjacent string literal tokens will be concatenated.
|
||||
*/
|
||||
|
||||
void SkipTokens (const token_t* TokenList, unsigned TokenCount);
|
||||
/* Skip tokens until we reach TOK_CEOF or a token in the given token list.
|
||||
|
@ -735,10 +735,6 @@ int AnyStatement (int* PendingToken)
|
||||
GotBreak = 1;
|
||||
break;
|
||||
|
||||
case TOK_PRAGMA:
|
||||
DoPragma ();
|
||||
break;
|
||||
|
||||
case TOK_SEMI:
|
||||
/* Empty statement. Ignore it */
|
||||
CheckSemi (PendingToken);
|
||||
|
29
test/val/bug2151.c
Normal file
29
test/val/bug2151.c
Normal file
@ -0,0 +1,29 @@
|
||||
/* Bug #2151 - #pragma causes errors when used within functions */
|
||||
|
||||
#pragma bss-name("BSS1")
|
||||
int
|
||||
#pragma code-name("CODE_WUT")
|
||||
main _Pragma("message(\"_Pragma note\")")
|
||||
(
|
||||
void
|
||||
_Pragma _Pragma (
|
||||
#pragma message("nested message 1")
|
||||
"message(\"nested message 2\")"
|
||||
)
|
||||
(
|
||||
"message(\"_Pragma in function parentheses\")")
|
||||
#pragma code-name("CODE")
|
||||
)
|
||||
#pragma bss-name("BSS")
|
||||
{
|
||||
extern int y;
|
||||
#pragma bss-name("BSS2")
|
||||
static
|
||||
#pragma zpsym ("y")
|
||||
int x; // TODO: currently in "BSS", but supposed to be in "BSS2"?
|
||||
x = 0;
|
||||
return x + y;
|
||||
#pragma bss-name("BSS")
|
||||
}
|
||||
|
||||
int y;
|
Loading…
x
Reference in New Issue
Block a user