This is a conversion from Oberon text to HTML, and from German to English. The converter software is still under development, and some features or information may be missing in this converted version. HTML hypertext facilities are not yet active in this document. To exploit the interactive facilities, use Oberon System 3 and the source of this text, available for download using binary ftp as Oberon System 3 archive. The converter from German to English is still under development as well. A previous version is also available for Oberon V4. To access this and other additional material use ftp.

For the convenience of our students, most of this information and the related material is available in German as well.

N.Wirth

This report is not intended as a programmer's tutorial. It is intentionally kept concise. Its function is to serve as a reference for programmers, implementors, and manual writers. What remains unsaid is mostly left so intentionally, either because it is derivable from stated rules of the language, or because it would require to commit the definition when a general commitment appears as unwise.

To describe the syntax, an extended Backus-Naur Formalism called EBNF is used. Brackets [ and ] denote optionality of the enclosed sentential form, and braces { and } denote its repetition (possibly 0 times). Syntactic entities (non-terminal symbols) are denoted by English words expressing their intuitive meaning. Symbols of the language vocabulary (terminal symbols) are denoted by strings enclosed in quote marks or words written in capital letters, so-called reserved words. Syntactic rules (productions) are marked by a $ sign at the left margin of the line.

1.

$ ident = letter {letter | digit}.

Examples:

x scan Oberon GetSymbol firstLetter

2.

A real number always contains a decimal point. Optionally it may also contain a decimal scale factor. The letter E (or D) is pronounced as "times ten to the power of". A real number is of type REAL, unless it has a scale factor containing the letter D; in this case it is of type LONGREAL.

$ number = integer | real.

$ integer = digit {digit} | digit {hexDigit} "H" .

$ real = digit {digit} "." {digit} [ScaleFactor].

$ ScaleFactor = ("E" | "D") ["+" | "-"] digit {digit}.

$ hexDigit = digit | "A" | "B" | "C" | "D" | "E" | "F".

$ digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9".

Examples:

1987

100H = 256

12.3

4.567E8 = 456700000

0.57712566D-6 = 0.00000057712566

3.

$ CharConstant = """ character """ | digit {hexDigit} "X".

4.

$ string = """ {character} """ .

Examples:

"OBERON" "Don't worry!"

5.

+ := ARRAY IS TO

- ^ BEGIN LOOP TYPE

* = CASE MOD UNTIL

/ # CONST MODULE VAR

~ < DIV NIL WHILE

& > DO OF WITH

. <= ELSE OR

, >= ELSIF POINTER

; .. END PROCEDURE

| : EXIT RECORD

( ) IF REPEAT

[ ] IMPORT RETURN

{ } IN THEN

6.

The identifier is then used to refer to the associated object. This is possible in those parts of a program only which are within the

1. If a type T is defined as POINTER TO T1 (see 6.4), the identifier T1 can be declared textually following the declaration of T, but it must lie within the same scope.

2. Field identifiers of a record declaration (see 6.3) are valid in field designators only.

In its declaration, an identifier in the global scope may be followed by an export mark (*) to indicate that it be exported from its declaring module. In this case, the identifier may be used in other modules, if they import the declaring module. The identifier is then prefixed by the identifier designating its module (see Ch. 11). The prefix and the identifier are separated by a period and together are called a

$ identdef = ident ["*"].

The following identifiers are predefined; their meaning is defined in the indicated sections:

ABS (10.2) LEN (10.2)

ASH (10.2) LONG (10.2)

BOOLEAN (6.1) LONGINT (6.1)

BYTE (6.1) LONGREAL (6.1)

CAP (10.2) MAX (10.2)

CHAR (6.1) MIN (10.2)

CHR (10.2) NEW (6.4)

DEC (10.2) ODD (10.2)

ENTIER (10.2) ORD (10.2)

EXCL (10.2) REAL (6.1)

FALSE (6.1) SET (6.1)

HALT (10.2) SHORT (10.2)

INC (10.2) SHORTINT (6.1)

INCL (10.2) SIZE (10.2)

INTEGER (6.1) TRUE (6.1)

$ ConstantDeclaration = identdef "=" ConstExpression.

$ ConstExpression = expression.

A constant expression can be evaluated by a mere textual scan without actually executing the program. Its operands are constants (see Ch. 8). Examples of constant declarations are

N = 100

limit = 2*N -1

all = {0 .. WordSize-1}

$ TypeDeclaration = identdef "=" type.

$ type = qualident | ArrayType | RecordType | PointerType | ProcedureType.

Examples:

Table = ARRAY N OF REAL

