Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Alex Sandro Garzão
Alex Sandro Garzão

Posted on

     

Suporte às funções do Pascal

Para quem não está acompanhando o POJ (Pascal on the JVM) é um compilador que transforma umsubset de Pascal para JASM (Java Assembly) de forma que possamos usar a JVM como ambiente de execução.

Na últimapostagem tivemos algumas melhorias na captura de erros, suporte a operadores relacionais para o tipostring e a possibilidade de definir (e utilizar) asprocedures do Pascal.

Nesta publicação vamos abordar o suporte às funções (functions) do Pascal. Falta pouco para podemos concluir o último objetivo do projeto: ler um número da entrada padrão e calcular o seu fatorial.

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).

Suporte às funções (functions) do Pascal

Até o momento tínhamos como definir e invocar àsprocedures do Pascal. A partirdeste PR é possível também definir bem como invocar asfunctions do Pascal.

Neste commit foi implementado um programa em Java para entender como a JVM lida com a definição e a chamada de funções. A partir do programa Java abaixo:

public class FunctionCall {    public static void main(String[] args) {        System.out.println("Hello from main!");        System.out.println(myMethod());    }    static String myMethod() {        return "Hello from myMethod!";    }}
Enter fullscreen modeExit fullscreen mode

Quando desassemblamos oclass obtemos o seguinteassembly:

1:  public class FunctionCall {2:      public static main([java/lang/String)V {3:          getstatic java/lang/System.out java/io/PrintStream4:          ldc "Hello from main!"5:          invokevirtual java/io/PrintStream.println(java/lang/String)V6:7:          getstatic java/lang/System.out java/io/PrintStream8:          invokestatic FunctionCall.myMethod()java/lang/String9:          invokevirtual java/io/PrintStream.println(java/lang/String)V10:11:         return12:     }13:14:     static myMethod()java/lang/String {15:         ldc "Hello from myMethod!"16:17:         areturn18:     }19: }
Enter fullscreen modeExit fullscreen mode

Com este exemplo foi possível identificar que:

  • Para invocar um método a JVM utilizou a instrução "invokestatic FunctionCall.myMethod()java/lang/String" (linha 8) onde:
    • invokestatic é a instrução que recebe como argumento a assinatura completa do método a ser chamado;
    • FunctionCall é o nome da classe;
    • myMethod()java/lang/String é assinatura completa do método com seus parâmetros (neste exemplo nenhum) e o tipo de retorno (neste exemplojava/lang/String);
  • Instruçãoareturn (linha 17) encerra a função e deixa na pilha a string de retorno.

Dito isso, a partir do programa Pascal abaixo:

program function_call_wo_params;function myfunction : string;begin    myfunction := 'Hello from myfunction!';end;begin    writeln('Hello from main!');    writeln(myfunction());end.
Enter fullscreen modeExit fullscreen mode

O POJ foi ajustado para gerar o seguinte JASM:

// Code generated by POJ 0.1public class function_call_wo_params {    ;; function myfunction : string;    static myfunction()java/lang/String {        ldc "Hello from myfunction!"        astore 100   ;; Posição 100 guarda o retorno da função        aload 100    ;; Empilha o retorno da função        areturn      ;; Deixa "Hello from myfunction!" na pilha    }    ;; procedure principal (main)    public static main([java/lang/String)V {        ;; writeln('Hello from main!');        getstatic java/lang/System.out java/io/PrintStream        ldc "Hello from main!"        invokevirtual java/io/PrintStream.print(java/lang/String)V        getstatic java/lang/System.out java/io/PrintStream        invokevirtual java/io/PrintStream.println()V        ;; writeln(myfunction());        getstatic java/lang/System.out java/io/PrintStream        invokestatic function_call_wo_params.myfunction()java/lang/String         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 modeExit fullscreen mode

Os mais atentos devem ter notado o "astore 100" acima e pensado:

  • Por que guardar o retorno da função em uma variável local? Isso se deve ao fato de que em Pascal o valor de retorno de uma função pode ser definido N vezes durante a função, mas só podemos empilhar um resultado na JVM;
  • Por que na posição 100? As variáveis locais de uma função ou procedimento iniciam na posição 0 então arbitrariamente foi escolhido a posição 100 para guardar o retorno;
  • Mas não seria possível otimizar para que neste exemplo somente fosse gerado a instruçãoldc "Hello from myfunction!" seguida da instruçãoareturn? Sim, seria, mas o POJ não implementa afase de otimizações existente em compiladores de mercado, algo que pode ser implementado futuramente.

Estecommit implementa o suporte ao tipo "function" na tabela de símbolos e noparser.

Nos exemplos acima as funções não tinham argumentos. Nestecommit foi implementado o resultado esperado para funções com argumentos. Com isso a partir do programa Pascal abaixo:

program function_call_with_two_params;function addvalues(value1, value2: integer) : integer;begin    addvalues := value1 + value2;end;begin    writeln('2+4=', addvalues(2, 4));end.
Enter fullscreen modeExit fullscreen mode

O POJ gerou corretamente o seguinte JASM:

// Code generated by POJ 0.1public class function_call_with_two_params {    ;; function addvalues(value1, value2: integer) : integer;    static addvalues(I, I)I {        ;; addvalues := value1 + value2;        iload 0        iload 1        iadd         istore 100        iload 100        ireturn     }    ;; procedure main    public static main([java/lang/String)V {        ;; writeln('2+4=', ...);        getstatic java/lang/System.out java/io/PrintStream        ldc "2+4="        invokevirtual java/io/PrintStream.print(java/lang/String)V        getstatic java/lang/System.out java/io/PrintStream        ;; aqui código para invocar addvalues(2, 4)        sipush 2        sipush 4        invokestatic function_call_with_two_params.addvalues(I, I)I         ;; aqui código para invocar writeln com retorno addvalues        invokevirtual java/io/PrintStream.print(I)V        getstatic java/lang/System.out java/io/PrintStream        invokevirtual java/io/PrintStream.println()V        return    }}
Enter fullscreen modeExit fullscreen mode

Próximos passos

Nas próximas publicações vamos falar sobre contextos, bugs encontrados, sentenças aninhadas, entrada de dados e concluir o último dos objetivos deste projeto: cálculo do fatorial de forma recursiva.

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)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

Sou apaixonado por tópicos como compiladores, linguagens de programação, máquinas virtuais, geradores de código, bancos de dados e sistemas de alto desempenho.
  • Location
    Canoas, RS, Brasil
  • Joined

More fromAlex Sandro Garzão

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp