Oberon/ETH Oberon/Tutorial/Compiler

These tutorial pages were written by André Fischer (afi) with editorial assistance of Hannes Marais, were hosted at the ETHZ and remain under the ETH license. Related content is found in the system via Book.Tool. Extended content is also available on paper. Some tutorial pages are in the WayBack archive.

Compiler, Builder and Analyzer User Guide

Tutorial objective

edit

Learn to use the Oberon Compiler and its front-end called Builder.

Estimated time: 30 minutes.

Introduction

edit

The input to the compiler are texts. Such texts are conveniently created in text viewers using the system editor[1]. The following naming convention (widely used) is recommended for files storing source programs:

name.Mod where name usually corresponds to the module's name (MODULE name;).

For an introduction to the Oberon programming language refer to the Literature on Oberon. But the only way to learn a new programming language is by reading and writing programs in it.

A first example

edit

The very first program is the same for all programming languages! In Oberon, the program to write hello, world is

MODULE Hello;
 IMPORT Out;

 PROCEDURE World*;
 BEGIN
  Out.String("hello, world");
  Out.Ln
 END World;

END Hello.

To learn how to use the compiler go through the following steps:

  1. mark the text above and execute Compiler.Compile * ,[2]
  2. observe the message in the Oberon log:
    compiling Hello 33
    The number following the module name is the size of the object file now stored in the current directory.
  3. execute Hello.World and watch the output hello, world in the log.

Using the compiler

edit

The Compiler is an important component of the Oberon system. Except for parts of the inner core, Oberon System 3 is implemented in the original Oberon language. The compiler supplied is an Oberon-2 compiler. Any Oberon-2 compiler is compatible in principle with System 3 and System 3 programs can be written and compiled with Oberon-2. The compiler can generate two types of object files: classical native object files containing target machine code or by default slim binaries. Slim binaries are a new form of object files that contain no object code at all, but a portable description of module's content that makes these files completely independent of the eventual target machine (platform independent). Object code generation is carried out on-the-fly by the module loader (depending on the underlying hardware) and takes no longer than loading traditional object files.

The module Compiler exports only two commands which are documented in a couple of variations in the Compiler.Tool and are described below.

Compiling source text(s) - Compiler.Compile

edit

Compiler.Compile @[\options] compiles the source text starting at the most recent text selection.

Compiler.Compile *[\options] compiles the source text of the marked viewer.

These two first variants of the command allow compiling a module directly from the text editor: there is no need to store the text first.

Compiler.Compile {[\dst=pathName] [\options] {fileName[\options]}}~ | ^ compiles the text of the files named in the parameter list. pathName directs the compiler to store new object files in the specified sub-directory.

The options are:

s - Enable generation of new symbol file
e - Enable generation of extended symbol file
u - Suppress compilation if the object file is up-to-date
w - Enable generation of warning messages

When compiling a sequence of modules, the order of the file names must comply with the module import hierarchy: from the bottom to the top; that is, clients of a module must be compiled after the module itself. You can avoid this by using the Builder facilities instead. Note that each file name may be followed by options.

The following options are valid only when the compiler must generate native object files. These files are not portable across platform boundaries. Therefore, these options should be used only when writing an extension that uses the low-level module SYSTEM or the built-in SIZE function. Example: Win.Audio.Mod

N - Enable generation of native object file
a - Suppress code generation for ASSERT function
p - Suppress initialization of local pointers to NIL
x - Disable Index Checks
n - Disable NIL Checks
t - Disable Type Checks
v - Enable Overflow Checks
c - Disable Range Checks
r - Suppress generation of ref-info
d - Generate MacsBug debugger information (MacOberon)
f - find text position corresponding to the selected program counter value
g - Suppress garbage collection after this compilation

If garbage collection is suppressed, compilation runs faster but might not be completed if too much memory or too many files are used (will trap).

Directing the object files - Compiler.SetDestPath

edit

Compiler.SetDestPath pathName directs the compiler to store new object files in the specified sub-directory.

Directing the loading of slim binaries

edit

The following commands influence the loading of slim binaries:

OMI.AssertsOn / OMI.AssertsOff enables/disables code generation for ASSERTS function.

OMI.ChecksOn / OMI.ChecksOff enables/disables index checks.

OMI.RefsOn / OMI.RefsOff enables/disables generation of detailed reference information.

These commands can be conveniently placed in the Configuration. Text file.

Unloading a module prior to execution

edit

If you make changes to a module and re-compile it after it had been used (i.e. loaded), you must unload it with the System.Free command or with the mouse:

