- This program will (hopefully) be able to act as a simple shell to take in input, parse it, and run the appropriate commands.
We will use the Composite and Strategy Design Pattern to create
Command
objects that get parsed from user input. From user input, we put that into astringstream
, from that we read out each string (since it handles whitespace for us) we then construct eachCommand
object if it matches'ls', 'echo', or 'mkdir'
. After identifying the command, we read in any options, ie if the user wrote'ls -a'
we read in'ls'
and add'-a'
as an extra parameter to theCommand
object. The connectors are treated as a special type of 'command' a command that has twoCommand
object references, a left and right, and executes them based on the condition of the connector. For example, if we see a&&
we construct theCommand
objects for both the left and right side and then create aConnector
object that has a reference to both that then evaulates the left and if it succeeds, then it will evaluate the right side.
user_input
class that holds a queue<Commands*> and a List<Commands*> that saves a list of already run commandsCommand
's class that holds a status code for if it finished successfully or failed, as well as achar*
of arguments for the user optionscmd_ls
class that holds arguments to run/bin/ls
with itschar*
of argumentscmd_echo
class that holds arguments to runecho
since it is built into the shellcmd_mkdir
class that holds arguments to run/bin/mkdir
with itschar*
of arguments
Connector
that takes in two commands and resolves the conditionals ('||' or '&&'), evaulates both if ';' is present
-
parsing
- we used
getline()
to read in the user input and then threw that into a stringstream constructor, then iterate over it using a while loop, if it matchedls
then we usedfork()
to create a child, thenwaitpid()
to have the child executels
usingexecvp()
. We did not account for connectors yet.
- we used
-
waitpid(), execvp(), fork()
- at first, we used the string from the stream to run
execvp()
but ran into problems, so we had to usechar*
to get around the errors. As forwaitpid()
andfork()
, after reading the man pages, watching some youtube, and experimenting with different options, we were able to figure out how to use both functions. Thanks to stackoverflow for help on theexecvp()
part and some youtube videos on explaining how to usefork()
andwaitpid()
link here
- at first, we used the string from the stream to run
-
connectors
- we did not account for connectors yet but have used the bash shell enough to use them and understand how they work (for the most part). We ran the connector examples in the assignment document and compared the outputs to what we expected to happen, this gave us an idea on how to approach the design of our program and how we should treat user input and parse it in a way that made the most sense when it came time for the program to execute the commands.
- parser algorithm
- finalize, account for edge cases(empty, gibberish, comment(#), not existant command, multiple commands, complicated connector decomposition), test to see if recognizes all valid commands, once done testing move on
- command class
- write each command its own class to hold status and argument list and execute command function, test via parser to make sure parser can correctly take in user input and call the appropriate command class
- user_input class
- Parsing
- We parsed the string using the boost tokenizer. It took a while to learn how to implement the tokenizer, but it's really useful for trimming and dealing with the whitespace in the string.
- Composite Pattern
- We ran into a lot of issues while trying to implement the composite pattern, so we resorted to just figuring out a way to get the parser functioning. We will go back in assignment 3 and adjust the design of the program in order to fit the composite pattern.
- Noteable Challenges
- Errors were fairly difficult to fix in such a large program. Next time we are going to incrementally develop the program extension and make sure it compiles. Coding large sections without compiling makes it difficult to find the error(s). A lot of time was wasted due to this.
- The boost tokenizer took a while to figure out since we've never used it before, but it's a great tool!
- Milestones
- compiles
- single executables work i.e. ls, cd
- multiple commands work i.e. ls -la && echo Hello World
- integration tests finished
- unit test - parser passes 100% of 22 unique tests
- added postfix implementation
- Parsing
- Adjusted parser to account for parenthesis and brackets.
- Parenthesis: All parenthesis outside of comments or echo strings must have a matching closing/opening parenthesis.
- If parenthesis do not match, the parser stops and outputs an error and reprompts for the command.
- Brackets: All bracket outside of comments or echo strings must have a matching closing/opening bracket.
- Noteable Challenges
- Implemented R'Shell using the Composite pattern, postfix notation (also called Reverse Polish Notation), and a postfix tree.
- Parser has been tweaked and is more efficient now.
- Milestones
- Connectors work consistently now (Including parenthesis).
- Parenthesis work correctly and have been thoroughly tested with nested and non-nested parenthesis.
- Test commands have been implemented.
- Integration test bash script error fixed. It no longer hangs and gets trapped in R'Shell when executed.
- Starting thorough debugging process and code revision.
- 35 unique integration tests across 7 bash scripts
- 40 unique parser tests across 3 test files
- Parsing
- Adjusted parser to account for i/o redirection, appends, and pipes.
- Appends and pipes need extra conditions in our parser because they use the same characters as connectors such as 'or' and 'output redirection.'
- Noteable Challenges
- 4 new classes to handle i/o redirection, appends, and pipes.
- Minor parser changes to handle specific connectors i.e. 'or' and 'output redirection.'
- 4 new unit_test classes to test i/o redirection, appends, and pipes.
- Milestones
- Adjust parser to handle all connectors appropriately.
- Input and Output Redirection work now.
- Append functions properly.
- Pipe functions properly.
- Integration tests all written and pass.
- Unit tests for parser all written and pass.
- Final assignment completed.