|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static long long parse_integer(const char *str, size_t len) { |
|
|
|
|
|
long long num = 0; |
|
|
|
|
|
long long power = 1; |
|
|
|
|
|
for (ssize_t i = len - 1; (ssize_t)i >= 0; --i) { |
|
|
|
|
|
char ch = str[i]; |
|
|
|
|
|
num += (ch - '0') * power; |
|
|
|
|
|
power *= 10; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return num; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const char *l2_token_kind_name(enum l2_token_kind kind) { |
|
|
const char *l2_token_kind_name(enum l2_token_kind kind) { |
|
|
switch (kind) { |
|
|
switch (kind) { |
|
|
case L2_TOK_OPEN_PAREN: |
|
|
case L2_TOK_OPEN_PAREN: |
|
|
|
|
|
|
|
|
return nl; |
|
|
return nl; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static long long read_integer(struct l2_lexer *lexer) { |
|
|
|
|
|
char buffer[32]; // Should be enough |
|
|
|
|
|
|
|
|
static int read_integer(struct l2_lexer *lexer, long long *num, long long *base, char **err) { |
|
|
|
|
|
unsigned char buffer[32]; // Should be enough |
|
|
size_t len = 0; |
|
|
size_t len = 0; |
|
|
|
|
|
|
|
|
while (len < sizeof(buffer) && is_numeric(peek_ch(lexer))) { |
|
|
|
|
|
buffer[len++] = read_ch(lexer); |
|
|
|
|
|
|
|
|
long long b = -1; |
|
|
|
|
|
while (len < sizeof(buffer)) { |
|
|
|
|
|
int ch = peek_ch(lexer); |
|
|
|
|
|
if (is_numeric(ch)) { |
|
|
|
|
|
buffer[len++] = ch; |
|
|
|
|
|
} else if (ch != '\'') { |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
read_ch(lexer); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int ch = peek_ch(lexer); |
|
|
|
|
|
int abbrev_prefix = len == 1 && buffer[0] == '0'; |
|
|
|
|
|
if (abbrev_prefix && ch == 'b') { |
|
|
|
|
|
b = 2; |
|
|
|
|
|
} else if (abbrev_prefix && ch == 'o') { |
|
|
|
|
|
b = 8; |
|
|
|
|
|
} else if (abbrev_prefix && ch == 'x') { |
|
|
|
|
|
b = 16; |
|
|
|
|
|
} else { |
|
|
|
|
|
// Need to parse the number as base 10 now |
|
|
|
|
|
long long n = 0; |
|
|
|
|
|
long long pow = 1; |
|
|
|
|
|
for (ssize_t i = len - 1; i >= 0; --i) { |
|
|
|
|
|
n += (buffer[i] - '0') * pow; |
|
|
|
|
|
pow *= 10; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (ch == 'r') { |
|
|
|
|
|
b = n; |
|
|
|
|
|
} else { |
|
|
|
|
|
*num = n; |
|
|
|
|
|
*base = 10; |
|
|
|
|
|
return 0; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (b < 2) { |
|
|
|
|
|
*err = "Number with base lower than 2"; |
|
|
|
|
|
return -1; |
|
|
|
|
|
} else if (b > 36) { |
|
|
|
|
|
*err = "Number with base higher than 36"; |
|
|
|
|
|
return -1; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Now that we know the base, we can read in the next part of the number |
|
|
|
|
|
read_ch(lexer); // Skip the base marker ('x', 'r', etc) |
|
|
|
|
|
len = 0; |
|
|
|
|
|
while (len < sizeof(buffer)) { |
|
|
|
|
|
int ch = peek_ch(lexer); |
|
|
|
|
|
if (ch == '\'') { |
|
|
|
|
|
continue; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int digit; |
|
|
|
|
|
if (ch >= '0' && ch <= '9') { |
|
|
|
|
|
digit = ch - '0'; |
|
|
|
|
|
} else if (ch >= 'a' && ch <= 'z') { |
|
|
|
|
|
digit = ch - 'a' + 10; |
|
|
|
|
|
} else if (ch >= 'A' && ch <= 'Z') { |
|
|
|
|
|
digit = ch - 'A' + 10; |
|
|
|
|
|
} else { |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (digit >= b) { |
|
|
|
|
|
*err = "Number with digit too big for the base"; |
|
|
|
|
|
return -1; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
buffer[len++] = digit; |
|
|
|
|
|
read_ch(lexer); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (len < 1) { |
|
|
|
|
|
*err = "Number with no digits"; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return parse_integer(buffer, len); |
|
|
|
|
|
|
|
|
long long n = 0; |
|
|
|
|
|
long long pow = 1; |
|
|
|
|
|
for (ssize_t i = len - 1; i >= 0; --i) { |
|
|
|
|
|
n += buffer[i] * pow; |
|
|
|
|
|
pow *= b; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
*num = n; |
|
|
|
|
|
*base = b; |
|
|
|
|
|
return 0; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void read_number(struct l2_lexer *lexer, struct l2_token *tok) { |
|
|
static void read_number(struct l2_lexer *lexer, struct l2_token *tok) { |
|
|
|
|
|
|
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
long long integral = read_integer(lexer); |
|
|
|
|
|
|
|
|
long long integral; |
|
|
|
|
|
long long base; |
|
|
|
|
|
char *err; |
|
|
|
|
|
if (read_integer(lexer, &integral, &base, &err) < 0) { |
|
|
|
|
|
tok->kind = L2_TOK_ERROR; |
|
|
|
|
|
tok->v.str = err; |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
if (peek_ch(lexer) != '.') { |
|
|
if (peek_ch(lexer) != '.') { |
|
|
tok->v.num = (double)integral * sign; |
|
|
tok->v.num = (double)integral * sign; |
|
|
return; |
|
|
return; |
|
|
|
|
|
|
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
char buffer[32]; |
|
|
|
|
|
|
|
|
unsigned char buffer[32]; |
|
|
size_t fraction_len = 0; |
|
|
size_t fraction_len = 0; |
|
|
while (fraction_len < sizeof(buffer) && is_numeric(peek_ch(lexer))) { |
|
|
|
|
|
buffer[fraction_len++] = read_ch(lexer); |
|
|
|
|
|
|
|
|
while (fraction_len < sizeof(buffer)) { |
|
|
|
|
|
int ch = peek_ch(lexer); |
|
|
|
|
|
if (ch == '\'') { |
|
|
|
|
|
continue; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int digit; |
|
|
|
|
|
if (ch >= '0' && ch <= '9') { |
|
|
|
|
|
digit = ch - '0'; |
|
|
|
|
|
} else if (ch >= 'a' && ch <= 'z') { |
|
|
|
|
|
digit = ch - 'a' + 10; |
|
|
|
|
|
} else if (ch >= 'A' && ch <= 'Z') { |
|
|
|
|
|
digit = ch - 'A' + 10; |
|
|
|
|
|
} else { |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (digit >= base) { |
|
|
|
|
|
tok->kind = L2_TOK_ERROR; |
|
|
|
|
|
tok->v.str = "Number with digits too big for the base"; |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
buffer[fraction_len++] = digit; |
|
|
|
|
|
read_ch(lexer); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (fraction_len < 1) { |
|
|
|
|
|
tok->kind = L2_TOK_ERROR; |
|
|
|
|
|
tok->v.str = "Fraction with no digits"; |
|
|
|
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
long long fraction = 0; |
|
|
long long fraction = 0; |
|
|
long long fraction_power = 1; |
|
|
long long fraction_power = 1; |
|
|
for (ssize_t i = fraction_len - 1; (ssize_t)i >= 0; --i) { |
|
|
for (ssize_t i = fraction_len - 1; (ssize_t)i >= 0; --i) { |
|
|
fraction += (buffer[i] - '0') * fraction_power; |
|
|
|
|
|
fraction_power *= 10; |
|
|
|
|
|
|
|
|
fraction += buffer[i] * fraction_power; |
|
|
|
|
|
fraction_power *= base; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
double num = (double)integral + ((double)fraction / (double)fraction_power); |
|
|
double num = (double)integral + ((double)fraction / (double)fraction_power); |
|
|
|
|
|
|
|
|
read_ch(lexer); |
|
|
read_ch(lexer); |
|
|
if (is_numeric(peek_ch(lexer))) { |
|
|
if (is_numeric(peek_ch(lexer))) { |
|
|
tok->kind = L2_TOK_DOT_NUMBER; |
|
|
tok->kind = L2_TOK_DOT_NUMBER; |
|
|
tok->v.integer = read_integer(lexer); |
|
|
|
|
|
|
|
|
long long num, base; |
|
|
|
|
|
char *err; |
|
|
|
|
|
if (read_integer(lexer, &num, &base, &err) < 0) { |
|
|
|
|
|
tok->kind = L2_TOK_ERROR; |
|
|
|
|
|
tok->v.str = err; |
|
|
|
|
|
} else { |
|
|
|
|
|
tok->v.integer = (int)num; |
|
|
|
|
|
} |
|
|
} else { |
|
|
} else { |
|
|
tok->kind = L2_TOK_PERIOD; |
|
|
tok->kind = L2_TOK_PERIOD; |
|
|
} |
|
|
} |