diff --git a/Makefile b/Makefile
index 410968a..7bc54f5 100644
--- a/Makefile
+++ b/Makefile
@@ -6,8 +6,13 @@
# make run: TO run the compiled binary files
# make clean: TO delete all the built binary files.
+#~~~~~~~~~~~~~~~~~~Libraries~~~~~~~~~~~~~~~~~~~~~~~~~#
+# Install readline library: sudo apt-get install libreadline6 libreadline6-dev
+# Install boost library: sudo apt-get install libboost-all-dev
+
#~~~~~~~~~~~~~~~~~~VARIABLES~~~~~~~~~~~~~~~~~~~~~~~~~#
-CC = g++
+CC = g++ -std=c++11
+# -std=c++11 This flag provides C++11 support in the g++ compiler
CFLAGS = -c -Wall
# argument Wall is used for giving warnings
@@ -15,13 +20,17 @@ CFLAGS = -c -Wall
a: all
run: all
./all
-all: main.o lexical.o syntax_analyser.o
- $(CC) main.o lexical.o syntax_analyser.o -o all -lboost_system -lboost_filesystem
+all: main.o parser.o lexical.o syntax_analyser.o processCtrl.o
+ $(CC) main.o parser.o lexical.o syntax_analyser.o processCtrl.o -o all -lboost_system -lboost_filesystem -lreadline
main.o: main.cpp
$(CC) $(CFLAGS) main.cpp
+parser.o: parser.cpp
+ $(CC) $(CFLAGS) parser.cpp
lexical.o: lexical.cpp
$(CC) $(CFLAGS) lexical.cpp
syntax_analyser.o: syntax_analyser.cpp
$(CC) $(CFLAGS) syntax_analyser.cpp
+processCtrl.o: processCtrl.cpp
+ $(CC) $(CFLAGS) processCtrl.cpp
clean:
rm -rf *o all
\ No newline at end of file
diff --git a/README.md b/README.md
index eace353..68ecbd5 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,93 @@
-# Shell-Development-Project
-This project contains C++ code for the creation of a unix shell. The shell will most likely be a subset of the BASH.
-Please refer the PDF included with other files to understand what shell really is, and what does it comprise of.
-More content will be added as the project advances.
+
+# Abstract
+ Most useful interaction with a UNIX system occurs through the shell. Using a series of easy to remember and
+ simple commands, one can navigate the UNIX file system and issue commands to perform a wide variety of tasks.
+ Even though it may appear simple, the shell encapsulates many significant components of the operating system.
+# Introduction
+ This project aims to create a command line interface that provides almost every functionality provided by the
+ BASH and look forward to implementing minute tweaks and quick fixes that can influence its performance in terms
+ of memory utilization, execution time and error handling. Moreover, the implementation methods make use of new
+ styles and libraries.
+ This includes implementation of concepts of Compiler Design (lexical analysis, syntax analysis, error handling)
+ amalgamated with the concepts of process creation and control in Unix Systems.
+ The project aims to make the shell more memory-efficient by making use of C++ Boost:: Filesystem Library that
+ enables Directory Traversal and implementation of Change Directory command (cd) in the Unix Environment. Also,
+ a new method of constructing SLR (1) parsing table has been improvised, this reduces the wastage of memory
+ caused using conventional Sparse Matrix Method.
+ Hence, the newly developed shell has been named BISHOP (Boost Implemented OPerational SHell).
+
+
Implementation Details
+
+# Environment:
+ The shell maintains many variables which allow the user to maintain settings and easily navigate the filesystem.
+ Two of these that are particularly important are the current working directory and the PATH. As its name implies,
+ the current working directory variable keeps track of the user's current directory. The kernel searches in the
+ directories specified by the PATH variable starting with the leftmost directory first.
+ Bishop’s environment uses Boost filesystem Library to check the user’s pwd (Present Working Directory) and
+ execute cd (change Directory) command effectively. Also, the program code makes use of C’s readline library
+ for text completion functionalities originally provided in the BASH.
+
+# Command Analysis:
+ Bishop parses the user input command by performing SLR (1) syntax analysis. The LR (k)-method uses two tables,
+ which describe the behavior of a push-down automaton, used during the parsing process. These two tables,
+ called action table and goto table, are sparse tables. Moreover, the data in them are not homogeneous in
+ structure since both item numbers and right sides of productions are stored.
+ I referred a paper which proposes: a new parsing table structure, which is dense and homogeneous; a parsing
+ algorithm; and an algorithm for generation of this table, based on the SLR (1)-method.
+
+
+
+The proposed parsing table structure has 4 attributes:
+- CurrentItem - the LR (0)-Item on the top the of stack
+- NextSymbol - the next symbol from the input queue
+- Result - an integer whose meaning depends on the value of the attribute Action
+- Action - if action is ‘S’, then Result contains the number of a LR(0)-Item; if action is ‘R’, then Result contains the number of a production; if action is ‘A’, then the input queue is recognized as true.
+
+# Pipelining:
+ UNIX provides a variety of useful programs for use (grep, ls, echo, to name a few).
+ Like instructions in C++, these programs tend to be quite effective at doing one specific thing
+ (Such as grep: searching text, ls: printing directories, and echo: printing text to the console).
+ However, programmers/OS users would like to accomplish large tasks consisting of many individual
+ operations. Doing such requires using results from previous steps in order to complete a larger
+ problem. Bishop supports this through the pipe operation (represented by the character |) just
+ like the BASH using Unix System calls (dup2(int oldfd, int newfd)).
+ A pipe in between two commands causes the standard output of one to be redirected into the standard
+ input of another. An example of this is provided below, using the pipe operation to search for all
+ processes with the name under root user:
+ ps auxx | grep “root”
+# Process Control:
+ Bishop uses the conventional methods of process creation and execution in Unix/Linux (fork () and execvp ()
+ system calls) aided by different implementation techniques like C++ STL (Standard Template Library) classes:
+ std::string and std::vector.
+- fork ():
+Every other process in the system is brought to life through a call to the fork () system call. A process calling fork is copied by the kernel. At this point, the process that called fork is known as the parent, and the newly created process is known as the child since the parent process caused the child to be created. The newly created process is essentially exactly the same as the parent, even having the exact same variables and open _les. Fork is unique in that it is called once by the parent process and returns twice (to the parent and child separately).
+To the parent, fork returns the process id (PID) of the newly created child. To the child, fork returns 0. If the call fails entirely, -1 is returned to the parent, and no child is created.
+
+For more information about fork, see its manpage by calling man 2 fork.
+
+- exec ():
+UNIX provides a function, known as exec, which allows programmer to change a process's address space in order to run an entirely new program. Running an exec command deletes the existing text, data, and stack segments of the existing process and replaces them with those of a new program.
+The system call interface provides a total of six different variations of the exec function which differ only on how they handle input arguments. This means that only one system call (usually execve ()) is actually required to be implemented. The other functions are stubs which perform necessary preparations and then eventually call execve.
+
+Bishop uses execvp (const char *file, char *const argv[]) system call as it maintains a vector of command input strings.
+
+# References:
+- Linux Lectures by Dr. B Frazer
+https://www.youtube.com/watch?v=9seb8hddeK4&index=2&t=7s&list=LLDUlQqsRbRzlDdJlyERjLBw
+- Pipes Lectures
+https://www.youtube.com/watch?v=uHH7nHkgZ4w
+- Machine Problem 4: The UNIX Shell, PDF- Texas A&M University
+- Stevens, W. Richard. Advanced Programming in the UNIX Environment
+- Linux System Programming: Talking Directly to the Kernel and C Library, Author: Robert Love
+- Parsing table structure and algorithm for the LR(k) parsing Method
+ BY: ILTSCHEV, V[elko] I[vanov]
+ [New LR Parsing method.pdf](https://github.com/Akashi96/High-Performance-Linked-Lists/files/1309805/New.LR.Parsing.method.pdf)
+# Necessary Installations:
+- C++ Boost Library:
+ sudo apt-get install libboost-all-dev
+- C Readline Library:
+ sudo apt-get install libreadline6 libreadline6-dev
+
+
+
-We hope we will be able to complete it in time. :)
diff --git a/a.out b/a.out
deleted file mode 100755
index 4faa47c..0000000
Binary files a/a.out and /dev/null differ
diff --git a/all b/all
index aa55663..e999460 100755
Binary files a/all and b/all differ
diff --git a/lexical.cpp b/lexical.cpp
index ff40467..4350c4e 100644
--- a/lexical.cpp
+++ b/lexical.cpp
@@ -20,13 +20,12 @@ int validateCmd(string cmd)
return 1;
}
boost::filesystem::path pathToBin("/bin/" + cmd);
- cout << "path=" << pathToBin << "\n";
- if (boost::filesystem::exists(pathToBin))
- {
- cout << "valid command";
- }
- else
- cout << "invalid command";
+ boost::filesystem::path pathToBin2("/usr/bin/" + cmd);
+ boost::filesystem::path pathToBin3("/usr/share/applications" + cmd);
+
+ // cout << "path=" << pathToBin << "\n";
+ if (! boost::filesystem::exists(pathToBin) && ! boost::filesystem::exists(pathToBin2) && ! boost::filesystem::exists(pathToBin3))
+ throw std::runtime_error(cmd + ": command not found");
return 0;
}
@@ -55,7 +54,8 @@ int validateDir(string dir)
// cout << "changed current path:" << boost::filesystem::current_path() <': return "";
break;
- case '&': return "";
+ case '&': if (testCmd[1] == ' ')
+ return "";
+ if (testCmd[1] == '&')
+ return "<&&>";
+ else
+ return "";
break;
case '/': return "";
@@ -118,7 +123,7 @@ int substrPos(string cmd, int it, int &strStartPos, int &strEndPos)
}
return 0;
}
-int cmdLexicalAnalysis(string cmd, string &tokenStream)
+int cmdLexicalAnalysis(string cmd, std::vector & tokenStream, std::vector & tokens, int& pipeCount)
{
int strStartPos, strEndPos, strLength, mark, commandTurn = 1, dirArg = 0;//strStartPos: Stores the index value of space before a token.
// srtEndPos: Stores the index value of space after a token.
@@ -181,11 +186,14 @@ int cmdLexicalAnalysis(string cmd, string &tokenStream)
if (dirArg == 1)
token = "";
}
- if (token == "")
+ if (token == "" || token == "<&&>")
+ {
commandTurn++;
-
- tokenStream.append(token);
- cout << "tokenStream" << tokenStream << endl;
+ if (token == "")
+ pipeCount++;
+ }
+ tokenStream.push_back(token);
+ tokens.push_back(strdup(subString.c_str()));
}
return 0;
-}
+}
\ No newline at end of file
diff --git a/lexical.h b/lexical.h
index 1bdef14..1ab9f6f 100644
--- a/lexical.h
+++ b/lexical.h
@@ -5,7 +5,7 @@
using namespace std;
string lexems(string testCmd);
-int cmdLexicalAnalysis(string cmd, string &tokenStream);
+int cmdLexicalAnalysis(string cmd, std::vector &tokenStream, std::vector &tokens, int& pipeCount);
int cmdSyntaxAnalysis(string cmd);
int substrPos(string cmd, int it, int &strStartPos, int &strEndpos);
int validateDir(string dir);
diff --git a/lexical.o b/lexical.o
index 34e9ed1..fe76e32 100644
Binary files a/lexical.o and b/lexical.o differ
diff --git a/main.cpp b/main.cpp
old mode 100644
new mode 100755
index f519185..e6351e2
--- a/main.cpp
+++ b/main.cpp
@@ -21,32 +21,143 @@
#include
#include
#include
+#include
+#include
#include
#include
//User Defined #INCLUDES
#include "lexical.h"
-
+// #include "termcolor.hpp"
using namespace std;
+/*
+ANSI colour codes.
+**Note that not all terminals support this; if colour sequences are not supported, garbage will show up.**
+
+Example:
+
+cout << "\033[1;31mbold red text\033[0m\n";
+Here, \033 is the ESC character, ASCII 27. It is followed by [, then zero or more numbers separated by ;,
+and finally the letter m. The numbers describe the colour and format to switch to from that point onwards.
+
+The codes for foreground and background colours are:
+____________________________________
+
+ foreground background
+
+black 30 40
+red 31 41
+green 32 42
+yellow 33 43
+blue 34 44
+magenta 35 45
+cyan 36 46
+white 37 47
+_____________________________________
+Additionally, we can use these:
+_________________________________________________________________
+
+reset 0 (everything back to normal)
+bold/bright 1 (often a brighter shade of the same colour)
+underline 4
+inverse 7 (swap foreground and background colours)
+bold/bright off 21
+underline off 24
+inverse off 27
+__________________________________________________________________
+
+See the table on Wikipedia for other, less widely supported codes.
+*/
+#define ANSI_COLOR_RED "\x1B[1;31m"
+#define ANSI_COLOR_YELLOW "\x1B[1;33m"
+#define ANSI_COLOR_BLUE "\x1B[1;34m"
+#define ANSI_COLOR_RESET "\x1B[1;0m"
+#define ANSI_COLOR_WHITE "\x1B[37m"
+#define ANSI_COLOR_GREEN "\x1B[1;32m"
int main()
{
- string cmd, pathtoHome, username, hostname;
- username = string(getenv("USER"));
- hostname = string(getenv("HOSTNAME"));
+ string pathtoHome, username, hostname;
+ username = string(getenv("USER")); // If compiler is showing error: "basic_string::_M_construct null not valid"
+ // that means Ubuntu isn't exporting the variable like it should,
+ // put "export HOSTNAME" in "/etc/bash.bashrc" and the code works.
+ hostname = string(getenv("HOSTNAME")); // it will export both the username and the hostname.
pathtoHome = "/home/" + username;
chdir (pathtoHome.c_str());
- while(cmd != "exit")
+ static char* line_read = (char *) NULL;
+ while(true)
{
- cout << username
- << "@"
- << hostname
- << ":"
- << boost::algorithm::replace_all_copy(boost::filesystem::current_path().string(), pathtoHome, "~")
- << "!>> "
- << flush;
- getline(cin,cmd);
- cmdSyntaxAnalysis(cmd);
+ string prompt = "\n"
+ +
+ username
+ // +
+ // ANSI_COLOR_RED
+ +
+ "@"
+ // +
+ // ANSI_COLOR_GREEN
+ +
+ hostname
+ // +
+ // ANSI_COLOR_YELLOW
+ +
+ ":"
+ // +
+ // ANSI_COLOR_BLUE
+ +
+ boost::algorithm::replace_all_copy(boost::filesystem::current_path().string(), pathtoHome, "~")
+ // +
+ // ANSI_COLOR_RESET
+ +
+ "!>> ";
+
+
+ line_read = readline (prompt.c_str());
+
+ if (! line_read || strcmp(line_read,"exit") == 0)
+ {
+ cout << endl;
+ break;
+ }
+
+ /* If the line has any text in it, save it on the history. */
+ if (line_read && *line_read)
+ add_history (line_read);
+ try
+ {
+ string cmd(line_read);
+ cmdSyntaxAnalysis(cmd);
+ }
+ catch (const std::exception& e)
+ {
+ cout << e.what() << "\n";
+ }
}
return 0;
-}
\ No newline at end of file
+}
+
+
+// /* A static variable for holding the line. */
+// static char *line_read = (char *)NULL;
+
+// /* Read a string, and return a pointer to it. Returns NULL on EOF. */
+// char *
+// rl_gets ()
+// {
+// /* If the buffer has already been allocated, return the memory
+// to the free pool. */
+// if (line_read)
+// {
+// free (line_read);
+// line_read = (char *)NULL;
+// }
+
+// /* Get a line from the user. */
+// line_read = readline ("");
+
+// /* If the line has any text in it, save it on the history. */
+// if (line_read && *line_read)
+// add_history (line_read);
+
+// return (line_read);
+// }
\ No newline at end of file
diff --git a/main.o b/main.o
index 0b988e8..bd587e8 100644
Binary files a/main.o and b/main.o differ
diff --git a/parser.cpp b/parser.cpp
new file mode 100644
index 0000000..a28eed2
--- /dev/null
+++ b/parser.cpp
@@ -0,0 +1,51 @@
+#include
+#include
+#include
+#include