feat: implement extern block reading and parsing
This commit is contained in:
@@ -0,0 +1,192 @@
|
||||
#include <compiler/fzl_parser.h>
|
||||
#include <compiler/fzl_token.h>
|
||||
#include <compiler/internals/parser.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// Parse extern definition
|
||||
fzl_node_t *pa_extern(fzl_parser_t *parser)
|
||||
{
|
||||
if (!parser || !peek(parser))
|
||||
return NULL;
|
||||
|
||||
fzl_token_t *kw = consume(parser);
|
||||
if (!kw || kw->type != FZL_TOKTYPE_EXTERN)
|
||||
{
|
||||
snprintf(plast_err, sizeof(plast_err),
|
||||
"'%s':%zu:%zu => expected 'extern' keyword",
|
||||
last_known_tok->filename, last_known_tok->ln, last_known_tok->cn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fzl_token_t *libname = consume(parser);
|
||||
if (!libname || libname->type != FZL_TOKTYPE_STR_LITERAL)
|
||||
{
|
||||
snprintf(plast_err, sizeof(plast_err),
|
||||
"'%s':%zu:%zu => expected library name after 'extern'",
|
||||
last_known_tok->filename, last_known_tok->ln, last_known_tok->cn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fzl_token_t *lbra = consume(parser);
|
||||
if (!lbra || lbra->type != FZL_TOKTYPE_LBRACE)
|
||||
{
|
||||
snprintf(plast_err, sizeof(plast_err),
|
||||
"'%s':%zu:%zu => expected '{' after library name",
|
||||
last_known_tok->filename, last_known_tok->ln, last_known_tok->cn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Typedefs array
|
||||
size_t td_remainder = 2;
|
||||
size_t td_count = 0;
|
||||
fzl_node_t **td = malloc(td_remainder * sizeof(fzl_node_t *));
|
||||
if (!td)
|
||||
{
|
||||
snprintf(plast_err, sizeof(plast_err), "out of memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Functions array
|
||||
size_t fn_remainder = 2;
|
||||
size_t fn_count = 0;
|
||||
fzl_node_t **fn = malloc(fn_remainder * sizeof(fzl_node_t *));
|
||||
if (!fn)
|
||||
{
|
||||
free(td);
|
||||
snprintf(plast_err, sizeof(plast_err), "out of memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool error = false;
|
||||
while (peek(parser))
|
||||
{
|
||||
if (is(parser, FZL_TOKTYPE_RBRACE))
|
||||
break;
|
||||
|
||||
if (td_remainder <= td_count)
|
||||
{
|
||||
td_remainder *= 2;
|
||||
fzl_node_t **newarr = realloc(td, td_remainder * sizeof(fzl_node_t *));
|
||||
if (!newarr)
|
||||
{
|
||||
snprintf(plast_err, sizeof(plast_err), "out of memory");
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
|
||||
td = newarr;
|
||||
}
|
||||
|
||||
if (fn_remainder <= fn_count)
|
||||
{
|
||||
fn_remainder *= 2;
|
||||
fzl_node_t **newarr = realloc(fn, fn_remainder * sizeof(fzl_node_t *));
|
||||
if (!newarr)
|
||||
{
|
||||
snprintf(plast_err, sizeof(plast_err), "out of memory");
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
|
||||
fn = newarr;
|
||||
}
|
||||
|
||||
if (is(parser, FZL_TOKTYPE_TYPEDEF))
|
||||
{
|
||||
fzl_node_t *result = pa_typedef(parser);
|
||||
if (!result)
|
||||
{
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
|
||||
td[td_count++] = result;
|
||||
}
|
||||
else if (is(parser, FZL_TOKTYPE_FUNCTION))
|
||||
{
|
||||
fzl_node_t *result = pa_externfn(parser);
|
||||
if (!result)
|
||||
{
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
|
||||
fn[fn_count++] = result;
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(plast_err, sizeof(plast_err),
|
||||
"'%s':%zu:%zu => unexpected statement inside extern block",
|
||||
last_known_tok->filename, last_known_tok->ln,
|
||||
last_known_tok->cn);
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
|
||||
fzl_token_t *sc = consume(parser);
|
||||
if (!sc || sc->type != FZL_TOKTYPE_SEMICOLON)
|
||||
{
|
||||
snprintf(plast_err, sizeof(plast_err), "'%s':%zu:%zu => missing ';'",
|
||||
last_known_tok->filename, last_known_tok->ln,
|
||||
last_known_tok->cn);
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (error)
|
||||
{
|
||||
for (size_t i = 0; i < td_count; i++)
|
||||
fzl_freeast(td[i]);
|
||||
free(td);
|
||||
|
||||
for (size_t i = 0; i < fn_count; i++)
|
||||
fzl_freeast(fn[i]);
|
||||
free(fn);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fzl_token_t *rbra = consume(parser);
|
||||
if (!rbra || rbra->type != FZL_TOKTYPE_RBRACE)
|
||||
{
|
||||
for (size_t i = 0; i < td_count; i++)
|
||||
fzl_freeast(td[i]);
|
||||
free(td);
|
||||
|
||||
for (size_t i = 0; i < fn_count; i++)
|
||||
fzl_freeast(fn[i]);
|
||||
free(fn);
|
||||
|
||||
snprintf(plast_err, sizeof(plast_err),
|
||||
"'%s':%zu:%zu => expected '}' after extern block",
|
||||
last_known_tok->filename, last_known_tok->ln, last_known_tok->cn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fzl_node_t *node = fzl_mknode(FZL_NODETYPE_EXTERN, kw);
|
||||
if (!node)
|
||||
{
|
||||
for (size_t i = 0; i < td_count; i++)
|
||||
fzl_freeast(td[i]);
|
||||
free(td);
|
||||
|
||||
for (size_t i = 0; i < fn_count; i++)
|
||||
fzl_freeast(fn[i]);
|
||||
free(fn);
|
||||
|
||||
snprintf(plast_err, sizeof(plast_err), "out of memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node->ext.libname = (char *)libname->value;
|
||||
node->ext.typedefs = td;
|
||||
node->ext.typedefs_count = td_count;
|
||||
node->ext.fns = fn;
|
||||
node->ext.fns_count = fn_count;
|
||||
|
||||
return node;
|
||||
}
|
||||
Reference in New Issue
Block a user