Fixed compiling with pragmas in the middle of declarations or statements.
This commit is contained in:
@@ -111,12 +111,6 @@ static void Parse (void)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for a #pragma */
|
|
||||||
if (CurTok.Tok == TOK_PRAGMA) {
|
|
||||||
DoPragma ();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check for a _Static_assert */
|
/* Check for a _Static_assert */
|
||||||
if (CurTok.Tok == TOK_STATIC_ASSERT) {
|
if (CurTok.Tok == TOK_STATIC_ASSERT) {
|
||||||
ParseStaticAssert ();
|
ParseStaticAssert ();
|
||||||
|
|||||||
@@ -41,12 +41,11 @@
|
|||||||
#include "chartype.h"
|
#include "chartype.h"
|
||||||
#include "segnames.h"
|
#include "segnames.h"
|
||||||
#include "tgttrans.h"
|
#include "tgttrans.h"
|
||||||
|
#include "xmalloc.h"
|
||||||
|
|
||||||
/* cc65 */
|
/* cc65 */
|
||||||
#include "codegen.h"
|
#include "codegen.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "expr.h"
|
|
||||||
#include "funcdesc.h"
|
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include "litpool.h"
|
#include "litpool.h"
|
||||||
#include "scanner.h"
|
#include "scanner.h"
|
||||||
@@ -58,7 +57,7 @@
|
|||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* data */
|
/* Data */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
@@ -142,6 +141,21 @@ typedef enum {
|
|||||||
PP_ERROR,
|
PP_ERROR,
|
||||||
} PushPopResult;
|
} 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
|
/* Check if the identifier in Ident is a keyword for a boolean value. Currently
|
||||||
** accepted are true/false/on/off.
|
** 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 */
|
/* 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 */
|
/* Handle a pragma that expects a string parameter */
|
||||||
{
|
{
|
||||||
StrBuf S = AUTO_STRBUF_INITIALIZER;
|
StrBuf S = AUTO_STRBUF_INITIALIZER;
|
||||||
|
|
||||||
|
/* Only PES_IMM is supported */
|
||||||
|
CHECK (Scope == PES_IMM);
|
||||||
|
|
||||||
/* We expect a string here */
|
/* We expect a string here */
|
||||||
if (GetString (B, &S)) {
|
if (GetString (B, &S)) {
|
||||||
/* Call the given function with the string argument */
|
/* 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 */
|
/* Handle a pragma that expects a segment name parameter */
|
||||||
{
|
{
|
||||||
const char* Name;
|
const char* Name;
|
||||||
unsigned char AddrSize = ADDR_SIZE_INVALID;
|
unsigned char AddrSize = ADDR_SIZE_INVALID;
|
||||||
StrBuf S = AUTO_STRBUF_INITIALIZER;
|
StrBuf S = AUTO_STRBUF_INITIALIZER;
|
||||||
StrBuf A = 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 */
|
/* Check for the "push" or "pop" keywords */
|
||||||
switch (ParsePushPop (B)) {
|
switch (ParsePushPop (B)) {
|
||||||
@@ -403,19 +495,12 @@ static void SegNamePragma (StrBuf* B, segment_t Seg)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case PP_PUSH:
|
case PP_PUSH:
|
||||||
Push = 1;
|
PushPop = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PP_POP:
|
case PP_POP:
|
||||||
/* Pop the old value and output it */
|
/* Pop the old value and output it */
|
||||||
PopSegName (Seg);
|
ApplySegNamePragma (Token, -1, 0, 0);
|
||||||
|
|
||||||
/* 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Done */
|
/* Done */
|
||||||
goto ExitPoint;
|
goto ExitPoint;
|
||||||
@@ -454,27 +539,14 @@ static void SegNamePragma (StrBuf* B, segment_t Seg)
|
|||||||
/* Get the address size for the segment */
|
/* Get the address size for the segment */
|
||||||
AddrSize = AddrSizeFromStr (SB_GetConstBuf (&A));
|
AddrSize = AddrSizeFromStr (SB_GetConstBuf (&A));
|
||||||
|
|
||||||
/* Set the address size for the segment if valid */
|
/* Check the address size for the segment */
|
||||||
if (AddrSize != ADDR_SIZE_INVALID) {
|
if (AddrSize == ADDR_SIZE_INVALID) {
|
||||||
SetSegAddrSize (Name, AddrSize);
|
Warning ("Invalid address size for segment");
|
||||||
} else {
|
|
||||||
Warning ("Invalid address size for segment!");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the new name and optionally address size */
|
/* Set the new name and optionally address size */
|
||||||
if (Push) {
|
ApplySegNamePragma (Token, PushPop, Name, AddrSize);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
@@ -484,13 +556,15 @@ static void SegNamePragma (StrBuf* B, segment_t Seg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ExitPoint:
|
ExitPoint:
|
||||||
|
|
||||||
/* Call the string buf destructor */
|
/* Call the string buf destructor */
|
||||||
SB_Done (&S);
|
SB_Done (&S);
|
||||||
SB_Done (&A);
|
SB_Done (&A);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void WrappedCallPragma (StrBuf* B)
|
|
||||||
|
static void WrappedCallPragma (pragma_scope_t Scope, StrBuf* B)
|
||||||
/* Handle the wrapped-call pragma */
|
/* Handle the wrapped-call pragma */
|
||||||
{
|
{
|
||||||
StrBuf S = AUTO_STRBUF_INITIALIZER;
|
StrBuf S = AUTO_STRBUF_INITIALIZER;
|
||||||
@@ -498,6 +572,9 @@ static void WrappedCallPragma (StrBuf* B)
|
|||||||
long Val;
|
long Val;
|
||||||
SymEntry *Entry;
|
SymEntry *Entry;
|
||||||
|
|
||||||
|
/* Only PES_IMM is supported */
|
||||||
|
CHECK (Scope == PES_IMM);
|
||||||
|
|
||||||
/* Check for the "push" or "pop" keywords */
|
/* Check for the "push" or "pop" keywords */
|
||||||
switch (ParsePushPop (B)) {
|
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 */
|
/* Change the character map */
|
||||||
{
|
{
|
||||||
long Index, C;
|
long Index, C;
|
||||||
|
|
||||||
|
/* Only PES_IMM is supported */
|
||||||
|
CHECK (Scope == PES_IMM);
|
||||||
|
|
||||||
/* Read the character index */
|
/* Read the character index */
|
||||||
if (!GetNumber (B, &Index)) {
|
if (!GetNumber (B, &Index)) {
|
||||||
return;
|
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 */
|
/* Enable/disable warnings */
|
||||||
{
|
{
|
||||||
long Val;
|
long Val;
|
||||||
@@ -627,6 +707,10 @@ static void WarnPragma (StrBuf* B)
|
|||||||
|
|
||||||
/* A warning name must follow */
|
/* A warning name must follow */
|
||||||
IntStack* S = GetWarning (B);
|
IntStack* S = GetWarning (B);
|
||||||
|
|
||||||
|
/* Only PES_IMM is supported */
|
||||||
|
CHECK (Scope == PES_IMM);
|
||||||
|
|
||||||
if (S == 0) {
|
if (S == 0) {
|
||||||
return;
|
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 */
|
/* Handle a pragma that expects a boolean parameter */
|
||||||
{
|
{
|
||||||
StrBuf Ident = AUTO_STRBUF_INITIALIZER;
|
StrBuf Ident = AUTO_STRBUF_INITIALIZER;
|
||||||
long Val;
|
long Val;
|
||||||
int Push;
|
int PushPop = 0;
|
||||||
|
|
||||||
|
/* Unused at the moment */
|
||||||
|
(void)Scope;
|
||||||
|
(void)Token;
|
||||||
|
|
||||||
/* Try to read an identifier */
|
/* Try to read an identifier */
|
||||||
int IsIdent = SB_GetSym (B, &Ident, 0);
|
int IsIdent = SB_GetSym (B, &Ident, 0);
|
||||||
|
|
||||||
/* Check if we have a first argument named "pop" */
|
/* Check if we have a first argument named "pop" */
|
||||||
if (IsIdent && SB_CompareStr (&Ident, "pop") == 0) {
|
if (IsIdent && SB_CompareStr (&Ident, "pop") == 0) {
|
||||||
PopInt (Stack);
|
/* Pop the old value and bail out */
|
||||||
|
ApplyPragma (-1, Stack, 0);
|
||||||
|
|
||||||
/* No other arguments allowed */
|
/* No other arguments allowed */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if we have a first argument named "push" */
|
/* Check if we have a first argument named "push" */
|
||||||
if (IsIdent && SB_CompareStr (&Ident, "push") == 0) {
|
if (IsIdent && SB_CompareStr (&Ident, "push") == 0) {
|
||||||
Push = 1;
|
PushPop = 1;
|
||||||
if (!GetComma (B)) {
|
if (!GetComma (B)) {
|
||||||
goto ExitPoint;
|
goto ExitPoint;
|
||||||
}
|
}
|
||||||
IsIdent = SB_GetSym (B, &Ident, 0);
|
IsIdent = SB_GetSym (B, &Ident, 0);
|
||||||
} else {
|
|
||||||
Push = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Boolean argument follows */
|
/* Boolean argument follows */
|
||||||
if (IsIdent) {
|
if (IsIdent) {
|
||||||
Val = BoolKeyword (&Ident);
|
Val = IsBoolKeyword (&Ident);
|
||||||
} else if (!GetNumber (B, &Val)) {
|
} else if (!GetNumber (B, &Val)) {
|
||||||
goto ExitPoint;
|
goto ExitPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set/push the new value */
|
/* Add this pragma and apply it whenever appropriately */
|
||||||
if (Push) {
|
ApplyPragma (PushPop, Stack, Val);
|
||||||
PushInt (Stack, Val);
|
|
||||||
} else {
|
|
||||||
IS_Set (Stack, Val);
|
|
||||||
}
|
|
||||||
|
|
||||||
ExitPoint:
|
ExitPoint:
|
||||||
/* Free the identifier */
|
/* 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 */
|
/* Handle a pragma that expects an int parameter */
|
||||||
{
|
{
|
||||||
long Val;
|
long Val;
|
||||||
int Push;
|
int Push;
|
||||||
|
|
||||||
|
/* Unused at the moment */
|
||||||
|
(void)Scope;
|
||||||
|
(void)Token;
|
||||||
|
|
||||||
/* Check for the "push" or "pop" keywords */
|
/* Check for the "push" or "pop" keywords */
|
||||||
switch (ParsePushPop (B)) {
|
switch (ParsePushPop (B)) {
|
||||||
|
|
||||||
@@ -749,7 +836,7 @@ static void IntPragma (StrBuf* B, IntStack* Stack, long Low, long High)
|
|||||||
|
|
||||||
case PP_POP:
|
case PP_POP:
|
||||||
/* Pop the old value and bail out */
|
/* Pop the old value and bail out */
|
||||||
PopInt (Stack);
|
ApplyPragma (-1, Stack, 0);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case PP_ERROR:
|
case PP_ERROR:
|
||||||
@@ -772,31 +859,32 @@ static void IntPragma (StrBuf* B, IntStack* Stack, long Low, long High)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set/push the new value */
|
/* Add this pragma and apply it whenever appropriately */
|
||||||
if (Push) {
|
ApplyPragma (Push, Stack, Val);
|
||||||
PushInt (Stack, Val);
|
|
||||||
} else {
|
|
||||||
IS_Set (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);
|
Note ("%s", Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void ParsePragma (void)
|
static void ParsePragmaString (void)
|
||||||
/* Parse the contents of the _Pragma statement */
|
/* Parse the contents of _Pragma */
|
||||||
{
|
{
|
||||||
pragma_t Pragma;
|
pragma_t Pragma;
|
||||||
StrBuf Ident = AUTO_STRBUF_INITIALIZER;
|
StrBuf Ident = AUTO_STRBUF_INITIALIZER;
|
||||||
|
|
||||||
/* Create a string buffer from the string literal */
|
/* Create a string buffer from the string literal */
|
||||||
StrBuf B = AUTO_STRBUF_INITIALIZER;
|
StrBuf B = AUTO_STRBUF_INITIALIZER;
|
||||||
|
|
||||||
|
|
||||||
SB_Append (&B, GetLiteralStrBuf (CurTok.SVal));
|
SB_Append (&B, GetLiteralStrBuf (CurTok.SVal));
|
||||||
|
|
||||||
/* Skip the string token */
|
/* Skip the string token */
|
||||||
@@ -837,111 +925,130 @@ static void ParsePragma (void)
|
|||||||
switch (Pragma) {
|
switch (Pragma) {
|
||||||
|
|
||||||
case PRAGMA_ALIGN:
|
case PRAGMA_ALIGN:
|
||||||
IntPragma (&B, &DataAlignment, 1, 4096);
|
/* TODO: PES_EXPR (PES_DECL) */
|
||||||
|
IntPragma (PES_STMT, Pragma, &B, &DataAlignment, 1, 4096);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PRAGMA_ALLOW_EAGER_INLINE:
|
case PRAGMA_ALLOW_EAGER_INLINE:
|
||||||
FlagPragma (&B, &EagerlyInlineFuncs);
|
FlagPragma (PES_STMT, Pragma, &B, &EagerlyInlineFuncs);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PRAGMA_BSSSEG:
|
case PRAGMA_BSSSEG:
|
||||||
Warning ("#pragma bssseg is obsolete, please use #pragma bss-name instead");
|
Warning ("#pragma bssseg is obsolete, please use #pragma bss-name instead");
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
case PRAGMA_BSS_NAME:
|
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;
|
break;
|
||||||
|
|
||||||
case PRAGMA_CHARMAP:
|
case PRAGMA_CHARMAP:
|
||||||
CharMapPragma (&B);
|
CharMapPragma (PES_IMM, &B);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PRAGMA_CHECKSTACK:
|
case PRAGMA_CHECKSTACK:
|
||||||
Warning ("#pragma checkstack is obsolete, please use #pragma check-stack instead");
|
Warning ("#pragma checkstack is obsolete, please use #pragma check-stack instead");
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
case PRAGMA_CHECK_STACK:
|
case PRAGMA_CHECK_STACK:
|
||||||
FlagPragma (&B, &CheckStack);
|
/* TODO: PES_SCOPE maybe? */
|
||||||
|
FlagPragma (PES_FUNC, Pragma, &B, &CheckStack);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PRAGMA_CODESEG:
|
case PRAGMA_CODESEG:
|
||||||
Warning ("#pragma codeseg is obsolete, please use #pragma code-name instead");
|
Warning ("#pragma codeseg is obsolete, please use #pragma code-name instead");
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
case PRAGMA_CODE_NAME:
|
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;
|
break;
|
||||||
|
|
||||||
case PRAGMA_CODESIZE:
|
case PRAGMA_CODESIZE:
|
||||||
IntPragma (&B, &CodeSizeFactor, 10, 1000);
|
/* PES_EXPR would be optimization nightmare */
|
||||||
|
IntPragma (PES_STMT, Pragma, &B, &CodeSizeFactor, 10, 1000);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PRAGMA_DATASEG:
|
case PRAGMA_DATASEG:
|
||||||
Warning ("#pragma dataseg is obsolete, please use #pragma data-name instead");
|
Warning ("#pragma dataseg is obsolete, please use #pragma data-name instead");
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
case PRAGMA_DATA_NAME:
|
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;
|
break;
|
||||||
|
|
||||||
case PRAGMA_INLINE_STDFUNCS:
|
case PRAGMA_INLINE_STDFUNCS:
|
||||||
FlagPragma (&B, &InlineStdFuncs);
|
/* TODO: PES_EXPR maybe? */
|
||||||
|
FlagPragma (PES_STMT, Pragma, &B, &InlineStdFuncs);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PRAGMA_LOCAL_STRINGS:
|
case PRAGMA_LOCAL_STRINGS:
|
||||||
FlagPragma (&B, &LocalStrings);
|
/* TODO: PES_STMT or even PES_EXPR */
|
||||||
|
FlagPragma (PES_FUNC, Pragma, &B, &LocalStrings);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PRAGMA_MESSAGE:
|
case PRAGMA_MESSAGE:
|
||||||
StringPragma (&B, MakeMessage);
|
/* PES_IMM is the only sensible option */
|
||||||
|
StringPragma (PES_IMM, &B, NoteMessagePragma);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PRAGMA_OPTIMIZE:
|
case PRAGMA_OPTIMIZE:
|
||||||
FlagPragma (&B, &Optimize);
|
/* TODO: PES_STMT or even PES_EXPR maybe? */
|
||||||
|
FlagPragma (PES_STMT, Pragma, &B, &Optimize);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PRAGMA_REGVARADDR:
|
case PRAGMA_REGVARADDR:
|
||||||
FlagPragma (&B, &AllowRegVarAddr);
|
/* TODO: PES_STMT or even PES_EXPR maybe? */
|
||||||
|
FlagPragma (PES_FUNC, Pragma, &B, &AllowRegVarAddr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PRAGMA_REGVARS:
|
case PRAGMA_REGVARS:
|
||||||
Warning ("#pragma regvars is obsolete, please use #pragma register-vars instead");
|
Warning ("#pragma regvars is obsolete, please use #pragma register-vars instead");
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
case PRAGMA_REGISTER_VARS:
|
case PRAGMA_REGISTER_VARS:
|
||||||
FlagPragma (&B, &EnableRegVars);
|
/* TODO: PES_STMT or even PES_EXPR (PES_DECL) maybe? */
|
||||||
|
FlagPragma (PES_FUNC, Pragma, &B, &EnableRegVars);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PRAGMA_RODATASEG:
|
case PRAGMA_RODATASEG:
|
||||||
Warning ("#pragma rodataseg is obsolete, please use #pragma rodata-name instead");
|
Warning ("#pragma rodataseg is obsolete, please use #pragma rodata-name instead");
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
case PRAGMA_RODATA_NAME:
|
case PRAGMA_RODATA_NAME:
|
||||||
SegNamePragma (&B, SEG_RODATA);
|
/* TODO: PES_STMT or even PES_EXPR maybe? */
|
||||||
|
SegNamePragma (PES_FUNC, PRAGMA_RODATA_NAME, &B);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PRAGMA_SIGNEDCHARS:
|
case PRAGMA_SIGNEDCHARS:
|
||||||
Warning ("#pragma signedchars is obsolete, please use #pragma signed-chars instead");
|
Warning ("#pragma signedchars is obsolete, please use #pragma signed-chars instead");
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
case PRAGMA_SIGNED_CHARS:
|
case PRAGMA_SIGNED_CHARS:
|
||||||
FlagPragma (&B, &SignedChars);
|
/* TODO: PES_STMT or even PES_EXPR maybe? */
|
||||||
|
FlagPragma (PES_FUNC, Pragma, &B, &SignedChars);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PRAGMA_STATICLOCALS:
|
case PRAGMA_STATICLOCALS:
|
||||||
Warning ("#pragma staticlocals is obsolete, please use #pragma static-locals instead");
|
Warning ("#pragma staticlocals is obsolete, please use #pragma static-locals instead");
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
case PRAGMA_STATIC_LOCALS:
|
case PRAGMA_STATIC_LOCALS:
|
||||||
FlagPragma (&B, &StaticLocals);
|
/* TODO: PES_STMT or even PES_EXPR (PES_DECL) maybe? */
|
||||||
|
FlagPragma (PES_FUNC, Pragma, &B, &StaticLocals);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PRAGMA_WRAPPED_CALL:
|
case PRAGMA_WRAPPED_CALL:
|
||||||
WrappedCallPragma(&B);
|
/* PES_IMM is the only sensible option */
|
||||||
|
WrappedCallPragma (PES_IMM, &B);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PRAGMA_WARN:
|
case PRAGMA_WARN:
|
||||||
WarnPragma (&B);
|
/* PES_IMM is the only sensible option */
|
||||||
|
WarnPragma (PES_IMM, &B);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PRAGMA_WRITABLE_STRINGS:
|
case PRAGMA_WRITABLE_STRINGS:
|
||||||
FlagPragma (&B, &WritableStrings);
|
/* TODO: PES_STMT or even PES_EXPR maybe? */
|
||||||
|
FlagPragma (PES_FUNC, Pragma, &B, &WritableStrings);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PRAGMA_ZPSYM:
|
case PRAGMA_ZPSYM:
|
||||||
StringPragma (&B, MakeZPSym);
|
/* PES_IMM is the only sensible option */
|
||||||
|
StringPragma (PES_IMM, &B, MakeZPSym);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
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 ();
|
NextToken ();
|
||||||
|
|
||||||
/* We expect an opening paren */
|
/* We expect an opening paren */
|
||||||
@@ -988,7 +1103,6 @@ void DoPragma (void)
|
|||||||
|
|
||||||
/* String literal */
|
/* String literal */
|
||||||
if (CurTok.Tok != TOK_SCONST) {
|
if (CurTok.Tok != TOK_SCONST) {
|
||||||
|
|
||||||
/* Print a diagnostic */
|
/* Print a diagnostic */
|
||||||
Error ("String literal expected");
|
Error ("String literal expected");
|
||||||
|
|
||||||
@@ -996,11 +1110,9 @@ void DoPragma (void)
|
|||||||
** enclosing paren, or a semicolon.
|
** enclosing paren, or a semicolon.
|
||||||
*/
|
*/
|
||||||
PragmaErrorSkip ();
|
PragmaErrorSkip ();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
/* Parse the pragma */
|
||||||
/* Parse the _Pragma statement */
|
ParsePragmaString ();
|
||||||
ParsePragma ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Closing paren needed */
|
/* Closing paren needed */
|
||||||
|
|||||||
@@ -44,8 +44,10 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void DoPragma (void);
|
void ConsumePragma (void);
|
||||||
/* Handle pragmas. These come always in form of the new C99 _Pragma() operator. */
|
/* Parse a pragma. The pragma comes always in the form of the new C99 _Pragma()
|
||||||
|
** operator.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -56,6 +56,7 @@
|
|||||||
#include "ident.h"
|
#include "ident.h"
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "litpool.h"
|
#include "litpool.h"
|
||||||
|
#include "pragma.h"
|
||||||
#include "preproc.h"
|
#include "preproc.h"
|
||||||
#include "scanner.h"
|
#include "scanner.h"
|
||||||
#include "standard.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 */
|
/* Get next token from input stream */
|
||||||
{
|
{
|
||||||
ident token;
|
ident token;
|
||||||
|
|
||||||
/* We have to skip white space here before shifting tokens, since the
|
/* 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
|
** tokens and the current line info is invalid at startup and will get
|
||||||
** initialized by reading the first time from the file. Remember if
|
** initialized by reading the first time from the file. Remember if we
|
||||||
** we were at end of input and handle that later.
|
** were at end of input and handle that later.
|
||||||
*/
|
*/
|
||||||
int GotEOF = (SkipWhite() == 0);
|
int GotEOF = (SkipWhite () == 0);
|
||||||
|
|
||||||
/* Current token is the lookahead token */
|
/* Current token is the lookahead token */
|
||||||
if (CurTok.LI) {
|
if (CurTok.LI) {
|
||||||
ReleaseLineInfo (CurTok.LI);
|
ReleaseLineInfo (CurTok.LI);
|
||||||
}
|
}
|
||||||
CurTok = NextTok;
|
|
||||||
|
|
||||||
/* When reading the first time from the file, the line info in NextTok,
|
/* Get the current token */
|
||||||
** which was copied to CurTok is invalid. Since the information from
|
CurTok = NextTok;
|
||||||
** the token is used for error messages, we must make it valid.
|
|
||||||
*/
|
|
||||||
if (CurTok.LI == 0) {
|
|
||||||
CurTok.LI = UseLineInfo (GetCurLineInfo ());
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Remember the starting position of the next token */
|
/* Remember the starting position of the next token */
|
||||||
NextTok.LI = UseLineInfo (GetCurLineInfo ());
|
NextTok.LI = UseLineInfo (GetCurLineInfo ());
|
||||||
|
|
||||||
/* Now handle end of input. */
|
/* Now handle end of input */
|
||||||
if (GotEOF) {
|
if (GotEOF) {
|
||||||
/* End of file reached */
|
/* End of file reached */
|
||||||
NextTok.Tok = TOK_CEOF;
|
NextTok.Tok = TOK_CEOF;
|
||||||
@@ -859,7 +854,8 @@ void NextToken (void)
|
|||||||
|
|
||||||
if (!PPParserRunning) {
|
if (!PPParserRunning) {
|
||||||
/* Check for a keyword */
|
/* Check for a keyword */
|
||||||
if ((NextTok.Tok = FindKey (token)) != TOK_IDENT) {
|
NextTok.Tok = FindKey (token);
|
||||||
|
if (NextTok.Tok != TOK_IDENT) {
|
||||||
/* Reserved word found */
|
/* Reserved word found */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1117,7 +1113,31 @@ void NextToken (void)
|
|||||||
UnknownChar (CurC);
|
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 */
|
/* Copy a pp-number from the input to Target */
|
||||||
|
|
||||||
void NextToken (void);
|
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);
|
void SkipTokens (const token_t* TokenList, unsigned TokenCount);
|
||||||
/* Skip tokens until we reach TOK_CEOF or a token in the given token list.
|
/* 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;
|
GotBreak = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOK_PRAGMA:
|
|
||||||
DoPragma ();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TOK_SEMI:
|
case TOK_SEMI:
|
||||||
/* Empty statement. Ignore it */
|
/* Empty statement. Ignore it */
|
||||||
CheckSemi (PendingToken);
|
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;
|
||||||
Reference in New Issue
Block a user