From 9d47486aac9cd1a4422b78ee273b7a27bf7b733a Mon Sep 17 00:00:00 2001 From: hachem Date: Tue, 8 Sep 2026 12:00:49 +0200 Subject: refactor: flatten src and migrate to meson --- src/lexer.c | 311 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 311 insertions(+) create mode 100644 src/lexer.c (limited to 'src/lexer.c') diff --git a/src/lexer.c b/src/lexer.c new file mode 100644 index 0000000..0d26f9a --- /dev/null +++ b/src/lexer.c @@ -0,0 +1,311 @@ +#include +#include + +#include "lexer.h" + +static bool is_alpha(char character) +{ + return (character >= 'a' && character <= 'z') || + (character >= 'A' && character <= 'Z') || + character == '_'; +} + +static bool is_digit(char character) +{ + return character >= '0' && character <= '9'; +} + +static bool is_hex_digit(char character) +{ + return is_digit(character) + || (character >= 'a' && character <= 'f') + || (character >= 'A' && character <= 'F'); +} + +static enum TokenType identifier_type(const char* start, size_t length) +{ + static const struct Keyword + { + const char* text; + size_t length; + enum TokenType type; + } keywords[] = + { + { "const", 5, TOKEN_CONST }, + { "data", 4, TOKEN_DATA }, + { "proc", 4, TOKEN_PROC }, + { "enum", 4, TOKEN_ENUM }, + { "struct", 6, TOKEN_STRUCT }, + { "stack", 5, TOKEN_STACK }, + { "if", 2, TOKEN_IF }, + { "else", 4, TOKEN_ELSE }, + { "goto", 4, TOKEN_GOTO }, + { "syscall", 7, TOKEN_SYSCALL }, + { "byte", 4, TOKEN_BYTE }, + { "word", 4, TOKEN_WORD }, + { "dword", 5, TOKEN_DWORD }, + { "qword", 5, TOKEN_QWORD }, + { "signed", 6, TOKEN_SIGNED }, + }; + + for (size_t i = 0; i < sizeof(keywords) / sizeof(keywords[0]); i += 1) + { + const struct Keyword* keyword = &keywords[i]; + if (keyword->length == length && memcmp(start, keyword->text, length) == 0) + return keyword->type; + } + + return TOKEN_IDENTIFIER; +} + +static char peek(struct Lexer* lexer) +{ + return *lexer->current; +} + +static char advance(struct Lexer* lexer) +{ + char c = *lexer->current; + lexer->current += 1; + return c; +} + +static bool match(struct Lexer* lexer, char expected) +{ + if (*lexer->current != expected) + return false; + lexer->current += 1; + return true; +} + +static void skip_whitespace(struct Lexer* lexer) +{ + for (;;) + { + char c = peek(lexer); + if (c == ' ' || c == '\t' || c == '\r') + advance(lexer); + else if (c == '\n') + { + lexer->line += 1; + advance(lexer); + } + else if (c == '/' && lexer->current[1] == '/') + { + while (peek(lexer) != '\n' && peek(lexer) != '\0') + advance(lexer); + } + else if (c == '/' && lexer->current[1] == '*') + { + advance(lexer); + advance(lexer); + while (!(peek(lexer) == '*' && lexer->current[1] == '/') && peek(lexer) != '\0') + { + if (peek(lexer) == '\n') + lexer->line += 1; + advance(lexer); + } + if (peek(lexer) != '\0') + { + advance(lexer); + advance(lexer); + } + } + else + return; + } +} + +static struct Token make_token(const struct Lexer* lexer, enum TokenType type, const char* start) +{ + struct Token token; + token.type = type; + token.start = start; + token.length = (size_t)(lexer->current - start); + token.line = lexer->line; + return token; +} + +struct Lexer create_lexer(const char* source) +{ + struct Lexer lexer; + lexer.name = NULL; + lexer.source = source; + lexer.current = source; + lexer.line = 1; + return lexer; +} + +static struct Token scan_string(struct Lexer* lexer, const char* start) +{ + while (peek(lexer) != '"') + { + char character = peek(lexer); + if (character == '\0') + return make_token(lexer, TOKEN_UNKNOWN, start); + if (character == '\n') + lexer->line += 1; + if (character == '\\' && lexer->current[1] != '\0') + advance(lexer); + advance(lexer); + } + + advance(lexer); + return make_token(lexer, TOKEN_STRING, start); +} + +static struct Token scan_char(struct Lexer* lexer, const char* start) +{ + while (peek(lexer) != '\'') + { + char character = peek(lexer); + if (character == '\0' || character == '\n') + return make_token(lexer, TOKEN_UNKNOWN, start); + if (character == '\\' && lexer->current[1] != '\0') + advance(lexer); + advance(lexer); + } + + advance(lexer); + return make_token(lexer, TOKEN_CHAR, start); +} + +struct Token scan_token(struct Lexer* lexer) +{ + skip_whitespace(lexer); + + const char* start = lexer->current; + if (peek(lexer) == '\0') + return make_token(lexer, TOKEN_EOF, start); + char character = advance(lexer); + + if (is_alpha(character)) + { + while (is_alpha(peek(lexer)) || is_digit(peek(lexer))) + advance(lexer); + return make_token(lexer, identifier_type(start, (size_t)(lexer->current - start)), start); + } + + if (is_digit(character)) + { + if (character == '0' && (peek(lexer) == 'x' || peek(lexer) == 'X')) + { + advance(lexer); + while (is_hex_digit(peek(lexer))) + advance(lexer); + return make_token(lexer, TOKEN_INTEGER, start); + } + + if (character == '0' && (peek(lexer) == 'b' || peek(lexer) == 'B')) + { + advance(lexer); + while (peek(lexer) == '0' || peek(lexer) == '1') + advance(lexer); + return make_token(lexer, TOKEN_INTEGER, start); + } + + while (is_digit(peek(lexer))) + advance(lexer); + + if (peek(lexer) == '.' && is_digit(lexer->current[1])) + { + advance(lexer); + while (is_digit(peek(lexer))) + advance(lexer); + return make_token(lexer, TOKEN_FLOAT, start); + } + + return make_token(lexer, TOKEN_INTEGER, start); + } + + if (character == '"') + return scan_string(lexer, start); + if (character == '\'') + return scan_char(lexer, start); + + switch (character) + { + case '=': return make_token(lexer, match(lexer, '=') ? TOKEN_EQUAL_EQUAL : TOKEN_EQUAL, start); + case '!': return make_token(lexer, match(lexer, '=') ? TOKEN_BANG_EQUAL : TOKEN_BANG, start); + case '<': return make_token(lexer, match(lexer, '=') ? TOKEN_LESS_EQUAL : TOKEN_LESS, start); + case '>': return make_token(lexer, match(lexer, '=') ? TOKEN_GREATER_EQUAL : TOKEN_GREATER, start); + case '+': return make_token(lexer, match(lexer, '=') ? TOKEN_PLUS_EQUAL : TOKEN_PLUS, start); + case '-': return make_token(lexer, match(lexer, '=') ? TOKEN_MINUS_EQUAL : TOKEN_MINUS, start); + case '*': return make_token(lexer, match(lexer, '=') ? TOKEN_STAR_EQUAL : TOKEN_STAR, start); + case '/': return make_token(lexer, match(lexer, '=') ? TOKEN_SLASH_EQUAL : TOKEN_SLASH, start); + case '%': return make_token(lexer, match(lexer, '=') ? TOKEN_PERCENT_EQUAL : TOKEN_PERCENT, start); + + case '^': return make_token(lexer, TOKEN_CARET, start); + case '.': return make_token(lexer, TOKEN_DOT, start); + case ',': return make_token(lexer, TOKEN_COMMA, start); + case ':': return make_token(lexer, TOKEN_COLON, start); + case '(': return make_token(lexer, TOKEN_LEFT_PAREN, start); + case ')': return make_token(lexer, TOKEN_RIGHT_PAREN, start); + case '[': return make_token(lexer, TOKEN_LEFT_BRACKET, start); + case ']': return make_token(lexer, TOKEN_RIGHT_BRACKET, start); + case '{': return make_token(lexer, TOKEN_LEFT_BRACE, start); + case '}': return make_token(lexer, TOKEN_RIGHT_BRACE, start); + } + + return make_token(lexer, TOKEN_UNKNOWN, start); +} + +const char* token_type_name(enum TokenType type) +{ + switch (type) + { + case TOKEN_EOF: return "eof"; + case TOKEN_IDENTIFIER: return "identifier"; + case TOKEN_INTEGER: return "integer"; + case TOKEN_FLOAT: return "float"; + case TOKEN_STRING: return "string"; + case TOKEN_CHAR: return "char"; + case TOKEN_CONST: return "const"; + case TOKEN_DATA: return "data"; + case TOKEN_PROC: return "proc"; + case TOKEN_ENUM: return "enum"; + case TOKEN_STRUCT: return "struct"; + case TOKEN_STACK: return "stack"; + case TOKEN_IF: return "if"; + case TOKEN_ELSE: return "else"; + case TOKEN_GOTO: return "goto"; + case TOKEN_SYSCALL: return "syscall"; + case TOKEN_BYTE: return "byte"; + case TOKEN_WORD: return "word"; + case TOKEN_DWORD: return "dword"; + case TOKEN_QWORD: return "qword"; + case TOKEN_SIGNED: return "signed"; + case TOKEN_EQUAL: return "equal"; + case TOKEN_PLUS: return "plus"; + case TOKEN_MINUS: return "minus"; + case TOKEN_STAR: return "star"; + case TOKEN_SLASH: return "slash"; + case TOKEN_PERCENT: return "percent"; + case TOKEN_CARET: return "caret"; + case TOKEN_BANG: return "bang"; + case TOKEN_LESS: return "less"; + case TOKEN_GREATER: return "greater"; + case TOKEN_DOT: return "dot"; + case TOKEN_COMMA: return "comma"; + case TOKEN_COLON: return "colon"; + case TOKEN_LEFT_PAREN: return "left_paren"; + case TOKEN_RIGHT_PAREN: return "right_paren"; + case TOKEN_LEFT_BRACKET: return "left_bracket"; + case TOKEN_RIGHT_BRACKET: return "right_bracket"; + case TOKEN_LEFT_BRACE: return "left_brace"; + case TOKEN_RIGHT_BRACE: return "right_brace"; + case TOKEN_EQUAL_EQUAL: return "equal_equal"; + case TOKEN_BANG_EQUAL: return "bang_equal"; + case TOKEN_PLUS_EQUAL: return "plus_equal"; + case TOKEN_MINUS_EQUAL: return "minus_equal"; + case TOKEN_STAR_EQUAL: return "star_equal"; + case TOKEN_SLASH_EQUAL: return "slash_equal"; + case TOKEN_PERCENT_EQUAL: return "percent_equal"; + case TOKEN_LESS_EQUAL: return "less_equal"; + case TOKEN_GREATER_EQUAL: return "greater_equal"; + case TOKEN_UNKNOWN: return "unknown"; + } + + return "unknown"; +} + -- cgit v1.3