[Oberon] Eliminating RETURN statements

Hans Klaver hklaver at dds.nl
Wed Apr 8 01:30:16 CEST 2020


In my experience eliminating RETURN statements from function bodies to comply with Oberon-07 syntax is not entirely trivial.

Wirth's example is deceptively simple:

  (* Oberon *)
  PROCEDURE F (x, y: INTEGER): INTEGER;
    IF x < y THEN RETURN y – x 
    ELSE RETURN x – y  
    END
  END F;

  (* Oberon-07 *)
  PROCEDURE F (x, y: INTEGER): INTEGER;
    IF x < y THEN x := y – x 
    ELSE x := x – y 
    END
  RETURN x
  END F;

But very often it is not that simple:

  int Fit (int i, j)
  {
      int k;
      for (k = 0; k <= piecemax[i]; k++)
          if (p[i][k])
	      if (puzzl[j + k])
                  return (false);
      return (true);
  };

Translating this C code to Oberon versions with a FOR 
statement is straightforward:

  (* Oberon *)
  PROCEDURE Fit (i, j: INTEGER): BOOLEAN;
    VAR k: INTEGER;
  BEGIN
    FOR k := 0 TO piecemax[i] DO
      IF p[i][k] THEN 
        IF puzzl[j + k] THEN RETURN FALSE END
      END
    END
    RETURN TRUE
  END Fit;

In Oberon-07 often an auxiliary variable is needed, but sometimes that will not be enough.

My first try below gives no compiler error, but has wrong semantics.
The code where this is from (the Puzzle benchmark from Hennessy's benchmark suite)
provides reference output, so it is not difficult to test this function:

  (* Oberon-07, wrong output! *)
  PROCEDURE Fit (i, j: INTEGER): BOOLEAN;
    VAR k: INTEGER; OK: BOOLEAN;
  BEGIN 
    OK := TRUE;
    FOR k := 0 TO piecemax[i] DO
      IF p[i][k] THEN 
        IF puzzl[j+k] THEN OK := FALSE END
      END
    END
  RETURN OK
  END Fit;

The loop needs an extra guard, and an Oberon FOR loop cannot do that,
so we also need to transform the FOR loop into a WHILE loop:

  (* Oberon-07, right output *)
  PROCEDURE Fit (i, j: INTEGER): BOOLEAN;
    VAR k: INTEGER; OK: BOOLEAN;
  BEGIN 
    k := 0; OK := TRUE;
    WHILE (k <= piecemax[i]) & OK DO
      IF p[i][k] THEN 
        IF puzzl[j + k] THEN OK := FALSE END
      END;
      INC(k)
    END
  RETURN OK
  END Fit;


Another example is the Place function of the same Puzzle benchmark.
The relevant part of the C code is easily translated to Oberon:

  (...)
      for (k = j; k <= size; k++)
          if (!puzzl[k]) return (k);
      return (0);
  }; /* Place */
    

  (* Oberon *)
  (...)
    FOR k := j TO size DO
    	IF ~ puzzl[k] THEN RETURN k END
    END;
    RETURN 0
  END Place;

In the port to Oberon-07 you need two auxiliary variables plus 
an extensive rewrite of the loop to get the correct semantics:

  (* Oberon-07 *)
  (...)
    k := j;  res := 0;  exit := FALSE;
    WHILE (k <= size) & (~ exit) DO
      IF ~ puzzl[k] THEN res := k; exit := TRUE
      ELSE INC(k)
      END
    END
  RETURN res
  END Place;

This Oberon-07 code is definitely much more convoluted than 
the C and older Oberon code, obscuring the algorithm considerably.

Without the reference output that is available in this case it 
would be quite difficult to prove that the semantics of this code 
is the same as that of the C and Oberon code.

I wonder if anyone could propose a simpler correct Oberon-07 version
of this code?

Maybe the Oberon-07 compiler should give a *warning* and not an error 
message if a function procedure has more RETURN statements than one 
single RETURN at its end. Then legacy code could be ported more easily 
and more clearly to the latest version of the language.

Oberon-07 versions of Hennessy's Stanford Benchmark Suite including
a link to the reference outputs can be found here:
  https://github.com/hansklav/Oberon-07/tree/master/Hennessy

Note that in Oberon System V5 the 2019 version of the compiler does not 
produce a workable binary (due to too many global variables), so use the 
2016-08-02 version.

I used OBNC (an Oberon-07 to C compiler that can be used on the 
Posix command line (Windows, Linux, macOS)) to get a version of 
Hennessy.Mod that returns all the reference output correct.

--
Hans Klaver


More information about the Oberon mailing list