Self-hosting and the fixed point
The Oberon compiler is written in Oberon. To build it, therefore, an Oberon compiler is needed. This is not a paradox but ordinary self-hosting — but it has a checkable consequence worth understanding precisely, because it is regularly confused.
What self-hosting does not prove
The phrase "the compiler builds itself" means nothing on its own. A compiler with a bug will build itself too — it will simply emit wrong code, and since there is nobody to check, the bug goes unnoticed.
What a fixed point proves
The real check looks different. Take the compiler sitting on the disk — call it generation 0 — and build its own sources with it. That gives generation 1. Now unload the old compiler from memory, load generation 1 and build the very same sources again. That gives generation 2.
If generations 1 and 2 match byte for byte, a fixed point has been reached.
Why that is substantial. Generation 1 was built by the old binary, generation 2 by the new one. If the new compiler emitted even slightly different code from the old, the generations would diverge. Matching means the transformation "source → binary" is stable: applied to its own output, it changes nothing.
This does not prove the compiler correct. It proves it consistent with itself, and that a compiler it builds behaves as the one that built it.
What it looks like on screen
In lab 7 you run one module, but the full experiment goes the same way — two blocks in the log:
OR Compiler 18.4.2016
compiling ORS 1756 992 76547166
compiling ORB 2325 408 2F03B698
compiling ORG 6650 34980 8F476858
compiling ORP 6188 144 E6FCC519
System.Free
ORP unloading
ORG unloading
ORB unloading
ORS unloading
OR Compiler 18.4.2016
compiling ORS 1756 992 76547166
compiling ORB 2325 408 2F03B698
compiling ORG 6650 34980 8F476858
compiling ORP 6188 144 E6FCC519
Code sizes, data sizes and keys match for all four modules. The line
OR Compiler 18.4.2016 is printed anew in the second block: that is the
new ORP.rsc, loaded from disk, announcing itself. So the second generation
really was built by fresh binaries and not by old ones left in memory — without
System.Free the experiment would have been meaningless.
The whole run is 715 million instructions and 1.1 billion cycles on simulated hardware.
Where C remains in this system
The honest answer: in two places, and both outside the machine.
The simulator. Verilator translates Verilog into C++, and that C++ executes the processor's logic. But this is not an implementation of RISC5 — it is an execution of its description. On an FPGA the same Verilog has no C anywhere.
The bridge to the host file system. When the compiler runs not inside the system but directly on the core, something has to hand it files. That wrapper is in C, and it substitutes for the file system only; it computes nothing itself.
The browser version does not even have that bridge: there the files live in a disk image and the compiler runs from inside the system, by mouse and keyboard. No C remains in the loop at all.
Rebuilding the whole system
The compiler is only four modules out of forty-two. The full experiment is to
rebuild the entire system: Kernel, Files, Display, Viewers, Texts,
Oberon, the editor, the graphics, the compiler itself — and compare the result
against what was on the disk.
We did that. Thirty-seven object files matched byte for byte, and the rebuilt image boots and gives the same screen checksum. Three modules do not compile and one shipped file is out of date; that is in the chapter on modules.
A trap in the check
Finally, a methodological note useful well beyond Oberon.
The first version of our check compared disk images byte for byte and happily reported "fixed point reached". It then turned out to pass just as happily on an untouched image, where no rebuild had run at all. A byte comparison does not distinguish "rebuilt and matched" from "never touched".
File dates were no help: this machine has no clock and every timestamp is zero.
The fix was positive evidence: after a real rebuild the disk must gain
PIO.rsc and PIO.smb, which were not there, and Math.rsc must change.
Their absence now counts as failure rather than as leniency.
The moral: a check that cannot fail checks nothing. Before believing a green tick, break what it guards and make sure it turns red.