when the mouse focus is positioned on a command name M.P and the middle mouse key is pressed, □ ■ ▁ a left mouse key interclick unloads the module M containing the command and loads a new copy of it, before the command is executed.

Programmer hint and warning: This is very useful while developing and debugging Oberon procedures. It is a handy short cut for executing a System.Free command, but module M is unloaded only when it has no client. Therefore, remember that System.Free and also Builder.Free offer additional possibilities.

Do not be surprised if your corrections have had no impact: the old module version is still in control! Too often will you forget to force the system to use the updated version.

The next example should help to concretize what has been said before:

MODULE Client;
  IMPORT Hello;

  PROCEDURE MyAction*;
  BEGIN Hello.World
  END MyAction;

END Client.
  1. select the beginning of the module text
  2. execute Compiler.Compile @
  3. execute Client.MyAction
  4. execute System.Free Hello ~
  5. observe and explain the log message: Hello unloading failed

Compiling a modified example

edit
MODULE Hello;
  IMPORT Out;

  PROCEDURE World*;
  BEGIN
    Out.String("hello, world");
    Out.Ln
  END World;

END HELLO.
  1. modify the text "hello, world" (e.g. "Hello Oberon")
  2. execute Compiler.Compile * (i.e. re-compile the program)
  3. execute Hello.World and see how the same "hello, world" appears in the Oberon log.
  4. force the system to unload the module and to execute the new version of the command Hello.World with a middle + left mouse keys interclick.

Locating and correcting a syntax error

edit
MODULE Hello;
  IMPORT Out;

  PROCEDURE World*;
  BEGIN
    Out.String("hello, world");
    Out.Ln
  END World;

END HELLO.
  1. delete a semicolon in the program
  2. move the caret to another position in the text
  3. execute Compiler.Compile *
      The Oberon log then displays:
     compiling Hello pos nn err 39
  4. select the line with the error message, and click on the [Locate] button in the menu bar of the Oberon log. This sets the caret at the position of the missing semicolon. The error can easily be corrected.

Debugging compiler detected syntax errors

edit

Compiler detected errors are reported in the Oberon log by messages of the form:
pos <error position> err <error number>

meaning: Error <error number> occurred at position <error position> in the source text.

The following procedure places the caret at an error position in the source text:

  1. make sure that the source text appears in a viewer
  2. mark the viewer
  3. select an error message line in the Oberon log
  4. click on the [Locate] button in the menu bar or
  5. execute the command TextDocs.Locate or
  6. execute the command Edit.Locate.

In some releases, Oberon compiler error numbers, with a short explanation for each, were listed in OberonErrors.Text. In PlugIn Oberon, running on a variety of MS Windows systems, the file is named OP2.Errors. In Oberon 2.3.7, a similar list is in the Errors section of Oberon.Text. [3]

You need to recompile a module until no error is reported. Warnings may however be issued, but they are not considered as errors and thus an object file is created.

The trap viewer

edit

If a command execution fails, the run-time error leads to an abnormal program termination and an error report is displayed in a text viewer 'System.Trap'. The error which caused the trap is identified with a trap code, the contents of certain system registers is displayed and the stack of procedure activations is displayed starting with the procedure on top of the invocation stack. All scalar variables and strings together with their values are also listed.

MODULE Trap;
  VAR arr: ARRAY 3 OF INTEGER;

  PROCEDURE count(n: INTEGER);
  BEGIN arr[n] := n; count(n+1)
  END count;

  PROCEDURE ForceIt*;
  BEGIN count(0)
  END ForceIt;

END Trap.
  1. select the beginning of the module text
  2. execute Compiler.Compile @
  3. execute Trap.ForceIt and study the content of the viewer.

Originally, trap codes were explained at the end of OberonErrors.Text. Subsequently, when the trap viewer was created or enhanced, the explanation in OberonErrors.Text became redundant and was removed.

In order to find the failing statement simply display the source program and mark its viewer. Then select the line in the trap viewer containing the procedure name of interest and recompile the program using the "\d" or "\f" option.

Using the builder

edit

The Builder provides a convenient front-end to the Oberon compiler described above. It makes sure that module texts are presented to the compiler in a correct order, whatever the order of the file names in the parameter list. It is however not a true make tool: all the modules to compile must be specified. Note that the parameter list must contain file names: these may differ from the module names, but that is a matter of convention. The Builder module commands are documented in the Builder.Tool.

Compiling source text - Builder.Compile

edit

Builder.Compile [\options] * compiles the source text of the marked viewer. All error markers inserted in the text are removed.

