Merge branch 'parser' into dev

This commit is contained in:
Jean 2026-01-28 21:28:14 +01:00
commit 0d425aa44c
6 changed files with 124 additions and 67 deletions

View file

@ -121,7 +121,7 @@ static int get_fd_target(const struct ast_redir *redir)
if (redir->io_number != -1)
return redir->io_number;
if (redir->type == AST_REDIR_TYPE_LESS
|| redir->type == AST_REDIR_TYPE_DLESS
|| redir->type == AST_REDIR_TYPE_LESSGREAT
|| redir->type == AST_REDIR_TYPE_LESSAND)
return 0;
return 1;

View file

@ -16,7 +16,16 @@ static enum ast_redir_type redir_tok_to_ast_type(enum token_type tok_type)
return AST_REDIR_TYPE_LESS;
case TOKEN_REDIR_RIGHT:
return AST_REDIR_TYPE_GREAT;
// TODO finish this
case TOKEN_REDIR_DOUBLE_RIGHT:
return AST_REDIR_TYPE_DGREAT;
case TOKEN_REDIR_LEFT_RIGHT:
return AST_REDIR_TYPE_LESSGREAT;
case TOKEN_REDIR_LEFT_AMP:
return AST_REDIR_TYPE_LESSAND;
case TOKEN_REDIR_RIGHT_AMP:
return AST_REDIR_TYPE_GREATAND;
case TOKEN_REDIR_RIGHT_PIPE:
return AST_REDIR_TYPE_CLOBBER;
default:
return AST_REDIR_TYPE_NULL;
}

View file

