From 967be9e750221ab2ab783f95df79bb26d290a45e Mon Sep 17 00:00:00 2001 From: Martial Simon Date: Mon, 15 Sep 2025 01:07:58 +0200 Subject: add: added projects --- 42sh/src/parser/parser_loops.c | 265 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 265 insertions(+) create mode 100644 42sh/src/parser/parser_loops.c (limited to '42sh/src/parser/parser_loops.c') diff --git a/42sh/src/parser/parser_loops.c b/42sh/src/parser/parser_loops.c new file mode 100644 index 0000000..bf1033a --- /dev/null +++ b/42sh/src/parser/parser_loops.c @@ -0,0 +1,265 @@ +#include + +#include "parser_functions.h" +#include "parser_utils.h" + +struct ast *parse_rule_while(struct lexer *lexer, enum parser_state *state) +{ + struct token next = lexer_peek(lexer); + + // Because we use this function for both while and until loops, this needs + // to be accounted for. The construction is exactly the same otherwise. + // The only difference is that the condition is NOT'ed in parse_rule_until + if (next.type != TOKEN_WHILE && next.type != TOKEN_UNTIL) + { + QUICK_CLEANUP + } + + lexer_pop(lexer); + next = lexer_peek(lexer); + + struct ast *cond = parse_compound_list(lexer, state); + next = lexer_peek(lexer); + + if (error_check(NULL, state, next)) + { + return NULL; + } + + if (next.type != TOKEN_DO) + { + cleanup(cond, state); + return NULL; + } + + lexer_pop(lexer); + + struct ast *body = parse_compound_list(lexer, state); + next = lexer_peek(lexer); + + if (error_check(cond, state, next)) + { + return NULL; + } + + if (next.type != TOKEN_DONE) + { + cleanup(cond, state); + cleanup(body, state); + return NULL; + } + + lexer_pop(lexer); + + struct ast *while_loop = ast_create(AST_WHILE); + + if (while_loop == NULL) + { + cleanup(cond, state); + cleanup(body, state); + return NULL; + } + + set_left(while_loop, cond); + set_right(while_loop, body); + + return while_loop; +} + +// Warning, does not respect the grammar for parse_rule_until. +// This is because we reuse the parse_rule_while method (the ast representation +// being exatly the same, minus the condition being negated) +struct ast *parse_rule_until(struct lexer *lexer, enum parser_state *state) +{ + struct token next = lexer_peek(lexer); + + if (next.type != TOKEN_UNTIL) + { + QUICK_CLEANUP + } + + struct ast *while_root = parse_rule_while(lexer, state); + next = lexer_peek(lexer); + + if (error_check(while_root, state, next)) + { + return NULL; + } + + struct ast *inverted = ast_create(AST_LOGICAL); + if (inverted == NULL) + { + cleanup(while_root, state); + return NULL; + } + + ((struct ast_logical *)inverted)->type = TOKEN_NEG; + + set_left(inverted, ((struct ast_while *)while_root)->cond); + ((struct ast_while *)while_root)->cond = inverted; + + return while_root; +} + +static struct string **_realloc_ast_command(struct ast *ast, size_t *capacity) +{ + struct ast_command *ast_c = ((struct ast_command *)ast); + size_t i = 0; + while (ast_c->args[i]) + { + i++; + } + struct string **p = + realloc(ast_c->args, (i + CMDSIZE) * sizeof(struct string *)); + if (!p) + { + errx(EXIT_FAILURE, "Realloc failed."); + } + ast_c->args = p; + *capacity = i + CMDSIZE; + memset(ast_c->args + i, 0, (CMDSIZE) * sizeof(struct string *)); + return p; +} + +static void fill_cmd(struct ast *ast, struct lexer *lexer) +{ + struct token next = lexer_peek(lexer); + size_t i = 0; + size_t capacity = CMDSIZE; + + struct string **arr = calloc(CMDSIZE, sizeof(struct string *)); + + ((struct ast_command *)ast)->args = arr; + while (ISWORD(next.type)) + { + if (i == capacity) + { + arr = _realloc_ast_command(ast, &capacity); + ((struct ast_command *)ast)->args = arr; + } + + litteral_reserved_word(&next); + arr[i] = next.value; + i++; + lexer_pop(lexer); + next = lexer_peek(lexer); + } +} + +static struct ast *fill_for_body(struct ast *root, struct lexer *lexer, + enum parser_state *state) +{ + clean_cons_tokens(TOKEN_NEWLINE, lexer); + + struct token next = lexer_peek(lexer); + + if (next.type != TOKEN_DO) + { + cleanup(root, state); + return NULL; + } + + lexer_pop(lexer); + next = lexer_peek(lexer); + + struct ast *cmp_lst = parse_compound_list(lexer, state); + + next = lexer_peek(lexer); + if (error_check(root, state, next)) + { + return NULL; + } + + set_right(root, cmp_lst); + + if (next.type != TOKEN_DONE) + { + cleanup(root, state); + return NULL; + } + + lexer_pop(lexer); + + return root; +} + +struct ast *parse_rule_for(struct lexer *lexer, enum parser_state *state) +{ + struct token next = lexer_peek(lexer); + + if (next.type != TOKEN_FOR) + { + QUICK_CLEANUP; + } + + lexer_pop(lexer); + next = lexer_peek(lexer); + + // It can be a keyword interpreted as a normal word + litteral_reserved_word(&next); + struct ast *for_node = ast_create(AST_FOR); + + // Cannot do both at the same time because I couldn't know why the code exit + // Was it because of the tokenor the ast and should I free something ? + if (for_node == NULL) + { + QUICK_CLEANUP; + } + + if (!(ISWORD(next.type))) + { + cleanup(for_node, state); + return NULL; + } + + ((struct ast_for *)for_node)->var = next.value; + + lexer_pop(lexer); + next = lexer_peek(lexer); + + if (next.type == TOKEN_SEMICOLON) + { + lexer_pop(lexer); + } + else if (next.type == TOKEN_NEWLINE || next.type == TOKEN_IN) + { + if (next.type == TOKEN_NEWLINE) + { + clean_cons_tokens(TOKEN_NEWLINE, lexer); + // We only need to peek if we destroyed tokens + next = lexer_peek(lexer); + } + + if (next.type == TOKEN_IN) + { + lexer_pop(lexer); + next = lexer_peek(lexer); + + struct ast *lst = ast_create(AST_COMMAND); + if (lst == NULL) + { + cleanup(for_node, state); + return NULL; + } + + fill_cmd(lst, lexer); + set_left(for_node, lst); + + next = lexer_peek(lexer); + if (next.type != TOKEN_SEMICOLON && next.type != TOKEN_NEWLINE) + { + cleanup(for_node, state); + return NULL; + } + + lexer_pop(lexer); + } + } + else if (next.type != TOKEN_DO) + { + cleanup(for_node, state); + return NULL; + } + + return fill_for_body(for_node, lexer, state); +} -- cgit v1.2.3