post

Per Brinch Hansen pages updated

After the scan of Brinch Hansen on Pascal compilers I went on and also scanned the book on Edison: Programming a Personal Computer.

The Per Brinch Hansen now are updated too, the Alfred Hartmann book on Concurrent Pascal added, the Software: Practice and Experience issue on Edision scanned and converted, all articles by per Brinch Hansen listed. Enjoy the works of one of the pioneers: simplicity and parallel programming Per Brinch Hansen!

post

Joyce

Joyce is a secure programming language for concurrent computing designed by Per Brinch Hansen in the 1980s. It is based on the sequential language Pascal and the principles of communicating sequential processes (CSP). It was created to address the shortcomings of CSP to be applied as a programming language, and to provide a tool, mainly for teaching, for distributed computing system implementation.

The language is based around the concept of agents; concurrently executed processes that communicate only by the use of channels and message passing. Agents may activate subagents dynamically and recursively. The development of Joyce formed the foundation of the language SuperPascal, also developed by Hansen around 1993. No source has been published.

Joyce – A Programming Language for Distributed Systems, 1987
Joyce A Language for Computer Networks, November 1979
A Multiprocessor Implementation of Joyce, 1989
Joyce performance on a Multiprocessor, 1988
The Joyce Language Report, 1989

Edison – a Multiprocessor Language

The Edison System, 1982, is comprised of both an operating system and programming environment. The system language, also named Edison, is simple yet powerful. The Edison language is comprised of only a few basic commands and structures. However, these basic fundamentals have been carefully chosen to establish the necessary foundation to produce powerful and extensive applications. The Edison System possesses adequate development facilities, yet is contained in a very small quantity of code. Per Brinch Hansen’s final development system for a PDP-11 contains approximately 10,000 lines of program text. This text includes the operating system, the compiler, the editor, the diskette formatting program, necessary assembly code, and other utility programs. This establishes a powerful yet small environment for the development of concurrent programs.

Software Practice and Experience, Volume 11 No 4. Devoted to the Edison papers, Per Brinch Hansen, see below.
Programming a Personal Computer, Per Brinch Hansen
The book describing thee Edison system, design, development, and listing of programs including compiler in the Edison language, and the interpreter/runtime written in PDP-11 Alva language.
The Design of Edison
(from Software Practice and Experience Vol 11, No 4), Per Brinch Hansen
The Development of Edison, Michael Wonderlich
The EDISON Multiprocessor Language and it’s port to OpenVMS
The Edison-ES programming language

Edison v1 compiler/interpreter

1987, R Kym Horsell
Compiler/interpreter for he Edison language, written in C.
Edisonv1 includes:
– a C preprocessor, cpp, which handles #include and #define commands inside Edison programs.
– an Edison compiler, edcomp, that translates Edison source code into a virtual (stack) machine code.
– an Edison interpreter, edrun, that loads and links machine code files.
– a runtime system stub.
– example programs culled from various textbooks on parallel and concurrent programming.
Local copy of the archive now lost on the internet

P de Wacht Edison compiler archive

Compiler for Edison in C and lex

Sources of Edison (compiler, operating system)


Software Practice and Experience, Volume 11 No 4, April 1981

A whole edition of this magazine devoted to the Edison system by Per Brinch Hansen, as sole author.

Available here complete! In parts, partially scanned like introduction and Edison Programs, partially as separate articles in PDF or HTMl format.


Design of Edison

The article on page 363 –

Edison Programs

Scan of page 397 – Edison programs

Language report: Edison – a Multiprocessor Language

The article Edison – a Multiprocessor Language on page 315 – in html format

by Per Brinch Hansen
Computer Science Department, University of Southern California,
Los Angeles, California 900007, USA


SUMMARY

This paper defines a programming language called Edison. The language
is suitable for teaching the principles of concurrent programming
and for designing reliable real-time programs for multiprocessor systems.
Edison is block structured and includes modules, concurrent statements,
and when statements.

KEY WORDS: Edison Programming language Multiprocessing Modules
Concurrent statements When statements


CONTENTS

  1. LANGUAGE OVERVIEW
  2. SYMBOLS AND SENTENCES
    1. Syntactic rules
    2. Characters
    3. Basic symbols
    4. Separators
    5. Character strings
  3. PROGRAMS AND EXECUTION
  4. NAMED ENTITIES
    1. Standard names
    2. Declarations
    3. Blocks, scopes, and contexts
    4. Modules
  5. VALUES, OPERATIONS, AND TYPES
    1. Type declarations
  6. CONSTANTS
    1. Constant declarations
  7. ELEMENTARY TYPES
    1. Type integer
    2. Arithmetic operators
    3. Type boolean
    4. Boolean operators
    5. Type character
    6. Enumeration types
    7. Elementary constructors
    8. Elementary relations
  8. RANGES
  9. RECORD TYPES
    1. Record constructors
    2. Record relations
  10. ARRAY TYPES
    1. Array constructors
    2. Array relations
  11. SET TYPES
    1. Set constructors
    2. Set relations
    3. Set operators
  12. CONSTRUCTORS
  13. VARIABLES
    1. Variable declarations
    2. Variable operands
    3. Field variables
    4. Indexed variables
    5. Retyped variables
  14. EXPRESSIONS
    1. Retyped factors
  15. STATEMENTS
    1. Skip statements
    2. Assignment statements
    3. Procedure calls
    4. If statements
    5. While statements
    6. When statements
    7. Concurrent statements
  16. PROCEDURES
    1. Complete procedures
    2. Parameters
    3. Functions
    4. Split procedures
    5. Library procedures
  17. PROGRAMS
  18. SYNTAX SUMMARY
  19. ACKNOWLEDGMENT
  20. INDEX

1. LANGUAGE OVERVIEW

This paper defines the programming language Edison. The language
is suitable both for teaching the principles of concurrent programming
and for designing reliable real-time programs for a multiprocessor
system.

The overriding concern in the design of Edison was to achieve
simplicity in the design of medium-sized programs of 1000-2000 lines
of text. This aim led to the selection of a small number of abstract
concepts for modular programming. In particular, the issues of
modularity, concurrency, and synchronization were
separated into distinct language features.

An Edison program describes operations on named entities called
constants, variables, and procedures. The constants and variables
have data values of fixed types. The types determine the possible
values of these entities and restrict the operations that can
be performed on them.

The data types integer, boolean, and character are standard types.
Other types are introduced by enumerating their values
or by describing how the values are composed from other values.
The composition methods for new types are the well-known arrays,
records, and sets. Every type has a name, and two operands are
of the same type only if their types are denoted by the same
name and have the same scope.

The computation of new data values from existing
values is described by expressions in which the operands
are constants, variables, and function calls, while the operators
are the conventional arithmetic, boolean, set, and relational
operators. The computation of composite values in terms of other values
is described by expression lists called constructors.

Statements describe operations such as the assignment of
values to variables and the execution of procedures. The if,
while and when statements describe a choice
among substatements to be executed depending on the truth values of
expressions. The concurrent statement denotes simultaneous
execution of several substatements as concurrent processes.
Process synchronization is controlled by when
statements. The execution of a when statement delays
a process until an expression is true and then performs
an operation on the common variables shared by the processes.
Concurrent processes can only execute when statements one
at a time.

The named entities and statements of a program are grouped into
blocks of two kinds, called procedures and modules. Blocks can
be combined to form other blocks in a nested fashion.

A procedure is a group of named entities and statements that
describe an operation on operands of fixed types. The operands
(known as parameters) may vary from one execution of
the procedure to another.
Each parameter is either a variable or another procedure.
The named entities introduced by a procedure are local
to the procedure and cannot be used outside it. Each execution
of the procedure creates a fresh instance of its parameters
and local variables. These entities disappear again
when the execution of the procedure terminates.

A module is a group of named entities that fall into
two categories: (1) local entities that can only be used within
the module, and (2) exported entities that can be used both
within the module and within the immediately-surrounding block.
The module entities exist as long as the entities of the
immediately-surrounding block. A module serves
to ensure that its local entities are only operated upon
by well-defined procedures which are exported from
the module to the immediately-surrounding block. To ensure
that the local variables are initialized before they are used,
a module includes a statement part that is executed when the module
entities are created.


2. SYMBOLS AND SENTENCES

The programming language Edison is a formal notation
in which programs can be written. The programs are texts
composed of symbol sequences known as sentences.

The language is described in terms of syntactic forms.
A syntactic form is a named class of symbols or sentences with
common properties. The definition of a syntactic form
consists of syntactic rules that define how sentences of the form
are composed and semantic rules that define the meaning of these sentences.

2.1. Syntactic rules

A syntactic rule described in a variant of the Backus-Naur notation
has the form

    S: E

where S stands for the name of the syntactic form while E stands for
a syntax expression that defines the corresponding class of sentences.
The name S consists of a capital letter possibly followed by small letters
and spaces.

Example of a syntactic rule:

    Parameter group:
      ['var'] Variable group # Procedure heading

A syntactic expression has the form

    T1 # T2 # ... # Tn

where T1, T2,…, Tn stand for terms that define classes of sentences.
A sentence of this form is composed by writing a sentence belonging to anyone of
the classes.

Example of a syntax expression:

    ['var'] Variable group # Procedure heading

A syntax term has the form

    F1 F2... Fn

where F1, F2,…, Fn stand for the syntax factors that define classes
of sentences. A sentence of the form is composed by writing a sentence of each
class in the order shown.

Example of a syntax term:

    ['var'] Variable group