Tree = POINTER TO Node

Node = RECORD key: INTEGER;

left, right: Tree

END

CenterNode = RECORD (Node)

name: ARRAY 32 OF CHAR;

subnode: Tree

END

Function* = PROCEDURE (x: INTEGER): INTEGER

1. BOOLEAN the truth values TRUE and FALSE.

2. CHAR the characters of the extended ASCII set (0X ... 0FFX).

3. SHORTINT the integers between -128 and 127.

4. INTEGER the integers between MIN(INTEGER) and MAX(INTEGER).

5. LONGINT the integers between MIN(LONGINT) and MAX(LONGINT).

6. REAL real numbers between MIN(REAL) and MAX(REAL).

7. LONGREAL real numbers between MIN(LONGREAL) and MAX(LONGREAL).

8. SET the sets of integers between 0 and MAX(SET).

Types 3 to 5 are

LONGREAL J REAL J LONGINT J INTEGER J SHORTINT

$ ArrayType = ARRAY length {"," length} OF type.

$ length = ConstExpression.

A declaration of the form

ARRAY N0, N1, ... , Nk OF T

is understood as an abbreviation of the declaration

ARRAY N0 OF

ARRAY N1 OF

...

ARRAY Nk OF T

Examples of array types:

ARRAY N OF INTEGER

ARRAY 10, 20 OF REAL

$ RecordType = RECORD ["(" BaseType ")"] FieldListSequence END.

$ BaseType = qualident.

$ FieldListSequence = FieldList {";" FieldList}.

$ FieldList = [IdentList ":" type].

$ IdentList = identdef {"," identdef}.

If a record type is exported, field identifiers that are to be visible outside the declaring module must be marked. They are called

Definition:

Examples of record types:

RECORD day, month, year: INTEGER

END

RECORD

name, firstname: ARRAY 32 OF CHAR;

age: INTEGER;

salary: REAL

END

$ PointerType = POINTER TO type.

If p is a variable of type P = POINTER TO T, then a call of the predefined procedure NEW(p) has the following effect (see 10.2): A variable of type T is allocated in free storage, and a pointer to it is assigned to p. This pointer p is of type P; the

$ ProcedureType = PROCEDURE [FormalParameters].

$ VariableDeclaration = IdentList ":" type.

Variables whose identifiers appear in the same list are all of the same type. Examples of variable declarations (refer to examples in Ch. 6):

i, j, k: INTEGER

x, y: REAL

p, q: BOOLEAN

s: SET

f: Function

a: ARRAY 100 OF REAL

w: ARRAY 16 OF

RECORD ch: CHAR;

count: INTEGER

END

t: Tree

If A designates an array, then A[E] denotes that element of A whose index is the current value of the expression E. The type of E must be an integer type. A designator of the form A[E1, E2, ... , En] stands for A[E1][E2] ... [En]. If p designates a pointer variable, p^ denotes the variable which is referenced by p. If r designates a record, then r.f denotes the field f of r. If p designates a pointer, p.f denotes the field f of the record p^, i.e. the dot implies dereferencing and p.f stands for p^.f, and p[E] denotes the element of p^ with index E.

The

1. T0 is an extension of the declared type T of v, and if

2. v is a variable parameter of record type or v is a pointer.

$ designator = qualident {"." ident | "[" ExpList "]" | "(" qualident ")" | "^" }.

$ ExpList = expression {"," expression}.

If the designated object is a variable, then the designator refers to the variable's current value. If the object is a procedure, a designator without parameter list refers to that procedure. If it is followed by a (possibly empty) parameter list, the designator implies an activation of the procedure and stands for the value resulting from its execution. The (types of the) actual parameters must correspond to the formal parameters as specified in the procedure's declaration (see Ch. 10).

Examples of designators (see examples in Ch. 7):

i (INTEGER)

a[i] (REAL)

w[3].ch (CHAR)

t.key (INTEGER)

t.left.right (Tree)

t(CenterNode).subnode (Tree)

$ expression = SimpleExpression [relation SimpleExpression].

$ relation = "=" | "#" | "<" | "<=" | ">" | ">=" | IN | IS.

$ SimpleExpression = ["+"|"-"] term {AddOperator term}.

$ AddOperator = "+" | "-" | OR .

$ term = factor {MulOperator factor}.

$ MulOperator = "*" | "/" | DIV | MOD | "&" .

$ factor = number | CharConstant | string | NIL | set |

$ designator [ActualParameters] | "(" expression ")" | "~" factor.

$ set = "{" [element {"," element}] "}".

$ element = expression [".." expression].

