Super Prev Next

Modules

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.