Merge branch 'parser' into dev
This commit is contained in:
commit
0d425aa44c
6 changed files with 124 additions and 67 deletions
|
|
@ -121,7 +121,7 @@ static int get_fd_target(const struct ast_redir *redir)
|
||||||
if (redir->io_number != -1)
|
if (redir->io_number != -1)
|
||||||
return redir->io_number;
|
return redir->io_number;
|
||||||
if (redir->type == AST_REDIR_TYPE_LESS
|
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)
|
|| redir->type == AST_REDIR_TYPE_LESSAND)
|
||||||
return 0;
|
return 0;
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,16 @@ static enum ast_redir_type redir_tok_to_ast_type(enum token_type tok_type)
|
||||||
return AST_REDIR_TYPE_LESS;
|
return AST_REDIR_TYPE_LESS;
|
||||||
case TOKEN_REDIR_RIGHT:
|
case TOKEN_REDIR_RIGHT:
|
||||||
return AST_REDIR_TYPE_GREAT;
|
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:
|
default:
|
||||||
return AST_REDIR_TYPE_NULL;
|
return AST_REDIR_TYPE_NULL;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -152,14 +152,15 @@ struct ast *parse_pipeline(struct lexer_context *ctx)
|
||||||
struct ast *parse_command(struct lexer_context *ctx)
|
struct ast *parse_command(struct lexer_context *ctx)
|
||||||
{
|
{
|
||||||
struct token *token = PEEK_TOKEN();
|
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
|
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 ast *parse_simple_command(struct lexer_context *ctx)
|
||||||
{
|
{
|
||||||
struct list *command_elements = NULL;
|
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)
|
if (token->type != TOKEN_WORD)
|
||||||
{
|
{
|
||||||
perror("Expected a command but got a different token type");
|
if (!has_prefix)
|
||||||
return NULL;
|
{
|
||||||
|
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);
|
else
|
||||||
command_elements = list_append(command_elements, command);
|
|
||||||
|
|
||||||
token = PEEK_TOKEN();
|
|
||||||
|
|
||||||
// Eventual elements
|
|
||||||
while (is_first(*token, RULE_ELEMENT))
|
|
||||||
{
|
{
|
||||||
// Get element
|
if (token->type == TOKEN_WORD)
|
||||||
struct ast *element = parse_element(ctx);
|
|
||||||
if (element == NULL)
|
|
||||||
{
|
{
|
||||||
list_deep_destroy(command_elements);
|
char *command = strdup(token->data);
|
||||||
return NULL;
|
command_elements = list_append(command_elements, command);
|
||||||
}
|
|
||||||
|
|
||||||
// Get element type
|
POP_TOKEN();
|
||||||
if (ast_is_word(element))
|
token = PEEK_TOKEN();
|
||||||
{
|
|
||||||
struct ast_word *element_word = ast_get_word(element);
|
|
||||||
command_elements =
|
|
||||||
list_append(command_elements, element_word->word);
|
|
||||||
}
|
}
|
||||||
else if (ast_is_redir(element))
|
// Eventual elements
|
||||||
|
while (is_first(*token, RULE_ELEMENT))
|
||||||
{
|
{
|
||||||
// TODO
|
// Get element
|
||||||
perror("NOT IMPLEMENTED");
|
struct ast *element = parse_element(ctx);
|
||||||
return NULL;
|
if (element == NULL)
|
||||||
}
|
{
|
||||||
else
|
return err_simple_command(command_elements, redirections);
|
||||||
{
|
}
|
||||||
perror("Internal error: unexpected return value from parse_element "
|
|
||||||
"in parse_simple_command");
|
|
||||||
list_deep_destroy(command_elements);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Forward
|
// Get element type
|
||||||
token = PEEK_TOKEN();
|
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
|
// Result
|
||||||
struct ast *result = ast_create_command(command_elements);
|
struct ast *result = ast_create_command(command_elements, redirections);
|
||||||
if (result == NULL)
|
if (result == NULL)
|
||||||
{
|
{
|
||||||
list_deep_destroy(command_elements);
|
return err_simple_command(command_elements, redirections);
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
@ -254,6 +293,17 @@ struct ast *parse_shell_command(struct lexer_context *ctx)
|
||||||
return parse_if_rule(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)
|
struct ast *parse_if_rule(struct lexer_context *ctx)
|
||||||
{
|
{
|
||||||
// If keyword
|
// If keyword
|
||||||
|
|
@ -272,38 +322,34 @@ struct ast *parse_if_rule(struct lexer_context *ctx)
|
||||||
token = POP_TOKEN();
|
token = POP_TOKEN();
|
||||||
if (token->type != TOKEN_THEN)
|
if (token->type != TOKEN_THEN)
|
||||||
{
|
{
|
||||||
ast_free(&condition_content);
|
|
||||||
perror("Expected the 'then' keyword but token has different type");
|
perror("Expected the 'then' keyword but token has different type");
|
||||||
return NULL;
|
return err_if_rule(&condition_content, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Then content
|
// Then content
|
||||||
struct ast *then_content = parse_compound_list(ctx);
|
struct ast *then_content = parse_compound_list(ctx);
|
||||||
if (then_content == NULL)
|
if (then_content == NULL)
|
||||||
{
|
{
|
||||||
ast_free(&condition_content);
|
return err_if_rule(&condition_content, &then_content, NULL);
|
||||||
ast_free(&then_content);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ast *else_content = NULL;
|
||||||
// Eventual else/elif clause(s)
|
// Eventual else/elif clause(s)
|
||||||
struct ast *else_content = parse_else_clause(ctx);
|
if (is_first(*token, RULE_ELSE_CLAUSE))
|
||||||
if (else_content == NULL)
|
|
||||||
{
|
{
|
||||||
ast_free(&condition_content);
|
else_content = parse_else_clause(ctx);
|
||||||
ast_free(&then_content);
|
if (else_content == NULL)
|
||||||
return NULL;
|
{
|
||||||
|
return err_if_rule(&condition_content, &then_content, NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fi keyword
|
// Fi keyword
|
||||||
token = POP_TOKEN();
|
token = POP_TOKEN();
|
||||||
if (token->type != TOKEN_FI)
|
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");
|
perror("Expected the 'fi' keyword but token has different type");
|
||||||
return NULL;
|
return err_if_rule(&condition_content, &then_content, &else_content);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Result
|
// Result
|
||||||
|
|
@ -311,11 +357,8 @@ struct ast *parse_if_rule(struct lexer_context *ctx)
|
||||||
ast_create_if(condition_content, then_content, else_content);
|
ast_create_if(condition_content, then_content, else_content);
|
||||||
if (result == NULL)
|
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)");
|
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;
|
return result;
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,15 @@
|
||||||
|
|
||||||
#include "../lists/lists.h"
|
#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));
|
struct ast_command *command_data = malloc(sizeof(struct ast_command));
|
||||||
if (!command_data)
|
if (!command_data)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
command_data->command = command;
|
command_data->command = command;
|
||||||
|
command_data->redirections = redirections;
|
||||||
|
|
||||||
return ast_create(AST_CMD, command_data);
|
return ast_create(AST_CMD, command_data);
|
||||||
}
|
}
|
||||||
|
|
@ -33,5 +35,6 @@ void ast_free_command(struct ast_command *command_data)
|
||||||
if (command_data == NULL)
|
if (command_data == NULL)
|
||||||
return;
|
return;
|
||||||
list_deep_destroy(command_data->command);
|
list_deep_destroy(command_data->command);
|
||||||
|
ast_list_deep_destroy(command_data->redirections);
|
||||||
free(command_data);
|
free(command_data);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
struct ast_command
|
struct ast_command
|
||||||
{
|
{
|
||||||
struct list *command; // A list of words (char*)
|
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.
|
* 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.
|
* @brief: frees the given ast_command and sets the pointer to NULL.
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ enum ast_redir_type
|
||||||
AST_REDIR_TYPE_NULL,
|
AST_REDIR_TYPE_NULL,
|
||||||
AST_REDIR_TYPE_LESS, // <
|
AST_REDIR_TYPE_LESS, // <
|
||||||
AST_REDIR_TYPE_GREAT, // >
|
AST_REDIR_TYPE_GREAT, // >
|
||||||
AST_REDIR_TYPE_DLESS, // <<
|
AST_REDIR_TYPE_LESSGREAT, // <>
|
||||||
AST_REDIR_TYPE_DGREAT, // >>
|
AST_REDIR_TYPE_DGREAT, // >>
|
||||||
AST_REDIR_TYPE_LESSAND, // <&
|
AST_REDIR_TYPE_LESSAND, // <&
|
||||||
AST_REDIR_TYPE_GREATAND, // >&
|
AST_REDIR_TYPE_GREATAND, // >&
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue