# Manual for the Seed7 programming language

## CONTENTS

1. INTRODUCTION
   1. What is Seed7?
   2. Why a new programming language?
   3. Features of Seed7
   4. How to read the manual
2. TUTORIAL
   1. Hello world
   2. Greeting
   3. Local declarations and expressions
   4. For loop and float expressions
   5. Parameters
   6. Declare a statement
   7. Template declaring a statement
3. DECLARATIONS
   1. Normal declarations
   2. Syntax declarations
   3. System declarations
4. PREDEFINED STATEMENTS
   1. Assignment
   2. while-statement
   3. repeat-statement
   4. for-statement
   5. for-step-statement
   6. for-each-statement
   7. if-statement
   8. case-statement
5. PREDEFINED TYPES
   1. boolean
   2. integer
   3. bigInteger
   4. rational
   5. bigRational
   6. float
   7. complex
   8. char
   9. string
   10. array
   11. hash
   12. set
   13. struct
   14. category
   15. reference
   16. ref_list
   17. program
   18. ptr
   19. ENUMERATION
   20. color
   21. time
   22. duration
   23. file
   24. text
   25. func
   26. varfunc
   27. void
   28. proc
   29. type
   30. object
   31. expr
6. PARAMETERS
   1. 'val' parameter
   2. 'ref' parameter
   3. 'in' parameter
   4. 'in var' parameter
   5. 'inout' parameter
   6. Symbol parameter
   7. 'attr' parameter
7. OBJECT ORIENTATION
   1. Interface and implementation
   2. Dynamic dispatch
   3. Inheritance
   4. Class methods
   5. Multiple dispatch
   6. Replacing pointers with interface types
8. FILE INPUT AND OUTPUT
   1. Conversion to strings and back
   2. Basic input and output operations
   3. Input and output with conversion
   4. Simple read and write statements
   5. Standard input and output files
   6. Access to operating system files
   7. Keyboard file
   8. Files with line structure
   9. Sockets
   10. User defined file types
   11. Scanning a file
9. STRUCTURED SYNTAX DEFINITION
   1. The Extended Backus-Naur Form
   2. The Seed7 Structured Syntax Description
   3. The syntax of a statement
   4. Priority and associativity
   5. The syntax of operators
   6. Syntax of predefined statements
   7. Advanced syntax definitions
   8. Comparison of EBNF and S7SSD
10. TOKENS
    1. White space
       1. Spaces
       2. Comments
       3. Line comments
    2. Identifiers
       1. Name identifiers
       2. Special identifiers
       3. Parentheses
    3. Literals
       1. Integer literals
       2. BigInteger literals
       3. Float literals
       4. String literals
       5. Character literals
11. EXPRESSIONS
    1. Parentheses
    2. Call expressions
    3. Dot expressions
12. OPERATING SYSTEM ACCESS
    1. Standard path representation
    2. readDir
    3. openDir
    4. getcwd
    5. chdir
    6. mkdir
    7. homeDir
    8. fileType
    9. fileMode
    10. setFileMode
    11. fileSize
    12. getATime
    13. getCTime
    14. getMTime
    15. setATime
    16. setMTime
    17. readlink
    18. symlink
    19. removeFile
    20. removeTree
    21. copyFile
    22. cloneFile
    23. moveFile
    24. argv(PROGRAM)
    25. name(PROGRAM)
    26. path(PROGRAM)
    27. dir(PROGRAM)
    28. file(PROGRAM)
    29. getenv
    30. setenv
    31. environment
13. DATABASE ABSTRACTION API
    1. Opening a database connection
    2. Other ways to open a database connection
    3. Prepared statements
    4. Bind values to placeholders
    5. Execute a prepared statement
    6. Fetch records from the result set
    7. Get columns from fetched records
14. PRIMITIVE ACTIONS
    1. Actions for the type ACTION
    2. Actions for array types
    3. Actions for the type bigInteger
    4. Actions for the types bin32 and bin64
    5. Actions for the type boolean
    6. Actions for byte strings
    7. Actions for the type char
    8. Actions for various directory, file and other commands
    9. Actions for text (console) screen output
    10. Actions for declarations
    11. Actions to do graphic output
    12. Actions for enumeration types
    13. Actions for the type clib_file
    14. Actions for the type float
    15. Actions to support the graphic keyboard
    16. Actions for hash types
    17. Actions for the type integer
    18. Actions for interface types
    19. Actions to support the text (console) screen keyboard
    20. Actions for the list type
    21. Actions for the type process
    22. Actions for the type pollData
    23. Actions for proc operations and statements
    24. Actions for the type program
    25. Actions for the type reference
    26. Actions for the type ref_list
    27. Actions for struct types
    28. Actions for set types
    29. Actions for the type PRIMITIVE_SOCKET
    30. Actions for the types database and sqlStatement
    31. Actions for the type string
    32. Actions for the type time
    33. Actions for the type type
    34. Actions for the type utf8_file
