#include "parser/parser_functions.h" #include "parser/parser_utils.h" struct ast *parse_rule_if(struct lexer *lexer, enum parser_state *state) { struct token next = lexer_peek(lexer); // Not mandatory because we checked before going in here if (next.type != TOKEN_IF) { QUICK_CLEANUP } struct ast *root = ast_create(AST_IF); if (root == NULL) { *state = ERROR; return NULL; } lexer_pop(lexer); struct ast *cond = parse_compound_list(lexer, state); next = lexer_peek(lexer); if (error_check(root, state, next)) { return NULL; } set_left(root, cond); if (next.type != TOKEN_THEN) { cleanup(root, state); return NULL; } lexer_pop(lexer); cond = parse_compound_list(lexer, state); next = lexer_peek(lexer); if (error_check(root, state, next)) { return NULL; } if (cond == NULL) { cleanup(root, state); return NULL; } set_right(root, cond); if (next.type != TOKEN_FI) { cond = parse_else_clause(lexer, state); if (cond == NULL) { cleanup(root, state); return NULL; } set_i(root, cond, 2); } lexer_pop(lexer); return root; } struct ast *parse_else_clause(struct lexer *lexer, enum parser_state *state) { struct token next = lexer_peek(lexer); struct ast *root = NULL; if (next.type == TOKEN_ELSE) { lexer_pop(lexer); struct ast *cond = parse_compound_list(lexer, state); if (cond == NULL) { cleanup(root, state); return NULL; } if (error_check(cond, state, next)) { return NULL; } return cond; } else if (next.type != TOKEN_ELIF) { cleanup(NULL, state); return NULL; } lexer_pop(lexer); // Doesn' it seems stupid to just manually re-creating the IF again? // Can't I just call parse_if there ? But we won't be following the grammar // This is a late-game optimization that might not be worth it root = ast_create(AST_IF); if (root == NULL) { cleanup(root, state); return NULL; } struct ast *cond = parse_compound_list(lexer, state); set_left(root, cond); if (error_check(root, state, next)) { return NULL; } next = lexer_peek(lexer); if (next.type != TOKEN_THEN) { cleanup(root, state); return NULL; } lexer_pop(lexer); set_right(root, parse_compound_list(lexer, state)); if (error_check(root, state, next)) { return NULL; } next = lexer_peek(lexer); if (next.type == TOKEN_ELSE || next.type == TOKEN_ELIF) { cond = parse_else_clause(lexer, state); if (error_check(root, state, next)) { return NULL; } set_i(root, cond, 2); } return root; }