Tells the compiler to generate code that checks for stack overflows. See
<tt><ref id="pragma-checkstack" name="#pragma checkstack"></tt> for an
explanation of this feature.
-
+
<tag><tt>--code-name seg</tt></tag>
before changing it. The value may later be restored by using the <tt/pop/
parameter with the <tt/#pragma/.
-<sect1><tt>#pragma bssseg ([push,]<name>)</tt><p>
+<sect1><tt>#pragma bssseg ([push,] <name>)</tt><p>
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
</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
stack overflows. The stack checking code will lead to somewhat larger and
The <tt/#pragma/ understands the push and pop parameters as explained above.
-<sect1><tt>#pragma codeseg ([push,]<name>)</tt><p>
+<sect1><tt>#pragma codeseg ([push,] <name>)</tt><p>
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
</verb></tscreen>
-<sect1><tt>#pragma codesize ([push,]<int>)</tt><label id="pragma-codesize"><p>
+<sect1><tt>#pragma codesize ([push,] <int>)</tt><label id="pragma-codesize"><p>
This pragma allows finer control about speed vs. size decisions in the code
generation and optimization phase. It gives the allowed size increase factor
The <tt/#pragma/ understands the push and pop parameters as explained above.
-<sect1><tt>#pragma dataseg ([push,]<name>)</tt><p>
+<sect1><tt>#pragma dataseg ([push,] <name>)</tt><p>
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
</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
disabled, otherwise it is enabled. Please note that this pragma only effects
The <tt/#pragma/ understands the push and pop parameters as explained above.
-<sect1><tt>#pragma rodataseg ([push,]<name>)</tt><p>
+<sect1><tt>#pragma rodataseg ([push,] <name>)</tt><p>
This pragma changes the name used for the RODATA segment (the RODATA
segment is used to store readonly data). The argument is a string
</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 regvaraddr pragma changes this. Taking the address of a register
</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
disabled (the default), the <tt/register/ keyword is ignored. Register
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
"on", default characters are signed, otherwise characters are unsigned.
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
pragma changes the default set by the compiler option <tt/-Cl/. If the
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>
-
- 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 <tt/<ref name="-W" id="option-W">/ compiler option.
+<sect1><tt>#pragma warn (name, [push,] on|off)</tt><label id="pragma-warn"><p>
- The <tt/#pragma/ understands the push and pop parameters as explained above.
+ Switch compiler warnings on or off. "name" is the name of a warning (see the
+ <tt/<ref name="-W" id="option-W">/ 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.
<sect1><tt>#pragma zpsym (<name>)</tt><p>
#include <string.h>
/* common */
+#include "chartype.h"
#include "segnames.h"
#include "tgttrans.h"
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 },
{ "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 */
/*****************************************************************************/
-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 */
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);
}
long Index, C;
/* Read the character index */
- if (!SB_GetNumber (B, &Index)) {
+ if (!GetNumber (B, &Index)) {
return;
}
if (Index < 1 || Index > 255) {
}
/* 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) {
+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);
}
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;
}
/* 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);
}
/* 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;
/* 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) {
* 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 */
break;
case PR_WARN:
- FlagPragma (&B, &WarnEnable);
+ WarnPragma (&B);
break;
case PR_ZPSYM:
SB_SkipWhite (&B);
if (SB_Get (&B) != ')') {
Error ("')' expected");
- return;
+ goto ExitPoint;
}
SB_SkipWhite (&B);
Error ("Unexpected input following pragma directive");
}
- /* Release the StrBuf */
+ExitPoint:
+ /* Release the string buffers */
SB_Done (&B);
+ SB_Done (&Ident);
}
-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;
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 */
/* 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;
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 */