feat: implement lexer+parser for example program
This commit is contained in:
@@ -0,0 +1,202 @@
|
||||
#include <compiler/fzl_reader.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(char *source)
|
||||
{
|
||||
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->source = source;
|
||||
reader->position = 0;
|
||||
reader->at_end = true;
|
||||
|
||||
return reader;
|
||||
}
|
||||
|
||||
// --- Read zone ---
|
||||
|
||||
// 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'));
|
||||
|
||||
char *value = malloc(size);
|
||||
memcpy(value, reader->source + reader->position, size);
|
||||
|
||||
size_t start = reader->position;
|
||||
reader->position += size;
|
||||
|
||||
fzl_token_t *tok = fzl_mktoken(
|
||||
FZL_TOKTYPE_NAME,
|
||||
start,
|
||||
reader->position - 1,
|
||||
value,
|
||||
size
|
||||
);
|
||||
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];
|
||||
|
||||
do
|
||||
{
|
||||
lpos++;
|
||||
size++;
|
||||
}
|
||||
while (reader->source[lpos] != open_symbol);
|
||||
size++;
|
||||
|
||||
if (size == 2)
|
||||
{
|
||||
fzl_token_t *tok = fzl_mktoken(
|
||||
FZL_TOKTYPE_STR_LITERAL,
|
||||
reader->position,
|
||||
reader->position + 1,
|
||||
"",
|
||||
0
|
||||
);
|
||||
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,
|
||||
reader->position,
|
||||
lpos,
|
||||
value,
|
||||
size - 2
|
||||
);
|
||||
free(value);
|
||||
|
||||
reader->position += size;
|
||||
|
||||
return tok;
|
||||
}
|
||||
|
||||
int fzl_read(fzl_reader_t *reader)
|
||||
{
|
||||
const size_t len = strlen(reader->source);
|
||||
if (reader->position >= len) return 0;
|
||||
|
||||
do {
|
||||
size_t p = reader->position;
|
||||
fzl_token_t *token;
|
||||
char curr = reader->source[p];
|
||||
|
||||
if (curr == '\n' || curr == ' ' || curr == '\r')
|
||||
{
|
||||
reader->position++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (curr == '\'' || curr == '"')
|
||||
token = parse_string_literal(reader);
|
||||
else if (curr == '(')
|
||||
{
|
||||
token = fzl_mktoken(
|
||||
FZL_TOKTYPE_LPAIR,
|
||||
p, p, NULL, 0);
|
||||
reader->position++;
|
||||
}
|
||||
else if (curr == ')')
|
||||
{
|
||||
token = fzl_mktoken(
|
||||
FZL_TOKTYPE_RPAIR,
|
||||
p, p, NULL, 0);
|
||||
reader->position++;
|
||||
}
|
||||
else if (curr >= 'A' && curr <= 'Z' ||
|
||||
curr >= 'a' && curr <= 'z')
|
||||
token = parse_name(reader);
|
||||
else
|
||||
{
|
||||
sprintf(last_err, "undefined token '%c'", curr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!token)
|
||||
{
|
||||
size_t line = 1, linepos = 1;
|
||||
for (size_t i = 0; i < p; i++)
|
||||
{
|
||||
char sym = reader->source[i];
|
||||
if (sym == '\n')
|
||||
{
|
||||
linepos = 1;
|
||||
line++;
|
||||
} else linepos++;
|
||||
}
|
||||
|
||||
sprintf(last_err, "error parsing token (position %ld of line %ld)", line, linepos);
|
||||
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 < len);
|
||||
|
||||
reader->at_end = true;
|
||||
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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user