
(********************************************************************)
(*                                                                  *)
(*  manual.txt                                                      *)
(*                                                                  *)
(*  Copyright (C) 1989 - 2021  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     Greeting
  2.3     Local declarations and expressions
  2.4     For loop and float expressions
  2.5     For loop and containers
  2.6     Parameters
  2.7     Declare a statement
  2.8     Template declaring a statement
  3.    DECLARATIONS
  3.1     Normal declarations
  3.2     Syntax declarations
  3.3     System declarations
  3.4     Pragmas
  4.    PREDEFINED STATEMENTS
  4.1     Assignment
  4.2     while-statement
  4.3     repeat-statement
  4.4     for-statement
  4.5     for-step-statement
  4.6     for-each-statement
  4.7     if-statement
  4.8     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.    FILE INPUT AND OUTPUT
  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 Seed7 Structured Syntax Description
  9.3     The syntax of a statement
  9.4     Priority and associativity
  9.5     The syntax of operators
  9.6     Syntax of predefined statements
  9.7     Advanced syntax definitions
  9.8     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    BigInteger literals
  10.3.3    Float literals
  10.3.4    String literals
  10.3.5    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    homeDir
  12.8    fileType
  12.9    fileMode
  12.10   setFileMode
  12.11   fileSize
  12.12   getATime
  12.13   getCTime
  12.14   getMTime
  12.15   setATime
  12.16   setMTime
  12.17   readlink
  12.18   symlink
  12.19   removeFile
  12.20   removeTree
  12.21   copyFile
  12.22   cloneFile
  12.23   moveFile
  12.24   argv(PROGRAM)
  12.25   name(PROGRAM)
  12.26   path(PROGRAM)
  12.27   dir(PROGRAM)
  12.28   file(PROGRAM)
  12.29   getenv
  12.30   setenv
  12.31   environment
  13.   DATABASE ABSTRACTION API
  13.1    Opening a database connection
  13.2    Other ways to open a database connection
  13.3    Prepared statements
  13.4    Bind values to placeholders
  13.5    Execute a prepared statement
  13.6    Fetch records from the result set
  13.7    Get columns from fetched records
  14.   PRIMITIVE ACTIONS
  14.1    Actions for the type ACTION
  14.2    Actions for array types
  14.3    Actions for the type bigInteger
  14.4    Actions for the types bin32 and bin64
  14.5    Actions for the type boolean
  14.6    Actions for byte strings
  14.7    Actions for the type char
  14.8    Actions for various directory, file and other commands
  14.9    Actions for text (console) screen output
  14.10   Actions for declarations
  14.11   Actions to do graphic output
  14.12   Actions for enumeration types
  14.13   Actions for the type clib_file
  14.14   Actions for the type float
  14.15   Actions to support the graphic keyboard
  14.16   Actions for hash types
  14.17   Actions for the type integer
  14.18   Actions for interface types
  14.19   Actions to support the text (console) screen keyboard
  14.20   Actions for the list type
  14.21   Actions for the type process
  14.22   Actions for the type pollData
  14.23   Actions for proc operations and statements
  14.24   Actions for the type program
  14.25   Actions for the type reference
  14.26   Actions for the type ref_list
  14.27   Actions for struct types
  14.28   Actions for set types
  14.29   Actions for the type PRIMITIVE_SOCKET
  14.30   Actions for the types database and sqlStatement
  14.31   Actions for the type string
  14.32   Actions for the type time
  14.33   Actions for the type type
  14.34   Actions for the type utf8_file
  15.   FOREIGN FUNCTION INTERFACE
  15.1    C types used by the implementation
  15.2    String conversions
  15.3    Operating system string and path conversions
  15.4    Macros to access the action parameters
  15.5    Functions to create action results
  15.6    Memory management macros
  15.7    Basic conversion functions
  15.8    Error handling
  16.   ERRORS
  16.1    Parsing errors
  16.2    Compilation errors
  16.3    Exceptions
  16.3.1  MEMORY_ERROR
  16.3.2  NUMERIC_ERROR
  16.3.3  OVERFLOW_ERROR
  16.3.4  INDEX_ERROR
  16.3.5  RANGE_ERROR
  16.3.6  FILE_ERROR
  16.3.7  DATABASE_ERROR
  16.3.8  ILLEGAL_ACTION
  16.4    Handlers
  16.5    Stack trace
  16.6    Suppressing exception checks
  16.7    Signals
  16.8    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 defined 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:

     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 which search for some data in a database can become
  more understandable by using a for statement to loop over the
  tables. A usage of such a for statement could be:

    for person1, person2
    where person1.age = person2.age and
         person1.mother = person2.mother and
         person1 <> person2 do
       writeln("Twins: " <& person1.name <& " and " <& person2.name);
    end for;

  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
      defined 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 gotos like break- and continue-statements are
      also omitted.

    - There is no return statement. Instead a result variable
      can be defined 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 defined 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:

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

    - Line 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
      defined.

    - 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
===========

    At the beginning we show how the basic features, that every programming
  language has, look like in Seed7.


2.1 Hello world

    Below is the hello world program of Seed7:

    $ include "seed7_05.s7i";

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

  Save this program to the file hello.sd7 and start it in a console with:

    s7 hello

  The Seed7 interpreter writes something like

    SEED7 INTERPRETER Version 5.0.11428  Copyright (c) 1990-2020 Thomas Mertes
    hello world

  You get information about the Seed7 interpreter and
  the output of the hello.sd7 program:

    hello world

  The the option -q can be used to suppress the line
  with information about the Seed7 interpreter:

    s7 -q hello

  The first line of the program

    $ include "seed7_05.s7i";

  includes all definitions of the standard library. In contrast to
  other 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.

  In the example above '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.


2.2 Greeting

    The program below starts a little dialog:

    $ include "seed7_05.s7i";

    const proc: main is func
      local
        var string: name is "";
      begin
        write("What's your name? ");
        readln(name);
        writeln("Hi " <& name <& "!");
      end func;

  Save this program to the file greeting.sd7 and start it in a console
  with:

    s7 greeting

  The program asks you for your name with:

    What's your name?

  After you entered your name and pressed enter it will greet you.
  This program uses the variable 'name' to store the name you entered.
  Variables must be defined. The place to to define and initialize
  all variables of a function is after the keyword local.

        var string: name is "";

  This defines the 'string' variable 'name'. This definition assigns
  also the initial value "" to 'name'. In Seed7 variables must be
  defined and always get an initial value. This seems unnecessary in
  small programs, but if programs grow bigger it helps readability a lot.

  The 'write' statement is similar to 'writeln', but it does not write
  a newline character. The 'readln' statement reads a line from the
  standard input file and assigns this line to the given variable.
  This function allows the usage of backspace the correct the input.
  By pressing enter the line is sent to the program. The final
  'writeln' statement contains the operator <& to concatenate strings.
  If necessary the <& operator converts values to 'string'.

  The greeting program above has a problem. If someone refuses to
  type his name and just presses enter the program writes:

    Hi !

  To avoid this we improve the program to check for special cases:

    $ include "seed7_05.s7i";

    const proc: main is func
      local
        var string: name is "";
      begin
        write("What's your name? ");
        readln(name);
        if name = "" then
          writeln("Greetings to the person who pressed enter!");
        elsif name = "name" then
          writeln("Interesting, your name is name.");
        else
          writeln("Hi " <& name <& "!");
        end if;
      end func;

  There can be zero or more 'elsif' parts, and the 'else' part
  is optional. As you can see the equaliy of strings is checked with '='.
  An if-statement is one way to improve the greeting program.
  Alternatively we can use a loop to insist on entering a name:

    $ include "seed7_05.s7i";

    const proc: main is func
      local
        var string: name is "";
      begin
        repeat
          write("What's your name? ");
          readln(name);
        until name <> "";
        writeln("Hi " <& name <& "!");
      end func;

  The repeat ... until loop repeats the statements
  between the two keywords until the condition name <> "" is TRUE.
  Note that the statements in the repeat loop are executed
  at least once. A solution with a while loop is:

    $ include "seed7_05.s7i";

    const proc: main is func
      local
        var string: name is "";
      begin
        write("What's your name? ");
        readln(name);
        while name = "" do
          write("Just pressing enter is not okay. What's your name? ");
          readln(name);
        end while;
        writeln("Hi " <& name <& "!");
      end func;

  The while loop repeats the statements between the keywords
  'do' and 'end' as long as the condition name = "" is TRUE.
  Note that the statements in a while loop might not be executed at all.
  In the example above this happens if a non-empty name is entered
  after the question: What's your name?


2.3 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;
          writeln(fahr <& " " <& celsius);
          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. The variable 'fahr' is
  incremented with the '+:=' operator. The expression to compute the
  'celsius' value uses an integer division ('div'). 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.4 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 executes the loop body with
  different values of 'fahr' (0, 20, 40 .. 280, 300). Omitting
  the 'step' part corrensponds to a step of 1:

    for fahr range lower to upper do
      celsius := flt(5 * (fahr - 32)) / 9.0;
      writeln(fahr lpad 3 <& " " <& celsius digits 2 lpad 6);
    end for;

  The keyword 'downto' can be used to run the for-loop backward:

    for fahr range upper downto lower do
      celsius := flt(5 * (fahr - 32)) / 9.0;
      writeln(fahr lpad 3 <& " " <& celsius digits 2 lpad 6);
    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.5 For loop and containers

    A for-loop can be used to iterate over an 'array':

    $ include "seed7_05.s7i";

    const proc: main is func
      local
        var integer: number is 0;
      begin
        for number range [] (0, 1, 2, 3, 5, 8, 13, 20, 40, 100) do
          write(number <& " ");
        end for;
        writeln;
      end func;

  In the example above '[] (0, 1, 2, 3, 5, 8, 13, 20, 40, 100)'
  is an array literal. For-loops can also interate over the elements
  of a 'set':

    $ include "seed7_05.s7i";

    const proc: main is func
      local
        var string: innerPlanet is "";
      begin
        for innerPlanet range {"Mercury", "Venus", "Earth", "Mars"} do
          write(innerPlanet <& " ");
        end for;
        writeln;
      end func;

  In the example above '{"Mercury", "Venus", "Earth", "Mars"}' is a set
  literal. For-loops can interate over the characters of a 'string':

    $ include "seed7_05.s7i";

    const proc: main is func
      local
        const set of char: vowels is {'a', 'e', 'i', 'o', 'u'};
        var char: letter is ' ';
      begin
        for letter range "the quick brown fox jumps over the lazy dog" do
          if letter not in vowels then
            write(letter);
          end if;
        end for;
        writeln;
      end func;

  All loops that iterate over a container can be combined with an 'until' condition:

    $ include "seed7_05.s7i";

    const proc: main is func
      local
        var string: testText is "";
        var char: ch is ' ';
        var boolean: controlCharFound is FALSE;
      begin
        write("Enter text: ");
        readln(testText);
        for ch range testText until controlCharFound do
          controlCharFound := ord(ch) < 32;
        end for;
        if controlCharFound then
          writeln("The text contains control chars.");
        end if;
      end func;


2.6 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: fib is 1;
      begin
        if num1 <> 1 and num1 <> 2 then
          fib := 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 parsing error:

    *** tst77.sd7(5):53: 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 parsing error:

    *** tst77.sd7(12):53: 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: stri is "";
      begin
        if number >= 0 then
          repeat
            stri := str(number mod 8) & stri;
            number := number mdiv 8;
          until number = 0;
        end if;
      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.7 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.8 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 sub-chapters.


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 "expr" is expr;
    $ system "integer" is integer;
    $ system "bigInteger" is bigInteger;
    $ 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 "overflow_error" is OVERFLOW_ERROR;
    $ system "range_error" is RANGE_ERROR;
    $ system "index_error" is INDEX_ERROR;
    $ system "file_error" is FILE_ERROR;
    $ system "database_error" is DATABASE_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;


3.4 Pragmas

    Pragmas specify how a program is processed. Like
  system declarations pragmas are introduced with a dollar
  sign ($) followed by the name of the pragma. The following
  pragmas exist:

  +-----------+------------------+----------------------------------------------+
  | pragma    | parameter        | comment                                      |
  +-----------+------------------+----------------------------------------------+
  | $ library | string           | Specify additional direcory for *.s7i files. |
  | $ message | string           | Writes a message during parsing.             |
  | $ info    | on or off        | Switch compilation info on or off.           |
  | $ trace   | string           | Sets compile-time tracing flags.             |
  | $ decls   | -                | Traces the declarations.                     |
  | $ names   | unicode or ascii | Allows Unicode (or Ascii) identifiers.       |
  +-----------+------------------+----------------------------------------------+

  An unknown pragma results in a parsing error:

    *** pragma.sd7(1):7: Illegal pragma "unknownPragma"
    $ unknownPragma
    ---------------^

  The pragma message can be used to write a message during
  parsing. To write "hello world" during parsing use:

    $ message "hello world";

  The pragma info can be used to change the verbosity level of
  the parsing phase. This overrules the -vn option of the
  interpreter. With

    $ info on;

  the parser writes information about library names and the
  number of the line currently processed. With

    $ info off;

  no such information is written.

  The pragma trace can be used to turn interpreter tracing
  on or off during the parsing of the program. This
  overrules the -dx option of the interpreter. The string
  parameter of the trace pragma allows a sequence of the
  characters +, -, a, c, d, e, h, m, u, s and *. These
  characters have the following meaning:

    + Turn the following flags on (default)
    - Turn the following flags off
    a Trace primitive actions
    c Do action check
    d Trace dynamic calls
    e Trace exceptions and handlers
    h Trace heap size (in combination with 'a')
    m Trace matching of expressions
    u Trace exec utility functions
    s Trace signals
    * All flags




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 | for_step_statement | for_each_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: statement1) ; (ref void: statement2) 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: dest) := (ref type: source)             is action "TYP_CPY";
    const proc: (inout proc: dest) := (ref proc: source)             is action "PRC_CPY";
    const proc: (inout func aType: dest) := (ref func aType: source) is action "PRC_CPY";
    const proc: (inout varfunc aType: dest) := (ref varfunc aType: source) is action "PRC_CPY";
    const proc: (inout ACTION: dest) := (in ACTION: source)          is action "ACT_CPY";
    const proc: (inout boolean: dest) := (in boolean: source)        is action "BLN_CPY";
    const proc: (inout integer: dest) := (in integer: source)        is action "INT_CPY";
    const proc: (inout char: dest) := (ref char: source)             is action "CHR_CPY";
    const proc: (inout string: dest) := (ref string: source)         is action "STR_CPY";
    const proc: (inout reference: dest) := (ref reference: source)   is action "REF_CPY";
    const proc: (inout ref_list: dest) := (in ref_list: source)      is action "RFL_CPY";
    const proc: (inout ptrType: dest) := (in ptrType: source)        is action "REF_CPY";
    const proc: (inout varptrType: dest) := (in varptrType: source)  is action "REF_CPY";
    const proc: (inout arrayType: dest) := (in arrayType: source)    is action "ARR_CPY";
    const proc: (inout bitset: dest) := (in bitset: source)          is action "SET_CPY";
    const proc: (inout structType: dest) := (in structType: source)  is action "SCT_CPY";
    const proc: (inout enumType: dest) := (in enumType: source)      is action "ENU_CPY";
    const proc: (inout clib_file: dest) := (ref clib_file: source)   is action "FIL_CPY";
    const proc: (inout interfaceType: dest) := (ref interfaceType: source) is action "ITF_CPY";
    const proc: (inout interfaceType: dest) := (ref aType: source)   is action "ITF_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: condition) do (in proc: statement) end while is action "PRC_WHILE";
    const proc: while (in boolean: condition)  do (in proc: statement) end while      is action "PRC_WHILE";

  Alternate declaration:

    const proc: while (ref func boolean: condition) do (in 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 (in proc: statement) until (ref func boolean: condition) is action "PRC_REPEAT";
    const proc: repeat (in proc: statement) until (in boolean: condition)       is action "PRC_REPEAT";

  Alternate declaration:

    const proc: repeat (in 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: lowerLimit) to (in aType: upperLimit) do
            (in proc: statements) end for is func
          begin
            variable := lowerLimit;
            if variable <= upperLimit then
              statements;
              while variable < upperLimit do
                incr(variable);
                statements;
              end while;
            end if;
          end func;

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

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


4.5 for-step-statement

  For example:

    for evenNumber range 0 to 10 step 2 do
      write(evenNumber);
    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 by the value behind 'step'. Then
      the control variable is 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 by the value behind 'step'.
      Then the control variable is 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_step_statement ::=
      'for' identifier 'range' expression [ 'to' | 'downto' ] expression 'step' expression 'do'
        statement
      'end' 'for' .


  Declaration:

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

    const proc: FOR_STEP_DECLS (in type: aType) is func
      begin
        if getobj((inout aType: variable) +:= (in integer: delta)) <> NIL then

          const proc: for (inout aType: variable) range (in aType: lowerLimit) to (in aType: upperLimit)
              step (in integer: incr_step) do
              (in proc: statements) end for is func
            begin
              variable := lowerLimit;
              while variable <= upperLimit do
                statements;
                variable +:= incr_step;
              end while;
            end func;

        end if;
        if getobj((inout aType: variable) -:= (in integer: delta)) <> NIL then

          const proc: for (inout aType: variable) range (in aType: upperLimit) downto (in aType: lowerLimit)
              step (in integer: decr_step) do
              (in proc: statements) end for is func
            begin
              variable := upperLimit;
              while variable >= lowerLimit do
                statements;
                variable -:= decr_step;
              end while;
            end func;

        end if;
      end func;

    FOR_STEP_DECLS(integer);


4.6 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_each_statement ::=
      'for' identifier 'range' expression 'do'
        statement
      'end' 'for' .


  Declaration:

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

    const proc: for (inout reference: variable) range (in ref_list: aRefList) do
                  (in proc: statement)
                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 minIdx(arr_obj) to maxIdx(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.7 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: dest) ::= 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: dest) ::= (ref ELSIF_RESULT: source) is action "ENU_CREATE";

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

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

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

    const ELSIF_PROC: elsif (in boolean: condition) then
                        (in proc: statements)
                      (in ELSIF_PROC: elsifPart)           is action "PRC_IF_ELSIF";

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