$ ActualParameters = "(" [ExpList] ")" .

The available operators are listed in the following tables. In some instances, several different operations are designated by the same operator symbol. In these cases, the actual operation is identified by the type of the operands.

OR logical disjunction

& logical conjunction

~ negation

These operators apply to BOOLEAN operands and yield a BOOLEAN result.

p OR q stands for "if p then TRUE, else q"

p & q stands for "if p then q, else FALSE"

~ p stands for "not p"

+ sum

- difference

* product

/ quotient

DIV integer quotient

MOD modulus

The operators +, -, *, and / apply to operands of numeric types. The type of the result is that operand's type which includes the other operand's type, except for division (/), where the result is the real type which includes both operand types. When used as operators with a single operand, - denotes sign inversion and + denotes the identity operation.

The operators DIV and MOD apply to integer operands only. They are related by the following formulas defined for any dividend x and positive divisors y:

x = (x DIV y) * y + (x MOD y)

0 <= (x MOD y) < y

+ union

- difference

* intersection

/ symmetric set difference

The monadic minus sign denotes the complement of x, i.e. -x denotes the set of integers between 0 and MAX(SET) which are not elements of x.

x - y = x * (-y)

x / y = (x-y) + (y-x)

= equal

# unequal

< less

<= less or equal

> greater

>= greater or equal

IN set membership

IS type test

Relations are Boolean. The ordering relations <, <=, >, and >= apply to the numeric types, CHAR, and character arrays (strings). The relations = and # also apply to the type BOOLEAN and to set, pointer, and procedure types.

1. T is an extension of the declared type T0 of v, and if

2. v is a variable parameter of record type or v is a pointer.

Assuming, for instance, that T is an extension of T0 and that v is a designator declared of type T0, then the test "v IS T" determines whether the actually designated variable is (not only a T0, but also) a T. The value of NIL IS T is undefined.

Examples of expressions (refer to examples in Ch. 7):

1987 (INTEGER)

i DIV 3 (INTEGER)

~p OR q (BOOLEAN)

(i+j) * (i-j) (INTEGER)

s - {8, 9, 13} (SET)

i + x (REAL)

a[i+j] * a[i-j] (REAL)

(0<=i) & (i<100) (BOOLEAN)

t.key = 0 (BOOLEAN)

k IN {i .. j-1} (BOOLEAN)

t IS CenterNode (BOOLEAN)

$ statement = [assignment | ProcedureCall |

$ IfStatement | CaseStatement | WhileStatement | RepeatStatement |

$ LoopStatement | WithStatement | EXIT | RETURN [expression] ].

$ assignment = designator ":=" expression.

The type of the expression must be included by the type of the variable, or it must extend the type of the variable. The following exceptions hold:

1. The constant NIL can be assigned to variables of any pointer or procedure type.

2. Strings can be assigned to any variable whose type is an array of characters, provided

the length of the string is less than that of the array. If a string s of length n is assigned

to an array a , the result is a[i] = si for i = 0 ... n-1, and a[n] = 0X.

Examples of assignments (see examples in Ch. 7):

i := 0

p := i = j

x := i + 1

k := log2(i+j)

F := log2

s := {2, 3, 5, 7, 11, 13}

a[i] := (x+y) * (x-y)

t.key := i

w[i+1].ch := "A"

$ ProcedureCall = designator [ActualParameters].

Examples of procedure calls:

ReadInt(i) (see Ch. 10)

WriteInt(j*2+1, 6)

INC(w[k].count)

$ StatementSequence = statement {";" statement}.

$ {ELSIF expression THEN StatementSequence}

$ [ELSE StatementSequence]

$ END.

If statements specify the conditional execution of guarded statements. The Boolean expression preceding a statement is called its

Example:

IF (ch >= "A") & (ch <= "Z") THEN ReadIdentifier

ELSIF (ch >= "0") & (ch <= "9") THEN ReadNumber

ELSIF ch = 22X THEN ReadString

END

$ CaseStatement = CASE expression OF case {"|" case} [ELSE StatementSequence] END.

$ case = [CaseLabelList ":" StatementSequence].

$ CaseLabelList = CaseLabels {"," CaseLabels}.

$ CaseLabels = ConstExpression [".." ConstExpression].

Example:

CASE ch OF

"A" .. "Z": ReadIdentifier

| "0" .. "9": ReadNumber

| 22X : ReadString

ELSE SpecialCharacter

END

$ WhileStatement = WHILE expression DO StatementSequence END.

Examples:

WHILE j > 0 DO

j := j DIV 2; i := i+1

END

