Как сгенерировать байт-код для оператора if-else

как сгенерировать код, соответствующий инструкции байт-кода IF THEN - ELSE с опциональной веткой ELSE?

Например, программа If-else.pas считается правильной, а программа If.pas не считается правильной, так как не содержит ветки ELSE.

Если-else.pas

var a, b : integer;
begin
    a := 3;
    b := 5;
    if a > b then 
        print(a)
    else 
        print(b)
end

Если.pas

var a, b : integer;
begin
    a := 3;
    b := 5;
    if a > b then 
        print(a)
end

Итак, Жасмин дает мне эту ошибку:

Output.j:62: Ошибка JAS: Метка: L11 не добавлен в код.

Output.j: найдена 1 ошибка

Моя грамматика .g имеет это правило:

stmt -> ID := expr
     | print( expr )
     | if( expr ) then ( stmt ) [ else stmt ]?
     | while( expr ) do stmt
     | begin stmt [ ; stmt ]* end

Для оператора if-else я написал следующее:

'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):
    })?

Но таким образом вторая ветвь не является факультативной, а всегда должна присутствовать. Как сделать его необязательным? Я думал, что нужен вопросительный знак (( 'else' s2 = stmt )?), но нет. Я использую ANTLR.

Спасибо.

Я не знаю, будут ли полезны файлы байт-кода (.J), сгенерированные Jasmin, но я их пишу.

Если-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 

person Community    schedule 23.05.2014    source источник


Ответы (1)


Проблема здесь в том, что вы всегда создаете переход к LNEXT, но не создаете саму метку, когда нет предложения else, что приводит к недопустимому коду. Вы должны сгенерировать метку безоговорочно.

Я не знаком с Antlr, но, судя по тому, как написан ваш код, я подозреваю, что это правильный способ сделать это.

'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):
    }
person Antimony    schedule 23.05.2014