Estruturas de repetição: repeat, while e for
Tags: compiling, go, antlr, ijvm
Published: 2024-04-12 02:40:48

Para quem não está acompanhando, o POJ (_Pascal on the JVM_) é um compilador que transforma um _subset_ de Pascal para JASM (_Java Assembly_) de forma que possamos usar a JVM como ambiente de execução.

Na [última postagem](https://dev.to/alexgarzao/novos-operadores-e-a-sentenca-if-b5f) eu tinha mais algumas funcionalidades para comentar, mas para facilitar a compreensão achei mais prudente separar em mais de uma postagem.

Como estamos compilando para a JVM faz-se necessário detalhar o funcionamento de várias pontos desta incrível máquina virtual. Com isso em vários momentos eu detalho o funcionamento interno da JVM bem como algumas das suas instruções.



## Declaração de variáveis

Apesar de importante, declaração de variáveis em Pascal não era a minha próxima meta, mas sim estruturas de controle como _for_, _while_ e _repeat_. Mas, para podermos exemplificar e corretamente implementar estas estruturas, a declaração de variáveis torna-se essencial.

Após todo o aprendizado no desenvolvimento do POJ (todas as postagens estão [aqui](https://dev.to/alexgarzao/series/26440)) foi relativamente fácil [alterar o parser](https://github.com/alexgarzao/poj/pull/22/commits/23bc8a94b966d8112eee6d57d9a3fdb50bfef9b9) bem como gerar o _assembly_ para declarar as variáveis em Java Assembly.

A partir do programa Pascal abaixo:

```
program VarDeclarations;
var
    msg1, msg2 : string;
begin
    msg1 := 'Message 1!';
    msg2 := 'Message 2!';
    writeln (msg1);
    writeln (msg2);
end.
```

O POJ gera o seguinte JASM:

```
// Code generated by POJ 0.1
public class var_declarations {
    public static main([java/lang/String)V {

        ;; msg1 := 'Message 1!';
        ldc "Message 1!"
        astore 1

        ;; msg2 := 'Message 2!';
        ldc "Message 2!"
        astore 2

        ;; writeln (msg1);
        getstatic java/lang/System.out java/io/PrintStream
        aload 1
        invokevirtual java/io/PrintStream.print(java/lang/String)V
        getstatic java/lang/System.out java/io/PrintStream
        invokevirtual java/io/PrintStream.println()V

        ;; writeln (msg2);
        getstatic java/lang/System.out java/io/PrintStream
        aload 2
        invokevirtual java/io/PrintStream.print(java/lang/String)V
        getstatic java/lang/System.out java/io/PrintStream
        invokevirtual java/io/PrintStream.println()V

        return
    }
}
```

Cabe aqui salientar que, para facilitar a compreensão, no exemplo acima as linhas iniciando com ";;" contém o trecho em Pascal que originou o JASM.

Em relação aos exemplos anteriores agora estamos utilizando duas novas instruções da JVM:
- astore \<N\>: retira da pilha uma string e armazena no slot de variáveis N
- aload \<N\>: carrega na pilha a string existente no slot de variáveis N

A alteração mais significativa é que agora o POJ gera uma [tabela de símbolos](https://github.com/alexgarzao/poj/blob/23bc8a94b966d8112eee6d57d9a3fdb50bfef9b9/codegen/symbol_table.go) compartilhada durante todo o processo de compilação.

Para quem tiver interesse, o PR que implementa a declaração de variáveis está [aqui](https://github.com/alexgarzao/poj/pull/22).




## Estrutura de controle _Repeat_

De posse de todo o conhecimento obtido até aqui, e com os pré-requisitos para implementarmos as estruturas de repetição de Pascal (sentença _if_, operadores relacionais e booleanos), optamos por iniciar com a estrutura "_Repeat Until_" por ser a mais simples dentre as estruturas de repetição.

Abaixo temos a sintaxe do _Repeat_:

```
1:    repeat            
2:        <bloco código>
3:    until <condição>;
```

O POJ implementa o seguinte comportamento:
- Na linha 1, ao reconhecer o _token_ _repeat_, gera e emite um _label_ (L1) que indica onde inicia o laço de repetição
- Na linha 2 o bloco de código é traduzido para JASM
- Na linha 3 a condição é avaliada e, caso seja válida (_true_) a execução salta para L1


Vamos a um exemplo que imprime os números de 10 até 19. A partir do programa Pascal abaixo:

```
program RepeatExample;
var
    i: integer;
begin
    i := 10;
    repeat
        writeln ('i=', i);
        i := i + 1;
    until i = 20;
end.
```

O POJ gera o seguinte JASM:

```
// Code generated by POJ 0.1
public class repeat_example {
    public static main([java/lang/String)V {

        ;; i := 10;
        sipush 10
        istore 1

    L1: ;; repeat
        ;; writeln ('i=', i);
        getstatic java/lang/System.out java/io/PrintStream
        ldc "i="
        invokevirtual java/io/PrintStream.print(java/lang/String)V
        getstatic java/lang/System.out java/io/PrintStream
        iload 1
        invokevirtual java/io/PrintStream.print(I)V
        getstatic java/lang/System.out java/io/PrintStream
        invokevirtual java/io/PrintStream.println()V

        ;; i := i + 1;
        iload 1
        sipush 1
        iadd 
        istore 1

        ;; until i = 20;
        iload 1
        sipush 20
        if_icmpne L2
        iconst 1 
        goto L3

    L2: iconst 0 

    L3: ifeq L1
        return
    }
}
```

Neste JASM não foram utilizadas novas instruções da JVM. Mais detalhes sobre estas instruções podem ser obtidas na [postagem anterior](https://dev.to/alexgarzao/novos-operadores-e-a-sentenca-if-b5f).

Para quem tiver interesse o PR que implementa a estrutura _Repeat_ está [aqui](https://github.com/alexgarzao/poj/pull/23).



## Estrutura de controle _While_

Dando sequências às estruturas de controle, a próxima estrutura implementada foi a _While_.

A estrutura _While_ pode ser vista como uma variação da _Repeat_, onde no caso do _Repeat_ o teste é executado no final enquanto que no _While_ o teste é executado no início. _Repeat_ sempre executa o bloco de código pelo menos uma vez, enquanto que o _While_ executa 0 ou mais vezes.

Abaixo temos a sintaxe do _While_:

```
1:    while <condição> do
2:    begin
3:        <bloco código>
4:    end;
```

O POJ implementa o seguinte comportamento:
- Na linha 1, ao reconhecer o _token_ _while_, executa os seguintes passos:
  - gera e emite um _label_ (L1) que indica onde está o condicional do _while_
  - gera um _label_ (L2) que indica o término do _while_
  - avalia a condição e, caso seja inválida (false) a execução salta para L2
- A linha 2 apenas indica o início do bloco
- Na linha 3 o bloco de código é traduzido para JASM
- Na linha 4 são executados os seguintes passos:
  - a execução salta para L1
  - emite o _label_ L2



Vamos a um exemplo. A partir do programa Pascal abaixo:

```
program WhileExample;
var
    i: integer;
begin
    i := 10;
    while i < 20 do
    begin
        writeln ('i=', i);
        i := i + 1;
    end;
end.
```

O POJ gera o seguinte JASM:

```
// Code generated by POJ 0.1
public class while_example {
    public static main([java/lang/String)V {

        ;; i := 10;
        sipush 10
        istore 1

    L1: ;; while i < 20 do
        iload 1
        sipush 20
        if_icmpge L3
        iconst 1 
        goto L4

    L3: iconst 0 

    L4: ifeq L2

        ;; writeln ('i=', i);
        getstatic java/lang/System.out java/io/PrintStream
        ldc "i="
        invokevirtual java/io/PrintStream.print(java/lang/String)V
        getstatic java/lang/System.out java/io/PrintStream
        iload 1
        invokevirtual java/io/PrintStream.print(I)V
        getstatic java/lang/System.out java/io/PrintStream
        invokevirtual java/io/PrintStream.println()V

        ;; i := i + 1;
        iload 1
        sipush 1
        iadd 
        istore 1

        ;; end; (do while)
        goto L1

    L2: return
    }
}
```

Em comparação com os exemplos anteriores, não foram utilizadas novas instruções da JVM.

Para quem tiver interesse o PR que implementa a estrutura "While" está [aqui](https://github.com/alexgarzao/poj/pull/24).



## Estrutura de controle _For_

Por ser considerada a mais complexa das estruturas de controle citadas nesta publicação (_repeat_, _while_ e _for_), propositadamente o _For_ foi deixado por último. 

Abaixo temos a sintaxe do _For_:

```
1:  for <var> := <início> to <fim> do
2:  begin
3:      <bloco código>
4:  end;
```

O POJ implementa o seguinte comportamento:
- Na linha 1, ao reconhecer o _token_ _for_, são executados os seguintes passos:
  - inicializa \<var\> com o valor \<início\>
  - gera e emite um _label_ (L1) que indica onde está o condicional do _for_
  - gera um _label_ (L2) que indica o término do _for_
  - avalia se \<var\> é \<= a \<fim\> e, caso seja inválida (false) a execução salta para o _label_ L2
- A linha 2 apenas indica o início do bloco
- Na linha 3 o bloco de código é traduzido para JASM
- Na linha 4 são executados os seguintes passos:
  - incrementa \<var\> em 1 unidade
  - a execução salta para o _label_ L1
  - emite o _label_ L2

Para a sua correta implementação o for engloba as seguintes tarefas:
- inicializar a variável definida no _for_
- incrementar/decrementar esta variável automaticamente no final do laço
- validar no início da sentença se o bloco deve ser executado





Vamos ao exemplo. A partir do programa Pascal abaixo:

```
program ForExample;
var
    i: integer;
begin
    for i := 10 to 19 do
    begin
        writeln ('inc i=', i);
    end;
end.
```

O POJ gera o seguinte JASM:

```
// Code generated by POJ 0.1
public class for_example {
    public static main([java/lang/String)V {

        ;; i := 10
        sipush 10
        istore 1

    L1: ;; i <= 19 ?
        iload 1
        sipush 19
        if_icmpgt L2

        ;; writeln ('inc i=', i);
        getstatic java/lang/System.out java/io/PrintStream
        ldc "inc i="
        invokevirtual java/io/PrintStream.print(java/lang/String)V
        getstatic java/lang/System.out java/io/PrintStream
        iload 1
        invokevirtual java/io/PrintStream.print(I)V
        getstatic java/lang/System.out java/io/PrintStream
        invokevirtual java/io/PrintStream.println()V

        ;; i := i + 1
        iload 1
        sipush 1
        iadd 
        istore 1

        ;; end; (do for)
        goto L1

    L2: return
    }
}
```

Para quem tiver interesse o PR que implementa a estrutura _For_ está [aqui](https://github.com/alexgarzao/poj/pull/25).




## Maiores informações

O repositório com o código completo do projeto e a sua documentação está [aqui](https://github.com/alexgarzao/poj).