Thanks for the examples, as well as the cautions... I'm trying to avoid goto's, but also trying to demonstrate that I can essentially duplicate an existing language that (unfortunately) had goto's.... Hopefully, I'll get the users to drop that need...
----- Original Message -----
From: "Etienne M. Gagnon"
To: "Discussion mailing list for the SableCC project"
Subject: Re: Using goto in language
Date: Tue, 11 Nov 2008 14:52:52 -0500
Hi Roger,
First, let me state loud and clear: you should avoid providing a goto
in your programming language, unless you have a really compelling
reason to provide it. I propose some alternative at the end of this
message.
Now, that being said, it really depends on what you want. If you want
arbitrary gotos, like in Basic and C, then it can be difficult to
implement on a tree structure (e.g. AST). Here's an example of ugly
valid C code:
#include <stdio.h>
void foo(void) {
goto label;
while(1) {
int i = 3;
label:
printf("i = %d\n", i);
return;
}
}
main() {
foo();
}
What do you think that this program will print? "3"? According to the C
specification, it will print an "undefined" value. Mind you: it is
valid, even though undefined. In other words, your compiler is free to
get your program to print whatever value it feels like. Yes, the
pleasures of C!
So, if this is what you want, you'll have to go about it the hard way:
generate bytecode instructions, then interpret the bytecode. This is
the traditional approach.
Now, if you want a cleaner goto (e.g. a structured goto), then there's
hope for you. The idea is as follows:
1- Semantic rule: A goto can only jump to a label directly located in
an enclosing scope.
2- At semantic analysis time, a record kept, for each scope, of the
labels it directly contains.
3- At interpretation time, when a goto in encountered, the stack is
unfolded until a suitable scope is found to handle the label.
Step 3 can be done in a variety of ways. An easy way is throwing an
exception.
Here's some pseudo-code:
pubic void caseAInstructionBlock(...) {
int startInstruction = 0;
boolean retry = true;
List<PInstruction> instructions = node.getInstructions();
int instructionCount = instructions.size();
while(rety) {
retry = false;
try{
for(int i = startInstruction; i < instructionCount; i++) {
instructions.get(i).apply(this); // execute the instruction
}
}
catch(GotoException e) {
Label label = e.getLabel();
if(labels.get(node).contains(label)) {
startInstruction = label.instructionLocation;
retry = true;
}
else {
throw e; // pass along to higher scope
}
}
}
}
This should give you the general idea. Be careful, though, not to end
up with the same semantic mess as Basic and C:
{
...
goto label;
int y = 2;
...
label:
print(y); // what do you print?!
}
The solution, here, is to force all declarations to the start of blocks
and to require an initial value (or, at least, to define a default
value, such as null or 0). In other words, one would need to write:
{
int y = 2;
...
goto label;
...
label:
print(y); // prints "2" or any later value assigned to y
}
My recommendation:
Gotos are fundamentally ugly. The better approach is to use labeled
break and continue statements for quick escapes, and exceptions for
error handling.
Have fun!
Etienne
Roger Pomeroy wrote:
Now that I have gotten a simple language interpreter mostly working, I'd like to extend it to allow a "goto" statement. I haven't seen any examples of how I might do that in sablecc, and did see a comment in a thread about tree structure not being valid (http://www.mail-archive.com/sablecc-discussion@xxxxxxxxxxxxxxxxx/msg00015.html) but not sure if that means I can't do it or not. Can anyone offer some advice (other than "don't try to do it") about how to walk thru a tree and deal with goto's?
Thanks!
Roger
--
Etienne M. Gagnon, Ph.D.
SableCC: http://sablecc.org
<< signature.asc >>
_______________________________________________
SableCC-Discussion mailing list
SableCC-Discussion@xxxxxxxxxxxxxxxxx
http://lists.sablecc.org/listinfo/sablecc-discussion