WHILE (t # NIL) & (t.key # i) DO

t := t.left

END

$ RepeatStatement = REPEAT StatementSequence UNTIL expression.

$ LoopStatement = LOOP StatementSequence END.

Example:

LOOP

IF t1 = NIL THEN EXIT END ;

IF k < t1.key THEN t2 := t1.left; p := TRUE

ELSIF k > t1.key THEN t2 := t1.right; p := FALSE

ELSE EXIT

END ;

t1 := t2

END

Although while and repeat statements can be expressed by loop statements containing a single exit statement, the use of while and repeat statements is recommended in the most frequently occurring situations, where termination depends on a single condition determined either at the beginning or the end of the repeated statement sequence. The loop statement is useful to express cases with several termination conditions and points.

Function procedures require the presence of a return statement indicating the result value. There may be several, although only one will be executed. In proper procedures, a return statement is implied by the end of the procedure body. An explicit return statement therefore appears as an additional (probably exceptional) termination point.

An exit statement consists of the symbol EXIT. It specifies termination of the enclosing loop statement and continuation with the statement following that loop statement. Exit statements are contextually, although not syntactically bound to the loop statement which contains them.

Example:

WITH t: CenterNode DO name := t.name; L := t.subnode END

There are two kinds of procedures, namely

All constants, variables, types, and procedures declared within a procedure body are

In addition to its formal parameters and locally declared objects, the objects declared in the environment of the procedure are also visible in the procedure (with the exception of those objects that have the same name as an object declared locally).

The use of the procedure identifier in a call within its declaration implies recursive activation of the procedure.

$ ProcedureDeclaration = ProcedureHeading ";" ProcedureBody ident.

$ ProcedureHeading = PROCEDURE ["*"] identdef [FormalParameters].

$ ProcedureBody = DeclarationSequence [BEGIN StatementSequence] END.

$ ForwardDeclaration = PROCEDURE "^" identdef [FormalParameters].

$ DeclarationSequence = {CONST {ConstantDeclaration ";"} |

$ TYPE {TypeDeclaration ";"} | VAR {VariableDeclaration ";"}}

$ {ProcedureDeclaration ";" | ForwardDeclaration ";"}.

A

Formal parameters are local to the procedure, i.e. their scope is the program text which constitutes the procedure declaration.

$ FormalParameters = "(" [FPSection {";" FPSection}] ")" [":" qualident].

$ FPSection = [VAR] ident {"," ident} ":" FormalType.

$ FormalType = {ARRAY OF} qualident.

The type of each formal parameter is specified in the parameter list. For variable parameters, it must be identical to the corresponding actual parameter's type, except in the case of a record, where it must be a base type of the corresponding actual parameter's type. For value parameters, the rule of assignment holds (see 9.1). If the formal parameter's type is specified as

ARRAY OF T

the parameter is said to be an

If a formal parameter specifies a procedure type, then the corresponding actual parameter must be either a procedure declared at level 0 or a variable (or parameter) of that procedure type. It cannot be a predefined procedure. The result type of a procedure can be neither a record nor an array.

Examples of procedure declarations:

PROCEDURE ReadInt(VAR x: INTEGER);

VAR i : INTEGER; ch: CHAR;

BEGIN i := 0; Read(ch);

WHILE ("0" <= ch) & (ch <= "9") DO

i := 10*i + (ORD(ch)-ORD("0")); Read(ch)

END ;

x := i

END ReadInt

PROCEDURE WriteInt(x: INTEGER); (* 0 <= x < 10^5 *)

VAR i: INTEGER;

buf: ARRAY 5 OF INTEGER;

BEGIN i := 0;

REPEAT buf[i] := x MOD 10; x := x DIV 10; INC(i) UNTIL x = 0;

REPEAT DEC(i); Write(CHR(buf[i] + ORD("0"))) UNTIL i = 0

END WriteInt

PROCEDURE log2(x: INTEGER): INTEGER;

VAR y: INTEGER; (*assume x>0*)

BEGIN y := 0;

WHILE x > 1 DO x := x DIV 2; INC(y) END ;

RETURN y

END log2

Function procedures:

Name Argument type Result type Function

ABS(x) numeric type type of x absolute value

ODD(x) integer type BOOLEAN x MOD 2 = 1

CAP(x) CHAR CHAR corresponding capital letter

ASH(x, n) x, n: integer type LONGINT x * 2

LEN(v, n) v: array LONGINT the length of v in dimension n

n: integer type

LEN(v) is equivalent with LEN(v, 0)

MAX(T) T = basic type T maximum value of type T

T = SET INTEGER maximum element of sets

MIN(T) T = basic type T minimum value of type T

T = SET INTEGER 0

SIZE(T) T = any type integer type no. of bytes required by T

Type conversion procedures:

Name Argument type Result type Function

ORD(x) CHAR INTEGER ordinal number of x

CHR(x) integer type CHAR character with ordinal number x

SHORT(x) LONGINT INTEGER identity

INTEGER SHORTINT

LONGREAL REAL (truncation possible)

LONG(x) SHORTINT INTEGER identity

INTEGER LONGINT

REAL LONGREAL

ENTIER(x) real type LONGINT largest integer not greater than x

Note that ENTIER(i/j) = i DIV j

Proper procedures:

Name Argument types Function

INC(v) integer type v := v+1

INC(v, x) integer type v := v+x

DEC(v) integer type v := v-1

DEC(v, x) integer type v := v-x

INCL(v, x) v: SET; x: integer type v := v + {x}

EXCL(v, x) v: SET; x: integer type v := v - {x}

COPY(x, v) x: character array, string v := x

v: character array

NEW(v) pointer type allocate v^

HALT(x) integer constant terminate program execution

The second parameter of INC and DEC may be omitted, in which case its default value is 1. In HALT(x), x is a parameter whose interpretation is left to the underlying system implementation.

$ module = MODULE ident ";" [ImportList] DeclarationSequence

$ [BEGIN StatementSequence] END ident "." .

$ ImportList = IMPORT import {"," import} ";" .

$ import = ident [":=" ident].

The import list specifies the modules of which the module is a client. If an identifier x is exported from a module M, and if M is listed in a module's import list, then x is referred to as M.x. If the form "M := M1" is used in the import list, that object declared within M1 is referenced as M.x .

Identifiers that are to be visible in client modules, i.e. outside the declaring module, must be marked by an export mark in their declaration.

The statement sequence following the symbol BEGIN is executed when the module is added to a system (loaded). Individual (parameterless) procedures can thereafter be activated from the system, and these procedures serve as

MODULE Out;

(*exported procedures: Write, WriteInt, WriteLn*)

IMPORT Texts, Oberon;

VAR W: Texts.Writer;

PROCEDURE Write*(ch: CHAR);

BEGIN Texts.Write(W, ch)

END ;

PROCEDURE WriteInt*(x, n: LONGINT);

VAR i: INTEGER; a: ARRAY 16 OF CHAR;

BEGIN i := 0;

IF x < 0 THEN Texts.Write(W, "-"); x := -x END ;

REPEAT a[i] := CHR(x MOD 10 + ORD("0")); x := x DIV 10; INC(i) UNTIL x = 0;

REPEAT Texts.Write(W, " "); DEC(n) UNTIL n <= i;

REPEAT DEC(i); Texts.Write(W, a[i]) UNTIL i = 0

END WriteInt;

PROCEDURE WriteLn*;

BEGIN Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf)

