]> git.sur5r.net Git - cc65/blobdiff - src/cc65/pragma.c
remove TABs
[cc65] / src / cc65 / pragma.c
index 57ad94c2a53340cca44f9db6159809315f426eef..b05ef6122bb4fce4efc24bd4f649999e395f16cc 100644 (file)
@@ -1,15 +1,15 @@
 /*****************************************************************************/
 /*                                                                           */
-/*                                pragma.c                                  */
+/*                                 pragma.c                                  */
 /*                                                                           */
-/*                 Pragma handling for the cc65 C compiler                  */
+/*                  Pragma handling for the cc65 C compiler                  */
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2004 Ullrich von Bassewitz                                       */
-/*               Römerstraße 52                                              */
-/*               D-70794 Filderstadt                                         */
-/* EMail:        uz@cc65.org                                                 */
+/* (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       */
@@ -37,6 +37,7 @@
 #include <string.h>
 
 /* common */
+#include "chartype.h"
 #include "segnames.h"
 #include "tgttrans.h"
 
 #include "scanstrbuf.h"
 #include "symtab.h"
 #include "pragma.h"
+#include "wrappedcall.h"
 
 
 
 /*****************************************************************************/
-/*                                  data                                    */
+/*                                   data                                    */
 /*****************************************************************************/
 
 
 
 /* Tokens for the #pragmas */
 typedef enum {
-    PR_ILLEGAL = -1,
-    PR_BSSSEG,
-    PR_CHARMAP,
-    PR_CHECKSTACK,
-    PR_CODESEG,
-    PR_CODESIZE,
-    PR_DATASEG,
-    PR_OPTIMIZE,
-    PR_REGVARADDR,
-    PR_REGVARS,
-    PR_RODATASEG,
-    PR_SIGNEDCHARS,
-    PR_STATICLOCALS,
-    PR_WARN,
-    PR_ZPSYM,
-    PR_COUNT
+    PRAGMA_ILLEGAL = -1,
+    PRAGMA_ALIGN,
+    PRAGMA_ALLOW_EAGER_INLINE,
+    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_INLINE_STDFUNCS,
+    PRAGMA_LOCAL_STRINGS,
+    PRAGMA_MESSAGE,
+    PRAGMA_OPTIMIZE,
+    PRAGMA_REGISTER_VARS,
+    PRAGMA_REGVARADDR,
+    PRAGMA_REGVARS,                                     /* obsolete */
+    PRAGMA_RODATA_NAME,
+    PRAGMA_RODATASEG,                                   /* obsolete */
+    PRAGMA_SIGNED_CHARS,
+    PRAGMA_SIGNEDCHARS,                                 /* obsolete */
+    PRAGMA_STATIC_LOCALS,
+    PRAGMA_STATICLOCALS,                                /* obsolete */
+    PRAGMA_WARN,
+    PRAGMA_WRAPPED_CALL,
+    PRAGMA_WRITABLE_STRINGS,
+    PRAGMA_ZPSYM,
+    PRAGMA_COUNT
 } pragma_t;
 
 /* Pragma table */
 static const struct Pragma {
-    const char*        Key;            /* Keyword */
-    pragma_t           Tok;            /* Token */
-} Pragmas[PR_COUNT] = {
-    {  "bssseg",       PR_BSSSEG       },
-    {   "charmap",      PR_CHARMAP      },
-    {  "checkstack",   PR_CHECKSTACK   },
-    {   "codeseg",     PR_CODESEG      },
-    {   "codesize",     PR_CODESIZE     },
-    {   "dataseg",     PR_DATASEG      },
-    {   "optimize",     PR_OPTIMIZE     },
-    {   "regvaraddr",  PR_REGVARADDR   },
-    {   "regvars",      PR_REGVARS      },
-    {   "rodataseg",   PR_RODATASEG    },
-    {  "signedchars",  PR_SIGNEDCHARS  },
-    {  "staticlocals", PR_STATICLOCALS },
-    {   "warn",         PR_WARN         },
-    {   "zpsym",               PR_ZPSYM        },
+    const char* Key;            /* Keyword */
+    pragma_t    Tok;            /* Token */
+} Pragmas[PRAGMA_COUNT] = {
+    { "align",                  PRAGMA_ALIGN              },
+    { "allow-eager-inline",     PRAGMA_ALLOW_EAGER_INLINE },
+    { "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 */
+    { "inline-stdfuncs",        PRAGMA_INLINE_STDFUNCS    },
+    { "local-strings",          PRAGMA_LOCAL_STRINGS      },
+    { "message",                PRAGMA_MESSAGE            },
+    { "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               },
+    { "wrapped-call",           PRAGMA_WRAPPED_CALL       },
+    { "writable-strings",       PRAGMA_WRITABLE_STRINGS   },
+    { "zpsym",                  PRAGMA_ZPSYM              },
 };
 
+/* 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.
- */
+** semicolon is reached.
+*/
 {
     static const token_t TokenList[] = { TOK_RPAREN, TOK_SEMI };
     SkipTokens (TokenList, sizeof(TokenList) / sizeof(TokenList[0]));
@@ -127,33 +167,220 @@ static int CmpKey (const void* Key, const void* Elem)
 
 
 
-static pragma_t FindPragma (const char* Key)
-/* Find a pragma and return the token. Return PR_ILLEGAL if the keyword is
- * not a valid pragma.
- */
+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, PR_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 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 */
 {
-    StrBuf S;
+    StrBuf S = AUTO_STRBUF_INITIALIZER;
 
     /* We expect a string here */
-    if (SB_GetString (B, &S)) {
-               /* Call the given function with the string argument */
-       Func (SB_GetConstBuf (&S));
-    } else {
-       Error ("String literal expected");
+    if (GetString (B, &S)) {
+        /* Call the given function with the string argument */
+        Func (SB_GetConstBuf (&S));
     }
 
     /* Call the string buf destructor */
-    DoneStrBuf (&S);
+    SB_Done (&S);
 }
 
 
@@ -161,69 +388,157 @@ static void StringPragma (StrBuf* B, void (*Func) (const char*))
 static void SegNamePragma (StrBuf* B, segment_t Seg)
 /* Handle a pragma that expects a segment name parameter */
 {
-    ident       Ident;
-    StrBuf      S;
     const char* Name;
-
-    /* Try to read an identifier */
+    StrBuf S = AUTO_STRBUF_INITIALIZER;
     int Push = 0;
-    if (SB_GetSym (B, Ident)) {
 
-        /* Check if we have a first argument named "pop" */
-        if (strcmp (Ident, "pop") == 0) {
+    /* Check for the "push" or "pop" keywords */
+    switch (ParsePushPop (B)) {
 
-            /* Pop the old value */
+        case PP_NONE:
+            break;
+
+        case PP_PUSH:
+            Push = 1;
+            break;
+
+        case PP_POP:
+            /* Pop the old value and output it */
             PopSegName (Seg);
 
-            /* Set the segment name */
-            g_segname (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);
+            }
 
             /* Done */
-            return;
+            goto ExitPoint;
 
-        /* Check if we have a first argument named "push" */
-        } else if (strcmp (Ident, "push") == 0) {
+        case PP_ERROR:
+            /* Bail out */
+            goto ExitPoint;
 
-            Push = 1;
-            SB_SkipWhite (B);
-            if (SB_Get (B) != ',') {
-                Error ("Comma expected");
-                return;
-            }
-            SB_SkipWhite (B);
+        default:
+            Internal ("Invalid result from ParsePushPop");
 
-        } else {
-            Error ("Invalid pragma arguments");
-            return;
-        }
     }
 
     /* A string argument must follow */
-    if (!SB_GetString (B, &S)) {
-       Error ("String literal expected");
-        return;
+    if (!GetString (B, &S)) {
+        goto ExitPoint;
     }
 
     /* Get the string */
     Name = SB_GetConstBuf (&S);
 
     /* Check if the name is valid */
-    if (!ValidSegName (Name)) {
+    if (ValidSegName (Name)) {
+
+        /* Set the new name */
+        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);
+        }
+
+    } else {
+
         /* Segment name is invalid */
-        Error ("Illegal segment name: `%s'", Name);
-        return;
+        Error ("Illegal segment name: '%s'", Name);
+
     }
 
-    /* Set the new name */
-    if (Push) {
-        PushSegName (Seg, Name);
+ExitPoint:
+    /* Call the string buf destructor */
+    SB_Done (&S);
+}
+
+
+static void WrappedCallPragma (StrBuf* B)
+/* Handle the wrapped-call pragma */
+{
+    StrBuf      S = AUTO_STRBUF_INITIALIZER;
+    const char *Name;
+    long Val;
+    SymEntry *Entry;
+
+    /* Check for the "push" or "pop" keywords */
+    switch (ParsePushPop (B)) {
+
+        case PP_NONE:
+            Error ("Push or pop required");
+            break;
+
+        case PP_PUSH:
+            break;
+
+        case PP_POP:
+            PopWrappedCall();
+
+            /* Done */
+            goto ExitPoint;
+
+        case PP_ERROR:
+            /* Bail out */
+            goto ExitPoint;
+
+        default:
+            Internal ("Invalid result from ParsePushPop");
+
+    }
+
+    /* A symbol argument must follow */
+    if (!SB_GetSym (B, &S, NULL)) {
+        goto ExitPoint;
+    }
+
+    /* Skip the following comma */
+    if (!GetComma (B)) {
+        /* Error already flagged by GetComma */
+        Error ("Value required for wrapped-call identifier");
+        goto ExitPoint;
+    }
+
+    if (!GetNumber (B, &Val)) {
+        Error ("Value required for wrapped-call identifier");
+        goto ExitPoint;
+    }
+
+    if (Val < 0 || Val > 255) {
+        Error ("Identifier must be between 0-255");
+        goto ExitPoint;
+    }
+
+    /* Get the string */
+    Name = SB_GetConstBuf (&S);
+    Entry = FindSym(Name);
+
+    /* Check if the name is valid */
+    if (Entry && Entry->Flags & SC_FUNC) {
+
+        PushWrappedCall(Entry, (unsigned char) Val);
+        Entry->Flags |= SC_REF;
+        Entry->V.F.Func->Flags |= FD_CALL_WRAPPER;
+
     } else {
-        SetSegName (Seg, Name);
+
+        /* Segment name is invalid */
+        Error ("Wrapped-call target does not exist or is not a function");
+
     }
-    g_segname (Seg);
 
+ExitPoint:
     /* Call the string buf destructor */
-    DoneStrBuf (&S);
+    SB_Done (&S);
 }
 
 
@@ -234,29 +549,38 @@ static void CharMapPragma (StrBuf* B)
     long Index, C;
 
     /* Read the character index */
-    if (!SB_GetNumber (B, &Index)) {
+    if (!GetNumber (B, &Index)) {
         return;
     }
-    if (Index < 1 || Index > 255) {
-       Error ("Character index out of range");
-       return;
+    if (Index < 0 || Index > 255) {
+        Error ("Character index out of range");
+        return;
     }
 
     /* Comma follows */
-    SB_SkipWhite (B);
-    if (SB_Get (B) != ',') {
-        Error ("Comma expected");
+    if (!GetComma (B)) {
         return;
     }
-    SB_SkipWhite (B);
 
     /* Read the character code */
-    if (!SB_GetNumber (B, &C)) {
+    if (!GetNumber (B, &C)) {
         return;
     }
-    if (C < 1 || C > 255) {
-       Error ("Character code out of range");
-       return;
+    if (C < 0 || C > 255) {
+        Error ("Character code out of range");
+        return;
+    }
+
+    /* Warn about remapping character code 0x00
+    ** (except when remapping it back to itself).
+    */
+    if (Index + C != 0 && IS_Get (&WarnRemapZero)) {
+        if (Index == 0) {
+            Warning ("Remapping from 0 is dangerous with string functions");
+        }
+        else if (C == 0) {
+            Warning ("Remapping to 0 can make string functions stop unexpectedly");
+        }
     }
 
     /* Remap the character */
@@ -265,65 +589,113 @@ static void CharMapPragma (StrBuf* B)
 
 
 
+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 */
 {
-    ident Ident;
-    long  Val;
-    int   Push;
+    StrBuf Ident = AUTO_STRBUF_INITIALIZER;
+    long   Val;
+    int    Push;
+
 
     /* Try to read an identifier */
-    int IsIdent = SB_GetSym (B, Ident);
+    int IsIdent = SB_GetSym (B, &Ident, 0);
 
     /* Check if we have a first argument named "pop" */
-    if (IsIdent && strcmp (Ident, "pop") == 0) {
-        if (IS_GetCount (Stack) < 2) {
-            Error ("Cannot pop, stack is empty");
-        } else {
-            IS_Drop (Stack);
-        }
+    if (IsIdent && SB_CompareStr (&Ident, "pop") == 0) {
+        PopInt (Stack);
         /* No other arguments allowed */
         return;
     }
 
     /* Check if we have a first argument named "push" */
-    if (IsIdent && strcmp (Ident, "push") == 0) {
+    if (IsIdent && SB_CompareStr (&Ident, "push") == 0) {
         Push = 1;
-        SB_SkipWhite (B);
-        if (SB_Get (B) != ',') {
-            Error ("Comma expected");
-            return;
+        if (!GetComma (B)) {
+            goto ExitPoint;
         }
-        SB_SkipWhite (B);
-        IsIdent = SB_GetSym (B, Ident);
+        IsIdent = SB_GetSym (B, &Ident, 0);
     } else {
         Push = 0;
     }
 
     /* Boolean argument follows */
     if (IsIdent) {
-        if (strcmp (Ident, "true") == 0 || strcmp (Ident, "on") == 0) {
-            Val = 1;
-        } else if (strcmp (Ident, "false") == 0 || strcmp (Ident, "off") == 0) {
-            Val = 0;
-        } else {
-            Error ("Pragma argument must be one of `on', `off', `true' or `false'");
-        }
-    } else if (!SB_GetNumber (B, &Val)) {
-        Error ("Invalid pragma argument");
-        return;
+        Val = BoolKeyword (&Ident);
+    } else if (!GetNumber (B, &Val)) {
+        goto ExitPoint;
     }
 
     /* Set/push the new value */
     if (Push) {
-        if (IS_IsFull (Stack)) {
-            Error ("Cannot push: stack overflow");
-        } else {
-            IS_Push (Stack, Val);
-        }
+        PushInt (Stack, Val);
     } else {
         IS_Set (Stack, Val);
     }
+
+ExitPoint:
+    /* Free the identifier */
+    SB_Done (&Ident);
 }
 
 
@@ -331,41 +703,36 @@ static void FlagPragma (StrBuf* B, IntStack* Stack)
 static void IntPragma (StrBuf* B, IntStack* Stack, long Low, long High)
 /* Handle a pragma that expects an int paramater */
 {
-    ident Ident;
     long  Val;
     int   Push;
 
-    /* Try to read an identifier */
-    int IsIdent = SB_GetSym (B, Ident);
+    /* Check for the "push" or "pop" keywords */
+    switch (ParsePushPop (B)) {
 
-    /* Check if we have a first argument named "pop" */
-    if (IsIdent && strcmp (Ident, "pop") == 0) {
-        if (IS_GetCount (Stack) < 2) {
-            Error ("Cannot pop, stack is empty");
-        } else {
-            IS_Drop (Stack);
-        }
-        /* No other arguments allowed */
-        return;
-    }
+        case PP_NONE:
+            Push = 0;
+            break;
 
-    /* Check if we have a first argument named "push" */
-    if (IsIdent && strcmp (Ident, "push") == 0) {
-        Push = 1;
-        SB_SkipWhite (B);
-        if (SB_Get (B) != ',') {
-            Error ("Comma expected");
+        case PP_PUSH:
+            Push = 1;
+            break;
+
+        case PP_POP:
+            /* Pop the old value and bail out */
+            PopInt (Stack);
             return;
-        }
-        SB_SkipWhite (B);
-        IsIdent = 0;
-    } else {
-        Push = 0;
+
+        case PP_ERROR:
+            /* Bail out */
+            return;
+
+        default:
+            Internal ("Invalid result from ParsePushPop");
+
     }
 
     /* Integer argument follows */
-    if (IsIdent || !SB_GetNumber (B, &Val)) {
-        Error ("Pragma argument must be numeric");
+    if (!GetNumber (B, &Val)) {
         return;
     }
 
@@ -377,11 +744,7 @@ static void IntPragma (StrBuf* B, IntStack* Stack, long Low, long High)
 
     /* Set/push the new value */
     if (Push) {
-        if (IS_IsFull (Stack)) {
-            Error ("Cannot push: stack overflow");
-        } else {
-            IS_Push (Stack, Val);
-        }
+        PushInt (Stack, Val);
     } else {
         IS_Set (Stack, Val);
     }
@@ -389,51 +752,52 @@ static void IntPragma (StrBuf* B, IntStack* Stack, long Low, long High)
 
 
 
+static void MakeMessage (const char* Message)
+{
+    fprintf (stderr, "%s(%u): Note: %s\n", GetInputName (CurTok.LI), GetInputLine (CurTok.LI), Message);
+}
+
+
+
 static void ParsePragma (void)
 /* Parse the contents of the _Pragma statement */
 {
     pragma_t Pragma;
-    ident    Ident;
+    StrBuf   Ident = AUTO_STRBUF_INITIALIZER;
 
     /* Create a string buffer from the string literal */
     StrBuf B = AUTO_STRBUF_INITIALIZER;
-    GetLiteralStrBuf (&B, CurTok.IVal);
-
-    /* Reset the string pointer, effectivly clearing the string from the
-     * string table. Since we're working with one token lookahead, this
-     * will fail if the next token is also a string token, but that's a
-     * syntax error anyway, because we expect a right paren.
-     */
-    ResetLiteralPoolOffs (CurTok.IVal);
+    SB_Append (&B, GetLiteralStrBuf (CurTok.SVal));
 
     /* Skip the string token */
     NextToken ();
 
     /* Get the pragma name from the string */
     SB_SkipWhite (&B);
-    if (!SB_GetSym (&B, Ident)) {
+    if (!SB_GetSym (&B, &Ident, "-")) {
         Error ("Invalid pragma");
-        return;
+        goto ExitPoint;
     }
 
     /* Search for the name */
-    Pragma = FindPragma (Ident);
+    Pragma = FindPragma (&Ident);
 
     /* Do we know this pragma? */
-    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 ("Unknown pragma `%s'", Ident);
-               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;
     }
 
     /* Check for an open paren */
     SB_SkipWhite (&B);
     if (SB_Get (&B) != '(') {
         Error ("'(' expected");
-        return;
+        goto ExitPoint;
     }
 
     /* Skip white space before the argument */
@@ -442,71 +806,123 @@ static void ParsePragma (void)
     /* Switch for the different pragmas */
     switch (Pragma) {
 
-       case PR_BSSSEG:
-           SegNamePragma (&B, SEG_BSS);
-           break;
+        case PRAGMA_ALIGN:
+            IntPragma (&B, &DataAlignment, 1, 4096);
+            break;
+
+        case PRAGMA_ALLOW_EAGER_INLINE:
+            FlagPragma (&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);
+            break;
+
+        case PRAGMA_CHARMAP:
+            CharMapPragma (&B);
+            break;
 
-       case PR_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 PR_CHECKSTACK:
-           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 PR_CODESEG:
-           SegNamePragma (&B, SEG_CODE);
-           break;
+        case PRAGMA_CODESIZE:
+            IntPragma (&B, &CodeSizeFactor, 10, 1000);
+            break;
 
-       case PR_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_INLINE_STDFUNCS:
+            FlagPragma (&B, &InlineStdFuncs);
+            break;
 
-       case PR_DATASEG:
-           SegNamePragma (&B, SEG_DATA);
-           break;
+        case PRAGMA_LOCAL_STRINGS:
+            FlagPragma (&B, &LocalStrings);
+            break;
 
-        case PR_OPTIMIZE:
+        case PRAGMA_MESSAGE:
+            StringPragma (&B, MakeMessage);
+            break;
+
+        case PRAGMA_OPTIMIZE:
             FlagPragma (&B, &Optimize);
             break;
 
-       case PR_REGVARADDR:
-                   FlagPragma (&B, &AllowRegVarAddr);
-           break;
+        case PRAGMA_REGVARADDR:
+            FlagPragma (&B, &AllowRegVarAddr);
+            break;
 
-       case PR_REGVARS:
-                   FlagPragma (&B, &EnableRegVars);
-           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 PR_RODATASEG:
-           SegNamePragma (&B, SEG_RODATA);
-           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 PR_SIGNEDCHARS:
-                   FlagPragma (&B, &SignedChars);
-           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 PR_STATICLOCALS:
-           FlagPragma (&B, &StaticLocals);
-           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 PR_WARN:
-            FlagPragma (&B, &WarnDisable);
+        case PRAGMA_WRAPPED_CALL:
+            WrappedCallPragma(&B);
             break;
 
-       case PR_ZPSYM:                    
-           StringPragma (&B, MakeZPSym);
-           break;
+        case PRAGMA_WARN:
+            WarnPragma (&B);
+            break;
 
-       default:
-                   Internal ("Invalid pragma");
+        case PRAGMA_WRITABLE_STRINGS:
+            FlagPragma (&B, &WritableStrings);
+            break;
+
+        case PRAGMA_ZPSYM:
+            StringPragma (&B, MakeZPSym);
+            break;
+
+        default:
+            Internal ("Invalid pragma");
     }
 
     /* Closing paren expected */
     SB_SkipWhite (&B);
     if (SB_Get (&B) != ')') {
         Error ("')' expected");
-        return;
+        goto ExitPoint;
     }
     SB_SkipWhite (&B);
 
@@ -521,8 +937,10 @@ static void ParsePragma (void)
         Error ("Unexpected input following pragma directive");
     }
 
-    /* Release the StrBuf */
-    DoneStrBuf (&B);
+ExitPoint:
+    /* Release the string buffers */
+    SB_Done (&B);
+    SB_Done (&Ident);
 }
 
 
@@ -535,29 +953,26 @@ void DoPragma (void)
 
     /* We expect an opening paren */
     if (!ConsumeLParen ()) {
-       return;
+        return;
     }
 
     /* String literal */
     if (CurTok.Tok != TOK_SCONST) {
 
-       /* Print a diagnostic */
-       Error ("String literal expected");
+        /* Print a diagnostic */
+        Error ("String literal expected");
 
-       /* Try some smart error recovery: Skip tokens until we reach the
-        * enclosing paren, or a semicolon.
-        */
-               PragmaErrorSkip ();
+        /* Try some smart error recovery: Skip tokens until we reach the
+        ** enclosing paren, or a semicolon.
+        */
+        PragmaErrorSkip ();
 
     } else {
 
-       /* Parse the _Pragma statement */
-       ParsePragma ();
+        /* Parse the _Pragma statement */
+        ParsePragma ();
     }
 
     /* Closing paren needed */
     ConsumeRParen ();
 }
-
-
-