#define _POSIX_C_SOURCE 200809L // === Includes #include "parsing_utils.h" #include #include #include #include #include "lexer/lexer.h" #include "utils/ast/ast.h" // === Static functions /* Returns true if c is a command terminator, false otherwise */ static bool isterminator(struct token *token) { if (token == NULL) return false; switch (token->type) { 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. */ static bool is_end_of_list(struct token *token) { if (token == NULL) return false; switch (token->type) { 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 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; } struct ast *parse_list(void) { struct list *result_list = NULL; struct ast *current_node = NULL; struct token *token = PEEK_TOKEN(); while (!is_end_of_list(token)) { if (token->type == TOKEN_SEMICOLON) { result_list = list_append(result_list, current_node); } 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) { // If condition struct token *token = POP_TOKEN(); if (token->type != TOKEN_IF) { puts("Internal error: expected a if rule but token has different " "type"); return NULL; } struct ast *condition_content = parse_compound_list(); // Then content token = POP_TOKEN(); if (token->type != TOKEN_THEN) { puts("Expected the 'then' keyword but token has different type"); return NULL; } struct ast *then_content = parse_compound_list(); // Eventual else/elif clause(s) struct ast *else_content = parse_else_clause(); token = POP_TOKEN(); if (token->type != TOKEN_FI) { puts("Expected the 'fi' keyword but token has different type"); // TODO free previous asts return NULL; } struct ast *result = ast_create_if(condition_content, then_content, else_content); if (result == NULL) { puts("Internal error: could not create a new AST (AST_IF)"); // TODO free previous asts return NULL; } return result; } struct ast *parse_compound_list(void) { struct list *result_list = NULL; // ast* list struct list *command_elements = NULL; // token* list struct token *token = PEEK_TOKEN(); while (token->type != TOKEN_THEN || token->type != TOKEN_ELIF || token->type != TOKEN_ELSE) { // 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(); } struct ast *result = ast_create_list(result_list); return result; } struct ast *parse_else_clause(void) { // Eventual elif content struct token *token = PEEK_TOKEN(); 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(); token = POP_TOKEN(); // Forward } if (result == NULL) result = ast_create_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; } }