#undef _POSIX_C_SOURCE #define _POSIX_C_SOURCE 200809L #include #include #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); }