/Oberon

Oberon parser, code model & browser, compiler and IDE with debugger, and an implementation of the Oberon+ programming language

Primary LanguageC++GNU General Public License v2.0GPL-2.0

Welcome to the Oberon+ parser, code model, compiler and IDE

This project started out as an Oberon-07 parser, code model and transpiler written in C++ and Qt, with the goal to build tools to better understand the Lola-2 compiler and to automatically translate it to maintainable C++ with minimal dependencies to other C++ libraries, and with no dependencies to the Oberon System (see the Lola and LolaCreator repositories).

Oberon turned out to be a language very well suited for compiler front and backend experiments because it is decently simple but still powerful enough to build real-world software, as it supports pointers, static and stack based data structures and call by reference, which are not usually available with scripting languages. In consequence, another goal of this project was to study the feasibility of reusing first LuaJIT and then Mono as a backend for statically typed programming languages like Oberon (see this article and this article). The current implementation of the compiler is able to map full Oberon+ to CIL/ECMA-335 bytecode and C99 source code, and run with good performance (see Linux report and Windows report). There is also a compatible version of the Oberon System, as well as a powerful IDE with semantic navigation and source-level debugging (see below).

During my work with Oberon and systems implemented in Oberon, I kept asking myself what properties the language would need to have so that I could use it for my own systems too, without giving up the goal of making it as simple as possible. From these considerations a new language emerged, which I call Oberon+ (i.e. "Oberon with extensions", abbreviated OBX); it is a general-purpose, procedural and object-oriented programming language in the tradition of and based on Oberon-07, Oberon-2 and Oberon 90, with all the elements of these languages, plus generic modules, enumerations, and many additional simplifications such as support for lower case keywords, optional semicolons, and flexible declaration sequences. See the language report and the dedicated language site for more information. The compiler supports both, Oberon+ as well as most of the syntax and semantics of the previous Oberon versions.

For representative examples of Oberon+ see the Are-we-fast-yet benchmark suite migrated to Oberon+. It also demonstrates generic programming with collections and iterators. A larger example also demonstrating backward compatibility is the Oberon System 3.

What this repository includes

  • The old Oberon-07 validating parser with code model, Lua source code transpiler, C++ transpiler and LuaJIT bytecode compiler (file prefix Ob)
  • The old OberonViewer, Oberon-07 IDE and OBNLC command line version of the compiler/transpiler
  • The Oberon+ LL(1) EBNF grammar
  • The new Oberon+ validating parser, code model, and LuaJIT, CIL/ECMA-335 bytecode and C99 compiler (file prefix Obx)
  • The new Oberon+ IDE (a separate one for LuaJIT and Mono), OBXLJ (LuaJIT) and OBXMC (Mono) command line version of the compiler
  • The Oberon+ version of the "Are we fast yet" and "Hennessy" benchmark suites
  • SDL2 and NAppGUI external library modules and examples

Planned or work-in-progress features

  • Oberon+ validating parser
  • IDE with semantic navigation & source-level debugger
  • LuaJIT compiler backend
  • Complete built-in procedure and Oakwood library implementations
  • Implement a CIL/ECMA-335 compiler backend (done for both IL and direct assembly generator)
  • Use a minimal Mono runtime as an alternative to the LuaJIT VM
  • Foreign Function Interface (FFI, see here for an example, and here for a tool to convert C headers to Oberon+ definition modules))
  • Implement a C transpiler backend (instead the originally planned LLVM backend)
  • Cross-platform OS abstraction/GUI library (using NAppGUI, see here)
  • Write documentation and focus articles (WIP)

The Oberon+ IDE

