From f6573d81f0e0b531baebad1be5f21188b501088d Mon Sep 17 00:00:00 2001 From: Jean Herail Date: Wed, 14 Jan 2026 20:42:31 +0100 Subject: [PATCH 1/2] feat(pretty-print): Just casually implemented the graphviz representation of parsed AST --- .gitignore | 1 + src/utils/ast/ast.c | 91 ++++++++++++++++++++++++++++++++++++++++++++- src/utils/ast/ast.h | 5 +++ 3 files changed, 95 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 64c4a76..ab7c85c 100644 --- a/.gitignore +++ b/.gitignore @@ -175,3 +175,4 @@ m4/ltversion.m4 m4/lt~obsolete.m4 Makefile +*.svg diff --git a/src/utils/ast/ast.c b/src/utils/ast/ast.c index 40b42d7..4019e44 100644 --- a/src/utils/ast/ast.c +++ b/src/utils/ast/ast.c @@ -1,9 +1,96 @@ -#include "ast.h" - #include #include +#include #include +#include "ast.h" + +static void ast_print_dot_recursive(struct ast *node, FILE *out) +{ + if (!node) + return; + + switch (node->type) + { + case AST_IF: + { + struct ast_if *if_data = ast_get_if(node); + fprintf(out, " node%p [label=\"IF\"];\n", (void *)node); + + if (if_data->condition) + { + fprintf(out, " node%p -> node%p;\n", (void *)node, + (void *)if_data->condition); + fprintf(out, " node%p [fillcolor=\"lightyellow\", style=\"filled\"];\n", + (void *)if_data->condition); + ast_print_dot_recursive(if_data->condition, out); + + if (if_data->then_clause) + { + fprintf(out, " node%p -> node%p [label=\"true\"];\n", + (void *)if_data->condition, (void *)if_data->then_clause); + ast_print_dot_recursive(if_data->then_clause, out); + } + + if (if_data->else_clause) + { + fprintf(out, " node%p -> node%p [label=\"false\"];\n", + (void *)if_data->condition, (void *)if_data->else_clause); + ast_print_dot_recursive(if_data->else_clause, out); + } + } + break; + } + case AST_CMD: + { + struct ast_cmd *cmd_data = ast_get_cmd(node); + fprintf(out, " node%p [label=\"", (void *)node); + struct list *l = cmd_data->cmd; + while (l) + { + fprintf(out, "%s", (char *)l->data); + if (l->next) + fprintf(out, " "); + l = l->next; + } + fprintf(out, "\"];\n"); + break; + } + case AST_END: + fprintf(out, " node%p [label=\"END\"];\n", (void *)node); + break; + default: + break; + } +} + +void ast_print_dot(struct ast *ast) +{ + // Always print to stdout so the user can see it in the terminal + printf("digraph AST {\n"); + if (ast) + { + ast_print_dot_recursive(ast, stdout); + } + printf("}\n"); + + if (!ast) + return; + + FILE *dot_pipe = popen("dot -Tsvg -o ast.svg", "w"); + if (!dot_pipe) + { + return; + } + + fprintf(dot_pipe, "digraph AST {\n"); + ast_print_dot_recursive(ast, dot_pipe); + fprintf(dot_pipe, "}\n"); + pclose(dot_pipe); + + system("open ast.svg"); +} + bool ast_is_if(struct ast *node) { assert(node != NULL); diff --git a/src/utils/ast/ast.h b/src/utils/ast/ast.h index 3247ba5..54fef4b 100644 --- a/src/utils/ast/ast.h +++ b/src/utils/ast/ast.h @@ -70,4 +70,9 @@ struct ast *ast_create_if(struct ast *condition, struct ast *then_clause, */ struct ast *ast_create_cmd(struct list *cmd); +/** + * Prints the Graphviz DOT representation of the given AST to stdout. + */ +void ast_print_dot(struct ast *ast); + #endif /* ! AST_H */ From 0ede8d3eef003ee31d8718fb14ce4260b21a3ce4 Mon Sep 17 00:00:00 2001 From: Jean Herail Date: Wed, 21 Jan 2026 19:57:44 +0100 Subject: [PATCH 2/2] Re-functionnal pretty-printing --- src/main.c | 5 +++++ src/parser/parser.c | 2 +- src/utils/ast/ast.c | 27 ++++++++++----------------- 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/main.c b/src/main.c index b664786..189f9db 100644 --- a/src/main.c +++ b/src/main.c @@ -60,6 +60,11 @@ int main(int argc, char **argv) // Call the parser to get the AST struct ast *command_ast = get_ast(); // We'll pass the options later + if (options.pretty_print) + { + ast_print_dot(command_ast); + } + // Call the executor with the AST r = execution(command_ast); diff --git a/src/parser/parser.c b/src/parser/parser.c index 30cecdd..8468b20 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -11,4 +11,4 @@ struct ast *get_ast_str(char *command) { (void)command; return NULL; -} +} \ No newline at end of file diff --git a/src/utils/ast/ast.c b/src/utils/ast/ast.c index 4019e44..cd875e7 100644 --- a/src/utils/ast/ast.c +++ b/src/utils/ast/ast.c @@ -1,10 +1,10 @@ +#include "ast.h" + #include #include #include #include -#include "ast.h" - static void ast_print_dot_recursive(struct ast *node, FILE *out) { if (!node) @@ -12,8 +12,7 @@ static void ast_print_dot_recursive(struct ast *node, FILE *out) switch (node->type) { - case AST_IF: - { + case AST_IF: { struct ast_if *if_data = ast_get_if(node); fprintf(out, " node%p [label=\"IF\"];\n", (void *)node); @@ -21,28 +20,30 @@ static void ast_print_dot_recursive(struct ast *node, FILE *out) { fprintf(out, " node%p -> node%p;\n", (void *)node, (void *)if_data->condition); - fprintf(out, " node%p [fillcolor=\"lightyellow\", style=\"filled\"];\n", + fprintf(out, + " node%p [fillcolor=\"lightyellow\", style=\"filled\"];\n", (void *)if_data->condition); ast_print_dot_recursive(if_data->condition, out); if (if_data->then_clause) { fprintf(out, " node%p -> node%p [label=\"true\"];\n", - (void *)if_data->condition, (void *)if_data->then_clause); + (void *)if_data->condition, + (void *)if_data->then_clause); ast_print_dot_recursive(if_data->then_clause, out); } if (if_data->else_clause) { fprintf(out, " node%p -> node%p [label=\"false\"];\n", - (void *)if_data->condition, (void *)if_data->else_clause); + (void *)if_data->condition, + (void *)if_data->else_clause); ast_print_dot_recursive(if_data->else_clause, out); } } break; } - case AST_CMD: - { + case AST_CMD: { struct ast_cmd *cmd_data = ast_get_cmd(node); fprintf(out, " node%p [label=\"", (void *)node); struct list *l = cmd_data->cmd; @@ -66,14 +67,6 @@ static void ast_print_dot_recursive(struct ast *node, FILE *out) void ast_print_dot(struct ast *ast) { - // Always print to stdout so the user can see it in the terminal - printf("digraph AST {\n"); - if (ast) - { - ast_print_dot_recursive(ast, stdout); - } - printf("}\n"); - if (!ast) return;