END WriteLn;

BEGIN Texts.OpenWriter(W)

END Out.

Module SYSTEM exports the data type BYTE. No representation of values is specified. Instead, certain compatibility rules with other types are given:

1. The type BYTE is compatible with CHAR and SHORTINT.

2. If a formal parameter is of type ARRAY OF BYTE, then the corresponding actual parameter may be

of any type.

The procedures contained in module SYSTEM are listed in the following tables. They correspond to single instructions compiled as in-line code. For details, the reader is referred to the processor manual. v stands for a variable, x, y, a, and n for expressions, and T for a type.

Function procedures:

Name Argument types Result type Function

ADR(v) any LONGINT address of variable v

BIT(a, n) a: LONGINT BOOLEAN bit n of Mem[a]

n: integer type

CC(n) integer constant BOOLEAN Condition n (0 <= n < 16)

LSH(x, n) x: integer type or SET type of x logical shift

n: integer type

ROT(x, n) x: integer type or SET type of x rotation

n: integer type

VAL(T, x) T, x: any type T x interpreted as of type T

Proper procedures:

Name Argument types Function

GET(a, v) a: LONGINT; v: any basic type v := Mem[a]

PUT(a, x) a: LONGINT; x: any basic type Mem[a] := x

MOVE(s, d, n) s, d: LONGINT; n: integer type Mem[d] ... Mem[d+n-1]

:= Mem[s] ... Mem[s+n-1]

NEW(v, n) v: any pointer type allocate storage block of n bytes

n: integer type assign its address to v

File: OberonReport.Text / NW 1.10.90

Home Up Intro Contents Chapter 1 2 3 4 5 6 7 8 9 10 Design Assert Timing EBNF Report Pas