A bit ago, I copied the sourcecode for my Pong game into a new directory, as a way to start work on my next game in my language. I proceeded to comment out a large chunk of code.
Tangent: languages often don't have good facilities for commenting out chunks of code that might already include commented out code. In C++, say, you've got your single line comments
// like this
And there are multiple-line comments
/*
* that can go on for many
* lines, like this
*/
And if you want to disable a chunk of code that has a single-line comment, it's fine:
for (int i=0; i<10; i++) {
if (i < 3) {
/*
// show small numbers
printf("small number %d", i);
*/
process_data(i);
}
But it gets tricky if I wanted to disable that entire loop because */ terminates a comment, even if the comment was itself in a comment.
C and C++ have one more tool, the preprocessor, which helps some, so I could just do this:
#if 0
for (int i=0; i<10; i++) {
if (i < 3) {
/*
// show small numbers
printf("small number %d", i);
*/
process_data(i);
}
#endif //0
but that's still not terrific. Maybe disabling code isn't what a compiler is for. Still.
But that's not what I came here to talk about today. As I was saying at the top, I commented out a bunch of code from my Pong game, and stuff wouldn't compile. Ok, I thought, perhaps I was sloppy and commented out half of a function, and the remaining bits are causing problems. That may well have been part of it, but I cleaned up the obvious errors like that, and still I was running into issues.
One thing that doesn't get a lot of coverage in compilers tutorials is how to deal with errors - lexing errors, parse errors - there's perhaps a paragraph talking about inserting a special error token into your language and that's what gets called when things go wrong, which is a start, but then what do you do when that production gets called? How do you present enough information to the user of your compiler to fix the problem?
Right now, I print a warning with a line number and a little more information, which isn't currently sufficient. For one thing, the line number doesn't line up with the actual line number of the file being compiled. I think part of that comes from my compiler starting at line number 0 versus emacs, which starts at 1. Also, if I #include files, those throw off the numbering. Whoops. So, that's stuff to fix.
It'd also be nice to know what column the error was on, if I know that.
I've looked a little bit at pycparser, which seems to do a better job than I am for this sort of thing. TODO: roll in more of pycparser's approach to error handling.
And even that isn't what I meant to be talking about.
So, I waded through the output of my compiler, complaining about unexpected closing braces, and I ultimately determined that code like this was causing trouble:
void display_char(char c) {
# sdl_show_char(c);
}
Seems innocuous - a call to an external function that I commented out, since I'm rewriting my graphics library. Except, whoops, aha. The body of display_char is empty. And, whaddayaknow, my compiler doesn't like empty bodies for functions. Or, as it turns out for if/elif/else bodies, either:
if (phase == PLAY_GAME) {
# draw_game();
} elif (phase == SHOW_TITLE) {
# draw_title();
} elif (phase == SHOW_CREDITS) {
# ...
}
As it turned out, that was super easy to fix - I just extended my grammar to allow statementlists to be 0 or more statements, instead of 1 or more, which is how they were before.
So, now I can have functions that do nothing, and blocks of code that are empty. Progress!
No comments:
Post a Comment