how do I generate the code corresponding to a bytecode instruction IF THEN - ELSE with the optioanal ELSE branch?
For example, the program If-else.pas is considered correct, while the program If.pas isn't considered correct, because it doesn't contains the ELSE branch.
If-else.pas
var a, b : integer;
begin
a := 3;
b := 5;
if a > b then
print(a)
else
print(b)
end
If.pas
var a, b : integer;
begin
a := 3;
b := 5;
if a > b then
print(a)
end
So Jasmin give me this error:
Output.j:62: JAS Error: Label: L11 has not been added to the code.
Output.j: Found 1 errors
My grammar .g has this rule:
stmt -> ID := expr
| print( expr )
| if( expr ) then ( stmt ) [ else stmt ]?
| while( expr ) do stmt
| begin stmt [ ; stmt ]* end
For the if-else statement I wrote this:
'if'
{
int lfalse = code.newLabel(); //Generates a new number for the LABEL
int lnext = lfalse;
}
( expr )
{
if($expr.type != Type.BOOLEAN) //Checking the condition is boolean
throw new IllegalArgumentException("Type error in '( expr )': expr is not a boolean.");
code.emit(Opcode.IFEQ, lfalse); //I create the instruction IFEQ L(lfalse)
}
'then' s1 = stmt
{
lnext = code.newLabel(); //Generates a new number for the LABEL
code.emit(Opcode.GOTO, lnext); //I create the instruction GOTO L(lnext)
code.emit(Opcode.LABEL, lfalse); //I create the instruction L(lfalse):
}
( 'else' s2 = stmt
{
code.emit(Opcode.LABEL, lnext); //I create the instruction L(lnext):
})?
But in this way the second branch is not optional, but must always be present.
How do I make it optional? I thought it was necessary the question mark (( 'else' s2 = stmt )?
), but no.
I am using ANTLR.
Thanks.
I do not know if the bytecode files (. J) generated by Jasmin will be useful, but I write it.
If-else.j
ldc 3
istore 1
ldc 5
istore 0
iload 1
iload 0
if_icmpgt L7
ldc 0
goto L8
L7:
ldc 1
L8:
ifeq L4
iload 1
invokestatic Output/printInt(I)V
goto L11
L4:
iload 0
invokestatic Output/printInt(I)V
L11:
return
If.j
ldc 3
istore 1
ldc 5
istore 0
iload 1
iload 0
if_icmpgt L7
ldc 0
goto L8
L7:
ldc 1
L8:
ifeq L4
iload 1
invokestatic Output/printInt(I)V
goto L11
L4:
return
The problem here is that you're always generating a jump to LNEXT, but you don't generate the label itself when there's no else clause, leading to invalid code. You need to generate the label unconditionally.
I'm not familiar with Antlr, but based on the way your code is written, I suspect this is the correct way to do it.
'if'
{
int lfalse = code.newLabel(); //Generates a new number for the LABEL
int lnext = lfalse;
}
( expr )
{
if($expr.type != Type.BOOLEAN) //Checking the condition is boolean
throw new IllegalArgumentException("Type error in '( expr )': expr is not a boolean.");
code.emit(Opcode.IFEQ, lfalse); //I create the instruction IFEQ L(lfalse)
}
'then' s1 = stmt
{
lnext = code.newLabel(); //Generates a new number for the LABEL
code.emit(Opcode.GOTO, lnext); //I create the instruction GOTO L(lnext)
code.emit(Opcode.LABEL, lfalse); //I create the instruction L(lfalse):
}
( 'else' s2 = stmt )?
{
code.emit(Opcode.LABEL, lnext); //I create the instruction L(lnext):
}