15. FOREIGN FUNCTION INTERFACE
    1. C types used by the implementation
    2. String conversions
    3. Operating system string and path conversions
    4. Macros to access the action parameters
    5. Functions to create action results
    6. Memory management macros
    7. Basic conversion functions
    8. Error handling
16. ERRORS
    1. Compile time errors
    2. Exceptions
       1. MEMORY_ERROR
       2. NUMERIC_ERROR
       3. OVERFLOW_ERROR
       4. INDEX_ERROR
       5. RANGE_ERROR
       6. FILE_ERROR
       7. DATABASE_ERROR
       8. ILLEGAL_ACTION
    3. Handlers
    4. Stack trace
    5. Suppressing exception checks
    6. Signals
    7. 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. This happens after the keyword local with:

        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. 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 (in_string)"><> "";
        writeln("Hi " <& name <& "!");
      end func;

The `repeat ... until` loop repeats the statements between the two keywords until the condition `(in_string)"><> ""` 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;

If a non-empty name is entered for the first time the `while` loop is not entered at all.

### 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;
          write(fahr);
          write(" ");
          writeln(celsius);
          fahr := fahr + increment;
        end while;
      end func;

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

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

### 2.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` is written as:

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

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

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

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

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

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

### 2.5 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 compile time error:

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

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

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

If you call this function with

    reset(number);

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

    reset(8);

results in a compile time error

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

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

    const func string: oct_str (in var integer: number) is func
      result
        var string: 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.6 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.7 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 "type" is type;
    $ 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;

