-
Notifications
You must be signed in to change notification settings - Fork 0
/
AST.cpp
177 lines (147 loc) · 4.64 KB
/
AST.cpp
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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
#include "AST.hpp"
#include <string>
#include <sstream>
#include <memory>
#include <unistd.h>
#include <iostream>
int CommandNode::execute() {
if (args.empty())
// Nothing to do
return EXIT_SUCCESS;
std::vector<char *> c_args;
for (const auto &arg : args) {
c_args.push_back(const_cast<char *>(arg.c_str()));
}
// Add a null pointer to the end of the array (required by execvp)
c_args.push_back(nullptr);
// Fork a child process
pid_t pid = fork();
if (pid == -1) {
// Error
perror("fork failed");
return EXIT_FAILURE;
} else if (pid == 0) {
// Child process
execvp(c_args[0], c_args.data());
perror("execvp failed"); // execvp doesn't return unless it fails
exit(EXIT_FAILURE);
} else {
// Parent process
int status;
waitpid(pid, &status, WUNTRACED);
return status;
}
}
int BuiltinCommandNode::execute() {
if (args[0] == "cd") {
if (args.size() == 1) {
// No arguments to cd, go to home directory
chdir(getenv("HOME"));
} else if (args.size() == 2) {
if (chdir(args[1].c_str()) == EXIT_FAILURE) {
perror("cd failed");
}
} else {
perror("cd: too many arguments");
}
return EXIT_SUCCESS;
} else if (args[0] == "exit") {
return EXIT_SUCCESS;
}
return EXIT_FAILURE;
}
int AndNode::execute() {
int status = left->execute();
if (status == EXIT_SUCCESS) {
status = right->execute();
}
return status;
}
int OrNode::execute() {
int status = left->execute();
if (status != EXIT_SUCCESS) {
status = right->execute();
}
return status;
}
int PipelineNode::execute() {
int pipefd[2];
if (pipe(pipefd) == -1) {
perror("pipe failed");
return EXIT_FAILURE;
}
pid_t left_pid = fork();
if (left_pid == -1) {
perror("fork failed");
return EXIT_FAILURE;
} else if (left_pid == 0) {
// In the child process (left side of the pipeline)
close(pipefd[0]); // Close the unused read end
dup2(pipefd[1], STDOUT_FILENO); // Redirect stdout to the write end of the pipe
close(pipefd[1]); // Close the write end after it's duplicated
int status = left->execute();
exit(status); // Exit with the status from the left side command
}
// Only parent process should reach this code
pid_t right_pid = fork();
if (right_pid == -1) {
perror("fork failed");
return EXIT_FAILURE;
} else if (right_pid == 0) {
// In the child process (right side of the pipeline)
close(pipefd[1]); // Close the unused write end
dup2(pipefd[0], STDIN_FILENO); // Redirect stdin to the read end of the pipe
close(pipefd[0]); // Close the read end after it's duplicated
int status = right->execute();
exit(status); // Exit with the status from the right side command
}
// Only parent process should reach this code
close(pipefd[0]); // Parent doesn't use the read end
close(pipefd[1]); // Parent doesn't use the write end
int status;
waitpid(left_pid, &status, 0); // Wait for the left side to finish
waitpid(right_pid, &status, 0); // Then wait for the right side to finish
return status; // Return the status of the last command in the pipeline
}
int SequenceNode::execute() {
int status = left->execute();
status = right->execute();
return status;
}
int SubshellNode::execute() {
pid_t pid = fork();
if (pid == -1) {
perror("fork failed");
return EXIT_FAILURE;
} else if (pid == 0) {
// In the child process
int status = child->execute();
exit(status); // Exit with the status from the child
}
// Only parent process should reach this code
int status;
waitpid(pid, &status, 0); // Wait for the child to finish
return status;
}
int RedirectionNode::execute() {
std::cout << "RedirectionNode::execute() not implemented" << std::endl;
int status = child->execute();
return status;
}
int BackgroundNode::execute() {
std::cout << "BackgroundNode::execute() not implemented" << std::endl;
int status = child->execute();
return status;
}
int NegateNode::execute() {
int status = child->execute();
return !status;
}
int AssignmentNode::execute() {
std::cout << "AssignmentNode::execute() not implemented" << std::endl;
return EXIT_SUCCESS;
}
int CommandSubstitutionNode::execute() {
std::cout << "CommandSubstitutionNode::execute() not implemented" << std::endl;
return EXIT_SUCCESS;
}