@ -152,14 +152,15 @@ struct ast *parse_pipeline(struct lexer_context *ctx)
struct ast *parse_command(struct lexer_context *ctx)
{
struct token *token = PEEK_TOKEN();
struct ast *result = NULL;
if (token->type == TOKEN_WORD)
if (is_first(*token, RULE_SIMPLE_COMMAND))
{
return parse_simple_command(ctx);
result = parse_simple_command(ctx);
}
else if (token->type == TOKEN_IF)
else if (is_first(*token, RULE_SHELL_COMMAND))
{
return parse_shell_command(ctx);
parse_shell_command(ctx);
}
else
{
@ -168,64 +169,102 @@ 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)
{
list_deep_destroy(command_elements);
list_deep_destroy(redirections);
return NULL;
}
struct ast *parse_simple_command(struct lexer_context *ctx)
{
struct list *command_elements = NULL;
struct list *redirections = NULL; // list of redirection ASTs
bool has_prefix = false;
struct token *token = PEEK_TOKEN();
if (is_first(*token, RULE_PREFIX))
{
has_prefix = true;
while (is_first(*token, RULE_PREFIX))
{
struct ast *redir = parse_prefix(ctx);
if (redir == NULL)
{
return err_simple_command(command_elements, redirections);
}
redirections = list_append(redirections, redir);
token = PEEK_TOKEN();
}
}
// WORD
struct token *token = POP_TOKEN();
if (token->type != TOKEN_WORD)
{
perror("Expected a command but got a different token type");
return NULL;
if (!has_prefix)
{
perror("Expected a command but got a different token type");
return err_simple_command(command_elements, redirections);
}
// else : only prefixes
}
char *command = strdup(token->data);
command_elements = list_append(command_elements, command);
token = PEEK_TOKEN();
// Eventual elements
while (is_first(*token, RULE_ELEMENT))
else
{
// Get element
struct ast *element = parse_element(ctx);
if (element == NULL)
if (token->type == TOKEN_WORD)
{
list_deep_destroy(command_elements);
return NULL;
}
char *command = strdup(token->data);
command_elements = list_append(command_elements, command);
// Get element type
if (ast_is_word(element))
{
struct ast_word *element_word = ast_get_word(element);
command_elements =
list_append(command_elements, element_word->word);
POP_TOKEN();
token = PEEK_TOKEN();
}
else if (ast_is_redir(element))
// Eventual elements
while (is_first(*token, RULE_ELEMENT))
{
// TODO
perror("NOT IMPLEMENTED");
return NULL;
}
else
{
perror("Internal error: unexpected return value from parse_element "
"in parse_simple_command");
list_deep_destroy(command_elements);
return NULL;
}
// Get element
struct ast *element = parse_element(ctx);
if (element == NULL)
{
return err_simple_command(command_elements, redirections);
}
// Forward
token = PEEK_TOKEN();
// 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();
}
}
// Result
struct ast *result = ast_create_command(command_elements);
struct ast *result = ast_create_command(command_elements, redirections);
if (result == NULL)
{
list_deep_destroy(command_elements);
return NULL;
return err_simple_command(command_elements, redirections);
}
return result;
}
@ -254,6 +293,17 @@ struct ast *parse_shell_command(struct lexer_context *ctx)
return parse_if_rule(ctx);
}
/* @brief: frees all the arguments. (helper func)
* @return: NULL.
*/
static void *err_if_rule(struct ast **cond, struct ast **then_clause, struct ast **else_clause)
{
ast_free(cond);
ast_free(then_clause);
ast_free(else_clause);
return NULL;
}
struct ast *parse_if_rule(struct lexer_context *ctx)
{
// If keyword
@ -272,38 +322,34 @@ struct ast *parse_if_rule(struct lexer_context *ctx)
token = POP_TOKEN();
if (token->type != TOKEN_THEN)
{
ast_free(&condition_content);
perror("Expected the 'then' keyword but token has different type");
return NULL;
return err_if_rule(&condition_content, NULL, NULL);
}
// Then content
struct ast *then_content = parse_compound_list(ctx);
if (then_content == NULL)
{
ast_free(&condition_content);
ast_free(&then_content);
return NULL;
return err_if_rule(&condition_content, &then_content, NULL);
}
struct ast *else_content = NULL;
// Eventual else/elif clause(s)
struct ast *else_content = parse_else_clause(ctx);
if (else_content == NULL)
if (is_first(*token, RULE_ELSE_CLAUSE))
{
ast_free(&condition_content);
ast_free(&then_content);
return NULL;
else_content = parse_else_clause(ctx);
if (else_content == NULL)
{
return err_if_rule(&condition_content, &then_content, NULL);
}
}
// Fi keyword
token = POP_TOKEN();
if (token->type != TOKEN_FI)
{
ast_free(&condition_content);
ast_free(&then_content);
ast_free(&else_content);
perror("Expected the 'fi' keyword but token has different type");
return NULL;
return err_if_rule(&condition_content, &then_content, &else_content);
}
// Result
@ -311,11 +357,8 @@ struct ast *parse_if_rule(struct lexer_context *ctx)
ast_create_if(condition_content, then_content, else_content);
if (result == NULL)
{
ast_free(&condition_content);
ast_free(&then_content);
ast_free(&else_content);
perror("Internal error: could not create a new AST (AST_IF)");
return NULL;
return err_if_rule(&condition_content, &then_content, &else_content);
}
return result;

View file

@ -5,13 +5,15 @@
#include "../lists/lists.h"
struct ast *ast_create_command(struct list *command)
struct ast *ast_create_command(struct list *command,
struct list *redirections)
{
struct ast_command *command_data = malloc(sizeof(struct ast_command));
if (!command_data)
return NULL;
command_data->command = command;
command_data->redirections = redirections;
return ast_create(AST_CMD, command_data);
}
@ -33,5 +35,6 @@ void ast_free_command(struct ast_command *command_data)
if (command_data == NULL)
return;
list_deep_destroy(command_data->command);
ast_list_deep_destroy(command_data->redirections);
free(command_data);
}

View file

@ -7,6 +7,7 @@
struct ast_command
{
struct list *command; // A list of words (char*)
struct ast_list *redirections; // A list of ASTs, all ast_redir
};
/**
@ -23,7 +24,8 @@ struct ast_command *ast_get_command(struct ast *node);
/**
* Creates a new AST node representing a command.
*/
struct ast *ast_create_command(struct list *command);
struct ast *ast_create_command(struct list *command,
struct list *redirections);
/*
* @brief: frees the given ast_command and sets the pointer to NULL.

View file

@ -8,7 +8,7 @@ enum ast_redir_type
AST_REDIR_TYPE_NULL,
AST_REDIR_TYPE_LESS, // <
AST_REDIR_TYPE_GREAT, // >
AST_REDIR_TYPE_DLESS, // <<
AST_REDIR_TYPE_LESSGREAT, // <>
AST_REDIR_TYPE_DGREAT, // >>
AST_REDIR_TYPE_LESSAND, // <&
AST_REDIR_TYPE_GREATAND, // >&