diff --git a/src/parser/parsing_utils.c b/src/parser/parsing_utils.c index 9ac32d8..1841c0c 100644 --- a/src/parser/parsing_utils.c +++ b/src/parser/parsing_utils.c @@ -1,4 +1,5 @@ #define _POSIX_C_SOURCE 200809L + // === Includes #include "parsing_utils.h" @@ -13,7 +14,7 @@ // === Static functions /* Returns true if c is a command terminator, false otherwise - */ +*/ static bool isterminator(struct token *token) { if (token == NULL) @@ -21,17 +22,20 @@ static bool isterminator(struct token *token) switch (token->type) { - case TOKEN_NEWLINE: - case TOKEN_SEMICOLON: - case TOKEN_EOF: - return true; - default: - return false; + case TOKEN_NEWLINE: + case TOKEN_SEMICOLON: + case TOKEN_EOF: + return true; + default: + return false; } } /* @brief: returns true if token is an end of list indicator. + * @warning: not used */ + +/* static bool is_end_of_list(struct token *token) { if (token == NULL) @@ -39,34 +43,20 @@ static bool is_end_of_list(struct token *token) switch (token->type) { - case TOKEN_NEWLINE: - case TOKEN_EOF: - return true; - default: - return false; + case TOKEN_NEWLINE: + case TOKEN_EOF: + return true; + default: + return false; } } +*/ // === Functions -/* Parses a simple list of words (command and arguments) - * and returns the resulting ast - */ -struct ast *parse_simple_command(void) +struct ast *parse_input(void) { - struct list *command_elements = NULL; - struct token *token = PEEK_TOKEN(); - - while (!isterminator(token)) - { - token = POP_TOKEN(); - char *word = strdup(token->data); - command_elements = list_append(command_elements, word); - token = PEEK_TOKEN(); - } - - struct ast *result = ast_create_command(command_elements); - return result; + return parse_list(); } struct ast *parse_list(void) @@ -76,57 +66,139 @@ struct ast *parse_list(void) struct token *token = PEEK_TOKEN(); - while (!is_end_of_list(token)) + // and_or + current_node = parse_and_or(); + if (current_node == NULL) + return NULL; + list_append(result_list, current_node); + + // Following and_or commands + token = PEEK_TOKEN(); + while (token->type == TOKEN_SEMICOLON) { - if (token->type == TOKEN_SEMICOLON) + token = POP_TOKEN(); + if (!isterminator(token)) // Follow(list) { - result_list = list_append(result_list, current_node); + current_node = parse_and_or(); + if (current_node == NULL) + { + //TODO free list + // There must be a function for that + return NULL; + } + list_append(result_list, current_node); + token = PEEK_TOKEN(); } - else - { - // TODO use parse_and_or() instead. - current_node = parse_simple_command(); - } - token = PEEK_TOKEN(); } result_list = list_append(result_list, current_node); return ast_create_list(result_list); } -struct ast *parse_if_rule(void) +struct ast *parse_and_or(void) { - // If condition - struct token *token = POP_TOKEN(); + return parse_pipeline(); +} - if (token->type != TOKEN_IF) +struct ast *parse_pipeline(void) +{ + return parse_command(); +} + +struct ast *parse_command(void) +{ + struct token *token = PEEK_TOKEN(); + + if (token->type == TOKEN_WORD) { - puts("Internal error: expected a if rule but token has different " - "type"); + return parse_simple_command(); + } + else if (token->type == TOKEN_IF) + { + return parse_shell_command(); + } + else + { + return ast_create_void(); // TODO not sure what to do + } +} + +struct ast *parse_simple_command(void) +{ + struct list *command_elements = NULL; + struct token *token = PEEK_TOKEN(); + if (token->type != TOKEN_WORD) + { + puts("Expected a command but got a different token type"); return NULL; } + while (token->type == TOKEN_WORD) + { + token = POP_TOKEN(); + char* word = strdup(token->data); + command_elements = list_append(command_elements, word); + token = PEEK_TOKEN(); + } + + struct ast *result = ast_create_command(command_elements); + return result; +} + +// TODO check compliance with the grammar +struct ast *parse_shell_command(void) +{ + return parse_if_rule(); +} + +struct ast *parse_if_rule(void) +{ + // If keyword + struct token *token = POP_TOKEN(); + if (token->type != TOKEN_IF) + { + puts("Internal error: expected a if rule but token has different " + "type"); + return NULL; + } + + // Condition content struct ast *condition_content = parse_compound_list(); - // Then content + // Then keyword token = POP_TOKEN(); - if (token->type != TOKEN_THEN) { + ast_free(&condition_content); puts("Expected the 'then' keyword but token has different type"); return NULL; } + // Then content struct ast *then_content = parse_compound_list(); + if (then_content == NULL) + { + ast_free(&condition_content); + ast_free(&then_content); + return NULL; + } // Eventual else/elif clause(s) struct ast *else_content = parse_else_clause(); + if (else_content == NULL) + { + ast_free(&condition_content); + ast_free(&then_content); + return NULL; + } token = POP_TOKEN(); if (token->type != TOKEN_FI) { + ast_free(&condition_content); + ast_free(&then_content); + ast_free(&else_content); puts("Expected the 'fi' keyword but token has different type"); - // TODO free previous asts return NULL; } @@ -134,8 +206,10 @@ struct ast *parse_if_rule(void) ast_create_if(condition_content, then_content, else_content); if (result == NULL) { + ast_free(&condition_content); + ast_free(&then_content); + ast_free(&else_content); puts("Internal error: could not create a new AST (AST_IF)"); - // TODO free previous asts return NULL; } @@ -145,53 +219,98 @@ struct ast *parse_if_rule(void) struct ast *parse_compound_list(void) { struct list *result_list = NULL; // ast* list - struct list *command_elements = NULL; // token* list + struct ast *current_cmd = NULL; struct token *token = PEEK_TOKEN(); - while (token->type != TOKEN_THEN || token->type != TOKEN_ELIF - || token->type != TOKEN_ELSE) + // Skip newlines + while (token->type == TOKEN_NEWLINE) { - // Parse simple command - if (token->type == TOKEN_SEMICOLON || token->type == TOKEN_NEWLINE) - { - // Stage (-> next command) - struct ast *command = ast_create_command(command_elements); - result_list = list_append(result_list, command); - command_elements = NULL; - } - - if (token->type == TOKEN_EOF) - { - puts("Syntax error: Unexpected end of stream"); // TODO pas très - // bien dit - return NULL; - } - - char *word = strdup(token->data); - - command_elements = list_append(command_elements, word); token = POP_TOKEN(); } + // and_or + current_cmd = parse_and_or(); + if (current_cmd == NULL) + return NULL; + list_append(result_list, current_cmd); + + // Following commands + token = PEEK_TOKEN(); + while (token->type == TOKEN_SEMICOLON || token->type == TOKEN_NEWLINE) + { + POP_TOKEN(); + + // Skip newlines + while (token->type == TOKEN_NEWLINE) + { + token = POP_TOKEN(); + } + + // and_or + current_cmd = parse_and_or(); + if (current_cmd == NULL) + return NULL; + list_append(result_list, current_cmd); + + token = PEEK_TOKEN(); + } + + // Eventual semicolons + if (token->type == TOKEN_SEMICOLON) + { + token = POP_TOKEN(); + } + + // Skip newlines + while (token->type == TOKEN_NEWLINE) + { + token = POP_TOKEN(); + } + + struct ast *result = ast_create_list(result_list); return result; } struct ast *parse_else_clause(void) { - // Eventual elif content struct token *token = PEEK_TOKEN(); + // Eventual elif content + while (token->type == TOKEN_ELIF) + { + // Condition + token = POP_TOKEN(); + struct ast *condition = parse_compound_list(); + + // 'then' + token = POP_TOKEN(); + if (token->type != TOKEN_THEN) + { + puts("Expected the 'then' keyword but got a different token type"); + return NULL; + } + + // Then clause + struct ast *then_content = parse_compound_list(); + + // Eventual else clause (recursive) + struct ast *else_content = NULL; + token = PEEK_TOKEN(); + if (token->type == TOKEN_ELSE || token->type == TOKEN_ELIF) + { + else_content = parse_else_clause(); + } + + struct ast *result = + ast_create_if(condition, then_content, else_content); + return result; + } + + // Eventual else content + struct ast *result = NULL; - // TODO handle ELIF - // while (token->type == TOKEN_ELIF) - // { - // puts("ABORTING ELIF: Not implemented ma gueule"); - // token = POP_TOKEN(); // Forward - // } - - // Eventual else content if (token->type == TOKEN_ELSE) { result = parse_compound_list(); @@ -203,18 +322,3 @@ struct ast *parse_else_clause(void) return result; } - -struct ast *parse_shell_command(void) -{ - struct token *token = PEEK_TOKEN(); - - switch (token->type) - { - case TOKEN_IF: - return parse_if_rule(); - - default: - puts("I think it's not implemented yet"); - return NULL; - } -} diff --git a/src/parser/parsing_utils.h b/src/parser/parsing_utils.h index 6fe6b89..5464981 100644 --- a/src/parser/parsing_utils.h +++ b/src/parser/parsing_utils.h @@ -19,33 +19,81 @@ return NULL; \ } -/* @brief: parses a list of [and_or] rules, separated by semicolons. +/* @brief Acts as the entry point of the parser, calls parse_list + * + * @code input = list '\n' + * | list EOF + * | '\n' + * | EOF + * ; + */ +struct ast* parse_input(void); + +/* @brief: parses a list of [and_or] rules separated by semicolons and that + * ends by a newline + * + * @code list = and_or { ';' and_or } [ ';' ] ; */ struct ast *parse_list(void); -/* @brief Parses a simple list of words (command and arguments) - * and returns the resulting ast - */ -struct ast *parse_simple_command(void); - -/* - */ -struct ast *parse_if_rule(void); - -/* - */ -struct ast *parse_shell_command(void); - -/* @brief parses commands inside if/else clauses and returns the corresponding - * AST list - */ -struct ast *parse_compound_list(void); - -/* +/* @brief Only parses a pipeline rule for the moment + * + * @code and_or = pipeline ; */ struct ast *parse_and_or(void); -/* +/* @brief Only parses a command rule for the moment + * + * @code pipeline = command ; + */ +struct ast* parse_pipeline(void); + +/* @brief Parses a simple command rule or a shell command rule depending on + * the first token. + * @note + * TOKEN_WORD => simple_command + * TOKEN_IF => shell_command + * + * @code command = simple_command + * | shell_command + * ; + */ +struct ast* parse_command(void); + +/* @brief Parses a simple list of words (command and arguments) + * ending by a separator + * + * @code simple_command = WORD { element } ; + */ +struct ast *parse_simple_command(void); + + +/* @brief Only parses if rules for the moment + * + * @code shell_command = if_rule ; + */ +struct ast *parse_shell_command(void); + + +/* @brief Parses a if rule (condition, then-clause, elif-clause, else-clause) + * + * @code if_rule = 'if' compound_list 'then' compound_list [else_clause] 'fi' ; + */ +struct ast *parse_if_rule(void); + + +/* @brief parses commands inside if/else clauses and returns the corresponding + * AST list + * + * @code compound_list = {'\n'} and_or { ( ';' | '\n' ) {'\n'} and_or } [';'] {'\n'} ; + */ +struct ast* parse_compound_list(void); + +/* @brief + * + * @code else_clause = 'else' compound_list + * | 'elif' compound_list 'then' compound_list [else_clause] + * ; */ struct ast *parse_else_clause(void);