This is a lean IDE (separate for LuaJIT and Mono) with the following features:

  • Full support of the new Oberon+ programming language
  • Syntax highlighting
  • Semantic code navigation; jump to the declaration of an ident (CTRL+click on the ident)
  • Mark all idents refering to the same declaration
  • Cross-reference view: list all instances of an identifier for easy navigation
  • Module view: shows the records declared in the module and their bound procedures together
  • Hierarchy view: shows the inheritance relation of a selected record or the overrides of a selected bound procedure
  • Browsing history, forward and backward navigation
  • Project files combine modules into a single project and associate them with virtual import paths
  • Built-in LuaJIT or Mono engine
  • Bytecode view (LuaJIT or IL assembler syntax), synchronized to source
  • Integrated source level debugger with breakpoints, stack trace and locals view
  • Built-in optional Oakwood or Oberon System backend library
  • Note that the LuaJIT version (ObxIde.pro) of the IDE is deprecated; use the Mono version (ObxIde2.pro) instead

Oberon+ IDE Screenshot

Oberon+ to CIL/ECMA-335 assembly and IL compiler

  • Generates either IL assembly language or assembly binaries compatible with ECMA-335/ISO 23271:2012
  • The generated code runs on Mono, .NET and CoreCLR (all supported platforms)
  • Optionally generates Mono debug symbol (MDB) files
  • The full Oberon+ language including generics and the Oakwood libraries are supported
  • The SYSTEM module is not supported (and not necessary)
  • FFI with dedicated Oberon+ language constructs for C library integration (see also this tool)

Oberon+ to C99 transpiler

  • Generates C code compatible with ISO 9899:1999 with no other dependencies than the C standard library and the Boehm-Demers-Weiser garbage collector
  • The full Oberon+ language including generics and the Oakwood libraries are supported
  • The SYSTEM module is not supported (and not necessary)
  • Oberon+ FFI language for cross-platform C library integration (see also this tool)

Oberon+ to LuaJIT bytecode compiler

  • This compiler is deprecated, use the CIL compiler instead.
  • Generates LuaJIT 2.0 compatible bytecode
  • The full Oberon+ language including the Oakwood libraries are supported
  • The SYSTEM module is not supported
  • The TRAP() and TRAPIF(condition:BOOLEAN) bult-in procedures let you escape to the debugger
  • FFI with dedicated Oberon+ language constructs for C library integration

Binary versions

Here is a binary version of the Oberon+ IDE for Windows (x86): http://software.rochus-keller.ch/OberonIDE_win32.zip, and here for Windows (AMD64): http://software.rochus-keller.ch/OberonIDE_win64.zip. Just unpack the ZIP somewhere on your drive and double-click either ObxIDE.exe; Qt libraries are included, as well as the OBXMC command line tool, the demo Oberon System and some other example projects (open the project using CTRL+O and then run it using CTRL+R, or right-click to open context menus and select the commands from there).

Here is a version of the Oberon+ IDE (Mono) for Linux x86: http://software.rochus-keller.ch/OberonIDE_linux_i386.tar.gz. Qt 5.4.2 is statically linked with the executables. OBXMC, Mono3 and examples are included as well. And here is a version for Linux x86_64: http://software.rochus-keller.ch/OberonIDE_linux_x86_64.tar.gz.

Here is a version of the Oberon IDE (Mono) for macOS x86_64 (>= El Capitan): http://software.rochus-keller.ch/OberonIDE_macOS_x64.dmg, and here is the version for macOS M1 (>= Monterey): http://software.rochus-keller.ch/OberonIDE_macOS_M1.dmg. The app can just be moved to the drive or used directly from the mounted DMG; everything required is included, also the Oberon System demo. Please note that the CTRL key is mapped to the command key on Mac, but you have to press CTRL+mouse key to trigger the right mouse button; to summarize: just click=left click, command+click=middle click, CTRL+click=right click; note that the shortcuts can differ between platforms. If macOS doesn't let you start the app with double click, use "Open" from the Finder context menu1.

Here is the old version of the Oberon+ IDE (LuaJIT) for Windows: http://software.rochus-keller.ch/OberonIDE_LuaJIT_win32.zip.

Here is the old version of the Oberon+ IDE (LuaJIT) for Linux x86: http://software.rochus-keller.ch/OberonIDE_LuaJIT_linux_i386.tar.gz. It requires a preinstalled Qt version >= 5.4.

