From 603def159756ed07bfbb2335f32e1e56800b52e5 Mon Sep 17 00:00:00 2001 From: "Gu://em_" Date: Tue, 20 Jan 2026 19:25:55 +0100 Subject: [PATCH 1/3] fix: includes with relative path and memory leaks --- src/parser/parsing_utils.c | 57 +++++++++++++++++++++++++------------- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/src/parser/parsing_utils.c b/src/parser/parsing_utils.c index 1841c0c..ea1b113 100644 --- a/src/parser/parsing_utils.c +++ b/src/parser/parsing_utils.c @@ -8,13 +8,13 @@ #include #include -#include "lexer/lexer.h" -#include "utils/ast/ast.h" +#include "../lexer/lexer.h" +#include "../utils/ast/ast.h" // === Static functions /* Returns true if c is a command terminator, false otherwise -*/ + */ static bool isterminator(struct token *token) { if (token == NULL) @@ -22,12 +22,12 @@ static bool isterminator(struct token *token) switch (token->type) { - case TOKEN_NEWLINE: - case TOKEN_SEMICOLON: - case TOKEN_EOF: - return true; - default: - return false; + case TOKEN_NEWLINE: + case TOKEN_SEMICOLON: + case TOKEN_EOF: + return true; + default: + return false; } } @@ -70,7 +70,7 @@ struct ast *parse_list(void) current_node = parse_and_or(); if (current_node == NULL) return NULL; - list_append(result_list, current_node); + result_list = list_append(result_list, current_node); // Following and_or commands token = PEEK_TOKEN(); @@ -82,11 +82,11 @@ struct ast *parse_list(void) current_node = parse_and_or(); if (current_node == NULL) { - //TODO free list - // There must be a function for that + // TODO free list + // There must be a function for that return NULL; } - list_append(result_list, current_node); + result_list = list_append(result_list, current_node); token = PEEK_TOKEN(); } } @@ -135,17 +135,37 @@ struct ast *parse_simple_command(void) while (token->type == TOKEN_WORD) { - token = POP_TOKEN(); - char* word = strdup(token->data); + token = pop_token(); + if (token == NULL) + { + // TODO free + return NULL; + } + char *word = strdup(token->data); + if (word == NULL) + { + // TODO free + puts("Internal error: Couldn't copy token content (is memory full " + "?)"); + return NULL; + } command_elements = list_append(command_elements, word); - token = PEEK_TOKEN(); + token = peek_token(); + if (token == NULL) + { + // TODO free + return NULL; + } } struct ast *result = ast_create_command(command_elements); + if (result == NULL) + { + // TODO free + } return result; } -// TODO check compliance with the grammar struct ast *parse_shell_command(void) { return parse_if_rule(); @@ -158,7 +178,7 @@ struct ast *parse_if_rule(void) if (token->type != TOKEN_IF) { puts("Internal error: expected a if rule but token has different " - "type"); + "type"); return NULL; } @@ -267,7 +287,6 @@ struct ast *parse_compound_list(void) token = POP_TOKEN(); } - struct ast *result = ast_create_list(result_list); return result; } From f1955f0532d425188362b6cc37677f7b209aa750 Mon Sep 17 00:00:00 2001 From: Matteo Flebus Date: Tue, 20 Jan 2026 18:59:40 +0100 Subject: [PATCH 2/3] refactor(lexer): now use struct instead of static var --- src/lexer/lexer.c | 67 ++++++++++++++++++++++------------------------- src/lexer/lexer.h | 15 ++++++++--- 2 files changed, 43 insertions(+), 39 deletions(-) diff --git a/src/lexer/lexer.c b/src/lexer/lexer.c index 1a630e3..bec5e24 100644 --- a/src/lexer/lexer.c +++ b/src/lexer/lexer.c @@ -10,42 +10,37 @@ #include "io_backend/io_backend.h" #include "utils/string_utils/string_utils.h" -static char *end_last_token; -static ssize_t remaining_chars; -static struct token *last_token; -static struct token *current_token; - -/* @brief: sets the current_token to [tok]. +/* @brief: sets the ctx->current_token to [tok]. * this function is called by token_peek(). */ -static void update_current_token(struct token *tok) +static void update_ctx->current_token(struct token *tok, struct lexer_context *ctx) { - current_token = tok; + ctx->current_token = tok; } /* @brief: frees the last token and sets it to [tok]. - * Also sets current_token to NULL. + * Also sets ctx->current_token to NULL. * this function is called by token_pop(). */ -static void update_last_token(struct token *tok) +static void update_ctx->previous_token(struct token *tok, struct lexer_context *ctx) { - free_token(&last_token); - last_token = tok; + free_token(&ctx->previous_token); + ctx->previous_token = tok; } /* @brief: updates the current position in the stream. * [stream] += [i] - * Also frees the last sent token, and sets it to current_token. + * Also frees the last sent token, and sets it to ctx->current_token. * Current token is then set to NULL. * This function is called by token_pop(). */ -static void save_state(char *stream, ssize_t i) +static void save_state(char *stream, ssize_t i, struct lexer_context *ctx) { - remaining_chars -= i; - end_last_token = stream + i; + ctx->remaining_chars -= i; + ctx->end_ctx->previous_token = stream + i; - update_last_token(current_token); - update_current_token(NULL); + update_ctx->previous_token(ctx->current_token); + update_ctx->current_token(NULL); } /* @return: true if a special character from the grammar was found, @@ -204,21 +199,21 @@ void free_token(struct token **tok) *tok = NULL; } -char *stream_init(void) +char *stream_init(struct lexer_context *ctx) { char *stream; - if (last_token == NULL) // at the begining + if (ctx->previous_token == NULL) // at the begining { - remaining_chars = stream_read(&stream); + ctx->remaining_chars = stream_read(&stream); } else { - stream = end_last_token; + stream = ctx->end_ctx->previous_token; } char *trimed_stream = trim_blank_left(stream); - remaining_chars -= trimed_stream - stream; + ctx->remaining_chars -= trimed_stream - stream; stream = trimed_stream; return stream; @@ -259,12 +254,12 @@ static bool update_lexing_mode(char *stream, ssize_t i, return *lexing_mode != mode_before_update; } -struct token *peek_token(void) +struct token *peek_token(struct lexer_context *ctx) { // we already created the upcoming token during the previous call to peek() - if (current_token != NULL) + if (ctx->current_token != NULL) { - return current_token; + return ctx->current_token; } char *stream = stream_init(); @@ -273,7 +268,7 @@ struct token *peek_token(void) // Usefull to know if we are inside a quote or double quote enum lexing_mode lexing_mode = LEXER_NORMAL; - while (i < remaining_chars) + while (i < ctx->remaining_chars) { // true if we didn't encounter a quote of any type at stream[i] // AND we are not inside quotes @@ -302,17 +297,17 @@ struct token *peek_token(void) } struct token *tok = new_token(stream, i); - update_current_token(tok); + update_ctx->current_token(tok); return tok; } -struct token *pop_token(void) +struct token *pop_token(struct lexer_context *ctx) { - if (current_token != NULL && current_token->type == TOKEN_EOF) + if (ctx->current_token != NULL && ctx->current_token->type == TOKEN_EOF) { // we reached end of input, frees all the token still allocated. - free_token(&last_token); - free_token(¤t_token); + free_token(&ctx->previous_token); + free_token(&ctx->current_token); return NULL; } char *stream = stream_init(); @@ -321,7 +316,7 @@ struct token *pop_token(void) // Usefull to know if we are inside a quote or double quote enum lexing_mode lexing_mode = LEXER_NORMAL; - while (i < remaining_chars) + while (i < ctx->remaining_chars) { // true if we didn't encounter a quote of any type at stream[i] // AND we are not inside quotes @@ -351,11 +346,11 @@ struct token *pop_token(void) // just in case peek() was not called before poping. // (this should never happen) - if (current_token == NULL) + if (ctx->current_token == NULL) { - current_token = new_token(stream, i); + ctx->current_token = new_token(stream, i); } save_state(stream, i); - return last_token; + return ctx->previous_token; } diff --git a/src/lexer/lexer.h b/src/lexer/lexer.h index 0da6f17..95c5504 100644 --- a/src/lexer/lexer.h +++ b/src/lexer/lexer.h @@ -3,6 +3,15 @@ #include +struct lexer_context +{ + char *end_last_token; + ssize_t remaining_chars; + + struct token *last_token; + struct token *current_token; +}; + enum lexing_mode { LEXER_NORMAL, @@ -55,7 +64,7 @@ struct token * @brief: returns the next (newly allocated) token without consuming it. * if end of input is reached, returns a token of type TOKEN_EOF. */ -struct token *peek_token(void); +struct token *peek_token(struct lexer_context *ctx); /* * @brief: returns the next (newly allocated) token and consumes it. @@ -66,7 +75,7 @@ struct token *peek_token(void); * and returns NULL. This means that after peeking a token EOF * in the parser, there must be EXACTLY ONE call to pop_token(). */ -struct token *pop_token(void); +struct token *pop_token(struct lexer_context *ctx); /* @note: maybe usefull for subshells. * @@ -96,6 +105,6 @@ void free_token(struct token **tok); * * @return: char* stream from which we tokenise. */ -char *stream_init(void); +char *stream_init(struct lexer_context *ctx); #endif /* ! LEXER_H */ From c3ab2585e1007e57499d13a09fdc62e166d7d070 Mon Sep 17 00:00:00 2001 From: Matteo Flebus Date: Tue, 20 Jan 2026 19:54:29 +0100 Subject: [PATCH 3/3] feat(parser): adapted to new lexer without static var --- src/parser/parser.c | 8 +++++--- src/parser/parser.h | 2 +- src/parser/parsing_utils.c | 20 ++++++++++---------- src/parser/parsing_utils.h | 30 ++++++++++++++---------------- 4 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/parser/parser.c b/src/parser/parser.c index cf7b052..d1fd70a 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -17,22 +17,23 @@ struct ast *get_ast() { + struct lexer_context *ctx = calloc(1, sizeof(struct lexer_context)); struct token *token = PEEK_TOKEN(); struct ast *res; if (token->type == TOKEN_EOF) { - token = pop_token(); + token = pop_token(ctx); return ast_create_end(); } else if (token->type == TOKEN_NEWLINE) { - token = pop_token(); + token = pop_token(ctx); return ast_create_void(); } else // TOKEN WORD { - res = parse_list(); + res = parse_list(ctx); } /* @@ -43,6 +44,7 @@ struct ast *get_ast() return NULL; } */ + destroy_lexer_context(&ctx); return res; } diff --git a/src/parser/parser.h b/src/parser/parser.h index d10cae8..5089212 100644 --- a/src/parser/parser.h +++ b/src/parser/parser.h @@ -10,7 +10,7 @@ * * @warning NOT IMPLEMENTED */ -struct ast *get_ast(); +struct ast *get_ast(void); /* @brief Builds the AST representation of the given command string. * diff --git a/src/parser/parsing_utils.c b/src/parser/parsing_utils.c index ea1b113..12b0f9b 100644 --- a/src/parser/parsing_utils.c +++ b/src/parser/parsing_utils.c @@ -54,12 +54,12 @@ static bool is_end_of_list(struct token *token) // === Functions -struct ast *parse_input(void) +struct ast *parse_input(struct lexer_context *ctx) { return parse_list(); } -struct ast *parse_list(void) +struct ast *parse_list(struct lexer_context *ctx) { struct list *result_list = NULL; struct ast *current_node = NULL; @@ -95,17 +95,17 @@ struct ast *parse_list(void) return ast_create_list(result_list); } -struct ast *parse_and_or(void) +struct ast *parse_and_or(struct lexer_context *ctx) { return parse_pipeline(); } -struct ast *parse_pipeline(void) +struct ast *parse_pipeline(struct lexer_context *ctx) { return parse_command(); } -struct ast *parse_command(void) +struct ast *parse_command(struct lexer_context *ctx) { struct token *token = PEEK_TOKEN(); @@ -123,7 +123,7 @@ struct ast *parse_command(void) } } -struct ast *parse_simple_command(void) +struct ast *parse_simple_command(struct lexer_context *ctx) { struct list *command_elements = NULL; struct token *token = PEEK_TOKEN(); @@ -166,12 +166,12 @@ struct ast *parse_simple_command(void) return result; } -struct ast *parse_shell_command(void) +struct ast *parse_shell_command(struct lexer_context *ctx) { return parse_if_rule(); } -struct ast *parse_if_rule(void) +struct ast *parse_if_rule(struct lexer_context *ctx) { // If keyword struct token *token = POP_TOKEN(); @@ -236,7 +236,7 @@ struct ast *parse_if_rule(void) return result; } -struct ast *parse_compound_list(void) +struct ast *parse_compound_list(struct lexer_context *ctx) { struct list *result_list = NULL; // ast* list struct ast *current_cmd = NULL; @@ -291,7 +291,7 @@ struct ast *parse_compound_list(void) return result; } -struct ast *parse_else_clause(void) +struct ast *parse_else_clause(struct lexer_context *ctx) { struct token *token = PEEK_TOKEN(); diff --git a/src/parser/parsing_utils.h b/src/parser/parsing_utils.h index 5464981..5b32490 100644 --- a/src/parser/parsing_utils.h +++ b/src/parser/parsing_utils.h @@ -4,7 +4,7 @@ // === Macros #define PEEK_TOKEN() \ - peek_token(); \ + peek_token(ctx); \ if (token == NULL) \ { \ puts("Internal error: cannot get the following token"); \ @@ -12,7 +12,7 @@ } #define POP_TOKEN() \ - pop_token(); \ + pop_token(ctx); \ if (token == NULL) \ { \ puts("Internal error: cannot get the following token"); \ @@ -27,26 +27,26 @@ * | EOF * ; */ -struct ast* parse_input(void); +struct ast *parse_input(struct lexer_context *ctx); /* @brief: parses a list of [and_or] rules separated by semicolons and that * ends by a newline * * @code list = and_or { ';' and_or } [ ';' ] ; */ -struct ast *parse_list(void); +struct ast *parse_list(struct lexer_context *ctx); /* @brief Only parses a pipeline rule for the moment * * @code and_or = pipeline ; */ -struct ast *parse_and_or(void); +struct ast *parse_and_or(struct lexer_context *ctx); /* @brief Only parses a command rule for the moment * * @code pipeline = command ; */ -struct ast* parse_pipeline(void); +struct ast *parse_pipeline(struct lexer_context *ctx); /* @brief Parses a simple command rule or a shell command rule depending on * the first token. @@ -58,36 +58,34 @@ struct ast* parse_pipeline(void); * | shell_command * ; */ -struct ast* parse_command(void); +struct ast *parse_command(struct lexer_context *ctx); /* @brief Parses a simple list of words (command and arguments) * ending by a separator * * @code simple_command = WORD { element } ; */ -struct ast *parse_simple_command(void); - +struct ast *parse_simple_command(struct lexer_context *ctx); /* @brief Only parses if rules for the moment * * @code shell_command = if_rule ; */ -struct ast *parse_shell_command(void); - +struct ast *parse_shell_command(struct lexer_context *ctx); /* @brief Parses a if rule (condition, then-clause, elif-clause, else-clause) * * @code if_rule = 'if' compound_list 'then' compound_list [else_clause] 'fi' ; */ -struct ast *parse_if_rule(void); - +struct ast *parse_if_rule(struct lexer_context *ctx); /* @brief parses commands inside if/else clauses and returns the corresponding * AST list * - * @code compound_list = {'\n'} and_or { ( ';' | '\n' ) {'\n'} and_or } [';'] {'\n'} ; + * @code compound_list = {'\n'} and_or { ( ';' | '\n' ) {'\n'} and_or } [';'] + * {'\n'} ; */ -struct ast* parse_compound_list(void); +struct ast *parse_compound_list(struct lexer_context *ctx); /* @brief * @@ -95,6 +93,6 @@ struct ast* parse_compound_list(void); * | 'elif' compound_list 'then' compound_list [else_clause] * ; */ -struct ast *parse_else_clause(void); +struct ast *parse_else_clause(struct lexer_context *ctx); #endif /* ! PARSING_UTILS_H */