Quantcast
Viewing all articles
Browse latest Browse all 3

Answer by glampert for Lexer+Parser code for my "Reedoo" programming language

C style

Well, the first thing I have to say is that your code is very C-like. The first action here would be to move all those loose functions and globals into two C++ classes, Lexer and Parser.


Another C vice of your code is to declare variables on top of a function.lex() is champion at that, with 18 variables piled at the top of the function.Absolutely don't do that in C++. Declare a variable in its point of use, restricting scope to where the var is needed.

Counters in for loops, especially, should be declared inside the loop:

int i;for (i = 0; i < prog.size(); ++i) // poor practice----for (int i = 0; i < prog.size(); ++i) // much better

And yet another old school C habit is to use the /**/ (multi-line comments) everywhere. Why not use the much more practical // for single liners? The single line comment is even valid in C now.


#define IO_ERROR "[IO ERROR] "#define SYNTAX_ERROR "[SYNTAX ERROR] "#define ASSIGN_ERROR "[ASSIGN ERROR] "

These macros are not very nice either. You should prefer a const std::stringor const char[]. For variables/constants that are file scoped, it is a goodpractice to declare them inside an unnamed namespace, effectively making the constants file-scoped:

namespace {    const std::string IO_ERROR     { "[IO ERROR] "     };    const std::string SYNTAX_ERROR { "[SYNTAX ERROR] " };    const std::string ASSIGN_ERROR { "[ASSIGN ERROR] " };}

The other globals you have should be made members of a class, but if they wereto remain as globals, then they should also be wrapped with an unnamed namespace.

using namespace std

This was already mentioned and I second for that. Don't use namespace stdbecause that defeats the purpose of a namespace, which is to allow identicalnames to coexist without clashes.

Possible bug?

bool rdo_is_reserved(string tok) {  int i;  for (i = 0; i < 9;i++) {    if (tok == reserved[i])      return true;    else      return false;  }  return false;}

This function is iterating from 0 to 8, however, the reserved arrayhas 14 elements. Is this intentional or a bug? But this function is useless anyway, since the Standard Library provides std::find(), which is meant for this kind of linear searches and conveys intent much more clearly.

Commented lines leftover

if (n != "") {  //is_expr = 1;  //lex_tokens.push_back(reserved[7] +":"+ n);}

Please clean up lines that are commented out. This is only liable to cause distraction and confuse the reader. Also, it conveys no important info since you can't know if the commented out code is correct or not.

Large functions

The lex() function is a massive beast. I wouldn't want to be the poor programmertasked with the job of modifying it or fixing a bug caused by it. This function needs an urgent refactoring. It should be broken down into several helper methods.

Calling exit()

lex() also calls exit(1) in its body. This is a bit harsh, don't you think? Terminating the program like this, without cleanup or error message. It should instead throw an exception. This is C++ and we have much more modern ways of handling errors, plus with an exception the caller has the chance of recovering from the error if possible.

goto and the lost label

You have a label inside the parse() function, TOP:, which I would expect be paired with a goto statement somewhere. However, I couldn't find a single goto inside the function. So what is that label even doing there?

Since you never did CS school, you might not be aware of the status of goto... Lets just say that it is quite controversial. I for one really don't think goto still has a place in modern C++, like I said before, the language has exceptions and automatic resource management, so goto is pretty outdated.

couts

Your code is also littered with cout calls, most are commented out.You shouldn't be using it directly inside functions like you did. Most userswon't want the verbose output on every execution of the program. If you need themfor debugging, a better approach is to wrap those calls into a macro that can be disabled at compile time, e.g.:

#define DEBUG_LOG(msg) do { std::cout << msg << std::end; } while(0)

Or use a better, more mature, log library. Do a search and you will find a ton of good options.


Viewing all articles
Browse latest Browse all 3

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>