oberonc is a single pass, self-hosting compiler for the
programming language. It targets the Java Virtual Machine (version >= 1.8).
This project was started to showcase Niklaus Wirth's approach to writing compilers (see "Compiler Construction - The Art of Niklaus Wirth" by Hanspeter Mössenböck for more details).
oberonc is inspired by Niklaus Wirth's compiler for a RISC processor available
The compiler is compact and does not depend on any third party libraries. It produces Java bytecode in one pass while parsing the source file. Although generating code for a stack machine is straightforward, this task is exacerbated by a complex class file format and the fact that the JVM was designed with the Java language in mind. In fact the JVM lacks many of the primitives required to support Oberon's features, specifically:
- value types
- pass by reference evaluation strategy
- procedure variables (pointer to functions) and relative structural compatibility of types
Implementing those features with workarounds increased significantly the size of the compiler, totaling roughly 6000 lines of Oberon.
The source code is written following as much as possible Niklaus Wirth's
oberonc compile itself in less than 300 ms on an old
Intel i5 @ 2.80GHz (~ 100 ms with a hot VM).
How to build
You can build the compiler on Linux or Windows, you need a JDK >= 1.8 installed, with java and javac in the environment path.
Because you need an Oberon compiler to compile the sources in
src, I have
added to the repository the binaries of the compiler to perform the
make build on the shell, the compiler will compile itself and
write the files in the
out folder. The
make bootstrap command is equivalent
make build, but it overwrites the files in the
To run the compiler, you need to have the OBERON_BIN environmental variable set
bin folder of the repository. This is taken care for you when
How to run the tests
One typical test is to make sure that, by compiling the compiler, we get the
same (bit by bit) class files originally included in the
To run this test simply type
make bootstrapTest (available only on Linux).
This will compile the sources into the
bootstrapOut folder and compare these
resulting class files with the ones in
bin. If something goes wrong
sha1sums will complain.
To run the tests included in the
tests folder, type
make test. The output
should look like this:
... TOTAL: 101 SUCCESSFUL: 101 FAILED: 0
Using the compiler
To use the compiler, you need to have the OBERON_BIN environmental variable set
bin folder of the repository, for example on Linux
export OBERON_BIN=~/oberonc/bin or
The command line syntax of
oberonc is simple.
Let's compile examples/Hello.Mod:
MODULE Hello; IMPORT Out; (* Import Out to print on the console *) BEGIN Out.String("Hello 世界"); Out.Ln (* print a new line *) END Hello.
Assuming you are at the root of the repository, the following command will compile the Hello.Mod example and place the generated classes in the current folder:
Linux java -cp $OBERON_BIN oberonc . examples/Hello.Mod Windows java -cp %OBERON_BIN% oberonc . examples/Hello.Mod
The first argument of oberonc is
., this is the existing folder where the
generated class will be written, the next arguments specify module files to
This will generate Hello.class and Hello.smb. The second file is a symbol file,
it is used only during compilation and enables
oberonc to perform separate
compilation of modules that import Hello. In this simple case Hello.Mod
does not export anything, but the other modules in the
examples folder do.
To run Hello.class, you need the OberonRuntime.class and Out.class. These are
present in the
bin folder so they are already in the class path, we just need
to include the current folder as well to locate Hello.class:
Linux java -cp $OBERON_BIN:. Hello Windows java -cp %OBERON_BIN%;. Hello
If you want to compile and run automatically a simple example called
make runFern. It should open a window like this one:
make clean will delete the output folders generated by
The compiler is distributed under the MIT license found in the LICENSE.txt file.