X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcc65%2Fpragma.c;h=bf93bcd5b948633bf6ab54e28601abd749bd6fb3;hb=dbbce2e939af8fd78f659e5c66eea8b002369ba2;hp=f4020cf3b64e8b2636f4c6af707d3e8d760828d7;hpb=d341e0ad767e43518364bbcceb2dd2900f92ddb9;p=cc65 diff --git a/src/cc65/pragma.c b/src/cc65/pragma.c index f4020cf3b..bf93bcd5b 100644 --- a/src/cc65/pragma.c +++ b/src/cc65/pragma.c @@ -6,10 +6,10 @@ /* */ /* */ /* */ -/* (C) 1998-2000 Ullrich von Bassewitz */ +/* (C) 1998-2002 Ullrich von Bassewitz */ /* Wacholderweg 14 */ /* D-70597 Stuttgart */ -/* EMail: uz@musoftware.de */ +/* EMail: uz@cc65.org */ /* */ /* */ /* This software is provided 'as-is', without any expressed or implied */ @@ -34,29 +34,37 @@ #include -#include +#include +/* common */ +#include "segnames.h" +#include "tgttrans.h" + +/* cc65 */ #include "codegen.h" #include "error.h" #include "expr.h" #include "global.h" #include "litpool.h" #include "scanner.h" -#include "segname.h" +#include "scanstrbuf.h" #include "symtab.h" #include "pragma.h" /*****************************************************************************/ -/* data */ +/* data */ /*****************************************************************************/ /* Tokens for the #pragmas */ typedef enum { + PR_ILLEGAL = -1, PR_BSSSEG, + PR_CHARMAP, + PR_CHECKSTACK, PR_CODESEG, PR_DATASEG, PR_REGVARADDR, @@ -64,15 +72,17 @@ typedef enum { PR_SIGNEDCHARS, PR_STATICLOCALS, PR_ZPSYM, - PR_ILLEGAL + PR_COUNT } pragma_t; /* Pragma table */ static const struct Pragma { const char* Key; /* Keyword */ - pragma_t Tok; /* Token */ -} Pragmas[] = { + pragma_t Tok; /* Token */ +} Pragmas[PR_COUNT] = { { "bssseg", PR_BSSSEG }, + { "charmap", PR_CHARMAP }, + { "checkstack", PR_CHECKSTACK }, { "codeseg", PR_CODESEG }, { "dataseg", PR_DATASEG }, { "regvaraddr", PR_REGVARADDR }, @@ -82,9 +92,6 @@ static const struct Pragma { { "zpsym", PR_ZPSYM }, }; -/* Number of pragmas */ -#define PRAGMA_COUNT (sizeof(Pragmas) / sizeof(Pragmas[0])) - /*****************************************************************************/ @@ -93,6 +100,17 @@ static const struct Pragma { +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 */ { @@ -107,48 +125,46 @@ static pragma_t FindPragma (const char* Key) */ { struct Pragma* P; - P = bsearch (Key, Pragmas, PRAGMA_COUNT, sizeof (Pragmas[0]), CmpKey); + P = bsearch (Key, Pragmas, PR_COUNT, sizeof (Pragmas[0]), CmpKey); return P? P->Tok : PR_ILLEGAL; } -static void StringPragma (void (*Func) (const char*)) +static void StringPragma (StrBuf* B, void (*Func) (const char*)) /* Handle a pragma that expects a string parameter */ { - if (curtok != TOK_SCONST) { - Error ("String literal expected"); - } else { - /* Get the string */ - const char* Name = GetLiteral (curval); + StrBuf S; + /* We expect a string here */ + if (SB_GetString (B, &S)) { /* Call the given function with the string argument */ - Func (Name); - - /* Reset the string pointer, removing the string from the pool */ - ResetLiteralOffs (curval); + Func (SB_GetConstBuf (&S)); + } else { + Error ("String literal expected"); } - /* Skip the string (or error) token */ - NextToken (); + /* Call the string buf destructor */ + DoneStrBuf (&S); } -static void SegNamePragma (void (*Func) (const char*)) +static void SegNamePragma (StrBuf* B, segment_t Seg) /* Handle a pragma that expects a segment name parameter */ { - if (curtok != TOK_SCONST) { - Error ("String literal expected"); - } else { - /* Get the segment name */ - const char* Name = GetLiteral (curval); + StrBuf S; + + if (SB_GetString (B, &S)) { + + /* Get the string */ + const char* Name = SB_GetConstBuf (&S); /* Check if the name is valid */ if (ValidSegName (Name)) { - /* Call the given function to set the name */ - Func (Name); + /* Set the new name */ + g_segname (Seg, Name); } else { @@ -157,97 +173,226 @@ static void SegNamePragma (void (*Func) (const char*)) } - /* Reset the string pointer, removing the string from the pool */ - ResetLiteralOffs (curval); + } else { + Error ("String literal expected"); } - /* Skip the string (or error) token */ - NextToken (); + /* Call the string buf destructor */ + DoneStrBuf (&S); } -static void FlagPragma (unsigned char* Flag) -/* Handle a pragma that expects a boolean paramater */ +static void CharMapPragma (StrBuf* B) +/* Change the character map */ { - /* Read a constant expression */ - struct expent val; - constexpr (&val); + long Index, C; + + /* Read the character index */ + if (!SB_GetNumber (B, &Index)) { + return; + } + if (Index < 1 || Index > 255) { + Error ("Character index out of range"); + return; + } - /* Store the value into the flag parameter */ - *Flag = (val.e_const != 0); + /* Comma follows */ + SB_SkipWhite (B); + if (SB_Get (B) != ',') { + Error ("Comma expected"); + return; + } + SB_SkipWhite (B); + + /* Read the character code */ + if (!SB_GetNumber (B, &C)) { + return; + } + if (C < 1 || C > 255) { + Error ("Character code out of range"); + return; + } + + /* Remap the character */ + TgtTranslateSet ((unsigned) Index, (unsigned char) C); } -void DoPragma (void) -/* Handle pragmas */ +static void FlagPragma (StrBuf* B, unsigned char* Flag) +/* Handle a pragma that expects a boolean paramater */ +{ + ident Ident; + long Val; + + if (SB_GetSym (B, Ident)) { + if (strcmp (Ident, "true") == 0 || strcmp (Ident, "on") == 0) { + *Flag = 1; + } else if (strcmp (Ident, "false") == 0 || strcmp (Ident, "off") == 0) { + *Flag = 0; + } else { + Error ("Pragma argument must be one of `on', `off', `true' or `false'"); + } + } else if (SB_GetNumber (B, &Val)) { + *Flag = (Val != 0); + } else { + Error ("Invalid pragma argument"); + } +} + + + +static void ParsePragma (void) +/* Parse the contents of the _Pragma statement */ { pragma_t Pragma; + ident Ident; - /* Skip the token itself */ + /* 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); + + /* Skip the string token */ NextToken (); - /* Identifier must follow */ - if (curtok != TOK_IDENT) { - Error ("Identifier expected"); - return; + /* Get the pragma name from the string */ + SB_SkipWhite (&B); + if (!SB_GetSym (&B, Ident)) { + Error ("Invalid pragma"); + return; } + /* 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 ("Unknown #pragma `%s'", CurTok.Ident); - return; + /* 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; } - /* 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"); + return; + } + + /* Skip white space before the argument */ + SB_SkipWhite (&B); /* Switch for the different pragmas */ switch (Pragma) { - case PR_BSSSEG: - SegNamePragma (g_bssname); - break; + case PR_BSSSEG: + SegNamePragma (&B, SEG_BSS); + break; + + case PR_CHARMAP: + CharMapPragma (&B); + break; + + case PR_CHECKSTACK: + FlagPragma (&B, &CheckStack); + break; - case PR_CODESEG: - SegNamePragma (g_codename); - break; + case PR_CODESEG: + SegNamePragma (&B, SEG_CODE); + break; - case PR_DATASEG: - SegNamePragma (g_dataname); - break; + case PR_DATASEG: + SegNamePragma (&B, SEG_DATA); + break; - case PR_REGVARADDR: - FlagPragma (&AllowRegVarAddr); - break; + case PR_REGVARADDR: + FlagPragma (&B, &AllowRegVarAddr); + break; - case PR_RODATASEG: - SegNamePragma (g_rodataname); - break; + case PR_RODATASEG: + SegNamePragma (&B, SEG_RODATA); + break; - case PR_SIGNEDCHARS: - FlagPragma (&SignedChars); - break; + case PR_SIGNEDCHARS: + FlagPragma (&B, &SignedChars); + break; - case PR_STATICLOCALS: - FlagPragma (&StaticLocals); - break; + case PR_STATICLOCALS: + FlagPragma (&B, &StaticLocals); + break; - case PR_ZPSYM: - StringPragma (MakeZPSym); - break; + case PR_ZPSYM: + StringPragma (&B, MakeZPSym); + break; - default: + default: Internal ("Invalid pragma"); } + /* Closing paren expected */ + SB_SkipWhite (&B); + if (SB_Get (&B) != ')') { + Error ("')' expected"); + return; + } + SB_SkipWhite (&B); + + /* Allow an optional semicolon to be compatible with the old syntax */ + if (SB_Peek (&B) == ';') { + SB_Skip (&B); + SB_SkipWhite (&B); + } + + /* Make sure nothing follows */ + if (SB_Peek (&B) != '\0') { + Error ("Unexpected input following pragma directive"); + } + + /* Release the StrBuf */ + DoneStrBuf (&B); +} + + + +void DoPragma (void) +/* Handle pragmas. These come always in form of the new C99 _Pragma() operator. */ +{ + /* Skip the token itself */ + NextToken (); + + /* We expect an opening paren */ + if (!ConsumeLParen ()) { + return; + } + + /* 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 (); }