4.8 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' .

    set_expression ::=
      expression .


  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: decisionValue) of end case                     is noop;
        const proc: case (ref aType: decisionValue) of
                      (ref WHEN_PROC: whenPart)
                    end case                                                        is action "PRC_CASE";
        const proc: case (ref aType: decisionValue) of
                      (ref WHEN_PROC: whenPart)
                      otherwise : (ref proc: statements)
                    end case                                                        is action "PRC_CASE_DEF";
        const proc: (ref WHEN_RESULT: dest) ::= enumlit                             is action "ENU_GENLIT";
        const WHEN_RESULT: WHEN_EMPTY (attr aType) is enumlit;
        const proc: (ref WHEN_PROC: dest) ::= (ref WHEN_RESULT: source)             is action "ENU_CREATE";
        const WHEN_PROC: when (ref SELECTOR_TYPE: whenSet) : (ref proc: statement)  is WHEN_EMPTY(aType);
        const WHEN_PROC: when (ref SELECTOR_TYPE: whenSet) : (ref proc: statement)
                           (ref WHEN_PROC: whenPart)                                is WHEN_EMPTY(aType);
      end func;

    CASE_DECLS(integer);
    CASE_DECLS(char);
    CASE_DECLS(boolean);



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

    In the following sub-chapters the predefined types of the
  standard library are introduced. The operators have, if not
  stated otherwise, the type described in the sub-chapter as
  parameter type and result type. The relations have also the
  type described in the sub-chapter 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 )
      A ? B : C  Ternary operator condition ? thenValue : elseValue
                  ( TRUE ? a : b => a,
                    FALSE ? a : b => b )
      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 )
      boolean(A) Convert an integer to a boolean value
                  ( Type of argument A: integer,
                    boolean(0) => FALSE,
                    boolean(1) => TRUE )
      boolean(A) Conversion of string to boolean
                  ( Type of argument A: string,
                    boolean("FALSE") => FALSE,
                    boolean("TRUE") => TRUE,
                    boolean("TRUE ") => EXCEPTION RANGE_ERROR,
                    boolean("ASDF") => EXCEPTION RANGE_ERROR )
      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. If 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:

    +-----------------------------+-------------------------+
    | Expression                  |  Result when the first  |
    |                             |  operand evaluates to   |
    |                             +------------+------------+
    |                             |   FALSE    |    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:

    If 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 64-bit integer
  numbers. An integer 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

  If an 'integer' operation overflows it raises the exception
  OVERFLOW_ERROR. The 'integer' functions are defined
  in the library "integer.s7i".

    Constants:
      integer.first  Minimum value of integer (-9223372036854775808)
      integer.last   Maximum value of integer (9223372036854775807)
    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 for every A, even for A = 0,
                    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 <= 63,
                    A << B => EXCEPTION OVERFLOW_ERROR for B < 0 or B >= 64,
                    A << B => A * 2 ** B,
                    A << 0 => A )
      A >> B    Arithmetic shift right
                  ( A >> B is okay for B >= 0 and B <= 63,
                    A >> B => EXCEPTION OVERFLOW_ERROR for B < 0 or B >= 64,
                    A >> B => A mdiv 2 ** B  for B <= 62,
                    A >> 0 => A,
                    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)),
                    0 >> B => 0 )
      !         Binomial coefficient
                  ( n ! k => 0 for k < 0,
                    n ! 0 => 1,
                    n ! 1 => n,
                    n ! k => 0 for n >= 0 and k > n,
                    n ! k => !n div (!k * !(n - k)) for k >= 0 and k <= n,
                    n ! k => (-1) ** k * (n + k - 1 ! k) for n < 0 and k >= 0 )
      A ? B : C  Ternary operator condition ? thenValue : elseValue
                  ( Type of argument A: boolean,
                    TRUE ? a : b => a,
                    FALSE ? a : b => b )
      A radix B  Convert the integer A to a string. The conversion
                 uses the numeral system with the base B.
                  ( Type of result: string,
                    48879 radix 16 => "beef",
                    -48879 radix 16 => "-beef",
                    123 radix 37 => EXCEPTION RANGE_ERROR )
      A RADIX B  Convert the integer A to a string. The conversion
                 uses the numeral system with the base B.
                  ( Type of result: string,
                    48879 RADIX 16 => "BEEF",
                    -48879 RADIX 16 => "-BEEF",
                    123 RADIX 37 => EXCEPTION RANGE_ERROR )
      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" )
      sci       Conversion to a string in scientific notation
                  ( Type of result: string,
                    12345 sci 4 => "1.2345e+4",
                    12345 sci 3 => "1.235e+4",
                    12345 sci 2 => "1.23e+4",
                    3141592 sci 0 => "3e+6",
                    27182818 sci 0 => "3e+7",
                    2**62 sci 6 => "4.611686e+18",
                    -1 sci 3 => "-1.000e+0",
                    -0 sci 2 => "0.00e+0" )
      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,
                    succ(integer.last) => EXCEPTION OVERFLOW_ERROR )
      pred(A)   Predecessor
                  ( pred(A) => A-1,
                    pred(integer.first) => EXCEPTION OVERFLOW_ERROR )
      abs(A)    Absolute value
                  ( abs(A) => A for A >= 0,
                  ( abs(A) => -A for A < 0,
                  ( abs(integer.first) => EXCEPTION OVERFLOW_ERROR )
      odd(A)    Odd value
                  ( Type of result: boolean )
      str(A)    Conversion to string
                  ( Type of result: string,
                    str(12345) => "12345" )
      literal(A) Conversion to a literal
                  ( Type of result: string,
                    literal(A) => str(A) )
      integer(A) Conversion of string to integer
                  ( Type of argument A: string,
                    integer("123") => 123,
                    integer("-123") => -123,
                    integer("+5") => 5,
                    integer(" 1") => EXCEPTION RANGE_ERROR,
                    integer("10 ") => EXCEPTION RANGE_ERROR,
                    integer("ASDF") => EXCEPTION RANGE_ERROR )
      integer(A, B) Convert numeric string, with specified radix, to an integer
                  ( Type of argument A: string,
                    integer("beef", 16) => 48879,
                    integer("-177", 8) => -127,
                    integer("10101010", 2) => 170,
                    integer("Cafe", 16) => 51966,
                    integer("0", 1) => EXCEPTION RANGE_ERROR,
                    integer("qwertyuiop", 37) => EXCEPTION RANGE_ERROR )
      sqrt(A)   Integer square root
                  ( sqrt(A) is okay for A >= 0,
                    sqrt(A) => trunc(sqrt(flt(A))),
                    sqrt(-1) => EXCEPTION NUMERIC_ERROR )
      log10(A)  Truncated base 10 logarithm
                  ( log10(A) is defined for A >= 0,
                    log10(10 ** A) = A for A >= 0,
                    log10(pred(10 ** A)) = pred(A) for A >= 0,
                    log10(10) => 1,
                    log10(1) => 0,
                    log10(0) => -1,
                    log10(-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(pred(2 ** A)) = pred(A) for A >= 0,
                    log2(2) => 1,
                    log2(1) => 0,
                    log2(0) => -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) => bitLength(pred(-A)) for A < 0,
                    bitLength(0) => 0,
                    bitLength(-1) => 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 )
      min(A, B) Minimum of two numbers.
                  ( min(1, 2) => 1 )
      max(A, B) Maximum of two numbers.
                  ( max(1, 2) => 2 )
      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,
                    incr(integer.last) => EXCEPTION OVERFLOW_ERROR )
      decr(A)   Decrement with 1
                  ( decr(A) => A -:= 1,
                    decr(integer.first) => EXCEPTION OVERFLOW_ERROR )

  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.


  Tables 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    |
    +-----+-----+---------+---------+----------+---------+


  Tables for the behavior of '!' (Binomial coefficient):

    +--------+---------------------------------------------------------+
    | n ! k  |                           k                             |
    |        +----+----+----+----+----+----+----+----+-----+----+------+
    |        | -5 | -4 | -3 | -2 | -1 |  0 |  1 |  2 |   3 |  4 |    5 |
    +---+----+----+----+----+----+----+----+----+----+-----+----+------+
    | n | -5 |  0 |  0 |  0 |  0 |  0 |  1 | -5 | 15 | -35 | 70 | -126 |
    |   +----+----+----+----+----+----+----+----+----+-----+----+------+
    |   | -4 |  0 |  0 |  0 |  0 |  0 |  1 | -4 | 10 | -20 | 35 |  -56 |
    |   +----+----+----+----+----+----+----+----+----+-----+----+------+
    |   | -3 |  0 |  0 |  0 |  0 |  0 |  1 | -3 |  6 | -10 | 15 |  -21 |
    |   +----+----+----+----+----+----+----+----+----+-----+----+------+
    |   | -2 |  0 |  0 |  0 |  0 |  0 |  1 | -2 |  3 |  -4 |  5 |   -6 |
    |   +----+----+----+----+----+----+----+----+----+-----+----+------+
    |   | -1 |  0 |  0 |  0 |  0 |  0 |  1 | -1 | -1 |  -1 | -1 |   -1 |
    |   +----+----+----+----+----+----+----+----+----+-----+----+------+
    |   |  0 |  0 |  0 |  0 |  0 |  0 |  1 |  0 |  0 |   0 |  0 |    0 |
    |   +----+----+----+----+----+----+----+----+----+-----+----+------+
    |   |  1 |  0 |  0 |  0 |  0 |  0 |  1 |  1 |  0 |   0 |  0 |    0 |
    |   +----+----+----+----+----+----+----+----+----+-----+----+------+
    |   |  2 |  0 |  0 |  0 |  0 |  0 |  1 |  2 |  1 |   0 |  0 |    0 |
    |   +----+----+----+----+----+----+----+----+----+-----+----+------+
    |   |  3 |  0 |  0 |  0 |  0 |  0 |  1 |  3 |  3 |   1 |  0 |    0 |
    |   +----+----+----+----+----+----+----+----+----+-----+----+------+
    |   |  4 |  0 |  0 |  0 |  0 |  0 |  1 |  4 |  6 |   4 |  1 |    0 |
    |   +----+----+----+----+----+----+----+----+----+-----+----+------+
    |   |  5 |  0 |  0 |  0 |  0 |  0 |  1 |  5 | 10 |  10 |  5 |    1 |
    +---+----+----+----+----+----+----+----+----+----+-----+----+------+


  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. A bigInteger literal is a sequence of digits
  followed by an underscore character (for example 1_ ). 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. Like decimal
  'bigInteger' literals the extended digits must be followed by
  an underscore character. Examples of 'bigInteger' literals are:

    0_   18446744073709551616_ 16#deadbeefcafe_

  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_ for every A, even for A = 0_,
                    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 => A * 2_ ** B  for B >= 0,
                    A << B => A >> -B for B < 0,
                    A << 0 => A,
                    0_ << B => 0_ for every B )
      A >> B    Arithmetic shift right
                  ( Type of argument B: integer,
                    A >> B => A mdiv 2_ ** B for B >= 0,
                    A >> B => A << -B for B < 0,
                    A >> 0 => A,
                    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)),
                    0_ >> B => 0_ for every B )
      !   Binomial coefficient
                  ( n ! k => 0_ for k < 0_,
                    n ! 0_ => 1_,
                    n ! 1_ => n,
                    n ! k => 0_ for n >= 0_ and k > n,
                    n ! k => !n div (!k * !(n - k)) for k >= 0_ and k <= n,
                    n ! k => (-1) ** k * (n + k - 1 ! k) for n < 0_ and k >= 0_ )
      A ? B : C  Ternary operator condition ? thenValue : elseValue
                  ( Type of argument A: boolean,
                    TRUE ? a : b => a,
                    FALSE ? a : b => b )
      A radix B  Convert the bigInteger A to a string. The conversion
                 uses the numeral system with the base B.
                  ( Type of result: string,
                    3735928559_ radix 16 => "deadbeef",
                    -3735928559_ radix 16 ) => "-deadbeef",
                    123_ radix 37 => EXCEPTION RANGE_ERROR )
      A RADIX B  Convert the integer A to a string. The conversion
                 uses the numeral system with the base B.
                  ( Type of result: string,
                    3735928559_ RADIX 16 => "DEADBEEF",
                    -3735928559_ RADIX 16 ) => "-DEADBEEF",
                    123_ RADIX 37 => EXCEPTION RANGE_ERROR )
      sci       Conversion to a string in scientific notation
                  ( Type of right operand: integer,
                    Type of result: string,
                    12345_ sci 4 => "1.2345e+4",
                    12345_ sci 3 => "1.235e+4",
                    12345_ sci 2 => "1.23e+4",
                    3141592_ sci 0 => "3e+6",
                    27182818_ sci 0 => "3e+7",
                    2_**62 sci 6 => "4.611686e+18",
                    -1_ sci 3 => "-1.000e+0",
                    -0_ sci 2 => "0.00e+0" )
      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 "+5" => 5_,
                    bigInteger parse " 1" => 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 )
      integer(A)  Ordinal number
                  ( Type of result: integer )
                    integer(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,
                    str(9876543210_) => "9876543210" )
      bigInteger(A) Convert an integer to a bigInteger
                  ( Type of argument A: integer,
                    bigInteger(1) => 1_ )
      bigInteger(A) Convert a numeric string to a bigInteger
                  ( Type of argument A: string,
                    bigInteger("123") => 123_,
                    bigInteger("-123") => -123_,
                    bigInteger("+5") => 5_,
                    bigInteger(" 1") => EXCEPTION RANGE_ERROR,
                    bigInteger("10 ") => EXCEPTION RANGE_ERROR,
                    bigInteger("ASDF") => EXCEPTION RANGE_ERROR )
      bigInteger(A, B) Convert numeric string, with specified radix, to a bigInteger
                  ( Type of argument A: string,
                    Type of argument B: integer,
                    bigInteger("deadbeef", 16) => 3735928559_,
                    bigInteger("-77777777777", 8) => -8589934591_,
                    bigInteger("10101010", 2) => 170_,
                    bigInteger("Cafe", 16) => 51966_,
                    bigInteger("0", 1) => EXCEPTION RANGE_ERROR,
                    bigInteger("qwertyuiop", 37) => EXCEPTION RANGE_ERROR )
      sqrt(A)   Integer square root
                  ( sqrt(A) is okay for A >= 0_
                    sqrt(A) => trunc(sqrt(flt(A))),
                    sqrt(-1_) => EXCEPTION NUMERIC_ERROR )
      modInverse(A, B) Compute the modular multiplicative inverse of A modulo B
      modPow(A, B, C) Compute the modular exponentiation of A ** B
      log10(A)  Truncated base 10 logarithm
                  ( log10(A) is defined for A >= 0_
                    log10(10_ ** A) = A for A >= 0_,
                    log10(pred(10_ ** A)) = pred(A) for A >= 0_,
                    log10(10_) => 1_,
                    log10(1_) => 0_,
                    log10(0_) => -1_,
                    log10(-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(pred(2_ ** A)) = pred(A) for A >= 0,
                    log2(2_) => 1_,
                    log2(1_) => 0_,
                    log2(0_) => -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) => bitLength(pred(-A)) for A < 0_,
                    bitLength(0_) => 0,
                    bitLength(-1_) => 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 )
      min(A, B) Minimum of two numbers.
                  ( min(1_, 2_) => 1_ )
      max(A, B) Maximum of two numbers.
                  ( max(1_, 2_) => 2_ )
      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.


  Tables 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_   |
    +-----+-----+---------+---------+----------+---------+


  Tables for the behavior of '!' (Binomial coefficient):

    +---------+--------------------------------------------------------------------+
    | n ! k   |                                k                                   |
    |         +-----+-----+-----+-----+-----+-----+-----+-----+------+-----+-------+
    |         | -5_ | -4_ | -3_ | -2_ | -1_ |  0_ |  1_ |  2_ |   3_ |  4_ |    5_ |
    +---+-----+-----+-----+-----+-----+-----+-----+-----+-----+------+-----+-------+
    | n | -5_ |  0_ |  0_ |  0_ |  0_ |  0_ |  1_ | -5_ | 15_ | -35_ | 70_ | -126_ |
    |   +-----+-----+-----+-----+-----+-----+-----+-----+-----+------+-----+-------+
    |   | -4_ |  0_ |  0_ |  0_ |  0_ |  0_ |  1_ | -4_ | 10_ | -20_ | 35_ |  -56_ |
    |   +-----+-----+-----+-----+-----+-----+-----+-----+-----+------+-----+-------+
    |   | -3_ |  0_ |  0_ |  0_ |  0_ |  0_ |  1_ | -3_ |  6_ | -10_ | 15_ |  -21_ |
    |   +-----+-----+-----+-----+-----+-----+-----+-----+-----+------+-----+-------+
    |   | -2_ |  0_ |  0_ |  0_ |  0_ |  0_ |  1_ | -2_ |  3_ |  -4_ |  5_ |   -6_ |
    |   +-----+-----+-----+-----+-----+-----+-----+-----+-----+------+-----+-------+
    |   | -1_ |  0_ |  0_ |  0_ |  0_ |  0_ |  1_ | -1_ | -1_ |  -1_ | -1_ |   -1_ |
    |   +-----+-----+-----+-----+-----+-----+-----+-----+-----+------+-----+-------+
    |   |  0_ |  0_ |  0_ |  0_ |  0_ |  0_ |  1_ |  0_ |  0_ |   0_ |  0_ |    0_ |
    |   +-----+-----+-----+-----+-----+-----+-----+-----+-----+------+-----+-------+
    |   |  1_ |  0_ |  0_ |  0_ |  0_ |  0_ |  1_ |  1_ |  0_ |   0_ |  0_ |    0_ |
    |   +-----+-----+-----+-----+-----+-----+-----+-----+-----+------+-----+-------+
    |   |  2_ |  0_ |  0_ |  0_ |  0_ |  0_ |  1_ |  2_ |  1_ |   0_ |  0_ |    0_ |
    |   +-----+-----+-----+-----+-----+-----+-----+-----+-----+------+-----+-------+
    |   |  3_ |  0_ |  0_ |  0_ |  0_ |  0_ |  1_ |  3_ |  3_ |   1_ |  0_ |    0_ |
    |   +-----+-----+-----+-----+-----+-----+-----+-----+-----+------+-----+-------+
    |   |  4_ |  0_ |  0_ |  0_ |  0_ |  0_ |  1_ |  4_ |  6_ |   4_ |  1_ |    0_ |
    |   +-----+-----+-----+-----+-----+-----+-----+-----+-----+------+-----+-------+
    |   |  5_ |  0_ |  0_ |  0_ |  0_ |  0_ |  1_ |  5_ | 10_ |  10_ |  5_ |    1_ |
    |---+-----+-----+-----+-----+-----+-----+-----+-----+-----+------+-----+-------+


  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. If a ' rational' operation overflows it raises
  the exception OVERFLOW_ERROR. In 'integer' computations an
  overflow can only happen with very huge positive or negative
  numbers. In 'rational' computations an overflow can
  happen with small numbers. Because of widening big denominators
  can be produced easily. E.g.: 1/1777 + 1/1999 = 3776/3552223 .
  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 )
      A ? B : C  Ternary operator condition ? thenValue : elseValue
                  ( Type of argument A: boolean,
                    TRUE ? a : b => a,
                    FALSE ? a : b => b )
      rational conv A   Conversion of integer to rational
                  ( Type of argument A: integer,
                    rational conv 1 => 1 / 1 )
      digits    Conversion to string with specified precision
                  ( Type of right operand: integer,
                    Type of result: string,
                    1/64 digits 7 => "0.0156250",
                    1/64 digits 4 => "0.0156",
                    1/64 digits 2 => "0.02",
                    355/113 digits 6 => "3.141593",
                    22/7 digits 0 => "3",
                    -1/2 digits 1 => "-1",
                    1/0 digits 5 => "Infinity",
                    -1/0 digits 6 => "-Infinity",
                    0/0 digits 7 => "NaN",
                    -1/2048 digits 3 => "0.000" )
      sci       Conversion to a string in scientific notation
                  ( Type of right operand: integer,
                    Type of result: string,
                    1/64 sci 4 => "1.5625e-2",
                    1/64 sci 3 => "1.563e-2",
                    1/64 sci 2 => "1.56e-2",
                    355/113 sci 6 => "3.141593e+0",
                    22/7 sci 0 => "3e+0",
                    -1/2 sci 1 => "-5.0e-1",
                    1/0 sci 5 => "Infinity",
                    -1/0 sci 6 => "-Infinity",
                    0/0 sci 7 => "NaN",
                    -1/2048 sci 3 => "-4.883e-4",
                    -0/1 sci 2 => "0.00e+0" )
      rational parse A   Conversion of string to rational
                  ( Type of argument A: string,
                    rational parse "3/5" => 3 / 5,
                    rational parse "1.25" => 5 / 4,
                    rational parse "0.(3)" => 1 / 3,
                    rational parse "1.23(45)" => 679 / 550,
                    rational parse "3.(142857)" => 22 / 7,
                    rational parse "0.(846153)" => 11 / 13 )
    Relations:
      =, <>, <, <=, >, >=
    Functions:
      abs(A)    Absolute value
      rat(A)    Conversion of integer to rational
                  ( Type of argument A: integer,
                    rat(1) => 1 / 1 )
      rational(A)  Conversion of integer to rational
                  ( Type of argument A: integer,
                    rational(1) => 1 / 1 )
      rational(A)  Conversion of string to rational
                  ( Type of argument A: string,
                    rational("3/5") => 3 / 5,
                    rational("1.25") => 5 / 4,
                    rational("0.(3)") => 1 / 3,
                    rational("1.23(45)") => 679 / 550,
                    rational("3.(142857)") => 22 / 7,
                    rational("0.(846153)") => 11 / 13 )
      floor(A)  Truncation towards negative infinity
                  ( Type of result: integer,
                    floor(9/5) =>  1, floor(1/1) =>  1,
                    floor(-1/1) => -1, floor(-9/5) => -2 )
      ceil(A)   Rounding up towards positive infinity
                  ( Type of result: integer,
                    ceil(6/5) =>  2, ceil(1/1) =>  1,
                    ceil(-1/1) => -1, ceil(-6/5) => -1 )
      trunc(A)  Truncation towards zero
                  ( Type of result: integer,
                    trunc(9/5) =>  1, trunc(1/1) =>  1,
                    trunc(-1/1) => -1, trunc(-9/5) => -1 )
      round(A)  Round towards zero
                  ( Type of result: integer,
                    round(1/2) => 1, round(-1/2) => -1,
                    round(2/5) => 0, round(-2/5) => 0 )
      round10(A, B)  Round with a decimal precision towards zero
                  ( Type of B: integer,
                    round10(1/4, 1) => 3/10, round10(-1/4, 1) => -3/10,
                    round10(2/5, 0) => 0/1, round(-2/5, 0) => 0/1 )
      str(A)    Conversion to string
                  ( Type of result: string )
      min(A, B) Minimum of two numbers.
                  ( min(2/5, 1/2) => 2/5 )
      max(A, B) Maximum of two numbers.
                  ( max(2/5, 1/2) => 1/2 )
      compare(A, B) Compare function
                  ( Type of result: integer,
                    compare(19/10, 2/1) => -1,
                    compare(26/5, 26/5) => 0,
                    compare(8/1, 79/10) => 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 )

  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 )
      A ? B : C  Ternary operator condition ? thenValue : elseValue
                  ( Type of argument A: boolean,
                    TRUE ? a : b => a,
                    FALSE ? a : b => b )
      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_ )
      digits    Conversion to string with specified precision
                  ( Type of right operand: integer,
                    Type of result: string,
                    1_/64_ digits 7 => "0.0156250",
                    1_/64_ digits 4 => "0.0156",
                    1_/64_ digits 2 => "0.02",
                    355_/113_ digits 6 => "3.141593",
                    22_/7_ digits 0 => "3",
                    -1_/2_ digits 1 => "-1",
                    1_/0_ digits 5 => "Infinity",
                    -1_/0_ digits 6 => "-Infinity",
                    0_/0_ digits 7 => "NaN",
                    -1_/2048_ digits 3 => "0.000" )
      sci       Conversion to a string in scientific notation
                  ( Type of right operand: integer,
                    Type of result: string,
                    1_/64_ sci 4 => "1.5625e-2",
                    1_/64_ sci 3 => "1.563e-2",
                    1_/64_ sci 2 => "1.56e-2",
                    355_/113_ sci 6 => "3.141593e+0",
                    22_/7_ sci 0 => "3e+0",
                    -1_/2_ sci 1 => "-5.0e-1",
                    1_/0_ sci 5 => "Infinity",
                    -1_/0_ sci 6 => "-Infinity",
                    0_/0_ sci 7 => "NaN",
                    -1_/2048_ sci 3 => "-4.883e-4",
                    -0_/1_ sci 2 => "0.00e+0" )
      bigRational parse A   Conversion of string to bigRational
                  ( Type of argument A: string,
                    bigRational parse "3/5"</span => 3_ / 5_,
                    bigRational parse "1.25" => 5_ / 4_,
                    bigRational parse "0.(3)" => 1_ / 3_,
                    bigRational parse "1.23(45)" => 679_ / 550_,
                    bigRational parse "3.(142857)" => 22_ / 7_,
                    bigRational parse "0.(846153)" => 11_ / 13_ )
    Relations:
      =, <>, <, <=, >, >=
    Functions:
      abs(A)    Absolute value
      rat(A)    Conversion of bigInteger to bigRational
                  ( Type of argument A: bigInteger,
                    rat(1_) => 1_ / 1_ )
      bigRational(A)  Conversion of integer to bigRational
                  ( Type of argument A: integer,
                    bigRational(1) => 1_ / 1_ )
      bigRational(A)  Conversion of bigInteger to bigRational
                  ( Type of argument A: bigInteger,
                    bigRational(1_) => 1_ / 1_ )
      bigRational(A)  Conversion of string to bigRational
                  ( Type of argument A: string,
                    bigRational("3/5") => 3_ / 5_,
                    bigRational("1.25") => 5_ / 4_,
                    bigRational("0.(3)") => 1_ / 3_,
                    bigRational("1.23(45)") => 679_ / 550_,
                    bigRational("3.(142857)") => 22_ / 7_,
                    bigRational("0.(846153)") => 11_ / 13_ )
      floor(A)  Truncation towards negative infinity
                  ( Type of result: bigInteger,
                    floor(9_/5_) =>  1_, floor(1_/1_) =>  1_,
                    floor(-1_/1_) => -1_, floor(-9_/5_) => -2_ )
      ceil(A)   Rounding up towards positive infinity
                  ( Type of result: bigInteger,
                    ceil(6_/5_) =>  2_, ceil(1_/1_) =>  1_,
                    ceil(-1_/1_) => -1_, ceil(-6_/5_) => -1_ )
      trunc(A)  Truncation towards zero
                  ( Type of result: bigInteger,
                    trunc(9_/5_) =>  1_, trunc(1_/1_) =>  1_,
                    trunc(-1_/1_) => -1_, trunc(-9_/5_) => -1_ )
      round(A)  Round towards zero
                  ( Type of result: bigInteger,
                    round(1_/2_) => 1_, round(-1_/2_) => -1_,
                    round(2_/5_) => 0_, round(-2_/5_) => 0_ )
      round10(A, B)  Round with a decimal precision towards zero
                  ( Type of B: integer,
                    round10(1_/4_, 1) => 3_/10_, round10(-1_/4_, 1) => -3_/10_,
                    round10(2_/5_, 0) => 0_/1_, round(-2_/5_, 0) => 0_/1_ )
      str(A)    Conversion to string
                  ( Type of result: string )
      min(A, B) Minimum of two numbers.
                  ( min(2_/5_, 1_/2_) => 2_/5_ )
      max(A, B) Maximum of two numbers.
                  ( max(2_/5_, 1_/2_) => 1_/2_ )
      compare(A, B) Compare function
                  ( Type of result: integer,
                    compare(19_/10_, 2_/1_) => -1,
                    compare(26_/5_, 26_/5_) => 0,
                    compare(8_/1_, 79_/10_) => 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 )

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