## 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 )
          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 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 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 )
          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 )
          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"⇒ 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 π
          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 )
          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) ⇒ A,
                        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 )
          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:
          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 )
          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,
                        "abcde"[2 .. 4] ⇒ "bcd",
                        "abcde"[2 .. 7] ⇒ "bcde",
                        "abcde"[4 .. 2] ⇒ "",
                        "abcde"[6 .. 8] ⇒ "",
                        "abcde"[-3 .. 4] ⇒ "abcd",
                        "abcde"[-3 .. 7] ⇒ "abcde",
                        "abcde"[-3 .. 0] ⇒ "" )
          [ A len B ] Access a substring from position A with length B
                      ( Type of arguments A and B: integer,
                        "abcde"[2 len 3] ⇒ "bcd",
                        "abcde"[2 len 5] ⇒ "bcde",
                        "abcde"[-3 len 8] ⇒ "abcd",
                        "abcde"[-1 len 9] ⇒ "abcde" )
          [ A .. ]  Access a substring beginning at position A
                      ( Type of argument A: integer,
                        "abcde"[3 ..] ⇒ "cde",
                        "abcde"[6 ..] ⇒ "",
                        "abcde"[-3 ..] ⇒ "abcde",
                        ""[1 ..] ⇒ "" )
          [ .. A ]  Access a substring ending at position A
                      ( Type of argument A: integer,
                        "abcde"[.. 4] ⇒ "abcd",
                        "abcde"[.. 6] ⇒ "abcde",
                        "abcde"[.. -3] ⇒ "",
                        ""[.. 5] ⇒ "" )
        Relations:
          =, <>, <, <=, >, >=
        Functions:
          length(A) Length of string
                      ( Type of result: integer,
                        length("") ⇒ 0 )
          pos(A,B)  First position of char B in string A
                      ( Type of argument B: char,
                        Type of result: integer,
                        pos("ABCABC",'B') ⇒ 2,
                        pos("XYZ",'A') ⇒ 0 )
          pos(A,B)  First position of string B in string A
                      ( Type of result: integer,
                        pos("ABCDE ABCDE","BC") ⇒ 2,
                        pos("XYZXYZ","ZYX") ⇒ 0,
                        pos("123456789","") ⇒ 0 )
          pos(A,B,C) First position of char B in string A
                     The search starts at position C of string A
                      ( Type of argument B: char,
                        Type of argument C: integer,
                        Type of result: integer,
                        pos("ABCABC",'B', 3) ⇒ 5,
                        pos("XYZYX",'Z', 4) ⇒ 0,
                        pos("12345",'3', 7) ⇒ 0 )
          pos(A,B,C) First position of string B in string A
                     The search starts at position C of string A
                      ( Type of argument C: integer,
                        Type of result: integer,
                        pos("ABCDE ABCDE","BC", 3) ⇒ 8,
                        pos("XYZXYZ","ZXY", 4) ⇒ 0,
                        pos("12345","34", 7) ⇒ 0 )
                        pos("123456789","", 2) ⇒ 0 )
          rpos(A,B) Last position of char B in string A
                      ( Type of argument B: char,
                        Type of result: integer,
                        rpos("ABCABC",'B') ⇒ 5,
                        rpos("XYZ",'A') ⇒ 0 )
          rpos(A,B) Last position of string B in string A
                      ( Type of result: integer,
                        rpos("ABCDE ABCDE","BC") ⇒ 8,
                        rpos("XYZXYZ","ZYX") ⇒ 0,
                        rpos("123456789","") ⇒ 0 )
          rpos(A,B,C) Last position of char B in string A
                     The search starts at position C of string A
                      ( Type of argument B: char,
                        Type of argument C: integer,
                        Type of result: integer,
                        rpos("ABCABC",'B', 4) ⇒ 2,
                        rpos("XYZYX",'Z', 2) ⇒ 0,
                        rpos("12345",'3', 5) ⇒ 3 )
          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).

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

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

        Literal:
          [] (elem1, elem2)  Create an array with the given elements
                        The starting index of the array is 1.
          [0] (elem1, elem2)  Create an array with the given elements
                        The starting index of the array is 0.
        Infix operators:
          &         Array concatenation
          times     Array generation
                      ( Left operand: integer,
                        Right operand: baseType,
                        A times B Generates an array baseType
                        with A elements of B,
                        (1 times B)[1] ⇒ B
                        -1 times B ⇒ EXCEPTION RANGE_ERROR )
          [ A .. B ] times C    Array generation
                      ( Type of arguments A and B: integer )
                        Type of argument C: baseType,
                        [ A .. B ] times C Generates an array baseType
                        with pred(B - A) elements of C,
                        [ -1 .. -2 ] times B ⇒ empty array,
                        [ -1 .. -3 ] times B ⇒ EXCEPTION RANGE_ERROR )
        Indices:
          [ A ]     Access one array element
                      ( Type of argument A: integer,
                        Type of result: baseType,
                        A[minIdx(A)] ⇒ First element,
                        A[maxIdx(A)] ⇒ Last element,
                        A[pred(minIdx(A))] ⇒ EXCEPTION 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 )
          [ A len B ]  Get a sub array from the position A with maximum length B
                      ( Type of arguments A and B: integer )
          [ A .. ]  Get a sub array beginning at position A
                      ( Type of argument A: integer )
          [ .. A ]  Get a sub array ending at position A
                      ( Type of argument A: integer )
        Relations:
          =, <>
        Functions:
          length(A) Length of array
                      ( Type of result: integer,
                        length(A) = succ(maxIdx(A) - minIdx(A)),
                        length(0 times TRUE) ⇒ 0,
                        length(5 times TRUE) ⇒ 5 )
          minIdx(A) Minimal index of array
                      ( Type of result: integer,
                        minIdx(3 times TRUE) ⇒ 1,
                        minIdx([-1 .. 4] times TRUE) ⇒ -1 )
          maxIdx(A) Maximal index of array
                      ( Type of result: integer,
                        maxIdx(3 times TRUE) ⇒ 3 )
          rand(A)   Random element from an array
                    The random elements are uniform distributed.
                      ( Type of result:  baseType )
          remove(A,B) Remove element with index B from array A and
                      return the removed element
                      ( Type of argument B: integer,
                        Type of result: baseType,
                        remove(0 times TRUE, 1) ⇒ EXCEPTION 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 C to the array A at position B
                      ( Type of argument B: integer,
                        Type of argument C: baseType )
          insert(A, B) Insert B into the sorted array A
                      ( Type of argument C: baseType )

### 5.11 hash

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

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

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

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

### 5.12 set

The type `set of baseType` describes a set of elements of a `baseType`. (including the empty set). The type `set of 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.

        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.

        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_REF1";

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

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

### 6.4 'in var' parameter

This function computes the greatest common divisor:

    const func integer: gcd (in var integer: a, in var integer: b) is func
      result
        var integer: 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 `circles` 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 `shapes` 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 curser, which is independend 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 .
  `

#### 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 .
  `

#### 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 ::=
    ''' .
  `

#### 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 | '"' .
  `

## 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`
  `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
  BLN_ |  | blnlib.c |  | `boolean` operations
  BST_ |  | bstlib.c |  | Operations for byte strings
  CHR_ |  | chrlib.c |  | `char` operations
  CMD_ |  | cmdlib.c |  | Various directory, file and other commands
  DCL_ |  | dcllib.c |  | Declaration operations
  DRW_ |  | drwlib.c |  | Drawing operations
  ENU_ |  | enulib.c |  | Enumeration operations
  FIL_ |  | fillib.c |  | `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
  PRC_ |  | prclib.c |  | `proc` operations and statements
  PRG_ |  | prglib.c |  | Program operations
  REF_ |  | reflib.c |  | `reference` operations
  RFL_ |  | rfllib.c |  | `ref_list` operations
  SCR_ |  | scrlib.c |  | Screen operations
  SCT_ |  | sctlib.c |  | `struct` operations
  SET_ |  | setlib.c |  | `set` operations
  SOC_ |  | soclib.c |  | `PRIMITIVE_SOCKET` operations
  STR_ |  | strlib.c |  | `string` operations
  TIM_ |  | timlib.c |  | `time` and `duration` operations
  TYP_ |  | typlib.c |  | `type` operations
  UT8_ |  | ut8lib.c |  | `utf8_file` operations

The C functions which implement primitive actions have lowercase names. E.g.: The action `'PRC_WHILE'` is implemented with the C function `'prc_while()'` in the file `"prclib.c"`. The parameter list for all C action functions is identical. Every *lib.c file has a corresponding *lib.h file which contains the prototypes for the action functions.

In a Seed7 program the operator `+` is used to add two `integer` values. The primitive action, which describes the addition of two integers, is `'INT_ADD'`. The connection between `+` and `'INT_ADD'` is done in the library `"integer.s7i"` with the definition:

    const func integer: (in integer: summand1) + (in integer: summand2) is action "INT_ADD";

To execute an action a corresponding C function must be present in the 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_LNG | arr_lng | a->max_position-a->min_position + 1
ARR_MAXIDX | arr_maxidx | a->max_position
ARR_MINIDX | arr_minidx | a->min_position
ARR_PUSH | arr_push | arrPush
ARR_RANGE | arr_range | arrRange
ARR_REMOVE | arr_remove | arrRemove
ARR_SORT | arr_sort | arrSort
ARR_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<<b))
BIN_LSHIFT_ASSIGN | bin_lshift_assign | a=(intType)((uintType)(a<<b))
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_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_MTIME | cmd_get_mtime | cmdGetMTime
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_MTIME | cmd_set_mtime | cmdSetMTime
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