Hier is the old version of the Oberon IDE (LuaJIT) for macOS x86_64: http://software.rochus-keller.ch/OberonIDE_LuaJIT_macOS_x64.dmg.

Here is a binary version of the old OberonViewer for Windows: http://software.rochus-keller.ch/OberonViewer_win32.zip Just download, unpack and run it; no installer is needed. The ZIP includes the needed Qt libraries.

Here is a binary version of the old OberonViewer for Linux x86: http://software.rochus-keller.ch/OberonViewer_linux_x86.tar.gz It requires a preinstalled Qt version >= 5.4.

Build Steps

Follow these steps if you want to build the Oberon+ IDE (Mono version) yourself. The build is using LeanQt and the BUSY build system. Note that compiling on Linux requires the build essentials, xcb, libxcb1-dev and libx11-dev packages. On Mac and Windows there are no additional requirements than a toolchain.

  1. Create a new directory; we call it the root directory here
  2. Download https://github.com/rochus-keller/Oberon/archive/refs/heads/master.zip and unpack it to the root directory; rename the resulting directory to "Oberon".
  3. Download https://github.com/rochus-keller/PeLib/archive/refs/heads/OBX.zip and unpack it to the root directory; rename the resulting directory to "PeLib".
  4. Download https://github.com/rochus-keller/MonoTools/archive/refs/heads/master.zip and unpack it to the root directory; rename the resulting directory to "MonoTools".
  5. Download https://github.com/rochus-keller/GuiTools/archive/refs/heads/master.zip and unpack it to the root directory; rename the resulting directory to "GuiTools".
  6. Download https://github.com/rochus-keller/LeanQt/archive/refs/heads/master.zip and unpack it to the root directory; rename the resulting directory to "LeanQt".
  7. Download https://github.com/rochus-keller/BUSY/archive/refs/heads/master.zip and unpack it to the root directory; rename the resulting directory to "build".
  8. Open a command line in the build directory and type cc *.c -O2 -lm -o lua or cl /O2 /MD /Fe:lua.exe *.c depending on whether you are on a Unix or Windows machine; wait a few seconds until the Lua executable is built.
  9. Now type ./lua build.lua ../Oberon -T ide (or lua build.lua ../Oberon -T ide on Windows); wait until the ObxIDE executable is built; you find it in the output subdirectory.

Instead of the command line you can run the build using LeanCreator which uses multiple cores and thus builds faster.

It is still possible to build the tools using Qt 5 with qmake; use ObxIde2.pro for this purpose and proceed as usual when building with Qt.

See https://github.com/rochus-keller/LeanQt/blob/main/Readme.md for instructions on how to build the OBXMC tool if you need it.

The OBX Platform Abstraction Layer (libPal) can be built together with the IDE; in this case just replace the -T ide by -T compiler_and_ide; on Linux x64 please run the BUSY build file in the runtime/Pal subdirectory.

Note that the Mono version of the Oberon+ IDE expects a subdirectory relative to the IDE executable called "mono"; this subdirectory shall contain copies of or links to the mono executable and the mscorlib.dll. Precompiled versions of these files are included in the binary versions referenced above.

Collaboration

The author is not ready yet for collaboration or to accept pull requests.

Support

If you need support or would like to post issues or feature requests please use the Github issue list at https://github.com/rochus-keller/Oberon/issues or send an email to the author.

Footnotes

  1. The OS might also block Mono when you try to run your Oberon+ app; if so, start the mono executable (located in the mono subdirectory) using "Open" from the Finder context menu; finally if you try to run an Oberon+ app accessing a dylib by FFI, the system might block this access; this can be circumvented by selecting the dylib (e.g. libSDL2.dylib) in the Finder and execute "Open with + Terminal" from the context menu; the OS then asks for permission to do so and if you accept it can later also be accessed from your Oberon+ app. The same might also apply to the mono native dylib.