HiveBrain v1.2.0
Get Started
← Back to all entries
debugcppMinor

Preparing interpreter for error-handling

Submitted by: @import:stackexchange-codereview··
0
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

func function_name param1 param2 param3 . / param3 * param1 param2


or like this

func to_radians deg . * deg / 3.14159 180


and also like this

func sind theta . sin to_radians theta


As 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 45


Which will then output

0.707107

0.707107

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

Solution

If you're going to get serious on this project, here are some questions worth considering:

  • 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::vector usage to make it more container-agnostic. If you decide to change std::vector to a std::map later on you won't have to change it all over the place. Also consider using std::back_insert_iterator instead of directly std::vector::push_back to 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.