DEV Community

Alex Sandro Garzão
Alex Sandro Garzão

Posted on

3 1 1 1 1

Estruturas de repetição: repeat, while e for

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 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) foi relativamente fácil alterar o parser 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.
Enter fullscreen mode Exit fullscreen mode

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
    }
}
Enter fullscreen mode Exit fullscreen mode

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 compartilhada durante todo o processo de compilação.

Para quem tiver interesse, o PR que implementa a declaração de variáveis está aqui.

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>;
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

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
    }
}
Enter fullscreen mode Exit fullscreen mode

Neste JASM não foram utilizadas novas instruções da JVM. Mais detalhes sobre estas instruções podem ser obtidas na postagem anterior.

Para quem tiver interesse o PR que implementa a estrutura Repeat está aqui.

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;
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

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
    }
}
Enter fullscreen mode Exit fullscreen mode

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.

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;
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

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
    }
}
Enter fullscreen mode Exit fullscreen mode

Para quem tiver interesse o PR que implementa a estrutura For está aqui.

Maiores informações

O repositório com o código completo do projeto e a sua documentação está aqui.

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay