A Pascal goto statement can cause one of two kinds of jumps: It can cause a local jump or a non-local jump. In case of a local jump, a label in the body of the same procedure or function is jumped to. In case of a non-local jump, a label in the body of another procedure or function is jumped to.
Local jumps can be handled by simply adding the JVM goto instruction to the code with as parameterlist the offset to the first instruction of the code that follows the label in the Pascal source. This offset can be computed by maintaining two lists while generating code. The first list contains all the labels parsed in the current procedure or function and the index of the instruction following the label. The other list contains labels instructions want to jump to, and the index of the instruction that wants to jump to it.
If the target label is in the first list, the offset can be calculated immediately, otherwise the label and the index of the goto instruction are put in the second list. Every time a label is parsed, it is put in the first list, and it is checked if it is in the second list. If this is so, these offsets can be calculated now, added as a parameterlist to the appropriate goto instruction, and that entry can be removed from the second list.
If at the end of the procedure or function there still are entries in the second list, this means these goto statements are non-local jumps. Non-local jumps are more difficult because there is no JVM instruction that lets you jump to an instruction in the code of another method. This problem can be solved by using exceptions.
For every label in the second list, instructions have to be added to the end of the code for the method, after the return. The offset to the first instruction of this piece of code has to be computed and added as a parameterlist to the goto instruction that wants to jump to the non-local label. This piece of code must cause an exception to be thrown that contains the target label.
The Java code for the exception could be:
public class GotoException extends Exception { GotoException(int l) { label = l; } public int label; }
If the flow of control reaches the goto instruction that causes a non-local jump, it causes a jump to the instructions that throw the exception containing the target label.
If a procedure or function has nested procedures or functions, and contains labels that can be jumped to, the code for that procedure or function has to contain code that can handle the exception. This code has to contain a goto instruction that can now jump to the label contained in the exception. This way the exception is caught by this procedure or function and the non-local jump has become a local jump.
If the target label is not in the calling procedure or function, and therefore there is no exception handler in the calling procedure or function, the exception mechanisme throws the exception automatically further up the method invocation chain until it reaches a method that can handle the exception, and complete the jump.
The athrow instruction causes all the frames of the methods that can not catch the exception to be popped from the stack. When the method is reached that can handle the exception, its operand stack is cleared and the objectref of the exception is pushed on it. This is the same as in Pascal where the working stack of the procedure or function is cleared before the execution proceeds at the label that was jumped to.