[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