// === Includes #include "parsing_utils.h" #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 struct ast *parse_input(void) { return parse_list(); } struct ast *parse_list(void) { struct list *result_list = NULL; struct ast *current_node = NULL; struct token *token = PEEK_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) { token = POP_TOKEN(); if (!isterminator(token)) // Follow(list) { 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(); } } return ast_create_list(result_list); } struct ast *parse_and_or(void) { return parse_pipeline(); } struct ast *parse_pipeline(void) { return parse_command(); } struct ast *parse_command(void) { struct token *token = PEEK_TOKEN(); if (token->type == TOKEN_WORD) { 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 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"); return NULL; } struct ast *result = 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)"); return NULL; } return result; } struct ast *parse_compound_list(void) { struct list *result_list = NULL; // ast* list struct ast *current_cmd = NULL; struct token *token = PEEK_TOKEN(); // Skip newlines while (token == TOKEN_NEWLINE) 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 == 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 == TOKEN_NEWLINE) token = POP_TOKEN(); struct ast *result = ast_create_list(result_list); return result; } struct ast *parse_else_clause(void) { 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; if (token->type == TOKEN_ELSE) { result = parse_compound_list(); token = POP_TOKEN(); // Forward } if (result == NULL) result = ast_create_void(); return result; }