From 3445a36a7c89ee561e304497bc2eb74f31221c70 Mon Sep 17 00:00:00 2001 From: Jean Herail Date: Thu, 22 Jan 2026 16:46:33 +0100 Subject: [PATCH 1/4] Pretty_print --- src/main.c | 5 ++ src/utils/ast/ast.c | 165 ++++++++++++++++++++++++++------------------ 2 files changed, 103 insertions(+), 67 deletions(-) diff --git a/src/main.c b/src/main.c index f9c4407..b86a9a7 100644 --- a/src/main.c +++ b/src/main.c @@ -76,6 +76,11 @@ int main(int argc, char **argv) // Retrieve and build first AST struct ast *command_ast = get_ast(ctx); + if (options.pretty_print) + { + ast_print_dot(command_ast); + } + // Main parse-execute loop while (command_ast != NULL && command_ast->type != AST_END) { diff --git a/src/utils/ast/ast.c b/src/utils/ast/ast.c index cd875e7..910fd10 100644 --- a/src/utils/ast/ast.c +++ b/src/utils/ast/ast.c @@ -2,9 +2,91 @@ #include #include +#include #include #include +void ast_free(struct ast **node) +{ + if (!node) + if (*node == NULL) + return; + // ast void does not need to be freed. + if (ast_is_if(*node)) + ast_free_if(ast_get_if(*node)); + else if (ast_is_command(*node)) + ast_free_command(ast_get_command(*node)); + else if (ast_is_list(*node)) + ast_free_list(ast_get_list(*node)); + else if (ast_is_and_or(*node)) + ast_free_and_or(ast_get_and_or(*node)); + else if (ast_is_redir(*node)) + ast_free_redir(ast_get_redir(*node)); +} + +struct ast *ast_create(enum ast_type type, void *data) +{ + struct ast *node = malloc(sizeof(struct ast)); + if (!node) + return NULL; + + node->type = type; + node->data = data; + + return node; +} + +/* struct ast *ast_create_if(struct ast *condition, struct ast *then_clause, + struct ast *else_clause) +{ + struct ast_if *if_data = malloc(sizeof(struct ast_if)); + if (!if_data) + return NULL; + + if_data->condition = condition; + if_data->then_clause = then_clause; + if_data->else_clause = else_clause; + + return ast_create(AST_IF, if_data); +} + +struct ast *ast_create_cmd(struct list *cmd) +{ + struct ast_cmd *cmd_data = malloc(sizeof(struct ast_cmd)); + if (!cmd_data) + return NULL; + + cmd_data->cmd = cmd; + + return ast_create(AST_CMD, cmd_data); +} */ +/* +bool ast_is_if(struct ast *node) +{ + assert(node != NULL); + return node->type == AST_IF; +} + +bool ast_is_cmd(struct ast *node) +{ + assert(node != NULL); + return node->type == AST_CMD; +} + +struct ast_if *ast_get_if(struct ast *node) +{ + assert(node != NULL); + assert(node->type == AST_IF); + return (struct ast_if *)node->data; +} + +struct ast_cmd *ast_get_cmd(struct ast *node) +{ + assert(node != NULL); + assert(node->type == AST_CMD); + return (struct ast_cmd *)node->data; +} + */ static void ast_print_dot_recursive(struct ast *node, FILE *out) { if (!node) @@ -12,6 +94,20 @@ static void ast_print_dot_recursive(struct ast *node, FILE *out) switch (node->type) { + case AST_LIST: { + struct ast_list *ast_list = ast_get_list(node); + fprintf(out, " node%p [label=\"LIST\"];\n", (void *)node); + + struct list *elt = ast_list->children; + while (elt != NULL) + { + struct ast *child = (struct ast *)elt->data; + fprintf(out, " node%p -> node%p;\n", (void *)node, (void *)child); + ast_print_dot_recursive(child, out); + elt = elt->next; + } + break; + } case AST_IF: { struct ast_if *if_data = ast_get_if(node); fprintf(out, " node%p [label=\"IF\"];\n", (void *)node); @@ -44,9 +140,9 @@ static void ast_print_dot_recursive(struct ast *node, FILE *out) break; } case AST_CMD: { - struct ast_cmd *cmd_data = ast_get_cmd(node); + struct ast_command *command_data = ast_get_command(node); fprintf(out, " node%p [label=\"", (void *)node); - struct list *l = cmd_data->cmd; + struct list *l = command_data->command; while (l) { fprintf(out, "%s", (char *)l->data); @@ -80,69 +176,4 @@ void ast_print_dot(struct ast *ast) 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); - return node->type == AST_IF; -} - -bool ast_is_cmd(struct ast *node) -{ - assert(node != NULL); - return node->type == AST_CMD; -} - -struct ast_if *ast_get_if(struct ast *node) -{ - assert(node != NULL); - assert(node->type == AST_IF); - return (struct ast_if *)node->data; -} - -struct ast_cmd *ast_get_cmd(struct ast *node) -{ - assert(node != NULL); - assert(node->type == AST_CMD); - return (struct ast_cmd *)node->data; -} - -static struct ast *ast_create(enum ast_type type, void *data) -{ - struct ast *node = malloc(sizeof(struct ast)); - if (!node) - return NULL; - - node->type = type; - node->data = data; - - return node; -} - -struct ast *ast_create_if(struct ast *condition, struct ast *then_clause, - struct ast *else_clause) -{ - struct ast_if *if_data = malloc(sizeof(struct ast_if)); - if (!if_data) - return NULL; - - if_data->condition = condition; - if_data->then_clause = then_clause; - if_data->else_clause = else_clause; - - return ast_create(AST_IF, if_data); -} - -struct ast *ast_create_cmd(struct list *cmd) -{ - struct ast_cmd *cmd_data = malloc(sizeof(struct ast_cmd)); - if (!cmd_data) - return NULL; - - cmd_data->cmd = cmd; - - return ast_create(AST_CMD, cmd_data); } From 2f2509f1c91b1e560ee8e6888feeab5b1414e8f0 Mon Sep 17 00:00:00 2001 From: Matteo Flebus Date: Thu, 22 Jan 2026 17:19:17 +0100 Subject: [PATCH 2/4] fix: clean merge of pretty-print with no memory leaks --- src/utils/ast/ast.c | 61 ++++++--------------------------------------- 1 file changed, 7 insertions(+), 54 deletions(-) diff --git a/src/utils/ast/ast.c b/src/utils/ast/ast.c index 910fd10..e336a73 100644 --- a/src/utils/ast/ast.c +++ b/src/utils/ast/ast.c @@ -1,3 +1,5 @@ +#define _POSIX_C_SOURCE 12344 + #include "ast.h" #include @@ -8,9 +10,8 @@ void ast_free(struct ast **node) { - if (!node) - if (*node == NULL) - return; + if (*node == NULL) + return; // ast void does not need to be freed. if (ast_is_if(*node)) ast_free_if(ast_get_if(*node)); @@ -22,6 +23,9 @@ void ast_free(struct ast **node) ast_free_and_or(ast_get_and_or(*node)); else if (ast_is_redir(*node)) ast_free_redir(ast_get_redir(*node)); + + free(*node); + *node = NULL; } struct ast *ast_create(enum ast_type type, void *data) @@ -36,57 +40,6 @@ struct ast *ast_create(enum ast_type type, void *data) return node; } -/* struct ast *ast_create_if(struct ast *condition, struct ast *then_clause, - struct ast *else_clause) -{ - struct ast_if *if_data = malloc(sizeof(struct ast_if)); - if (!if_data) - return NULL; - - if_data->condition = condition; - if_data->then_clause = then_clause; - if_data->else_clause = else_clause; - - return ast_create(AST_IF, if_data); -} - -struct ast *ast_create_cmd(struct list *cmd) -{ - struct ast_cmd *cmd_data = malloc(sizeof(struct ast_cmd)); - if (!cmd_data) - return NULL; - - cmd_data->cmd = cmd; - - return ast_create(AST_CMD, cmd_data); -} */ -/* -bool ast_is_if(struct ast *node) -{ - assert(node != NULL); - return node->type == AST_IF; -} - -bool ast_is_cmd(struct ast *node) -{ - assert(node != NULL); - return node->type == AST_CMD; -} - -struct ast_if *ast_get_if(struct ast *node) -{ - assert(node != NULL); - assert(node->type == AST_IF); - return (struct ast_if *)node->data; -} - -struct ast_cmd *ast_get_cmd(struct ast *node) -{ - assert(node != NULL); - assert(node->type == AST_CMD); - return (struct ast_cmd *)node->data; -} - */ static void ast_print_dot_recursive(struct ast *node, FILE *out) { if (!node) From 5faa179b63e49b6f0668f794094a4c77c5249a98 Mon Sep 17 00:00:00 2001 From: Matteo Flebus Date: Thu, 22 Jan 2026 19:06:58 +0100 Subject: [PATCH 3/4] fix(parser): rule if now works --- src/execution/execution.h | 2 +- src/parser/parsing_utils.c | 29 +++++++++++++++++------------ 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/execution/execution.h b/src/execution/execution.h index 872f0ad..c3e0080 100644 --- a/src/execution/execution.h +++ b/src/execution/execution.h @@ -2,8 +2,8 @@ #define EXECUTION_H #include "../utils/ast/ast.h" -#include "../utils/lists/lists.h" #include "../utils/hash_map/hash_map.h" +#include "../utils/lists/lists.h" /** * @brief Execute the AST diff --git a/src/parser/parsing_utils.c b/src/parser/parsing_utils.c index 3be4f05..2273654 100644 --- a/src/parser/parsing_utils.c +++ b/src/parser/parsing_utils.c @@ -78,16 +78,16 @@ struct ast *parse_list(struct lexer_context *ctx) while (token->type == TOKEN_SEMICOLON) { token = POP_TOKEN(); - // if (!isterminator(token)) // Follow(list) + // if (!isterminator(token)) // Follow(list) // { - current_node = parse_and_or(ctx); - if (current_node == NULL) - { - // TODO free list - // There must be a function for that - return NULL; - } - result_list = list_append(result_list, current_node); + current_node = parse_and_or(ctx); + if (current_node == NULL) + { + // TODO free list + // There must be a function for that + return NULL; + } + result_list = list_append(result_list, current_node); // } token = PEEK_TOKEN(); } @@ -247,31 +247,34 @@ struct ast *parse_compound_list(struct lexer_context *ctx) while (token->type == TOKEN_NEWLINE) { token = POP_TOKEN(); + token = PEEK_TOKEN(); } // and_or current_cmd = parse_and_or(ctx); if (current_cmd == NULL) return NULL; - list_append(result_list, current_cmd); + result_list = list_append(result_list, current_cmd); // Following commands token = PEEK_TOKEN(); while (token->type == TOKEN_SEMICOLON || token->type == TOKEN_NEWLINE) { POP_TOKEN(); + token = PEEK_TOKEN(); // Skip newlines while (token->type == TOKEN_NEWLINE) { token = POP_TOKEN(); + token = PEEK_TOKEN(); } // and_or current_cmd = parse_and_or(ctx); if (current_cmd == NULL) return NULL; - list_append(result_list, current_cmd); + result_list = list_append(result_list, current_cmd); token = PEEK_TOKEN(); } @@ -280,12 +283,14 @@ struct ast *parse_compound_list(struct lexer_context *ctx) if (token->type == TOKEN_SEMICOLON) { token = POP_TOKEN(); + token = PEEK_TOKEN(); } // Skip newlines while (token->type == TOKEN_NEWLINE) { token = POP_TOKEN(); + token = PEEK_TOKEN(); } struct ast *result = ast_create_list(result_list); @@ -333,8 +338,8 @@ struct ast *parse_else_clause(struct lexer_context *ctx) if (token->type == TOKEN_ELSE) { + token = POP_TOKEN(); // eat else result = parse_compound_list(ctx); - token = POP_TOKEN(); // Forward } if (result == NULL) From 82f35cfa082f27939946f935711cb65ee6e05f7e Mon Sep 17 00:00:00 2001 From: Matteo Flebus Date: Thu, 22 Jan 2026 19:57:49 +0100 Subject: [PATCH 4/4] feat(parser): and_or_rule in progress --- src/lexer/lexer_utils.c | 8 +++++++ src/lexer/lexer_utils.h | 4 +++- src/parser/parsing_utils.c | 46 +++++++++++++++++++++++++++++++++++++- src/utils/ast/ast_and_or.h | 1 + 4 files changed, 57 insertions(+), 2 deletions(-) diff --git a/src/lexer/lexer_utils.c b/src/lexer/lexer_utils.c index 0a0a23d..4206c4c 100644 --- a/src/lexer/lexer_utils.c +++ b/src/lexer/lexer_utils.c @@ -98,6 +98,14 @@ static void set_token_keyword(struct token *tok, char *begin, ssize_t size) { tok->type = TOKEN_ELIF; } + else if (strncmp(begin, "&&", size) == 0) + { + tok->type = TOKEN_AND; + } + else if (strncmp(begin, "||", size) == 0) + { + tok->type = TOKEN_OR; + } // no keywords found. if (tok->type == TOKEN_NULL) diff --git a/src/lexer/lexer_utils.h b/src/lexer/lexer_utils.h index 729e912..83bc772 100644 --- a/src/lexer/lexer_utils.h +++ b/src/lexer/lexer_utils.h @@ -56,7 +56,9 @@ enum token_type TOKEN_THEN, TOKEN_ELSE, TOKEN_FI, - TOKEN_ELIF + TOKEN_ELIF, + TOKEN_AND, + TOKEN_OR }; struct token diff --git a/src/parser/parsing_utils.c b/src/parser/parsing_utils.c index 2273654..2daeb3d 100644 --- a/src/parser/parsing_utils.c +++ b/src/parser/parsing_utils.c @@ -13,6 +13,20 @@ // === Static functions +enum ast_and_or_type and_or_tok_to_ast(enum token_type tok_type) +{ + switch (tok_type) + { + case TOKEN_AND: + return AST_AND_OR_TYPE_AND; + case TOKEN_OR: + return AST_AND_OR_TYPE_OR; + default: + fprintf(stderr, "and_or impossible to init, wrong token type"); + return AST_AND_OR_NULL; + } +} + /* Returns true if c is a command terminator, false otherwise static bool isterminator(struct token *token) { @@ -98,7 +112,37 @@ struct ast *parse_list(struct lexer_context *ctx) struct ast *parse_and_or(struct lexer_context *ctx) { - return parse_pipeline(ctx); + struct ast *result = parse_pipeline(ctx); + struct token *token = PEEK_TOKEN(); + + if (token->type == TOKEN_AND || token->type == TOKEN_OR) + { + // set left part + + struct ast *left = result; + + // eat and_or token + token = POP_TOKEN(); + + // set type + enum ast_and_or_type type = and_or_tok_to_ast(token->type); + + token = PEEK_TOKEN(); + + // skip newlines + while (token->type == TOKEN_NEWLINE) + { + token = POP_TOKEN(); + token = PEEK_TOKEN(); + } + + // right part + struct ast *right = parse_pipeline(ctx); + + result = ast_create_and_or(left, right, type); + } + + return result; } struct ast *parse_pipeline(struct lexer_context *ctx) diff --git a/src/utils/ast/ast_and_or.h b/src/utils/ast/ast_and_or.h index 7bbe76c..344cfbf 100644 --- a/src/utils/ast/ast_and_or.h +++ b/src/utils/ast/ast_and_or.h @@ -7,6 +7,7 @@ enum ast_and_or_type { + AST_AND_OR_NULL, AST_AND_OR_TYPE_AND, AST_AND_OR_TYPE_OR };