5.6 float

    The type 'float' consists of double precision floating point
  numbers. Float literals use 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 function '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
      PI        Mathematical constant &pi;
      E         Euler's 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,
                    NaN ** 0.0 => 1.0,
                    NaN ** B => NaN for B <> 0.0,
                    0.0 ** B => 0.0 for B > 0.0,
                    0.0 ** 0.0 => 1.0,
                    0.0 ** B => Infinity for B < 0.0,
                    (-0.0) ** B => -Infinity for B < 0.0 and odd(B),
                    1.0 ** B => 1.0,
                    1.0 ** NaN => 1.0,
                    A ** NaN => NaN for A <> 1.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,
                    NaN ** 0 => 1.0,
                    NaN ** B => NaN for B <> 0,
                    0.0 ** B => 0.0 for B > 0,
                    0.0 ** 0 => 1.0,
                    0.0 ** B => Infinity for B < 0,
                    (-0.0) ** B => -Infinity for B < 0 and odd(B),
                    A ** B => 1.0 / A ** (-B) for B < 0 )
      A ? B : C  Ternary operator condition ? thenValue : elseValue
                  ( Type of argument A: boolean,
                    TRUE ? a : b => a,
                    FALSE ? a : b => b )
      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" )
      sci       Conversion to a string in scientific notation
                  ( Type of right operand: integer,
                    Type of result: string,
                    0.012345 sci 4 => "1.2345e-2",
                    1.2468 sci 2 => "1.25e+0",
                    3.1415 sci 0 => "3e+0",
                    0.125 sci 1 => "1.2e-1",
                    0.375 sci 1 => "3.8e-1",
                    Infinity sci 5 => "Infinity",
                    -Infinity sci 6 => "-Infinity",
                    NaN sci 7 => "NaN",
                    -0.004 sci 2 => "-4.00e-3" )
      exp       Set the number of exponent digits in a scientific float notation.
                  ( Type of left operand: string,
                    Type of right operand: integer,
                    Type of result: string,
                    0.012345 sci 4 exp 2 => "1.2345e-02",
                    1.2468e15 sci 2 exp 1 => "1.25e+15",
                    3.1415 sci 0 exp 3 => "3e+000",
                    0.125 sci 1 exp 2 => "1.2e-01",
                    0.375 sci 1 exp 2 => "3.8e-01",
                    Infinity sci 5 exp 2 => "Infinity",
                    -Infinity sci 6 exp 2 => "-Infinity",
                    NaN sci 7 exp 2 => "NaN",
                    -0.004 sci 2 exp 2 => "-4.00e-03" )
      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 )
      float(A)  Conversion of integer to float
                  ( Type of argument A: integer,
                    float(1) => 1.0 )
      float(A)  Conversion of string to float
                  ( Type of argument A: string )
      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
      isNegativeZero(A)   Check if A is negative zero (-0.0)
      isPositiveZero(A)   Check if A is +0.0
      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(1.0)  =>  0.0,
                    log(0.0)  => -Infinity,
                    log(-1.0) =>  NaN )
      log10(A)  Base 10 logarithm
                  ( log10(A) is okay for A > 0.0,
                    log10(1.0)  =>  0.0,
                    log10(0.0)  => -Infinity,
                    log10(-1.0) =>  NaN )
      log2(A)  Base 2 logarithm
                  ( log2(A) is okay for A > 0.0,
                    log2(1.0)  =>  0.0,
                    log2(0.0)  => -Infinity,
                    log2(-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) => EXCEPTION RANGE_ERROR,
                    rand(1.0, 0.0) => EXCEPTION RANGE_ERROR )
      min(A, B) Minimum of two numbers.
                  ( min(2.5, 4.5) => 2.5 )
      max(A, B) Maximum of two numbers.
                  ( max(2.5, 4.5) => 4.5 )
      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 a 'float' real part and a '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 )
      A ? B : C  Ternary operator condition ? thenValue : elseValue
                  ( Type of argument A: boolean,
                    TRUE ? a : b => a,
                    FALSE ? a : b => b )
      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 )
      complex(A)  Return a complex number from its real part
                  ( Type of argument A: integer )
      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" )
      compare(A, B) Compare function
                  ( Type of result: integer )
      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.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
    backspace        BS       \b
    escape           ESC      \e
    formfeed         FF       \f
    newline          NL (LF)  \n
    carriage return  CR       \r
    horizontal tab   HT       \t
    vertical tab     VT       \v
    backslash        (\)      \\
    apostrophe       (')      \'
    double quote     (")      \"
    control-A                 \A
      ...
    control-Z                 \Z

  Additionally the following escape sequence can be used:

    - A backslash followed by an integer literal and a semicolon
      is 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:
      A ? B : C  Ternary operator condition ? thenValue : elseValue
                  ( Type of argument A: boolean,
                    TRUE ? a : b => a,
                    FALSE ? a : b => b )
      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 )
      integer(A)  Ordinal number
                  ( Type of result: integer )
      chr(A)    Conversion of integer to char
                  ( Type of argument: integer )
      char(A)   Conversion of integer to char
                  ( Type of argument: integer )
      char(A)   Conversion of string to char
                  ( Type of argument A: string )
      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.
  Therefore they 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:

    ""   " "   "\""   "'"   "Gold"   "A\"B !"   "Euro: \8364;"   "CRLF\r\n"

  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_output' or 'enable_io'
                  ( write("i=" <& i digits 2 lpad 6 <& " $"); )
      mult      String multiplication
                  ( Type of right operand: integer,
                    "LA" mult 3 => "LALALA",
                    "WORD" mult 0 => "",
                    "ANY" mult -1 => EXCEPTION RANGE_ERROR )
      A ? B : C  Ternary operator condition ? thenValue : elseValue
                  ( Type of argument A: boolean,
                    TRUE ? a : b => a,
                    FALSE ? a : b => b )
      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 INDEX_ERROR,
                    "abcde"[6] => EXCEPTION INDEX_ERROR )
      [ A .. B ] Access a substring from position A to B
                  ( Type of arguments A and B: integer,
                    S [A .. B] is okay for A >= 1 and B >= pred(A),
                    "abcde"[2 .. 4] => "bcd",
                    "abcde"[2 .. 7] => "bcde",
                    "abcde"[4 .. 3] => "",
                    "abcde"[4 .. 2] => EXCEPTION INDEX_ERROR,
                    "abcde"[6 .. 8] => "",
                    "abcde"[1 .. 3] => "abc",
                    "abcde"[0 .. 3] => EXCEPTION INDEX_ERROR,
                    "abcde"[1 .. 0] => "",
                    "abcde"[1 .. -1] => EXCEPTION INDEX_ERROR )
      [ A len B ] Access a substring from position A with length B
                  ( Type of arguments A and B: integer,
                    S [A len B] is okay for A >= 1 and B >= 0,
                    "abcde"[2 len 3] => "bcd",
                    "abcde"[2 len 5] => "bcde",
                    "abcde"[3 len 0] => "",
                    "abcde"[3 len -1] => EXCEPTION INDEX_ERROR,
                    "abcde"[1 len 2] => "ab",
                    "abcde"[0 len 2] => EXCEPTION INDEX_ERROR )
      [ A .. ]  Access a substring beginning at position A
                  ( Type of argument A: integer,
                    S [A ..] is okay for A >= 1,
                    "abcde"[3 ..] => "cde",
                    "abcde"[6 ..] => "",
                    ""[1 ..] => "",
                    "abcde"[1 ..] => "abcde",
                    "abcde"[0 ..] =>  EXCEPTION INDEX_ERROR )
      [ .. A ]  Access a substring ending at position A
                  ( Type of argument A: integer,
                    S [.. A] is okay for A >= 0,
                    "abcde"[.. 4] => "abcd",
                    "abcde"[.. 6] => "abcde",
                    ""[.. 5] => "",
                    "abcde"[.. 0] => "",
                    "abcde"[.. -1] => EXCEPTION INDEX_ERROR )
    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 )
      rpos(A,B,C) Last position of char B in string A
                 The search starts at position C of string A
                  ( Type of argument C: integer,
                    Type of result: integer,
                    rpos("ABCABC","BC", 4) => 2,
                    rpos("XYZYX","ZY", 2) => 0,
                    rpos("12345","34", 5) => 3 )
      startsWith(A,B) Determine if a string starts with a prefix.
                  ( Type of result: boolean,
                    startsWith("tmp_s7c.c", "tmp_") => TRUE,
                    startsWith("example", "E") => FALSE )
      endsWith(A,B) Determine if a string ends with a suffix.
                  ( Type of result: boolean,
                    endsWith("hello.sd7", ".sd7") => TRUE,
                    endsWith("A string", "\0;") => FALSE )
      equalAtIndex(A,B,C) Check if A has the searched characters B starting from C.
                  ( Type of result: boolean,
                    equalAtIndex("The quick brown fox", "quick", 5) => TRUE,
                    equalAtIndex("axis", "xi", 3) => FALSE )
      replace(A,B,C) Search A for occurrences of B and replace them with C
                  ( replace("old gold", "old", "one") => "one gone" )
      replace2(A,B,C,D) Search A for occurrences of B followed by C and
                replace them with D.
                  ( replace2("x := (*ord*) y;", "(*", "*)", "") => "x :=  y;" )
      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" )
      ltrim(A)   Removes leading spaces and control chars
                  ( ltrim(" /n xyz /r") => "xyz /r" )
      rtrim(A)   Removes trailing spaces and control chars
                  ( rtrim(" /n xyz /r") => " /n 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   Append B to A
                  ( Type of argument B: char,
                    A &:= B => A := A & str(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 INDEX_ERROR,
                    A @:= [succ(length(A))] 'x' => EXCEPTION INDEX_ERROR )
      A @:= [B] C  Assign C to the position B of string A
                  ( Type of argument B: integer,
                    A @:= [B] C =>
                        A := A[..pred(B)] & C & A[B+length(C)..],
                    A @:= [0] "xyz" => EXCEPTION INDEX_ERROR,
                    A @:= [pred(length(A))] "xyz" => EXCEPTION INDEX_ERROR )


5.10 array

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

    const type: striArrayType is array string;
    const type: structArrayType is array aStructType;

  This defines 'striArrayType' as an array type with 'string' elements. The
  second line defines 'structArrayType' as an array type with aStructType
  elements. Variables of these types are declared with:

    var striArrayType: striArr1 is striArrayType.value;
    var striArrayType: striArr2 is 0 times "";
    var striArrayType: striArr3 is [] ("one", "two");
    var striArrayType: striArr4 is [0] ("zero", "one");
    var structArrayType: structArr1 is structArrayType.value;
    var structArrayType: structArr2 is 10 times aStructType.value;
    var structArrayType: structArr3 is [42 .. 365] times aStructType.value;

  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". An array type with 'char' index and
  'bigInteger' elements is defined as:

    const type: charIndexArray is array [char] bigInteger;

  Variables of this type are declared with:

    var charIndexArray: bigArr1 is charIndexArray.value;
    var charIndexArray: bigArr2 is char times 42_;
    var charIndexArray: bigArr3 is [char] (0_, 1_, 2_);
    var charIndexArray: bigArr4 is [' '] (32_, 33_, 34_);

    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 INDEX_ERROR,
                    A[succ(maxIdx(A))] => EXCEPTION INDEX_ERROR )
      [ A .. B ]  Get a sub array from the position A to the position B
                  ( Type of arguments A and B: integer,
                    X [ A .. B ] is okay for A >= minIdx(X) and B >= pred(A),
                    anArray[pred(minIdx(anArray)) .. n] => EXCEPTION INDEX_ERROR,
                    anArray[n .. n - 2] => EXCEPTION INDEX_ERROR )
      [ A len B ]  Get a sub array from the position A with maximum length B
                  ( Type of arguments A and B: integer,
                    X [ A len B ] is okay for A >= minIdx(X) and B >= 0,
                    anArray[pred(minIdx(anArray)) len n] => EXCEPTION INDEX_ERROR,
                    anArray[n len -1] => EXCEPTION INDEX_ERROR )
      [ A .. ]  Get a sub array beginning at position A
                  ( Type of argument A: integer,
                    X [ A .. ] is okay for A >= minIdx(X),
                    anArray[pred(minIdx(anArray)) ..] => EXCEPTION INDEX_ERROR )
      [ .. A ]  Get a sub array ending at position A
                  ( Type of argument A: integer,
                    X [ .. A ] is okay for A >= pred(minIdx(X)),
                    anArray[.. minIdx(anArray) - 2] => EXCEPTION INDEX_ERROR )
    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(A,B) is okay for B >= minIdx(A) and B <= maxIdx(A),
                    remove(anArray, 0) => EXCEPTION INDEX_ERROR for minIdx(anArray) = 1,
                    remove(anArray, 5) => EXCEPTION INDEX_ERROR for maxIdx(anArray) = 4 )
      remove(A,B,C) Remove the sub-array with with index B and length C from array A and
                  return the removed sub-array
                  ( Type of argument B: integer,
                    Type of argument C: integer,
                    remove(A,B,C) is okay for B >= minIdx(A) and B <= maxIdx(A) and C >= 0,
                    remove(anArray, 0, 1) => EXCEPTION INDEX_ERROR for minIdx(anArray) = 1,
                    remove(anArray, 6, 1) => EXCEPTION INDEX_ERROR for maxIdx(anArray) = 4,
                    remove(anArray, 1, -1) => EXCEPTION INDEX_ERROR )
      sort(A)   Sort array using the compare(baseType, baseType) function
    Statements:
      A &:= B   Append B to A
                  ( A &:= B => A := A & B )
      A &:= B   Append element B to A
                  ( Type of argument B: baseType,
                    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 element C into array A at index B
                  ( Type of argument B: integer,
                    Type of argument C: baseType,
                    insert(A,B,C) is okay for B >= minIdx(A) and B <= succ(maxIdx(A)),
                    insert(anArray, 0, anElement) => EXCEPTION INDEX_ERROR for minIdx(anArray) = 1,
                    insert(anArray, 6, anElement) => EXCEPTION INDEX_ERROR for maxIdx(anArray) = 4 )
      insert(A,B,C) Insert array C into array A at index B
                  ( Type of argument B: integer,
                    insert(A,B,C) is okay for B >= minIdx(A) and B <= succ(maxIdx(A)),
                    insert(anArray, 0, anotherAnarry) => EXCEPTION INDEX_ERROR for minIdx(anArray) = 1,
                    insert(anArray, 6, anotherAnarry) => EXCEPTION INDEX_ERROR for maxIdx(anArray) = 4 )
      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'. An example of a hash type declaration is:

    const type: aHashType is hash [string] integer;

  This defines 'aHashType' as a hash type with 'integer' elements and
  'string' keys. Variables of this type are declared with:

    var aHashType: aHashTable is aHashType.value;

  The expressions 'aHashType.value' and 'aHashType.EMPTY_HASH' describe
  empty hash tables. Beside them there are no hash table literals.
  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). An example of a set type
  declaration is:

    const type: aSetType is set of integer;

  This defines 'aSetType' as a set type with 'integer' elements.
  Variables of this type are declared with:

    var aSetType: aSet is aSetType.value;
    var aSetType: aSet is {1, 2, 3};

  The type 'set of baseType' is
  defined in the library "set.s7i". This abstract data type decides
  about the implementation of the set. When 'baseType' values can be
  mapped to 'integer' with the 'ord' function and 'ord' does never
  raise an exception the set is implemented as 'bitset(baseType)'
  (defined in the library "bitsetof.htm"), otherwise the set is
  implemented as 'hashset(baseType)' (defined in the library
  "hashsetof.htm"). 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
                  ( {1, 3} | {2, 3} => {1, 2, 3} )
      &         Intersection
                  ( {1, 3} & {2, 3} => {3} )
      -         Difference
                  ( {1, 3} - {2, 3} => {1} )
      ><        Symmetric Difference
                  ( {1, 3} >< {2, 3} => {1, 2} )
      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 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 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. An example of a
  struct type declaration is:

    const type: aStructType is new struct
        var string: name is "";
      end struct

  Variables of this type are declared with:

    var aStructType: aStructVariable is aStructType.value;

  In 'aStructType.value' all elements have the initialisation values from
  the struct declaration of 'aStructType'. Besides 'aStructType.value'
  there are no struct literals.

    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'.
  The 'category' functions are defined in the library "category.s7i".

    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,
                    category parse "does not exist" => EXCEPTION RANGE_ERROR )
    Relations:
      =, <>
    Functions:
      ord(A)    Ordinal number
                  ( Type of result: integer )
      category(A)  Conversion of integer to category
                  ( Type of argument A: integer,
                    category(ord(INTOBJECT)) => INTOBJECT )
      str(A)    Conversion to string
                  ( Type of result: string,
                    str(CHAROBJECT) => "CHAROBJECT" )
      category(A)  Conversion of string to category
                  ( Type of argument A: string,
                    category("FLOATOBJECT") => FLOATOBJECT,
                    category("does not exist") => EXCEPTION RANGE_ERROR )
    Statements:
      for A range B to C do
        D
      end for   Loop over all categories from B to C
                  ( Type of argument D: proc )
      for A range B downto C do
        D
      end for   Loop over all categories from B down to C
                  ( Type of argument D: proc )


5.15 reference

    The type 'reference' describes a reference to any
  object. The 'reference' functions are defined in
  the library "reference.s7i".


    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 )
      objNumber(A) Delivers an unique number for each object
                  ( Type of result: integer,
                    objNumber(NIL) => 0 )
      isVar(A)  Reference to a variable object
                  ( Type of result: boolean,
                    isVar(NIL) => EXCEPTION RANGE_ERROR )
      formalParams(A) Gets the formal parameters of a function
                  ( Type of result: ref_list,
                    formalParams(NIL) => EXCEPTION RANGE_ERROR )
      localVars(A) Gets the local variables of a function
                  ( Type of result: ref_list,
                    localVars(NIL) => EXCEPTION RANGE_ERROR,
                    localVars(A) => EXCEPTION RANGE_ERROR for category(A) <> BLOCKOBJECT )
      localConsts(A) Gets the local constants of a function
                  ( Type of result: ref_list,
                    localConsts(NIL) => EXCEPTION RANGE_ERROR,
                    localConsts(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 )
      resultVar(A) Gets the result variable of a function
                  ( resultVar(NIL) => EXCEPTION RANGE_ERROR,
                    resultVar(A) => EXCEPTION RANGE_ERROR for category(A) <> BLOCKOBJECT )
      resultInitValue(A) Gets the initialization value of the result
                         object of a function
                  ( resultInitValue(NIL) => EXCEPTION RANGE_ERROR,
                    resultInitValue(A) => EXCEPTION RANGE_ERROR for category(A) <> BLOCKOBJECT )
      arrayToList(A) Return the array elements as list
                  ( Type of result: ref_list,
                    arrayToList(NIL) => EXCEPTION RANGE_ERROR,
                    arrayToList(A) => EXCEPTION RANGE_ERROR for category(A) <> ARRAYOBJECT )
      arrayMinIdx(A) Return the minimal index of an array
                  ( Type of result: integer,
                    arrayMinIdx(NIL) => EXCEPTION RANGE_ERROR,
                    arrayMinIdx(A) => EXCEPTION RANGE_ERROR for category(A) <> ARRAYOBJECT )
      arrayMaxIdx(A) Return the maximal index of an array
                  ( Type of result: integer,
                    arrayMaxIdx(NIL) => EXCEPTION RANGE_ERROR,
                    arrayMaxIdx(A) => EXCEPTION RANGE_ERROR for category(A) <> ARRAYOBJECT )
      structToList(A) Return the struct elements as list
                  ( Type of result: ref_list,
                    structToList(NIL) => EXCEPTION RANGE_ERROR,
                    structToList(A) => EXCEPTION RANGE_ERROR for category(A) <> STRUCTOBJECT )
      interfaceToStruct(A) Return the struct to which the interface object points.
                  ( interfaceToStruct(NIL) => EXCEPTION RANGE_ERROR,
                    interfaceToStruct(A) => EXCEPTION RANGE_ERROR for category(A) <> INTERFACEOBJECT )
      file(A)   File name of the referenced object
                  ( Type of result: string,
                    file(NIL) => EXCEPTION RANGE_ERROR )
      line(A)   Line number of the referenced object
                  ( Type of result: integer,
                    line(NIL) => EXCEPTION RANGE_ERROR )
      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, clib_file) Dereference as clib_file
                  ( Type of result: clib_file,
                    getValue(NIL, clib_file) => EXCEPTION RANGE_ERROR,
                    getValue(A, clib_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 )
      setFormalParams(A, B) Set the formal parameters of a function
                  ( Type of argument B: ref_list,
                    setFormalParams(NIL, B) => EXCEPTION RANGE_ERROR )


5.16 ref_list

    The type 'ref_list' describes a list of 'reference' objects.
  The 'ref_list' functions are defined in
  the library "ref_list.s7i".

    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 INDEX_ERROR,
                    A[succ(length(A))] => EXCEPTION INDEX_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 INDEX_ERROR,
                    A @:= [succ(length(A))] C => EXCEPTION INDEX_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.
  The 'program' functions are defined in the library "progs.s7i".

    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 )
      sysVar(A, B)  Return a reference of the system var B of program A
                  ( Type of result: reference,
                    Type of argument B: string )
      errorCount(A)  Number of errors in the program A
                  ( Type of result: integer )
      globalObjects(A)  List of global defined objects 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 functions 'str' and 'parse' 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))) )
      compare(A, B) Compare function
                  ( Type of result: integer )
      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.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 )
      gray(BR)  Create a gray color value from BR
                  ( Type of argument BR: integer )
      compare(A, B) Compare function
                  ( Type of result: integer )
      hashCode(A) Hash function
                  ( Type of result: 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:
      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
      time(A)  Conversion of string to time
                  ( Type of argument A: string,
                    time("2005-02-28 12:00:01") => 2005-02-28 12:00:01,
                    time("2005-02-29 12:00:01") => EXCEPTION RANGE_ERROR )
      str(A)    Conversion to string
                  ( Type of result: string )
      strDate(A)  Conversion of the date to string
                    with ISO 8601 YYYY-MM-DD date format
                  ( Type of result: string )
      strTime(A)  Conversion of the daytime to string
                    with ISO 8601 hh:mm:ss time format
                  ( Type of result: string )
      strDateTime(A)  Conversion of date and time to string
                    with ISO 8601 YYYY-MM-DD hh:mm:ss format
                  ( 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 )
      daysInMonth(A)  Calculate the number of days in a month
                  ( 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(Y, D)  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 argument Y: integer,
                    Type of argument D: integer,
                    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:
      await(A)  Wait until the given time


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 )
      +         Add a duration to a time
                  ( Type of left operand: time,
                    Type of result: time )
      -         Subtract a duration from a time
                  ( Type of left operand: time,
                    Type of result: time )
      -         Subtract two times
                  ( Type of left operand: time,
                    Type of right operand: time )
      duration parse A   Conversion of string to duration
                  ( Type of argument A: string,
                    duration parse "P2M28DT12H1S" => P2M28DT12H1S,
                    duration parse "P13M28DT12H1S" => EXCEPTION RANGE_ERROR )
    Relations:
      =, <>, <, <=, >, >=
    Functions:
      duration(A)  Conversion of string to duration
                  ( Type of argument A: string,
                    duration("P2M28DT12H1S") => P2M28DT12H1S,
                    duration("P13M28DT12H1S") => EXCEPTION RANGE_ERROR )
      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:
      A +:= B   Increment A by B
                  ( A +:= B => A := A + B )
      A -:= B   Decrement A by B
                  ( A -:= B => A := A - B )
      A +:= B   Increment time A by B
                  ( Type of argument A: time,
                    A +:= B => A := A + B )
      A -:= B   Decrement time A by B
                  ( Type of argument A: time,
                    A -:= B => A := A - B )
      wait(A)   Wait for given duration

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

  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.23 file

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

    Variables:
      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
      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 )
      openUtf8(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 )
      openUtf16(A, B) Open external UTF-16 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 )
      popen8(A, B) Open a UTF-8 pipe to a process
                  ( Type of argument A: string,
                    Type of argument B: string,
                    Type of result: file,
                    Returns STD_NULL if popen8 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 )
      compare(A, B) Compare function
                  ( Type of result: integer )
      hashCode(A) Hash function
                  ( Type of result: integer )
    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:
      openWindow(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
      clear(A, UP, LO, LE, RI)  Clear an area of the window
                  ( Type of argument UP: integer
                    Type of argument LO: integer
                    Type of argument LE: integer
                    Type of argument RI: integer )
      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: resultVariable is baseType.value;
      begin
        statements
      end func
                Create a baseType function
                  ( Type of 'statements': proc,
                    Type of result: func baseType )

      func
      result
        var baseType: resultVariable 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: tak is 0;
      begin
        if y >= x then
          tak := z;
        else
          tak := 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: conjunction is FALSE;
      begin
        if first then
          conjunction := second;
        end if;
      end func;

  Here the second parameter is only evaluated if 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, hashes
  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. Examples of type declarations are:

    const type: intArrayType is array integer;
    const type: arrayIndexChar is array [char] string;
    const type: hashType is hash [string] intArrayType;
    const type: setType is set of char;

  Note that type declarations should always be made at the top level. E.g.:

    $ include "seed7_05.s7i";

    const type: intArrayType is array integer;

    const proc: main is func
      local
        var intArrayType: arr is [](1, 2);
      begin
        writeln(length(arr));
      end func;

  If the type declaration of 'intArrayType' would be inside of the 'local'
  declaration block you would receive a parsing error:

    *** tst249.sd7(6):52: Match for {var intArrayType : {arr } is {[ ] {1 , 2 } } } failed
        var intArrayType: arr is [](1, 2);

  A 'local' declaration block is parsed completely before it is executed.
  This causes that 'intArrayType' is not defined during the parsing.

    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 )
      isFunc(A)  Is this type a 'func' type
                  ( Type of result: boolean,
                    isFunc(func char) => TRUE,
                    isFunc(varfunc char) => FALSE )
                    isFunc(char) => FALSE )
      isVarfunc(A)  Is this type a 'varfunc' type
                  ( Type of result: boolean,
                    isVarfunc(func char) => FALSE,
                    isVarfunc(varfunc char) => TRUE,
                    isVarfunc(char) => FALSE )
      resultType(A)  Get the result type of a 'func' or 'varfunc' type
                  ( resultType(func char) => char,
                    resultType(proc) => void,
                    resultType(integer) => EXCEPTION RANGE_ERROR )
      isDerived(A)  Is this type derived from another type
                  ( Type of result: boolean,
                    isDerived(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 )
      typeNumber(A)  Get an unique number for a type
                  ( Type of result: integer )
      typeObject(A)  Get a unique object (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 safe
  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 sub-chapters 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 variable globalStri contains the value "a,a". If the function
  header would be

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

  the variable globalStri 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 is 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. An 'in' parameter should be preferred
  over an 'val' parameter, when possible.

  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 behavior.
  The function below defines the primitive action for the
  semicolon operator:

    const proc: (ref void: statement1) ; (ref void: statement2) 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: lengthSum is 0;
      local
        var integer: index is 0;
      begin
        for index range 1 to length(arr) do
          lengthSum +:= 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. An 'in' parameter should be
  preferred over an 'ref' parameter, when possible.

  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: prime is FALSE;
      local
        var integer: count is 2;
      begin
        if number = 2 then
          prime := TRUE;
        elsif number >= 3 then
          while number rem count <> 0 and count * count <= number do
            incr(count);
          end while;
          prime := 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
      result
        var array array integer: product is 0 times 0 times 0;
      local
        var integer: index1 is 1;
      begin
        product := length(a) times length(b) times 0;
        for index1 range 1 to length(a) do
          for index2 range 1 to length(b) do
            product[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_IN1";
    const func f_param: in (ref type param) : (ref expr param)  is action "DCL_IN2";

    const proc: IN_PARAM_IS_VALUE (ref type: aType)             is action "TYP_SET_IN_PARAM_VALUE";
    const proc: IN_PARAM_IS_REFERENCE (ref type: aType)         is action "TYP_SET_IN_PARAM_REF";


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: gcd is 0;
      local
        var integer: help is 0;
      begin
        while a <> 0 do
          help := b rem a;
          b := a;
          a := help;
        end while;
        gcd := 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
      return stri[1];

  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: aShape, inout window: aWindow) 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: aCircle is circle.value;
      begin
        aCircle.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: aLine is line.value;
      begin
        aLine.xLen := xLen;
        aLine.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: aShape, inout window: aWindow) 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 clib_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';
    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 '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: inFile, in integer: maxLength) 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 taste 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: a) + (in Number: b) is DYNAMIC;

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

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

    type_implements_interface(Integer, Number);

    const type: Float is new struct
        var float: data 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: sum is Float.value;
      begin
        sum.data := flt(a.data) + b.data;
      end func;

    const func Float: (in Float: a) + (in Integer: b) is func
      result
        var Float: sum is Float.value;
      begin
        sum.data := a.data + flt(b.data);
      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: sum is Integer.value;
      begin
        sum.data := a.data + b.data;
      end func;

    const func Float: (in Float: a) + (in Float: b) is func
      result
        var Float: sum is Float.value;
      begin
        sum.data := a.data + b.data;
      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: anElem).left  is DYNAMIC;
    const varfunc element: (inout element: anElem).left  is DYNAMIC;
    const func    element: (ref   element: anElem).right is DYNAMIC;
    const varfunc element: (inout element: anElem).right is DYNAMIC;
    const func    integer: (ref   element: anElem).item  is DYNAMIC;
    const varfunc integer: (inout element: anElem).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: sum is 0;
      begin
        if anElem <> element.NIL then
          sum := 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. FILE INPUT AND OUTPUT
