/*****************************************************************************/
/* */
-/* pragma.c */
+/* pragma.c */
/* */
-/* Pragma handling for the cc65 C compiler */
+/* Pragma handling for the cc65 C compiler */
/* */
/* */
/* */
-/* (C) 1998-2009, Ullrich von Bassewitz */
+/* (C) 1998-2011, Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/*****************************************************************************/
-/* 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_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[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 },
+ { "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 },
};
/* Result of ParsePushPop */
static pragma_t FindPragma (const StrBuf* Key)
-/* Find a pragma and return the token. Return PR_ILLEGAL if the keyword is
+/* Find a pragma and return the token. Return PRAGMA_ILLEGAL if the keyword is
* not a valid pragma.
*/
{
struct Pragma* P;
- P = bsearch (SB_GetConstBuf (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;
}
*/
{
if (!SB_GetString (B, S)) {
- Error ("String literal expected");
+ Error ("String literal expected");
return 0;
}
return 1;
*/
{
if (!SB_GetNumber (B, Val)) {
- Error ("Constant integer expected");
+ Error ("Constant integer expected");
return 0;
}
return 1;
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)) {
/* Skip the following comma */
if (!GetComma (B)) {
+ /* Error already flagged by GetComma */
Res = PP_ERROR;
}
} else {
- /* Unknown keyword */
- Error ("Invalid pragma arguments");
- Res = PP_ERROR;
+ /* Unknown keyword, roll back */
+ SB_SetIndex (B, Index);
}
}
/* 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 */
} else {
Error ("Character index out of range");
}
- return;
+ return;
}
/* Comma follows */
} else {
Error ("Character code out of range");
}
- return;
+ return;
}
/* Remap the character */
int Push;
/* A warning name must follow */
- IntStack* S =GetWarning (B);
+ IntStack* S = GetWarning (B);
if (S == 0) {
return;
}
/* 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 ();
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'", SB_GetConstBuf (&Ident));
- goto ExitPoint;
+ 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 */
/* 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_BSSSEG:
+ Warning ("#pragma bssseg is obsolete, please use #pragma bss-name instead");
+ /* FALLTHROUGH */
+ case PRAGMA_BSS_NAME:
+ SegNamePragma (&B, SEG_BSS);
+ break;
- case PR_CHARMAP:
- CharMapPragma (&B);
- break;
+ case PRAGMA_CHARMAP:
+ CharMapPragma (&B);
+ break;
- case PR_CHECKSTACK:
- FlagPragma (&B, &CheckStack);
- 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_CODESEG:
- SegNamePragma (&B, SEG_CODE);
- 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_CODESIZE:
- IntPragma (&B, &CodeSizeFactor, 10, 1000);
- 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 PR_DATASEG:
- SegNamePragma (&B, SEG_DATA);
- break;
+ case PRAGMA_LOCAL_STRINGS:
+ FlagPragma (&B, &LocalStrings);
+ break;
- case PR_OPTIMIZE:
+ 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:
+ case PRAGMA_WARN:
WarnPragma (&B);
break;
- case PR_ZPSYM:
- StringPragma (&B, MakeZPSym);
- break;
+ case PRAGMA_WRITABLE_STRINGS:
+ FlagPragma (&B, &WritableStrings);
+ break;
+
+ case PRAGMA_ZPSYM:
+ StringPragma (&B, MakeZPSym);
+ break;
- default:
- Internal ("Invalid pragma");
+ default:
+ Internal ("Invalid pragma");
}
/* Closing paren expected */
/* 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 ();
}
-
-
-