### 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_IN1VAR | dcl_in1var
DCL_IN2VAR | dcl_in2var
DCL_INOUT1 | dcl_inout1
DCL_INOUT2 | dcl_inout2
DCL_PARAM_ATTR | dcl_param_attr
DCL_REF1 | dcl_ref1
DCL_REF2 | dcl_ref2
DCL_SYMB | dcl_symb
DCL_VAL1 | dcl_val1
DCL_VAL2 | dcl_val2
DCL_VAR | dcl_var

### 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_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_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_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
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

### 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_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 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 Compile time errors

The compile time errors are not fatal (the program can execute) except for the error 1 (Out of heap space) which terminates the compilation process and no execution occurs. The following compile time errors exist:

  1: |  | Fatal Error: Out of heap space
  2: |  | File "%s" not found
  3: |  | Include file "%s" not found
  4: |  | "END OF FILE" encountered
  5: |  | Illegal character in text "%s"
  6: |  | Unclosed comment
  7: |  | Illegal pragma "%s"
  8: |  | Illegal action "%s"
  9: |  | Illegal system declaration "%s"
  10: |  | Integer "%s" too big
  11: |  | Negative exponent in integer literal
  12: |  | Digit expected found "%s"
  13: |  | Integer "%dE%s" too big
  14: |  | Integer base "%ld" not between 2 and 36
  15: |  | Extended digit expected found "%s"
  16: |  | Illegal digit "%c" in based integer "%d#%s"
  17: |  | Based integer "%d#%s" too big
  18: |  | "'" expected found "%s"
  19: |  | Character literal exceeds source line
  20: |  | Use \" instead of "" to represent " in a string
  21: |  | Use / instead of \\ as path delimiter
  22: |  | Illegal string escape "\%s"
  23: |  | Numerical escape sequences should end with ";" not "%s"
  24: |  | String continuations should end with "\" not "%s"
  25: |  | String literal exceeds source line
  26: |  | Name expected found "%s"
  27: |  | Integer literal expected found "%s"
  28: |  | String literal expected found "%s"
  29: |  | Identifier expected found "%s"
  30: |  | Expression expected found "%s"
  31: |  | Declaration of parameter %s failed
  32: |  | Declaration of "%s" failed
  33: |  | Exception "%s" raised
  34: |  | "%s" declared twice
  35: |  | "%s" not declared
  36: |  | Associativity expected found "%s"
  37: |  | Statement priority "%s" too big
  38: |  | Syntax with two parameters before operator is illegal
  39: |  | Empty syntax declaration
  40: |  | Dot expression requested as syntax description
  41: |  | "%s" redeclared with infix priority %d not %d
  42: |  | "%s" redeclared with prefix priority %d not %d
  43: |  | Priority %d required for parameter after "%s" not %d
  44: |  | Priority <= %d expected found "%s" with priority %d
  45: |  | "%s" must have priority %d not %d for dot expression
  46: |  | "%s" expected found "%s"
  47: |  | "%s" expected found "%s"
  48: |  | Undefined type for literal "%s"
  49: |  | "newtype", "subtype", "func", "enumlit" or "action" expected found "%s"
  50: |  | "func" or "type" expected found "%s"
  51: |  | Match for %s failed
  52: |  | Variable expected in %s found %s
  53: |  | Type expected found %s
  54: |  | Procedure expected found %s expression
  55: |  | Parameter specifier expected found "%s"
  56: |  | Evaluate type expression %s failed
  57: |  | Overlong UTF-8 encoding used for character "%s" (U+%04x)
  58: |  | UTF-16 surrogate character found in UTF-8 encoding "%s" (U+%04x)
  59: |  | Non Unicode character found "%s" (U+%04x)
  60: |  | UTF-8 continuation byte expected found "%s" (U+%04x)
  61: |  | Unexpected UTF-8 continuation byte found "%s" (U+%04x)
  62: |  | Solitary UTF-8 start byte found "%s" (U+%04x)
  63: |  | UTF-16 byte order mark found "%s" (U+%04x)
  64: |  | The numerical escape sequence "\%u;" is too big
  |  | Undefined error