========================

    Files are 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 '<&' if
  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). If 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 := openWindow(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 an inout/output 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 sub-chapters 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: stri is "";
      begin
        if aBool then
          stri := "TRUE";
        else
          stri := "FALSE";
        end if;
      end func;

    const func boolean: (attr boolean) parse (in string: stri) is func
      result
        var boolean: aBoolean is FALSE;
      begin
        if stri = "TRUE" then
          aBoolean := TRUE;
        elsif stri = "FALSE" then
          aBoolean := 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 '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: padded is "";
      begin
        if leng > length(stri) then
          padded := " " mult leng - length(stri) & stri;
        else
          padded := stri;
        end if;
      end func;

    const func string: (ref string: stri) rpad (in integer: leng) is func
      result
        var string: padded is "";
      begin
        if leng > length(stri) then
          padded := stri & " " mult leng - length(stri);
        else
          padded := 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
      return str(aValue) lpad leng;

    const func string: (in aType: aValue) rpad (in integer: leng) is
      return str(aValue) rpad leng;

  Values of type 'integer' and 'bigInteger' can be written in
  a numeral system with a radix (base) other than 10. The
  operators 'radix' and 'RADIX' can be used for this purpose.
  E.g. the statements

    writeln(48879 radix 16);
    writeln(3735928559_ RADIX 16);

  produce the following output:

    beef
    DEADBEEF

  For 'float' values exist additional ways to convert them to
  strings. The 'digits' operator allows the specification of a
  precision. E.g. 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

  Scientific notation for 'float' is supported with the
  conversion operator 'sci'. The statements

    writeln(0.012345 sci 4);
    writeln(1.2468 sci 2 );
    writeln(3.1415 sci 0);
    writeln(0.125 sci 1);
    writeln(0.375 sci 1);

  produce the following output:

    1.2345e-2
    1.25e+0
    3e+0
    1.2e-1
    3.8e-1

  The operator 'exp' is used to specify the number of exponent digits.  The statements

    writeln(0.012345 sci 4 exp 2);
    writeln(1.2468e15 sci 2 exp 1);
    writeln(3.1415 sci 0 exp 3);
    writeln(0.125 sci 1 exp 2);
    writeln(0.375 sci 1 exp 2);

  produce the following output:

    1.2345e-02
    1.25e+15
    3e+000
    1.2e-01
    3.8e-01


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 sequential
  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.
  If '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 (in null_file: inFile) is
      return inFile.bufferChar = '\n';

  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 if mixing scanner and
  file functions.

  The type 'null_file' provides default functions to write end-of-line:

    const proc: writeln (inout null_file: outFile) is func
      begin
        write(outFile, "\n");
      end func;

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

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

    const proc: read (inout file: aFile, inout string: stri) is func
      begin
        stri := getwd(aFile);
      end func;

    const proc: readln (inout file: aFile, inout string: stri) is func
      begin
        stri := getln(aFile);
      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
      begin
        aValue := aType parse getwd(aFile);
      end func;

    const proc: readln (inout file: aFile, inout aType: aValue) is func
      begin
        aValue := aType parse trimValue(aType, getln(aFile));
      end func;

  The next declaration defines 'backSpace':

    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
        writeln(OUT, aValue);
      end func;

  Additional procedures defined outside of 'enable_io' are:

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

    const proc: writeln 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 if 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, if 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. The path must use the standard path representation.
  This means that a slash ('/') is used as path delimiter.
  A path with a backslash or a drive letter 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. If 'open' is called, with a mode
  not listed in the table above, the exception RANGE_ERROR
  is raised. If there is not enough memory to convert 'path'
  to the system path type the exception MEMORY_ERROR
  is raised. If '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 has 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 'openUtf8' can be used the same
  way as 'open':

    my_out := openUtf8("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 := openUtf8("utf8_file", "w");
    write("\16#feff;");

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

    my_out := openUtf8("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 := openUtf8("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 'openUtf16' opens an Unicode file which uses the
  UTF-16LE or UTF-16BE encoding. The function 'openUtf16' checks for
  a BOM and depending on that it opens an UTF-16LE or UTF-16BE file.

  The functions 'openUtf16le' and 'openUtf16be' open Unicode files
  with the UTF-16LE and UTF-16BE encoding respectively. If the
  file is opened with one of the modes "w", "w+", "wt" or "wt+" an
  appropriate BOM is created. If the file is opened with any other
  mode the application program is in charge to handle optional BOM
  markers. This way 'openUtf16le' and 'openUtf16be' 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 clib_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 'clib_file'
  points directly to an operating system file. Objects
  of type 'clib_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
  'clib_file' are defined. But outside 'external_file' the
  type 'clib_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 clib_file: primitive_file,
        in string: file_name) is func
      result
        var external_file: standardFile is external_file.value;
      begin
        standardFile.ext_file := primitive_file;
        standardFile.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 function
  'open'. 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') if 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_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_CTL_PAD_CENTER         Control numeric keypad center key
    KEY_ALT_LEFT               Alt cursor left
    KEY_ALT_RIGHT              Alt cursor right
    KEY_ALT_UP                 Alt cursor up
    KEY_ALT_DOWN               Alt cursor down
    KEY_ALT_HOME               Alt home key
    KEY_ALT_END                Alt end key
    KEY_ALT_PGUP               Alt page up
    KEY_ALT_PGDN               Alt page down
    KEY_ALT_INS                Alt insert key
    KEY_ALT_DEL                Alt delete key
    KEY_ALT_PAD_CENTER         Alt numeric keypad center key
    KEY_NL                     Newline/enter/return key (equal to KEY_CTL_J)
    KEY_BS                     Backspace (equal to KEY_CTL_H)
    KEY_TAB                    Horizontal tab (equal to KEY_CTL_H)
    KEY_CR                     Carriage return (equal to KEY_CTL_M)
    KEY_ESC                    Escape key
    KEY_MENU                   Menu key
    KEY_PRINT                  Print key
    KEY_PAUSE                  Pause key
    KEY_SFT_NL                 Shift newline/enter/return key
    KEY_SFT_BS                 Shift backspace
    KEY_SFT_TAB                Shift tab (same as KEY_BACKTAB)
    KEY_BACKTAB                Shift tab (same as KEY_SFT_TAB)
    KEY_SFT_ESC                Shift escape
    KEY_SFT_MENU               Shift menu
    KEY_SFT_PRINT              Shift print
    KEY_SFT_PAUSE              Shift pause
    KEY_CTL_NL                 Control newline/enter/return key
    KEY_CTL_BS                 Control backspace
    KEY_CTL_TAB                Control tab
    KEY_CTL_ESC                Control escape
    KEY_CTL_MENU               Control menu
    KEY_CTL_PRINT              Control print
    KEY_CTL_PAUSE              Control pause
    KEY_ALT_NL                 Alt newline/enter/return key
    KEY_ALT_BS                 Alt backspace
    KEY_ALT_TAB                Alt tab
    KEY_ALT_ESC                Alt escape
    KEY_ALT_MENU               Alt menu
    KEY_ALT_PRINT              Alt print
    KEY_ALT_PAUSE              Alt pause
    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_NULCHAR                Nul character key
    KEY_NULLCMD                Null command of window manager
    KEY_REDRAW                 Redraw command of window manager
    KEY_MOUSE1                 Mouse button 1 (counted from left)
    KEY_MOUSE2                 Mouse button 2 (counted from left)
    KEY_MOUSE3                 Mouse button 3 (counted from left)
    KEY_MOUSE4                 Mouse wheel scroll up
    KEY_MOUSE5                 Mouse wheel scroll down
    KEY_MOUSE_FWD              Mouse forward button
    KEY_MOUSE_BACK             Mouse back button
    KEY_SFT_MOUSE1             Shift mouse button 1 (counted from left)
    KEY_SFT_MOUSE2             Shift mouse button 2 (counted from left)
    KEY_SFT_MOUSE3             Shift mouse button 3 (counted from left)
    KEY_SFT_MOUSE4             Shift mouse wheel scroll up
    KEY_SFT_MOUSE5             Shift mouse wheel scroll down
    KEY_SFT_MOUSE_FWD          Shift mouse forward button
    KEY_SFT_MOUSE_BACK         Shift mouse back button
    KEY_CTL_MOUSE1             Control mouse button 1 (counted from left)
    KEY_CTL_MOUSE2             Control mouse button 2 (counted from left)
    KEY_CTL_MOUSE3             Control mouse button 3 (counted from left)
    KEY_CTL_MOUSE4             Control mouse wheel scroll up
    KEY_CTL_MOUSE5             Control mouse wheel scroll down
    KEY_CTL_MOUSE_FWD          Control mouse forward button
    KEY_CTL_MOUSE_BACK         Control mouse back button
    KEY_ALT_MOUSE1             Alt mouse button 1 (counted from left)
    KEY_ALT_MOUSE2             Alt mouse button 2 (counted from left)
    KEY_ALT_MOUSE3             Alt mouse button 3 (counted from left)
    KEY_ALT_MOUSE4             Alt mouse wheel scroll up
    KEY_ALT_MOUSE5             Alt mouse wheel scroll down
    KEY_ALT_MOUSE_FWD          Alt mouse forward button
    KEY_ALT_MOUSE_BACK         Alt mouse back button
    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;

  A 'GRAPH_KEYBOARD' additionally provides the following functions:

    - 'buttonPressed', which determines if a given button is
      currently pressed.
    - 'getxpos', which returns the X position of the mouse cursor
      when a button was pressed.
    - 'getypos', which returns the Y position of the mouse cursor
      when a button was pressed.

  The functions 'getxpos' and 'getypos' can be used to determine
  which position was "clicked". The program below uses 'getxpos'
  and 'getypos' to produce a dot for each keypress.

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

    const proc: main is func
      local
        var char: command is ' ';
      begin
        screen(640, 480);
        KEYBOARD := GRAPH_KEYBOARD;
        command := getc(KEYBOARD);
        while command = KEY_MOUSE1 do
          fcircle(getxpos(KEYBOARD), getypos(KEYBOARD), 4, light_red);
          command := getc(KEYBOARD);
        end while;
      end func;

  The current position of the mouse cursor, which is independent
  from key presses can be retrieved with the following functions:

    - 'pointerXPos', which returns the actual X position of the
      mouse pointer.
    - 'pointerYPos', which returns the actual Y position of the
      mouse pointer.

  The functions 'pointerXPos' and 'pointerYPos' can be used to move
  something with the cursor (e.g.: drag and drop). The program below
  uses 'buttonPressed' to determine how long the mouse button is
  pressed. This is used together with 'pointerXPos' and 'pointerYPos'
  to draw along the mouse cursor while the mouse button is pressed:

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

    const proc: main is func
      local
        var char: command is ' ';
      begin
        screen(640, 480);
        KEYBOARD := GRAPH_KEYBOARD;
        command := getc(KEYBOARD);
        while command = KEY_MOUSE1 do
          while buttonPressed(KEYBOARD, KEY_MOUSE1) do
            fcircle(pointerXPos(curr_win), pointerYPos(curr_win), 4, light_red);
          end while;
          command := getc(KEYBOARD);
        end while;
      end func;

  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 := openEcho(KEYBOARD, OUT);
        repeat
          ch := getc(IN);
        until ch = '!';
        writeln;
      end func;

  An 'echo_file' checks also for control-C ('KEY_CTL_C'). If
  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 := openEcho(KEYBOARD, OUT);
        IN := openLine(IN);
        repeat
          ch := getc(IN);
          write(ch);
        until ch = '!';
      end func;

  This program terminates if 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 current line is: " <& line(aText));
    writeln("The current 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: my_file_type is sub null_file struct
        ...
        (* Local data *)
        ...
      end struct;

  It is not necessary to derive the type 'my_file_type' directly from
  'null_file'. The type 'my_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(my_file_type, 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 open a 'my_file_type' file:

    const func file: open_my_file (  (* Parameters *) ) is func
      result
        var file: newFile is STD_NULL;
      local
        var my_file_type: new_file is my_file_type.value;
      begin
        ...
        (* Initialization of the data elements of new_file *)
        newFile := toInterface(new_file);
        ...
      end func;

  Note that the function 'toInterface' is used to generate a new 'file'
  object. Now only the two basic I/O operations must be defined:

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

    const proc: gets (inout my_file_type: 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. If 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 Seed7 comment from a 'file'.
    getComment
      Reads a possibly nested Seed7 comment from a 'file'.
    skipClassicComment
      Skips a classic C 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'.
    getInteger
      Reads a decimal integer with optional sign from a 'file'.
    getNumber
      Reads a numeric literal (integer, bigInteger or float literal) from a 'file'.
    getNonDigits
      Reads a sequence of non digits from a 'file'.
    getQuotedText
      Reads a text quoted with " or ' from a 'file'.
    getSimpleStringLiteral
      Read a simple string literal 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. If normal I/O functions
  need to be combined with scanner functions care has to be taken:

    - If 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 if it is necessary to read
  numeric input without failing if 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'. If 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: processed 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);
          processed := getWhiteSpace(inFile);
          currSymbol := getSymbolOrComment(inFile);
          while currSymbol <> "" do
            processed &:= currSymbol;
            processed &:= 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 if
  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 are described with identifiers. An
      identifier 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 ( ... ) .

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

    - If 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 ::=
      { ebnf_statement } .

    ebnf_statement ::=
      identifier '::=' ebnf_expression '.' .

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

    term ::=
      factor { factor } .

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


9.2 The Seed7 Structured Syntax Description

    The Seed7 Structured Syntax Description is abbreviated with S7SSD.
  The S7SSD can describe most but not all of the syntax of a
  programming language. The syntax of identifiers, literals and
  comments is not described with S7SSD. S7SSD views a program as
  a big typeless expression. The syntax of this expression is
  described with prefix-, infix- and postfix-operators. The operators
  have a priority and an associativity. Operators can have one or
  more operator symbols. The operator symbols of an operator can be
  adjacent or they can have parameters in between. The S7SSD of
  an infix + is:

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

  This defines the + as left associative infix operator with
  priority 7. The + operator is an infix operator because the
  operator pattern is:

    () + ()

  The place of the parameters is specified with (). Any expression
  can be used as parameter. The type of the parameters and the type
  of the result of + is not specified by the S7SSD. Checks for the
  correct type are not done at the syntactic level. This way S7SSD
  allows syntax that would not be allowed in a corresponding EBNF
  description. S7SSD considers just operator symbols and their
  priority and associativity.


9.3 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. If 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.4 Priority and associativity

    If 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:

    +-------------------------------------------+--------+
    | Associativity                             | 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 an
  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.5 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)

  If 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: negation is TRUE;
      begin
        if aBool then
          negation := FALSE;
        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 if 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).
      If 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.6 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.7 Advanced syntax definitions

  If 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.8 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 } .

  The EBNF description can become long if many priority levels
  exist, as it is the case in Seed7.

  There are some things which are out of the scope of S7SSD.
  The syntax of comments, tokens (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 identifier, integer,
  bigInteger or float literal. 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 } '*)' .

    any_character ::=
      simple_literal_character | apostrophe | '"' | '\' |
      control_character  .

    control_character ::=
      NUL | SOH | STX | ETX | EOT | ENQ | ACK | BEL |
      BS  | TAB | LF  | VT  | FF  | CR  | SO  | SI  |
      DLE | DC1 | DC2 | DC3 | DC4 | NAK | SYN | ETB |
      CAN | EM  | SUB | ESC | FS  | GS  | RS  | US  |
      DEL .

  If a comment is not closed at the end of the main file a parsing error
  is triggered:

    *** tst256.sd7(2):6: Unclosed comment
    (* Unclosed comment


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 several types of literals

    integer literals
    biginteger literals
    float literals
    character literals
    string literals

  Syntax:

    literal ::=
      integer_literal | biginteger_literal | float_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 .

  If an integer literal cannot be read a parsing error
  is triggered:

    *** tst256.sd7(2):10: Integer "12345678901234567890" too big
    const integer: tooBig is 12345678901234567890;
    ---------------------------------------------^
    *** tst256.sd7(3):11: Negative exponent in integer literal
    const integer: negativeExponent is 1e-1;
    -------------------------------------^
    *** tst256.sd7(4):12: Digit expected found ";"
    const integer: digitExpected is 1e;
    ----------------------------------^
    *** tst256.sd7(5):13: Integer "1E20" too big
    const integer: integerWithExponentTooBig is 1e20;
    ------------------------------------------------^
    *** tst256.sd7(6):14: Integer base "37" not between 2 and 36
    const integer: baseNotBetween2To36 is 37#0;
    ----------------------------------------^
    *** tst256.sd7(7):15: Extended digit expected found ";"
    const integer: extendedDigitExpected is 16#;
    -------------------------------------------^
    *** tst256.sd7(8):16: Illegal digit "G" in based integer "16#G"
    const integer: illegalBasedDigit is 16#G;
    ----------------------------------------^
    *** tst256.sd7(9):17: Based integer "16#ffffffffffffffff" too big
    const integer: basedIntegerTooBig is 16#ffffffffffffffff;
    --------------------------------------------------------^


10.3.2 BigInteger literals

    A bigInteger literal is a sequence of digits followed by the
  underline character. The sequence of digits is taken to be
  decimal. Based numbers can be specified when a sequence of
  digits is followed by the # character, a sequence of extended
  digits and the underline character. 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:

    biginteger_literal ::=
      decimal_integer [ based_integer ] '_' .


10.3.3 Float literals

    A float literal consists of two decimal integer literals
  separated by a decimal point. The basic float literal may be
  followed by the letter E or e an optional + or - sign and a
  decimal exponent.

  Syntax:

    float_literal ::=
      decimal_integer '.' decimal_integer [ float_exponent ] .

    float_exponent ::=
      ( 'E' | 'e' ) [ '+' | '-' ] decimal_integer .


10.3.4 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
    backspace        BS       \b
    escape           ESC      \e
    formfeed         FF       \f
    newline          NL (LF)  \n
    carriage return  CR       \r
    horizontal tab   HT       \t
    vertical tab     VT       \v
    backslash        (\)      \\
    apostrophe       (')      \'
    double quote     (")      \"
    control-A                 \A
      ...
    control-Z                 \Z

  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.

    - A backslash followed by an integer literal and a semicolon
      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_literal_element } '"' .

    string_literal_element ::=
      simple_literal_character | escape_sequence | apostrophe .

    simple_literal_character ::=
      letter | digit | parenthesis | special_literal_character |
      utf8_encoded_character .

    special_literal_character ::=
      ' ' | '!' | '#' | '$' | '%' | '&' | '*' | '+' | ',' | '-' |
      '.' | '/' | ':' | ';' | '<' | '=' | '>' | '?' | '@' | '^' |
      '_' | '`' | '|' | '~' .

    escape_sequence ::=
      '\a' | '\b' | '\e' | '\f' | '\n' | '\r' | '\t' | '\v' |
      '\\' | '\''' | '\"' | '\' upper_case_letter |
      '\' { space } '\' | '\' integer_literal ';' .

    apostrophe ::=
      ''' .

  If an string literal cannot be read a parsing error
  is triggered:

    *** tst256.sd7(2):20: Use \" instead of "" to represent " in a string
    const string: wrongQuotationRepresentation is "double "" quotations";
    -------------------------------------------------------^
    *** tst256.sd7(3):21: Illegal string escape "\z"
    const string: illegalStringEscape is "\z";
    ---------------------------------------^
    *** tst256.sd7(4):22: Numerical escape sequences should end with ";" not "x"
    const string: wrongNumericEscape is "\1234xyz";
    ------------------------------------------^
    *** tst256.sd7(5):23: The numerical escape sequence "\1234678123467892346;" is too big
    const string: numericEscapeTooBig is "asd\1234678123467892346;dfdfg";
    -------------------------------------------------------------^
    *** tst256.sd7(6):24: String continuations should end with "\" not "c"
    const string: backslashExpected is "string \      continuation";
    --------------------------------------------------^
    *** tst256.sd7(7):25: String literal exceeds source line
    const string: exceedsSourceLine is "abc
    ---------------------------------------^
    *** tst256.sd7(8):27: Integer literal expected found "1.5"
    const string: integerExpected is "\1.5;";
    --------------------------------------^


10.3.5 Character literals

    A character literal is an UTF-8 encoded Unicode character
  enclosed in apostrophes. For example:

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

  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 ::=
      apostrophe char_literal_element apostrophe .

    char_literal_element ::=
      simple_literal_character | escape_sequence | apostrophe | '"' .

  If an char literal cannot be read a parsing error
  is triggered:

    *** tst256.sd7(2):18: "'" expected found ";"
    const char: apostropheExpected is 'x;
    ------------------------------------^
    *** tst256.sd7(3):19: Character literal exceeds source line
    const char: charExceeds is '
    ----------------------------^



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. Syntax rules
  are defined with syntax declarations. How syntax declarations
  work is described in Chapter 3.2 (Syntax declarations) and
  chapter 9 (Structured syntax definition). The syntax
  declarations support the extensible syntax of Seed7. A
  simplified description of user defined expressions, which
  does not take priority levels into account, is:

    expression ::=
      prefix_expression | infix_expression | simple_expression .

    prefix_expression ::=
      identifier { identifier | expression } .

    infix_expression ::=
      expression identifier { identifier | expression } .

    simple_expression ::=
      dot_expression .

  The chapters below describe the predefined syntax rules
  of simple expressions.


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 [ '(' parameter_list ')' ] .

    primary_expression ::=
      parentheses_expression | token .

    parameter_list ::=
      expression { ',' expression } .


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", "dir.s7i" and "environment.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
        'array string'.
    RANGE_ERROR
        'dirPath' does not use the standard path representation
        or it cannot be converted to 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
        'array string'.
    RANGE_ERROR
        'dirPath' does not use the standard path representation
        or it cannot be converted to 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' does not use the standard path representation
        or it cannot be converted to 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' does not use the standard path representation
        or it cannot be converted to 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 homeDir

    The function 'homeDir' returns the home directory of the user
  as absolute path.

    const func string: homeDir is ...

  This function should be preferred over the use of an environment
  variable such as '$HOME'. '$HOME' is not supported under all operating
  systems and it is not guaranteed, that it uses the standard path
  representation.

  Returns:
    The absolute path of the home directory.

  Possible exceptions:
    MEMORY_ERROR
        Not enough memory to represent the result 'string'.
    FILE_ERROR
        Not able to determine the home directory.

  Examples:
    The statement

      my_dir := homeDir;

    assigns the full path of the home directory to the
    'string' variable 'my_dir'.


12.8 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'
  can also return 'FILE_SYMLINK', because it does not follow symbolic
  links. All functions which use a file path, except 'fileTypeSL'
  and 'readlink' follow symbolic links.  A return value of
  'FILE_ABSENT' does not imply that a file with this name can be
  created, since missing directories and illegal file names cause
  also 'FILE_ABSENT'.

  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' does not use the standard path representation.
    FILE_ERROR
        The system function returns an error other than ENOENT,
        ENOTDIR or ENAMETOOLONG.


12.9 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' does not use the standard path representation
        or it cannot be converted to the system path type.
    FILE_ERROR
        A system function returns an error.


12.10 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' does not use the standard path representation
        or it cannot be converted to the system path type.
    FILE_ERROR
        A system function returns an error.


12.11 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' does not use the standard path representation
        or it cannot be converted to 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.12 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' does not use the standard path representation
        or it cannot be converted to the system path type.
    FILE_ERROR
        A system function returns an error.


12.13 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' does not use the standard path representation
        or it cannot be converted to the system path type.
    FILE_ERROR
        A system function returns an error.


12.14 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' does not use the standard path representation
        or it cannot be converted to the system path type.
    FILE_ERROR
        A system function returns an error.


12.15 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' does not use the standard path representation
        or it cannot be converted to 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 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' does not use the standard path representation
        or it cannot be converted to 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.17 readlink

    The function 'readlink' reads the destination of a symbolic link:

    const func string: readlink (in string: filePath) is ...

  Returns:
    The symbolic link referred 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' does not use the standard path representation
        or it cannot be converted to the system path type.
    FILE_ERROR
        The file described with 'filePath' does not exist or is not a symbolic link.


12.18 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' does not use the standard path
        representation or one of them cannot be converted to the
        system path type.
    FILE_ERROR
        A system function returns an error.


12.19 removeFile

    The function 'removeFile' removes a file of any type unless it
  is a directory that is not empty. An attempt to remove a directory
  that is not empty triggers FILE_ERROR.

    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' does not use the standard path representation
        or it cannot be converted to the system path type.
    FILE_ERROR
        The file does not exist or a system function returns an error.


12.20 removeTree

    The function 'removeTree' removes a file of any type inclusive
  a directory tree:

    const proc: removeTree (in string: filePath) is ...

  Possible exceptions:
    MEMORY_ERROR
        Not enough memory to convert 'filePath' to the system path type.
    RANGE_ERROR
        'filePath' does not use the standard path representation
        or it cannot be converted to the system path type.
    FILE_ERROR
        The file does not exist or a system function returns an error.


12.21 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' does not use the standard path
        representation or one of them cannot be converted to the
        system path type.
    FILE_ERROR
        Source file does not exist, destination file already exists or
        a system function returns an error.


12.22 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' does not use the standard path
        representation or one of them cannot be converted to the
        system path type.
    FILE_ERROR
        Source file does not exist, destination file already exists or
        a system function returns an error.


12.23 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' does not use the standard path
        representation or one of them cannot be converted to the
        system path type.
    FILE_ERROR
        Source file does not exist, destination file already exists or
        a system function returns an error.


12.24 argv(PROGRAM)

    The function 'argv(PROGRAM)' returns the argument vector of
  the program as array of strings. The name of the program is
  not part of the argument vector.

    const func array string: argv (PROGRAM) is ...

  Returns:
    An array of strings containing the argument vector.


12.25 name(PROGRAM)

    The function 'name(PROGRAM)' returns the name of the program
  without path and extension. The name returned by 'name(PROGRAM)'
  is the same for interpreted and compiled programs. The function
  'name(PROGRAM)' does not follow symbolic links. It determines,
  with which name a program was called. When several symbolic
  links refer to one program 'name(PROGRAM)' returns the name
  of the symbolic link.

    const func string: name (PROGRAM) is ...

  Returns:
    The name of the program.


12.26 path(PROGRAM)

    The function 'path(PROGRAM)' returns the absolute path
  of the program. For an interpreted program this is the
  absolute path of the source file. For a compiled program
  this is the absolute path of the executable. The function
  'path(PROGRAM)' does follow symbolic links.

    const func string: path (PROGRAM) is ...

  Returns:
    The absolute path of the program.


12.27 dir(PROGRAM)

    The function 'dir(PROGRAM)' returns the absolute path of the
  directory containing the program. The function 'dir(PROGRAM)'
  allows placing configuration data in the directory of the program.
  'dir(PROGRAM)' is based on 'path(PROGRAM)'.

    const func string: dir (PROGRAM) is ...

  Returns:
    The absolute path of the directory containing the program.


12.28 file(PROGRAM)

    The function 'file(PROGRAM)' returns the filename of the
  program without path. 'file(PROGRAM)' is based on 'path(PROGRAM)'.

    const func string: file (PROGRAM) is ...

  Returns:
    The filename of the program.


12.29 getenv

    The function 'getenv' determines the value of an
  environment variable.

    const func string: getenv (in string: name) is ...

  The function 'getenv' 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.30 setenv

    The function 'setenv' adds or changes an environment
  variable.

    const proc: setenv (in string: name, in string: value) is ...

  The function 'setenv' 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.


12.31 environment

    The function 'environment' returns the list of
  environment variable names as array of strings.

    const func array string: environment is ...

  Returns:
    The list of environment variable names.

  Possible exceptions:
    MEMORY_ERROR
        Not enough memory to create the result.



13. DATABASE ABSTRACTION API
============================

    Seed7 provides an abstraction layer for database access. There
  is an application programming interface (API), which defines how
  a client may access a database. Seed7 accomplishes database
  independence by using database drivers as abstraction layers
  between the application and the database. There are database
  drivers for MySQL, MariaDB, SQLLite, PostgreSQL, Oracle, Firebird,
  Interbase, Db2 and SQL Server databases. Databases can also be
  accessed via the ODBC interface. The following example uses the
  datapase abstraction API:

    const proc: dbDemo is func
      local
        var database: currDb is database.value;
        var sqlStatement: statement is sqlStatement.value;
        var integer: index is 0;
      begin
        currDb := openDatabase(DB_MYSQL, "testDb", "testUser", "testPassword");
        if currDb <> database.value then
          statement := prepare(currDb, "SELECT * FROM testTable");
          execute(statement);
          while fetch(statement) do
            for index range 1 to columnCount(statement) do
              write(column(statement, index, string) <& ", ");
            end for;
            writeln;
          end while;
          close(currDb);
        end if;
      end func;


13.1 Opening a database connection

  To open a database connection you need to provide several things:

    - The database type used.
    - The 'host' where the database is running.
      An empty 'host' name ("") specifies the local machine ("localhost").
    - The 'port' to access the database.
      A 'port' of 0 specifies the default port of the database.
    - The 'name' of the database.
    - A database 'user' name.
    - The 'password' of the database user.

  Depending on the database a corresponding database driver must
  be used:

  Database Type | Driver        | Default port | Comment
  --------------+---------------+--------------+--------------------------------------
  MySQL         | DB_MYSQL      |   3306       |
  MariaDB       | DB_MYSQL      |   3306       |
  SQLLite       | DB_SQLITE     |              | Host must be "" and port must be 0.
  PostgreSQL    | DB_POSTGRESQL |   5432       |
  Oracle        | DB_OCI        |   1521       |
  Firebird      | DB_FIRE       |              |
  Interbase     | DB_FIRE       |              |
  Db2           | DB_DB2        |  50000       |
  SQL Server    | DB_SQL_SERVER |   1433       |
   various DBs  | DB_ODBC       |              | Needs an ODBC driver to connect to a database.
  Sybase based  | DB_TDS        |   1433       |Supports SQL Server and Sybase.

  A basic function to open a database is:

    const func database: openDatabase (in dbCategory: driver, in string: host,
                                       in integer: port, in string: dbName,
                                       in string: user, in string: password)

  The following statements each open a database:

    currDb := openDatabase(DB_MYSQL, "www.example.org", 0, "testDb", "testUser", "testPassword");

    currDb := openDatabase(DB_MYSQL, "192.0.2.235", 0, "testDb", "testUser", "testPassword");

    currDb := openDatabase(DB_POSTGRESQL, "1234:feed::dead:beef", 0, "testDb", "testUser", "testPassword");

    currDb := openDatabase(DB_POSTGRESQL, "localhost", 0, "testDb", "testUser", "testPassword");

    currDb := openDatabase(DB_OCI, "", 0, "aServiceName", "testUser", "testPassword");

    currDb := openDatabase(DB_OCI, "www.example.org", 2345, "aServiceName", "testUser", "testPassword");

    currDb := openDatabase(DB_OCI, "192.0.2.235", 0, "aSid", "testUser", "testPassword");

    currDb := openDatabase(DB_DB2, "www.example.org", 0, "testDb", "testUser", "testPassword");

    currDb := openDatabase(DB_SQL_SERVER, "192.168.1.13", 0, "testDb", "testUser", "testPassword");

    currDb := openDatabase(DB_TDS, "192.168.1.13", 0, "testDb", "testUser", "testPassword");

  The 'host' can be specified by name (e.g.: "www.example.org"),
  by an IPv4 address (e.g.: "192.0.2.235") or by an IPv6
  address in colon notation (e.g.: "1234:feed::dead:beef").
  Specifying "" as 'host' means "localhost".


13.1.1 Opening an Oracle database connection

  When using the 'DB_OCI' driver you can either supply a net_service_name
  from tnsnames.ora or a service_name or a sid as 'dbName'. If
  tnsnames.ora is used the parameter 'host' must be "" and the
  parameter 'port' must be 0.

    currDb := openDatabase(DB_OCI, "", 0, "tnsnamesOraEntryName", "testUser", "testPassword");


13.1.2 Opening a Db2 database connection

  When using the 'DB_DB2' driver you can either supply a DSN
  (data source name) from db2cli.ini (or db2dsdriver.cfg) or a
  database name as 'dbName'. If a DSN is used the parameter
  'host' must be "" and the parameter 'port' must be 0.

    currDb := openDatabase(DB_DB2, "", 0, "databaseAlias", "testUser", "testPassword");


13.1.3 Opening a SQL Server database connection

  When using the 'DB_SQL_SERVER' driver you can either supply a database name
  from the local machine or a database that can be accessed via
  TCP/IP. To access a database at the local machine the parameter
  'host' must be "" and the parameter 'port' must be 0.
  If TCP/IP is used it must be enabled in the database.

    currDb := openDatabase(DB_SQL_SERVER, "", 0, "localDb", "testUser", "testPassword");


13.1.4 Opening a SQLite database connection

  A SQLite database can be opened with:

    currDb := openDatabase(DB_SQLITE, "", 0, "aDir/dbName.db", "testUser", "testPassword");

    currDb := openDatabase(DB_SQLITE, "", 0, "aDir/dbName", "testUser", "testPassword");

  The path to the database file (in the example above "aDir/dbName")
  can be specified with or without the extension ".db".
  For a SQLite database 'host' must be "" and 'port' must be 0.


13.1.5 Opening a ODBC database connection

  The Seed7 database driver 'DB_ODBC' is special, as the ODBC
  interface itself allows connecting to several database types.
  The ODBC interface library accomplishes this by using ODBC drivers.
  Unfortunately these drivers do come in varying quality. Accessing
  a database directly via the Seed7 driver should be the preferred
  method. For SQL Server ODBC is the only connection interface.
  Opening an ODBC database can be done with the following function:

    const func database: openDatabase (DB_ODBC, in string: odbcDriver,
                                       in string: server, in string: dbName,
                                       in string: user, in string: password)

  A SQL Server can be opened with:

    currDb := openDatabase(DB_ODBC, "sqlserver", "", "", "testUser", "testPassword");

    currDb := openDatabase(DB_ODBC, "sqlserver", "", "", "", "");

  If 'server' or 'dbName' are empty ("") the default values of the
  ODBC driver are used. The ODBC driver may provide also default
  values for 'user' and 'password'.

  ODBC uses also data source names (DSNs) to specify possible
  database connections. It is possible to open an ODBC database
  by specifying the data source name (DSN) in the parameter
  'dbName'. In this case the parameters 'odbcDriver' and 'server'
  must be "".

    currDb := openDatabase(DB_ODBC, "", "", "dsnName", "testUser", "testPassword");

    currDb := openDatabase(DB_ODBC, "", "", "dsnName", "", "");

  When opening using a DSN succeeds, the parameters 'odbcDriver'
  and 'server' are ignored. A DSN might also specify 'user'
  and 'password'. In this case this parameters can be left empty,
  when openDatabase() is called.

  When using windows the DSNs and the ODBC drivers can be managed
  with:

    Start -> Control Panel -> Administrative Tools -> Data Sources (ODBC).

  The data source names (DSNs) of unixODBC are specified in the
  file odbc.ini. The ODBC drivers of unixODBC are specified
  in the file odbcinst.ini.


13.2 Other ways to open a database connection

  There is another variant of opening a database:

    const func database: openDatabase (in dbCategory: driver, in string: dbPath,
                                       in string: user, in string: password)

  The 'dbPath' can be given in one of these forms:

    - host:port/dbName
    - host/dbName
    - dbName

  The 'host' can be specified by name (e.g.: "www.example.org"),
  or by IPv4 address (e.g.: "192.0.2.235") or by IPv6 address in
  colon notation (e.g.: "[1234:feed::dead:beef]"). Note that an
  IPv6 address must be enclosed in brackets. If 'host' is not
  specified the default host ("localhost") will be used. If 'port'
  is not specified the default port of the driver will be used. The
  following statements each open a database:

    currDb := openDatabase(DB_MYSQL, "www.example.org:1234/testDb", "testUser", "testPassword");

    currDb := openDatabase(DB_MYSQL, "[1234:feed::dead:beef]:1234/testDb", "testUser", "testPassword");

    currDb := openDatabase(DB_POSTGRESQL, "192.0.2.235/testDb", "testUser", "testPassword");

    currDb := openDatabase(DB_POSTGRESQL, "testDb", "testUser", "testPassword");

    currDb := openDatabase(DB_OCI, "sidOrServiceName", "testUser", "testPassword");

    currDb := openDatabase(DB_OCI, "tnsnamesOraEntryName", "testUser", "testPassword");

  If 'driver' is 'DB_ODBC' the 'dbPath' can be specified in one
  of these forms:

    - odbcDriver:dbServer/dbName
    - odbcDriver:dbServer
    - dbServer/dbName
    - odbcDataSourceName

  Use a value like "sqlserver" for 'odbcDriver'.

  If 'driver' is 'DB_SQLITE' then 'dbPath' is the path of a
  database file:

    - sqlitePath

  The 'sqlitePath' uses the Seed7 standard path representation.
  A SQLite database can be opened with:

    currDb := openDatabase(DB_SQLITE, "aDir/dbName", "testUser", "testPassword");

  It is also possible ot open a database with a connect string:

    const func database: openDatabase (in dbCategory: driver, in string: connectStri)

  The 'connectStri' must be in one of the forms

    - user:password@dbPath
    - user@dbPath
    - dbPath

  If no 'user' is specified the user "guest" will be used. If no
  'password' is specified the password "guest" will be used. The
  'dbPath' is specified as before.


13.3 Prepared statements

  All SQL statements (e.g. SELECT, CREATE, INSERT, UPDATE) can be
  executed by using prepared statements. The database abstraction
  API does not provide a way to execute SQL without a prepared
  statement. After a prepared statement has been created it can be
  executed multiple times. Databases usually optimize prepared
  statements for fast execution. Prepared statements are created
  with the following function:

    const func sqlStatement: prepare (in database: db, in string: sqlStatementStri)

  Regarding the parameter sqlStatementStri some things must be considered:

    - A question mark (?) will be used as placeholder for bind variables.
    - Strings in a SQL statement are enclosed in apostrophes (e.g. 'abc').
      - A string consists of all characters between the enclosing
        apostrophes.
      - Apostrophe characters (') in a string must be doubled to
        get one apostrophe character in the string.
    - Comments in a SQL statement start with /* and end with */.
    - Line comments in a SQL statement start with -- and end
      with a newline character ('\n').
    - Table and field names can be enclosed in double quotes (e.g. "aTable").
      - This way a table or field name may contain spaces or other
        characters, that are normally not allowed.
      - Double quotes in a quoted name must be doubled (be aware that several
        databases do not allow double quotes in names).

  The following statements each create a prepared SQL statement:

    statement := prepare(currDb, "CREATE TABLE customers (name CHAR(128), area CHAR(128))");

    statement := prepare(currDb, "SELECT * FROM customers");

    statement := prepare(currDb, "SELECT * FROM customers /* comment */ WHERE name = 'adam'");

    statement := prepare(currDb, "SELECT * FROM customers -- Comment\n  WHERE name != 'adam'");

    statement := prepare(currDb, "SELECT * FROM customers WHERE name = ?");

    statement := prepare(currDb, "SELECT * FROM customers WHERE name LIKE '%''%'");

    statement := prepare(currDb, "SELECT \"a field\" FROM \"a table\"");

  Preparing a statement fails with a RANGE_ERROR, if the database
  is not open. This is checked by the driver. Other things are
  checked by the database. The database might raise the exception
  DATABASE_ERROR. Note that some databases do not check everything,
  when preparing the statement. So an illegal SQL statement might
  be accepted by prepare(), but executing the prepared statement
  later will fail.

  Executing a prepared statement that neither has bind variables
  nor returns a result is quite simple:

    statement := prepare(currDb, "CREATE TABLE customers (name CHAR(128), area CHAR(128))");
    execute(statement);


13.4 Bind values to placeholders

  Question marks (?) in a prepared statement string are used as
  placeholder for bind variables. Before a prepared statement is
  executed it is necessary to bind values to the placeholders (?).
  Prepared statements without placeholders do not need a binding.
  It is possible to bind the same placeholder as often as you like.
  even with values from different types. This can be used to
  execute the same prepared statement multiple times with
  different values. The binding is done with a bind() function.
  For several types bind() functions are defined:

    const proc: bind (inout sqlStatement: statement, in integer: pos, in bigInteger: num)

    const proc: bind (inout sqlStatement: statement, in integer: pos, in bigRational: num)

    const proc: bind (inout sqlStatement: statement, in integer: pos, in boolean: flag)

    const proc: bind (inout sqlStatement: statement, in integer: pos, in bstring: bstri)

    const proc: bind (inout sqlStatement: statement, in integer: pos, in float: number)

    const proc: bind (inout sqlStatement: statement, in integer: pos, in integer: number)

    const proc: bind (inout sqlStatement: statement, in integer: pos, NULL)

    const proc: bind (inout sqlStatement: statement, in integer: pos, in string: stri)

    const proc: bind (inout sqlStatement: statement, in integer: pos, in time: timeData)

    const proc: bind (inout sqlStatement: statement, in integer: pos, in duration: durationData)

  Binding fails with a RANGE_ERROR, if the statement has not
  been prepared. Binding is done by position. Position numbers
  start with 1. To bind the 'integer' 12345 to the third
  placeholder (?) of a prepared statement do:

    bind(statement, 3, 12345);

  The bind() functions check the given position (pos) and raise
  the exception RANGE_ERROR, if no corresponding placeholder (?)
  is found. This happens if pos <= 0 holds or if pos is greater
  than the number of placeholders. The bind() functions check
  also, if the type of the given value fits to the database
  column. If the type does not fit the exception RANGE_ERROR is
  raised.

  Another example with binding is:

    write("name? ");
    readln(name);
    statement := prepare(currDb, "SELECT name, area FROM customers WHERE name = ?");
    bind(statement, 1, name);
    execute(statement);
    . . .  Write a list of names and areas.

  Binding protects against SQL injection. SQL injection is a
  technique to attack applications. SQL injection is possible,
  if the SQL statement is build from user input. Suppose we
  do the example above without binding:

    write("name? ");
    readln(name);
    statement := prepare(currDb, "SELECT name, area FROM customers WHERE name = '" <& name <& "'");
    execute(statement);
    . . .  Write a list of names and areas.

  Suppose the user enters (when asked for the name):

    ' UNION SELECT login, password FROM user --

  This would prepare and execute the SQL statement:

    SELECT name, area FROM customers WHERE name = '' UNION SELECT login, password FROM user --'

  The result would additionally contain secret data you certainly would not like to be displayed.


13.5 Execute a prepared statement

  To make a prepared statement run it must be executed.
  Prepared statements are executed with the following function:

    const proc: execute (inout sqlStatement: statement)

  The following statement executes a prepared SQL statement:

    execute(statement);

  Executing fails with a RANGE_ERROR, if the statement has not
  been prepared. Executing fails with a DATABASE_ERROR, if
  not all parameters have been bound. If the database returns
  an error the exception DATABASE_ERROR gets also raised. Note
  that illegal SQL statements might raise a DATABASE_ERROR in
  prepare() or in execute(). When the exception is raised
  depends on the database.

  There are prepared statements, that return a result set of
  records (e.g.: SELECT) and others that do not
  return data (e.g.: UPDATE). After executing a prepared
  statement the number of columns in a record (row) of the
  result set can be retrieved with the following function:

    const func integer: columnCount (in sqlStatement: statement)

  If a prepared statement does not return data columnCount()
  returns 0. The names of the columns in a record (row) of
  the result set can be obtained with the function:

    const func string: columnName (in sqlStatement: statement, in integer: column)

  These functions can be combined to write the column names
  of a prepared statement:

    execute(statement);
    for columnNum range 1 to columnCount(statement) do
      write(columnName(statement, columnNum) <& " ");
    end for;
    writeln;


13.6 Fetch records from the result set

  After executing a prepared statement that returns data
  (e.g.: SELECT), the records (rows) can be fetched one by one
  with fetch(). After executing a prepared statement
  returning no data fetching is not necessary. Fetching is done
  with the following function:

    const func boolean: fetch (in sqlStatement: statement)

  The function returns TRUE, if a record of the result set
  could be fetched successfully. The function returns FALSE,
  if there is no data (e.g.: UPDATE) or no more row (record)
  to fetch. The following example shows how fetch() is usually
  used:

    execute(statement);
    while fetch(statement) do
      . . .  Process a record from the result set.
    end while;


13.7 Get columns from fetched records

  After a record (row) has been fetched from a result set
  individual column data can be retrieved with a column() function.
  For several types column() functions are defined:

    const func bigInteger: column (in sqlStatement: statement, in integer: column, attr bigInteger)

    const func bigRational: column (in sqlStatement: statement, in integer: column, attr bigRational)

    const func boolean: column (in sqlStatement: statement, in integer: column, attr boolean)

    const func bstring: column (in sqlStatement: statement, in integer: column, attr bstring)

    const func duration: column (in sqlStatement: statement, in integer: column, attr duration)

    const func float: column (in sqlStatement: statement, in integer: column, attr float)

    const func integer: column (in sqlStatement: statement, in integer: column, attr integer)

    const func string: column (in sqlStatement: statement, in integer: column, attr string)

    const func time: column (in sqlStatement: statement, in integer: column, attr time)

  Getting a column fails with a RANGE_ERROR, if no record
  has been fetched from the result set. Column numbers start
  with 1. To get column number four from the current result
  record (row) as 'integer' do:

    column(statement, 4, integer);

  The column() functions check the given position (column) and
  raise the exception RANGE_ERROR, if no corresponding column
  exists in the result record. This happens if column <= 0
  is TRUE or if column is greater than the number of columns
  (which can be obtained with columnCount()). Database columns can
  be NULL. This can be checked with the following function:

    const func boolean: isNull (in sqlStatement: statement, in integer: column)

  The function isNull() returns TRUE, if the specified column
  is NULL. Otherwise isNull() returns FALSE. The column()
  functions return a default value, if a column is NULL. The
  following default values are used:

  Type        | Default value
  ------------+----------------
  bigInteger  | 0_
  bigRational | 0_/1_
  boolean     | FALSE
  bstring     | bstring("")
  duration    | duration.value
  float       | 0.0
  integer     | 0
  string      | ""
  time        | time.value



14. 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)
    _MOD      Modulo (Reminder of _MDIV integer division)
    _MULT     Multiply
    _NE       Not equal
    _NEGATE   Change sign
    _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
    BIN_  binlib.c  'bin32' and 'bin64' 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
    CON_  conlib.c  'console_file' operations
    DCL_  dcllib.c  Declaration operations
    DRW_  drwlib.c  Drawing operations
    ENU_  enulib.c  Enumeration operations
    FIL_  fillib.c  'clib_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
    PCS_  pcslib.c  'process' operations
    POL_  pollib.c  'pollData' operations
    PRC_  prclib.c  'proc' operations and statements
    PRG_  prglib.c  Program operations
    REF_  reflib.c  'reference' operations
    RFL_  rfllib.c  'ref_list' operations
    SCT_  sctlib.c  'struct' operations
    SET_  setlib.c  'set' operations
    SOC_  soclib.c  'PRIMITIVE_SOCKET' operations
    SQL_  sqllib.c  'database' 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 s7 interpreter. The function for the
  action 'INT_ADD' is 'int_add()'. The function 'int_add()'
  is defined in the file "intlib.c" with:

    objectType int_add (listType arguments)

      { /* 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 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 arguments);

  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 s7 interpreter
  understands a primitive action.

  To allow a primitive function in a compiled Seed7 program the
  Seed7 compiler (s7c) needs to know the action also. The
  compiler function which creates code for the 'INT_ADD' action is:

    const proc: process (INT_ADD, in reference: function,
        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 defined in "seed7/lib/comp/int_act.s7i" and
  called from the function 'process_action' with:

    elsif action_name = "INT_ADD" then
      process(INT_ADD, function, 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:

    objectType int_log2 (listType arguments)

      { /* 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.
     */
    intType intLog2 (intType number)

      {
        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);

  The helper functions are also used in the code generated by
  the Seed7 compiler:

    const proc: process (INT_LOG2, in reference: function,
        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);");

  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 (s7c) inline code is generated for many
  primitive actions. To implement the remaining primitive
  actions the functions of the "seed7_05.a" library are used.


14.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_EQ              act_eq              ==
    ACT_GEN             act_gen
    ACT_ICONV1          act_iconv1          actIConv
    ACT_ICONV3          act_iconv3          actIConv
    ACT_NE              act_ne              !=
    ACT_ORD             act_ord             actOrd
    ACT_STR             act_str             actStr
    ACT_VALUE           act_value           actValue


14.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_INSERT          arr_insert          arrInsert
    ARR_INSERT_ARRAY    arr_insert_array    arrInsertArray
    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_REMOVE_ARRAY    arr_remove_array    arrRemoveArray
    ARR_SORT            arr_sort            arrSort
    ARR_SUBARR          arr_subarr          arrSubarr, arrSubarrTemp
    ARR_TAIL            arr_tail            arrTail
    ARR_TIMES           arr_times           times_ ...


14.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_ADD_ASSIGN      big_add_assign      bigAddAssign, bigAddAssignSignedDigit
    BIG_BIT_LENGTH      big_bit_length      bigBitLength
    BIG_CMP             big_cmp             bigCmp
    BIG_CONV            big_conv            (noop)
    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_DIV_REM         big_div_rem         bigDivRem
    BIG_EQ              big_eq              bigEq
    BIG_FROM_BSTRI_BE   big_fromBStriBe     bigFromBStriBe
    BIG_FROM_BSTRI_LE   big_fromBStriLe     bigFromBStriLe
    BIG_GCD             big_gcd             bigGcd
    BIG_GE              big_ge              bigCmp >= 0
    BIG_GT              big_gt              bigCmp > 0
    BIG_HASHCODE        big_hashcode        bigHashCode
    BIG_ICONV1          big_iconv1          bigIConv
    BIG_ICONV3          big_iconv3          bigIConv
    BIG_INCR            big_incr            bigIncr
    BIG_IPOW            big_ipow            bigIPow
    BIG_LE              big_le              bigCmp <= 0
    BIG_LOG10           big_log10           bigLog10
    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_MOD             big_mod             bigMod
    BIG_MULT            big_mult            bigMult
    BIG_MULT_ASSIGN     big_mult_assign     bigMultAssign
    BIG_NE              big_ne              bigNe
    BIG_NEGATE          big_negate          bigNegate
    BIG_ODD             big_odd             bigOdd
    BIG_ORD             big_ord             bigOrd
    BIG_PARSE1          big_parse1          bigParse
    BIG_PARSE_BASED     big_parse_based     bigParseBased
    BIG_PLUS            big_plus            (noop)
    BIG_PRED            big_pred            bigPred
    BIG_RADIX           big_RADIX           bigRadix
    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_SBTR_ASSIGN     big_sbtr_assign     bigSbtrAssign, bigAddAssignSignedDigit
    BIG_STR             big_str             bigStr
    BIG_SUCC            big_succ            bigSucc
    BIG_TO_BSTRI_BE     big_toBStriBe       bigToBStriBe
    BIG_TO_BSTRI_LE     big_toBStriLe       bigToBStriLe
    BIG_VALUE           big_value           bigValue
    BIG_radix           big_radix           bigRadix


14.4 Actions for the types bin32 and bin64

    Action name         blnlib.c function   bln_rtl.c function
    BIN_AND             bin_and             &
    BIN_AND_ASSIGN      bin_and_assign      &=
    BIN_BIG             bin_big             bigFromUInt64
    BIN_BINARY          bin_binary          bigToUInt64
    BIN_CARD            bin_card            uintCard
    BIN_CMP             bin_cmp             uintCmp
    BIN_GET_BINARY_FROM_SET bin_get_binary_from_set setToUInt
    BIN_LSHIFT          bin_lshift          (intType)((uintType)(a<&ltb))
    BIN_LSHIFT_ASSIGN   bin_lshift_assign   a=(intType)((uintType)(a<&ltb))
    BIN_OR              bin_or              |
    BIN_OR_ASSIGN       bin_or_assign       |=
    BIN_RADIX           bin_RADIX           uintRadix
    BIN_RSHIFT          bin_rshift          (intType)((uintType)(a>>b))
    BIN_RSHIFT_ASSIGN   bin_rshift_assign   a=(intType)((uintType)(a>>b))
    BIN_STR             bin_str             uintStr
    BIN_XOR             bin_xor             ^
    BIN_XOR_ASSIGN      bin_xor_assign      ^=
    BIN_radix           bin_radix           uintRadix


14.5 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_EQ              bln_eq              ==
    BLN_GE              bln_ge              >=
    BLN_GT              bln_gt              >
    BLN_ICONV1          bln_iconv1          & 1
    BLN_ICONV3          bln_iconv3          & 1
    BLN_LE              bln_le              <=
    BLN_LT              bln_lt              <
    BLN_NE              bln_ne              !=
    BLN_NOT             bln_not             !
    BLN_OR              bln_or              ||
    BLN_ORD             bln_ord             (intType)
    BLN_TERNARY         bln_ternary         ((cond)?(thenExpr):(elseExpr))
    BLN_VALUE           bln_value           blnValue


14.6 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_PARSE1          bst_parse1          bstParse
    BST_STR             bst_str             bstStr
    BST_VALUE           bst_value           bstValue


14.7 Actions for the type char

    Action name         chrlib.c function   chr_rtl.c function
    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_ICONV1          chr_iconv1          (charType)
    CHR_ICONV3          chr_iconv3          (charType)
    CHR_INCR            chr_incr            ++
    CHR_IS_LETTER       chr_is_letter       chrIsLetter
    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
    CHR_WIDTH           chr_width           chrWidth


14.8 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_ENVIRONMENT     cmd_environment     cmdEnvironment
    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_GROUP       cmd_get_group       cmdGetGroup
    CMD_GET_MTIME       cmd_get_mtime       cmdGetMTime
    CMD_GET_OWNER       cmd_get_owner       cmdGetOwner
    CMD_GET_SEARCH_PATH cmd_getSearchPath   cmdGetSearchPath
    CMD_HOME_DIR        cmd_homeDir         cmdHomeDir
    CMD_LS              cmd_ls              cmdLs
    CMD_MKDIR           cmd_mkdir           cmdMkdir
    CMD_MOVE            cmd_move            cmdMove
    CMD_READLINK        cmd_readlink        cmdReadlink
    CMD_REMOVE_FILE     cmd_remove_file     cmdRemoveFile
    CMD_REMOVE_TREE     cmd_remove_tree     cmdRemoveTree
    CMD_SETENV          cmd_setenv          cmdSetenv
    CMD_SET_ATIME       cmd_set_atime       cmdSetATime
    CMD_SET_FILEMODE    cmd_set_filemode    cmdSetFileMode
    CMD_SET_GROUP       cmd_set_group       cmdSetGroup
    CMD_SET_MTIME       cmd_set_mtime       cmdSetMTime
    CMD_SET_OWNER       cmd_set_owner       cmdSetOwner
    CMD_SET_SEARCH_PATH cmd_setSearchPath   cmdSetSearchPath
    CMD_SHELL           cmd_shell           cmdShell
    CMD_SHELL_ESCAPE    cmd_shell_escape    cmdShellEscape
    CMD_SYMLINK         cmd_symlink         cmdSymlink
    CMD_TO_OS_PATH      cmd_to_os_path      cmdToOsPath
    CMD_UNSETENV        cmd_unsetenv        cmdUnsetenv


14.9 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_COLUMN          con_column          conColumn
    CON_CURSOR          con_cursor          conCursor
    CON_FLUSH           con_flush           conFlush
    CON_HEIGHT          con_height          conHeight
    CON_H_SCL           con_h_scl           conHScroll
    CON_LINE            con_line            conLine
    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


14.10 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_IN1             dcl_in1
    DCL_IN1VAR          dcl_in1var
    DCL_IN2             dcl_in2
    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


14.11 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_BORDER          drw_border          drwBorder
    DRW_CAPTURE         drw_capture         drwCapture
    DRW_CIRCLE          drw_circle          drwCircle
    DRW_CLEAR           drw_clear           drwClear
    DRW_CMP             drw_cmp             uintCmpGeneric((genericType)(a))
    DRW_COLOR           drw_color           drwColor
    DRW_CONVPOINTLIST   drw_convPointList   drwConvPointList
    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_GETIMAGE        drw_getImage        drwGetImage
    DRW_GETIMAGEPIXEL   drw_getImagePixel   drwGetImagePixel
    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_SCREEN_HEIGHT   drw_screen_height   drwScreenHeight
    DRW_SCREEN_WIDTH    drw_screen_width    drwScreenWidth
    DRW_SETCLOSEACTION  drw_setCloseAction  drwSetCloseAction
    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_VALUE           drw_value           drwValue
    DRW_WIDTH           drw_width           drwWidth
    DRW_XPOS            drw_xpos            drwXPos
    DRW_YPOS            drw_ypos            drwYPos


14.12 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


14.13 Actions for the type clib_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_OPEN_NULL_DEVICE fil_open_null_device filOpenNullDevice
    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_TRUNCATE        fil_truncate        filTruncate
    FIL_VALUE           fil_value           filValue
    FIL_WORD_READ       fil_word_read       filWordRead
    FIL_WRITE           fil_write           filWrite


14.14 Actions for the type float

    Action name         fltlib.c function   flt_rtl.c function
    FLT_ABS             flt_abs             fabs
    FLT_ACOS            flt_acos            acos
    FLT_ADD             flt_add             +
    FLT_ADD_ASSIGN      flt_add_assign      +=
    FLT_ASIN            flt_asin            asin
    FLT_ATAN            flt_atan            atan
    FLT_ATAN2           flt_atan2           atan2
    FLT_BITS2DOUBLE     flt_bits2double     (x.bits=a, x.aDouble)
    FLT_BITS2SINGLE     flt_bits2single     (x.bits=a, x.aSingle)
    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_DECOMPOSE       flt_decompose       frexp
    FLT_DGTS            flt_dgts            fltDgts
    FLT_DIV             flt_div             /
    FLT_DIV_ASSIGN      flt_div_assign      /=
    FLT_DOUBLE2BITS     flt_double2bits     (x.aDouble=a, x.bits)
    FLT_EQ              flt_eq              ==
    FLT_EXP             flt_exp             exp
    FLT_FLOOR           flt_floor           floor
    FLT_GE              flt_ge              >=
    FLT_GT              flt_gt              >
    FLT_HASHCODE        flt_hashcode        (x.floatValue=a, x.intValue)
    FLT_ICAST           flt_icast           (x.intValue=a, x.floatValue)
    FLT_ICONV1          flt_iconv1          (float)
    FLT_ICONV3          flt_iconv3          (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_LOG2            flt_log2            log2
    FLT_LSHIFT          flt_lshift          ldexp
    FLT_LT              flt_lt              <
    FLT_MOD             flt_mod             fltMod
    FLT_MULT            flt_mult            *
    FLT_MULT_ASSIGN     flt_mult_assign     *=
    FLT_NE              flt_ne              !=
    FLT_NEGATE          flt_negate          -
    FLT_PARSE1          flt_parse1          fltParse
    FLT_PLUS            flt_plus            (noop)
    FLT_POW             flt_pow             pow
    FLT_RAND            flt_rand            fltRand
    FLT_REM             flt_rem             fmod
    FLT_ROUND           flt_round           a<0.0?-((intType)(0.5-a)):(intType)(0.5+a)
    FLT_RSHIFT          flt_rshift          ldexp
    FLT_SBTR            flt_sbtr            -
    FLT_SBTR_ASSIGN     flt_sbtr_assign     -=
    FLT_SCI             flt_sci             fltSci
    FLT_SIN             flt_sin             sin
    FLT_SINGLE2BITS     flt_single2bits     (x.aSingle=a, x.bits)
    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


14.15 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


14.16 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_RAND_KEY        hsh_rand_key        hshRand
    HSH_REFIDX          hsh_refidx
    HSH_UPDATE          hsh_update          hshUpdate
    HSH_VALUES          hsh_values          hshValues


14.17 Actions for the type integer

    Action name         intlib.c function   int_rtl.c function
    INT_ABS             int_abs             labs
    INT_ADD             int_add             +
    INT_ADD_ASSIGN      int_add_assign      +=
    INT_BINOM           int_binom           intBinom
    INT_BIT_LENGTH      int_bit_length      intBitLength
    INT_BYTES_BE_2_INT  int_bytes_be_2_int  intBytesBe2Int
    INT_BYTES_BE_2_UINT int_bytes_be_2_uint intBytesBe2UInt
    INT_BYTES_BE_SIGNED int_bytes_be_signed intBytesBe
    INT_BYTES_BE_UNSIGNED int_bytes_be_unsigned intBytesBe
    INT_BYTES_LE_2_INT  int_bytes_le_2_int  intBytesLe2Int
    INT_BYTES_LE_2_UINT int_bytes_le_2_uint intBytesLe2UInt
    INT_BYTES_LE_SIGNED int_bytes_le_signed intBytesLe
    INT_BYTES_LE_UNSIGNED int_bytes_le_unsigned intBytesLe
    INT_CMP             int_cmp             intCmp
    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_GT              int_gt              >
    INT_HASHCODE        int_hashcode        (noop)
    INT_ICONV1          int_iconv1          (noop)
    INT_ICONV3          int_iconv3          (noop)
    INT_INCR            int_incr            ++
    INT_LE              int_le              <=
    INT_LOG10           int_log10           intLog10
    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_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_NEGATE          int_negate          -
    INT_ODD             int_odd             &1
    INT_PARSE1          int_parse1          intParse
    INT_PLUS            int_plus            (noop)
    INT_POW             int_pow             intPow
    INT_PRED            int_pred            --
    INT_RADIX           int_RADIX           intRadix
    INT_RAND            int_rand            intRand
    INT_REM             int_rem             %
    INT_RSHIFT          int_rshift          a>>b /* C with arithmetic shift */
                                            a<0?~(~a>>b):a>>b /* C with logical shift */
    INT_RSHIFT_ASSIGN   int_rshift_assign   a>>=b /* C with arithmetic shift */
                                            if (a<0) a= ~(~a>>b); else a>>=b; /* C with logical shift */
    INT_SBTR            int_sbtr            -
    INT_SBTR_ASSIGN     int_sbtr_assign     -=
    INT_SQRT            int_sqrt            intSqrt
    INT_STR             int_str             intStr
    INT_SUCC            int_succ            +1
    INT_VALUE           int_value           intValue
    INT_radix           int_radix           intRadix


14.18 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_DESTR           itf_destr           itfDestr
    ITF_EQ              itf_eq              ==
    ITF_HASHCODE        itf_hashcode        (intType)(((memSizeType)a)>>6)
    ITF_NE              itf_ne              !=
    ITF_SELECT          itf_select
    ITF_TO_INTERFACE    itf_to_interface


14.19 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


14.20 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


14.21 Actions for the type process

    Action name         pcslib.c function   pcs_rtl.c function
    PCS_CHILD_STDERR    pcs_child_stderr    pcsChildStdErr
    PCS_CHILD_STDIN     pcs_child_stdin     pcsChildStdIn
    PCS_CHILD_STDOUT    pcs_child_stdout    pcsChildStdOut
    PCS_CMP             pcs_cmp             pcsCmp
    PCS_CPY             pcs_cpy             pcsCpy
    PCS_CREATE          pcs_create          pcsCreate
    PCS_DESTR           pcs_destr           pcsDestr
    PCS_EMPTY           pcs_empty
    PCS_EQ              pcs_eq              pcsEq
    PCS_EXIT_VALUE      pcs_exit_value      pcsExitValue
    PCS_HASHCODE        pcs_hashcode        pcsHashCode
    PCS_IS_ALIVE        pcs_is_alive        pcsIsAlive
    PCS_KILL            pcs_kill            pcsKill
    PCS_NE              pcs_ne              !pcsEq
    PCS_PIPE2           pcs_pipe2           pcsPipe2
    PCS_PTY             pcs_pty             pcsPty
    PCS_START           pcs_start           pcsStart
    PCS_STR             pcs_str             pcsStr
    PCS_VALUE           pcs_value           pcsValue
    PCS_WAIT_FOR        pcs_wait_for        pcsWaitFor


14.22 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


14.23 Actions for proc operations and statements

    Action name         prclib.c function
    PRC_ARGS            prc_args            arg_v
    PRC_BEGIN           prc_begin
    PRC_BLOCK           prc_block
    PRC_BLOCK_CATCH_ALL prc_block_catch_all
    PRC_BLOCK_OTHERWISE prc_block_otherwise
    PRC_CASE            prc_case            switch
    PRC_CASE_DEF        prc_case_def        switch
    PRC_CASE_HASHSET    prc_case_hashset    switch (hshIdxDefault0(...)
    PRC_CASE_HASHSET_DEF prc_case_hashset_def switch (hshIdxDefault0(...)
    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_DOWNTO_STEP prc_for_downto_step for
    PRC_FOR_TO          prc_for_to          for
    PRC_FOR_TO_STEP     prc_for_to_step     for
    PRC_HEAPSTAT        prc_heapstat
    PRC_HSIZE           prc_hsize           heapsize
    PRC_IF              prc_if              if
    PRC_IF_ELSIF        prc_if_elsif        if
    PRC_IF_NOOP         prc_if_noop         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 {stmts} while (!(cond));
    PRC_REPEAT_NOOP     prc_repeat_noop     do {} while (!(cond));
    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 (cond) {stmts}
    PRC_WHILE_NOOP      prc_while_noop      while (cond) {}


14.24 Actions for the type program

    Action name         prglib.c function   prg_comp.c function
    PRG_CPY             prg_cpy             prgCpy
    PRG_CREATE          prg_create
    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_GLOBAL_OBJECTS  prg_global_objects  prgGlobalObjects
    PRG_MATCH           prg_match           prgMatch
    PRG_MATCH_EXPR      prg_match_expr      prgMatchExpr
    PRG_NAME            prg_name            arg_0
    PRG_NE              prg_ne              !=
    PRG_OWN_NAME        prg_own_name        programName
    PRG_OWN_PATH        prg_own_path        programPath
    PRG_PATH            prg_path            programPath
    PRG_STR_PARSE       prg_str_parse       prgStrParse
    PRG_SYOBJECT        prg_syobject        prgSyobject
    PRG_SYSVAR          prg_sysvar          prgSysvar
    PRG_VALUE           prg_value           prgValue


14.25 Actions for the type reference

    Action name         reflib.c function   ref_data.c function
    REF_ADDR            ref_addr            &
    REF_ALLOC           ref_alloc           refAlloc
    REF_ALLOC_INT       ref_alloc_int       refAllocInt
    REF_ALLOC_STRI      ref_alloc_stri      refAllocStri
    REF_ALLOC_VAR       ref_alloc_var       refAllocVar
    REF_ARRMAXIDX       ref_arrmaxidx       refArrmaxidx
    REF_ARRMINIDX       ref_arrminidx       refArrminidx
    REF_ARRTOLIST       ref_arrtolist       refArrtolist
    REF_BODY            ref_body            refBody
    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_CPY             ref_cpy             refCpy
    REF_CREATE          ref_create          refCreate
    REF_DEREF           ref_deref
    REF_EQ              ref_eq              ==
    REF_FILE            ref_file            refFile
    REF_GETREF          ref_getref          refGetRef
    REF_HASHCODE        ref_hashcode        (intType)(((memSizeType)a)>>6)
    REF_HSHDATATOLIST   ref_hshdatatolist   refHshDataToList
    REF_HSHKEYSTOLIST   ref_hshkeystolist   refHshKeysToList
    REF_HSHLENGTH       ref_hshlength       refHshLength
    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_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_SETVAR          ref_setvar          refSetVar
    REF_STR             ref_str             refStr
    REF_SYMB            ref_symb
    REF_TRACE           ref_trace           printf
    REF_TYPE            ref_type            refType
    REF_VALUE           ref_value           refValue


14.26 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


14.27 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]


14.28 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_CONV1           set_conv1           (noop)
    SET_CONV3           set_conv3           (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_ICONV1          set_iconv1          setIConv
    SET_ICONV3          set_iconv3          setIConv
    SET_INCL            set_incl            setIncl
    SET_INTERSECT       set_intersect       setIntersect
    SET_INTERSECT_ASSIGN set_intersect_assign setIntersectAssign
    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_SCONV1          set_sconv1          setSConv
    SET_SCONV3          set_sconv3          setSConv
    SET_SYMDIFF         set_symdiff         setSymdiff
    SET_UNION           set_union           setUnion
    SET_UNION_ASSIGN    set_union_assign    setUnionAssign
    SET_VALUE           set_value           setValue


14.29 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_SET_OPT_BOOL    soc_setOptBool      socSetOptBool
    SOC_SOCKET          soc_socket          socSocket
    SOC_WORD_READ       soc_word_read       socWordRead
    SOC_WRITE           soc_write           socWrite


14.30 Actions for the types database and sqlStatement

    Action name         sqllib.c function   sql_rtl.c function
    SQL_BIND_BIGINT     sql_bind_bigint     sqlBindBigInt
    SQL_BIND_BIGRAT     sql_bind_bigrat     sqlBindBigRat
    SQL_BIND_BOOL       sql_bind_bool       sqlBindBool
    SQL_BIND_BSTRI      sql_bind_bstri      sqlBindBStri
    SQL_BIND_DURATION   sql_bind_duration   sqlBindDuration
    SQL_BIND_FLOAT      sql_bind_float      sqlBindFloat
    SQL_BIND_INT        sql_bind_int        sqlBindInt
    SQL_BIND_NULL       sql_bind_null       sqlBindNull
    SQL_BIND_STRI       sql_bind_stri       sqlBindStri
    SQL_BIND_TIME       sql_bind_time       sqlBindTime
    SQL_CLOSE           sql_close           sqlClose
    SQL_CMP_DB          sql_cmp_db          ptrCmp
    SQL_CMP_STMT        sql_cmp_stmt        ptrCmp
    SQL_COLUMN_BIGINT   sql_column_bigint   sqlColumnBigInt
    SQL_COLUMN_BIGRAT   sql_column_bigrat   sqlColumnBigRat
    SQL_COLUMN_BOOL     sql_column_bool     sqlColumnBool
    SQL_COLUMN_BSTRI    sql_column_bstri    sqlColumnBStri
    SQL_COLUMN_DURATION sql_column_duration sqlColumnDuration
    SQL_COLUMN_FLOAT    sql_column_float    sqlColumnFloat
    SQL_COLUMN_INT      sql_column_int      sqlColumnInt
    SQL_COLUMN_STRI     sql_column_stri     sqlColumnStri
    SQL_COLUMN_TIME     sql_column_time     sqlColumnTime
    SQL_COMMIT          sql_commit          sqlCommit
    SQL_CPY_DB          sql_cpy_db          sqlCpyDb
    SQL_CPY_STMT        sql_cpy_stmt        sqlCpyStmt
    SQL_CREATE_DB       sql_create_db       sqlCreateDb
    SQL_CREATE_STMT     sql_create_stmt     sqlCreateStmt
    SQL_DESTR_DB        sql_destr_db        sqlDestrDb
    SQL_DESTR_STMT      sql_destr_stmt      sqlDestrStmt
    SQL_DRIVER          sql_driver          sqlDriver
    SQL_EMPTY_DB        sql_empty_db
    SQL_EMPTY_STMT      sql_empty_stmt
    SQL_EQ_DB           sql_eq_db           ==
    SQL_EQ_STMT         sql_eq_stmt         ==
    SQL_ERR_CODE        sql_err_code        sqlErrCode
    SQL_ERR_DB_FUNC     sql_err_db_func     sqlErrDbFunc
    SQL_ERR_LIB_FUNC    sql_err_lib_func    sqlErrLibFunc
    SQL_ERR_MESSAGE     sql_err_message     sqlErrMessage
    SQL_EXECUTE         sql_execute         sqlExecute
    SQL_FETCH           sql_fetch           sqlFetch
    SQL_GET_AUTO_COMMIT sql_get_auto_commit sqlGetAutoCommit
    SQL_IS_NULL         sql_is_null         sqlIsNull
    SQL_NE_DB           sql_ne_db           !=
    SQL_NE_STMT         sql_ne_stmt         !=
    SQL_OPEN_DB2        sql_open_db2        sqlOpenDb2
    SQL_OPEN_FIRE       sql_open_fire       sqlOpenFire
    SQL_OPEN_LITE       sql_open_lite       sqlOpenLite
    SQL_OPEN_MY         sql_open_my         sqlOpenMy
    SQL_OPEN_OCI        sql_open_oci        sqlOpenOci
    SQL_OPEN_ODBC       sql_open_odbc       sqlOpenOdbc
    SQL_OPEN_POST       sql_open_post       sqlOpenPost
    SQL_OPEN_SQLSRV     sql_open_sqlsrv     sqlOpenSqlServer
    SQL_OPEN_TDS        sql_open_tds        sqlOpenTds
    SQL_PREPARE         sql_prepare         sqlPrepare
    SQL_ROLLBACK        sql_rollback        sqlRollback
    SQL_SET_AUTO_COMMIT sql_set_auto_commit sqlSetAutoCommit
    SQL_STMT_COLUMN_COUNT sql_stmt_column_count sqlStmtColumnCount
    SQL_STMT_COLUMN_NAME  sql_stmt_column_name  sqlStmtColumnName


14.31 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_FOR             str_for             for
    STR_FOR_KEY         str_for_key         for
    STR_FOR_VAR_KEY     str_for_var_key     for
    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_LTRIM           str_ltrim           strLtrim
    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_RTRIM           str_rtrim           strRtrim
    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


14.32 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


14.33 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_SET_IN_PARAM_REF   typ_set_in_param_ref
    TYP_SET_IN_PARAM_VALUE typ_set_in_param_value
    TYP_STR             typ_str             typStr
    TYP_VALUE           typ_value           typValue
    TYP_VARCONV         typ_varconv
    TYP_VARFUNC         typ_varfunc         typVarfunc


14.34 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



15. FOREIGN FUNCTION INTERFACE
==============================

    Foreign functions cannot be called directly. It is necessary to
  write wrapper functions. Several things must be done to call a
  foreign function:

    - The C types used by Seed7 must be converted to the C types used
      by the foreign function (E.g.: 'string' and path conversions).
      The result of the foreign function and parameters, which return
      a value, must be converted back. This conversions are usually
      done in a wrapper function.
    - A function with the action prototype (a function with a
      'listType' parameter and an 'objectType' result) must be
      defined. Predefined macros help to access the action arguments
      and to create result values. The action function must be
      registered in the file "primitiv.c".
    - The new action must be introduced to Seed7. This is usually
      done in an *.s7i library file, which introduces an action
      definition.

  In general two functions are needed: A wrapper function and an
  action function. The corresponding function definitions can be
  placed in two *.c files. Corresponding *.h files contain prototypes.
  Assume, we have the library "superlib" and the function 'doWurx1'
  from "superlib" should be called from a Seed7 program. The three
  letter abbreviation sup is used to determine the file and function
  names for wrapper and action. The following files and functions are
  used:

  File         | Function    | Comment
  -------------+-------------+------------------------------------------
  superlib.a   | doWurx1     | External library (the extension may vary)
  superlib.h   | doWurx1     | Prototype of the external C function
  sup_rtl.c    | supDoWurx1  | Wrapper function
  sup_rtl.h    | supDoWurx1  | Prototype of the wrapper function
  suplib.c     | sup_doWurx1 | Action function
  suplib.h     | sup_doWurx1 | Prototype of the action function
  primitiv.c   |             | Alphabetical list of all primitive actions
  makefile     |             | Makefile name depends on operating system and C compiler
  superlib.s7i | doWurx1     | Introduces the external function to a Seed7 program

  The C prototype of 'doWurx1' is defined in the file "superlib.h":

    int doWurx1 (char *name);

  This function accepts an UTF-8 'name' and it returns 0 on success.
  Every other return value indicates that the string is too long. In
  this case the exception RANGE_ERROR should be raised. The wrapper
  function is defined in the file "sup_rtl.c" with:

    #include "version.h"
    #include "stdio.h"
    #include "superlib.h"
    #include "common.h"
    #include "striutl.h"
    #include "rtl_err.h"

    void supDoWurx1 (const striType name)
      {
        cstriType cName;
        errInfoType err_info = OKAY_NO_ERROR;
        int wurxResult;

        cName = stri_to_cstri8(name, &err_info);
        if (cName == NULL) {
          raise_error(err_info);
        } else {
          wurxResult = doWurx1(cName);
          free_cstri8(cName, name);
          if (wurxResult != 0) {
            raise_error(RANGE_ERROR);
          }
        }
      }

  The prototype of 'supDoWurx1' is defined in the file "sup_rtl.h" with:

    void supDoWurx1 (const striType name);

  The action function for 'supDoWurx1' is defined in the file
  "suplib.c" with:

    #include "version.h"
    #include "stdio.h"
    #include "common.h"
    #include "data.h"
    #include "syvarutl.h"
    #include "objutl.h"
    #include "sup_rtl.h"

    objectType sup_doWurx1 (listType arguments)
      {
        isit_stri(arg_1(arguments));
        supDoWurx1(take_stri(arg_1(arguments)));
        return SYS_EMPTY_OBJECT;
      }

  The prototype of 'sup_doWurx1' is defined in the file "suplib.h" with:

    objectType sup_doWurx1 (listType arguments);

  The action is introduced to the interpreter, by changing the file
  "primitiv.c". An include directive for "suplib.h" must be added:

    #include "strlib.h"
    #include "suplib.h"
    #include "timlib.h"

  The file "primitiv.c" contains a list of alphabetically sorted primitive
  actions. Each action entry takes a line. It is important to add the new
  action "SUP_DO_WURX" at the correct place:

    { "STR_VALUE",               str_value,               },

    { "SUP_DO_WURX",             sup_doWurx1,             },

    { "TIM_AWAIT",               tim_await,               },

  The new files must be added to the makefile. Depending on C compiler and
  operating system Seed7 uses several makefiles. In the correct "makefile"
  suplib and sup_rtl must be added to lists of source
  and object files. Adding the suplib object file results in:

    LOBJ = actlib.o arrlib.o biglib.o blnlib.o bstlib.o chrlib.o cmdlib.o conlib.o dcllib.o drwlib.o \
           enulib.o fillib.o fltlib.o hshlib.o intlib.o itflib.o kbdlib.o lstlib.o pollib.o prclib.o \
           prglib.o reflib.o rfllib.o sctlib.o setlib.o soclib.o strlib.o suplib.o timlib.o typlib.o ut8lib.o

  Adding the "suplib" source file results in:

    LSRC = actlib.c arrlib.c biglib.c blnlib.c bstlib.c chrlib.c cmdlib.c conlib.c dcllib.c drwlib.c \
           enulib.c fillib.c fltlib.c hshlib.c intlib.c itflib.c kbdlib.c lstlib.c pollib.c prclib.c \
           prglib.c reflib.c rfllib.c sctlib.c setlib.c soclib.c strlib.c suplib.c timlib.c typlib.c ut8lib.c

  and object files. Adding the sup_rtl object file results in:

    ROBJ = arr_rtl.o bln_rtl.o bst_rtl.o chr_rtl.o cmd_rtl.o con_rtl.o dir_rtl.o drw_rtl.o fil_rtl.o \
           flt_rtl.o hsh_rtl.o int_rtl.o set_rtl.o soc_rtl.o str_rtl.o sup_rtl.o tim_rtl.o ut8_rtl.o \
           heaputl.o striutl.o

  Adding the "sup_rtl" source file results in:

    RSRC = arr_rtl.c bln_rtl.c bst_rtl.c chr_rtl.c cmd_rtl.c con_rtl.c dir_rtl.c drw_rtl.c fil_rtl.c \
           flt_rtl.c hsh_rtl.c int_rtl.c set_rtl.c soc_rtl.c str_rtl.c sup_rtl.c tim_rtl.c ut8_rtl.c \
           heaputl.c striutl.c

  The external library "superlib" itself is added with:

    SYSTEM_LIBS = -lm superlib.a

  The interpreter must be compiled, so the changes can take effect.
  To actually call the new function it must be introduced in a Seed7
  library. This is done with the library "super.s7i":

    const proc: doWurx1 (in string: name) is action "SUP_DO_WURX";


15.1 C types used by the implementation

  Several Seed7 types correspond to simple C types, which are
  defined in "common.h":

    Seed7 type       C type     Comment
    boolean          boolType   _Bool, bool or int
    integer          intType    32- or 64-bit signed int
    float            floatType  float (or double)
    char             charType   32-bit unsigned int
    clib_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" and in "data.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
    reference    objectType  struct objectStruct  Interpreter type for Seed7 objects
    ref_list     listType    struct listStruct    Interpreter type for Seed7 object lists

  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 arrayStruct      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".

  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      x11_winRecord *                   drw_x11.c   Functions cast from struct winStruct * to x11_winRecord *
                     winType      win_winRecord *                   drw_win.c   Functions cast from struct winStruct * to win_winRecord *
    database         databaseType dbType                            sql_fire.c  Functions cast from databaseType to dbType
                     databaseType dbType                            sql_lite.c  Functions cast from databaseType to dbType
                     databaseType dbType                            sql_my.c    Functions cast from databaseType to dbType
                     databaseType dbType                            sql_oci.c   Functions cast from databaseType to dbType
                     databaseType dbType                            sql_odbc.c  Functions cast from databaseType to dbType
                     databaseType dbType                            sql_post.c  Functions cast from databaseType to dbType
    sqlStatement     sqlStmtType  preparedStmtType                  sql_fire.c  Functions cast from sqlStmtType to preparedStmtType
                     sqlStmtType  preparedStmtType                  sql_lite.c  Functions cast from sqlStmtType to preparedStmtType
                     sqlStmtType  preparedStmtType                  sql_my.c    Functions cast from sqlStmtType to preparedStmtType
                     sqlStmtType  preparedStmtType                  sql_oci.c   Functions cast from sqlStmtType to preparedStmtType
                     sqlStmtType  preparedStmtType                  sql_odbc.c  Functions cast from sqlStmtType to preparedStmtType
                     sqlStmtType  preparedStmtType                  sql_post.c  Functions cast from sqlStmtType to preparedStmtType

  There are also C types without corresponding Seed7 type. They are
  defined in "common.h":

    C type       C definition        Comment
    int16Type    short int           It is assumed that sizeof(short int) == 2
    uint16Type   unsigned short int  Unsigned integer type with the size of int16Type
    int32Type    int                 If sizeof(int) == 4
                 long                If sizeof(long) == 4
    uint32Type   unsigned int32Type  Unsigned integer type with the size of int32Type
    int64Type    long                If sizeof(long) == 8
                 long long           If sizeof(long long) == 8
                 __int64             If sizeof(__int64) == 8
    uint64Type   unsigned int64Type  Unsigned integer type with the size of int64Type
    int128Type   __int128            If sizeof(__int128) == 16
                 __int128_t          If sizeof(__int128_t) == 16
    uint128Type  unsigned __int128   If sizeof(unsigned __int128) == 16
                 __uint128_t         If sizeof(__uint128_t) == 16
    uintType     unsigned intType    Unsigned integer type with the size of intType
    cstriType    char *              String type of the C compiler
    ustriType    unsigned char *     Helpful for unsigned comparisons
    wstriType    uint16Type *        UTF-16 string
    strElemType  charType            UTF-32 character element of string.
    os_striType  char *              If the OS uses UTF-8 chars
                 wchar_t *           If the OS uses UTF-16 chars
    memSizeType  uint32Type          If C uses 32-bit pointers
                 uint64Type          If C uses 64-bit pointers
    errInfoType  int                 Represents predefined Exceptions


15.2 String conversions

  Seed7 strings are UTF-32 encoded and C strings are zero terminated
  byte sequences. C uses also byte sequences with a length. The byte
  sequences can be encoded with ISO-8859-1 or UTF-8. To convert between
  the different representations, "striutl.h" defines conversion functions
  between the types 'striType', 'cstriType', 'bstriType' and 'wstriType'.
  The type 'wstriType' is always a string of UTF-16 characters, even if
  'wchar_t' is a 32-bit type. A 'wstriType' string can be zero terminated
  or a buffer with a length, that is specified with a parameter.


  Function Summary

    cstriType stri_to_cstri (const const_striType stri, errInfoType *err_info)
      Create an ISO-8859-1 encoded C string from a Seed7 UTF-32 string.

    cstriType stri_to_cstri8 (const const_striType stri, errInfoType *err_info)
      Create an UTF-8 encoded C string from a Seed7 UTF-32 string.

    cstriType stri_to_cstri8_buf (const const_striType stri, memSizeType *length)
      Create an UTF-8 encoded C string buffer from a Seed7 UTF-32 string.

    bstriType stri_to_bstri (const const_striType stri, errInfoType *err_info)
      Create an ISO-8859-1 encoded bstring from a Seed7 UTF-32 string.

    bstriType stri_to_bstri8 (const_striType stri)
      Create an UTF-8 encoded bstring from a Seed7 UTF-32 string.

    wstriType stri_to_wstri_buf (const const_striType stri, memSizeType *length,
        errInfoType *err_info)
      Create an UTF-16 encoded wide string buffer from a Seed7 UTF-32 string.

    striType cstri_to_stri (const_cstriType cstri)
      Copy an ISO-8859-1 (Latin-1) encoded C string to a Seed7 string.

    striType cstri_buf_to_stri (const_cstriType cstri, memSizeType length)
      Copy an ISO-8859-1 (Latin-1) encoded C string buffer to a Seed7 string.

    striType cstri8_to_stri (const_cstriType cstri, errInfoType *err_info)
      Copy an UTF-8 encoded C string to a Seed7 string.

    striType cstri8_buf_to_stri (const_cstriType cstri, memSizeType length,
        errInfoType *err_info)
      Copy an UTF-8 encoded C string buffer to a Seed7 string.

    striType cstri8_or_cstri_to_stri (const_cstriType cstri)
      Copy an UTF-8 or ISO-8859-1 encoded C string to a Seed7 string.

    striType wstri_buf_to_stri (const_wstriType wstri, memSizeType length,
        errInfoType *err_info)
      Copy an UTF-16 encoded wide string buffer to a Seed7 string.


  Function Detail

  stri_to_cstri

    cstriType stri_to_cstri (const const_striType stri, errInfoType *err_info)

      Create an ISO-8859-1 encoded C string from a Seed7 UTF-32 string.
      The memory for the zero byte terminated C string is allocated.
      The C string result must be freed with the macro free_cstri().

      Parameters:
        stri - Seed7 UTF-32 string to be converted.
        err_info - Unchanged if the function succeeds, and
                   MEMORY_ERROR if the memory allocation failed, and
                   RANGE_ERROR if stri contains a null character
                          or a character that is higher than the
                          highest allowed ISO-8859-1 character (255).

      Returns:
        an ISO-8859-1 encoded null terminated C string, or
        NULL if the memory allocation failed or the
        conversion failed (the error is indicated by err_info).


  stri_to_cstri8

    cstriType stri_to_cstri8 (const const_striType stri, errInfoType *err_info)

      Create an UTF-8 encoded C string from a Seed7 UTF-32 string.
      The memory for the zero byte terminated C string is allocated.
      The C string result must be freed with the macro free_cstri8().
      This function is intended to create temporary strings, that
      are used as parameters. To get good performance the allocated
      memory for the C string is oversized.

      Parameters:
        stri - Seed7 UTF-32 string to be converted.
        err_info - Unchanged if the function succeeds, and
                   MEMORY_ERROR if the memory allocation failed, and
                   RANGE_ERROR if stri contains a null character
                          or a character that is higher than the
                          highest allowed Unicode character (U+10FFFF).

      Returns:
        an UTF-8 encoded null terminated C string, or
        NULL if the memory allocation failed or the
        conversion failed (the error is indicated by err_info).


  stri_to_cstri8_buf

    cstriType stri_to_cstri8_buf (const const_striType stri, memSizeType *length)

      Create an UTF-8 encoded C string buffer from a Seed7 UTF-32 string.
      The memory for the zero byte terminated C string is allocated.
      Zero bytes inside the string are copied to the C string.
      The C string result must be freed with the macro free_cstri8().
      This function is intended to create temporary strings, that
      are used as parameters. To get good performance the allocated
      memory for the C string is oversized.

      Parameters:
        stri - Seed7 UTF-32 string to be converted.
        length - Place to return the length of the result (without '\0').

      Returns:
        an UTF-8 encoded null terminated C string, or
        NULL if the memory allocation failed.


  stri_to_bstri

    bstriType stri_to_bstri (const const_striType stri, errInfoType *err_info)

      Create an ISO-8859-1 encoded bstring from a Seed7 UTF-32 string.
      The memory for the bstring is allocated. No zero byte is added
      to the end of the bstring. No special action is done, if the
      UTF-32 string contains a null character.

      Parameters:
        stri - Seed7 UTF-32 string to be converted.
        err_info - Unchanged if the function succeeds, and
                   MEMORY_ERROR if the memory allocation failed, and
                   RANGE_ERROR if stri contains a character
                          that is higher than the highest
                          allowed ISO-8859-1 character (255).

      Returns:
        an ISO-8859-1 encoded bstring, or
        NULL if the memory allocation failed or the
        conversion failed (the error is indicated by err_info).


  stri_to_bstri8

    bstriType stri_to_bstri8 (const_striType stri)

      Create an UTF-8 encoded bstring from a Seed7 UTF-32 string.
      The memory for the bstring is allocated. No zero byte is added
      to the end of the bstring. No special action is done, if
      the original string contains a null character.

      Parameters:
        stri - Seed7 UTF-32 string to be converted.

      Returns:
        an UTF-8 encoded bstring, or
        NULL if the memory allocation failed.


  stri_to_wstri_buf

    wstriType stri_to_wstri_buf (const const_striType stri, memSizeType *length,
        errInfoType *err_info)

      Create an UTF-16 encoded wide string buffer from a Seed7 UTF-32 string.
      The memory for the zero byte terminated wide string is allocated.
      The wide string result must be freed with the macro free_wstri().
      This function is intended to create temporary strings, that
      are used as parameters. To get good performance the allocated
      memory for the wide string is oversized.

      Parameters:
        stri - Seed7 UTF-32 string to be converted.
        length - Place to return the character length of the result (without '\0').
        err_info - Unchanged if the function succeeds, and
                   MEMORY_ERROR if the memory allocation failed, and
                   RANGE_ERROR if stri contains a character
                          that is higher than the highest
                          allowed Unicode character (U+10FFFF).

      Returns:
        an UTF-16 encoded null terminated wide string, or
        NULL if the memory allocation failed or the
        conversion failed (the error is indicated by err_info).


  cstri_to_stri

    striType cstri_to_stri (const_cstriType cstri)

      Copy an ISO-8859-1 (Latin-1) encoded C string to a Seed7 string.
      The memory for the UTF-32 encoded Seed7 string is allocated.

      Parameters:
        cstri - Null terminated ISO-8859-1 encoded C string.

      Returns:
        an UTF-32 encoded Seed7 string, or
        NULL if the memory allocation failed.


  cstri_buf_to_stri

    striType cstri_buf_to_stri (const_cstriType cstri, memSizeType length)

      Copy an ISO-8859-1 (Latin-1) encoded C string buffer to a Seed7 string.
      The memory for the UTF-32 encoded Seed7 string is allocated.

      Parameters:
        cstri - ISO-8859-1 encoded C string buffer (not null terminated).
        length - Byte length of the ISO-8859-1 encoded C string buffer.

      Returns:
        an UTF-32 encoded Seed7 string, or
        NULL if the memory allocation failed.


  cstri8_to_stri

    striType cstri8_to_stri (const_cstriType cstri, errInfoType *err_info)

      Copy an UTF-8 encoded C string to a Seed7 string.
      The memory for the UTF-32 encoded Seed7 string is allocated.

      Parameters:
        cstri - Null terminated UTF-8 encoded C string.
        err_info - Unchanged if the function succeeds, and
                   MEMORY_ERROR if the memory allocation failed, and
                   RANGE_ERROR if the conversion failed.

      Returns:
        an UTF-32 encoded Seed7 string, or
        NULL if the memory allocation failed or
        illegal UTF-8 encodings are used.


  cstri8_buf_to_stri

    striType cstri8_buf_to_stri (const_cstriType cstri, memSizeType length,
        errInfoType *err_info)

      Copy an UTF-8 encoded C string buffer to a Seed7 string.
      The memory for the UTF-32 encoded Seed7 string is allocated.

      Parameters:
        cstri - UTF-8 encoded C string buffer (not null terminated).
        length - Byte length of the UTF-8 encoded C string buffer.
        err_info - Unchanged if the function succeeds, and
                   MEMORY_ERROR if the memory allocation failed, and
                   RANGE_ERROR if the conversion failed.

      Returns:
        an UTF-32 encoded Seed7 string, or
        NULL if the memory allocation failed or
        illegal UTF-8 encodings are used.


  cstri8_or_cstri_to_stri

    striType cstri8_or_cstri_to_stri (const_cstriType cstri)

      Copy an UTF-8 or ISO-8859-1 encoded C string to a Seed7 string.
      The memory for the UTF-32 encoded Seed7 string is allocated.

      Parameters:
        cstri - Null terminated UTF-8 or ISO-8859-1 encoded C string.

      Returns:
        an UTF-32 encoded Seed7 string, or
        NULL if the memory allocation failed.


  wstri_buf_to_stri

    striType wstri_buf_to_stri (const_wstriType wstri, memSizeType length,
        errInfoType *err_info)

      Copy an UTF-16 encoded wide string buffer to a Seed7 string.
      The memory for the UTF-32 encoded Seed7 string is allocated.

      Parameters:
        wstri - UTF-16 encoded wide string buffer (not null terminated).
        length - Character length of the UTF-16 encoded wide string buffer.
        err_info - Unchanged if the function succeeds, and
                   MEMORY_ERROR if the memory allocation failed.

      Returns:
        an UTF-32 encoded Seed7 string, or
        NULL if the memory allocation failed.


15.3 Operating system string and path conversions

  Operating systems disagree in their Unicode encoding (UTF-8 or UTF-16).
  To cope with this, "striutl.h" defines the type 'os_striType' and
  functions to convert to and from 'os_striType'. 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.


  Function Summary

    striType conv_from_os_stri (const const_os_striType os_stri, memSizeType length)
      Convert an os_striType string with length to a Seed7 UTF-32 string.

    os_striType stri_to_os_stri (const_striType stri, errInfoType *err_info)
      Convert a Seed7 UTF-32 string to a null terminated os_striType string.

    striType os_stri_to_stri (const_os_striType os_stri, errInfoType *err_info)
      Convert a null terminated os_striType string to a Seed7 UTF-32 string.

    os_striType cp_to_os_path (const_striType std_path, int *path_info,
        errInfoType *err_info)
      Convert a Seed7 standard path to a path used by system calls.

    striType cp_from_os_path (const_os_striType os_path, errInfoType *err_info)
      Convert a path returned by a system call to a Seed7 standard path.


  Function Detail

  conv_from_os_stri

    striType conv_from_os_stri (const const_os_striType os_stri,
        memSizeType length)

      Convert an os_striType string with length to a Seed7 UTF-32 string.
      Many system calls return os_striType data with length. System calls
      are defined in "version.h" and "os_decls.h". They are prefixed
      with os_ and use strings of the type os_striType. Depending on the
      operating system os_striType can describe byte or wide char strings.
      The encoding can be Latin-1, UTF-8, UTF-16 or it can use a code page.

      Parameters:
        os_stri - Possibly binary string (may contain null characters).
        length - Length of os_stri in characters.

      Returns:
        a Seed7 UTF-32 string, or
        NULL if an error occurred.


  stri_to_os_stri

    os_striType stri_to_os_stri (const_striType stri, errInfoType *err_info)

      Convert a Seed7 UTF-32 string to a null terminated os_striType string.
      The memory for the null terminated os_striType string is allocated.
      The os_striType result is allocated with the macro os_stri_alloc()
      and it must be freed with the macro os_stri_free(). Strings allocated
      with os_stri_alloc() must be freed in the reverse order of their
      creation. This allows that allocations work in a stack like manner.
      Many system calls have parameters with null terminated os_striType
      strings. System calls are defined in "version.h" and "os_decls.h".
      They are prefixed with os_ and use strings of the type os_striType.
      Depending on the operating system os_striType can describe byte or
      wide char strings. The encoding can be Latin-1, UTF-8, UTF-16 or
      it can use a code page.

      Parameters:
        stri - Seed7 UTF-32 string to be converted.
        err_info - Unchanged if the function succeeds, and
                   MEMORY_ERROR if the memory allocation failed, and
                   RANGE_ERROR if the conversion failed.

      Returns:
        a null terminated os_striType value used by system calls, or
        NULL if an error occurred.


  os_stri_to_stri

    striType os_stri_to_stri (const_os_striType os_stri, errInfoType *err_info)

      Convert a null terminated os_striType string to a Seed7 UTF-32 string.
      Many system calls return null terminated os_striType strings. System
      calls are defined in "version.h" and "os_decls.h". They are prefixed
      with os_ and use strings of the type os_striType. Depending on the
      operating system os_striType can describe byte or wide char strings.
      The encoding can be Latin-1, UTF-8, UTF-16 or it can use a code page.

      Parameters:
        os_stri - Null terminated os_striType string to be converted.
        err_info - Unchanged if the function succeeds, and
                   MEMORY_ERROR if the memory allocation failed.

      Returns:
        a Seed7 UTF-32 string, or
        NULL if an error occurred.


  cp_to_os_path

    os_striType cp_to_os_path (const_striType std_path, int *path_info, errInfoType *err_info)

      Convert a Seed7 standard path to a path used by system calls.
      The memory for the null terminated os_striType path is allocated.
      The os_striType result is allocated with the macro os_stri_alloc()
      and it must be freed with the macro os_stri_free(). Strings allocated
      with os_stri_alloc() must be freed in the reverse order of their
      creation. This allows that allocations work in a stack like manner.
      System calls are defined in "version.h" and "os_decls.h". They are
      prefixed with os_ and use system paths of the type os_striType.
      Depending on the operating system os_striType can describe byte or
      wide char strings. The encoding can be Latin-1, UTF-8, UTF-16 or
      it can use a code page. Beyond the conversion to os_striType a
      mapping to drive letters might take place on some operating systems.

    Parameters:
        std_path - UTF-32 encoded Seed7 standard path to be converted.
        path_info - Unchanged if the function succeeds, and
                    PATH_IS_EMULATED_ROOT if the path is "/", and
                    PATH_NOT_MAPPED if the path cannot be mapped.
        err_info - Unchanged if the function succeeds, and
                   MEMORY_ERROR if the memory allocation failed, and
                   RANGE_ERROR if the path is not a standard path.

      Returns:
        a null terminated os_striType path used by system calls, or
        NULL if an error occurred.


  cp_from_os_path

    striType cp_from_os_path (const_os_striType os_path, errInfoType *err_info)

      Convert a path returned by a system call to a Seed7 standard path.
      System calls are defined in "version.h" and "os_decls.h". They are
      prefixed with os_ and use system paths of the type os_striType.
      Depending on the operating system os_striType can describe byte or
      wide char strings. The encoding can be Latin-1, UTF-8, UTF-16 or
      it can use a code page. Beyond the conversion from os_striType a
      mapping from drive letters might take place on some operating
      systems.

      Parameters:
        os_path - Null terminated os_striType path to be converted.
        err_info - Unchanged if the function succeeds, and
                   MEMORY_ERROR if the memory allocation failed.

      Returns:
        an UTF-32 encoded Seed7 standard path, or
        NULL if the memory allocation failed.


15.4 Macros to access the action parameters

  A primitive action function has one parameter named 'arguments'. The
  'arguments' parameter has the type 'listType' and contains a list of
  objects. The header file "objutl.h" defines macros like 'arg_1',
  'arg_2', 'arg_3', etc. to get a specific object from the 'arguments'.


  Functions (macros) to get a Seed7 object from a list

    objectType arg_1 (listType arguments)
      Take the first object from the list.

    objectType arg_2 (listType arguments)
      Take the second object from the list.

    objectType arg_3 (listType arguments)
      Take the third object from the list.

    . . . . . .


    objectType arg_12 (listType arguments)
      Take the twelfth object from the list.

  An object value contains a specific C implementation type. The header
  file "objutl.h" defines macros like 'isit_char' and 'isit_set' to
  check, if an object has the requested type. If the object has not
  the requested C implementation type and error message is written.


  Functions (macros) to check the C type of Seed7 objects

    void isit_array (objectType arg)
      Check if the object type is arrayType.

    void isit_bigint (objectType arg)
      Check if the object type is bigIntType.

    void isit_bool (objectType arg)
      Check if the object type is boolType.

    void isit_bstri (objectType arg)
      Check if the object type is bstriType.

    void isit_char (objectType arg)
      Check if the object type is charType.

    void isit_database (objectType arg)
      Check if the object type is databaseType.

    void isit_file (objectType arg)
      Check if the object type is fileType.

    void isit_float (objectType arg)
      Check if the object type is floatType.

    void isit_hash (objectType arg)
      Check if the object type is hashType.

    void isit_int (objectType arg)
      Check if the object type is intType.

    void isit_poll (objectType arg)
      Check if the object type is pollType.

    void isit_set (objectType arg)
      Check if the object type is setType.

    void isit_socket (objectType arg)
      Check if the object type is socketType.

    void isit_sqlstmt (objectType arg)
      Check if the object type is sqlStmtType.

    void isit_stri (objectType arg)
      Check if the object type is striType.

    void isit_struct (objectType arg)
      Check if the object type is structType.

    void isit_win (objectType arg)
      Check if the object type is winType.

  The header file "objutl.h" defines macros like 'take_bool' and
  'take_file'. This macros return a value with the requested
  C implementation type.


  Functions (macros) to get the C values of Seed7 objects

    arrayType take_array (objectType arg)
      Take the array value from an object.

    bigIntType take_bigint (objectType arg)
      Take the bigInteger value from an object.

    boolType take_bool (objectType arg)
      Take the boolean value from an object.

    bstriType take_bstri (objectType arg)
      Take the bstring value from an object.

    charType take_char (objectType arg)
      Take the char value from an object.

    databaseType take_database (objectType arg)
      Take the database value from an object.

    fileType take_file (objectType arg)
      Take the file value from an object.

    floatType take_float (objectType arg)
      Take the float value from an object.

    hashType take_hash (objectType arg)
      Take the hash table value from an object.

    intType take_int (objectType arg)
      Take the integer value from an object.

    pollType take_poll (objectType arg)
      Take the poll data value from an object.

    setType take_set (objectType arg)
      Take the set value from an object.

    socketType take_socket (objectType arg)
      Take the socket value from an object.

    sqlStmtType take_sqlstmt (objectType arg)
      Take the SQL prepared statement value from an object.

    striType take_stri (objectType arg)
      Take the string value from an object.

    structType take_struct (objectType arg)
      Take the struct value from an object.

    winType take_win (objectType arg)
      Take the struct value from an object.


15.5 Functions to create action results

  A primitive action function has a result of type 'objectType'.
  The header file "objutl.h" defines macros like 'bld_bigint_temp'
  and 'bld_stri_temp' to create an object with the specified type.


  Functions to create Seed7 objects with a C value

    objectType bld_array_temp (arrayType temp_array)
      Create an object with an arrayType value.

    objectType bld_bigint_temp (bigIntType temp_bigint)
      Create an object with a bigIntType value.

    objectType bld_bstri_temp (bstriType temp_bstri)
      Create an object with a bstriType value.

    objectType bld_char_temp (charType temp_char)
      Create an object with a charType value.

    objectType bld_database_temp (databaseType temp_database)
      Create an object with a databaseType value.

    objectType bld_file_temp (fileType temp_file)
      Create an object with a fileType value.

    objectType bld_float_temp (floatType temp_float)
      Create an object with a floatType value.

    objectType bld_hash_temp (hashType temp_hash)
      Create an object with a hashType value.

    objectType bld_int_temp (intType temp_int)
      Create an object with an intType value.

    objectType bld_poll_temp (pollType temp_poll)
      Create an object with a pollType value.

    objectType bld_set_temp (setType temp_set)
      Create an object with a setType value.

    objectType bld_socket_temp (socketType temp_socket)
      Create an object with a socketType value.

    objectType bld_sqlstmt_temp (sqlStmtType temp_sqlstmt)
      Create an object with a sqlStmtType value.

    objectType bld_stri_temp (striType temp_stri)
      Create an object with a striType value.

    objectType bld_struct_temp (structType temp_struct)
      Create an object with a structType value.

    objectType bld_win_temp (winType temp_win)
      Create an object with a winType value.


15.6 Memory management macros

  The conversion functions mentioned above use macros to do the
  memory management. Some of this macros are not based on malloc()
  but manage the memory in a stack. Therefore it is important to
  use the correct macro to allocate and free memory. The macros
  below are defined in the header file "striutl.h".


  Macro Summary

    void free_cstri (cstriType cstri, striType stri)
      Macro to free memory that has been allocated by stri_to_cstri().

    void free_cstri8 (cstriType cstri, striType stri)
      Macro to free memory that has been allocated by stri_to_cstri8() or stri_to_cstri8_buf().

    void free_wstri (wstriType wstri, striType stri)
      Macro to free memory that has been allocated by stri_to_wstri_buf().

    boolType os_stri_alloc (os_striType &var, memSizeType len)
      Macro to allocate memory for an os_striType string.

    void os_stri_free (os_striType var)
      Macro to free memory that has been allocated with os_stri_alloc.


  Macro Detail

  free_cstri

    void free_cstri (cstriType cstri, striType stri)

      Macro to free memory that has been allocated by stri_to_cstri().

      Parameters:
        cstri - The string to be freed.
        stri - The parameter that was used when stri_to_cstri() was called.


  free_cstri8

    void free_cstri8 (cstriType cstri, striType stri)

      Macro to free memory that has been allocated by stri_to_cstri8() or stri_to_cstri8_buf().

      Parameters:
        cstri - The string to be freed.
        stri - The parameter that was used when stri_to_cstri8() or stri_to_cstri8_buf() was called.


  free_wstri

    void free_wstri (wstriType wstri, striType stri)

      Macro to free memory that has been allocated by stri_to_wstri_buf().

      Parameters:
        cstri - The string to be freed.
        stri - The parameter that was used when stri_to_wstri_buf() was called.


  os_stri_alloc

    boolType os_stri_alloc (os_striType &var, memSizeType len)

      Macro to allocate memory for an os_striType string.
      Strings allocated with os_stri_alloc() must be freed with
      os_stri_free() in the reverse order of their creation. This allows
      that allocations work in a stack like manner.

      Parameters:
        var - Reference to a variable to which the
                   allocated memory is assigned.
        len - Size of the allocated memory in characters.

      Returns:
        TRUE if the allocation succeeds, and
        FALSE if the memory allocation failed.


  os_stri_free

    void os_stri_free (os_striType var)

      Macro to free memory that has been allocated with os_stri_alloc.
      Strings allocated with os_stri_alloc() must be freed with
      os_stri_free() in the reverse order of their creation. This allows
      that allocations work in a stack like manner. The strings returned
      by stri_to_os_stri and cp_to_os_path are also allocated with
      os_stri_alloc. Therefore they must also be freed with
      os_stri_free() in the reverse order of their creation.

      Parameters:
        var - The string to be freed.


15.7 Basic conversion functions

  The conversion functions mentioned above are implemented with
  basic conversion functions. In some situations it might make sense
  to use the basic conversion functions directly. This functions are
  optimized for performance. Some functions use loop unrolling
  inspired by Duff's device. The basic conversion functions below
  are defined in the header file "striutl.h".


  Function Summary

    void memcpy_to_strelem (register strElemType *const dest,
        register const const_ustriType src, memSizeType len)
      Copy len bytes to Seed7 characters in a string.

    void memset_to_strelem (register strElemType *const dest,
        register const strElemType ch, memSizeType len)
      Fill len Seed7 characters with the character ch.

    boolType memcpy_from_strelem (register const const_ustriType dest,
        register const strElemType *const src, memSizeType len)
      Copy len Seed7 characters to a byte string.

    const strElemType * memchr_strelem (register const strElemType *mem,
        const strElemType ch, memSizeType len)
      Scan the first len Seed7 characters for the character ch.

    memSizeType utf8_to_stri (strElemType *const dest_stri,
        memSizeType *const dest_len, const_ustriType ustri, memSizeType len)
      Convert an UTF-8 encoded string to an UTF-32 encoded string.

    memSizeType stri_to_utf8 (const ustriType out_stri,
        const strElemType *strelem, memSizeType len)
      Convert an UTF-32 encoded string to an UTF-8 encoded string.

    memSizeType stri_to_utf16 (const wstriType out_wstri,
        register const strElemType *strelem, memSizeType len,
        errInfoType *const err_info)
      Convert an UTF-32 encoded string to an UTF-16 encoded string.


  Function Detail

  memcpy_to_strelem

    void memcpy_to_strelem (register strElemType *const dest,
        register const const_ustriType src, memSizeType len)

      Copy len bytes to Seed7 characters in a string.
      This function works also correct if 'src' and 'dest' point
      to the same address. In other words it works correct for:

       memcpy_to_strelem(mem, (ustriType) mem, num);

      Parameters:
        dest - Destination array with UTF-32 encoded characters.
        src - Source array with ISO-8859-1 encoded bytes.
        len - Number of bytes in 'src' and UTF-32 characters in 'dest'.


  memset_to_strelem

    void memset_to_strelem (register strElemType *const dest,
        register const strElemType ch, memSizeType len)

      Fill len Seed7 characters with the character ch.

      Parameters:
        dest - Destination array with UTF-32 encoded characters.
        ch - UTF-32 encoded character to be filled into 'dest'.
        len - Specifies how often 'ch' is filled into 'dest'.


 memcpy_from_strelem

    boolType memcpy_from_strelem (register const const_ustriType dest,
        register const strElemType *const src, memSizeType len)

      Copy len Seed7 characters to a byte string.
      This function uses loop unrolling inspired by Duff's device
      and a trick with a binary or (|=) to check for allowed values.

      Parameters:
        dest - Destination array with ISO-8859-1 encoded bytes.
        src - Source array with UTF-32 encoded characters.
        len - Number of UTF-32 characters in 'src' and bytes in 'dest'.

      Returns:
        TRUE if one of the characters does not fit into a byte,
        FALSE otherwise.


  memchr_strelem

    const strElemType *memchr_strelem (register const strElemType *mem,
        const strElemType ch, memSizeType len)

      Scan the first len Seed7 characters for the character ch.

      Parameters:
        mem - Array with UTF-32 characters.
        ch - UTF-32 character to be searched in 'mem'.
        len - Number of UTF-32 characters in 'mem'.

      Returns:
        a pointer to the matching character, or NULL if the
        character does not occur in the given string area.


  utf8_to_stri

    memSizeType utf8_to_stri (strElemType *const dest_stri,
        memSizeType *const dest_len, const_ustriType ustri, memSizeType len)

      Convert an UTF-8 encoded string to an UTF-32 encoded string.
      The source and destination strings are not '\0' terminated.
      The memory for the destination dest_stri is not allocated.

      Parameters:
        dest_stri - Destination of the UTF-32 encoded string.
        dest_len - Place to return the length of dest_stri.
        ustri - UTF-8 encoded string to be converted.
        len - Number of bytes in ustri.

      Returns:
        the number of bytes in ustri that are left unconverted, or
        0 if ustri has been successfully converted.


  stri_to_utf8

    memSizeType stri_to_utf8 (const ustriType out_stri,
        const strElemType *strelem, memSizeType len)

      Convert an UTF-32 encoded string to an UTF-8 encoded string.
      The source and destination strings are not '\0' terminated.
      The memory for the destination out_stri is not allocated.

      Parameters:
        out_stri - Destination of the UTF-8 encoded string.
        strelem - UTF-32 encoded string to be converted.
        len - Number of UTF-32 characters in strelem.

      Returns:
        the length of the converted UTF-8 string.


  stri_to_utf16

    memSizeType stri_to_utf16 (const wstriType out_wstri,
        register const strElemType *strelem, memSizeType len,
        errInfoType *const err_info)

      Convert an UTF-32 encoded string to an UTF-16 encoded string.
      The source and destination strings are not '\0' terminated.
      The memory for the destination out_wstri is not allocated.

      Parameters:
        out_wstri - Destination of the UTF-16 encoded string.
        strelem - UTF-32 encoded string to be converted.
        len - Number of UTF-32 characters in strelem.
        err_info - Unchanged if the function succeeds, and
                   MEMORY_ERROR if *strelem contains a character
                          that is higher than the highest allowed
                          Unicode character (U+10FFFF).

      Returns:
        the length of the converted UTF-16 string in characters.


15.8 Error handling

  The C programming language does not provide exceptions. Seed7 uses
  several methods to provide error handling. Before an actual exception
  is raised an error state can be handled in different ways:

    - The integer type 'errInfoType' is used to describe an
      error state. Usually a variable or parameter named 'err_info' is
      used to store the error state. The value 'OKAY_NO_ERROR' is used
      to describe that no error occurred. Values like 'MEMORY_ERROR',
      'NUMERIC_ERROR', 'OVERFLOW_ERROR', 'RANGE_ERROR', 'FILE_ERROR',
      'DATABASE_ERROR' and 'ACTION_ERROR' describe errors that occurred.
    - In some situations a function has only one possible error
      situation (e.g. a 'MEMORY_ERROR'). This is handled with functions
      that return NULL in case of a 'MEMORY_ERROR'.

  C code can check the value of the 'err_info' variable, or check if a
  function returns NULL. In case of error it is possible to do some
  cleaning up. An error situation can be propergated this way over
  several function levels. It is important to assure that an existing
  error situation ('err_info' has a value not equal to 'OKAY_NO_ERROR')
  is not reset to a situation that no error occurred.

  An actual exception can be triggered with the macro 'raise_error'.
  This macro takes an 'errInfoType' parameter to describe the actual
  exception. Note that all cleaning up must be done before 'raise_error'
  is called. This macro calls the function 'raise_exception2' with
  the additional parameters __FILE__ and __LINE__. The function
  'raise_exception2' has different implementations for interpreted
  and compiled programs:

    - In the interpreter 'raise_exception2' sets a fail flag and the
      function is left normally.
    - In compiled code 'raise_exception2' uses a 'longjmp' to continue
      executing at the handler code of the exception.

  That means that 'raise_error' also returns normally in the
  interpreter. Therefore a function that calls 'raise_error' must
  return after it has called this function. Surrounding functions
  must also return. This must be done up to the current action
  function. So either all these functions always return immediate
  or a special return value (e.g. NULL) signals them to return.
  Doing some clean up, when the special return value is received,
  will not work in compiled code. If cleaning up is necessary the
  call of 'raise_error' should be done in the outer function.


  Function Summary

    void raise_error (errInfoType err_info)
      Macro to raise an exception.


  Function Detail

  raise_error

    void raise_error (errInfoType err_info)

      Macro to raise an exception. This macro calls the function
      raise_exception2 with the additional parameters __FILE__ and
      __LINE__. The function raise_exception2 has different
      implementations for interpreted and compiled programs.

      Parameters:
        err_info - The exception to be raised.



16. ERRORS
==========

16.1 Parsing errors

  Parsing errors are triggered by interpreter and compiler. The checks
  for these errors are done before the program is executed respectively
  compiled. The errors do not terminate parsing except for error 1
  (Out of heap space). If there are errors the program cannot
  be interpreted respectively compiled. The interpreter option
  -x can be used to execute even if the program contains
  errors. The following parsing 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: Illegal string escape "\%s"
    22: Numerical escape sequences should end with ";" not "%s"
    23: The numerical escape sequence "\%u;" is too big
    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: Syntax declared twice
    41: Dot expression requested as syntax description
    42: "%s" redeclared with infix priority %d not %d
    43: "%s" redeclared with prefix priority %d not %d
    44: Priority %d required for parameter after "%s" not %d
    45: Priority <= %d expected found "%s" with priority %d
    46: "%s" must have priority %d not %d for dot expression
    47: "%s" expected found "%s"
    48: Undefined type for literal "%s"
    49: Kind of in-parameter (val or ref) unspecified for type "%s"
    50: "newtype", "subtype", "func", "enumlit" or "action" expected found "%s"
    51: "func" or "type" expected found "%s"
    52: Match for %s failed
    53: Variable expected in %s found %s
    54: Type expected found %s
    55: Procedure expected found %s expression
    56: Parameter specifier expected found "%s"
    57: Evaluate type expression %s failed
    58: Overlong UTF-8 encoding used for character "%s" (U+%04x)
    59: UTF-16 surrogate character found in UTF-8 encoding "%s" (U+%04x)
    60: Non Unicode character found "%s" (U+%04x)
    61: UTF-8 continuation byte expected found "%s" (U+%04x)
    62: Unexpected UTF-8 continuation byte found "%s" (U+%04x)
    63: Solitary UTF-8 start byte found "%s" (U+%04x)
    64: UTF-16 byte order mark found "%s" (U+%04x)
    65: Use / instead of \\ as path delimiter
        Undefined error


16.2 Compilation errors

  The compiler does checks when generating code. As a result of
  the checks some errors might be triggered:

    Expression raises "%s".
    Catch of "%s" although the checks are suppressed.
    Catch of otherwise although the checks for %s are suppressed.
    When values "%s" do overlap.
    Forward defined function called.
    Forward definition of the called function.


16.3 Exceptions

  An exception is an anomalous event that arises during program execution.
  Exceptions change the normal flow of program execution. An exception
  transfers the execution to a corresponding exception handler. If no
  corresponding exception handler exists the program is terminated.
  There are various exceptions, which can be raised: MEMORY_ERROR,
  NUMERIC_ERROR, OVERFLOW_ERROR, INDEX_ERROR, RANGE_ERROR, FILE_ERROR,
  DATABASE_ERROR and ILLEGAL_ACTION. A program can raise an exception
  with the 'raise' statement. For example:

    raise RANGE_ERROR;


16.3.1 MEMORY_ERROR

  The exception MEMORY_ERROR is raised if there is not enough memory
  to store some data. This error can be raised from the run-time library
  or from the interpreter kernel. Catching a MEMORY_ERROR is possible,
  but it must be done with care. Variables involved in a MEMORY_ERROR
  may have an illegal value. A 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.


16.3.2 NUMERIC_ERROR

  The exception NUMERIC_ERROR is raised if a numeric operation
  cannot deliver a correct result. This includes several things that
  are mathematically undefined such as division by zero, integer
  exponentiation with a negative exponent, square root of a negative
  number and logarithm of a negative number. NUMERIC_ERROR can be
  raised by operations of several types:

    It may be raised from the following 'integer' operations:
        !, **, div, rem, mdiv, mod, sqrt, log2, log10.
    It may be raised from the following 'bigInteger' operations:
        !, **, div, rem, mdiv, mod, sqrt, log2, log10.
    It may be raised from the following 'rational' operation:
        /.
    It may be raised from the following 'bigRational' operation:
        /.

  In detail the following conditions can cause a numeric error:

     - Division (div, rem, mdiv, mod, /) by zero.
       E.g.: 1 div 0 raises NUMERIC_ERROR. Note that a 'float' division
       by zero does not raise NUMERIC_ERROR but returns Infinity or
       -Infinity instead.
     - Exponentiation (**) if the exponent is a negative 'integer'.
       E.g.: 2 ** (-1) raises NUMERIC_ERROR.
     - Functions (sqrt, log2, log10, !) that are only defined for
       positive arguments. E.g.: sqrt(-1) raises NUMERIC_ERROR.


16.3.3 OVERFLOW_ERROR

  An integer overflow occurs if a calculation produces a result that
  cannot be stored in an 'integer' variable. This happens if the result
  is less than 'integer.first' or greater than 'integer.last'.

    It may be raised from the following 'integer' operations:
        - (sign), +, -, *, **, div, rem, mdiv, mod, <<, >>, +:=, -:=,
        *:=, <<:=, >>:=, !, abs, succ, pred, incr, decr.

  In detail the following conditions can cause an overflow:

     - Negating can overflow because in a two's complement representation
       there is no corresponding positive value for the most negative
       integer. E.g.: -integer.first raises OVERFLOW_ERROR.
     - Addition, subtraction, multiplication and exponentiation (+, -,
       *, **, succ, pred) trigger an overflow if the result would be
       less than 'integer.first' or greater than 'integer.last'.
     - Arithmetic operations that change a variable (+:=, -:=, *:=, incr,
       decr) trigger an overflow if the variable would get a value that
       is less than 'integer.first' or greater than 'integer.last'.
     - Division with 'div' and 'mdiv' can overflow because a division by
       -1 is the same as negating the dividend. E.g.: integer.first div -1
       raises OVERFLOW_ERROR.
     - Remainder and modulo are defined to raise OVERFLOW_ERROR if
       the dividend is the most negative integer and the divisor is -1.
       E.g.: integer.first rem -1 raises OVERFLOW_ERROR. This has been
       defined as overflow because it can trigger so called undefined
       behavior of the underlying C code.
     - All shift operations ('<<', '>>', <<:= and '>>:=') trigger an
       overflow if the shift amount is negative or greater equal 64.
     - Left shift operations ('<<' and <<:=) can also trigger an
       overflow if the shift result would be less than 'integer.first'
       or greater than 'integer.last'.
     - Binomial coefficient ('!') triggers an overflow if the result
       would be less than 'integer.first' or greater than 'integer.last'.
     - Computing the absolute value with abs can overflow, if it is
       called with the most negative integer. E.g.: abs(integer.first)
       raises OVERFLOW_ERROR.

  The interpreter checks always for an integer overflow. By default the
  compiler generates code to check for an integer overflow. The option
  -so can be used to suppress the generation of integer overflow checks.
  If an overflow situation occurs, although overflow checking has been
  switched off (with -so), the behavior is undefined (see chapter
  16.6 Suppressing exception checks).

  The separate overflow exception allows easy recognition of overflow
  situations. All overflow situations, where OVERFLOW_ERROR is raised
  correspond to C situations, which have undefined behavior. The
  overflow concept of Seed7 has been designed to allow, that simple
  C code is generated, if the overflow checks are switched off.

  Compiler optimizations (e.g. with -oc2 or -oc3) can reduce the
  potential of overflow. In an optimized program an expression might
  be rephrased, such that an overflow is avoided and the correct
  result is computed instead. Consider the expression:

    number + integer.last + integer.first

  If 'number' is between succ(integer.first) and 0 the expression
  can be evaluated and no overflow will occur. For other values of
  'number' the exception OVERFLOW_ERROR is raised. When the expression
  above is optimized it is rephrased to:

    pred(number)

  This expression only triggers OVERFLOW_ERROR, if number has the
  value integer.first.

  With overflow checks it is guaranteed that an integer overflow
  always raises OVERFLOW_ERROR. But you cannot rely on OVERFLOW_ERROR
  being raised if there is an alternate way to return the correct
  result.


16.3.4 INDEX_ERROR

  An INDEX_ERROR occurs if an index is used to access an 'array', 'string',
  'bstring' or 'ref_list' element beyond the elements that actually exist.
  E.g. An attempt to get an element of a 'string',
  'bstring' or 'ref_list' with a negative or zero index raises INDEX_ERROR.

    It may be raised from the following 'array' operations:
        [index], [index ..], [.. index], [start .. stop], [index len length], insert, remove.
    It may be raised from the following 'string' operations:
        [index], [index ..], [.. index], [start .. stop], [index len length], @:= [index] char, @:= [index] string.
    It may be raised from the following 'bstring' operation:
        [index].
    It may be raised from the following 'ref_list' operations:
        [index], @:= [index] element.

  The interpreter checks always if an index refers to an existing element.
  By default the compiler generates code to check if indices refer to an
  existing element. The option -si can be used to suppress the generation
  of index checks. If a nonexisting element is referred, although index
  checking has been switched off (with -si), the behavior is undefined
  (see chapter 16.6 Suppressing exception checks).


16.3.5 RANGE_ERROR

  Many functions define a range of valid arguments and raise RANGE_ERROR
  if this range is violated.

    It may be raised from the following 'boolean' operations:
        parse, rand.
    It may be raised from the following 'integer' operations:
        parse, radix, RADIX, sci, rand, integer.
    It may be raised from the following 'bigInteger' operations:
        parse, radix, RADIX, sci, rand, ord, bigInteger, bitLength, modInverse, modPow, .
    It may be raised from the following 'rational' operations:
        parse, digits, sci.
    It may be raised from the following 'bigRational' operations:
        parse, digits, sci.
    It may be raised from the following 'float' operations:
        parse, digits, sci, rand, round, trunc.
    It may be raised from the following 'complex' operations:
        parse, digits, sci.
    It may be raised from the following 'char' operations:
        chr, rand.
    It may be raised from the following 'string' operations:
        mult, pos, rpos.
    It may be raised from the following 'bitset' operations:
        conv, parse, min, max, rand.
    It may be raised from the following 'array' operations:
        times, rand.
    It may be raised from the following 'hash' operations:
        [.
    It may be raised from the following 'bin32' operations:
        radix, RADIX.
    It may be raised from the following 'bin64' operations:
        radix, RADIX.
    It may be raised from the following 'category' operations:
        parse.
    It may be raised from the following 'ref_list' operations:
        pos.
    It may be raised from the following 'file' operations:
        open, write, gets, length, seek, tell.


16.3.6 FILE_ERROR

  A FILE_ERROR occurs if an illegal operation with a file is done.

    It may be raised by the following functions:
        fileSize, bigFileSize, fileType, fileTypeSL, fileMode, setFileMode,
        readDir, removeFile, removeTree, moveFile, cloneFile, copyFile,
        readlink, symlink, hasNext, seek, tell, bigTell, setbuf, write,
        inetSocketAddress, inetListenerAddress, openInetSocket, openInetListener.


16.3.7 DATABASE_ERROR

  The exception DATABASE_ERROR may be raised by database
  functions. If a DATABASE_ERROR is caught it is possible
  to get some information about the cause of the error with:

    const func string: errMessage (DATABASE_ERROR)

  There are messages coming from the database and from the Seed7
  database driver. The database driver may have a message like:

    Searching for dynamic libraries failed: libclntsh.so

  This indicates that the connector library could not be found.
  In this case the environment variable LD_LIBRARY_PATH could
  be used to specify the place of the connector library.


16.3.8 ILLEGAL_ACTION

  The exception ILLEGAL_ACTION may be raised by the interpreter
  kernel, if a primitive action does not point to any legal action.
  This check is only done if the s7 interpreter is compiled with
  '#define WITH_ACTION_CHECK'. The ILLEGAL_ACTION exception
  is also raised if the primitive action ACT_ILLEGAL is executed.


16.4 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;

  An 'otherwise' handler catches exceptions, that are not caught
  by the other handlers:

    block
      doSomething(someValue);
    exception
      catch RANGE_ERROR: writeln("RANGE_ERROR");
      otherwise:         writeln("Any other exception");
    end block;


16.5 Stack trace

  If an exception is not caught the program is terminated and the s7
  interpreter writes a stack trace:

    *** Uncaught exception NUMERIC_ERROR raised with
    {integer: <SYMBOLOBJECT> *NULL_ENTITY_OBJECT* div fuel_max }

    Stack:
    in (val integer: dividend) div (val integer: divisor) at integer.s7i(116)
    in init_display at lander.sd7(839)
    in setup at lander.sd7(908)
    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 sigutl.c(218)

  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.

  If s7c is called with the option -g it instructs the
  C compiler to generate 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,
  if an uncaught exception occurs. This option allows debuggers
  to handle uncaught Seed7 exceptions. Note that -e sends the
  signal SIGFPE. This is done even if the exception is not
  related to floating point operations.

    ./s7 s7c -g -e lander
    gdb ./lander

  Then the debugger should be able to run the program and to
  write a backtrace if a crash occurs:

    (gdb) run
    Starting program: /home/tm/seed7_5/prg/lander

    Program received signal SIGFPE, Arithmetic exception.
    0x000000000041b942 in o_3912_init_display () at lander.sd7:839
    839         fuel_gauge := 40 * rocket.fuel div fuel_max;
    (gdb) bt
    #0  0x000000000041b942 in o_3912_init_display () at lander.sd7:839
    #1  0x000000000041c2e5 in o_3917_setup () at lander.sd7:908
    #2  0x0000000000421fe1 in main (argc=1, argv=0x7fffffffdf28) 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:

    ./s7 s7c -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 if an uncaught exception occurs. This
  allows the debugger to show a backtrace for uncaught Seed7 exceptions.


16.6 Suppressing exception checks

  A Seed7 program can be compiled with the option -sx, to suppress the
  generation of checks for exceptions. The suppressed checks x are
  specified with letters from the following list:

    d Suppress the generation of checks for integer division by zero.
    i Suppress the generation of index checks (e.g. string, array).
    o Suppress the generation of integer overflow checks.
    r Suppress the generation of range checks.

  If an exception situation occurs, although exception checking has
  been switched off (with -s), the behavior is undefined. In this
  case the following things can happen:

     - The exception is still raised.
     - A different exception is raised.
     - The program hangs.
     - The program crashes.
     - The computation continues with some garbage value. This garbage
       value can then trigger dangerous things: The X-ray dosis computed
       by your program might be totally wrong. Your program might compute
       the statics of a bridge wrong.

  Undefined behavior is a term used in the language specification
  of C and in other programming languages. Undefined behavior usually
  means that the behavior of the program is unpredictable. Normally
  Seed7 has a well defined behavior in all situations. Even in
  situations where the language specification of C refers to
  undefined behavior.

  A handler for an exception can only work reliable if the checks
  for the exception are done. The compiler warns if -s is used
  and there is a handler for an exception. e.g.:

    *** example.sd7(123): Catch of OVERFLOW_ERROR although the checks are suppressed.

  Only a program that never raises the specific exception and that
  does not have a handler for this exception can be considered
  to be compiled without checks for that exception. Careful program
  analysis and testing (the exception should never be raised) is
  necessary to decide about the omission of exception checking.


16.7 Signals

  A signal is an asynchronous notification of an event. The event
  can come from outside such as a request to terminate the program.
  The event can also come from the program itself such as a memory
  access violation (segfault). Several signals are handled by the
  Seed7 run-time library. The interpreter respectively compiler
  option -ts can be used to influence the behavior, if a signal
  is sent to a Seed7 program (see below). The following signals are
  handled by Seed7:

  Signal  | Special handler      | Behavior without -ts   | Behavior with -ts
  --------+----------------------+------------------------+-----------------------
  SIGABRT | raise OVERFLOW_ERROR | Raises exception       | Dialog to decide
  SIGILL  | raise OVERFLOW_ERROR | Raises exception       | Dialog to decide
  SIGINT  | -                    | Terminate with message | Dialog to decide
  SIGFPE  | raise NUMERIC_ERROR  | Raises exception       | Dialog to decide
  SIGTERM | -                    | Terminate with message | Terminate with message
  SIGSEGV | -                    | Terminate program      | Terminate with message
  SIGPIPE | -                    | Ignored                | Ignored
  SIGWINCH| Resize console       | -                      | -
  SIGALRM | Wait for some time   | -                      | -

  Depending on the actual C compiler and operating system the
  signals SIGABRT or SIGILL might be used to raise OVERFLOW_ERROR
  and the signal SIGFPE might be used to raise NUMERIC_ERROR.

  If the interpreter respectively compiler option -ts has been
  used some signals (see table above) trigger a dialog at the
  console. E.g.:

    *** SIGNAL SIGINT RAISED

    *** The following commands are possible:
      RETURN  Continue
      *       Terminate
      /       Trigger SIGFPE
      !n      Raise exception with number (e.g.: !1 raises MEMORY_ERROR)

  The user can enter a command and activate it with RETURN.
  If the program was waiting for an input at the console the
  input can be entered again:

    re-enter input>

  Triggering SIGFPE is useful if the program runs in a debugger.
  In this case SIGFPE will activate the debugger prompt. Raising
  an exception (e.g.: MEMORY_ERROR) can be used to get a stack
  trace (this works only in the interpreter). A compiled program
  must be executed with a debugger to get a stack trace.


16.8 Other errors and warnings

  No more memory. Parsing 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.

  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 if 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 if the
    basic libraries are defined wrong.

  Action $%s with empty value
    This error can happen if an action tries to do something
    with NULL and NULL is not allowed as value. If parsing works
    correct this should never happen.

  Action $%s requires variable %s not constant
    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 if the basic libraries are defined
    wrong. Principally this error is possible with the following
    operations: :=, incr, decr, wrd_rd, lin_rd

