Support for Pascal functions

王林
Release: 2024-07-16 08:03:50
Original
468 people have browsed it

Suporte às funções do Pascal

For those who are not following POJ (Pascal on the JVM) it is a compiler that transforms a subset from Pascal to JASM (Java Assembly) so that we can use the JVM as an execution environment.

In the last post we had some improvements in error capture, support for relational operators for the string type and the possibility of defining (and using) Pascal's procedures.

In this publication we will cover support for Pascal functions (functions). Not long before we can complete the last objective of the project: reading a number from standard input and calculating its factorial.

As we are compiling for the JVM, it is necessary to detail the functioning of various points of this incredible virtual machine. Therefore, at various times I detail the internal workings of the JVM as well as some of its instructions (opcodes).

Support for Pascal functions (functions)

Until now we had a way to define and invoke Pascal's procedures. From this PR it is also possible to define and invoke Pascal's functions.

In this commit, a Java program was implemented to understand how the JVM deals with defining and calling functions. From the Java program below:

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!";
    }
}
Copy after login
e

When we disassemble the class we get the following assembly:

1:  public class FunctionCall {
2:      public static main([java/lang/String)V {
3:          getstatic java/lang/System.out java/io/PrintStream
4:          ldc "Hello from main!"
5:          invokevirtual java/io/PrintStream.println(java/lang/String)V
6:
7:          getstatic java/lang/System.out java/io/PrintStream
8:          invokestatic FunctionCall.myMethod()java/lang/String
9:          invokevirtual java/io/PrintStream.println(java/lang/String)V
10:
11:         return
12:     }
13:
14:     static myMethod()java/lang/String {
15:         ldc "Hello from myMethod!"
16:
17:         areturn
18:     }
19: }
Copy after login
e

With this example it was possible to identify that:

  • To invoke a method, the JVM used the instruction "invokestatic FunctionCall.myMethod()java/lang/String" (line 8) where:
    • invokestatic is the instruction that receives as an argument the complete signature of the method to be called;
    • FunctionCall is the name of the class;
    • myMethod()java/lang/String is the complete signature of the method with its parameters (in this example none) and the return type (in this example java/lang/String);
  • Instruction areturn (line 17) terminates the function and leaves the return string on the stack.

That said, from the Pascal program below:

program function_call_wo_params;

function myfunction : string;
begin
    myfunction := 'Hello from myfunction!';
end;

begin
    writeln('Hello from main!');
    writeln(myfunction());
end.
Copy after login
e

POJ has been adjusted to generate the following JASM:

// Code generated by POJ 0.1
public 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
    }
}
Copy after login
e

The most attentive must have noticed the "astore 100" above and thought:

  • Why store the function return in a local variable? This is due to the fact that in Pascal the return value of a function can be set N times during the function, but we can only stack one result in the JVM;
  • Why in position 100? The local variables of a function or procedure start at position 0, so position 100 was arbitrarily chosen to store the return;
  • But wouldn't it be possible to optimize so that in this example only the ldc "Hello from myfunction!" instruction was generated followed by the areturn instruction? Yes, it would be, but POJ does not implement the optimization phase that exists in market compilers, something that could be implemented in the future.

This commit implements support for the "function" type in the symbol table and parser.

In the examples above, the functions had no arguments. In this commit, the expected result for functions with arguments was implemented. With this from the Pascal program below:

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.
Copy after login
e

POJ correctly generated the following JASM:

// Code generated by POJ 0.1
public 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
    }
}
Copy after login
e

Next steps

In the next publications we will talk about contexts, bugs found, nested sentences, data entry and conclude the last of the objectives of this project: calculating the factorial recursively.

Complete project code

The repository with the project's complete code and documentation is here.

The above is the detailed content of Support for Pascal functions. For more information, please follow other related articles on the PHP Chinese website!

source:dev.to
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!