diff options
| author | LLLL Colonq <llll@colonq> | 2026-06-05 20:32:17 -0400 |
|---|---|---|
| committer | LLLL Colonq <llll@colonq> | 2026-06-05 20:32:17 -0400 |
| commit | b456aa44a172171d4b6120ec566c1499ec25a690 (patch) | |
| tree | 7a835e42351ffd39e5620f5d8e705ef8c69d838e /src | |
| parent | 48ab2cb8e3de88dbd0722337bd4617ad22de1a12 (diff) | |
Fix integer parsing
Diffstat (limited to 'src')
| -rw-r--r-- | src/lexer.c | 37 | ||||
| -rw-r--r-- | src/parser.c | 11 | ||||
| -rw-r--r-- | src/utils.c | 1 |
3 files changed, 37 insertions, 12 deletions
diff --git a/src/lexer.c b/src/lexer.c index adfe8d3..5d9c5e7 100644 --- a/src/lexer.c +++ b/src/lexer.c @@ -1,6 +1,7 @@ #include <lcq/pit/utils.h> #include <lcq/pit/lexer.h> #include <lcq/pit/types.h> +#include <stdio.h> const char *PIT_LEX_TOKEN_NAMES[PIT_LEX_TOKEN__SENTINEL] = { /* [PIT_LEX_TOKEN_EOF] = */ "eof", @@ -92,20 +93,34 @@ restart: } advance(st); return PIT_LEX_TOKEN_STRING_LITERAL; - default: + default: { if (pit_ctype_isspace(c)) goto restart; - if (pit_ctype_isdigit(c)) { - if (c == '0') { - int next = peek(st); - if (next != 'x' && next != 'o' && next != 'b') return PIT_LEX_TOKEN_INTEGER_LITERAL; - advance(st); /* skip base specifier */ - } - while (match(st, is_hexdigit)) {} - return PIT_LEX_TOKEN_INTEGER_LITERAL; + pit_lex_token ret = PIT_LEX_TOKEN_INTEGER_LITERAL; + int num_idx = 0; + bool leading_dash = false; + bool zero_prefix = false; + if (!is_symchar(c)) { + st->error = "unknown character"; + return PIT_LEX_TOKEN_ERROR; } else { - while (match(st, is_symchar)) {} - return PIT_LEX_TOKEN_SYMBOL; + do { + leading_dash = false; + switch (num_idx) { + case 0: + if (c == '0') zero_prefix = true; + else if (c == '-') { leading_dash = true; continue; } + break; + case 1: + if (zero_prefix && (c == 'x' || c == 'o' || c == 'b')) continue; + break; + } + if (!is_hexdigit(c)) ret = PIT_LEX_TOKEN_SYMBOL; + ++num_idx; + } while (c = peek(st), match(st, is_symchar)); } + if (leading_dash) return PIT_LEX_TOKEN_SYMBOL; + return ret; + } } } diff --git a/src/parser.c b/src/parser.c index 5dc57db..77b4172 100644 --- a/src/parser.c +++ b/src/parser.c @@ -129,7 +129,16 @@ pit_value pit_parse(pit_runtime *rt, pit_parser *st, bool *eof) { i64 idx = st->cur.start; i64 base = 10; i64 total = 0; + bool neg = false; char c = st->lexer->input[idx++]; + if (c == '-') { + neg = true; + if (idx < st->cur.end) { + c = st->lexer->input[idx++]; + } else { + pit_error(rt, "malformed negative integer literal"); return PIT_NIL; + } + } if (c == '0' && idx + 1 < st->cur.end) { switch (st->lexer->input[idx++]) { case 'b': base = 2; break; @@ -145,7 +154,7 @@ pit_value pit_parse(pit_runtime *rt, pit_parser *st, bool *eof) { pit_error(rt, "integer literal too large"); return PIT_NIL; } } - return pit_integer_new(rt, total); + return pit_integer_new(rt, neg ? -total : total); } case PIT_LEX_TOKEN_STRING_LITERAL: { char buf[256] = {0}; diff --git a/src/utils.c b/src/utils.c index 7f2831b..53a9ebf 100644 --- a/src/utils.c +++ b/src/utils.c @@ -45,6 +45,7 @@ int pit_string_vsnprintf(char *buf, size_t len, char *format, va_list ap) { if (length_mod == 'l') arg = va_arg(ap, long); else arg = va_arg(ap, int); if (arg == 0) { WRITE('0') } else { + if (arg < 0) { WRITE('-'); arg = -arg; } while (arg != 0) { WRITE_SCRATCH('0' + (char) (arg % 10)); arg /= 10; } while (sidx > 0) { WRITE(scratch[sidx - 1]); sidx -= 1; } } |
