summaryrefslogtreecommitdiff
path: root/pit/src/lexer.c
diff options
context:
space:
mode:
authorLLLL Colonq <llll@colonq>2026-07-09 23:51:55 -0400
committerLLLL Colonq <llll@colonq>2026-07-09 23:51:55 -0400
commit2bdcaf319b1d74ffbaccf08a58336f804761beab (patch)
treec21de6df74ec79b5574ad2b89fcc275d10847802 /pit/src/lexer.c
Refactor into monorepo
Diffstat (limited to 'pit/src/lexer.c')
-rw-r--r--pit/src/lexer.c139
1 files changed, 139 insertions, 0 deletions
diff --git a/pit/src/lexer.c b/pit/src/lexer.c
new file mode 100644
index 0000000..a2b0c7d
--- /dev/null
+++ b/pit/src/lexer.c
@@ -0,0 +1,139 @@
+#include <lcq/pit/utils.h>
+#include <lcq/pit/lexer.h>
+
+const char *PIT_LEX_TOKEN_NAMES[PIT_LEX_TOKEN__SENTINEL] = {
+ /* [PIT_LEX_TOKEN_EOF] = */ "eof",
+ /* [PIT_LEX_TOKEN_LPAREN] = */ "lparen",
+ /* [PIT_LEX_TOKEN_RPAREN] = */ "rparen",
+ /* [PIT_LEX_TOKEN_LSQUARE] = */ "lsquare",
+ /* [PIT_LEX_TOKEN_RSQUARE] = */ "rsquare",
+ /* [PIT_LEX_TOKEN_DOT] = */ "dot",
+ /* [PIT_LEX_TOKEN_QUOTE] = */ "quote",
+ /* [PIT_LEX_TOKEN_INTEGER_LITERAL] = */ "integer_literal",
+ /* [PIT_LEX_TOKEN_STRING_LITERAL] = */ "string_literal",
+ /* [PIT_LEX_TOKEN_SYMBOL] = */ "symbol",
+};
+
+const char *pit_lex_token_name(pit_lex_token t) {
+ return PIT_LEX_TOKEN_NAMES[t];
+}
+
+static bool is_more_input(pit_lexer *st) {
+ return st && st->end < st->len;
+}
+
+static int is_symchar(int c) {
+ return c != '(' && c != ')' && c != '[' && c != ']' && c != '.' && c != '\'' && c != '"'
+ && pit_libc_ctype_isprint(c)
+ && !pit_libc_ctype_isspace(c);
+}
+
+static int is_hexdigit(int c) {
+ return pit_libc_ctype_isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
+}
+
+static char peek(pit_lexer *st) {
+ if (is_more_input(st)) return st->input[st->end];
+ else return 0;
+}
+
+static char advance(pit_lexer *st) {
+ if (is_more_input(st)) {
+ char ret = st->input[st->end++];
+ if (ret == '\n') {
+ st->line += 1;
+ st->column = 0;
+ } else {
+ st->column += 1;
+ }
+ return ret;
+ }
+ else return 0;
+}
+
+static bool match(pit_lexer *st, int (*f)(int)) {
+ if (f(peek(st))) {
+ advance(st);
+ return true;
+ } else return false;
+}
+
+void pit_lex_bytes(pit_lexer *ret, char *buf, i64 len) {
+ ret->len = len;
+ ret->input = buf;
+ ret->start = 0;
+ ret->end = 0;
+ ret->line = ret->start_line = 1;
+ ret->column = ret->start_column = 0;
+ ret->error = NULL;
+}
+
+pit_lex_token pit_lex_next(pit_lexer *st) {
+restart:
+ st->start = st->end;
+ st->start_line = st->line;
+ st->start_column = st->column;
+ char c = advance(st);
+ switch (c) {
+ case 0: return PIT_LEX_TOKEN_EOF;
+ case ';': while (is_more_input(st) && advance(st) != '\n'); goto restart;
+ case '(': return PIT_LEX_TOKEN_LPAREN;
+ case ')': return PIT_LEX_TOKEN_RPAREN;
+ case '[': return PIT_LEX_TOKEN_LSQUARE;
+ case ']': return PIT_LEX_TOKEN_RSQUARE;
+ case '.': return PIT_LEX_TOKEN_DOT;
+ case '\'': return PIT_LEX_TOKEN_QUOTE;
+ case '"':
+ while (peek(st) != '"') {
+ if (peek(st) == '\\') advance(st); /* skip escaped characters */
+ if (!advance(st)) {
+ st->error = "unterminated string";
+ return PIT_LEX_TOKEN_ERROR;
+ }
+ }
+ advance(st);
+ return PIT_LEX_TOKEN_STRING_LITERAL;
+ default: {
+ if (pit_libc_ctype_isspace(c)) goto restart;
+ pit_lex_token ret = PIT_LEX_TOKEN_INTEGER_LITERAL;
+ int num_idx = 0;
+ bool hex = false;
+ bool leading_dash = false;
+ bool zero_prefix = false;
+ if (!is_symchar(c)) {
+ st->error = "unknown character";
+ return PIT_LEX_TOKEN_ERROR;
+ } else {
+ 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) {
+ if (c == 'x') { hex = true; continue; }
+ else if (c == 'o' || c == 'b') continue;
+ }
+ break;
+ }
+ if (!(pit_libc_ctype_isdigit(c) || (hex && 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;
+ }
+ }
+}
+
+void pit_lex_cstr(pit_lexer *ret, char *buf) {
+ ret->input = buf;
+ ret->len = (i64) pit_libc_string_strlen(buf);
+ ret->start = 0;
+ ret->end = 0;
+ ret->line = ret->start_line = 1;
+ ret->column = ret->start_column = 0;
+ ret->error = NULL;
+}