Department of Computing, Macquarie University

Obr Language Reference Manual

Obr is a simple imperative language modelled on the Oberon family of languages designed by Niklaus Wirth. This document provides background information needed to understand the semantics of the language.

The document has five subsections, each dealing with one aspect of the language: basic symbols, programs, declarations, statements, and expressions. Basic symbols are the indivisible atoms of the language, and their meanings are defined by relating them to our shared experience with programming languages. All other constructs are composite---each is formed by combining parts. Their meanings can thus be defined in terms of the meanings of their components and fundamental concepts such as ``sequence of execution.''

Basic Symbols

The basic symbols of Obr are its identifiers, denotations, and delimiters. The following regular expressions describe the structure of identifiers and integers in Obr.
Identifier: [a-zA-Z][a-zA-Z0-9]*
Integer: [0-9]+
Upper- and lower-case versions of the same letter are distinct. The delimiters and other denotations of the language are the following special characters and keywords:
( ) : ; + - * = , := ~ # < > . [ ] .. |
AND ARRAY BEGIN BOOLEAN CONST DO ELSE ELSIF END EXIT FALSE FOR IF
INTEGER LOOP MOD OF OR PROGRAM RETURN THEN TO TRUE VAR WHILE 
An identifier is a freely chosen representation for an object. It is given meaning by a construct of the program. The appearances at which an identifier is given a meaning are called defining occurrences of that identifier. All other appearances of the identifier are called applied occurrences.

Denotations have the usual meanings.

Keywords can be used only as indicated by the context-free grammar productions.

Comments are arbitrary sequences of characters beginning with ``(*'' and ending with ``*)''. Comments cannot be nested. Comments, spaces, and newlines may not appear within basic symbols. Two adjacent basic symbols must be separated by one or more comments, spaces, or newlines, unless one of the basic symbols is a special character. Otherwise comments, spaces, and newlines are meaningless.

Program Structure

Program      : "PROGRAM" Identifier "(" ParameterDecl (";" ParameterDecl)* ")" ":" "INTEGER" ";"
               Declarations "BEGIN" StatementSeq "END" Identifier ".".
StatementSeq : Statement*.
A program specifies a computation by describing a sequence of actions. A computation specified in Obr may be realized by any sequence of actions having the same effect as the one described here for the given computation. The meaning of constructs that do not satisfy the rules given here is undefined. Whether, and in what manner, a particular implementation of Obr gives meaning to undefined constructs is outside the scope of this definition.

A program is executed by reading parameter values from the standard input and executing the component StatementSeq. A Return statement must be executed to terminate the program.

The component statements of a statement sequence are executed in the sequence in which they were written.

Visibility rules

Obr programs contain only one scope: the global scope. Hence all identifiers must be declared as either parameters to the program or in the global declaration section. Thus the visibility rules of Obr are very simple: every applied occurrence of an identifier must identify a defining occurrence of that identifier in the global scope. It is illegal to have two defining occurrences of the same identifier, or an applied occurrence with no corresponding defining occurrence.

All of the occurrences of Identifier in the productions for Program, ParameterDecl, ConstantDecl and VariableDecl are defining occurrences, except the last occurrence in Program. All instances of Identifier in other productions are applied occurrences.

The last occurrence of Identifier in the Program production must identify the defining occurrence immediately after the "PROGRAM" keyword.

Declarations

ParameterDecl : Identifier ":" "INTEGER". 
Declarations  : ("CONST" (ConstantDecl ";")+)?
                ("VAR" (VariableDecl ";")+)?.
ConstantDecl  : Identifier "=" Integer.
VariableDecl  : Identifier ":" TypeSpec.
TypeSpec      : "INTEGER"
              | "BOOLEAN"
              | "ARRAY" Integer "OF" "INTEGER".

Values, Types, Objects, and Variables

Values are abstract entities upon which operations may be performed, types classify values according to the operations that may be performed on them, and objects are the concrete instances of values that are operated upon. Two objects are equal if they are instances of the same value. A variable of type t is a concrete instance of an abstract entity that can refer to (or contain) an object that is an instance of a value of type t.

Every object and variable has a specified extent during which it can be operated upon. The extents of denotations are unbounded; the extents of constants and variables are determined by their declarations.

Values of type "INTEGER" have the usual meanings. The range of integer values is determined by the particular implementation of Obr.

Values of type "BOOLEAN" represent truth values. Only two Boolean values exist: true and false, denoted by the keywords "TRUE" and "FALSE", respectively.

Values of array type represent collections of a given number of integer elements.

Parameter Declarations

A variable is created, and the identifier represents this variable. The extent of the created variable is the entire execution history of the program. It refers initially to an object read from the standard input before program execution begins. The objects read are referred to by the variables named in the parameter list in order from left to right.

If the parameter declaration has the form:

Identifier : t
then the created variable can refer to objects of type t.

Constant Declarations

A constant is created, and the identifier represents this constant. The extent of the created constant begins when the declaration is executed and ends when execution of the program is complete.

If the constant declaration has the form:

Identifier = integer
then the created constant refers to an object whose value is that of the specified integer denotation.

Variable Declarations

A variable is created, and the identifier represents this variable. The extent of the created variable begins when the declaration is executed and ends when execution of the program is complete.

If the variable declaration has the form:

Identifier : t
then the created variable can refer to objects of type t. Initially, it refers to an arbitrary object.

Statements

Statement   : Identifier ":=" Expression ";"
            | Identifier "[" Expression "]" ":=" Expression ";"
            | Conditional
            | Iteration
            | "EXIT" ";"
            | "RETURN" Expression ";".
