]> git.sur5r.net Git - cc65/blobdiff - src/cc65/pragma.c
More tabs to spaces
[cc65] / src / cc65 / pragma.c
index 4b690d7a9e3a688d337422f2db2599954c381676..fe7101d97c2e2e2cc2908d0d28b418f44c154cf3 100644 (file)
@@ -1,12 +1,12 @@
 /*****************************************************************************/
 /*                                                                           */
-/*                                pragma.c                                  */
+/*                                 pragma.c                                  */
 /*                                                                           */
-/*                 Pragma handling for the cc65 C compiler                  */
+/*                  Pragma handling for the cc65 C compiler                  */
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2010, Ullrich von Bassewitz                                      */
+/* (C) 1998-2011, Ullrich von Bassewitz                                      */
 /*                Roemerstrasse 52                                           */
 /*                D-70794 Filderstadt                                        */
 /* EMail:         uz@cc65.org                                                */
 #include "scanstrbuf.h"
 #include "symtab.h"
 #include "pragma.h"
+#include "trampoline.h"
 
 
 
 /*****************************************************************************/
-/*                                  data                                    */
+/*                                   data                                    */
 /*****************************************************************************/
 
 
@@ -63,6 +64,8 @@
 /* Tokens for the #pragmas */
 typedef enum {
     PRAGMA_ILLEGAL = -1,
+    PRAGMA_ALIGN,
+    PRAGMA_ALLOW_EAGER_INLINE,
     PRAGMA_BSS_NAME,
     PRAGMA_BSSSEG,                                      /* obsolete */
     PRAGMA_CHARMAP,
@@ -73,6 +76,7 @@ typedef enum {
     PRAGMA_CODESIZE,
     PRAGMA_DATA_NAME,
     PRAGMA_DATASEG,                                     /* obsolete */
+    PRAGMA_INLINE_STDFUNCS,
     PRAGMA_LOCAL_STRINGS,
     PRAGMA_OPTIMIZE,
     PRAGMA_REGVARADDR,
@@ -85,6 +89,7 @@ typedef enum {
     PRAGMA_STATIC_LOCALS,
     PRAGMA_STATICLOCALS,                                /* obsolete */
     PRAGMA_WARN,
+    PRAGMA_WRAPPED_CALL,
     PRAGMA_WRITABLE_STRINGS,
     PRAGMA_ZPSYM,
     PRAGMA_COUNT
@@ -92,33 +97,37 @@ typedef enum {
 
 /* Pragma table */
 static const struct Pragma {
-    const char*        Key;            /* Keyword */
-    pragma_t           Tok;            /* Token */
+    const char* Key;            /* Keyword */
+    pragma_t    Tok;            /* Token */
 } Pragmas[PRAGMA_COUNT] = {
-    { "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           },
+    { "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      },
+    { "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 */
@@ -139,8 +148,8 @@ typedef enum {
 
 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]));
@@ -158,8 +167,8 @@ static int CmpKey (const void* Key, const void* Elem)
 
 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.
- */
+** not a valid pragma.
+*/
 {
     struct Pragma* P;
     P = bsearch (SB_GetConstBuf (Key), Pragmas, PRAGMA_COUNT, sizeof (Pragmas[0]), CmpKey);
@@ -170,8 +179,8 @@ static pragma_t FindPragma (const StrBuf* Key)
 
 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.
- */
+** comma is found. Return a value <> 0 otherwise.
+*/
 {
     SB_SkipWhite (B);
     if (SB_Get (B) != ',') {
@@ -186,11 +195,11 @@ static int GetComma (StrBuf* B)
 
 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.
- */
+** string is found. Returns a value <> 0 otherwise.
+*/
 {
     if (!SB_GetString (B, S)) {
-       Error ("String literal expected");
+        Error ("String literal expected");
         return 0;
     }
     return 1;
@@ -200,11 +209,11 @@ static int GetString (StrBuf* B, StrBuf* S)
 
 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.
- */
+** number is found. Returns a value <> 0 otherwise.
+*/
 {
     if (!SB_GetNumber (B, Val)) {
-       Error ("Constant integer expected");
+        Error ("Constant integer expected");
         return 0;
     }
     return 1;
@@ -214,9 +223,9 @@ static int GetNumber (StrBuf* B, long* Val)
 
 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.
- */
+** 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;
@@ -260,8 +269,8 @@ static int HasStr (StrBuf* B, const char* E)
 
 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.
- */
+** following comma is expected and skipped.
+*/
 {
     StrBuf Ident      = AUTO_STRBUF_INITIALIZER;
     PushPopResult Res = PP_NONE;
@@ -328,8 +337,8 @@ static void PushInt (IntStack* S, long 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.
- */
+** accepted are true/false/on/off.
+*/
 {
     if (SB_CompareStr (Ident, "true") == 0) {
         return 1;
@@ -364,8 +373,8 @@ static void StringPragma (StrBuf* B, void (*Func) (const char*))
 
     /* We expect a string here */
     if (GetString (B, &S)) {
-               /* Call the given function with the string argument */
-       Func (SB_GetConstBuf (&S));
+        /* Call the given function with the string argument */
+        Func (SB_GetConstBuf (&S));
     }
 
     /* Call the string buf destructor */
@@ -440,6 +449,84 @@ ExitPoint:
 }
 
 
+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:
+            PopTrampoline();
+
+            /* 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 | SC_STORAGE)) {
+
+        PushTrampoline(Entry, Val);
+        Entry->Flags |= SC_REF;
+
+    } else {
+
+        /* Segment name is invalid */
+        Error ("Wrapped-call target does not exist or is not a function or array");
+
+    }
+
+ExitPoint:
+    /* Call the string buf destructor */
+    SB_Done (&S);
+}
+
+
 
 static void CharMapPragma (StrBuf* B)
 /* Change the character map */
@@ -450,14 +537,9 @@ static void CharMapPragma (StrBuf* B)
     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;
+    if (Index < 0 || Index > 255) {
+        Error ("Character index out of range");
+        return;
     }
 
     /* Comma follows */
@@ -469,14 +551,21 @@ static void CharMapPragma (StrBuf* B)
     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");
+    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");
         }
-       return;
     }
 
     /* Remap the character */
@@ -673,13 +762,13 @@ static void ParsePragma (void)
 
     /* Do we know this pragma? */
     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).
-                */
+        /* 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));
+            Warning ("Unknown pragma `%s'", SB_GetConstBuf (&Ident));
         }
-               goto ExitPoint;
+        goto ExitPoint;
     }
 
     /* Check for an open paren */
@@ -695,41 +784,53 @@ static void ParsePragma (void)
     /* Switch for the different pragmas */
     switch (Pragma) {
 
-       case PRAGMA_BSSSEG:
+        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;
+            SegNamePragma (&B, SEG_BSS);
+            break;
 
-       case PRAGMA_CHARMAP:
-           CharMapPragma (&B);
-           break;
+        case PRAGMA_CHARMAP:
+            CharMapPragma (&B);
+            break;
 
-       case PRAGMA_CHECKSTACK:
+        case PRAGMA_CHECKSTACK:
             Warning ("#pragma checkstack is obsolete, please use #pragma check-stack instead");
             /* FALLTHROUGH */
         case PRAGMA_CHECK_STACK:
-           FlagPragma (&B, &CheckStack);
-           break;
+            FlagPragma (&B, &CheckStack);
+            break;
 
-       case PRAGMA_CODESEG:
+        case PRAGMA_CODESEG:
             Warning ("#pragma codeseg is obsolete, please use #pragma code-name instead");
             /* FALLTHROUGH */
         case PRAGMA_CODE_NAME:
-           SegNamePragma (&B, SEG_CODE);
-           break;
+            SegNamePragma (&B, SEG_CODE);
+            break;
 
-       case PRAGMA_CODESIZE:
-           IntPragma (&B, &CodeSizeFactor, 10, 1000);
-           break;
+        case PRAGMA_CODESIZE:
+            IntPragma (&B, &CodeSizeFactor, 10, 1000);
+            break;
 
-       case PRAGMA_DATASEG:
+        case PRAGMA_DATASEG:
             Warning ("#pragma dataseg is obsolete, please use #pragma data-name instead");
             /* FALLTHROUGH */
         case PRAGMA_DATA_NAME:
-           SegNamePragma (&B, SEG_DATA);
-           break;
+            SegNamePragma (&B, SEG_DATA);
+            break;
+
+        case PRAGMA_INLINE_STDFUNCS:
+            FlagPragma (&B, &InlineStdFuncs);
+            break;
 
         case PRAGMA_LOCAL_STRINGS:
             FlagPragma (&B, &LocalStrings);
@@ -739,37 +840,41 @@ static void ParsePragma (void)
             FlagPragma (&B, &Optimize);
             break;
 
-       case PRAGMA_REGVARADDR:
-                   FlagPragma (&B, &AllowRegVarAddr);
-           break;
+        case PRAGMA_REGVARADDR:
+            FlagPragma (&B, &AllowRegVarAddr);
+            break;
 
-       case PRAGMA_REGVARS:
+        case PRAGMA_REGVARS:
             Warning ("#pragma regvars is obsolete, please use #pragma register-vars instead");
             /* FALLTHROUGH */
         case PRAGMA_REGISTER_VARS:
-                   FlagPragma (&B, &EnableRegVars);
-           break;
+            FlagPragma (&B, &EnableRegVars);
+            break;
 
-       case PRAGMA_RODATASEG:
+        case PRAGMA_RODATASEG:
             Warning ("#pragma rodataseg is obsolete, please use #pragma rodata-name instead");
             /* FALLTHROUGH */
         case PRAGMA_RODATA_NAME:
-           SegNamePragma (&B, SEG_RODATA);
-           break;
+            SegNamePragma (&B, SEG_RODATA);
+            break;
 
-       case PRAGMA_SIGNEDCHARS:
+        case PRAGMA_SIGNEDCHARS:
             Warning ("#pragma signedchars is obsolete, please use #pragma signed-chars instead");
             /* FALLTHROUGH */
         case PRAGMA_SIGNED_CHARS:
-                   FlagPragma (&B, &SignedChars);
-           break;
+            FlagPragma (&B, &SignedChars);
+            break;
 
-       case PRAGMA_STATICLOCALS:
+        case PRAGMA_STATICLOCALS:
             Warning ("#pragma staticlocals is obsolete, please use #pragma static-locals instead");
             /* FALLTHROUGH */
         case PRAGMA_STATIC_LOCALS:
-           FlagPragma (&B, &StaticLocals);
-           break;
+            FlagPragma (&B, &StaticLocals);
+            break;
+
+       case PRAGMA_WRAPPED_CALL:
+           WrappedCallPragma(&B);
+           break;
 
         case PRAGMA_WARN:
             WarnPragma (&B);
@@ -779,12 +884,12 @@ static void ParsePragma (void)
             FlagPragma (&B, &WritableStrings);
             break;
 
-       case PRAGMA_ZPSYM:
-           StringPragma (&B, MakeZPSym);
-           break;
+        case PRAGMA_ZPSYM:
+            StringPragma (&B, MakeZPSym);
+            break;
 
-       default:
-                   Internal ("Invalid pragma");
+        default:
+            Internal ("Invalid pragma");
     }
 
     /* Closing paren expected */
@@ -822,29 +927,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 ();
 }
-
-
-