diff --git a/doc/cc65.sgml b/doc/cc65.sgml
index a1daf3dea..2226cc26f 100644
--- a/doc/cc65.sgml
+++ b/doc/cc65.sgml
@@ -118,7 +118,7 @@ Here is a description of all the command line options:
Tells the compiler to generate code that checks for stack overflows. See
for an
explanation of this feature.
-
+
--code-name seg
@@ -731,7 +731,7 @@ If the first parameter is #pragma bssseg ([push,]<name>)
+#pragma bssseg ([push,] <name>)
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
@@ -787,7 +787,7 @@ parameter with the
-#pragma checkstack ([push,]on|off)
+#pragma checkstack ([push,] on|off)
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
@@ -800,7 +800,7 @@ parameter with the #pragma codeseg ([push,]<name>)
+#pragma codeseg ([push,] <name>)
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
@@ -818,7 +818,7 @@ parameter with the
-#pragma codesize ([push,]<int>)
+#pragma codesize ([push,] <int>)
This pragma allows finer control about speed vs. size decisions in the code
generation and optimization phase. It gives the allowed size increase factor
@@ -828,7 +828,7 @@ parameter with the #pragma dataseg ([push,]<name>)
+#pragma dataseg ([push,] <name>)
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
@@ -846,7 +846,7 @@ parameter with the
-#pragma optimize ([push,]on|off)
+#pragma optimize ([push,] on|off)
Switch optimization on or off. If the argument is "off", optimization is
disabled, otherwise it is enabled. Please note that this pragma only effects
@@ -862,7 +862,7 @@ parameter with the #pragma rodataseg ([push,]<name>)
+#pragma rodataseg ([push,] <name>)
This pragma changes the name used for the RODATA segment (the RODATA
segment is used to store readonly data). The argument is a string
@@ -880,7 +880,7 @@ parameter with the
-#pragma regvaraddr ([push,]on|off)
+#pragma regvaraddr ([push,] on|off)
The compiler does not allow to take the address of register variables.
The regvaraddr pragma changes this. Taking the address of a register
@@ -904,7 +904,7 @@ parameter with the
-#pragma regvars ([push,]on|off)
+#pragma regvars ([push,] on|off)
Enables or disables use of register variables. If register variables are
disabled (the default), the #pragma signedchars ([push,]on|off)
+#pragma signedchars ([push,] on|off)
Changes the signedness of the default character type. If the argument is
"on", default characters are signed, otherwise characters are unsigned.
@@ -925,7 +925,7 @@ parameter with the #pragma staticlocals ([push,]on|off)
+#pragma staticlocals ([push,] on|off)
Use variables in the bss segment instead of variables on the stack. This
pragma changes the default set by the compiler option #pragma warn ([push,]on|off)
+#pragma warn (name, [push,] on|off)
- Switch compiler warnings on or off. If the argument is "off", warnings are
- disabled, otherwise they're enabled. The default is "on", but may be changed
- with the / compiler option.
-
- The / compiler option for a list). The name is
+ 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
+ changing it.
#pragma zpsym (<name>)
diff --git a/src/cc65/pragma.c b/src/cc65/pragma.c
index 108f86614..47f4da0af 100644
--- a/src/cc65/pragma.c
+++ b/src/cc65/pragma.c
@@ -37,6 +37,7 @@
#include
/* common */
+#include "chartype.h"
#include "segnames.h"
#include "tgttrans.h"
@@ -84,9 +85,9 @@ static const struct Pragma {
const char* Key; /* Keyword */
pragma_t Tok; /* Token */
} Pragmas[PR_COUNT] = {
- { "bssseg", PR_BSSSEG },
+ { "bssseg", PR_BSSSEG },
{ "charmap", PR_CHARMAP },
- { "checkstack", PR_CHECKSTACK },
+ { "checkstack", PR_CHECKSTACK },
{ "codeseg", PR_CODESEG },
{ "codesize", PR_CODESIZE },
{ "dataseg", PR_DATASEG },
@@ -94,16 +95,24 @@ static const struct Pragma {
{ "regvaraddr", PR_REGVARADDR },
{ "regvars", PR_REGVARS },
{ "rodataseg", PR_RODATASEG },
- { "signedchars", PR_SIGNEDCHARS },
- { "staticlocals", PR_STATICLOCALS },
+ { "signedchars", PR_SIGNEDCHARS },
+ { "staticlocals", PR_STATICLOCALS },
{ "warn", PR_WARN },
{ "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
* not a valid pragma.
*/
{
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;
}
+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*))
/* 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)) {
+ if (GetString (B, &S)) {
/* Call the given function with the string argument */
Func (SB_GetConstBuf (&S));
- } else {
- Error ("String literal expected");
}
/* Call the string buf destructor */
@@ -161,67 +355,64 @@ 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;
+ StrBuf S = AUTO_STRBUF_INITIALIZER;
const char* Name;
- /* Try to read an identifier */
+ /* Check for the "push" or "pop" keywords */
int Push = 0;
- if (SB_GetSym (B, Ident)) {
+ switch (ParsePushPop (B)) {
- /* Check if we have a first argument named "pop" */
- if (strcmp (Ident, "pop") == 0) {
+ case PP_NONE:
+ break;
- /* Pop the old value */
+ 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);
/* 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);
+ }
+ g_segname (Seg);
+
+ } else {
+
/* Segment name is invalid */
Error ("Illegal segment name: `%s'", Name);
- return;
+
}
- /* Set the new name */
- if (Push) {
- PushSegName (Seg, Name);
- } else {
- SetSegName (Seg, Name);
- }
- g_segname (Seg);
-
+ExitPoint:
/* Call the string buf destructor */
SB_Done (&S);
}
@@ -234,7 +425,7 @@ 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) {
@@ -248,15 +439,12 @@ static void CharMapPragma (StrBuf* B)
}
/* 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) {
@@ -275,50 +463,52 @@ static void CharMapPragma (StrBuf* B)
-static void FlagPragma (StrBuf* B, IntStack* Stack)
-/* Handle a pragma that expects a boolean paramater */
+static void WarnPragma (StrBuf* B)
+/* Enable/disable warnings */
{
- ident Ident;
- long Val;
- int Push;
+ long Val;
+ int Push;
- /* Try to read an identifier */
- int IsIdent = SB_GetSym (B, Ident);
-
- /* 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 */
+ /* A warning name must follow */
+ IntStack* S =GetWarning (B);
+ if (S == 0) {
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");
+ /* 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;
- }
- SB_SkipWhite (B);
- IsIdent = SB_GetSym (B, Ident);
- } else {
- Push = 0;
+
+ case PP_ERROR:
+ /* Bail out */
+ return;
+
+ default:
+ Internal ("Invalid result from ParsePushPop");
}
/* 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'");
- }
+ 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;
@@ -326,14 +516,60 @@ static void FlagPragma (StrBuf* B, IntStack* Stack)
/* Set/push the new value */
if (Push) {
- if (IS_IsFull (Stack)) {
- Error ("Cannot push: stack overflow");
- } else {
- IS_Push (Stack, Val);
+ PushInt (S, Val);
+ } else {
+ 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 {
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)
/* 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;
}
@@ -387,11 +618,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);
}
@@ -403,7 +630,7 @@ 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;
@@ -421,13 +648,13 @@ static void ParsePragma (void)
/* 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) {
@@ -435,15 +662,15 @@ static void ParsePragma (void)
* 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;
+ 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 */
@@ -501,7 +728,7 @@ static void ParsePragma (void)
break;
case PR_WARN:
- FlagPragma (&B, &WarnEnable);
+ WarnPragma (&B);
break;
case PR_ZPSYM:
@@ -516,7 +743,7 @@ static void ParsePragma (void)
SB_SkipWhite (&B);
if (SB_Get (&B) != ')') {
Error ("')' expected");
- return;
+ goto ExitPoint;
}
SB_SkipWhite (&B);
@@ -531,8 +758,10 @@ static void ParsePragma (void)
Error ("Unexpected input following pragma directive");
}
- /* Release the StrBuf */
+ExitPoint:
+ /* Release the string buffers */
SB_Done (&B);
+ SB_Done (&Ident);
}
diff --git a/src/cc65/scanstrbuf.c b/src/cc65/scanstrbuf.c
index 219377a76..d33f88a25 100644
--- a/src/cc65/scanstrbuf.c
+++ b/src/cc65/scanstrbuf.c
@@ -162,23 +162,31 @@ void SB_SkipWhite (StrBuf* B)
-int SB_GetSym (StrBuf* B, char* S)
-/* Get a symbol from the string buffer. S must be able to hold MAX_IDENTLEN
- * characters. Returns 1 if a symbol was found and 0 otherwise.
+int SB_GetSym (StrBuf* B, StrBuf* Ident, const char* SpecialChars)
+/* Get a symbol from the string buffer. If SpecialChars is not NULL, it
+ * 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))) {
- unsigned I = 0;
char C = SB_Peek (B);
do {
- if (I < MAX_IDENTLEN) {
- ++I;
- *S++ = C;
- }
+ SB_AppendChar (Ident, C);
SB_Skip (B);
C = SB_Peek (B);
- } while (IsIdent (C) || IsDigit (C));
- *S = '\0';
+ } while (IsIdent (C) || IsDigit (C) || strchr (SpecialChars, C) != 0);
+ SB_Terminate (Ident);
return 1;
} else {
return 0;
@@ -188,15 +196,17 @@ int SB_GetSym (StrBuf* B, char* S)
int SB_GetString (StrBuf* B, StrBuf* S)
-/* Get a string from the string buffer. S will be initialized by the function
- * and will return the correctly terminated string on return. The function
- * returns 1 if a string was found and 0 otherwise.
+/* Get a string from the string buffer. Returns 1 if a string was found and 0
+ * otherwise. Errors are only output in case of invalid strings (missing end
+ * of string).
*/
{
char C;
- /* Initialize S */
- SB_Init (S);
+ /* Clear S */
+ SB_Clear (S);
+
+ /* A string starts with quote marks */
if (SB_Peek (B) == '\"') {
/* 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,
* 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
- * zero otherwise.
+ * zero otherwise. Errors are only output for invalid numbers.
*/
{
int Sign;
@@ -249,65 +259,12 @@ int SB_GetNumber (StrBuf* B, long* Val)
unsigned Base;
unsigned DigitVal;
+
/* Initialize Val */
*Val = 0;
- /* Check for a sign */
- Sign = 1;
- switch (SB_Peek (B)) {
- case '-':
- Sign = -1;
- /* FALLTHROUGH */
- case '+':
- SB_Skip (B);
- SB_SkipWhite (B);
- break;
- }
-
- /* Check for the different formats */
- C = SB_Peek (B);
- if (IsDigit (C)) {
-
- if (C == '0') {
- /* Hex or octal */
- SB_Skip (B);
- if (tolower (SB_Peek (B)) == 'x') {
- SB_Skip (B);
- Base = 16;
- if (!IsXDigit (SB_Peek (B))) {
- Error ("Invalid hexadecimal number");
- return 0;
- }
- } else {
- Base = 8;
- }
- } else {
- Base = 10;
- }
-
- /* Read the number */
- while (IsXDigit (C = SB_Peek (B)) && (DigitVal = HexVal (C)) < Base) {
- *Val = (*Val * Base) + DigitVal;
- SB_Skip (B);
- }
-
- /* Allow optional 'U' and 'L' modifiers */
- C = SB_Peek (B);
- if (C == 'u' || C == 'U') {
- SB_Skip (B);
- C = SB_Peek (B);
- if (C == 'l' || C == 'L') {
- SB_Skip (B);
- }
- } else if (C == 'l' || C == 'L') {
- SB_Skip (B);
- C = SB_Peek (B);
- if (C == 'u' || C == 'U') {
- SB_Skip (B);
- }
- }
-
- } else if (C == '\'') {
+ /* Handle character constants */
+ if (SB_Peek (B) == '\'') {
/* Character constant */
SB_Skip (B);
@@ -318,14 +275,70 @@ int SB_GetNumber (StrBuf* B, long* Val)
} else {
/* Skip the quote */
SB_Skip (B);
+ return 1;
}
+ }
- } else {
+ /* Check for a sign. A sign must be followed by a digit, otherwise it's
+ * not a number
+ */
+ Sign = 1;
+ switch (SB_Peek (B)) {
+ case '-':
+ Sign = -1;
+ /* FALLTHROUGH */
+ case '+':
+ if (!IsDigit (SB_LookAt (B, SB_GetIndex (B) + 1))) {
+ return 0;
+ }
+ SB_Skip (B);
+ break;
+ }
- /* Invalid number */
- Error ("Numeric constant expected");
+ /* We must have a digit now, otherwise its not a number */
+ C = SB_Peek (B);
+ if (!IsDigit (C)) {
return 0;
+ }
+ /* Determine the base */
+ if (C == '0') {
+ /* Hex or octal */
+ SB_Skip (B);
+ if (tolower (SB_Peek (B)) == 'x') {
+ SB_Skip (B);
+ Base = 16;
+ if (!IsXDigit (SB_Peek (B))) {
+ Error ("Invalid hexadecimal number");
+ return 0;
+ }
+ } else {
+ Base = 8;
+ }
+ } else {
+ Base = 10;
+ }
+
+ /* Read the number */
+ while (IsXDigit (C = SB_Peek (B)) && (DigitVal = HexVal (C)) < Base) {
+ *Val = (*Val * Base) + DigitVal;
+ SB_Skip (B);
+ }
+
+ /* Allow optional 'U' and 'L' modifiers */
+ C = SB_Peek (B);
+ if (C == 'u' || C == 'U') {
+ SB_Skip (B);
+ C = SB_Peek (B);
+ if (C == 'l' || C == 'L') {
+ SB_Skip (B);
+ }
+ } else if (C == 'l' || C == 'L') {
+ SB_Skip (B);
+ C = SB_Peek (B);
+ if (C == 'u' || C == 'U') {
+ SB_Skip (B);
+ }
}
/* Success, value read is in Val */
diff --git a/src/cc65/scanstrbuf.h b/src/cc65/scanstrbuf.h
index 29002052e..a49a5f035 100644
--- a/src/cc65/scanstrbuf.h
+++ b/src/cc65/scanstrbuf.h
@@ -6,10 +6,10 @@
/* */
/* */
/* */
-/* (C) 2002 Ullrich von Bassewitz */
-/* Wacholderweg 14 */
-/* D-70597 Stuttgart */
-/* EMail: uz@cc65.org */
+/* (C) 2002-2009, Ullrich von Bassewitz */
+/* Roemerstrasse 52 */
+/* D-70794 Filderstadt */
+/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
@@ -52,22 +52,26 @@
void SB_SkipWhite (StrBuf* B);
/* Skip whitespace in the string buffer */
-int SB_GetSym (StrBuf* B, char* S);
-/* Get a symbol from the string buffer. S must be able to hold MAX_IDENTLEN
- * characters. Returns 1 if a symbol was found and 0 otherwise.
+int SB_GetSym (StrBuf* B, StrBuf* Ident, const char* SpecialChars);
+/* Get a symbol from the string buffer. If SpecialChars is not NULL, it
+ * 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);
-/* Get a string from the string buffer. S will be initialized by the function
- * and will return the correctly terminated string on return. The function
- * returns 1 if a string was found and 0 otherwise.
+/* Get a string from the string buffer. Returns 1 if a string was found and 0
+ * otherwise. Errors are only output in case of invalid strings (missing end
+ * of string).
*/
int SB_GetNumber (StrBuf* B, long* Val);
/* 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
- * zero otherwise.
+ * zero otherwise. Errors are only output for invalid numbers.
*/