From 9f967dc9b47965a12ac665715c26342c71702535 Mon Sep 17 00:00:00 2001 From: "Gu://em_" Date: Fri, 30 Jan 2026 20:00:44 +0100 Subject: [PATCH] refactor: removed duplicate code for while/until loops in parser --- src/parser/grammar_advanced.c | 166 ++++++++++++++-------------------- src/parser/grammar_basic.c | 10 +- 2 files changed, 78 insertions(+), 98 deletions(-) diff --git a/src/parser/grammar_advanced.c b/src/parser/grammar_advanced.c index c1e9d20..a1235c1 100644 --- a/src/parser/grammar_advanced.c +++ b/src/parser/grammar_advanced.c @@ -9,6 +9,8 @@ #include "grammar.h" #include "grammar_basic.h" +// === Static functions + static enum ast_redir_type redir_tok_to_ast_type(enum token_type tok_type) { switch (tok_type) @@ -32,6 +34,71 @@ static enum ast_redir_type redir_tok_to_ast_type(enum token_type tok_type) } } +/* + * @brief parses a while/until loop starting with the condition + * (after the while/until keyword) + * @arg negate_condition Set to true for until loops, false for while loops + */ +static struct ast *parse_loop(struct lexer_context *ctx, bool negate_condition) +{ + // condition + struct ast *condition = parse_compound_list(ctx); + if (condition == NULL) + return NULL; + if (negate_condition) + { + condition = + ast_create_neg(true, condition); // TODO check result (beware to not + // exceed the function lines limit) + } + + struct token *token = PEEK_TOKEN(); + + // 'do' + if (token->type != TOKEN_DO) + { + ast_free(&condition); + perror("Syntax error: expected the 'do' keyowrd but got a different " + "token"); + return NULL; + } + POP_TOKEN(); + token = PEEK_TOKEN(); + + // body + struct ast *body = parse_compound_list(ctx); + if (body == NULL) + { + ast_free(&condition); + return NULL; + } + token = PEEK_TOKEN(); + + // 'done' + if (token->type != TOKEN_DONE) + { + ast_free(&condition); + perror("Syntax error: expected the 'done' keyowrd but got a different " + "token"); + return NULL; + } + POP_TOKEN(); + + struct ast *result = ast_create_loop(condition, body); + if (result == NULL) + { + ast_free(&condition); + ast_free(&body); + perror("Internal error: could not create ast node (is your memory full " + "?)"); + return NULL; + } + + return result; +} + +// === Functions + struct ast *parse_redirection(struct lexer_context *ctx) { struct token *token = PEEK_TOKEN(); @@ -110,53 +177,7 @@ struct ast *parse_while(struct lexer_context *ctx) } POP_TOKEN(); - // condition - struct ast *condition = parse_compound_list(ctx); - if (condition == NULL) - return NULL; - token = PEEK_TOKEN(); - - // 'do' - if (token->type != TOKEN_DO) - { - ast_free(&condition); - perror("Syntax error: expected the 'do' keyowrd but got a different " - "token"); - return NULL; - } - POP_TOKEN(); - token = PEEK_TOKEN(); - - // body - struct ast *body = parse_compound_list(ctx); - if (body == NULL) - { - ast_free(&condition); - return NULL; - } - token = PEEK_TOKEN(); - - // 'done' - if (token->type != TOKEN_DONE) - { - ast_free(&condition); - perror("Syntax error: expected the 'done' keyowrd but got a different " - "token"); - return NULL; - } - POP_TOKEN(); - - struct ast *result = ast_create_loop(condition, body); - if (result == NULL) - { - ast_free(&condition); - ast_free(&body); - perror("Internal error: could not create ast node (is your memory full " - "?)"); - return NULL; - } - - return result; + return parse_loop(ctx, true); } struct ast *parse_until(struct lexer_context *ctx) @@ -172,54 +193,5 @@ struct ast *parse_until(struct lexer_context *ctx) } POP_TOKEN(); - // condition - struct ast *condition = parse_compound_list(ctx); - if (condition == NULL) - return NULL; - condition = - ast_create_neg(true, condition); // TODO check result (beware to not - // exceed function lines limit) - token = PEEK_TOKEN(); - - // 'do' - if (token->type != TOKEN_DO) - { - ast_free(&condition); - perror("Syntax error: expected the 'do' keyowrd but got a different " - "token"); - return NULL; - } - POP_TOKEN(); - token = PEEK_TOKEN(); - - // body - struct ast *body = parse_compound_list(ctx); - if (body == NULL) - { - ast_free(&condition); - return NULL; - } - token = PEEK_TOKEN(); - - // 'done' - if (token->type != TOKEN_DONE) - { - ast_free(&condition); - perror("Syntax error: expected the 'done' keyowrd but got a different " - "token"); - return NULL; - } - POP_TOKEN(); - - struct ast *result = ast_create_loop(condition, body); - if (result == NULL) - { - ast_free(&condition); - ast_free(&body); - perror("Internal error: could not create ast node (is your memory full " - "?)"); - return NULL; - } - - return result; + return parse_loop(ctx, true); } diff --git a/src/parser/grammar_basic.c b/src/parser/grammar_basic.c index c5a5ee3..b7f58bd 100644 --- a/src/parser/grammar_basic.c +++ b/src/parser/grammar_basic.c @@ -349,7 +349,15 @@ struct ast *parse_shell_command(struct lexer_context *ctx) { return parse_if_rule(ctx); } - // TODO loops and case + else if (is_first(*token, RULE_WHILE)) + { + return parse_while(ctx); + } + else if (is_first(*token, RULE_UNTIL)) + { + return parse_until(ctx); + } + // TODO for and case else { perror("Syntax error: unexpected token in parse_shell_command");