A syntax factor has one of the four forms:

  1.     [E]*
    

    This form is an abbreviation for the syntax expression Empty # E # E E # E E E…
    where the name Empty denotes the empty sentence while E denotes a syntax
    expression. A sentence of this form is composed by writing either nothing
    or a finite sequence of sentences of the class E.

    Examples of a syntax factor:

        [Letter # Digit # '_']*
    

     

  2.     [E]
    

    This form is an abbreviation for the syntax expression Empty # E.
    A sentence of this form is composed by writing either nothing or
    a sentence of the class E.

    Example of a syntax factor:

        ['var']
    

     

  3.     N
    

    where N denotes the name of a syntactic form. A sentence of this
    form is composed according to the syntactic rule named N.

  4.  

    Example of a syntax factor:

        Variable group
    

     

  5.     'C1 C2... Cn'
    

    where C1, C2,…, Cn denote characters. A symbol of this form
    is composed of the characters written in the order shown. In particular,
    the syntax factors ‘#’, ‘:’, ‘[‘, ‘]’, ‘*’, and ”’ denote
    the characters #, :, [, ], *, and ‘ used as program symbols.

  6.  

    Example of a syntax factor:

        'var'
    
  7.  

2.2. Characters

    Character:
     Graphic character # New line character
    Graphic Character:
     Letter # Digit # Special character # Space
    Letter:
     'a' # 'b' # 'c' # 'd' # 'e' # 'f' # 'g' # 'h' # 'i' #
     'j' # 'k' # 'l' # 'm' # 'n' # 'o' # 'p' # 'q' # 'r' #
     's' # 't' # 'u' # 'v' # 'w' # 'x' # 'y' # 'z'
    Digit:
     '0' # '1' # '2' # '3' # '4' # '5' # '6' # '7' # '8' # '9'
    Special character:
     '"' # ''' # '(' # ')' # '*' # '+' # ',' # '-' # '.' #
     ':' # ';' # '<' # '=' # '>' # '[' # ']' # '_'

Characters are used to form basic symbols
(see Section 2.3).
A graphic character is represented by a graphic picture
or the deliberate omission thereof (a space). A new line
character marks the end of each line of text.

The character set may be extended with more letters and special
characters. In particular, the letters may be extended with capital
letters. The meaning of capital letters is explained in sections
2.3 and
4.


2.3. Basic symbols

    Basic symbol:
     Special symbol # Word symbol # Name # Numeral #
     Graphic symbol
    Special symbol:
     '+' # '-' # '*' # '=' # '<>' # '<' # '<=' # '>' # '>=' #
     ':=' # '(' # ')' # '[' # ']' # '.' # ',' # ':' # ';'
    Word symbol:
     'also' # 'and' # 'array' # 'begin' # 'cobegin' #
     'const' # 'div' # 'do' # 'else' # 'end' # 'enum' #
     'if' # 'in' # 'lib' # 'mod' # 'module' # 'not' #
     'or' # 'post' # 'pre' # 'proc' # 'record' # 'set' #
     'skip' # 'val' # 'var' # 'when' # 'while' #

The basic symbols are either special symbols, word symbols,
names
(see Section 4),
numerals
(see Section 7.1),
or graphic symbols
(see Section 7.5).

The special symbols and the word symbols have fixed meanings
which will be defined later.

Any capital letter used in a word symbol is considered equivalent
to the corresponding small letter. In this report the word
symbols are printed in boldface type.

2.4. Separators

    Separator:
     Space # New line character # '"' Comment '"'
    Comment:
     [Character]*

The character ” cannot occur within a comment.

Any basic symbol preceded by one or more separators stands
for the basic symbol itself. Two adjacent word symbols or names must be
separated by at least one separator.

Example:

    "This is a comment"

2.5. Character strings

    Character list:
     ''' Graphic character '''
      [',' ''' Graphic character ''']*
    Character string:
     ''' Graphic character [Graphic character]* '''

A character list denotes a sequence of graphic characters.
Character lists are used in constructors
(see Section 12).

A character string is an abbreviation for a character list that
contains the same sequence of graphic characters.

Example of character lists:

    '.'
    'E', 'd', 'i', 's', 'o', 'n'

Examples of character strings:

    '.'
    'Edison'

3. PROGRAMS AND EXECUTION

A program is a description of one or more related data processes,
each process taking place in a number of separate steps. In each step
a well-defined action (an operation) is performed on a set
of entities (the operands).

The act of following a program text and performing the operations
described by it is called the execution of a program (and its operations).
A person or device that executes a program (or part of it) is called
a processor.

The operands of a program generally denote data values that
either remain fixed (constants) or change during the execution (variables).

The operations are generally rules for deriving new data values (results)
from previous data values given by operands. Operations may also use data
values to determine the order in which subsequent operations are to
be executed.

The execution of an operation will have one of three outcomes:

  1. Termination: after a finite time the processor completes the operation.
  2. Failure: after a finite time the processor detects that the operation
    is meaningless and cannot continue the execution of the program.

 

  • Cycling: the processor executes the same cycle of operations
    endlessly.The execution of certain operations may be influenced by properties
    that are not fully described in this report since they vary from
    processor to processor. Such properties are said to be system dependent.

    A program may prescribe a sequence of operations to be carried out
    strictly one at a time. Such a sequence is known as a process.
    A program may also allow several processes to take place simultaneously.
    They are know as concurrent processes.


    4. NAMED ENTITIES

        Name:
         Letter [Letter # Digit # '_']*
    

    Any capital letter used in a name is considered equivalent to
    the corresponding small letter. The word symbols cannot be used
    as names. Apart from that names may be chosen freely.

    A name denotes an entity used in a program. The entity is
    either a constant
    (see Section 6),
    a data type
    (see Section 5),
    a record field
    (see Section 9),
    a variable
    (see Section 13),
    or a procedure
    (see Section 16).

    Examples:

        char
        s
        table
        matrix1
        rc4000a
        end_of_file
    

    4.1. Standard names

        Standard name:
         'bool' # 'char' # 'false' # 'int' # 'true'
    

    The standard names denote the standard types bool, char, int,
    and the truth values false, true
    (see Section 7).
    These names can be used throughout a program without being declared.

    4.2. Declarations

        Declaration:
         Constant declaration list # Type declaration #
         Variable declaration list # Procedure declaration #
         Module declaration
    

    A declaration introduces names to denote program entities
    and describes some of their properties. The entities are either
    constants
    (see Section 6.1),
    types
    (see Section 5.1),
    variables
    (see Section 13.1),
    procedures
    (see Section 16),
    or modules
    (see Section 4.4).

    The use of a name within a program to denote an entity must be
    preceded by a declaration which introduces the name and describes
    the entity it stands for (unless the name is a standard name).
    A declaration of an entity is generally valid within
    one block only
    (see Section 4.3).
    Outside this block the same name
    can be declared and used with other meanings.

    4.3. Blocks, scopes, and contexts

    A block is a piece of program text consisting of (1) declarations
    of named entities, and (2) statements which define operations on
    these entities. The only possible kinds of
    blocks are procedures
    (see Section 16),
    modules
    (see Section 4.4),
    and programs
    (see Section 17).

    Generally a block Q can be a part of another block P in which case
    P is said to contain Q. The block Q is then called an inner block
    of P, while P is called a surrounding block of Q. In general
    a program will consist of a hierarchy of nested blocks.

    The innermost block in which a declaration of a named entity appears
    is called the origin of that declaration.

    The scope of a named entity x is that part of the program text in
    which the name x may be used to denote the entity. A named entity
    is said to be known within its scope.

    The scope generally extends from the declaration of the entity to
    the end of its origin, with the following additional rules:

    1. If the origin is a module M then the scope may be extended to
      the end of the immediately-surrounding block B. The entity is
      then said to be exported from M to B
      (see Section 4.4).
  • If the same name is declared with another meaning in an inner
    block of the origin then the scope does not include the inner block.A given name can only be declared with one meaning in the same block.
    And a name cannot be exported to a surrounding block in which the same
    name is declared with another meaning.

    The meaning of a name used at some point in a block is determined
    by the following rules:

    1. Local entity: if the use of the name is preceded by a declaration
      in the same block of an entity of that name then the use of the name
      denotes the entity.

 

 

  • Exported entity: if the use of the name is preceded by a module
    in the same block from which a declared entity of that name is exported
    to the block then the use of the name denotes the entity.

 

 

  • Global entity: if neither of the above apply then the name has the
    same meaning it has in the immediately-surrounding block at the point
    where the given block begins.When several processes are executed concurrently or when
    a single process calls one or more procedures recursively,
    several instances of a named entity may exist simultaneously.
    At any given moment, however, a process can only operate
    on a single instance of every entity that is know to the process
    at the moment.

    When a process executes a statement it operates on known
    entities selected from a set of entities the current context
    of the process. The context consists of (1) an instance of every
    entity declared in the procedures surrounding the statement,
    and (2) an instance of every entity declared in the modules
    contained in these procedures.

    When a process refers to a known entity an instance of that entity
    is located in the current context of the process in accordance
    with the scope rules.

    Throughout this report the phrase ‘the current context’
    refers to the current context of the process that performs a given
    operation.

    The dynamic changes of contexts are further explained in Sections
    4.4,
    15.3,
    15.7
    and
    17.

    4.4. Modules

    A module is a block that introduces two kinds of named entities
    known as local and exported entities. The module also describes
    an initial operation on these entities.

    The local entities can only be used within the module. The exported
    entities can be used both within the module and within the block
    that immediately surrounds the module.

    A module is either contained in a procedure or in another module.
    When a procedure body is executed an operation known as module
    initialisation is performed on all modules declared within the
    procedure body.

    The initialisation of a module M take place in three steps:

    1. The local and exported entities declared in M are created
      and added to the current context.

 

 

  • The modules declared in M are initialised one at a time in the
    order written.

 

  • The initial operation of M is performed.When the execution of the procedure terminates the entities
    of the module (and those of its inner modules) disappear again.

        Module declaration:
         'module' [Local declaration # Exported declaration]*
           Statement part
        Local declaration:
         Declaration
        Exported declaration:
         '*' Declaration
        Statement part:
         'begin' Statement list 'end'
    

    A module declaration describes a module by means of declarations
    of local and exported entities and by a statement part which
    describes the initial operation by means of a statement list
    (see Section 15).

    An export symbol * in front of a module declaration has no effect.
    Exported entities are discussed further in Sections
    6.1,
    7.6,
    9,
    10,
    11,
    13.1
    and
    16.

    Example:

        module
          const max = 10
          array stack[1 : max] (int)
          var lifo : stack; size : int
        
          *proc push(x : int)
          begin size := size+1; lifo[size] := x end
        
          *proc pop(var x : int)
          begin x := lifo[size]; size := size - 1 end
        
          *proc empty : bool
          begin val empty := (size = 0) end
        
        begin size := 0 end
    

    5. VALUES, OPERATIONS, AND TYPES

    Data are physical phenomena chosen by convention to
    represent facts or ideas. The same fact or idea can be represented
    by a variety of different data. The common notion of data representing
    the same fact or idea will be called a value.

    Data values are grouped into classes called types. A type is
    a named set of values. Each value is of one and only one type.

    The operands that yield data values during execution are constants
    (see Section 6),
    variables
    (see Section 13),
    and expressions
    (see Section 14).

    Any value yielded by an operand during execution will be of one and
    only one type. The operand type can be determined from the program
    text without executing it.

    Standard operations on values are denoted by symbols called operators.
    New operations are described in terms of previously defined operations
    by means of procedures
    (see Section 16).

    Every operation applies to operands of fixed types and delivers
    results of fixed types.

    The types integers, boolean, and character are standard types — types
    that are available without being declared. All other types must be introduced
    by means of type declarations.

    5.1. Type declarations

        Type declaration:
         Enumeration type declaration # Record type declaration #
         Array type declaration # Set type declaration
    

    A type declaration describes a new type which is either an enumeration
    type
    (see Section 7.6),
    record type
    (see Section 9),
    array type
    (see Section 10),
    or set type
    (see Section 11).


    6. CONSTANTS

    A constant is a fixed value of a fixed type.

        Constant symbol:
         Numeral # Truth symbol # Character symbol #
         Enumeration symbol # Constant symbol
    

    A constant symbol denotes a constant and is either a numeral
    (see Section 7.1),
    a truth symbol
    (see Section 7.3),
    an enumeration symbol
    (see Section 7.6),
    or a constant synonym
    (see Section 6.1).

    6.1. Constant declarations

        Constant declaration list:
         'const' Constant declaration
          [';' Constant declaration]*
        Constant declaration:
         Constant synonym '=' Constant symbol
        Constant symbol:
         Name
    

    Every constant declaration introduces a name, called a constant synonym,
    to denote a constant. A constant declaration cannot be of the form
    x = x where x is the synonym.

    The scope rules
    (see Section 4.3)
    apply to declared constants. A constant
    c declared in a module is exported to the immediately-surrounding
    block by exporting the constant declaration list that introduces c
    (see Section 4.4).

    Example:

        const namelength = 12; on = true; last = '.';
         nl = char(10); lf = nl
    

    7. ELEMENTARY TYPES

    An elementary type consists of a finite set of successive
    values, called elementary values.

    The values of any elementary type can be mapped onto a finite set
    of successive integer values (and vice versa). The integer value
    that corresponds to an elementary value x is called
    the ordinal value of x and is denoted int(x).

    The elementary types comprise the standard types integer,
    boolean, and character as well as the enumeration types introduced
    by type declarations.

    7.1. Type integer

    The standard type integer is an elementary type denoted
    by the standard name int. The integer values are a finite
    set of successive whole numbers including both positive and negative
    values. The range of integers is system-dependent. For any
    integer value x we have int(x) = x.

        Numeral:
         Digit [Digit]*
    

    A numeral is a conventional decimal notation for a non-negative
    integer value. Negative integer values must be denoted by
    expressions
    (see Section 14).

    Examples:

        0
        1351
    

    7.2. Arithmetic operands

    The arithmetic operators apply to operands of type
    integer and yield a result of type integer. When applied
    to two operands of type integer the operators +, -,
    *, div, mod denote addition, subtraction,
    multiplication, division, and modulo, respectively.
    The results of
    x div y
    and
    x mod y
    are the truncated quotient of x divided by y
    and the remainder of x div y. They satisfy
    the relation
    x = (x div y) * y + x mod y.

    When applied to a single operand of type integer + and –
    are conventional sign operators.

    An arithmetic operation terminates if the result is within
    the range of integers; otherwise, it fails.

    7.3. Type boolean

    The standard type boolean is an elementary type denoted by
    the standard name bool.

        Truth symbol:
         'false' # 'true'
    

    The truth symbols are standard names that denote the boolean
    values. The boolean values have the ordinal values int(false) = 0
    and int(true) = 1.

    7.4. Boolean operators

    The boolean operators not, and, or
    denote negation, disjunction, and conjunction, respectively.
    They apply to one or two operands of type boolean and yield
    a result of type boolean according to the following rules:

        not false = true          not true = false
        x and false = false       x and true = x
        x or false = x            x or true = true
    

    where x denotes an arbitrary boolean value. A boolean
    operation always terminates.

    7.5. Type character

    The standard type character is an elementary type denoted by the
    standard name char. The set of characters and their
    ordinal values are system dependent
    (see Section 2.2).

        Character symbol:
         Graphic symbol # Control symbol
        Graphic symbol:
         ''' Graphic character '''
        Control symbol:
         'char' '(' Numeral ')'
    

    A character symbol denotes a value of type character. A graphic
    symbol 'c' denotes the graphic character c.
    A control symbol char(n) denotes the character with the
    ordinal value n.

    Examples:

        'a'
        '0'
        ';'
        char(10)
    

    7.6. Enumeration types

        Enumeration type declaration:
         'enum' Type name '(' Enumeration symbol list ')'
        Enumeration symbol list:
         Enumeration symbol [',' Enumeration symbol]*
        Type name:
         Name
        Enumeration symbol:
         Name
    

    An enumeration type declaration introduces a name, called a type name,
    to denote an elementary type and introduces a list of names, called
    enumeration symbols, to denote the successive values of the type.

    The values of an enumeration type enum T(c0,c1,…,cn)
    have the ordinal values
    int(c0) = 0,
    int(c1) = 1, …,
    int(cn) = n.

    The scope rules
    (see Section 4.3)
    apply to an enumeration type and its values. An enumeration type declared
    in a module can be exported together with its values to the
    immediately-surrounding block
    (see Section 4.4).

    Example:

         enum task(flow, scan, log)
         enum filekind(empty, scratch, ascii, code)
    

    7.7. Elementary constructors

        Elementary constructor:
         Type name '(' Expression ')'
    

    An elementary constructor denotes a mapping of the values
    of one elementary type onto the values of a (usually different)
    elementary type. The type name must denote an
    elementary type and the expression must be of an elementary type.

    The elementary constructor int(x) denotes the ordinal
    value of an elementary value x of type T.
    If y is the ordinal value of x,
    that is int(x) = y, then T(y) = x.
    For a value y of any elementary type we have T(y) =
    T(int(y))
    .

    Examples:

        int(slot)
        bool(1 - x)
        char(x + int('0'))
        task(x)
    

    7.8. Elementary relations

    The relational operators =, <>, <, <=, >, >=
    denote the relations equal, not equal, less, not greater,
    greater, and not less. These operators apply to two operands
    of the same elementary type and yield a result of type boolean.

    These operators have their conventional meaning for operands
    of type integer: they yield the value true if the operand values
    satisfy the relations, and the value false
    if they do not. If x and y are values
    of another elementary type then x = y has
    the same value as int(x) = int(y), and similarly
    for the other relations.

    These operations always terminate.


    8. RANGES

    A range is a finite set of successive elementary values of the same
    type from a lower bound x to an upper bound y both included (where x <= y).
    The type of the values is know as the range type.

        Range symbol:
         Lower bound ':' Upper bound
        Lower bound:
         Constant symbol
        Upper bound:
         Constant symbol
    

    A range symbol denotes a range. The bounds are denoted by constant
    symbols which must be of the same elementary type (the range type).

    Ranges are used to define the possible index values of array types
    (see Section 10).

    Examples:

        1 : namelength
        false : true
        'a' : 'b'
        flow : log
    

    9. RECORD TYPES

    A record type consists of a finite set of values, called
    record values. Each record value consists of a finite sequence of
    other values known as fields. Each field is of some known
    type. The set of record values consists of all the possible
    sequences of the possible field values.

        Record type declaration:
         'record' Type name '(' Field list ')'
        Field list:
         Field group [';' Field group]*
        Field group:
         Field name [',' Field name]* ':' Field type
        Field name:
         Name
        Field type:
         Type name
    

    A record type declaration introduces a type name to denote a record
    type. The field list introduces names, called field names, to denote
    the fields. A group of fields have the known type given by another type
    name, called the field type.

    A record type declaration cannot use its own type name as a field type.
    The scope rules
    (see Section 4.3)
    apply to a record type and its fields.
    A record type declared within a module can be exported to the
    immediately-surrounding block
    (see Section 4.4),
    but the corresponding field names
    remain local to the module and cannot be exported from it.

    Examples:

          record semaphore(count : int)
          record time(hour, minute, second : int)
          record attributes(kind : filekind; address : int; protected : bool)
          record entry(id : name; attr : attributes)
    

    9.1. Record constructors

        Record constructor:
         Type name '(' Expression list ')'
        Expression list:
         Expression [',' Expression]*
    

    A record constructor denotes a record value of the type given by
    the type name. The expression list must contain one expression for each
    field of the record type. The order in which the expressions are listed
    in the record constructor and the order in which the field names are listed
    in the record type declaration define a one-to-one correspondence
    between the expressions and the fields. The expressions must be of the same
    types as the corresponding fields.

    The result of executing a record constructor is a record value in
    which the fields are the values obtained by evaluating the corresponding
    expressions in the order written. The execution terminates if the
    evaluation of the expressions terminates.

    Examples:

        semaphore(0)
        time(x, y+5, 0)
        attributes(code, x, true)
        entry(name('edit'), attributes(code, x, true))
    

    9.2. Record relations

    The relational operators = and <> apply to operands of the same record
    type and yield a result of type boolean. Two record values x and y
    of the same type are equal (denoted x = y) if all the corresponding
    fields of the values are equal. The relation x <> y has the same
    value as not (x = y).

    These operations always terminate.


    10. ARRAY TYPES

    An array type consists of a finite set of values, called
    array values. Each array value consists of a finite sequence of other
    values known as elements. The elements are of the same known type. The set
    of array values consists of all the possible sequences of the possible
    element values.

    The elements are distinguished by their position in the array value.
    The positions are denoted by the successive values in a range known as
    the index range. The position of an element is called its index value.

    An array type with n elements of type character is called a
    string of length n.

        Array type declaration:
         'array' Type name '[' Index range ']'
          '(' Element type ')'
        Index range:
         Range symbol
        Element type:
         Type name
    

    An array type declaration introduces a name to denote an
    array type. The index range is given by a range symbol
    (see Section 8).
    The known type of the elements is given by another type name, called
    the element type.

    An array type declaration cannot use its own type name as the
    element type. The scope rules
    (see Section 4.3)
    apply to an array type. An array type declared within a module can be exported
    to the immediately-surrounding block
    (see Section 4.4).

    Examples:

        array name [1 : namelength] (char)
        array poll [false : true] (int)
        array timetable ['a' : 'b'] (time)
        array namelist [flow : log] (name)
    

    10.1. Array constructors

        Array constructor:
         Type name '(' Expression list ')'
    

    An array constructor denotes an array value of the type given by
    the type name. The expression list
    (see Section 9.1)
    must contain one
    expression for each element of the array value (unless the array type
    is a string type). The order in which the expressions are listed
    in the array constructor and the order in which the array elements
    are arranged by the index values define a one to one correspondence
    between the expressions and the elements. The expressions must be of the
    element type given by the array type declaration.

    An array constructor for a string type of length n
    must contain m expressions of type character (where
    1 <= m <= n). This is an abbreviation for an array value consisting
    of the character values given by the m expressions followed
    by n - m spaces.

    The result of executing an array constructor is an array value in
    which the elements are the values obtained by evaluating the corresponding
    expressions in the order written. The execution terminates if the evaluation
    of the expressions terminates.

    Examples:

        name('do',nl,c)
        poll(x+1, y)
        timetable(time(12,30,0), time(x,y+5,0))
        namelist(name('flow'), name('scan'), name('log))
    

    10.2. Array relations

    The relational operators = and <> apply to operands of the same array
    type and yield a result of type boolean. Two array values x and y of the
    same type are equal (denoted x = y) if all the corresponding
    elements of the values are equal. The relation x <> y has
    the same value as not (x = y).

    These operations always terminate.


    11. SET TYPES

    A set type consists of a finite set of values, called set values.
    Each set value consists of a finite (possibly empty) set
    of other values. These other values are known as
    the members of the set value. The members are of the same known
    elementary type, called the base type.

    A member must have an ordinal number in the range 0 : setlimit
    where the upper bound is a system-dependent integer called the set
    limit
    (see Sections 7, 8).

    The range of possible members is called the base range of the set type.
    The set of set values consists of all the possible subsets (including
    the empty one) that can be formed from the values in the base range.

        Set type declaration:
         'set' Type name '(' Base type ')'
        Base type:
         Type name
    

    A set type declaration introduces a type name to denote a set type.
    The known base type is given by another type name and must be
    elementary.

    The scope rules
    (see Section 4.3)
    apply to a set type. A set type
    declared within a module can be exported to the immediately-surrounding
    block
    (see Section 4.4).

    Examples:

        set intset(int)
        set boolset(bool)
        set charset(char)
        set taskset(task)
    

    11.1. Set constructors

        Set constructor:
         Type name ['(' Expression list ')']
    

    A set constructor denotes a set value of the type given by the type name.
    The expression list (if any) consists of one or more expressions
    of the base type given by the set type declaration
    (see Section 9.1).

    The result of executing a set constructor is a set value in which
    the members are the values obtained by evaluating the expressions in
    the order written. The evaluation fails if any of the expression
    values are outside the base range.

    A set constructor without an expression list denotes the
    empty set, which has no members.

    Examples:

        intset
        boolset(x = y)
        charset('0123456789')
        taskset(scan, log)
    

    11.2. Set relations

    The relational operation in applies to operands v and x
    where x denotes a set value of type T while v denotes an elementary
    value of the base type. The relation v in x is
    true if the value v is a member of the set x. The evaluation
    of the relation fails if the value of v is outside the base range.
    The empty set T has no members, that is (v in T) = false
    for all values v in the base range.

    The relational operators = and <> apply to operands x and y
    of the same set type. The relation x = y is true if (v in x)
    = (v in y) for all values v in the base range. The relation
    x <> y has the same values as not (x = y). These operations
    always terminate.

    11.3. Set operators

    The set operators +, -, * denote union, difference, and intersection,
    respectively. These apply to operands x and y of the same set type
    and yield a result of that type.

    For any value v in the base range of the set type:

        v in (x+y)    means   (v in x) or (v in y)
        v in (x-y)    means   (v in x) and not (v in y)
        v in (x*y)    means   (v in x) and (v in y)
    

    The operations always terminate.


    12. CONSTRUCTORS

        Constructor:
         Elementary constructor # Record constructor #
         Array constructor # Set constructor
    

    A constructor denotes a mapping of one or more values of fixed
    types onto a value of a (usually different) type. It is either
    an elementary constructor
    (see Section 7.7),
    a record constructor
    (see Section 9.1),
    an array constructor
    (see Section 10.1),
    or a set constructor
    (see Section 11.1).


    13. VARIABLES

    A variable is a named entity that may assume any of the values of
    a known type. The value of a variable may be used in expressions
    (see Section 14)
    to compute other values and may be changed by means of
    assignments
    (see Section 15.2).

    A variable of a record or array type consists of a group of other
    variables known as subvariables. A variable of an elementary type or a set
    type has no subvariables. A variable that is not a subvariable
    of any other variable is called a whole variable.

    13.1. Variable declarations

        Variable declaration list:
         'var' Variable group [';' Variable group]*
        Variable group:
         Variable name [',' Variable name]* ':' Type name
        Variable name:
         Name
    

    Every variable group in a variable declaration list introduces
    one or more names, called variable names, to denote whole variables of the known
    type given by the type name.

    Other whole variables known as parameters and function variables are
    introduced by procedures
    (see Section 16).

    The scope rules
    (see Section 4.3)
    apply to every whole variable.
    A whole variable v declared in a module is exported to the
    immediately-surrounding block by exporting the variable
    declaration list that introduces v
    (see Section 4.4).

    Example:

        var x, y, size : int; full, free : bool; c, slot : char;
         job : task; s : semaphore; file : entry;
         answers : poll; schedule : timetable; tasks : namelist;
         months : intset; digits : charset;
    

    13.2. Variable operands

        Variable symbol:
         Whole variable symbol # Subvariable symbol #
         Retyped variable symbol
        Whole variable symbol:
         Variable name # Function variable symbol
        Subvariable symbol:
         Field variable symbol # Indexed variable symbol
    

    A variable symbol denotes a whole variable, a subvariable, or
    a retyped variable
    (see Section 13.5)
    used as an operand.

    A whole variable is denoted by a known variable name or by
    a function variable symbol
    (see Section 16.3).

    A subvariable is denoted by a field variable symbol
    (see Section 13.3)
    or an indexed variable symbol
    (see Section 13.4).

    The evaluation of a variable symbol involves locating the corresponding
    variable in the current context. This is called variable selection.
    The selection of a whole variable always terminates. The selection
    of a subvariable is described later.

    If a variable symbol occurs within an expression
    (see Section 14)
    the corresponding variable is first selected and then a copy
    of its value is obtained. This is called variable retrieval.
    The retrieval terminates if the selection does.

    Examples of whole variable symbols:

        x
        s
        file
        answers
        schedule
        tasks
        val empty
    

    13.3. Field variables

    A variable of a record type is called a record variable. It
    contains a subvariable for each field of the record value. The
    subvariables are known as field variables. Their types are the
    corresponding field types given by the record type declaration.

        Field variable symbol:
         Record variable symbol '.' Field name
        Record variable symbol:
         Variable symbol
    

    A field variable symbol v.f consists of a record variable symbol
    v followed by a field name f.

    A field variable is selected in two steps:

    1. The record variable is selected.
    2. The field value given by the field name is selected within
      the record variable.

    The selection of the field variable terminates if the selected
    of the record variable does.

    If v denotes a record variable of type T then the relation

    v = T(v.f1, v.f2, …, v.fm)

    is true, where v.f1, v.f2, …, v.fm denotes the values of the field
    variables of v.

    Examples:

        s.count
        schedule[c].second
        file.attr.kind
    

    13.4. Indexed variables

    A variable of an array type is called an array variable. It contains
    a subvariable for each element of the array value. The subvariables
    are known as indexed variables. Their type is the element type
    given in the array type declaration.

        Indexed variable symbol:
         Array variable symbol '[' Index expression ']'
        Array variable symbol:
         Variable symbol
        Index expression:
         Expression
    

    An indexed variable symbol v[e] consists of an array variable symbol
    v followed by an index expression e.
    The index expression is an expression of the
    same type as the index range given in the array type declaration.

    An indexed variable is selected in three steps:

    1. The array variable is selected.

     

  • The index expression is evaluated to obtain an index value.
  •  

     

  • The indexed variable corresponding to the index value is
    selected within the array variable.The selection of an indexed variable terminates if the selection
    of the array variable terminates and if the evaluation of the index
    expression yields an index value within the index range. The
    selection fails if the index value is outside the index range.

    If v denotes an array variable of type T then the relation

    v = T(v[e1], v[e2], …, v[em])

    is true where v[e1], v[e2], …, v[em] denote the values
    of the indexed variables of v.

    Examples:

        answers[false]
        schedule[c]
        tasks[job][x+1]
        file.id[12]
    

    13.5. Retyped variables

    In most computers data values are held as binary numerals known as
    stored values. The following describes a system depended operation
    that only applies to computers in which stored values of the same
    type occupy the same amount of storage.

    If the stored values of two types occupy the same amount of
    storage the types are said to be of the same length.

    An operation known as retyping maps the values of one type
    onto another type of the same length in such a way that the
    corresponding values of the two types have the same stored values.

    If x denotes a variable of type T1 then x : T2 denotes the
    same variable considered to be of another type T2 of the
    same length. The variable x : T2 is called a retyped variable.

    A selection of possible subvariables of x : T2 proceeds as if
    x was of type T2.

    A retrieval of x : T2 yields a value of type T2 with the same
    stored value as the value of x.

    An assignment
    (see Section 15.2)
    to x : T2 of a value y of type
    T2 assigns a value to x with the same stored value as the value of y.

        Retyped variable symbol:
         Variable symbol ':' Type name
    

    A retyped variable is denoted by a variable symbol followed by a known
    type name.

    Example:
    schedule

    : attributes


    14. EXPRESSIONS

        Expression:
         Simple expression
          [Relational operator Simple expression]
        Relational operator:
         '=' # '&amp;lt;&amp;gt;' # '&amp;lt;' # '&amp;lt;=' # '&amp;gt;' # '&amp;gt;=' # 'in'
        Simple expression:
         [Sign operator] Term #
         Simple expression Adding operator Term
        Sign operator:
         '+' # '-'
        Adding operator:
         '+' # '-' # 'or'
        Term:
         [Term Multiplying operator] Factor
        Multiplying operator:
         '*' # 'div' # 'mod' # 'and'
        Factor:
         Simple operand # '(' Expression ')' #
         'not' Factor # Retyped factor
        Simple operand:
         Constant symbol # Constructor #
         Variable symbol # Procedure call
    

    An expression denotes a rule for computing a value of a fixed
    type known as the expression type. An expression consists of operands
    denoting values and operators denoting operations on the values. Parentheses
    may be used to prescribe the order in which the operators are to be applied
    to the operands. The execution of an expression is known as its evaluation.

    An operator denotes a standard operation on the values of one or two
    operands. The same operator may stand for several different operations depending
    on the operand types. The execution of an operator yields a single
    value as described in Sections
    7.2,
    7.4,
    7.8,
    9.2,
    10.2,
    11.2
    and
    11.3.

    Each operator restricts the operands to which it may be applied
    to belong to certain types only. The syntactic rules for expressions, which
    describe no restrictions arising from types, include many forms that are
    invalid.

    The value of an expression is found either as the value of
    a simple expression or by applying a relational operator
    to the values of two simple expressions.

    The value of a simple expression is found either as the value of a term,
    or by applying a sign operator to the value of a term, or by applying
    an adding operator to the values of another simple expression and a term.

    The value of a term is found either as the value of a factor,
    or by applying a multiplying operator to the values of another term and a
    factor.

    The value of a factor is found either as the value of a simple operand,
    or another expression, or by applying a not operator to the value of
    another factor, or by evaluating a retyped factor
    (see Section 14.1).

    The value of a simple operand is found either as the value of a constant
    (see Section 6),
    a constructor
    (see Section 12),
    a variable
    (see Section 13.2),
    or a procedure call
    (see Section 15.3).

    Examples of simple operands:

        false
        attributes(code, x, true)
        schedule[c].second
        gcd(189, 215)
    

    Examples of factors:

        ... all the examples above ...
        (1 &amp;lt;= x)
        not full
        s : int
    

    Examples of terms:

        ... all the examples above ...
        5 * x div y
        (1 &amp;lt;= x) and (x &amp;lt;= namelength)
    

    Examples of simple expressions:

        ... all the examples above ...
        -10
        x + y - 1
    

    Examples of expressions:

        ... all the examples above ...
        1 &amp;lt;= x
        c in digits
    

    14.1. Retyped expressions

    If x denotes a value of type T1 then x : T2 denotes a value of type T2
    with the same stored value as the value of x. The types T1 and T2
    must be of the same length
    (see Section 13.5).
    The operand x : T2 is called a retyped factor. Its value is system dependent.

        Retyped factor:
         Factor ':' Type name
    

    A retyped factor consists of a factor followed by a known type name.

    Example:

        s : int
    

    15. STATEMENTS

        Statement:
         Skip statement # Assignment statement #
         Procedure call # If statement #
         While statement # When statement #
         Concurrent statement
        Statement list:
         Statement [';' Statement]*
    

    A statement denotes one or more operations and determines (at least
    partially) the order in which these operations are to be executed.
    A statement is either a skip statement
    (see Section 15.1),
    an assignment statement
    (see Section 15.2),
    a procedure call
    (see Section 15.3),
    an if statement
    (see Section 15.4),
    a while statement
    (see Section 15.5),
    a when statement
    (see Section 15.6),
    or a concurrent statement
    (see Section 15.7).

    A statement list denotes execution of a sequence of statements.

    The statements of a statement list are executed one at a time
    in the order written.

    Examples of statement lists:

        full := false
        send(x); read(x)
    

    15.1. Skip statements

        Skip statement:
         'skip'
    

    The word symbol skip denotes the empty operation. The
    execution of a skip has no effect and always terminates.

    15.2. Assignment statements

        Assignment statement:
         Variable symbol ':=' Expression
    

    An assignment statement denotes assignment of a value given by
    an expression to a variable. The variable and the expression must be
    of the same type.

    An assignment statement is executed in three steps:

    1. The variable is selected.

     

  • The expression is evaluated to obtain a value.
  •  

     

  • The value is assigned to the variable.An assignment to a subvariable of a whole variable assigns
    a value to the subvariable without changing the values of the remaining
    subvariables.

    If v denotes a record variable of the type

          record T (f1 : T1; f2 : T2; ...; fm : Tm)
    

    then

           v.f1 := e1    means    v := T(e1, v.f2, ..., v.fm)
           v.f2 := e2    means    v := T(v.f1, e2, ..., v.fm)
    			  ...
           v.fm := em    means    v := T(v.f1, v.f2, ..., em)
    

    where f1, f2, …, fm are the field names of the record type T
    while e1, e2, …, em are expressions of the field type T1, T2, …, Tm.

    Similarly, if v denotes an array of the type

          array T [i1 : im] (Te)
    

    then

          v[i1] := e1    means    v := T(e1, v[i2], ..., v[im])
          v[i2] := e2    means    v := T(v[i1], e2, ..., v[im])
    			      ...
          v[im] := em    means    v := T(v[i1], v[i2], ..., em)
    

    where i1, i2, …, im are the index values of the array type T while
    e1, e2, …, em are expressions of the element type Te.

    Examples:

        x := x + 1
        c := char(x + int('0'))
        full := false
        job := log
        val empty := (size = 0)
        file := entry(name('edit'), attributes(code, x, true))
        s.count := s.count + 1
        schedule[c] := time(12, 30, 0)
    

    15.3. Procedure calls

        Procedure call:
         Procedure name ['(' Argument list ')']
        Argument list:
         Argument [',' Argument]*
        Argument:
         Value argument # Variable argument # Procedure argument
        Value argument:
         Expression
        Variable argument:
         Variable symbol
        Procedure argument:
         Procedure name
    

    A procedure call denotes execution of a known procedure given by
    the procedure name
    (see Section 16).

    The argument list denotes operands that may be operated upon by the
    procedure. The argument list must contain one argument for each parameter
    of the procedure. The order in which the arguments are written in the
    procedure call and the order in which the parameters are listed in the procedure
    declaration define a one to one correspondence between the arguments
    and the parameters.

    Each argument is either a value argument, a variable argument, or
    a procedure argument.

    A value argument must correspond to a value parameter and must be
    an expression of the same type as the corresponding parameter.

    A variable argument must correspond to a variable parameter and must be
    a variable symbol of the same type as the corresponding parameter.

    A procedure argument must correspond to a procedure parameter
    and must be the name of a procedure with the same heading as the
    corresponding parameter (apart from the choice of procedure and
    parameter names).

    The execution of a procedure call takes place in six steps:

    1. The parameters of the procedure called are created one at
      a time in the order listed:

    A value parameter is created as a fresh variable which is
    assigned the value obtained by evaluating the corresponding value argument.

    A variable parameter is created by selecting the corresponding
    variable argument.

    A procedure parameter is created by selecting the corresponding
    procedure argument and selecting a context associated with the
    argument (as described below).

  • A new current context is formed from a context associated
    with the procedure called extended with the parameters.
  •  

    The procedure body is then executed as described in steps (3)-(5):

     

  • The auxiliary entries declared in the procedure body are created
    and added to the current context. The initial values of the auxiliary
    variables are undefined.
  •  

     

  • The local modules of the procedure are initialised one at a time
    in the order written. This extends the current context further as
    described in Section 4.4. The current context is then also
    attached as an attribute to all procedures declared in the
    body (and to all procedures declared in the local modules
    of the body).
  •  

     

  • The statement part of the procedure body is executed.
  •  

     

  • The old context, used prior to the call is re-established
    as the current context.During the execution of the procedure body every operation
    on a variable parameter stands for the same operation performed on
    the corresponding variable argument,
    and every call of a procedure parameter stands
    for the same call of the corresponding procedure argument in the context
    associated with the argument. These parameters are said to be bound
    to the corresponding arguments during the execution of the
    procedure body.

    When a procedure call is used as a statement it must refer to a
    general procedure
    (see Section 16.1).

    When a procedure call is used as an operand in an expression
    it must refer to a function
    (see Section 16.3).
    The execution of a function computes a value of a fixed type given by
    the procedure declaration.

    Examples:

        init
        receive(x)
        gcd(189, 215)
    

    15.4. If statements

        If statement:
         'if' Conditional statement list 'end'
        Conditional statement list:
         Conditional statement ['else' Conditional statement]*
        Conditional statement:
         Boolean expression 'do' Statement list
        Boolean expression:
         Expression
    

    An if statement denotes a single execution of a conditional
    statement list.

    A conditional statement list denotes execution of one
    of several conditional statements (or none of them). Each conditional
    statement consists of an expression of type boolean and a statement list.

    The execution of an if statement consists of executing the conditional
    statement list once.

    The execution of a conditional statement list consists of first
    evaluating the boolean expressions one at a time in the order written
    until one yielding the value true is found or until all have
    been found the yield the value false. If the value obtained
    from an expression is true then the statement list that follows
    the expression is executed; otherwise, none of the statement
    lists are executed. In the latter case, the statement lists are
    said to be skipped.

    Examples:

        if x mod y &amp;lt;&amp;gt; 0 do send(x) end
    
        if job = flow do flow_analysis
        else job = scan do alarm_scanning
        else job = log do data_logging
        else true do error end
    

    15.5. While statements

        While statement:
         'while' Conditional statement list 'end'
    

    A while statement denotes one or more executions of a
    conditional statement list
    (see Section 15.4).

    The execution of a while statement consists of executing the conditional
    statement list repeatedly until all the statement lists are skipped.

    If statement lists continue to be executed forever then the execution cycles.

    Examples:

        while x &amp;lt;&amp;gt; last do send(x); read(x) end
    
        while x &amp;gt; y do x := x - y
        else x &amp;lt; y do y := y - x end
    

    15.6. When statements

        When statement:
          'when' Synchronized statement 'end'
        Synchronized statement:
         Conditional statement list
    

    A when statement consists of a conditional statement list
    known as a synchronized statement. This is a mechanism which can be
    used to give concurrent processes exclusive access to
    common variables when their values satisfy certain conditions.

    A process executes a when statement in two phases:

    1. Synchronization phase: the process is delayed until no other process
      is executing the critical phase of a when statement.

     

  • Critical phase: the synchronized statement is executed as
    described in Section
    15.4.
    If the statement lists are skipped
    the process returns to the synchronizing phase;
    otherwise the execution of the when statement is terminated.Each synchronizing phase of a process lasts a finite time only
    provided that the critical phase of all other concurrent processes
    terminate.

    Concurrent processes are further discussed in Section
    15.7.

    Examples:

        when true do s.count := s.count + 1 end
    
        when s.count &amp;gt; 0 do s.count := s.count - 1 end
    
        when free do x := 1; free := false
        else x &amp;gt; 0 do x := x + 1 end
    

    15.7. Concurrent statements

        Concurrent statement:
         'cobegin' Process statement list 'end'
        Process statement list:
         Process statement ['also' Process statement]*
        Process statement:
         Process constant 'do' Statement list
        Process constant:
         Constant symbol
    

    A concurrent statement denotes execution of a process statement list.
    The process statement list consists of process statements to be
    executed simultaneously. Each process statement describes a process by
    means of a constant symbol (the process constant) and a statement
    list. The type and meaning of process constants are system dependent.
    They may, for example, be used to specify the amount of storage
    required by a process or the processor that must perform the process.

    The execution of a concurrent statement consists of executing the
    process statements simultaneously. The relative ordering of operations
    performed by different processes is unspecified. The execution of such
    operations may generally overlap in time (unless they are described by
    when statements). The execution of a concurrent statement terminates
    when all the concurrent processes terminate.

    When a process reaches a concurrent statement the current context
    of that process becomes the initial context of each of the concurrent
    processes.

    The variable instances in the initial context of the processes are called
    common variables because they can be operated upon by all the
    processes. The common variables enable processes to exchange
    values during their execution.

    When a process calls one or more procedures its its initial
    context is extended with variable instances that are inaccessible
    to the other processes. They are called the private variables of the
    process.

    Two common variables are said to be disjoint if they are different
    variable instances or if none of them is a subvariable of the other;
    otherwise, they are called intersecting variables.

    If each of several concurrent processes only operates on
    private variables and disjoint, common variables then the effect
    of executing a concurrent statement is the same as the effect
    of executing the process statements one at a time in any order.

    But, if concurrent processes operate on intersecting, common
    variables then the effect of executing a concurrent statement is generally
    unpredictable since nothing is known about the order in which the processes
    operate on these variables. However, by restricting the operations on
    intersecting, common variables to well-defined disciplines
    under the control of modules
    (see Section 4.4),
    procedures
    (see Section 16),
    and when statements
    (see Section 15.6)
    it is possible to formulate concurrent statements that make predictable
    use of such variables. The theories used to reason about concurrent
    statements, when statements, and common variables are beyond
    the scope of this report.

    When concurrent processes terminate, the execution of
    all procedures called by these processes has also ended. Consequently,
    the private variables of the processes have disappeared leaving
    only the common variables in the context. The execution of the
    program now continues as a single process in the current context
    of common variables.

    The meaning of variable retrieval
    (see Section 13.2)
    and assignment
    (see Section 15.2)
    defined earlier is valid only if these operations
    are performed one at a time on a given variable. Concurrent processes
    can ensure that this assumption is satisfied by performing all
    operations on intersecting, common variables within when statements.
    The assumption is always satisfied for operations on private variables
    since each of these variables can be used only by a single process
    which performs all its operations (including those on variables) one
    at a time.

    If any of the concurrent processes reaches a concurrent
    statement the execution fails.

    Examples:

        cobegin 1 do print end
    
        cobegin 1 do producer
        also 2 do consumer end
    
        cobegin 1 do node(b[0], b[1])
        also 2 do node(b[1], b[2])
        also 3 do node(b[2], b[0])
        also 4 do send(b[0], 9999) end
    

    16. PROCEDURES

        Procedure declaration:
         Complete procedure declaration # Split procedure part #
          Library procedure declaration
    

    A procedure declaration describes a named procedure. It is either
    a complete procedure
    (see Section 16.1),
    a split procedure
    (see Section 16.4),
    or a library procedure
    (see Section 16.5).

    A procedure declared in a module can be exported to the
    immediately-surrounding block
    (see Section 4.4).

    16.1. Complete procedures

        Complete procedure declaration:
         Procedure heading Procedure body
        Procedure heading:
         'proc' Procedure name ['(' Parameter list ')']
           [':' Function type]
        Procedure name:
         Name
        Function type:
         Type name
        Procedure body:
         [Declaration]* Statement part
    

    A complete procedure declaration defines a procedure completely.
    The procedure heading introduces a name, called a procedure name, to denote
    the procedure and describes the parameters by a parameter list
    (see Section 16.2).
    If the heading includes a known type name, called the function
    type, the the procedure is a function
    (see Section 16.3);
    otherwise, it is a general procedure.

    The procedure body consists of declarations
    (see Section 4.2)
    which describe auxiliary entities used by the procedure and a statement
    part
    (see Section 4.4)
    which describes a sequence of operations on the
    parameters and auxiliary entities.

    A procedure acts as a block
    (see Section 4.3).
    The parameters and
    auxiliary entities are local to the procedure and can only be used
    within the procedure body. The procedure name is local to the
    immediately-surrounding block.

    The execution of the procedure body is invoked by executing a procedure
    call
    (see Section 15.3).

    A procedure may call itself recursively.

    Examples:

        proc init begin full := false end
    
        proc consumer
        var y : char
        begin receive(y);
          while y &amp;lt;&amp;gt; last do
            write(y); receive(y)
          end;
          write(y); write(nl)
        end
    
        proc wait(var s : semaphore)
        begin when s.count &amp;gt; 0 do s.count := s.count - 1 end end
    
        proc push(c : int)
        begin size := size + 1; lifo[size] := c end
    
        proc gcd(x, y: int): int
        begin
          while x &amp;gt; y do x := x - y
          else x &amp;lt; y do y := y - x end;
          val gcd := x
        end
    

    16.2. Parameters

        Parameter list:
         Parameter group [';' Parameter group]*
        Parameter group:
         Value parameter group # Variable parameter group #
         Procedure parameter
        Value parameter group:
         Variable group
        Variable parameter group:
         'var' Variable group
        Procedure parameter:
         Procedure heading
    

    A parameter list describes one or more group of parameters.

    A value parameter group introduces a group of local variables
    known as value parameters. Each value parameter is assigned the
    value of an argument before the procedure body is executed.

    A variable parameter group introduces a group of local variables known
    as variable parameters. Each variable parameter denotes a variable
    argument which is selected before the procedure body is executed.

    A procedure parameter introduces a procedure heading to denote
    a procedure argument and its associated context which are selected before
    the procedure body is executed.

    Examples:

        x, y : int
        var s : semaphore
        id : name; proc lookup(x : name; var y : attributes)
    

    16.3. Functions

    A function is a procedure that describes the computation of a single
    value of a fixed type (the function type). A function call can be used as
    an operand in an expression. The procedure body of a function assigns the value
    of the function to a local variable, called the function variable. The last
    value assigned to this variable during the execution of the procedure
    body becomes the value of the procedure call that invoked
    the execution.

        Function variable symbol:
          'val' Procedure name
    

    A function variable is denoted by the procedure name of the given
    function. The function variable is only known in the body of the function.

    Examples of a function variable symbol:

        val gcd
    

    16.4. Split procedures

    In a procedure that contains mutually recursive procedures some procedure
    calls must precede the corresponding procedure bodies in the program text.
    A procedure that is called in this way must have its declaration split into
    two parts: a predeclaration that precedes these calls and a postdeclaration
    that follows them.

        Split procedure part:
         Procedure predeclaration # Procedure postdeclaration
        Procedure predeclaration:
         'pre' Procedure heading
        Procedure postdeclaration:
         'post' Complete procedure declaration
    

    A procedure predeclaration is a procedure heading that describes how
    to call a split procedure. The procedure name introduced by the procedure
    heading can be used in the program text that extends from the predeclaration
    to the end of the block in which the predeclaration appears.

    A procedure postdeclaration is a complete procedure declaration that
    describes how to call and execute a split procedure. The pre- and post declarations
    must appear in the same block in that order but may be separated by other
    declarations in the same block. The procedure headings of the pre- and
    post declarations must be identical.

    A split procedure declared in a module is exported to the
    immediately-surrounding block
    (see Section 4.4)
    by exporting the corresponding predeclaration.

    Example:

        pre proc variable_symbol(succ : symbols)
        ... other declarations ...
        post proc variable_symbol(succ : symbols)
        begin ... end
    

    16.5. Library procedures

    A program library is a group of procedures that can be called
    by a program without being included in the program. The library
    procedures, which have the form of separate programs
    (see Section 17),
    cannot use global variables or global procedures
    (see Section 4.3).

    A program may call a library procedure if the program contains a declaration
    of the procedure heading and a description of where the procedure body
    is located in the library.

        Library procedure declaration:
         'lib' Procedure heading '[' Library key ']'
        Library key:
         Expression
    

    A library procedure declaration describes a library procedure by
    means of a procedure heading and a library key. The library key
    is an expression that indicates the location of
    the procedure body in the library. The type of the expression is system
    dependent.

    When the library procedure is called the library key is
    evaluated and used to locate the procedure body in the library.
    The execution of the body then proceeds as described earlier
    (see Section 15.3).

    The procedure heading used in the program and the procedure heading used
    in the library to describe the procedure must be the same.

    Example:

        lib proc edit(source, dest : name) [name('edit')]
    

    17. PROGRAMS

        Program:
         [Constant declaration list # Type declaration]*
          Complete procedure declaration
    

    A program consists of a declaration of constants, types, and a single,
    complete procedure
    (see Sections 6.1,
    5.1,
    and
    16.1).

    A program acts as a block
    (see Section 4.3).
    The declared entities
    can be used throughout the program.

    The execution of the program consists of executing a call
    of the procedure in a system dependent context. Initially, the program
    is executed as a single process in the given context.

    Example:

          "This program defines two processes connected by a buffer module.
          A producer process reads a sequence of characters terminated by
          a period and sends them through the buffer to a consumer process
          that receives the characters and writes them. The procedures for
          reading and writing characters are system dependent parameters
          of the program."
        
        const last = '.'; nl = char(10)
        
        proc copier(proc read(var c : char); proc write(c : char))
        
          module
            var slot : char; full : bool
        
          * proc send(c : char)
            begin when not full do slot := c; full := true end end
        
          * proc receive(var c : char)
            begin when full do c := slot; full := false end end
        
          begin full := false end
        
          proc producer
          var x : char
          begin read(x);
            while x &amp;lt;&amp;gt; last do
              send(x); read(x)
            end;
            send(x)
          end
        
          proc consumer
          var y : char
          begin receive(y);
            while y &amp;lt;&amp;gt; last do
              write(y); receive(y)
            end;
            write(y); write(nl)
          end
        
        begin
          cobegin 1 do producer
          also 2 do consumer end
        end
    

    18. SYNTAX SUMMARY

    The following is a list of the syntactic forms of the language.
    Trivial syntactic forms have been omitted. Some forms have been
    eliminated by replacing all references to their names with the
    corresponding syntax expressions. Other forms that were defined
    recursively earlier have been replaced by equivalent ones that are
    defined iteratively. Separators and character strings, which are
    alternative representations of other syntactic forms, are defined
    elsewhere
    (see Sections 2.4
    and
    2.5).

    Name:

     

    Letter [Letter # Digit # ‘_’]*

    Numeral: 

     

    Digit [Digit]*

    Character symbol: 

     

    ”’ Graphic character ”’ # ‘char’ ‘(‘ Numeral ‘)’

    Constant symbol: 

     

    Constant name # Numeral # Character symbol

    Constant declaration: 

     

    Constant name ‘=’ Constant symbol

    Constant declaration list: 

     

    ‘const’ Constant declaration
    [‘;’ Constant declaration]*

    Enumeration symbol list: 

     

    Constant name [‘,’ Constant name]*

    Enumeration type declaration: 

     

    ‘enum’ Type name ‘(‘ Enumeration symbol list ‘)’

    Field group: 

     

    Field name [‘,’ Field name]* ‘:’ Type name

    Field list: 

    Field group [‘;’ Field group]*

    Record type declaration:

  •  

     

    ‘record’ Type name ‘(‘ Field list ‘)’

    Range symbol: 

    Constant symbol ‘:’ Constant symbol

    Array type declaration:

  •  

     

    ‘array’ Type name ‘[‘ Range symbol ‘]’ ‘(‘ Type name ‘)’

    Set type declaration: 

    ‘set’ Type name ‘(‘ Type name ‘)’

    Type declaration:

  •  

     

    Enumeration type declaration # Record type declaration #
    Array type declaration # Set type declaration

    Variable group: 

     

    Variable name [‘,’ Variable name]* ‘:’ Type name

    Variable declaration list: 

     

    ‘var’ Variable group [‘;’ Variable group]*

    Parameter group: 

     

    [‘var’] Variable group # Procedure heading

    Parameter list: 

     

    Parameter group [‘;’ Parameter group]*

    Procedure heading: 

     

    ‘proc’ Procedure name [‘(‘ Parameter list ‘)’]
    [‘:’ Type name]

    Complete procedure declaration: 

     

    Procedure heading [Declaration]* Statement part

    Procedure declaration: 

     

    ‘pre’ Procedure heading #
    [‘post’] Complete procedure declaration #
    ‘lib’ Procedure heading ‘[‘ Expression ‘]’

    Module declaration: 

     

    ‘module’ [Declaration # Exported declaration]*
    Statement part

    Declaration: 

     

    Constant declaration list # Type declaration #
    Variable declaration list # Procedure declaration #
    Module declaration

    Exported declaration: 

     

    ‘*’ Declaration

    Variable symbol: 

     

    Variable name # ‘val’ Procedure name #
    Variable symbol ‘.’ Field name #
    Variable symbol ‘[‘ Expression ‘]’ #
    Variable symbol ‘:’ Type name

    Expression list: 

     

    Expression [‘,’ Expression]*

    Constructor: 

     

    Type name [‘(‘ Expression list ‘)’]

    Factor: 

     

    Constant symbol # Constructor # Variable symbol #
    Procedure call # ‘(‘ Expression ‘)’ #
    ‘not’ Factor # Factor ‘:’ Type name

    Multiplying operator: 

     

    ‘*’ # ‘div’ # ‘mod’ # ‘and’

    Term: 

     

    Factor [Multiplying operator Factor]*

    Adding operator: 

     

    ‘+’ # ‘-‘ # ‘or’

    Simple expression: 

     

    [‘+’ # ‘-‘] Term [Adding operator Term]*

    Relational operator: 

    ‘=’ # ‘<>’ # ‘<‘ # ‘<=’ # ‘>’ # ‘>=’ # ‘in’

    Expression:Simple expression
    [Relational operator Simple expression]

    Argument:Expression # Variable symbol # Procedure name

    Argument list:Argument [‘,’ Argument]*

    Procedure call:Procedure name [‘(‘ Argument list ‘)’]

    Conditional statement:Expression ‘do’ Statement list

    Conditional statement list:Conditional statement [‘else’ Conditional statement]*

    Process statement:Constant symbol ‘do’ Statement list

    Process statement list:Process statement [‘also’ Process statement]*

    Statement:’skip’ # Variable symbol ‘:=’ Expression #
    Procedure call #
    ‘if’ Conditional statement list ‘end’ #
    ‘while’ Conditional statement list ‘end’ #
    ‘when’ Conditional statement list ‘end’ #
    ‘cobegin’ Process statement list ‘end’

    Statement list:Statement [‘;’ Statement]*

    Statement part:’begin’ Statement list ‘end’

    Program:[Constant declaration list # Type declaration]*
    Complete procedure declaration

    ACKNOWLEDGMENT

    The programming language Edison was developed for a multiprocessor system built by Mostek Corporation. This language report was first
    written in January 1979 and was then revised in July 1979, January 1980, and September 1980. In writing (and rewriting) this report I have benefitted greatly from the constructive criticism of Peter Naur. I have also received helpful suggestions from Jon Fellows, David Gries, and Habib Maghami.


post

Concurrent and Sequential Pascal, Solo

Per Brinch Hansen announced Sequenatila and Concurrent Pascal in the Pascal User Group Newsletter nr 4, July 1976:

Concurrent Pascal is a programming language designed by Per Brinch Hansen for writing concurrent computing programs such as operating systems and real-time computing monitoring systems on shared memory computers. A separate language, Sequential Pascal, is used as the language for applications programs run by the operating systems written in Concurrent Pascal. Both languages are extensions of Niklaus Wirth’s Pascal, and share a common threaded code interpreter.
Several constructs in Pascal were removed from Concurrent Pascal for simplicity and security:
– Variant records
– Goto statement, and labels
– Procedures as parameters
– Packed arrays
– Pointer types
– File types, and associated standard input/output procedures
These omissions make it possible to guarantee, by a combination of compile-time checks and minimal run-time checking in the threaded-code interpreter, that a program can not damage itself or another program by addressing outside its allotted space.

Concurrent Pascal includes class, monitor, and process data types. Instances of these types are declared as variables, and initialized in an init statement.
Classes and monitors are similar: both package private variables and procedures with public procedures (called procedure entries). A class instance can be used by only one process, whereas a monitor instance may be shared by processes. Monitors provide the only mechanism for interprocess communication in a Concurrent Pascal program.
Only one process can execute within a given monitor instance at a time. A built in data type, the queue, together with operations delay and continue, are used for scheduling within monitors. Each variable of type queue can hold one process. If many processes are to be delayed in a monitor, multiple queue variables, usually organized as an array, must be provided. The single process queue variable gives a monitor full control over medium-term scheduling, but the programmer is responsible for unblocking the correct process.
A process, like a class or monitor, has local variables, procedures, and an initial statement, but has no procedure entries. The initial statement ordinarily executes forever, calling local procedures, class procedures, and monitor procedures. Processes communicate through monitor procedures. Language rules prevent deadlock by imposing a hierarchy on monitors. But nothing can prevent a monitor from erroneously forgetting to unblock a delayed process (by not calling continue) so the system can still effectively hang up through programming errors.
The configuration of processes, monitors, and classes in a Concurrent Pascal program is normally established at the start of execution, and is not changed thereafter. The communication paths between these components are established by variables passed in the init statements, since class and monitor instance variables cannot be used as procedure parameters.
Solo
The single-user operating system Solo is written in the programming language Concurrent Pascal. It supports the development of Sequential and Concurrent Pascal programs for the PDP 11/45 computer. Input/output are handled by concurrent processes. Pascal programs can call one another recursively and pass arbitrary parameters among themselves. This makes it possible to use Pascal as a job control language. Solo is the first major example of a hierarchical concurrent program implemented in terms of abstract data types (classes, monitors and processes) with compile-time control of most access rights

The Architecture of Concurrent Programs, 1977.
About the languages and Solo operating system.
Most of the book is covered in the following articles.
A Concurrent Pascal Compiler for Minicomputers
Afred C. Hartmann (who wrote the compiler!)
Concurrent Pascal Introduction July 1975
Concurrent Pascal Machine October 1975
Concurrent Pascal Report June 1975
Distributed processes:
a Concurrent Programming Concept, 1978
Experience with Modular Concurrent Programming, 1977
IEEE Programming Language Concurrent Pascal, 1975
Monitors and Concurrent Pascal:
A Personal History, 1993
Multiprocessor architecture for Concurrent Programs, 1978
The Structure of the Nadex Operating System
Robert Ypung, Virgil Wallentine 1981
Network: A Multiprocessor Program
Overview of Concurrent Pascal for the Interdata, 1978
The Programming Language Concurrent Pascal, 1975
Reproducable Testing of Monitors, 1978
Scheduling in Concurrent Pascal
Schneider, Bernmstein, 1978
The Solo Operating System:
Processes, Monitors and Classes, 1976
The Solo Operating system:
A Concurrent Pascal Program, 1976
Solo32: A Concurrent Pascal Operating System
with Unix Interface, Martin Wilde, 1984

The archive with the sources of Solo and the Pascal compilers Concurrent and Sequential Pascal for a PDP-11/34

From http://www.bitsavers.org/bits/DEC/pdp11/Brinch_Hansen_SOLO/

LIST(CATALOG,ALL,CONSOLE)
CONSOLE: 
SOLO SYSTEM FILES

AUTOLOAD     SCRATCH      PROTECTED         1 PAGES
BACKUP       SEQCODE      PROTECTED         4 PAGES
BACKUPMAN    ASCII        PROTECTED         3 PAGES
BACKUPTEXT   ASCII        PROTECTED        14 PAGES
BUILDBATTEXT ASCII        UNPROTECTED       1 PAGES
BUILDTEXT    ASCII        UNPROTECTED       4 PAGES
CARDS        SEQCODE      PROTECTED         5 PAGES
CARDSMAN     ASCII        PROTECTED         2 PAGES
CARDSTEXT    ASCII        PROTECTED        12 PAGES
CATALOG      SCRATCH      PROTECTED        15 PAGES
CDISKTEXT    ASCII        UNPROTECTED      10 PAGES
COMMANDS     ASCII        UNPROTECTED       1 PAGES
CONSOLE      SEQCODE      PROTECTED         1 PAGES
CONSOLEMAN   ASCII        PROTECTED         1 PAGES
CONSOLETEXT  ASCII        PROTECTED         8 PAGES
COPY         SEQCODE      PROTECTED         4 PAGES
COPYMAN      ASCII        PROTECTED         2 PAGES
COPYTEXT     ASCII        PROTECTED        12 PAGES
CPASCAL      SEQCODE      PROTECTED         7 PAGES
CPASCALMAN   ASCII        PROTECTED         3 PAGES
CPASCALTEXT  ASCII        PROTECTED        18 PAGES
CPASS1       SEQCODE      PROTECTED        20 PAGES
CPASS1TEXT   ASCII        PROTECTED        54 PAGES
CPASS2       SEQCODE      PROTECTED        26 PAGES
CPASS2TEXT   ASCII        PROTECTED        72 PAGES
CPASS3       SEQCODE      PROTECTED        35 PAGES
CPASS3TEXT   ASCII        PROTECTED        90 PAGES
CPASS4       SEQCODE      PROTECTED        27 PAGES
CPASS4TEXT   ASCII        PROTECTED        71 PAGES
CPASS5       SEQCODE      PROTECTED        20 PAGES
CPASS5TEXT   ASCII        PROTECTED        56 PAGES
CPASS6       SEQCODE      PROTECTED        16 PAGES
CPASS6TEXT   ASCII        PROTECTED        53 PAGES
CPASS7       SEQCODE      PROTECTED        18 PAGES
CPASS7TEXT   ASCII        PROTECTED        56 PAGES
CPTEXT       ASCII        UNPROTECTED       2 PAGES
DISK         SEQCODE      PROTECTED         2 PAGES
DISKMAN      ASCII        PROTECTED         1 PAGES
DISKTEXT     ASCII        PROTECTED         9 PAGES
DO           SEQCODE      PROTECTED        11 PAGES
DOMAN        ASCII        PROTECTED         3 PAGES
DOTEXT       ASCII        PROTECTED        26 PAGES
EDIT         SEQCODE      PROTECTED         8 PAGES
EDITMAN      ASCII        PROTECTED         5 PAGES
EDITTEXT     ASCII        PROTECTED        20 PAGES
FILE         SEQCODE      PROTECTED        20 PAGES
FILEMAN      ASCII        PROTECTED         3 PAGES
FILETEXT     ASCII        PROTECTED        54 PAGES
IO           SEQCODE      PROTECTED         4 PAGES
IOTEXT       ASCII        PROTECTED        13 PAGES
JOB          SEQCODE      PROTECTED        40 PAGES
JOBBUFFER1   SCRATCH      PROTECTED        20 PAGES
JOBBUFFER2   SCRATCH      PROTECTED        20 PAGES
JOBINPUT     SEQCODE      PROTECTED         3 PAGES
JOBINPUTTEXT ASCII        PROTECTED         6 PAGES
JOBOUTPUT    SEQCODE      PROTECTED         2 PAGES
JOBOUTPUTTXT ASCII        PROTECTED         6 PAGES
JOBPREFIX    ASCII        PROTECTED         1 PAGES
JOBSERVICE   SEQCODE      PROTECTED         3 PAGES
JOBSERVICETX ASCII        PROTECTED         8 PAGES
JOBSTREAM    CONCODE      PROTECTED        17 PAGES
JOBSTREAMTXT ASCII        PROTECTED        50 PAGES
KERNELTEXT1  ASCII        UNPROTECTED     134 PAGES
KERNELTEXT2  ASCII        UNPROTECTED     129 PAGES
KERNELTEXT3  ASCII        UNPROTECTED     147 PAGES
KERNELTEXT4  ASCII        UNPROTECTED     171 PAGES
LIST         SEQCODE      PROTECTED         7 PAGES
LISTMAN      ASCII        PROTECTED         2 PAGES
LISTTEXT     ASCII        PROTECTED        19 PAGES
MAKETEMP     SEQCODE      PROTECTED         4 PAGES
MAKETEMPMAN  ASCII        PROTECTED         1 PAGES
MAKETEMPTEXT ASCII        PROTECTED        12 PAGES
MOVE         SEQCODE      PROTECTED         2 PAGES
MOVEMAN      ASCII        PROTECTED         1 PAGES
MOVETEXT     ASCII        PROTECTED        10 PAGES
MTOPTEXT     ASCII        UNPROTECTED       4 PAGES
NEXT         SCRATCH      PROTECTED       255 PAGES
PIPELINE     CONCODE      PROTECTED         4 PAGES
PIPELINETEXT ASCII        PROTECTED         8 PAGES
PREFIX       ASCII        PROTECTED         6 PAGES
PRINTER      SEQCODE      PROTECTED         3 PAGES
PRINTERMAN   ASCII        PROTECTED         2 PAGES
PRINTERTEXT  ASCII        PROTECTED        11 PAGES
READ         SEQCODE      PROTECTED         4 PAGES
READMAN      ASCII        PROTECTED         2 PAGES
READTEXT     ASCII        PROTECTED        12 PAGES
REALTIME     CONCODE      PROTECTED        11 PAGES
REALTIMETEXT ASCII        PROTECTED        23 PAGES
RKBOOTTEXT   ASCII        UNPROTECTED       6 PAGES
SOLO         CONCODE      PROTECTED        18 PAGES
SOLOBATTEXT  ASCII        UNPROTECTED       4 PAGES
SOLOCOPY     ASCII        PROTECTED         1 PAGES
SOLOFILES    ASCII        PROTECTED         1 PAGES
SOLOTEXT     ASCII        PROTECTED        52 PAGES
SPASCAL      SEQCODE      PROTECTED         7 PAGES
SPASCALMAN   ASCII        PROTECTED         3 PAGES
SPASCALTEXT  ASCII        PROTECTED        18 PAGES
SPASS1       SEQCODE      PROTECTED        20 PAGES
SPASS1TEXT   ASCII        PROTECTED        53 PAGES
SPASS2       SEQCODE      PROTECTED        26 PAGES
SPASS2TEXT   ASCII        PROTECTED        73 PAGES
SPASS3       SEQCODE      PROTECTED        35 PAGES
SPASS3TEXT   ASCII        PROTECTED        91 PAGES
SPASS4       SEQCODE      PROTECTED        26 PAGES
SPASS4TEXT   ASCII        PROTECTED        65 PAGES
SPASS5       SEQCODE      PROTECTED        19 PAGES
SPASS5TEXT   ASCII        PROTECTED        54 PAGES
SPASS6       SEQCODE      PROTECTED        16 PAGES
SPASS6TEXT   ASCII        PROTECTED        53 PAGES
SPASS7       SEQCODE      PROTECTED        18 PAGES
SPASS7TEXT   ASCII        PROTECTED        56 PAGES
START        SEQCODE      PROTECTED         3 PAGES
STARTMAN     ASCII        PROTECTED         3 PAGES
STARTTEXT    ASCII        PROTECTED        11 PAGES
SUPERMAC     ASCII        UNPROTECTED      30 PAGES
TAPE         SEQCODE      PROTECTED         3 PAGES
TAPEMAN      ASCII        PROTECTED         2 PAGES
TAPETEXT     ASCII        PROTECTED        14 PAGES
TEMP1        SCRATCH      PROTECTED       255 PAGES
TEMP2        SCRATCH      PROTECTED       255 PAGES
TOTAPETEXT   ASCII        UNPROTECTED       4 PAGES
WRITE        SEQCODE      PROTECTED         2 PAGES
WRITEMAN     ASCII        PROTECTED         1 PAGES
WRITETEXT    ASCII        PROTECTED         9 PAGES
XMAC         ASCII        UNPROTECTED       1 PAGES
   125 ENTRIES
  3391 PAGES
post

Superpascal language

SuperPascal—a secure programming language for publication of parallel scientific algorithms. SuperPascal extends a subset of IEEE Standard Pascal with deterministic statements for parallel processes and synchronous message communication. A parallel statement denotes parallel execution of a fixed number of statements. A forall statement denotes parallel execution of the same statement by a dynamic number of processes. Recursive procedures may be combined with parallel and forall statements to define recursive parallel processes. Parallel processes communicate by sending typed messages through channels created dynamically. SuperPascal omits ambiguous and insecure features of Pascal. Restrictions on the use of variables enable a single‐pass compiler to check that parallel processes are disjoint, even if the processes use procedures with global variables.

Recently the sources of SuperPascal appeared online at his website (http://brinch-hansen.net/). This subset of Pascal, enhanced with constructs for parallel computing is not super Pascal, but a well structured, easy to understand compiler-interpreter combination for the study of concurrent programming.

Since the information is available in ‘shar’ archive format, with Latex encoded documents, the files are converted to more convenient text and pdf format.
SuperPascal sources as distributed in a shar file by Per Brinch Hansen for a Sun workstation
The same SuperPascal sources as distributed in a zipfile file for a Sun workstation

Since SuperPascal is nearly ISO Standard Pascal, it is easy to get SuperPascal compiled with more modern Pascal compilers like Freepascal and the GNU Pascal compiler.
The SuperPascal software can be accessed freely from the Brinch Hansen Archive. It consists of a compiler and interpreter, which are both written in normal, sequential Pascal (ISO Level 1 standard Pascal). This is supported by the GNU Pascal compiler and newer versions of the Free Pascal compiler (2.7.1+) with the -Miso switch, with the following respective small modifications to the code.

For GPC, the file interpret.p uses the non-standard clock function (line 1786), which is used to obtain the system time. Instead, the Extended Pascal getTimeStamp function can be used (which is supported by the GNU Pascal compiler), by declaring a variable of type TimeStamp, setting that with the current time using getTimeStamp and assigning the Second field of the TimeStamp to the variable t.

Free Pascal also needs a solution to the above “clock” problem (On windows, just declare gettickcount as external with “clock” as name). In addition, the reset/rewrites that are marked as non-standard in the source need to be changed to assign/reset (or rewrite) pairs. (GPC probably only errors on this if you enable strict flags), and the C preprocessor commands #include ‘xx’ must be changed to {$include ‘xx’}.

So small changes were necessary, here the projects:

SuperPascal FPC project (original github https://github.com/octonion/superpascal)
SuperPascal GNU project (original github https://github.com/samplx/SuperPascal)

Articles on SuperPascal

SuperPascal: a Publication Language for Parallel Scientific Computing, 1994
The Programming Language SuperPascal, November 1993
The SuperPascal User Manual, November 1993
Anonymous FTP of the SuperPascal Software, November 1993
The SuperPascal Software Notes, November 1993
Note on the Sun Pascal clock statement used in the interpreter

From Wikipedia:

SuperPascal is based on Niklaus Wirth’s sequential language Pascal, extending it with features for safe and efficient concurrency. Pascal itself was used heavily as a publication language in the 1970s; it was used to teach structured programming practices and featured in text books, for example, on compilers and programming languages. Brinch Hansen had earlier developed the language Concurrent Pascal, one of the earliest concurrent languages for the design of operating systems and real-time control systems.

The requirements of SuperPascal were based on the experience gained by Brinch Hansen over three years in developing a set of model parallel programs, which implemented methods for common problems in computational science.This experimentation allowed him to make the following conclusions about the future of parallel scientific computing:

Future parallel computers will be general-purpose, allowing programmers to think in terms of problem-orientated process configurations. This was based on his experience programming networks of transputers, which were general-purpose processors able to be connected in arrays, trees or hypercubes.
Regular problems in computational science require only deterministic parallelism, that is, expecting communication from a particular channel, rather than from several.
Parallel scientific algorithms can be developed in an elegant publication language and tested on a sequential computer. When it is established an algorithm works, it can easily be implemented in a parallel implementation language.

These then led to the following requirements for a parallel publication language:

-The language should extend a widely used standard language with deterministic parallelism and message communication. The extensions should be in the spirit of the standard language.
-The language should make it possible to program arbitrary configurations of parallel processes connected by communication channels. These configurations may be defined iteratively or recursively and created dynamically.
-The language should enable a single-pass compiler to check that parallel processes do not interfere in a time-dependent manner.

Features
The key ideas in the design of SuperPascal was to provide a secure programming, with abstract concepts for parallelism.

Security
SuperPascal is secure in that it should enable its compiler and run-time system to detect as many cases as possible in which the language concepts break down and produce meaningless results. SuperPascal imposes restrictions on the use of variables that enable a single-pass compiler to check that parallel processes are disjoint, even if the processes use procedures with global variables, eliminating time-dependent errors. Several features in Pascal were ambiguous or insecure and were omitted from SuperPascal, such as labels and goto statements, pointers and forward declarations.

Parallelism
The parallel features of SuperPascal are a subset of occam 2, with the added generality of dynamic process arrays and recursive parallel processes.

A parallel statement denotes that the fixed number of statements it contains must be executed in parallel. For example:

parallel
  source() |
  sink()
end

A forall statement denotes the parallel execution of a statement by a dynamic number of processes, for example:

forall i := 0 to 10 do
  something()

Channels and communication
Parallel processes communicate by sending typed messages through channels created dynamically. Channels are not variables in themselves, but are identified by a unique value known as the channel reference, which are held by channel variables. A channel is declared, for example, by the declaration

type channel = *(boolean, integer);
  var c: channel;

which defines a new (mixed) type named channel and a variable of this type named c. A mixed type channel is restricted to transmitting only the specified types, in this case boolean and integer values. The channel c is initialised by the open statement:

open(c)

Message communication is then achieved with the send(channel, value) and receive(channel, variable) statements. The expression or variable providing the value for send, and the variable in receive, must both be of the same type as the first channel argument. The following example shows the use of these functions in a process that receives a value from the left channel and outputs it on the right one.

var left, right: channel; a: number;
  receive(left, a);
  send(right, a)

The functions send and receive can both take multiple input and output arguments respectively:

  send(channel, e1, e2,..., en);
  receive(channel, v1, v2,..., vn)

The following run-time communication errors can occur:
– Channel contention occurs when two parallel processes both attempt to send or receive on the same channel simultaneously.
A message type error occurs when two parallel processes attempt to communicate through the same channel and the output expression and input variable are of different types.
Deadlock occurs when a send or receive operation waits indefinitely for completion.

– Recursive procedures can be combined with parallel and forall statements to create parallel recursive processes. The following example shows how a pipeline of processes can be recursively defined using a parallel statement.

procedure pipeline(min, max: integer; left, right: channel);
var middle: channel;
begin
  if min < max then
    begin
      open(middle);
      parallel
        node(min, left, middle) |
        pipeline(min + 1, max, middle, right)
      end
    end
  else node(min, left, right)
end;
end;

Another example is the recursive definition of a process tree:

procedure tree(depth: integer, bottom: channel);
var left, right: channel;
begin
  if depth > 0 then
    begin
      open(left, right);
      parallel
        tree(depth - 1, left) |
        tree(depth - 1, right) |
        root(bottom, left, right)
      end
    end
  else leaf(bottom)

Interference control
The most difficult aspect of concurrent programming is unpredictable or non-reproducible behaviour caused by time-dependent errors. Time-dependent errors are caused by interference between parallel processes, due to variable updates or channel conflicts. If processes sharing a variable, update it at unpredictable times, the resulting behaviour of the program is time-dependent. Similarly, if two processes simultaneously try to send or receive on a shared channel, the resulting effect is time-dependent.

SuperPascal enforces certain restrictions on the use of variables and communication to minimise or eliminate time-dependent errors. With variables, a simple rule is required: parallel processes can only update disjoint sets of variables. For example, in a parallel statement a target variable cannot be updated by more than a single process, but an expression variable (which can’t be updated) may be used by multiple processes. In some circumstances, when a variable such as an array is the target of multiple parallel processes, and the programmer knows its element-wise usage is disjoint, then the disjointness restriction may be overridden with a preceding statement.

Structure and syntax
SuperPascal is a block structured language, with the same basic syntax as Pascal. A program consists of a header, global variable definitions, function or procedure definitions and a main procedure. Functions and procedures consists of blocks, where a block is a set of statements. Statements are separated by semicolons, as opposed to languages like C or Java, where they are terminated by semicolons.

The following is an example of a complete SuperPascal program, which constructs a pipeline communication structure with 100 nodes. A master node sends an integer token to the first node, this is then passed along the pipeline and incremented at each step, and finally received by the master node and printed out.

program pipeline;

const
    len = 100;

type
    channel = *(integer);

var
    left, right: channel;
    value: integer;

procedure node(i: integer; left, right: channel);
var value: integer;
begin
    receive(left, value);
    send(right, value+1)
end;

procedure create(left, right: channel);
type row = array [0..len] of channel;
var c: row; i: integer;
begin
    c[0] := left;
    c[len] := right;
    for i := 1 to len-1 do
        open(c[i]);
    forall i := 1 to len do
        node(i, c[i-1], c[i])
end;

begin
    open(left, right);

    parallel
        send(left, 0) |
        create(left, right) |
        receive(right, value)
    end;

    writeln('The resulting value is ', value)
end.

Per Brinch Hansen

hansenBrinch Hansen was one of the pioneers of concurrent programming and operating systems (kernels). In the 1960s, Brinch Hansen worked at the Danish computer company Regnecentralen, first in the compiler group headed by Peter Naur and Jørn Jensen, and, later, as the chief architect of the RC 4000 minicomputer and its renowned operating system kernel (RC 4000 Multiprogramming System). In 1972, he wrote the first comprehensive textbook on Operating System Principles.

In 1970 his research in computer science focused on concurrent programming.  Inspired by Ole-Johan Dahl and Kristen Nygaard’s programming language Simula 67, he invented the monitor concept in 1972. In the United States, he also developed the first concurrent programming language, Concurrent Pascal, in 1975. In 1977, he wrote the first book on Concurrent Programming: The Architecture of Concurrent Programs.

Per Brinch Hansen has concentrated on simplicity. Only the essential, always ask why complications are tolerated. His book on Programming a Personal Computer, read by me in 1983, made a lasting deep impresssion on me.

Two citations from Per Brinch Hansen on simplicity and programming
– Writing is a rigorous test of simplicity: It is just not possible to write convincingly about ideas that cannot be understood.
– Programming is the art of writing essays in crystal clear prose and making them executable

Information on the work of Per Brinch Hansen:
Solo and Concurrent/Sequential Pascal
Edison system
Joyce A programming language for networks
SuperPascal
– Collected articles by Per Brinch Hansen http://brinch-hansen.net/.

Books in my library:

pbhoperating Operating System Principles
(1973, ISBN 0-13-637843-9) (scanned)
pbharchitecture The Architecture of Concurrent Programs
(1977, ISBN 0-13-044628-9)
Concurrent Pascal and Solo
Programming a Personal Computer, Per Brinch Hansen
The book describing the Edison system, design,
development,listing of programs including compiler in the Edison language,
and the interpreter/runtime written in PDP-11 Alva language.
(1983, ISBN 0-13-730267-3), the Edison system
Programming a Personal Computer, Per Brinch Hansen
OCR version (thanks Daniel Toffetti)
pbhpascalcompiler Brinch Hansen on Pascal Compilers
(1985, ISBN 0-13-083098-4) (scanned)
pbhpascalcompiler Brinch Hansen on Pascal Compilers
OCR version (thanks Daniel Toffetti)
The Search for Simplicity.
Essays on Parallel ProgrammingSee below.
(1996, ISBN 0-8186-7566-7

The Search for Simplicity. Essays on Parallel Programming.

The Cobol compiler for the Siemens 3003
Design considerations for the RC 4000 computer
The logical structure of the RC 4000 computer
The RC 4000 real-time control system at Pulawy
RC 4000 Software: Multiprogramming System (abridged)
RC 4000 Computer: Reference Manual
RC 4000 Software: Multiprogramming System (complete)
The nucleus of a multiprogramming system
An outline of a course on operating system principles
Structured multiprogramming
Shared classes
Testing a multiprogramming system
The programming language Concurrent Pascal
The Solo operating system: A Concurrent Pascal program
The Solo operating system: Processes, monitors, and classes
The programmer as a young dog
Experience with modular concurrent programming
Design principles
Network—A multiprocessor program
Distributed processes: A concurrent programming concept
Reproducible testing of monitors
A keynote address on concurrent programming
The design of Edison
Joyce—A programming language for distributed systems
A multiprocessor implementation of Joyce
The nature of parallel programming
The Joyce Language Report
The linear search rediscovered
Householder reduction of linear equations
Monitors and Concurrent Pascal: A personal history
Model programs for computational science
Parallel cellular automata
Multiple-length division revisited
SuperPascal—A publication language
Interference control in SuperPascal
Efficient parallel recursion
The all-pairs pipeline
Balancing a pipeline
Java’s insecure parallelism
The evolution of operating systems
The invention of concurrent programming

Other books:
– Studies in Computational Science: Parallel Programming Paradigms (1995, ISBN 0-13-439324-4)
– Programming for Everyone in Java (1999, ISBN 0-387-98683-9)
– Classic Operating Systems: From Batch Processing to Distributed Systems (2001, ISBN 0-387-95113-X)
– The Origin of Concurrent Programming: From Semaphores to Remote Procedure Calls (2004, ISBN 0-387-95401-5)
– A Programmer’s Story: The Life of a Computer Pioneer (2004, local copy available here at http://brinch-hansen.net/)
– Many articles in the scientific journals, many available at local copy of http://brinch-hansen.net/.


With father

Class of 1949

Age 21

Ivar Bech

Naur and Brinch Hansen

Naur, Dahl, Brinch Hansen

Compiler Group

RC4000 computer

1959

1967

1975