lboasso / oberonc

An Oberon-07 compiler for the JVM

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

VAR parameter passing not working

KevinRH opened this issue · comments

The following code assigns 0 to j.

MODULE ParTest;

    IMPORT Out;

    VAR j: INTEGER;

    PROCEDURE P(x: INTEGER; VAR y, z: INTEGER);
    BEGIN
        IF x > 0 THEN y := x ELSE z := x END
    END P;

BEGIN
    P(-1, j, j);
    Out.String("j = "); Out.Int(j, 0)  (*j should be -1*)
END ParTest.

Hi Kevin,

I am not sure I follow your reasoning. Could you explain why j should be -1?
I have tried your example on the original ETH Oberon System for Windows and it prints j = 1. The same code compiled with oberonc, produce the same result.

Sorry, the procedure call should be P(-1, j, j). I've amended my original post.

I see your point now. You are exploiting the aliasing of VAR parameters, something not defined in the specification, so arguably implementation dependent. The problem is that the JVM does not provide the mechanism to express "pass by reference" semantic, so the compiler emulates it by wrapping primitives in arrays of length 1. The above example is semantically equivalent to the following Java code:

public final class ParTest {
  public static String[] args = new String[0];
  public static int j;

  public static final void P(int var0, int[] var1, int[] var2) {
    if(var0 > 0) {
      var1[0] = var0;
    } else {
      var2[0] = var0;
    }
  }

  static {
    int[] var0 = new int[]{j};
    int[] var1 = new int[]{j};
    P(-1, var0, var1);
    j = var1[0];
    j = var0[0];
    Out.String("j = \u0000".toCharArray());
    Out.Int(j, 0);
  }
}

The assignments to j after the call to P are in reverse order (an implementation detail). I could keep the order of the parameter declarations of P in the assignments. This would produce the right result for this particular example, but it is not a general solution.

Hi Luca,

The specification states

A variable parameter corresponds to an actual parameter that is a variable, and it stands for that variable.

This is unambiguous. There is no need for a caveat on aliasing: it is permitted and I don't agree that it is an "implementation issue". You've implemented pass by value-result instead of pass by reference.

I understand the difficulties. I've just finished my own compiler from Oberon to JVM (you got there first -- grrr, bravo :) ) and the only way I could get around it was to implement variables of all (!) types as 1-element arrays! My compiler is written in Java. It's not a modification of Wirth's compiler but is "Wirthian" in spirit -- single pass, top down recursive descent, etc. It'll be fun and interesting to compare them. :)

Best regards
Kevin

What I have implemented simulates pass by reference and, unless you have aliasing, it works quite well. The Gardens Point Component Pascal compiler uses a similar approach and in fact has the same problem compiling the following:

MODULE Test1;
  IMPORT CPmain, Console;
  VAR j: INTEGER;

  PROCEDURE P(x: INTEGER; VAR y, z: INTEGER);
  BEGIN
      IF x > 0 THEN z := x ELSE  y := x END
  END P;

BEGIN
  P(-1, j, j);
  Console.WriteInt(j, 0);  (*It prints 0, but j should be -1*)
  Console.WriteLn
END Test1.

Your approach would work but I prefer not to wrap everything :)
I would be interested to see your compiler, please publish it.
The bootstrap took me a while to get right, since I had to read the JVM specification to produce the correct class files, but it was fun to drop ASM as a dependency! I would be curious if your compiler can compile mine :)

Feel free to contact me by email.
Cheers,
Luca

Will do. I'm just doing some final tests. And, yes, of course, I'll try it on your compiler :)
Best regards
Kevin

Awesome!
Regarding this VAR parameter passing special case, I will postpone any fix until I find a better solution. I am quite satisfied with the current behavior since and the Gardens Point Component Pascal compiler employs a similar solution.