Getting started with Oberon and OBNC

Karl Landström 2017-05-27 (edited 2017-05-30)

The purpose of this short introduction is not to teach the Oberon programming language but rather to show how Oberon programs are compiled with the OBNC compiler. It also assumes that OBNC is installed on your system.

A First Program

An Oberon program consists of a collection of modules. Each module can contain declarations of constants, types, variables and procedures. A module can also contain a statement sequence with the purpose of initializing variables or starting the execution of the program. The smallest valid Oberon program is the empty module:

MODULE M;
END M.

Of course, an empty module serves no purpose. A slightly more interesting example is the Hello World program:

MODULE hello;
	IMPORT Out;
BEGIN
	Out.String("hello, world");
	Out.Ln
END hello.

To create an executable program for the module hello, we first need to save it in a text document with the name hello.obn. OBNC assumes that every source file has the extension .obn. In a terminal, we then go to the directory which contains the file hello.obn and compile the module with the command

obnc hello.obn

An executable file with the name hello should now have been created. If the program is run with the command

./hello

it should output

hello, world

Using Libraries

As far as the Oberon language is concerned all modules exist in a flat name space. In the module hello above, for instance, the imported module Out refers to a module in OBNC’s basic library. However, if a file named Out.obn exists in the same directory as hello.obn, that module will be used instead. To compensate for Oberon’s lack of module name spaces, OBNC uses a naming convention where non-basic library modules have a prefix.

The method for finding imported modules works like this: First OBNC searches the current directory. Then it searches the colon-separated paths in the environment variable OBNC_IMPORT_PATH. Finally it searches the library directory where OBNC is installed. If an imported module starts with a lower-case prefix, for instance libM, then OBNC also searches first-level subdirectories named lib. The command obnc-path prints the directory path for a module.

To keep identifiers at a reasonable length, a non-basic library module is typically imported without the prefix, using Oberon’s convenient import alias feature:

IMPORT M := libM;

Here is an example using modules stdArgs and stdErr from the library obnc-libstd. These modules are installed in a directory named std.

MODULE PrintArgs;

	IMPORT Args := stdArgs, Out, Err := stdErr;

	VAR
		i, res: INTEGER;
		arg: ARRAY 32 OF CHAR;

BEGIN
	FOR i := 0 TO Args.count - 1 DO
		Args.Get(i, arg, res);
		IF res = 0 THEN
			Out.String(arg);
			Out.Ln
		ELSE
			Err.String("Argument number ");
			Err.Int(i + 1, 0);
			Err.String(" is too long");
			Err.Ln;
			ASSERT(FALSE)
		END
	END
END PrintArgs.