diff --git a/src/ast.c b/src/ast.c index a0ba01c..ccd7d8c 100644 --- a/src/ast.c +++ b/src/ast.c @@ -7,9 +7,13 @@ extern AST* root; static char* asttype_names[] = { - [AST_TYPE_CALL] = "FUNC CALL", [AST_TYPE_NUM] = "NUMBER", - [AST_TYPE_VREF] = "VAR REFERENCE", [AST_TYPE_VDEF] = "VAR DEFINITION", - [AST_TYPE_BLOCK] = "BLOCK", [AST_TYPE_EXC] = "EXCEPTION" + [AST_TYPE_CALL] = "FUNC CALL", + [AST_TYPE_NUM] = "NUMBER", + [AST_TYPE_VREF] = "VAR REFERENCE", + [AST_TYPE_VDEF] = "VAR DEFINITION", + [AST_TYPE_BLOCK] = "BLOCK", + [AST_TYPE_EXC] = "EXCEPTION", + [AST_TYPE_FDEF] = "FUNCTION DEFINITION" }; AST* ast_init(ASTType type, void* data) { @@ -30,6 +34,7 @@ void ast_destroy(AST* ast) { case AST_TYPE_VREF: ast_vref_data_destroy(ast->data); break; case AST_TYPE_VDEF: ast_vdef_data_destroy(ast->data); break; case AST_TYPE_BLOCK: ast_block_data_destroy(ast->data); break; + case AST_TYPE_FDEF: ast_fdef_data_destroy(ast->data); break; default: log_dbgf("Unknown ast type %d (max: %d)", ast->type, AST_TYPE_MAX); } @@ -54,6 +59,7 @@ void ast_print_i(AST* ast, int i) { case AST_TYPE_VREF: ast_vref_print(ast->data, i + 2); break; case AST_TYPE_VDEF: ast_vdef_print(ast->data, i + 2); break; case AST_TYPE_BLOCK: ast_block_print(ast->data, i + 2); break; + case AST_TYPE_FDEF: ast_fdef_print(ast->data, i + 2); break; default: exit(1); } INDENT_FIELD_NONL_END; @@ -209,3 +215,32 @@ void ast_block_print(ASTBlockData* data, int depth) { INDENT_END; } + +ASTFDefData* +ast_fdef_data_init(char* name, size_t argc, AST** argv, AST* body) { + ASTFDefData* fdef = malloc(sizeof(ASTFDefData)); + + fdef->name = name; + fdef->argc = argc; + fdef->argv = argv; + fdef->body = body; + + return fdef; +} + +void ast_fdef_data_destroy(ASTFDefData* fdef) { + free(fdef->name); + for (int i = 0; i < fdef->argc; ast_destroy(fdef->argv[i++])); + ast_destroy(fdef->body); +} + +void ast_fdef_print(ASTFDefData* fdef, int i) { + INDENT_BEGIN(i) + INDENT_TITLE("ASTFDefData", fdef); + INDENT_FIELD("name", "%s", fdef->name); + INDENT_FIELD("argc", "%ld", fdef->argc); + INDENT_FIELD_LIST("argv", fdef->argv, fdef->argc, ast_print_i); + INDENT_FIELD_EXT_NONL_START("body"); + ast_print_i(fdef->body, i + 2); + INDENT_FIELD_NONL_END; +} diff --git a/src/grammar.y b/src/grammar.y index 5f41658..8e9ea09 100644 --- a/src/grammar.y +++ b/src/grammar.y @@ -71,7 +71,6 @@ inputstart: } ; - input: inputstart { $$ = $1; @@ -89,8 +88,6 @@ inputend: } ; - - argstart: exp { ArgArr* argarr = argarr_init(); @@ -195,4 +192,11 @@ exp: strcpy(to, "div"); $$ = ast_init(AST_TYPE_CALL, ast_call_data_init(to, 2, argv)); } + + | WORD GROUPS arg GROUPE EQ exp { + size_t argc = $3->ln; + AST** argv = $3->buf; + argarr_destroypsv($3); + $$ = ast_init(AST_TYPE_FDEF, ast_fdef_data_init($1, argc, argv, $6)); + } %% diff --git a/src/include/ast.h b/src/include/ast.h index 1e33ee2..d0d9bc3 100644 --- a/src/include/ast.h +++ b/src/include/ast.h @@ -22,7 +22,8 @@ typedef enum { AST_TYPE_VDEF, // A variable definition. AST_TYPE_VREF, // A variable reference. AST_TYPE_BLOCK, // A block of code (scope). - AST_TYPE_MAX = AST_TYPE_BLOCK, + AST_TYPE_FDEF, // A function definition. + AST_TYPE_MAX = AST_TYPE_FDEF, } ASTType; // An Abstract Syntax Tree. @@ -52,7 +53,7 @@ void ast_num_print(ASTNumData*, int i); // An exception. typedef struct ASTEXCDATA { - char* msg; // The exception message. + char* msg; // The exception message. AST* trace; // The previous exception. } ASTExcData; // Create a new `ASTExecData. @@ -122,4 +123,19 @@ void ast_block_data_destroy(ASTBlockData* block); // Print an `ASTBlockData`. void ast_block_print(ASTBlockData*, int i); +typedef struct { + char* name; // Function name. + size_t argc; // Argument count. + AST** argv; // Argument vector. + AST* body; // Function body. +} ASTFDefData; + +// Create a new `ASTFDefData`. +ASTFDefData* +ast_fdef_data_init(char* name, size_t argc, AST** argv, AST* body); +// Destroy an `ASTFDefData`. +void ast_fdef_data_destroy(ASTFDefData* fdef); +// Print an `ASTFDefData`. +void ast_fdef_print(ASTFDefData* fdef, int i); + #endif