|
@@ -47,7 +47,8 @@
|
|
|
#define STB_C_LEX_C_DECIMAL_INTS Y // "0|[1-9][0-9]*" CLEX_intlit
|
|
|
#define STB_C_LEX_C_HEX_INTS Y // "0x[0-9a-fA-F]+" CLEX_intlit
|
|
|
#define STB_C_LEX_C_OCTAL_INTS Y // "[0-7]+" CLEX_intlit
|
|
|
-#define STB_C_LEX_C_DECIMAL_FLOATS Y // "[0-9]*(.[0-9]*([eE]-?[0-9]+)?) CLEX_floatlit
|
|
|
+#define STB_C_LEX_C_DECIMAL_FLOATS Y // "[0-9]*(.[0-9]*([eE][-+]?[0-9]+)?) CLEX_floatlit
|
|
|
+#define STB_C_LEX_C99_HEX_FLOATS N // "0x{hex}+(.{hex}*)?[pP][-+]?{hex}+ CLEX_floatlit
|
|
|
#define STB_C_LEX_C_IDENTIFIERS Y // "[_a-zA-Z][_a-zA-Z0-9]*" CLEX_id
|
|
|
#define STB_C_LEX_C_DQ_STRINGS Y // double-quote-delimited strings with escapes CLEX_dqstring
|
|
|
#define STB_C_LEX_C_SQ_STRINGS N // single-quote-delimited strings with escapes CLEX_ssstring
|
|
@@ -173,11 +174,6 @@ extern void stb_c_lexer_get_location(const stb_lexer *lexer, const char *where,
|
|
|
#define Y(x) 1
|
|
|
#define N(x) 0
|
|
|
|
|
|
-#if STB_C_LEX_USE_STDLIB(x)
|
|
|
-#define STB__CLEX_use_stdlib
|
|
|
-#include <stdlib.h>
|
|
|
-#endif
|
|
|
-
|
|
|
#if STB_C_LEX_INTEGERS_AS_DOUBLES(x)
|
|
|
typedef double stb__clex_int;
|
|
|
#define intfield real_number
|
|
@@ -202,6 +198,10 @@ typedef long stb__clex_int;
|
|
|
#define STB__clex_define_shifts
|
|
|
#endif
|
|
|
|
|
|
+#if STB_C_LEX_C99_HEX_FLOATS(x)
|
|
|
+#define STB__clex_hex_floats
|
|
|
+#endif
|
|
|
+
|
|
|
#if STB_C_LEX_C_HEX_INTS(x)
|
|
|
#define STB__clex_hex_ints
|
|
|
#endif
|
|
@@ -222,6 +222,11 @@ typedef long stb__clex_int;
|
|
|
#define STB__clex_discard_preprocessor
|
|
|
#endif
|
|
|
|
|
|
+#if STB_C_LEX_USE_STDLIB(x) && (!defined(STB__clex_hex_floats) || __STDC_VERSION__ >= 199901L)
|
|
|
+#define STB__CLEX_use_stdlib
|
|
|
+#include <stdlib.h>
|
|
|
+#endif
|
|
|
+
|
|
|
// Now pick a definition of Y/N that's conducive to
|
|
|
// defining the enum of token names.
|
|
|
#if STB_C_LEX_DEFINE_ALL_TOKEN_NAMES(x) || defined(STB_C_LEXER_SELF_TEST)
|
|
@@ -366,34 +371,95 @@ static int stb__clex_parse_suffixes(stb_lexer *lexer, long tokenid, char *start,
|
|
|
}
|
|
|
|
|
|
#ifndef STB__CLEX_use_stdlib
|
|
|
+static double stb__clex_pow(double base, unsigned int exponent)
|
|
|
+{
|
|
|
+ double value=1;
|
|
|
+ for ( ; exponent; exponent >>= 1) {
|
|
|
+ if (exponent & 1)
|
|
|
+ value *= base;
|
|
|
+ base *= base;
|
|
|
+ }
|
|
|
+ return value;
|
|
|
+}
|
|
|
+
|
|
|
static double stb__clex_parse_float(char *p, char **q)
|
|
|
{
|
|
|
+ char *s = p;
|
|
|
double value=0;
|
|
|
- while (*p >= '0' && *p <= '9')
|
|
|
- value = value*10 + (*p++ - '0');
|
|
|
+ int base=10;
|
|
|
+ int exponent=0;
|
|
|
+
|
|
|
+#ifdef STB__clex_hex_floats
|
|
|
+ if (*p == '0') {
|
|
|
+ if (p[1] == 'x' || p[1] == 'X') {
|
|
|
+ base=16;
|
|
|
+ p += 2;
|
|
|
+ }
|
|
|
+ }
|
|
|
+#endif
|
|
|
+
|
|
|
+ for (;;) {
|
|
|
+ if (*p >= '0' && *p <= '9')
|
|
|
+ value = value*base + (*p++ - '0');
|
|
|
+#ifdef STB__clex_hex_floats
|
|
|
+ else if (base == 16 && *p >= 'a' && *p <= 'f')
|
|
|
+ value = value*base + 10 + (*p++ - 'a');
|
|
|
+ else if (base == 16 && *p >= 'A' && *p <= 'F')
|
|
|
+ value = value*base + 10 + (*p++ - 'A');
|
|
|
+#endif
|
|
|
+ else
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
if (*p == '.') {
|
|
|
- double powten=1, addend = 0;
|
|
|
+ double pow, addend = 0;
|
|
|
++p;
|
|
|
- while (*p >= '0' && *p <= '9') {
|
|
|
- addend = addend + 10*(*p++ - '0');
|
|
|
- powten *= 10;
|
|
|
+ for (pow=1; ; pow*=base) {
|
|
|
+ if (*p >= '0' && *p <= '9')
|
|
|
+ addend = addend*base + (*p++ - '0');
|
|
|
+#ifdef STB__clex_hex_floats
|
|
|
+ else if (base == 16 && *p >= 'a' && *p <= 'f')
|
|
|
+ addend = addend*base + 10 + (*p++ - 'a');
|
|
|
+ else if (base == 16 && *p >= 'A' && *p <= 'F')
|
|
|
+ addend = addend*base + 10 + (*p++ - 'A');
|
|
|
+#endif
|
|
|
+ else
|
|
|
+ break;
|
|
|
}
|
|
|
- value += addend / powten;
|
|
|
+ value += addend / pow;
|
|
|
}
|
|
|
- if (*p == 'e' || *p == 'E') {
|
|
|
+#ifdef STB__clex_hex_floats
|
|
|
+ if (base == 16) {
|
|
|
+ // exponent required for hex float literal
|
|
|
+ if (*p != 'p' && *p != 'P') {
|
|
|
+ *q = s;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ exponent = 1;
|
|
|
+ } else
|
|
|
+#endif
|
|
|
+ exponent = (*p == 'e' || *p == 'E');
|
|
|
+
|
|
|
+ if (exponent) {
|
|
|
int sign = p[1] == '-';
|
|
|
- int exponent=0;
|
|
|
- double pow10=1;
|
|
|
- p += 1+sign;
|
|
|
+ unsigned int exponent=0;
|
|
|
+ double power=1;
|
|
|
+ ++p;
|
|
|
+ if (*p == '-' || *p == '+')
|
|
|
+ ++p;
|
|
|
while (*p >= '0' && *p <= '9')
|
|
|
exponent = exponent*10 + (*p++ - '0');
|
|
|
- // can't use pow() from stdlib, so do it slow way
|
|
|
- while (exponent-- > 0)
|
|
|
- pow10 *= 10;
|
|
|
+
|
|
|
+#ifdef STB__clex_hex_floats
|
|
|
+ if (base == 16)
|
|
|
+ power = stb__clex_pow(2, exponent);
|
|
|
+ else
|
|
|
+#endif
|
|
|
+ power = stb__clex_pow(10, exponent);
|
|
|
if (sign)
|
|
|
- value /= pow10;
|
|
|
+ value /= power;
|
|
|
else
|
|
|
- value *= pow10;
|
|
|
+ value *= power;
|
|
|
}
|
|
|
*q = p;
|
|
|
return value;
|
|
@@ -632,15 +698,37 @@ int stb_c_lexer_get_token(stb_lexer *lexer)
|
|
|
goto single_char;
|
|
|
|
|
|
case '0':
|
|
|
- #ifdef STB__clex_hex_ints
|
|
|
+ #if defined(STB__clex_hex_ints) || defined(STB__clex_hex_floats)
|
|
|
if (p+1 != lexer->eof) {
|
|
|
if (p[1] == 'x' || p[1] == 'X') {
|
|
|
- char *q = p+2;
|
|
|
+ char *q;
|
|
|
+
|
|
|
+ #ifdef STB__clex_hex_floats
|
|
|
+ for (q=p+2;
|
|
|
+ q != lexer->eof && ((*q >= '0' && *q <= '9') || (*q >= 'a' && *q <= 'f') || (*q >= 'A' && *q <= 'F'));
|
|
|
+ ++q);
|
|
|
+ if (q != lexer->eof) {
|
|
|
+ if (*q == '.' STB_C_LEX_FLOAT_NO_DECIMAL(|| *q == 'p' || *q == 'P')) {
|
|
|
+ #ifdef STB__CLEX_use_stdlib
|
|
|
+ lexer->real_number = strtod((char *) p, (char**) &q);
|
|
|
+ #else
|
|
|
+ lexer->real_number = stb__clex_parse_float(p, &q);
|
|
|
+ #endif
|
|
|
+
|
|
|
+ if (p == q)
|
|
|
+ return stb__clex_token(lexer, CLEX_parse_error, p,q);
|
|
|
+ return stb__clex_parse_suffixes(lexer, CLEX_floatlit, p,q, STB_C_LEX_FLOAT_SUFFIXES);
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+ #endif // STB__CLEX_hex_floats
|
|
|
+
|
|
|
+ #ifdef STB__clex_hex_ints
|
|
|
#ifdef STB__CLEX_use_stdlib
|
|
|
lexer->int_number = strtol((char *) p, (char **) &q, 16);
|
|
|
#else
|
|
|
stb__clex_int n=0;
|
|
|
- while (q != lexer->eof) {
|
|
|
+ for (q=p+2; q != lexer->eof; ++q) {
|
|
|
if (*q >= '0' && *q <= '9')
|
|
|
n = n*16 + (*q - '0');
|
|
|
else if (*q >= 'a' && *q <= 'f')
|
|
@@ -649,16 +737,16 @@ int stb_c_lexer_get_token(stb_lexer *lexer)
|
|
|
n = n*16 + (*q - 'A') + 10;
|
|
|
else
|
|
|
break;
|
|
|
- ++q;
|
|
|
}
|
|
|
- lexer->int_field = n; // int_field is macro that expands to real_number/int_number depending on type of n
|
|
|
+ lexer->int_number = n;
|
|
|
#endif
|
|
|
if (q == p+2)
|
|
|
return stb__clex_token(lexer, CLEX_parse_error, p-2,p-1);
|
|
|
return stb__clex_parse_suffixes(lexer, CLEX_intlit, p,q, STB_C_LEX_HEX_SUFFIXES);
|
|
|
+ #endif
|
|
|
}
|
|
|
}
|
|
|
- #endif // STB__clex_hex_ints
|
|
|
+ #endif // defined(STB__clex_hex_ints) || defined(STB__clex_hex_floats)
|
|
|
// can't test for octal because we might parse '0.0' as float or as '0' '.' '0',
|
|
|
// so have to do float first
|
|
|
|
|
@@ -694,14 +782,14 @@ int stb_c_lexer_get_token(stb_lexer *lexer)
|
|
|
stb__clex_int n=0;
|
|
|
while (q != lexer->eof) {
|
|
|
if (*q >= '0' && *q <= '7')
|
|
|
- n = n*8 + (q - '0');
|
|
|
+ n = n*8 + (*q - '0');
|
|
|
else
|
|
|
break;
|
|
|
++q;
|
|
|
}
|
|
|
if (q != lexer->eof && (*q == '8' || *q=='9'))
|
|
|
- return stb__clex_token(tok, CLEX_parse_error, p, q);
|
|
|
- lexer->int_field = n;
|
|
|
+ return stb__clex_token(lexer, CLEX_parse_error, p, q);
|
|
|
+ lexer->int_number = n;
|
|
|
#endif
|
|
|
return stb__clex_parse_suffixes(lexer, CLEX_intlit, p,q, STB_C_LEX_OCTAL_SUFFIXES);
|
|
|
}
|
|
@@ -716,12 +804,12 @@ int stb_c_lexer_get_token(stb_lexer *lexer)
|
|
|
stb__clex_int n=0;
|
|
|
while (q != lexer->eof) {
|
|
|
if (*q >= '0' && *q <= '9')
|
|
|
- n = n*10 + (q - '0');
|
|
|
+ n = n*10 + (*q - '0');
|
|
|
else
|
|
|
break;
|
|
|
++q;
|
|
|
}
|
|
|
- lexer->int_field = n;
|
|
|
+ lexer->int_number = n;
|
|
|
#endif
|
|
|
return stb__clex_parse_suffixes(lexer, CLEX_intlit, p,q, STB_C_LEX_OCTAL_SUFFIXES);
|
|
|
}
|
|
@@ -734,6 +822,7 @@ int stb_c_lexer_get_token(stb_lexer *lexer)
|
|
|
#ifdef STB_C_LEXER_SELF_TEST
|
|
|
|
|
|
#include <stdio.h>
|
|
|
+#include <stdlib.h>
|
|
|
|
|
|
static void print_token(stb_lexer *lexer)
|
|
|
{
|
|
@@ -789,7 +878,15 @@ multiline comments */
|
|
|
|
|
|
void dummy(void)
|
|
|
{
|
|
|
- printf("test",1); // https://github.com/nothings/stb/issues/13
|
|
|
+ double some_floats[] = {
|
|
|
+ 1.0501, -10.4e12, 5E+10,
|
|
|
+#ifdef STB__clex_hex_floats
|
|
|
+ 0x1.0p+24, 0xff.FP-8, 0x1p-23,
|
|
|
+#endif
|
|
|
+ 4.
|
|
|
+ };
|
|
|
+
|
|
|
+ printf("test %d",1); // https://github.com/nothings/stb/issues/13
|
|
|
}
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
@@ -806,7 +903,7 @@ int main(int argc, char **argv)
|
|
|
}
|
|
|
fclose(f);
|
|
|
|
|
|
- stb_c_lexer_init(&lex, text, text+len, (char *) malloc(1<<16), 1<<16);
|
|
|
+ stb_c_lexer_init(&lex, text, text+len, (char *) malloc(0x10000), 0x10000);
|
|
|
while (stb_c_lexer_get_token(&lex)) {
|
|
|
if (lex.token == CLEX_parse_error) {
|
|
|
printf("\n<<<PARSE ERROR>>>\n");
|