
(********************************************************************)
(*                                                                  *)
(*  manual.txt                                                      *)
(*                                                                  *)
(*  Copyright (C) 1989 - 2012  Thomas Mertes                        *)
(*  All rights reserved.                                            *)
(*                                                                  *)
(*  Documentation: Manual for the Seed7 programming language        *)
(*                                                                  *)
(*  This file is distributed "AS IS" in the hope that it will be    *)
(*  useful, but WITHOUT ANY WARRANTY; without even the implied      *)
(*  warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.*)
(*                                                                  *)
(********************************************************************)



CONTENTS
========

  1.    INTRODUCTION
  1.1     What is Seed7?
  1.2     Why a new programming language?
  1.3     Features of Seed7
  1.4     How to read the manual
  2.    TUTORIAL
  2.1     Hello world
  2.2     Local declarations and expressions
  2.3     For loop and float expressions
  2.4     Parameters
  2.5     Declare a statement
  2.6     Template declaring a statement
  3.    DECLARATIONS
  3.1     Normal declarations
  3.2     Syntax declarations
  3.3     System declarations
  4.    PREDEFINED STATEMENTS
  4.1     Assignment
  4.2     while-statement
  4.3     repeat-statement
  4.4     for-statement
  4.5     for-each-statement
  4.6     if-statement
  4.7     case-statement
  5.    PREDEFINED TYPES
  5.1     boolean
  5.2     integer
  5.3     bigInteger
  5.4     rational
  5.5     bigRational
  5.6     float
  5.7     complex
  5.8     char
  5.9     string
  5.10    array
  5.11    hash
  5.12    set
  5.13    struct
  5.14    category
  5.15    reference
  5.16    ref_list
  5.17    program
  5.18    ptr
  5.19    ENUMERATION
  5.20    color
  5.21    time
  5.22    duration
  5.23    file
  5.24    text
  5.25    func
  5.26    varfunc
  5.27    void
  5.28    proc
  5.29    type
  5.30    object
  5.31    expr
  6.    PARAMETERS
  6.1     'val' parameter
  6.2     'ref' parameter
  6.3     'in' parameter
  6.4     'in var' parameter
  6.5     'inout' parameter
  6.6     Symbol parameter
  6.7     'attr' parameter
  7.    OBJECT ORIENTATION
  7.1     Interface and implementation
  7.2     Dynamic dispatch
  7.3     Inheritance
  7.4     Class methods
  7.5     Multiple dispatch
  7.6     Replacing pointers with interface types
  8.    THE FILE SYSTEM
  8.1     Conversion to strings and back
  8.2     Basic input and output operations
  8.3     Input and output with conversion
  8.4     Simple read and write statements
  8.5     Standard input and output files
  8.6     Access to operating system files
  8.7     Keyboard file
  8.8     Files with line structure
  8.9     Sockets
  8.10    User defined file types
  8.11    Scanning a file
  9.    STRUCTURED SYNTAX DEFINITION
  9.1     The Extended Backus-Naur Form
  9.2     The syntax of a statement
  9.3     Priority and associativity
  9.4     The syntax of operators
  9.5     Syntax of predefined statements
  9.6     Advanced syntax definitions
  9.7     Comparison of EBNF and S7SSD
  10.   TOKENS
  10.1    White space
  10.1.1    Spaces
  10.1.2    Comments
  10.1.3    Line comments
  10.2    Identifiers
  10.2.1    Name identifiers
  10.2.2    Special identifiers
  10.2.3    Parentheses
  10.3    Literals
  10.3.1    Integer literals
  10.3.2    String literals
  10.3.3    Character literals
  11.   EXPRESSIONS
  11.1    Parentheses
  11.2    Call expressions
  11.3    Dot expressions
  12.   OPERATING SYSTEM ACCESS
  12.1    Standard path representation
  12.2    readDir
  12.3    openDir
  12.4    getcwd
  12.5    chdir
  12.6    mkdir
  12.7    fileType
  12.8    fileMode
  12.9    setFileMode
  12.10   fileSize
  12.11   getATime
  12.12   getCTime
  12.13   getMTime
  12.14   setATime
  12.15   setMTime
  12.16   readlink
  12.17   symlink
  12.18   removeFile
  12.19   removeAnyFile
  12.20   copyFile
  12.21   cloneFile
  12.22   moveFile
  12.23   argv(PROGRAM)
  12.24   path(PROGRAM)
  12.25   dir(PROGRAM)
  12.26   getenv
  12.27   setenv
  13.   PRIMITIVE ACTIONS
  13.1    Actions for the type ACTION
  13.2    Actions for array types
  13.3    Actions for the type bigInteger
  13.4    Actions for the type boolean
  13.5    Actions for byte strings
  13.6    Actions for the type char
  13.7    Actions for various directory, file and other commands
  13.8    Actions for text (console) screen output
  13.9    Actions for declarations
  13.10   Actions to do graphic output
  13.11   Actions for enumeration types
  13.12   Actions for the type PRIMITIVE_FILE
  13.13   Actions for the type float
  13.14   Actions to support the graphic keyboard
  13.15   Actions for hash types
  13.16   Actions for the type integer
  13.17   Actions for interface types
  13.18   Actions to support the text (console) screen keyboard
  13.19   Actions for the list type
  13.20   Actions for the type pollData
  13.21   Actions for proc operations and statements
  13.22   Actions for the type program
  13.23   Actions for the type reference
  13.24   Actions for the type ref_list
  13.25   Actions for struct types
  13.26   Actions for set types
  13.27   Actions for the type PRIMITIVE_SOCKET
  13.28   Actions for the type string
  13.29   Actions for the type time
  13.30   Actions for the type type
  13.31   Actions for the type utf8_file
  14.   ERRORS
  14.1    Compile time errors
  14.2    Exceptions
  14.3    Handlers
  14.4    Stack trace
  14.5    Other errors and warnings



1. INTRODUCTION
===============


1.1 What is Seed7?

    Seed7 is a general-purpose programming language. It is a
  higher level language compared to Ada, C++ and Java. In Seed7
  new statements and operators can be declared easily. Functions
  with type results and type parameters are more elegant than
  the usual template or generics concept. Object orientation is
  used when it brings advantages and not in places when other
  solutions are more obvious. Although Seed7 contains several
  concepts of other programming languages it is generally not
  considered as a direct descendant of any other programming
  language.

  The programmer should concentrate on problem solving instead
  of administration or the fulfillment of some paradigm.
  Therefore Seed7 allows programming in the "problem space"
  instead of bending everything into a small syntactic or
  semantic concept. The predefined constructs of Seed7 are
  defined in a way to be easy readable and understandable. This
  practical approach can be summarized as:

    <font color="orange"> Programming should be fun 

  Seed7 programs can be interpreted or compiled. Therefore Seed7
  can be used for scripting and for "real" programs.


1.2 Why a new programming language?

    Conventional programming languages have a firmly given
  syntactic structure. The form of the statements, operators,
  declarations, procedures and functions is fixed in the
  language definition and cannot be changed by the user. It is
  only possible to declare new procedures, functions and in
  some languages also new operators. However the syntax of
  procedure-, function and operator calls cannot be changed.
  Although this rigid pattern is favorable for the portability
  of programs, the improvement of a programming language is
  almost impossible. Extensions are however desirable, in order
  to repair existing weaknesses, to introduce new more obvious
  constructs and to adapt the programming language to different
  application areas. E.g.: In the area of mathematics the
  readability of a program can be substantially increased by
  the introduction of matrix and vector operators. After
  declaring an inner product and an outer (or cross) product for
  vectors it is possible to write e.g.

    v1: = v2 cross v3;   write(v1 * v2);

  Programs searching some data can become more understandable
  by using a search statement instead of a search procedure. A
  call of a new declared search statement could be:

    search person1.age = person2.age and
       person1.mother = person2.mother and
       person1 <> person2
    when found
       write("Twins: " <& person1.name <& " and " <& person2.name);
    else
       write("No twins found.");
    end search;

  Such extensions make understanding, changing and debugging of
  a program easier.


1.3 Features of Seed7

  Seed7 has the following features

    - User defined statements and operators.

    - Types are first class objects and therefore templates and
      generics can be defined easily without special syntax.

    - Predefined constructs like arrays or for-loops are
      declared in the language itself.

    - Object orientation is based on interfaces, supports
      multiple dispatch and allows to connect methods to objects.

    - Static type checking and no automatic casts.

    - exception handling

    - overloading of procedures/functions/operators/statements

    - Various predefined types like resizable arrays, hashes,
      bitsets, structs, etc.

  But a new programming language differs not only from existing
  ones by new features. The real advantage comes from omitting
  features which are outdated.

  Several concepts in use by other languages are not present

    - There is no goto statement.
      Hidden goto's like break- and continue-statements are
      also omitted.

    - There is no return statement. Instead a result variable
      can be declared to which the result of a function can
      be assigned.

    - There are no automatic type conversions.
      When a subprogram should be used for different types
      it must be overloaded.

    - There are no variable length parameter lists.
      Instead it is possible to use arrays as parameters.

    - There are no default parameters.
      But it is easy to define two subprograms: One with and
      one without an additional parameter.

    - There is no special "parameter" called "self" or "this".
      In a procedure the receiving object is declared as
      formal parameter with a user-defined name.

    - There is no macro feature since this mechanism is too
      similar to the subprogram feature. Instead subprograms
      can be used in a more flexible way than in other languages.

    - There are no reserved words.

    - There is no conceptual distinction between functions,
      operators, procedures and statements.

    - The procedure calling mechanism is not based on a concept
      with an object-message pair (An object receives a message).
      Instead a match is done over a list of objects. This more
      general (and powerful) mechanism is called multiple dispatch
      and it includes the simple object-message mechanism as
      special case.

  There are several concepts which are also used by other languages:

    - Comments start with (* and end with *) and may be nested.

    - Comments start with # and are terminated with the end of the line.

  There are several concepts which are new

    - Variables and constants must be initialized when they are
      declared.

    - Every expression has exactly one type.
      That means that overloaded functions are resolved with
      their actual parameters and not with the context of their
      call. (This is different to the overloading mechanism
      used by ADA)

    - With a syntax declaration new operators and statements
      can be defined.

    - Not only predefined operator symbols can be
      overloaded. Additionally it is possible to invent
      completely new operator symbols.

  Several restrictions of other languages are released

    - There is no limitation in the length of an identifier and
      all characters of an identifier are significant.

    - Statements and parentheses can be nested without limitation
      in depth.

    - The number of parameters and local variables is not
      limited.

    - Strings can contain any characters (also the NUL character)
      This allows holding binary information in strings.

    - Although strings are not NUL terminated they have
      no size limitation. (Except there is no more memory)

    - String literals can have any length.

    - There is no limitation in the length of a source line.

    - There is no level limitation for nesting includes.


1.4 How to read the manual

    You can have several views of the Seed7 programming language.
  Dependent on the view you can concentrate on specific
  chapters.

  For example Seed7 can be used as conventional programming language.
  In this case you are interested in how the statements look like,
  which types are available, which operators are predefined, how
  to declare variables and procedures and other things like these.
  The statements and the predefined types are described in chapter
  4 (Predefined statements) and chapter 5 (Predefined types) and the
  declaration mechanism is described in chapter 3 (Declarations).

  But Seed7 is also an object oriented programming language.
  In this case you are interested in how to define new classes,
  how instances are generated, the method calling mechanism,
  the predefined class hierarchy and other things like these.
  The object orientation of Seed7 is described in chapter 7
  (Object orientation). A good example for classes and instances
  is the file system which is described in chapter 8 (The file
  system).

  And Seed7 is also an extensible programming language.
  In this case you are interested in how to declare new
  statements, how to define new operators, assigning a priority
  and an associativity to operators and other things like these.
  An overview about syntax declarations can be found in
  Chapter 3.2 (Syntax declarations). A detailed description
  of the Seed7 syntax definitions can be found in chapter 9
  (Structured syntax definition). Chapter 4 (Predefined
  statements) contains various examples of syntax and semantic
  declarations. The basic parts of the syntax are described in
  chapter 10 (Tokens) and chapter 11 (Expressions).



2. TUTORIAL
===========

    We begin with a tutorial introduction to Seed7. In
  this chapter we want to show the principal ideas that
  make Seed7 work. At this point, we are not trying to be
  complete or precise. We just want to give a clear view
  to the primary philosophic ideas of Seed7. When the
  primary ideas are understood a complete and precise
  reference can be learned easier.


2.1 Hello world

    A Seed7 program consists of a sequence of declarations.
  With each declaration a type and a name is attached to the
  new object. In addition every new declared object gets an
  initial value. 

  Here is an example of an object declaration:

    const proc: main is func
      begin
        writeln("hello world");
      end func;

  The object 'main' is declared as constant and 'proc'
  is the type of 'main'. Declaring 'main' with the type
  'proc' makes a procedure out of it. The object 'main' gets a

    func ... end func

  construct as value. The 'func' construct is similar to
  begin ... end in PASCAL and { ... } in C. Inside the 'func' is a
  'writeln' statement with the "hello world" string. The
  'writeln' statement is used to write a 'string' followed by a
  newline character. To use this declaration as the standard
  hello world example program, we have to add a few things:

    $ include "seed7_05.s7i";

    const proc: main is func
      begin
        writeln("hello world");
      end func;

  The first line includes all definitions of the standard
  library. In contrast to other standard libraries the seed7_05.s7i
  library contains not only function declarations but also
  declarations of statements and operators.
  Additionally the seed7_05.s7i library defines the 'main' function
  as entry point for a Seed7 program.

  If you write this program in a file called hello.sd7
  and execute the command

    hi hello

  The Seed7 interpreter writes something like

    HI INTERPRETER Version 4.5.79  Copyright (c) 1990-2005 Thomas Mertes
       245 syntax.s7i
      2635 seed7_05.s7i
        33 hello.sd7
      2913 lines total
     29130 lines per second
    1184171 bytes
    hello world

  You get information about the Seed7 interpreter, a list of
  libraries included and how many lines they contain, the
  number of bytes used by the hello.sd7 program and finally
  the output of the hello.sd7 program itself:

    hello world


2.2 Local declarations and expressions

    To write a Fahrenheit to Celsius conversion table we use
  the following program:

    (* Print a Fahrenheit-Celsius table
       for Fahrenheit values between 0 and 300 *)

    $ include "seed7_05.s7i";

    const proc: main is func
      local
        const integer: lower is 0;
        const integer: upper is 300;
        const integer: increment is 20;
        var integer: fahr is 0;
        var integer: celsius is 0;
      begin
        fahr := lower;
        while fahr <= upper do
          celsius := 5 * (fahr - 32) div 9;
          write(fahr);
          write(" ");
          writeln(celsius);
          fahr := fahr + increment;
        end while;
      end func;

  Everything between (* and *) is a comment, which is ignored.
  This program contains local constants and variables of the
  type 'integer'. The constants and variables must be
  initialized when they are declared. This program contains
  also an assignment, a while-statement and the expression to
  compute the 'celsius' value. Note that the statements inside
  the while-loop are between 'do' and 'end while'. The
  expression to compute the 'celsius' value uses an integer
  division ('div'). The 'write' statement can be used to write
  strings and integers without a newline character. The output
  produced by this program is

    0 -17
    20 -6
    40 4
    60 15
    80 26
    100 37
    120 48
    140 60
    160 71
    180 82
    200 93
    220 104
    240 115
    260 126
    280 137
    300 148


2.3 For loop and float expressions

    An improved version of the program to write the Fahrenheit
  to Celsius conversion table is:

    $ include "seed7_05.s7i";
      include "float.s7i";

    const proc: main is func
      local
        const integer: lower is 0;
        const integer: upper is 300;
        const integer: increment is 20;
        var integer: fahr is 0;
        var float: celsius is 0.0;
      begin
        for fahr range lower to upper step increment do
          celsius := flt(5 * (fahr - 32)) / 9.0;
          writeln(fahr lpad 3 <& " " <& celsius digits 2 lpad 6);
        end for;
      end func;

  To use the type 'float' it is necessary to include
  "float.s7i". The 'float' variable 'celsius' must be
  initialized with 0.0 (instead of 0). The for-loop is
  written as:

    for ... range ... to ... step ... do
      ...
    end for

  To specify a lower and an upper limit together with a step
  value. For a step value of 1 the for-loop it is written as:

    for ... range ... to ... do
      ...
    end for

  And for a step value of -1 it can be written as:

    for ... range ... downto ... do
      ...
    end for

  Since Seed7 is strong typed 'integer' and 'float' values
  cannot be mixed in expressions. Therefore the 'integer'
  expression '5 * (fahr - 32)' is converted to 'float' with
  the function 'flt'. For the same reason a '/' division and
  the value '9.0' must be used. The '<&' operator is used to
  concatenate elements before writing. If the right operand of
  the '<&' operator has not the type 'string' it is converted to
  a 'string' using the 'str' function. The 'lpad' operator
  converts the value of 'fahr' to a string and pads spaces to
  the left until the string has length 3. The 'digits' operator
  converts the value of 'celsius' to a string with 2 decimal
  digits. The resulting string is padded left up to a length
  of 6.


2.4 Parameters

    Most parameters are not changed inside a function. Seed7
  uses 'in' parameters to describe this situation:

    const func integer: negate (in integer: num1) is
      return -num1;

    const func integer: fib (in integer: num1) is func
      result
        var integer: result is 1;
      begin
        if num1 <> 1 and num1 <> 2 then
          result := fib(pred(num1)) + fib(num1 - 2);
        end if;
      end func;

  The functions above use 'in' parameters named 'num1'.
  An assignment to 'num1' is not allowed. A formal 'in'
  parameter like 'num1' behaves like a constant. 
  Trying to change a formal 'in' parameter:

    const proc: wrong (in integer: num2) is func
      begin
        num2 := 0;
      end func;

  results in a compile time error:

    *** tst77.sd7(5):52: Variable expected in {num2 := 0 } found parameter (in integer: num2)
        num2 := 0;

  When a function wants to change the value of the actual
  parameter it can use an 'inout' parameter:

    const proc: reset (inout integer: num2) is func
      begin
        num2 := 0;
      end func;

  If you call this function with

    reset(number);

  the variable 'number' has the value 0 afterwards. Calling
  'reset' with a constant instead of a variable:

    reset(8);

  results in a compile time error

    *** tst77.sd7(12):52: Variable expected in {8 reset } found constant integer: 8
        reset(8);

  Sometimes an 'in' parameter is needed, but you need to change
  the formal parameter in the function without affecting the
  actual parameter. In this case we use the 'in var' parameter:

    const func string: oct_str (in var integer: number) is func
      result
        var string: result is "";
      begin
        while number >= 0 do
          result := str(number rem 8) & result;
          number := number div 8;
        end while;
      end func;

  As you can see this works like a combination of an 'in'
  parameter with a local 'var'.

  Conventionally there are two kinds of parameters:
  'call by value' and 'call by reference'. When taking the
  access right (constant or variable) into account we get
  the following table:

    +-----------+-----------+--------------+
    | parameter |  call by  | access right |
    +-----------+-----------+--------------+
    | val       |   value   | const        |
    | ref       | reference | const        |
    | in        | val / ref | const        |
    | in var    |   value   | var          |
    | inout     | reference | var          |
    +-----------+-----------+--------------+

  Additionally to the parameters we already know this table
  describes also 'val' and 'ref' parameters which use
  'call by value' and 'call by reference' and have a constant
  formal parameter. The 'in' parameter is called by
  'val / ref' in this table which is easily explained:

    An 'in' parameter is either a 'val' or a 'ref' parameter
    depending on the type of the parameter.

  The parameter

    in integer: number

  is a 'val' parameter which could also be declared as

    val integer: number

  while the parameter

    in string: stri

  is a 'ref' parameter which could also be declared as

    ref string: stri

  The meaning of the 'in' parameter is predefined for most
  types. Usually types with small amounts of data use 'val'
  as 'in' parameter while types with bigger data amounts use
  'ref'. Most of the time it is not necessary to care if an
  'in' parameter is really a 'val' or 'ref' parameter. 

  In rare cases a 'ref' parameter would have undesired side
  effects with global variables or other 'ref' parameters.
  In these cases an explicit 'val' parameter instead of an
  'in' parameter makes sense.

  In all normal cases an 'in' parameter should be preferred
  over an explicit 'val' and 'ref' parameter.


2.5 Declare a statement

    This example program writes its arguments

    $ include "seed7_05.s7i";       # Standard Seed7 library

    const proc: main is func
      local
        var string: stri is "";
      begin
        for stri range argv(PROGRAM) do
          write(stri <& " ");
        end for;
        writeln;
      end func;

  The for-statement iterates over 'argv(PROGRAM)'.
  The function 'argv(PROGRAM)' returns an 'array string'
  (='array' of 'string' elements). The for-statement is overloaded
  for various collection types. In the standard Seed7 library
  "seed7_05.s7i" the for-statement for arrays is declared as
  follows:

    const proc: for (inout baseType: variable) range (in arrayType: arr_obj) do
                  (in proc: statements)
                end for is func
      local
        var integer: number is 0;
      begin
        for number range 1 to length(arr_obj) do
          variable := arr_obj[number];
          statements;
        end for;
      end func;

  The syntax of this for-statement is declared as:

    $ syntax expr: .for.().range.().to.().do.().end.for is              -> 25;

  Additionally everybody can overload the for-statement also.
  Because of these powerful features Seed7 does not need Iterators.


2.6 Template declaring a statement

  Templates are just normal functions with types as parameters.
  The following template function declares for-statements:

    const proc: FOR_DECLS (in type: aType) is func
      begin

        const proc: for (inout aType: variable) range (in aType: low) to (in aType: high) do
            (in proc: statements) end for is func
          begin
            variable := low;
            if variable <= high then
              statements;
              while variable < high do
                incr(variable);
                statements;
              end while;
            end if;
          end func;

      end func;
 
    FOR_DECLS(char);
    FOR_DECLS(boolean);

  The body of the 'FOR_DECLS' function contains a declaration of
  the for-statement for the type aType. Calling 'FOR_DECLS' with
  'char' and 'boolean' as parameter creates corresponding declarations
  of for-statements. The example above is a simplified part of
  the library "forloop.s7i".



3. DECLARATIONS
===============

    A declaration specifies the identifier, type, and other
  aspects of language elements such as variables, constants
  and functions. In Seed7 everything must be declared before
  it is used. Seed7 uses three kinds of declarations:

    - Normal declarations
    - Syntax declarations
    - System declarations

  which are described in detail in the following subchapters.


3.1 Normal declarations

    Normal declarations are the most commonly used form of
  declarations. To contrast them to the syntax declarations normal
  declarations are sometimes called semantic declarations. Seed7
  uses uniform looking declaration constructs to declare variables,
  constants, types, functions and parameters. For example:

    const integer: ONE is 1;

  declares the 'integer' constant 'ONE' which is initialized with the
  value 1. Variable declarations are also possible. For example:

    var integer: number is 0;

  declares the 'integer' variable 'number' which is initialized with
  the value 0. Type declarations are done as constant declarations
  where the type of the declared constant is 'type':

    const type: myChar is char;

  Function declarations are also a form of constant declaration:

    const func boolean: flipCoin is
      return rand(FALSE, TRUE);

  Each object declared with a 'const' or 'var' declaration obtains
  an initial value. It is not possible to use 'const' or 'var'
  declarations without initial value. Declarations with
  initialization expressions are also possible. For example

    var string: fileName is NAME & ".txt";

  The expression is evaluated and the result is assigned to
  the new object. This is done in the analyze phase of the
  interpreter or compiler, before the execution of the program
  starts. The initialization expressions may contain any
  function (or operator) call. That way user defined functions
  can also be used to initialize a constant or variable:

    const boolean: maybe is flipCoin;

  Constant and variable declarations can be global or local.
  The mechanism to define a parameter like 'x' is similar to the
  'const' or 'var' declarations:

    const func float: inverse (in float: x) is
      return 1/x;

  Function parameters, such as the parameter 'statement' in
  the example below, act as call-by-name parameters:

    const proc: possiblyDo (in proc: statement) is func
      begin
        if flipCoin then
          statement;
        end if;
      end func;

  Abstract data types such as 'subtype', 'struct', 'subrange', 'array', 'hash', 'set',
  'interface' and 'enum' are realized as
  functions which return a type. E.g.: The type 'array' is defined in the
  "seed7_05.s7i" library with the following header:

    const func type: array (in type: baseType) is func

  User defined abstract data types are also possible.

  The initialization uses the creation operation ( ::= ).
  Explicit calls of the create operation are not needed.

  The lifetime of an object goes like this:

  1. Memory is reserved for the new object (stack or heap memory
     make no difference here).

  2. The content of the new memory is undefined (It may contain
     garbage), therefore a create statement is necessary instead of
     an assignment.

  3. The create statements copies the right expression to the left
     expression taking into account that the left expression is
     undefined.

  4. If the object is variable other values can be assigned using
     the assign statement ( := ). The assignment can assume that the
     left expression contains a legal value. This allows that for
     strings (and some other types which are just references to a
     memory area) the memory containing the old string value (and
     not the memory of the object itself) can be freed when
     necessary.

  5. At the end of the lifetime of an object the destroy statement
     is executed. For strings (and some other types which are just
     references to a memory area) the memory containing the string
     value (and not the memory of the object itself) is freed.

  6. The memory of the object is freed.

  The first three steps are usually hidden in the declaration
  statement. The expression

    ONE . ::= . 1

  is executed to assign 1 to the object ONE. There are two
  reasons to use ::= instead of := to assign the initialization
  value.

  1. The assignment ( := ) can only be used to assign a value
    to a variable and initialization is also needed for
    constants.

  2. Sometimes some initializations are needed for the new
    object in addition to the pure assignment.

  For all predefined types the creation operator ( ::= )
  is already defined. To allow the declaration of objects of a
  new user defined type the constructor operation for this type
  must be defined.


3.2 Syntax declarations

    Syntax declarations are used to specify the syntax, priority
  and associativity of operators, statements, declarations and
  other constructs. A syntax declaration which defines the
  '+' operator is:

    $ syntax expr: .(). + .()   is ->  7;

  Most syntax definitions can be found in the file "syntax.s7i".
  A detailed description of the syntax declarations can be
  found in chapter 9 (Structured syntax definition)
  There is also a hard coded syntax for function calls with
  a parenthesis enclosed parameter list where the parameters
  are separated by commas. The hard coded syntax is described
  in chapter 11 (Expressions).
  Here we use a more complex syntax description:


3.3 System declarations

    With system declarations the analyzer and the interpreter
  are informed about which objects should be used for various system
  internal purposes. An example of a system declaration is

    $ system "integer" is integer;

  This defines that the type of all integer literals is 'integer'.
  Additionally 'integer' is used as type for all integers generated
  by primitive actions.
  There are different objects which are defined by a
  system declaration

    - The types of literals and simple expressions for example:
        'string' for strings and 'integer' for integers

    - Which objects should be used as result values for
      primitive actions for example:
        TRUE, FALSE and empty

    - The EXCEPTIONS which are to be raised by
      primitive actions for example:
        NUMERIC_ERROR and MEMORY_ERROR

    - Which objects should be used for several implicit
      actions for example:
        := ::= 'destroy' 'write' and 'flush'

  The following system declarations exist

    $ system "type" is type;
    $ system "expr" is expr;
    $ system "integer" is integer;
    $ system "char" is char;
    $ system "string" is string;
    $ system "proc" is proc;
    $ system "float" is float;

    $ system "true" is TRUE;
    $ system "false" is FALSE;
    $ system "empty" is empty;

    $ system "memory_error" is MEMORY_ERROR;
    $ system "numeric_error" is NUMERIC_ERROR;
    $ system "range_error" is RANGE_ERROR;
    $ system "io_error" is IO_ERROR;
    $ system "illegal_action" is ILLEGAL_ACTION;

    $ system "assign" is := ;
    $ system "create" is ::= ;
    $ system "destroy" is destroy;
    $ system "ord" is ord;
    $ system "in" is in;
    $ system "prot_outfile" is PROT_OUTFILE;
    $ system "flush" is flush;
    $ system "write" is write;
    $ system "writeln" is writeln;
    $ system "main" is main;



4. PREDEFINED STATEMENTS
========================

    The library contains several predefined statements:
  assignment, while-statement, repeat-statement, for-statement,
  if-statement, case-statement and procedure call.


  Syntax:

    statement ::=
      single_statement [ ';' [ statement ] ] .

    single_statement ::=
      assignment_statement | while_statement | repeat_statement |
      for_statement | if_statement | case_statement |
      procedure_call | empty_statement .

    empty_statement ::=
      'noop' .

  Everywhere where one statement can be written a sequence of
  statements can also be used. The semicolon-operator concatenates
  two statements giving a new statement. The semicolon operator
  can also be used behind the last statement of a statement
  sequence. In this case the semicolon is just ignored.


  Declaration:

    $ syntax expr: .(). ; .() is            <- 50;
    $ syntax expr: .(). ; is                <- 50 [1];

    const proc: (ref void param) ; (ref void param) is noop;


4.1 Assignment

  For example:

    minimum := maximum div 2;

  Semantics:
    The expression at the right side of the assignment symbol is
    evaluated and assigned to the variable at the left side.


  Syntax:

    assignment_statement ::=
      designator ':=' expression .

  The assignment statement is defined for every standard type.

  If an assignment for a new user defined type is needed it
  must be defined additionally.


  Declaration:

    $ syntax expr: .(). := .() is                     <-> 20;

    const proc: (inout type param) := (ref type param) is           action "TYP_CPY";
    const proc: (inout proc param) := (ref proc param) is           action "PRC_CPY";
    const proc: (inout func aType param) := (ref func aType param) is action "PRC_CPY";
    const proc: (inout varfunc aType param) := (ref varfunc aType param) is action "PRC_CPY";
    const proc: (inout ACTION param) := (in ACTION param) is        action "ACT_CPY";
    const proc: (inout boolean param) := (in boolean param) is      action "BLN_CPY";
    const proc: (inout integer param) := (in integer param) is      action "INT_CPY";
    const proc: (inout char param) := (ref char param) is           action "CHR_CPY";
    const proc: (inout string param) := (ref string param) is       action "STR_CPY";
    const proc: (inout reference param) := (ref reference param) is action "REF_CPY";
    const proc: (inout ref_list param) := (in ref_list param) is    action "RFL_CPY";
    const proc: (inout ptrType param) := (in ptrType param) is      action "REF_CPY";
    const proc: (inout varptrType param) := (in varptrType param) is action "REF_CPY";
    const proc: (inout arrayType param) := (in arrayType param) is  action "ARR_CPY";
    const proc: (inout bitset param) := (in bitset param) is        action "SET_CPY";
    const proc: (inout structType param) := (in structType param) is action "SCT_CPY";
    const proc: (inout enumType param) := (in enumType param) is    action "ENU_CPY";
    const proc: (inout PRIMITIVE_FILE param) := (ref PRIMITIVE_FILE param) is action "FIL_CPY";
    const proc: (inout file param) := (ref file param) is           action "CLS_CPY";
    const proc: (inout file param) := (ref null_file param) is      action "CLS_CPY2";
    const proc: (inout file param) := (ref external_file param) is  action "CLS_CPY2";


4.2 while-statement

  For example:

    while maximum > minimum do
      minimum := 2 * minimum + stepValue;
      decr(stepValue);
    end while;

  Semantics:
    First the condition between 'while' and 'do' is evaluated.
    When this evaluation yields 'FALSE', the while-statement is
    finished. When the evaluation yields 'TRUE', the statement
    between 'do' and 'end' is executed and the whole while-statement
    is executed again.


  Syntax:

    while_statement ::=
      'while' expression 'do'
        statement
      'end' 'while' .

  The expression must be of type 'boolean'.


  Declaration:

    $ syntax expr: .while.().do.().end.while is       -> 25;

    const proc: while (ref func boolean param) do (ref proc param) end while is action "PRC_WHILE";
    const proc: while (ref boolean param)  do (ref proc param) end while is     action "PRC_WHILE";

  Alternate declaration:

    const proc: while (ref func boolean: condition) do (ref proc: statement) end while is func
      begin
        if condition then
          statement;
          while condition do
            statement;
          end while;
        end if;
      end func;


4.3 repeat-statement

  For example:

    repeat
      incr(minimum);
      maximum := maximum - stepValue;
    until 2 * minimum > maximum;

  Semantics:
    The statement between 'repeat' and 'until' is executed.
    Then the condition after 'until' is evaluated. When this
    evaluation yields 'TRUE', the repeat-statement is finished.
    When the evaluation yields 'FALSE' the repeat-statement is
    executed again.


  Syntax:

    repeat_statement ::=
      'repeat'
        statement
      'until' expression .

  The expression must be of type 'boolean'.


  Declaration:

    $ syntax expr: .repeat.().until.() is             -> 25;

    const proc: repeat (ref proc param) until (ref func boolean param) is action "PRC_REPEAT";
    const proc: repeat (ref proc param) until (ref boolean param) is      action "PRC_REPEAT";

  Alternate declaration:

    const proc: repeat (ref proc: statement) until (ref func boolean: condition) is func
      begin
        statement;
        if not condition then
          repeat
            statement;
          until condition;
        end if;
      end func;


4.4 for-statement

  For example:

    for index range min_index to max_index do
      sumValue +:= field[index];
    end for;

  Semantics:
    When the 'to' symbol is used the for-statement is defined as
    follows:
      First the lower limit and the upper limit which stand behind
      'range' and 'to' are evaluated. Then the lower limit is assigned
      to the control variable which stands behind 'for'. If the value
      of the control variable is less than or equal the upper limit
      the statements behind 'do' are executed. After that the control
      variable is incremented and compared with the upper limit
      again. This compare - execute - increment cycle is repeated
      until the control variable is greater than the upper limit.
    When the 'downto' symbol is used the for-statement is defined as
    follows:
      First the upper limit and the lower limit which stand behind
      'range' and 'downto' are evaluated. Then the upper limit is
      assigned to the control variable which stands behind 'for'. If
      the value of the control variable is greater than or equal the
      lower limit the statements behind 'do' are executed. After that
      the control variable is decremented and compared with the lower
      limit again. This compare - execute - increment cycle is
      repeated until the control variable is less than the lower limit.


  Syntax:

    for_statement ::=
      'for' identifier 'range' expression [ 'to' | 'downto' ] expression 'do'
        statement
      'end' 'for' .


  Declaration:

    $ syntax expr: .for.().range.().to.().do.().end.for is     -> 25;
    $ syntax expr: .for.().range.().downto.().do.().end.for is -> 25;

    const proc: FOR_DECLS (in type: aType) is func
      begin
        const proc: for (inout aType: variable) range
            (in aType: lower_limit) to (in aType: upper_limit) do
            (in proc: statements) end for is func
          begin
            variable := lower_limit;
            if variable <= upper_limit then
              statements;
              while variable < upper_limit do
                incr(variable);
                statements;
              end while;
            end if;
          end func;

        const proc: for (inout aType: variable) range
            (in aType: upper_limit) downto (in aType: lower_limit) do
            (in proc: statements) end for is func
          begin
            variable := upper_limit;
            if variable >= lower_limit then
              statements;
              while variable > lower_limit do
                decr(variable);
                statements;
              end while;
            end if;
          end func;
      end func;

    FOR_DECLS(integer);
    FOR_DECLS(char);
    FOR_DECLS(boolean);


4.5 for-each-statement

  For example:

    for currObject range element_list do
      result &:= " " & str(currObject);
    end for;

  Semantics:
    First the element list which stands behind 'range' is evaluated.
    If the element list is empty the for-each-statement is finished.
    Otherwise the first element of the element list is assigned
    to the control variable which stands behind 'for'. Then the
    statements behind 'do' are executed. If there is no next element
    in the element the for-each-statement is finished. Otherwise
    the next element of the element list is assigned to the control
    variable. This check for next element - execute cycle is repeated
    until there is no next element in the element list.


  Syntax:

    for_statement ::=
      'for' identifier 'range' expression 'do'
        statement
      'end' 'for' .


  Declaration:

    $ syntax expr: .for.().range.().do.().end.for is          -> 25;

    const proc: for (ref reference param) range (ref ref_list param) do
                  (ref proc param)
                end for is action "RFL_FOR";

    const proc: for (inout baseType: variable) range (in arrayType: arr_obj) do
                  (in proc: statements)
                end for is func
      local
        var integer: number is 0;
      begin
        for number range 1 to length(arr_obj) do
          variable := arr_obj[number];
          statements;
        end for;
      end func;

    const proc: for (inout baseType: variable) range (in setType: a_set) do
                  (in proc: statements)
                end for is func
      begin
        for variable range min(a_set) to max(a_set) do
          if variable in a_set then
            statements;
          end if;
        end for;
      end func;


4.6 if-statement

  For example:

    if sumValue < minimum then
      factor := sumValue;
      sumValue := minimum;
    elsif sumValue > maximum then
      factor := -sumValue;
      sumValue := maximum;
    else
      factor := 0;
    end if;

  Semantics:
    The expressions before 'then' are evaluated in row.
    When such an expression evaluates to 'TRUE' the statements
    behind 'then' are executed and the if-statement is finished.
    If all expressions before 'then' evaluate to 'FALSE' and an
    else-part is present the statements behind 'else' are executed
    and the if-statement is finished.
    If all expressions before 'then' evaluate to 'FALSE' and no
    else-part is present the if-statement is finished.


  Syntax:

    if_statement ::=
      'if' expression 'then'
        statement
      { 'elsif' expression 'then'
        statement }
      [ 'else'
        statement ]
      'end' 'if' .

  The expression must be of type 'boolean'.


  Declaration:

    $ syntax expr: .if.().then.().end.if is           -> 25;
    $ syntax expr: .if.().then.().().end.if is        -> 25;

    $ syntax expr: .elsif.().then.() is               <- 60;
    $ syntax expr: .elsif.().then.().() is            <- 60;
    $ syntax expr: .else.() is                        <- 60;

    const type: ELSIF_RESULT is newtype;
    const proc: (ref ELSIF_RESULT param) ::= enumlit is  action "ENU_GENLIT";
    const ELSIF_RESULT: ELSIF_EMPTY is enumlit;
    const type: ELSIF_PROC is                        (func ELSIF_RESULT);
    const proc: (ref ELSIF_PROC param) ::= (ref ELSIF_RESULT param) is action "ENU_CREATE";

    const proc:       if (in boolean param) then
                        (in proc param)
                      end if is                        action "PRC_IF";

    const proc:       if (in boolean param) then
                        (in proc param)
                      (in ELSIF_PROC param)
                      end if is                        action "PRC_IF_ELSIF";

    const ELSIF_PROC: elsif (in boolean param) then
                        (in proc param) is             action "PRC_IF";

    const ELSIF_PROC: elsif (in boolean param) then
                        (in proc param)
                      (in ELSIF_PROC param) is         action "PRC_IF_ELSIF";

    const ELSIF_PROC: else
                        (in void param) is             ELSIF_EMPTY;


    const proc: if TRUE  then (in void param) end if is                           noop;
    const proc: if TRUE  then (in void param) (in ELSIF_PROC param) end if is     noop;
    const proc: if FALSE then (in proc param) end if is                           noop;
    const proc: if FALSE then (in proc param) (in ELSIF_RESULT param) end if is   noop;
    const ELSIF_PROC: elsif TRUE  then (in void param) is                         ELSIF_EMPTY;
    const ELSIF_PROC: elsif TRUE then (in void param) (in ELSIF_PROC param)   is  ELSIF_EMPTY;
    const ELSIF_PROC: elsif FALSE then (in proc param) is                         ELSIF_EMPTY;
    const ELSIF_PROC: elsif FALSE then (in proc param) (in ELSIF_RESULT param) is ELSIF_EMPTY;


4.7 case-statement

  For example:

    case currChar of
      when {'A' .. 'Z'} | {'a' .. 'z'}:
        characterClass := LETTER;
      when {'0' .. '9'}:
        characterClass := DIGIT;
      when {'!', '$', '%', '&', '*', '+', ',', '-', '.', '/',
          ':', ';', '<', '=', '>', '?', '@', '\', '^', '`',
          '|', '~'}:
        characterClass := SPECIAL;
      when {'(', ')', '[', ']', '{', '}'}:
        characterClass := PAREN;
      when {'"'}:  # Also possible '\"'
        characterClass := APPOSTROPHE;
      when {'''}:  # Also possible '\''
        characterClass := QUOTE;
      otherwise:
        characterClass := ILLEGAL;
    end case;

  Semantics:
    The expression between 'case' and 'of' is evaluated. When the
    resulting value is element of a set behind a 'when' the
    statements behind the corresponding colon are executed and
    the case-statement is finished. If the value is not element of
    a set behind a 'when' and an 'otherwise' part is present the
    statements behind the colon of the 'otherwise' are executed
    and the case-statement is finished. If the value is not element
    of a set behind a 'when' and no 'otherwise' part is present
    the case-statement is finished.


  Syntax:

    case_statement ::=
      'case' expression 'of'
        { 'when' set_expression ':'
          statement }
        [ 'otherwise' ':'
          statement ]
      'end' 'case' .


  Declaration:

    $ syntax expr: .case.().of.().end.case is                      -> 25;
    $ syntax expr: .case.().of.().otherwise. : .().end.case is     -> 25;
    $ syntax expr: .case.().of.end.case is                         -> 25;

    $ syntax expr: .when.(). : .().() is              <- 60;
    $ syntax expr: .when.(). : .() is                 <- 60;

    const proc: CASE_DECLS (in type: aType) is func
      local
        var type: WHEN_RESULT is void;
        var type: WHEN_PROC is void;
        var type: SELECTOR_TYPE is void;
      begin
        WHEN_RESULT := newtype;
        WHEN_PROC := (func WHEN_RESULT);
        SELECTOR_TYPE := set of aType;
        const proc: case (ref aType param) of end case                       is noop;
        const proc: case (ref aType param) of
                      (ref WHEN_PROC param)
                    end case                                                 is action "PRC_CASE";
        const proc: case (ref aType param) of
                      (ref WHEN_PROC param)
                      otherwise : (ref proc param)
                    end case                                                 is action "PRC_CASE_DEF";
        const proc: (ref WHEN_RESULT param) ::= enumlit                      is action "ENU_GENLIT";
        const WHEN_RESULT: WHEN_EMPTY (attr aType) is enumlit;
        const proc: (ref WHEN_PROC param) ::= (ref WHEN_RESULT param)        is action "ENU_CREATE";
        const WHEN_PROC: when (ref SELECTOR_TYPE param) : (ref proc param)   is WHEN_EMPTY(aType);
        const WHEN_PROC: when (ref SELECTOR_TYPE param) : (ref proc param)
                           (ref WHEN_PROC param)                             is WHEN_EMPTY(aType);
      end func;

    CASE_DECLS(integer);
    CASE_DECLS(char);



5. PREDEFINED TYPES
===================

    In the following subchapters the predefined types of the
  standard library are introduced. The operators have, when not
  stated otherwise, the type described in the subchapter as
  parameter type and result type. The relations have also the
  type described in the subchapter as parameter type and
  a result of type 'boolean'. In the descriptions => is used
  to show an equivalent expression.


5.1 boolean

    The type 'boolean' consists of the two truth values
  TRUE and FALSE. The 'boolean' functions are defined in
  the library "boolean.s7i".

    Prefix operators:
      not       Negation
                  ( not TRUE => FALSE,
                    not FALSE => TRUE )
    Infix operators:
      and       Logical and
                  ( TRUE and TRUE => TRUE,
                    A and B => FALSE else )
      or        Inclusive logical or
                  ( FALSE or FALSE => FALSE,
                    A or B => TRUE else )
      boolean conv A   Conversion of integer to boolean
                  ( Type of argument A: integer,
                    boolean conv 0 => FALSE,
                    boolean conv 1 => TRUE )
      boolean parse A   Conversion of string to boolean
                  ( Type of argument A: string,
                    boolean parse "FALSE" => FALSE,
                    boolean parse "TRUE" => TRUE,
                    boolean parse "TRUE " => EXCEPTION RANGE_ERROR,
                    boolean parse "ASDF" => EXCEPTION RANGE_ERROR )
    Relations:
      =, <>, >, >=, <, <=
                  ( A relation B =>
                    ord(A) relation ord(B) )
    Functions:
      ord(A)    Ordinal number
                  ( Type of result: integer,
                    ord(FALSE) => 0, ord(TRUE) => 1 )
      succ(A)   Successor
                  ( succ(FALSE) => TRUE,
                    succ(TRUE) => EXCEPTION RANGE_ERROR )
      pred(A)   Predecessor
                  ( pred(FALSE) => EXCEPTION RANGE_ERROR )
                    pred(TRUE) => FALSE )
      str(A)    Conversion to string
                  ( Type of result: string,
                    str(FALSE) => "FALSE",
                    str(TRUE) => "TRUE" )
      rand(A, B) Random value in the range [A, B]
                 The random values are uniform distributed.
                  ( rand(A, B) returns a random value such that
                    A <= rand(A, B) and rand(A, B) <= B holds.
                    rand(A, A) => A,
                    rand(TRUE, FALSE) => EXCEPTION RANGE_ERROR )
      compare(A, B) Compare function
                  ( Type of result: integer,
                    compare(FALSE, TRUE) => -1,
                    compare(TRUE, TRUE) => 0,
                    compare(TRUE, FALSE) => 1 )
      hashCode(A) Hash function
                  ( Type of result: integer )
    Statements:
      incr(A)   Increment
                  ( incr(A) => A:=succ(A) )
      decr(A)   Decrement
                  ( decr(A) => A:=pred(A) )


    The logical operators 'and' and 'or' work strictly left
  to right. First they evaluate the left operand and then
  the right operand. When the result of the operation can be
  determined after evaluation of the left operand the right
  operand is not evaluated. This can be used to check for
  a boundary in a boolean expression. Naturally side effects
  of the right operand of the 'and' and 'or' operator only
  take place when the operand is executed.


  Table for the behavior of different boolean expressions:

                               Result when the    Result when the
    Expression                  first operand      first operand
                             evaluates to FALSE  evaluates to TRUE

    not A                           TRUE               FALSE
    A and B  respectively
      not((not A)or(not B))         FALSE                B
    A or  B  respectively
      not((not A)and(not B))          B                TRUE
    A >  B  respectively
      A and(not B)                  FALSE              not B
    A >= B  respectively
      A or(not B)                   not B              TRUE
    A <  B  respectively
      (not A)and B                    B                FALSE
    A <= B  respectively
      (not A)or B                   TRUE                 B
    not (A and B)  respectively
      (not A)or(not B)              TRUE               not B
    not (A or B)  respectively
      (not A)and(not B)             not B              FALSE


  Optimizing boolean expressions:

    When the result of a boolean expression can be
  determined at compile time, the expression can be
  replaced by a constant. Additionally the following
  equations can be used:

    (A or  B) and (A or  C)  =  A or  (B and C)
    (A and B) or  (A and C)  =  A and (B or  C)


5.2 integer

    The type 'integer' consists of signed integer numbers
  which are at least 32 bits wide. An 'integer' literal is
  a sequence of digits which is taken to be decimal. The
  sequence of digits may be followed by the letter E or e
  an optional + sign and a decimal exponent. Based numbers
  can be specified when the sequence of digits is followed
  by the # character and a sequence of extended digits.
  The decimal number in front of the # character specifies
  the base of the number which follows the # character.
  As base a number between 2 and 36 is allowed. As
  extended digits the letters A or a can be used for 10,
  B or b can be used for 11 and so on to Z or z which can
  be used as 35. Examples of 'integer' literals are:

    0   2147483647   1E6   2e+9   16#c0   16#FFFF   8#177777   2#1010101010

  The result of an 'integer' operation is undefined when
  it overflows. The 'integer' functions are defined in
  the library "integer.s7i".

    Prefix operators:
      +         Identity
      -         Change sign
      !         Factorial
    Infix operators:
      +         Addition
      -         Subtraction
      *         Multiplication
      div       Integer division truncated towards zero
                  ( A div B => trunc(flt(A) / flt(B)),
                    A div 0 => EXCEPTION NUMERIC_ERROR )
      rem       Reminder of integer division div
                  ( A rem B => A - (A div B) * B,
                    A rem 0 => EXCEPTION NUMERIC_ERROR )
      mdiv      Integer division truncated towards negative infinity
                  ( A mdiv B => round(floor(flt(A) / flt(B))),
                    A mdiv 0 => EXCEPTION NUMERIC_ERROR )
      mod       Reminder of integer division mdiv
                  ( A mod B => A - (A mdiv B) * B,
                    A mod 0 => EXCEPTION NUMERIC_ERROR )
      **        Power
                  ( A ** B is okay for B >= 0,
                    A ** 0 => 1,
                    1 ** B => 1 for B >= 0,
                    A ** B => -(-A) ** B for A <= 0 and B >= 0 and odd(B),
                    A ** B => (-A) ** B for A <= 0 and B >= 0 and not odd(B),
                    A ** -1 => EXCEPTION NUMERIC_ERROR )
      A << B    Shift left
                  ( A << B is okay for B >= 0 and B <= 31,
                    A << B => A * 2 ** B,
                    A << 0 => A )
      A >> B    Arithmetic shift right
                  ( A >> B is okay for B >= 0 and B <= 31,
                    A >> B => A mdiv 2 ** B  for B <= 30,
                    A >> B => C for A >= 0 holds: C >= 0
                    A >> B => C for A < 0 holds: C < 0
                    A >> B => 0 for A >= 0 and B > ord(log2(A)),
                    A >> B => -1 for A < 0 and B > ord(log2(-A)),
                    A >> 0 => A )
      !         Binomial coefficient
                  ( A ! B => !A div (!B * !(A - B)) )
      lpad      Left padding with spaces
                  ( 123 lpad  8 => "     123",
                    123 lpad  4 => " 123",
                    123 lpad  3 => "123",
                    123 lpad  2 => "123",
                    123 lpad -8 => "123" )
                    -12 lpad  4 => " -12",
                    -12 lpad  3 => "-12",
                    -12 lpad  2 => "-12" )
      lpad0     Left padding with zeros
                  ( 123 lpad0  8 => "00000123",
                    123 lpad0  4 => "0123",
                    123 lpad0  3 => "123",
                    123 lpad0  2 => "123",
                    123 lpad0 -8 => "123",
                    -12 lpad0  4 => "-012",
                    -12 lpad0  3 => "-12",
                    -12 lpad0  2 => "-12" )
      rpad      Right padding with spaces
                  ( 123 rpad  8 => "123     ",
                    123 rpad  4 => "123 ",
                    123 rpad  3 => "123",
                    123 rpad  2 => "123",
                    123 rpad -8 => "123" )
                    -12 rpad  4 => "-12 ",
                    -12 rpad  3 => "-12",
                    -12 rpad  2 => "-12" )
      integer conv A   Identity
                  ( integer conv A => A )
      integer parse A   Conversion of string to integer
                  ( Type of argument A: string,
                    integer parse "123" => 123,
                    integer parse "-123" => -123,
                    integer parse "+5" => 5,
                    integer parse " 1" => EXCEPTION RANGE_ERROR,
                    integer parse "10 " => EXCEPTION RANGE_ERROR,
                    integer parse "ASDF" => EXCEPTION RANGE_ERROR )
    Relations:
      =, <>, <, <=, >, >=
    Functions:
      ord(A)    Identity
      succ(A)   Successor
                  ( succ(A) => A+1 )
      pred(A)   Predecessor
                  ( pred(A) => A-1 )
      abs(A)    Absolute value
      odd(A)    Odd value
                  ( Type of result: boolean )
      str(A)    Conversion to string
                  ( Type of result: string )
      literal(A) Conversion to a literal
                  ( Type of result: string,
                    literal(A) => str(A) )
      sqrt(A)   Integer square root
                  ( sqrt(A) is okay for A >= 0
                    sqrt(A) => trunc(sqrt(flt(A))),
                    sqrt(-1) => EXCEPTION NUMERIC_ERROR )
      log2(A)   Truncated base 2 logarithm
                  ( log2(A) returns the position of the
                    highest bit set. It is defined for A >= 0
                    log2(2 ** A) = A for A >= 0,
                    log2(0) => -1,
                    log2(1) => 0,
                    log2(2) => 1,
                    log2(-1) => EXCEPTION NUMERIC_ERROR )
      bitLength(A) Number of bits in the minimal two's-complement
                   representation, excluding the sign bit.
                  ( bitLength(A) => succ(log2(A)) for A >= 0,
                    bitLength(A) => succ(log2(pred(-A))) for A < 0 )
      lowestSetBit(A) Index of the lowest-order one bit
                      For A <> 0 this is equal to the number of
                      lowest-order zero bits.
                  ( A >> B << B = A for A <> 0 and B = lowestSetBit(A),
                    lowestSetBit(0) => -1,
                    lowestSetBit(1) => 0,
                    lowestSetBit(2) => 1 )
      rand(A, B) Random number in the range [A, B]
                 The random values are uniform distributed.
                  ( rand(A, B) returns a random number such that
                    A <= rand(A, B) and rand(A, B) <= B holds.
                    rand(A, A) => A,
                    rand(1, 0) => EXCEPTION RANGE_ERROR )
      compare(A, B) Compare function
                  ( compare(1, 2) => -1,
                    compare(5, 5) => 0,
                    compare(8, 7) => 1 )
      hashCode(A) Hash function
    Statements:
      A +:= B   Increment A by B
                  ( A +:= B => A := A + B )
      A -:= B   Decrement A by B
                  ( A -:= B => A := A - B )
      A *:= B   Multiplying copy
                  ( A *:= B => A := A * B )
      A <<:= B  Shift left copy
                  ( A <<:= B => A := A << B )
      A >>:= B  Shift right copy
                  ( A >>:= B => A := A >> B )
      incr(A)   Increment with 1
                  ( incr(A) => A +:= 1 )
      decr(A)   Decrement with 1
                  ( decr(A) => A -:= 1 )

  For the operations 'div' and 'rem' holds for all A:
    (A div B) * B + A rem B = A           when B <> 0
    -A div B = -(A div B)                 when B <> 0
    -A rem B = -(A rem B)                 when B <> 0
    A rem B >= 0 and A rem B < abs(B)     when B <> 0 and A >= 0
    A rem B <= 0 and A rem B > -abs(B)    when B <> 0 and A <= 0

  For the operations 'mdiv' and 'mod' holds for all A:
    (A mdiv B) * B + A mod B = A          when B <> 0
    -A mdiv B = A mdiv -B                 when B <> 0
    -A mod -B = -(A mod B)                when B <> 0
    A mod B >= 0 and A mod B < B          when B > 0
    A mod B <= 0 and A mod B > B          when B < 0

  For the operation 'mdiv' holds:
    A mdiv B = A div B - 1            when A and B have different
                                      signs and A rem B <> 0 holds.
    A mdiv B = A div B                when A and B have the same
                                      sign or A rem B = 0 holds.
    A mdiv B = (A - 1) div B - 1      when A > 0 and B < 0 holds.
    A mdiv B = (A + 1) div B - 1      when A < 0 and B > 0 holds.
    A mdiv 2 ** B = A >> B            when B >= 0 holds

  For the operation 'mod' holds:
    A mod B = A rem B + B      when A and B have different
                               signs and A rem B <> 0 holds.
    A mod B = A rem B          when A and B have the same
                               sign or A rem B = 0 holds.


  Table for the behavior of 'div', 'rem', 'mdiv' and 'mod':

     A    B   A div B   A rem B   A mdiv B  A mod B

     5    3      1         2         1         2
     4    3      1         1         1         1
     3    3      1         0         1         0
     2    3      0         2         0         2
     1    3      0         1         0         1
     0    3      0         0         0         0
    -1    3      0        -1        -1         2
    -2    3      0        -2        -1         1
    -3    3     -1         0        -1         0
    -4    3     -1        -1        -2         2
    -5    3     -1        -2        -2         1

     A    B   A div B   A rem B   A mdiv B  A mod B

     5   -3     -1         2        -2        -1
     4   -3     -1         1        -2        -2
     3   -3     -1         0        -1         0
     2   -3      0         2        -1        -1
     1   -3      0         1        -1        -2
     0   -3      0         0         0         0
    -1   -3      0        -1         0        -1
    -2   -3      0        -2         0        -2
    -3   -3      1         0         1         0
    -4   -3      1        -1         1        -1
    -5   -3      1        -2         1        -2


  For the 'sqrt' function holds (when A >= 0):
    sqrt(A) * sqrt(A) <= A and
    (sqrt(A) + 1) * (sqrt(A) + 1) > A


5.3 bigInteger

    The type 'bigInteger' describes signed integer numbers of
  unlimited size. The literals of the type 'bigInteger' are sequences
  of digits followed by an underscore character (for example 1_ ).
  Although 'bigInteger' operations cannot overflow, it can happen
  that there is not enough memory to represent a 'bigInteger' value.
  In this case the exception 'MEMORY_ERROR' is raised. The 'bigInteger'
  functions are defined in the library "bigint.s7i".

    Prefix operators:
      +         Identity
      -         Change sign
      !         Factorial
    Infix operators:
      +         Addition
      -         Subtraction
      *         Multiplication
      div       Integer division truncated towards zero
                  ( A div B => trunc(A / B),
                    A div 0_ => EXCEPTION NUMERIC_ERROR )
      rem       Reminder of integer division div
                  ( A rem B => A - (A div B) * B,
                    A rem 0_ => EXCEPTION NUMERIC_ERROR )
      mdiv      Integer division truncated towards negative infinity
                  ( A mdiv B => floor(A / B),
                    A mdiv 0_ => EXCEPTION NUMERIC_ERROR )
      mod       Reminder of integer division mdiv
                  ( A mod B => A - (A mdiv B) * B,
                    A mod 0_ => EXCEPTION NUMERIC_ERROR )
      A ** B    Power
                  ( Type of argument B: integer,
                    A ** B is okay for B >= 0,
                    A ** 0 => 1_,
                    1_ ** B => 1_ for B >= 0,
                    A ** B => -(-A) ** B for A <= 0 and B >= 0 and odd(B),
                    A ** B => (-A) ** B for A <= 0 and B >= 0 and not odd(B),
                    A ** -1 => EXCEPTION NUMERIC_ERROR )
      A << B    Shift left
                  ( Type of argument B: integer,
                    A << B is okay for B >= 0,
                    A << B => A * 2_ ** B,
                    A << 0 => A,
                    A << -1 => EXCEPTION NUMERIC_ERROR )
      A >> B    Arithmetic shift right
                  ( Type of argument B: integer,
                    A >> B is okay for B >= 0,
                    A >> B => A mdiv 2_ ** B,
                    A >> B => C for A >= 0_ holds: C >= 0_
                    A >> B => C for A < 0_ holds: C < 0_
                    A >> B => 0_ for A >= 0_ and B > ord(log2(A)),
                    A >> B => -1_ for A < 0_ and B > ord(log2(-A)),
                    A >> 0 => A,
                    A >> -1 => EXCEPTION NUMERIC_ERROR )
      bigInteger conv A   Conversion of integer to bigInteger
                  ( Type of argument A: integer,
                    bigInteger conv 1 => 1_ )
      bigInteger parse A   Conversion of string to integer
                  ( Type of argument A: string,
                    bigInteger parse "123" => 123_,
                    bigInteger parse "-123" => -123_,
                    bigInteger parse " 1" => EXCEPTION RANGE_ERROR,
                    bigInteger parse "+5" => EXCEPTION RANGE_ERROR,
                    bigInteger parse "10 " => EXCEPTION RANGE_ERROR,
                    bigInteger parse "ASDF" => EXCEPTION RANGE_ERROR )
    Relations:
      =, <>, <, <=, >, >=
    Functions:
      ord(A)    Ordinal number
                  ( Type of result: integer )
                    ord(99999999999999999999_) => EXCEPTION RANGE_ERROR )
      succ(A)   Successor
                  ( succ(A) => A+1_ )
      pred(A)   Predecessor
                  ( pred(A) => A-1_ )
      abs(A)    Absolute value
      odd(A)    Odd value
                  ( Type of result: boolean )
      str(A)    Conversion to string
                  ( Type of result: string )
      sqrt(A)   Integer square root
                  ( sqrt(A) is okay for A >= 0_
                    sqrt(A) => trunc(sqrt(flt(A))),
                    sqrt(-1_) => EXCEPTION NUMERIC_ERROR )
      log2(A)   Truncated base 2 logarithm
                  ( log2(A) returns the position of the
                    highest bit set. It is defined for A >= 0
                    log2(2_ ** A) = A for A >= 0,
                    log2(0_) => -1_,
                    log2(1_) => 0_,
                    log2(2_) => 1_,
                    log2(-1) => EXCEPTION NUMERIC_ERROR )
      gcd(A, B) Greatest common divisor of A and B.
                  ( gcd(A, B) = gcd(B, A),
                    gcd(A, B) = gcd(-A, B),
                    gcd(A, 0) = abs(A) )
      bitLength(A) Number of bits in the minimal two's-complement
                   representation, excluding the sign bit.
                  ( Type of result: integer,
                    bitLength(A) => ord(succ(log2(A))) for A >= 0_,
                    bitLength(A) => ord(succ(log2(pred(-A)))) for A < 0_ )
      lowestSetBit(A) Index of the lowest-order one bit
                      For A <> 0_ this is equal to the number of
                      lowest-order zero bits.
                  ( Type of result: integer,
                    A >> B << B = A for A <> 0_ and B = lowestSetBit(A),
                    lowestSetBit(0_) => -1,
                    lowestSetBit(1_) => 0,
                    lowestSetBit(2_) => 1 )
      rand(A, B) Random number in the range [A, B]
                 The random values are uniform distributed.
                  ( rand(A, B) returns a random number such that
                    A <= rand(A, B) and rand(A, B) <= B holds.
                    rand(A, A) => A,
                    rand(1_, 0_) => EXCEPTION RANGE_ERROR )
      compare(A, B) Compare function
                  ( Type of result: integer,
                    compare(1_, 2_) => -1,
                    compare(5_, 5_) => 0,
                    compare(8_, 7_) => 1 )
      hashCode(A) Hash function
                  ( Type of result: integer )
    Statements:
      A +:= B   Increment A by B
                  ( A +:= B => A := A + B )
      A -:= B   Decrement A by B
                  ( A -:= B => A := A - B )
      A *:= B   Multiplying copy
                  ( A *:= B => A := A * B )
      A <<:= B  Shift left copy
                  ( A <<:= B => A := A << B )
      A >>:= B  Shift right copy
                  ( A >>:= B => A := A >> B )
      incr(A)   Increment with 1
                  ( incr(A) => A +:= 1_ )
      decr(A)   Decrement with 1
                  ( decr(A) => A -:= 1_ )

  For the operations 'div' and 'rem' holds for all A:
    (A div B) * B + A rem B = A           when B <> 0_
    -A div B = -(A div B)                 when B <> 0_
    -A rem B = -(A rem B)                 when B <> 0_
    A rem B >= 0_ and A rem B < abs(B)    when B <> 0_ and A >= 0_
    A rem B <= 0_ and A rem B > -abs(B)   when B <> 0_ and A <= 0_

  For the operations 'mdiv' and 'mod' holds for all A:
    (A mdiv B) * B + A mod B = A          when B <> 0_
    -A mdiv B = A mdiv -B                 when B <> 0_
    -A mod -B = -(A mod B)                when B <> 0_
    A mod B >= 0_ and A mod B < B         when B > 0_
    A mod B <= 0_ and A mod B > B         when B < 0_

  For the operation 'mdiv' holds:
    A mdiv B = A div B - 1_           when A and B have different
                                      signs and A rem B <> 0_ holds.
    A mdiv B = A div B                when A and B have the same
                                      sign or A rem B = 0_ holds.
    A mdiv B = (A - 1_) div B - 1_    when A > 0_ and B < 0_ holds.
    A mdiv B = (A + 1_) div B - 1_    when A < 0_ and B > 0_ holds.
    A mdiv 2_ ** B = A >> B           when B >= 0 holds

  For the operation 'mod' holds:
    A mod B = A rem B + B      when A and B have different
                               signs and A rem B <> 0_ holds.
    A mod B = A rem B          when A and B have the same
                               sign or A rem B = 0_ holds.


  Table for the behavior of 'div', 'rem', 'mdiv' and 'mod':

     A    B   A div B   A rem B   A mdiv B  A mod B

     5_   3_     1_        2_        1_        2_
     4_   3_     1_        1_        1_        1_
     3_   3_     1_        0_        1_        0_
     2_   3_     0_        2_        0_        2_
     1_   3_     0_        1_        0_        1_
     0_   3_     0_        0_        0_        0_
    -1_   3_     0_       -1_       -1_        2_
    -2_   3_     0_       -2_       -1_        1_
    -3_   3_    -1_        0_       -1_        0_
    -4_   3_    -1_       -1_       -2_        2_
    -5_   3_    -1_       -2_       -2_        1_

     A    B   A div B   A rem B   A mdiv B  A mod B

     5_  -3_    -1_        2_       -2_       -1_
     4_  -3_    -1_        1_       -2_       -2_
     3_  -3_    -1_        0_       -1_        0_
     2_  -3_     0_        2_       -1_       -1_
     1_  -3_     0_        1_       -1_       -2_
     0_  -3_     0_        0_        0_        0_
    -1_  -3_     0_       -1_        0_       -1_
    -2_  -3_     0_       -2_        0_       -2_
    -3_  -3_     1_        0_        1_        0_
    -4_  -3_     1_       -1_        1_       -1_
    -5_  -3_     1_       -2_        1_       -2_


  For the 'sqrt' function holds (when A >= 0_):
    sqrt(A) * sqrt(A) <= A and
    (sqrt(A) + 1_) * (sqrt(A) + 1_) > A


5.4 rational

    The type 'rational' consists of rational numbers
  represented with an 'integer' numerator and an 'integer'
  denominator. The values of the type 'rational' are
  finite and periodical decimal numbers. Rational literals
  do not exist. The result of a 'rational' operation
  is undefined when it overflows. The 'rational' functions
  are defined in the library "rational.s7i".

    Elements:
      var integer: numerator is 0;
      var integer: denominator is 1;
    Prefix operators:
      +         Identity
      -         Change sign
    Infix operators:
      +         Addition
      -         Subtraction
      *         Multiplication
      /         Division
      /         Create rational from numerator and denominator
                  ( Type of left operand: integer,
                    Type of right operand: integer )
      **        Power
                  ( rational ** integer )
      rational conv A   Conversion of integer to rational
                  ( Type of argument A: integer,
                    rational conv 1 => 1 / 1 )
      rational parse A   Conversion of string to rational
                  ( Type of argument A: string )
    Relations:
      =, <>, <, <=, >, >=
    Functions:
      abs(A)    Absolute value
      rat(A)    Conversion of integer to rational
                  ( Type of argument A: integer,
                    rat(1) => 1 / 1 )
      floor(A)  Truncation towards negative infinity
                  ( Type of result: integer,
                    floor( 1.8)=> 1, floor( 1.0)=> 1,
                    floor(-1.0)=>-1, floor(-1.8)=>-2 )
      ceil(A)   Rounding up towards positive infinity
                  ( Type of result: integer,
                    ceil( 1.2)=> 2, ceil( 1.0)=> 1,
                    ceil(-1.0)=>-1, ceil(-1.2)=>-1 )
      trunc(A)  Truncation towards zero
                  ( Type of result: integer,
                    trunc( 1.8)=> 1, trunc( 1.0)=> 1,
                    trunc(-1.0)=>-1, trunc(-1.8)=>-1 )
      round(A)  Round towards zero
                  ( Type of result: integer,
                    round(0.5)=>1, round(-0.5)=>-1,
                    round(0.4)=>0, round(-0.4)=>0 )
      str(A)    Conversion to string
                  ( Type of result: string )
      compare(A, B) Compare function
                  ( Type of result: integer,
                    compare(1.9, 2.0) => -1,
                    compare(5.2, 5.2) => 0,
                    compare(8.0, 7.9) => 1 )
      hashCode(A) Hash function
                  ( Type of result: integer )
    Statements:
      A +:= B   Increment A by B
                  ( A +:= B => A := A + B )
      A -:= B   Decrement A by B
                  ( A -:= B => A := A - B )
      A *:= B   Multiplying copy
                  ( A *:= B => A := A * B )

  All calculations with 'rational' numbers are done exact.
  (Without any rounding)


5.5 bigRational

    The type 'bigRational' consists of rational numbers
  represented with an 'bigInteger' numerator and an
  'bigInteger' denominator. The values of the type
  'bigRational' are finite and periodical decimal numbers.
  BigRational literals do not exist. Although 'bigRational'
  operations cannot overflow, it can happen that there
  is not enough memory to represent a 'bigRational' value.
  In this case the exception 'MEMORY_ERROR' is raised.
  The 'bigRational' functions are defined in the library
  "bigrat.s7i".

    Elements:
      var bigInteger: numerator is 0_;
      var bigInteger: denominator is 1_;
    Prefix operators:
      +         Identity
      -         Change sign
    Infix operators:
      +         Addition
      -         Subtraction
      *         Multiplication
      /         Division
      /         Create bigRational from numerator and denominator
                  ( Type of left argument: bigInteger,
                    Type of right argument: bigInteger )
      **        Power
                  ( bigRational ** integer )
      bigRational conv A   Conversion of integer to bigRational
                  ( Type of argument A: integer,
                    bigRational conv 1 => 1_ / 1_ )
      bigRational conv A   Conversion of bigInteger to bigRational
                  ( Type of argument A: bigInteger,
                    bigRational conv 1_ => 1_ / 1_ )
      bigRational parse A   Conversion of string to bigRational
                  ( Type of argument A: string )
    Relations:
      =, <>, <, <=, >, >=
    Functions:
      abs(A)    Absolute value
      rat(A)    Conversion of bigInteger to bigRational
                  ( Type of argument A: bigInteger,
                    rat(1_) => 1_ / 1_ )
      floor(A)  Truncation towards negative infinity
                  ( Type of result: bigInteger,
                    floor( 1.8)=> 1, floor( 1.0)=> 1,
                    floor(-1.0)=>-1, floor(-1.8)=>-2 )
      ceil(A)   Rounding up towards positive infinity
                  ( Type of result: bigInteger,
                    ceil( 1.2)=> 2, ceil( 1.0)=> 1,
                    ceil(-1.0)=>-1, ceil(-1.2)=>-1 )
      trunc(A)  Truncation towards zero
                  ( Type of result: bigInteger,
                    trunc( 1.8)=> 1, trunc( 1.0)=> 1,
                    trunc(-1.0)=>-1, trunc(-1.8)=>-1 )
      round(A)  Round towards zero
                  ( Type of result: bigInteger,
                    round(0.5)=>1, round(-0.5)=>-1,
                    round(0.4)=>0, round(-0.4)=>0 )
      str(A)    Conversion to string
                  ( Type of result: string )
      compare(A, B) Compare function
                  ( Type of result: integer,
                    compare(1.9, 2.0) => -1,
                    compare(5.2, 5.2) => 0,
                    compare(8.0, 7.9) => 1 )
      hashCode(A) Hash function
                  ( Type of result: integer )
    Statements:
      A +:= B   Increment A by B
                  ( A +:= B => A := A + B )
      A -:= B   Decrement A by B
                  ( A -:= B => A := A - B )
      A *:= B   Multiplying copy
                  ( A *:= B => A := A * B )

  All calculations with 'bigRational' numbers are done exact.
  (Without any rounding)


5.6 float

    The type 'float' consists of single precision floating point
  numbers. Float literals are base 10 and contain a decimal point.
  There must be at least one digit before and after the decimal point.
  An exponent part, which is introduced with E or e, is optional.
  The exponent can be signed, but the mantissa is not. A literal does
  not have a sign, + or - are unary operations. Examples of 'float'
  literals are:

  3.14159265358979
  1.0E-12
  0.1234

  The functions 'str' and the operators 'digits' and 'parse'
  create and accept float literals with sign. Basic 'float'
  functions are defined in the library "float.s7i".
  Trigonometric- and other mathematical functions are defined
  in the library "math.s7i".

    Constants:
      Infinity  Positive infinity
      NaN       Not-a-Number
    Prefix operators:
      +         Identity
      -         Change sign
    Infix operators:
      +         Addition
      -         Subtraction
      *         Multiplication
      /         Division
                  ( A / 0.0 =>  Infinity for A > 0.0,
                    A / 0.0 => -Infinity for A < 0.0,
                    0.0 / 0.0 => NaN )
      **        Power
                  ( A ** B is okay for A > 0.0,
                    A ** B is okay for A < 0.0 and B is integer,
                    A ** B => NaN for A < 0.0 and B is not integer,
                    A ** 0.0 => 1.0,
                    0.0 ** B => 0.0 for B > 0.0,
                    0.0 ** 0.0 => 1.0,
                    0.0 ** B => Infinity for B < 0.0 )
      **        Power
                  ( Type of right operand: integer
                    A ** B is okay for A > 0.0,
                    A ** B is okay for A < 0.0,
                    A ** 0 => 1.0,
                    0.0 ** B => 0.0 for B > 0,
                    0.0 ** 0 => 1.0,
                    0.0 ** B => Infinity for B < 0 )
      float conv A   Conversion of integer to float
                  ( Type of argument A: integer,
                    float conv 1 => 1.0 )
      digits    Conversion to string with specified precision
                  ( Type of right operand: integer,
                    Type of result: string,
                    0.012345 digits 4 => "0.0123",
                    1.2468 digits 2 => "1.25",
                    0.125 digits 2 => "0.12",
                    0.375 digits 2 => "0.38",
                    Infinity digits A => "Infinity",
                    -Infinity digits A => "-Infinity",
                    NaN digits A => "NaN" )
      float parse A   Conversion of string to float
                  ( Type of argument A: string )
    Relations:
      =, <>, <, <=, >, >=
    Functions:
      abs(A)    Absolute value
      flt(A)    Conversion of integer to float
                  ( Type of argument A: integer,
                    flt(1) => 1.0 )
      floor(A)  Truncation towards negative infinity
                  ( floor( 1.8)=> 1.0, floor( 1.0)=> 1.0,
                    floor(-1.0)=>-1.0, floor(-1.2)=>-2.0,
                    floor( 0.9)=> 0.0, floor(-0.1)=>-1.0 )
      ceil(A)   Rounding up towards positive infinity
                  ( ceil( 1.2)=> 2.0, ceil( 1.0)=> 1.0,
                    ceil(-1.8)=>-1.0, ceil(-1.0)=>-1.0,
                    ceil( 0.1)=> 1.0, ceil(-0.9)=> 0.0 )
      trunc(A)  Truncation towards zero
                  ( Type of result: integer,
                    trunc( 1.8)=> 1, trunc( 1.0)=> 1,
                    trunc(-1.8)=>-1, trunc(-1.0)=>-1,
                    trunc( 0.9)=> 0, trunc(-0.9)=> 0 )
      round(A)  Round towards zero
                  ( Type of result: integer,
                    round(1.5)=>2, round(-1.5)=>-2,
                    round(0.5)=>1, round(-0.5)=>-1,
                    round(0.4)=>0, round(-0.4)=>0 )
      str(A)    Conversion to string
                  ( Type of result: string,
                    str(Infinity) => "Infinity",
                    str(-Infinity) => "-Infinity",
                    str(NaN) => "NaN" )
      isnan(A)  Check if A is Not-a-Number
      sin(A)    Sine
      cos(A)    Cosine
      tan(A)    Tangent
      exp(A)    Exponential function
      log(A)    Natural logarithm
                  ( log(A) is okay for A > 0.0,
                    log(0.0)  => -Infinity,
                    log(-1.0) =>  NaN )
      log10(A)  Base 10 logarithm
                  ( log10(A) is okay for A > 0.0,
                    log10(0.0)  => -Infinity,
                    log10(-1.0) =>  NaN )
      sqrt(A)   Square root
                  ( sqrt(A) is okay for A >= 0.0,
                    sqrt(-1.0) => NaN )
      asin(A)   Inverse sine
                  ( asin(A) is okay for A >= -1.0 and A <= 1.0,
                    asin(2.0) => NaN )
      acos(A)   Inverse cosine
                  ( acos(A) is okay for A >= -1.0 and A <= 1.0,
                    acos(2.0) => NaN )
      atan(A)   Inverse tangent
      atan2(A, B) Inverse tangent of A / B
      sinh(A)   Hyperbolic sine
      cosh(A)   Hyperbolic cosine
      tanh(A)   Hyperbolic tangent
      rand(A, B) Random number in the range [A, B]
                 The random values are uniform distributed.
                  ( rand(A, B) returns a random number such that
                    A <= rand(A, B) and rand(A, B) <= B holds.
                    rand(A, A) => A,
                    rand(1.0, 0.0) => EXCEPTION RANGE_ERROR )
      compare(A, B) Compare function
                  ( Type of result: integer,
                    compare(1.9, 2.1) => -1,
                    compare(5.3, 5.3) => 0,
                    compare(7.8, 7.7) => 1 )
      hashCode(A) Hash function
                  ( Type of result: integer )
    Statements:
      A +:= B   Increment A by B
                  ( A +:= B => A := A + B )
      A -:= B   Decrement A by B
                  ( A -:= B => A := A - B )
      A *:= B   Multiplying copy
                  ( A *:= B => A := A * B )
      A /:= B   Dividing copy
                  ( A /:= B => A := A / B )


5.7 complex

    The type 'complex' consists of complex numbers represented
  with an 'float' real part and an 'float' imaginary part.
  Complex literals do not exist. The 'complex' functions are
  defined in the library "complex.s7i".

    Elements:
      var float: re is 0.0;
      var float: im is 0.0;
    Prefix operators:
      +         Identity
      -         Change sign
      conj      Complex conjugate
    Infix operators:
      +         Addition
      -         Subtraction
      *         Multiplication
      /         Division
                  ( A / complex(0.0) => complex(NaN, NaN) )
      **        Power
                  ( Type of right operand: integer
                    A ** B is okay for A > complex(0.0),
                    A ** B is okay for A < complex(0.0),
                    A ** 0 => complex(1.0),
                    complex(0.0) ** B => complex(0.0) for B > 0,
                    complex(0.0) ** 0 => complex(1.0),
                    complex(0.0) ** B => complex(Infinity, NaN) for B < 0 )
      complex conv A   Conversion of integer to complex
                  ( Type of argument A: integer,
                    complex conv A => complex(flt(A)) )
      complex conv A   Conversion of float to complex
                  ( Type of argument A: float,
                    complex conv A => complex(A) )
      digits    Conversion to string with specified precision
                  ( Type of right operand: integer,
                    Type of result: string,
                    complex(3.1415) digits 2 => "3.14+0.00i" )
      complex parse A   Conversion of string to complex
                  ( Type of argument A: string )
    Relations:
      =, <>
    Functions:
      abs(A)    Absolute value
                  ( Type of result: float )
      sqrAbs(A) Square of absolute value
                  ( Type of result: float )
      arg(A)    Argument (=angle of the polar form of A)
                  ( Type of result: float )
      complex(A, B)  Return a complex number from its real and imaginary part
                  ( Type of argument A: float,
                    Type of argument B: float )
      complex(A)  Return a complex number from its real part
                  ( Type of argument A: float )
      polar(A, B)  Return a complex number from polar coordinates
                  ( Type of argument A: float,
                    Type of argument B: float )
      str(A)    Conversion to string
                  ( Type of result: string,
                    str(complex(1.125)) => "1.125+0.0i" )
    Statements:
      A +:= B   Increment A by B
                  ( A +:= B => A := A + B )
      A -:= B   Decrement A by B
                  ( A -:= B => A := A - B )
      A *:= B   Multiplying copy
                  ( A *:= B => A := A * B )
      A /:= B   Dividing copy
                  ( A /:= B => A := A / B )


5.8 char

    The type 'char' describes Unicode characters encoded
  with UTF-32. In the source file a character literal is
  written as UTF-8 encoded Unicode character enclosed in
  single quotes. In order to represent non-printable
  characters and certain printable characters the following
  escape sequences may be used.

    audible alert    BEL      \a    backslash    (\)   \\
    backspace        BS       \b    apostrophe   (')   \'   
    escape           ESC      \e    double quote (")   \"
    formfeed         FF       \f
    newline          NL (LF)  \n    control-A          \A
    carriage return  CR       \r      ...
    horizontal tab   HT       \t    control-Z          \Z
    vertical tab     VT       \v

  Additionally the following escape sequence can be used:

    - Two backslashes with an integer literal between them are
      interpreted as character with the specified ordinal number.
      Note that the integer literal is interpreted decimal unless
      it is written as based integer.

  Examples of character literals are:

    'a'   ' '   '\n'   '!'   '\\'   '2'   '"'   '\"'   '\''   '\8\'

  To use characters beyond ASCII (which is a subset of Unicode)
  in the source file make sure that the editor uses UTF-8
  encoded characters. The 'char' functions are defined in
  the library "char.s7i".

    Infix operators:
      char conv A   Conversion of integer to char
                  ( Type of argument A: integer,
                    char conv 65 => 'A' )
      char parse A   Conversion of string to char
                  ( Type of argument A: string )
    Relations:
      =, <>, <, <=, >, >=
    Functions:
      ord(A)    Ordinal number
                  ( Type of result: integer )
      chr(A)    Conversion of integer to char
                  ( Type of argument: integer )
      succ(A)   Successor
                  ( succ(A)=>chr(succ(ord(A))) )
      pred(A)   Predecessor
                  ( pred(A)=>chr(pred(ord(A))) )
      str(A)    Conversion to string
                  ( Type of result: string,
                    str('A') => "A" )
      literal(A) Conversion to a literal
                  ( Type of result: string,
                    literal('A') => "'A'" )
      upper(A)  Conversion to upper case character
                  ( upper('A') => 'A' )
                  ( upper('z') => 'Z' )
      lower(A)  Conversion to lower case character
                  ( lower('A') => 'a' )
                  ( lower('z') => 'z' )
      rand(A, B) Random character in the range [A, B]
                 The random values are uniform distributed.
                  ( rand(A, B) returns a random character such that
                    A <= rand(A, B) and rand(A, B) <= B holds.
                    rand(A, A) => A,
                    rand('B', 'A') => EXCEPTION RANGE_ERROR )
      compare(A, B) Compare function
                  ( Type of result: integer,
                    compare('A', 'B') => -1,
                    compare('A', 'A') => 0,
                    compare('B', 'A') => 1 )
      hashCode(A) Hash function
                  ( Type of result: integer )
    Statements:
      incr(A)   Increment
                  ( incr(A) => A := succ(A) )
      decr(A)   Decrement
                  ( decr(A) => A := pred(A) )


5.9 string

    The type 'string' describes sequences of Unicode characters
  (including the empty string). The characters in the 'string'
  use the UTF-32 encoding. Strings are not '\0\' terminated
  and therefore can also contain binary data. Although 'string's
  are allowed to grow very big, it can happen that there is not
  enough memory to represent a 'string' value. In this case the
  exception 'MEMORY_ERROR' is raised. In the source file a string
  literal is a sequence of UTF-8 encoded Unicode characters
  surrounded by double quotes.

  To represent control characters and certain other characters
  in strings the same escape sequences as for character literals
  may be used. E.g.: Quotation characters (") inside strings can
  be represented by preceding them with a backslash ( \" ).
  Additionally there is the following possibility:

    - Two backslashes with a sequence of blanks, horizontal tabs,
      carriage returns and new lines between them are completely
      ignored. The ignored characters are not part of the string.
      This can be used to continue a string in the following line.
      Note that in this case the leading spaces in the new line
      are not part of the string. Although this possibility exists
      also for character literals it is mentioned here, since it
      makes more sense to use it with string literals

  Examples of string literals are:

    ""   " "   "\""   "'"   "String"   "CAN\"T !"

  To use characters beyond ASCII (which is a subset of Unicode)
  in the source file make sure that the editor uses UTF-8
  encoded characters. The 'string' functions are defined in
  the library "string.s7i".

    Infix operators:
      &         String concatenation
                  ( "All " & "OK" => "All OK" )
      <&        String concatenation with weak priority
                Overloaded for various types with 'enable_io'
                  ( write("i=" <& i digits 2 len 6 <& " $"); )
      mult      String multiplication
                  ( Type of right operand: integer,
                    "LA" mult 3 => "LALALA",
                    "WORD" mult 0 => "",
                    "ANY" mult -1 => EXCEPTION RANGE_ERROR )
      lpad      Left padding with spaces
                  ( Type of right operand: integer,
                    "HELLO" lpad  8 => "   HELLO",
                    "HELLO" lpad  6 => " HELLO",
                    "HELLO" lpad  5 => "HELLO",
                    "HELLO" lpad  4 => "HELLO",
                    "HELLO" lpad  0 => "HELLO",
                    "HELLO" lpad -8 => "HELLO" )
      lpad0      Left padding with zeroes
                  ( Type of right operand: integer,
                    "12" lpad0  5 => "00012",
                    "12" lpad0  3 => "012",
                    "12" lpad0  2 => "12",
                    "12" lpad0  1 => "12",
                    "12" lpad0  0 => "12",
                    "12" lpad0 -5 => "12" )
      rpad      Right padding with spaces
                  ( Type of right operand: integer,
                    "HELLO" rpad  8 => "HELLO   ",
                    "HELLO" rpad  6 => "HELLO ",
                    "HELLO" rpad  5 => "HELLO",
                    "HELLO" rpad  4 => "HELLO",
                    "HELLO" rpad  0 => "HELLO",
                    "HELLO" rpad -8 => "HELLO" )
      string parse A   Identity
    Indices:
      [ A ]     Access one character
                  ( Type of argument A: integer,
                    Type of result: char,
                    "abcde"[1] => 'a',
                    "abcde"[5] => 'e',
                    "abcde"[0] => EXCEPTION RANGE_ERROR,
                    "abcde"[6] => EXCEPTION RANGE_ERROR )
      [ A .. B ] Access a substring from position A to B
                  ( Type of arguments A and B: integer,
                    "abcde"[2 .. 4] => "bcd",
                    "abcde"[2 .. 7] => "bcde",
                    "abcde"[4 .. 2] => "",
                    "abcde"[6 .. 8] => "",
                    "abcde"[-3 .. 4] => "abcd",
                    "abcde"[-3 .. 7] => "abcde",
                    "abcde"[-3 .. 0] => "" )
      [ A len B ] Access a substring from position A with length B
                  ( Type of arguments A and B: integer,
                    "abcde"[2 len 3] => "bcd",
                    "abcde"[2 len 5] => "bcde",
                    "abcde"[-3 len 8] => "abcd",
                    "abcde"[-1 len 9] => "abcde" )
      [ A .. ]  Access a substring beginning at position A
                  ( Type of argument A: integer,
                    "abcde"[3 ..] => "cde",
                    "abcde"[6 ..] => "",
                    "abcde"[-3 ..] => "abcde",
                    ""[1 ..] => "" )
      [ .. A ]  Access a substring ending at position A
                  ( Type of argument A: integer,
                    "abcde"[.. 4] => "abcd",
                    "abcde"[.. 6] => "abcde",
                    "abcde"[.. -3] => "",
                    ""[.. 5] => "" )
    Relations:
      =, <>, <, <=, >, >=
    Functions:
      length(A) Length of string
                  ( Type of result: integer,
                    length("") => 0 )
      pos(A,B)  First position of char B in string A
                  ( Type of argument B: char,
                    Type of result: integer,
                    pos("ABCABC",'B')=>2,
                    pos("XYZ",'A')=>0 )
      pos(A,B)  First position of string B in string A
                  ( Type of result: integer,
                    pos("ABCDE ABCDE","BC")=>2,
                    pos("XYZXYZ","ZYX")=>0,
                    pos("123456789","")=>0 )
      pos(A,B,C) First position of char B in string A
                 The search starts at position C of string A
                  ( Type of argument B: char,
                    Type of argument C: integer,
                    Type of result: integer,
                    pos("ABCABC",'B', 3)=>5,
                    pos("XYZYX",'Z', 4)=>0,
                    pos("12345",'3', 7)=>0 )
      pos(A,B,C) First position of string B in string A
                 The search starts at position C of string A
                  ( Type of argument C: integer,
                    Type of result: integer,
                    pos("ABCDE ABCDE","BC", 3)=>8,
                    pos("XYZXYZ","ZXY", 4)=>0,
                    pos("12345","34", 7)=>0 )
                    pos("123456789","", 2)=>0 )
      rpos(A,B) Last position of char B in string A
                  ( Type of argument B: char,
                    Type of result: integer,
                    rpos("ABCABC",'B')=>5,
                    rpos("XYZ",'A')=>0 )
      rpos(A,B) Last position of string B in string A
                  ( Type of result: integer,
                    rpos("ABCDE ABCDE","BC")=>8,
                    rpos("XYZXYZ","ZYX")=>0,
                    rpos("123456789","")=>0 )
      rpos(A,B,C) Last position of char B in string A
                 The search starts at position C of string A
                  ( Type of argument B: char,
                    Type of argument C: integer,
                    Type of result: integer,
                    rpos("ABCABC",'B', 4)=>2,
                    rpos("XYZYX",'Z', 2)=>0,
                    rpos("12345",'3', 5)=>3 )
      replace(A,B,C) Replace all occurrences of string B in
                string A by string C
                  ( replace("old gold", "old", "one")=>
                    "one gone" )
      split(A,B) Split A into strings delimited by B
                  ( Type of argument B: char,
                    Type of result: array string,
                    split("", ':') => [](""),
                    split(":", ':') => []("", ""),
                    split("15:30", ':') => []("15", "30") )
      split(A,B) Split A into strings delimited by B
                  ( Type of result: array string,
                    split("", "") => [](""),
                    split("ABC", "") => []("ABC"),
                    split("", "; ") => [](""),
                    split("writeln; readln;", "; ") => []("writeln", "readln;") )
      join(A,B) Join the elements of A together with B's between them
                  ( Type of argument A: array string,
                    Type of argument B: char,
                    join([]("This", "is", "a", "test"), ' ') => "This is a test" )
      join(A,B) Join the elements of A together with B's between them
                  ( Type of argument A: array string,
                    Type of argument B: string,
                    join([]("pro", "gram"), "") => "program" )
      trim(A)   Removes leading and trailing spaces and control chars
                  ( trim(" /n xyz /r") = "xyz" )
      str(A)    Conversion to string
                  ( Type of result: string,
                    str(A) => A )
      literal(A) Conversion to a literal
                  ( Type of result: string,
                    literal("ABC") => "\"ABC\"",
                    literal("O' \"X\"") => "\"O\' \\\"X\\\"\"" )
      upper(A)  Conversion to upper case characters
                  ( upper("Upper")=>"UPPER" )
      lower(A)  Conversion to lower case characters
                  ( lower("Lower")=>"lower" )
      compare(A, B) Compare function
                  ( Type of result: integer,
                    compare("ABC", "ABCD") => -1,
                    compare("ABC", "ABC") => 0,
                    compare("ABCD", "ABCC") => 1 )
      hashCode(A) Hash function
                  ( Type of result: integer )
    Statements:
      A &:= B   Append B to A
                  ( A &:= B => A := A & B )
      A @:= [B] C  Assign C to element B of string A
                  ( Type of argument B: integer,
                    Type of argument C: char,
                    A @:= [B] C =>
                        A := A[..pred(B)] & str(C) & A[succ(B)..],
                    A @:= [0] 'x' => EXCEPTION RANGE_ERROR,
                    A @:= [succ(length(A))] 'x' => EXCEPTION RANGE_ERROR )


5.10 array

    The type 'array baseType' describes sequences of 'baseType'
  elements (including the empty sequence).

    For example: 'array integer' describes arrays of integer elements.

  An element of an array can be accessed with an 'integer' index.
  The minimal and maximal indices of an array are part of the value
  and can be obtained with the functions 'minIdx' and 'maxIdx'.
  There are functions which generate arrays with the default minimal
  index of 1 and other functions which generate arrays with the minimal
  index taken from a parameter. The 'array' functions are defined
  in the library "array.s7i". Arrays with non-integer index are defined
  in the library "idxarray.s7i".

    Literal:
      [] (elem1, elem2)  Create an array with the given elements
                    The starting index of the array is 1.
      [0] (elem1, elem2)  Create an array with the given elements
                    The starting index of the array is 0.
    Infix operators:
      &         Array concatenation
      times     Array generation
                  ( Left operand: integer,
                    Right operand: baseType,
                    A times B Generates an 'array baseType'
                    with A elements of B,
                    (1 times B)[1] => B
                    -1 times B => EXCEPTION RANGE_ERROR )
      [ A .. B ] times C    Array generation
                  ( Type of arguments A and B: integer )
                    Type of argument C: baseType,
                    [ A .. B ] times C Generates an 'array baseType'
                    with pred(B - A) elements of C,
                    [ -1 .. -2 ] times B => empty array,
                    [ -1 .. -3 ] times B => EXCEPTION RANGE_ERROR )
    Indices:
      [ A ]     Access one array element
                  ( Type of argument A: integer,
                    Type of result: baseType,
                    A[minIdx(A)] => First element,
                    A[maxIdx(A)] => Last element,
                    A[pred(minIdx(A))] => EXCEPTION RANGE_ERROR,
                    A[succ(maxIdx(A))] => EXCEPTION RANGE_ERROR )
      [ A .. B ] Access a sub array
                  ( Type of arguments A and B: integer )
      [ A .. ]  Access a sub array beginning at position A
                  ( Type of argument A: integer )
      [ .. A ]  Access a sub array ending at position A
                  ( Type of argument A: integer )
    Relations:
      =, <>
    Functions:
      length(A) Length of array
                  ( Type of result: integer,
                    length(A) = succ(maxIdx(A) - minIdx(A)),
                    length(0 times TRUE) => 0,
                    length(5 times TRUE) => 5 )
      minIdx(A) Minimal index of array
                  ( Type of result: integer,
                    minIdx(3 times TRUE) => 1,
                    minIdx([-1 .. 4] times TRUE) => -1 )
      maxIdx(A) Maximal index of array
                  ( Type of result: integer,
                    maxIdx(3 times TRUE) => 3 )
      rand(A)   Random element from an array
                The random elements are uniform distributed.
                  ( Type of result:  baseType )
      remove(A,B) Remove element with index B from array A and
                  return the removed element
                  ( Type of argument B: integer,
                    Type of result: baseType,
                    remove(0 times TRUE, 1) => EXCEPTION RANGE_ERROR )
      sort(A)   Sort array using the compare(baseType, baseType) function
    Statements:
      A &:= B   Append B to A
                  ( A &:= B => A := A & B )
      for A range B do
        C
      end for   Loop over all elements of an array
                  ( Type of argument A: baseType,
                    Type of argument C: proc )
      insert(A, B, C) Insert C to the array A at position B
                  ( Type of argument B: integer,
                    Type of argument C: baseType )
      insert(A, B) Insert B into the sorted array A
                  ( Type of argument C: baseType )


5.11 hash

    The type 'hash [keyType] baseType' describes hash tables with
  elements of 'baseType'. The elements can be accessed with an index
  of 'keyType'.

    For example: 'hash [string] integer' describes hash tables with
    'integer' elements and 'string' keys.

  The 'keyType' of a hash needs to provide the functions 'hashCode'
  and 'compare'. Besides this the 'keyType' can be any type. The
  'hash' functions are defined in the library "hash.s7i".

    Constants:
      hashType.EMPTY_HASH  Empty hash table
    Infix operators:
      in        Element
                  ( Left argument: baseType,
                    Type of result: boolean )
      not in    Is not Element
                  ( Left argument: baseType,
                    Type of result: boolean )
    Indices:
      [ A ]     Access one hash table element
                  ( Type of argument A: keyType,
                    Type of result: baseType )
    Functions:
      length(A) Number of elements in hash table A
                  ( Type of result: integer,
                    length(hashType.EMPTY_HASH) => 0 )
      keys(A)   Unsorted array of keys from hash table A
                  ( Type of result: array keyType )
      values(A) Unsorted array of values from hash table A
                  ( Type of result: array baseType )
      flip(A)   Deliver a hash with keys and values flipped
                  ( Type of result: hash [baseType] array keyType )
    Statements:
      incl(A,B,C) Include element B to hash table A
                  ( Type of argument B: keyType,
                    Type of argument C: baseType )
      excl(A,B) Exclude element B from hash table A
                  ( Type of argument B: keyType )
      A @:= [B] C  Assign C to element B of hash table A
                  ( Type of argument B: keyType,
                    Type of argument C: baseType )
      for A range B do
        C
      end for   Unsorted loop over all values of a hash
                  ( Type of argument A: baseType,
                    Type of argument C: proc )
      for key A range B do
        C
      end for   Unsorted loop over all keys of a hash
                  ( Type of argument A: keyType,
                    Type of argument C: proc )
      for A key B range C do
        D
      end for   Unsorted loop over all values and keys of a hash
                  ( Type of argument A: baseType,
                    Type of argument B: keyType,
                    Type of argument D: proc )


5.12 set

    The type 'set of baseType' describes a set of elements of a
  'baseType'. (including the empty set). The type 'set of integer'
  is an alternate name for 'bitset', which is defined in the library
  "bitset.s7i".

    Constants:
      setType.EMPTY_SET  Empty set
      EMPTY_SET  Empty set of the type bitset
    Infix operators:
      |         Union 
      &         Intersection
      -         Difference
      ><        Symmetric Difference
      in        Element
                  ( Left argument: baseType,
                    Type of result: boolean )
      not in    Is not Element
                  ( Left argument: baseType,
                    Type of result: boolean )
    Relations:
      =, <>     Equal and not equal
                  ( Type of result: boolean )
      <=        Subset
                  ( Type of result: boolean,
                    A <= B => TRUE when no element X exists for which
                       X in A and X not in B
                    holds.
                    A <= B => FALSE when an element X exists for which
                       X in A and X not in B
                    holds.
                    setType.EMPTY_SET <= A => TRUE,
                    A <= setType.EMPTY_SET => FALSE for A <> EMPTY_SET,
                    A <= B => B >= A )
      <         Proper subset
                  ( Type of result: boolean,
                    A < B => A <= B and not A = B,
                    setType.EMPTY_SET < A => TRUE for A <> EMPTY_SET,
                    A < setType.EMPTY_SET => FALSE,
                    A < B => B > A )
      >=        Superset
                  ( Type of result: boolean,
                    A >= B => TRUE when no element X exists for which
                       X in B and X not in A
                    holds.
                    A >= B => FALSE when an element X exists for which
                       X in B and X not in A
                    holds.
                    A >= setType.EMPTY_SET => TRUE,
                    setType.EMPTY_SET >= A => FALSE for A <> EMPTY_SET,
                    A >= B => B <= A )
      >         Proper superset
                  ( Type of result: boolean,
                    A > B => A >= B and not A = B,
                    A > setType.EMPTY_SET => TRUE for A <> EMPTY_SET,
                    setType.EMPTY_SET > A => FALSE,
                    A > B => B < A )
    Functions:
      card      Cardinality of a set
                  ( Type of result: integer,
                    card(setType.EMPTY_SET) => 0  )
      min       Minimal element
                  ( Type of result: baseType,
                    Delivers the element from the set for
                    which the following condition holds:
                       Element <= X
                    for all X which are in the set.
                    min(setType.EMPTY_SET) => EXCEPTION RANGE_ERROR )
      max       Maximum element
                  ( Type of result: baseType,
                    Delivers the element from the set for
                    which the following condition holds:
                       Element >= X
                    for all X which are in the set.
                    min(setType.EMPTY_SET) => EXCEPTION RANGE_ERROR )
      str(A)    Conversion to string
                  ( Type of result: string,
                    str(setType.EMPTY_SET) => "{}",
                    str({}) => "{}" )
                    str({1, 2}) => "{1, 2}" )
      rand      Random element from a set
                The random elements are uniform distributed.
                  ( Type of result: baseType,
                    rand(setType.EMPTY_SET) => EXCEPTION RANGE_ERROR )
      compare(A, B) Compare function
                  ( Type of result: integer )
      hashCode(A) Hash function
                  ( Type of result: integer )
    Statements:
      incl(A,B) Include element B to set A
                  ( Type of argument B: baseType )
      excl(A,B) Exclude element B from set A
                  ( Type of argument B: baseType )
      for A range B do
        C
      end for   Loop over all elements of a set
                  ( Type of argument A: baseType,
                    Type of argument C: proc )


5.13 struct

    The type 'struct' describes all structured types.

    Type generators:
      new struct
        var aType: name is value;
        ...
      end struct
                Create new structure type

      new metaType struct
        var aType: name is value;
        ...
      end struct
                Create new structure type as subtype of 'metaType',
                which is not a structure

      sub metaType struct
        var aType: name is value;
        ...
      end struct
                Create new structure type as subtype of 'metaType',
                which is a structure type. The new structure type inherits all
		elements of the structure type 'metaType'.

      var aType: name is value
                Declare structure element 'name' with 'value'

    Infixoperators:
      .         Access Element of STRUCT
                  ( example.element )
      ->        Access Element of ptr STRUCT
                  ( example->element )
    Relations:
      =, <>
    Functions:
      incl(A, B) Include element in MODULE
                  ( Type of argument B: reference )
      excl(A, B) Exclude element from MODULE
                  ( Type of argument B: reference )


5.14 category

    The type 'category' describes the category of a 'reference'.

    Constants:
      SYMBOLOBJECT, DECLAREDOBJECT, FORWARDOBJECT, FWDREFOBJECT, BLOCKOBJECT,
      CALLOBJECT,MATCHOBJECT, TYPEOBJECT, FORMPARAMOBJECT, INTOBJECT,
      BIGINTOBJECT, CHAROBJECT, STRIOBJECT, BSTRIOBJECT, ARRAYOBJECT,
      HASHOBJECT, STRUCTOBJECT, CLASSOBJECT, INTERFACEOBJECT, SETOBJECT,
      FILEOBJECT, SOCKETOBJECT, LISTOBJECT, FLOATOBJECT, WINOBJECT,
      ENUMLITERALOBJECT, CONSTENUMOBJECT, VARENUMOBJECT, REFOBJECT,
      REFLISTOBJECT, EXPROBJECT, ACTOBJECT, VALUEPARAMOBJECT, REFPARAMOBJECT,
      RESULTOBJECT, LOCALVOBJECT, PROGOBJECT
    Infix operators:
      category conv A   Conversion of integer to category
                  ( Type of argument A: integer,
                    category conv ord(INTOBJECT) => INTOBJECT )
      category parse A   Conversion of string to category
                  ( Type of argument A: string,
                    category parse "FLOATOBJECT" => FLOATOBJECT )
    Relations:
      =, <>
    Functions:
      ord(A)    Ordinal number
                  ( Type of result: integer )
      str(A)    Conversion to string
                  ( Type of result: string,
                    str(CHAROBJECT) => "CHAROBJECT" )


5.15 reference

    The type 'reference' describes a reference to any
  object.

    Constants:
      NIL       Reference to no element.
    Relations:
      =, <>
    Functions:
      category(A) Get the category of the referenced object
                  ( Type of result: category,
                    category(NIL) => EXCEPTION RANGE_ERROR )
      str(A)    Conversion to string
                  ( Type of result: string )
      getType(A) Get the type of the referenced object
                  ( Type of result: type,
                    getType(NIL) => EXCEPTION RANGE_ERROR )
      obj_number(A) Delivers an unique number for each object
                  ( Type of result: integer,
                    obj_number(NIL) => 0 )
      isVar(A)  Reference to a variable object
                  ( Type of result: boolean,
                    isVar(NIL) => EXCEPTION RANGE_ERROR )
      params(A) Gets the formal parameters of a function
                  ( Type of result: ref_list )
      local_vars(A) Gets the local variables of a function
                  ( Type of result: ref_list,
                    local_vars(NIL) => EXCEPTION RANGE_ERROR,
                    local_vars(A) => EXCEPTION RANGE_ERROR for category(A) <> BLOCKOBJECT )
      local_consts(A) Gets the local constants of a function
                  ( Type of result: ref_list,
                    local_consts(NIL) => EXCEPTION RANGE_ERROR,
                    local_consts(A) => EXCEPTION RANGE_ERROR for category(A) <> BLOCKOBJECT )
      body(A)   Gets the body of a function
                  ( body(NIL) => EXCEPTION RANGE_ERROR,
                    body(A) => EXCEPTION RANGE_ERROR for category(A) <> BLOCKOBJECT )
      func_result(A) Gets the result object of a function
      func_res_init(A) Gets the initialization value of the result
                       object of a function
      array_to_list(A) Return the array elements as list
                  ( Type of result: ref_list,
                    array_to_list(NIL) => EXCEPTION RANGE_ERROR,
                    array_to_list(A) => EXCEPTION RANGE_ERROR for category(A) <> ARRAYOBJECT )
      array_min_index(A) Return the minimal index of an array
                  ( Type of result: integer,
                    array_min_index(NIL) => EXCEPTION RANGE_ERROR,
                    array_min_index(A) => EXCEPTION RANGE_ERROR for category(A) <> ARRAYOBJECT )
      array_max_index(A) Return the maximal index of an array
                  ( Type of result: integer,
                    array_max_index(NIL) => EXCEPTION RANGE_ERROR,
                    array_max_index(A) => EXCEPTION RANGE_ERROR for category(A) <> ARRAYOBJECT )
      struct_to_list(A) Return the struct elements as list
                  ( Type of result: ref_list,
                    struct_to_list(NIL) => EXCEPTION RANGE_ERROR,
                    struct_to_list(A) => EXCEPTION RANGE_ERROR for category(A) <> STRUCTOBJECT )
      interface_to_struct(A) Return the struct to which the interface object points.
                  ( interface_to_struct(NIL) => EXCEPTION RANGE_ERROR,
                    interface_to_struct(A) => EXCEPTION RANGE_ERROR for category(A) <> INTERFACEOBJECT )
      file(A)   File name of the referenced object
                  ( Type of result: string )
      line(A)   Line number of the referenced object
                  ( Type of result: integer )
      alloc(A)  Create a copy of the object referenced by A
                The object value of the copy is set to NULL
      getValue(A, reference) Dereference as reference
                  ( Type of result: reference,
                    getValue(NIL, reference) => EXCEPTION RANGE_ERROR,
                    getValue(A, reference) => EXCEPTION RANGE_ERROR for
                        category(A) not in {FWDREFOBJECT, REFOBJECT, REFPARAMOBJECT, RESULTOBJECT,
                        LOCALVOBJECT, ENUMLITERALOBJECT, CONSTENUMOBJECT, VARENUMOBJECT} )
      getValue(A, ref_list) Dereference as ref_list
                  ( Type of result: ref_list,
                    getValue(NIL, ref_list) => EXCEPTION RANGE_ERROR,
                    getValue(A, ref_list) => EXCEPTION RANGE_ERROR for
                        category(A) not in {MATCHOBJECT, CALLOBJECT, REFLISTOBJECT} )
      getValue(A, integer) Dereference as integer
                  ( Type of result: integer,
                    getValue(NIL, integer) => EXCEPTION RANGE_ERROR,
                    getValue(A, integer) => EXCEPTION RANGE_ERROR for category(A) <> INTOBJECT )
      getValue(A, bigInteger) Dereference as bigInteger
                  ( Type of result: bigInteger,
                    getValue(NIL, bigInteger) => EXCEPTION RANGE_ERROR,
                    getValue(A, bigInteger) => EXCEPTION RANGE_ERROR for category(A) <> BIGINTOBJECT )
      getValue(A, float) Dereference as float
                  ( Type of result: float,
                    getValue(NIL, float) => EXCEPTION RANGE_ERROR,
                    getValue(A, float) => EXCEPTION RANGE_ERROR for category(A) <> FLOATOBJECT )
      getValue(A, char) Dereference as char
                  ( Type of result: char,
                    getValue(NIL, char) => EXCEPTION RANGE_ERROR,
                    getValue(A, char) => EXCEPTION RANGE_ERROR for category(A) <> CHAROBJECT )
      getValue(A, string) Dereference as string
                  ( Type of result: string,
                    getValue(NIL, string) => EXCEPTION RANGE_ERROR,
                    getValue(A, string) => EXCEPTION RANGE_ERROR for category(A) <> STRIOBJECT )
      getValue(A, bitset) Dereference as bitset
                  ( Type of result: bitset,
                    getValue(NIL, bitset) => EXCEPTION RANGE_ERROR,
                    getValue(A, bitset) => EXCEPTION RANGE_ERROR for category(A) <> SETOBJECT )
      getValue(A, PRIMITIVE_FILE) Dereference as PRIMITIVE_FILE
                  ( Type of result: PRIMITIVE_FILE,
                    getValue(NIL, PRIMITIVE_FILE) => EXCEPTION RANGE_ERROR,
                    getValue(A, PRIMITIVE_FILE) => EXCEPTION RANGE_ERROR for category(A) <> FILEOBJECT )
      getValue(A, program) Dereference as program
                  ( Type of result: program,
                    getValue(NIL, program) => EXCEPTION RANGE_ERROR,
                    getValue(A, program) => EXCEPTION RANGE_ERROR for category(A) <> PROGOBJECT )
      getValue(A, ACTION) Dereference as ACTION
                  ( Type of result: ACTION,
                    getValue(NIL, ACTION) => EXCEPTION RANGE_ERROR,
                    getValue(A, ACTION) => EXCEPTION RANGE_ERROR for category(A) <> ACTOBJECT )
      getValue(A, type) Dereference as type
                  ( Type of result: type,
                    getValue(NIL, type) => EXCEPTION RANGE_ERROR,
                    getValue(A, type) => EXCEPTION RANGE_ERROR for category(A) <> TYPEOBJECT )
      compare(A, B) Compare function
                  ( Type of result: integer )
      hashCode(A) Hash function
                  ( Type of result: integer )
    Statements:
      setVar(A, B) Set var flag of referenced object A to B
                  ( Type of argument B: boolean,
                    setVar(NIL, B) => EXCEPTION RANGE_ERROR )
      setCategory(A, B) Set the category of the referenced object A to B
                  ( Type of argument B: category,
                    setCategory(NIL, B) => EXCEPTION RANGE_ERROR )
      setType(A, B) Set the type of the referenced object A to B
                  ( Type of argument B: type,
                    setType(NIL, B) => EXCEPTION RANGE_ERROR )
      setValue(A, B) Set the value of the referenced object A to B
                  ( Type of argument B: ref_list )
      setParams(A, B) Set the formal parameters of a function
                  ( Type of argument B: ref_list )


5.16 ref_list

    The type 'ref_list' describes a list of 'reference' objects.

    Constants:
      ref_list.EMPTY  Empty reference list.
    Infix operators:
      &         Ref_list list concatenation
      A in B    Is element in ref_list
                  ( Type of argument A: reference,
                    Type of result: boolean )
      A not in B  Is element not in ref_list
                  ( Type of argument A: reference,
                    Type of result: boolean )
    Indices:
      [ A ]     Access one ref_list element
                  ( Type of argument A: integer,
                    Type of result: reference,
                    A[1]=>First element,
                    A[length(A)]=>Last element,
                    A[0] => EXCEPTION RANGE_ERROR,
                    A[succ(length(A))] => EXCEPTION RANGE_ERROR )
      [ A .. B ]  Access a sub list
                  ( Type of arguments A and B: integer )
      [ A .. ]  Access a sub list beginning at position A
                  ( Type of argument A: integer )
      [ .. A ]  Access a sub list ending at position A
                  ( Type of argument A: integer )
    Relations:
      =, <>
    Functions:
      length(A) Length of ref_list
                  ( Type of result: integer,
                    length(ref_list.EMPTY) => 0 )
      make_list(A) Create ref_list with element A
                  ( Type of argument A: reference )
      pos(A,B)  First position of reference B in ref_list A
                  ( Type of argument B: reference,
                    Type of result: integer )
      pos(A,B,C) First position of reference B in ref_list A
                 The search starts at position C of ref_list A
                  ( Type of argument B: reference,
                    Type of argument C: integer,
                    Type of result: integer )
      incl(A, B) Include element in list
                  ( Type of argument B: reference )
      excl(A, B) Exclude element from list
                  ( Type of argument B: reference )
    Statements:
      A &:= B   Append B to A
                  ( A &:= B => A := A & B )
      A @:= [B] C  Assign C to element B of ref_list A
                  ( Type of argument B: integer,
                    Type of argument C: reference,
                    A @:= [B] C =>
                        A := A[..pred(B)] & make_list(C) & A[succ(B)..],
                    A @:= [0] C => EXCEPTION RANGE_ERROR,
                    A @:= [succ(length(A))] C => EXCEPTION RANGE_ERROR )
      for A range B do
        C
      end for   Loop over all elements of a ref_list
                  ( Type of argument A: reference,
                    Type of argument C: proc )


5.17 program

    The type 'program' describes a Seed7 program.

    Constants:
      program.EMPTY  Empty program.
    Relations:
      =, <>
    Functions:
      parseFile(A)  Parse the file with the name A
                  ( Type of argument A: string )
      parseStri(A)  Parse the string A
                  ( Type of argument A: string )
      evaluate(A, B)  Evaluate the expression B which is part of program A
                  ( Type of result: reference,
                    Type of argument B: reference )
      sys_var(A, B)  Return a reference of the system var B of program A
                  ( Type of result: reference,
                    Type of argument B: string )
      error_count(A)  Number of errors in the program A
                  ( Type of result: integer )
      declared_objects(A)  List of objects declared in the program A
                  ( Type of result: ref_list )
      syobject(A, B)  Return object with name B in program A
                  ( Type of result: reference,
                    Type of argument B: string )
      match(A, B)  Return object from program A which matches B
                  ( Type of result: reference,
                    Type of argument B: ref_list )
    Statements:
      execute(A) Execute the program referred by A


5.18 ptr

    The type 'ptr baseType' describes a pointer to an object
  of a 'baseType'. With

    const type: ptrType is ptr baseType;

  a new pointer type 'ptrType' is declared.

    Constants:
      ptrType.NIL   Reference to no element
    Prefix operators:
      &         Address of
                  ( Type of operand: baseType )
    Postfix operators:
      ^         Dereference
                  ( Type of result: baseType )
    Infix operators:
      ptrType conv A  Conversion from reference A to ptrType
      reference conv A  Conversion from ptrType A to reference
    Relations:
      =, <>
    Functions:
      base_type(ptrType)  Gets the baseType of a ptrType
                  ( Type of argument ptrType: type )


5.19 ENUMERATION

    With

    const type: enumType is new enum
        enum_literal1, enum_literal2
      end enum;

  a new enumeration type is declared. The values of this type are:

    enum_literal1 and enum_literal2

  For a enumeration type only few operations are predefined.
  Additional operations must be defined separately. So it is
  necessary to define the 'str' and 'parse' functions in order to
  do I/O for a new enumeration type.

    Infix operators:
      enumType conv A  Conversion from integer A to enumType
                  ( Type of argument A: integer,
                    enumType conv 0 => enum_literal1 )
      integer conv A   Conversion from enumType A to integer
                  ( Type of result: integer,
                    integer conv enum_literal1 => 0 )
    Relations:
      =, <>, <, <=, >, >=
    Functions:
      ord(A)    Ordinal number
                  ( Type of result: integer )
      succ(A)   Successor
                  ( succ(A)=>enumType conv(succ(ord(A))) )
      pred(A)   Predecessor
                  ( pred(A)=>enumType conv(pred(ord(A))) )
    Statements:
      incr(A)   Increment
                  ( incr(A) => A:=succ(A) )
      decr(A)   Decrement
                  ( decr(A) => A:=pred(A) )


5.20 color

    The type 'color' describes colors. The 'color'
  functions are defined in the library "color.s7i".

    Elements:
      var integer: red_part is 0;
      var integer: green_part is 0;
      var integer: blue_part is 0;
    Constants:
      black         is color(0, 0, 0);
      dark_red      is color(32768, 0, 0);
      dark_green    is color(0, 32768, 0);
      brown         is color(32768, 16384, 0);
      dark_blue     is color(0, 0, 32768);
      dark_magenta  is color(32768, 0, 32768);
      dark_cyan     is color(0, 65535, 65535);
      light_gray    is color(49152, 49152, 49152);
      dark_gray     is color(16384, 16384, 16384);
      light_red     is color(65535, 0, 0);
      light_green   is color(0, 65535, 0);
      yellow        is color(65535, 65535, 0);
      light_blue    is color(0, 0, 65535);
      light_magenta is color(65535, 0, 65535);
      light_cyan    is color(32768, 65535, 65535);
      white         is color(65535, 65535, 65535);
      orange        is color(65535, 32768, 0);
      amber         is color(49152, 32768, 16384);
      pink          is color(65535, 32768, 32768);
    Infix operators:
      +         Add two colors in an additive color system
    Relations:
      =, <>
    Functions:
      color(R,G,B) Creates a color from Red, Green and Blue 
                  ( Type of argument R: integer,
                    Type of argument G: integer,
                    Type of argument B: integer )


5.21 time

    The type 'time' describes times and dates.
  For dates the proleptic Gregorian calendar is used (which assumes
  that the Gregorian calendar was even in effect at dates preceding
  its official introduction). This convention is used according to
  ISO 8601 which also defines that positive and negative years exist
  and that the year preceding 1 is 0. Time is measured in hours,
  minutes, seconds and micro seconds. Additionally information about
  the difference to UTC and a flag indicating daylight saving time
  is maintained also. The 'time' functions are defined in the
  library "time.s7i".

    Elements:
      var integer: year is 0;
      var integer: month is 1;
      var integer: day is 1;
      var integer: hour is 0;
      var integer: minute is 0;
      var integer: second is 0;
      var integer: micro_second is 0;
    Infix operators:
      +         Add a duration to a time
                  ( Type of right operand: duration )
      -         Subtract a duration from a time
                  ( Type of right operand: duration )
      -         Subtract two times
                  ( Type of result: duration )
      time parse A   Conversion of string to time
                  ( Type of argument A: string,
                    time parse "2005-02-28 12:00:01" => 2005-02-28 12:00:01,
                    time parse "2005-02-29 12:00:01" => EXCEPTION RANGE_ERROR )
    Relations:
      =, <>, <, <=, >, >=
    Functions:
      time(NOW)  Gets the current time
      str(A)    Conversion to string
                  ( Type of result: string )
      strDate(A)  Conversion of the date to string
                  ( Type of result: string )
      strTime(A)  Conversion of the daytime to string
                  ( Type of result: string )
      strTimeZone(A)  Conversion of the time zone to string
                  ( Type of result: string )
      truncToSecond(A)  Truncate a time to a second
      truncToMinute(A)  Truncate a time to a minute
      truncToHour(A)  Truncate a time to a hour
      truncToDay(A)  Truncate a time to a day
      truncToMonth(A)  Truncate a time to a month
      truncToYear(A)  Truncate a time to a year
      isLeapYear(A)  Determine if a given year is a leap year
                  ( Type of argument A: integer )
                  ( Type of result: boolean )
      daysInYear(Y)  Calculate the number of days in a year
                  ( Type of argument Y: integer,
                    Type of result: integer )
      daysInMonth(Y, M)  Calculate the number of days in a month
                  ( Type of argument Y: integer,
                    Type of argument M: integer,
                    Type of result: integer )
      dayOfWeek(A)  Day of the week with Monday as 1
                  ( Type of result: integer )
      dayOfYear(A)  Day of the year with 1 January as 1
                  ( Type of result: integer )
      weekOfYear(A)  Compute the week number of a year (0 to 53).
                    According to ISO 8601: Week number 1 of
                    every year contains the 4. of january.
                  ( Type of result: integer )
      weekDateYear(A)  Compute the year of the ISO 8601 week date
                  ( Type of result: integer )
      weekDateWeek(A)  Compute the week of the ISO 8601 week date
                  ( Type of result: integer )
      toUTC(A)  Conversion to Coordinated Universal Time (UTC)
      julianDayNumber(A)  Number of days that have elapsed since
                January 1, 4713 BC in the proleptic Julian calendar
                  ( Type of result: integer )
      julianDayNumToTime(A)  Convert julian day number to time
                  ( Type of argument A: integer )
      timestamp1970(A)  Time expressed in seconds since the
                Unix Epoch (1970-01-01 00:00:00 UTC)
                  ( Type of result: integer )
      timestamp1970ToTime(A)  Convert a timestamp into a time from
                the local time zone
                  ( Type of argument A: integer )
      compare(A, B)  Compare function
                  ( Type of result: integer )
      hashCode(A)  Hash function
                  ( Type of result: integer )
    Statements:
      A +:= B   Increment A by B
                  ( Type of argument B: duration,
                    A +:= B => A := A + B )
      A -:= B   Decrement A by B
                  ( Type of argument B: duration,
                    A -:= B => A := A - B )
      await(A)  Wait until the given time

  For the operations '+' (add a duration to a time) and
  '-' (subtract two time values) holds:
    tim2 + (tim1 - tim2) = tim1

  For the operations '-' (subtract a duration from a time) and
  '-' (subtract two time values) holds:
    tim1 - (tim1 - tim2) = tim2


5.22 duration

    The type 'duration' describes time and date durations.
  The 'duration' functions are defined in the library
  "duration.s7i".

    Prefix operators:
      +         Identity
      -         Change sign
    Infix operators:
      +         Add two durations
      -         Subtract two durations
      *         Multiply a duration by an integer
                  ( Type of left operand: integer )
      *         Multiply a duration by an integer
                  ( Type of right operand: integer )
      duration parse A   Conversion of string to duration
                  ( Type of argument A: string,
                    duration parse "0-02-28 12:00:01" => 0-02-28 12:00:01,
                    duration parse "0-13-29 12:00:01" => EXCEPTION RANGE_ERROR )
    Relations:
      =, <>, <, <=, >, >=
    Functions:
      getYears(A)  Obtains the years of a duration
                  ( Type of result: integer )
      getMonths(A) Obtains the months of a duration
                  ( Type of result: integer )
      getDays(A)   Obtains the days of a duration
                  ( Type of result: integer )
      getHours(A)  Obtains the hours of a duration
                  ( Type of result: integer )
      getMinutes(A) Obtains the minutes of a duration
                  ( Type of result: integer )
      getSeconds(A) Obtains the seconds of a duration
                  ( Type of result: integer )
      getMicroSeconds(A)  Obtains the micro seconds of a duration
                  ( Type of result: integer )
      toYears(A)  Return the duration in years
                  ( Type of result: integer )
      toMonths(A) Return the duration in months
                  ( Type of result: integer )
      toDays(A)   Return the duration in days
                  ( Type of result: integer )
      toHours(A)  Return the duration in hours
                  ( Type of result: integer )
      toMinutes(A) Return the duration in minutes
                  ( Type of result: integer )
      toSeconds(A) Return the duration in seconds
                  ( Type of result: integer )
      toMicroSeconds(A)  Return the duration in micro seconds
                  ( Type of result: integer )
      str(A)    Conversion to string
                  ( Type of result: string )
      compare(A, B) Compare function
                  ( Type of result: integer )
      hashCode(A) Hash function
                  ( Type of result: integer )
    Statements:
      wait(A)   Wait for given duration

  For the operations '-' (negate a duration) and
  '-' (subtract two time values) holds:
    (tim1 - tim2) = - (tim2 - tim1)


5.23 file

    The type 'file' is the interface type for sequential files.
  The 'file' functions are defined in the library "file.s7i".

    Constants:
      STD_NULL  Standard null file
      STD_IN    Standard input of the operating system
      STD_OUT   Standard output of the operating system
      STD_ERR   Standard error output of the operating system
    Variables:
      IN        Standard input file used for file input
                  operations when no file is specified
                  ( IN is initialized with STD_IN )
      OUT       Standard output file used for file output
                  operations when no file is specified
                  ( OUT is initialized with STD_OUT )
    Relations:
      =, <>
    Functions:
      open(A, B) Open external file
                  ( Type of argument A: string,
                    Type of argument B: string,
                    Type of result: file,
                    Returns STD_NULL if open was not
                    possible )
      open_utf8(A, B) Open external UTF-8 file
                  ( Type of argument A: string,
                    Type of argument B: string,
                    Type of result: file,
                    Returns STD_NULL if open was not
                    possible )
      popen(A, B) Open a pipe to a process
                  ( Type of argument A: string,
                    Type of argument B: string,
                    Type of result: file,
                    Returns STD_NULL if popen was not
                    possible )
      openInetSocket(port) Open local Internet client socket
                  ( Type of argument port: integer,
                    Type of result: file,
                    Returns STD_NULL if open was not
                    possible )
      openInetSocket(addr, port) Open Internet client socket
                  ( Type of argument addr: string,
                    Type of argument port: integer,
                    Type of result: file,
                    Returns STD_NULL if open was not
                    possible )
      length(A) Length of file A
                  ( Type of result: integer )
      tell(A)   Return the actual file position
                  ( Type of argument: file,
                    The first position in the file is 1 )
      getc(A)   Get one character from file A
                  ( Type of result: char )
      gets(A, B) Get string with maximum length B from file A
                  ( Type of argument A: integer,
                    Type of argument B: file,
                    Type of result: string,
                    gets(A, -1) => EXCEPTION RANGE_ERROR )
      getwd(A)  Get one word from file A
                  ( Type of result: string )
      getln(A)  Get one line from file A
                  ( Type of result: string )
      eoln(A)   End of line
                  ( Type of result: boolean )
      hasNext(A) A call of getc does not return the EOF character
                  ( Type of result: boolean )
      eof(A)    End of file
                  ( Type of result: boolean )
    Statements:
      write(A, B) Write string B to file A
                  ( Type of argument B: string )
      writeln(A) Write a new line to file A
      writeln(A, B) Write string B and new line to file A
                  ( Type of argument B: string )
      read(A, B) Read a word from file A into string B
                  ( Type of right operand: string )
      readln(A)  Read a line from file A
      readln(A, B) Read a line from file A into the string B
                  ( Type of right operand: string )
      backSpace(A) Write backspace to file A
      close(A)  Close file A
      flush(A)  Flush file A
      seek(A, B) Set actual file position of file A to B
                  ( Type of argument B: integer,
                    seek(A, 1) => Set to file begin,
                    seek(A, length(A)) => Set to last position,
                    seek(A, length(A) + 1) => Set to end of file,
                    seek(A, 0) => EXCEPTION RANGE_ERROR )


5.24 text

    The type 'text' describes two dimensional files.
  The 'text' functions are defined in the library "text.s7i".

    Relations:
      =, <>
    Functions:
      open_window(F, A, B, C, D) Open a text
                  ( Type of argument A: integer,
                    Type of argument B: integer,
                    Type of argument C: integer,
                    Type of argument D: integer )
      height(A) Height of the text
                  ( Type of result: integer )
      width(A)  Width of the text
                  ( Type of result: integer )
      line(A)   Current line of the text
                  ( Type of result: integer )
      column(A) Current column of the text
                  ( Type of result: integer )
    Statements:
      write(A, B) Write string B to text A
                  ( Type of argument B: string )
      writeln(A) Write a new line to text A
      writeln(A, B) Write string B and new line to text A
                  ( Type of argument B: string )
      read(A, B) Read a word from text A into string B
                  ( Type of right operand: string )
      readln(A)  Read a line from text A
      readln(A, B) Read a line from text A into the string B
                  ( Type of right operand: string )
      backSpace(A) Write backspace to text A
      close(A)  Close text A
      flush(A)  Flush text A
      clear(A)  Clear the window
      v_scroll(A) Scroll the window vertical
      h_scroll(A) Scroll the window horizontal
      color(A, B) Set foreground color of the text A
                  ( Type of argument B: color )
      color(A, B, C) Set foreground and background color of the text A
                  ( Type of argument B: color,
                    Type of argument C: color )
      setPos(A, B, C) Set the current position of the text A
                  ( Type of argument B: integer
                    Type of argument C: integer )
      setLine(A, B) Set the current line of the text A
                  ( Type of argument B: integer )
      setColumn(A, B) Set the current column of the text A
                  ( Type of argument B: integer )
      box(A)    Write a box around the window
      clear_box(A) Clear the box around the window
      cursor_on(A) Make the cursor visible
      cursor_off(A) Make the cursor invisible


5.25 func

    The type 'func baseType' describes functions which return
  a 'baseType'. For example: 'func integer' describes an 'integer'
  function.

    Values:
      ord, str, abs, sqrt, rand, A + B, A * B, A ** B,
      trunc, round, sin, cos, compare, hashCode, pos,
      replace, trim, length, keys, color, dayOfWeek,
      ...
                Every function declared with const func ... is a value

    Prefix operators:
      func
      result
        var baseType: result is baseType.value;
      begin
        statements
      end func
                Create a baseType function
                  ( Type of 'statements': proc,
                    Type of result: func baseType )

      func
      result
        var baseType: result is baseType.value;
      local
        declarations
      begin
        statements
      end func
                Create a baseType function with local variables
                  ( Type of 'declarations': proc,
                    Type of 'statements': proc,
                    Type of result: func baseType )

      return value
                Create a function with the result type of value
                  ( Type of value: anyType - which means: any type,
                    Type of result: func anyType )

  Functions are declared as constants with a 'func' type and
  are initialized with a 'func result ...' or 'return ...' operator.
  For example:

    const func integer: tak (in integer: x, in integer: y, in integer: z) is func
      result
        var integer: result is 0;
      begin
        if y >= x then
          result := z;
        else
          result := tak(tak(pred(x), y, z),
                        tak(pred(y), z, x),
                        tak(pred(z), x, y));
        end if;
      end func

  Another example using the 'return' function:

    const func float: convertRadianToDegree (in float: x) is
      return x * 57.295779513082320876798154814114;

  This 'return' function should not be confused with a 'return'
  statement. It is important to note that no 'return' statement
  exists. The declaration for the 'return' function is as follows:

    const func func aType: return (ref func aType param)  is action "PRC_RETURN";
    const func func aType: return (ref aType param)       is action "PRC_RETURN";

  The 'func' types can also be used for parameters.
  Functions which use a 'func' parameter do not evaluate this
  parameter before the function call. Instead this parameter can
  be evaluated zero or more times inside the function. For example:

    const func boolean: (in boolean: first) and (in func boolean: second) is func
      result
        var boolean: result is FALSE;
      begin
        if first then
          result := second;
        end if;
      end func;

  Here the second parameter is only evaluated when the first
  parameter is 'TRUE'.


5.26 varfunc

    The type 'varfunc baseType' describes functions which return
  a 'baseType' variable. For example: A function which returns an
  'integer' variable is described with 'varfunc integer'. A call 
  of a 'varfunc' can be used at the left side of an assignment.
  Generally a 'varfunc' can be used at places where an 'inout'
  parameter requests a variable.

    Prefix operators:
      return var value;
                Create a varfunc which returns the variable 'value'
                  ( Type of value: anyType - which means: any type,
                    Accessright of value: var = A variable, an 'inout' parameter or a 'varfunc'
                    Type of result: varfunc anyType )

    Varfunctions are used to express 'array', 'hash' and 'struct'
  accesses which can be used at the left and right side of an
  assignment. The access function for a 'hash' is defined as:

    const func baseType: (in hashType: aHash) [ (in keyType: aKey) ] is
      return INDEX(aHash, aKey, hashCode(aKey), hashType.keyCompare);

    const varfunc baseType: (inout hashType: aHash) [ (in keyType: aKey) ] is
      return var INDEX(aHash, aKey, hashCode(aKey), hashType.keyCompare);

  The example above shows that functions with 'in' and 'inout'
  parameters can be overloaded. At the right side of an assignment
  the 'func' is called, while at the left side the 'varfunc'
  is called. That way the access functions of arrays, hashs
  and structs can be used in the usual way. 


5.27 void

    The type 'void' describes the empty type.

    Value:
      empty     This is the only value of the type 'void'.


5.28 proc

    The type 'proc' describes procedures. The type 'proc'
  is defined as 'func void'.

    Values:
      noop;
      while ... do ... end while;
      repeat ... until ... ;
      writeln( ... );
      A := B;
      incr(A);
      ...
                Every procedure declared with const proc: ... is a value
                The procedure 'noop' does nothing and is used as empty procedure.

    Prefix operators:
      func
      begin
        statements
      end func
                Create a procedure
                  ( Type of 'statements': proc,
                    Type of result: proc )

      func
      local
        declarations
      begin
        statements
      end func
                Create a procedure with local variables
                  ( Type of 'declarations': proc,
                    Type of 'statements': proc,
                    Type of result: proc )


5.29 type

    The type 'type' describes all types.

    Values:
      void, boolean, integer, rational, float, char,
      string, reference, ref_list, color, time, duration
      file, proc, type, ...
                Every type declared with const type: ... is a value
                The type 'void' is used as empty type.
    Prefix operators:
      func      Function type
                  ( func char => Function which returns a char )
      varfunc   Varfunc type
                  ( varfunc char => Function which returns a char variable )
      ptr       Pointer type
                  ( ptr bitset => Pointer to bitset )
      array     Array type
                  ( array string => Array of strings )
      set of    Set type
                  ( set of integer => Set of integer )
      subtype   Create subtype of existing type
                  ( subtype char => Subtype of char )
    Relations:
      =, <>
    Functions:
      str(A)    Conversion to string
                  ( Type of result: string )
      newtype   Create a new type
      gentype   Generate a type
      gensub(A) Generate a subtype
      typeof(A) Get the type of an expression
                  ( Type of argument A: Defined for all types,
                    typeof(1) => integer,
                    typeof("asdf") => string )
      is_func(A)  Is this type a 'func' type
                  ( Type of result: boolean,
                    is_func(func char) => TRUE,
                    is_func(varfunc char) => FALSE )
                    is_func(char) => FALSE )
      is_varfunc(A)  Is this type a 'varfunc' type
                  ( Type of result: boolean,
                    is_varfunc(func char) => FALSE,
                    is_varfunc(varfunc char) => TRUE,
                    is_varfunc(char) => FALSE )
      result_type(A)  Get the result type of a 'func' or 'varfunc' type
                  ( result_type(func char) => char,
                    result_type(char) => EXCEPTION RANGE_ERROR )
      is_derived(A)  Is this type derived from another type
                  ( Type of result: boolean,
                    is_derived(subtype char) => TRUE )
      meta(A)       Get the type from which type A is derived
                  ( meta(subtype char) => char )
      base_type(A)  Get the base type of an array, pointer or
                    set type
                  ( base_type(array char) => char,
                    base_type(ptr string) => string,
                    base_type(set of integer) => integer )                    
      type_number(A)  Get an unique number for a type
                  ( Type of result: integer )
      match_obj(A)  Get the match object of a type
                  ( Type of result: reference )
      compare(A, B) Compare function
                  ( Type of result: integer )
      hashCode(A) Hash function
                  ( Type of result: integer )
    Statements:
      addInterface(A, B)  Adds the interface type B to the implementation type A
      const aType: name is value
                Declare constant 'name' with 'value'
      var aType: name is value
                Declare variable 'name' with 'value'


5.30 object

    The type 'object' is used as meta type for various types.
  This allows defining common operations for all this types.
  The type 'object' is not used as element type for container
  classes since this can be done much better and type save
  with abstract data types like 'array', 'set', 'hash' and
  others.

    Functions:
      TRACE_OBJ(A)  Write internal information


5.31 expr

    The type 'expr' is used to describe unmatched expressions.
  These are expressions where the recognizing of the functions
  and the type check is not done yet. This is used for example
  in the definition of function bodies.

    Functions:
      WRITE_EXPR(A)
                Write expr A to FILE OUT



6. PARAMETERS
=============

    The following subchapters introduce the parameter types of
  Seed7.


6.1 'val' parameter

  Value parameters are marked with the keyword 'val'.
  A value parameter copies the value of the actual parameter.
  Value parameters are used, when copying is cheap or
  when copying  is necessary for the correct behavior.
  The function below appends a comma and a string to the
  variable 'globalStri':

    const proc: appendStri (val string: stri) is func
      begin
        globalStri &:= ",";
        globalStri &:= stri;
      end func;

  After doing

    globalStri &:= "a";
    appendStri(globalStri);

  the globalStri variable contains the value "a,a". If the function
  header would be

    const proc: appendStri (in string: stri) is func

  the globalStri variable would contain the value "a,a,". This
  difference is because of the following reasons:

  For arrays 'in' parameters are equal to 'ref' parameters.
  When appendStri called with globalStri as parameter an unwanted
  side effect takes place: Every change of globalStri changes also
  the 'ref' parameter stri. Changes to the 'ref' parameter would
  also change the global variable. Such unwanted side effects can
  also take place between parameters (when at least one parameter
  is an 'inout' parameter).

  In most cases such unwanted side effects are impossible or can
  be avoided easily. When possible 'in' parameters should be
  preferred over 'val' parameters.

  Semantics:
    When calling a function a formal 'val' parameter gets its
    value from the corresponding actual parameter. This is done
    with a create procedure ( ::= ). In the function it is only
    possible to read a formal 'val' parameter. Changing a formal
    'val' parameter is not possible. When a function is left a
    'destr' procedure is called for every 'val' parameter. Formal
    'val' parameters have the access right 'const'.


  Syntax:

    val_parameter ::=
      'val' type_expression ':' identifier_declaration |
      'val' type_expression 'param' .


  Declaration:

    $ syntax expr: .val.().param is                   -> 40;
    $ syntax expr: .val.(). : .(expr) is              -> 40;

    const func f_param: val (ref type param) param is               action "DCL_VAL1";
    const func f_param: val (ref type param) : (ref expr param) is  action "DCL_VAL2";


6.2 'ref' parameter

  Reference parameters are marked with the keyword 'ref'.
  A reference parameter refers to the value of the actual parameter.
  Reference parameters are used, when copying is expensive and
  referring to the value does not change the correct bahavior.
  The function below defines the primitive action for the
  semicolon operator:

    const proc: (ref void param) ; (ref void param) is noop;

  In this definition and other definitions of primitive actions
  'ref' parameters are used. For normal functions usually 
  'in' parameters are used instead of 'ref' parameters:

    const func integer: total_length (in array string: arr) is func
      result
        var integer: result is 0;
      local
        var integer: index is 0;
      begin
        for index range 1 to length(arr) do
          result +:= length(arr[index]);
        end for;
      end func;

  Above function could also be defined with the following
  function head:

    const func integer: total_length (ref array string: arr) is func

  Since for array types (and also for struct types) 'in'
  parameters are defined to act as 'ref' parameters both
  definitions are equal. When possible 'in' parameters should
  be preferred over 'ref' parameters.

  Semantics:
    When calling a function a formal 'ref' parameter is set to
    refer to the corresponding actual parameter. In the function
    it is only possible to read a formal 'ref' parameter.
    Changing a formal 'ref' parameter is not possible. Formal
    'ref' parameters have the access right 'const'.


  Syntax:

    ref_parameter ::=
      'ref' type_expression ':' identifier_declaration |
      'ref' type_expression 'param' .


  Declaration:

    $ syntax expr: .ref.().param is                   -> 40;
    $ syntax expr: .ref.(). : .(expr) is              -> 40;

    const func f_param: ref (ref type param) param is               action "DCL_REF1";
    const func f_param: ref (ref type param) : (ref expr param) is  action "DCL_REF2";


6.3 'in' parameter

  Input parameters are marked with the keyword 'in'.
  Depending on the type an input parameter is either a
  value or a reference parameter. The function below
  checks if a given number is a prime number:

    const func boolean: is_prime (in integer: number) is func
      result
        var boolean: result is FALSE;
      local
        var integer: count is 2;
      begin
        if number = 2 then
          result := TRUE;
        elsif number >= 3 then
          while number rem count <> 0 and count * count <= number do
            incr(count);
          end while;
          result := number rem count <> 0;
        end if;
      end func;

  The following function defines the ex (outer) product:

    const func array array integer:
        (in array integer: a) ex (in array integer: b) is func
      return
        var array array integer: result is 0 times 0 times 0;
      local
        var integer: index1 is 1;
      begin
        result := length(a) times length(b) times 0;
        for index1 range 1 to length(a) do
          for index2 range 1 to length(b) do
            result[index1][index2] := a[index1] * b[index2];
          end for;
        end for;
      end func;

  Although both examples use 'in' parameters the parameter in the
  first example is actually a 'val' parameter while the parameters
  in the second example are actually 'ref' parameters. When a new
  type is created with the 'newtype' function it is necessary to
  specify the meaning of the 'in' parameter. This is done with a
  call of the IN_PARAM_IS_VALUE or the IN_PARAM_IS_REFERENCE function
  with the new generated type as parameter. If a new type is created
  with the 'subtype' function this specification is optional since
  the base type has already a specification of the 'in' parameter.

  Semantics:
    Depending on the type an 'in' parameter is equivalent to an
    'val' (call by value) parameter or to an 'ref' (call by reference)
    parameter. Formal 'in' parameters have the access right 'const'.


  Syntax:

    in_parameter ::=
      'in' type_expression ':' identifier_declaration .


  Declaration:

    $ syntax expr: .in.().param is                    -> 40;
    $ syntax expr: .in.(). : .(expr) is               -> 40;

    const func f_param: in (ref type param) param is                action "DCL_REF1";

    const proc: IN_PARAM_IS_VALUE (ref type: aType) is func
      begin
        const func f_param: in (attr aType) : (ref expr param) is   action "DCL_VAL2";
      end func;

    const proc: IN_PARAM_IS_REFERENCE (ref type: aType) is func
      begin
        const func f_param: in (attr aType) : (ref expr param) is   action "DCL_REF2";
      end func;


6.4 'in var' parameter

  This function computes the greatest common divisor:

    const func integer: gcd (in var integer: a, in var integer: b) is func
      result
        var integer: result is 0;
      local
        var integer: help is 0;
      begin
        while a <> 0 do
          help := b rem a;
          b := a;
          a := help;
        end while;
        result := b;
      end func;

  Semantics:
    When calling a function a formal 'in var' parameter gets its
    value from the corresponding actual parameter. This is done
    with a create procedure ( ::= ). In the function it is
    possible to read and change a formal 'in var' parameter.
    Changing a formal 'in var' parameter has no effect on the
    actual parameter. When a function is left a 'destr' procedure
    is called for every 'in var' parameter. Formal 'in var'
    parameters have the access right 'var'.


  Syntax:

    in_var_parameter ::=
      'in var' type-expression ':' identifier_declaration .


  Declaration:

    $ syntax expr: .in.var.().param is                -> 40;
    $ syntax expr: .in.var.(). : .(expr) is           -> 40;

    const func f_param: in var (ref type param) param is               action "DCL_IN1VAR";
    const func f_param: in var (ref type param) : (ref expr param) is  action "DCL_IN2VAR";


6.5 'inout' parameter

  This procedure doubles the given parameter 'number':

    const proc: double (inout integer: number) is func
      begin
        number := 2 * number;
      end func;

  Semantics:
    When calling a function a formal 'inout' parameter is set to 
    refer to the corresponding actual parameter. In the function
    it is possible to read and change a formal 'inout' parameter.
    Changing a formal 'inout' parameter changes the actual
    parameter as well. Formal 'inout' parameters have the
    access right 'var'.


  Syntax:

    inout_parameter ::=
      'inout' type_expression ':' identifier_declaration .


  Declaration:

    $ syntax expr: .inout.().param is                 -> 40;
    $ syntax expr: .inout.(). : .(expr) is            -> 40;

    const func f_param: inout (ref type param) param is                action "DCL_INOUT1";
    const func f_param: inout (ref type param) : (ref expr param) is   action "DCL_INOUT2";


6.6 Symbol parameter

  Some functions need symbols at fixed places in the parameter
  list. The following IF-statement requests the keywords 'THEN',
  'END' and 'IF' at specific places:

    IF condition THEN
      statement
    END IF;

  After defining the syntax of this IF-statement with

    $ syntax expr: .IF.().THEN.().END.IF is -> 25;

  the semantic can be defined with:

    const proc: IF (in boolean: condition) THEN
                  (in proc: statement)
                END IF is func

                  begin
                    case condition of
                      when {TRUE}: statement;
                    end case;
                  end func;

  The symbol parameters are just written outside the parentheses.
  A call of this statement could be:

    IF value < maximum THEN
      write(value)
    END IF;

  Semantics:
  Symbol parameters must be defined in a syntax definition and in
  a corresponding semantic definition. In the semantic definition
  symbol parameters are written outside of the parentheses.
  In the actual parameter list the corresponding symbol of the
  formal parameter list must be written.


  Syntax:

    symbol_parameter ::=
      name_identifier | special_identifier .


6.7 'attr' parameter

  This declaration associates a name to the type 'char':

    const string: name (attr char) is "char";

  This 'name' can be used as follows:

    writeln(name(char));

  It is possible to overload such declarations:

    const string: name (attr boolean) is "boolean";
    const string: name (attr float) is "float";

  An 'attr' parameter can be used in a function also:

    const func char: (attr char) parse (in string: stri) is func
      result
        var char: result is ' ';
      begin
        if length(stri) >= 1 then
          result := stri[1];
        else
          raise RANGE_ERROR;
        end if;
      end func;

  Semantics:
  The actual parameter which corresponds to an 'attr' parameter
  must be the type mentioned in the declaration of the 'attr' parameter.
  An 'attr' parameter does not declare a formal parameter
  variable which could be used inside a function.


  Syntax:

    attr_parameter ::=
      'attr' type_expression .



7. OBJECT ORIENTATION
=====================

    Many people will be familiar with object-orientation from
  languages like C++, Smalltalk, and Java. Seed7 follows the
  route of declaring "interfaces". An interface is a common
  set of operations supported by an object. For instance
  cars, motorcycles, lorries and vans can all accelerate or
  brake, if they are legal to drive on the road they can all
  indicate right and left.

  This view isn't new. C provides a primitive form of
  interfacing. When you write to a 'file' in C you use the same
  interface ('fprintf') for hard disk files, console output and
  printer output. The implementation does totally different
  things for these files. Unix has used the "everything is a
  file" philosophy for ages (even network communication uses
  the file' interface (see sockets)).

  For short: An interface defines which methods are supported
  while the implementation describes how this is done.
  Several types with different method implementations can
  share the same interface. 


7.1 Interface and implementation

  Seed7 uses interface types and implementation types.
  Objects declared with an interface type refer to a value
  which has an implementation type. This situation is
  described with the following picture:

              +----------------+
    declared  |    interface   |<--- interface type
    object:   |     object     |     (known at compile-time)
              +----------------+
                      |
                      | refer to value
                      V
              +----------------+
    value:    | implementation |<--- implementation type
              |     object     |     (unknown at compile-time)
              +----------------+

  The interface type of an object can always be determined
  at compile-time. Several implementation types can belong
  to one interface type (they implement the interface type).
  E.g.: The types 'null_file', 'external_file' and 'socket'
  implement the 'file' interface. On the other hand: An
  implementation type can also implement several interface
  types. An interface object can only refer to a value with
  an implementation type that implements the interface.
  E.g.: A 'shape' variable cannot refer to a 'socket'.

  A new interface type is declared with:

    const type: shape is new interface;

  Interface (DYNAMIC) functions describe what can be done
  with objects of an interface type. An interface function
  for a 'shape' could be:

    const proc: draw (in shape param, inout window param) is DYNAMIC;

  Now we know that it is possible to 'draw' a 'shape' to a
  'window'. How this drawing is done is described in the
  implementation type. An implementation type for 'shape' is:

    const type: circle is new struct
        var integer: radius is 0;
      end struct;

  The fact that the type 'circle' is an implementation type of
  'shape' is described with:

    type_implements_interface(circle, shape);

  The function which implements 'draw' for 'circle's is:

    const proc: draw (in circle: aCircle, inout window: aWindow) is func
      begin
        circle(aWindow.win, aWindow.currX, aWindow.currY,
            aCircle.radius, aWindow.foreground);
      end func;

  In the classic OOP philosophy a message is sent to an object.
  To express this situation classic OO languages use the
  following method call syntax:

    param1.method(param2, param3)

  In the method the receiving object is referred with 'self' or
  'this'. The other parameters use the same mechanisms as in
  procedural programming languages (value or reference parameter). 
  Seed7 uses a different approach: Instead of an implicit defined
  'self' or 'this' parameter, all formal parameters get a user
  defined name. To reflect this symmetric approach a Seed7 method
  call looks like a normal function call:

    method(param1, param2, param3)

  The definition of the 'draw' function above uses the formal
  parameter 'aCircle' in the role of a 'self' or 'this' parameter.
  Formal parameters which have an implementation type are
  automatically in the role of a 'self' or 'this' parameter.

  A function to create new circle objects can also be helpful:

    const func circle: circle (in integer: radius) is func
      result
        var circle: result is circle.value;
      begin
        result.radius := radius;
      end func;

  Now we can draw a 'circle' object with:

    draw(circle(50), aWindow);

  Although the statement above does exactly what it should
  do and the separation between interface and implementation
  is obvious, most OO enthusiasts would not be thrilled. All
  decisions which implementation function should be called
  can be made at compile time. To please the OO fans such
  decisions must be made at runtime. This decision process
  is called dynamic dispatch.


7.2 Dynamic dispatch

    When the implementation types have different implementations
  of the same function (method) a dynamic dispatch is necessary.
  The type of the value, referred by an interface object, is not
  known at compile-time. In this case the program must decide at
  runtime which implementation of the function should be invoked.
  This decision is based on the implementation type of the value
  (referred by the interface object). A dynamic dispatch only
  takes place when a DYNAMIC (or interface) function is called.
  When the program is analyzed (in the interpreter or compiler)
  the interface functions take precedence over normal functions
  when both are to be considered.

  To demonstrate the dynamic dispatch we define the type 'line'
  which also implements a 'shape':

    const type: line is new struct
        var integer: xLen is 0.0;
        var integer: yLen is 0.0;
      end func;

    type_implements_interface(line, shape);

    const proc: draw (in line: aLine, in window: aWindow) is func
      begin
        line(aWindow.win, aWindow.currX, aWindow.currY,
            aLine.xLen, aLine.yLen, aWindow.foreground);
      end func;

    const func line: line (in integer: xLen, in integer: yLen) is func
      result
        var line: result is line.value;
      begin
        result.xLen := xLen;
        result.yLen := yLen;
      end func;

  In addition we define a normal (not DYNAMIC) function 
  which draws 'shape's to the 'currWindow':

    const proc: draw (in shape: aShape) is func
      begin
        draw(aShape, currWindow);
      end func;

  In the example above the call of the (DYNAMIC) interface
  function is 'draw(aShape, currWindow)'. The
  interface function declared with

    const proc: draw (in shape param, inout window param) is DYNAMIC;

  decides which implementation function has to be called.
  The dynamic dispatch works as follows:

  - For all parameters which have an interface type the
    parameter is replaced with its value. In this case the
    parameter 'aShape' is replaced by a value of type
    'circle' or 'line'.

  - The same logic as in the analyze part of the compiler
    is used to find the matching function. In this search
    normal functions take precedence over interface functions.

  - When a matching function is found it is called.

  This process describes the principal logic of the dynamic
  dispatch. In practice it is not necessary to execute the
  analyze part of the compiler during the runtime. It is
  possible to simplify this process with tables and function
  pointers.


7.3 Inheritance

    When a new 'struct' type is defined it is possible to
  inherit from an existing 'struct' type. E.g.:

    const type: external_file is sub null_file struct
        var PRIMITIVE_FILE: ext_file is PRIMITIVE_NULL_FILE;
        var string: name is "";
      end struct;

  That way the type 'external_file' inherits the fields and
  methods of 'null_file', which is declared as:

    const type: null_file is new struct
      var char: bufferChar is '\n';
      var boolean: io_empty is FALSE;
      var boolean: io_ok is TRUE;
    end struct;

  In most situations it makes sense when the implementation
  types inherit from a basic implementation type such as
  'null_file'. That way it is possible to define functions
  which are inherited by all derived implementation types.
  In the standard library the function 'getln' is such a
  function:

    const func string: getln (inout null_file: aFile) is func
      result
        var string: stri is "";
      local
        var string: buffer is "";
      begin
        buffer := gets(aFile, 1);
        while buffer <> "\n" and buffer <> "" do
          stri &:= buffer;
          buffer := gets(aFile, 1);
        end while;
        aFile.bufferChar := buffer[1];
      end func;

  All inherited types of 'null_file' inherit the function
  'getln', but they are also free to redefine it. In the
  'getln' function above the function call 'gets(aFile, 1)'
  uses the (DYNAMIC) interface function:

    const func string: gets (inout file param, in integer param) is DYNAMIC;

  In other OO languages the distinction between interface type
  and basic implementation type is not done. Such languages
  either use a dynamic dispatch for every method call (as Java
  does) or need a keyword to request a dynamic dispatch (as C++
  does with the 'virtual' keyword).

  When assignments take place between inherited implementation
  types it is important to note that structure assignments are
  done with (deep) copies. Naturally such assignments can only
  copy the elements that are present in both structures.
  In the following example just the 'null_file' elements
  are copied from 'anExternalFile' to 'aNullFile':

    const proc: example is func
      local
        var null_file: aNullFile is null_file.value;
        var external_file: anExternalFile is external_file.value;
      begin
        aNullFile := anExternalFile;
        write(aNullFile, "hello");
      end func;

  Although the variable 'anExternalFile' is assigned to
  'aNullFile', the statement 'write(aNullFile, "hello")'
  calls the 'write' function (method) of the type 'null_file'.

  A new interface type can also inherit from an existing
  interface type:

    const type: shape is sub object interface;

  Although inheritance is a very powerful feature it should
  be used with care. In many situations it makes more sense
  that a new type has an element of another type (so called
  has-a relation) instead of inheriting from that type (so
  called is-a relation).


7.4 Class methods

    Many object-oriented programming languages support methods
  that are associated with a class instead of an instantiated
  object. Such methods are called class methods or static
  methods. Seed7 supports class methods via attribute ('attr')
  parameters which allow that a function is attached to a type:

    const func circle: create (attr circle, in integer: radius) is
      return circle(radius);

  This 'create' function is attached to the type 'circle' and can be called with

    create(circle, 10)

  Many languages require that the class name must precede the
  method name when a class method is called (E.g. 'circle::create(10)'
  in C++). In contrast to that 'attr' parameters are not
  restricted to a specific parameter position. They can be used
  in any parameter position as in the following example:

    const func circle: create (in integer: radius, attr circle) is
      return circle(radius);

  This function can be called with

    create(10, circle)

  Attribute parameters can be used for any type not just for
  interface and implementation types. Objects which do not
  have a function type such as a character constant can also
  be attached to a type:

    const char: (attr char) . value is ' ';

  This way attributes can be used to specify properties
  of a type such as its default 'value'.
  Programming languages such as Seed7 which support function
  definitions outside a class can also use normal functions
  instead of class methods. It is a matter of tast if a
  function should be grouped to a type or if it should
  exist stand alone and is called with:

    circle(10)



7.5 Multiple dispatch

    The Seed7 object system allows multiple dispatch (not to
  be confused with multiple inheritance). The methods are
  not assigned to one type (class). The decision which
  function (method) is called at runtime is done based upon
  the types of several arguments. The classic object
  orientation is a special case where a method is connected
  to one class and the dispatch decision is done based on
  the type of the 'self' or 'this' parameter.
  The classic object orientation is a single dispatch system.

  In the following example the type 'Number' is introduced
  which is capable to unify numerical types. The type
  'Number' is an interface type which defines
  the interface function for the '+' operation:

    const type: Number is sub object interface;

    const func Number: (in Number param) + (in Number param) is DYNAMIC;

  The interface type 'Number' can represent an 'Integer' or a 'Float':

    const type: Integer is new struct
        var integer: val is 0;
      end struct;

    type_implements_interface(Integer, Number);

    const type: Float is new struct
        var float: val is 0.0;
      end struct;

    type_implements_interface(Float, Number);

  The declarations of the converting '+' operators are:

    const func Float: (in Integer: a) + (in Float: b) is func
      result
        var Float: result is Float.value;
      begin
        result.val := flt(a.val) + b.val;
      end func;

    const func Float: (in Float: a) + (in Integer: b) is func
      result
        var Float: result is Float.value;
      begin
        result.val := a.val + flt(b.val);
      end func;

  The declarations of the normal '+' operators (which do not convert) are:

    const func Integer: (in Integer: a) + (in Integer: b) is func
      result
        var Integer: result is Integer.value;
      begin
        result.val := a.val + b.val;
      end func;

    const func Float: (in Float: a) + (in Float: b) is func
      result
        var Float: result is Float.value;
      begin
        result.val := a.val + b.val;
      end func;

  The type 'Number' can be extended to support other
  operators and there can be also implementations using
  'complex', 'bigInteger', 'bigRational', etc. . That way
  'Number' can be used as universal type for math
  calculation. Further extending can lead to an universal
  type. Such an universal type is loved by proponents of
  dynamic typed languages, but there are also good reasons
  to have distinct types for different purposes.


7.6 Replacing pointers with interface types

    Many languages have the concept of a pointer. It is possible
  to implement data structures, such as lists and trees, with
  pointers. Although Seed7 supports the concept of a pointer, they
  are not well suited to describe such data structures. Instead of
  pointers interface types can be used. This way list, trees and
  other advanced data structures can be defined.

  The following example shows how to do this:
  The interface type 'element' will be used as "pointer":

    const type: element is new interface;

  An implementation type for the empty 'element' (emptyElement)
  can be used as basic implementation type from which other
  implementation types can inherit:

    const type: emptyElement is new struct
      end struct;

  That the implementation type 'emptyElement' implements the
  interface type 'element' is described with:

    type_implements_interface(emptyElement, element);

  Since every Seed7 expression has exactly one type, it is
  necessary to define a special 'NIL' value (used with  'element.NIL')
  for the type 'element':

    const element: (attr element) . NIL is emptyElement.value;

  Now the struct with two "pointers" and an 'integer' can be
  declared:

    const type: treeElement is sub emptyElement struct
        var element: left is element.NIL;
        var element: right is element.NIL;
        var integer: item is 0;
      end struct;

  Finally the type 'treeElement' is defined as implementation
  of the type 'element':

    type_implements_interface(treeElement, element);

  To allow the direct access to the structure elements 'left', 'right'
  and 'item' for objects of type 'element' the following declarations
  are necessary:

    const func    element: (ref   element param).left  is DYNAMIC;
    const varfunc element: (inout element param).left  is DYNAMIC;
    const func    element: (ref   element param).right is DYNAMIC;
    const varfunc element: (inout element param).right is DYNAMIC;
    const func    integer: (ref   element param).item  is DYNAMIC;
    const varfunc integer: (inout element param).item  is DYNAMIC;

  When all this was declared the following code is possible:

    const proc: addItem (inout element: anElem, in integer: item) is func
      begin
        if anElem = element.NIL then
          anElem := xalloc(treeElement.value);
          anElem.item := item;
        elsif item < anElem.item then
          addItem(anElem.left, item);
        elsif item > anElem.item then
          addItem(anElem.right, item);
        end if;
      end func;

    const proc: listItems (in element: anElem) is func
      begin
        if anElem <> element.NIL then
          listItems(anElem.left);
          write(" " <& anElem.item);
          listItems(anElem.right);
        end if;
      end func;

    const func integer: sum (in element: anElem) is func
      result
        var integer: result is 0;
      begin
        if anElem <> element.NIL then
          result := anElem.item + sum(anElem.left) + sum(anElem.right);
        end if;
      end func;

  New elements can be created with the function 'xalloc'.
  This way interface and implementation types help to provide the
  pointer functionality.

  Pointers and interface types are not always the best solution.
  Abstract data types like dynamic arrays, hash tables, struct
  types and set types can also be used to declare data structures.


8. THE FILE SYSTEM
==================

    The file system is used for communication in various ways.
  For example: To write strings on the screen we use the
  following statements:

    write("hello world");
    writeln;

  The procedure 'write' writes a given string and 'writeln' means: Write newline.
  We can also write data of various types with 'write':

    write("result = ");
    write(number div 5);
    write(" ");
    writeln(not error);

  The 'writeln' above writes data and then terminates the line.
  This is equal to a 'write' followed by a 'writeln'. Instead of
  multiple write statements the '<&' operator can be used to
  concatenate the elements to be written:

    writeln("result = " <& number div 5 <& " " <& not error);

  The '<&' operator needs a 'string' as left operand and
  is overloaded for various types as right operand. To allow things like

    write(next_time <& " \r");

  the '<&' operator is also overloaded for various types as
  left operand and a 'string' as right operand.
  This allows you to concatenate several objects with '<&' when
  at least the first or the second object is a 'string'.
  We can also read data from the keyboard:

    write("Amount? ");
    read(amount);

  The user is allowed to use backspace and sends the input
  to the program with the RETURN-key. To let the user respond
  with the RETURN-key we can write:

    writeln("Type RETURN");
    readln;

  To read a line of data we can use 'readln':

    write("Your comment? ");
    readln(user_comment_string);

  In the previous examples all 'read' statements read from the
  file 'IN' and all 'write' statements write to the file 'OUT'. The
  files 'IN' and 'OUT' are initialized with 'STD_IN' and 'STD_OUT'
  which are the stdin and stdout files of the operating system.
  (Usually the keyboard and the screen). When we want to write
  to other files we use write statements with the file as first
  parameter. To write a line of text to the file "info.fil" we
  use the following statements:

    info_file := open("info.fil", "w");
    writeln(info_file, "This is the first line of the info file.");
    close(info_file);

  First the external file is opened for writing and then it is
  used. To read the file back in the string 'stri' we write:

    info_file := open("info.fil", "r");
    readln(info_file, stri);
    close(info_file);

  It is also possible to write values of other types to
  'info_file':

    writeln(info_file, number);

  Here the 'number' is converted to a string which is written
  to the file. A 'number' is read back with:

    readln(info_file, number);

  For doing I/O to a window on the screen we write:

    window1 := open_window(screen, 10, 10, 5, 60);
    box(window1);
    setPos(window1, 3, 1);
    write(window1, "hello there");

  This opens the window 'window1' on the 'screen' at the position
  10, 10. This window has 5 lines and 60 columns. A box (of
  characters: - | + ) is written to surround the 'window1' and
  finally the string "hello there" is written in the window
  'window1' at Position 3, 1. If we want to clear the 'window1'
  we write:

    clear(window1);

  Files can be used for much more things. Here is a list of
  goals for a file system:

    - A concept which provides conversions from arbitrary
      types to strings and back.

    - Basic input and output operations to process a file
      character wise, word wise or line wise.

    - Input and output statements which combine input with
      conversion respectively conversion with output.

    - Simple read and write statements for standard
      input and output for arbitrary types.

    - Standard input and output files and the possibility
      to route the standard I/O to any file.

    - Access to operating system files and devices.

    - An interface which allows the user to define
      his own file types.

  In the following subchapters we discuss each of these goals.


8.1 Conversion to strings and back

    We archive the goal of doing I/O for arbitrary types with
  two conversion functions. In order to do I/O with a type
  the 'str' and 'parse' functions must be defined for that
  type. As an example we show the conversion functions for the
  type 'boolean':

    const func string: str (in boolean: aBool) is func
      result
        var string: result is "";
      begin
        if aBool then
          result := "TRUE";
        else
          result := "FALSE";
        end if;
      end func;

    const func boolean: (attr boolean) parse (in string: stri) is func
      result
        var boolean: result is FALSE;
      begin
        if stri = "TRUE" then
          result := TRUE;
        elsif stri = "FALSE" then
          result := FALSE;
        else
          raise RANGE_ERROR;
        end if;
      end func;

  The 'str' function must deliver a corresponding string for
  every value of the type. The 'parse' operator parses a string
  and delivers the converted value as result. If the conversion
  is not successful the exception RANGE_ERROR is raised. The
  attribute used with 'parse' allows that it is overloaded for
  different types.

  After defining the 'str' and 'parse' functions for a type the
  'enable_io' function can be called for this type as in:

    enable_io(boolean);

  The 'enable_io' template declares various io functions like
  'read', 'write' and others for the provided type (in this
  example 'boolean'). If only output (or only input) is needed
  for a type it is possible to define just 'str' (or 'parse')
  and activate just 'enable_output' (or 'enable_input').

  There is also a formatting operator called 'lpad' which is based
  on the 'str' function. The statements

    write(12 lpad 6);
    write(3 lpad 6);
    writeln(45 lpad 6);
    write(678 lpad 6);
    write(98765 lpad 6);
    writeln(4321 lpad 6);

  produce the following output:

        12     3    45
       678 98765  4321

  As we see the 'lpad' operator can be used to produce right
  justified output. There is also a 'rpad' operator to produce
  left justified output. The basic definitions of the 'lpad'
  and 'rpad' operators work on strings and are as follows:

    const func string: (ref string: stri) lpad (in integer: leng) is func
      result
        var string: result is "";
      begin
        if leng > length(stri) then
          result := " " mult leng - length(stri) & stri;
        else
          result := stri;
        end if;
      end func;

    const func string: (ref string: stri) rpad (in integer: leng) is func
      result
        var string: result is "";
      begin
        if leng > length(stri) then
          result := stri & " " mult leng - length(stri);
        else
          result := stri;
        end if;
      end func;

  The 'enable_io' template contains definitions of 'lpad' and 'rpad'
  to work on the type specified with 'enable_io':

    const func string: (in aType: aValue) lpad (in integer: leng) is func
      result
        var string: stri is "";
      begin
        stri := str(aValue) lpad leng;
      end func;

    const func string: (in aType: aValue) rpad (in integer: leng) is func
      result
        var string: stri is "";
      begin
        stri := str(aValue) rpad leng;
      end func;

  For 'float' values exists an additional way to convert them to
  strings. The 'digits' operator allows the specification of a
  precision. For example the statements

    writeln(3.1415 digits 2);
    writeln(4.0 digits 2);

  produce the following output:

    3.14
    4.00

  A combination with the 'lpad' operator as in

    writeln(3.1415 digits 2 lpad 6);
    writeln(99.9 digits 2 lpad 6);

  is also possible and produces the following output:

      3.14
     99.90


8.2 Basic input and output operations

    To allow arbitrary user defined file-types beside the
  operating system files we chose a model in which the
  I/O methods are assigned to the type of the file-value and
  not to the type of the file-variable. This allows a file
  variable to point to any file-value. The file-variables
  have the type 'file', which is the interface type for sequencial
  files. For the operating system files and for each user
  defined file a file-type must be declared which has the
  I/O methods defined. These file-types are derived (direct
  or indirect) from the type 'null_file' for which all I/O
  methods are defined upon a base of basic string I/O
  methods. So for a new user defined file-type only the
  basic string I/O methods must be defined.

  The two basic I/O methods defined for 'null_file' are

    const proc: write (ref null_file: aFile, in string: stri) is noop;
    const string: gets (ref null_file: aFile, ref integer: maxLength) is "";

  A 'write' to 'null_file' with any string has no effect.
  Reading any number of characters with 'gets' from
  'null_file' delivers the empty string. When a user defined
  file type is declared these are the two methods, which must
  be redefined, for the new file-type. Based upon these
  two methods three more methods are defined for
  'null_file', named  'getc', 'getwd' and 'getln'.
  These methods get a character, a word and a line
  respectively. A word is terminated by a space, a tab
  or a linefeed. A line is terminated by a linefeed.
  This methods need not to be redefined for a user defined
  file type but for performance reasons they can also be
  redefined. The definitions for 'getc', 'getwd' and 'getln' for
  'null_file' are

    const func char: getc (inout null_file: aFile) is func
      result
        var char: ch is ' ';
      local
        var string: buffer is "";
      begin
        buffer := gets(aFile, 1);
        if buffer = "" then
          ch := EOF;
        else
          ch := buffer[1];
        end if;
      end func;

    const func string: getwd (inout null_file: aFile) is func
      result
        var string: stri is "";
      local
        var string: buffer is "";
      begin
        repeat
          buffer := gets(aFile, 1);
        until buffer <> " " and buffer <> "\t";
        while buffer <> " " and buffer <> "\t" and
            buffer <> "\n" and buffer <> "" do
          stri &:= buffer;
          buffer := gets(aFile, 1);
        end while;
        if buffer = "" then
          aFile.bufferChar := EOF;
        else
          aFile.bufferChar := buffer[1];
        end if;
      end func;

    const func string: getln (inout null_file: aFile) is func
      result
        var string: stri is "";
      local
        var string: buffer is "";
      begin
        buffer := gets(aFile, 1);
        while buffer <> "\n" and buffer <> "" do
          stri &:= buffer;
          buffer := gets(aFile, 1);
        end while;
        if buffer = "" then
          aFile.bufferChar := EOF;
        else
          aFile.bufferChar := buffer[1];
        end if;
      end func;

  Note that 'getwd' skips leading spaces and tabs while 'getc' and
  'getln' do not.
  When 'getc', 'getwd' or 'getln' is not defined for a new user defined
  file type the declarations from the 'null_file' are used instead.
  These declarations are based on the method 'gets' which must be
  defined for every new user defined file-type.

  Note that there is an assignment to the variable 'bufferChar'.
  This variable is an element of 'null_file' and therefore also
  an element of all derived file types. This allows an
  'eoln' function to test if the last 'getwd' or 'getln' reach the end
  of a line. Here is a definition of the 'eoln' function:

    const func boolean: eoln (ref null_file: aFile) is func
      result
        var boolean: result is TRUE;
      begin
        result := aFile.bufferChar = '\n';
      end func;

  Besides assigning a value to 'bufferChar' in 'getwd' and 'getln'
  and using it in 'eoln' the standard 'file' functions do nothing
  with 'bufferChar'. The functions of the "scanfile.s7i" library
  use the 'bufferChar' variable as current character in the scan
  process. As such all functions of the "scanfile.s7i" library
  assume that the first character to be processed is always in
  'bufferChar'. Since the standard 'file' functions do not have
  this behavior, care has to be taken when mixing scanner and
  file functions.

  The next declarations allows various I/O operations for strings:

    const proc: writeln (inout file: aFile, in string: stri) is func
      begin
        write(aFile, stri);
        writeln(aFile);
      end func;

    const proc: read (inout file: aFile, inout string: stri) is func
      begin
        stri := getwd(aFile);
        aFile.io_empty := stri = "";
        aFile.io_ok := TRUE;
      end func;

    const proc: readln (inout file: aFile, inout string: stri) is func
      begin
        stri := getln(aFile);
        aFile.io_empty := stri = "";
        aFile.io_ok := TRUE;
      end func;


8.3 Input and output with conversion

    Normally we need a combination of an I/O operation with
  a conversion operation. There are several functions which are
  based on the 'str' and 'parse' conversions and on the basic
  I/O-functions. The declaration of this functions is done by
  the templates 'enable_io', 'enable_input' and 'enable_output'.
  The templates 'enable_io' and 'enable_output' define the following
  'write' function:

    const proc: write (in file: aFile, in aType: aValue) is func
      begin
        write(aFile, str(aValue));
      end func;

  The templates 'enable_io' and 'enable_input' define the following
  'read' and 'readln' functions:

    const proc: read (inout file: aFile, inout aType: aValue) is func
      local
        var string: stri is "";
      begin
        stri := getwd(aFile);
        aFile.io_empty := stri = "";
        block
          aValue := aType parse stri;
          aFile.io_ok := TRUE;
        exception
          catch RANGE_ERROR:
            aFile.io_ok := FALSE;
        end block;
      end func;

    const proc: readln (inout file: aFile, inout aType: aValue) is func
      local
        var string: stri is "";
      begin
        stri := getln(aFile);
        aFile.io_empty := stri = "";
        block
          aValue := aType parse stri;
          aFile.io_ok := TRUE;
        exception
          catch RANGE_ERROR:
            aFile.io_ok := FALSE;
        end block;
      end func;

  The next two declarations define 'writeln' and 'backSpace':

    const proc: writeln (ref external_file: aFile) is func
      begin
        write(aFile, "\n");
      end func;

    const proc: backSpace (ref external_file: aFile) is func
      begin
        write(aFile, "\b \b");
      end func;


8.4 Simple read and write statements

    The simple input/output for the standard I/O-files are
  'read' and 'write' which are defined with 'enable_io'. Simple
  I/O may look like:

    write("Amount? ");
    read(amount);

  'read' and 'write' use the files 'IN' and 'OUT', which are described
  in the next chapter.  Here is the definition of the 'read' and
  'write' procedures done with 'enable_io':

    const proc: read (inout aType: aValue) is func
      begin
        read(IN, aValue);
      end func;

    const proc: readln (inout aType: aValue) is func
      begin
        readln(IN, aValue);
      end func;

    const proc: write (in aType: aValue) is func
      begin
        write(OUT, aValue);
      end func;

    const proc: writeln (in aType: aValue) is func
      begin
        write(OUT, aValue);
        writeln(OUT);
      end func;

  Additional procedures defined outside of 'enable_io' are:

    const proc: readln is func
      local
        var string: stri is "";
      begin
        stri := getln(IN);
        IN.io_empty := stri = "";
        IN.io_ok := TRUE;
      end func;

    const proc: read (NL) is func
      begin
        readln;
      end func;

    const proc: writeln is func
      begin
        writeln(OUT);
      end func;

    const proc: write (NL) is func
      begin
        writeln(OUT);
      end func;

  As an example when you call

    readln(number);

  the readln(integer) procedure calls

    readln(IN, number);

  if the file IN has not redefined readln(IN, integer) this
  procedure calls

    stri := getln(IN);

  and 'getln' may call gets(IN, 1) in a loop or may be defined
  for the file 'IN'. Finally the 'parse' function converts the
  string read into an 'integer' and assigns it to 'number'

    number := integer parse stri;


8.5 Standard input and output files

    The standard I/O files are 'IN' for input and 'OUT' for output.
  'IN' and 'OUT' are 'file' variables, which are defined as follows:

    var file: IN is STD_IN;
    var file: OUT is STD_OUT;

  The files 'STD_IN' and 'STD_OUT' are the standard input and
  output files of the operating system (Usually the keyboard and
  the screen). Because 'IN' and 'OUT' are variables redirection of
  standard input or standard output can be done easily by
  assigning a new value to them:

    IN := OTHER_FILE;

  After that all 'read' statements refer to OTHER_FILE.
  Most operating systems have also a stderr file which
  can be accessed via the name 'STD_ERR'. If you want to
  write error messages to the screen even when stdout
  is redirected elsewhere you can write:

    writeln(STD_ERR, "ERROR MESSAGE");

  To redirect the standard output to 'STD_ERR' you can write:

    OUT := STD_ERR;

  There is also a file 'STD_NULL' defined. Anything written to
  it is ignored. Reading from it does deliver empty strings.
  This file can be used to initialize file variables as in:

    var file: MY_FILE is STD_NULL;

  It is also used to represent an illegal file value, when for
  example an attempt to 'open' a 'file' fails.


8.6 Access to operating system files

    The interface type 'file' is also used to access
  operating system files. Usually a file variable is defined

    var file: my_out is STD_NULL;

  and the result of the 'open' function is assigned to this file
  variable

    my_out := open("my_file", "w");

  The first parameter of 'open' is the path of the file to
  be opened. Seed7 always uses the slash ('/') as path
  delimiter. The use of a backslash in a path may raise the
  exception 'RANGE_ERROR'. The second parameter of 'open'
  specifies the mode:

    Binary mode:
      "r"   ... Open file for reading.
      "w"   ... Truncate to zero length or create file for writing.
      "a"   ... Append; open or create file for writing at end-of-file.
      "r+"  ... Open file for update (reading and writing).
      "w+"  ... Truncate to zero length or create file for update.
      "a+"  ... Append; open or create file for update, writing at end-of-file.
    Text mode:
      "rt"  ... Open file for reading.
      "wt"  ... Truncate to zero length or create file for writing.
      "at"  ... Append; open or create file for writing at end-of-file.
      "rt+" ... Open file for update (reading and writing).
      "wt+" ... Truncate to zero length or create file for update.
      "at+" ... Append; open or create file for update, writing at end-of-file.

  Note that Seed7 defines the modes "r", "w", "a", "r+", "w+"
  and "a+" as binary modes. When 'open' is called, with a mode
  not listed in the table above, the exception 'RANGE_ERROR'
  is raised. When there is not enough memory to convert 'path'
  to the system path type the exception 'MEMORY_ERROR'
  is raised. When 'open' fails for other reasons it returns
  'STD_NULL'. E.g.: It is not allowed to 'open' a directory.
  An attempt to 'open' a directory returns 'STD_NULL'. It is
  recommended to check the file variable after opening a file:

    if my_out <> STD_NULL then

  After that output to 'my_out' is possible with

    writeln(my_out, "hi there");

  When processing of a file is finished it should be closed

    close(my_out);

  Writing to a file after it has been closed results in the
  exception 'FILE_ERROR'. The following program writes
  "hi there" to the file "my_file":

    $ include "seed7_05.s7i";

    const proc: main is func
      local
        var file: my_out is STD_NULL;
      begin
        my_out := open("my_file", "w");
        if my_out <> STD_NULL then
          writeln(my_out, "hi there");
          close(my_out);
        end if;
      end func;

  Note that 'open' opens BYTE files. Writing
  a character with an ordinal >= 256 such as

    writeln(my_out, "illegal char: \256\");

  results in the exception 'RANGE_ERROR'. To write Unicode
  characters other file types must be used. The libraries
  "utf8.s7i" and "utf16.s7i" provide access to UTF-8 and
  UTF-16 files. The function 'open_utf8' can be used the same
  way as 'open':

    my_out := open_utf8("utf8_file", "w");

  An UTF-8 file accepts all Unicode characters. That way

    writeln(my_out, "Unicode char: \256\");

  works without problems. UTF-8 files are byte order independent.
  Therefore they do not need a byte order mark (BOM).
  In case a BOM is required it can be written by the user program:

    my_out := open_utf8("utf8_file", "w");
    write("\16#FEFF\");

  The following example expects a mandatory BOM at the beginning of an UTF-8 file:

    my_out := open_utf8("utf8_file", "r");
    if getc(my_file) <> '\16#FEFF\' then
      writeln("The BOM is missing"");
    else
      ...
    end if;

  Accepting an optional BOM at the beginning of an UTF-8 file is done with:

    my_out := open_utf8("utf8_file", "r");
    if getc(my_file) <> '\16#FEFF\' then
      # This is a file without BOM (the first character will be read later).
      seek(my_file, 1);
    end if;
    ...

  UTF-16 comes in two flavors UTF-16LE and UTF-16BE. To support
  both flavors the "utf16.s7i" library defines several functions.

  The function 'open_utf16' opens an Unicode file which uses the
  UTF-16LE or UTF-16BE encoding. The function 'open_utf16' checks for
  a BOM and depending on that it opens an UTF-16LE or UTF-16BE file.

  The functions 'open_utf16le' and 'open_utf16be' open Unicode files
  with the UTF-16LE and UTF-16BE encoding respectively. When the
  file is opened with one of the modes "w", "w+", "wt" or "wt+" an
  appropriate BOM is created. When the file is opened with any other
  mode the application program is in charge to handle optional BOM
  markers. This way 'open_utf16le' and 'open_utf16be' can be used
  to open existing files without BOM.

  External BYTE files use the implementation type 'external_file'.
  The type 'external_file' is defined as:

    const type: external_file is sub null_file struct
        var PRIMITIVE_FILE: ext_file is PRIMITIVE_null_file;
        var string: name is "";
      end struct;

  This means that every data item of the type 'external_file'
  has the elements from 'null_file' and additionally the
  elements 'ext_file' and 'name'. The type 'PRIMITIVE_FILE'
  points directly to an operating system file. Objects
  of type 'PRIMITIVE_FILE' can only have operating system
  files as values while objects of type 'file' can also have
  other files as values. To allow the implementation of the
  type 'external_file' several operations for the type
  'PRIMITIVE_FILE' are defined. But outside 'external_file' the
  type 'PRIMITIVE_FILE' and its operations should not be used.

  There are three predefined external files 'STD_IN', 'STD_OUT'
  and 'STD_ERR' which have the following declarations:

    const func external_file: INIT_STD_FILE (ref PRIMITIVE_FILE: primitive_file,
        in string: file_name) is func
      result
        var external_file: result is external_file.value;
      begin
        result.ext_file := primitive_file;
        result.name := file_name;
      end func;

    var external_file: STD_IN is  INIT_STD_FILE(PRIMITIVE_INPUT,  "STD_IN");
    var external_file: STD_OUT is INIT_STD_FILE(PRIMITIVE_OUTPUT, "STD_OUT");
    var external_file: STD_ERR is INIT_STD_FILE(PRIMITIVE_ERROR,  "STD_ERR");

  It is possible to do I/O directly with them, but it is more wisely
  to use them only to initialize user defined file variables as in:

    var file: err is STD_ERR;

  In the rest of the program references to such a variable can be
  used:

    writeln(err, "Some error occurred");

  In this case redirection of the file 'err' can be done very easy.
  Another way to access external files is to use the 'open'
  function. The modes used by 'open' differ from those used
  by the 'fopen' function in the C library.
  The following table compares the file modes of Seed7 and C:

    Seed7 'open' mode   C 'fopen' mode
    "r"                 "rb"
    "w"                 "wb"
    "a"                 "ab"
    "r+"                "rb+"
    "w+"                "wb+"
    "a+"                "ab+"
    "rt"                "r"
    "wt"                "w"
    "at"                "a"
    "rt+"               "r+"
    "wt+"               "w+"
    "at+"               "a+"

  The difference between binary and text mode is as follows:

    - Binary mode provides an implementation independent
      behavior on all operating systems. In binary mode no
      conversion to and from the line end character ('\n')
      is done. This has the advantage that an 'external_file'
      written in binary mode is identical on all operating
      systems. Reading files with different line endings
      ("\n" and "\r\n") is supported by every 'external_file':
      The functions 'getwd', 'getln', 'read' and 'readln', of
      'external_file' skip a carriage return ('\r') when it
      is just before a linefeed ('\n'). The rest of the
      'external_file' functions like 'getc' and 'gets' deliver
      line endings unchanged.

    - The behavior of an 'external_file' in text mode is
      implementation dependent. Under Unix/Linux/Bsd text and
      binary modes are identical. Other operating systems
      prefer to do some line end conversions in text mode:
      When reading a file all occurrences of "\r\n" are
      converted to '\n'. When writing to a file all
      occurrences of '\n' are converted to "\r\n". Note that
      text mode cannot be used to automatically create files
      with "\r\n" line endings under Unix/Linux/Bsd.

  The library "utf8.s7i" defines the
  implementation type 'utf8_file' as

    const type: utf8_file is sub external_file struct
      end struct;


8.7 Keyboard file

    As stated earlier 'STD_IN' provides an interface to the keyboard
  which is line buffered and echoed on 'STD_OUT'. This means that
  you can see everything you typed. Additionally you can correct
  your input with BACKSPACE until you press RETURN. But sometimes
  an unbuffered and unechoed input is needed. This is provided in
  the library "keybd.s7i", which defines the type 'keyboard_file'
  and the file 'KEYBOARD'. Characters typed at the keyboard are
  queued (first in first out) and can be read directly from
  'KEYBOARD' without any possibility to correct. Additionally
  'KEYBOARD' does not echo the characters. Reading from 'KEYBOARD'
  delivers normal Unicode characters or special codes (which may be
  or may not be Unicode characters) for function and cursor keys.
  Unicode characters and special codes both are 'char' values. The
  library "keybd.s7i" defines 'char' constants for various keys:

    Key character constant     Description
    KEY_CTL_A to KEY_CTL_Z     The control keys ctrl-a to ctrl-z
    KEY_ALT_A to KEY_ALT_Z     The alternate keys alt-a to alt-z
    KEY_ALT_0 to KEY_ALT_9     The alternate keys alt-0 to alt-9
    KEY_F1 to KEY_F10          Function keys F1 to F10
    KEY_SFT_F1 to KEY_SFT_F10  Shifted function keys F1 to F10
    KEY_CTL_F1 to KEY_CTL_F10  Control function keys F1 to F10
    KEY_ALT_F1 to KEY_ALT_F10  Alternate function keys F1 to F10
    KEY_BS                     Backspace (equal to KEY_CTL_H)
    KEY_TAB                    Horizontal Tab (equal to KEY_CTL_H)
    KEY_NL                     Newline/Enter/Return key (equal to KEY_CTL_J)
    KEY_CR                     Carriage return (equal to KEY_CTL_M)
    KEY_ESC                    Escape key
    KEY_NULCHAR                Nul character key
    KEY_BACKTAB                Horizontal back tab
    KEY_LEFT                   Cursor left
    KEY_RIGHT                  Cursor right
    KEY_UP                     Cursor up
    KEY_DOWN                   Cursor down
    KEY_HOME                   Home key
    KEY_END                    End key
    KEY_PGUP                   Page up
    KEY_PGDN                   Page down
    KEY_INS                    Insert key
    KEY_DEL                    Delete key
    KEY_PAD_CENTER             Numeric keypad center key
    KEY_CTL_LEFT               Control cursor left
    KEY_CTL_RIGHT              Control cursor right
    KEY_CTL_UP                 Control cursor up
    KEY_CTL_DOWN               Control cursor down
    KEY_CTL_HOME               Control home key
    KEY_CTL_END                Control end key
    KEY_CTL_PGUP               Control page up
    KEY_CTL_PGDN               Control page down
    KEY_CTL_INS                Control insert key
    KEY_CTL_DEL                Control delete key
    KEY_SCRLUP                 Scroll up key
    KEY_SCRLDN                 Scroll down key
    KEY_INSLN                  Insert line key
    KEY_DELLN                  Delete line key
    KEY_ERASE                  Erase key
    KEY_CTL_CR                 Control carriage return
    KEY_NULLCMD                Null command of window manager
    KEY_REDRAW                 Redraw command of window manager
    KEY_NEWWINDOW              New window command of window manager
    KEY_MOUSE1                 Mouse key 1 (counted from left)
    KEY_MOUSE2                 Mouse key 2 (counted from left)
    KEY_MOUSE3                 Mouse key 3 (counted from left)
    KEY_MOUSE4                 Mouse key 4 (counted from left)
    KEY_MOUSE5                 Mouse key 5 (counted from left)
    KEY_UNDEF                  Undefined key
    KEY_NONE                   No key pressed (returned by busy_getc)

  The following example uses the 'char' constant 'KEY_UP':

    $ include "seed7_05.s7i";
      include "keybd.s7i";

    const proc: main is func
      begin
        writeln("Please press cursor up");
        while getc(KEYBOARD) <> KEY_UP do
          writeln("This was not cursor up");
        end while;
        writeln("Cursor up was pressed");
      end func;

  Programs should use the 'char' constants defined in "keybd.s7i"
  to deal with function and cursor keys, since the special key
  codes may change in future versions of Seed7.

  Additionally to the operations possible with a 'file' there
  are two functions that are applicable only to files of type
  'keyboard_file':

    - 'busy_getc', which delivers the next character
      from the keyboard or 'KEY_NONE' if no key has been pressed.
    - 'keypressed', which returns TRUE if a character
      is available from the keyboard and FALSE otherwise.

  Note that 'keypressed' does not actually read a character. Reading
  must be done with a different function after 'keypressed' returns
  TRUE. Both functions ('busy_getc' and 'keypressed') are useful
  when user input is allowed while some processing takes place.
  The following program uses 'busy_getc(KEYBOARD)' to display
  the time until a key is pressed:

    $ include "seed7_05.s7i";
      include "time.s7i";
      include "keybd.s7i";

    const proc: main is func
      begin
        writeln;
        while busy_getc(KEYBOARD) = KEY_NONE do
          write(time(NOW) <& "\r");
          flush(OUT);
        end while;
        writeln;
        writeln;
      end func;

  Seed7 programs can run in two modes:

    - Console mode, where the program runs in a console/terminal window (the default).
    - Graphics mode, where the program has its own graphic window.

  This two modes are supported with two basic keyboard files:

    - 'CONSOLE_KEYBOARD', which uses a terminfo or console driver.
    - 'GRAPH_KEYBOARD', which uses a X11 or GDI driver.

  The file 'KEYBOARD' is actually a variable which refers to one
  of the two basic keyboard files.  The declaration of the type
  'keyboard_file' and the file 'KEYBOARD' in "keybd.s7i" is:

    const type: keyboard_file is subtype file;

    var keyboard_file: KEYBOARD is CONSOLE_KEYBOARD;

  Graphic programs switch to to the 'GRAPH_KEYBOARD' driver with:

    KEYBOARD := GRAPH_KEYBOARD;

  Some file types are defined to support the 'KEYBOARD'. One such
  file type is 'echo_file', which is defined in the library "echo.s7i".
  An 'echo_file' file can be used to write input characters to
  an output file. This is useful since 'KEYBOARD' does not echo its
  input, but 'echo_file' is not restricted to support 'KEYBOARD'.
  The following program writes echoes of the keys typed and exits as
  soon as a '!' is encountered:

    $ include "seed7_05.s7i";
      include "keybd.s7i";
      include "echo.s7i";

    const proc: main is func
      local
        var char: ch is ' ';
      begin
        IN := open_echo(KEYBOARD, OUT);
        repeat
          ch := getc(IN);
        until ch = '!';
        writeln;
      end func;

  An 'echo_file' checks also for control-C (KEY_CTL_C). When
  control-C is typed an 'echo_file' asks if the program should be
  terminated:

    terminate (y/n)?

  Answering 'y' or 'Y' is interpreted as 'yes' and the program
  is terminated with the following message:

    *** PROGRAM TERMINATED BY USER

  Any other input removes the question and the program continues
  to read input.
  
  Another helpful file type is 'line_file', which is defined in the
  library "line.s7i". A 'line_file' allows to correct the input with
  BACKSPACE until a RETURN (represented with '\n') is encountered.
  In contrast to this editing feature the possibility to edit a line
  of 'STD_IN' is provided by the operating system. The following
  program uses 'echo_file' and 'line_file' to simulate input line
  editing:

    $ include "seed7_05.s7i";
      include "keybd.s7i";
      include "echo.s7i";
      include "line.s7i";

    const proc: main is func
      local
        var char: ch is ' ';
      begin
        IN := open_echo(KEYBOARD, OUT);
        IN := open_line(IN);
        repeat
          ch := getc(IN);
          write(ch);
        until ch = '!';
      end func;

  This program terminates when a line containing '!' is confirmed
  with RETURN.


8.8 Files with line structure

  The library "text.s7i" defines the type 'text', which is a
  subtype of 'file'. The type 'text' adds a line structure and
  other features such as scrolling and color to 'file'. The
  lines and columns of a 'text' start with 1 in the upper left
  corner and increase downward and rightward. The function
  'setPos' sets the current line and column of a 'text':

    setPos(aText, 10, 20);

  The functions 'setLine' and 'setColumn' set just the
  line and column respectively:

    setLine(aText, 2);
    setColumn(aText, 72);

  The current line and column of a 'text' file can be retrieved
  with 'line' and 'column':

    writeln("The curent line is: " <& line(aText));
    writeln("The curent column is: " <& column(aText));

  The current height and width of a 'text' file can be retrieved
  with 'height' and 'width':

    writeln("The height is: " <& height(aText));
    writeln("The width is: " <& width(aText));

  To allow random access output to a text console (or text window)
  the library "console.s7i" defines the type 'console_file'. The function

    open(CONSOLE)

  returns a 'console_file'.


8.9 Sockets

    The library "socket.s7i" defines types and functions to
  access sockets. The implementation type for sockets is
  'socket'. As interface type 'file' is used:

    var file: clientSocket is STD_NULL;

  With 'openInetSocket' an Internet client socket can be opened:

    clientSocket := openInetSocket("www.google.com", 80);

  The function 'openInetSocket' creates and connects a socket.
  Opening an Internet socket at the local host is also done with
  a variant of 'openInetSocket':

    clientSocket := openInetSocket(1080);

  Since sockets use the 'file' interface functions
  like 'writeln' and 'getln' can be used:

    sock := openInetSocket(serverName, 80);
    if sock <> STD_NULL then
      writeln(sock, "GET " <& address <& " HTTP/1.1");
      writeln(sock, "Host: " <& hostname);
      writeln(sock, "User-Agent: BlackHole");
      writeln(sock);
      line := getln(sock);
      if startsWith(line, "HTTP") then
        statusInfo := trim(line[pos(line, " ") ..]);
        statusCode := statusInfo[.. pred(pos(statusInfo, " "))];
      end if;
    end if;

  The example above sends a HTTP request to a server and gets
  the status code from the response. The example above consists
  of code from the library "gethttp.s7i".

  Server sockets are supported with the type 'listener'.
  A listener is defined with:

    var listener: myListener is listener.value;

  The library "listener.s7i" defines the function 'openInetListener',
  which opens a 'listener':

    aListener := openInetListener(1080);

  The function 'listen' is used to listen for incoming socket
  connections of a 'listener', and to
  limit the incoming queue:

    listen(aListener, 10);

  The function 'accept' returns the first connected socked
  of the 'listener':

    serverSocket := accept(aListener);

  Together the functions above can be use to process requests without sessions:

    aListener := openInetListener(1080);
    listen(aListener, 10);
    while TRUE do
      sock := accept(aListener);
      # Read and process the request from sock.
      close(sock);
    end while;

  A similar loop is used in the comanche webserver (see main function).
  The function 'waitForRequest' can be used to process requests with session:

    aListener := openInetListener(2021);
    listen(aListener, 10);
    while TRUE do
      waitForRequest(aListener, existingConnection, newConnection);
      if existingConnection <> STD_NULL then
        # Read and process the request from existingConnection.
      end if;
      if newConnection <> STD_NULL then
        # Send welcome message to newConnection.
      end if;
    end while;

  Similar code is used in the program "ftpserv.sd7".
  The implementation of 'waitForRequest' is based on 'pollData',
  which is defined in "poll.s7i".


8.10 User defined file types

    In addition to the predefined file types it is often
  necessary to define a new type of file. Such a new file
  has several possibilities:

    - It could store its contents in a string (not only to be
      faster but also to provide additional file operations)

    - The information can be processed (e.g. to upper case)
      and sent to another file.

    - It could work just like an Unix utility (Think of
      more, sort, tee, uniq ...)

    - It could provide a file-like interface for something
      with an other interface. (e.g. The contents of a
      directory, or random access I/O to the screen)

  With the following declaration we define a new file type:

    const type: NEW_FILE is sub null_file struct
        ...
        (* Local data *)
        ...
      end struct;

  It is not necessary to derive the NEW_FILE type directly from
  'null_file'. The NEW_FILE type may also be an indirect descendant
  of 'null_file'. So it is possible to create file type hierarchies.
  The interface implemented by the new file needs also to be specified:

    type_implements_interface(NEW_FILE, file);

  The type 'file' is not the only interface
  type which can be used. There is also the type 'text' which
  is derived from 'file'. The type 'text'
  describes a line oriented file which allows 'setPos' (which moves the
  current position to the line and column specified) and other functions.
  It is also possible to define new interface types which derive
  from 'file' or 'text'.

  As next an open function is needed to generate a new NEW_FILE:

    const func file: open_new_file (  (* Parameters *) ) is func
      result
        var file: result is STD_NULL;
      begin
        ...
        (* Initialization of the local data *)
        result := malloc( ... );
        ...
      end func;

  Note the usage of the 'malloc' function to generate a new data
  item. This data item is not freed automatically but if you
  do not open files to often this does not hurt. Now only the
  two basic I/O operations must be defined:

    const proc: write (inout NEW_FILE: new_fil, in string: stri) is func
      begin
        ...
        (* Statements that do the output *)
        ...
      end func;

    const proc: gets (inout NEW_FILE: new_fil, in integer: leng) is func
      result
        var string: stri is "";
      begin
        ...
        (* Statements that do the input *)
        ...
      end func;


8.11 Scanning a file

    The I/O concept introduced in the previous chapters separates
  the input of data from its conversion. The 'read', 'readln',
  'getwd' and 'getln' functions are designed to read whitespace
  separated data elements. When the data elements are not separated
  by whitespace characters this I/O concept is not possible.
  Instead the functions which read from the file need some
  knowledge about the type which they intend to read. Fortunately
  this is a well researched area. The lexical scanners used by
  compilers solve exactly this problem.

  Lexical scanners read symbols from a file and use the concept of
  a current character. A symbol can be a name, a number, a string,
  an operator, a parenthesis or something else. The current
  character is the first character to be processed when scanning a
  symbol. After a scanner has read a symbol the current character
  contains the character just after the symbol. This character
  could be the first character of the next symbol or some
  whitespace character. If the set of symbols is chosen wisely all
  decisions about the type of the symbol and when to stop reading
  characters for a symbol can be done based on the current
  character.

  Every 'file' contains a 'bufferChar' variable which is used as
  current character by the scanner functions defined in the
  "scanfile.s7i" library. The "scanfile.s7i" library contains
  skip... and get... functions. The skip... procedures return void
  and are used to skip input while the get... functions return the
  string of characters they have read. The following basic scanner
  functions are defined in the "scanfile.s7i" library:

    skipComment
      Skips a possibly nested comment from a 'file'.
    getComment
      Reads a possibly nested comment from a 'file'.
    skipLineComment
      Skips a line comment from a 'file'.
    getLineComment
      Reads a line comment from a 'file'.
    getDigits
      Reads a sequence of digits from a 'file'.
    getNumber
      Reads a numeric literal from a 'file'.
    getNonDigits
      Reads a sequence of non digits from a 'file'.
    getQuotedText
      Reads a text quoted with " or ' from a 'file'.
    getCharLiteral
      Reads a character literal from a 'file'.
    getStringLiteral
      Reads a string literal from a 'file'.
    getName
      Reads an alphanumeric name from a 'file'.

  Contrary to 'read' and 'getwd' basic scanner functions
  do not skip leading whitespace characters. To skip whitespace
  characters one of the following functions can be used:

    skipSpace
      Skips space characters from a 'file'.
    skipWhiteSpace
      Skips whitespace characters from a 'file'.
    getWhiteSpace
      Reads whitespace characters from a 'file'.
    getWord
      Reads a white space delimited word from a 'file'.
    skipLine
      Skips a line from a 'file'.
    getLine
      Reads a line from a 'file'.

  The advanced scanner functions do skip whitespace characters
  before reading a symbol:

    getSymbolOrComment
      Reads a symbol or a comment from a 'file'.
    getSymbol
      Reads a symbol from a 'file'.
    getSymbolWithHtmlEntities
      Reads a symbol, where html entities are allowed, from a 'file'.
    getHtmlTagSymbolOrComment
      Reads a HTML tag, a symbol or a comment from a 'file'.
    skipXmlComment
      Skips a XML comment from a 'file'.
    getXmlTagOrContent
      Reads a XML/HTML tag or the XML/HTML content text from a 'file'.
    getXmlCharacterReference
      Reads a predefined XML entity from a 'file'.
    getXmlTagHeadOrContent
      Reads a XML/HTML tag head or a XML/HTML content from a 'file'.
    getSymbolInXmlTag
      Reads a symbol which can appear inside a XML/HTML tag from a 'file'.
    getNextXmlAttribute
      Reads name and value of an attribute inside a XML tag from 'file'.
    getHtmlAttributeValue
      Reads a HTML tag attribute value from a 'file'.
    getNextHtmlAttribute
      Reads name and value of an attribute inside a HTML tag from a 'file'.
    getSimpleSymbol
      Reads a simple symbol from a 'file'.

  All scanner functions assume that the first character to be
  processed is in 'bufferChar' and after they are finished the next
  character which should be processed is also in 'bufferChar'.
  To use scanner functions for a new opened file it is necessary to
  assign the first character to the 'bufferChar' with:

    myFile.bufferChar := getc(myFile);

  In most cases whole files are either processed with normal I/O
  functions or with scanner functions. When normal I/O functions
  need to be combined with scanner functions care has to be taken:

    - When the last function which read from a file was
      one of 'read', 'readln', 'getwd' or 'getln'
      the 'bufferChar' already contains the character which
      should be processed next and therefore subsequent scanner
      functions can be used.

    - Other I/O functions like 'getc' and 'gets'
      do not assign something to 'bufferChar'. In this
      case something should be assigned to 'bufferChar'.

    - Switching back from scanner functions to
      normal I/O functions is best done when the content of
      'bufferChar' is known. For example at the end
      of the line.

  Scanner functions are helpful when it is necessary to read
  numeric input without failing when no digits are present:

    skipWhiteSpace(IN);
    if eoln(IN) then
      writeln("empty input");
    elsif IN.bufferChar in {'0' .. '9'} then
      number := integer parse getDigits(IN);
      skipLine(IN);
      writeln("number " <& number);
    else
      stri := getLine(IN);
      writeln("command " <& literal(stri));
    end if;

  The function 'getSymbol' is designed to read Seed7 symbols. When
  the end of the file is reached it returns "".
  With 'getSymbol' name-value pairs can be read:

    name := getSymbol(inFile);
    while name <> "" do
      if name <> "#" and getSymbol(inFile) = nt color=maroon>"="/font> then
        aValue = getSymbol(inFile);
        if aValue <> "" then
          if aValue[1] = '"' then
            keyValueHash @:= [name] aValue[2 ..];
          elsif aValue[1] in {'0' .. '9'} then
            keyValueHash @:= [name] aValue;
          end if;
        end if;
      end if;
    end while;

  The following loop can be used to process the symbols of a Seed7 program:

    inFile.bufferChar := getc(inFile);
    currSymbol := getSymbol(inFile);
    while currSymbol <> "" do
      ... process currSymbol ...
      currSymbol := getSymbol(inFile);
    end while;

  Whitespace and comments are automatically skipped with the
  function 'getSymbol'. When comments should also be returned the
  function 'getSymbolOrComment' can be used. Together with the
  function 'getWhiteSpace' it is even possible to get the
  whitespace between the symbols:

    const func string: processFile (in string: fileName) is func
      result
        var string: result is "";
      local
        var file: inFile is STD_NULL;
        var string: currSymbol is "";
      begin
        inFile := open(fileName, "r");
        if inFile <> STD_NULL then
          inFile.bufferChar := getc(inFile);
          result := getWhiteSpace(inFile);
          currSymbol := getSymbolOrComment(inFile);
          while currSymbol <> "" do
            result &:= currSymbol;
            result &:= getWhiteSpace(inFile);
            currSymbol := getSymbolOrComment(inFile);
          end while;
        end if;
      end func;

  In the example above the function 'processFile' gathers all
  symbols, whitespace and comments in the string it returns. The
  string returned by 'processFile' is equivalent to the one
  returned by the function 'getf'. That way it is easy to test
  the scanner functionality.

  The logic with 'getWhiteSpace' and 'getSymbolOrComment' can be used
  to add HTML tags to comments and literals. The following function
  colors comments with green, string and char literals with maroon and
  numeric literals with purple:

    const proc: sourceToHtml (inout file: inFile, inout file: outFile) is func
      local
        var string: currSymbol is "";
      begin
        inFile.bufferChar := getc(inFile);
        write(outFile, "<pre>\n");
        write(outFile, getWhiteSpace(inFile));
        currSymbol := getSymbolOrComment(inFile);
        while currSymbol <> "" do
          currSymbol := replace(currSymbol, "&", "&amp;");
          currSymbol := replace(currSymbol, "<", "&lt;");
          if currSymbol[1] in {'"', '''} then
            write(outFile, "<font color=\"maroon\">");
            write(outFile, currSymbol);
            write(outFile, "</font>");
          elsif currSymbol[1] = '#' or startsWith(currSymbol, "(*") then
            write(outFile, "<font color=\"green\">");
            write(outFile, currSymbol);
            write(outFile, "</font>");
          elsif currSymbol[1] in digit_char then
            write(outFile, "<font color=\"purple\">");
            write(outFile, currSymbol);
            write(outFile, "</font>");
          else
            write(outFile, currSymbol);
          end if;
          write(outFile, getWhiteSpace(inFile));
          currSymbol := getSymbolOrComment(inFile);
        end while;
        write(outFile, "</pre>\n");
      end func;

  The functions 'skipSpace' and 'skipWhiteSpace' are defined in
  the "scanfile.s7i" library as follows:

    const proc: skipSpace (inout file: inFile) is func
      local
        var char: ch is ' ';
      begin
        ch := inFile.bufferChar;
        while ch = ' ' do
          ch := getc(inFile);
        end while;
        inFile.bufferChar := ch;
      end func;

    const proc: skipWhiteSpace (inout file: inFile) is func
      begin
        while inFile.bufferChar in white_space_char do
          inFile.bufferChar := getc(inFile);
        end while;
      end func;

  The functions 'skipComment' and 'skipLineComment', which can be
  used to skip Seed7 comments, are defined as follows:

    const proc: skipComment (inout file: inFile) is func
      local
        var char: character is ' ';
      begin
        character := getc(inFile);
        repeat
          repeat
            while character not in special_comment_char do
              character := getc(inFile);
            end while;
            if character = '(' then
              character := getc(inFile);
              if character = '*' then
                skipComment(inFile);
                character := getc(inFile);
              end if;
            end if;
          until character = '*' or character = EOF;
          if character <> EOF then
            character := getc(inFile);
          end if;
        until character = ')' or character = EOF;
        if character = EOF then
          inFile.bufferChar := EOF;
        else
          inFile.bufferChar := getc(inFile);
        end if;
      end func; # skipComment

    const proc: skipLineComment (inout file: inFile) is func
      local
        var char: character is ' ';
      begin
        repeat
          character := getc(inFile);
        until character = '\n' or character = EOF;
        inFile.bufferChar := character;
      end func; # skipLineComment




9. STRUCTURED SYNTAX DEFINITION
===============================

    Most programming languages have only predefined constructs like
  statements and operators. Seed7, on the other hand, additionally
  allows user defined constructs. This chapter introduces the Seed7
  Structured Syntax Description (S7SSD) which is used to define the
  syntax of new constructs. The syntax of predefined constructs is
  also defined with S7SSD.

    The syntax descriptions used in manuals of conventional
  programming languages have no relationship to the approach used by
  the syntax analysis of the corresponding interpreters/compilers.
  S7SSD is a simple syntax description that can be used by humans
  and compilers/interpreters. Although compiler-compilers follow the
  path of machine readable syntax descriptions, they use much more
  complicated syntax and semantic descriptions and do not allow
  users of the language to define new constructs.

    There are different existing notations to specify the syntax of
  programming languages. Backus-Naur Form (BNF) and its variants
  like Extended Backus-Naur Form (EBNF) are examples of such syntax
  specifications. Since it is easier to understand new concepts when
  they are compared to well known concepts, EBNF will be used as a
  base to explain S7SSD.


9.1 The Extended Backus-Naur Form

    As the name says the Extended Backus-Naur Form is an extension
  of BNF. The extension allows the definition of repetitions and
  optional parts without the use of recursion. EBNF has the
  following elements:

    - Nonterminal symbols consist of lower case letters and
      underline characters.

    - Terminal symbols are quoted strings or names in upper case
      characters which describe unprintable characters (control
      characters).

    - The concatenation of nonterminal and/or terminal symbols is
      described by writing them in sequence.

    - With | two alternatives can be separated.

    - Expressions of the extended Backus-Naur form can be put within
      parentheses ( ... ) .

    - When an expression is optional it is enclosed in square
      brackets [ ... ] .

    - When an expression may be omitted or repeated it is
      enclosed in curly braces { ... } .

  The syntax of the extended Backus-Naur form can be described in
  extended Backus-Naur form:

    syntax_description ::=
      { statement } .

    statement ::=
      identifier '::=' expression '.' .

    expression ::=
      term { '|' term } .

    term ::=
      factor { factor } .

    factor ::=
      identifier | string | '(' expression ')' |
      '[' expression ']' | '{' expression '}' .


9.2 The syntax of a statement

    To explain the Seed7 Structured Syntax Description we design a
  new statement, the 'loop' statement. The 'loop' statement should
  be similar to 'while' and 'repeat' loops but instead of having
  the conditional exit at the beginning or at the end, it should
  have a conditional exit in the middle of the loop. This middle
  conditional exit should be part of the 'loop' statement. Note that
  the 'break' statement, which exists in some programming languages,
  is a statement on its own and is not part of the loop which it
  leaves. Therefore the middle conditional exit should not be
  confused with a 'break' statement. An example of the new 'loop'
  statement is:

    loop
      ch := getc(inFile);
    until ch = '\n' do
      stri &:= str(ch);
    end loop;

  The 'loop' example above reads characters from a file and
  concatenates them to a string until the character '\n' is read.
  The '\n' ends the loop. Hence it is not added to the string.
  An equivalent solution without the usage of the 'loop' statement
  would be:

    repeat
      ch := getc(inFile);
      if ch <> '\n' then
        stri &:= str(ch);
      end if;
    until ch = '\n';

  The S7SSD of the 'loop' statement is:

    $ syntax expr: .loop.().until.().do.().end.loop   is -> 25;

  The details of the S7SSD 'syntax' definition will be explained
  later. For now we concentrate at the heart of the S7SSD, the
  expression:

    .loop.().until.().do.().end.loop

  For the purpose of the syntax description we can just remove the
  dots, which gives:

     loop () until () do () end loop

  This are the keywords used in a 'loop' statement. The symbol ()
  acts as placeholder for an expression.
  With EBNF the 'loop' statement can be described as:

    loop_statement ::=
      'loop'
        statement
      'until' expression 'do'
        statement
      'end' 'loop' .

  An EBNF description may use many nonterminal symbols such as
  'statement' or 'expression'. S7SSD does not distinguish
  between different nonterminal symbols. Instead S7SSD only
  knows one nonterminal symbol: ()

  Therefore S7SSD cannot distinguish between 'statement',
  'expression' or something else. At the syntax level any kind of
  expression can by substituted for a S7SSD nonterminal symbol ().
  With EBNF it is possible to describe constraints such as the type
  of an expression. S7SSD relies on semantic checks to verify
  such constraints. Given the S7SSD of the 'loop' statement an
  expression like

    loop
      "X"
    until 1+2 do
      integer
    end loop

  would be legal as it contains the required keywords

   loop  until  do  end  loop

  and the expressions

    "X"  1+2  integer

  at the places of the () symbols. This is exactly what the syntax
  definition specifies, but it would be not be considered correct
  given the description of the 'loop' statement at the beginning of
  the chapter. To determine which types of expressions are allowed
  at the places of the () symbol, a semantic definition of the
  'loop' statement is necessary. A semantic definition is just a
  function definition which uses the keywords and parameters from
  the syntax definition. The definition of the 'loop' function
  (semantic definition of the 'loop' statement) is:

    const proc: loop
                  (in proc: statements1)
                until (ref func boolean: condition) do
                  (in proc: statements2)
                end loop is func
      local
        var boolean: exitLoop is FALSE;
      begin
        repeat
          statements1;
          if not condition then
            statements2;
          else
            exitLoop := TRUE;
          end if;
        until exitLoop;
      end func;

  This definition determines the types of the expressions accepted
  between the keywords. Besides that the semantic definition of the
  'loop' statement is just a normal function definition. Note that
  the sequence of keywords and parameters in the header of this
  function definition is determined by the corresponding syntax
  definition.

  The parameters 'statements1', 'condition' and 'statements2' are
  call-by-name parameters. A call-by-name parameter is a function
  without parameters. Function types such as 'proc' or 'func boolean'
  are used as type of formal call-by-name parameters. An expression
  with the correct type is allowed as actual call-by-name parameter.
  This actual parameter expression is not evaluated when the
  function is called. Instead the expression is evaluated every time
  the formal call-by-name parameter is used. This way 'statements1',
  'condition' and 'statements2' are not executed when the 'loop'
  function is called. Inside the body of the 'loop' function the
  call-by-name parameters are executed at some places.

  The 'loop' function uses a 'repeat' and an 'if' statement to
  implement the desired behavior. When necessary the call-by-name
  parameters are executed several times.

  For the 'loop' example with the semantic errors (see above) we
  would get an error message like:

    *** chkloop.sd7(35):51: Match for {loop "X" until {1 + 2 } do integer end loop } failed


9.3 Priority and associativity

    When a syntax construct has parameters before the first symbol
  or after the last symbol the priority and the associativity of the
  construct are significant. Constructs with stronger priority bind
  their parameters earlier than constructs with weaker priority. The
  priority is described by a natural number (inclusive 0). The
  strongest priority is 0. Weaker priorities are described by larger
  numbers. What bind means is can be explained with an example:

                                      =
    A = B + C * D                    / \
                                    A   +
    * priority  6                      / \
    + priority  7                     B   *
    = priority 12                        / \
                                        C   D

  The * operator has the strongest priority (6) of all operators
  involved. Therefore the * takes its parameters first. Then
  the + (with priority 7) and at last the = (with priority 12)
  follows. This leads to the the following interpretation of
  the expression:

    A = (B + (C * D))

  The associativity describes, in which order constructs with equal
  priority bind their parameters. For example

    A - B - C

  can be interpreted in two ways:

    (A - B) - C    or   A - (B - C)

  The first interpretation is usually preferred by mathematicians
  and is described with the associativity -> . Generally four
  associativities are possible:
                                                   Symbol

    Binding from left to right                       ->

    Binding from right to left                       <-

    Neither the left nor the right parameter
    are allowed to have the same priority            <->

    At the left side there is a binding from
    left to right and at the right side there
    is a binding from right to left                 -><-

  The last two possibilities give no legal interpretation in the
  subtraction example. The third kind of associativity ( <-> ) is
  used by the equal operator ( = ) of Pascal because there a
  expression like

    A = B = C

  is not legal.

  There is a second way to describe the associativity. The
  associativity describes if an operand must have a stronger
  priority than the priority of the operator. For example:

                             -                     7
    A - B - C              /   \                 /   \
                          /     \           <=7 /     \ <7
    - priority 7 ->      /       \             /       \
                        -         C           7         0
                      /   \                 /   \
                     /     \           <=7 /     \ <7
                    /       \             /       \
                   A         B           0         0

  The numbers in the nodes of the right tree show the priority of
  each sub expression (sub tree). With < and <= the required
  condition for the priority of an operand is described. An
  interpretation is legal if all this conditions are met. If there
  are more than one legal interpretations or no legal
  interpretation the expression is illegal.

  Table for the possibilities of associativity:

    +---------------+----------------------------------------------+
    | associativity |             The priority of the              |
    +               +----------------------+-----------------------+
    |               | left operand must be | right operand must be |
    +---------------+----------------------+-----------------------+
    |      ->       |          <=          |          <            |
    |      <-       |          <           |          <=           |
    |      <->      |          <           |          <            |
    |     -><-      |          <=          |          <=           |
    +---------------+----------------------+-----------------------+
    |               |          than that of the operator           |
    +---------------+----------------------------------------------+

  The parameter before the operator symbol is called left operand.
  The parameter after the last symbol of a construct is called
  right operand. In case of normal operators the last symbol of a
  construct and the operator symbol are identical. If this is not
  the case there is a third kind of operand. Between the operator
  symbol and the last symbol of a construct are the middle operands.
  Middle operands can have any priority.


9.4 The syntax of operators

    A syntax definition specifies the way a usage of a statement
  or operator must be written. For example a call of the
  'not' operator looks like:

    not okay

  To describe the syntax of the 'not' operator we write:

    $ syntax expr: .not.() is <- 13;

  This means that a 'not' expression is constructed with the
  symbol 'not' followed by a parameter. The place of the
  parameter is marked with the () sign. The syntax description
  contains no information about the types of the parameters. At
  the syntax level a parameter may be anything. With '<-' the
  associativity of the 'not' operator is specified as right
  associative. This means that the right operand is allowed to
  have the same priority as the operator symbol. So the
  expression

    not not okay

  is legal and means

    not (not okay)

  When the associativity of the 'not' operator is specified with
  '->' instead of '<-' the 'not not' expression above is not legal.
  With 13 the priority of the whole 'not' operator is determined.
  As convention priorities from 1 to 20 are used by operators
  and priority 25 is used by statements. Arithmetic operators
  have priorities from 1 to 11 and comparisons have priority 12.

  To define the 'not' operator completely there must be also
  a semantic definition which is as follows:

    const func boolean: not (in boolean: aBool) is func
      result
        var boolean: result is FALSE;
      begin
        if aBool then
          result := FALSE;
        else
          result := TRUE;
        end if;
      end func;

  In the declaration the 'not' operator is written exactly
  in the same way it is written when it is called. The syntax
  definition is used at both places: declaration and call.
  The syntax and semantic declarations define precisely how
  the 'not' operator works.

    As next example we try an infix operator like the 'and' operator.
  A call of the 'and' operator may look like:

    okay and not error

  To describe the syntax of the 'and' operator we write:

    $ syntax expr: .().and.() is    -> 14;

  This means that an 'and' expression is constructed with the
  symbol 'and' surrounded by parameters. The '->' defines the
  'and' operator as left associative. This means that an expression
  like

    A and B and C

  is interpreted as

    (A and B) and C

  With 14 the priority of the whole 'and' operator is determined.
  Since priority 14 is weaker than the priority of the 'not' operator
  which is 13 the example expression is evaluated as:

    okay and (not error)

  Note that the expression

    okay and not error

  makes no sense when the 'and' operator has priority 12 instead of 14.

  S7SSD treats everything as operator description. Operators
  have priority and associativity. The priority and associativity
  determine in which succession S7SSD syntax rules get applied.
  To explain priority and associativity we use the basic arithmetic
  operations (+,-,*,/). To describe them with EBNF we can write:

    factor :=
      number | name .

    expression_5 ::=
      factor |
      ( '+' expression_5 ) |
      ( '-' expression_5 ) .

    expression_6 ::=
      expression_5 |
      ( expression_6 '*' expression_7 ) |
      ( expression_6 '/' expression_7 ) .

    expression_7 ::=
      expression_6 |
      ( expression_7 '+' expression_6 ) |
      ( expression_7 '-' expression_6 ) .

  This describes the following things:

    - The operators have different priorities:
      - Plus and minus signs are executed first
      - Multiplication and division are executed second.
      - Addition and subtraction are executed last.

    - These priorities are exactly what we expect from an
      arithmetic expression.

    - Additionally we see that ++2 is allowed and interpreted as
      +(+(2)) which means that the plus sign is a right-associative
      operator.

    - We can also see that a*b*c is allowed and interpreted as
      (a*b)*c which means that the multiplication is a
      left-associative operator.

  All this things can also be described with S7SSD:

    $ syntax expr: . + .()      is <-  5;
    $ syntax expr: . - .()      is <-  5;
    $ syntax expr: .(). * .()   is  -> 6;
    $ syntax expr: .(). / .()   is  -> 6;
    $ syntax expr: .(). + .()   is  -> 7;
    $ syntax expr: .(). - .()   is  -> 7;

  As we can see S7SSD is shorter as the description with EBNF.
  A syntax statement is explained as follows:

    - The $ is used to introduce all hard coded statements.

    - The keyword 'syntax' introduces a structured syntax
      description.

    - The result of the recognized expression will have
      the type 'expr'. The type 'expr' is used between the syntax
      and the semantic analysis. The type 'expr' describes
      expressions which are syntactically analyzed but not
      semantically analyzed. After the semantic analysis (and
      during the runtime) the type 'expr' is not used.

    - The colon ':' is used as separator between type and syntax
      description.

    - A dot expression like '.(). * .()' is introduced (as can
      probably be guessed by the name) with a dot. For the purpose
      of the syntax description we can just remove the dots in
      our mind: '() * ()'

    - The symbol 'is' is used in all Seed7 declarations as
      separator between the name and the value.

    - The associativity is described with one of the symbols
      -> (left-associative), <- (right-associative),
      <-> (not associative) and -><- (both associativities).
      When there are no left or right operands, as it is the case
      for the 'loop' statement, the associativity is irrelevant.

    - Finally the priority of the syntax construct is defined with
      a integer literal like '6'. The priority '6' is used for the
      operators '*', '/', 'div', 'rem', 'mdiv' and 'mod'.


9.5 Syntax of predefined statements

    Predefined statements can also be defined with S7SSD.
  E.g.: The 'while' statement. A use of the 'while' statement is:

    while element_index > 0 and okay do
      processElement;
      write(".");
    end while;

  To describe the syntax of the 'while' statement we write:

    $ syntax expr: .while.().do.().end.while is -> 25;

  This means that the 'while' statement is an expression with the
  symbols 'while', 'do', 'end' and 'while'. With '->' the
  associativity of the 'while' statement is specified as left
  associative. The associativity has no meaning for the
  'while' statement since there is no parameter before the first
  symbol or after the last symbol. The priority of the whole
  'while' statement is 25.

  The semantic definition of the 'while' statement is as follows:

    const proc: while (ref func boolean: condition) do
        (ref proc: statement) end while is func
      begin
        if condition then
          statement;
          while condition do
            statement;
          end while;
        end if;
      end func;

  The syntax definition is used for the declaration and for the call.
  This declaration defines precisely how the 'while' statement
  works. It is based on the 'if' statement and uses recursion
  to emulate the repetition of the loop body.
  Another example for a syntax description is the
  'repeat' statement

    repeat
      processElement;
      write(".");
    until element_index = 0 or not okay;

  which has the following syntax description:

    $ syntax expr: .repeat.().until.() is -> 25;

  This means that the 'repeat' statement is an expression with
  the symbols 'repeat' and 'until' and a parameter between
  'repeat' and 'until' and after 'until'. With 25 the priority
  of the whole 'repeat' statement is determined. With '->' the
  associativity of the 'repeat' statement is specified as left
  associative. This allows priorities from 0 to 24 for the
  parameter after 'until'. Since statements have priority 25
  it is not possible to write a statement direct behind 'until'.

  A simple 'if' statement, without
  'elsif' part, is the next example.
  A usage of this 'if' statement might be:

    if okay then
      writeln("okay");
    else
      writeln("not okay");
    end if;

  As syntax description we use

    $ syntax expr: .if.().then.().end.if is            -> 25;
    $ syntax expr: .if.().then.().else.().end.if is    -> 25;

  Note that this description allows 'if' statements with and
  without 'else' parts. As semantic description we use

    const proc: if (in boolean: condition) then
                  (in proc: statement)
                end if is func
      begin
        case condition of
          when {TRUE}: statement;
        end case;
      end func;

    const proc: if (in boolean: condition) then
                  (in proc: statement1)
                else
                  (in proc: statement2)
                end if is func
      begin
        case condition of
          when {TRUE}:  statement1;
          when {FALSE}: statement2;
        end case;
      end func;

  The two forms of the 'if' statement are based on the
  'case' statement. A more complex 'if' statement with 'elsif'
  parts can be:

    if number < 0 then
      write("less");
    elsif number = 0 then
      write("equal");
    else
      write("greater");
    end if;

  How to define the syntax and the semantic for this statement
  is described in the next chapter.


9.6 Advanced syntax definitions

  When we want to use some special syntax which should be only
  allowed at some place we do the following:

    - Define the special syntax with S7SSD in a way that does not
      contradict with the rest of the syntax definitions.

    - Use semantic definitions to make sure that this syntax
      construct can only be used at the place desired.

  The EBNF of the 'if' statement with 'elsif' parts is:

    if_statement ::=
      'if' expression 'then'
        statement
      { 'elsif' expression 'then'
        statement }
      [ 'else'
        statement ]
      'end' 'if' .

  The S7SSD of this 'if' statement is:

    $ syntax expr : .if.().then.().end.if           is -> 25;
    $ syntax expr : .if.().then.().().end.if        is -> 25;

    $ syntax expr : .elsif.().then.()               is <- 60;
    $ syntax expr : .elsif.().then.().()            is <- 60;
    $ syntax expr : .else.()                        is <- 60;

  Instead of one rule (as EBNF does) the rule is broken into several
  S7SSD rules. This is necessary because S7SSD does not support the
  [ ] and { } notations. They are not supported for good reasons:
  They complicate the parameter lists and they are also not so easy
  to implement. On the other hand, the BNF like rules of S7SSD
  lead to semantic constructs which are easy to parse and easy to
  compile. The broken down S7SSD rules of the 'if' statement
  corresponds to the following EBNF description:

    if_statement ::=
      'if' expression 'then'
        statement
      'end' 'if' .

    if_statement ::=
      'if' expression 'then'
        statement
        elseif_or_else_part
      'end' 'if' .

    elseif_or_else_part ::=
      'elsif' expression 'then'
        statement .

    elseif_or_else_part ::=
      'elsif' expression 'then'
        statement
        elseif_or_else_part .

    elseif_or_else_part ::=
      'else'
        statement .

  Since S7SSD uses only one nonterminal symbol '()' it is the job
  of the semantic level to make sure that only the right nonterminal
  symbol can be used. This is done by introducing the type
  'ELSIF_PROC' (which corresponds to the nonterminal symbol
  'elseif_or_else_part' of the EBNF) and the type
  'ELSIF_RESULT' (which is the result
  of the 'ELSIF_PROC').

  Normally a syntax declaration can be used in many semantic
  declarations. E.g.: The syntax of the '+' operator is defined
  once and the semantic of the '+' operator is defined for the types
  'integer', 'bigInteger', 'float', 'complex', ... This possibility
  is not needed for the 'if' statement. For each of the five
  S7SSD syntax rules of the 'if' statement just one
  corresponding semantic declaration is done:

    # Semantic for the syntax: .if.().then.().end.if
    const proc: if (in boolean: condition) then
                  (in proc: statements)
                end if                                    is func
      begin
        case condition of
          when {TRUE}: statements;
        end case;
      end func;

    # Semantic for the syntax: .if.().then.().().end.if
    const proc: if (in boolean: condition) then
                  (in proc: statements)
                (in ELSIF_PROC: elsifPart)
                end if                                    is func
      begin
        case condition of
          when {TRUE}: statements;
          when {FALSE}: elsifPart;
        end case;
      end func;

    # Semantic for the syntax: .elsif.().then.()
    const ELSIF_PROC: elsif (in boolean: condition) then
                        (in proc: statements)             is func
      begin
        case condition of
          when {TRUE}: statements;
        end case;
      end func;

    # Semantic for the syntax: .elsif.().then.().()
    const ELSIF_PROC: elsif (in boolean: condition) then
                        (in proc: statements)
                      (in ELSIF_PROC: elsifPart)          is func
      begin
        case condition of
          when {TRUE}: statements;
          when {FALSE}: elsifPart;
        end case;
      end func;

    # Semantic for the syntax: .else.()
    const ELSIF_PROC: else
                        (ref void: voidValue)        is ELSIF_EMPTY;

  Since no other functions of type 'ELSIF_PROC' are defined only
  legal 'if' statements can be written.


9.7 Comparison of EBNF and S7SSD

  In the S7SSD of the 'loop' statement

    $ syntax expr: .loop.().until.().do.().end.loop is -> 25;

  are no nonterminal expressions '()' before the first keyword or
  after the last keyword. Therefore the associativity does not play
  any role. The nonterminal expressions '()' of the 'loop' statement
  are all surrounded by keywords and therefore they can have any
  priority. As priority of the 'loop' 25 is chosen just because
  most other statements have also priority 25. The assignments
  (:= +:= *:= ...) have priority 20 and all operators used in
  arithmetic, boolean and string expressions have priorities less
  than 20. BTW: The semicolon operator (;) is defined with the
  priority 50. Operators with a priority of 0 get their parameters
  before operators with priority 1 and so on.

  The corresponding EBNF description of the 'loop' statement would
  be:

    expression_25 ::=
      'loop'
        expression_127
      'until' expression_127 'do'
        expression_127
      'end' 'loop' .

  We must keep in mind that alternative rules for expression_25 are
  also possible and that for every priority level a rule like

    expression_127 ::= expression_126 .

  is defined. Additionally the following rules are defined:

    expression_0 ::= token | parentheses_expression |
      call_expression | dot_expression .

    token ::=
      identifier | literal .

    parentheses_expression ::=
      '(' expression_127 ')' .

    call_expression ::=
      expression_127 [ '('
      [ expression_127 { ',' expression_127 } ]
      ')' ] .

    dot_expression ::=
      [ '.' ] call_expression { '.' call_expression } .

  There are some things which are out of the scope of S7SSD.
  The syntax of tokens (whitespace, comments, identifiers and
  literals) and expressions (parentheses, function calls and dot
  expressions) is hard coded. The hard coded constructs are described
  in chapter 10 (Tokens) and chapter 11 (Expressions).

  For the reasons mentioned above it is not possible to transform
  every EBNF syntax description into S7SSD. Transforming S7SSD
  descriptions to EBNF is always possible.

  The advantage of S7SSD lies in its simplicity and that a fast
  automated syntax recognition algorithm can be easily implemented.
  It is exactly the combination of hard coded syntax recognition and
  flexible syntax rules that make it successful.



10. TOKENS
=========

    A program consists of a sequence of tokens which may be delimited
  by white space. There are two types of tokens:

    identifiers
    literals

  Syntax:

    program ::=
      { white_space | token } .

    token ::=
      identifier | literal .


10.1 White space

    There are three types of white space

    spaces
    comments
    line comments

  White space always terminates a preceding token. Some white
  space is required to separate otherwise adjacent tokens.

  Syntax:

    white_space ::=
      ( space | comment | line_comment )
      { space | comment | line_comment } .


10.1.1 Spaces

    There are several types of space characters which are ignored
  except as they separate tokens:

    blanks, horizontal tabs, carriage returns and new lines.

  Syntax:

    space ::=
      ' ' | TAB | CR | NL .


10.1.2 Comments

    Comments are introduced with the characters (* and are
  terminated with the characters *) . For example:

    (* This is a comment *)

  Comment nesting is allowed so it is possible to comment out
  larger sections of the program which can also include comments.
  Comments cannot occur within string or character literals.

  Syntax:

    comment ::=
      '(*' { any_character } '*)' .


10.1.3 Line comments

    Line comments are introduced with the character # and are
  terminated with the end of the line.
  For example:

    # This is a comment

  Comments cannot occur within string, character or numerical
  literals.

  Syntax:

    line_comment ::=
      '#' { any_character } NL .


10.2 Identifiers

    There are three types of identifiers

    name identifiers
    special identifiers
    parenthesis

  Identifiers can be written adjacent except that between two
  name identifiers and between two special identifiers white space
  must be used to separate them.

  Syntax:

    identifier ::=
      name_identifier | special_identifier | parenthesis .


10.2.1 Name identifiers

    A name identifier is a sequence of letters, digits and
  underscores ( _ ). The first character must be a letter or an
  underscore. Examples of name identifiers are:

    NUMBER  integer  const  if  UPPER_LIMIT  LowerLimit  x5  _end

  Upper and lower case letters are different. Name identifiers
  may have any length and all characters are significant. The
  name identifier is terminated with a character which is
  neither a letter (or _ ) nor a digit. The terminating
  character is not part of the name identifier.

  Syntax:

    name_identifier ::=
      ( letter | underscore ) { letter | digit | underscore } .

    letter ::=
      upper_case_letter | lower_case_letter .

    upper_case_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' .

    lower_case_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' .

    underscore ::=
      '_' .


10.2.2 Special identifiers

    A special identifier is a sequence of special characters.
  Examples of special identifiers are:

    +  :=  <=  *  ->  ,  &

  Here is a list of all special characters:

    ! $ % & * + , - . / : ; < = > ? @ \ ^ ` | ~

  Special identifiers may have any length and all characters are
  significant. The special identifier is terminated with a character
  which is not a special character. The terminating character is
  not part of the special identifier.

  Syntax:

    special_identifier ::=
      special_character { special_character } .

    special_character ::=
      '!' | '$' | '%' | '&' | '*' | '+' | ',' | '-' | '.' | '/' |
      ':' | ';' | '<' | '=' | '>' | '?' | '@' | '\' | '^' | '`' |
      '|' | '~' .


10.2.3 Parentheses

    A parenthesis is one of the following characters:

    ( ) [ ] { }

  Note that a parenthesis consists of only one character. Except
  for the character sequence (* (which introduces a comment)
  a parenthesis is terminated with the next character.

  Syntax:

    parenthesis ::=
      '(' | ')' | '[' | ']' | '{' | '}' .


10.3 Literals

    There are three types of literals

    integer literals
    character literals
    string literals

  Syntax:

    literal ::=
      integer_literal | character_literal | string_literal .


10.3.1 Integer literals

    An integer literal is a sequence of digits which is taken to
  be decimal. The sequence of digits may be followed by the letter
  E or e an optional + sign and a decimal exponent. Based numbers
  can be specified when the sequence of digits is followed by
  the # character and a sequence of extended digits. The decimal
  number in front of the # character specifies the base of the
  number which follows the # character. As base a number between
  2 and 36 is allowed. As extended digits the letters A or a can
  be used for 10, B or b can be used for 11 and so on to Z or z
  which can be used as 35.

  Syntax:

    integer_literal ::=
      decimal_integer [ exponent | based_integer ] .

    decimal_integer ::=
      digit { digit } .

    exponent ::=
      ( 'E' | 'e' ) [ '+' ] decimal_integer .

    based_integer ::=
      '#' extended_digit { extended_digit } .

    extended_digit ::=
      letter | digit .


10.3.2 String literals

    A string literal is a sequence of UTF-8 encoded Unicode
  characters surrounded by double quotes. For example:

    ""   " "   "\""   "'"   "\'"   "String"   "ch=\" "   "\n\n"

  In order to represent non-printable characters and certain
  printable characters the following escape sequences may be
  used.

    audible alert    BEL      \a    backslash    (\)   \\
    backspace        BS       \b    apostrophe   (')   \'   
    escape           ESC      \e    double quote (")   \"
    formfeed         FF       \f
    newline          NL (LF)  \n    control-A          \A
    carriage return  CR       \r      ...
    horizontal tab   HT       \t    control-Z          \Z
    vertical tab     VT       \v

  Additionally there are the following possibilities:

    - Two backslashes with a sequence of blanks, horizontal tabs,
      carriage returns and new lines between them are completely
      ignored. The ignored characters are not part of the string.
      This can be used to continue a string in the following line.
      Note that in this case the leading spaces in the new line
      are not part of the string.

    - Two backslashes with an integer literal between them is
      interpreted as character with the specified ordinal number.
      Note that the integer literal is interpreted decimal unless
      it is written as based integer.

  Strings are implemented with length field and UTF-32 encoding.
  Strings are not '\0\' terminated and therefore can also contain
  binary data.

  Syntax:

    string_literal ::=
      '"' { string_character } '"' .

    string_character ::=
      printable_character | escape_sequence .

    escape_sequence ::=
      '\a' | '\b' | '\e' | '\f' | '\n' | '\r' | '\t' | '\v' |
      '\\' | '\''' | '\"' | '\' upper_case_letter |
      '\' { space } '\' | '\' integer_literal '\' .


10.3.3 Character literals

    A character literal is an UTF-8 encoded Unicode character
  enclosed in single quotes. For example:

    'a'   ' '   '\n'   '!'   '\\'   '2'   '"'   '\"'   '\''

  To represent control characters and certain other characters in
  character literals the same escape sequences as for string
  literals may be used.

  Syntax:

    character_literal ::=
      ''' ( printable_character | escape_sequence ) ''' .

    escape_sequence ::=
      '\a' | '\b' | '\e' | '\f' | '\n' | '\r' | '\t' | '\v' |
      '\\' | '\''' | '\"' | '\' upper_case_letter |
      '\' { space } '\' | '\' integer_literal '\' .



11. EXPRESSIONS
===============

    There are two types of expressions. On one side there so
  called simple expressions which are constructed using fixed
  predefined syntax rules. On the other side there are expressions
  which are constructed according to syntax rules defined with
  syntax declarations. Here we describe only simple expressions.
  How syntax declarations work is described in Chapter 3.2
  (Syntax declarations) and chapter 9 (Structured syntax
  definition). There are only few fixed predefined syntax rules:


11.1 Parentheses

    Parentheses can be used to override any precedence
  rules of predefined and user defined syntax constructs.
  For example

    2 * (3 + 4)

  specifies that the + operator gets his parameters first.

  Syntax:

    parentheses_expression ::=
      '(' expression ')' .


11.2 Call expressions

    Call expressions can also be used to form a list.
  For example

    writeln("hello world")

  forms a list expression with the elements

    "hello world"
    writeln

  The meta object of this list is specified with the system
  declaration "system expr" which is defined in the include
  file "syntax.s7i" included from "seed7_05.s7i" as

    $ system "expr" is expr;

  A call expression with two parameters as

    pos("Scotty! Beam me up.", "am")

  forms a list expression with the elements

    "Scotty! Beam me up."
    "am"
    pos

  Syntax:

    call_expression ::=
      primary_expression [ '(' comma_expression ')' ] .

    primary_expression ::=
      parentheses_expression | atom .


11.3 Dot expressions

    Dot expressions start with a dot and have dots as separator
  between the elements of the list. For example

    .not.TRUE

  and

    .OKAY.and.GO_ON

  form list expressions with the elements

    not
    TRUE

  and

    OKAY
    and
    GO_ON

  The meta object of this list is specified with the system
  declaration "system expr" which is defined in the include
  file "syntax.s7i" included from "seed7_05.s7i" as

    $ system "expr" is expr;

  Dot expressions override the priority of the elements.
  Dot expressions are used in 'syntax' declarations.

  Syntax:

    dot_expression ::=
      [ '.' ] call_expression { '.' call_expression } .



12. OPERATING SYSTEM ACCESS
===========================

    Seed7 provides a portable access to the services provided
  by an operating system. This interface is oriented towards
  Posix and Unix. The functions in this chapter are defined
  in the libraries "osfiles.s7i" and "dir.s7i".


12.1 Standard path representation

    A path specifies the location of a file in a file system.
  Operating systems have different concepts how a path should
  look like. Seed7 compensates this differences with a standard
  path representation. Standard paths are used by all Seed7
  functions dealing with paths. The standard path representation
  uses strings with the following properties to describe paths:

    - The slash ('/') is used as path delimiter.
    - Drive letters are not allowed, but there is a solution
      to replace them.
    - Except for the path "/" a standard path is not allowed
      to end with a slash.

  When a function like 'open' is called with a path that is not
  "/", but ends with a slash, the exception 'RANGE_ERROR' is
  raised. Under Windows a standard path like "/c" is mapped to
  the drive "C:". Reading the directory "/" under Windows
  returns a list of available drives. A path with a backslash
  or with a drive letter may raise the exception 'RANGE_ERROR',
  when a function like 'open' is called.  

  An absolute path specifies an unique location in the file
  system. Absolute paths always start with a slash. A relative
  path specifies a location relative to the current working
  directory of the program. Although standard paths are defined
  in a portable way, an absolute path will usually not be portable.


12.2 readDir

    The function 'readDir' provides a portable access to the
  contents of directories in the file system. It reads the
  specified directory and the filenames are stored in the
  string-array result. The files "." and ".." are left out from
  the result. Note that the strings contain only the filenames.
  Additional information must be obtained with other calls.

    const func array string: readDir (in string: dirPath) is ...

  Returns:
    An array of strings containing the names of all
    files in the specified directory, except "." and ".."
    
  Possible exceptions:
    MEMORY_ERROR
        Not enough memory to convert 'dirPath' to the system
        path type or not enough memory to represent the result
        'string array'.
    RANGE_ERROR
        'dirPath' is not representable in the system path type.
    FILE_ERROR
        A system function returns an error.
    
  Examples:
    After the declaration
    
      var array string: dir_array is 0 times "";
    
    the statement
    
      dir_array := readDir(".");
    
    reads the current working directory and stores it into the
    string-array 'dir_array'. The components of the directory
    can now be accessed via indexing:
    
      for index range 1 to length(dir_array) do
        writeln(dir_array[index]);
      end for;
    

12.3 openDir

    The function 'openDir' opens the specified
  directory as file. Each line in this directory file
  contains the filename of a file present in the the
  directory. The files "." and ".." are left out from the
  directory file. Note that only filenames can be read
  from the directory file. Additional information must be
  obtained with other calls.

    const func file: openDir (in string: dirPath) is ...

  Returns:
    The directory file of the specified directory.
    
  Possible exceptions:
    MEMORY_ERROR
        Not enough memory to convert 'dirPath' to the system
        path type or not enough memory to represent the result
        'string array'.
    RANGE_ERROR
        'dirPath' is not representable in the system path type.
    FILE_ERROR
        A system function returns an error.
    
  Examples:
      ...

      include "dir.s7i";

      var file: dir_file is STD_NULL;
      var string: file_name is "";

      ...

      dir_file := openDir(".");
      file_name := getln(dir_file);
      while file_name <> "" do
        writeln(file_name);
        file_name := getln(dir_file);
      end while;
    

12.4 getcwd

    The function 'getcwd' returns the current working
  directory of the calling process as absolute path.

    const func string: getcwd is ...

  Returns:
    The absolute path of the current working directory.
    
  Possible exceptions:
    MEMORY_ERROR
        Not enough memory to represent the result 'string'.
    FILE_ERROR
        The system function returns an error.
    
  Examples:
    The statement
    
      my_dir := getcwd;
    
    assigns the full path of the current working directory to
    the 'string' variable 'my_dir'.
    

12.5 chdir

    The function 'chdir' changes the current working
  directory of the calling process to the specified directory.

    const proc: chdir (in string: name) is ...

  Possible exceptions:
    MEMORY_ERROR
        Not enough memory to convert 'name' to the system path type.
    RANGE_ERROR
        'name' is not representable in the system path type.
    FILE_ERROR
        A system function returns an error.
    
  Examples:
    The statement
    
      chdir("/usr/bin");
    
    changes the current working directory to "/usr/bin".
    

12.6 mkdir

    The function 'mkdir' creates a new directory.

    const proc: mkdir (in string: name) is ...

  Possible exceptions:
    MEMORY_ERROR
        Not enough memory to convert 'name' to the system path type.
    RANGE_ERROR
        'name' is not representable in the system path type.
    FILE_ERROR
        A system function returns an error.
    
  Examples:
    The statement
    
      mkdir("my_dir");
    
    creates the directory "my_dir".
    

12.7 fileType

    The type of a file can determined with 'fileType' or
  'fileTypeSL':

    const func integer: fileType (in string: filePath) is ...
    const func integer: fileTypeSL (in string: filePath) is ...

  The function 'fileType' does follow symbolic links.
  Therefore 'fileType' never returns 'FILE_SYMLINK'.
  The function 'fileTypeSL' does not follow symbolic
  links. Therefore 'fileTypeSL' can also return
  'FILE_SYMLINK'. Most functions which use a file path
  except 'fileTypeSL' and 'readlink' follow symbolic links. 

  Returns:
    FILE_ABSENT
        A component of path does not exist.
    FILE_UNKNOWN
        The file exists but has an unknown type.
    FILE_REGULAR
        The file is a regular file.
    FILE_DIR
        The file is a directory.
    FILE_CHAR
        The file is a character special file.
    FILE_BLOCK
        The file is a block special file.
    FILE_FIFO
        The file is a pipe or FIFO special file.
    FILE_SYMLINK
        The file is a symbolic link.
    FILE_SOCKET
        The file is a socket.
    
  Possible exceptions:
    MEMORY_ERROR
        Not enough memory to convert 'filePath' to the system path type.
    RANGE_ERROR
        'filePath' is not representable in the system path type.
    FILE_ERROR
        The system function returns an error other than ENOENT or ENOTDIR.
    

12.8 fileMode

    The permissions of a file can determined with 'fileMode':

    const func fileMode: fileMode (in string: filePath) is ...

  Returns:
    The 'fileMode' which is defined as 'set of filePermission'.
    
  The literal values of 'filePermission' are:
    EXEC_OTHER
        others have execute permission
    WRITE_OTHER
        others have write permission
    READ_OTHER
        others have read permission
    EXEC_GROUP
        group has execute permission
    WRITE_GROUP
        group has write permission
    READ_GROUP
        group has read permission
    EXEC_USER
        owner has execute permission
    WRITE_USER
        owner has write permission
    READ_USER
        owner has read permission
    
  Possible exceptions:
    MEMORY_ERROR
        Not enough memory to convert 'filePath' to the system path type.
    RANGE_ERROR
        'filePath' is not representable in the system path type.
    FILE_ERROR
        A system function returns an error.
    

12.9 setFileMode

    The permissions of a file can changed with 'setFileMode':

    const proc: setFileMode (in string: filePath, in fileMode: newFileMode) is ...

  The type 'fileMode' is defined as 'set of filePermission'.

  The literal values of 'filePermission' are:
    EXEC_OTHER
        others have execute permission
    WRITE_OTHER
        others have write permission
    READ_OTHER
        others have read permission
    EXEC_GROUP
        group has execute permission
    WRITE_GROUP
        group has write permission
    READ_GROUP
        group has read permission
    EXEC_USER
        owner has execute permission
    WRITE_USER
        owner has write permission
    READ_USER
        owner has read permission
    
  Possible exceptions:
    MEMORY_ERROR
        Not enough memory to convert 'filePath' to the system path type.
    RANGE_ERROR
        'filePath' is not representable in the system path type.
    FILE_ERROR
        A system function returns an error.
    

12.10 fileSize

    The size of a file can be determined with 'fileSize' and 'bigFileSize':

    const func integer: fileSize (in string: filePath) is ...
    const func bigInteger: bigFileSize (in string: filePath) is ...

  Returns:
    For directories a size of 0 is returned. For other file types
    the operating system functions 'stat()' and 'seek()' are
    used to determine the size of a file. The functions 'fileSize'
    and 'bigFileSize' succeed when at least one strategy to determine
    the file size succeeds. 
    
  Possible exceptions:
    MEMORY_ERROR
        Not enough memory to convert 'filePath' to the system path type.
    RANGE_ERROR
        'filePath' is not representable in the system path type.
    RANGE_ERROR
        The file size is not representable as 'integer'
        (this exception is not raised by 'bigFileSize').
    FILE_ERROR
        It was not possible to determine the file size.
    

12.11 getATime

    The access time of a file is returned by the function 'getATime':

    const func time: getATime (in string: filePath) is ...

  Possible exceptions:
    MEMORY_ERROR
        Not enough memory to convert 'filePath' to the system path type.
    RANGE_ERROR
        'filePath' is not representable in the system path type.
    FILE_ERROR
        A system function returns an error.
    

12.12 getCTime

    The change time of a file is returned by the function 'getCTime':

    const func time: getCTime (in string: filePath) is ...

  Possible exceptions:
    MEMORY_ERROR
        Not enough memory to convert 'filePath' to the system path type.
    RANGE_ERROR
        'filePath' is not representable in the system path type.
    FILE_ERROR
        A system function returns an error.
    

12.13 getMTime

    The modification time of a file is returned by the function 'getMTime':

    const func time: getMTime (in string: filePath) is ...

  Possible exceptions:
    MEMORY_ERROR
        Not enough memory to convert 'filePath' to the system path type.
    RANGE_ERROR
        'filePath' is not representable in the system path type.
    FILE_ERROR
        A system function returns an error.
    

12.14 setATime

    The function 'setATime' sets the access time of a file:

    const proc: setATime (in string: filePath, in time: aTime) is ...

  Possible exceptions:
    MEMORY_ERROR
        Not enough memory to convert 'filePath' to the system path type.
    RANGE_ERROR
        'filePath' is not representable in the system path type or
        'aTime' is invalid or cannot be converted to the system file time.
    FILE_ERROR
        A system function returns an error.
    

12.15 setMTime

    The function 'setMTime' sets the modification time of a file:

    const proc: setMTime (in string: filePath, in time: aTime) is ...

  Possible exceptions:
    MEMORY_ERROR
        Not enough memory to convert 'filePath' to the system path type.
    RANGE_ERROR
        'filePath' is not representable in the system path type or
        'aTime' is invalid or cannot be converted to the system file time.
    FILE_ERROR
        A system function returns an error.
    

12.16 readlink

    The function 'readlink' reads the destination of a symbolic link:

    const func string: readlink (in string: filePath) is ...

  Returns:
    The symbolic link refered by 'filePath'. 
    
  Possible exceptions:
    MEMORY_ERROR
        Not enough memory to convert 'filePath' to the system path type or not
        enough memory to represent the result 'string'.
    RANGE_ERROR
        'filePath' is not representable in the system path type.
    FILE_ERROR
        The file described with 'filePath' does not exist or is not a symbolic link.
    

12.17 symlink

    The function 'symlink' creates a symbolic link called
  'dest' that contains the string referred by 'source':

    const proc: symlink (in string: source, in string: dest) is ...

  Parameters:
    source
        String to be contained in the symbolic link.
    dest
        Name of the symbolic link to be created.
    
  Possible exceptions:
    MEMORY_ERROR
        Not enough memory to convert 'source' or 'dest'
        to the system path type.
    RANGE_ERROR
        'source' or 'dest' is not representable in the
        system path type.
    FILE_ERROR
        A system function returns an error.
    

12.18 removeFile

    The function 'removeFile' removes a file or
  empty directory:

    const proc: removeFile (in string: filePath) is ...

  Possible exceptions:
    MEMORY_ERROR
        Not enough memory to convert 'filePath' to the system path type.
    RANGE_ERROR
        'filePath' is not representable in the system path type.
    FILE_ERROR
        The file does not exist or a system function returns an error.
    

12.19 removeAnyFile

    The function 'removeAnyFile' removes a file independent
  of its file type:

    const proc: removeAnyFile (in string: filePath) is ...

  Possible exceptions:
    MEMORY_ERROR
        Not enough memory to convert 'filePath' to the system path type.
    RANGE_ERROR
        'filePath' is not representable in the system path type.
    FILE_ERROR
        The file does not exist or a system function returns an error.
    

12.20 copyFile

    The function 'copyFile' copies a file or directory
  tree:

    const proc: copyFile (in string: sourcePath, in string: destPath) is ...

  Permissions/mode, ownership and timestamps of the destination file
  are determined independent of the corresponding source properties.
  The destination file gets the permissions/mode defined by umask.
  The user executing the program is the owner of the destination file.
  The timestamps of the destination file are set to the current time.
  Symbolic links in sourcePath are always followed.
  Therefore 'copyFile' will never create a symbolic link.
  Note that 'copyFile' does not preserve hard
  links (they are resolved to distinct files).

  Possible exceptions:
    MEMORY_ERROR
        Not enough memory to convert 'sourcePath' or 'destPath'
        to the system path type.
    RANGE_ERROR
        'sourcePath' or 'destPath' is not representable in the
        system path type.
    FILE_ERROR
        Source file does not exist, destination file already exists or
        a system function returns an error.
    

12.21 cloneFile

    The function 'cloneFile' clones a file or directory
  tree:

    const proc: cloneFile (in string: sourcePath, in string: destPath) is ...

  Permissions/mode, ownership and timestamps of the original are
  preserved. Symlinks are not followed. Instead the symlink
  is copied. Note that 'cloneFile' does not preserve hard
  links (they are resolved to distinct files).

  Possible exceptions:
    MEMORY_ERROR
        Not enough memory to convert 'sourcePath' or 'destPath'
        to the system path type.
    RANGE_ERROR
        'sourcePath' or 'destPath' is not representable in the
        system path type.
    FILE_ERROR
        Source file does not exist, destination file already exists or
        a system function returns an error.
    

12.22 moveFile

    The function 'moveFile' moves and/or renames a
  file or directory tree:

    const proc: moveFile (in string: sourcePath, in string: destPath) is ...

  The function uses the C 'rename()' function.
  When 'rename()' fails the file (or directory tree)
  is cloned with 'cloneFile' (which preserves
  permissions/mode, ownership and timestamps) to the new place
  and with the new name. When 'cloneFile' succeeds
  the original file is deleted. When 'cloneFile' fails (no space on
  device or other reason) all remains of the failed clone are
  removed. Note that 'cloneFile' works for
  symbolic links but does not preserve hard links (they are
  resolved to distinct files).

  Possible exceptions:
    MEMORY_ERROR
        Not enough memory to convert 'sourcePath' or 'destPath'
        to the system path type.
    RANGE_ERROR
        'sourcePath' or 'destPath' is not representable in the
        system path type.
    FILE_ERROR
        Source file does not exist, destination file already exists or
        a system function returns an error.
    

12.23 argv(PROGRAM)

    The function 'argv(PROGRAM)' returns the argument
  vector of the program as array of strings.

    const func array string: argv (PROGRAM) is ...

  Returns:
    An array of strings containing the argument vector.
    

12.24 path(PROGRAM)

    The function 'path(PROGRAM)' returns the absolute
  path of the program.

    const func string: path (PROGRAM) is ...

  Returns:
    The absolute path of the program.
    

12.25 dir(PROGRAM)

    The function 'dir(PROGRAM)' returns the absolute
  path of the directory containing the program. The dir(PROGRAM)
  function allows placing configuration data in the directory
  of the program.

      const func string: dir (PROGRAM) is ...

  Returns:
    The absolute path of the directory containing the program.
    

12.26 getenv

    The function 'getenv' determines the value of an
  environment variable.

    const func string: getenv (in string: name) is ...

  The 'getenv' function searches the environment for an
  environment variable with the given 'name'. When such
  an environment variable exists the corresponding 'string'
  value is returned.

  Returns:
    The value of an environment variable or ""
    when the requested environment variable does not exist.
    
  Possible exceptions:
    MEMORY_ERROR
        Not enough memory to convert 'name' to the system string type or not
        enough memory to represent the result 'string'.
    

12.27 setenv

    The function 'setenv' adds or changes an environment
  variable. 

    const proc: setenv (in string: name, in string: value) is ...

  The 'setenv' function searches the environment for an
  environment variable with the given 'name'. When such
  an environment variable exists the corresponding value is
  changed to 'value'. When no environment variable with
  the given 'name' exists a new environment variable
  'name' with the value 'value' is created.

  Possible exceptions:
    MEMORY_ERROR
        Not enough memory to convert 'name' or 'value' to
        the system string type.
    RANGE_ERROR
        A system function returns an error.
    


13. PRIMITIVE ACTIONS
=====================

    Not all functions can be described by calling other
  functions of the same language. For this reason and for
  performance reasons several functions are defined using a
  mechanism called action. For example: It is easy to define
  the while-statement by using recursion. But this would
  hurt performance and it would also use a huge amount of
  memory for the runtime stack. In practice an implementation
  of the while-statement can use a conditional jump
  instead of a subroutine call. Since Seed7 has no 'goto'
  statement, this is not an option. Instead the primitive
  action PRC_WHILE can be used. The while-statement is
  defined in the basic Seed7 library 'seed7_05.s7i' with:

    const proc: while (in func boolean param) do
        (in proc param) end while is action "PRC_WHILE";

  This declaration shows the types and the position of
  the parameters of a while-statement. Such an action
  declaration contains enough information to use the defined
  construct. The semantic of all primitive actions is
  hard coded in the interpreter and in the compiler. The
  parameters of the hard coded actions and the corresponding
  definitions in Seed7 must match. If you are interested in
  the Seed7 definitions of primitive actions just look into
  the file 'seed7_05.s7i'.

    Currently there are several hundred primitive actions
  predefined in the interpreter. They all have names in upper
  case characters which have the form:

    TYPE_ACTION

  Which means that for example all 'integer' actions start
  with INT_ and all assignment actions end with _CPY .
  The following list shows actions which are used with more
  than one type:

    _ABS      Absolute value
    _ADD      Addition
    _CAT      Concatenation
    _CMP      Compare
    _CPY      Copy (Assignment)
    _CREATE   Initialize (Construct)
    _DESTR    Destroy (Destruct)
    _DECR     Decrement
    _DIV      Division
    _EQ       Equal
    _GE       Greater equal
    _GETC     Get one character from a file
    _GETS     Get 'string' with maximum length from a file
    _GT       Greater than
    _HASHCODE Compute a hashCode
    _HEAD     Head of 'string', 'array' or 'ref_list'
    _ICONV    Conversion of 'integer' to another type
    _IDX      Index (Element) of 'string', 'array' or 'ref_list'
    _INCR     Increment
    _IPOW     Power with 'integer' exponent
    _LE       Less equal
    _LNG      Length
    _LOG2     Base 2 logarithm
    _LOWER    Convert to lower case
    _LSHIFT   Shift left
    _LT       Less than
    _MDIV     Modulo division (Integer division truncated towards negative infinity)
    _MINUS    Change sign
    _MOD      Modulo (Reminder of _MDIV integer division)
    _MULT     Multiply
    _NE       Not equal
    _ODD      Odd number
    _ORD      Ordinal number
    _PARSE    Conversion of 'string' to another type
    _PLUS     Positive sign (noop)
    _POW      Power
    _PRED     Predecessor
    _RAND     Random value
    _RANGE    Range of 'string', 'array' or 'ref_list'
    _REM      Remainder (Reminder of _DIV integer division)
    _RSHIFT   Arithmetic shift right
    _SBTR     Subtract
    _SCAN     Convert from 'string' to another type
    _SEEK     Set actual file position of a file
    _SQRT     Square root
    _STR      Convert to 'string'
    _SUCC     Successor
    _TAIL     Tail of 'string', 'array' or 'ref_list'
    _TELL     Return the actual file position
    _UPPER    Convert to upper case
    _VALUE    Dereference a reference
    _WRITE    Write 'string' to file

  Primitive actions are defined for many types. The functions
  which implement the primitive actions are grouped together
  in *lib.c files. The following list contains the action
  prefix, the file containing the functions and a description:

    ACT_  actlib.c  'ACTION' operations
    ARR_  arrlib.c  'array' operations
    BIG_  biglib.c  'bigInteger' operations
    BLN_  blnlib.c  'boolean' operations
    BST_  bstlib.c  Operations for byte strings
    CHR_  chrlib.c  'char' operations
    CMD_  cmdlib.c  Various directory, file and other commands
    DCL_  dcllib.c  Declaration operations
    DRW_  drwlib.c  Drawing operations
    ENU_  enulib.c  Enumeration operations
    FIL_  fillib.c  'PRIMITIVE_FILE' operations
    FLT_  fltlib.c  'float' operations
    HSH_  hshlib.c  'hash' operations
    INT_  intlib.c  'integer' operations
    ITF_  itflib.c  Operations for interface types
    KBD_  kbdlib.c  Keyboard operations
    LST_  lstlib.c  List operations
    PRC_  prclib.c  proc operations and statements
    PRG_  prglib.c  Program operations
    REF_  reflib.c  'reference' operations
    RFL_  rfllib.c  'ref_list' operations
    SCR_  scrlib.c  Screen operations
    SCT_  sctlib.c  'struct' operations
    SET_  setlib.c  'set' operations
    SOC_  soclib.c  'PRIMITIVE_SOCKET' operations
    STR_  strlib.c  'string' operations
    TIM_  timlib.c  'time' and 'duration' operations
    TYP_  typlib.c  'type' operations
    UT8_  ut8lib.c  'utf8_file' operations

  The C functions which implement primitive actions have
  lowercase names. E.g.: The action 'PRC_WHILE' is implemented
  with the C function 'prc_while()' in the file 'prclib.c'.
  The parameter list for all C action functions is identical.
  Every *lib.c file has a corresponding *lib.h file which
  contains the prototypes for the action functions.

  In a Seed7 program the operator '+' is used to add two 'integer'
  values. The primitive action, which describes the addition of
  two integers, is 'INT_ADD'. The connection between '+'
  and 'INT_ADD' is done in the library "integer.s7i" with the definition:

    const func integer: (in integer: summand1) + (in integer: summand2) is action "INT_ADD";

  To execute an action a corresponding C function must
  be present in the hi interpreter. The function for the
  action 'INT_ADD' is 'int_add()'. The function 'int_add()'
  is defined in the file 'intlib.c' with:

    #ifdef ANSI_C

    objecttype int_add (listtype arguments)
    #else

    objecttype int_add (arguments)
    listtype arguments;
    #endif

      { /* int_add */
        isit_int(arg_1(arguments));
        isit_int(arg_3(arguments));
        return(bld_int_temp(
            take_int(arg_1(arguments)) +
            take_int(arg_3(arguments))));
      } /* int_add */

  The action functions use ANSI C prototypes and K&R function headers.
  The function 'int_add()' adds the first and the third argument (the
  second argument contains the + symbol. The file 'objutl.h'
  contains several macros and functions which help to handle the
  arguments (parameter list) of a C primitive action function.

    - The macros 'arg_1', 'arg_2',
      'arg_3', etc. can be used to get an individual argument
      (E.g.: 'arg_3(arguments)' ).

    - The macros 'isit_int', 'isit_stri',
      'isit_file', etc. can be used to check for the correct
      'category' of an argument
      (E.g.: 'isit_int(arg_1(arguments))' ).

    - The macros 'take_char', 'take_float',
      'take_bigint', etc. can be used to get the corresponding
      value of an argument (E.g.: 'take_int(arg_1(arguments))' ).

    - The functions 'bld_int_temp', 'bld_array_temp',
      'bld_win_temp', etc. can be used to create the (objecttype)
      result of a primitive action (E.g.: 'return(bld_int_temp(0))' ).

  The file 'intlib.h' contains the prototype for the 'int_add()'
  function:

    objecttype int_add (listtype);

  and also a definition for the K&R C language:

    objecttype int_add ();

  Additionally every primitive action is registered in the file
  'primitive.c'. The line which incorporates 'INT_ADD' is:

    { "INT_ADD",             int_add,             },

  The entries of the primitive action in the file 'primitive.c' are
  sorted alphabetically. With this definitions the hi interpreter
  understands a primitive action.

  To allow a primitive function in a compiled Seed7 program the
  Seed7 compiler (comp.sd7) needs to know the action also. The
  compiler function which creates code for the 'INT_ADD' action is:

    const proc: process_int_add (in ref_list: params, inout expr_type: c_expr) is func

      begin
        c_expr.expr &:= "(";
        process_expr(params[1], c_expr);
        c_expr.expr &:= ") + (";
        process_expr(params[3], c_expr);
        c_expr.expr &:= ")";
      end func;

  This function is called from the function 'process_action' with:

    elsif action_name = "INT_ADD" then
      process_int_add(params, c_expr);

  Some primitive actions are more complicated and inline code would
  not be the best solution for it. In this case an additional helper
  function is used. The action 'INT_LOG2' is such an action. The
  definition of the function 'int_log2()' in the file 'intlib.c' is:

    #ifdef ANSI_C

    objecttype int_log2 (listtype arguments)
    #else

    objecttype int_log2 (arguments)
    listtype arguments;
    #endif

      { /* int_log2 */
        isit_int(arg_1(arguments));
        return bld_int_temp(
            intLog2(take_int(arg_1(arguments))));
      } /* int_log2 */

  The main work for the primitive action 'INT_LOG2' is done in
  the helper function 'intLog2()'. The helper function 'intLog2()'
  can be found in the file 'int_rtl.c':

    /**
     *  Compute the truncated base 2 logarithm of an integer number.
     *  @return the truncated base 2 logarithm.
     *  @exception NUMERIC_ERROR The number is negative.
     */
    #ifdef ANSI_C

    inttype intLog2 (inttype number)
    #else

    inttype intLog2 (number)
    inttype number;
    #endif

      {
        int result;

      /* intLog2 */
        if (unlikely(number < 0)) {
          raise_error(NUMERIC_ERROR);
          result = 0;
        } else {
          result = uintMostSignificantBit((uinttype) number);
        } /* if */
        return result;
      } /* intLog2 */

  The file 'int_rtl.h' contains a prototype definition for the
  'intLog2()' helper function:

    inttype intLog2 (inttype number);

  and also a definition for the K&R C language:

    inttype intLog2 ();

  The helper functions are also used in the code generated by
  the Seed7 compiler:

    const proc: process_int_log2 (in ref_list: params, inout expr_type: c_expr) is func

      begin
        c_expr.expr &:= "intLog2(";
        process_expr(params[1], c_expr);
        c_expr.expr &:= ")";
      end func;

  The compiler writes a prototype of 'intLog2()' in the
  function 'write_prototypes':

    declareExtern("inttype     intLog2 (inttype);");

  Several Seed7 types correspond to simple C types, which are
  defined in 'common.h':

    Seed7 type       C type     Comment
    boolean          booltype   int
    integer          inttype    32- or 64-bit signed int
    float            floattype  float (or double)
    char             chartype   32-bit unsigned int
    PRIMITIVE_FILE   filetype   FILE *
    PRIMITIVE_SOCKET sockettype int or unsigned int

  Other Seed7 types correspond to C pointers, which point to a struct.
  Some of this structs are used in all situations: In the interpreter
  and in the compiler and under different operation systems and with
  different runtime libraries. This invariant structs are defined
  in 'common.h':

    Seed7 type       C type    C struct           Comment
    string           stritype  struct stristruct  UTF-32 encoded, can contain null chars
    set              settype   struct setstruct    
    bstring          bstritype struct bstristruct Byte sequence, can contain null bytes

  Other Seed7 types also correspond to struct pointers, but the structs
  are different in interpreted and compiled Seed7 programs. The
  structs for interpreted programs are defined in 'data.h' and
  the structs for compiled programs are defined in 'data_rtl.h':

    Seed7 type  C type (interpreted)  C struct (interpreted)  C type (compiled)  C struct (compiled)
    array       arraytype             struct stristruct       rtlArraytype       struct rtlArraystruct
    hash        hashtype              struct hashstruct       rtlHashtype        struct rtlHashstruct
    struct      structtype            struct structstruct     rtlStructtype      struct rtlStructstruct

  Because interpreter and compiler use different structs the
  functions from e.g. 'arrlib.c' cannot use functions
  from 'arr_rtl.c'.

  Finally some Seed7 types depend on the operating system or runtime
  library used:

    Seed7 type       C type      Defined as                        Sourcefile  Comment
    bigInteger       biginttype  struct bigintstruct *             big_rtl.c   The built-in bigInteger library
                     biginttype  mpz_ptr                           big_gmp.c   The GNU Multiple Precision Arithmetic Library
    pollData         polltype    struct select_based_pollstruct *  pol_sel.c   Functions cast it to implementation dependent struct
                     polltype    struct poll_based_pollstruct *    pol_unx.c   Functions cast it to implementation dependent struct
    PRIMITIVE_WINDOW wintype     struct x11_winstruct *            drw_x11.c   Functions cast from winstruct * to x11_winstruct *
                     wintype     struct win_winstruct *            drw_win.c   Functions cast from winstruct * to win_winstruct *

  Seed7 strings are UTF-32 encoded and C strings are zero
  terminated byte sequences. To convert between the different
  representations, 'striutl.h' defines conversion functions
  like 'cp_to_cstri', 'stri_to_bstri', 'stri_to_bstri8',
  'cstri_to_stri', 'cstri8_to_stri' and 'cstri8_or_cstri_to_stri'.
  Operating systems disagree in their Unicode encoding (UTF-8
  or UTF-16). To cope with this, 'striutl.h' defines the
  type 'os_stritype' and the functions 'stri_to_os_stri'
  and 'os_stri_to_stri'. The different concepts to
  represent a file path (path delimiter and drive letter) are
  handled with 'cp_to_os_path' and 'cp_from_os_path'.

  All the *lib.c files containing primitive actions and various
  other files with their functions are grouped together in the
  's7_comp.a' library (Licensed under GPL). Furthermore the C
  primitive action functions (E.g.: int_parse) of the *lib.c
  files may use corresponding functions (E.g.: intParse) which
  can be found in *_rtl.c files (E.g.: 'int_rtl.c'). The *_rtl.c
  files are grouped together in the 'seed7_05.a' library
  (Licensed under LGPL). When a Seed7 program is compiled with
  the Seed7 compiler (comp.sd7) inline code is generated for
  many primitive actions. To implement the remaining primitive
  actions the functions of the 'seed7_05.a' library are used.

13.1 Actions for the type ACTION

    Action name         actlib.c function   act_comp.c function
    ACT_ILLEGAL         act_illegal          
    ACT_CPY             act_cpy             =
    ACT_CREATE          act_create           
    ACT_GEN             act_gen              
    ACT_STR             act_str             actStr
    ACT_VALUE           act_value           actValue

13.2 Actions for array types

    Action name         arrlib.c function   arr_rtl.c function
    ARR_APPEND          arr_append          arrAppend
    ARR_ARRLIT          arr_arrlit          arrArrlit
    ARR_ARRLIT2         arr_arrlit2         arrArrlit2
    ARR_BASELIT         arr_baselit         arrBaselit
    ARR_BASELIT2        arr_baselit2        arrBaselit2
    ARR_CAT             arr_cat             arrCat
    ARR_CONV            arr_conv            (noop)
    ARR_CPY             arr_cpy             cpy_ ...
    ARR_CREATE          arr_create          create_ ...
    ARR_DESTR           arr_destr           destr_ ...
    ARR_EMPTY           arr_empty            
    ARR_EXTEND          arr_extend          arrExtend
    ARR_GEN             arr_gen             arrGen
    ARR_HEAD            arr_head            arrHead
    ARR_IDX             arr_idx             a->arr[b-a->min_position]
    ARR_LNG             arr_lng             a->max_position-a->min_position + 1
    ARR_MAXIDX          arr_maxidx          a->max_position
    ARR_MINIDX          arr_minidx          a->min_position
    ARR_PUSH            arr_push            arrPush
    ARR_RANGE           arr_range           arrRange
    ARR_REMOVE          arr_remove          arrRemove
    ARR_SORT            arr_sort            arrSort
    ARR_TAIL            arr_tail            arrTail
    ARR_TIMES           arr_times           times_ ...

13.3 Actions for the type bigInteger

    Action name         biglib.c function   big_rtl.c function
    BIG_ABS             big_abs             bigAbs
    BIG_ADD             big_add             bigAdd, bigAddTemp
    BIG_BIT_LENGTH      big_bit_length      bigBitLength
    BIG_CLIT            big_clit            bigCLit
    BIG_CMP             big_cmp             bigCmp
    BIG_CPY             big_cpy             bigCpy
    BIG_CREATE          big_create          bigCreate
    BIG_DECR            big_decr            bigDecr
    BIG_DESTR           big_destr           bigDestr
    BIG_DIV             big_div             bigDiv
    BIG_EQ              big_eq              bigEq
    BIG_GCD             big_gcd             bigGcd
    BIG_GE              big_ge              bigCmp >= 0
    BIG_GROW            big_grow            bigGrow
    BIG_GT              big_gt              bigCmp > 0
    BIG_HASHCODE        big_hashcode        bigHashCode
    BIG_ICONV           big_iconv           bigIConv
    BIG_INCR            big_incr            bigIncr
    BIG_IPOW            big_ipow            bigIPow
    BIG_LE              big_le              bigCmp <= 0
    BIG_LOG2            big_log2            bigLog2
    BIG_LOWEST_SET_BIT  big_lowest_set_bit  bigLowestSetBit
    BIG_LSHIFT          big_lshift          bigLShift
    BIG_LSHIFT_ASSIGN   big_lshift_assign   bigLShiftAssign
    BIG_LT              big_lt              bigCmp < 0
    BIG_MDIV            big_mdiv            bigMDiv
    BIG_MINUS           big_minus           bigMinus
    BIG_MOD             big_mod             bigMod
    BIG_MULT            big_mult            bigMult
    BIG_MULT_ASSIGN     big_mult_assign     bigMultAssign
    BIG_NE              big_ne              bigNe
    BIG_ODD             big_odd             bigOdd
    BIG_ORD             big_ord             bigOrd
    BIG_PARSE           big_parse           bigParse
    BIG_PLUS            big_plus            (noop)
    BIG_PRED            big_pred            bigPred
    BIG_RAND            big_rand            bigRand
    BIG_REM             big_rem             bigRem
    BIG_RSHIFT          big_rshift          bigRShift
    BIG_RSHIFT_ASSIGN   big_rshift_assign   bigRShiftAssign
    BIG_SBTR            big_sbtr            bigSbtr, bigSbtrTemp
    BIG_SHRINK          big_shrink          bigShrink
    BIG_STR             big_str             bigStr
    BIG_SUCC            big_succ            bigSucc
    BIG_VALUE           big_value           bigValue

13.4 Actions for the type boolean

    Action name         blnlib.c function   bln_rtl.c function
    BLN_AND             bln_and             &&
    BLN_CPY             bln_cpy             blnCpy
    BLN_CREATE          bln_create          blnCreate
    BLN_GE              bln_ge              >=
    BLN_GT              bln_gt              >
    BLN_ICONV           bln_iconv           & 1
    BLN_LE              bln_le              <=
    BLN_LT              bln_lt              <
    BLN_NOT             bln_not             !
    BLN_OR              bln_or              ||
    BLN_ORD             bln_ord             (inttype)

13.5 Actions for byte strings

    Action name         bstlib.c function   bst_rtl.c function
    BST_APPEND          bst_append          bstAppend
    BST_CAT             bst_cat             bstCat
    BST_CMP             bst_cmp             bstCmp
    BST_CPY             bst_cpy             bstCpy
    BST_CREATE          bst_create          bstCreate
    BST_DESTR           bst_destr           bstDestr
    BST_EMPTY           bst_empty            
    BST_EQ              bst_eq              a->size==b->size && memcmp(a,b,a->size*sizeof(unsigned char))==0
    BST_HASHCODE        bst_hashcode        bstHashCode
    BST_IDX             bst_idx             a->mem[b-1]
    BST_LNG             bst_lng             a->size
    BST_NE              bst_ne              a->size!=b->size || memcmp(a,b,a->size*sizeof(unsigned char))!=0
    BST_PARSE           bst_parse           bstParse
    BST_STR             bst_str             bstStr
    BST_VALUE           bst_value           bstValue

13.6 Actions for the type char

    Action name         chrlib.c function   chr_rtl.c function
    CHR_CHR             chr_chr             (chartype)
    CHR_CLIT            chr_clit            chrCLit
    CHR_CMP             chr_cmp             chrCmp
    CHR_CONV            chr_conv            (noop)
    CHR_CPY             chr_cpy             chrCpy
    CHR_CREATE          chr_create          chrCreate
    CHR_DECR            chr_decr            --
    CHR_EQ              chr_eq              ==
    CHR_GE              chr_ge              >=
    CHR_GT              chr_gt              >
    CHR_HASHCODE        chr_hashcode        (inttype)((schartype)a)
    CHR_ICONV           chr_iconv           (chartype)
    CHR_INCR            chr_incr            ++
    CHR_LE              chr_le              <=
    CHR_LOW             chr_low             chrLow
    CHR_LT              chr_lt              <
    CHR_NE              chr_ne              !=
    CHR_ORD             chr_ord             (inttype)
    CHR_PRED            chr_pred            -1
    CHR_STR             chr_str             chrStr
    CHR_SUCC            chr_succ            +1
    CHR_UP              chr_up              chrUp
    CHR_VALUE           chr_value           chrValue

13.7 Actions for various directory, file and other commands

    Action name         cmdlib.c function   cmd_rtl.c function
    CMD_BIG_FILESIZE    cmd_big_filesize    cmdBigFileSize
    CMD_CHDIR           cmd_chdir           cmdChdir
    CMD_CLONE_FILE      cmd_clone_file      cmdCloneFile
    CMD_CONFIG_VALUE    cmd_config_value    cmdConfigValue
    CMD_COPY_FILE       cmd_copy_file       cmdCopyFile
    CMD_FILEMODE        cmd_filemode        cmdFileMode
    CMD_FILESIZE        cmd_filesize        cmdFileSize
    CMD_FILETYPE        cmd_filetype        cmdFileType
    CMD_FILETYPE_SL     cmd_filetype_sl     cmdFileTypeSL
    CMD_GETCWD          cmd_getcwd          cmdGetcwd
    CMD_GETENV          cmd_getenv          cmdGetenv
    CMD_GET_ATIME       cmd_get_atime       cmdGetATime
    CMD_GET_CTIME       cmd_get_ctime       cmdGetCTime
    CMD_GET_MTIME       cmd_get_mtime       cmdGetMTime
    CMD_LS              cmd_ls              cmdLs
    CMD_MKDIR           cmd_mkdir           cmdMkdir
    CMD_MOVE            cmd_move            cmdMove
    CMD_PIPE2           cmd_pipe2           cmdPipe2
    CMD_PTY             cmd_pty             cmdPty
    CMD_READLINK        cmd_readlink        cmdReadlink
    CMD_REMOVE          cmd_remove          cmdRemove
    CMD_REMOVE_ANY_FILE cmd_remove_any_file cmdRemoveAnyFile
    CMD_SETENV          cmd_setenv          cmdSetenv
    CMD_SET_ATIME       cmd_set_atime       cmdSetATime
    CMD_SET_FILEMODE    cmd_set_filemode    cmdSetFileMode
    CMD_SET_MTIME       cmd_set_mtime       cmdSetMTime
    CMD_SHELL           cmd_shell           cmdShell
    CMD_SHELL_ESCAPE    cmd_shell_escape    cmdShellEscape
    CMD_START_PROCESS   cmd_start_process   cmdStartProcess
    CMD_SYMLINK         cmd_symlink         cmdSymlink
    CMD_TO_OS_PATH      cmd_to_os_path      cmdToOsPath

13.8 Actions for text (console) screen output

    Action name         scrlib.c function   con_inf.c/con_rtl.c/con_win.c function
    CON_CLEAR           con_clear           conClear
    CON_CURSOR          con_cursor          conCursor
    CON_FLUSH           con_flush           conFlush
    CON_HEIGHT          con_height          conHeight
    CON_H_SCL           con_h_scl           conHScroll
    CON_OPEN            con_open            conOpen
    CON_SETPOS          con_setpos          conSetpos
    CON_V_SCL           con_v_scl           conVScroll
    CON_WIDTH           con_width           conWidth
    CON_WRITE           con_write           conWrite

13.9 Actions for declarations

    Action name         dcllib.c function
    DCL_ATTR            dcl_attr
    DCL_CONST           dcl_const
    DCL_ELEMENTS        dcl_elements
    DCL_FWD             dcl_fwd
    DCL_FWDVAR          dcl_fwdvar
    DCL_GETFUNC         dcl_getfunc
    DCL_GETOBJ          dcl_getobj
    DCL_GLOBAL          dcl_global
    DCL_IN1VAR          dcl_in1var
    DCL_IN2VAR          dcl_in2var
    DCL_INOUT1          dcl_inout1
    DCL_INOUT2          dcl_inout2
    DCL_PARAM_ATTR      dcl_param_attr
    DCL_REF1            dcl_ref1
    DCL_REF2            dcl_ref2
    DCL_SYMB            dcl_symb
    DCL_VAL1            dcl_val1
    DCL_VAL2            dcl_val2
    DCL_VAR             dcl_var

13.10 Actions to do graphic output

    Action name         drwlib.c function   drw_rtl.c/drw_x11.c/drw_win.c function
    DRW_ARC             drw_arc             drwArc
    DRW_ARC2            drw_arc2            drwArc2
    DRW_BACKGROUND      drw_background      drwBackground
    DRW_CIRCLE          drw_circle          drwCircle
    DRW_CLEAR           drw_clear           drwClear
    DRW_CMP             drw_cmp             uintCmpGeneric((generictype)(a))
    DRW_COLOR           drw_color           drwColor
    DRW_COPYAREA        drw_copyarea        drwCopyArea
    DRW_CPY             drw_cpy             drwCpy
    DRW_CREATE          drw_create          drwCreate
    DRW_DESTR           drw_destr           drwDestr
    DRW_EMPTY           drw_empty            
    DRW_EQ              drw_eq              ==
    DRW_FARCCHORD       drw_farcchord       drwFArcChord
    DRW_FARCPIESLICE    drw_farcpieslice    drwFArcPieSlice
    DRW_FCIRCLE         drw_fcircle         drwFCircle
    DRW_FELLIPSE        drw_fellipse        drwFEllipse
    DRW_FLUSH           drw_flush           drwFlush
    DRW_FPOLYLINE       drw_fpolyLine       drwFPolyLine
    DRW_GENPOINTLIST    drw_genPointList    drwGenPointList
    DRW_GET             drw_get             drwGet
    DRW_GETPIXEL        drw_getPixel        drwGetPixel
    DRW_HASHCODE        drw_hashcode        (inttype)(((memsizetype)a)>>6)
    DRW_HEIGHT          drw_height          drwHeight
    DRW_IMAGE           drw_image           drwImage
    DRW_LINE            drw_line            drwLine
    DRW_NE              drw_ne              !=
    DRW_NEW_PIXMAP      drw_new_pixmap      drwNewPixmap
    DRW_OPEN            drw_open            drwOpen
    DRW_OPEN_SUB_WINDOW drw_open_sub_window drwOpenSubWindow
    DRW_PARC            drw_parc            drwPArc
    DRW_PCIRCLE         drw_pcircle         drwPCircle
    DRW_PFARCCHORD      drw_pfarcchord      drwPFArcChord
    DRW_PFARCPIESLICE   drw_pfarcpieslice   drwFArcPieSlice
    DRW_PFCIRCLE        drw_pfcircle        drwPFCircle
    DRW_PFELLIPSE       drw_pfellipse       drwPFEllipse
    DRW_PIXELTORGB      drw_pixelToRgb      drwPixelToRgb
    DRW_PLINE           drw_pline           drwPLine
    DRW_POINT           drw_point           drwPoint
    DRW_POINTER_XPOS    drw_pointer_xpos    drwPointerXpos
    DRW_POINTER_YPOS    drw_pointer_ypos    drwPointerYpos
    DRW_POLYLINE        drw_polyLine        drwPolyLine
    DRW_PPOINT          drw_ppoint          drwPPoint
    DRW_PRECT           drw_prect           drwPRect
    DRW_PUT             drw_put             drwPut
    DRW_RECT            drw_rect            drwRect
    DRW_RGBCOL          drw_rgbcol          drwRgbColor
    DRW_SETCONTENT      drw_setContent      drwSetContent
    DRW_SETPOS          drw_setPos          drwSetPos
    DRW_SETTRANSPARENTCOLOR drw_setTransparentColor drwSetTransparentColor
    DRW_TEXT            drw_text            drwText
    DRW_TOBOTTOM        drw_toBottom        drwToBottom
    DRW_TOTOP           drw_toTop           drwToTop
    DRW_WIDTH           drw_width           drwWidth
    DRW_XPOS            drw_xpos            drwXPos
    DRW_YPOS            drw_ypos            drwYPos

13.11 Actions for enumeration types

    Action name         enulib.c function    
    ENU_CONV            enu_conv            (noop)
    ENU_CPY             enu_cpy             =
    ENU_CREATE          enu_create           
    ENU_EQ              enu_eq              ==
    ENU_GENLIT          enu_genlit           
    ENU_ICONV2          enu_iconv2          (noop)
    ENU_NE              enu_ne              !=
    ENU_ORD2            enu_ord2            (noop)
    ENU_VALUE           enu_value           enuValue

13.12 Actions for the type PRIMITIVE_FILE

    Action name         fillib.c function   fil_rtl.c function
    FIL_BIG_LNG         fil_big_lng         filBigLng
    FIL_BIG_SEEK        fil_big_seek        filBigSeek
    FIL_BIG_TELL        fil_big_tell        filBigTell
    FIL_CLOSE           fil_close           fclose
    FIL_CPY             fil_cpy             fltCpy
    FIL_CREATE          fil_create          fltCreate
    FIL_EMPTY           fil_empty            
    FIL_EOF             fil_eof             feof
    FIL_EQ              fil_eq              ==
    FIL_ERR             fil_err             stderr
    FIL_FLUSH           fil_flush           fflush
    FIL_GETC            fil_getc            fgetc
    FIL_GETS            fil_gets            filGets
    FIL_HAS_NEXT        fil_has_next        filHasNext
    FIL_IN              fil_in              stdin
    FIL_INPUT_READY     fil_input_ready     filInputReady
    FIL_LINE_READ       fil_line_read       filLineRead
    FIL_LIT             fil_lit             filLit
    FIL_LNG             fil_lng             filLng
    FIL_NE              fil_ne              !=
    FIL_OPEN            fil_open            filOpen
    FIL_OUT             fil_out             stdout
    FIL_PCLOSE          fil_pclose          filPclose
    FIL_POPEN           fil_popen           filPopen
    FIL_PRINT           fil_print           filPrint
    FIL_SEEK            fil_seek            filSeek
    FIL_SETBUF          fil_setbuf          filSetbuf
    FIL_TELL            fil_tell            filTell
    FIL_VALUE           fil_value           filValue
    FIL_WORD_READ       fil_word_read       filWordRead
    FIL_WRITE           fil_write           filWrite

13.13 Actions for the type float

    Action name         fltlib.c function   flt_rtl.c function
    FLT_A2TAN           flt_a2tan           atan2
    FLT_ABS             flt_abs             fabs
    FLT_ACOS            flt_acos            acos
    FLT_ADD             flt_add             +
    FLT_ASIN            flt_asin            asin
    FLT_ATAN            flt_atan            atan
    FLT_CAST            flt_cast            (x.floatvalue=a, x.intvalue)
    FLT_CEIL            flt_ceil            ceil
    FLT_CMP             flt_cmp             fltCmp
    FLT_COS             flt_cos             cos
    FLT_COSH            flt_cosh            cosh
    FLT_CPY             flt_cpy             fltCpy
    FLT_CREATE          flt_create          fltCreate
    FLT_DGTS            flt_dgts            fltDgts
    FLT_DIV             flt_div             /
    FLT_DIV_ASSIGN      flt_div_assign      /=
    FLT_EQ              flt_eq              ==
    FLT_EXP             flt_exp             exp
    FLT_FLOOR           flt_floor           floor
    FLT_GE              flt_ge              >=
    FLT_GROW            flt_grow            +=
    FLT_GT              flt_gt              >
    FLT_HASHCODE        flt_hashcode        (x.floatvalue=a, x.intvalue)
    FLT_ICAST           flt_icast           (x.intvalue=a, x.floatvalue)
    FLT_ICONV           flt_iconv           (float)
    FLT_IFLT            flt_iflt            (float)
    FLT_IPOW            flt_ipow            fltIPow
    FLT_ISNAN           flt_isnan           isnan
    FLT_ISNEGATIVEZERO  flt_isnegativezero  fltIsNegativeZero
    FLT_LE              flt_le              <=
    FLT_LOG             flt_log             log
    FLT_LOG10           flt_log10           log10
    FLT_LT              flt_lt              <
    FLT_MINUS           flt_minus           -
    FLT_MULT            flt_mult            *
    FLT_MULT_ASSIGN     flt_mult_assign     *=
    FLT_NE              flt_ne              !=
    FLT_PARSE           flt_parse           fltParse
    FLT_PLUS            flt_plus            (noop)
    FLT_POW             flt_pow             pow
    FLT_RAND            flt_rand            fltRand
    FLT_ROUND           flt_round           a<0.0?-((inttype)(0.5-a)):(inttype)(0.5+a)
    FLT_SBTR            flt_sbtr            -
    FLT_SCI             flt_sci             fltSci
    FLT_SHRINK          flt_shrink          -=
    FLT_SIN             flt_sin             sin
    FLT_SINH            flt_sinh            sinh
    FLT_SQRT            flt_sqrt            sqrt
    FLT_STR             flt_str             fltStr
    FLT_TAN             flt_tan             tan
    FLT_TANH            flt_tanh            tanh
    FLT_TRUNC           flt_trunc           (inttype)
    FLT_VALUE           flt_value           fltValue

13.14 Actions to support the graphic keyboard

    Action name         drwlib.c function   kbd_rtl.c/drw_x11.c/drw_win.c function
    GKB_BUSY_GETC       gkb_busy_getc       gkbKeyPressed() ? gkbGetc() : 512
    GKB_BUTTON_PRESSED  gkb_button_pressed  gkbButtonPressed
    GKB_BUTTON_XPOS     gkb_button_xpos     gkbButtonXpos
    GKB_BUTTON_YPOS     gkb_button_ypos     gkbButtonYpos
    GKB_GETC            gkb_getc            gkbGetc
    GKB_GETS            gkb_gets            gkbGets
    GKB_KEYPRESSED      gkb_keypressed      gkbKeyPressed
    GKB_LINE_READ       gkb_line_read       gkbLineRead
    GKB_RAW_GETC        gkb_raw_getc        gkbRawGetc
    GKB_WINDOW          gkb_window          gkbWindow
    GKB_WORD_READ       gkb_word_read       gkbWordRead

13.15 Actions for hash types

    Action name         hshlib.c function   hsh_rtl.c function
    HSH_CONTAINS        hsh_contains        hshContains
    HSH_CPY             hsh_cpy             hshCpy
    HSH_CREATE          hsh_create          hshCreate
    HSH_DESTR           hsh_destr           hshDestr
    HSH_EMPTY           hsh_empty           hshEmpty
    HSH_EXCL            hsh_excl            hshExcl
    HSH_FOR             hsh_for             for
    HSH_FOR_DATA_KEY    hsh_for_data_key    for
    HSH_FOR_KEY         hsh_for_key         for
    HSH_IDX             hsh_idx             hshIdx, hshIdxAddr
    HSH_IDX2            hsh_idx2             
    HSH_INCL            hsh_incl            hshIncl
    HSH_KEYS            hsh_keys            hshKeys
    HSH_LNG             hsh_lng             a->size
    HSH_REFIDX          hsh_refidx           
    HSH_VALUES          hsh_values          hshValues

13.16 Actions for the type integer

    Action name         intlib.c function   int_rtl.c function
    INT_ABS             int_abs             labs
    INT_ADD             int_add             +
    INT_BINOM           int_binom           intBinom
    INT_BIT_LENGTH      int_bit_length      intBitLength
    INT_CMP             int_cmp             intCmp
    INT_CONV            int_conv            (noop)
    INT_CPY             int_cpy             intCpy
    INT_CREATE          int_create          intCreate
    INT_DECR            int_decr            --
    INT_DIV             int_div             /
    INT_EQ              int_eq              ==
    INT_FACT            int_fact            fact[a]
    INT_GE              int_ge              >=
    INT_GROW            int_grow            +=
    INT_GT              int_gt              >
    INT_HASHCODE        int_hashcode        (noop)
    INT_INCR            int_incr            ++
    INT_LE              int_le              <=
    INT_LOG2            int_log2            intLog2
    INT_LOWEST_SET_BIT  int_lowest_set_bit  intLowestSetBit
    INT_LPAD0           int_lpad0           intLpad0
    INT_LSHIFT          int_lshift          <<
    INT_LSHIFT_ASSIGN   int_lshift_assign   <<=
    INT_LT              int_lt              <
    INT_MDIV            int_mdiv            a>0&&b<0 ? (a-1)/b-1 : a<0&&b>0 ? (a+1)/b-1 : a/b
    INT_MINUS           int_minus           -
    INT_MOD             int_mod             c=a%b, ((a>0&&b<0) || (a<0&&b>0)) && c!=0 ? c+b : c
    INT_MULT            int_mult            *
    INT_MULT_ASSIGN     int_mult_assign     *=
    INT_NE              int_ne              !=
    INT_ODD             int_odd             &1
    INT_ORD             int_ord             (noop)
    INT_PARSE           int_parse           intParse
    INT_PLUS            int_plus            (noop)
    INT_POW             int_pow             intPow
    INT_PRED            int_pred            --
    INT_RAND            int_rand            intRand
    INT_REM             int_rem             %
    INT_RSHIFT          int_rshift          a>>b<br />a<0?~(~a>>b):a>>b
    INT_RSHIFT_ASSIGN   int_rshift_assign   a>>=b<br />if (a<0) a= ~(~a>>b); else a>>=b;
    INT_SBTR            int_sbtr            -
    INT_SHRINK          int_shrink          -=
    INT_SQRT            int_sqrt            intSqrt
    INT_STR             int_str             intStr
    INT_STR_BASED       int_str_based       intStrBased
    INT_SUCC            int_succ            +1
    INT_VALUE           int_value           intValue

13.17 Actions for interface types

    Action name         itflib.c function    
    ITF_CMP             itf_cmp             uintCmpGeneric
    ITF_CONV2           itf_conv2           (noop)
    ITF_CPY             itf_cpy             =
    ITF_CPY2            itf_cpy2            =
    ITF_CREATE          itf_create           
    ITF_CREATE2         itf_create2          
    ITF_EQ              itf_eq              ==
    ITF_HASHCODE        itf_hashcode        (inttype)(((memsizetype)a)>>6)
    ITF_NE              itf_ne              !=
    ITF_TO_HEAP         itf_to_heap          
    ITF_TO_INTERFACE    itf_to_interface     

13.18 Actions to support the text (console) screen keyboard

    Action name         kbdlib.c function   kbd_rtl.c/kbd_inf.c function
    KBD_BUSY_GETC       kbd_busy_getc       kbdKeyPressed() ? kbdGetc() : 512
    KBD_GETC            kbd_getc            kbdGetc
    KBD_GETS            kbd_gets            kbdGets
    KBD_KEYPRESSED      kbd_keypressed      kbdKeyPressed
    KBD_LINE_READ       kbd_line_read       kbdLineRead
    KBD_RAW_GETC        kbd_raw_getc        kbdRawGetc
    KBD_WORD_READ       kbd_word_read       kbdWordRead

13.19 Actions for the list type

    Action name         lstlib.c function
    LST_CAT             lst_cat
    LST_CPY             lst_cpy
    LST_CREATE          lst_create
    LST_DESTR           lst_destr
    LST_ELEM            lst_elem
    LST_EMPTY           lst_empty
    LST_EXCL            lst_excl
    LST_HEAD            lst_head
    LST_IDX             lst_idx
    LST_INCL            lst_incl
    LST_LNG             lst_lng
    LST_RANGE           lst_range
    LST_TAIL            lst_tail

13.20 Actions for the type pollData

    Action name         pollib.c function   pol_unx.c/pol_sel.c function
    POL_ADD_CHECK       pol_addCheck        polAddCheck
    POL_CLEAR           pol_clear           polClear
    POL_CPY             pol_cpy             polCpy
    POL_CREATE          pol_create          polCreate
    POL_DESTR           pol_destr           polDestr
    POL_EMPTY           pol_empty           polEmpty
    POL_GET_CHECK       pol_getCheck        polGetCheck
    POL_GET_FINDING     pol_getFinding      polGetFinding
    POL_HAS_NEXT        pol_hasNext         polHasNext
    POL_ITER_CHECKS     pol_iterChecks      polIterChecks
    POL_ITER_FINDINGS   pol_iterFindings    polIterFindings
    POL_NEXT_FILE       pol_nextFile        polNextFile
    POL_POLL            pol_poll            polPoll
    POL_REMOVE_CHECK    pol_removeCheck     polRemoveCheck
    POL_VALUE           pol_value           polValue

13.21 Actions for proc operations and statements

    Action name         prclib.c function    
    PRC_ARGS            prc_args             
    PRC_BEGIN           prc_begin            
    PRC_BLOCK           prc_block            
    PRC_BLOCK_DEF       prc_block_def        
    PRC_CASE            prc_case            switch
    PRC_CASE_DEF        prc_case_def        switch
    PRC_CPY             prc_cpy              
    PRC_CREATE          prc_create           
    PRC_DECLS           prc_decls            
    PRC_DYNAMIC         prc_dynamic          
    PRC_EXIT            prc_exit            exit
    PRC_FOR_DOWNTO      prc_for_downto      for
    PRC_FOR_TO          prc_for_to          for
    PRC_HEAPSTAT        prc_heapstat         
    PRC_HSIZE           prc_hsize           heapsize
    PRC_IF              prc_if              if
    PRC_IF_ELSIF        prc_if_elsif        if
    PRC_INCLUDE         prc_include          
    PRC_LOCAL           prc_local            
    PRC_NOOP            prc_noop            prcNoop
    PRC_RAISE           prc_raise           raise_error
    PRC_REPEAT          prc_repeat          do
    PRC_RES_BEGIN       prc_res_begin        
    PRC_RES_LOCAL       prc_res_local        
    PRC_RETURN          prc_return           
    PRC_RETURN2         prc_return2          
    PRC_SETTRACE        prc_settrace         
    PRC_TRACE           prc_trace            
    PRC_VARFUNC         prc_varfunc          
    PRC_VARFUNC2        prc_varfunc2         
    PRC_WHILE           prc_while           while

13.22 Actions for the type program

    Action name         prglib.c function   prg_comp.c function
    PRG_CPY             prg_cpy             prgCpy
    PRG_CREATE          prg_create           
    PRG_DECL_OBJECTS    prg_decl_objects    prgDeclObjects
    PRG_DESTR           prg_destr            
    PRG_EMPTY           prg_empty            
    PRG_EQ              prg_eq              ==
    PRG_ERROR_COUNT     prg_error_count     prgErrorCount
    PRG_EVAL            prg_eval            prgEval
    PRG_EXEC            prg_exec            prgExec
    PRG_FIL_PARSE       prg_fil_parse       prgFilParse
    PRG_FIND            prg_find             
    PRG_INTERPRETER     prg_interpreter     interpreterPath
    PRG_MATCH           prg_match           prgMatch
    PRG_MATCH_EXPR      prg_match_expr      prgMatchExpr
    PRG_NAME            prg_name            arg_0
    PRG_NE              prg_ne              !=
    PRG_PATH            prg_path            programPath
    PRG_PROG            prg_prog             
    PRG_STR_PARSE       prg_str_parse       prgStrParse
    PRG_SYOBJECT        prg_syobject        prgSyobject
    PRG_SYSVAR          prg_sysvar          prgSysvar
    PRG_VALUE           prg_value           prgValue

13.23 Actions for the type reference

    Action name         reflib.c function   ref_data.c function
    REF_ADDR            ref_addr            &
    REF_ALLOC           ref_alloc           refAlloc
    REF_ARRMAXIDX       ref_arrmaxidx       refArrmaxidx
    REF_ARRMINIDX       ref_arrminidx       refArrminidx
    REF_ARRTOLIST       ref_arrtolist       refArrtolist
    REF_BODY            ref_body            refBody
    REF_BUILD           ref_build            
    REF_CAST            ref_cast             
    REF_CATEGORY        ref_category        refCategory
    REF_CAT_PARSE       ref_cat_parse       refCatParse
    REF_CAT_STR         ref_cat_str         refCatStr
    REF_CMP             ref_cmp             refCmp
    REF_CONTENT         ref_content          
    REF_CONV            ref_conv            (noop)
    REF_CPY             ref_cpy             refCpy
    REF_CREATE          ref_create          refCreate
    REF_DEREF           ref_deref            
    REF_EQ              ref_eq              ==
    REF_FILE            ref_file            refFile
    REF_FIND            ref_find             
    REF_HASHCODE        ref_hashcode        (inttype)(((memsizetype)a)>>6)
    REF_HSHDATATOLIST   ref_hshdatatolist   refHshDataToList
    REF_HSHKEYTOLIST    ref_hshkeytolist    refHshKeyToList
    REF_ISSYMB          ref_issymb           
    REF_ISVAR           ref_isvar           refIsvar
    REF_ITFTOSCT        ref_itftosct        refItftosct
    REF_LINE            ref_line            refLine
    REF_LOCAL_CONSTS    ref_local_consts    refLocalConsts
    REF_LOCAL_VARS      ref_local_vars      refLocalVars
    REF_MKREF           ref_mkref            
    REF_NAME            ref_name             
    REF_NE              ref_ne              !=
    REF_NIL             ref_nil              
    REF_NUM             ref_num             refNum
    REF_PARAMS          ref_params          refParams
    REF_PROG            ref_prog             
    REF_RESINI          ref_resini          refResini
    REF_RESULT          ref_result          refResult
    REF_SCAN            ref_scan             
    REF_SCTTOLIST       ref_scttolist       refScttolist
    REF_SELECT          ref_select          a->stru[b]
    REF_SETCATEGORY     ref_setcategory     refSetCategory
    REF_SETPARAMS       ref_setparams       refSetParams
    REF_SETTYPE         ref_settype         refSetType
    REF_STR             ref_str             refStr
    REF_SYMB            ref_symb             
    REF_TRACE           ref_trace           printf
    REF_TYPE            ref_type            refType
    REF_VALUE           ref_value           refValue

13.24 Actions for the type ref_list

    Action name         rfllib.c function   rfl_data.c function
    RFL_APPEND          rfl_append          rflAppend
    RFL_CAT             rfl_cat             rflCat
    RFL_CPY             rfl_cpy             rflCpy
    RFL_CREATE          rfl_create          rflCreate
    RFL_DESTR           rfl_destr           rflDestr
    RFL_ELEM            rfl_elem            rflElem
    RFL_ELEMCPY         rfl_elemcpy         rflElemcpy
    RFL_EMPTY           rfl_empty            
    RFL_EQ              rfl_eq              rflEq
    RFL_EXCL            rfl_excl             
    RFL_EXPR            rfl_expr             
    RFL_FOR             rfl_for             for
    RFL_FOR_UNTIL       rfl_for_until       for
    RFL_HEAD            rfl_head            rflHead
    RFL_IDX             rfl_idx             rflIdx
    RFL_INCL            rfl_incl            rflIncl
    RFL_IPOS            rfl_ipos            rflIpos
    RFL_LNG             rfl_lng             rflLng
    RFL_MKLIST          rfl_mklist          rflMklist
    RFL_NE              rfl_ne              rflNe
    RFL_NOT_ELEM        rfl_not_elem        !rflElem
    RFL_POS             rfl_pos             rflPos
    RFL_RANGE           rfl_range           rflRange
    RFL_SETVALUE        rfl_setvalue        rflSetvalue
    RFL_TAIL            rfl_tail            rflTail
    RFL_TRACE           rfl_trace            
    RFL_VALUE           rfl_value           rflValue

13.25 Actions for struct types

    Action name         sctlib.c function    
    SCT_ALLOC           sct_alloc            
    SCT_CAT             sct_cat              
    SCT_CONV            sct_conv             
    SCT_CPY             sct_cpy             cpy_ ...
    SCT_CREATE          sct_create          create_ ...
    SCT_DESTR           sct_destr           destr_ ...
    SCT_ELEM            sct_elem             
    SCT_EMPTY           sct_empty            
    SCT_INCL            sct_incl             
    SCT_LNG             sct_lng              
    SCT_REFIDX          sct_refidx           
    SCT_SELECT          sct_select          a->stru[b]

13.26 Actions for set types

    Action name         setlib.c function   set_rtl.c function
    SET_ARRLIT          set_arrlit          setArrlit
    SET_BASELIT         set_baselit         setBaselit
    SET_CARD            set_card            setCard
    SET_CMP             set_cmp             setCmp
    SET_CONV            set_conv            (noop)
    SET_CPY             set_cpy             setCpy
    SET_CREATE          set_create          setCreate
    SET_DESTR           set_destr           setDestr
    SET_DIFF            set_diff            setDiff
    SET_ELEM            set_elem            setElem
    SET_EMPTY           set_empty            
    SET_EQ              set_eq              setEq
    SET_EXCL            set_excl            setExcl
    SET_GE              set_ge              setIsSubset(b, a)
    SET_GT              set_gt              setIsProperSubset(b, a)
    SET_HASHCODE        set_hashcode        setHashCode
    SET_ICONV           set_iconv           setIConv
    SET_INCL            set_incl            setIncl
    SET_INTERSECT       set_intersect       setIntersect
    SET_LE              set_le              setIsSubset
    SET_LT              set_lt              setIsProperSubset
    SET_MAX             set_max             setMax
    SET_MIN             set_min             setMin
    SET_NE              set_ne              setNe
    SET_NEXT            set_next            setNext
    SET_NOT_ELEM        set_not_elem        !setElem
    SET_RAND            set_rand            setRand
    SET_RANGELIT        set_rangelit        setRangelit
    SET_SCONV           set_sconv           setSConv
    SET_SYMDIFF         set_symdiff         setSymdiff
    SET_UNION           set_union           setUnion
    SET_VALUE           set_value           setValue

13.27 Actions for the type PRIMITIVE_SOCKET

    Action name         strlib.c function   str_rtl.c function
    SOC_ACCEPT          soc_accept          socAccept
    SOC_ADDR_FAMILY     soc_addr_family     socAddrFamily
    SOC_ADDR_NUMERIC    soc_addr_numeric    socAddrNumeric
    SOC_ADDR_SERVICE    soc_addr_service    socAddrService
    SOC_BIND            soc_bind            socBind
    SOC_CLOSE           soc_close           socClose
    SOC_CONNECT         soc_connect         socConnect
    SOC_CPY             soc_cpy             =
    SOC_CREATE          soc_create           
    SOC_EMPTY           soc_empty            
    SOC_EQ              soc_eq              ==
    SOC_GETC            soc_getc            socGetc
    SOC_GETS            soc_gets            socGets
    SOC_GET_ADDR        soc_get_addr        socGetAddr
    SOC_GET_HOSTNAME    soc_get_hostname    socGetHostname
    SOC_HAS_NEXT        soc_has_next        socHasNext
    SOC_INET_ADDR       soc_inet_addr       socInetAddr
    SOC_INET_LOCAL_ADDR soc_inet_local_addr socInetLocalAddr
    SOC_INET_SERV_ADDR  soc_inet_serv_addr  socInetServAddr
    SOC_INPUT_READY     soc_input_ready     socInputReady
    SOC_LINE_READ       soc_line_read       socLineRead
    SOC_LISTEN          soc_listen          socListen
    SOC_NE              soc_ne              !=
    SOC_RECV            soc_recv            socRecv
    SOC_RECVFROM        soc_recvfrom        socRecvfrom
    SOC_SEND            soc_send            socSend
    SOC_SENDTO          soc_sendto          socSendto
    SOC_SOCKET          soc_socket          socSocket
    SOC_WORD_READ       soc_word_read       socWordRead
    SOC_WRITE           soc_write           socWrite

13.28 Actions for the type string

    Action name         strlib.c function   str_rtl.c function
    STR_APPEND          str_append          strAppend
    STR_CAT             str_cat             strConcat, strConcatTemp
    STR_CHIPOS          str_chipos          strChIpos
    STR_CHPOS           str_chpos           strChPos
    STR_CHSPLIT         str_chsplit         strChSplit
    STR_CLIT            str_clit            strCLit
    STR_CMP             str_cmp             strCompare
    STR_CPY             str_cpy             strCopy
    STR_CREATE          str_create          strCreate
    STR_DESTR           str_destr           strDestr
    STR_ELEMCPY         str_elemcpy         a->mem[b-1]=c
    STR_EQ              str_eq              a->size==b->size && memcmp(a,b,a->size*sizeof(strelemtype))==0
    STR_GE              str_ge              strGe
    STR_GT              str_gt              strGt
    STR_HASHCODE        str_hashcode        strHashCode
    STR_HEAD            str_head            strHead
    STR_IDX             str_idx             a->mem[b-1]
    STR_IPOS            str_ipos            strIpos
    STR_LE              str_le              strLe
    STR_LIT             str_lit             strLit
    STR_LNG             str_lng             a->size
    STR_LOW             str_low             strLow, strLowTemp
    STR_LPAD            str_lpad            strLpad
    STR_LPAD0           str_lpad0           strLpad0, strLpad0Temp
    STR_LT              str_lt              strLt
    STR_MULT            str_mult            strMult
    STR_NE              str_ne              a->size!=b->size || memcmp(a,b,a->size*sizeof(strelemtype))!=0
    STR_POS             str_pos             strPos
    STR_POSCPY          str_poscpy          memcpy
    STR_PUSH            str_push            strPush
    STR_RANGE           str_range           strRange
    STR_RCHIPOS         str_rchipos         strRChIpos
    STR_RCHPOS          str_rchpos          strRChPos
    STR_REPL            str_repl            strRepl
    STR_RIPOS           str_ripos           strRIPos
    STR_RPAD            str_rpad            strRpad
    STR_RPOS            str_rpos            strRpos
    STR_SPLIT           str_split           strSplit
    STR_STR             str_str             (noop)
    STR_SUBSTR          str_substr          strSubstr
    STR_TAIL            str_tail            strTail
    STR_TOUTF8          str_toutf8          strToUtf8
    STR_TRIM            str_trim            strTrim
    STR_UP              str_up              strUp, strUpTemp
    STR_UTF8TOSTRI      str_utf8tostri      strUtf8ToStri
    STR_VALUE           str_value           strValue

13.29 Actions for the type time

    Action name         timlib.c function   tim_unx.c/tim_win.c function
    TIM_AWAIT           tim_await           timAwait
    TIM_FROM_TIMESTAMP  tim_from_timestamp  timFromTimestamp
    TIM_NOW             tim_now             timNow
    TIM_SET_LOCAL_TZ    tim_set_local_tz    timSetLocalTZ

13.30 Actions for the type type

    Action name         typlib.c function   typ_data.c function
    TYP_ADDINTERFACE    typ_addinterface     
    TYP_CMP             typ_cmp             typCmp
    TYP_CPY             typ_cpy             typCpy
    TYP_CREATE          typ_create          typCreate
    TYP_DESTR           typ_destr           typDestr
    TYP_EQ              typ_eq              ==
    TYP_FUNC            typ_func            typFunc
    TYP_GENSUB          typ_gensub           
    TYP_GENTYPE         typ_gentype          
    TYP_HASHCODE        typ_hashcode        (inttype)(((memsizetype)a)>>6)
    TYP_ISDECLARED      typ_isdeclared       
    TYP_ISDERIVED       typ_isderived       typIsDerived
    TYP_ISFORWARD       typ_isforward        
    TYP_ISFUNC          typ_isfunc          typIsFunc
    TYP_ISVARFUNC       typ_isvarfunc       typIsVarfunc
    TYP_MATCHOBJ        typ_matchobj        typMatchobj
    TYP_META            typ_meta            typMeta
    TYP_NE              typ_ne              !=
    TYP_NUM             typ_num             typNum
    TYP_RESULT          typ_result          typResult
    TYP_STR             typ_str             typStr
    TYP_VALUE           typ_value           typValue
    TYP_VARCONV         typ_varconv          
    TYP_VARFUNC         typ_varfunc         typVarfunc

13.31 Actions for the type utf8_file

    Action name         ut8lib.c function   ut8_rtl.c function
    UT8_GETC            ut8_getc            ut8Getc
    UT8_GETS            ut8_gets            ut8Gets
    UT8_LINE_READ       ut8_line_read       ut8LineRead
    UT8_SEEK            ut8_seek            ut8Seek
    UT8_WORD_READ       ut8_word_read       ut8WordRead
    UT8_WRITE           ut8_write           ut8Write



14. ERRORS
==========

14.1 Compile time errors

  The compile time errors are not fatal (the program can
  execute) except for the error 1 (Out of heap space) which
  terminates the compilation process and no execution occurs.
  The following compile time errors exist:

     1: Fatal Error: Out of heap space
     2: File "%s" not found
     3: Include file "%s" not found
     4: "END OF FILE" encountered
     5: Illegal character in text "%s"
     6: Unclosed comment
     7: Illegal pragma "%s"
     8: Illegal action "%s"
     9: Illegal system declaration "%s"
    10: Integer "%s" too big
    11: Negative exponent in integer literal
    12: Digit expected found "%s"
    13: Integer "%dE%s" too big
    14: Integer base "%ld" not between 2 and 36
    15: Extended digit expected found "%s"
    16: Illegal digit "%c" in based integer "%d#%s"
    17: Based integer "%d#%s" too big
    18: "'" expected found "%s"
    19: Character literal exceeds source line
    20: Use \" instead of "" to represent " in a string
    21: Use / instead of \\ as path delimiter
    22: Illegal string escape "\%s"
    23: Numerical escape sequences should end with "\" not "%s");
    24: String continuations should end with "\" not "%s");
    25: String literal exceeds source line
    26: Name expected found "%s"
    27: Integer literal expected found "%s"
    28: String literal expected found "%s"
    29: Identifier expected found "%s"
    30: Expression expected found "%s"
    31: Declaration of parameter %s failed
    32: Declaration of "%s" failed
    33: Exception "%s" raised
    34: "%s" declared twice
    35: "%s" not declared
    36: Associativity expected found "%s"
    37: Statement priority "%s" too big
    38: Syntax with two parameters before operator is illegal
    39: Empty syntax declaration
    40: Dot expression requested as syntax description
    41: "%s" redeclared with infix priority %d not %d
    42: "%s" redeclared with prefix priority %d not %d
    43: Priority %d required for parameter after "%s" not %d
    44: Priority <= %d expected found "%s" with priority %d
    45: "%s" must have priority %d not %d for dot expression
    46: "%s" expected found "%s"
    47: "%s" expected found "%s"
    48: Undefined type for literal "%s"
    49: "newtype", "subtype", "func", "enumlit" or "action" expected found "%s"
    50: "func" or "type" expected found "%s"
    51: Match for %s failed
    52: Variable expected in %s found %s
    53: Type expected found %s
    54: Procedure expected found %s expression
    55: Parameter specifier expected found "%s"
    56: Evaluate type expression %s failed
        Undefined error


14.2 Exceptions

  There are various exceptions which can be raised during
  program execution:

    MEMORY_ERROR:
      May be raised by various operations of the following types:
          'array', 'struct', 'hash', 'file', 'func', 'proc', 'reference', 'string'.
      Additionally the interpreter kernel may raise this exception also.
    NUMERIC_ERROR:
      May be raised from the following 'integer' operations:
          !, **, div, rem, mdiv, mod, ld.
      May be raised from the following 'bigInteger' operations:
          **, div, rem, mdiv, mod.
    RANGE_ERROR:
      May be raised from the following 'integer' operation:
          parse, rand.
      May be raised from the following 'bigInteger' operation:
          parse, rand.
      May be raised from the following 'float' operation:
          parse, rand.
      May be raised from the following 'char' operation:
          str.
      May be raised from the following 'string' operation:
          @:=, mult, pos.
      May be raised from the following 'bitset' operation:
          min, max, rand.
      May be raised from the following 'array' operation:
          [ ].
      May be raised from the following 'hash' operation:
          [ ].
      May be raised from the following 'file' operation:
          open, gets, write, seek.
    FILE_ERROR:
      May be raised by the following functions:
          fileSize, bigFileSize, fileType, fileTypeSL, fileMode, setFileMode,
          readDir, remove, removeAnyFile, rename, cloneFile, copyFile,
          readlink, symlink, hasNext, seek, tell, bigTell, setbuf, write,
          inetSocketAddress, openInetSocket, openInetListener
    ILLEGAL_ACTION:
      May be raised by the interpreter kernel when a primitive action
      does not point to any legal action. This check is only done when
      the hi interpreter is compiled with '#define WITH_ACTION_CHECK'.
      The ILLEGAL_ACTION exception is also raised when the primitive
      action ACT_ILLEGAL is executed.

  A program can raise an exception with the 'raise' statement. For example:

    raise RANGE_ERROR;


14.3 Handlers

  To catch an EXCEPTION the following handler construct can be used:

    block
      number := 1 div 0;
    exception
      catch NUMERIC_ERROR:
        number := 1;
    end block;

  It is also possible to catch several EXCEPTIONS:

    block
      doSomething(someValue);
    exception
      catch MEMORY_ERROR:  writeln("MEMORY_ERROR");
      catch NUMERIC_ERROR: writeln("NUMERIC_ERROR");
    end block;


14.4 Stack trace

  When an EXCEPTION is not caught the program is terminated and the hi
  interpreter writes a stack trace:

    *** Uncaught EXCEPTION NUMERIC_ERROR raised with
    {integer: <SYMBOLOBJECT> *NULL_ENTITY_OBJECT* div fuel_max }

    Stack:
    in {(val integer param) div (val integer param) } at integer.s7i(95)
    in init_display at lander.sd7(840)
    in setup at lander.sd7(909)
    in main at lander.sd7(1541)

  The stack trace shows that a 'NUMERIC_ERROR' was raised by the 'div' operation.
  This operation is defined in line 95 of "integer.s7i". More interesting is that
  'div' was called from the function 'init_display' in
  line 840 of "lander.sd7". A 'NUMERIC_ERROR' with 'div' is
  probably caused by a zero division. A short examination in "lander.sd7" shows that an assignment to
  'fuel_max' was commented out to show how stack traces work.

  A compiled program creates a much shorter crash message:

    *** Uncaught EXCEPTION NUMERIC_ERROR raised at tmp_lander.c(764)

  To get more information there are two possibilities:

     - Start the program in the interpreter instead.
     - Compile the program with the options -g -e and start it
       from a debugger.

  The option -g instructs the C compiler to include
  debugging information. This way a debugger like gdb can
  run the program and provide information. The option -e
  tells the compiler to generate code which sends a signal
  when an uncaught exception occurs. This option allows
  debuggers to handle uncaught Seed7 exceptions. Note that
  -e sends the signal SIGFPE. This is done even when the
  exception is not related to floating point operations.

    ./hi comp -g -e lander
    gdb ./lander

  Then the debugger should be able to run the program and to
  write a backtrace when a crash occurs:

    (gdb) run
    Starting program: /home/tm/seed7_5/prg/lander 

    Program received signal SIGFPE, Arithmetic exception.
    0x08068518 in o_2541_init_display () at lander.sd7:840
    840	    fuel_gauge := 40 * rocket.fuel div fuel_max;
    (gdb) bt
    #0  0x08068518 in o_2541_init_display () at lander.sd7:840
    #1  0x08068c21 in o_2546_setup () at lander.sd7:909
    #2  0x0806c304 in main (argc=1, argv=0xbffff324) at lander.sd7:1541

  Sometimes it is helpful to debug the generated C program instead of
  the Seed7 source. The option -g-debug_c creates debug
  information, which refers to the C program generated by the Seed7 compiler:

    ./hi comp -g-debug_c -e lander
    gdb ./lander

  Now the debugger refers to the temporary file "tmp_lander.c":  

    (gdb) run
    Starting program: /home/tm/seed7_5/prg/lander 

    Program received signal SIGFPE, Arithmetic exception.
    0x08068518 in o_2541_init_display () at tmp_lander.c:19727
    19727	o_2428_fuel_gauge=((40) * (((structtype)(o_2338_rocket))->stru[10].value.intvalue/*->o_2336_fuel*/)) / (o_2431_fuel_max);
    (gdb) bt
    #0  0x08068518 in o_2541_init_display () at tmp_lander.c:19727
    #1  0x08068c21 in o_2546_setup () at tmp_lander.c:19864
    #2  0x0806c304 in main (argc=1, argv=0xbffff324) at tmp_lander.c:21188

  Some Seed7 exceptions do not send signals. This hinders the debugger
  to recognize that an uncaught exception occurred. The compiler option -e
  can help in this situation. It instructs the compiler to generate
  code which sends a signal when an uncaught exception occurs. This
  allows the debugger to show a backtrace for uncaught Seed7 exceptions.


14.5 Other errors and warnings

  No more memory. Program terminated.
    This error message is displayed after the compile time error 1
    (Out of heap space) . The file name and line number of the
    analyzer source code where this happens is displayed together
    with internal heap information. If this happens the -m option
    can be used to make more memory available. Perhaps this slows
    the compilation phase down.

  System declaration for main missing
    Each program must contain a system declaration that describes
    which procedure to start as first one.

  EXCEPTION %s raised with
    If your trace level specifies exception tracing exceptions
    and handlers are displayed with this messages and the user
    must type the ENTER-key to accept.

  ACTION $%s REQUIRES %s NOT %s
    This error can happen when an action tries to do something
    with the wrong primitive value. For example adding an
    integer to a string with INT_ADD. Since the analyze phase
    checks for the right types this error can only happen when the
    basic libraries are defined wrong.

  ACTION $%s REQUIRES VARIABLE %s NOT %s
    This error can happen with actions which assign a value to
    a constant. Since the analyze phase checks for variable objects
    this error can only happen when the basic libraries are defined
    wrong. Principally this error is possible with the following
    operations: :=, incr, decr, wrd_rd, lin_rd

