diff --git a/src/ast/ast.c b/src/ast/ast.c index 13808322..dc76c3d6 100644 --- a/src/ast/ast.c +++ b/src/ast/ast.c @@ -69,6 +69,26 @@ char *ast_type_to_string(enum ast_type type) return "AST_WORD"; case AST_EMPTY: return "AST_EMPTY"; + case AST_FOR: + return "AST_FOR"; + case AST_WHILE: + return "AST_WHILE"; + case AST_UNTIL: + return "AST_UNTIL"; + case AST_AND_OR: + return "AST_AND_OR"; + case AST_NEGATE: + return "AST_NEGATE"; + case AST_PIPELINE: + return "AST_PIPELINE"; + case AST_REDIRECTION: + return "AST_REDIRECTION"; + case AST_AND: + return "AST_AND"; + case AST_OR: + return "AST_OR"; + case AST_COMMAND: + return "AST_COMMAND"; default: return "UNKNOWN"; } @@ -81,6 +101,10 @@ void print_ast(struct ast_node *node, int depth, bool logger_enabled) for (int i = 0; i < depth; i++) printf(" "); printf("%s\n", ast_type_to_string(node->type)); + if (node->type == AST_WORD) + { + printf("%s:\n", node->value); + } logger(node->value, LOGGER_PARSER, logger_enabled); for (int i = 0; i < node->children_count; i++) print_ast(node->children[i], depth + 1, logger_enabled); diff --git a/src/ast/ast.h b/src/ast/ast.h index fe03589c..78acb585 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -25,6 +25,17 @@ enum ast_type AST_WORD, AST_EMPTY, AST_UNEXPECTED, + AST_REDIRECTION, + AST_PIPELINE, + AST_WHILE, + AST_UNTIL, + AST_FOR, + AST_AND_OR, + AST_NEGATE, + AST_AND, + AST_OR, + AST_COMMAND, + AST_WORD_ASSIGNMENT }; /** diff --git a/src/execute/Makefile.am b/src/execute/Makefile.am index d8eb79aa..f90de87b 100644 --- a/src/execute/Makefile.am +++ b/src/execute/Makefile.am @@ -1,6 +1,6 @@ lib_LIBRARIES = libexecute.a -libexecute_a_SOURCES = ast_eval.c ast_eval.h ../parser/parser.h \ +libexecute_a_SOURCES = pipeline.c loop.c ast_eval.c ast_eval.h ../parser/parser.h \ builtin.c builtin.h \ ../ast/ast.h diff --git a/src/execute/ast_eval.c b/src/execute/ast_eval.c index bb0efe05..c09ae08b 100644 --- a/src/execute/ast_eval.c +++ b/src/execute/ast_eval.c @@ -134,6 +134,16 @@ int match_ast(struct ast_node *node, bool logger_enabled) return ast_eval_command_list(node, logger_enabled); case AST_EMPTY: return 0; + case AST_WHILE: + return while_loop(node, logger_enabled); + case AST_UNTIL: + return until_loop(node, logger_enabled); + case AST_FOR: + return for_loop(node, logger_enabled); + case AST_AND_OR: + return ast_and_or(node, logger_enabled); + case AST_PIPELINE: + return pipeline_eval(node, logger_enabled); default: return -1; } diff --git a/src/execute/ast_eval.h b/src/execute/ast_eval.h index 1e8fbac3..1e679952 100644 --- a/src/execute/ast_eval.h +++ b/src/execute/ast_eval.h @@ -20,5 +20,10 @@ * logger is enabled or not. \return The exit status of the last command. */ int match_ast(struct ast_node *node, bool logger_enabled); +int while_loop(struct ast_node *node, bool logger_enabled); +int until_loop(struct ast_node *node, bool logger_enabled); +int for_loop(struct ast_node *node, bool logger_enabled); +int pipeline_eval(struct ast_node *node, bool logger_enabled); +int ast_and_or(struct ast_node *node, bool logger_enabled); #endif /* AST_EVAL_H */ diff --git a/src/execute/loop.c b/src/execute/loop.c new file mode 100644 index 00000000..e2ed1294 --- /dev/null +++ b/src/execute/loop.c @@ -0,0 +1,42 @@ +#include "../ast/ast.h" +#include "ast_eval.h" + +int while_loop(struct ast_node *node, bool logger_enabled) +{ + int status = 0; + while (match_ast(node->children[0], logger_enabled) == 0) + { + if (logger_enabled) + { + printf("while loop\n"); + } + status = match_ast(node->children[1], logger_enabled); + } + return status; +} + +int until_loop(struct ast_node *node, bool logger_enabled) +{ + int status = 0; + while (match_ast(node->children[0], logger_enabled) != 0) + { + if (logger_enabled) + { + printf("until loop\n"); + } + status = match_ast(node->children[1], logger_enabled); + } + return status; +} +int for_loop(struct ast_node *node, bool logger_enabled) +{ + if (logger_enabled) + { + printf("for loop\n"); + } + if (node == NULL) + { + return -1; + } + return 0; +} \ No newline at end of file diff --git a/src/execute/pipeline.c b/src/execute/pipeline.c new file mode 100644 index 00000000..69111cf5 --- /dev/null +++ b/src/execute/pipeline.c @@ -0,0 +1,88 @@ +#include "../ast/ast.h" +#include "ast_eval.h" + +#include +#include +#include +#include + +int pipeline_eval(struct ast_node *node, bool logger_enabled) +{ + if (logger_enabled) + { + printf("pipeline\n"); + } + int start = 0; + int stat = 0; + if (node->children_count > 0 && node->children[0]->type == AST_NEGATE) + { + start = 1; + } + int input_fd = STDIN_FILENO; + for (int i = start; i < node->children_count; i++) + { + int pipes[2]; + if (i != node->children_count) + { + if (pipe(pipes) == -1) + { + return -1; + } + } + pid_t pid = fork(); + if (pid == 0) + { + if (i != start) + { + dup2(input_fd, STDIN_FILENO); + close(input_fd); + } + if (i != node->children_count - 1) + { + dup2(pipes[1], STDOUT_FILENO); + close(pipes[0]); + close(pipes[1]); + } + stat = match_ast(node->children[i], logger_enabled); + exit(stat); + } + if (i != start) + close(input_fd); + if (i != node->children_count) + { + close(pipes[1]); + input_fd = pipes[0]; + } + int status; + waitpid(pid, &status, 0); + stat = WEXITSTATUS(status); + } + if (start == 1) + { + stat = !stat; + } + + return stat; +} + +int ast_and_or(struct ast_node *node, bool logger_enabled) +{ + int status = 0; + for (int i = 0; i < node->children_count; i++) + { + if (node->children[i]->type == AST_AND && status == 1) + { + printf("and\n"); + i++; + } + else if (node->children[i]->type == AST_OR && status == 0) + { + i++; + } + else + { + status = match_ast(node->children[i], logger_enabled); + } + } + return status; +} diff --git a/src/lexer/lexer.c b/src/lexer/lexer.c index 42c9a955..79976a5c 100644 --- a/src/lexer/lexer.c +++ b/src/lexer/lexer.c @@ -23,6 +23,7 @@ struct lex_match lex_match[] = { { "&&", TOKEN_AND }, { "||", TOKEN_OR }, { "|", TOKEN_PIPE }, { "!", TOKEN_NEGATE }, { "<", TOKEN_REDIR }, { ">", TOKEN_REDIR }, { ">>", TOKEN_REDIR }, { "<&", TOKEN_REDIR }, { ">&", TOKEN_REDIR }, + { "done", TOKEN_DONE}, { ">|", TOKEN_REDIR }, { "<>", TOKEN_REDIR } }; diff --git a/src/lexer/token.h b/src/lexer/token.h index b117e679..589db868 100644 --- a/src/lexer/token.h +++ b/src/lexer/token.h @@ -34,7 +34,8 @@ enum token_type TOKEN_NEGATE, // \! TOKEN_REDIR, // >, <, >>, >&, <&, >|, <> TOKEN_DOUBLE_QUOTE, // " - TOKEN_WORD_ASSIGNMENT // variable= + TOKEN_WORD_ASSIGNMENT, // variable= + TOKEN_DONE }; /** diff --git a/src/parser/Makefile.am b/src/parser/Makefile.am index 4bc3cc48..29240dcf 100644 --- a/src/parser/Makefile.am +++ b/src/parser/Makefile.am @@ -3,7 +3,7 @@ lib_LIBRARIES = libparser.a libparser_a_SOURCES = parser.c parser.h \ parser_condition.c parser_element.c \ ../ast/ast.c ../ast/ast.h \ - ../lexer/lexer.c ../lexer/lexer.h + ../lexer/lexer.c ../lexer/lexer.h parser_functionnal.c libparser_a_CFLAGS = -Wall -Wextra -Werror -std=c99 -pedantic libparser_a_CPPFLAGS =-I$(top_srcdir) diff --git a/src/parser/parser.c b/src/parser/parser.c index 869d2c48..79f7dc9f 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -76,6 +76,7 @@ int parser_loop(struct lexer *lexer, bool logger_enabled, { return 2; } + //print_ast(ast, 0, logger_enabled); if (pretty_print_enabled) { // print_ast(ast, 0, logger_enabled); @@ -85,6 +86,7 @@ int parser_loop(struct lexer *lexer, bool logger_enabled, return_value = match_ast(ast, logger_enabled); if (return_value != 0 && return_value != 1) { + printf("%d\n", return_value); fprintf(stderr, "Error while executing\n"); // ast_free(ast); // return return_value; diff --git a/src/parser/parser.h b/src/parser/parser.h index 676894ad..c6981a37 100644 --- a/src/parser/parser.h +++ b/src/parser/parser.h @@ -13,6 +13,8 @@ #include "../lexer/lexer.h" #include "../lexer/token.h" +#include + /** * \brief Parse loop the given lexer * \param lexer The lexer to parse. @@ -88,6 +90,7 @@ struct ast_node *pipeline(struct lexer *lexer); /** * \brief command = simple_command | shell_command ; + * \brief IMPORTANT !!! AST_COMMAND CAN HANDLE REDIRECTION !! * \param lexer The lexer to parse. * \return A pointer to the AST. */ @@ -107,6 +110,39 @@ struct ast_node *simple_command(struct lexer *lexer); */ struct ast_node *element(struct lexer *lexer); +/** + * \brief redirection = [IONUMBER] ( '>' | '<' | '>>' | '>&' | '<&' | '>|' | '<>' ) WORD ; + * \param lexer The lexer to parse. + * \return A pointer to the AST. + */ +struct ast_node *redirection(struct lexer *lexer); + +/** + * \brief rule_while = 'while' compound_list 'do' compound_list 'done' ; + * \param lexer The lexer to parse. + * \return A pointer to the AST. + */ +struct ast_node *rule_while(struct lexer *lexer); + +/** + * \brief rule_until = 'until' compound_list 'do' compound_list 'done' ; + * \param lexer The lexer to parse. + * \return A pointer to the AST. + */ +struct ast_node *rule_until(struct lexer *lexer); + +/** + * \brief rule_for = 'for' WORD [in WORD {',' WORD}] 'do' compound_list 'done' ; + * \param lexer The lexer to parse. + * \return A pointer to the AST. + */ +struct ast_node *rule_for(struct lexer *lexer); +/** + * \brief redirection; + * \param lexer The lexer to parse. + * \return A pointer to the AST. + */ +struct ast_node *prefix(struct lexer *lexer); /** * \brief Return the next token type without consuming it. * \param lexer The lexer to parse. @@ -121,4 +157,4 @@ enum token_type parser_peek(struct lexer *lexer); */ enum token_type parser_pop(struct lexer *lexer); -#endif /* ! PARSER_H*/ +#endif /* ! PARSER_H */ \ No newline at end of file diff --git a/src/parser/parser_condition.c b/src/parser/parser_condition.c index 0afc1f12..6cfd1a77 100644 --- a/src/parser/parser_condition.c +++ b/src/parser/parser_condition.c @@ -10,7 +10,14 @@ struct ast_node *shell_command(struct lexer *lexer) { - return rule_if(lexer); + struct ast_node *current = rule_if(lexer); + if (current == NULL) + current = rule_while(lexer); + if (current == NULL) + current = rule_until(lexer); + if (current == NULL) + current = rule_for(lexer); + return current; } struct ast_node *rule_if(struct lexer *lexer) @@ -122,3 +129,123 @@ struct ast_node *compound_list(struct lexer *lexer) } return current; } + +struct ast_node *rule_while(struct lexer *lexer) +{ + struct ast_node *current = ast_node_new(AST_WHILE); + char *value = lexer_peek(lexer).data; + if (strcmp(value, "while") == 0) + { + free(value); + parser_pop(lexer); + struct ast_node *condition = compound_list(lexer); + if (condition == NULL) + { + goto ERROR; + } + ast_append(current, condition); + value = lexer_peek(lexer).data; + if (strcmp(value, "do") == 0) + { + free(value); + parser_pop(lexer); + struct ast_node *response = compound_list(lexer); + if (response == NULL) + goto ERROR; + ast_append(current, response); + value = lexer_peek(lexer).data; + if (strcmp(value, "done") == 0) + { + free(value); + parser_pop(lexer); + return current; + } + } + } + free(value); + ERROR: + ast_free(current); + return NULL; +} + +struct ast_node *rule_until(struct lexer *lexer) +{ + struct ast_node *current = ast_node_new(AST_UNTIL); + char *value = lexer_peek(lexer).data; + if (strcmp(value, "until") == 0) + { + free(value); + parser_pop(lexer); + struct ast_node *condition = compound_list(lexer); + if (condition == NULL) + { + goto ERROR; + } + ast_append(current, condition); + value = lexer_peek(lexer).data; + if (strcmp(value, "do") == 0) + { + free(value); + parser_pop(lexer); + struct ast_node *response = compound_list(lexer); + if (response == NULL) + goto ERROR; + ast_append(current, response); + value = lexer_peek(lexer).data; + if (strcmp(value, "done") == 0) + { + free(value); + parser_pop(lexer); + return current; + } + } + } + free(value); + ERROR: + ast_free(current); + return NULL; +} + +struct ast_node *rule_for(struct lexer *lexer) +{ + struct ast_node *current = ast_node_new(AST_FOR); + char *value = lexer_peek(lexer).data; + if (strcmp(value, "for") == 0) + { + free(value); + parser_pop(lexer); + if (parser_peek(lexer) != TOKEN_WORD) + goto ERROR; + if (parser_peek(lexer) == TOKEN_SEMICOLON) + { + goto END; + } + + END: + while (parser_peek(lexer) == TOKEN_EOL) + { + parser_pop(lexer); + } + value = lexer_peek(lexer).data; + if (strcmp(value, "do") == 0) + { + free(value); + parser_pop(lexer); + struct ast_node *response = compound_list(lexer); + if (response == NULL) + goto ERROR; + ast_append(current, response); + value = lexer_peek(lexer).data; + if (strcmp(value, "done") == 0) + { + free(value); + parser_pop(lexer); + return current; + } + } + } + free(value); + ERROR: + ast_free(current); + return NULL; +} \ No newline at end of file diff --git a/src/parser/parser_element.c b/src/parser/parser_element.c index 790e1583..7ec50749 100644 --- a/src/parser/parser_element.c +++ b/src/parser/parser_element.c @@ -57,30 +57,114 @@ struct ast_node *list(struct lexer *lexer) struct ast_node *and_or(struct lexer *lexer) { - return pipeline(lexer); + struct ast_node *current = ast_node_new(AST_AND_OR); + struct ast_node *child = pipeline(lexer); + if (child != NULL) + { + ast_append(current, child); + while (parser_peek(lexer) == TOKEN_AND || parser_peek(lexer) == TOKEN_OR) + { + if (parser_peek(lexer) == TOKEN_AND) + ast_append(current, ast_node_new(AST_AND)); + else + ast_append(current, ast_node_new(AST_OR)); + parser_pop(lexer); + while (parser_peek(lexer) == TOKEN_EOL) + parser_pop(lexer); + child = pipeline(lexer); + if (child == NULL) + { + ast_free(current); + return NULL; + } + //parser_pop(lexer); + ast_append(current, child); + } + return current; + } + ast_free(current); + return NULL; } struct ast_node *pipeline(struct lexer *lexer) { - return command(lexer); + struct ast_node *current = ast_node_new(AST_PIPELINE); + if (parser_peek(lexer) == TOKEN_NEGATE) + { + ast_append(current, ast_node_new(AST_NEGATE)); + } + struct ast_node *child = command(lexer); + if (child != NULL) + { + ast_append(current, child); + while (parser_peek(lexer) == TOKEN_PIPE) + { + parser_pop(lexer); + while (parser_peek(lexer) == TOKEN_EOL) + parser_pop(lexer); + child = command(lexer); + if (child == NULL) + { + ast_free(current); + return NULL; + } + ast_append(current, child); + } + return current; + } + ast_free(current); + return NULL; } struct ast_node *command(struct lexer *lexer) { - struct ast_node *current = simple_command(lexer); - if (current != NULL) + struct ast_node *current = ast_node_new(AST_COMMAND); + struct ast_node *child = simple_command(lexer); + if (child != NULL) + { + ast_append(current, child); return current; - current = shell_command(lexer); - if (current != NULL) + } + child = shell_command(lexer); + if (child != NULL) + { + ast_append(current, child); + child = redirection(lexer); + while (child != NULL) + { + ast_append(current, child); + child = redirection(lexer); + } return current; + } return NULL; } struct ast_node *simple_command(struct lexer *lexer) { struct ast_node *current = ast_node_new(AST_SIMPLE_COMMAND); + struct ast_node *child = prefix(lexer); + if (child != NULL) + { + ast_append(current, child); + struct ast_node *child2 = prefix(lexer); + while (child2 != NULL) + { + ast_append(current, child2); + child2 = prefix(lexer); + } + } if (parser_peek(lexer) == TOKEN_WORD) { + char *value = lexer_peek(lexer).data; + if (strcmp(value, "while") == 0 || strcmp(value, "until") == 0 || + strcmp(value, "for") == 0 || strcmp(value, "do") == 0) + { + free(value); + ast_free(current); + return NULL; + } + free(value); struct ast_node *new = ast_node_word(lexer_peek(lexer).data); parser_pop(lexer); ast_append(current, new); @@ -98,13 +182,17 @@ struct ast_node *simple_command(struct lexer *lexer) struct ast_node *element(struct lexer *lexer) { + struct ast_node *current = redirection(lexer); + if (current != NULL) + return current; if (parser_peek(lexer) == TOKEN_WORD || parser_peek(lexer) == TOKEN_IF || parser_peek(lexer) == TOKEN_THEN || parser_peek(lexer) == TOKEN_ELSE - || parser_peek(lexer) == TOKEN_ELIF || parser_peek(lexer) == TOKEN_FI) + || parser_peek(lexer) == TOKEN_ELIF || parser_peek(lexer) == TOKEN_FI + || parser_peek(lexer) == TOKEN_DONE) { struct ast_node *curr = ast_node_word(lexer_peek(lexer).data); parser_pop(lexer); return curr; } return NULL; -} +} \ No newline at end of file diff --git a/src/parser/parser_functionnal.c b/src/parser/parser_functionnal.c new file mode 100644 index 00000000..ee1eda14 --- /dev/null +++ b/src/parser/parser_functionnal.c @@ -0,0 +1,50 @@ +#include +#include "parser.h" + +struct ast_node *prefix(struct lexer *lexer) +{ + if (parser_peek(lexer) == TOKEN_WORD_ASSIGNMENT) + { + struct ast_node *current = ast_node_new(AST_WORD_ASSIGNMENT); + current->value = lexer_peek(lexer).data; + parser_pop(lexer); + return current; + } + return redirection(lexer); +} + + +int is_number(char *str) +{ + int i = 0; + while (str[i]) + { + if (!isdigit(str[i])) + return 0; + i++; + } + return 1; +} + +struct ast_node *redirection(struct lexer *lexer) +{ + struct ast_node *current = ast_node_new(AST_REDIRECTION); + char *value = lexer_peek(lexer).data; + if (is_number(value)) + { + ast_append(current, ast_node_word(value)); + } + if (parser_peek(lexer) == TOKEN_REDIR) + { + current->value = lexer_peek(lexer).data; + parser_pop(lexer); + if (parser_peek(lexer) == TOKEN_WORD) + { + ast_append(current, ast_node_word(lexer_peek(lexer).data)); + parser_pop(lexer); + return current; + } + } + ast_free(current); + return NULL; +} \ No newline at end of file