wip: working on analyzer
- Feat: add `nest_ctx` and `fin_ctx` fns for working with context and environment - Feat: add block analyzer - Feat: add conditional statement analyzer
This commit is contained in:
@@ -21,8 +21,11 @@ add_executable(fzc
|
||||
src/compiler/utils/fzl_ctable.c
|
||||
src/compiler/checkers/fzl_loop_check.c
|
||||
src/compiler/analyzer/utility.c
|
||||
src/compiler/analyzer/context.c
|
||||
src/compiler/analyzer/an_block.c
|
||||
src/compiler/analyzer/an_call.c
|
||||
src/compiler/analyzer/an_common.c
|
||||
src/compiler/analyzer/an_conditional.c
|
||||
src/compiler/analyzer/an_identifier.c
|
||||
src/compiler/fzl_analyzer.c
|
||||
src/compiler/fzl_debug.c
|
||||
|
||||
@@ -16,21 +16,6 @@ typedef enum
|
||||
FZL_AN_CTX_TYPE_LOOP, // when analyzing loop
|
||||
} fzl_an_ctx_type_t;
|
||||
|
||||
// Analyzer descriptor
|
||||
typedef struct
|
||||
{
|
||||
char *warnings[256];
|
||||
size_t warnings_top;
|
||||
|
||||
char *errors[256];
|
||||
size_t errors_top;
|
||||
|
||||
fzl_symtable_t *symbols[256];
|
||||
size_t symbols_top;
|
||||
|
||||
fzl_node_t *root;
|
||||
} fzl_analyzer_t;
|
||||
|
||||
// Inner node analyzing result descriptor
|
||||
typedef struct
|
||||
{
|
||||
@@ -48,6 +33,22 @@ typedef struct fzl_an_ctx
|
||||
fzl_an_ctx_type_t type;
|
||||
} fzl_an_ctx_t;
|
||||
|
||||
// Analyzer descriptor
|
||||
typedef struct
|
||||
{
|
||||
char *warnings[256];
|
||||
size_t warnings_top;
|
||||
|
||||
char *errors[256];
|
||||
size_t errors_top;
|
||||
|
||||
fzl_symtable_t *symbols[256];
|
||||
size_t symbols_top;
|
||||
|
||||
fzl_node_t *root;
|
||||
fzl_an_ctx_t *ctx;
|
||||
} fzl_analyzer_t;
|
||||
|
||||
// Temp container for error
|
||||
extern char alast_error[256];
|
||||
|
||||
@@ -69,5 +70,11 @@ void fzl_freeanalyzer(fzl_analyzer_t *analyzer);
|
||||
fzl_an_res_t analyze_common(fzl_analyzer_t *analyzer, fzl_node_t *node);
|
||||
fzl_an_res_t analyze_call(fzl_analyzer_t *analyzer, fzl_node_t *call_node);
|
||||
fzl_an_res_t analyze_identifier(fzl_analyzer_t *analyzer, fzl_node_t *id);
|
||||
fzl_an_res_t analyze_conditional(fzl_analyzer_t *analyzer, fzl_node_t *cond);
|
||||
fzl_an_res_t analyze_function(fzl_analyzer_t *analyzer, fzl_node_t *fn_node);
|
||||
fzl_an_res_t analyze_block(fzl_analyzer_t *analyzer, fzl_node_t *block_node);
|
||||
|
||||
fzl_an_ctx_t *an_nest_ctx(fzl_analyzer_t *analyzer, fzl_an_ctx_type_t type);
|
||||
fzl_an_ctx_t *an_fin_ctx(fzl_analyzer_t *analyzer);
|
||||
|
||||
#endif // FZL_ANALYZER_H
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
#include <common/fzl_types.h>
|
||||
#include <compiler/fzl_analyzer.h>
|
||||
#include <compiler/fzl_parser.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
char block_problem[256];
|
||||
|
||||
// Analyze block
|
||||
fzl_an_res_t analyze_block(fzl_analyzer_t *analyzer, fzl_node_t *block_node)
|
||||
{
|
||||
if (!analyzer)
|
||||
return (fzl_an_res_t){.error = true};
|
||||
|
||||
if (!block_node || block_node->type != FZL_NODETYPE_BLOCK)
|
||||
{
|
||||
snprintf(block_problem, sizeof(block_problem), "node is not typeof BLOCK");
|
||||
an_push_error(analyzer, NULL, block_problem);
|
||||
return (fzl_an_res_t){.error = true};
|
||||
}
|
||||
|
||||
an_nest_ctx(analyzer, FZL_AN_CTX_TYPE_UNNECESSARY);
|
||||
|
||||
bool has_return = false;
|
||||
bool error = false;
|
||||
for (size_t i = 0; i < block_node->list.entry_count; i++)
|
||||
{
|
||||
if (has_return)
|
||||
an_push_warning(analyzer, block_node->list.entries[i]->token,
|
||||
"this node will never execute");
|
||||
|
||||
fzl_an_res_t entry_res =
|
||||
analyze_common(analyzer, block_node->list.entries[i]);
|
||||
if (entry_res.error)
|
||||
error = true;
|
||||
|
||||
if (block_node->list.entries[i]->type == FZL_NODETYPE_RETURN)
|
||||
has_return = true;
|
||||
}
|
||||
|
||||
an_fin_ctx(analyzer);
|
||||
|
||||
return (fzl_an_res_t){.error = error, .type = FZL_TYPE_NULL};
|
||||
}
|
||||
@@ -57,8 +57,7 @@ fzl_an_res_t analyze_call(fzl_analyzer_t *analyzer, fzl_node_t *call_node)
|
||||
{
|
||||
if (!call_node || call_node->type != FZL_NODETYPE_CALL)
|
||||
{
|
||||
an_push_error(analyzer, call_node->token,
|
||||
"provided node is not typeof CALL");
|
||||
an_push_error(analyzer, NULL, "provided node is not typeof CALL");
|
||||
return (fzl_an_res_t){.error = true};
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <compiler/fzl_analyzer.h>
|
||||
#include <compiler/fzl_parser.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// Analyzer main function
|
||||
fzl_an_res_t analyze_common(fzl_analyzer_t *analyzer, fzl_node_t *node)
|
||||
@@ -10,18 +11,20 @@ fzl_an_res_t analyze_common(fzl_analyzer_t *analyzer, fzl_node_t *node)
|
||||
fzl_an_res_t res = {.error = false, .type = FZL_TYPE_NULL, .classname = NULL};
|
||||
switch (node->type)
|
||||
{
|
||||
case FZL_NODETYPE_FUNCTION:
|
||||
res = analyze_function(analyzer, node);
|
||||
break;
|
||||
|
||||
case FZL_NODETYPE_CONDITIONAL:
|
||||
res = analyze_conditional(analyzer, node);
|
||||
break;
|
||||
|
||||
case FZL_NODETYPE_IDENTIFIER:
|
||||
res = analyze_identifier(analyzer, node);
|
||||
break;
|
||||
|
||||
case FZL_NODETYPE_BLOCK:
|
||||
for (size_t i = 0; i < node->list.entry_count; i++)
|
||||
{
|
||||
fzl_an_res_t entry_res =
|
||||
analyze_common(analyzer, node->list.entries[i]);
|
||||
if (entry_res.error)
|
||||
res.error = true;
|
||||
}
|
||||
res = analyze_block(analyzer, node);
|
||||
break;
|
||||
|
||||
case FZL_NODETYPE_CALL:
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
#include <common/fzl_types.h>
|
||||
#include <compiler/fzl_analyzer.h>
|
||||
#include <compiler/fzl_parser.h>
|
||||
#include <compiler/fzl_token.h>
|
||||
#include <stdio.h>
|
||||
|
||||
char cond_problem[256];
|
||||
|
||||
// Analyze conditional statement
|
||||
fzl_an_res_t analyze_conditional(fzl_analyzer_t *analyzer, fzl_node_t *cond)
|
||||
{
|
||||
if (!analyzer)
|
||||
return (fzl_an_res_t){.error = true};
|
||||
|
||||
if (!cond || cond->type != FZL_NODETYPE_CONDITIONAL)
|
||||
{
|
||||
an_push_error(analyzer, NULL, "provided node is not typeof CONDITIONAL");
|
||||
return (fzl_an_res_t){.error = true};
|
||||
}
|
||||
|
||||
fzl_an_res_t cond_res = analyze_common(analyzer, cond->cond.condition);
|
||||
fzl_an_res_t true_res = analyze_common(analyzer, cond->cond.true_block);
|
||||
fzl_an_res_t else_res = analyze_common(analyzer, cond->cond.else_block);
|
||||
|
||||
if (cond_res.error || true_res.error || else_res.error)
|
||||
return (fzl_an_res_t){.error = true};
|
||||
|
||||
if (cond_res.type != FZL_TYPE_BOOL)
|
||||
an_push_warning(analyzer, cond->cond.condition->token,
|
||||
"resulting type is not bool");
|
||||
|
||||
if (cond->cond.condition->token->type == FZL_TOKTYPE_BOOL_LITERAL)
|
||||
{
|
||||
snprintf(cond_problem, sizeof(cond_problem), "condition is always %s",
|
||||
(char *)cond->cond.condition->token->value);
|
||||
an_push_warning(analyzer, cond->cond.condition->token, cond_problem);
|
||||
}
|
||||
|
||||
return (fzl_an_res_t){.error = false, .type = FZL_TYPE_NULL};
|
||||
}
|
||||
@@ -13,8 +13,7 @@ fzl_an_res_t analyze_identifier(fzl_analyzer_t *analyzer, fzl_node_t *id)
|
||||
|
||||
if (!id || id->type != FZL_NODETYPE_IDENTIFIER)
|
||||
{
|
||||
snprintf(id_problem, sizeof(id_problem), "cannot parse identifier");
|
||||
an_push_error(analyzer, NULL, id_problem);
|
||||
an_push_error(analyzer, NULL, "provided node is not typeof IDENTIFIER");
|
||||
return (fzl_an_res_t){.error = true};
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
#include <compiler/fzl_analyzer.h>
|
||||
#include <compiler/utils/fzl_symtable.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// Nest context
|
||||
fzl_an_ctx_t *an_nest_ctx(fzl_analyzer_t *analyzer, fzl_an_ctx_type_t type)
|
||||
{
|
||||
if (!analyzer)
|
||||
return NULL;
|
||||
|
||||
fzl_an_ctx_t *ctx = malloc(sizeof(fzl_an_ctx_t));
|
||||
if (!ctx)
|
||||
return NULL;
|
||||
|
||||
ctx->type = type;
|
||||
if (analyzer->ctx != NULL)
|
||||
ctx->parent = analyzer->ctx;
|
||||
|
||||
analyzer->ctx = ctx;
|
||||
analyzer->symbols[analyzer->symbols_top++] = fzl_mksymt();
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
// Close context and return parent
|
||||
fzl_an_ctx_t *an_fin_ctx(fzl_analyzer_t *analyzer)
|
||||
{
|
||||
if (!analyzer || !analyzer->ctx)
|
||||
return NULL;
|
||||
|
||||
fzl_an_ctx_t *current = analyzer->ctx;
|
||||
fzl_an_ctx_t *parent = current->parent;
|
||||
analyzer->ctx = parent;
|
||||
fzl_freesymt(analyzer->symbols[--analyzer->symbols_top]);
|
||||
|
||||
free(current);
|
||||
return parent;
|
||||
}
|
||||
@@ -67,7 +67,11 @@ void fzl_analyze(fzl_analyzer_t *analyzer)
|
||||
if (!analyzer)
|
||||
return;
|
||||
|
||||
analyzer->symbols[analyzer->symbols_top++] = fzl_mksymt();
|
||||
if (an_nest_ctx(analyzer, FZL_AN_CTX_TYPE_UNNECESSARY) == NULL)
|
||||
{
|
||||
an_push_error(analyzer, NULL, "failed to make global context");
|
||||
return;
|
||||
}
|
||||
|
||||
fzl_node_t *current = analyzer->root;
|
||||
while (current != NULL)
|
||||
@@ -79,14 +83,7 @@ void fzl_analyze(fzl_analyzer_t *analyzer)
|
||||
current = current->next;
|
||||
}
|
||||
|
||||
if (analyzer->symbols_top < 0)
|
||||
{
|
||||
an_push_error(analyzer, NULL,
|
||||
"undefined error (early finish of global environment)");
|
||||
return;
|
||||
}
|
||||
|
||||
fzl_freesymt(analyzer->symbols[--analyzer->symbols_top]);
|
||||
an_fin_ctx(analyzer);
|
||||
}
|
||||
|
||||
void fzl_freeanalyzer(fzl_analyzer_t *analyzer)
|
||||
|
||||
Reference in New Issue
Block a user