1
0
mirror of https://github.com/cc65/cc65.git synced 2025-08-14 14:26:27 +00:00

Rewrote most of the #pragma parsing code. I'm still not satisfied, but at

least, it's a bit better than before. #pragma warn (...) is now used to switch
single warnings instead of a global on/off switch.



git-svn-id: svn://svn.cc65.org/cc65/trunk@4362 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
uz
2009-10-13 21:24:32 +00:00
parent 583b9f8fcc
commit a1fb355a9a
4 changed files with 484 additions and 238 deletions

View File

@@ -731,7 +731,7 @@ If the first parameter is <tt/push/, the old value is saved onto a stack
before changing it. The value may later be restored by using the <tt/pop/ before changing it. The value may later be restored by using the <tt/pop/
parameter with the <tt/#pragma/. parameter with the <tt/#pragma/.
<sect1><tt>#pragma bssseg (&lsqb;push,&rsqb;&lt;name&gt;)</tt><p> <sect1><tt>#pragma bssseg (&lsqb;push,&rsqb; &lt;name&gt;)</tt><p>
This pragma changes the name used for the BSS segment (the BSS segment This pragma changes the name used for the BSS segment (the BSS segment
is used to store uninitialized data). The argument is a string enclosed is used to store uninitialized data). The argument is a string enclosed
@@ -787,7 +787,7 @@ parameter with the <tt/#pragma/.
</verb></tscreen> </verb></tscreen>
<sect1><tt>#pragma checkstack ([push,]on|off)</tt><label id="pragma-checkstack"><p> <sect1><tt>#pragma checkstack ([push,] on|off)</tt><label id="pragma-checkstack"><p>
Tells the compiler to insert calls to a stack checking subroutine to detect Tells the compiler to insert calls to a stack checking subroutine to detect
stack overflows. The stack checking code will lead to somewhat larger and stack overflows. The stack checking code will lead to somewhat larger and
@@ -800,7 +800,7 @@ parameter with the <tt/#pragma/.
The <tt/#pragma/ understands the push and pop parameters as explained above. The <tt/#pragma/ understands the push and pop parameters as explained above.
<sect1><tt>#pragma codeseg ([push,]&lt;name&gt;)</tt><p> <sect1><tt>#pragma codeseg ([push,] &lt;name&gt;)</tt><p>
This pragma changes the name used for the CODE segment (the CODE segment This pragma changes the name used for the CODE segment (the CODE segment
is used to store executable code). The argument is a string enclosed in is used to store executable code). The argument is a string enclosed in
@@ -818,7 +818,7 @@ parameter with the <tt/#pragma/.
</verb></tscreen> </verb></tscreen>
<sect1><tt>#pragma codesize ([push,]&lt;int&gt;)</tt><label id="pragma-codesize"><p> <sect1><tt>#pragma codesize ([push,] &lt;int&gt;)</tt><label id="pragma-codesize"><p>
This pragma allows finer control about speed vs. size decisions in the code This pragma allows finer control about speed vs. size decisions in the code
generation and optimization phase. It gives the allowed size increase factor generation and optimization phase. It gives the allowed size increase factor
@@ -828,7 +828,7 @@ parameter with the <tt/#pragma/.
The <tt/#pragma/ understands the push and pop parameters as explained above. The <tt/#pragma/ understands the push and pop parameters as explained above.
<sect1><tt>#pragma dataseg ([push,]&lt;name&gt;)</tt><p> <sect1><tt>#pragma dataseg ([push,] &lt;name&gt;)</tt><p>
This pragma changes the name used for the DATA segment (the DATA segment This pragma changes the name used for the DATA segment (the DATA segment
is used to store initialized data). The argument is a string enclosed in is used to store initialized data). The argument is a string enclosed in
@@ -846,7 +846,7 @@ parameter with the <tt/#pragma/.
</verb></tscreen> </verb></tscreen>
<sect1><tt>#pragma optimize ([push,]on|off)</tt><label id="pragma-optimize"><p> <sect1><tt>#pragma optimize ([push,] on|off)</tt><label id="pragma-optimize"><p>
Switch optimization on or off. If the argument is "off", optimization is Switch optimization on or off. If the argument is "off", optimization is
disabled, otherwise it is enabled. Please note that this pragma only effects disabled, otherwise it is enabled. Please note that this pragma only effects
@@ -862,7 +862,7 @@ parameter with the <tt/#pragma/.
The <tt/#pragma/ understands the push and pop parameters as explained above. The <tt/#pragma/ understands the push and pop parameters as explained above.
<sect1><tt>#pragma rodataseg ([push,]&lt;name&gt;)</tt><p> <sect1><tt>#pragma rodataseg ([push,] &lt;name&gt;)</tt><p>
This pragma changes the name used for the RODATA segment (the RODATA This pragma changes the name used for the RODATA segment (the RODATA
segment is used to store readonly data). The argument is a string segment is used to store readonly data). The argument is a string
@@ -880,7 +880,7 @@ parameter with the <tt/#pragma/.
</verb></tscreen> </verb></tscreen>
<sect1><tt>#pragma regvaraddr ([push,]on|off)</tt><p> <sect1><tt>#pragma regvaraddr ([push,] on|off)</tt><p>
The compiler does not allow to take the address of register variables. The compiler does not allow to take the address of register variables.
The regvaraddr pragma changes this. Taking the address of a register The regvaraddr pragma changes this. Taking the address of a register
@@ -904,7 +904,7 @@ parameter with the <tt/#pragma/.
</verb></tscreen> </verb></tscreen>
<sect1><tt>#pragma regvars ([push,]on|off)</tt><label id="pragma-regvars"><p> <sect1><tt>#pragma regvars ([push,] on|off)</tt><label id="pragma-regvars"><p>
Enables or disables use of register variables. If register variables are Enables or disables use of register variables. If register variables are
disabled (the default), the <tt/register/ keyword is ignored. Register disabled (the default), the <tt/register/ keyword is ignored. Register
@@ -914,7 +914,7 @@ parameter with the <tt/#pragma/.
The <tt/#pragma/ understands the push and pop parameters as explained above. The <tt/#pragma/ understands the push and pop parameters as explained above.
<sect1><tt>#pragma signedchars ([push,]on|off)</tt><label id="pragma-signedchars"><p> <sect1><tt>#pragma signedchars ([push,] on|off)</tt><label id="pragma-signedchars"><p>
Changes the signedness of the default character type. If the argument is Changes the signedness of the default character type. If the argument is
"on", default characters are signed, otherwise characters are unsigned. "on", default characters are signed, otherwise characters are unsigned.
@@ -925,7 +925,7 @@ parameter with the <tt/#pragma/.
The <tt/#pragma/ understands the push and pop parameters as explained above. The <tt/#pragma/ understands the push and pop parameters as explained above.
<sect1><tt>#pragma staticlocals ([push,]on|off)</tt><label id="pragma-staticlocals"<p> <sect1><tt>#pragma staticlocals ([push,] on|off)</tt><label id="pragma-staticlocals"<p>
Use variables in the bss segment instead of variables on the stack. This Use variables in the bss segment instead of variables on the stack. This
pragma changes the default set by the compiler option <tt/-Cl/. If the pragma changes the default set by the compiler option <tt/-Cl/. If the
@@ -935,13 +935,13 @@ parameter with the <tt/#pragma/.
The <tt/#pragma/ understands the push and pop parameters as explained above. The <tt/#pragma/ understands the push and pop parameters as explained above.
<sect1><tt>#pragma warn ([push,]on|off)</tt><label id="pragma-warn"><p> <sect1><tt>#pragma warn (name, [push,] on|off)</tt><label id="pragma-warn"><p>
Switch compiler warnings on or off. If the argument is "off", warnings are Switch compiler warnings on or off. "name" is the name of a warning (see the
disabled, otherwise they're enabled. The default is "on", but may be changed <tt/<ref name="-W" id="option-W">/ compiler option for a list). The name is
with the <tt/<ref name="-W" id="option-W">/ compiler option. either followed by "pop", which restores the last pushed state, or by "on" or
"off", optionally preceeded by "push" to push the current state before
The <tt/#pragma/ understands the push and pop parameters as explained above. changing it.
<sect1><tt>#pragma zpsym (&lt;name&gt;)</tt><p> <sect1><tt>#pragma zpsym (&lt;name&gt;)</tt><p>

View File

@@ -37,6 +37,7 @@
#include <string.h> #include <string.h>
/* common */ /* common */
#include "chartype.h"
#include "segnames.h" #include "segnames.h"
#include "tgttrans.h" #include "tgttrans.h"
@@ -100,10 +101,18 @@ static const struct Pragma {
{ "zpsym", PR_ZPSYM }, { "zpsym", PR_ZPSYM },
}; };
/* Result of ParsePushPop */
typedef enum {
PP_NONE,
PP_POP,
PP_PUSH,
PP_ERROR,
} PushPopResult;
/*****************************************************************************/ /*****************************************************************************/
/* Code */ /* Helper functions */
/*****************************************************************************/ /*****************************************************************************/
@@ -127,29 +136,214 @@ static int CmpKey (const void* Key, const void* Elem)
static pragma_t FindPragma (const char* Key) 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 PR_ILLEGAL if the keyword is
* not a valid pragma. * not a valid pragma.
*/ */
{ {
struct Pragma* P; struct Pragma* P;
P = bsearch (Key, Pragmas, PR_COUNT, sizeof (Pragmas[0]), CmpKey); P = bsearch (SB_GetConstBuf (Key), Pragmas, PR_COUNT, sizeof (Pragmas[0]), CmpKey);
return P? P->Tok : PR_ILLEGAL; return P? P->Tok : PR_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;
/* 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)) {
Res = PP_ERROR;
}
} else {
/* Unknown keyword */
Error ("Invalid pragma arguments");
Res = PP_ERROR;
}
}
/* 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*)) static void StringPragma (StrBuf* B, void (*Func) (const char*))
/* Handle a pragma that expects a string parameter */ /* Handle a pragma that expects a string parameter */
{ {
StrBuf S; StrBuf S = AUTO_STRBUF_INITIALIZER;
/* We expect a string here */ /* We expect a string here */
if (SB_GetString (B, &S)) { if (GetString (B, &S)) {
/* Call the given function with the string argument */ /* Call the given function with the string argument */
Func (SB_GetConstBuf (&S)); Func (SB_GetConstBuf (&S));
} else {
Error ("String literal expected");
} }
/* Call the string buf destructor */ /* Call the string buf destructor */
@@ -161,58 +355,47 @@ static void StringPragma (StrBuf* B, void (*Func) (const char*))
static void SegNamePragma (StrBuf* B, segment_t Seg) static void SegNamePragma (StrBuf* B, segment_t Seg)
/* Handle a pragma that expects a segment name parameter */ /* Handle a pragma that expects a segment name parameter */
{ {
ident Ident; StrBuf S = AUTO_STRBUF_INITIALIZER;
StrBuf S;
const char* Name; const char* Name;
/* Try to read an identifier */ /* Check for the "push" or "pop" keywords */
int Push = 0; int Push = 0;
if (SB_GetSym (B, Ident)) { switch (ParsePushPop (B)) {
/* Check if we have a first argument named "pop" */ case PP_NONE:
if (strcmp (Ident, "pop") == 0) { break;
/* Pop the old value */ case PP_PUSH:
Push = 1;
break;
case PP_POP:
/* Pop the old value and output it */
PopSegName (Seg); PopSegName (Seg);
/* Set the segment name */
g_segname (Seg); g_segname (Seg);
/* Done */ /* Done */
return; goto ExitPoint;
/* Check if we have a first argument named "push" */ case PP_ERROR:
} else if (strcmp (Ident, "push") == 0) { /* Bail out */
goto ExitPoint;
Push = 1; default:
SB_SkipWhite (B); Internal ("Invalid result from ParsePushPop");
if (SB_Get (B) != ',') {
Error ("Comma expected");
return;
}
SB_SkipWhite (B);
} else {
Error ("Invalid pragma arguments");
return;
}
} }
/* A string argument must follow */ /* A string argument must follow */
if (!SB_GetString (B, &S)) { if (!GetString (B, &S)) {
Error ("String literal expected"); goto ExitPoint;
return;
} }
/* Get the string */ /* Get the string */
Name = SB_GetConstBuf (&S); Name = SB_GetConstBuf (&S);
/* Check if the name is valid */ /* Check if the name is valid */
if (!ValidSegName (Name)) { if (ValidSegName (Name)) {
/* Segment name is invalid */
Error ("Illegal segment name: `%s'", Name);
return;
}
/* Set the new name */ /* Set the new name */
if (Push) { if (Push) {
@@ -222,6 +405,14 @@ static void SegNamePragma (StrBuf* B, segment_t Seg)
} }
g_segname (Seg); g_segname (Seg);
} else {
/* Segment name is invalid */
Error ("Illegal segment name: `%s'", Name);
}
ExitPoint:
/* Call the string buf destructor */ /* Call the string buf destructor */
SB_Done (&S); SB_Done (&S);
} }
@@ -234,7 +425,7 @@ static void CharMapPragma (StrBuf* B)
long Index, C; long Index, C;
/* Read the character index */ /* Read the character index */
if (!SB_GetNumber (B, &Index)) { if (!GetNumber (B, &Index)) {
return; return;
} }
if (Index < 1 || Index > 255) { if (Index < 1 || Index > 255) {
@@ -248,15 +439,12 @@ static void CharMapPragma (StrBuf* B)
} }
/* Comma follows */ /* Comma follows */
SB_SkipWhite (B); if (!GetComma (B)) {
if (SB_Get (B) != ',') {
Error ("Comma expected");
return; return;
} }
SB_SkipWhite (B);
/* Read the character code */ /* Read the character code */
if (!SB_GetNumber (B, &C)) { if (!GetNumber (B, &C)) {
return; return;
} }
if (C < 1 || C > 255) { if (C < 1 || C > 255) {
@@ -275,50 +463,52 @@ static void CharMapPragma (StrBuf* B)
static void FlagPragma (StrBuf* B, IntStack* Stack) static void WarnPragma (StrBuf* B)
/* Handle a pragma that expects a boolean paramater */ /* Enable/disable warnings */
{ {
ident Ident;
long Val; long Val;
int Push; int Push;
/* Try to read an identifier */ /* A warning name must follow */
int IsIdent = SB_GetSym (B, Ident); IntStack* S =GetWarning (B);
if (S == 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);
}
/* No other arguments allowed */
return; return;
} }
/* Check if we have a first argument named "push" */ /* Comma follows */
if (IsIdent && strcmp (Ident, "push") == 0) { if (!GetComma (B)) {
Push = 1;
SB_SkipWhite (B);
if (SB_Get (B) != ',') {
Error ("Comma expected");
return; return;
} }
SB_SkipWhite (B);
IsIdent = SB_GetSym (B, Ident); /* Check for the "push" or "pop" keywords */
} else { switch (ParsePushPop (B)) {
case PP_NONE:
Push = 0; 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 */ /* Boolean argument follows */
if (IsIdent) { if (HasStr (B, "true") || HasStr (B, "on")) {
if (strcmp (Ident, "true") == 0 || strcmp (Ident, "on") == 0) {
Val = 1; Val = 1;
} else if (strcmp (Ident, "false") == 0 || strcmp (Ident, "off") == 0) { } else if (HasStr (B, "false") || HasStr (B, "off")) {
Val = 0; Val = 0;
} else {
Error ("Pragma argument must be one of `on', `off', `true' or `false'");
}
} else if (!SB_GetNumber (B, &Val)) { } else if (!SB_GetNumber (B, &Val)) {
Error ("Invalid pragma argument"); Error ("Invalid pragma argument");
return; return;
@@ -326,14 +516,60 @@ static void FlagPragma (StrBuf* B, IntStack* Stack)
/* Set/push the new value */ /* Set/push the new value */
if (Push) { if (Push) {
if (IS_IsFull (Stack)) { PushInt (S, Val);
Error ("Cannot push: stack overflow");
} else { } else {
IS_Push (Stack, Val); IS_Set (S, Val);
} }
}
static void FlagPragma (StrBuf* B, IntStack* Stack)
/* Handle a pragma that expects a boolean paramater */
{
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;
}
/* 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 { } else {
IS_Set (Stack, Val); IS_Set (Stack, Val);
} }
ExitPoint:
/* Free the identifier */
SB_Done (&Ident);
} }
@@ -341,41 +577,36 @@ static void FlagPragma (StrBuf* B, IntStack* Stack)
static void IntPragma (StrBuf* B, IntStack* Stack, long Low, long High) static void IntPragma (StrBuf* B, IntStack* Stack, long Low, long High)
/* Handle a pragma that expects an int paramater */ /* Handle a pragma that expects an int paramater */
{ {
ident Ident;
long Val; long Val;
int Push; int Push;
/* Try to read an identifier */ /* Check for the "push" or "pop" keywords */
int IsIdent = SB_GetSym (B, Ident); switch (ParsePushPop (B)) {
/* Check if we have a first argument named "pop" */ case PP_NONE:
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;
}
/* 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");
return;
}
SB_SkipWhite (B);
IsIdent = 0;
} else {
Push = 0; 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 */ /* Integer argument follows */
if (IsIdent || !SB_GetNumber (B, &Val)) { if (!GetNumber (B, &Val)) {
Error ("Pragma argument must be numeric");
return; return;
} }
@@ -387,11 +618,7 @@ static void IntPragma (StrBuf* B, IntStack* Stack, long Low, long High)
/* Set/push the new value */ /* Set/push the new value */
if (Push) { if (Push) {
if (IS_IsFull (Stack)) { PushInt (Stack, Val);
Error ("Cannot push: stack overflow");
} else {
IS_Push (Stack, Val);
}
} else { } else {
IS_Set (Stack, Val); IS_Set (Stack, Val);
} }
@@ -403,7 +630,7 @@ static void ParsePragma (void)
/* Parse the contents of the _Pragma statement */ /* Parse the contents of the _Pragma statement */
{ {
pragma_t Pragma; pragma_t Pragma;
ident Ident; StrBuf Ident = AUTO_STRBUF_INITIALIZER;
/* Create a string buffer from the string literal */ /* Create a string buffer from the string literal */
StrBuf B = AUTO_STRBUF_INITIALIZER; StrBuf B = AUTO_STRBUF_INITIALIZER;
@@ -421,13 +648,13 @@ static void ParsePragma (void)
/* Get the pragma name from the string */ /* Get the pragma name from the string */
SB_SkipWhite (&B); SB_SkipWhite (&B);
if (!SB_GetSym (&B, Ident)) { if (!SB_GetSym (&B, &Ident, "-")) {
Error ("Invalid pragma"); Error ("Invalid pragma");
return; goto ExitPoint;
} }
/* Search for the name */ /* Search for the name */
Pragma = FindPragma (Ident); Pragma = FindPragma (&Ident);
/* Do we know this pragma? */ /* Do we know this pragma? */
if (Pragma == PR_ILLEGAL) { if (Pragma == PR_ILLEGAL) {
@@ -435,15 +662,15 @@ static void ParsePragma (void)
* for unknown pragmas, however, we're allowed to warn - and we will * for unknown pragmas, however, we're allowed to warn - and we will
* do so. Otherwise one typo may give you hours of bug hunting... * do so. Otherwise one typo may give you hours of bug hunting...
*/ */
Warning ("Unknown pragma `%s'", Ident); Warning ("Unknown pragma `%s'", SB_GetConstBuf (&Ident));
return; goto ExitPoint;
} }
/* Check for an open paren */ /* Check for an open paren */
SB_SkipWhite (&B); SB_SkipWhite (&B);
if (SB_Get (&B) != '(') { if (SB_Get (&B) != '(') {
Error ("'(' expected"); Error ("'(' expected");
return; goto ExitPoint;
} }
/* Skip white space before the argument */ /* Skip white space before the argument */
@@ -501,7 +728,7 @@ static void ParsePragma (void)
break; break;
case PR_WARN: case PR_WARN:
FlagPragma (&B, &WarnEnable); WarnPragma (&B);
break; break;
case PR_ZPSYM: case PR_ZPSYM:
@@ -516,7 +743,7 @@ static void ParsePragma (void)
SB_SkipWhite (&B); SB_SkipWhite (&B);
if (SB_Get (&B) != ')') { if (SB_Get (&B) != ')') {
Error ("')' expected"); Error ("')' expected");
return; goto ExitPoint;
} }
SB_SkipWhite (&B); SB_SkipWhite (&B);
@@ -531,8 +758,10 @@ static void ParsePragma (void)
Error ("Unexpected input following pragma directive"); Error ("Unexpected input following pragma directive");
} }
/* Release the StrBuf */ ExitPoint:
/* Release the string buffers */
SB_Done (&B); SB_Done (&B);
SB_Done (&Ident);
} }

View File

@@ -162,23 +162,31 @@ void SB_SkipWhite (StrBuf* B)
int SB_GetSym (StrBuf* B, char* S) int SB_GetSym (StrBuf* B, StrBuf* Ident, const char* SpecialChars)
/* Get a symbol from the string buffer. S must be able to hold MAX_IDENTLEN /* Get a symbol from the string buffer. If SpecialChars is not NULL, it
* characters. Returns 1 if a symbol was found and 0 otherwise. * points to a string that contains characters allowed within the string in
* addition to letters, digits and the underline. Note: The identifier must
* still begin with a letter.
* Returns 1 if a symbol was found and 0 otherwise but doesn't output any
* errors.
*/ */
{ {
/* Handle a NULL argument for SpecialChars transparently */
if (SpecialChars == 0) {
SpecialChars = "";
}
/* Clear Ident */
SB_Clear (Ident);
if (IsIdent (SB_Peek (B))) { if (IsIdent (SB_Peek (B))) {
unsigned I = 0;
char C = SB_Peek (B); char C = SB_Peek (B);
do { do {
if (I < MAX_IDENTLEN) { SB_AppendChar (Ident, C);
++I;
*S++ = C;
}
SB_Skip (B); SB_Skip (B);
C = SB_Peek (B); C = SB_Peek (B);
} while (IsIdent (C) || IsDigit (C)); } while (IsIdent (C) || IsDigit (C) || strchr (SpecialChars, C) != 0);
*S = '\0'; SB_Terminate (Ident);
return 1; return 1;
} else { } else {
return 0; return 0;
@@ -188,15 +196,17 @@ int SB_GetSym (StrBuf* B, char* S)
int SB_GetString (StrBuf* B, StrBuf* S) int SB_GetString (StrBuf* B, StrBuf* S)
/* Get a string from the string buffer. S will be initialized by the function /* Get a string from the string buffer. Returns 1 if a string was found and 0
* and will return the correctly terminated string on return. The function * otherwise. Errors are only output in case of invalid strings (missing end
* returns 1 if a string was found and 0 otherwise. * of string).
*/ */
{ {
char C; char C;
/* Initialize S */ /* Clear S */
SB_Init (S); SB_Clear (S);
/* A string starts with quote marks */
if (SB_Peek (B) == '\"') { if (SB_Peek (B) == '\"') {
/* String follows, be sure to concatenate strings */ /* String follows, be sure to concatenate strings */
@@ -241,7 +251,7 @@ int SB_GetNumber (StrBuf* B, long* Val)
/* Get a number from the string buffer. Accepted formats are decimal, octal, /* Get a number from the string buffer. Accepted formats are decimal, octal,
* hex and character constants. Numeric constants may be preceeded by a * hex and character constants. Numeric constants may be preceeded by a
* minus or plus sign. The function returns 1 if a number was found and * minus or plus sign. The function returns 1 if a number was found and
* zero otherwise. * zero otherwise. Errors are only output for invalid numbers.
*/ */
{ {
int Sign; int Sign;
@@ -249,25 +259,49 @@ int SB_GetNumber (StrBuf* B, long* Val)
unsigned Base; unsigned Base;
unsigned DigitVal; unsigned DigitVal;
/* Initialize Val */ /* Initialize Val */
*Val = 0; *Val = 0;
/* Check for a sign */ /* Handle character constants */
if (SB_Peek (B) == '\'') {
/* Character constant */
SB_Skip (B);
*Val = SignExtendChar (TgtTranslateChar (ParseChar (B)));
if (SB_Peek (B) != '\'') {
Error ("`\'' expected");
return 0;
} else {
/* Skip the quote */
SB_Skip (B);
return 1;
}
}
/* Check for a sign. A sign must be followed by a digit, otherwise it's
* not a number
*/
Sign = 1; Sign = 1;
switch (SB_Peek (B)) { switch (SB_Peek (B)) {
case '-': case '-':
Sign = -1; Sign = -1;
/* FALLTHROUGH */ /* FALLTHROUGH */
case '+': case '+':
if (!IsDigit (SB_LookAt (B, SB_GetIndex (B) + 1))) {
return 0;
}
SB_Skip (B); SB_Skip (B);
SB_SkipWhite (B);
break; break;
} }
/* Check for the different formats */ /* We must have a digit now, otherwise its not a number */
C = SB_Peek (B); C = SB_Peek (B);
if (IsDigit (C)) { if (!IsDigit (C)) {
return 0;
}
/* Determine the base */
if (C == '0') { if (C == '0') {
/* Hex or octal */ /* Hex or octal */
SB_Skip (B); SB_Skip (B);
@@ -307,27 +341,6 @@ int SB_GetNumber (StrBuf* B, long* Val)
} }
} }
} else if (C == '\'') {
/* Character constant */
SB_Skip (B);
*Val = SignExtendChar (TgtTranslateChar (ParseChar (B)));
if (SB_Peek (B) != '\'') {
Error ("`\'' expected");
return 0;
} else {
/* Skip the quote */
SB_Skip (B);
}
} else {
/* Invalid number */
Error ("Numeric constant expected");
return 0;
}
/* Success, value read is in Val */ /* Success, value read is in Val */
*Val *= Sign; *Val *= Sign;
return 1; return 1;

View File

@@ -6,9 +6,9 @@
/* */ /* */
/* */ /* */
/* */ /* */
/* (C) 2002 Ullrich von Bassewitz */ /* (C) 2002-2009, Ullrich von Bassewitz */
/* Wacholderweg 14 */ /* Roemerstrasse 52 */
/* D-70597 Stuttgart */ /* D-70794 Filderstadt */
/* EMail: uz@cc65.org */ /* EMail: uz@cc65.org */
/* */ /* */
/* */ /* */
@@ -52,22 +52,26 @@
void SB_SkipWhite (StrBuf* B); void SB_SkipWhite (StrBuf* B);
/* Skip whitespace in the string buffer */ /* Skip whitespace in the string buffer */
int SB_GetSym (StrBuf* B, char* S); int SB_GetSym (StrBuf* B, StrBuf* Ident, const char* SpecialChars);
/* Get a symbol from the string buffer. S must be able to hold MAX_IDENTLEN /* Get a symbol from the string buffer. If SpecialChars is not NULL, it
* characters. Returns 1 if a symbol was found and 0 otherwise. * points to a string that contains characters allowed within the string in
* addition to letters, digits and the underline. Note: The identifier must
* still begin with a letter.
* Returns 1 if a symbol was found and 0 otherwise but doesn't output any
* errors.
*/ */
int SB_GetString (StrBuf* B, StrBuf* S); int SB_GetString (StrBuf* B, StrBuf* S);
/* Get a string from the string buffer. S will be initialized by the function /* Get a string from the string buffer. Returns 1 if a string was found and 0
* and will return the correctly terminated string on return. The function * otherwise. Errors are only output in case of invalid strings (missing end
* returns 1 if a string was found and 0 otherwise. * of string).
*/ */
int SB_GetNumber (StrBuf* B, long* Val); int SB_GetNumber (StrBuf* B, long* Val);
/* Get a number from the string buffer. Accepted formats are decimal, octal, /* Get a number from the string buffer. Accepted formats are decimal, octal,
* hex and character constants. Numeric constants may be preceeded by a * hex and character constants. Numeric constants may be preceeded by a
* minus or plus sign. The function returns 1 if a number was found and * minus or plus sign. The function returns 1 if a number was found and
* zero otherwise. * zero otherwise. Errors are only output for invalid numbers.
*/ */