feat(parser): redirections
This commit is contained in:
parent
04ff7376eb
commit
8a5c589742
17 changed files with 78 additions and 108 deletions
|
|
@ -25,7 +25,8 @@
|
||||||
|
|
||||||
// === Structures
|
// === Structures
|
||||||
|
|
||||||
enum rule {
|
enum rule
|
||||||
|
{
|
||||||
RULE_NULL = 0,
|
RULE_NULL = 0,
|
||||||
RULE_INPUT,
|
RULE_INPUT,
|
||||||
RULE_LIST,
|
RULE_LIST,
|
||||||
|
|
@ -43,8 +44,9 @@ enum rule {
|
||||||
NUMBER_OF_RULES
|
NUMBER_OF_RULES
|
||||||
};
|
};
|
||||||
|
|
||||||
struct firsts_list {
|
struct firsts_list
|
||||||
enum token_type* tokens; // Heap allocated array
|
{
|
||||||
|
enum token_type *tokens; // Heap allocated array
|
||||||
size_t list_length;
|
size_t list_length;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
|
||||||
#include "grammar_advanced.h"
|
#include "grammar_advanced.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
@ -8,7 +10,7 @@
|
||||||
|
|
||||||
static enum ast_redir_type redir_tok_to_ast_type(enum token_type tok_type)
|
static enum ast_redir_type redir_tok_to_ast_type(enum token_type tok_type)
|
||||||
{
|
{
|
||||||
switch(tok_type)
|
switch (tok_type)
|
||||||
{
|
{
|
||||||
case TOKEN_REDIR_LEFT:
|
case TOKEN_REDIR_LEFT:
|
||||||
return AST_REDIR_TYPE_LESS;
|
return AST_REDIR_TYPE_LESS;
|
||||||
|
|
@ -22,9 +24,6 @@ static enum ast_redir_type redir_tok_to_ast_type(enum token_type tok_type)
|
||||||
|
|
||||||
struct ast *parse_redirection(struct lexer_context *ctx)
|
struct ast *parse_redirection(struct lexer_context *ctx)
|
||||||
{
|
{
|
||||||
(void)ctx;
|
|
||||||
return NULL;
|
|
||||||
/*
|
|
||||||
struct token *token = PEEK_TOKEN();
|
struct token *token = PEEK_TOKEN();
|
||||||
int io_number = -1;
|
int io_number = -1;
|
||||||
if (token->type == TOKEN_IONUMBER)
|
if (token->type == TOKEN_IONUMBER)
|
||||||
|
|
@ -40,7 +39,6 @@ struct ast *parse_redirection(struct lexer_context *ctx)
|
||||||
"else");
|
"else");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
// char *redir_op = strdup(token->data);
|
|
||||||
|
|
||||||
enum ast_redir_type redir_type = redir_tok_to_ast_type(token->type);
|
enum ast_redir_type redir_type = redir_tok_to_ast_type(token->type);
|
||||||
POP_TOKEN();
|
POP_TOKEN();
|
||||||
|
|
@ -49,14 +47,12 @@ struct ast *parse_redirection(struct lexer_context *ctx)
|
||||||
if (token->type != TOKEN_WORD)
|
if (token->type != TOKEN_WORD)
|
||||||
{
|
{
|
||||||
perror("Syntax error: expected a word after redirection");
|
perror("Syntax error: expected a word after redirection");
|
||||||
// free(redir_op);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
char *target = strdup(token->data);
|
char *target = strdup(token->data);
|
||||||
POP_TOKEN();
|
POP_TOKEN();
|
||||||
|
|
||||||
return ast_create_redir(io_number, redir_type, target);
|
return ast_create_redir(target, io_number, redir_type);
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ast *parse_prefix(struct lexer_context *ctx)
|
struct ast *parse_prefix(struct lexer_context *ctx)
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,8 @@
|
||||||
/*
|
/*
|
||||||
* @brief parses a redirection rule
|
* @brief parses a redirection rule
|
||||||
*
|
*
|
||||||
* @code redirection = [IONUMBER] ( '>' | '<' | '>>' | '>&' | '<&' | '>|' | '<>' ) WORD ;
|
* @code redirection = [IONUMBER] ( '>' | '<' | '>>' | '>&' | '<&' | '>|' | '<>'
|
||||||
|
* ) WORD ;
|
||||||
*
|
*
|
||||||
* @first TOKEN_IONUMBER, TOKEN_REDIRECTION
|
* @first TOKEN_IONUMBER, TOKEN_REDIRECTION
|
||||||
*/
|
*/
|
||||||
|
|
@ -23,5 +24,4 @@ struct ast *parse_redirection(struct lexer_context *ctx);
|
||||||
*/
|
*/
|
||||||
struct ast *parse_prefix(struct lexer_context *ctx);
|
struct ast *parse_prefix(struct lexer_context *ctx);
|
||||||
|
|
||||||
|
|
||||||
#endif /* ! GRAMMAR_ADVANCED_H */
|
#endif /* ! GRAMMAR_ADVANCED_H */
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,14 @@
|
||||||
#include <stdbool.h>
|
|
||||||
#define _POSIX_C_SOURCE 200809L
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
|
||||||
|
#include "grammar_basic.h"
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "../utils/lists/lists.h"
|
#include "../utils/lists/lists.h"
|
||||||
#include "grammar.h"
|
#include "grammar.h"
|
||||||
#include "grammar_advanced.h"
|
#include "grammar_advanced.h"
|
||||||
#include "grammar_basic.h"
|
|
||||||
|
|
||||||
// === Static functions
|
// === Static functions
|
||||||
|
|
||||||
|
|
@ -398,7 +399,8 @@ struct ast *parse_else_clause(struct lexer_context *ctx)
|
||||||
token = POP_TOKEN();
|
token = POP_TOKEN();
|
||||||
if (token->type != TOKEN_THEN)
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,11 @@
|
||||||
#include "ast_end.h"
|
#include "ast_end.h"
|
||||||
#include "ast_if.h"
|
#include "ast_if.h"
|
||||||
#include "ast_list.h"
|
#include "ast_list.h"
|
||||||
|
#include "ast_neg.h"
|
||||||
|
#include "ast_pipe.h"
|
||||||
#include "ast_redir.h"
|
#include "ast_redir.h"
|
||||||
#include "ast_void.h"
|
#include "ast_void.h"
|
||||||
#include "ast_word.h"
|
#include "ast_word.h"
|
||||||
#include "ast_pipe.h"
|
|
||||||
#include "ast_neg.h"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prints the Graphviz DOT representation of the given AST to stdout.
|
* Prints the Graphviz DOT representation of the given AST to stdout.
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
#ifndef AST_BASE_H
|
#ifndef AST_BASE_H
|
||||||
#define AST_BASE_H
|
#define AST_BASE_H
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
enum ast_type
|
enum ast_type
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,12 @@
|
||||||
struct ast_neg
|
struct ast_neg
|
||||||
{
|
{
|
||||||
bool negation; // True negates the child's output
|
bool negation; // True negates the child's output
|
||||||
struct ast* child;
|
struct ast *child;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool ast_is_neg(struct ast *node);
|
bool ast_is_neg(struct ast *node);
|
||||||
struct ast_neg *ast_get_neg(struct ast *node);
|
struct ast_neg *ast_get_neg(struct ast *node);
|
||||||
struct ast *ast_create_neg(bool negation, struct ast* child);
|
struct ast *ast_create_neg(bool negation, struct ast *child);
|
||||||
void ast_free_neg(struct ast_neg* node);
|
void ast_free_neg(struct ast_neg *node);
|
||||||
|
|
||||||
#endif /* ! AST_NEG_H */
|
#endif /* ! AST_NEG_H */
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,14 @@
|
||||||
|
|
||||||
struct ast_pipe
|
struct ast_pipe
|
||||||
{
|
{
|
||||||
struct ast* left;
|
struct ast *left;
|
||||||
struct ast* right;
|
struct ast *right;
|
||||||
// Output of left will be redirected to right stdin
|
// Output of left will be redirected to right stdin
|
||||||
};
|
};
|
||||||
|
|
||||||
bool ast_is_pipe(struct ast *node);
|
bool ast_is_pipe(struct ast *node);
|
||||||
struct ast_pipe *ast_get_pipe(struct ast *node);
|
struct ast_pipe *ast_get_pipe(struct ast *node);
|
||||||
struct ast *ast_create_pipe(struct ast* left, struct ast* right);
|
struct ast *ast_create_pipe(struct ast *left, struct ast *right);
|
||||||
void ast_free_pipe(struct ast_pipe* node);
|
void ast_free_pipe(struct ast_pipe *node);
|
||||||
|
|
||||||
#endif /* ! AST_PIPE_H */
|
#endif /* ! AST_PIPE_H */
|
||||||
|
|
|
||||||
|
|
@ -14,13 +14,12 @@ struct ast_redir *ast_get_redir(struct ast *node)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ast *ast_create_redir(struct ast *child, char *filename, int io_number,
|
struct ast *ast_create_redir(char *filename, int io_number,
|
||||||
enum ast_redir_type type)
|
enum ast_redir_type type)
|
||||||
{
|
{
|
||||||
struct ast_redir *redir = malloc(sizeof(struct ast_redir));
|
struct ast_redir *redir = malloc(sizeof(struct ast_redir));
|
||||||
if (!redir)
|
if (!redir)
|
||||||
return NULL;
|
return NULL;
|
||||||
redir->child = child;
|
|
||||||
redir->filename =
|
redir->filename =
|
||||||
filename; // Takes ownership? Usually yes in simple ASTs, or dup. Let's
|
filename; // Takes ownership? Usually yes in simple ASTs, or dup. Let's
|
||||||
// assume pointer copy for now, but user must manage memory.
|
// assume pointer copy for now, but user must manage memory.
|
||||||
|
|
@ -34,7 +33,6 @@ void ast_free_redir(struct ast_redir *redir)
|
||||||
{
|
{
|
||||||
if (!redir)
|
if (!redir)
|
||||||
return;
|
return;
|
||||||
ast_free(&redir->child);
|
|
||||||
free(redir->filename);
|
free(redir->filename);
|
||||||
free(redir);
|
free(redir);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ enum ast_redir_type
|
||||||
|
|
||||||
struct ast_redir
|
struct ast_redir
|
||||||
{
|
{
|
||||||
struct ast *child;
|
|
||||||
char *filename;
|
char *filename;
|
||||||
int io_number; // The FD being redirected (default -1 if not specified,
|
int io_number; // The FD being redirected (default -1 if not specified,
|
||||||
// implies 0 or 1 based on type)
|
// implies 0 or 1 based on type)
|
||||||
|
|
@ -26,7 +25,7 @@ struct ast_redir
|
||||||
|
|
||||||
bool ast_is_redir(struct ast *node);
|
bool ast_is_redir(struct ast *node);
|
||||||
struct ast_redir *ast_get_redir(struct ast *node);
|
struct ast_redir *ast_get_redir(struct ast *node);
|
||||||
struct ast *ast_create_redir(struct ast *child, char *filename, int io_number,
|
struct ast *ast_create_redir(char *filename, int io_number,
|
||||||
enum ast_redir_type type);
|
enum ast_redir_type type);
|
||||||
void ast_free_redir(struct ast_redir *redir);
|
void ast_free_redir(struct ast_redir *redir);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
#define _POSIX_C_SOURCE 200809L
|
#define _POSIX_C_SOURCE 200809L
|
||||||
#include "ast_word.h"
|
#include "ast_word.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
|
@ -17,6 +17,7 @@ struct ast *ast_create_word(char *word)
|
||||||
struct ast *res = ast_create(AST_WORD, ast_node);
|
struct ast *res = ast_create(AST_WORD, ast_node);
|
||||||
if (res == NULL)
|
if (res == NULL)
|
||||||
{
|
{
|
||||||
|
free(ast_node->word);
|
||||||
free(ast_node);
|
free(ast_node);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ struct ast_word *ast_get_word(struct ast *node);
|
||||||
/**
|
/**
|
||||||
* Creates a new AST node representing a command.
|
* Creates a new AST node representing a command.
|
||||||
*/
|
*/
|
||||||
struct ast *ast_create_word(char* word);
|
struct ast *ast_create_word(char *word);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @brief: frees the given ast_command and sets the pointer to NULL.
|
* @brief: frees the given ast_command and sets the pointer to NULL.
|
||||||
|
|
|
||||||
|
|
@ -9,27 +9,19 @@ TestSuite(IO_Backend);
|
||||||
|
|
||||||
Test(IO_Backend, init_null)
|
Test(IO_Backend, init_null)
|
||||||
{
|
{
|
||||||
struct iob_context ctx =
|
struct iob_context ctx = { .mode = IOB_MODE_NULL, .args = NULL };
|
||||||
{
|
|
||||||
.mode = IOB_MODE_NULL,
|
|
||||||
.args = NULL
|
|
||||||
};
|
|
||||||
int actual = iob_init(&ctx);
|
int actual = iob_init(&ctx);
|
||||||
int expected = IOB_ERROR_BAD_ARG;
|
int expected = IOB_ERROR_BAD_ARG;
|
||||||
cr_expect(actual == expected, "Expected: %d. Got: %d", expected, actual);
|
cr_expect(actual == expected, "Expected: %d. Got: %d", expected, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
Test(IO_Backend, init_stdin)
|
Test(IO_Backend, init_stdin)
|
||||||
{
|
{
|
||||||
struct iob_context ctx =
|
struct iob_context ctx = { .mode = IOB_MODE_STDIN, .args = NULL };
|
||||||
{
|
|
||||||
.mode = IOB_MODE_STDIN,
|
|
||||||
.args = NULL
|
|
||||||
};
|
|
||||||
int actual = iob_init(&ctx);
|
int actual = iob_init(&ctx);
|
||||||
int expected = 0;
|
int expected = 0;
|
||||||
cr_expect(actual == expected, "Expected: %d. Got: %d", expected, actual);
|
cr_expect(actual == expected, "Expected: %d. Got: %d", expected, actual);
|
||||||
iob_close();
|
iob_close();
|
||||||
}
|
}
|
||||||
|
|
||||||
// WARNING: this one could fail because of iob_close in the previous test
|
// WARNING: this one could fail because of iob_close in the previous test
|
||||||
|
|
@ -37,82 +29,62 @@ iob_close();
|
||||||
Test(IO_Backend, init_script)
|
Test(IO_Backend, init_script)
|
||||||
{
|
{
|
||||||
char *script_name = "script.tmp";
|
char *script_name = "script.tmp";
|
||||||
struct iob_context ctx = {
|
struct iob_context ctx = { .mode = IOB_MODE_SCRIPT, .args = script_name };
|
||||||
.mode = IOB_MODE_SCRIPT,
|
|
||||||
.args = script_name
|
|
||||||
};
|
|
||||||
// Create file
|
// Create file
|
||||||
FILE *f = fopen(script_name, "w");
|
FILE *f = fopen(script_name, "w");
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
int actual = iob_init(&ctx);
|
int actual = iob_init(&ctx);
|
||||||
int expected = 0;
|
int expected = 0;
|
||||||
cr_expect(actual == expected, "Expected: %d. Got: %d", expected, actual);
|
cr_expect(actual == expected, "Expected: %d. Got: %d", expected, actual);
|
||||||
iob_close();
|
iob_close();
|
||||||
remove(script_name);
|
remove(script_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
Test(IO_Backend, init_script_not_a_file)
|
Test(IO_Backend, init_script_not_a_file)
|
||||||
{
|
{
|
||||||
char *script_name = "not_a_file.tmp";
|
char *script_name = "not_a_file.tmp";
|
||||||
struct iob_context ctx = {
|
struct iob_context ctx = { .mode = IOB_MODE_SCRIPT, .args = script_name };
|
||||||
.mode = IOB_MODE_SCRIPT,
|
|
||||||
.args = script_name
|
|
||||||
};
|
|
||||||
int actual = iob_init(&ctx);
|
int actual = iob_init(&ctx);
|
||||||
int expected = IOB_ERROR_CANNOT_OPEN_FILE;
|
int expected = IOB_ERROR_CANNOT_OPEN_FILE;
|
||||||
cr_expect(actual == expected, "Expected: %d. Got: %d", expected, actual);
|
cr_expect(actual == expected, "Expected: %d. Got: %d", expected, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
Test(IO_Backend, init_script_null)
|
Test(IO_Backend, init_script_null)
|
||||||
{
|
{
|
||||||
struct iob_context ctx =
|
struct iob_context ctx = { .mode = IOB_MODE_SCRIPT, .args = NULL };
|
||||||
{
|
|
||||||
.mode = IOB_MODE_SCRIPT,
|
|
||||||
.args = NULL
|
|
||||||
};
|
|
||||||
int actual = iob_init(&ctx);
|
int actual = iob_init(&ctx);
|
||||||
int expected = IOB_ERROR_CANNOT_OPEN_FILE;
|
int expected = IOB_ERROR_CANNOT_OPEN_FILE;
|
||||||
cr_expect(actual == expected, "Expected: %d. Got: %d", expected, actual);
|
cr_expect(actual == expected, "Expected: %d. Got: %d", expected, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
Test(IO_Backend, init_cmd)
|
Test(IO_Backend, init_cmd)
|
||||||
{
|
{
|
||||||
char *cmd = "iamacommand --yesido";
|
char *cmd = "iamacommand --yesido";
|
||||||
struct iob_context ctx = {
|
struct iob_context ctx = { .mode = IOB_MODE_CMD, .args = cmd };
|
||||||
.mode = IOB_MODE_CMD,
|
|
||||||
.args = cmd
|
|
||||||
};
|
|
||||||
int actual = iob_init(&ctx);
|
int actual = iob_init(&ctx);
|
||||||
int expected = 0;
|
int expected = 0;
|
||||||
cr_expect(actual == expected, "Expected: %d. Got: %d", expected, actual);
|
cr_expect(actual == expected, "Expected: %d. Got: %d", expected, actual);
|
||||||
iob_close();
|
iob_close();
|
||||||
}
|
}
|
||||||
|
|
||||||
Test(IO_Backend, init_cmd_null)
|
Test(IO_Backend, init_cmd_null)
|
||||||
{
|
{
|
||||||
struct iob_context ctx =
|
struct iob_context ctx = { .mode = IOB_MODE_CMD, .args = NULL };
|
||||||
{
|
|
||||||
.mode = IOB_MODE_CMD,
|
|
||||||
.args = NULL
|
|
||||||
};
|
|
||||||
int actual = iob_init(&ctx);
|
int actual = iob_init(&ctx);
|
||||||
int expected = IOB_ERROR_BAD_ARG;
|
int expected = IOB_ERROR_BAD_ARG;
|
||||||
cr_expect(actual == expected, "Expected: %d. Got: %d", expected, actual);
|
cr_expect(actual == expected, "Expected: %d. Got: %d", expected, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
Test(IO_Backend, init_already_init)
|
Test(IO_Backend, init_already_init)
|
||||||
{
|
{
|
||||||
char *cmd = "iamacommand --yesido";
|
char *cmd = "iamacommand --yesido";
|
||||||
struct iob_context ctx = {
|
struct iob_context ctx = { .mode = IOB_MODE_CMD, .args = cmd };
|
||||||
.mode = IOB_MODE_CMD,
|
|
||||||
.args = cmd
|
|
||||||
};
|
|
||||||
iob_init(&ctx);
|
iob_init(&ctx);
|
||||||
int actual = iob_init(&ctx);
|
int actual = iob_init(&ctx);
|
||||||
int expected = IOB_ERROR_MODULE_ALREADY_INITIALIZED;
|
int expected = IOB_ERROR_MODULE_ALREADY_INITIALIZED;
|
||||||
cr_expect(actual == expected, "Expected: %d. Got: %d", expected, actual);
|
cr_expect(actual == expected, "Expected: %d. Got: %d", expected, actual);
|
||||||
iob_close();
|
iob_close();
|
||||||
}
|
}
|
||||||
|
|
||||||
Test(IO_Backend, close_not_init)
|
Test(IO_Backend, close_not_init)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue