From ce5b5f7a38b9ad2d3d1c361e02c0073ddfd6299e Mon Sep 17 00:00:00 2001 From: 552020 Date: Mon, 11 Dec 2023 15:28:54 +0100 Subject: [PATCH 01/29] remove g_debug_level as glorbal variable --- include/minishell.h | 5 +++-- src/lexer/lexer.c | 2 +- src/minishell.c | 6 ++---- src/parser/parser.c | 4 ++-- src/tokenizer/tokenizer.c | 9 ++++++--- src/utils/init.c | 1 + src/utils/read_input.c | 5 +++-- 7 files changed, 18 insertions(+), 14 deletions(-) diff --git a/include/minishell.h b/include/minishell.h index 45bfb85..461aee4 100644 --- a/include/minishell.h +++ b/include/minishell.h @@ -31,7 +31,7 @@ typedef enum e_debug_level DEBUG_ALL // Debug everything } t_debug_level; -extern t_debug_level g_debug_level; +// extern t_debug_level g_debug_level; /* Error messages*/ @@ -272,6 +272,7 @@ typedef struct s_data t_lexeme *lexeme_arr; t_ast_node *ast_root; int last_exit_status; + t_debug_level g_debug_level; } t_data; t_ast_node *parser(t_lexeme *lexemes, int start, int end, @@ -298,7 +299,7 @@ int ft_arrlen(char **arr); /* Varia */ void check_input(int argc, char **argv); -char *read_input(void); +char *read_input(t_data *data); t_token *tokenizer(t_data *data, const char *input); size_t count_words_tokenizer(const char *input); diff --git a/src/lexer/lexer.c b/src/lexer/lexer.c index f76a1d2..5103dff 100644 --- a/src/lexer/lexer.c +++ b/src/lexer/lexer.c @@ -107,7 +107,7 @@ int lexemize(t_data *data) { create_lexeme_arr(data); data->lexeme_arr = lexer(data); - if (g_debug_level == DEBUG_ALL || g_debug_level == DEBUG_LEXER) + if (data->g_debug_level == DEBUG_ALL || data->g_debug_level == DEBUG_LEXER) { printf("\n***Lexer***\n\n"); print_lexeme_arr(data->lexeme_arr, data->token_count); diff --git a/src/minishell.c b/src/minishell.c index 97fb60d..6584af8 100644 --- a/src/minishell.c +++ b/src/minishell.c @@ -12,9 +12,6 @@ #include "minishell.h" -// t_debug_level g_debug_level = DEBUG_ALL; -t_debug_level g_debug_level = DEBUG_OFF; - void execute_main(t_data *data, int *exit_status) { if (handle_heredocs(data->ast_root, data) == SUCCESS) @@ -34,10 +31,11 @@ int main(int argc, char **argv, char **envp) check_input(argc, argv); initialize_data(envp, &data); + // data.g_debug_level = DEBUG_ALL; while (1) { handle_signals_main(); - input = read_input(); + input = read_input(&data); tokenize(&data, input); if (lexemize(&data) == SUCCESS) { diff --git a/src/parser/parser.c b/src/parser/parser.c index 593fc54..e037d1c 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -14,10 +14,10 @@ void parse(t_data *data) { - if (g_debug_level == DEBUG_ALL || g_debug_level == DEBUG_AST) + if (data->g_debug_level == DEBUG_ALL || data->g_debug_level == DEBUG_AST) printf("***Parsing***\n\n"); data->ast_root = parser(data->lexeme_arr, 0, data->token_count - 1, data); - if (g_debug_level == DEBUG_ALL || g_debug_level == DEBUG_AST) + if (data->g_debug_level == DEBUG_ALL || data->g_debug_level == DEBUG_AST) { printf("\n***Printing AST***\n\n"); print_ast(data->ast_root, 7); diff --git a/src/tokenizer/tokenizer.c b/src/tokenizer/tokenizer.c index 78ae416..0e62b3b 100644 --- a/src/tokenizer/tokenizer.c +++ b/src/tokenizer/tokenizer.c @@ -72,7 +72,8 @@ void tokenize(t_data *data, char *input) char *reshuffled; char *expanded; - if (g_debug_level == DEBUG_ALL || g_debug_level == DEBUG_TOKENIZER) + if (data->g_debug_level == DEBUG_ALL + || data->g_debug_level == DEBUG_TOKENIZER) printf("\n***Tokenization***\n\n"); trimmed = strip_ending_trailing_spaces(input); tmp = reshuffle_single_quotes(trimmed); @@ -86,7 +87,8 @@ void tokenize(t_data *data, char *input) // printf("Expanded: %s\n", expanded); input = NULL; data->token_count = count_words_tokenizer(expanded); - if (g_debug_level == DEBUG_ALL || g_debug_level == DEBUG_TOKENIZER) + if (data->g_debug_level == DEBUG_ALL + || data->g_debug_level == DEBUG_TOKENIZER) printf("Token count: %zu\n\n", data->token_count); data->token_arr = create_token_array(data); data->token_arr = tokenizer(data, expanded); @@ -95,6 +97,7 @@ void tokenize(t_data *data, char *input) free(expanded); expanded = NULL; } - if (g_debug_level == DEBUG_ALL || g_debug_level == DEBUG_TOKENIZER) + if (data->g_debug_level == DEBUG_ALL + || data->g_debug_level == DEBUG_TOKENIZER) print_token_arr(data->token_arr, data->token_count); } diff --git a/src/utils/init.c b/src/utils/init.c index 7e9c3d1..8d65c04 100644 --- a/src/utils/init.c +++ b/src/utils/init.c @@ -31,4 +31,5 @@ void initialize_data(char **envp, t_data *data) free_exit(data, "Error: malloc data->env_table failed\n"); initialize_table(envp, data); initialize_envp_arr(data); + data->g_debug_level = DEBUG_OFF; } diff --git a/src/utils/read_input.c b/src/utils/read_input.c index b892ddc..1df8b12 100644 --- a/src/utils/read_input.c +++ b/src/utils/read_input.c @@ -12,7 +12,7 @@ #include "minishell.h" -char *read_input(void) +char *read_input(t_data *data) { char *input; @@ -23,7 +23,8 @@ char *read_input(void) exit(0); } add_history(input); - if (g_debug_level == DEBUG_ALL || g_debug_level == DEBUG_TOKENIZER) + if (data->g_debug_level == DEBUG_ALL + || data->g_debug_level == DEBUG_TOKENIZER) printf("readline: %s\n", input); return (input); } From ea219c85b6e92b282ed2eb6c4735cb51316f17e4 Mon Sep 17 00:00:00 2001 From: 552020 Date: Mon, 11 Dec 2023 15:29:54 +0100 Subject: [PATCH 02/29] rename g_deubug_level to debug_level --- include/minishell.h | 4 ++-- src/lexer/lexer.c | 2 +- src/minishell.c | 2 +- src/parser/parser.c | 4 ++-- src/tokenizer/tokenizer.c | 12 ++++++------ src/utils/init.c | 2 +- src/utils/read_input.c | 3 +-- 7 files changed, 14 insertions(+), 15 deletions(-) diff --git a/include/minishell.h b/include/minishell.h index 461aee4..469eea3 100644 --- a/include/minishell.h +++ b/include/minishell.h @@ -31,7 +31,7 @@ typedef enum e_debug_level DEBUG_ALL // Debug everything } t_debug_level; -// extern t_debug_level g_debug_level; +// extern t_debug_level debug_level; /* Error messages*/ @@ -272,7 +272,7 @@ typedef struct s_data t_lexeme *lexeme_arr; t_ast_node *ast_root; int last_exit_status; - t_debug_level g_debug_level; + t_debug_level debug_level; } t_data; t_ast_node *parser(t_lexeme *lexemes, int start, int end, diff --git a/src/lexer/lexer.c b/src/lexer/lexer.c index 5103dff..569aff3 100644 --- a/src/lexer/lexer.c +++ b/src/lexer/lexer.c @@ -107,7 +107,7 @@ int lexemize(t_data *data) { create_lexeme_arr(data); data->lexeme_arr = lexer(data); - if (data->g_debug_level == DEBUG_ALL || data->g_debug_level == DEBUG_LEXER) + if (data->debug_level == DEBUG_ALL || data->debug_level == DEBUG_LEXER) { printf("\n***Lexer***\n\n"); print_lexeme_arr(data->lexeme_arr, data->token_count); diff --git a/src/minishell.c b/src/minishell.c index 6584af8..04f5a52 100644 --- a/src/minishell.c +++ b/src/minishell.c @@ -31,7 +31,7 @@ int main(int argc, char **argv, char **envp) check_input(argc, argv); initialize_data(envp, &data); - // data.g_debug_level = DEBUG_ALL; + // data.debug_level = DEBUG_ALL; while (1) { handle_signals_main(); diff --git a/src/parser/parser.c b/src/parser/parser.c index e037d1c..1778f7c 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -14,10 +14,10 @@ void parse(t_data *data) { - if (data->g_debug_level == DEBUG_ALL || data->g_debug_level == DEBUG_AST) + if (data->debug_level == DEBUG_ALL || data->debug_level == DEBUG_AST) printf("***Parsing***\n\n"); data->ast_root = parser(data->lexeme_arr, 0, data->token_count - 1, data); - if (data->g_debug_level == DEBUG_ALL || data->g_debug_level == DEBUG_AST) + if (data->debug_level == DEBUG_ALL || data->debug_level == DEBUG_AST) { printf("\n***Printing AST***\n\n"); print_ast(data->ast_root, 7); diff --git a/src/tokenizer/tokenizer.c b/src/tokenizer/tokenizer.c index 0e62b3b..67c85a1 100644 --- a/src/tokenizer/tokenizer.c +++ b/src/tokenizer/tokenizer.c @@ -72,8 +72,8 @@ void tokenize(t_data *data, char *input) char *reshuffled; char *expanded; - if (data->g_debug_level == DEBUG_ALL - || data->g_debug_level == DEBUG_TOKENIZER) + if (data->debug_level == DEBUG_ALL + || data->debug_level == DEBUG_TOKENIZER) printf("\n***Tokenization***\n\n"); trimmed = strip_ending_trailing_spaces(input); tmp = reshuffle_single_quotes(trimmed); @@ -87,8 +87,8 @@ void tokenize(t_data *data, char *input) // printf("Expanded: %s\n", expanded); input = NULL; data->token_count = count_words_tokenizer(expanded); - if (data->g_debug_level == DEBUG_ALL - || data->g_debug_level == DEBUG_TOKENIZER) + if (data->debug_level == DEBUG_ALL + || data->debug_level == DEBUG_TOKENIZER) printf("Token count: %zu\n\n", data->token_count); data->token_arr = create_token_array(data); data->token_arr = tokenizer(data, expanded); @@ -97,7 +97,7 @@ void tokenize(t_data *data, char *input) free(expanded); expanded = NULL; } - if (data->g_debug_level == DEBUG_ALL - || data->g_debug_level == DEBUG_TOKENIZER) + if (data->debug_level == DEBUG_ALL + || data->debug_level == DEBUG_TOKENIZER) print_token_arr(data->token_arr, data->token_count); } diff --git a/src/utils/init.c b/src/utils/init.c index 8d65c04..43579af 100644 --- a/src/utils/init.c +++ b/src/utils/init.c @@ -31,5 +31,5 @@ void initialize_data(char **envp, t_data *data) free_exit(data, "Error: malloc data->env_table failed\n"); initialize_table(envp, data); initialize_envp_arr(data); - data->g_debug_level = DEBUG_OFF; + data->debug_level = DEBUG_OFF; } diff --git a/src/utils/read_input.c b/src/utils/read_input.c index 1df8b12..be0141f 100644 --- a/src/utils/read_input.c +++ b/src/utils/read_input.c @@ -23,8 +23,7 @@ char *read_input(t_data *data) exit(0); } add_history(input); - if (data->g_debug_level == DEBUG_ALL - || data->g_debug_level == DEBUG_TOKENIZER) + if (data->debug_level == DEBUG_ALL || data->debug_level == DEBUG_TOKENIZER) printf("readline: %s\n", input); return (input); } From 3af540e78b64fc2588a061165ebf35eb87dffae3 Mon Sep 17 00:00:00 2001 From: 552020 Date: Tue, 12 Dec 2023 08:49:53 +0100 Subject: [PATCH 03/29] move commented out debugging line outside the function --- src/minishell.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/minishell.c b/src/minishell.c index 04f5a52..e246112 100644 --- a/src/minishell.c +++ b/src/minishell.c @@ -23,6 +23,10 @@ void execute_main(t_data *data, int *exit_status) } } +/* +to debug add this line in main, before the while loop: +data.debug_level = DEBUG_ALL; +*/ int main(int argc, char **argv, char **envp) { char *input; @@ -31,7 +35,6 @@ int main(int argc, char **argv, char **envp) check_input(argc, argv); initialize_data(envp, &data); - // data.debug_level = DEBUG_ALL; while (1) { handle_signals_main(); From cd7b674c60f6271c8bca327f12fded01721ff418 Mon Sep 17 00:00:00 2001 From: 552020 Date: Wed, 13 Dec 2023 13:28:57 +0100 Subject: [PATCH 04/29] update isspecialchar adding logic for &&, || and () --- src/tokenizer/utils.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/tokenizer/utils.c b/src/tokenizer/utils.c index 2e28b23..51223a7 100644 --- a/src/tokenizer/utils.c +++ b/src/tokenizer/utils.c @@ -19,10 +19,12 @@ int ft_isspace(int c) else return (0); } - +// TODO: the logic for parentheses could be improved +// we should check if the parentheses are balanced int isspecialchar(char c, const char *str) { - if (c == '<' || c == '>' || c == '|' || c == '$' || c == '"' || c == '\'') + if (c == '<' || c == '>' || c == '|' || c == '$' || c == '"' || c == '\'' + || c == '(' || c == ')' || (c == '&' && *(str + 1) == '&')) { if (c == '$') { From 8019f27db350b6c6c4d77717bcbe44633ae9b3f1 Mon Sep 17 00:00:00 2001 From: 552020 Date: Wed, 13 Dec 2023 13:40:49 +0100 Subject: [PATCH 05/29] improve count_words_special_chars --- src/tokenizer/count_words.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/tokenizer/count_words.c b/src/tokenizer/count_words.c index 8827fe4..4b831f4 100644 --- a/src/tokenizer/count_words.c +++ b/src/tokenizer/count_words.c @@ -54,6 +54,18 @@ void count_word_special_char(const char **str_ptr, size_t *words) parse_redirect(str_ptr); else if (**str_ptr == '\'' || **str_ptr == '"') parse_quotes(str_ptr); + else if (**str_ptr == '&' && *(*str_ptr + 1) == '&') + (*str_ptr) += 2; + else if (**str_ptr == '|') + { + (*str_ptr)++; + if (**str_ptr == '|') + (*str_ptr)++; + } + else if (**str_ptr == '(') + (*str_ptr)++; + else if (**str_ptr == ')') + (*str_ptr)++; else { if (**str_ptr) From 0d4ae454691db35ae8feab457b671bf62f586a36 Mon Sep 17 00:00:00 2001 From: 552020 Date: Wed, 13 Dec 2023 13:43:53 +0100 Subject: [PATCH 06/29] remove unecessary strdup of | in the case of pipe to the string field of the t_token --- src/tokenizer/assign.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/tokenizer/assign.c b/src/tokenizer/assign.c index b0ae98a..4a101ac 100644 --- a/src/tokenizer/assign.c +++ b/src/tokenizer/assign.c @@ -29,9 +29,6 @@ void assign_word(const char **str_ptr, t_data *data, size_t *idx) void assign_pipe(const char **str_ptr, t_data *data, size_t *idx) { data->token_arr[*idx].type = T_PIPE; - data->token_arr[*idx].str = ft_strdup("|"); - if (!data->token_arr[*idx].str) - free_exit(data, "Error: ft_strdup failed\n"); (*idx)++; (*str_ptr)++; } From 95dc58f17da7c3b85472a8fcf9be91d5d1ee40a3 Mon Sep 17 00:00:00 2001 From: 552020 Date: Wed, 13 Dec 2023 13:49:48 +0100 Subject: [PATCH 07/29] add logic in the tokenizer for new symbols - pull internal loop to external function - initialise all token to T_UNKNOWN type --- src/tokenizer/tokenizer.c | 79 +++++++++++++++++++++++++++------------ 1 file changed, 56 insertions(+), 23 deletions(-) diff --git a/src/tokenizer/tokenizer.c b/src/tokenizer/tokenizer.c index 67c85a1..c653f38 100644 --- a/src/tokenizer/tokenizer.c +++ b/src/tokenizer/tokenizer.c @@ -30,36 +30,72 @@ char *strip_ending_trailing_spaces(char const *str) t_token *create_token_array(t_data *data) { t_token *token_arr; + size_t idx; token_arr = (t_token *)ft_calloc(data->token_count + 1, sizeof(t_token)); if (!token_arr) free_exit(data, "Error: ft_calloc failed\n"); + idx = 0; + while (idx < data->token_count) + { + token_arr[idx].type = T_UNKNOWN; + token_arr[idx].str = NULL; + idx++; + } + token_arr[idx].type = T_END; + token_arr[idx].str = NULL; return (token_arr); } +void tokenizer_internal_loop(t_data *data, const char *str, size_t *idx) +{ + skip_spaces(&str); + if (isregularchar(*str, str)) + assign_word(&str, data, &idx); + else if (*str == '(') + assign_parentheses_open(&str, data, &idx); + else if (*str == ')') + assign_parentheses_close(&str, data, &idx); + else if (*str == '&' && *(str + 1) == '&') + assign_log_and(&str, data, &idx); + else if (*str == '|' && *(str + 1) == '|') + assign_log_or(&str, data, &idx); + else if (*str == '<' || *str == '>') + assign_redirect_in_out_heredoc_append(&str, data, &idx); + else if (*str == '|') + assign_pipe(&str, data, &idx); + else if (*str == '$') + assign_env_var(&str, data, &idx); + else if (*str == '\'' || *str == '"') + assign_quotes(&str, data, &idx); + else + handle_unexpected_char(&str); +} + t_token *tokenizer(t_data *data, const char *str) { size_t idx; idx = 0; while (*str) - { - skip_spaces(&str); - if (isregularchar(*str, str)) - assign_word(&str, data, &idx); - else if (*str == '<' || *str == '>') - assign_redirect_in_out_heredoc_append(&str, data, &idx); - else if (*str == '|') - assign_pipe(&str, data, &idx); - else if (*str == '$' && *(str + 1) == '?') - assign_shell_var(&str, data, &idx); - else if (*str == '$') - assign_env_var(&str, data, &idx); - else if (*str == '\'' || *str == '"') - assign_quotes(&str, data, &idx); - else - handle_unexpected_char(&str); - } + tokenizer_internal_loop(data, str, &idx); + // { + // skip_spaces(&str); + // if (isregularchar(*str, str)) + // assign_word(&str, data, &idx); + // else if (*str == '<' || *str == '>') + // assign_redirect_in_out_heredoc_append(&str, data, &idx); + // else if (*str == '|') + // assign_pipe(&str, data, &idx); + // else if (*str == '$' && *(str + 1) == '?') + // assign_shell_var(&str, data, &idx); + // else if (*str == '$') + // assign_env_var(&str, data, &idx); + // else if (*str == '\'' || *str == '"') + // assign_quotes(&str, data, &idx); + // else + // handle_unexpected_char(&str); + // } data->token_arr[idx].type = T_END; data->token_arr[idx].str = NULL; return (data->token_arr); @@ -72,8 +108,7 @@ void tokenize(t_data *data, char *input) char *reshuffled; char *expanded; - if (data->debug_level == DEBUG_ALL - || data->debug_level == DEBUG_TOKENIZER) + if (data->debug_level == DEBUG_ALL || data->debug_level == DEBUG_TOKENIZER) printf("\n***Tokenization***\n\n"); trimmed = strip_ending_trailing_spaces(input); tmp = reshuffle_single_quotes(trimmed); @@ -87,8 +122,7 @@ void tokenize(t_data *data, char *input) // printf("Expanded: %s\n", expanded); input = NULL; data->token_count = count_words_tokenizer(expanded); - if (data->debug_level == DEBUG_ALL - || data->debug_level == DEBUG_TOKENIZER) + if (data->debug_level == DEBUG_ALL || data->debug_level == DEBUG_TOKENIZER) printf("Token count: %zu\n\n", data->token_count); data->token_arr = create_token_array(data); data->token_arr = tokenizer(data, expanded); @@ -97,7 +131,6 @@ void tokenize(t_data *data, char *input) free(expanded); expanded = NULL; } - if (data->debug_level == DEBUG_ALL - || data->debug_level == DEBUG_TOKENIZER) + if (data->debug_level == DEBUG_ALL || data->debug_level == DEBUG_TOKENIZER) print_token_arr(data->token_arr, data->token_count); } From 7f38596e8059b07cd1e485094570692c1f688a9e Mon Sep 17 00:00:00 2001 From: 552020 Date: Wed, 13 Dec 2023 14:04:54 +0100 Subject: [PATCH 08/29] complete tokenizer --- Makefile | 4 ++-- include/minishell.h | 12 +++++++--- src/debug/debug.c | 46 ++++++++++++++++++++---------------- src/tokenizer/assign_bonus.c | 42 ++++++++++++++++++++++++++++++++ src/tokenizer/tokenizer.c | 44 +++++++++++++++++----------------- src/tokenizer/tokenizer.h | 27 +++++++++++++++++++++ 6 files changed, 127 insertions(+), 48 deletions(-) create mode 100644 src/tokenizer/assign_bonus.c create mode 100644 src/tokenizer/tokenizer.h diff --git a/Makefile b/Makefile index 937b730..8ab1f70 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ UNAME_S := $(shell uname -s) # # Set include paths conditionally ifeq ($(UNAME_S), Darwin) CFLAGS += -fsanitize=address -g -O1 - INCLUDES = -I./include -I./libft/include -I/opt/homebrew/opt/readline/include -I./libft/include -I/usr/local/opt/readline/include -I./src/wildcard + INCLUDES = -I./include -I./libft/include -I/opt/homebrew/opt/readline/include -I./libft/include -I/usr/local/opt/readline/include -I./src/wildcard -I./src/tokenizer else INCLUDES = -I./include -I./libft/include -I./src/wildcard @@ -39,7 +39,7 @@ endif # endif SRCS = minishell.c \ - tokenizer/tokenizer.c tokenizer/utils.c tokenizer/assign.c tokenizer/count_words.c tokenizer/assign_redirect.c tokenizer/reshuffle_quotes.c tokenizer/reshuffle_quotes_utils.c \ + tokenizer/tokenizer.c tokenizer/utils.c tokenizer/assign.c tokenizer/count_words.c tokenizer/assign_redirect.c tokenizer/reshuffle_quotes.c tokenizer/reshuffle_quotes_utils.c tokenizer/assign_bonus.c \ wildcard/wildcard.c wildcard/build_pattern.c wildcard/build_pattern_init.c wildcard/free.c wildcard/utils.c wildcard/init_entries.c wildcard/matching.c wildcard/matching_utils.c \ lexer/lexer.c lexer/lexemes_redirect.c lexer/lexemes.c lexer/quotes.c lexer/var_subs.c lexer/wrappers.c lexer/lexer_helper.c lexer/check_syntax.c lexer/lexer_helper.c lexer/quotes_helper.c \ parser/parser.c parser/create_node.c parser/fill_node_cmd_args.c parser/fill_node_redirects.c parser/parser_utils.c \ diff --git a/include/minishell.h b/include/minishell.h index 469eea3..42e8904 100644 --- a/include/minishell.h +++ b/include/minishell.h @@ -1,4 +1,5 @@ #include "libft.h" +#include "tokenizer.h" #include // Comment needed to prevent autoformat to move the include above the comment #include @@ -86,9 +87,14 @@ typedef enum e_token_type // 7 - " the whole string in between " quotes included T_SINGLE_QUOTE, // 8 - ' the whole string in between ' quotes included - T_ENV_VAR, // 9 - $ followed by a valid variable name - T_SHELL_VAR, // 10 - $ followed by a shell variable symbol like $? - T_END, // 11 - End of token array + T_ENV_VAR, // 9 - $ followed by a valid variable name + T_SHELL_VAR, // 10 - $ followed by a shell variable symbol like $? + T_END, // 11 - End of token array + T_UNKNOWN, // 12 - Unknown token + T_LOG_OR, // 13 - || + T_LOG_AND, // 14 - && + T_PARENTHESES_OPEN, // 15 - ( + T_PARENTHESES_CLOSE, // 16 - ) } t_token_type; typedef struct s_token diff --git a/src/debug/debug.c b/src/debug/debug.c index 527ccd0..2cf1546 100644 --- a/src/debug/debug.c +++ b/src/debug/debug.c @@ -30,6 +30,20 @@ void print_token_arr(t_token *token_arr, size_t token_count) token_type = "T_ENV_VAR"; else if (token_arr[i].type == T_SHELL_VAR) token_type = "T_SHELL_VAR"; + else if (token_arr[i].type == T_DOUBLE_QUOTE) + token_type = "T_DOUBLE_QUOTE"; + else if (token_arr[i].type == T_SINGLE_QUOTE) + token_type = "T_SINGLE_QUOTE"; + else if (token_arr[i].type == T_ENV_VAR) + token_type = "T_ENV_VAR"; + else if (token_arr[i].type == T_LOG_OR) + token_type = "T_LOG_OR"; + else if (token_arr[i].type == T_LOG_AND) + token_type = "T_LOG_AND"; + else if (token_arr[i].type == T_PARENTHESES_OPEN) + token_type = "T_PARENTHESES_OPEN"; + else if (token_arr[i].type == T_PARENTHESES_CLOSE) + token_type = "T_PARENTHESES_CLOSE"; else if (token_arr[i].type == T_END) token_type = "T_END"; else @@ -84,14 +98,16 @@ void print_lexeme_arr(t_lexeme *lexeme_arr, size_t lexeme_count) // for is not allowed!!! void print_ast(t_ast_node *node, int depth) { - // Print indentation - for (int i = 0; i < depth; ++i) + int i; + + i = 0; + while (i < depth) + { printf("- "); - // Print node type and cmd + i++; + } if (node->type == N_PIPE) - { printf("|\n"); - } else if (node->type == N_COMMAND) { printf("%s", node->cmd); @@ -104,7 +120,6 @@ void print_ast(t_ast_node *node, int depth) } printf("\n"); } - // Print children if (node->children[0]) print_ast(node->children[0], depth + 1); if (node->children[1]) @@ -119,9 +134,7 @@ int get_max_depth(t_ast_node *node) return (0); if (node->type == N_COMMAND) return (1); - // If it's a pipe node, we compute the depth of the left child left_depth = get_max_depth(node->children[0]); - // Since it's a pipe, it means there's an additional depth left_depth++; return (left_depth); } @@ -190,8 +203,7 @@ void print_node(t_ast_node *node, int depth, bool is_last_sibling[]) void print_ast_new(t_ast_node *root) { - bool is_last_sibling[100] = {false}; - + bool is_last_sibling[100] = {false}; // Assuming a max depth of 100; can be dynamically allocated if needed print_node(root, 0, is_last_sibling); } @@ -205,19 +217,12 @@ void print_node_info(t_ast_node *node) printf("Node is NULL\n"); return ; } - switch (node->type) - { - case N_PIPE: + if (node->type == N_PIPE) printf("Type: PIPE\n"); - break ; - case N_COMMAND: + else if (node->type == N_COMMAND) printf("Type: COMMAND\n"); - break ; - default: + else printf("Type: UNKNOWN\n"); - break ; - } - // Print data if (node->cmd) { printf("cmd: %s\n", node->cmd); @@ -226,7 +231,6 @@ void print_node_info(t_ast_node *node) { printf("Cmd: NULL\n"); } - // Print arguments if (node->args) { printf("Arguments: "); diff --git a/src/tokenizer/assign_bonus.c b/src/tokenizer/assign_bonus.c new file mode 100644 index 0000000..890fe74 --- /dev/null +++ b/src/tokenizer/assign_bonus.c @@ -0,0 +1,42 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* assign_bonus.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: slombard +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2023/12/13 13:10:30 by slombard #+# #+# */ +/* Updated: 2023/12/13 13:10:33 by slombard ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" +#include "tokenizer.h" + +void assign_parentheses_open(const char **str, t_data *data, size_t *idx) +{ + data->token_arr[*idx].type = T_PARENTHESES_OPEN; + (*idx)++; + (*str)++; +} + +void assign_parentheses_close(const char **str, t_data *data, size_t *idx) +{ + data->token_arr[*idx].type = T_PARENTHESES_CLOSE; + (*idx)++; + (*str)++; +} + +void assign_log_and(const char **str, t_data *data, size_t *idx) +{ + data->token_arr[*idx].type = T_LOG_AND; + (*idx)++; + (*str) += 2; +} + +void assign_log_or(const char **str, t_data *data, size_t *idx) +{ + data->token_arr[*idx].type = T_LOG_OR; + (*idx)++; + (*str) += 2; +} diff --git a/src/tokenizer/tokenizer.c b/src/tokenizer/tokenizer.c index c653f38..17cc313 100644 --- a/src/tokenizer/tokenizer.c +++ b/src/tokenizer/tokenizer.c @@ -47,29 +47,29 @@ t_token *create_token_array(t_data *data) return (token_arr); } -void tokenizer_internal_loop(t_data *data, const char *str, size_t *idx) +void tokenizer_internal_loop(t_data *data, const char **str, size_t *idx) { - skip_spaces(&str); - if (isregularchar(*str, str)) - assign_word(&str, data, &idx); - else if (*str == '(') - assign_parentheses_open(&str, data, &idx); - else if (*str == ')') - assign_parentheses_close(&str, data, &idx); - else if (*str == '&' && *(str + 1) == '&') - assign_log_and(&str, data, &idx); - else if (*str == '|' && *(str + 1) == '|') - assign_log_or(&str, data, &idx); - else if (*str == '<' || *str == '>') - assign_redirect_in_out_heredoc_append(&str, data, &idx); - else if (*str == '|') - assign_pipe(&str, data, &idx); - else if (*str == '$') - assign_env_var(&str, data, &idx); - else if (*str == '\'' || *str == '"') - assign_quotes(&str, data, &idx); + skip_spaces(str); + if (isregularchar(**str, *str)) + assign_word(str, data, idx); + else if (**str == '(') + assign_parentheses_open(str, data, idx); + else if (**str == ')') + assign_parentheses_close(str, data, idx); + else if (**str == '&' && *(*str + 1) == '&') + assign_log_and(str, data, idx); + else if (**str == '|' && *(*str + 1) == '|') + assign_log_or(str, data, idx); + else if (**str == '<' || **str == '>') + assign_redirect_in_out_heredoc_append(str, data, idx); + else if (**str == '|') + assign_pipe(str, data, idx); + else if (**str == '$') + assign_env_var(str, data, idx); + else if (**str == '\'' || **str == '"') + assign_quotes(str, data, idx); else - handle_unexpected_char(&str); + handle_unexpected_char(str); } t_token *tokenizer(t_data *data, const char *str) @@ -78,7 +78,7 @@ t_token *tokenizer(t_data *data, const char *str) idx = 0; while (*str) - tokenizer_internal_loop(data, str, &idx); + tokenizer_internal_loop(data, &str, &idx); // { // skip_spaces(&str); // if (isregularchar(*str, str)) diff --git a/src/tokenizer/tokenizer.h b/src/tokenizer/tokenizer.h new file mode 100644 index 0000000..0491c23 --- /dev/null +++ b/src/tokenizer/tokenizer.h @@ -0,0 +1,27 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* tokenizer.h :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: slombard +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2023/12/12 08:52:35 by slombard #+# #+# */ +/* Updated: 2023/12/12 08:52:38 by slombard ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#ifndef TOKENIZER_H +#define TOKENIZER_H + +#ifndef MINISHELL_H + +#include "minishell.h" +#endif + +void assign_parentheses_open(const char **str, t_data *data, size_t *idx); +void assign_parentheses_close(const char **str, t_data *data, size_t *idx); +void assign_log_and(const char **str, t_data *data, size_t *idx); +void assign_log_or(const char **str, t_data *data, size_t *idx); +// void assign_redirect_in(const char **str, t_data *data, size_t *idx); + +#endif From e8566fc520c4a7331e6f982902bba8509d76f17e Mon Sep 17 00:00:00 2001 From: 552020 Date: Wed, 13 Dec 2023 14:38:02 +0100 Subject: [PATCH 09/29] update lexer --- Makefile | 2 +- include/minishell.h | 41 ++++++++++++++--------- src/debug/debug.c | 8 ++--- src/lexer/lexemes.c | 12 ------- src/lexer/lexemes_bonus.c | 60 ++++++++++++++++++++++++++++++++++ src/lexer/lexer.c | 12 +++++++ src/lexer/lexer_helper.c | 6 +++- src/lexer/lexer_helper_bonus.c | 49 +++++++++++++++++++++++++++ src/tokenizer/assign_bonus.c | 4 +-- src/utils/free_functions.c | 2 -- 10 files changed, 158 insertions(+), 38 deletions(-) create mode 100644 src/lexer/lexemes_bonus.c create mode 100644 src/lexer/lexer_helper_bonus.c diff --git a/Makefile b/Makefile index 8ab1f70..d0e6086 100644 --- a/Makefile +++ b/Makefile @@ -41,7 +41,7 @@ endif SRCS = minishell.c \ tokenizer/tokenizer.c tokenizer/utils.c tokenizer/assign.c tokenizer/count_words.c tokenizer/assign_redirect.c tokenizer/reshuffle_quotes.c tokenizer/reshuffle_quotes_utils.c tokenizer/assign_bonus.c \ wildcard/wildcard.c wildcard/build_pattern.c wildcard/build_pattern_init.c wildcard/free.c wildcard/utils.c wildcard/init_entries.c wildcard/matching.c wildcard/matching_utils.c \ - lexer/lexer.c lexer/lexemes_redirect.c lexer/lexemes.c lexer/quotes.c lexer/var_subs.c lexer/wrappers.c lexer/lexer_helper.c lexer/check_syntax.c lexer/lexer_helper.c lexer/quotes_helper.c \ + lexer/lexer.c lexer/lexemes_redirect.c lexer/lexemes.c lexer/lexemes_bonus.c lexer/quotes.c lexer/var_subs.c lexer/wrappers.c lexer/lexer_helper.c lexer/lexer_helper_bonus.c lexer/check_syntax.c lexer/lexer_helper.c lexer/quotes_helper.c \ parser/parser.c parser/create_node.c parser/fill_node_cmd_args.c parser/fill_node_redirects.c parser/parser_utils.c \ utils/check_input.c utils/free_functions.c utils/init.c \ builtins/pwd.c builtins/env.c builtins/export.c builtins/unset.c builtins/cd.c builtins/exit.c builtins/echo.c builtins/exit_utils.c utils/read_input.c \ diff --git a/include/minishell.h b/include/minishell.h index 42e8904..17774e7 100644 --- a/include/minishell.h +++ b/include/minishell.h @@ -93,8 +93,8 @@ typedef enum e_token_type T_UNKNOWN, // 12 - Unknown token T_LOG_OR, // 13 - || T_LOG_AND, // 14 - && - T_PARENTHESES_OPEN, // 15 - ( - T_PARENTHESES_CLOSE, // 16 - ) + T_PARENTHESIS_OPEN, // 15 - ( + T_PARENTHESIS_CLOSE, // 16 - ) } t_token_type; typedef struct s_token @@ -164,18 +164,22 @@ int find_next_env_var_if_any(const char **str); # define CMD_FOUND 1 typedef enum e_lexeme_type { - L_COMMAND, // Command to be executed - L_ARGUMENT, // Argument to a command - L_PIPE, // Pipe operdator, signaling chaining of commands - L_REDIRECT_INPUT, // Input redirection operator (<) - L_REDIRECT_OUTPUT, // Output redirection operator (>) - L_REDIRECT_APPEND, // Append redirection operator (>>) - L_HEREDOC, // Heredoc redirection operator (<<) - L_HEREDOC_DELIMITER, // Delimiter for heredoc (<<) - L_FILENAME_STDIN, // Filename used in redirections - L_FILENAME_STDOUT, // Filename used in redirections - L_UNDEFINED, // Undefined lexeme type - L_END // End of lexeme array + L_COMMAND, // Command to be executed + L_ARGUMENT, // Argument to a command + L_PIPE, // Pipe operdator, signaling chaining of commands + L_REDIRECT_INPUT, // Input redirection operator (<) + L_REDIRECT_OUTPUT, // Output redirection operator (>) + L_REDIRECT_APPEND, // Append redirection operator (>>) + L_HEREDOC, // Heredoc redirection operator (<<) + L_HEREDOC_DELIMITER, // Delimiter for heredoc (<<) + L_FILENAME_STDIN, // Filename used in redirections + L_FILENAME_STDOUT, // Filename used in redirections + L_LOG_AND, // Logical AND operator (&&) + L_LOG_OR, // Logical OR operator (||) + L_PARENTHESIS_OPEN, // Open parentheses + L_PARENTHESIS_CLOSED, // Close parentheses + L_UNDEFINED, // Undefined lexeme type + L_END // End of lexeme array } t_lexeme_type; typedef enum e_lexeme_status @@ -187,8 +191,7 @@ typedef enum e_lexeme_status typedef struct s_lexeme { t_lexeme_type type; - char *str; // The actual value (could be after variable substitution) - char *original; // Original value (useful for environment variables) + char *str; // The actual value (could be after variable substitution) t_lexeme_status status; } t_lexeme; @@ -202,6 +205,10 @@ t_lexeme redirect_out_target_lexeme(t_token *token, t_lexeme redirect_append_lexeme(t_token *token, t_data *data); t_lexeme heredoc_lexeme(t_token *token, t_data *data); t_lexeme heredoc_delimiter_lexeme(t_token *token, t_data *data); +t_lexeme log_or_lexeme(t_token *token, t_data *data); +t_lexeme log_and_lexeme(t_token *token, t_data *data); +t_lexeme parentheses_open_lexeme(t_token *token, t_data *data); +t_lexeme parentheses_close_lexeme(t_token *token, t_data *data); t_lexeme t_double_quotes_var_subs(t_token *token, t_data *data); t_lexeme single_quote_lexeme(t_token *token, t_data *data); t_lexeme t_env_var_subs(t_token *token, t_data *data); @@ -226,6 +233,8 @@ void lexer_t_var_subs(t_data *data, size_t i); void lexer_t_quotes_var_subs(t_data *data, size_t i); void lexer_t_pipe(t_data *data, size_t i); void lexer_t_redirects_and_word(t_data *data, size_t *i); +void lexer_t_log_and_or(t_data *data, size_t i); +void lexer_t_parentheses(t_data *data, size_t i); void finalize_lexeme_array(t_data *data, size_t i); void command_and_args(size_t token_count, diff --git a/src/debug/debug.c b/src/debug/debug.c index 2cf1546..66fd52d 100644 --- a/src/debug/debug.c +++ b/src/debug/debug.c @@ -40,10 +40,10 @@ void print_token_arr(t_token *token_arr, size_t token_count) token_type = "T_LOG_OR"; else if (token_arr[i].type == T_LOG_AND) token_type = "T_LOG_AND"; - else if (token_arr[i].type == T_PARENTHESES_OPEN) - token_type = "T_PARENTHESES_OPEN"; - else if (token_arr[i].type == T_PARENTHESES_CLOSE) - token_type = "T_PARENTHESES_CLOSE"; + else if (token_arr[i].type == T_PARENTHESIS_OPEN) + token_type = "T_PARENTHESIS_OPEN"; + else if (token_arr[i].type == T_PARENTHESIS_CLOSE) + token_type = "T_PARENTHESIS_CLOSE"; else if (token_arr[i].type == T_END) token_type = "T_END"; else diff --git a/src/lexer/lexemes.c b/src/lexer/lexemes.c index 0976678..ad51e96 100644 --- a/src/lexer/lexemes.c +++ b/src/lexer/lexemes.c @@ -36,9 +36,6 @@ t_lexeme redirect_append_lexeme(t_token *token, t_data *data) lexeme.str = ft_strdup(token->str); if (!lexeme.str) free_exit(data, "Error: malloc lexeme.str failed\n"); - lexeme.original = ft_strdup(token->str); - if (!lexeme.original) - free_exit(data, "Error: malloc lexeme.original failed\n"); lexeme.status = LEXED; return (lexeme); } @@ -52,9 +49,6 @@ t_lexeme heredoc_lexeme(t_token *token, t_data *data) if (!lexeme.str) free_exit(data, "Error: malloc lexeme.str failed\n"); lexeme.original = ft_strdup(token->str); - if (!lexeme.original) - free_exit(data, "Error: malloc lexeme.original failed\n"); - lexeme.status = LEXED; return (lexeme); } @@ -66,9 +60,6 @@ t_lexeme heredoc_delimiter_lexeme(t_token *token, t_data *data) lexeme.str = ft_strdup(token->str); if (!lexeme.str) free_exit(data, "Error: malloc lexeme.str failed\n"); - lexeme.original = ft_strdup(token->str); - if (!lexeme.original) - free_exit(data, "Error: malloc lexeme.original failed\n"); lexeme.status = LEXED; return (lexeme); } @@ -81,9 +72,6 @@ t_lexeme word_lexeme(t_token *token, t_data *data) lexeme.str = ft_strdup(token->str); if (!lexeme.str) free_exit(data, "Error: malloc lexeme.str failed\n"); - lexeme.original = ft_strdup(token->str); - if (!lexeme.original) - free_exit(data, "Error: malloc lexeme.original failed\n"); lexeme.status = NOT_LEXED; return (lexeme); } diff --git a/src/lexer/lexemes_bonus.c b/src/lexer/lexemes_bonus.c new file mode 100644 index 0000000..b1d59ce --- /dev/null +++ b/src/lexer/lexemes_bonus.c @@ -0,0 +1,60 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* lexemes_bonus.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: slombard +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2023/12/13 14:20:12 by slombard #+# #+# */ +/* Updated: 2023/12/13 14:20:14 by slombard ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +t_lexeme log_or_lexeme(t_token *token, t_data *data) +{ + t_lexeme lexeme; + + (void)token; + (void)data; + lexeme.type = L_LOG_OR; + lexeme.str = NULL; + lexeme.status = LEXED; + return (lexeme); +} + +t_lexeme log_and_lexeme(t_token *token, t_data *data) +{ + t_lexeme lexeme; + + (void)token; + (void)data; + lexeme.type = L_LOG_AND; + lexeme.str = NULL; + lexeme.status = LEXED; + return (lexeme); +} + +t_lexeme parentheses_open_lexeme(t_token *token, t_data *data) +{ + t_lexeme lexeme; + + (void)token; + (void)data; + lexeme.type = L_PARENTHESIS_OPEN; + lexeme.str = NULL; + lexeme.status = LEXED; + return (lexeme); +} +t_lexeme parentheses_close_lexeme(t_token *token, t_data *data) +{ + t_lexeme lexeme; + + (void)token; + (void)data; + lexeme.type = L_PARENTHESIS_CLOSED; + lexeme.str = NULL; + lexeme.status = LEXED; + return (lexeme); +} \ No newline at end of file diff --git a/src/lexer/lexer.c b/src/lexer/lexer.c index 569aff3..e0d6b05 100644 --- a/src/lexer/lexer.c +++ b/src/lexer/lexer.c @@ -14,10 +14,20 @@ void create_lexeme_arr(t_data *data) { + size_t i; + data->lexeme_arr = malloc(sizeof(t_lexeme) * (data->token_count + 1)); if (!data->lexeme_arr) free_exit(data, "Error: malloc lexeme_arr failed\n"); ft_memset(data->lexeme_arr, 0, sizeof(t_lexeme) * (data->token_count + 1)); + i = 0; + while (i < data->token_count) + { + data->lexeme_arr[i].status = NOT_LEXED; + data->lexeme_arr[i].type = L_UNDEFINED; + data->lexeme_arr[i].str = NULL; + i++; + } } void command_and_args(size_t token_count, t_lexeme *lexeme_arr) @@ -55,6 +65,8 @@ t_lexeme *lexer(t_data *data) lexer_t_var_subs(data, i); lexer_t_quotes_var_subs(data, i); lexer_t_pipe(data, i); + lexer_t_log_and_or(data, i); + lexer_t_parentheses(data, i); lexer_t_redirects_and_word(data, &i); i++; } diff --git a/src/lexer/lexer_helper.c b/src/lexer/lexer_helper.c index bd597c4..4ddcd05 100644 --- a/src/lexer/lexer_helper.c +++ b/src/lexer/lexer_helper.c @@ -68,7 +68,11 @@ void lexer_t_redirects_and_word(t_data *data, size_t *i) || data->token_arr[*i].type == T_SHELL_VAR || data->token_arr[*i].type == T_DOUBLE_QUOTE || data->token_arr[*i].type == T_SINGLE_QUOTE - || data->token_arr[*i].type == T_PIPE) + || data->token_arr[*i].type == T_PIPE + || data->token_arr[*i].type == T_LOG_OR + || data->token_arr[*i].type == T_LOG_AND + || data->token_arr[*i].type == T_PARENTHESIS_OPEN + || data->token_arr[*i].type == T_PARENTHESIS_CLOSE) { return ; } diff --git a/src/lexer/lexer_helper_bonus.c b/src/lexer/lexer_helper_bonus.c new file mode 100644 index 0000000..e74c108 --- /dev/null +++ b/src/lexer/lexer_helper_bonus.c @@ -0,0 +1,49 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* lexer_helper_bonus.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: slombard +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2023/12/13 14:29:09 by slombard #+# #+# */ +/* Updated: 2023/12/13 14:29:11 by slombard ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +void lexer_t_log_and_or(t_data *data, size_t i) +{ + if (data->token_arr[i].type == T_ENV_VAR + || data->token_arr[i].type == T_SHELL_VAR + || data->token_arr[i].type == T_DOUBLE_QUOTE + || data->token_arr[i].type == T_SINGLE_QUOTE + || data->token_arr[i].type == T_PIPE) + { + return ; + } + else if (data->token_arr[i].type == T_LOG_OR) + data->lexeme_arr[i] = log_or_lexeme(&data->token_arr[i], data); + else if (data->token_arr[i].type == T_LOG_AND) + data->lexeme_arr[i] = log_and_lexeme(&data->token_arr[i], data); +} + +void lexer_t_parentheses(t_data *data, size_t i) +{ + if (data->token_arr[i].type == T_ENV_VAR + || data->token_arr[i].type == T_SHELL_VAR + || data->token_arr[i].type == T_DOUBLE_QUOTE + || data->token_arr[i].type == T_SINGLE_QUOTE + || data->token_arr[i].type == T_PIPE + || data->token_arr[i].type == T_LOG_OR + || data->token_arr[i].type == T_LOG_AND) + { + return ; + } + else if (data->token_arr[i].type == T_PARENTHESIS_OPEN) + data->lexeme_arr[i] = parentheses_open_lexeme(&data->token_arr[i], + data); + else if (data->token_arr[i].type == T_PARENTHESIS_CLOSE) + data->lexeme_arr[i] = parentheses_close_lexeme(&data->token_arr[i], + data); +} \ No newline at end of file diff --git a/src/tokenizer/assign_bonus.c b/src/tokenizer/assign_bonus.c index 890fe74..d51b783 100644 --- a/src/tokenizer/assign_bonus.c +++ b/src/tokenizer/assign_bonus.c @@ -15,14 +15,14 @@ void assign_parentheses_open(const char **str, t_data *data, size_t *idx) { - data->token_arr[*idx].type = T_PARENTHESES_OPEN; + data->token_arr[*idx].type = T_PARENTHESIS_OPEN; (*idx)++; (*str)++; } void assign_parentheses_close(const char **str, t_data *data, size_t *idx) { - data->token_arr[*idx].type = T_PARENTHESES_CLOSE; + data->token_arr[*idx].type = T_PARENTHESIS_CLOSE; (*idx)++; (*str)++; } diff --git a/src/utils/free_functions.c b/src/utils/free_functions.c index e8e7368..16de4af 100644 --- a/src/utils/free_functions.c +++ b/src/utils/free_functions.c @@ -44,8 +44,6 @@ void free_lexeme_arr(t_data *data) { free(data->lexeme_arr[i].str); data->lexeme_arr[i].str = NULL; - free(data->lexeme_arr[i].original); - data->lexeme_arr[i].original = NULL; } i++; } From 72773ad40bc01216fbe632f4cae1ec58e103b9d8 Mon Sep 17 00:00:00 2001 From: 552020 Date: Wed, 13 Dec 2023 14:42:21 +0100 Subject: [PATCH 10/29] update assigns in redirect --- src/lexer/lexemes_redirect.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/lexer/lexemes_redirect.c b/src/lexer/lexemes_redirect.c index 2e35755..e60c688 100644 --- a/src/lexer/lexemes_redirect.c +++ b/src/lexer/lexemes_redirect.c @@ -20,7 +20,6 @@ t_lexeme redirect_in_lexeme(t_token *token, t_data *data) lexeme.str = ft_strdup(token->str); if (!lexeme.str) free_exit(data, "Error: malloc lexeme.str failed\n"); - lexeme.original = NULL; lexeme.status = LEXED; return (lexeme); } @@ -53,7 +52,6 @@ t_lexeme redirect_in_target_lexeme(t_token *token, t_data *data) lexeme.type = L_FILENAME_STDIN; lexeme.str = assign_redirect_target(token, data); - lexeme.original = NULL; lexeme.status = LEXED; return (lexeme); } @@ -66,7 +64,6 @@ t_lexeme redirect_out_lexeme(t_token *token, t_data *data) lexeme.str = ft_strdup(token->str); if (!lexeme.str) free_exit(data, "Error: malloc lexeme.str failed\n"); - lexeme.original = NULL; lexeme.status = LEXED; return (lexeme); } @@ -77,7 +74,6 @@ t_lexeme redirect_out_target_lexeme(t_token *token, t_data *data) lexeme.type = L_FILENAME_STDOUT; lexeme.str = assign_redirect_target(token, data); - lexeme.original = NULL; lexeme.status = LEXED; return (lexeme); } From 82caf9572439ba7c12d414e6d991ef671bc46888 Mon Sep 17 00:00:00 2001 From: 552020 Date: Wed, 13 Dec 2023 14:50:50 +0100 Subject: [PATCH 11/29] some updates --- src/lexer/check_syntax.c | 11 ++++++++--- src/lexer/lexemes.c | 4 ---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/lexer/check_syntax.c b/src/lexer/check_syntax.c index d2fc28e..90caf09 100644 --- a/src/lexer/check_syntax.c +++ b/src/lexer/check_syntax.c @@ -15,7 +15,8 @@ int lexeme_is_operator(t_lexeme_type type) { if (type == L_PIPE || type == L_REDIRECT_INPUT || type == L_REDIRECT_OUTPUT - || type == L_REDIRECT_APPEND || type == L_HEREDOC) + || type == L_REDIRECT_APPEND || type == L_HEREDOC || type == L_LOG_OR + || type == L_LOG_AND) return (1); return (0); } @@ -57,11 +58,14 @@ int check_unexpected_token(t_data *data, size_t index) int check_syntax_error(t_data *data) { - size_t i; + size_t i; + t_lexeme curr; + curr = data->lexeme_arr[i]; i = 0; while (i < data->token_count + 1) { + curr = data->lexeme_arr[i]; if (lexeme_is_operator(data->lexeme_arr[i].type)) { if (check_initial_pipe(data, i)) @@ -70,7 +74,8 @@ int check_syntax_error(t_data *data) return (1); else if (check_unexpected_token(data, i)) return (1); - else if (data->lexeme_arr[i + 1].type == L_PIPE) + else if (curr.type == L_PIPE || curr.type == L_LOG_OR + || curr.type == L_LOG_AND) { printf("Syntax error: unexpected token %s\n", data->lexeme_arr[i + 1].str); diff --git a/src/lexer/lexemes.c b/src/lexer/lexemes.c index ad51e96..a7041dc 100644 --- a/src/lexer/lexemes.c +++ b/src/lexer/lexemes.c @@ -20,9 +20,6 @@ t_lexeme pipe_lexeme(t_token *token, t_data *data) lexeme.str = ft_strdup(token->str); if (!lexeme.str) free_exit(data, "Error: malloc lexeme.str failed\n"); - lexeme.original = ft_strdup(token->str); - if (!lexeme.original) - free_exit(data, "Error: malloc lexeme.original failed\n"); lexeme.status = LEXED; return (lexeme); } @@ -48,7 +45,6 @@ t_lexeme heredoc_lexeme(t_token *token, t_data *data) lexeme.str = ft_strdup(token->str); if (!lexeme.str) free_exit(data, "Error: malloc lexeme.str failed\n"); - lexeme.original = ft_strdup(token->str); return (lexeme); } From 1e185211ce0de9c94aa8a005f21209a6edb4b79c Mon Sep 17 00:00:00 2001 From: 552020 Date: Wed, 13 Dec 2023 14:52:18 +0100 Subject: [PATCH 12/29] remove some original --- src/lexer/quotes.c | 4 ---- src/lexer/var_subs.c | 6 ------ 2 files changed, 10 deletions(-) diff --git a/src/lexer/quotes.c b/src/lexer/quotes.c index c58d681..fd877eb 100644 --- a/src/lexer/quotes.c +++ b/src/lexer/quotes.c @@ -89,7 +89,6 @@ t_lexeme t_double_quotes_var_subs(t_token *token, t_data *data) free_exit(data, "Error: malloc lexeme.str failed\n"); lexeme.type = L_UNDEFINED; lexeme.status = NOT_LEXED; - lexeme.original = NULL; return (lexeme); } @@ -98,9 +97,6 @@ t_lexeme single_quote_lexeme(t_token *token, t_data *data) t_lexeme lexeme; lexeme.type = L_UNDEFINED; - lexeme.original = ft_strdup(token->str); - if (!lexeme.original) - free_exit(data, "Error: malloc lexeme.original failed\n"); lexeme.str = strip_quotes(token->str, data); lexeme.status = NOT_LEXED; return (lexeme); diff --git a/src/lexer/var_subs.c b/src/lexer/var_subs.c index 973c0b6..902e3d0 100644 --- a/src/lexer/var_subs.c +++ b/src/lexer/var_subs.c @@ -37,9 +37,6 @@ t_lexeme t_env_var_subs(t_token *token, t_data *data) t_lexeme lexeme; char *value; - lexeme.original = ft_strdup(token->str); - if (!lexeme.original) - free_exit(data, "Error: malloc lexeme.original failed\n"); value = lookup_env_value(token->str + 1, data->env_arr); lexeme.type = L_UNDEFINED; lexeme.str = ft_strdup(value); @@ -54,9 +51,6 @@ t_lexeme t_shell_var_subs(t_token *token, t_data *data) t_lexeme lexeme; char *value; - lexeme.original = ft_strdup(token->str); - if (!lexeme.original) - free_exit(data, "Error: malloc lexeme.original failed\n"); value = ft_itoa(data->last_exit_status); if (!value) free_exit(data, "Error: malloc value failed\n"); From 13dd85577213a435056abef49612a42d0ac74a28 Mon Sep 17 00:00:00 2001 From: 552020 Date: Wed, 13 Dec 2023 15:03:54 +0100 Subject: [PATCH 13/29] solve compiler issues --- src/lexer/check_syntax.c | 2 +- src/lexer/var_subs.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lexer/check_syntax.c b/src/lexer/check_syntax.c index 90caf09..8ab2c7f 100644 --- a/src/lexer/check_syntax.c +++ b/src/lexer/check_syntax.c @@ -61,8 +61,8 @@ int check_syntax_error(t_data *data) size_t i; t_lexeme curr; - curr = data->lexeme_arr[i]; i = 0; + curr = data->lexeme_arr[i]; while (i < data->token_count + 1) { curr = data->lexeme_arr[i]; diff --git a/src/lexer/var_subs.c b/src/lexer/var_subs.c index 902e3d0..92208e0 100644 --- a/src/lexer/var_subs.c +++ b/src/lexer/var_subs.c @@ -51,6 +51,7 @@ t_lexeme t_shell_var_subs(t_token *token, t_data *data) t_lexeme lexeme; char *value; + (void)token; value = ft_itoa(data->last_exit_status); if (!value) free_exit(data, "Error: malloc value failed\n"); From 765d6ff0c58d3eef11da5c69df9056eab1be2597 Mon Sep 17 00:00:00 2001 From: 552020 Date: Wed, 13 Dec 2023 15:53:46 +0100 Subject: [PATCH 14/29] WIP --- Makefile | 2 +- include/minishell.h | 22 ++++++- src/parser/create_node.c | 10 ++++ src/parser/free.c | 66 +++++++++++++++++++++ src/parser/parser.c | 118 ++++++++++++++++++-------------------- src/parser/parser_utils.c | 29 ++++++++++ 6 files changed, 184 insertions(+), 63 deletions(-) create mode 100644 src/parser/free.c diff --git a/Makefile b/Makefile index d0e6086..83c9877 100644 --- a/Makefile +++ b/Makefile @@ -42,7 +42,7 @@ SRCS = minishell.c \ tokenizer/tokenizer.c tokenizer/utils.c tokenizer/assign.c tokenizer/count_words.c tokenizer/assign_redirect.c tokenizer/reshuffle_quotes.c tokenizer/reshuffle_quotes_utils.c tokenizer/assign_bonus.c \ wildcard/wildcard.c wildcard/build_pattern.c wildcard/build_pattern_init.c wildcard/free.c wildcard/utils.c wildcard/init_entries.c wildcard/matching.c wildcard/matching_utils.c \ lexer/lexer.c lexer/lexemes_redirect.c lexer/lexemes.c lexer/lexemes_bonus.c lexer/quotes.c lexer/var_subs.c lexer/wrappers.c lexer/lexer_helper.c lexer/lexer_helper_bonus.c lexer/check_syntax.c lexer/lexer_helper.c lexer/quotes_helper.c \ - parser/parser.c parser/create_node.c parser/fill_node_cmd_args.c parser/fill_node_redirects.c parser/parser_utils.c \ + parser/parser.c parser/create_node.c parser/fill_node_cmd_args.c parser/fill_node_redirects.c parser/parser_utils.c parser/free.c \ utils/check_input.c utils/free_functions.c utils/init.c \ builtins/pwd.c builtins/env.c builtins/export.c builtins/unset.c builtins/cd.c builtins/exit.c builtins/echo.c builtins/exit_utils.c utils/read_input.c \ executor/redirections.c executor/heredoc.c executor/execute_builtins.c executor/executor.c executor/utils.c executor/handle_pipe.c executor/handle_single_cmd.c executor/ft_realpath.c executor/path_finder.c executor/cmd_and_args_arr.c \ diff --git a/include/minishell.h b/include/minishell.h index 17774e7..270046c 100644 --- a/include/minishell.h +++ b/include/minishell.h @@ -246,6 +246,9 @@ typedef enum e_node_type { N_PIPE, N_COMMAND, + N_PARENTHESES, + N_LOG_OR, + N_LOG_AND, } t_node_type; typedef struct s_ast_node @@ -264,6 +267,15 @@ typedef struct s_ast_node struct s_ast_node *children[2]; // For output redirection. } t_ast_node; +typedef struct s_parser +{ + int i; + t_ast_node *node; + int parenthesis_sibling; + int end; + int start; +} t_parser; + typedef struct s_node_list { t_ast_node *node; @@ -334,7 +346,15 @@ void debug_ast(t_ast_node *node); void print_hash_table(t_env_table *env_table); void print_envp_arr(char **envp); t_ast_node *create_node(t_node_type type, t_data *data); - +void free_str_arr(char **arr); +void free_cmd_node(t_ast_node *node); +void free_ast(t_ast_node *node); +void init_parser_vars(t_parser *vars, int start, int end); +int find_parenthesis_sibling(t_lexeme *lexemes, int start, + int end); +t_ast_node *build_parentheses_node(t_ast_node *node, + t_lexeme *lexemes, int start, int end, + t_data *data); /* Heredoc */ int handle_heredocs(t_ast_node *node, t_data *data); diff --git a/src/parser/create_node.c b/src/parser/create_node.c index 01d52aa..3e91894 100644 --- a/src/parser/create_node.c +++ b/src/parser/create_node.c @@ -53,3 +53,13 @@ t_ast_node *build_cmd_node(t_lexeme *lexemes, int start, int end, t_data *data) } return (node); } + +t_ast_node *build_parentheses_node(t_ast_node *node, t_lexeme *lexemes, + int start, int end, t_data *data) +{ + node->cmd = ft_strdup("minishell"); + if (node->cmd == NULL) + free_exit(data, "Error: ft_strdup failed\n"); + node->args = build_args_arr(lexemes, start, end, data); + return (node); +} diff --git a/src/parser/free.c b/src/parser/free.c new file mode 100644 index 0000000..a034315 --- /dev/null +++ b/src/parser/free.c @@ -0,0 +1,66 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* free.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: slombard +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2023/12/13 15:11:49 by slombard #+# #+# */ +/* Updated: 2023/12/13 15:11:51 by slombard ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +void free_str_arr(char **arr) +{ + int i; + + i = 0; + while (arr[i]) + { + free(arr[i]); + arr[i] = NULL; + i++; + } + free(arr); + arr = NULL; +} + +void free_cmd_node(t_ast_node *node) +{ + if (node->cmd) + { + free(node->cmd); + node->cmd = NULL; + } + if (node->args) + free_str_arr(node->args); + if (node->input_files) + free_str_arr(node->input_files); + if (node->output_files) + free_str_arr(node->output_files); + if (node->heredoc_del) + { + free(node->heredoc_del); + node->heredoc_del = NULL; + } +} + +void free_ast(t_ast_node *node) +{ + if (node->type == N_COMMAND) + { + free_cmd_node(node); + } + else if (node->type == N_PIPE) + { + free_ast(node->children[0]); + free_ast(node->children[1]); + } + if (node) + { + free(node); + node = NULL; + } +} diff --git a/src/parser/parser.c b/src/parser/parser.c index 1778f7c..c13ac67 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -29,84 +29,80 @@ void parse(t_data *data) free_lexeme_arr(data); } -t_ast_node *parser(t_lexeme *lexemes, int start, int end, t_data *data) +t_ast_node *parser_parentheses(t_parser *vars, t_lexeme *lexemes, t_data *data) { - int i; - t_ast_node *node; - - node = NULL; - i = end; - while (i >= start) + if (lexemes[vars->i].type == L_PARENTHESIS_CLOSED) { - if (lexemes[i].type == L_PIPE) + vars->parenthesis_sibling = find_parenthesis_sibling(lexemes, + vars->start, vars->end); + if (vars->parenthesis_sibling == -1) + free_exit(data, "Error: parentheses not balanced\n"); + else if (vars->parenthesis_sibling == vars->start) + { + vars->node = create_node(N_PARENTHESES, data); + build_parentheses_node(vars->node, lexemes, vars->start + 1, + vars->end - 1, data); + return (vars->node); + } + else if (vars->parenthesis_sibling > vars->start) { - node = create_node(N_PIPE, data); - node->children[1] = build_cmd_node(lexemes, i + 1, end, data); - end = i - 1; - i = end; - while (i >= start && lexemes[i].type != L_PIPE) - i--; - if (i > start) - node->children[0] = parser(lexemes, start, end, data); - else - node->children[0] = build_cmd_node(lexemes, start, end, data); - return (node); + vars->i = vars->parenthesis_sibling - 1; } - i--; } - node = build_cmd_node(lexemes, start, end, data); - return (node); + if (lexemes[vars->i].type == L_PARENTHESIS_OPEN) + { + return ; + } } -void free_str_arr(char **arr) +t_ast_node *parser_pipe(t_parser *vars, t_lexeme *lexemes, t_data *data) { - int i; - - i = 0; - while (arr[i]) + if (lexemes[vars->i].type == L_PIPE) { - free(arr[i]); - arr[i] = NULL; - i++; + vars->node = create_node(N_PIPE, data); + vars->node->children[1] = build_cmd_node(lexemes, vars->i + 1, + vars->end, data); + vars->end = vars->i - 1; + vars->i = vars->end; + while (vars->i >= vars->start && lexemes[vars->i].type != L_PIPE) + vars->i--; + if (vars->i > vars->start) + vars->node->children[0] = parser(lexemes, vars->start, vars->end, + data); + else + vars->node->children[0] = build_cmd_node(lexemes, vars->start, + vars->end, data); + return (vars->node); } - free(arr); - arr = NULL; } -void free_cmd_node(t_ast_node *node) +void parser_log_and_or(t_parser *vars, t_lexeme *lexemes, t_data *data) { - if (node->cmd) - { - free(node->cmd); - node->cmd = NULL; - } - if (node->args) - free_str_arr(node->args); - if (node->input_files) - free_str_arr(node->input_files); - if (node->output_files) - free_str_arr(node->output_files); - if (node->heredoc_del) + if (lexemes[vars->i].type == L_LOG_AND || lexemes[vars->i].type == L_LOG_OR) { - free(node->heredoc_del); - node->heredoc_del = NULL; + if (lexemes[vars->i].type == L_LOG_OR) + vars->node = create_node(N_LOG_OR, data); + else + vars->node = create_node(N_LOG_AND, data); + vars->node->children[1] = parser(lexemes, vars->i + 1, vars->end, data); + vars->end = vars->i - 1; + vars->i = vars->end; + vars->node->children[0] = parser(lexemes, vars->start, vars->end, data); } } -void free_ast(t_ast_node *node) +parser(t_lexeme *lexemes, int start, int end, t_data *data) { - if (node->type == N_COMMAND) - { - free_cmd_node(node); - } - else if (node->type == N_PIPE) - { - free_ast(node->children[0]); - free_ast(node->children[1]); - } - if (node) + t_parser vars; + + init_parser_vars(&vars, start, end); + while (vars.i >= vars.start) { - free(node); - node = NULL; + parser_parentheses(&vars, lexemes, data); + parser_pipe(&vars, lexemes, data); + parser_log_and_or(&vars, lexemes, data); + vars.i--; } -} + vars.node = build_cmd_node(lexemes, start, end, data); + return (vars.node); +} \ No newline at end of file diff --git a/src/parser/parser_utils.c b/src/parser/parser_utils.c index fdc6b89..a7cf13a 100644 --- a/src/parser/parser_utils.c +++ b/src/parser/parser_utils.c @@ -40,3 +40,32 @@ int ft_arrlen(char **arr) i++; return (i); } + +void init_parser_vars(t_parser *vars, int start, int end) +{ + vars->i = end; + vars->end = end; + vars->start = start; + vars->node = NULL; +} + +int find_parenthesis_sibling(t_lexeme *lexemes, int start, int end) +{ + int i; + int parentheses_balance; + + (void)end; + i = start; + parentheses_balance = 0; + while (i >= start) + { + if (lexemes[i].type == L_PARENTHESIS_CLOSED) + parentheses_balance++; + else if (lexemes[i].type == L_PARENTHESIS_OPEN) + parentheses_balance--; + if (parentheses_balance == 0) + return (i); + i--; + } + return (-1); +} From cf195c351b4d7e31800ce54398a5e76a0b5904c7 Mon Sep 17 00:00:00 2001 From: 552020 Date: Thu, 14 Dec 2023 12:45:07 +0100 Subject: [PATCH 15/29] compiles --- src/parser/create_node.c | 54 ++++++++++++++++++++++++++++++++++++++++ src/parser/parser.c | 15 ++++++++--- 2 files changed, 65 insertions(+), 4 deletions(-) diff --git a/src/parser/create_node.c b/src/parser/create_node.c index 3e91894..0054d29 100644 --- a/src/parser/create_node.c +++ b/src/parser/create_node.c @@ -54,6 +54,60 @@ t_ast_node *build_cmd_node(t_lexeme *lexemes, int start, int end, t_data *data) return (node); } +char **build_args_arr(t_lexeme *lexemes, int start, int end, t_data *data) +{ + char **args; + int i; + int j; + + args = (char **)malloc(sizeof(char *) * (end - start + 1)); + if (args == NULL) + free_exit(data, "Error: malloc args failed\n"); + i = start; + j = 0; + while (i <= end) + { + if (lexemes[i].type == L_COMMAND || lexemes[i].type == L_ARGUMENT) + args[j] = ft_strdup(lexemes[i].str); + else if (lexemes[i].type == L_PIPE) + args[j] = ft_strdup("|"); + else if (lexemes[i].type == L_REDIRECT_INPUT) + args[j] = ft_strdup("<"); + else if (lexemes[i].type == L_REDIRECT_OUTPUT) + args[j] = ft_strdup(">"); + else if (lexemes[i].type == L_REDIRECT_APPEND) + args[j] = ft_strdup(">>"); + else if (lexemes[i].type == L_HEREDOC) + args[j] = ft_strdup("<<"); + else if (lexemes[i].type == L_HEREDOC_DELIMITER) + args[j] = ft_strdup(lexemes[i].str); + else if (lexemes[i].type == L_FILENAME_STDIN) + args[j] = ft_strdup(lexemes[i].str); + else if (lexemes[i].type == L_FILENAME_STDOUT) + args[j] = ft_strdup(lexemes[i].str); + else if (lexemes[i].type == L_PARENTHESIS_OPEN) + args[j] = ft_strdup("("); + else if (lexemes[i].type == L_PARENTHESIS_CLOSED) + args[j] = ft_strdup(")"); + else if (lexemes[i].type == L_LOG_AND) + args[j] = ft_strdup("&&"); + else if (lexemes[i].type == L_LOG_OR) + args[j] = ft_strdup("||"); + else + { + // This should never happen + args[j] = ft_strdup("ERROR"); + free_exit(data, "Error: Parenthesis node: unknown lexeme type\n"); + } + if (args[j] == NULL) + free_exit(data, "Error: ft_strdup failed\n"); + j++; + i++; + } + args[j] = NULL; + return (args); +} + t_ast_node *build_parentheses_node(t_ast_node *node, t_lexeme *lexemes, int start, int end, t_data *data) { diff --git a/src/parser/parser.c b/src/parser/parser.c index c13ac67..aa796cd 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -49,10 +49,12 @@ t_ast_node *parser_parentheses(t_parser *vars, t_lexeme *lexemes, t_data *data) vars->i = vars->parenthesis_sibling - 1; } } + // This sould be never be the case if (lexemes[vars->i].type == L_PARENTHESIS_OPEN) { - return ; + return (NULL); } + return (NULL); } t_ast_node *parser_pipe(t_parser *vars, t_lexeme *lexemes, t_data *data) @@ -74,6 +76,7 @@ t_ast_node *parser_pipe(t_parser *vars, t_lexeme *lexemes, t_data *data) vars->end, data); return (vars->node); } + return (NULL); } void parser_log_and_or(t_parser *vars, t_lexeme *lexemes, t_data *data) @@ -91,15 +94,19 @@ void parser_log_and_or(t_parser *vars, t_lexeme *lexemes, t_data *data) } } -parser(t_lexeme *lexemes, int start, int end, t_data *data) +t_ast_node *parser(t_lexeme *lexemes, int start, int end, t_data *data) { t_parser vars; init_parser_vars(&vars, start, end); while (vars.i >= vars.start) { - parser_parentheses(&vars, lexemes, data); - parser_pipe(&vars, lexemes, data); + vars.node = parser_parentheses(&vars, lexemes, data); + if (vars.node) + return (vars.node); + vars.node = parser_pipe(&vars, lexemes, data); + if (vars.node) + return (vars.node); parser_log_and_or(&vars, lexemes, data); vars.i--; } From 368d3455f1603aa00172acce1749d4d76f6a538e Mon Sep 17 00:00:00 2001 From: 552020 Date: Thu, 14 Dec 2023 12:57:11 +0100 Subject: [PATCH 16/29] update debug functions --- src/debug/debug.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/debug/debug.c b/src/debug/debug.c index 66fd52d..35fca68 100644 --- a/src/debug/debug.c +++ b/src/debug/debug.c @@ -95,7 +95,6 @@ void print_lexeme_arr(t_lexeme *lexeme_arr, size_t lexeme_count) printf("\n"); } -// for is not allowed!!! void print_ast(t_ast_node *node, int depth) { int i; @@ -113,13 +112,21 @@ void print_ast(t_ast_node *node, int depth) printf("%s", node->cmd); if (node->args) { - for (int i = 0; node->args[i] != NULL; ++i) + i = 0; + while (node->args[i] != NULL) { printf(" %s", node->args[i]); + i++; } } printf("\n"); } + else if (node->type == N_LOG_OR) + printf("||\n"); + else if (node->type == N_LOG_AND) + printf("&&\n"); + else + printf("UNKNOWN\n"); if (node->children[0]) print_ast(node->children[0], depth + 1); if (node->children[1]) @@ -173,11 +180,12 @@ void print_node(t_ast_node *node, int depth, bool is_last_sibling[]) if (!node) return ; print_indentation(depth, is_last_sibling, depth - 1); - // Print node type and cmd if (node->type == N_PIPE) - { printf("|\n"); - } + else if (node->type == N_LOG_OR) + printf("||\n"); + else if (node->type == N_LOG_AND) + printf("&&\n"); else if (node->type == N_COMMAND) { printf("%s", node->cmd); @@ -189,7 +197,6 @@ void print_node(t_ast_node *node, int depth, bool is_last_sibling[]) } printf("\n"); } - // Print children if (node->children[0]) { print_node(node->children[0], depth + 1, is_last_sibling); From a0493bb33b6d5aab0087a184bf39ba575630d51e Mon Sep 17 00:00:00 2001 From: 552020 Date: Thu, 14 Dec 2023 15:01:09 +0100 Subject: [PATCH 17/29] solve some issue with parser --- Makefile | 6 +-- src/debug/debug.c | 105 +++++++++----------------------------- src/debug/print_ast_new.c | 85 ++++++++++++++++++++++++++++++ src/lexer/check_syntax.c | 16 +++--- src/lexer/lexemes.c | 11 ++-- src/lexer/lexer.c | 8 ++- src/minishell.c | 1 + src/parser/parser.c | 23 +++++++-- 8 files changed, 156 insertions(+), 99 deletions(-) create mode 100644 src/debug/print_ast_new.c diff --git a/Makefile b/Makefile index 83c9877..f8e0975 100644 --- a/Makefile +++ b/Makefile @@ -45,10 +45,10 @@ SRCS = minishell.c \ parser/parser.c parser/create_node.c parser/fill_node_cmd_args.c parser/fill_node_redirects.c parser/parser_utils.c parser/free.c \ utils/check_input.c utils/free_functions.c utils/init.c \ builtins/pwd.c builtins/env.c builtins/export.c builtins/unset.c builtins/cd.c builtins/exit.c builtins/echo.c builtins/exit_utils.c utils/read_input.c \ - executor/redirections.c executor/heredoc.c executor/execute_builtins.c executor/executor.c executor/utils.c executor/handle_pipe.c executor/handle_single_cmd.c executor/ft_realpath.c executor/path_finder.c executor/cmd_and_args_arr.c \ + executor/redirections.c executor/heredoc.c executor/execute_builtins.c executor/executor.c executor/utils.c executor/handle_pipe.c executor/handle_single_cmd.c executor/ft_realpath.c executor/path_finder.c executor/cmd_and_args_arr.c executor/wait.c \ envp/env_vars.c envp/free.c envp/hash_table.c envp/utils.c \ - utils/ft_isvalidvarname.c tokenizer/reshuffle_quotes.c \ - utils/signals.c executor/wait.c debug/debug.c tokenizer/reshuffle_quotes_utils.c + utils/ft_isvalidvarname.c utils/signals.c \ + debug/debug.c debug/print_ast_new.c OBJS = $(addprefix $(OBJ_DIR)/, $(SRCS:.c=.o)) OBJS := $(OBJS:/=_) diff --git a/src/debug/debug.c b/src/debug/debug.c index 35fca68..89108ec 100644 --- a/src/debug/debug.c +++ b/src/debug/debug.c @@ -84,6 +84,14 @@ void print_lexeme_arr(t_lexeme *lexeme_arr, size_t lexeme_count) lexeme_type = "L_FILENAME_STDOUT"; else if (lexeme_arr[i].type == L_UNDEFINED) lexeme_type = "L_UNDEFINED"; + else if (lexeme_arr[i].type == L_LOG_OR) + lexeme_type = "L_LOG_OR"; + else if (lexeme_arr[i].type == L_LOG_AND) + lexeme_type = "L_LOG_AND"; + else if (lexeme_arr[i].type == L_PARENTHESIS_OPEN) + lexeme_type = "L_PARENTHESIS_OPEN"; + else if (lexeme_arr[i].type == L_PARENTHESIS_CLOSED) + lexeme_type = "L_PARENTHESIS_CLOSE"; else if (lexeme_arr[i].type == L_END) lexeme_type = "L_END"; else @@ -133,87 +141,18 @@ void print_ast(t_ast_node *node, int depth) print_ast(node->children[1], depth + 1); } -int get_max_depth(t_ast_node *node) -{ - int left_depth; - - if (!node) - return (0); - if (node->type == N_COMMAND) - return (1); - left_depth = get_max_depth(node->children[0]); - left_depth++; - return (left_depth); -} - -void print_indentation(int depth, bool is_last_sibling[], int last_index) -{ - int i; - - i = 0; - while (i < depth - 1) - { - if (i == last_index) - { - if (is_last_sibling[i]) - printf(" "); - else - printf("│ "); - } - else - printf(" "); - i++; - } - if (depth > 0) - { - if (is_last_sibling[last_index]) - printf("└── "); - else - printf("├── "); - } -} +// int get_max_depth(t_ast_node *node) +// { +// int left_depth; -void print_node(t_ast_node *node, int depth, bool is_last_sibling[]) -{ - int i; - - if (!node) - return ; - print_indentation(depth, is_last_sibling, depth - 1); - if (node->type == N_PIPE) - printf("|\n"); - else if (node->type == N_LOG_OR) - printf("||\n"); - else if (node->type == N_LOG_AND) - printf("&&\n"); - else if (node->type == N_COMMAND) - { - printf("%s", node->cmd); - i = 0; - while (node->args && node->args[i] != NULL) - { - printf(" %s", node->args[i]); - i++; - } - printf("\n"); - } - if (node->children[0]) - { - print_node(node->children[0], depth + 1, is_last_sibling); - } - if (node->children[1]) - { - is_last_sibling[depth] = true; - print_node(node->children[1], depth + 1, is_last_sibling); - } -} - -void print_ast_new(t_ast_node *root) -{ - bool is_last_sibling[100] = {false}; - // Assuming a max depth of 100; can be dynamically allocated if needed - print_node(root, 0, is_last_sibling); -} +// if (!node) +// return (0); +// if (node->type == N_COMMAND) +// return (1); +// left_depth = get_max_depth(node->children[0]); +// left_depth++; +// return (left_depth); +// } void print_node_info(t_ast_node *node) { @@ -228,6 +167,12 @@ void print_node_info(t_ast_node *node) printf("Type: PIPE\n"); else if (node->type == N_COMMAND) printf("Type: COMMAND\n"); + else if (node->type == N_LOG_OR) + printf("Type: LOG_OR\n"); + else if (node->type == N_LOG_AND) + printf("Type: LOG_AND\n"); + else if (node->type == N_PARENTHESES) + printf("Type: PARENTHESIS\n"); else printf("Type: UNKNOWN\n"); if (node->cmd) diff --git a/src/debug/print_ast_new.c b/src/debug/print_ast_new.c new file mode 100644 index 0000000..808d32b --- /dev/null +++ b/src/debug/print_ast_new.c @@ -0,0 +1,85 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* print_ast_new.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: slombard +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2023/12/14 14:19:43 by slombard #+# #+# */ +/* Updated: 2023/12/14 14:19:44 by slombard ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +void print_indentation(int depth, bool is_last_sibling[], int last_index) +{ + int i; + + i = 0; + while (i < depth - 1) + { + if (i == last_index) + { + if (is_last_sibling[i]) + printf(" "); + else + printf("│ "); + } + else + printf(" "); + i++; + } + if (depth > 0) + { + if (is_last_sibling[last_index]) + printf("└── "); + else + printf("├── "); + } +} + +void print_node(t_ast_node *node, int depth, bool is_last_sibling[]) +{ + int i; + + if (!node) + return ; + print_indentation(depth, is_last_sibling, depth - 1); + if (node->type == N_PIPE) + printf("|\n"); + else if (node->type == N_LOG_OR) + printf("||\n"); + else if (node->type == N_LOG_AND) + printf("&&\n"); + else if (node->type == N_COMMAND) + { + printf("%s", node->cmd); + i = 0; + while (node->args && node->args[i] != NULL) + { + printf(" %s", node->args[i]); + i++; + } + printf("\n"); + } + else if (node->type == N_PARENTHESES) + printf("()\n"); + if (node->children[0]) + { + is_last_sibling[depth] = (node->children[1] == NULL); + print_node(node->children[0], depth + 1, is_last_sibling); + } + if (node->children[1]) + { + is_last_sibling[depth] = true; + print_node(node->children[1], depth + 1, is_last_sibling); + } +} + +void print_ast_new(t_ast_node *root) +{ + bool is_last_sibling[100] = {false}; + // Assuming a max depth of 100; can be dynamically allocated if needed + print_node(root, 0, is_last_sibling); +} \ No newline at end of file diff --git a/src/lexer/check_syntax.c b/src/lexer/check_syntax.c index 8ab2c7f..33df388 100644 --- a/src/lexer/check_syntax.c +++ b/src/lexer/check_syntax.c @@ -33,7 +33,7 @@ int check_initial_pipe(t_data *data, size_t index) return (0); } -int check_unexpected_enf_of_input(t_data *data, size_t index) +int check_unexpected_end_of_input(t_data *data, size_t index) { if (data->lexeme_arr[index + 1].type == L_END) { @@ -59,23 +59,25 @@ int check_unexpected_token(t_data *data, size_t index) int check_syntax_error(t_data *data) { size_t i; - t_lexeme curr; + t_lexeme next; i = 0; - curr = data->lexeme_arr[i]; while (i < data->token_count + 1) { - curr = data->lexeme_arr[i]; + if (i == data->token_count) + next.type = L_END; + else + next = data->lexeme_arr[i + 1]; if (lexeme_is_operator(data->lexeme_arr[i].type)) { if (check_initial_pipe(data, i)) return (1); - else if (check_unexpected_enf_of_input(data, i)) + else if (check_unexpected_end_of_input(data, i)) return (1); else if (check_unexpected_token(data, i)) return (1); - else if (curr.type == L_PIPE || curr.type == L_LOG_OR - || curr.type == L_LOG_AND) + else if (next.type == L_PIPE || next.type == L_LOG_OR + || next.type == L_LOG_AND) { printf("Syntax error: unexpected token %s\n", data->lexeme_arr[i + 1].str); diff --git a/src/lexer/lexemes.c b/src/lexer/lexemes.c index a7041dc..95bd4fc 100644 --- a/src/lexer/lexemes.c +++ b/src/lexer/lexemes.c @@ -16,10 +16,13 @@ t_lexeme pipe_lexeme(t_token *token, t_data *data) { t_lexeme lexeme; + (void)token; + (void)data; lexeme.type = L_PIPE; - lexeme.str = ft_strdup(token->str); - if (!lexeme.str) - free_exit(data, "Error: malloc lexeme.str failed\n"); + lexeme.str = NULL; + // lexeme.str = ft_strdup(token->str); + // if (!lexeme.str) + // free_exit(data, "Error: malloc lexeme.str failed\n"); lexeme.status = LEXED; return (lexeme); } @@ -68,6 +71,6 @@ t_lexeme word_lexeme(t_token *token, t_data *data) lexeme.str = ft_strdup(token->str); if (!lexeme.str) free_exit(data, "Error: malloc lexeme.str failed\n"); - lexeme.status = NOT_LEXED; + lexeme.status = LEXED; return (lexeme); } diff --git a/src/lexer/lexer.c b/src/lexer/lexer.c index e0d6b05..3517280 100644 --- a/src/lexer/lexer.c +++ b/src/lexer/lexer.c @@ -49,7 +49,8 @@ void command_and_args(size_t token_count, t_lexeme *lexeme_arr) else lexeme_arr[i].type = L_ARGUMENT; } - else if (lexeme_arr[i].type == L_PIPE) + else if (lexeme_arr[i].type == L_PIPE || lexeme_arr[i].type == L_LOG_AND + || lexeme_arr[i].type == L_LOG_OR) command_flag = NO_CMD_YET; i++; } @@ -62,12 +63,17 @@ t_lexeme *lexer(t_data *data) i = 0; while (i < data->token_count) { + printf("i: %zu\n", i); + printf("data->token_arr[i].str: %s\n", data->token_arr[i].str); + printf("data->token_arr[i].type: %d\n", data->token_arr[i].type); lexer_t_var_subs(data, i); lexer_t_quotes_var_subs(data, i); lexer_t_pipe(data, i); lexer_t_log_and_or(data, i); lexer_t_parentheses(data, i); lexer_t_redirects_and_word(data, &i); + printf("data->lexeme_arr[i].str: %s\n", data->lexeme_arr[i].str); + printf("data->lexeme_arr[i].type: %d\n", data->lexeme_arr[i].type); i++; } finalize_lexeme_array(data, i); diff --git a/src/minishell.c b/src/minishell.c index e246112..3792a2a 100644 --- a/src/minishell.c +++ b/src/minishell.c @@ -35,6 +35,7 @@ int main(int argc, char **argv, char **envp) check_input(argc, argv); initialize_data(envp, &data); + data.debug_level = DEBUG_ALL; while (1) { handle_signals_main(); diff --git a/src/parser/parser.c b/src/parser/parser.c index aa796cd..f3783ff 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -66,7 +66,9 @@ t_ast_node *parser_pipe(t_parser *vars, t_lexeme *lexemes, t_data *data) vars->end, data); vars->end = vars->i - 1; vars->i = vars->end; - while (vars->i >= vars->start && lexemes[vars->i].type != L_PIPE) + while (vars->i >= vars->start && (lexemes[vars->i].type != L_PIPE + && lexemes[vars->i].type != L_LOG_OR + && lexemes[vars->i].type != L_LOG_AND)) vars->i--; if (vars->i > vars->start) vars->node->children[0] = parser(lexemes, vars->start, vars->end, @@ -79,7 +81,7 @@ t_ast_node *parser_pipe(t_parser *vars, t_lexeme *lexemes, t_data *data) return (NULL); } -void parser_log_and_or(t_parser *vars, t_lexeme *lexemes, t_data *data) +t_ast_node *parser_log_and_or(t_parser *vars, t_lexeme *lexemes, t_data *data) { if (lexemes[vars->i].type == L_LOG_AND || lexemes[vars->i].type == L_LOG_OR) { @@ -90,8 +92,19 @@ void parser_log_and_or(t_parser *vars, t_lexeme *lexemes, t_data *data) vars->node->children[1] = parser(lexemes, vars->i + 1, vars->end, data); vars->end = vars->i - 1; vars->i = vars->end; - vars->node->children[0] = parser(lexemes, vars->start, vars->end, data); + while (vars->i >= vars->start && (lexemes[vars->i].type != L_PIPE + && lexemes[vars->i].type != L_LOG_OR + && lexemes[vars->i].type != L_LOG_AND)) + vars->i--; + if (vars->i > vars->start) + vars->node->children[0] = parser(lexemes, vars->start, vars->end, + data); + else + vars->node->children[0] = parser(lexemes, vars->start, vars->end, + data); + return (vars->node); } + return (NULL); } t_ast_node *parser(t_lexeme *lexemes, int start, int end, t_data *data) @@ -107,7 +120,9 @@ t_ast_node *parser(t_lexeme *lexemes, int start, int end, t_data *data) vars.node = parser_pipe(&vars, lexemes, data); if (vars.node) return (vars.node); - parser_log_and_or(&vars, lexemes, data); + vars.node = parser_log_and_or(&vars, lexemes, data); + if (vars.node) + return (vars.node); vars.i--; } vars.node = build_cmd_node(lexemes, start, end, data); From e4135e737395224159c64aaf6b2fac77dfb768a6 Mon Sep 17 00:00:00 2001 From: 552020 Date: Thu, 14 Dec 2023 15:53:00 +0100 Subject: [PATCH 18/29] WIP --- src/parser/parser.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/parser/parser.c b/src/parser/parser.c index f3783ff..8cf8d23 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -66,9 +66,7 @@ t_ast_node *parser_pipe(t_parser *vars, t_lexeme *lexemes, t_data *data) vars->end, data); vars->end = vars->i - 1; vars->i = vars->end; - while (vars->i >= vars->start && (lexemes[vars->i].type != L_PIPE - && lexemes[vars->i].type != L_LOG_OR - && lexemes[vars->i].type != L_LOG_AND)) + while (vars->i >= vars->start && (lexemes[vars->i].type != L_PIPE)) vars->i--; if (vars->i > vars->start) vars->node->children[0] = parser(lexemes, vars->start, vars->end, @@ -92,16 +90,12 @@ t_ast_node *parser_log_and_or(t_parser *vars, t_lexeme *lexemes, t_data *data) vars->node->children[1] = parser(lexemes, vars->i + 1, vars->end, data); vars->end = vars->i - 1; vars->i = vars->end; - while (vars->i >= vars->start && (lexemes[vars->i].type != L_PIPE - && lexemes[vars->i].type != L_LOG_OR + while (vars->i >= vars->start && (lexemes[vars->i].type != L_LOG_OR && lexemes[vars->i].type != L_LOG_AND)) vars->i--; if (vars->i > vars->start) - vars->node->children[0] = parser(lexemes, vars->start, vars->end, - data); - else - vars->node->children[0] = parser(lexemes, vars->start, vars->end, - data); + vars->start evars->node->children[0] = parser(lexemes, vars->start, + vars->end, data); return (vars->node); } return (NULL); @@ -117,12 +111,13 @@ t_ast_node *parser(t_lexeme *lexemes, int start, int end, t_data *data) vars.node = parser_parentheses(&vars, lexemes, data); if (vars.node) return (vars.node); - vars.node = parser_pipe(&vars, lexemes, data); + vars.node = parser_log_and_or(&vars, lexemes, data); if (vars.node) return (vars.node); - vars.node = parser_log_and_or(&vars, lexemes, data); + vars.node = parser_pipe(&vars, lexemes, data); if (vars.node) return (vars.node); + vars.i--; } vars.node = build_cmd_node(lexemes, start, end, data); From 744c2d771c2f90544a39870a0cef352f92e799f5 Mon Sep 17 00:00:00 2001 From: Stefano Lombardo Date: Thu, 14 Dec 2023 18:26:12 +0100 Subject: [PATCH 19/29] fix compilation for Ubuntu --- Makefile | 4 ++-- src/parser/parser.c | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index f8e0975..325f1a0 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ NAME = minishell CFLAGS = -g -Wall -Wextra -Werror LIBFT = ./libft/libft.a LIBS = -lreadline -INCLUDES = -I./include -I./libft/include -I./src/wildcard +INCLUDES = -I./include -I./libft/include -I./src/wildcard -I./src/tokenizer SRC_DIR = src OBJ_DIR = obj @@ -16,7 +16,7 @@ ifeq ($(UNAME_S), Darwin) INCLUDES = -I./include -I./libft/include -I/opt/homebrew/opt/readline/include -I./libft/include -I/usr/local/opt/readline/include -I./src/wildcard -I./src/tokenizer else - INCLUDES = -I./include -I./libft/include -I./src/wildcard + INCLUDES = -I./include -I./libft/include -I./src/wildcard -I./src/tokenizer endif ifeq ($(UNAME_S), Darwin) diff --git a/src/parser/parser.c b/src/parser/parser.c index 8cf8d23..e8d33ff 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -3,10 +3,10 @@ /* ::: :::::::: */ /* parser.c :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: bsengeze +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2023/11/30 07:15:23 by bsengeze #+# #+# */ -/* Updated: 2023/11/30 07:15:25 by bsengeze ### ########.fr */ +/* Updated: 2023/12/14 18:25:41 by slombard ### ########.fr */ /* */ /* ************************************************************************** */ @@ -34,7 +34,7 @@ t_ast_node *parser_parentheses(t_parser *vars, t_lexeme *lexemes, t_data *data) if (lexemes[vars->i].type == L_PARENTHESIS_CLOSED) { vars->parenthesis_sibling = find_parenthesis_sibling(lexemes, - vars->start, vars->end); + vars->start, vars->end); if (vars->parenthesis_sibling == -1) free_exit(data, "Error: parentheses not balanced\n"); else if (vars->parenthesis_sibling == vars->start) @@ -63,17 +63,17 @@ t_ast_node *parser_pipe(t_parser *vars, t_lexeme *lexemes, t_data *data) { vars->node = create_node(N_PIPE, data); vars->node->children[1] = build_cmd_node(lexemes, vars->i + 1, - vars->end, data); + vars->end, data); vars->end = vars->i - 1; vars->i = vars->end; while (vars->i >= vars->start && (lexemes[vars->i].type != L_PIPE)) vars->i--; if (vars->i > vars->start) vars->node->children[0] = parser(lexemes, vars->start, vars->end, - data); + data); else vars->node->children[0] = build_cmd_node(lexemes, vars->start, - vars->end, data); + vars->end, data); return (vars->node); } return (NULL); @@ -94,8 +94,8 @@ t_ast_node *parser_log_and_or(t_parser *vars, t_lexeme *lexemes, t_data *data) && lexemes[vars->i].type != L_LOG_AND)) vars->i--; if (vars->i > vars->start) - vars->start evars->node->children[0] = parser(lexemes, vars->start, - vars->end, data); + vars->start = vars->i; + vars->node->children[0] = parser(lexemes, vars->start, vars->end, data); return (vars->node); } return (NULL); From 73eecb5703ba3269d7e462bc8edaf7c975587d88 Mon Sep 17 00:00:00 2001 From: Stefano Lombardo Date: Thu, 14 Dec 2023 22:42:24 +0100 Subject: [PATCH 20/29] WIP --- i | 0 minishell_bonus | Bin 0 -> 236520 bytes src/debug/debug.c | 24 ++++---- src/lexer/lexer.c | 12 ++-- src/parser/parser.c | 140 +++++++++++++++++++++++--------------------- 5 files changed, 90 insertions(+), 86 deletions(-) create mode 100644 i create mode 100755 minishell_bonus diff --git a/i b/i new file mode 100644 index 0000000..e69de29 diff --git a/minishell_bonus b/minishell_bonus new file mode 100755 index 0000000000000000000000000000000000000000..b2dd12001a54d3a5dbecdd19e804e544501f4e6e GIT binary patch literal 236520 zcmeFadwf*Y)i*v#KqG>Q7Bwo$h#=u=P*6a?fD8@_8WEIw3y}nf0>NZPK)D)FrZE<+ zwO(3ly;WPQv|5YWVo)T}dI{D`+G6sRlT==IJZILZd^y@ZbKS6G8`| zwj2JHYG|-*%T)kV=4(81BVCbZ8!Y>1JX0D8S&}Z>--2EWV#-jVx+h(CUh4Z`x%G90 zXG#ON?X@d-C{XSlrRq)TrK4>&^-+><8tO0SXuTI0vue3$F48q=x+YC$%8<6FDUCg8 z6aE{m`31`o!1!m%Af1sTSWZ@CAycvq{$224tnxo;uT0Z*?NWS#Wp6E*DNTFlgN}CD z-#^pMGjw~|`k_qQ%ap2@LZOouR$p=I$deXU4qI5gIKFJyveBmwJ9Xsnx|-o9iwKk} zjDPg0v(BBx?r372>CW6W>fZ1pj6;fW;-7x}h@&q3`xDypopKJ$``9y)%(bt{QO zxk*DD{t@4FIq!Kr0RM=i?6DSCs*dH3s@E2=%=Y&d0EcA&jse3=^^au1FV2EbxxyLv zw`Sp!%2Iz_miqg%)E8!v=f*7f7iPi#A`AZfEchR1!9OSqepMFyKV+%@FiU-NmikY! z)IXc0{#ew9@h|vyZWj5!55!D7tJ(=X3m<4|*@Wc2Q z{42_W{}~W7@oz+ZzaSIdmrtEJy}YujwrYNLU975h=JYcc)-0}?S#ia}s!)0P{6#g3 z%j;qlwXyPYg_;quc40a27FR7TM^vf`;kLGF$-;`cRr` z*3>Q!&0SDgU5obSE~_Y?SG~AmVfD3Dp+yx77uL)TEv>DNQ5HnLxmuP*71fJFb=C8$ z7A=V_ud9lM<}R$Mt0Idf@mO7GUTsyCstVOCsahObQoW=qR2g3qs#;bx_nNBEyqemp zcz-f^RLqT4*DMaruZqoGS}FMCQx~hPs;#X7LsgWQqg-554uL8J9}Uf2P*Dq()v?gh zit5;s>dH_p6jh4AW^=D9pS$3y@_7~23qwn4s~5-Sg(~LGt*WaFK@(!qB#hjnSuvMa zr-sg&Hg(dOf3eR zmS3U>O})8qJ4w}Z?l5x|IkkK0Ij5OF$5Vf#sYKc7srUMOm#3cdl=*8LuG&2i6McW)z?)bUAXF%WG@gsZB31@f5E%u&)eRs!Nd(Ys#yW?tm&p^Jr zqr%=ZfbZ@&-`+ED@9vmr?-{UncZ{(24Ai?jj<@#=(7QVhwf79nyE}61Jp=OYj=z6t z^kpE1{`Q^$82a0L243iI?-_8RzrAOmh5q)Q0T%k(dj?kMZ|^zrLVtVD01N%?Jp(KB zxAzRF(BIxOkV1cZ&j1Sj?L7l0^tbm6n9$$eGf+bRe{22W4Zk^--Y_{N{($>NY*%>i z*9Y!b2JYj5`$d8Ks=)naf%{p3`{{xENZ@{a;C@u#epujsK;Zt^!2RKY`(A|15C-VBr1-f&1@z???P?YGTLb z(ZpY(^*cMuW=2Ldjd&^AIDRU^LhA53VD6bWyrAzoI1%!e#_@NeCfeBjRu*HrVuvI2 zT*zyLo`X{D1%1~L?*&}~zgqA|UBP0|m(fILbn7Q)M7MV3MRT@CcYGP^4F&@=gZxzc zJn=(A&-k=vJi(#(kXh0C@wvQ=CO(Yyj5drv05{Gc__b4s!M?rwzmG-+e;H_P`=sw! z3Lr0Lfeyj4Fq&A|6-~rDqYaU+XhUg9v|$$R-;O4lok!M&LiJra@o5TH1{iP@?7KIk zWg+oZfB$Euy0oOBY%(x96NUV51OMBVC>y=;r5D`hx2;L6{61RW7){LDP#JCLHlUbx zO+>mzG(nJ!4G}=!hA2xBr=yLtHi5|oEx~CELm_87_H>;4t`nMvLGf_3F|tV`v?Fw@ z+h%9=Sfxr|Q}Mtzh2aAp{J$bbfPXtX4+g~r8vgyIp-^*V6T2~ai!1o9Fzn_;>sLCV z_#x=m^)Eq=-CKclIVc@c-ta7%baE1rJ;`qMi}vKyuiO(_c3eYbPjqgp;N-LxJQXU~ z(gfU}U{+b*6mJ8xz9~l|Y+)*|!S)(Ti=v?1!e~yC5JaIFAz@c2 z{taobaa4PYg8uMIl$n_&;_bnHXpVGJk`88rFjqVIAAxBP=57a8`bSReFN zXS89uqwrrN$tsX^Bq^Vw88vx16_IhWkfH=+@9=dOf(y&(4^~{3f4cbybE1b z7DhD&etWlQPHS_B6FMq_fM|0mQv(eu1x>uGGCE|WjF4D&=l%alrF_m%0*`FNSZZzP ze&CTg7`WYH2RC%zdjv0Y;t*^67u(^aXMqmQwX#cwB3i&p+9@XQ2V*kFJw#FW$u7W~ zBkfiW;1nSN01kRrxp^~jG{0x%dR80mJM|zu9P_t0VsoTbvq1=Hc9tX0fdfI{Nkxd6 zBBcm?juyBNn1B)dIkRRw6`j5%z8lL#(~mWax6)OLBDvvf-RA~&>!T_=fHxAcbpe6ln~qE z8oQ@gQlBTel9CAwb};4)5FTN9N=yz*ZA`Q4F6?}K@?~zJ(HlZG)IEoBfB-u-c^I@I zB-&V(BbPE!Xxw#8F&f`Txn3yaEuJ1Q6WA7J>F|>C(@MZCz-ZOO9IQijq|@I_Q$sj!Pr zcC5v0>_c-nHu_KgHK-D2<||wY9u_wT?Ud%TQyJo0qm85Ls64vt*Ok(iU@A>opvlH) z!)2Z+goY@Vi40*MhJfA-2GWMuz{Du}bS7A1pIlhI2yHr_J!8epz``qLJH-4*rnF|~ za3yBC!5!B#V5t9CaIT)R3w|x6aK?Qt!G~+XFP$rlwV1hRgJPlxsFK0r*<3H3_$!^U zNYmKSHThl%2h)zt0Cr78(=^D^vipOm~P`>7g zte$|MDXbToCXg4iQ=X4!m;^R@W=-bU99bgwh6oc4-e}$&apDAlI+p}u(+M<#(UDYq zhkFYkn-36sn@?LF83iD`jrvC+n^@meunto(J*3l>4>^#BU|fH!6xb~o8q+aTB(IS> z)g|L%3a0KRxS015Q!l`z^9K4b`?;9S#N_OxyBX@KjK|uGZjkgQFz}Wz!+*AnAIk;U z8Ww`c{Z*dlh%*$d+E5%39;#&t-Z)TrzGURZB?8u%rC|LaBreIEjnZPnbY|5(O;(-w z#G6%TN)%e${%ukH+ve7^d1?@|zA{3Mg$y94mynCskPH7QhAi@d&=0FWllq5H-x|#j z#<<_8X`(~eb^DcMy#EBK_B+B~PTNA3i?BF`8ULe{B3H@Tu5}P2GTl%q#o=hdx$hTN zs5CTx=EIa?r_AHc&hwXu0c2R~72vpn^_Ow+nkBp8mThL3q%BbNFG*SCWRk*NrlmoZ zDpiondFSU}N0p{qe7(%As17PiMQTm|jfF ziFGhXkjG|TLgHkXiYep9VY@;i=k!i=Brv2Sr?MlD%m5gTU@ds?6fD)k`dT8tOqt~C zpWl5B2GM-$z(S@439NkgC{AUiN{X_4bzfSl1D~wmXOy~2)*F99#knClsW7Q$Gpu(S z%anWx!@-o;gnj;+3BFdiK2qt1b@xO6E(2qey4HHu31KVNltz!6iRSH!%lKk13=U4Otid|ZX@iy-kxqK zMVpd}yyS{$%pu}@`JoX9o8VyiiM^M#LRS=<*Q!ZXHk3xAcSLhU8o)~Zrd$G_zayAe z)vvrG6z_pSjSb6(Rj|2(O+EcnSSZ010RPl}9Lsx?Fo_MUTt?HO6t~Cb$qSLk|38qOPUMQ z_(u5G()PC;)cd9Fz|7j7|2L1e1GTm{{Yz_WDmH2Lscn&L28s#4zP9n50d2#~nbqFE z-u$XXhd9uQ;k9#%k>I5VMbXaWS*+%yYeA1Gklvp^fbirn{1+9{34TUvG$XXx8H)cx z9LQsTNW$X?GPt9}>!ePtV2 zyonattczl|6N&w-H^Ht=jhzHCXX~HM&i(gc19evWpw>iWXG3HsMZaT<>=nW0E8*cV ziQiD)q-feuaPem6LHZ#cR3sT1+92QP$eZyVypEn8>57Xg5}jp6n+1%+HWWgiHtIwC zbxrXXaoOpyhfg7LLOWeQLga|-YKZKrZ_4vX`Oc43ACU#+P$t&hIzwtX<0fWx7CbfU z%?*XgV=?~PqK%U{R5)Neqm5BqPY0ZmS)nw{OADZ9^DVGchbkP-G6f#y&VcLhhkP;v zUeEn=vWPaUkxNX?Mc#Xr8FXO@BI^#|c_(Rqcq-(StcVdX!HF9ms8G@KAMNNA-Zz&P z(W5jh>_x;NXm(z95yKwDVlSe^=O4L<#U4a%UD~Ge$#I#Bm`_B%*c^FK(39XaE~DdM zxUdkFndl^TL=#_--GT$P^o=qP03uuA_v2K8vg#zAgOn{(Y#@X?SA%WHPH(@)+@ooV zR9kD-KtQ%~_YYaBnV>;xE!7P!RajA(nUtoM328K4P$fBf-qaILgPji#cToz33mP46 zvoxKvB+5umnQ7Id%{5R@cwhRnGulj(qA^-ZsNnNt2qMkbm%14r@sPR89ePKhW#{#j z=F+gI-tF&Z@mqqtn=EU0b)qJk_)QUlOEmGzLKMM?vthjgt`7s4tcfU@3MhtW2101$dV9$2eSl+j$$BzSY6uY5NzrJ7t+9- zc;25f%o47zCS(oe+PN%hv(G5vo5^Q&QX|QY!=6MwTcY}_H0tKDP;M#aV7>2;&a^;C z_^|F@#Vb)(W?L$gNXp(vt>#)LF_bGkIz=gO5r@#g5z;_xo93qRqfzew0i%s;*n2|k zxh##^5wOliuu02wBPeIJZy7Az-t4@NO?u`3xfYK07r$$R&@y0pBLVkiFnY}9;Kq$g z1dQ&o*&P^gln2&Z!+JW&;P|zw#>H%i&h{!o(o%(E%F@~L0K4JpB9;w_JIHtLOVO== z&ci0fAy&T!FbPHzc_eOFLnOUIOKjwg?A;kzwE5APM-U?=5|glBZq*Mrf546|SXWH9 z_2~r)j`A$rH~Keb{L{^v4b;ZY7$Q!R2I%sct+%Q{?rc#_5-ei7)kYx?J;c+qicwK1 z^qap>q1dguwG5KjR;f3307ABcgK}$o9!K{*e`L5&LDw!*WHKvQx6aborNwBW!*+ou zm^EZF1KVnrjsz1v&!`$?Z}>eS&3)TEmT~~W-EGKCd%g6 zu{y`KZP^@!RXWE%R(Y#TdZlX7j8%>AcX23T=9Q2gdneva<8sY*z4U_`$M(|tDYV{b zYXf74jEnu6hJEw2ihc0AyX;gb4%NrTX$4>=YRbS!Yp36djqqU6=9Kr^)&}O_xKQEo1IJE zHvJd?t1&H0oh;OtD!FCO4l5$7Lc>ZYF5a#&k9}k?*klU6Dnh*dmIwheTgAXMJ(GRR z;@N{dU;%f5Yng0Yd}qCjSZGWoVgk`dpI2?RSGvs0VHuS<)8!yN<5z}*(J|)ba~2q( zFlb$++ZS&d1E(RNnRfwoZJdSy6W^z}i=7?=wrTYQ-KqJ(X2JCaAJ?)p6tLZ@$YEsQ zUkLmR3Sw2zu1~7ryj`R-hgt0%(Z=2{YMVORkH8NL;7(brnz>{K4d^>AhX^(56`9$a zoh4^tnH%8NMQ+Linj?GIMDkRg?aR<&1Gewxz7cKg`IeFd(KhF0ai-k*$R5bK=k!SD z3Yo|}(?xoG@TA_&rSg7`e;AdZpWA|&vp%o)Ad?4K+ap09p9965$#-HGYP@!*qbvXT zJ287Zy0@Lpd$z_5t~v_|`SJxx?OYdqhles9h==o*29sRnWF@;U3?=9+b-?r^XaRc~ zw}3(|e(qyx zfP42%-*|={4gIIfGP~KSLI=TH`ulKl70wWiGf{A2hZ3iuG_2ECHv^)br+HemyucVs zJS$aKD>V=v%58P_876HaQ}&7Tb>f&>Je7b#1a~r1VPi85k^J!Woy?E|!{gnSs|^ zPO3%aX=ej}meVk!kil*1UocH0s2xoyKfaC9%8Dp6Tb(*ZgDqkpLgd4cPv&b`%v!3f zP`0AIPnxly;n-?Pk9e&VVg}N62)`cwKzBS8hgF=0*QhU_o8uqs$TJs`e&zy@T<)H9 z6%NB*7wk413TgyCc$TS2Sgs2+6fD}v>yKg$3`U!?*!)27A7|UlOF5Pkg*=&wtAti8 z!cz$9^gGV><^k9B3@94r6s~5tF6e{cCp*0zzf?Wb4qqrv&>3-s$4%1fC3Ipf4BCQW z(J8XeF#t&!BwniUFppb2Sf)_bM)N&Wwe1%T43L1eG>XP$3ko_e@sdmH@D6k<(}(&< zmuyC(Eq~Jt4h8FnVyfEcpWsW3`aGl99Pydp5EVtxCQ}EmCJ+n$if-H6K!2opfJMbD zmQoB@4bu^Y#W=tHHjwG{cw!F@BndL!9}@*>tS~iSN02C5{K;J@LmeVOQ+l|AotmA$asjQAz20g_v@j~LGq_2_o6)@KrEf}b6T3p+ z$T}No2981t580Pq!6#}iWh@9kRz*W{7G}`^{R4SO&rb2QAjb}^Alz{@w0u1Q{R};( zDW(p1HR=8F!}dT96SaYI&}VYrrkb1Hsz_z<&h92-79jrv%U`s31FAXpj8L+R(G-HT zVczr2@1-xX5ylJz2APh)6oG<~;R8*>$e?LWpfziP4n1drh@HDDIP?A)0;wr7fZ@)% zYdo#E92DG+(u~x4p->;$B@fBO(~Sg{|N6_7`=xVG%#+l z7?0aFNT8=bxS5h>%=2~J(ga8)7Hx^bj#reOg%_RrY7Em8cJ(9=9zI;oPHQx!ld)Vfcu z81Zr@+M~XIq79pgHV|d>!dkC%(IBlQv4!KCHxgS;#0}CEtmzSrunpEYeUEzcDh?C{ z`MKIf6^p4gwY$Ru@#YJjj2W)pT^O{5XZ$QV#YNy^+eNTLLbDD))x@RVufr>O*|?yM zdo}{-OUGi{ywO9aV_m+-kkI*CpI}H+C5VdK$6wI59>GxkJ)B+e+q@7q?_!g%Vv#HX zx3+gDhu@%CV2*to}95o5KK2cvgS^O}-LJbO#*v-)a2ut49byjI6WwVp9 zTG)#ik*&Gml)&6r-PM}pqHhOjB4}^)G+kT@}-nyIGvQ7bK?gZ-!h>B zkN=&5>+2*L^c_|Z9}V~?6zIfI3?*k{q@oAtYchw8!RzROs`J#dUoX~Ocqv^uswLc1 zBo_58h!N(Bz`GL<<(7Ug!1c7=f)D3I4+UnQkdvrSsb{5rxhW<|J?T5bK6%09u-O3?tY+ zUfwE&TOzQ=Te)+Al@TU$Sdwcel~i}X5%&q$i^j&Vp-Xa;;(bY3aTcuva2q$e=ogY@ zOSs@8dTe!^pARB*1QnhLqnuCkwq;)VupPR}f$@uZDPl;DDE&MzU!>9JX(&rOWQl26 z9zThVBcbG|QAU~%{UJWR09DOSs0k5k967U*{5Xzzq&0GirjchfN&-;sU9UOG;T+TS z|M2~2Ku1c`f#WGb+d_EC*Mc@-Zc*remGZn$Y>ht+_*mNf zr*0nXqwaw|`W^yzCUJj$lM?sUp(s7-%~$wo;y$ABe*padqPPbH#C5LEEN-rD{GJs4&xyR+rjbrzf?RsbvzU6*gGJk&D%^J_g@-`11)`OqPzfOIkoQ za|Ap;s*Zx;^tegGa2!lVIE?(WHI{u?v*&EC$UJ0MlaH`tap_!)*#7Cy_~kYoW@#CrKPZuef(KUsczV;GnwYnQaCzvlqQXY zCaXEjZL(B1NnSpCU*|U2tnx9L+duz?;aXbiOD^Uh$9Whz&b`5OvLS-%X6N`-G=?Mz zohUb>U6z|rZrakHvI6OYbX;E^;cH{6mW&Uo;8Ff9kstmlkd&6e7%kjkLc&K) zn{(PxTEt6NXaay9gR5IQ^XcuFO~)}Rk8(-R*@ePU9v(Xgau#)bdOT^GGbVU;!wA zkEf`}bj>mej^}7h`#_t^GP{c@ACnn3K0aWdSlr^uX-y8{A}cc@UAbUAzaWIq8r_e~ z&}Zt*J_3zCzc$^*?D1;JEt{QT7%i|K90#F@TYC*N@M!OO1XekZ+oF9-I|VSsmwu$U z(zkqmq%ziK=baN=2l@{jC#yDtvS@R+B!SINIohQ*Dtf=5qC}f|zE1C==9@L{DI#OL zOdDFQm(|!$Q>#*w;8XN=TxgPtCm1BZ=Gfpq=WOrb@P;{uUs&P>tQ-o1Ypd^6H1^EZ z)x{`vb$9hvX5?OU9fpU@mplG0VVhMCb0;%#K|TmJ;dV3L)hon(kzqiu8xv{0=331; z>;=d>pXrT~h8qa-8lbP?CwK36!+Mi1D(}ig@S3yxi0$5Akc;pzCYTI>Eh23xlOZSTWiH9!CV)L`xVFSKj0f_fZh3}y2&wTX3b?7w5xe*5qL`>^U! zo4(Sj*kt!T^sxh14cG*C*zgR*3?bI)eYZBx=)tTm!}hfOvMa)ZI*r27ncjjKoC3+z z%9{OeMHvTCh2MDbkI}u4{qKxp&7gWdA72lXi03nrf*lmQ+=XRQd7nlt{c3g7l;FonvwHC@k_zk4^b}4I!aG$6W%#%V8Ry% zy&0c#09a2XW?pGhGmn~A^lOo7=JK}ML-q#$lUD!w)vc!W;AM|ya?h_}C}fxIX;#wq zD_Hlj>QcWp3fiM!-7DFl2g(Nteq|Rtj0W^Z@QONuc$z+xCfYV8Ob&eIn!+tedei$DkY~m4n1Jz1`R)C8}>42n3t6}|DPbkbT$SB! z-T9UoWnQ9XS5Jf>KV)xqzR?BpGqRCmeaa1>tkkjLbaEnXE#2-@);|VE#0iJGVXL^1b4J%QrVZ$)~8>s;km5R;4>VO@D-) zj;tz$VN5=(>4H;*I(8}7a`ars^G%$o8$z(mnON)c6v+#MBR=iusk&T1F?~Mv`E-QM zK7=2oBYf&ZSR)8nJF6)dPsjACN|{)hA`{d#Md3B3cW=fSa##+s;!ObTjVM!u&DjpH zLCV1faQ3R;`Y#~}2bh2VKv{_&8?5J-bMpag*pySEqw{2II<`z?Qn%`4 z&aU%h531bsc9-4$+^PCZ^+fC>59PQsV(O%Tm(l%-5jKCY1(p2eMszhkP^=xHPzlJ# z!G+>p=^fb6eQ=X~D&AKv^W@{UzpF!}xbi;Tb?8@qdwIKvBah_C6bE?h;{j~`L2K4d zDrxBc)^nEW%W|0)|0cpuBbgrVGA-F6kB-n&Z(IcO#_?;3u;)j%)e`pNv`YlGimz@{d zkdh>}LjyGZ?OZg4t_Dftk{s+FwW&woGSnvKQ4UeRjHhDwq3U+kj{00RDo>B>Tyb=^ z2IGHF7^}jXb3=Tm2n59jyT=%!$>Y-D+bEf8JjxzQ4(A856~BVUql8+d_3+%NwIROG zEjT8yNvl46F+rW_On>VKQXPA5DwPr3Oml^Js5K)P0|vA5Lq@r`e~8}3+b5*)kFi1- zohk_AdxJnez2Y9y5$Id4VLKE-fR4}50S?U$-*MOX5}XXMh`>A-81_=a3OEFcpsOj< zgV1qq`x1n*$WCv{ala~fEZR#BCesEymM{rbX_U?V#+9Xv_dnyk|5MA4+=D9Z#r_7v ziIuw$$=aWr4LdqJC|ueLShJVVgPWaCd(mGY!mM3#zRhn#_eD$A7qMT&2%h&+wwD%5 z-FCbsNmz3!PnnzUaAR_FY1BhrX0GvM%AhxwPByhZFDymhw^f{EREl{l~d^Z@VCnhqSxlK=*3$@HQ9c*MyYlg#Y zY!(sN*o$|IC&3&6QWaM+=r@|q0{!4Ba<+;d#g`V_5v65K2~9mOlBfX0=v?2Fs||p5 zfAD?rBS+;@=Bd^hi&Q5(i^pKi5q!D`4?odY7>W)%8hP<7uH91!ZCK99%*0k zo@!Y|pnu#Y8nt0K6>4v913kJ#Iv&^5)JVuJdhX{yq|P~}mjgKF*s*>1cE>^`W^ah; zSDGoLKGvDhfEm*u?TOgVVjkrC%w7L~(*hX)SHc3Gm}LDP^Do_=hnry>vA1uwg~y+l z0f5nvk5-_#yae?jCwlcoO;kZgKtaiEG3?fkx?@^nt7)tPz_E2oK8qk-slM{MCbDY9(zM*lj7V&EAE-G*l3K`A$qMRPh0Q%^D zcctpuF_w;d$!55x9V(~YeFFlGh;HzwDc#(!HqrC-P*%s`-Djo>UCeNU%4^VjbV>nu zLhNWQ+C50)6c~PNj>dcZxcG9aK>fhMgOcXPA5|+|rw18+Z7=2;Jf>ILV$Mvy+z*|c zJUW9fKTd#mTfmHxM0}5|74Qv)KqiL+?UFj?6|8#-gFFkgTfw?JvP1LZr(~ehBLV(& zShVr%B8Us8!E@f%9j*$Kc#y3QXX{aA1UV=^A_K(FEbL+Sb9%fx3Ges#t?z=$7hx*S zFt#}ApfZ0!I14mCj`zINqJlg4jmj98qVmCzvZF&xm`26c4%!cX)Y|ZS7U8Vp&g}ef zK6an-NpOmCg_1aPv>77${66Op2B$;kE3aOP;iplMIprjAxFDkr-Q)Zv7Y;TgTHK-Z zK39b&mU!oL1R;E4j!j`cX?AYBO>Yz=FIE#7U&_SrMSA&NI15kB$lc?(b2CJ}U>qp! zz@rk(pH(2dX{HD*%m;%xL9Ulj60=y4Z{zJF<;RHeeo8dFEYxs5?^n0D@N*y)6MA0nIMO>DYYOD2z?)a(|EDZc42G;`0b zR%#!qky_cp2ht0o%B++sJISPP!S%CLf)7!7GQQb4&TwhQVgP>`)HIHphYegD{}9ejj;4pXy@J{8Gg6MjVQ1+a5E)CQjdeK8#% zmFhwe_hs*6&X;Y?8DPOUkxw@NY!tZ=rfpxh3VWGXxColWCKWz%%i*};i!Zb0D3ed( zdV|l^i9yZO0${MEu(?gQ<%-d?*H}PGeImgd@DD_{f|$Ea`hmw<@}hY4SS705PZH~e>q5qhcXt|0)|I-s3`^?lGe z0f#g5wVo9uJBdwUzAzV!qH#HMiLcz99IR7&=DW`p=Q=3}9akPZ#(X~iG%Pfn(`M_Z zDIEqji8)s()U2`vUqxI`Q7z8f-~+GmcYR=TCiiH2m8R2Wo3w4 zRAJO`PU+Sv9;g{~+@jnGWSCs0>HyG5$8rO}(FhE1GyIq)A471|3Oo1}5YNU}I{Gk`1!EIw-B;jV6EENA9`-XJY^OP{9L15wW!a>{ef2a@=i{5td|dfsSkw7p1LkN9 z*xh~}bQl3uA`wivAUdpAU9BSGr zBX%!h#|`#SFZNV`luu`P;2dV!FIIy@yQa}~_9hQpyJ#=pN?p5hZwkt-?nDh9BQW}| z+#6c<518E7MQQ-ZYZj3%tKYS1xq;jP4=6H3Qp^`>8#ORf+ZXE8R2t({>K%mRhQxZO z)eYnKyyZ!W4_5_;C#Hxme*E3 zKK@`?gves2a(sm*v06SMYwuy_6@oIWJ&`N?Q1gTClu#adDnyC!bY=kgn@IG@M6P%w z1}QTU`^!9^-jE>^L4?=OLM4#cO!Nf&w1JA(tP=Jw4Ta0g6v!$WyhBmtpZZE|n8C(u zpu-TDWU|zcemvif5K}=fZW0IWcA~9g+`;Z(qdnLEJIqwr0iBmd_pQcIjX_e9l z#qR1BKh?_!jqQW+wVLr=hB5f`LqZ6u3oRFz9#0oUUTNr^$!Mst>x$3OYJ^n79ExgNN84h9Qx zKHm%HcHDPd0V>irly+0cR`D|w-B4kt2K2G}O@cy=iYk*S@Du<0hdgd^?7IpX!>}R9 z3ec+kXBCd^f4lg8H1~37B3Ojl?x(z8vyrRWi1`jhmwKw__E6?FCG8lKRiw}}jKIjm zug6qC&mE7k!>Q|HL>4689_P?WZg7N)lOorKW1$rrqIx)Qp{C;{We-)|U|Z|0TYDV? z2!pCljT5@NB%e=!RDKj1bbM-JcAM2!vJ8p0FolTQIfJh^EgMwNKC+6kJ)R3g4rk6< z87=@LgeYMRiTh0qh;swx5J|C>hYtc-#_+lk0M|fVYZci!lbKw7Q#YOsDUQ>XFqO)( z3#D2!-Bk*U^F7HN{v^Y=LH<)`Y5ReNn43Ph09ss$R%JmT=@%BM<6BvM{~9dnp(TFB zO&J7no^M=2`LmpSq#B``SS-41eP%J+c{QN3G#-gT1l>mp)M2Y1xE zAN+5Ga0o|S-_ajExWP^_AFlieBBx{9{@8*TERK1~*XG=~Z_dx85Sg|BhwPR9&x!uC zx@7jnNUQHknPWC*YOQSy%io94O!a#S0S~Xev|4WzxW3|BekxOibpsjAdMX6-nAL-u z&8(-Yu***HV7q3OVGrTng>YYw^Sj!t1y7Y0VmHft;Lqf5rR6=(_ry(=-PTaxC) zS2s(G>pOG6gp*-*CXm&3Q6HCyGFUfHCrwsW`DvY$$pq{q?wfOFf+0>=m8q9XnA`+H zp8o2JPG*t=Y*xd$-o~(JFkK^-=uLN>=I|5D{*UYcAR#1sWCdmH#MP&`$|&PC0Qh7KOJGD+ zkA)^B!WxYQ%#Tl|mX^Q;c?4naVA*kDzvm--ywL)`5u0fNm5jPUQ#U=8CYcl z*23BZhTj{<51I3q#zXjYi28{6mDMIU2e}Apytv(2H9-adXheOmTMgUU2Ft6e-trgi?0w3uovWj3m-x` zm?qG9EktP?e>KomoL#C^Q#~eg&LIc>T38~voo6ee~A}d%w}f*tH!(_U)58h5^uR~NE<{=qq|)p;T-rv>u7Q_?TfB5 zlfMSog_;8@%!hYh;EK7~8E1IQUIxy;F7vn5@g$ryZR4I@-6)@Wg)crM-H~8BhbWm4 zvWn{4S0nbfcCBk#brCewRU#iUY&mn=P}+w_(cwKN$W4GWDyf+XIh@CFt7gE)@rOfR z=M%y?M4Uai@@Ic#7{V=BJ2v6j_~t-JL<^`!2-hEdy&8c^3LLhO*!@*^D9Ug{6Uzr6K}*g1w3(5=@hOX{nAFEAB=w6gZW9i96DG zP;Rzn=fRK${tS+kk$wlZ8^s{-Lnz{-Pbm5W4E>2-dfomVn*R0-^iu=v|CLP|`DJC= zIO7%MJoS$ zj3g-UBfd!ycQaWqJ4;z!6K~SQ-&e%hBYD`JYW6|{nt&rc-*mybn$ZP{(KrLAWCtiI z4)DYWceAjULqFY1e0+l-Q8pP*-wkhV-hW4xhM(g>A~fWzFKv_ePezJ)y304XRqSzj zpNQ9(e7u7jX<4<>juF!>uT(8F0k2IekD9FiyLI{)*g9iNk-4jO#^1w=HK@=jMaT02cE?zDSPY`!vp!Zr%T7<@_&UmmQ_GI8n5~r{p|l{XMqRWt)i~OqXP&wNqFpjRuy@Kd{Znw%><;!7uuO0R143 zHc>{^#Hl8-`*sPBee}OV|x~NZ>6ZTTWJxR3TtN*jAN02aS>0z~)W4wmgq1*egol`>>WIF>WFsw;2 z+pi{t$0$G46i*1nUQqNBiaowuR!t0gPg^33a>Y?GP5wV{Z76sS%pxI7O|jrs18x8u z4M68JtLSd{9Hk~Y0Bz#)pM$owkE99Zu>H49lLYGe|%ZBZZy=W;uNnT`jb!6SgA&gorViE#v{b?DVWub2$YBy<`pUS8%2$qf*W~D>z<^UB88$KS5Rsj^@l0OPHN@ki zc!YvOipycxc$591PmTb%hauhpiB$@Hq>s2v6T=5R#786OB_fVW&HpN-i1z-IFg2+5 zg-+YoIM1ZcEj>yz>E2$whvAX00rE*QJwOK7Kf8#+eWS@q>^AvecYZ1)_{m#ebt}&E zB=rQw{!}ZvFs?jHEh`KU`zCnWU%NTyAOvpf-0xwo>9|pa3)CZhf|S=PbPkXjhx#XE zX(+q$j@mlpY6nZAQMaF=dhXIch^~Nwp8JE2dPt#vMp52$ZAUZ|2#3)T4YMGX?_@p? zEpLV>>F`@*Mi(KWJx#%Am&HQcooI_?apZrNiGgp7%n)wB^pv?R< zuKp7qk2s6?hF916re z9y0nemD7+;p~`{#O2?K?mSa}VFVHzio_z_(8XOH`+&dX6$c9x9A>nGH6p0HUO-HCl z?R>%9*UYzfN$ZHbzUu85JgQszp*@w-72!&Y;*L&x6kPPfyBy*~iu9ueN(CH!2#dCA zr%jgg?Qrn-u=zrI2<~8tSlVPBo|# zGKz5Q4}(xvFx>954Sh>DbeL^Oj?IEa)Cg9jXUO7WG$t$z3U&?~M_sNt+?)yQo^h$M zV5Q07^D(VtcqU`=Fbs6_B<;)7l`;M?NV33M2!UA=>%S9G&*kwP)G&+`Z8?cC1)$4- zihjcgo|LbEvNRARd^lS@OJLyHj#>5^jZtjaK&uV9%~N3EyfI}oNM}KAUj`^ zt!2lEQ2G=ycUc*CRQ7TOz`oxFNq?!@vAXnyQc4$gGE|T=X(klz#J&kNKL0K86q5-i zxl#r$rWkHjnIB!^^FFE4Gr?MnN{wN+_!T@8r8N9w;v?TgDws<4%i4+vRZ^wctDiQb z9R5~3g0*P99#b5J{O^^SQV$8s@;Zt3gZui!1bl1*GaP~xRk=LS)YCFLhH-fZUHd)k zv=FuLn@*#zJ1s}Tc&`BfRxjm;R;n}W%5bEJtA36hi+md%k?ecPtXc3nDB z*00=bf8~A+YS77>;Ut@oa5rg3*@OrVgS1nA{ov!9xZiAsMy}SS4NeJ^0|0AFGR56& z_SZfbt+ahgVKBW7Hgb(gZv%&2a$$Zqoay6XUh88CLPeCPXIzbRZh?D>wZF-eFKR>< zK|Z*qzgHq!&cqx0)#p9!01pldcJa}g*|@J_CMPuE0g@ISC4+%MBNNX*W9No$aQ5t%W#-j7&+|V97H{x=IsI@DfAv z`zkau-Btdqo?eX=SeD&raT+AeSh1-P_92``z6AjBTKKsABpzH8v=$HANZ2%4XK;qc zxqNEjU=@-WS3*KPJWj8*km2&{a=gvW&U*lP8;ABbI!8sdR>{NJXVEJ-mE#<*PApDB z!iMYCaWH8a-e!-XNfS7HgKn!RL7{kAYaQUY(IwIm*u6I(_sX7V7S71IM({ zW0p<(TrYi5{$E)yJpneE)=Tp4Q5VOpS;MKkK$38r>@&ZMCae0`iOGCcagiq0lj9@a zU#yZz;a!Yq_qdWhB#&3o5vW`A5pK}8(bm|rL7w&|R#^<%%DAY$fL(wEkStGSB%n`6 zy^Osr5?#%OD;en30{UIw0Qe=tH($Dyk?VM-NV2$5vl#BOP#YHCg$=|x!IkG$)N5t> zr+&Foz zpePyG+IR~c1FyG*&8i>Y3&(qw8{|Mvwg_#WR2FPeufeFW@+PJ_4mo-A8D`yjIeX-J zNQ;=L(*m1(Finke%NdAozT%6CzRXv|Y26Tc7i`+mGZ@dKBkvZhJHTvl>%FTaM<)^V zJlw9D)FgPGUE*V)9&f`N3N=1D-~T~?O~8klfFKDx5`RYf8HLf$|A1dnQg+%VA>ypMo7^IktDkW7}k)foE;>UJ@`w&`%rG3sqp&l&|w# zQqm%7rYyiCAR}}7do>tYcrl=vaX}ra&b$p)u>J%XC&QXyzh;z&zxiL8Q7XVD(~P1I zGMe){E1@mE^0SNKQ@;)&XAe8Y=1kf-DCICO^FSFL2aq-6jCCDAFxX(65a`O_Xf&dYR*WqI+MNrkrrA>Wqj`2I{ z&0)&T!|*w2AF^&amM)qp^CiX0n&Ok~LLs5yCQC61Ue9hsXF+`qCeqxlX`WFud{|LP z`xDpAifp0)!CRRr2sH%aYa|Iwf=me|6yUNOFkr5FezUDuL3sW%?L_uRpylM9==Qs$ z{*g@?$oO@~@q;0j^YVpSb1n1H0GvR;&jHZCMy)*5K{NO#nNa+r3~gN}agdQY(+hE7 z+b4`LQ0sF9R6KiQjB;JgyhMYZO7hbSg8ACv`e=>}5ce~tpQ2}BX6|B%&E)|Xui(n4 zk%0E>W?I^{a^P&F|1`Sk6z|g{Z)f3}&cu%6xXo{ns0$JFa&(0TFr$)JdiCf=KBv~M z9x7kDSIJ&T=;Xrg&R8eHpc?ha5ap`zZPH;-Q}8-D)60nnS4VnMk;mNZwIUAS#!)wG zE*JI@Czrm0(6(Pq{9mB)4pgma4rXR&8o@XGug+)LFtuBB?n}|Ff6hZfc!-|#KRbrv z<|*Ea4ksZ4tB3eWwrw~>!A$Ln?(pDL^xj~l_=*>-r=owGo%RdT&>j04fTLamFmgj) z=!iX#jTsYxv=>V_klZJIP4HB7@?>$P1Ax5F6E&4P3%(jRoV zIfpc8)w4k6qZQX6HiEXnroQ)VZiJ$4=hA@_T^k~M3%1CXZR{|$+p%Wl-g0xiCDRE+ zd?-OJ0UO6Zh!wLlvoHSB6DC(FUgP*%SbGjCoWG($ZsUQ@_H^`6^A!PPPv{;n}5FZQtDB-r~7gr#1=?@0}0f5teXp z5B_!tuC{jN7d+L3%p!?zBe5P1COYg@IxIF)CsSkq6lmH;05fexQ4+*UKPlR^C={vJ}j=Zyc4{Vd=#!8 ziZlFp!OsHh9mF0lL!u~t)lm%R6^`~t1vvkT+JzY38@L3?Vi>2JyJ8h}{LTOExK>%x7u{Wl-h-LHxZz zd?hR5fr7ZrAl{!9F&}ZHvHMRnVv>u24DB8ySl=;N7iGrkAy`Wd)`-kl2Mg9^2J2un zf1$ofC$Kq$e2o+-6Cd6`j|`AM4kWXkGk7{8TRqPAgSs7InI9AGEV!N@7Rj^#lcd|Y z*YU1<1wYqDui1G*x_kNXjC;Lk5Iyb{KveGaV}s~%uK=QQuk{Ae<6Z$o9Je3Lq-?I>R7(+$(^n+$(Gl?|0oRfT-N-V2x!1CUwUfrZ0$9qu z{$j9BGeJ`LxGSXe&JJq zdYPL%91O3r4A%mmo3n_Q{7UWz5XX^7#!sr81vKaVso15zT^SP~c$fXsGUIf?sm7-pz@bt4XfJqp6W>C#l$Rs#@^5}s2`mR4w(VvLL z65SXBU!2*CABK*Pr7`4nd4AJV*6e&mef(QtV~+QcA}0Hzs@Yb(!YX#q$S z;q}Eak-aPK!7fH<)o4nXf&W@dx!N#WZmSle%I`!aTo;+|Nzy0<>xN?H5PPEw@Qq`v zwB>Dx?l6Ng6tV!ym+SDf8-vW+=@1bCOzZHo5{>t_czd-5|GPBZze47Nv z{Jbu)Z4C^%A&|G?L%177{il0|7EcnR&8vxTn#EGTkrmQjC%je5^My4>m`QBOAueD9Ao=rE&f&zJ8ihr;`1m#!8$Ge zla}+T8N^3K$`I@Rj%@@bey%INM$IVxINQh$h~W`GjX(Tai+`XIe;~y_$`wB>;=iG+ ze}d(_6c|D4hck+QvK9YK%e73SW)y#=B{&QO9`V!oyW&UBRQA?yv>t>hvk`2P2jU`u z3pMSmx12WvU!1KTRnB0Sn(r|l0v8~vbC|)ByKWi_Q^RP^AI6hME9Ofq^Ggg_j7(mg zq(sAukvI#gVhpau`>(Pz0}agr(%h+O(3DJ7$3ddY30UI=U>YgKxkk}rDxp`n&@v@q zY1FIV|4g;%-~x_+we$F)=s= zggFK1$0W%sI282L6}79{C9e--DW!X+6FXVT$B#2j*ks{73(Iw35XtR` zZXEv*I5-i=Xgn5QT+Q@dA?6y=FY9cR-v$+3Ff)N{^FHBiRsAka=_>vT&Bd#F;=glN z@x|3^SNmRfa(B`d!AXKN=Btp%b<8UM=FQh=fjwa!TO_;dpR(YSNf=Nk5%CV*xk7p8 zZ^mwA>$Xtr1b&8>eYtZ(AunXHBAeuk+H$ZNj8B}tpT?@qZng`;A;4?3KYlS8=s@5E z!GjT4x|!4yhlu%txwM1UWPMa0!Pge_iGi-@>5-P&Kak!ddEmi>;U==h%93GBwCx~K zk6XCEiqtvhWu#IYFmbA*2yOCB2mGE(9i9+dZ1ses2{p!a+htB{=U~`~>D4!EN?}4* zZ@m@f9!r3xczug00yP#3G&|?0du}jv@mWOu%9c=!8}BX9v}@@pXqvb!=(QxigCa-6 zWsiUd2VO=6G7GDTgA){d?r*VFwg`>DUsP*OPtM(gxzN~Q3O1QwQKf%j!*t#tHRlPV z(a*>Fd!aao&?E@(D0b6f1y8*(s5N0>ytbc^lJJjfSQ7**8JEc!C`tZAXGG3HY@jAXF5*QW0vNRoQ$wLh# z@mGv5K6KGG3i6Akk1@RDV+dQ}qHT5Gc1N*nlGwIHeE9@KCx%E{!S$tBPh{vt`@M%Q zEJJMPW&EhvxcpV=A0X?s3WtXRA1VvS;KYHtVex}LzpRV%5kGDp01kKn(HlI0K{umKEFBHztN#bgncm?#Io8|IDCehR zFcXKkYEfUrs)+iy|nuB;wmJ8a4ykLgC)-;zIo0 zhRe2@nr*1T2L@^fsiXG8l=OO8q*wRLsHckmPVy=Y&LNR)cxXN*vUw>3_GX0j_GC|6 zFGu_I)*jmY0}LQjo_E85AJ)dBxU!sv=}MHGt!zY}>F7gy@-}!1tHe$;dKT$U@$Gzy z-}T~4Au`L@VPiUGhLS^jfL3jyG$R`$^1fP^mf$Y(b%(h+1U0=C*aqX@g5h%x2J6lZ zn9I^*56>Sk+=~x%NCZ;OX2n#adyc13)QpbojJ=)2i*^yW{c1yf zTlDib^`sk5SmhUz;aK*h2@ZhBPnQs73wiVC*;`lLW7IQFKQ3l2r@gqSZajqxvs+ zMCMSE>FF=Rv3=%FhlEewq%zm+DfN!lT8ip@G@^bvXPU7XwufFoiE0`Xh=UJh| z^IJd8vySR`R3u+wxz4RR5d59Daf| zQd?V7J2pHoRzA04;li4^;dvF+3#%%7gnA4fJa}f!RaJ|tudRqx*DS_ukC0S^=hnm* z$Hs;STpRDv0|H!BQM+ z_!V`rTHERhFDO=98DC;SXJlg~FlXq2a@!uQu5t z1zuRStZGqJc}1eepgh@tEsK>fCKVgQ&C&KxMGou;cup59y{4MjY#50Q2fg)7FU*EQ?W4a@(Hvf z4l-ChC&xCUmUAg7OqkwE$$8yQ8_%Ij)Mq) zS@EhCSB7img{v1YiN^v`WB8PNMS;haRn*pD#EI|q;627)j6-nZ1v4{NhR=;$WC6qq zFRrPqs>3kHXHyr)!UFT_NCeyIevom6%(b)XD&|)qbWmqMMrB2;V%UVL#n+U_Dy~@Q za@Tlaj0w?VZoIaZQZ22iy^2~@R@Wlr)YL8y4X7JWzJ9hwoDh_Xg)747o$AVPbtPC- z&#SJg?GY-gs$EoFSBDT6Ms0Of<=Aj&vSBJz^APV?J4HexLK(x`;`vo>+W;<(FRH4o zo*TyK#T5jst-3l6ZaqR_{6AJx6JAuYc)0~b&^nJ_^au@G3_=I1yvZR)pcQ(l?c^W#A70#zAvw=S{TyTU=vzu;xg-ofk4Rxtm;M84ANID z55u*F)yx|<4>3O+DqdQF9wD&@E#M2V~PC56Es`UH zmMpCd#TVCA#X@r{LsfGZ)F>q~=?y=xsjXdpeE7^t>BG8k&Ekd2!%M4U3&M3Zh%+!? z-SMUuy%T`$SX7;CeQ)?lh|6UYXGRTyj>@Lng~q@{8y^G{AJy8AI=J85rIkUIY26Koz9RJjx(Wkn$d`U%YflMKObd5o17^6IcF$4r(Stu7q57mN) zy1Z)H+^Qv*;}=ziudJzF9MnUoGXVk$ir|`W8c5e8l~7usnd-$*KI3>Ei{T*o2C(Kr zfml^JgG%`V*H|8YO84xjBpo*4s;cGT@#Dki&YCtYq-si%5udeZkao&+^&-%rZ8tdQUEmQ53*5kKv={t}}TdloNHhufr5DG#v8W3V15#?C^{#HA`WR zAzr3R!9Fh@%YZ&}#;iza%EW0GL_!mnEMYP*9kMGyGExYysG20khK1bTDL(o(JXy~L zSOIYA%uwy+6`nE~c$m=)9`A>Z2%Wj0dSPXF#8`WwOrxq#Hq|F?OPJ)8V@6uS@yn@c$t43SFH^u_Cyy9;+Q`wT zoH}weC$*eo@=ouak1{6|Dn0?rZCsBYkV-8<8AZ8)<-k;`1m%e0RO()on@~2PtR9p~ zwWIt5W$2(#==8y;viKy>LzWRG zsZ@WIAES(-ynjS0wGic#T<)RF8;N~sl-HwdL%9QG7s@hh6BHc``cqS>(J0Ty-q386 z>qe(iD^T8q&BuFDeu=%>Z79Dx4oAmPzC1pa%Eu1sgbArsG0MalXcy&DY=AF7S%t@z z8&H0Z@?n&x;>l?X$^-G3*+Kaj%6u$ei}8fL80GtXG>@_jhcFhP{3Xf_C>wA}=3$f_ zIOEfT@>m?#+J*85=cH0S@ja>=r=?OuQ9gn^~Yo`3c_DxDDky7r|~Q-<}P-p}gZ_*bQZ$ zOJKLcQ0Vt4N24sh40c0VaXIXU@{BpD)b~-&t4O7Ojq(YU?I=fFf&Mx)6#4*V80ABA z(cdV~u0(&M+<|fp>#JaQl)dMnzfs}9FcGL&nVLvNJtUyF88=C4SlcB1@jCHfn0_zYcz z{zmx_$|%Y&Q7%Bad^P$T{S#B^}HGOLir`iQk1uEM7t>a--32gUXJo%ls`n-f^x>KXcy&}@1R|L zgzg2D#VGH-4RWJ=6J;gJ9^Zw%QI0@)FUr56Y(iOaJNgUdpHPO5#yI*O#y85zccfC2 zQJ!}v=uuvB7urYJhVo&QPv4F9QAWOx_E8@B1GIlkD0C^xVw5+djG|251Nl*&@k7v~ z?D-?mqdXmD3(A=&9h8Ia2R%+$oc#dkQ9gvS3}xR3F-}lk^AN@v%03TcoS|$&*^09A z5sWjG-G72{hC@5QLs^2dlp9g@`W5I=u1494@_m$@D3@#oJFcA=bx@`Y#6 zKFacEp+CyOzlQ!O5Bd%CM>%#2;ta}>&%xirq0q%m@Eerxqnw7aZ7bSGdG7OQALZRB zH=+C#Wh=^GzJT^o9`PdDKRy(?7i9^`yzP)5WxN^Vh4(F~)Ey|l_Y&d+%AqgA?@%uI zE&9D5;ylVQ%12&--=XaLD#j_w7|Jy$hrR~CL7D$L@SNslgqwN1C$}*I_{t9}Ox1!vLvg#wyqx=MAE6Q&=phwxK1N3;OrSHd}M|ort z^e9)MT!Qk%U7$z#FO-{6-u*Ykca$qWL3~H~%BQJRpJK#~PS_pgE|hanPWwCTj`Ck9 z??pLdH^wWMkr@lVa_o<56s_~qv|mvLWO-(DTs){d?027*dG5z z;$Pd*kU19@hZIgZr0DE|gO}#737v8D*ukgtM~^D{OHnrU0Uj&#AKQ!J-)7WvE7tt6 zt()*Kf%aCjGIB`a4Y_CbIw1ENNCX?9>QVf20DsyG=QaKae+B>6hVf<`D=hsAOTP=% ze+7KH4?fw#dqVGT91k0zwDftu${_;z^H}Z^{Zgs855CaCr=dQ-e=0S^%l`^tFZ2rm z{|4Yc@xpU|WZS<9@E-sk^}<)X^p67mBH&eCcfvMD?fwuDU#9ZP>D}d9dIF;h( zl)dugO;k9j6}vqEyfX)7_ls?S-v{`4B(VKH#oA>j;5+s~-z^U@dvGfCXCHl=rSA{; z-vJMM<;*)$gbagbGT}o~sZ+dg*eq{=(t|h)fD;;qI0sp*jKulE#kmPMJBO!IwLw0W zF3u+4oLrJheGhCbpWK^O=b(yy`X+E51kNZgpS+>Mgz!CpKQjWk1g>2kS6O{~cf+tg zIh8ucM?cBZj|6QTBVL3~Zz50L*6-QmFwx`aY@w!0AWhfHU)q zKs?C{*)}c(e0*v4eqI6ikUalW*vv&AC;FnI!J}!R^__32xsds$zuUYzc0e=(l z5-)tdfJOejfbRtScAt)oR{lN*BA1$+O8wqTpWABrj|2Q0kyL7ikAAAqhe2~G;E^e* z)Cez}{d9sdBXQOMXU180X#m%*4ce8EsG^-80M3!o6edhB&Ofaj+W`M3;Cw04^2mGI z>ai2>JI+p}*7@kKv-I6CzwQP6H$M227TzE5JI@Kk>AWdc&&hzdOiQK4c-yC*LzJG> zVF7U7o1RMj$%~WsmX(qF4|kuJN)7bEkF#w&4ETLzndfeb%{E>E&ToOUiWPPqh+92& z0Y2#bRO%N#_#+nH6MGcT0{(&z{)~kW1)OhmKj4GkZQ;`Z{|n$Z`rxZ9d?DadFG!`{ z^1)xR@S6bt67a=7c$I}e3iz~{+4;W$_!EF06yj7RH~PczMF;b z0{oOq0=Z4@CRcy#6}TFH5C9@WKBe z@G$Cb0(`;csnl?<{2WJNQ6WT}O~9!w-*-%T6F95qq*50K`9xhlUBLNyMJjb{5T`)l z^haBLdSY+lid5=7T-)&kd2(MDky$I_ZZh!7=cZD3vcitLjaIKpz}o;H6m07lS03)a zy;m8S^Qe27i}NUOj-0n|KCQs%Ge4F3o42jJor;N;cMotrT#!ng=9PD`(ur}TcQ3?4 zz_aBCBLTm#8hc4z`rPw`0qJJ~ely_L`QWt{9s|4saQ@(pwO8J;A|vT<1N_q~u{YQMU{5w*fyY*nbDR{#tk#a;TM=^DOF60(ckT z|A)OVfs>=C{_mch?&+D?o$1+obM7YDWOHxs%}EkMNFYFv04oGoAb|xVa$f@BMiGS- z1eE2_9|D312+FM}s2qy$lS@GbQSd+x5#*Bnf4}cl_e{?okjtNcnEvceclCSq>ecmL z)vM}P=|UQ1F(JS-Rs#O~Nw7mk;AYYfIBC#9&_nC{=9BOX0B(M8aP+)($2BKD7{jP`;j~1HJ(8y&`#B zC1pVVR{{Rn(|USV6~>QkAEtjK;5PvNi%9(Y!uS^ezWR)wp2>yr56Gu~3*esuyrB@j zG7otFKG)N;x{y9)-;SCFUo)TcfVU&? zjw{5A9UA6yHQ-kRzI!B{9Ya1&0Q`5Khg^%mFAd?{fUo&N|Kshu0RQs<@Mi#DcTP{w z*CYI?&?Nuw0seQuACAEDsOJcLmE@0oeIDRX5njkY%89hwxej!0-($%} zz>fv|e86ADbG{9~7#1*TbOUFf^I-EWq+fPJSUz_F{;#h7?Fi2Re*Kq?oi!MjmHjJ> z{~q99ya2m&BlJ%V;X`WC*T2%!b83Xg191V??h<47Uumez#A{`e+*iW0vLTo z-?nt}&<6My0Dn6||5c&SSL9(ea5}!;({pqLM-9@1p8)vx0pB44&)eg>0e>FwRS|ez zj@|`$-8XuAej0(_9p>>F!0!fp-$?sv58Ky!fWQAg{f`5NK)`lh+0(Osg#I2vpK@{@ z;MW1(pS_mRm`|>qzVXez$3u;PpAPu`S7A-JkWY>y&lFaL#x=nC)zv*cUjcqzUYsMm zkjDLhFT19vXI>$VU?2)O`FII99pCCdzvY9lR|4=`ftybwZ}*%4_`cWnU!N-gzZLLZ zBk@;+^|21{mjJ&l0>2?F&vO7j{W`2E7Q(4_)TGC^l8;+}*Y@rH^YIwq-vIoNg>+(1 zhh_Cozz?{-r)OMYS+Ts0d9xAm>am`@?mK;tF-ex?IS)AR0%tm31oBnQ=mK92c=m># zo&|+)HAe~j1i&W(-d}ll1AZUi*A&K&T^^R_U4XB+v1ooCdn|-M19Rbp0X`1! zzeMP(?UDH#f}hs`-zNg!Eu=pW@TuPgyl_pUY_}K@7=JZ>4!Z^YF9L55;U@t8-S1-_ zURV!hlfwSl4fq4MVhuZz{?=jocLDwe;6IMQZx7+m0DjSJJv}=|=&KO~AnQH++B4fe_ShSt=gnkFGl;dh4CrxekMuqt<=Mnz?=IMtl{%T&<`17lG^gWh37G5%3d!iaiB|`J}wlB|VEc9)7O*S>HA>dg;8=2% z>n6ir+JrInmdj+%gfN~qPxr_osFmL$XaJ@dER&oCGlpE9CZXW{HCXHB74UtJgfJg6 z_aJ=?0p$wt-ZjHnuq&_LH{nhbu_q6gc(0o9AOnBfgoAt-@|*2;kExepf~}^$^&Ah_ z;Z3;1+z&PPlg<4+bHBpeZ#4IN%>5B_f7aYzHFpbZ2)ulAZ#4H-b6;rgTnFLRVeW^T z`^n~hp1EIP?l+qIJ?8$1xj$>}ubR6B+dVI?Q}AjucMW~`U$0dgQ4*YT($uMwTBnaSudNB7&Y5h`sK%PM+h&@!fC_#T|4#G}ZCv}p z+{i1z>0}?5;`gA3D1N8ui(>xm7yokfaK&#lef8-9>Awf#zv92!s6=<{r>z?PkxRv2 z&N&ONB|)FpVEC)}mqMZ_{ujq8=#c^WDMJrb{JkbA{&FqkkZ$mx^rtlj_*bW4_Ka$ zzZ>9p+@|=q4%lCQ^X~w^4lR$@Uk1cK6V_*K4;ES;uk8oq=XwlB6o304D*kl6_4?KP z?w1Pi*Bksx2jpjAHozb9BPDr2tQTo{q4Xs(4fSMmOyz zHZ;KhzQJ!E5dX#y|7nA7hFQI0DgS%p92G6kdL!5{Kq&8=4)#ouXUfWH?c1urAkHBj)Y z_${LX{1*(qEVmTk1&@l4kDd(wJ3p=v(<}nC@UHlO3h}F-P>?Lggjo3p#s4dI&1(77 zL2~hWOK-h?75_{4qCoMpPbmrpbbVfme_~63f3(5BrcdlZzU_fs%}RgRuNBc`yH_lw ze*{*Y75{aEe?>1$eWCcrj}P$A|Bb%CZovLHbYg(N;J1qZy#f3CjWDzrejwR-nPIdB z3VxNJ&rS~Tw=;r&;Qlom6K$n`mcgG`K(p}iRtL**^1`$EnOr%)`+Ep4`kH9RZ0|yV zW3faM;xZOb@Z6-Bmsrf3?OrS}rwy^o;tt$o0OrtU6+Z{BVqa@uCLQk>25k3oV9V&E zY@6I#yoxX8&!cs`A>MUN!H?5fBvP1gCA#dor@UB8sIE+lD2;aLMaZWowS|3 znUQgLddr>PaxEi znu}j2XZu~ax2ASvsM1ccMB1$Msf_MS^XZ1M99~B(XGWTtwJN4Ut~)a&;8k3PH_ohT zV)-Zz@*2N@@7m-!^EYtXZaZ`QHvy@5XAmIsvV69(qlY6f-(`AOk@Q_)@;|p2FUEq_ zJ*2gqv=(?j$FtjnXH(4EWsU%9Vt>4`67M6&cH(gS#u5{di?YO1jG7?ON!-Y&iQ559 zB;LUrFR?eClL>x}l}daUZ_-wLE?zmSy?PK$b9mxAd;3=-P;pEefDWIjS>^B>WI6k4 z&aL=)jI*D&9w2uj$!iO^JdbRfa91V`EN#J}*yN$_J(H*p`{ zBoagL>?J;r=VanA{H7Ai@CK~y3Odg9-px#A2*{aaZph4LGIfAjiNW}>t@z1!)98Cgm z3hB1;Lk~ha|MEDETUfCRVmfb0oFx^PkigqDpTWCj=tc9qpxW#>>Ms(AL^bi2W zHcu#5l>cTH-R?2M3G00$qo=9;|q_`(i+!HD8MWr~0>q#TU87+|FIpi@F zO7Zg$N(WN>eiVz94y5?w2zlvy@rqLX`?&k*K#G3_q55NO3+}epHI*a(K!A z%EbUuia$hJMv6a)=R^|#rWzC;+{xxPo%hv8659MM0Gup;?m$e zPo%gfQrwG5@sS`}9!T-;B9JjsoT*tAeM<4O0ZK%qcmuktCsN!KDej3B_d38xnI}@* z6DjVA6!%1mdm_a>k>Z|6aW5*xf52oSQk+f$=;Q~#Q7PUGKzSg=zl?z9;?^7)Gr2HQ zJX0veGe(M&a9)b9L?{uF;&mEzTb6#oX`j#r0Tb3C>r$74;@d=szj zCGP9>U=CNf2;1Ee3d|*Se2#T3s}*s)WF!Yqv95)6w=?cik)&$$@ zzC-9T6YQuvmBHmE*oovFG`|K5V%Ba+Q5sB>rUU;fc+bo3{(i_p%MfLueGr?x-7@Jk zATZ5?)*NfuY0C8a{gjnOvMVR>7V zg*u6TKE~L*C;)lc-E7~CUKfpC7e-HwVDzj+4@!Bw#zu5T%~n&tBV~9i5*<%zZR+P( zL}vXIuRGp_ENyK4^gBJWNDJw>0oJd~XIi z)W}jPqLHU3S&fz_8hM5UJWn+8%o<`*Ba=tf$g|4$oH81DwtoY;7mYk8!)Gfk8hNgy zx6-!Cc_0h_D;5JtjeHyes*&fFalV#m0>EhGWtj<(a@qay#>$FD&Wc9Pibl?gM$QuG zWJM!qMI&crUX>M%oE43nE!4=LEPE8mBvd2s>31LnPc-sspQ%~Wnw`Bg=a$Z^_AYA! zC{v)3FUU|CXGJ4tMI&cLBWF86yeumkIV&1DD;hZ~8aXQ(IV&1DD;halsFAIww47F0L{4CmQ)%67W6I$k$epaG;T| zD|?>_7ii=sGF))Vibl>BYUE#+Q5YsvBR}mou~kaK&tw?`U7Pc&-K)Ch{-cm?ONvJRQ&KdtCmQ($ ziL=BLjr?M53#f$}xx5V_{!7E7Mm`4Isz&~E8K2Rt0nQX?RL5gGay-_9|4GWPh3>auQQ)-`;Joba_ko`i`Mj`+&(Oy?na?bo8b=)H z<4RG63m2vkEbF>$ebvjb8`z80B-FKg)k#SNx6YgfaG9r@rlxdN~rz{E+m(-?(srd(z_89jMLzQ-ZVt89fd(0@M-L4rM zGec>w)QpYUnzWH^%fE!QhPq>W(TYQ&E1yG$M`#UgjnEppAfQ!!E@@@mK;*M&@v^&> zPS(&dg`G8YOkrn*juf`!Hy4b4uzekb;?@jMH_GKFc%*W9w~_SmohhoDR~Kq&W0gy9 zZV4EJ5SSwt7#wzC+(H`s`ZzAs$a=}l}l#9V53>Q{KiaclCpbGLyDQ31gz_fk` zx^dZ9W2*0TL}m3YAEikw0Rpd^(W^GL`buL16rfWY8JxQq>1wDH!rEV1ToU~Ghg5HU=8r>6`m6o`O6k4ATX*EV^HAZPQg|w;;CatU+ z$lYm>>%2k*JyCfI6!Ze+$tY-F=ukmdi-N8U2PD>h7<9$0cIXo$;U7dol<>v7JRd6G z1PSkb3KWf+cK96k4(FS`*5HCU`rpCGN;~V1MOG6lsPJ+bs$DDbX$C4KfW;pMs*-B~ z@I9O$WZBgcsQ1JYQzL=K!~sOBl|V~^*|qB=(3&`rfqDtFc{q^AvKu6@F!4Uie2`ee zms!cbF*MlyDiTWN7-t{Rzn_^%p5XjfZ>W)DsdL3hw9j}lT-Nou_2q{jahPTATf@wh zb)C1~N?kw_+X#tMCTQF|2@ac-#5P4Fw#}2MIEEyqyEDgY^z9Lem)-prJY^)s>0|gz zD@NR7+7)9NXM+3Vaf*AS-Vlc~H;pr4zKN5TVa9}QrSf3P$)3*0L*1Zh%m@?Ih(pIk zA`YD%M6^geZtV%%uW4nsgVIAtyLfN#Y)nQsdK|Gat*n(Ygly1kiYVC_~+?s+xrD-o$0iW%qcyIVRe7>;J?d2R0>}$(_ zOD-K*Z`_D=C$&k{EeFYGHv*YH_x}CbhLx z{s-8kmgv3#bcDbrwQ@_?r1tX)Y*K3qY*Ggl+N2JQto3(##Wty~En$QrNnI!NYtIv#)VC#IY*N=pY*OFxifvMl^knew!$;N&QY*jIl}mULeLM^{kLKHmT>l0-Mwy zB#yC3Jzw*oZBl;}`&4h6)Jp@~q+av-wn-%(fe5<7t@OX?Kq`F|qRFimI~o?6NiM*+jS}ccQbo8;g4UVjh{zowfkV9nG!YBr4L~D_U{Im^jMU{Kf1}P=?CZf;8Epg|fPenQV3&4Xs;+5^2o|X*GxG*DNCT5I0bi$A{RO z>X0b`rxx90$E_|@qEWIjJW|OPe^Aw32~PgIHg}YiELvKA;isfzOG-9e_$evbkEoLM z&!=qP!(BgHg?e*dt3Z_JekIUGUD@i)y(z(Y8tlk%#A5H6DOatcN@maDl@eSDVM6t) z%V7T3iMpfv74EXe^;f+?;Vfk`LTJYpCDdv8rxSaYTQf`1P7awm9N3lE3^S`S#Qg(t zo89MTC@%Lw@UpuvGq}yohC$1}jkvxWD5JeY+_yt6{0WA#<~`>VL=`G|&rQ^zvD4)i z=QGPfvEBj2xOHhd)PKW`{ww}K_??>Qrvk^?{V-Mt52PXfDS%m4HD47XKauJbnqD)ECC&S z#)e2h2cNN_GDX+HXKa`RbnqD)F6KBLe8w6jpo7m?lc4F~Gd4m3I{1u@lzBsK3xtzV=eA=$WUq#p3zi_>kWIIP+Vzgu>LSUt09bqXuTmO zsii0|Gx|Br)PC{j-VfCx-o}o8O0_SQw5Y6YJy?@b1#Nx<`HJO?to?C!IGpC)yC_AowUIA1Q?6XwdCmS(fKw*Y|DoO z-D;jj{e|8@;!cu~7Cd|ypYtuaqMdPkH)yYUW1DI5V-z1rax?huASwI3&WDVQTZ1aX zhR@?S9s;!3Z@~!chTQ0ee-4xD<8z#nZLMTm!>*`(U^B2c!+x*Qu>T`5>=zO4j`QzC zvk(#PP7vddig0(LT92$aMYuajEKZL13m`ilqa=Qd_r5*a_b`Z68&gX`e0!`&a4)%T z?ID&uP6Fjt{AtS1@$RokAOj&?Z?E*1hXg*M1U#4GdlxY{dESp0WtBjn4|wj7y{lV| zIKEG`-NpKJ_Cm-$T));Eg!s+C$jLg=?&EblzAT4LxVz6d1}L$vC6%&;ZTE%5lWkOD zRQlu)a)bTd!ML2cw5LlN|6HKNFNFT#Wp}^BG!8iB?iu+J58DP=-)$nh$>}^MM3w zWqqnrtihmI#q%G+o#7p|P)pTjIcg0YJ43m}ty43hTKWn|KZKNu-QyfL2*fvbJhl~x z#x7`B47%}~_Qz){KQcVG*)q?xH7RD15GK$ud-zKp^HjPk|ms?zGV3)ENA_YO1w({5SZoC zHR9v^t?(wn(M^0plB0O5f+LCeLHR6-pI-r%y=qBFkb1s(P_#-~GLgr-&)>nL* z1iS=CH}PO}<9KHR+wquAoTHog43{g)<(+tLfo1na1S-}Xga%fb;VpWTs$#AzMLXWjY9*tu;P zr$LrMgO(=e{z*KI(=bZobXwMHvM_lLR;kUbp&Ap2hk*ObB}@rt*Q4q4>KuYpHnx?P z22W@rrG?3Y4RNJ~Nedq#mlh@=>54bYmlh_iffgo%q2;e3m_NkOl1qtd9dKLyK^O{& zb-EHD*xZtS#_{ww}gDx($6NWB7r{c2{~47{b&k)kOD~tMiL=e6_T{RUWO{Q{*A3hM(Iy5 zO262%Vk^x>8>{q7roxYbsqhqb);-+4chqLNL)bd$^hQmEdyE$cIQU#ddiEakx@ExH zp;o;;Gn^=K{Hm72xa{JJd$eh%wj=eW?kq!gOgR4S38^m~rqtV&+|sE^ZY7O`%S@B+ zC`XrCZUSqp)LN2lc0akja{IfG>{@gTWx9D{glzL7L$(5BM|;FWw}o2}%+WQluw1?q zZV7fPB0HQQWOip-z8mzc*pvSJpAxf0H)*o_VC;bg5Jp_`)?o7Yb zv~@ao4HuQg5gU{9Nm0`Cpu?GnaoZP0k_w8>3Po(&X!+*o%L zqu04(P1Ns(QNPWo{C3{18>ZOpHT+=SuA9NMX!`@D21BW{{z?)W6dL;)e#~&z4Mg)v zAz{r&wlT14ToQ1s?W#)x z_eTfHAVD$M$Z*f*4@D?OHz!R*N(C1r1+!6#n-x7hhAlU?-2)qS-5mZ_d;+X(G z-{b0SZD6MWBK04kb`TXSU0eTNOvFZ50DS8qE2yg%cI(s(!!G~t(h#xTAK zjL)}Jq0hI}!2kz7-%?4W75IEh8E-)(){+`ci1GQB65j-GBnW9u9Zdqp=bQQ_Fh1W> zh2DZv;+x>@n$d_8`X;EDi4gy#;n6q2QQ$W47Q|;XYk+h2e7>k zbxu$z&I#c2O}dkJFFE$ulCYT^@vHX5+PS@5iqGfo0;X{tqBlt6KZ0iU?_eOdx0}Qc zi#d6<2kvhBs&)pSIN#F6Cpc)W|Zt! zA=#={5}YaoFZ+a2%JX?nNO0=J2*IiIq6DYs32sM%L&TKvz|KnW@sPv6g#?Ef4%;>3 zLxe+Qv}O;+A0|8fpx@3eFos`AJEpLT<(I zh>%+`DJtZ4427Ig95<7!DvnGqvIUA`LWJ!6xlytOisLB~oFshivuiP*dBrhlM1pjqlMBB##dKp^3|Z6#8m1eZOBo+%a4|g? zA>#xsa89aUoMO816(H8D8#K6>ZUUz9g9aDVV-PZq&@kQj0~)LGgciD(PM*r>m~Nba z)Ki7ijdbC3BYhdrFx?;)ryJxom~Qa7Je+RahEUo}H~4H-M5h~>`|*Beu6Ofr~m9E23oX1c-DtQ2?s^l~x12%zK}Xu`{!v;DUaP_%RW)0lpmU-LO% zlz^9_nbi4`1pG9=m~+mRk67!|bE*+IPXdkUF=(<*mjqh0xW6oc)-*q?bIzAQTbiG% zI~Pb`p%uRr!&K)h-cjJdkIa7dL3Z_v)11tHax(kL$?PX5v!9&IesVJV$;s>|C$pcN z%zkp5OQv$s*-soq{mAU+Y$hYKpImhI!*5QL!R+TL1hi0Z&5E}Z?O&FqJS z^Ru4|5%MFmpE5MxoXmc5OYoTYc>PD9CWF}zJ$q`xFZ+yPr3!terVD+grp@f<`@pJC zo7oQojcGIcA+eTp;p``EW`oI%wyf*M^-6cAxk~pMLwDzZZk^07bQd4i9<1s%@;zH7FQfNRhAWtPTy}RG zR6xD#(3?HxG`yjoZB1bIbWPyA^|i8rXl?~NEd6d<)zu_9Qb_*2T_{=k1&iZAvPPne z9L;A;ag^dnp-2Op_Si~q9$IymDZB;Ukm5gH$IXDoZWE|U^#<3eH%%;mwznNQWaXqg$h}nNarReB< z`X~)6a-tY5>iqdhCw?gE)9#Z0~CCQv1^J&>l4h6z-2>}6LCI}C5I7GEtVHdIZ%PJ%1z zu=Y`7md`uuWYc+VemBWv=z_R)bVDe#eT>2=w2RN7e1BX?XqOCACBsx{MFSI*Eo+#1 zpTe%q{muR=;eM+(2<(?Buw`YpZ3Gt_AsVaYuzl!5( z97Q~CVo7C`R7OcWz)aYYFGBs2QvT#0qu##CuGSgd(l(ee8$EZ#2aR+GByn~Q^!l+H7 z3!*knGf`{BKs7S0s%52BbrC7mxhvNeGx4>MQr++ZN_By#w(2?=HRA??_^V0*#h|=r zMimr6W{NVs0!1xq_G7{lB49pVP=^SUo6?=LK6lgCYJeC=VwIkvBi3kw2?95NQa- z>7-Fgq_cWAd^2ND3MFIJOmZ<&x4Iev#;(X%L;xWphw0P{57LVn)t4MBkAG`wu zYL&-KsXYuM7O&4wL$3Y{R(4BYvz5MPLz6Untx8|BmA+=f_Y)UkqR_|JZ1+>xb+}WG zP!UE6$;<9eLCV&Q$`LxaOC}keR`pB7Ug6?k9=W(#h!^(kgxD(@L+mGsJ>UJCA<9_+ zFC3Z+>{{`UHGj}`cmw6ab=s}Mh1vQaF=}H4N!@xVBUx77LG8;-?2m#mOh0jJuaU!E z8prPr#8}s=TKS;4ai#`W>RzA5tr-!k4oqu=eBz8lksBnBBQpWljvRqL=uwi-x`Bv) zURWUSN-JBfwBUw_pYFx2#->m`j76bQJ$%EIX}6iUeRBp<|1VGveS8)7hCdBV>PK;J zW)4QFn{VR&DSp=5x6BvRffw zzJ?19>UB?LRP0XeM5gL)IPJ9TCavA8>xJn95vRvDj@;X%DuB9t%(_43(D z$?nwfpx*Q?c*+0r#Q<`5>LCaO2lXD0=ZYo(jKo})X~Hlhvp?Qg8QGnhk=>~o*`1n^ z-KkhiLVwE0?$nIzPR+c7H(o||r)Fe#YNl{^>L<&7ie%htf#f@T`nw{9gzQdT?K3q! z+_Kj}y%PbdDA*2qLFO*9CLhCPWIJd^wu5FmK)fs?+d(t39W*1`K{NN^eIg^06V{zwp*W&?V!&}pfO<%>Lsz3glq>j2lXaoJLvNsA*~77 z4r&hS^~^!N{7iOXLbijNgL)IP9rVT8p@~Du13HEUPLT?aT zaY!j&WajA6?4A&VzR1kc(^N<<$%)Jyy+DHteHp5c-kuS;np`PzvL!?E7`oF(i@I{; zVOqMTT%92YS>YfMe!mPk@YPz=%<4iMrJpsY^{%X3%(yv29%6N88FjB6fvUB6T3`9C zMyxJ4N=ZHlI=ucevm{noXKhwVtd_(ow^5eFDrMs4600XuFfDaw9xKwu`d__4q&^Qx zs3LXgC>5#gIq|c#bc)K*Rldl~rCSq|0#`)pw&}k}a3Of4Fjd)^UCU$^xW79_>F4e2 z{Af%GEtsgnw-df)4+Qe;!+;A}taKMFRl4m~_M4kQ ztx>H?%ZU9^^GQp@{`RCbI%$UKmEt#cjPV`;zhai%VgjqI>;=TFckeb5`dLYp>GEg@ zO}BoerrYid;rdo3yi)T}zgY9IEC<5%E3_DwSkO$up5{UVm;YDV35^K|?5w)vfrVl2Z9|+2$RquZ7&P zw|Cz(>#-My5<0I`wr`0jmF;Ill*;zoMwH5mzLm-ZCe!A|O)~!w*+zl9T{sY8YbL{*0Pvjqp>HgwyH7= zWAmq>eN{+XIn5fn?MgRm=o$s$n_RGlRL% ztDyBD&~V68b69x41Of|hH^b*5Jo9>IlM3%spfHg8_{eEa&WpmcTg-yp?fw|EPCHwx z-EN)xf&@pNMe1E0U=pn|ZoQk&&3r6oF*g^P+{j_A2=6kF{CMIlF_uVj`WsJhfjs6V z7V~Di7lU>z=3vlamBpQd4mlDq=SE=0OWv?b-mpsEurNz1dBd_|)(3gRng$VM@9X~j z6bKSru#CxNck_#M-37aEJ)fbJt8;=pN>ylwnTJ-z_;wHXd_!V(NMZ!!os!sNXoSQb zV-1PwA67H&Je8Qxx`&h2w(gxLE0L!{S}Q|Z+Xn1dRl|wh=1wu#TwdU1cYlG{odRvT z4sW1&xZiC~sI;ou2^{5aXC{U(N<>EG62CG%YM3%DQAdYcmMk@xYaQx)MZzI1xo+esY>B_Luls(c=z8a{Y$GprB$EOst~1DG@teqUP9{0UN#mSGaOpfljH(2m%etOD z#&XxeZJ(IdtQ z7@Q-?#)r-52TR;-6>NOCA@eSisbf=PA>rh zQ9oEm;!U4^uyzF?^n*1Htt#+?#Tc992aCk|_Jc*phWf#pf;i#Ehs+{`_#gVgIvLys zez5oqZ*u?_`N3jG9LNvWCjoc7LO)oniRy`*ciYn41DP!3&1@nFpRJQxTd)dN zODS&8HjZ^W>&0ct920D>mubvga||OjFlBl}IT>hiUpZY9-$8HSo!`jR2*sA+I?L*; z6N)Y4f_dAZ;f$Pf14-Nva;_0`ji(u|C1P%h1{Z23atoOW+Dz+3@>f;Ri64r{vQ7ga zZY>`l%KWX75T`i1Q2*fKZX;fYFD}V^G)uT*EXn-%Tz2h}%%_~XqpBqHx17vBhGK7? z2<@9br-F#aa$a`#OO*K{wC7c-&~Dd_yYm_e!eRx5_JU9am~T!FCCw4;BSyeIr{q9y zHDqDE$l(#gjW|_$BPJ+4C;=P+Ymdre=>p_e>$c)%af^znR>O&;JlX_1twHS!XWc-Q z2Gb4fFBUPJ9jjs(bFLqNVBC6RLMVpMM^uX8`TVK~*Z=CxdTr~C7sF=G6<-Tl*rSNw zKIbcDis7Cr+)LRPb76NU+y>@tgwa=)^#(*j+*&;`%)vKJ4zk9^M+9DnFWLAUe5jR@ zJ~QQra@Ngr@oD~Vz(|5s9iJh-SuKxxGd@!So*wZvtD0Ecll)EGWlwUvO`gr3Q>a_u& z8)M@y`4t#tdfaIlf7xdYE5VJiadS$9$1V|nHF-GzzQ>KR@z*3!?{Q;n{2vl%^tdrL z{(6GMT0HU?H>X5++!z~wLm;i*(Ij9_iAZo`Y}}j@;ZYIB-;(aN#N)=;_}ewrpcak~ z)1wgLf4DJre`4K6itl)Qc03*u;&_~@XUl8Qq_&X;H_P<$U*J72yZavC>2mcp4Lm)B zTdl*T~zy{#FuwdY=AdtPROt8+aJE;nPg4xAIs)aSa- ze?bzoR_P5Xm!sio%5#Tn%AK0>+zFa;ho(GtE2hj*RrXoZZjzjwX`26DVNQ+(y(;Ptxso~WsHST(mZvKkYD-nvalKv~TWHmqu?=0c%r-GWTVt-B|M9lsg{Nzo-| z`QW|)9PqkoDKfXYtp_}LRyoBy-d6j2fZv=*vpcpm(gQwzL#|& z#Q(6DJpyKfUdCs~y9nTlnW&iZ_`$Z%0|he&S@CstijBw09BjoutSBt@eNL7Cp2|BFsoKL2eF>Bwu!oG`Gt5#-Yshq^#gBUs2_X88ZuOQ?v50ME{6%W zy9&QC_h87NG8du~EirK<0x0*mkWq!eV&PH|4~A>SQ@7Hq?rL*;H= zlP`sPOexfT88mUdK=H?GJ0`K2ZMlU~IldT)#0T8jbQm%I2S3i_y1Q{J9piQk8!<@F2gaCzdzoTj&Um;c;)Oe@Omtp8Jpo>V;oFlfs7BQ=cy zJzF@=t%`aUxQAH`#aeaze8i}FhR+9z8d!ZH8^2|JU2hnCOmSc#mRa?I%{-bB!*Jc( zao{w9FsQDX%R~+`1J}-)_QsqRJK_K?6fqm)ZSVB0)_NhB~{I5^~dP5LTG0A6-C_ajz|yN&T9_{=Rn zlI!u)l^%yl>1ibRg@CMr;iRB~zx-O>Gydk=yO0# z1;^rW_@=qIHAluwE^d*)9DL2RB%*4BJBI+zfi2q?HJ_Fna z%Yl4Gvj({6P*8Tnfer=T8}NkpD{!3f*pd<+Ya(?lL{f`A-hUrpVbq@Jkx?ss044;J z5;CYPpF(*)xu90;Rr1jaK|Ff~GnD1Ikr*@_C(zvLgBEAnPC*QDIAv-?;X6<*F&YtcW zUsd8JDWpMv+A6R29L8sE*hqMcU3)g;EOc8g);M_+(_>+rg(gnBRre`k&u|~Q$YARY zDa4R@O<_iuLj6yPt($KGq5p6gLv>EBiFu|9lBLqzWM)ye&HpbR;?{Skhx((cPW4Cj z5~b0ABzax7BVue0{ox%0Y8#_3)G!?Ai_+|)bcl565NUL!#*f?~($7<%?J9!&Qrhit zeE~X!m)&hsV9G#x*QUtyVb{q7ar!{@XYU@E;cH$ex%O~2@dSgPG{JQkgv)GV8pNL6 zrfFWPX<>uETz2>FVVZ5DBWboxkEB_!1>PpTW})}9Zl&{tA!~PE9nxza8KKuaB|>jZ z$Yt#^(ldsCBbjdt%S6i~YbGjKq?{$Qg26LGseTKhb5_vub!B2F4o+~zK2ehDB_G-) zAKGRX@G81|eirZ^LeW{kLFhJp&H}arK$oMOm;B+7KPj0+z3elFl{B*e4s^YgnFU;j zfS)q600!z)W){G}M^37H7eNFy+H?HJSvs;OVV*4MTB#=}+vbZ;3omsT0}EuZ@27sw zz*d5WYI%{Ng^rk*e$VGmxz3d+D_n=`4fQeWd`z1(+r7fDbS{^*uuE3UHeVa zs&NB(e`?5%(y1}J)6l7z9I#^XGuyaz@~lvGya7s79mklWe$9~T*<}l>j)4}5nVM;B(IPuEvaKUKF4)#VKMp!Lr?lt#N3AR@Yr+Y0`k-f?oMH9kO zO$U?O!M*cpC7&O`{5VWzhtZK_c9H)Ol!LXw~0?r%tcQBy#Pd^#jOp*h0pglQ30C(PF(SPkngX*CF|fqr>6 zq^G6ZFqE|NBguyGB*u|sos10!OEcg|Quceqtxw5gpEC#S-k}a8J(F{IvllQ6zDB;xn zSS*Fq^QKC__`@!y^k z|LwU6)QCCp-<~7T$%+5=ocM3gy@NMiPW-p$rl43;x$ojl+A4k0hGOv3#$s9eqzxkE zHa4Djypu7f-;AFzCl7=)YQ+HkEwt10WCZM-d?{?D(+udDL|%%!;AGtGr;p|PYPDCU z_CE$PuSNom>AeW4l|zkMtoT}n>YU3!xVo0ld&|iG$?K63TyN_QgHf(L)rf6xZ~4$o zwk3!ua_@f&?Dbbioq8#NA0l%6woGUozm`y(onlJ z)J7lu$PKl<$033mp>=)*iL2{mIkQeSd=R9b(K@pCTD49}Eb7&=eg@M|Hw9~ru97{; z=Xs)AuD?+w+PJ7sD{7^Bpw(yyYUy@|&^oXiyUBnbr)iC3Aca!2+_k2SUR(iSY z?mvYT$4-n;92@xGSLHQ!X+W`VGRtj*yVTIyA*3}WR5c@_v_?c}jRrK9lW}vc}hDp zN;@=4J2WhwS9KKTIKg~}&yF__;<9L;Hos3CXrH!x_Tb$MP2hNYL(VuJ$GKH|P)<%2 z@9*z&u8r&PP+M3KSZd^%I$k$YEUT8i8dHsn`X##SVp^J*qDwkRZ$@xd2|aww6pe)w z0g>cQAYZpFQHF`-{9=>j{*o|WcdrVQ9A>t*wb#)4Y6qU=J4v%CTs^MuBDJg=h|se` zO4Y(jb|fboP%?~G@Ll}&G7D&47|PhZ_H@w=23<$(tUE0%yYZ?M*NFFr-mECIpXiLU8!nBSSM3El-tVQu0!AXm*tZ z;F9zP3c_l&FTKL&CGMzOMTA*g-r{9<&xClb5yvb`hJ7DzAQ*M%ykr7F#wpWMBeK`j zjjBSdZH=$IPDpTCnd+^h9dwUaT?yk%|yfg2#llQJ=V2E zQ=2`5sZn9nJx*5VW|>i>ZdG5+aFhG45yKaRtiM9m1-of1pTRnlX`26r1XePcrfoEt z6`IV5v}S4{7-s^GN0tWN#UyIoK+?-+Nq7&(PeQ(Sw36>6`P$isFJG6&>JwV?U`WbZg)&2Gz0wKHS$cHq@sQ+}rZ= zAn~abxVIIbN`ZS@@u>v&w#1@)+pps8P(Z`IEuW1~rPv%lg^Y+#rP#bIpVg;QEbmik z5MJ_M{GE⁢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 D*~3Q? literal 0 HcmV?d00001 diff --git a/src/debug/debug.c b/src/debug/debug.c index 89108ec..63db31b 100644 --- a/src/debug/debug.c +++ b/src/debug/debug.c @@ -154,7 +154,7 @@ void print_ast(t_ast_node *node, int depth) // return (left_depth); // } -void print_node_info(t_ast_node *node) +void print_node_info(t_ast_node *node, int level) { int i; @@ -175,14 +175,11 @@ void print_node_info(t_ast_node *node) printf("Type: PARENTHESIS\n"); else printf("Type: UNKNOWN\n"); + printf("Level: %i\n", level); if (node->cmd) - { printf("cmd: %s\n", node->cmd); - } else - { printf("Cmd: NULL\n"); - } if (node->args) { printf("Arguments: "); @@ -243,15 +240,18 @@ void print_node_info(t_ast_node *node) printf("Heredoc FD: -1\n"); if (node->children[0]) { - printf("Child 1:\n"); - print_node_info(node->children[0]); + level = level + 1; + printf("\n"); + printf("Child 1/%i:\n", level); + print_node_info(node->children[0], level); } else printf("Child 1: NULL\n"); if (node->children[1]) { - printf("Child 2:\n"); - print_node_info(node->children[1]); + printf("\n"); + printf("Child 2/%i:\n", level); + print_node_info(node->children[1], level); } else printf("Child 2: NULL\n"); @@ -260,9 +260,9 @@ void print_node_info(t_ast_node *node) void debug_ast(t_ast_node *root) { - printf("------ DEBUGGING AST ------\n"); - print_node_info(root); - printf("------ END OF AST ------\n"); + printf("------ NODES INFO ------\n"); + print_node_info(root, 0); + printf("------ END OF NODES INFO ------\n"); } void print_hash_table(t_env_table *env_table) diff --git a/src/lexer/lexer.c b/src/lexer/lexer.c index 3517280..ef51abb 100644 --- a/src/lexer/lexer.c +++ b/src/lexer/lexer.c @@ -6,7 +6,7 @@ /* By: slombard +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2023/11/30 07:12:29 by slombard #+# #+# */ -/* Updated: 2023/11/30 07:53:34 by slombard ### ########.fr */ +/* Updated: 2023/12/14 18:31:26 by slombard ### ########.fr */ /* */ /* ************************************************************************** */ @@ -63,17 +63,17 @@ t_lexeme *lexer(t_data *data) i = 0; while (i < data->token_count) { - printf("i: %zu\n", i); - printf("data->token_arr[i].str: %s\n", data->token_arr[i].str); - printf("data->token_arr[i].type: %d\n", data->token_arr[i].type); + // printf("i: %zu\n", i); + // printf("data->token_arr[i].str: %s\n", data->token_arr[i].str); + // printf("data->token_arr[i].type: %d\n", data->token_arr[i].type); lexer_t_var_subs(data, i); lexer_t_quotes_var_subs(data, i); lexer_t_pipe(data, i); lexer_t_log_and_or(data, i); lexer_t_parentheses(data, i); lexer_t_redirects_and_word(data, &i); - printf("data->lexeme_arr[i].str: %s\n", data->lexeme_arr[i].str); - printf("data->lexeme_arr[i].type: %d\n", data->lexeme_arr[i].type); + // printf("data->lexeme_arr[i].str: %s\n", data->lexeme_arr[i].str); + // printf("data->lexeme_arr[i].type: %d\n", data->lexeme_arr[i].type); i++; } finalize_lexeme_array(data, i); diff --git a/src/parser/parser.c b/src/parser/parser.c index e8d33ff..e700773 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -6,7 +6,7 @@ /* By: slombard +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2023/11/30 07:15:23 by bsengeze #+# #+# */ -/* Updated: 2023/12/14 18:25:41 by slombard ### ########.fr */ +/* Updated: 2023/12/14 22:30:37 by slombard ### ########.fr */ /* */ /* ************************************************************************** */ @@ -29,97 +29,101 @@ void parse(t_data *data) free_lexeme_arr(data); } -t_ast_node *parser_parentheses(t_parser *vars, t_lexeme *lexemes, t_data *data) +// t_ast_node *parser_parentheses(t_parser *vars, t_lexeme *lexemes, +// t_data *data) +t_ast_node *parser_parentheses(t_lexeme *lexemes, int start, int end, + t_parser *vars, t_data *data) { - if (lexemes[vars->i].type == L_PARENTHESIS_CLOSED) + vars->parenthesis_sibling = find_parenthesis_sibling(lexemes, start, end); + if (vars->parenthesis_sibling == -1) + free_exit(data, "Error: parentheses not balanced\n"); + else if (vars->parenthesis_sibling == start) { - vars->parenthesis_sibling = find_parenthesis_sibling(lexemes, - vars->start, vars->end); - if (vars->parenthesis_sibling == -1) - free_exit(data, "Error: parentheses not balanced\n"); - else if (vars->parenthesis_sibling == vars->start) - { - vars->node = create_node(N_PARENTHESES, data); - build_parentheses_node(vars->node, lexemes, vars->start + 1, - vars->end - 1, data); - return (vars->node); - } - else if (vars->parenthesis_sibling > vars->start) - { - vars->i = vars->parenthesis_sibling - 1; - } + vars->node = create_node(N_PARENTHESES, data); + build_parentheses_node(vars->node, lexemes, start + 1, end - 1, data); + return (vars->node); } - // This sould be never be the case - if (lexemes[vars->i].type == L_PARENTHESIS_OPEN) + else if (vars->parenthesis_sibling > vars->start) { + vars->i = vars->parenthesis_sibling - 1; return (NULL); } return (NULL); } -t_ast_node *parser_pipe(t_parser *vars, t_lexeme *lexemes, t_data *data) +// t_ast_node *parser_pipe(t_parser *vars, t_lexeme *lexemes, t_data *data) +t_ast_node *parser_pipe(t_lexeme *lexemes, int start, int end, t_parser *vars, + t_data *data) { - if (lexemes[vars->i].type == L_PIPE) - { - vars->node = create_node(N_PIPE, data); - vars->node->children[1] = build_cmd_node(lexemes, vars->i + 1, - vars->end, data); - vars->end = vars->i - 1; - vars->i = vars->end; - while (vars->i >= vars->start && (lexemes[vars->i].type != L_PIPE)) - vars->i--; - if (vars->i > vars->start) - vars->node->children[0] = parser(lexemes, vars->start, vars->end, - data); - else - vars->node->children[0] = build_cmd_node(lexemes, vars->start, - vars->end, data); - return (vars->node); - } - return (NULL); + printf("parser_pipe\n"); + vars->node = create_node(N_PIPE, data); + vars->node->children[1] = build_cmd_node(lexemes, vars->i + 1, end, data); + end = vars->i - 1; + vars->i = end; + while (vars->i >= start && lexemes[vars->i].type != L_PIPE) + vars->i--; + if (vars->i > start) + vars->node->children[0] = parser(lexemes, start, end, data); + else + vars->node->children[0] = build_cmd_node(lexemes, start, end, data); + return (vars->node); } -t_ast_node *parser_log_and_or(t_parser *vars, t_lexeme *lexemes, t_data *data) +// t_ast_node *parser_log_and_or(t_parser *vars, t_lexeme *lexemes, +// t_data *data) +t_ast_node *parser_log_and_or(t_lexeme *lexemes, int start, int end, + t_parser *vars, t_data *data) { - if (lexemes[vars->i].type == L_LOG_AND || lexemes[vars->i].type == L_LOG_OR) - { - if (lexemes[vars->i].type == L_LOG_OR) - vars->node = create_node(N_LOG_OR, data); - else - vars->node = create_node(N_LOG_AND, data); - vars->node->children[1] = parser(lexemes, vars->i + 1, vars->end, data); - vars->end = vars->i - 1; - vars->i = vars->end; - while (vars->i >= vars->start && (lexemes[vars->i].type != L_LOG_OR - && lexemes[vars->i].type != L_LOG_AND)) - vars->i--; - if (vars->i > vars->start) - vars->start = vars->i; - vars->node->children[0] = parser(lexemes, vars->start, vars->end, data); - return (vars->node); - } - return (NULL); + if (lexemes[vars->i].type == L_LOG_OR) + vars->node = create_node(N_LOG_OR, data); + else + vars->node = create_node(N_LOG_AND, data); + vars->node->children[1] = parser(lexemes, vars->i + 1, end, data); + end = vars->i - 1; + vars->i = end; + while (vars->i > start && (lexemes[vars->i].type != L_LOG_OR + && lexemes[vars->i].type != L_LOG_AND)) + vars->i--; + if (vars->i > start) + start = vars->i; + vars->node->children[0] = parser(lexemes, start, end, data); + return (vars->node); } t_ast_node *parser(t_lexeme *lexemes, int start, int end, t_data *data) { - t_parser vars; + t_parser vars; init_parser_vars(&vars, start, end); while (vars.i >= vars.start) { - vars.node = parser_parentheses(&vars, lexemes, data); - if (vars.node) - return (vars.node); - vars.node = parser_log_and_or(&vars, lexemes, data); - if (vars.node) + if (lexemes[vars.i].type == L_PARENTHESIS_CLOSED) + { + vars.node = parser_parentheses(lexemes, start, end, &vars, data); + if (vars.node) + return (vars.node); + } + if (lexemes[vars.i].type == L_PARENTHESIS_OPEN) + return (NULL); + if (lexemes[vars.i].type == L_LOG_AND + || lexemes[vars.i].type == L_LOG_OR) + { + vars.node = parser_log_and_or(lexemes, start, end, &vars, data); return (vars.node); - vars.node = parser_pipe(&vars, lexemes, data); - if (vars.node) + } + vars.i--; + } + vars.i = end; + while (vars.i >= vars.start) + { + if (lexemes[vars.i].type == L_PIPE) + { + // vars.node = parser_pipe(&vars, lexemes, data); + vars.node = parser_pipe(lexemes, start, end, &vars, data); return (vars.node); - + } vars.i--; } vars.node = build_cmd_node(lexemes, start, end, data); return (vars.node); -} \ No newline at end of file +} From cb7791553943d6b3cc371fbeb4cc799c327bc259 Mon Sep 17 00:00:00 2001 From: 552020 Date: Fri, 15 Dec 2023 20:41:02 +0100 Subject: [PATCH 21/29] WIP --- .minishell_history | 0 src/minishell.c | 4 ++++ src/parser/parser.c | 47 ++++++++++++++++++++++++++++++++------------- 3 files changed, 38 insertions(+), 13 deletions(-) create mode 100644 .minishell_history diff --git a/.minishell_history b/.minishell_history new file mode 100644 index 0000000..e69de29 diff --git a/src/minishell.c b/src/minishell.c index 3792a2a..a82a17b 100644 --- a/src/minishell.c +++ b/src/minishell.c @@ -12,6 +12,8 @@ #include "minishell.h" +#define HISTORY_PATH "./.minishell_history" + void execute_main(t_data *data, int *exit_status) { if (handle_heredocs(data->ast_root, data) == SUCCESS) @@ -35,6 +37,7 @@ int main(int argc, char **argv, char **envp) check_input(argc, argv); initialize_data(envp, &data); + read_history(HISTORY_PATH); // Load history data.debug_level = DEBUG_ALL; while (1) { @@ -50,5 +53,6 @@ int main(int argc, char **argv, char **envp) free_ast(data.ast_root); data.ast_type = UNDEFINED; } + write_history(HISTORY_PATH); // Save history on exit return (exit_status); } diff --git a/src/parser/parser.c b/src/parser/parser.c index e700773..acff5be 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -56,37 +56,55 @@ t_ast_node *parser_pipe(t_lexeme *lexemes, int start, int end, t_parser *vars, t_data *data) { printf("parser_pipe\n"); + printf("start: %d\n", start); + printf("end: %d\n", end); vars->node = create_node(N_PIPE, data); - vars->node->children[1] = build_cmd_node(lexemes, vars->i + 1, end, data); + vars->node->children[1] = build_cmd_node(lexemes, start + 1, end, data); end = vars->i - 1; vars->i = end; - while (vars->i >= start && lexemes[vars->i].type != L_PIPE) + while (vars->i >= vars->start && lexemes[vars->i].type != L_PIPE + && lexemes[vars->i].type != L_LOG_AND + && lexemes[vars->i].type != L_LOG_OR) vars->i--; - if (vars->i > start) + if (vars->i > vars->start) + { + start = vars->i + 1; + printf("calling parser in parser_pipe\n"); vars->node->children[0] = parser(lexemes, start, end, data); + } else + { + printf("start: %d\n", start); + printf("end: %d\n", end); + printf("calling build_cmd_node in parser_pipe\n"); vars->node->children[0] = build_cmd_node(lexemes, start, end, data); + } return (vars->node); } -// t_ast_node *parser_log_and_or(t_parser *vars, t_lexeme *lexemes, -// t_data *data) +// vars.start is pointing to the first lexeme of the array +// It gets updated when parse is called recursively +// start is pointing to the matching lexeme t_ast_node *parser_log_and_or(t_lexeme *lexemes, int start, int end, t_parser *vars, t_data *data) { + printf("parser_log_and_or\n"); + printf("start: %d\n", start); + printf("end: %d\n", end); if (lexemes[vars->i].type == L_LOG_OR) vars->node = create_node(N_LOG_OR, data); else vars->node = create_node(N_LOG_AND, data); - vars->node->children[1] = parser(lexemes, vars->i + 1, end, data); + vars->node->children[1] = parser(lexemes, start + 1, end, data); end = vars->i - 1; vars->i = end; - while (vars->i > start && (lexemes[vars->i].type != L_LOG_OR - && lexemes[vars->i].type != L_LOG_AND)) + while (vars->i >= vars->start && (lexemes[vars->i].type != L_LOG_OR + || lexemes[vars->i].type != L_LOG_AND)) vars->i--; - if (vars->i > start) - start = vars->i; - vars->node->children[0] = parser(lexemes, start, end, data); + // if (vars->i > vars->start) + // start = vars->i; + start = vars->i; + vars->node->children[0] = parser(lexemes, start + 1, end, data); return (vars->node); } @@ -94,6 +112,9 @@ t_ast_node *parser(t_lexeme *lexemes, int start, int end, t_data *data) { t_parser vars; + printf("parser\n"); + printf("start: %d\n", start); + printf("end: %d\n", end); init_parser_vars(&vars, start, end); while (vars.i >= vars.start) { @@ -108,7 +129,7 @@ t_ast_node *parser(t_lexeme *lexemes, int start, int end, t_data *data) if (lexemes[vars.i].type == L_LOG_AND || lexemes[vars.i].type == L_LOG_OR) { - vars.node = parser_log_and_or(lexemes, start, end, &vars, data); + vars.node = parser_log_and_or(lexemes, vars.i, end, &vars, data); return (vars.node); } vars.i--; @@ -119,7 +140,7 @@ t_ast_node *parser(t_lexeme *lexemes, int start, int end, t_data *data) if (lexemes[vars.i].type == L_PIPE) { // vars.node = parser_pipe(&vars, lexemes, data); - vars.node = parser_pipe(lexemes, start, end, &vars, data); + vars.node = parser_pipe(lexemes, vars.i, end, &vars, data); return (vars.node); } vars.i--; From fdaff6cc844151277578faded6bb61eab7e80467 Mon Sep 17 00:00:00 2001 From: Stefano Lombardo Date: Fri, 15 Dec 2023 22:12:30 +0100 Subject: [PATCH 22/29] echo hello | echo hello | echo hello && echo hello && echo hello | echo hello is working --- src/parser/parser.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/parser/parser.c b/src/parser/parser.c index acff5be..0697c91 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -6,7 +6,7 @@ /* By: slombard +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2023/11/30 07:15:23 by bsengeze #+# #+# */ -/* Updated: 2023/12/14 22:30:37 by slombard ### ########.fr */ +/* Updated: 2023/12/15 22:10:05 by slombard ### ########.fr */ /* */ /* ************************************************************************** */ @@ -55,18 +55,29 @@ t_ast_node *parser_parentheses(t_lexeme *lexemes, int start, int end, t_ast_node *parser_pipe(t_lexeme *lexemes, int start, int end, t_parser *vars, t_data *data) { + int l_pipe_found; + + l_pipe_found = 0; printf("parser_pipe\n"); printf("start: %d\n", start); printf("end: %d\n", end); vars->node = create_node(N_PIPE, data); + printf("build_cmd_node\n"); + printf("start: %d\n", start + 1); + printf("end: %d\n", end); vars->node->children[1] = build_cmd_node(lexemes, start + 1, end, data); end = vars->i - 1; vars->i = end; - while (vars->i >= vars->start && lexemes[vars->i].type != L_PIPE - && lexemes[vars->i].type != L_LOG_AND + // while (vars->i >= vars->start && lexemes[vars->i].type != L_PIPE + while (vars->i >= vars->start && lexemes[vars->i].type != L_LOG_AND && lexemes[vars->i].type != L_LOG_OR) + { vars->i--; - if (vars->i > vars->start) + if (lexemes[vars->i].type == L_PIPE) + l_pipe_found = 1; + printf("vars->i: %d\n", vars->i); + } + if (vars->i > vars->start || l_pipe_found) { start = vars->i + 1; printf("calling parser in parser_pipe\n"); @@ -74,6 +85,7 @@ t_ast_node *parser_pipe(t_lexeme *lexemes, int start, int end, t_parser *vars, } else { + start = vars->i + 1; printf("start: %d\n", start); printf("end: %d\n", end); printf("calling build_cmd_node in parser_pipe\n"); From 1c464a30a0177cc541aa7ae97eb7f897676b4f36 Mon Sep 17 00:00:00 2001 From: Stefano Lombardo Date: Sat, 16 Dec 2023 00:16:45 +0100 Subject: [PATCH 23/29] fix small bug parenthesis --- include/minishell.h | 16 +++++++-------- src/debug/debug.c | 6 +++--- src/lexer/lexer_helper.c | 7 ++++--- src/lexer/lexer_helper_bonus.c | 10 +++++----- src/minishell.c | 4 ++-- src/parser/parser.c | 36 +++++++++++++++++----------------- src/parser/parser_utils.c | 13 ++++++++---- src/tokenizer/assign_bonus.c | 6 +++--- 8 files changed, 52 insertions(+), 46 deletions(-) diff --git a/include/minishell.h b/include/minishell.h index 270046c..e648b53 100644 --- a/include/minishell.h +++ b/include/minishell.h @@ -87,14 +87,14 @@ typedef enum e_token_type // 7 - " the whole string in between " quotes included T_SINGLE_QUOTE, // 8 - ' the whole string in between ' quotes included - T_ENV_VAR, // 9 - $ followed by a valid variable name - T_SHELL_VAR, // 10 - $ followed by a shell variable symbol like $? - T_END, // 11 - End of token array - T_UNKNOWN, // 12 - Unknown token - T_LOG_OR, // 13 - || - T_LOG_AND, // 14 - && - T_PARENTHESIS_OPEN, // 15 - ( - T_PARENTHESIS_CLOSE, // 16 - ) + T_ENV_VAR, // 9 - $ followed by a valid variable name + T_SHELL_VAR, // 10 - $ followed by a shell variable symbol like $? + T_END, // 11 - End of token array + T_UNKNOWN, // 12 - Unknown token + T_LOG_OR, // 13 - || + T_LOG_AND, // 14 - && + T_PARENTHESIS_OPEN, // 15 - ( + T_PARENTHESIS_CLOSED, // 16 - ) } t_token_type; typedef struct s_token diff --git a/src/debug/debug.c b/src/debug/debug.c index 63db31b..be478c4 100644 --- a/src/debug/debug.c +++ b/src/debug/debug.c @@ -42,8 +42,8 @@ void print_token_arr(t_token *token_arr, size_t token_count) token_type = "T_LOG_AND"; else if (token_arr[i].type == T_PARENTHESIS_OPEN) token_type = "T_PARENTHESIS_OPEN"; - else if (token_arr[i].type == T_PARENTHESIS_CLOSE) - token_type = "T_PARENTHESIS_CLOSE"; + else if (token_arr[i].type == T_PARENTHESIS_CLOSED) + token_type = "T_PARENTHESIS_CLOSED"; else if (token_arr[i].type == T_END) token_type = "T_END"; else @@ -91,7 +91,7 @@ void print_lexeme_arr(t_lexeme *lexeme_arr, size_t lexeme_count) else if (lexeme_arr[i].type == L_PARENTHESIS_OPEN) lexeme_type = "L_PARENTHESIS_OPEN"; else if (lexeme_arr[i].type == L_PARENTHESIS_CLOSED) - lexeme_type = "L_PARENTHESIS_CLOSE"; + lexeme_type = "L_PARENTHESIS_CLOSED"; else if (lexeme_arr[i].type == L_END) lexeme_type = "L_END"; else diff --git a/src/lexer/lexer_helper.c b/src/lexer/lexer_helper.c index 4ddcd05..73328fb 100644 --- a/src/lexer/lexer_helper.c +++ b/src/lexer/lexer_helper.c @@ -3,12 +3,13 @@ /* ::: :::::::: */ /* lexer_helper.c :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: slombard +#+ +:+ +#+ */ +/* By: slombard +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2023/11/30 18:59:11 by slombard #+# #+# */ -/* Updated: 2023/11/30 18:59:14 by slombard ### ########.fr */ +/* Updated: 2023/12/16 00:09:37 by slombard ### ########.fr */ /* */ /* ************************************************************************** */ + #include "minishell.h" void finalize_lexeme_array(t_data *data, size_t i) @@ -72,7 +73,7 @@ void lexer_t_redirects_and_word(t_data *data, size_t *i) || data->token_arr[*i].type == T_LOG_OR || data->token_arr[*i].type == T_LOG_AND || data->token_arr[*i].type == T_PARENTHESIS_OPEN - || data->token_arr[*i].type == T_PARENTHESIS_CLOSE) + || data->token_arr[*i].type == T_PARENTHESIS_CLOSED) { return ; } diff --git a/src/lexer/lexer_helper_bonus.c b/src/lexer/lexer_helper_bonus.c index e74c108..9a13ab1 100644 --- a/src/lexer/lexer_helper_bonus.c +++ b/src/lexer/lexer_helper_bonus.c @@ -3,10 +3,10 @@ /* ::: :::::::: */ /* lexer_helper_bonus.c :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: slombard +#+ +:+ +#+ */ +/* By: slombard +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2023/12/13 14:29:09 by slombard #+# #+# */ -/* Updated: 2023/12/13 14:29:11 by slombard ### ########.fr */ +/* Updated: 2023/12/15 23:58:14 by slombard ### ########.fr */ /* */ /* ************************************************************************** */ @@ -42,8 +42,8 @@ void lexer_t_parentheses(t_data *data, size_t i) } else if (data->token_arr[i].type == T_PARENTHESIS_OPEN) data->lexeme_arr[i] = parentheses_open_lexeme(&data->token_arr[i], - data); - else if (data->token_arr[i].type == T_PARENTHESIS_CLOSE) + data); + else if (data->token_arr[i].type == T_PARENTHESIS_CLOSED) data->lexeme_arr[i] = parentheses_close_lexeme(&data->token_arr[i], - data); + data); } \ No newline at end of file diff --git a/src/minishell.c b/src/minishell.c index a82a17b..05269ce 100644 --- a/src/minishell.c +++ b/src/minishell.c @@ -3,10 +3,10 @@ /* ::: :::::::: */ /* minishell.c :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: slombard +#+ +:+ +#+ */ +/* By: slombard +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2023/12/05 17:45:46 by slombard #+# #+# */ -/* Updated: 2023/12/05 17:45:52 by slombard ### ########.fr */ +/* Updated: 2023/12/15 22:18:17 by slombard ### ########.fr */ /* */ /* ************************************************************************** */ diff --git a/src/parser/parser.c b/src/parser/parser.c index 0697c91..f503d48 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -6,7 +6,7 @@ /* By: slombard +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2023/11/30 07:15:23 by bsengeze #+# #+# */ -/* Updated: 2023/12/15 22:10:05 by slombard ### ########.fr */ +/* Updated: 2023/12/16 00:11:53 by slombard ### ########.fr */ /* */ /* ************************************************************************** */ @@ -58,13 +58,13 @@ t_ast_node *parser_pipe(t_lexeme *lexemes, int start, int end, t_parser *vars, int l_pipe_found; l_pipe_found = 0; - printf("parser_pipe\n"); - printf("start: %d\n", start); - printf("end: %d\n", end); + // printf("parser_pipe\n"); + // printf("start: %d\n", start); + // printf("end: %d\n", end); vars->node = create_node(N_PIPE, data); - printf("build_cmd_node\n"); - printf("start: %d\n", start + 1); - printf("end: %d\n", end); + // printf("build_cmd_node\n"); + // printf("start: %d\n", start + 1); + // printf("end: %d\n", end); vars->node->children[1] = build_cmd_node(lexemes, start + 1, end, data); end = vars->i - 1; vars->i = end; @@ -75,20 +75,20 @@ t_ast_node *parser_pipe(t_lexeme *lexemes, int start, int end, t_parser *vars, vars->i--; if (lexemes[vars->i].type == L_PIPE) l_pipe_found = 1; - printf("vars->i: %d\n", vars->i); + // printf("vars->i: %d\n", vars->i); } if (vars->i > vars->start || l_pipe_found) { start = vars->i + 1; - printf("calling parser in parser_pipe\n"); + // printf("calling parser in parser_pipe\n"); vars->node->children[0] = parser(lexemes, start, end, data); } else { start = vars->i + 1; - printf("start: %d\n", start); - printf("end: %d\n", end); - printf("calling build_cmd_node in parser_pipe\n"); + // printf("start: %d\n", start); + // printf("end: %d\n", end); + // printf("calling build_cmd_node in parser_pipe\n"); vars->node->children[0] = build_cmd_node(lexemes, start, end, data); } return (vars->node); @@ -100,9 +100,9 @@ t_ast_node *parser_pipe(t_lexeme *lexemes, int start, int end, t_parser *vars, t_ast_node *parser_log_and_or(t_lexeme *lexemes, int start, int end, t_parser *vars, t_data *data) { - printf("parser_log_and_or\n"); - printf("start: %d\n", start); - printf("end: %d\n", end); + // printf("parser_log_and_or\n"); + // printf("start: %d\n", start); + // printf("end: %d\n", end); if (lexemes[vars->i].type == L_LOG_OR) vars->node = create_node(N_LOG_OR, data); else @@ -124,9 +124,9 @@ t_ast_node *parser(t_lexeme *lexemes, int start, int end, t_data *data) { t_parser vars; - printf("parser\n"); - printf("start: %d\n", start); - printf("end: %d\n", end); + // printf("parser\n"); + // printf("start: %d\n", start); + // printf("end: %d\n", end); init_parser_vars(&vars, start, end); while (vars.i >= vars.start) { diff --git a/src/parser/parser_utils.c b/src/parser/parser_utils.c index a7cf13a..33f5307 100644 --- a/src/parser/parser_utils.c +++ b/src/parser/parser_utils.c @@ -1,12 +1,12 @@ /* ************************************************************************** */ /* */ /* ::: :::::::: */ -/* fill_node_redirects.c :+: :+: :+: */ +/* parser_utils.c :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: bsengeze +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2023/11/30 07:10:36 by bsengeze #+# #+# */ -/* Updated: 2023/11/30 07:10:38 by bsengeze ### ########.fr */ +/* Updated: 2023/12/16 00:15:19 by slombard ### ########.fr */ /* */ /* ************************************************************************** */ @@ -55,10 +55,15 @@ int find_parenthesis_sibling(t_lexeme *lexemes, int start, int end) int parentheses_balance; (void)end; - i = start; + i = end; + printf("find_parenthesis_sibling\n"); + printf("start: %d\n", start); + printf("end: %d\n", end); parentheses_balance = 0; while (i >= start) { + printf("i: %d\n", i); + printf("lexemes[i].type: %d\n", lexemes[i].type); if (lexemes[i].type == L_PARENTHESIS_CLOSED) parentheses_balance++; else if (lexemes[i].type == L_PARENTHESIS_OPEN) diff --git a/src/tokenizer/assign_bonus.c b/src/tokenizer/assign_bonus.c index d51b783..ef3ac77 100644 --- a/src/tokenizer/assign_bonus.c +++ b/src/tokenizer/assign_bonus.c @@ -3,10 +3,10 @@ /* ::: :::::::: */ /* assign_bonus.c :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: slombard +#+ +:+ +#+ */ +/* By: slombard +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2023/12/13 13:10:30 by slombard #+# #+# */ -/* Updated: 2023/12/13 13:10:33 by slombard ### ########.fr */ +/* Updated: 2023/12/16 00:08:29 by slombard ### ########.fr */ /* */ /* ************************************************************************** */ @@ -22,7 +22,7 @@ void assign_parentheses_open(const char **str, t_data *data, size_t *idx) void assign_parentheses_close(const char **str, t_data *data, size_t *idx) { - data->token_arr[*idx].type = T_PARENTHESIS_CLOSE; + data->token_arr[*idx].type = T_PARENTHESIS_CLOSED; (*idx)++; (*str)++; } From 537703764bddbe173e04a234ee621d7b99602f6b Mon Sep 17 00:00:00 2001 From: 552020 Date: Sat, 16 Dec 2023 14:54:55 +0100 Subject: [PATCH 24/29] fix leak --- src/parser/create_node.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/parser/create_node.c b/src/parser/create_node.c index 0054d29..64c9b75 100644 --- a/src/parser/create_node.c +++ b/src/parser/create_node.c @@ -60,7 +60,10 @@ char **build_args_arr(t_lexeme *lexemes, int start, int end, t_data *data) int i; int j; - args = (char **)malloc(sizeof(char *) * (end - start + 1)); + printf("build_args_arr\n"); + printf("start: %d\n", start); + printf("end: %d\n", end); + args = (char **)malloc(sizeof(char *) * (end - start + 2)); if (args == NULL) free_exit(data, "Error: malloc args failed\n"); i = start; From db60ce65aa6300d0c3f1ddd8016ace34e3c0a3f1 Mon Sep 17 00:00:00 2001 From: 552020 Date: Sat, 16 Dec 2023 16:33:15 +0100 Subject: [PATCH 25/29] solve leak on empty command --- src/parser/parser.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/parser/parser.c b/src/parser/parser.c index f503d48..b2c8b00 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -16,7 +16,9 @@ void parse(t_data *data) { if (data->debug_level == DEBUG_ALL || data->debug_level == DEBUG_AST) printf("***Parsing***\n\n"); - data->ast_root = parser(data->lexeme_arr, 0, data->token_count - 1, data); + // data->ast_root = parser(data->lexeme_arr, 0, data->token_count - 1, + // data); + data->ast_root = parser(data->lexeme_arr, 0, data->token_count, data); if (data->debug_level == DEBUG_ALL || data->debug_level == DEBUG_AST) { printf("\n***Printing AST***\n\n"); @@ -34,6 +36,7 @@ void parse(t_data *data) t_ast_node *parser_parentheses(t_lexeme *lexemes, int start, int end, t_parser *vars, t_data *data) { + printf("parser_parentheses\n"); vars->parenthesis_sibling = find_parenthesis_sibling(lexemes, start, end); if (vars->parenthesis_sibling == -1) free_exit(data, "Error: parentheses not balanced\n"); @@ -45,6 +48,10 @@ t_ast_node *parser_parentheses(t_lexeme *lexemes, int start, int end, } else if (vars->parenthesis_sibling > vars->start) { + printf("else if (vars->parenthesis_sibling > vars->start)\n"); + printf("vars->parenthesis_sibling: %d\n", vars->parenthesis_sibling); + // this is the case where the parentheses are not the first lexemA + // i.e. they will not be the root node vars->i = vars->parenthesis_sibling - 1; return (NULL); } @@ -124,20 +131,26 @@ t_ast_node *parser(t_lexeme *lexemes, int start, int end, t_data *data) { t_parser vars; - // printf("parser\n"); - // printf("start: %d\n", start); - // printf("end: %d\n", end); + printf("parser\n"); + printf("start: %d\n", start); + printf("end: %d\n", end); init_parser_vars(&vars, start, end); + printf("before while loop in parser\n"); + printf("lexemes[vars.i].type: %d\n", lexemes[vars.i].type); while (vars.i >= vars.start) { + printf("while loop in parser\n"); + printf("vars.i: %d\n", vars.i); + printf("vars.start: %d\n", vars.start); if (lexemes[vars.i].type == L_PARENTHESIS_CLOSED) { - vars.node = parser_parentheses(lexemes, start, end, &vars, data); + vars.node = parser_parentheses(lexemes, start, vars.i, &vars, data); if (vars.node) return (vars.node); } if (lexemes[vars.i].type == L_PARENTHESIS_OPEN) - return (NULL); + continue ; + // return (NULL); if (lexemes[vars.i].type == L_LOG_AND || lexemes[vars.i].type == L_LOG_OR) { From f78b6a8a324dd20920058f554f9e1272bcf4eccf Mon Sep 17 00:00:00 2001 From: 552020 Date: Sat, 16 Dec 2023 17:55:58 +0100 Subject: [PATCH 26/29] WIP --- include/minishell.h | 2 ++ src/parser/parser.c | 18 +++++++++++++++--- src/parser/parser_utils.c | 13 +++++++++++++ 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/include/minishell.h b/include/minishell.h index e648b53..3a816ab 100644 --- a/include/minishell.h +++ b/include/minishell.h @@ -430,4 +430,6 @@ int ft_free_ret(char **ret, size_t i); int check_parenthesis(t_ast_node *cmd); void free_exit_code(t_data *data, char *error_message, int exit_code); +bool is_command_entirely_enclosed(t_lexeme *lexemes, + int start, int end); #endif diff --git a/src/parser/parser.c b/src/parser/parser.c index b2c8b00..3cdbded 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -127,10 +127,16 @@ t_ast_node *parser_log_and_or(t_lexeme *lexemes, int start, int end, return (vars->node); } +// The problem we face in this loop now is that if we find a paranteses +// which doesn't take the whole command, after finding the matching opening one +// we want to check also for pipes + t_ast_node *parser(t_lexeme *lexemes, int start, int end, t_data *data) { t_parser vars; + bool enclosed_cmd; + enclosed_cmd = is_command_entirely_enclosed(lexemes, start, end); printf("parser\n"); printf("start: %d\n", start); printf("end: %d\n", end); @@ -142,18 +148,23 @@ t_ast_node *parser(t_lexeme *lexemes, int start, int end, t_data *data) printf("while loop in parser\n"); printf("vars.i: %d\n", vars.i); printf("vars.start: %d\n", vars.start); - if (lexemes[vars.i].type == L_PARENTHESIS_CLOSED) + printf("lexemes[vars.i].type: %d\n", lexemes[vars.i].type); + if (lexemes[vars.i].type == L_PARENTHESIS_CLOSED && enclosed_cmd) { vars.node = parser_parentheses(lexemes, start, vars.i, &vars, data); if (vars.node) return (vars.node); } - if (lexemes[vars.i].type == L_PARENTHESIS_OPEN) - continue ; + printf("after if (lexemes[vars.i].type == L_PARENTHESIS_CLOSED)\n"); + printf("vars.i: %d\n", vars.i); + printf("lexemes[vars.i].type: %d\n", lexemes[vars.i].type); + // if (lexemes[vars.i].type == L_PARENTHESIS_OPEN) + // continue ; // return (NULL); if (lexemes[vars.i].type == L_LOG_AND || lexemes[vars.i].type == L_LOG_OR) { + printf("if (lexemes[vars.i].type == L_LOG_AND ...\n"); vars.node = parser_log_and_or(lexemes, vars.i, end, &vars, data); return (vars.node); } @@ -162,6 +173,7 @@ t_ast_node *parser(t_lexeme *lexemes, int start, int end, t_data *data) vars.i = end; while (vars.i >= vars.start) { + printf("second while loop in parser for L_PIPE\n"); if (lexemes[vars.i].type == L_PIPE) { // vars.node = parser_pipe(&vars, lexemes, data); diff --git a/src/parser/parser_utils.c b/src/parser/parser_utils.c index 33f5307..ff20912 100644 --- a/src/parser/parser_utils.c +++ b/src/parser/parser_utils.c @@ -74,3 +74,16 @@ int find_parenthesis_sibling(t_lexeme *lexemes, int start, int end) } return (-1); } +bool is_command_entirely_enclosed(t_lexeme *lexemes, int start, int end) +{ + int sibling_index; + + if (lexemes[start].type != L_PARENTHESIS_OPEN) + { + return (false); + } + // find_parenthesis_sibling finds the matching opening parenthesis for the first closing one. + sibling_index = find_parenthesis_sibling(lexemes, start, end); + // Check if the matching parenthesis is the first lexeme in the current segment. + return (sibling_index == start); +} From 7539dafa443c64bd1a069e776edb51638f0eac32 Mon Sep 17 00:00:00 2001 From: 552020 Date: Sat, 16 Dec 2023 18:56:51 +0100 Subject: [PATCH 27/29] WIP --- src/parser/parser.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/parser/parser.c b/src/parser/parser.c index 3cdbded..cbec986 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -171,12 +171,20 @@ t_ast_node *parser(t_lexeme *lexemes, int start, int end, t_data *data) vars.i--; } vars.i = end; + pritnf("before second while loop in parser\n"); + printf("vars.i: %d\n", vars.i); + printf("end: %d\n", end); while (vars.i >= vars.start) { + printf("vars.i: %d\n", vars.i); + printf("lexemes[vars.i].type: %d\n", lexemes[vars.i].type); printf("second while loop in parser for L_PIPE\n"); if (lexemes[vars.i].type == L_PIPE) { // vars.node = parser_pipe(&vars, lexemes, data); + printf("calling parser_pipe\n"); + printf("vars.i: %d\n", vars.i); + printf("end: %d\n", end); vars.node = parser_pipe(lexemes, vars.i, end, &vars, data); return (vars.node); } From f4d055d6712cb46968ec5fe87fb86ca33cea2c14 Mon Sep 17 00:00:00 2001 From: 552020 Date: Sun, 17 Dec 2023 16:06:23 +0100 Subject: [PATCH 28/29] GIT --- i | 0 src/parser/parser.c | 5 +++-- 2 files changed, 3 insertions(+), 2 deletions(-) delete mode 100644 i diff --git a/i b/i deleted file mode 100644 index e69de29..0000000 diff --git a/src/parser/parser.c b/src/parser/parser.c index cbec986..c4c7831 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -79,9 +79,10 @@ t_ast_node *parser_pipe(t_lexeme *lexemes, int start, int end, t_parser *vars, while (vars->i >= vars->start && lexemes[vars->i].type != L_LOG_AND && lexemes[vars->i].type != L_LOG_OR) { - vars->i--; + printf("lexemes[vars->i].type: %d\n", lexemes[vars->i].type); if (lexemes[vars->i].type == L_PIPE) l_pipe_found = 1; + vars->i--; // printf("vars->i: %d\n", vars->i); } if (vars->i > vars->start || l_pipe_found) @@ -171,7 +172,7 @@ t_ast_node *parser(t_lexeme *lexemes, int start, int end, t_data *data) vars.i--; } vars.i = end; - pritnf("before second while loop in parser\n"); + printf("before second while loop in parser\n"); printf("vars.i: %d\n", vars.i); printf("end: %d\n", end); while (vars.i >= vars.start) From f4b4ba32bc562452053070ef10e014a5e1408e9e Mon Sep 17 00:00:00 2001 From: 552020 Date: Sun, 17 Dec 2023 22:34:55 +0100 Subject: [PATCH 29/29] WIP --- include/minishell.h | 1 + src/debug/debug.c | 6 ++- src/debug/print_ast_new.c | 3 ++ src/parser/create_node.c | 2 + src/parser/parser.c | 77 ++++++++++++++++++++++++++++++--------- src/parser/parser_utils.c | 19 +++++++--- src/parser/test.c | 40 ++++++++++++++++++++ 7 files changed, 124 insertions(+), 24 deletions(-) create mode 100644 src/parser/test.c diff --git a/include/minishell.h b/include/minishell.h index 3a816ab..08e5e57 100644 --- a/include/minishell.h +++ b/include/minishell.h @@ -432,4 +432,5 @@ void free_exit_code(t_data *data, char *error_message, int exit_code); bool is_command_entirely_enclosed(t_lexeme *lexemes, int start, int end); +void print_node_info(t_ast_node *node, int level); #endif diff --git a/src/debug/debug.c b/src/debug/debug.c index be478c4..964393e 100644 --- a/src/debug/debug.c +++ b/src/debug/debug.c @@ -133,6 +133,8 @@ void print_ast(t_ast_node *node, int depth) printf("||\n"); else if (node->type == N_LOG_AND) printf("&&\n"); + else if (node->type == N_PARENTHESES) + printf("()\n"); else printf("UNKNOWN\n"); if (node->children[0]) @@ -243,7 +245,7 @@ void print_node_info(t_ast_node *node, int level) level = level + 1; printf("\n"); printf("Child 1/%i:\n", level); - print_node_info(node->children[0], level); + // print_node_info(node->children[0], level); } else printf("Child 1: NULL\n"); @@ -251,7 +253,7 @@ void print_node_info(t_ast_node *node, int level) { printf("\n"); printf("Child 2/%i:\n", level); - print_node_info(node->children[1], level); + // print_node_info(node->children[1], level); } else printf("Child 2: NULL\n"); diff --git a/src/debug/print_ast_new.c b/src/debug/print_ast_new.c index 808d32b..7c611fc 100644 --- a/src/debug/print_ast_new.c +++ b/src/debug/print_ast_new.c @@ -82,4 +82,7 @@ void print_ast_new(t_ast_node *root) bool is_last_sibling[100] = {false}; // Assuming a max depth of 100; can be dynamically allocated if needed print_node(root, 0, is_last_sibling); + // (void)root; + // (void)is_last_sibling; + // printf("hello print_ast_new\n"); } \ No newline at end of file diff --git a/src/parser/create_node.c b/src/parser/create_node.c index 64c9b75..e8b3ead 100644 --- a/src/parser/create_node.c +++ b/src/parser/create_node.c @@ -118,5 +118,7 @@ t_ast_node *build_parentheses_node(t_ast_node *node, t_lexeme *lexemes, if (node->cmd == NULL) free_exit(data, "Error: ft_strdup failed\n"); node->args = build_args_arr(lexemes, start, end, data); + node->children[0] = NULL; + node->children[1] = NULL; return (node); } diff --git a/src/parser/parser.c b/src/parser/parser.c index c4c7831..6d9a883 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -22,11 +22,18 @@ void parse(t_data *data) if (data->debug_level == DEBUG_ALL || data->debug_level == DEBUG_AST) { printf("\n***Printing AST***\n\n"); - print_ast(data->ast_root, 7); + // print_ast(data->ast_root, 7); printf("\n***Printing AST NEW***\n\n"); - print_ast_new(data->ast_root); + // print_ast_new(data->ast_root); printf("\n*** AST nodes content ***\n\n"); - debug_ast(data->ast_root); + // debug_ast(data->ast_root); + print_node_info(data->ast_root, 0); + printf("children of root:\n"); + print_node_info(data->ast_root->children[0], 1); + print_node_info(data->ast_root->children[1], 1); + printf("children of right child of root:\n"); + print_node_info(data->ast_root->children[1]->children[0], 2); + print_node_info(data->ast_root->children[1]->children[1], 2); } free_lexeme_arr(data); } @@ -37,11 +44,14 @@ t_ast_node *parser_parentheses(t_lexeme *lexemes, int start, int end, t_parser *vars, t_data *data) { printf("parser_parentheses\n"); + printf("start: %d\n", start); + printf("end: %d\n", end); vars->parenthesis_sibling = find_parenthesis_sibling(lexemes, start, end); if (vars->parenthesis_sibling == -1) free_exit(data, "Error: parentheses not balanced\n"); else if (vars->parenthesis_sibling == start) { + printf("else if (vars->parenthesis_sibling == start)\n"); vars->node = create_node(N_PARENTHESES, data); build_parentheses_node(vars->node, lexemes, start + 1, end - 1, data); return (vars->node); @@ -63,8 +73,11 @@ t_ast_node *parser_pipe(t_lexeme *lexemes, int start, int end, t_parser *vars, t_data *data) { int l_pipe_found; + int enclosed_cmd; + int pipe; l_pipe_found = 0; + pipe = vars->i; // printf("parser_pipe\n"); // printf("start: %d\n", start); // printf("end: %d\n", end); @@ -72,8 +85,23 @@ t_ast_node *parser_pipe(t_lexeme *lexemes, int start, int end, t_parser *vars, // printf("build_cmd_node\n"); // printf("start: %d\n", start + 1); // printf("end: %d\n", end); - vars->node->children[1] = build_cmd_node(lexemes, start + 1, end, data); - end = vars->i - 1; + enclosed_cmd = is_command_entirely_enclosed(lexemes, pipe + 1, end); + printf("enclosed_cmd: %d\n", enclosed_cmd); + if (enclosed_cmd) + { + printf("if (enclosed_cmd)\n"); + if (lexemes[end].type == L_END) + end--; + printf("start: %d\n", pipe + 1); + printf("end: %d\n", end); + vars->node->children[1] = parser_parentheses(lexemes, pipe + 1, end, + vars, data); + } + else + vars->node->children[1] = build_cmd_node(lexemes, pipe + 1, end, data); + end = pipe - 1; + // vars->node->children[1] = build_cmd_node(lexemes, start + 1, end, data); + // end = vars->i - 1; vars->i = end; // while (vars->i >= vars->start && lexemes[vars->i].type != L_PIPE while (vars->i >= vars->start && lexemes[vars->i].type != L_LOG_AND @@ -88,7 +116,7 @@ t_ast_node *parser_pipe(t_lexeme *lexemes, int start, int end, t_parser *vars, if (vars->i > vars->start || l_pipe_found) { start = vars->i + 1; - // printf("calling parser in parser_pipe\n"); + printf("calling parser in parser_pipe\n"); vars->node->children[0] = parser(lexemes, start, end, data); } else @@ -96,7 +124,15 @@ t_ast_node *parser_pipe(t_lexeme *lexemes, int start, int end, t_parser *vars, start = vars->i + 1; // printf("start: %d\n", start); // printf("end: %d\n", end); - // printf("calling build_cmd_node in parser_pipe\n"); + // enclosed_cmd = is_command_entirely_enclosed(lexemes, start, end); + // if (enclosed_cmd) + // vars->node->children[0] = parser_parentheses(lexemes, start, end, + // vars, data); + // else + // { + // printf("calling build_cmd_node in parser_pipe\n"); + // vars->node->children[0] = build_cmd_node(lexemes, start, end, data); + // } vars->node->children[0] = build_cmd_node(lexemes, start, end, data); } return (vars->node); @@ -137,18 +173,19 @@ t_ast_node *parser(t_lexeme *lexemes, int start, int end, t_data *data) t_parser vars; bool enclosed_cmd; - enclosed_cmd = is_command_entirely_enclosed(lexemes, start, end); printf("parser\n"); + enclosed_cmd = is_command_entirely_enclosed(lexemes, start, end); + printf("enclosed_cmd: %d\n", enclosed_cmd); printf("start: %d\n", start); printf("end: %d\n", end); init_parser_vars(&vars, start, end); printf("before while loop in parser\n"); - printf("lexemes[vars.i].type: %d\n", lexemes[vars.i].type); + // printf("lexemes[vars.i].type: %d\n", lexemes[vars.i].type); while (vars.i >= vars.start) { printf("while loop in parser\n"); printf("vars.i: %d\n", vars.i); - printf("vars.start: %d\n", vars.start); + // printf("vars.start: %d\n", vars.start); printf("lexemes[vars.i].type: %d\n", lexemes[vars.i].type); if (lexemes[vars.i].type == L_PARENTHESIS_CLOSED && enclosed_cmd) { @@ -156,12 +193,14 @@ t_ast_node *parser(t_lexeme *lexemes, int start, int end, t_data *data) if (vars.node) return (vars.node); } - printf("after if (lexemes[vars.i].type == L_PARENTHESIS_CLOSED)\n"); - printf("vars.i: %d\n", vars.i); - printf("lexemes[vars.i].type: %d\n", lexemes[vars.i].type); - // if (lexemes[vars.i].type == L_PARENTHESIS_OPEN) - // continue ; - // return (NULL); + if (lexemes[vars.i].type == L_PARENTHESIS_CLOSED && !enclosed_cmd) + { + // skip to the matching opening parenthesis + vars.i = find_parenthesis_sibling(lexemes, start, vars.i); + } + // printf("after if (lexemes[vars.i].type == L_PARENTHESIS_CLOSED)\n"); + // printf("vars.i: %d\n", vars.i); + // printf("lexemes[vars.i].type: %d\n", lexemes[vars.i].type); if (lexemes[vars.i].type == L_LOG_AND || lexemes[vars.i].type == L_LOG_OR) { @@ -174,7 +213,7 @@ t_ast_node *parser(t_lexeme *lexemes, int start, int end, t_data *data) vars.i = end; printf("before second while loop in parser\n"); printf("vars.i: %d\n", vars.i); - printf("end: %d\n", end); + // printf("end: %d\n", end); while (vars.i >= vars.start) { printf("vars.i: %d\n", vars.i); @@ -187,10 +226,14 @@ t_ast_node *parser(t_lexeme *lexemes, int start, int end, t_data *data) printf("vars.i: %d\n", vars.i); printf("end: %d\n", end); vars.node = parser_pipe(lexemes, vars.i, end, &vars, data); + printf("parse before return\n"); + printf("vars.node->type: %d\n", vars.node->type); return (vars.node); } vars.i--; } vars.node = build_cmd_node(lexemes, start, end, data); + printf("parse before return\n"); + printf("vars.node->type: %d\n", vars.node->type); return (vars.node); } diff --git a/src/parser/parser_utils.c b/src/parser/parser_utils.c index ff20912..aa7b055 100644 --- a/src/parser/parser_utils.c +++ b/src/parser/parser_utils.c @@ -56,14 +56,18 @@ int find_parenthesis_sibling(t_lexeme *lexemes, int start, int end) (void)end; i = end; - printf("find_parenthesis_sibling\n"); - printf("start: %d\n", start); - printf("end: %d\n", end); + // printf("find_parenthesis_sibling\n"); + // printf("start: %d\n", start); + // printf("end: %d\n", end); parentheses_balance = 0; + // printf("lexemes[i].type: %d\n", lexemes[i].type); + if (lexemes[i].type == L_END) + i--; + // printf("lexemes[i].type: %d\n", lexemes[i].type); while (i >= start) { - printf("i: %d\n", i); - printf("lexemes[i].type: %d\n", lexemes[i].type); + // printf("i: %d\n", i); + // printf("lexemes[i].type: %d\n", lexemes[i].type); if (lexemes[i].type == L_PARENTHESIS_CLOSED) parentheses_balance++; else if (lexemes[i].type == L_PARENTHESIS_OPEN) @@ -78,12 +82,17 @@ bool is_command_entirely_enclosed(t_lexeme *lexemes, int start, int end) { int sibling_index; + // printf("is_command_entirely_enclosed\n"); + // printf("start: %d\n", start); + // printf("end: %d\n", end); if (lexemes[start].type != L_PARENTHESIS_OPEN) { return (false); } // find_parenthesis_sibling finds the matching opening parenthesis for the first closing one. sibling_index = find_parenthesis_sibling(lexemes, start, end); + // printf("sibling_index: %d\n", sibling_index); + // printf("start: %d\n", start); // Check if the matching parenthesis is the first lexeme in the current segment. return (sibling_index == start); } diff --git a/src/parser/test.c b/src/parser/test.c new file mode 100644 index 0000000..e2ac701 --- /dev/null +++ b/src/parser/test.c @@ -0,0 +1,40 @@ + +t_ast_node *parser(t_lexeme *lexemes, int start, int end, t_data *data) +{ + t_parser vars; + bool enclosed_cmd; + + enclosed_cmd = is_command_entirely_enclosed(lexemes, start, end); + init_parser_vars(&vars, start, end); + while (vars.i >= vars.start) + { + printf("lexemes[vars.i].type: %d\n", lexemes[vars.i].type); + if (lexemes[vars.i].type == L_PARENTHESIS_CLOSED && enclosed_cmd) + { + vars.node = parser_parentheses(lexemes, start, vars.i, &vars, data); + if (vars.node) + return (vars.node); + } + if (lexemes[vars.i].type == L_PARENTHESIS_CLOSED && !enclosed_cmd) + vars.i = find_parenthesis_sibling(lexemes, start, vars.i); + if (lexemes[vars.i].type == L_LOG_AND + || lexemes[vars.i].type == L_LOG_OR) + { + vars.node = parser_log_and_or(lexemes, vars.i, end, &vars, data); + return (vars.node); + } + vars.i--; + } + vars.i = end; + while (vars.i >= vars.start) + { + if (lexemes[vars.i].type == L_PIPE) + { + vars.node = parser_pipe(lexemes, vars.i, end, &vars, data); + return (vars.node); + } + vars.i--; + } + vars.node = build_cmd_node(lexemes, start, end, data); + return (vars.node); +} \ No newline at end of file