388 lines
10 KiB
C
388 lines
10 KiB
C
#include "compiler/fzl_token.h"
|
|
#include "compiler/utils/fzl_linked.h"
|
|
#include <compiler/fzl_reader.h>
|
|
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
// 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, "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 || strcmp(value, "null") == 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)
|
|
{
|
|
size_t p = move(reader, 1);
|
|
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 NULL;
|
|
}
|
|
|
|
return fzl_mktoken(type, l.line, l.col, NULL, 0, l.filename);
|
|
}
|
|
|
|
// Add double-char token
|
|
fzl_token_t *add_double(fzl_reader_t *reader, fzl_toktype_t type)
|
|
{
|
|
size_t p = move(reader, 2);
|
|
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 NULL;
|
|
}
|
|
|
|
return fzl_mktoken(type, l.line, l.col, NULL, 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->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);
|
|
}
|