ref: split parser into separate files
This commit is contained in:
@@ -0,0 +1,164 @@
|
||||
#include <compiler/fzl_parser.h>
|
||||
#include <compiler/internals/parser.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// Parse primary
|
||||
fzl_node_t *pa_primary(fzl_parser_t *parser)
|
||||
{
|
||||
if (!parser || !peek(parser))
|
||||
return NULL;
|
||||
|
||||
if (is(parser, FZL_TOKTYPE_STR_LITERAL) ||
|
||||
is(parser, FZL_TOKTYPE_NUM_LITERAL) ||
|
||||
is(parser, FZL_TOKTYPE_BOOL_LITERAL) ||
|
||||
is(parser, FZL_TOKTYPE_NULL_LITERAL))
|
||||
{
|
||||
fzl_token_t *tok = consume(parser);
|
||||
return fzl_mknode(FZL_NODETYPE_LITERAL, tok);
|
||||
}
|
||||
else if (is(parser, FZL_TOKTYPE_STR_FORMAT_START))
|
||||
{
|
||||
consume(parser);
|
||||
|
||||
size_t remainder = 2;
|
||||
size_t count = 0;
|
||||
fzl_node_t **entries = malloc(remainder * sizeof(fzl_node_t *));
|
||||
if (!entries)
|
||||
{
|
||||
snprintf(plast_err, sizeof(plast_err), "out of memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (peek(parser) && peek(parser)->type != FZL_TOKTYPE_STR_FORMAT_END)
|
||||
{
|
||||
if (is(parser, FZL_TOKTYPE_STR_FORMAT_END))
|
||||
break;
|
||||
|
||||
if (remainder <= count)
|
||||
{
|
||||
remainder *= 2;
|
||||
fzl_node_t **newentries =
|
||||
realloc(entries, remainder * sizeof(fzl_node_t *));
|
||||
if (!newentries)
|
||||
{
|
||||
snprintf(plast_err, sizeof(plast_err), "out of memory");
|
||||
for (size_t i = 0; i < count; i++)
|
||||
fzl_freeast(entries[i]);
|
||||
|
||||
free(entries);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
entries = newentries;
|
||||
}
|
||||
|
||||
fzl_node_t *expr = pa_expression(parser);
|
||||
if (expr == NULL)
|
||||
{
|
||||
for (size_t i = 0; i < count; i++)
|
||||
fzl_freeast(entries[i]);
|
||||
|
||||
free(entries);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
entries[count++] = expr;
|
||||
}
|
||||
|
||||
fzl_token_t *end = consume(parser);
|
||||
if (end->type != FZL_TOKTYPE_STR_FORMAT_END)
|
||||
{
|
||||
snprintf(plast_err, sizeof(plast_err),
|
||||
"'%s':%zu:%zu => unterminated format string",
|
||||
last_known_tok->filename, last_known_tok->ln,
|
||||
last_known_tok->cn);
|
||||
|
||||
for (size_t i = 0; i < count; i++)
|
||||
fzl_freeast(entries[i]);
|
||||
|
||||
free(entries);
|
||||
}
|
||||
|
||||
if (count < 1)
|
||||
{
|
||||
snprintf(plast_err, sizeof(plast_err),
|
||||
"'%s':%zu:%zu => do you really need empty format string?",
|
||||
last_known_tok->filename, last_known_tok->ln,
|
||||
last_known_tok->cn);
|
||||
|
||||
for (size_t i = 0; i < count; i++)
|
||||
fzl_freeast(entries[i]);
|
||||
|
||||
free(entries);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fzl_node_t *node = fzl_mknode(FZL_NODETYPE_FMT_STRING, entries[0]->token);
|
||||
if (!node)
|
||||
{
|
||||
snprintf(plast_err, sizeof(plast_err), "out of memory");
|
||||
for (size_t i = 0; i < count; i++)
|
||||
fzl_freeast(entries[i]);
|
||||
|
||||
free(entries);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node->list.entries = entries;
|
||||
node->list.entry_count = count;
|
||||
|
||||
return node;
|
||||
}
|
||||
else if (is(parser, FZL_TOKTYPE_LPAREN))
|
||||
{
|
||||
consume(parser);
|
||||
fzl_node_t *node = pa_expression(parser);
|
||||
if (!is(parser, FZL_TOKTYPE_RPAREN))
|
||||
{
|
||||
snprintf(plast_err, sizeof(plast_err), "'%s': expected ')' at %ld:%ld",
|
||||
last_known_tok->filename, last_known_tok->ln,
|
||||
last_known_tok->cn);
|
||||
fzl_freeast(node);
|
||||
return NULL;
|
||||
}
|
||||
consume(parser);
|
||||
return node;
|
||||
}
|
||||
else if (is(parser, FZL_TOKTYPE_NAME))
|
||||
{
|
||||
fzl_token_t *name = consume(parser);
|
||||
if (!is(parser, FZL_TOKTYPE_NAME))
|
||||
return fzl_mknode(FZL_NODETYPE_IDENTIFIER, name);
|
||||
|
||||
fzl_token_t *realname = consume(parser); // :D
|
||||
fzl_node_t *decl = fzl_mknode(FZL_NODETYPE_DECLARATION, name);
|
||||
decl->var.type = name;
|
||||
decl->var.identifier = fzl_mknode(FZL_NODETYPE_IDENTIFIER, realname);
|
||||
return decl;
|
||||
}
|
||||
else if (is(parser, FZL_TOKTYPE_TYPE))
|
||||
{
|
||||
fzl_token_t *type = consume(parser);
|
||||
fzl_token_t *name = consume(parser);
|
||||
if (!name || name->type != FZL_TOKTYPE_NAME)
|
||||
{
|
||||
snprintf(plast_err, sizeof(plast_err),
|
||||
"'%s': expected name after type at %ld:%ld",
|
||||
last_known_tok->filename, last_known_tok->ln,
|
||||
last_known_tok->cn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fzl_node_t *decl = fzl_mknode(FZL_NODETYPE_DECLARATION, type);
|
||||
decl->var.type = type;
|
||||
decl->var.identifier = fzl_mknode(FZL_NODETYPE_IDENTIFIER, name);
|
||||
return decl;
|
||||
}
|
||||
|
||||
if (!plast_err[0])
|
||||
snprintf(plast_err, sizeof(plast_err),
|
||||
"'%s': expected expression at %ld:%ld", last_known_tok->filename,
|
||||
last_known_tok->ln, last_known_tok->cn);
|
||||
return NULL;
|
||||
}
|
||||
Reference in New Issue
Block a user