Conditional : "IF" Expression "THEN" StatementSeq ("ELSE" StatementSeq)? "END".
Iteration   : "LOOP" StatementSeq "END"
            | "WHILE" Expression "DO" StatementSeq "END"
            | "FOR" Identifier ":=" Expression "TO" Expression "DO"
              StatementSeq "END".

Assignments

An assignment statement causes the variable or array element represented by the identifier or subscripted identifier on the left to refer to a new instance of the value yielded by the expression on the right. The type of the expression must be the same as the type of the left-hand side.

Conditionals

Conditional statements specify the conditional execution of guarded statements. The Boolean expression preceding a statement is called its guard. The guards are evaluated in sequence of occurrence, until one evaluates to true, whence its associated statement sequence is executed. If no guard is satisfied, the statement sequence following the symbol "ELSE" is executed, if there is one.

Iterations

A "LOOP" form of iteration repeatedly executes its component statement sequence. The only way to exit a "LOOP" is using an exit statement or return statement.

An iteration of the form

WHILE e DO s END
is identical in meaning to the iteration
LOOP IF ~ e THEN EXIT END; s END
An iteration of the form
FOR id := e1 TO e2 DO s END
requires that id be an integer variable, e1 and e2 be expressions yielding integer values, and the iteration is identical in meaning to the sequence of statements
id := e1;
limit := e2;
LOOP
  IF id > limit THEN EXIT END;
  s; 
  id := id + 1;
END;
where limit is a compiler-generated temporary integer variable.

Exit statements

An exit statement may appear only within the component statement sequence of a "LOOP" iteration. Execution of an exit statement causes termination of the smallest enclosing "LOOP" statement and continuation with the statement following that "LOOP" statement.

Return

A return statement is executed by first evaluating the component expression. Execution of the program is then terminated, with the value of the component expression as the result. The type of the expression must be the same as the return type of the program (which is always "integer") or real in which case the real value is truncated before being returned.

Expressions

Expression structure in Obr is determined by operator precedence and associativity in the usual way:
Expression : SimpleExp | Expression RelOp SimpleExp.
RelOp      : "=" | "#" | "<" | ">".
SimpleExp  : Term | SimpleExp AddOp Term.
AddOp      : "+" | "-" | "OR".
Term       : Factor | Term MulOp Factor.
MulOp      : "*" | "/" | "MOD" | "AND".
Factor     : Identifier | Integer |
           | Identifier "[" Expression "]" 
           | "TRUE" | "FALSE" | "(" Expression ")"
           | "~" Factor | "-" Factor.
Each subexpression (SimpleExp, Term and Factor) may be evaluated to yield an object of a certain type. The operands of an expression may be evaluated in an arbitrary order unless the operator is "OR" or "AND" (see below).

The following table shows all Obr operators with their the operand type(s) and result type.

     Op1      Op2      Result     Operation

=    integer   integer   Boolean     integer equality 
     Boolean   Boolean   Boolean     Boolean equality  
#    integer   integer   Boolean     integer inequality 
     Boolean   Boolean   Boolean     Boolean inequality  
<    integer   integer   Boolean     integer less than  
>    integer   integer   Boolean     integer greater than  
+    integer   integer   integer     integer addition  
-    integer   integer   integer     integer subtraction  
*    integer   integer   integer     integer multiplication  
/    integer   integer   integer     integer division  
MOD  integer   integer   integer     integer remainder  
OR   Boolean   Boolean   Boolean     disjunction   
AND  Boolean   Boolean   Boolean     conjunction   
-    integer             integer     integer negation  
~    Boolean             Boolean     Boolean complement  
Equality yields the value true if its operands have the same value. Otherwise, it yields the value false.

The arithmetic operators addition, subtraction, multiplication, division, and remainder have the usual meaning as long as the values of all operands and results lie in the range permitted by the mapping from Obr objects to target machine objects. Division and remainder are defined only when the value of the right operand is nonzero.

The result of an integer division operation with dividend m and divisor n # 0 is determined as follows:

  1. Let q and 0 < r < |n| be two integers such that m = q * n + r.
  2. If r = 0 then the result of m / n is q.
  3. Otherwise, if m > 0 and n > 0 then the result of m / n is q.
  4. Otherwise, the result of m / n is either q or q+1 at the discretion of the implementor.
The result of the remainder operation m MOD n is given by: m - (m / n) * n.

The Boolean operators "OR" and "AND" are evaluated in a ``short circuit'' fashion. That is, when evaluating "OR" if the left operand evaluates to true then evaluation of the "OR" returns true and the right operand is not evaluated. Similarly, when evaluating "AND" if the left operand evaluates to false then evaluation of the "AND" returns false and the right operand is not evaluated.

Sample Obr Programs

The following is an Obr program to compute the greatest common divisor of two integers. The initial values of the parameters are read from the standard input device as a part of the initialisation process. The result returned by the program is written to the standard output device as a part of the finalisation process.
PROGRAM GCD (x : INTEGER; y : INTEGER) : INTEGER;

BEGIN
    WHILE x # y DO
        IF x > y
            THEN x := x - y
            ELSE y := y - x
        END
    END;
    RETURN x
END GCD.
The factorial program below uses a constant declaration to define the limit imposed by machine arithmetic. If the initial value of v is invalid, the program returns -1 as the answer.
PROGRAM Factorial (v : INTEGER) : INTEGER;

CONST
    limit = 7;

VAR
    c : INTEGER;
    fact : INTEGER;

BEGIN
    IF (v < 0) OR (v > limit) THEN
        RETURN -1
    ELSE
        c := 0;
        fact := 1;
        WHILE c < v DO
            c := c + 1;
            fact := fact * c
        END;
        RETURN fact
    END
END Factorial.

Tony Sloane
Last modified: Wed Sep 9 2009
Copyright (C) 2003-2011 by Macquarie University. All rights reserved.