summaryrefslogtreecommitdiff
path: root/42sh/src/parser/parser_loops.c
diff options
context:
space:
mode:
authorMartial Simon <msimon_fr@hotmail.com>2025-09-15 01:07:58 +0200
committerMartial Simon <msimon_fr@hotmail.com>2025-09-15 01:07:58 +0200
commit967be9e750221ab2ab783f95df79bb26d290a45e (patch)
tree6802900a5e975f9f68b169f0f503f040056d6952 /42sh/src/parser/parser_loops.c
add: added projectsHEADmain
Diffstat (limited to '42sh/src/parser/parser_loops.c')
-rw-r--r--42sh/src/parser/parser_loops.c265
1 files changed, 265 insertions, 0 deletions
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 <err.h>
+
+#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);
+}