DEV Community

Alex Sandro Garzão
Alex Sandro Garzão

Posted on

Resolução de alguns bugs

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 implementamos o suporte às functions do Pascal.

Nesta publicação vamos falar sobre coisas bacanas? Nem tanto rsrsrs. Desta vez só vamos falar de bugs mesmo :-)

Como estamos compilando para a JVM faz-se necessário detalhar o funcionamento de vários 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 (opcodes).

Bug referente aos parâmetros passados ao programa pela linha de comando

Quando implementei a declaração de variáveis eu não atentei para o fato de que, na JVM, a primeira variável na função principal é o args, um array que contém os argumentos passados para o programa. Com isso neste PR eu reservo a primeira posição implicitamente para args.

Bug ao lidar com variáveis locais e globais

Como os programas em Pascal de teste continham apenas variáveis globais eu não havia notado um erro grave na geração do JASM. No momento em que criei programas que continham variáveis globais e locais percebi que algo de errado não estava certo rsrsrs.

A partir do programa Pascal abaixo:

program global_var_declaration;
var
    globalvar : integer;
begin
    globalvar := 123;
    write (globalvar);
end.
Enter fullscreen mode Exit fullscreen mode

O POJ gerava o seguinte JASM:

// Code generated by POJ 0.1
public class global_var_declaration {
    public static main([java/lang/String)V {
        ;; globalvar := 123;
        bipush 123
        istore 1

        ;; write (globalvar);
        getstatic java/lang/System.out java/io/PrintStream
        iload 1
        invokevirtual java/io/PrintStream.print(I)V

        return
    }
}
Enter fullscreen mode Exit fullscreen mode

Para tentar identificar o problema criei um programa em Java equivalente ao programa em Pascal acima:

public class GlobalVarDeclaration {
    public static int globalVar;

    public static void main(String[] args) {
        globalVar = 123;
        System.out.println(globalVar);
    }
}
Enter fullscreen mode Exit fullscreen mode

Quando desassemblei o class eu obtive o seguinte assembly:

 1: public class GlobalVarDeclaration {
 2:     public static globalVar I
 3:
 4:     public static main([java/lang/String)V {
 5:         bipush 123
 6:         putstatic GlobalVarDeclaration.globalVar I
 7:
 8:         getstatic java/lang/System.out java/io/PrintStream
 9:         getstatic GlobalVarDeclaration.globalVar I
10:         invokevirtual java/io/PrintStream.println(I)V
11:
12:         return
13:     }
14: }
Enter fullscreen mode Exit fullscreen mode

Neste momento percebi a declaração "public static globalVar I" (linha 2) e as instruções putstatic (linha 6) e getstatic (linha 9). O esperado eram as instruções astore e istore utilizadas pelo POJ até o momento. Lendo a documentação da JVM percebi que o POJ estava declarando as variáveis globais como se fossem variáveis locais de uma função para a JVM :-D

Enfim, até o momento o POJ estava usando (erroneamente) os opcodes aload/iload/astore/istore para variáveis globais, mas o correto seria declarar as variáveis como públicas (como na linha 2) e utilizar o getstatic/putstatic.

Com isso o código foi refatorado aqui para que a tabela de símbolos consiga lidar com declarações locais e globais. E aqui o código foi refatorado para que a tabela de símbolos consiga gerar as instruções corretas para as variáveis locais e globais.

A geração de código JASM foi alterada aqui para lidar com a nova tabela de símbolos bem como limpar as declarações locais após o término de uma função ou procedimento.

Com isso, a partir do programa Pascal abaixo:

program GlobalVarDeclaration;
var
    globalvar : integer;
begin
    globalvar := 123;
    write (globalvar);
end.
Enter fullscreen mode Exit fullscreen mode

O POJ passou a gerar corretamente o seguinte JASM:

// Code generated by POJ 0.1
public class global_var_declaration {
    public static globalvar I

    public static main([java/lang/String)V {
        ;; globalvar := 123;
        bipush 123
        putstatic global_var_declaration.globalvar I

        ;; write (globalvar);
        getstatic java/lang/System.out java/io/PrintStream
        getstatic global_var_declaration.globalvar I
        invokevirtual java/io/PrintStream.print(I)V

        return
    }
}
Enter fullscreen mode Exit fullscreen mode

Próximos passos

Na próxima publicação vamos falar sobre contextos e sentenças aninhadas.

Código completo do projeto

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

Top comments (0)