summaryrefslogtreecommitdiff
path: root/42sh/src/ast/ast_pretty_print.c
diff options
context:
space:
mode:
authorMartial Simon <msimon_fr@hotmail.com>2025-09-15 01:07:58 +0200
committerMartial Simon <msimon_fr@hotmail.com>2025-09-15 01:07:58 +0200
commit967be9e750221ab2ab783f95df79bb26d290a45e (patch)
tree6802900a5e975f9f68b169f0f503f040056d6952 /42sh/src/ast/ast_pretty_print.c
add: added projectsHEADmain
Diffstat (limited to '42sh/src/ast/ast_pretty_print.c')
-rw-r--r--42sh/src/ast/ast_pretty_print.c247
1 files changed, 247 insertions, 0 deletions
diff --git a/42sh/src/ast/ast_pretty_print.c b/42sh/src/ast/ast_pretty_print.c
new file mode 100644
index 0000000..17c5b2a
--- /dev/null
+++ b/42sh/src/ast/ast_pretty_print.c
@@ -0,0 +1,247 @@
+#undef _POSIX_C_SOURCE
+#define _POSIX_C_SOURCE 200809L
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "ast/ast.h"
+#include "ast/ast_accessors.h"
+#include "ast/ast_redirect.h"
+#include "lexer/token.h"
+
+#define BUFFER_SIZE 10000
+
+static char *_type_to_string[] = { [AST_LOGICAL] = "logical block",
+ [AST_COMMAND] = "command",
+ [AST_IF] = "conditionnal block",
+ [AST_LIST] = "list",
+ [AST_PIPELINE] = "pipeline",
+ [AST_REDIRECTION] = "redirection",
+ [AST_WHILE] = "while",
+ [AST_ASSIGN] = "assign",
+ [AST_FOR] = "for" };
+
+typedef char *(*tostring)(struct ast *);
+
+static char *_args_tostring(struct string **args)
+{
+ struct string *output = string_create(NULL);
+ size_t i = 0;
+ while (args[i])
+ {
+ struct string *c = string_deepcopy(args[i++]);
+ string_catenate(output, c);
+ if (args[i])
+ string_pushstr(output, " - ");
+ }
+ char *data = output->data;
+ free(output);
+ return data;
+}
+
+static char *_ast_command_tostring(struct ast *ast)
+{
+ char buf[BUFFER_SIZE] = { 0 };
+ char *args_to_string = _args_tostring(((struct ast_command *)ast)->args);
+ int len = snprintf(buf, BUFFER_SIZE, "%s\\nargs: %s",
+ _type_to_string[ast->type], args_to_string);
+ free(args_to_string);
+ char *str = malloc((len + 1) * sizeof(char));
+ for (int i = 0; i < len; i++)
+ {
+ str[i] = buf[i];
+ }
+ str[len] = 0;
+ return str;
+}
+
+static char *_ast_if_tostring(struct ast *ast)
+{
+ char buf[BUFFER_SIZE] = { 0 };
+ int len = snprintf(buf, BUFFER_SIZE, "%s\\n", _type_to_string[ast->type]);
+ char *str = malloc((len + 1) * sizeof(char));
+ for (int i = 0; i < len; i++)
+ {
+ str[i] = buf[i];
+ }
+ str[len] = 0;
+ return str;
+}
+
+static char *_get_token_type_to_str(struct ast *ast)
+{
+ enum token_type t = ((struct ast_logical *)ast)->type;
+ switch (t)
+ {
+ case TOKEN_AND:
+ return "&&";
+ case TOKEN_OR:
+ return "||";
+ case TOKEN_NEG:
+ return "!";
+ default:
+ return "unknown";
+ }
+}
+
+static char *_ast_logical_tostring(struct ast *ast)
+{
+ char buf[BUFFER_SIZE] = { 0 };
+ int len = snprintf(buf, BUFFER_SIZE, "%s\\n%s", _type_to_string[ast->type],
+ _get_token_type_to_str(ast));
+ char *str = malloc((len + 1) * sizeof(char));
+ for (int i = 0; i < len; i++)
+ {
+ str[i] = buf[i];
+ }
+ str[len] = 0;
+ return str;
+}
+
+static char *_ast_list_tostring(struct ast *ast)
+{
+ char buf[BUFFER_SIZE] = { 0 };
+ size_t nb_c = ((struct ast_list *)ast)->nb_children;
+ int len = snprintf(buf, BUFFER_SIZE, "%s\\n%lu child(ren)",
+ _type_to_string[ast->type], nb_c);
+ char *str = malloc((len + 1) * sizeof(char));
+ for (int i = 0; i < len; i++)
+ {
+ str[i] = buf[i];
+ }
+ str[len] = 0;
+ return str;
+}
+
+static char *_ast_pipeline_tostring(struct ast *ast)
+{
+ char buf[BUFFER_SIZE] = { 0 };
+ int len = snprintf(buf, BUFFER_SIZE, "%s\\nleft | right",
+ _type_to_string[ast->type]);
+ char *str = malloc((len + 1) * sizeof(char));
+ for (int i = 0; i < len; i++)
+ {
+ str[i] = buf[i];
+ }
+ str[len] = 0;
+ return str;
+}
+
+static char *_ast_assign_tostring(struct ast *ast)
+{
+ char buf[BUFFER_SIZE] = { 0 };
+ struct string *name = ((struct ast_assign *)ast)->name;
+ struct string *value = ((struct ast_assign *)ast)->val;
+ int len = snprintf(buf, BUFFER_SIZE, "%s\\n%s=%s",
+ _type_to_string[ast->type], name->data, value->data);
+ char *str = malloc((len + 1) * sizeof(char));
+ for (int i = 0; i < len; i++)
+ {
+ str[i] = buf[i];
+ }
+ str[len] = 0;
+ return str;
+}
+
+static char *_ast_redirection_tostring(struct ast *ast)
+{
+ struct redirect r = ((struct ast_redirection *)ast)->redirect;
+ char buf[BUFFER_SIZE] = { 0 };
+ int len =
+ snprintf(buf, BUFFER_SIZE, "%s\\n%s %s %s", _type_to_string[ast->type],
+ r.fd->data, r.redir->data, r.file->data);
+ char *str = malloc((len + 1) * sizeof(char));
+ for (int i = 0; i < len; i++)
+ {
+ str[i] = buf[i];
+ }
+ str[len] = 0;
+ return str;
+}
+
+static char *_ast_while_tostring(struct ast *ast)
+{
+ char buf[BUFFER_SIZE] = { 0 };
+ int len = snprintf(buf, BUFFER_SIZE, "%s\\nleft is cond\nright is body",
+ _type_to_string[ast->type]);
+ char *str = malloc((len + 1) * sizeof(char));
+ for (int i = 0; i < len; i++)
+ {
+ str[i] = buf[i];
+ }
+ str[len] = 0;
+ return str;
+}
+
+static char *_ast_for_tostring(struct ast *ast)
+{
+ char buf[BUFFER_SIZE] = { 0 };
+ int len = snprintf(buf, BUFFER_SIZE, "%s\\nleft is words\nright is body",
+ _type_to_string[ast->type]);
+ char *str = malloc((len + 1) * sizeof(char));
+ for (int i = 0; i < len; i++)
+ {
+ str[i] = buf[i];
+ }
+ str[len] = 0;
+ return str;
+}
+
+static const tostring _node_to_string_ltable[] = {
+ [AST_LOGICAL] = _ast_logical_tostring,
+ [AST_COMMAND] = _ast_command_tostring,
+ [AST_IF] = _ast_if_tostring,
+ [AST_LIST] = _ast_list_tostring,
+ [AST_PIPELINE] = _ast_pipeline_tostring,
+ [AST_REDIRECTION] = _ast_redirection_tostring,
+ [AST_WHILE] = _ast_while_tostring,
+ [AST_ASSIGN] = _ast_assign_tostring,
+ [AST_FOR] = _ast_for_tostring
+};
+
+static char *_ast_to_string(struct ast *ast)
+{
+ return _node_to_string_ltable[ast->type](ast);
+}
+
+static void _pretty_print_internal(struct ast *ast, FILE *f)
+{
+ if (!ast)
+ {
+ return;
+ }
+ char *format = _ast_to_string(ast);
+ fprintf(f, "\t%lu [label=\"%s\"];\n", (size_t)ast, format);
+ free(format);
+ size_t i = 0;
+ struct ast *child = NULL;
+ do
+ {
+ child = get_i(ast, i);
+ if (!child)
+ {
+ break;
+ }
+ i++;
+ fprintf(f, "\t%lu -- %lu;\n", (size_t)ast, (size_t)child);
+ _pretty_print_internal(child, f);
+ } while (child);
+}
+
+void pretty_print(struct ast *ast)
+{
+ FILE *f = fopen("ast.dot", "w");
+ if (!f)
+ {
+ fprintf(stderr,
+ "pretty_print: unable to open a file to write the DOT AST.\n");
+ return;
+ }
+
+ fprintf(f, "graph {\n");
+
+ _pretty_print_internal(ast, f);
+
+ fprintf(f, "}\n");
+ fclose(f);
+}