Builder.Compile [\options] ({fileName}~ | ^ | *) compiles the text of the files named in the parameter list, automatically determining a correct compilation order of the modules. All the modules to compile must be specified, i.e. it is not a true make tool. The options are those of the Compiler.Compile command.

Efficient handling of compiler detected errors

edit

Builder.MarkErrors [^] when the selection contains an error message written by the compiler in the Oberon log, this command inserts an error marker in the marked text for that message and for all of the following messages. An error marker is a special (builder) gadget displaying the number of the error code discovered at that location in the program text. The following error message

pos 111 err 4

would cause 4 to be placed at the position 111.

Builder.NextError advances the caret to the next error marker. When the end of text is reached, searching wraps around to the beginning.

Builder.ClearErrors removes all error markers in the marked text. Automatically performed by a Builder.Compile * command.

Unloading modules - Builder.Free

edit

Builder.Free {fileName}~ | ^ unloads every module named in the parameter list in a correct order. Since file names must appear in the parameter list, this command can only free modules for which the source text is available. To unload other modules use System.Free.

Inserting module icons - Builder.InsertHierarchy

edit

Builder.InsertHierarchy {fileName}~ | ^ inserts an icon for each module named in the parameter list at the caret. The icons are inserted in a correct order of compilation. Each icon is captioned with a file name and its Cmd attribute value is "Desktops.OpenDoc '#Caption '". An example of such icons is found in the Compiler.Panel.

Using the analyzer

edit

The Analyzer provides a convenient complement to the Oberon compiler for locating additional potential errors in a syntactically correct program text. Compiler errors are reported first. No object code is generated. The analyzer locates:

  • non-exported items (variables / constants / types / fields) that are declared but never used, used before being initialized(*), never initialized and initialized but never used.
  • non-exported [type-bound] procedures that are never called.
  • imported modules that are never used.

(*) For variables declared in a different scope, no warning is produced (see option \u, however).

The Analyzer module command is documented in the Analyzer.Tool.

Analyzing source text - Analyzer.Analyze

edit

Analyzer.Analyze @[\options] analyzes the source text starting at the most recent text selection.

Analyzer.Analyze *[\options] analyzes the source text of the marked viewer.

These two first variants of the command allow analyzing a module directly from the text editor: there is no need to store the text first.

Analyzer.Analyze {fileName[\options]}~ | ^ analyzes the source text of the files named in the parameter list.

Analyzer.Analyze warns for possible errors in the Oberon log by message of the form:

pos <error position> warning <warning number>

Refer to Debugging compiler detected syntax error.

Analyzer.Analyze also reports the number of statements (assignment, if, while, procedure call, etc.) in the module. This is convenient for determining the complexity of a program, instead of the number of lines.

Error markers can be inserted in the source text as explained in Efficient handling of compiler detected errors.

Additional information can be obtained by specifying one or several options:

i (intermediate) - locates
- items that are already declared in an outer scope.
- the use of or the assignment to intermediate items, e.g. local variables/parameters declared in an outer scope.
s (evaluation sequence) - locates calls of procedures with more than one parameter, where function calls occur in the parameter list. The evaluation sequence of parameters may affect the side effects of these functions.
t (type-bound) - locates
- the redefinition of type bound procedures.
- the new definition of type bound procedures in an extended type.
u (used) - locates variables declared in a different scope which are used before set.
v (VAR parameter) - locates variables that are used as VAR parameters and are therefore not ensured to be initialized.
x (exported) - locates exported items that are declared but not used by the module itself, used before being initialized, never initialized or initialized but never used.

Index

edit
[ A | B | C | E | N | O | S | T | U ]

A

Analyzer.Analyze
Analyzer.Tool

B

Builder.ClearErrors
Builder.Compile
Builder.Free
Builder.InsertHierarchy
Builder.MarkErrors
Builder.NextError
Builder.Tool

C

Compiler.Compile
Compiler.Panel
Compiler.SetDestPath
Compiler.Tool

E

error marker

N

native object files

O

OberonErrors.Text

S

slim binaries

T

trap viewer

U

unload module


Revised, afi 10 Dec 1996
Installed on 30 05 1997


  1. In V2 (Ceres Oberon) Edit.Open <fileName> . In ETH Oberon Edit.Open <fileName> or ET.Open <fileName> . In V5 (FPGA Oberon) Edit.Open <fileName> .
  2. A command which can be executed with MM in ETH Oberon is crimson. A targeted hyperlink is blue. An untargeted hyperlink is scarlet.
  3. The mailing list has a discussion beginning at 2023-01-07.