/* common */
#include "chartype.h"
+#include "tgttrans.h"
/* cc65 */
+#include "datatype.h"
#include "error.h"
#include "hexval.h"
#include "ident.h"
-static char ParseChar (StrBuf* B)
+static int ParseChar (StrBuf* B)
/* Parse a character. Converts \n into EOL, etc. */
{
- unsigned I;
+ unsigned I;
+ unsigned Val;
int C;
/* Check for escape chars */
if ((C = SB_Get (B)) == '\\') {
- switch (SB_Get (B)) {
+ switch (SB_Peek (B)) {
+ case '?':
+ C = '?';
+ SB_Skip (B);
+ break;
+ case 'a':
+ C = '\a';
+ SB_Skip (B);
+ break;
case 'b':
C = '\b';
+ SB_Skip (B);
break;
case 'f':
C = '\f';
+ SB_Skip (B);
break;
case 'r':
C = '\r';
+ SB_Skip (B);
break;
case 'n':
C = '\n';
+ SB_Skip (B);
break;
case 't':
C = '\t';
+ SB_Skip (B);
+ break;
+ case 'v':
+ C = '\v';
+ SB_Skip (B);
break;
case '\"':
C = '\"';
+ SB_Skip (B);
break;
case '\'':
C = '\'';
+ SB_Skip (B);
break;
case '\\':
C = '\\';
+ SB_Skip (B);
break;
case 'x':
case 'X':
/* Hex character constant */
+ SB_Skip (B);
C = HexVal (SB_Get (B)) << 4;
C |= HexVal (SB_Get (B));
- break;
+ break;
case '0':
- /* Octal constant */
- C = 0;
- goto Octal;
case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
/* Octal constant */
- C = 1;
-Octal: I = 0;
- while (SB_Peek (B) >= '0' && SB_Peek (B) <= '7' && I++ < 4) {
- C = (C << 3) | (SB_Get (B) - '0');
- }
+ I = 0;
+ Val = SB_Get (B) - '0';
+ while (SB_Peek (B) >= '0' && SB_Peek (B) <= '7' && ++I <= 3) {
+ Val = (Val << 3) | (SB_Get (B) - '0');
+ }
+ C = (int) Val;
+ if (Val > 256) {
+ Error ("Character constant out of range");
+ C = ' ';
+ }
break;
default:
- Error ("Illegal character constant");
- C = ' ';
- break;
+ Error ("Illegal character constant 0x%02X", SB_Get (B));
+ C = ' ';
+ break;
}
}
-
-
-
-
/*****************************************************************************/
-/* Code */
+/* Code */
/*****************************************************************************/
+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.
+ */
+{
+ int Sign;
+ char C;
+ 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 == '\'') {
+
+ /* 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 */
+ *Val *= Sign;
+ return 1;
+}
+
+
+