A module is a collection of declarations of constants, types, variables, and procedures, together with a sequence of statements for the purpose of assigning initial values to the variables. A module constitutes a text that is compilable as a unit.
Module = MODULE ident ";" [ImportList]
DeclarationSequence
[ BEGIN StatementSequence ]
END ident ".".
ImportList = IMPORT Import {"," Import} ";".
Import = [ident ":="] ident.
The import list specifies the names of the imported modules. If a module A is imported by a module M and A exports an identifier x, then x is referred to as A.x within M. If A is imported as B := A, the object x is referenced as B.x. This allows short alias names in qualified identifiers. A module must not import itself. Identifiers that are to be exported (i.e. that are to be visible in client modules) must be marked by an export mark in their declaration (see section Declarations and scope rules).
The statement sequence following the symbol BEGIN is executed when the module is added to a system (loaded), which is done after the imported modules have been loaded. It follows that cyclic import of modules is illegal. Individual (parameterless and exported) procedures can be activated from the system, and these procedures serve as commands.
MODULE Trees;
(* exports:
Tree, Node, Insert, Search, Write, NewTree
*)
(* exports read-only: Node.name *)
IMPORT Texts, Oberon;
TYPE
Tree* = POINTER TO Node;
Node* = RECORD
name-: POINTER TO ARRAY OF CHAR;
left, right: Tree
END;
VAR w: Texts.Writer;
PROCEDURE (t: Tree) Insert* (name: ARRAY OF CHAR);
VAR p, father: Tree;
BEGIN
p := t;
REPEAT father := p;
IF name = p.name^ THEN RETURN END;
IF name < p.name^ THEN p := p.left
ELSE p := p.right
END
UNTIL p = NIL;
NEW(p); p.left := NIL; p.right := NIL;
NEW(p.name,LEN(name)+1);
COPY(name,p.name^);
IF name < father.name^ THEN father.left := p
ELSE father.right := p
END;
END Insert;
PROCEDURE (t: Tree) Search* (name: ARRAY OF CHAR): Tree;
VAR p: Tree;
BEGIN
p := t;
WHILE (p # NIL) & (name # p.name^) DO
IF name = p.name^ THEN p := p.left
ELSE p := p.right
END
END;
RETURN p
END Search;
PROCEDURE (t: Tree) Write*;
BEGIN
IF t.left # NIL THEN t.left.Write END;
Texts.WriteString(w, t.name^);
Texts.WriteLn(w);
Texts.Append(Oberon.Log, w.buf);
IF t.right # NIL THEN t.right.Write END
END Write;
PROCEDURE NewTree* (): Tree;
VAR t: Tree;
BEGIN
NEW(t); NEW(t.name, 1);
t.name[0] := 0X;
t.left := NIL; t.right := NIL;
RETURN t
END NewTree;
BEGIN
Texts.OpenWriter(w)
END Trees.