diff --git a/src/parser/grammar_advanced.c b/src/parser/grammar_advanced.c index e69de29..0f29b9b 100644 --- a/src/parser/grammar_advanced.c +++ b/src/parser/grammar_advanced.c @@ -0,0 +1,28 @@ +#include "grammar_advanced.h" + +#include + +#include "grammar_basic.h" + +struct ast *parse_redirection(struct lexer_context *ctx) +{ + struct token *token = PEEK_TOKEN(); + if (token->type == TOKEN_IONUMBER) + { + // TODO + POP_TOKEN(); + token = PEEK_TOKEN(); + } + + if (token->type != TOKEN_REDIRECTION) + { + puts("Syntax error: expected a redirection token but got something " + "else"); + return NULL; + } +} + +struct ast *parse_prefix(struct lexer_context *ctx) +{ + return parse_redirection(ctx); +} diff --git a/src/parser/grammar_advanced.h b/src/parser/grammar_advanced.h index 8773655..72b5a43 100644 --- a/src/parser/grammar_advanced.h +++ b/src/parser/grammar_advanced.h @@ -1,4 +1,27 @@ #ifndef GRAMMAR_ADVANCED_H #define GRAMMAR_ADVANCED_H +#include "grammar.h" + +// === Functions + +/* + * @brief parses a redirection rule + * + * @code redirection = [IONUMBER] ( '>' | '<' | '>>' | '>&' | '<&' | '>|' | '<>' ) WORD ; + * + * @first TOKEN_IONUMBER, TOKEN_REDIRECTION + */ +struct ast *parse_redirection(struct lexer_context *ctx); + +/* + * @brief parses a prefix rule + * + * @code prefix = redirection ; + * + * @first first(redirection) + */ +struct ast *parse_prefix(struct lexer_context *ctx); + + #endif /* ! GRAMMAR_ADVANCED_H */ diff --git a/src/parser/grammar_basic.c b/src/parser/grammar_basic.c index b7f74c0..efa105d 100644 --- a/src/parser/grammar_basic.c +++ b/src/parser/grammar_basic.c @@ -3,9 +3,9 @@ #include #include -#include "../lexer/lexer.h" #include "../utils/lists/lists.h" #include "grammar.h" +#include "grammar_advanced.h" // === Static functions @@ -124,46 +124,86 @@ struct ast *parse_command(struct lexer_context *ctx) struct ast *parse_simple_command(struct lexer_context *ctx) { struct list *command_elements = NULL; - struct token *token = PEEK_TOKEN(); + + // WORD + struct token *token = POP_TOKEN(); if (token->type != TOKEN_WORD) { puts("Expected a command but got a different token type"); return NULL; } + char *command = strdup(token->data); + command_elements = list_append(command_elements, command); + token = PEEK_TOKEN(); + + // Eventual elements while (token->type == TOKEN_WORD) { - token = pop_token(ctx); - if (token == NULL) + // Get element + struct ast *element = parse_element(ctx); + if (element == NULL) { - // TODO free + list_deep_destroy(command_elements); return NULL; } - char *word = strdup(token->data); - if (word == NULL) + + // Get element type + if (ast_is_word(element)) { - // TODO free - puts("Internal error: Couldn't copy token content (is memory full " - "?)"); + struct ast_word *element_word = ast_get_word(element); + command_elements = + list_append(command_elements, element_word->word); + } + else if (ast_is_redir(element)) + { + // TODO + puts("NOT IMPLEMENTED"); return NULL; } - command_elements = list_append(command_elements, word); - token = peek_token(ctx); - if (token == NULL) + else { - // TODO free + puts("Internal error: unexpected return value from parse_element " + "in parse_simple_command"); + list_deep_destroy(command_elements); return NULL; } + + // Forward + POP_TOKEN(); + token = PEEK_TOKEN(); } + // Result struct ast *result = ast_create_command(command_elements); if (result == NULL) { - // TODO free + list_deep_destroy(command_elements); + return NULL; } return result; } +struct ast *parse_element(struct lexer_context *ctx) +{ + struct token *token = PEEK_TOKEN(); + if (token->type == TOKEN_WORD) + { + // TODO + puts("NOT IMPLEMENTED"); + return NULL; + } + else if (token->type == TOKEN_IONUMBER || token->type == TOKEN_REDIRECTION) + { + return parse_redirection(ctx); + } + else + { + puts("Syntax error: unexpected token at parse_element"); + return NULL; + } +} + struct ast *parse_shell_command(struct lexer_context *ctx) { return parse_if_rule(ctx); diff --git a/src/parser/grammar_basic.h b/src/parser/grammar_basic.h index cb49172..f1c2f77 100644 --- a/src/parser/grammar_basic.h +++ b/src/parser/grammar_basic.h @@ -6,7 +6,8 @@ // === Functions -/* @brief: parses a list of [and_or] rules separated by semicolons and that +/* + * @brief parses a list of [and_or] rules separated by semicolons and that * ends by a newline * * @code list = and_or { ';' and_or } [ ';' ] ; @@ -15,7 +16,8 @@ */ struct ast *parse_list(struct lexer_context *ctx); -/* @brief Only parses a pipeline rule for the moment +/* + * @brief Only parses a pipeline rule for the moment * * @code and_or = pipeline { ( '&&' | '||' ) {'\n'} pipeline } ; * @@ -23,7 +25,8 @@ struct ast *parse_list(struct lexer_context *ctx); */ struct ast *parse_and_or(struct lexer_context *ctx); -/* @brief Only parses a command rule for the moment +/* + * @brief Only parses a command rule for the moment * * @code pipeline = command ; * @@ -31,7 +34,8 @@ struct ast *parse_and_or(struct lexer_context *ctx); */ struct ast *parse_pipeline(struct lexer_context *ctx); -/* @brief Parses a simple command rule or a shell command rule depending on +/* + * @brief Parses a simple command rule or a shell command rule depending on * the first token. * @note * TOKEN_WORD => simple_command @@ -44,7 +48,8 @@ struct ast *parse_pipeline(struct lexer_context *ctx); */ struct ast *parse_command(struct lexer_context *ctx); -/* @brief Parses a simple list of words (command and arguments) +/* + * @brief Parses a simple list of words (command and arguments) * ending by a separator * * @code simple_command = WORD { element } ; @@ -53,7 +58,19 @@ struct ast *parse_command(struct lexer_context *ctx); */ struct ast *parse_simple_command(struct lexer_context *ctx); -/* @brief Only parses if rules for the moment +/* + * @brief Parses an element rule + * + * @code element = WORD + * | redirection + * ; + * + * @first WORD, first(redirection) + */ +struct ast *parse_element(struct lexer_context *ctx); + +/* + * @brief Only parses if rules for the moment * * @code shell_command = if_rule ; * @@ -61,7 +78,8 @@ struct ast *parse_simple_command(struct lexer_context *ctx); */ struct ast *parse_shell_command(struct lexer_context *ctx); -/* @brief Parses a if rule (condition, then-clause, elif-clause, else-clause) +/* + * @brief Parses a if rule (condition, then-clause, elif-clause, else-clause) * * @code if_rule = 'if' compound_list 'then' compound_list [else_clause] 'fi' ; * @@ -69,7 +87,8 @@ struct ast *parse_shell_command(struct lexer_context *ctx); */ struct ast *parse_if_rule(struct lexer_context *ctx); -/* @brief parses commands inside if/else clauses and returns the corresponding +/* + * @brief parses commands inside if/else clauses and returns the corresponding * AST list * * @code compound_list = {'\n'} and_or { ( ';' | '\n' ) {'\n'} and_or } [';'] @@ -79,7 +98,8 @@ struct ast *parse_if_rule(struct lexer_context *ctx); */ struct ast *parse_compound_list(struct lexer_context *ctx); -/* @brief +/* + * @brief * * @code else_clause = 'else' compound_list * | 'elif' compound_list 'then' compound_list [else_clause] diff --git a/src/utils/ast/ast.h b/src/utils/ast/ast.h index a98d88b..fc35666 100644 --- a/src/utils/ast/ast.h +++ b/src/utils/ast/ast.h @@ -9,6 +9,7 @@ #include "ast_list.h" #include "ast_redir.h" #include "ast_void.h" +#include "ast_word.h" /** * Prints the Graphviz DOT representation of the given AST to stdout. diff --git a/src/utils/ast/ast_base.h b/src/utils/ast/ast_base.h index e09b25d..4ae00ec 100644 --- a/src/utils/ast/ast_base.h +++ b/src/utils/ast/ast_base.h @@ -11,7 +11,8 @@ enum ast_type AST_AND_OR, AST_REDIR, AST_VOID, - AST_CMD + AST_CMD, + AST_WORD }; struct ast diff --git a/src/utils/ast/ast_word.c b/src/utils/ast/ast_word.c new file mode 100644 index 0000000..d798c77 --- /dev/null +++ b/src/utils/ast/ast_word.c @@ -0,0 +1,45 @@ +#include "ast_word.h" + +#include +#include +#include + +struct ast *ast_create_word(char *word) +{ + struct ast_word *ast_node = malloc(sizeof(struct ast_word)); + if (ast_node == NULL) + return NULL; + + ast_node->type = AST_WORD; + ast_node->word = strdup(word); + struct ast *res = ast_create(AST_WORD, ast_node); + if (res == NULL) + { + free(ast_node); + return NULL; + } + + return res; +} + +struct ast_word *ast_get_word(struct ast *node) +{ + if (node == NULL || node->type != AST_WORD) + return NULL; + + return node->data; +} + +bool ast_is_word(struct ast *node) +{ + return node && node->type == AST_WORD; +} + +void ast_free_word(struct ast_word *ast_node) +{ + if (ast_node == NULL) + return; + + free(ast_node->word); + free(ast_node); +} diff --git a/src/utils/ast/ast_word.h b/src/utils/ast/ast_word.h new file mode 100644 index 0000000..d5e0e1d --- /dev/null +++ b/src/utils/ast/ast_word.h @@ -0,0 +1,35 @@ +#ifndef AST_WORD_H +#define AST_WORD_H + +#include + +#include "ast_base.h" + +struct ast_word +{ + enum ast_type type; + char *word; +}; + +/** + * Checks if the given AST node is a command. + */ +bool ast_is_word(struct ast *node); + +/** + * Retrieves the command data from the given AST node. + * Assumes that the node is of type AST_CMD. + */ +struct ast_word *ast_get_word(struct ast *node); + +/** + * Creates a new AST node representing a command. + */ +struct ast *ast_create_word(char* word); + +/* + * @brief: frees the given ast_command and sets the pointer to NULL. + */ +void ast_free_word(struct ast_word *ast_node); + +#endif /* ! AST_WORD_H */