From 115377edfe5bc36758ea7883846c7e5e0764ca64 Mon Sep 17 00:00:00 2001 From: Matteo Flebus Date: Fri, 30 Jan 2026 19:13:27 +0100 Subject: [PATCH] feat(lexer + parser): export handling --- src/lexer/lexer_utils.c | 2 + src/lexer/lexer_utils.h | 3 +- src/parser/grammar_basic.c | 125 ++++++++++++++++++++++--------------- 3 files changed, 80 insertions(+), 50 deletions(-) diff --git a/src/lexer/lexer_utils.c b/src/lexer/lexer_utils.c index dee3f88..c2265e8 100644 --- a/src/lexer/lexer_utils.c +++ b/src/lexer/lexer_utils.c @@ -72,6 +72,8 @@ static void set_token_keyword(struct token *tok, char *begin, ssize_t size) tok->type = TOKEN_ELSE; else if (strncmp(begin, "elif", size) == 0 && size == 4) tok->type = TOKEN_ELIF; + else if (strncmp(begin, "export", size) == 0 && size == 6) + tok->type = TOKEN_ELIF; // no keywords found. if (tok->type == TOKEN_NULL) diff --git a/src/lexer/lexer_utils.h b/src/lexer/lexer_utils.h index af64455..6f6ade2 100644 --- a/src/lexer/lexer_utils.h +++ b/src/lexer/lexer_utils.h @@ -72,7 +72,8 @@ enum token_type TOKEN_FOR, TOKEN_WHILE, TOKEN_UNTIL, - TOKEN_CASE + TOKEN_CASE, + TOKEN_EXPORT }; struct token diff --git a/src/parser/grammar_basic.c b/src/parser/grammar_basic.c index 86ed089..c3a4ea0 100644 --- a/src/parser/grammar_basic.c +++ b/src/parser/grammar_basic.c @@ -174,14 +174,33 @@ struct ast *parse_command(struct lexer_context *ctx) /* @brief: frees command_elements and redirections lists (helper func) * @return: NULL */ -static void *err_simple_command(struct list *command_elements, - struct list *redirections) +static void *err_s_com(struct list *command_elements, struct list *redirections, + struct list *assignments); { list_deep_destroy(command_elements); list_deep_destroy(redirections); + list_deep_destroy(assignments); return NULL; } +static ast *parse_export(struct lexer_context *ctx) +{ + struct token *token = PEEK_TOKEN(); + if (token->type != TOKEN_EXPORT) + { + fprintf(stderr, "expected the export keyword in parse_export"); + return NULL; + } + POP_TOKEN(); + token = PEEK_TOKEN(); + if (token->type != TOKEN_ASSIGNMENT_WORD) + { + fprintf(stderr, "in parser: export must be followed by 'x=y'"); + return NULL; + } + return ast_create_assignment(token->data, true); +} + struct ast *parse_simple_command(struct lexer_context *ctx) { struct list *command_elements = NULL; @@ -198,7 +217,7 @@ struct ast *parse_simple_command(struct lexer_context *ctx) struct ast *prefix = parse_prefix(ctx); if (prefix == NULL) { - return err_simple_command(command_elements, redirections); + return err_s_com(command_elements, redirections); } if (prefix->type == AST_ASSIGNMENT) { @@ -214,66 +233,70 @@ struct ast *parse_simple_command(struct lexer_context *ctx) if (token->type != TOKEN_WORD) { - if (!has_prefix) + if (!has_prefix && token->type != TOKEN_EXPORT) { perror("Expected a command but got a different token type"); - return err_simple_command(command_elements, redirections); + return err_s_com(command_elements, redirections, assignments); + } + if (token->type == TOKEN_EXPORT) + { + struct ast *assignment_export = parse_export(ctx); + if (assignment == NULL) + return err_s_com(command_elements, redirections, assignments); + + assignments = list_append(assignments, assignment_export); } - // else : only prefixes } - else + else // TOKEN WORD { - if (token->type == TOKEN_WORD) + char *command = strdup(token->data); + command_elements = list_append(command_elements, command); + + POP_TOKEN(); + token = PEEK_TOKEN(); + } + // Eventual elements + while (is_first(*token, RULE_ELEMENT)) + { + // Get element + struct ast *element = parse_element(ctx); + if (element == NULL) { - char *command = strdup(token->data); - command_elements = list_append(command_elements, command); - - POP_TOKEN(); - token = PEEK_TOKEN(); + return err_s_com(command_elements, redirections, assignments); } - // Eventual elements - while (is_first(*token, RULE_ELEMENT)) + + // Get element type + if (ast_is_word(element)) { - // Get element - struct ast *element = parse_element(ctx); - if (element == NULL) - { - return err_simple_command(command_elements, redirections); - } + struct ast_word *element_word = ast_get_word(element); - // Get element type - if (ast_is_word(element)) - { - struct ast_word *element_word = ast_get_word(element); - - // TODO test this fix for the memory leaks - char *word = strdup(element_word->word); - ast_free(&element); - command_elements = list_append(command_elements, word); - // end of fix - } - else if (ast_is_redir(element)) - { - // append redirections to the list of redirections - redirections = list_append(redirections, element); - } - else - { - perror("Internal error: unexpected return value from " - "parse_element in parse_simple_command"); - return err_simple_command(command_elements, redirections); - } - - // Forward - token = PEEK_TOKEN(); + // TODO test this fix for the memory leaks + char *word = strdup(element_word->word); + ast_free(&element); + command_elements = list_append(command_elements, word); + // end of fix } + else if (ast_is_redir(element)) + { + // append redirections to the list of redirections + redirections = list_append(redirections, element); + } + else + { + perror("Internal error: unexpected return value from " + "parse_element in parse_simple_command"); + return err_s_com(command_elements, redirections, assignments); + } + + // Forward + token = PEEK_TOKEN(); } struct ast *result = ast_create_command(command_elements, redirections, assignments); if (result == NULL) { - return err_simple_command(command_elements, redirections); + return err_s_com(command_elements, redirections, assignments); } return result; } @@ -290,6 +313,10 @@ struct ast *parse_element(struct lexer_context *ctx) { return parse_redirection(ctx); } + else if (token->type == TOKEN_EXPORT) + { + return parse_export(ctx); + } else { perror("Syntax error: unexpected token at parse_element"); @@ -455,8 +482,8 @@ struct ast *parse_else_clause(struct lexer_context *ctx) token = POP_TOKEN(); if (token->type != TOKEN_THEN) { - perror( - "Expected the 'then' keyword but got a different token type"); + perror("Expected the 'then' keyword but got a different token " + "type"); return NULL; }