+static int
+read_num (const char *p, reader_stack *st)
+{
+ int i = 0;
+ // Use an unsigned intermediate to simplify overflow checks.
+ uint64_t x = 0;
+ // Disallow "number" composed of ancillary number components only.
+ bool gotdigits = false;
+ // Skip for now, later we'll check again to potentially negate.
+ if (p[0] == '-')
+ i++;
+ // TODO: asterisk-deliminated *octal*
+ // TODO: other bases?
+ for (; p[i]; i++)
+ {
+ if (p[i] >= '0' && p[i] <= '9')
+ {
+ if (x * 10 + (p[i] - '0') < x)
+ goto read_float;
+ x = x * 10 + (p[i] - '0');
+ gotdigits = true;
+ continue;
+ }
+
+ // TODO: decimal points, exponent notation
+ // NB. a terminal decimal denotes a FIX
+ // NB. exponent notation doesn't necessarily indicate a float
+
+ // TODO: distinguish 'delimiter' characters that terminate
+ // number from 'identifier' chars that cause parsing to fail
+ // (and potentially be parsed as an atom)
+ break;
+ }
+ if (!gotdigits)
+ return 0;
+ if (p[0] != '-')
+ {
+ if (x <= INT32_MAX)
+ (--(st->pos))->fix32 = new_fix32 ((int32_t)x);
+ else if (x <= INT64_MAX)
+ (--(st->pos))->fix64 = new_fix64 (x);
+ else
+ goto read_float;
+ }
+ else
+ {
+ if (-x >= (uint64_t)INT32_MIN)
+ (--(st->pos))->fix32 = new_fix32 (0 - (int32_t)x);
+ else if (-x >= (uint64_t)INT64_MIN)
+ (--(st->pos))->fix64 = new_fix64 (0 - (int64_t)x);
+ else
+ goto read_float;
+ }
+ st->framelen++;
+ return i;
+ read_float:
+ assert(0 && "unimplemented: promote num to float");
+ return i;
+}
+