debugcppMinor
Preparing interpreter for error-handling
Viewed 0 times
interpreterhandlingerrorpreparingfor
Problem
This is a follow-up to the question that I posted earlier regarding my interpreter.
After a lot of help, I refactored my code and added more functionality to it. Now, it allows users to declare functions like so
or like this
and also like this
As you can see, you would use a period ("
On top of that, it can read from source code.
Here's an example of such a source code:
Which will then output
If you have ever programmed using a Lisp-like programming language -- such as scheme -- you would notice that there are a lot of similarities with what I made. In fact, it was inspired by those programming languages.
Anyways, there's one limitation behind the code for the interpreter: when it encounters an error from within the user's source code, it's programmed to crash completely. That's not a problem. I did that on purpose. It's one way indicates to the user that there was an error.
Now, I want to implement a more appropriate error handler. But, before I do that, I would like to ensure that my code is easier to maintain.
I have a hunch that I should separate my code into multiple files. But that's just one, and even that I need help on how I should approach it.
What would be your suggestion?
```
#include
#include
#include
#include
#include
#include
#include // mmocny: I needed to add this to use atof
#include
using namespace std;
//----------------------------------
class Variable
{
public:
Variable(const string& name, double val)
: name_(name), val_(val) // mmocny: Use initializer l
After a lot of help, I refactored my code and added more functionality to it. Now, it allows users to declare functions like so
func function_name param1 param2 param3 . / param3 * param1 param2or like this
func to_radians deg . * deg / 3.14159 180and also like this
func sind theta . sin to_radians thetaAs you can see, you would use a period ("
.") to tell the interpreter to stop taking in parameters and start reading the body of the function.On top of that, it can read from source code.
Here's an example of such a source code:
; Variables
def PI * 4 atan 1
; Functions
func to_rad deg . * deg / PI 180
func sind theta . sin to_rad theta
; Run the program
sin to_rad 45
sind 45Which will then output
0.7071070.707107If you have ever programmed using a Lisp-like programming language -- such as scheme -- you would notice that there are a lot of similarities with what I made. In fact, it was inspired by those programming languages.
Anyways, there's one limitation behind the code for the interpreter: when it encounters an error from within the user's source code, it's programmed to crash completely. That's not a problem. I did that on purpose. It's one way indicates to the user that there was an error.
Now, I want to implement a more appropriate error handler. But, before I do that, I would like to ensure that my code is easier to maintain.
I have a hunch that I should separate my code into multiple files. But that's just one, and even that I need help on how I should approach it.
What would be your suggestion?
```
#include
#include
#include
#include
#include
#include
#include // mmocny: I needed to add this to use atof
#include
using namespace std;
//----------------------------------
class Variable
{
public:
Variable(const string& name, double val)
: name_(name), val_(val) // mmocny: Use initializer l
Solution
If you're going to get serious on this project, here are some questions worth considering:
Now some specific comments regarding your presented code:
-
This function can be expressed more directly:
-
While skimming through your code I notice it's really bare of any comments. You might want to look into fixing that.
-
One more point, when reorganizing your code into multiple source files do not use any
- Are you using version control? We all have our preferences here but the important thing is you're using something. It gives you a way to hit 'UNDO' in case you make a big oopsie.
- Are there any unit tests? If you're currently not unit testing I would strongly suggest you start doing that now before your interpreter gets bigger. I like to use google test but there are many other C++ testing frameworks to choose from. Unit testing gives you a way to better control entropy in your project and this becomes more important as your project grows.
- Is the code well separated into different appropriate source files? Just like you wouldn't stuff every sentence into one gigantic paragraph in an essay, you don't want to stuff all your class, functions and variables into one source. In C++ it's customary to put each defined class in its own respective header(.h) and implementation(.cpp) file.
Now some specific comments regarding your presented code:
- There is no clear separation between the lexing stage, parsing stage and processing in your design which is the usual expected approach when writing a translator, compiler or interpreter etc. It seems like these stages are mixed in together in an ad-hoc fashion inside your interpreter class. This coupling and lack of clear separation in your code will make it harder to maintain later when you add more stuff to it.
- Typedef'ing
std::vectorusage to make it more container-agnostic. If you decide to changestd::vectorto astd::maplater on you won't have to change it all over the place. Also consider usingstd::back_insert_iteratorinstead of directlystd::vector::push_backto make it even more container-agnostic.
-
This function can be expressed more directly:
bool is_all_blank(const string& line)
{
// Shouldn't it check for other possible whitespace too? Like tab for example
return line.find_first_not_of( " \t" ) == string::npos;
}-
While skimming through your code I notice it's really bare of any comments. You might want to look into fixing that.
-
One more point, when reorganizing your code into multiple source files do not use any
using namespace directives in the header files. Reason being you don't want this header to pollute the namespace of the components that includes this header.Code Snippets
bool is_all_blank(const string& line)
{
// Shouldn't it check for other possible whitespace too? Like tab for example
return line.find_first_not_of( " \t" ) == string::npos;
}Context
StackExchange Code Review Q#2236, answer score: 5
Revisions (0)
No revisions yet.