From a70ad011f361993d1e71e26ad549e0989ca6bd4e Mon Sep 17 00:00:00 2001 From: samsonium Date: Mon, 26 Oct 2026 21:34:54 +0300 Subject: [PATCH] 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 --- CMakeLists.txt | 3 ++ include/compiler/fzl_analyzer.h | 37 +++++++++++++--------- src/compiler/analyzer/an_block.c | 44 ++++++++++++++++++++++++++ src/compiler/analyzer/an_call.c | 3 +- src/compiler/analyzer/an_common.c | 17 ++++++---- src/compiler/analyzer/an_conditional.c | 40 +++++++++++++++++++++++ src/compiler/analyzer/an_identifier.c | 3 +- src/compiler/analyzer/context.c | 38 ++++++++++++++++++++++ src/compiler/fzl_analyzer.c | 15 ++++----- 9 files changed, 165 insertions(+), 35 deletions(-) create mode 100644 src/compiler/analyzer/an_block.c create mode 100644 src/compiler/analyzer/an_conditional.c create mode 100644 src/compiler/analyzer/context.c diff --git a/CMakeLists.txt b/CMakeLists.txt index c8db2e1..d4e31cc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/include/compiler/fzl_analyzer.h b/include/compiler/fzl_analyzer.h index 0572478..546b140 100644 --- a/include/compiler/fzl_analyzer.h +++ b/include/compiler/fzl_analyzer.h @@ -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 diff --git a/src/compiler/analyzer/an_block.c b/src/compiler/analyzer/an_block.c new file mode 100644 index 0000000..9a88b35 --- /dev/null +++ b/src/compiler/analyzer/an_block.c @@ -0,0 +1,44 @@ +#include +#include +#include +#include +#include + +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}; +} diff --git a/src/compiler/analyzer/an_call.c b/src/compiler/analyzer/an_call.c index 263a8f6..10ea7e8 100644 --- a/src/compiler/analyzer/an_call.c +++ b/src/compiler/analyzer/an_call.c @@ -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}; } diff --git a/src/compiler/analyzer/an_common.c b/src/compiler/analyzer/an_common.c index 66581a7..490c6c9 100644 --- a/src/compiler/analyzer/an_common.c +++ b/src/compiler/analyzer/an_common.c @@ -3,6 +3,7 @@ #include #include #include +#include // 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: diff --git a/src/compiler/analyzer/an_conditional.c b/src/compiler/analyzer/an_conditional.c new file mode 100644 index 0000000..f37dd48 --- /dev/null +++ b/src/compiler/analyzer/an_conditional.c @@ -0,0 +1,40 @@ +#include +#include +#include +#include +#include + +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}; +} diff --git a/src/compiler/analyzer/an_identifier.c b/src/compiler/analyzer/an_identifier.c index 203d956..a56c2cd 100644 --- a/src/compiler/analyzer/an_identifier.c +++ b/src/compiler/analyzer/an_identifier.c @@ -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}; } diff --git a/src/compiler/analyzer/context.c b/src/compiler/analyzer/context.c new file mode 100644 index 0000000..472bfb3 --- /dev/null +++ b/src/compiler/analyzer/context.c @@ -0,0 +1,38 @@ +#include +#include +#include + +// 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; +} diff --git a/src/compiler/fzl_analyzer.c b/src/compiler/fzl_analyzer.c index cb8f7f8..4c9560d 100644 --- a/src/compiler/fzl_analyzer.c +++ b/src/compiler/fzl_analyzer.c @@ -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)