### 16.2 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`, `RANGE_ERROR`, `FILE_ERROR` and `ILLEGAL_ACTION`. A program can raise an exception with the `raise` statement. For example:

    raise RANGE_ERROR;

#### 16.2.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.2.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.2.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.2.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. An attempt to get an element of a `string`, `bstring` or `ref_list` with a negative or zero index raises also `INDEX_ERROR`.

It may be raised from the following `array` operations:
  [index], remove.
It may be raised from the following `string` operations:
  [index], @:= [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.2.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.2.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.2.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.2.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.3 Handlers

To catch an EXCEPTION the following handler construct can be used:

    block
      number := 1 div 0;
    exception
      catch NUMERIC_ERROR:
        number := 1;
    end block;

It is also possible to catch several EXCEPTIONS:

    block
      doSomething(someValue);
    exception
      catch MEMORY_ERROR:  writeln("MEMORY_ERROR");
      catch NUMERIC_ERROR: writeln("NUMERIC_ERROR");
    end block;

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.4 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.5 Suppressing exception checks

A Seed7 program can be compiled with the option -s x, 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.6 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.7 Other errors and warnings

No more memory. Program terminated.
  This error message is displayed after the compile time error 1 (Out of heap space) . The file name and line number of the analyzer source code where this happens is displayed together with internal heap information.
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 REQUIRES VARIABLE %s NOT %s
  This error can happen with actions which assign a value to a constant. Since the analyze phase checks for variable objects this error can only happen if the basic libraries are defined wrong. Principally this error is possible with the following operations: :=, incr, decr, wrd_rd, lin_rd