#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); }