#include "compiler/fzl_token.h" #include "compiler/utils/fzl_linked.h" #include #include #include #include #include #include // Last error from reader static char last_err[256] = {0}; fzl_reader_t *fzl_mkreader(fzl_linked_t *linked) { fzl_reader_ll_t *first_node = malloc(sizeof(fzl_reader_ll_t)); first_node->token = NULL; first_node->next = NULL; fzl_reader_t *reader = malloc(sizeof(fzl_reader_t)); reader->first = first_node; reader->last = first_node; reader->linked = linked; reader->source = linked->source; reader->size = linked->total_sz; reader->position = 0; return reader; } // --- Read zone --- // Move cursor forward // @deprecated static size_t move(fzl_reader_t *reader, size_t len) { if (!reader) return 0; return reader->position += len; } // Try parse name fzl_token_t *parse_name(fzl_reader_t *reader) { size_t lpos = reader->position; size_t size = 0; do { lpos++; size++; } while ((reader->source[lpos] >= 'A' && reader->source[lpos] <= 'Z') || (reader->source[lpos] >= 'a' && reader->source[lpos] <= 'z') || (reader->source[lpos] >= '0' && reader->source[lpos] <= '9') || (reader->source[lpos] == '_')); char *value = malloc(size + 1); memcpy(value, reader->source + reader->position, size); value[size] = '\0'; size_t start = reader->position; move(reader, size); fzl_token_t *tok; fzl_file_loc l; bool ok = fzl_linked_getpos(reader->linked, start, &l); if (!ok) { snprintf(last_err, sizeof(last_err), "failed to locate line:col"); return NULL; } if (strcmp(value, "class") == 0) tok = fzl_mktoken(FZL_TOKTYPE_CLASS, l.line, l.col, value, size, l.filename); else if (strcmp(value, "new") == 0) tok = fzl_mktoken(FZL_TOKTYPE_NEW, l.line, l.col, value, size, l.filename); else if (strcmp(value, "fn") == 0) tok = fzl_mktoken(FZL_TOKTYPE_FUNCTION, l.line, l.col, value, size, l.filename); else if (strcmp(value, "return") == 0) tok = fzl_mktoken(FZL_TOKTYPE_RETURN, l.line, l.col, value, size, l.filename); else if (strcmp(value, "if") == 0) tok = fzl_mktoken(FZL_TOKTYPE_IF, l.line, l.col, value, size, l.filename); else if (strcmp(value, "else") == 0) tok = fzl_mktoken(FZL_TOKTYPE_ELSE, l.line, l.col, value, size, l.filename); else if (strcmp(value, "true") == 0 || strcmp(value, "false") == 0) tok = fzl_mktoken(FZL_TOKTYPE_BOOL_LITERAL, l.line, l.col, value, size, l.filename); else if (strcmp(value, "null") == 0) tok = fzl_mktoken(FZL_TOKTYPE_NULL_LITERAL, l.line, l.col, value, size, l.filename); else if (strcmp(value, "str") == 0 || strcmp(value, "char") == 0 || strcmp(value, "bool") == 0 || strcmp(value, "uint") == 0 || strcmp(value, "int") == 0 || strcmp(value, "i8") == 0 || strcmp(value, "i16") == 0 || strcmp(value, "i32") == 0 || strcmp(value, "i64") == 0 || strcmp(value, "u8") == 0 || strcmp(value, "u16") == 0 || strcmp(value, "u32") == 0 || strcmp(value, "u64") == 0) tok = fzl_mktoken(FZL_TOKTYPE_TYPE, l.line, l.col, value, size, l.filename); else tok = fzl_mktoken(FZL_TOKTYPE_NAME, l.line, l.col, value, size, l.filename); free(value); return tok; } // Try parse string literal fzl_token_t *parse_string_literal(fzl_reader_t *reader) { size_t lpos = reader->position; size_t size = 0; if (reader->source[lpos] != '\'' && reader->source[lpos] != '"') return NULL; char open_symbol = reader->source[lpos]; char close_symbol = '\0'; do { lpos++; size++; if (reader->source[lpos] == open_symbol) close_symbol = open_symbol; } while (reader->source[lpos] != open_symbol && lpos < reader->size); size++; fzl_file_loc l; bool ok = fzl_linked_getpos(reader->linked, reader->position, &l); if (!ok) { snprintf(last_err, sizeof(last_err), "failed to locate line:col"); return NULL; } if (close_symbol != open_symbol) { snprintf(last_err, sizeof(last_err), "'%s': unterminated string at %ld:%ld", l.filename, l.line, l.col); return NULL; } if (size == 2) { fzl_token_t *tok = fzl_mktoken(FZL_TOKTYPE_STR_LITERAL, l.line, l.col, "", 0, l.filename); move(reader, 2); return tok; } char *value = malloc(size - 2); memcpy(value, reader->source + reader->position + 1, size - 2); fzl_token_t *tok = fzl_mktoken(FZL_TOKTYPE_STR_LITERAL, l.line, l.col, value, size - 2, l.filename); free(value); move(reader, size); return tok; } // Parse numeric literal fzl_token_t *parse_number(fzl_reader_t *reader) { if (!reader) return NULL; size_t size = 0; size_t lpos = reader->position; do { size++; lpos++; } while ((reader->source[lpos] >= '0' && reader->source[lpos] <= '9') && lpos < reader->size); char *value = malloc(size * sizeof(char) + 1); memcpy(value, reader->source + reader->position, size); value[size] = '\0'; fzl_file_loc l; bool ok = fzl_linked_getpos(reader->linked, reader->position, &l); if (!ok) { snprintf(last_err, sizeof(last_err), "failed to locate line:col"); return NULL; } fzl_token_t *tok = fzl_mktoken(FZL_TOKTYPE_NUM_LITERAL, l.line, l.col, value, size, l.filename); free(value); if (!tok) return NULL; move(reader, size); return tok; } // Add single-char token fzl_token_t *add_single(fzl_reader_t *reader, fzl_toktype_t type) { fzl_file_loc l; bool ok = fzl_linked_getpos(reader->linked, reader->position, &l); if (!ok) { snprintf(last_err, sizeof(last_err), "failed to locate line:col"); return NULL; } move(reader, 1); return fzl_mktoken(type, l.line, l.col, "", 0, l.filename); } // Add double-char token fzl_token_t *add_double(fzl_reader_t *reader, fzl_toktype_t type) { fzl_file_loc l; bool ok = fzl_linked_getpos(reader->linked, reader->position, &l); if (!ok) { snprintf(last_err, sizeof(last_err), "failed to locate line:col"); return NULL; } move(reader, 2); return fzl_mktoken(type, l.line, l.col, "", 0, l.filename); } // Skip symbols until '\n' or EOF void skip_comment(fzl_reader_t *reader) { move(reader, 2); while (reader->position < reader->size) { if (reader->source[reader->position++] == '\n') break; } } int fzl_read(fzl_reader_t *reader) { if (reader->position >= reader->size) return 0; do { size_t p = reader->position; fzl_token_t *token; char curr = reader->source[p]; if (curr == '\n' || curr == ' ' || curr == '\r') { move(reader, 1); continue; } if (curr == '\'' || curr == '"') token = parse_string_literal(reader); else if (curr == '/' && reader->source[p + 1] == '/') { skip_comment(reader); continue; } else if (curr == '=' && reader->source[p + 1] == '=') token = add_double(reader, FZL_TOKTYPE_EQEQ); else if (curr == '>' && reader->source[p + 1] == '=') token = add_double(reader, FZL_TOKTYPE_REQ); else if (curr == '<' && reader->source[p + 1] == '=') token = add_double(reader, FZL_TOKTYPE_LEQ); else if (curr == '!' && reader->source[p + 1] == '=') token = add_double(reader, FZL_TOKTYPE_NEQ); else if (curr == '|' && reader->source[p + 1] == '|') token = add_double(reader, FZL_TOKTYPE_DVBAR); else if (curr == '&' && reader->source[p + 1] == '&') token = add_double(reader, FZL_TOKTYPE_DAMPERSAND); else if (curr == '>') token = add_single(reader, FZL_TOKTYPE_RANGLE); else if (curr == '<') token = add_single(reader, FZL_TOKTYPE_LANGLE); else if (curr == '!') token = add_single(reader, FZL_TOKTYPE_NOT); else if (curr == ';') token = add_single(reader, FZL_TOKTYPE_SEMICOLON); else if (curr == '{') token = add_single(reader, FZL_TOKTYPE_LBRACE); else if (curr == '}') token = add_single(reader, FZL_TOKTYPE_RBRACE); else if (curr == '(') token = add_single(reader, FZL_TOKTYPE_LPAREN); else if (curr == ')') token = add_single(reader, FZL_TOKTYPE_RPAREN); else if (curr == ',') token = add_single(reader, FZL_TOKTYPE_COMMA); else if (curr == '.') token = add_single(reader, FZL_TOKTYPE_DOT); else if (curr == '*') token = add_single(reader, FZL_TOKTYPE_STAR); else if (curr == '/') token = add_single(reader, FZL_TOKTYPE_SLASH); else if (curr == '+') token = add_single(reader, FZL_TOKTYPE_PLUS); else if (curr == '-') token = add_single(reader, FZL_TOKTYPE_MINUS); else if (curr == '^') token = add_single(reader, FZL_TOKTYPE_CARET); else if (curr == '%') token = add_single(reader, FZL_TOKTYPE_PERCENT); else if (curr == '=') token = add_single(reader, FZL_TOKTYPE_EQ); else if ((curr >= 'A' && curr <= 'Z') || (curr >= 'a' && curr <= 'z') || curr == '_') token = parse_name(reader); else if (curr >= '0' && curr <= '9') token = parse_number(reader); else { fzl_file_loc l; bool ok = fzl_linked_getpos(reader->linked, p, &l); if (!ok) { snprintf(last_err, sizeof(last_err), "failed to locate line:col"); return -1; } sprintf(last_err, "'%s': undefined token '%c' at %ld:%ld", l.filename, curr, l.line, l.col); return -1; } if (!token) { if (!last_err[0]) { fzl_file_loc l; bool ok = fzl_linked_getpos(reader->linked, p, &l); if (!ok) { snprintf(last_err, sizeof(last_err), "failed to locate line:col"); return -1; } sprintf(last_err, "'%s': cannot parse token at %ld:%ld", l.filename, l.line, l.col); } return -1; } fzl_reader_ll_t *tok_node = malloc(sizeof(fzl_reader_ll_t)); tok_node->next = NULL; tok_node->token = token; reader->last->next = tok_node; reader->last = tok_node; } while (reader->position < reader->size); return 0; } // --- Read zone end --- char *fzl_reader_geterror() { return last_err; } void free_node_and_next(fzl_reader_ll_t *node) { if (!node) return; if (node->next) free_node_and_next(node->next); if (node->token) fzl_freetoken(node->token); free(node); } void fzl_freereader(fzl_reader_t *reader) { if (!reader) return; if (reader->first) free_node_and_next(reader->first); free(reader); }