/*****************************************************************************/
/* */
-/* pragma.c */
+/* pragma.c */
/* */
-/* Pragma handling for the cc65 C compiler */
+/* Pragma handling for the cc65 C compiler */
/* */
/* */
/* */
-/* (C) 1998 Ullrich von Bassewitz */
-/* Wacholderweg 14 */
-/* D-70597 Stuttgart */
-/* EMail: uz@musoftware.de */
+/* (C) 1998-2011, Ullrich von Bassewitz */
+/* Roemerstrasse 52 */
+/* D-70794 Filderstadt */
+/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
#include <stdlib.h>
-#include <ctype.h>
+#include <string.h>
-#include "global.h"
+/* common */
+#include "chartype.h"
+#include "segnames.h"
+#include "tgttrans.h"
+
+/* cc65 */
+#include "codegen.h"
#include "error.h"
+#include "expr.h"
+#include "global.h"
#include "litpool.h"
-#include "symtab.h"
#include "scanner.h"
-#include "codegen.h"
-#include "expr.h"
+#include "scanstrbuf.h"
+#include "symtab.h"
#include "pragma.h"
/*****************************************************************************/
-/* data */
+/* data */
/*****************************************************************************/
/* Tokens for the #pragmas */
typedef enum {
- PR_BSSSEG,
- PR_CODESEG,
- PR_DATASEG,
- PR_REGVARADDR,
- PR_RODATASEG,
- PR_SIGNEDCHARS,
- PR_STATICLOCALS,
- PR_ZPSYM,
- PR_ILLEGAL
+ PRAGMA_ILLEGAL = -1,
+ PRAGMA_ALIGN,
+ PRAGMA_BSS_NAME,
+ PRAGMA_BSSSEG, /* obsolete */
+ PRAGMA_CHARMAP,
+ PRAGMA_CHECK_STACK,
+ PRAGMA_CHECKSTACK, /* obsolete */
+ PRAGMA_CODE_NAME,
+ PRAGMA_CODESEG, /* obsolete */
+ PRAGMA_CODESIZE,
+ PRAGMA_DATA_NAME,
+ PRAGMA_DATASEG, /* obsolete */
+ PRAGMA_LOCAL_STRINGS,
+ PRAGMA_OPTIMIZE,
+ PRAGMA_REGVARADDR,
+ PRAGMA_REGISTER_VARS,
+ PRAGMA_REGVARS, /* obsolete */
+ PRAGMA_RODATA_NAME,
+ PRAGMA_RODATASEG, /* obsolete */
+ PRAGMA_SIGNED_CHARS,
+ PRAGMA_SIGNEDCHARS, /* obsolete */
+ PRAGMA_STATIC_LOCALS,
+ PRAGMA_STATICLOCALS, /* obsolete */
+ PRAGMA_WARN,
+ PRAGMA_WRITABLE_STRINGS,
+ PRAGMA_ZPSYM,
+ PRAGMA_COUNT
} pragma_t;
/* Pragma table */
static const struct Pragma {
- const char* Key; /* Keyword */
- pragma_t Tok; /* Token */
-} Pragmas[] = {
- { "bssseg", PR_BSSSEG },
- { "codeseg", PR_CODESEG },
- { "dataseg", PR_DATASEG },
- { "regvaraddr", PR_REGVARADDR },
- { "rodataseg", PR_RODATASEG },
- { "signedchars", PR_SIGNEDCHARS },
- { "staticlocals", PR_STATICLOCALS },
- { "zpsym", PR_ZPSYM },
+ const char* Key; /* Keyword */
+ pragma_t Tok; /* Token */
+} Pragmas[PRAGMA_COUNT] = {
+ { "align", PRAGMA_ALIGN },
+ { "bss-name", PRAGMA_BSS_NAME },
+ { "bssseg", PRAGMA_BSSSEG }, /* obsolete */
+ { "charmap", PRAGMA_CHARMAP },
+ { "check-stack", PRAGMA_CHECK_STACK },
+ { "checkstack", PRAGMA_CHECKSTACK }, /* obsolete */
+ { "code-name", PRAGMA_CODE_NAME },
+ { "codeseg", PRAGMA_CODESEG }, /* obsolete */
+ { "codesize", PRAGMA_CODESIZE },
+ { "data-name", PRAGMA_DATA_NAME },
+ { "dataseg", PRAGMA_DATASEG }, /* obsolete */
+ { "local-strings", PRAGMA_LOCAL_STRINGS },
+ { "optimize", PRAGMA_OPTIMIZE },
+ { "register-vars", PRAGMA_REGISTER_VARS },
+ { "regvaraddr", PRAGMA_REGVARADDR },
+ { "regvars", PRAGMA_REGVARS }, /* obsolete */
+ { "rodata-name", PRAGMA_RODATA_NAME },
+ { "rodataseg", PRAGMA_RODATASEG }, /* obsolete */
+ { "signed-chars", PRAGMA_SIGNED_CHARS },
+ { "signedchars", PRAGMA_SIGNEDCHARS }, /* obsolete */
+ { "static-locals", PRAGMA_STATIC_LOCALS },
+ { "staticlocals", PRAGMA_STATICLOCALS }, /* obsolete */
+ { "warn", PRAGMA_WARN },
+ { "writable-strings", PRAGMA_WRITABLE_STRINGS },
+ { "zpsym", PRAGMA_ZPSYM },
};
-/* Number of pragmas */
-#define PRAGMA_COUNT (sizeof(Pragmas) / sizeof(Pragmas[0]))
+/* Result of ParsePushPop */
+typedef enum {
+ PP_NONE,
+ PP_POP,
+ PP_PUSH,
+ PP_ERROR,
+} PushPopResult;
/*****************************************************************************/
-/* Code */
+/* Helper functions */
/*****************************************************************************/
+static void PragmaErrorSkip (void)
+/* Called in case of an error, skips tokens until the closing paren or a
+ * semicolon is reached.
+ */
+{
+ static const token_t TokenList[] = { TOK_RPAREN, TOK_SEMI };
+ SkipTokens (TokenList, sizeof(TokenList) / sizeof(TokenList[0]));
+}
+
+
+
static int CmpKey (const void* Key, const void* Elem)
/* Compare function for bsearch */
{
-static pragma_t FindPragma (const char* Key)
-/* Find a pragma and return the token. Return PR_ILLEGAL if the keyword is
+static pragma_t FindPragma (const StrBuf* Key)
+/* Find a pragma and return the token. Return PRAGMA_ILLEGAL if the keyword is
* not a valid pragma.
*/
{
struct Pragma* P;
- P = bsearch (Key, Pragmas, PRAGMA_COUNT, sizeof (Pragmas[0]), CmpKey);
- return P? P->Tok : PR_ILLEGAL;
+ P = bsearch (SB_GetConstBuf (Key), Pragmas, PRAGMA_COUNT, sizeof (Pragmas[0]), CmpKey);
+ return P? P->Tok : PRAGMA_ILLEGAL;
+}
+
+
+
+static int GetComma (StrBuf* B)
+/* Expects and skips a comma in B. Prints an error and returns zero if no
+ * comma is found. Return a value <> 0 otherwise.
+ */
+{
+ SB_SkipWhite (B);
+ if (SB_Get (B) != ',') {
+ Error ("Comma expected");
+ return 0;
+ }
+ SB_SkipWhite (B);
+ return 1;
+}
+
+
+
+static int GetString (StrBuf* B, StrBuf* S)
+/* Expects and skips a string in B. Prints an error and returns zero if no
+ * string is found. Returns a value <> 0 otherwise.
+ */
+{
+ if (!SB_GetString (B, S)) {
+ Error ("String literal expected");
+ return 0;
+ }
+ return 1;
+}
+
+
+
+static int GetNumber (StrBuf* B, long* Val)
+/* Expects and skips a number in B. Prints an eror and returns zero if no
+ * number is found. Returns a value <> 0 otherwise.
+ */
+{
+ if (!SB_GetNumber (B, Val)) {
+ Error ("Constant integer expected");
+ return 0;
+ }
+ return 1;
+}
+
+
+
+static IntStack* GetWarning (StrBuf* B)
+/* Get a warning name from the string buffer. Returns a pointer to the intstack
+ * that holds the state of the warning, and NULL in case of errors. The
+ * function will output error messages in case of problems.
+ */
+{
+ IntStack* S = 0;
+ StrBuf W = AUTO_STRBUF_INITIALIZER;
+
+ /* The warning name is a symbol but the '-' char is allowed within */
+ if (SB_GetSym (B, &W, "-")) {
+
+ /* Map the warning name to an IntStack that contains its state */
+ S = FindWarning (SB_GetConstBuf (&W));
+
+ /* Handle errors */
+ if (S == 0) {
+ Error ("Pragma expects a warning name as first argument");
+ }
+ }
+
+ /* Deallocate the string */
+ SB_Done (&W);
+
+ /* Done */
+ return S;
+}
+
+
+
+static int HasStr (StrBuf* B, const char* E)
+/* Checks if E follows in B. If so, skips it and returns true */
+{
+ unsigned Len = strlen (E);
+ if (SB_GetLen (B) - SB_GetIndex (B) >= Len) {
+ if (strncmp (SB_GetConstBuf (B) + SB_GetIndex (B), E, Len) == 0) {
+ /* Found */
+ SB_SkipMultiple (B, Len);
+ return 1;
+ }
+ }
+ return 0;
}
-static void StringPragma (void (*Func) (const char*))
+static PushPopResult ParsePushPop (StrBuf* B)
+/* Check for and parse the "push" and "pop" keywords. In case of "push", a
+ * following comma is expected and skipped.
+ */
+{
+ StrBuf Ident = AUTO_STRBUF_INITIALIZER;
+ PushPopResult Res = PP_NONE;
+
+ /* Remember the current string index, so we can go back in case of errors */
+ unsigned Index = SB_GetIndex (B);
+
+ /* Try to read an identifier */
+ if (SB_GetSym (B, &Ident, 0)) {
+
+ /* Check if we have a first argument named "pop" */
+ if (SB_CompareStr (&Ident, "pop") == 0) {
+
+ Res = PP_POP;
+
+ /* Check if we have a first argument named "push" */
+ } else if (SB_CompareStr (&Ident, "push") == 0) {
+
+ Res = PP_PUSH;
+
+ /* Skip the following comma */
+ if (!GetComma (B)) {
+ /* Error already flagged by GetComma */
+ Res = PP_ERROR;
+ }
+
+ } else {
+
+ /* Unknown keyword, roll back */
+ SB_SetIndex (B, Index);
+ }
+ }
+
+ /* Free the string buffer and return the result */
+ SB_Done (&Ident);
+ return Res;
+}
+
+
+
+static void PopInt (IntStack* S)
+/* Pops an integer from an IntStack. Prints an error if the stack is empty */
+{
+ if (IS_GetCount (S) < 2) {
+ Error ("Cannot pop, stack is empty");
+ } else {
+ IS_Drop (S);
+ }
+}
+
+
+
+static void PushInt (IntStack* S, long Val)
+/* Pushes an integer onto an IntStack. Prints an error if the stack is full */
+{
+ if (IS_IsFull (S)) {
+ Error ("Cannot push: stack overflow");
+ } else {
+ IS_Push (S, Val);
+ }
+}
+
+
+
+static int BoolKeyword (StrBuf* Ident)
+/* Check if the identifier in Ident is a keyword for a boolean value. Currently
+ * accepted are true/false/on/off.
+ */
+{
+ if (SB_CompareStr (Ident, "true") == 0) {
+ return 1;
+ }
+ if (SB_CompareStr (Ident, "on") == 0) {
+ return 1;
+ }
+ if (SB_CompareStr (Ident, "false") == 0) {
+ return 0;
+ }
+ if (SB_CompareStr (Ident, "off") == 0) {
+ return 0;
+ }
+
+ /* Error */
+ Error ("Pragma argument must be one of `on', `off', `true' or `false'");
+ return 0;
+}
+
+
+
+/*****************************************************************************/
+/* Pragma handling functions */
+/*****************************************************************************/
+
+
+
+static void StringPragma (StrBuf* B, void (*Func) (const char*))
/* Handle a pragma that expects a string parameter */
{
- if (curtok != TOK_SCONST) {
- Error (ERR_STRLIT_EXPECTED);
+ StrBuf S = AUTO_STRBUF_INITIALIZER;
+
+ /* We expect a string here */
+ if (GetString (B, &S)) {
+ /* Call the given function with the string argument */
+ Func (SB_GetConstBuf (&S));
+ }
+
+ /* Call the string buf destructor */
+ SB_Done (&S);
+}
+
+
+
+static void SegNamePragma (StrBuf* B, segment_t Seg)
+/* Handle a pragma that expects a segment name parameter */
+{
+ StrBuf S = AUTO_STRBUF_INITIALIZER;
+ const char* Name;
+
+ /* Check for the "push" or "pop" keywords */
+ int Push = 0;
+ switch (ParsePushPop (B)) {
+
+ case PP_NONE:
+ break;
+
+ case PP_PUSH:
+ Push = 1;
+ break;
+
+ case PP_POP:
+ /* Pop the old value and output it */
+ PopSegName (Seg);
+ g_segname (Seg);
+
+ /* Done */
+ goto ExitPoint;
+
+ case PP_ERROR:
+ /* Bail out */
+ goto ExitPoint;
+
+ default:
+ Internal ("Invalid result from ParsePushPop");
+
+ }
+
+ /* A string argument must follow */
+ if (!GetString (B, &S)) {
+ goto ExitPoint;
+ }
+
+ /* Get the string */
+ Name = SB_GetConstBuf (&S);
+
+ /* Check if the name is valid */
+ if (ValidSegName (Name)) {
+
+ /* Set the new name */
+ if (Push) {
+ PushSegName (Seg, Name);
+ } else {
+ SetSegName (Seg, Name);
+ }
+ g_segname (Seg);
+
} else {
- /* Get the string */
- const char* Name = GetLiteral (curval);
- /* Call the given function with the string argument */
- Func (Name);
+ /* Segment name is invalid */
+ Error ("Illegal segment name: `%s'", Name);
- /* Reset the string pointer, removing the string from the pool */
- ResetLiteralOffs (curval);
}
- /* Skip the string (or error) token */
- NextToken ();
+ExitPoint:
+ /* Call the string buf destructor */
+ SB_Done (&S);
}
-static void FlagPragma (unsigned char* Flag)
+static void CharMapPragma (StrBuf* B)
+/* Change the character map */
+{
+ long Index, C;
+
+ /* Read the character index */
+ if (!GetNumber (B, &Index)) {
+ return;
+ }
+ if (Index < 1 || Index > 255) {
+ if (Index == 0) {
+ /* For groepaz */
+ Error ("Remapping 0 is not allowed");
+ } else {
+ Error ("Character index out of range");
+ }
+ return;
+ }
+
+ /* Comma follows */
+ if (!GetComma (B)) {
+ return;
+ }
+
+ /* Read the character code */
+ if (!GetNumber (B, &C)) {
+ return;
+ }
+ if (C < 1 || C > 255) {
+ if (C == 0) {
+ /* For groepaz */
+ Error ("Remapping 0 is not allowed");
+ } else {
+ Error ("Character code out of range");
+ }
+ return;
+ }
+
+ /* Remap the character */
+ TgtTranslateSet ((unsigned) Index, (unsigned char) C);
+}
+
+
+
+static void WarnPragma (StrBuf* B)
+/* Enable/disable warnings */
+{
+ long Val;
+ int Push;
+
+ /* A warning name must follow */
+ IntStack* S = GetWarning (B);
+ if (S == 0) {
+ return;
+ }
+
+ /* Comma follows */
+ if (!GetComma (B)) {
+ return;
+ }
+
+ /* Check for the "push" or "pop" keywords */
+ switch (ParsePushPop (B)) {
+
+ case PP_NONE:
+ Push = 0;
+ break;
+
+ case PP_PUSH:
+ Push = 1;
+ break;
+
+ case PP_POP:
+ /* Pop the old value and bail out */
+ PopInt (S);
+ return;
+
+ case PP_ERROR:
+ /* Bail out */
+ return;
+
+ default:
+ Internal ("Invalid result from ParsePushPop");
+ }
+
+ /* Boolean argument follows */
+ if (HasStr (B, "true") || HasStr (B, "on")) {
+ Val = 1;
+ } else if (HasStr (B, "false") || HasStr (B, "off")) {
+ Val = 0;
+ } else if (!SB_GetNumber (B, &Val)) {
+ Error ("Invalid pragma argument");
+ return;
+ }
+
+ /* Set/push the new value */
+ if (Push) {
+ PushInt (S, Val);
+ } else {
+ IS_Set (S, Val);
+ }
+}
+
+
+
+static void FlagPragma (StrBuf* B, IntStack* Stack)
/* Handle a pragma that expects a boolean paramater */
{
- /* Read a constant expression */
- struct expent val;
- constexpr (&val);
+ StrBuf Ident = AUTO_STRBUF_INITIALIZER;
+ long Val;
+ int Push;
+
+
+ /* 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);
+ /* No other arguments allowed */
+ return;
+ }
- /* Store the value into the flag parameter */
- *Flag = (val.e_const != 0);
+ /* Check if we have a first argument named "push" */
+ if (IsIdent && SB_CompareStr (&Ident, "push") == 0) {
+ Push = 1;
+ if (!GetComma (B)) {
+ goto ExitPoint;
+ }
+ IsIdent = SB_GetSym (B, &Ident, 0);
+ } else {
+ Push = 0;
+ }
+
+ /* Boolean argument follows */
+ if (IsIdent) {
+ Val = BoolKeyword (&Ident);
+ } else if (!GetNumber (B, &Val)) {
+ goto ExitPoint;
+ }
+
+ /* Set/push the new value */
+ if (Push) {
+ PushInt (Stack, Val);
+ } else {
+ IS_Set (Stack, Val);
+ }
+
+ExitPoint:
+ /* Free the identifier */
+ SB_Done (&Ident);
}
-void DoPragma (void)
-/* Handle pragmas */
+static void IntPragma (StrBuf* B, IntStack* Stack, long Low, long High)
+/* Handle a pragma that expects an int paramater */
+{
+ long Val;
+ int Push;
+
+ /* Check for the "push" or "pop" keywords */
+ switch (ParsePushPop (B)) {
+
+ case PP_NONE:
+ Push = 0;
+ break;
+
+ case PP_PUSH:
+ Push = 1;
+ break;
+
+ case PP_POP:
+ /* Pop the old value and bail out */
+ PopInt (Stack);
+ return;
+
+ case PP_ERROR:
+ /* Bail out */
+ return;
+
+ default:
+ Internal ("Invalid result from ParsePushPop");
+
+ }
+
+ /* Integer argument follows */
+ if (!GetNumber (B, &Val)) {
+ return;
+ }
+
+ /* Check the argument */
+ if (Val < Low || Val > High) {
+ Error ("Pragma argument out of bounds (%ld-%ld)", Low, High);
+ return;
+ }
+
+ /* Set/push the new value */
+ if (Push) {
+ PushInt (Stack, Val);
+ } else {
+ IS_Set (Stack, Val);
+ }
+}
+
+
+
+static void ParsePragma (void)
+/* Parse the contents of the _Pragma statement */
{
pragma_t Pragma;
+ StrBuf Ident = AUTO_STRBUF_INITIALIZER;
- /* Skip the token itself */
+ /* Create a string buffer from the string literal */
+ StrBuf B = AUTO_STRBUF_INITIALIZER;
+ SB_Append (&B, GetLiteralStrBuf (CurTok.SVal));
+
+ /* Skip the string token */
NextToken ();
- /* Identifier must follow */
- if (curtok != TOK_IDENT) {
- Error (ERR_IDENT_EXPECTED);
- return;
+ /* Get the pragma name from the string */
+ SB_SkipWhite (&B);
+ if (!SB_GetSym (&B, &Ident, "-")) {
+ Error ("Invalid pragma");
+ goto ExitPoint;
}
+ /* Search for the name */
+ Pragma = FindPragma (&Ident);
+
/* Do we know this pragma? */
- Pragma = FindPragma (CurTok.Ident);
- if (Pragma == PR_ILLEGAL) {
- /* According to the ANSI standard, we're not allowed to generate errors
- * for unknown pragmas, however, we're allowed to warn - and we will
- * do so. Otherwise one typo may give you hours of bug hunting...
- */
- Warning (WARN_UNKNOWN_PRAGMA);
- return;
+ if (Pragma == PRAGMA_ILLEGAL) {
+ /* According to the ANSI standard, we're not allowed to generate errors
+ * for unknown pragmas, but warn about them if enabled (the default).
+ */
+ if (IS_Get (&WarnUnknownPragma)) {
+ Warning ("Unknown pragma `%s'", SB_GetConstBuf (&Ident));
+ }
+ goto ExitPoint;
}
- /* Skip the identifier and check for an open paren */
- NextToken ();
- ConsumeLParen ();
+ /* Check for an open paren */
+ SB_SkipWhite (&B);
+ if (SB_Get (&B) != '(') {
+ Error ("'(' expected");
+ goto ExitPoint;
+ }
+
+ /* Skip white space before the argument */
+ SB_SkipWhite (&B);
/* Switch for the different pragmas */
switch (Pragma) {
- case PR_BSSSEG:
- StringPragma (g_bssname);
- break;
+ case PRAGMA_ALIGN:
+ IntPragma (&B, &DataAlignment, 1, 4096);
+ break;
+
+ case PRAGMA_BSSSEG:
+ Warning ("#pragma bssseg is obsolete, please use #pragma bss-name instead");
+ /* FALLTHROUGH */
+ case PRAGMA_BSS_NAME:
+ SegNamePragma (&B, SEG_BSS);
+ break;
+
+ case PRAGMA_CHARMAP:
+ CharMapPragma (&B);
+ break;
+
+ case PRAGMA_CHECKSTACK:
+ Warning ("#pragma checkstack is obsolete, please use #pragma check-stack instead");
+ /* FALLTHROUGH */
+ case PRAGMA_CHECK_STACK:
+ FlagPragma (&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);
+ break;
+
+ case PRAGMA_CODESIZE:
+ IntPragma (&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);
+ break;
+
+ case PRAGMA_LOCAL_STRINGS:
+ FlagPragma (&B, &LocalStrings);
+ break;
+
+ case PRAGMA_OPTIMIZE:
+ FlagPragma (&B, &Optimize);
+ break;
+
+ case PRAGMA_REGVARADDR:
+ FlagPragma (&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);
+ break;
+
+ case PRAGMA_RODATASEG:
+ Warning ("#pragma rodataseg is obsolete, please use #pragma rodata-name instead");
+ /* FALLTHROUGH */
+ case PRAGMA_RODATA_NAME:
+ SegNamePragma (&B, SEG_RODATA);
+ break;
+
+ case PRAGMA_SIGNEDCHARS:
+ Warning ("#pragma signedchars is obsolete, please use #pragma signed-chars instead");
+ /* FALLTHROUGH */
+ case PRAGMA_SIGNED_CHARS:
+ FlagPragma (&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);
+ break;
+
+ case PRAGMA_WARN:
+ WarnPragma (&B);
+ break;
+
+ case PRAGMA_WRITABLE_STRINGS:
+ FlagPragma (&B, &WritableStrings);
+ break;
+
+ case PRAGMA_ZPSYM:
+ StringPragma (&B, MakeZPSym);
+ break;
+
+ default:
+ Internal ("Invalid pragma");
+ }
- case PR_CODESEG:
- StringPragma (g_codename);
- break;
+ /* Closing paren expected */
+ SB_SkipWhite (&B);
+ if (SB_Get (&B) != ')') {
+ Error ("')' expected");
+ goto ExitPoint;
+ }
+ SB_SkipWhite (&B);
- case PR_DATASEG:
- StringPragma (g_dataname);
- break;
+ /* Allow an optional semicolon to be compatible with the old syntax */
+ if (SB_Peek (&B) == ';') {
+ SB_Skip (&B);
+ SB_SkipWhite (&B);
+ }
- case PR_REGVARADDR:
- FlagPragma (&AllowRegVarAddr);
- break;
+ /* Make sure nothing follows */
+ if (SB_Peek (&B) != '\0') {
+ Error ("Unexpected input following pragma directive");
+ }
- case PR_RODATASEG:
- StringPragma (g_rodataname);
- break;
+ExitPoint:
+ /* Release the string buffers */
+ SB_Done (&B);
+ SB_Done (&Ident);
+}
- case PR_SIGNEDCHARS:
- FlagPragma (&SignedChars);
- break;
- case PR_STATICLOCALS:
- FlagPragma (&StaticLocals);
- break;
- case PR_ZPSYM:
- StringPragma (MakeZPSym);
- break;
+void DoPragma (void)
+/* Handle pragmas. These come always in form of the new C99 _Pragma() operator. */
+{
+ /* Skip the token itself */
+ NextToken ();
- default:
- Internal ("Invalid pragma");
+ /* We expect an opening paren */
+ if (!ConsumeLParen ()) {
+ return;
}
- /* Closing paren needed */
- ConsumeRParen ();
-}
+ /* String literal */
+ if (CurTok.Tok != TOK_SCONST) {
+ /* Print a diagnostic */
+ Error ("String literal expected");
+ /* Try some smart error recovery: Skip tokens until we reach the
+ * enclosing paren, or a semicolon.
+ */
+ PragmaErrorSkip ();
+ } else {
+
+ /* Parse the _Pragma statement */
+ ParsePragma ();
+ }
+
+ /* Closing paren needed */
+ ConsumeRParen ();
+}