1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
|
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* parser.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: nahaddac <nahaddac@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2020/06/17 18:09:04 by nahaddac #+# #+# */
/* Updated: 2020/10/10 18:38:37 by charles ### ########.fr */
/* */
/* ************************************************************************** */
/*
** \file parse.c
** \brief Parser
*/
#include "minishell.h"
#include "parser.h"
static char *g_sep_str_lookup[] = {
[TAG_END] = ";",
[TAG_OR] = "||",
[TAG_REDIR_IN] = "<",
[TAG_REDIR_APPEND] = ">>",
[TAG_PARENT_CLOSE] = ")",
[TAG_AND] = "&&",
[TAG_PIPE] = "|",
[TAG_REDIR_OUT] = ">",
[TAG_PARENT_OPEN] = "(",
};
t_parsed *destroy_ret(t_parsed *destroyed, t_parsed *ret)
{
parsed_destroy(destroyed);
return (ret);
}
/*
** \brief Parse a expression pipeline
** \param input Input tokens
** \return Parsed containning a pipeline of expression
** Parsed error if a pipe is missing
** or the expression parser return an error
*/
t_parsed *parse_pipeline(t_tok_lst *input)
{
t_parsed *expr;
t_parsed *tail;
t_ast *expr_ast;
t_ast *pipeline_ast;
expr = parse_expr(input);
if (parsed_check(expr) || expr->rest == NULL || expr->rest->tag != TAG_PIPE)
return (expr);
tok_lst_pop_front(&expr->rest, free);
if (expr->rest == NULL)
return (destroy_ret(expr, parsed_expected()));
if (parsed_check(tail = parse_pipeline(expr->rest)))
return (destroy_ret(expr, tail));
expr_ast = expr->ast;
free(expr);
if (tail->ast->tag == AST_CMD || tail->ast->tag == AST_PARENT)
{
pipeline_ast = ast_new(AST_PIPELINE);
exit_if((pipeline_ast->pipeline = ft_lstnew(tail->ast)) == NULL);
}
else
pipeline_ast = tail->ast;
exit_if(ft_lstpush_front_node(&pipeline_ast->pipeline, expr_ast) == NULL);
tail->ast = pipeline_ast;
return (tail);
}
/*
** \brief Build a operation AST node from left, right components
** and a separator tag
** \param left Left hand side of the operation
** \param right Right hand side of the operation
** \param sep_tag Separator tag of the operation
** \return Parsed containning an operation AST
*/
static t_parsed *st_parse_op_build(
t_parsed *left, t_parsed *right, enum e_tok sep_tag)
{
t_ast *ast;
exit_if((ast = ast_new(AST_OP)) == NULL);
ast->op.left = left->ast;
ast->op.right = right->ast;
ast->op.sep = sep_tag;
left->rest = right->rest;
left->ast = ast;
free(right);
return (left);
}
/*
** \brief Parse an operation (&&, ||, ;)
** \param input Input tokens
** \return Parsed containning an operation AST
** Parsed error if separator isn't valid
** or left/right parser failed
*/
t_parsed *parse_op(t_tok_lst *input)
{
t_parsed *left;
t_parsed *right;
enum e_tok sep_tag;
if (input == NULL)
return (NULL);
if (parsed_check(left = parse_pipeline(input)))
return (left);
if ((input = left->rest) == NULL || input->tag & TAG_PARENT_CLOSE)
return (left);
if (!((sep_tag = input->tag) & TAG_IS_SEP))
{
tok_lst_destroy(&left->rest, free);
parsed_destroy(left);
return (parsed_unexpected(g_sep_str_lookup[sep_tag]));
}
tok_lst_pop_front(&input, free);
if (input == NULL && sep_tag == TAG_END)
return ((left->rest = NULL) ? left : left);
if (input == NULL)
return (destroy_ret(left, parsed_expected()));
right = parse_op(input);
if (parsed_check(right))
return (destroy_ret(left, right));
return (st_parse_op_build(left, right, sep_tag));
}
/*
** \brief Parse the lexer output into an AST
** \param input Lexer output, a list of tokens
** \return Parsed containning the AST to evaluate
** Parsed error if one of the parser failed
*/
t_parsed *parse(t_tok_lst *input)
{
t_parsed *parsed;
t_parsed *ret;
if (input == NULL)
return (NULL);
parsed = parse_op(input);
if (parsed_check(parsed))
return (parsed);
if (parsed->rest != NULL)
{
ret = parsed_unexpected(parsed->rest->content);
tok_lst_destroy(&parsed->rest, free);
ast_destroy(parsed->ast);
free(parsed);
return (ret);
}
return (parsed);
}
|