From a1fb355a9ab6058b3b353eec4509608d431c7995 Mon Sep 17 00:00:00 2001 From: uz Date: Tue, 13 Oct 2009 21:24:32 +0000 Subject: [PATCH] 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 --- doc/cc65.sgml | 36 ++-- src/cc65/pragma.c | 479 +++++++++++++++++++++++++++++++----------- src/cc65/scanstrbuf.c | 145 +++++++------ src/cc65/scanstrbuf.h | 28 +-- 4 files changed, 467 insertions(+), 221 deletions(-) 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)

- - 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. +#pragma warn (name, [push,] on|off)

- 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 */ - PopSegName (Seg); + case PP_PUSH: + Push = 1; + break; - /* Set the segment name */ + case PP_POP: + /* Pop the old value and output it */ + PopSegName (Seg); 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,65 +463,113 @@ static void CharMapPragma (StrBuf* B) +static void WarnPragma (StrBuf* B) +/* Enable/disable warnings */ +{ + long Val; + int Push; + + /* A warning name must follow */ + IntStack* S =GetWarning (B); + if (S == 0) { + return; + } + + /* 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; + + case PP_ERROR: + /* Bail out */ + return; + + default: + Internal ("Invalid result from ParsePushPop"); + } + + /* Boolean argument follows */ + 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; + } + + /* Set/push the new value */ + if (Push) { + PushInt (S, Val); + } else { + IS_Set (S, Val); + } +} + + + static void FlagPragma (StrBuf* B, IntStack* Stack) /* Handle a pragma that expects a boolean paramater */ { - ident Ident; - long Val; - int Push; + StrBuf Ident = AUTO_STRBUF_INITIALIZER; + long Val; + int Push; + /* Try to read an identifier */ - int IsIdent = SB_GetSym (B, Ident); + int IsIdent = SB_GetSym (B, &Ident, 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); - } + 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 && strcmp (Ident, "push") == 0) { + if (IsIdent && SB_CompareStr (&Ident, "push") == 0) { Push = 1; - SB_SkipWhite (B); - if (SB_Get (B) != ',') { - Error ("Comma expected"); - return; + if (!GetComma (B)) { + goto ExitPoint; } - SB_SkipWhite (B); - IsIdent = SB_GetSym (B, Ident); + IsIdent = SB_GetSym (B, &Ident, 0); } else { Push = 0; } /* 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'"); - } - } else if (!SB_GetNumber (B, &Val)) { - Error ("Invalid pragma argument"); - return; + Val = BoolKeyword (&Ident); + } else if (!GetNumber (B, &Val)) { + goto ExitPoint; } /* 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); } + +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,83 +259,86 @@ int SB_GetNumber (StrBuf* B, long* Val) unsigned Base; unsigned DigitVal; + /* Initialize Val */ *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; switch (SB_Peek (B)) { case '-': Sign = -1; /* FALLTHROUGH */ case '+': + if (!IsDigit (SB_LookAt (B, SB_GetIndex (B) + 1))) { + return 0; + } SB_Skip (B); - SB_SkipWhite (B); break; } - /* Check for the different formats */ + /* We must have a digit now, otherwise its not a number */ C = SB_Peek (B); - if (IsDigit (C)) { + if (!IsDigit (C)) { + return 0; + } - if (C == '0') { - /* Hex or octal */ + /* Determine the base */ + if (C == '0') { + /* Hex or octal */ + SB_Skip (B); + if (tolower (SB_Peek (B)) == 'x') { 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; + Base = 16; + if (!IsXDigit (SB_Peek (B))) { + Error ("Invalid hexadecimal number"); + return 0; } } else { - Base = 10; + 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); - } + /* 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 */ + /* Allow optional 'U' and 'L' modifiers */ + C = SB_Peek (B); + if (C == 'u' || C == 'U') { + SB_Skip (B); C = SB_Peek (B); - if (C == 'u' || C == 'U') { + if (C == 'l' || C == 'L') { 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 == '\'') { - - /* Character constant */ + } else if (C == 'l' || C == 'L') { SB_Skip (B); - *Val = SignExtendChar (TgtTranslateChar (ParseChar (B))); - if (SB_Peek (B) != '\'') { - Error ("`\'' expected"); - return 0; - } else { - /* Skip the quote */ + C = SB_Peek (B); + if (C == 'u' || C == 'U') { SB_Skip (B); } - - } else { - - /* Invalid number */ - Error ("Numeric constant expected"); - return 0; - } /* 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. */ -- 2.39.2