# Ox Syntax Reference

## Chapter contents:

Lexical conventions
  Comment

Identifiers
  Keywords
  Constants
    Integer constants
    Character constants
    Double constants
    Matrix constants
    String constants
    Array constants

Objects
  Types
    Type conversion

  Lvalue
  Scope

External declarations
  Enumerations
  Specifiers
  External variable declarations
  Function declarations
  Function definitions
    Returning values
    Variable length argument list

  Classes
  Member function definitions
    Constructor and destructor functions
    The `this` reference and member scope
    Static members
    Derived classes
    Virtual functions

Statements
  Selection statements
  Iteration statements
  Jump statements
  Declaration statements

Expressions
  Primary expressions
  Multiple assignment
  Postfix expressions
    Member reference
    Function calls
    Explicit type conversion
    Indexing vector and array types
    Postfix incrementation
    Transpose

  Unary expressions
    Prefix incrementation
    Unary minus and plus
    Logical negation
    Address operator
    New and delete

  Power expressions
  Multiplicative expressions
  Additive expressions
  Concatenation expressions
  Relational expressions
  Equality expressions
  Logical dot-AND expressions
  Logical-AND expressions
  Logical dot-OR expressions
  Logical-OR expressions
  Conditional expression
  Assignment expressions
  Comma expression
  Constant expressions

Preprocessing
  File inclusion
  Import of modules
  Conditional compilation
  Pragmas

Difference with ANSI C and C++

Tables:

Escape sequences
Operator precedence
Result from dot operators
Result from relational operators
Result from operators involving an empty matrix as argument
Result from relational operators involving missing values

## Lexical conventions

### Comment

Anything between `/*` and `*/` is considered comment. This comment can be nested (unlike C and C++). Everything following `//` up to the end of the line is also comment, but is ignored inside `/*` ... `*/` type comment. So nested comment is possible:

        one = cons + 1;   // comment
        /* two = cons + 1;   // comment
        */

## Identifiers

Identifiers are made up of letters and digits. The first character must be a letter. Underscores (_) count as a letter. The maximum length of an identifier is 60 characters, additional characters are ignored.

### Keywords

The following keywords are reserved:

    array    decl     extern   new      this
    break    default  for      operator virtual
    case     delete   goto     return   while
    char     do       if       short
    class    double   inline   static
    const    else     int      string
    continue enum     matrix   switch

### Constants

#### Integer constants

A sequence of digits is an integer constant. A hexadecimal constant is a sequence of digits and the letters `A` to `F` or `a` to `f`, prefixed by `0x` or `0X`.

#### Character constants

Character constants are interpreted as an integer constant. A character constant is an integer constant consisting of a single character enclosed in single quotes (e.g. `'a'` and `'0'`) or an escape sequence enclosed in single quotes.

### Table syn.1: Escape-sequence

    \"      double quote
    \'      single quote
    \0      null character
    \\      backslash
    \a      alert (bel)
    \b      backspace
    \f      formfeed
    \n      newline
    \r      carriage return
    \t      horizontal tab
    \v      vertical tab
    \xhh    hexadecimal number hh

So `'\n'` is the integer constant corresponding to the newline character.

#### Double constants

A double constant consists of an integer part, a decimal point, a fraction part, an `e`, `E`, `d` or `D` and an optionally signed integer exponent. Either the integer or the fraction part may be missing (not both); either the decimal point or the full exponent may be missing (not both). A hexadecimal double constant is written as `0x.`hhhhhhhhhhhhhhhh. The format used is an 8 byte IEEE real. The hexadecimal string is written with the most significant byte first (the sign and exponent are on the left). If any hexadecimal digits are missing, the string is left padded with 0's. Double constants in an external declaration may use a dot to represent a missing values. This sets the variable to NaN (Not a Number).

#### Matrix constants

A matrix constant lists within `<` and `>` the elements of the matrix, row by row. Each row is delimited by a semicolon, successive elements in a row are separated by a comma. For example:

        < 00, 01, 02; 10, 11, 12 >
        < 0.0, 0.1, 0.2 >
        < 1100 >

which are respectively a 2 by 3 matrix, a 1 by 3 matrix and a 1 by 1 matrix, the first constant is:

    00   01   02
    10   11   12

The comma is optional, so the first matrix constant may be written as (the semicolon is still required):

        < 00 01 02; 10 11 12 >

The index of each row is one higher than the previous row. Within each row, the column index of an element is one higher than that created with the previous element in the same row.

An integer range may be specified, e.g. `2:5` corresponds to `2,3,4,5`. The range may decrease, so that `5.3:2.8` corresponds to `5.3,4.3,3.3`.

A stepsize may be specified, as in `2:[2]8`, which gives `2,4,6,8`.

A specific element in the matrix can be set. This overrides the location implicit in the position of the element in the matrix constant. Note that the top left element is `[0][0]`, the second element in the first row `[0][1]`, etc.

A number of identical elements can be specified, e.g. `[3]*0` corresponds to `0,0,0`. Unspecified elements are set to zero.

As an example involving all types, consider:

        < [4]*1,2; 10,11,14-2; 1:4; [3][4]=99,2; 8:[-3]2 >

which corresponds to:

     1    1    1   1   2   0
    10   11   12   0   0   0
     1    2    3   4   0   0
     0    0    0   0  99   2
     8    5    2   0   0   0

Missing values in a matrix constant could be represented with a dot or `.NaN`, which represents NaN (Not a Number), e.g.:

        < .,2,3; 4,.,6 >

Similarly, `.Inf` represents infinity. An empty matrix can be writen as:

        < >

Further examples are given in external declarations.

#### String constants

A string constant is a text enclosed in double quotes, for example: `"tailor"`. Adjacent string constants are concatenated. A null character is always appended to indicate the end of a string. The maximum length of a string constant is 1024 characters. Escape sequences can be used to represent special characters.

#### Array constants

An array constant is a list of constants in braces, separated by a comma. This is a recursive definition, because the constant can itself be an array constant. The terminating level consists of non-array constants. Each level of array constants creates an array of references. For example:

        { "tinker", "tailor", "soldier" }
        {{ "tinker", "tailor"}, {"soldier"} }

## Objects

### Types

Variables in Ox are implicitly typed, and can change type during their lifetime. The life of a variable corresponds to the level of its declaration. Its scope is the section of the program in which it can be seen. Scope and life do not have to coincide.

There are three basic types and four derived types.

- int: a signed integer.
- double: double precision floating point type.
- matrix: a two-dimensional array of doubles which can be manipulated as a whole.
- string
- array: an array of references.
- function
- class
- reference to class object

#### Type conversion

When a double is converted to an int, the fractional part is discarded; if the resulting value cannot be represented, the behaviour is undefined. When an int is converted to a double, the nearest representation will be used. For example, conversion to int of 1.3 and 1.7 will be 1 on both occasions.

A single element of a string (a character) is of type int. An int or double can be assigned to a string element, which first results in conversion to int, and then to a single byte character.

Also see explicit type conversion.

### Scope

Variables declared at the start of a statement block have scope and life restricted to the block. These variables are called automatic: they are created and initialized whenever the block is entered, and removed as soon as the block is exited. Variables declared outside any statement block have global scope and life; these are called static. Note that Ox assignment of arithmetic types and string type implies copying over the contents from the right-hand side to the left-hand side. Automatic variables of any type can be assigned to variables with broader scope.

## External declarations

An Ox program consists of a sequence of external declarations. These either reserve storage for an object, or serve to inform of the existence of objects created elsewhere. Each program must define one function called `main`, where execution of the program will start.

### Enumerations

An enumeration defines a list of integer constants. By default, the first member will have value 0, and each successive member will have a value of one plus that of the previous member. The value of a member can be set by assigning it a constant integer value.

Enumerator names only exist in the file in which they occur. Enumerations should be placed in header files if they need to be shared between several source files.

Here are some examples with corresponding values:

        enum { C_FIRST, C_SECOND, C_THIRD };               // 0,1,2
        enum { T_INT, T_DBL=2, T_STR, T_MAT=C_THIRD };   // 0,2,3,2
        enum { FLAG0,FLAG1, FLAG2=FLAG1*2, FLAG3=FLAG2*2};//0,1,2,4
        enum { T_ERR = 1.0 } ;                             // error

### Specifiers

The `static` specifier restricts the scope of the declared object to the remainder of the file. Although it will exist throughout the program's life, it cannot be seen from other files. In classes, the `static` keyword is used with a different meaning. The `extern` specifier informs the remainder of the file that the object can be accessed, although defined (created) in another file. The `extern` and `static` specifiers are mutually exclusive. External declarations are most conveniently placed in header files.

### External variable declarations

The `static` or `extern` specifier and the `const` qualifier preceding an external variable declaration list applies to all variables in the list. Each identifier creates space for an object with global lifetime, unless declared `extern` or `const`.

A `const` object must be initialized (unless declared `extern`) but its value may not be changed thereafter. Unless declared `extern`, a `const` object cannot be accessed from other files. If of scalar type, a `const` can appear in a constant-expression.

At the external level of declarations, as treated here, it is possible to specify a matrix size, and initialize that matrix to zero. If an external variable is created without explicit value and without dimensions, it will default to an int with value 0. Here are some examples:

        decl a, b;                  // default to type int, value 0
        enum { AAP, NOOT, MIES, WIM };
        const decl ia = NOOT, ib = NOOT + WIM;         // type: int
        const decl ma = < NOOT, AAP; 0, 1 >;        // type: matrix
        const decl aa = {"tinker", "tailor"};        // type: array
        decl id = ia * (WIM - 1) * MIES + ib;          // type: int
        decl da = ia + 0.;                          // type: double
        decl mb = <0:3; 4:7; 8:11>;                 // type: matrix
        decl ab = { ma, ma};                         // type: array
        extern decl elsewhere;             // defined in other file

        decl mc[3][3] = 1.5;        // 3 x 3 matrix with values 1.5
        decl md[2][1];                    // 3 x 1 matrix of zeros

        enum { ZUS = id };                // error: id is not const
        decl ih = id;                     // error: id is not const
        decl ia;                          // error: already defined

### Function declarations

A function declaration communicates the number of arguments and their types to a file, so that the function can be called correctly from that file. The actual creation of the function is done through a function definition (which at the same time declares the function). A function can be declared many times, but type and number of arguments must always be identical:

        test0();                     // function takes no arguments
        test1(const a1);                      // one const argument
        test2(const a2, a3);       // two arguments, first is const
        static test3(a1);       // cannot be used outside this file
        extern test4(a1);     // function defined outside this file
        print(a1, ...);             // variable number of arguments
        test1(a1);     // error: previous declaration was different

A second form, which uses `extern` string-constant, provides dynamic linking of extension functions (which could be written in C, FORTRAN, etc.; creation of dynamic link libraries is platform dependent). In the following example, `test5` corresponds to the external function `MyCFunc`(), located in the dynamic library `mydll`. When the Ox program is linked, `mydll` will be automatically loaded, and the function imported.

        extern "mydll,MyCFunc" test5(a1);

### Function definitions

A function definition specifies the function header and body, and declares the function so that it can be used in the remainder of the file. A function can be declared many times, but defined only once.

The use of `const` is recommended: arguments declared `const` can be referenced, but cannot be changed inside the function. If the argument is a `const` reference, the reference cannot be changed, but what it references can. The `decl` keyword is optional in front of an argument. An empty argument list indicates that the function takes no arguments at all. The `...` indicates a variable number of arguments; it must have the last position in the header, but cannot be the first.

        test1(const a1);                    // declaration of test1
        print(a1, ...);             // variable number of arguments
        test2(const a1, a2)                  // definition of test2
        {
            test1(a2);                       // call function test1
            print(a1, 1, 2, "\n");         // at least one argument
            test1(a2, 1);       // error: wrong number of arguments
            a2 = 1;                            // a2 may be changed
            a1 = 1;                           // error: a1 is const
            /* ... */
        }

All function arguments are passed by value. This means that a copy of the actual object is made. For int, double, matrix and string types the whole object is copied. Any changes to the copy are lost as soon as the function returns. Derived types are accessed through a reference, and that reference is passed by value. However, what is pointed to may be changed, and that change will remain in effect after function return. So passing references allows a function to make a permanent change to a variable, for examples see function calls. It is good practice to label an argument `const` if a function doesn't change the variable. This increases program clarity and enables the compiler to generate more efficient code.

#### Returning a value

All functions may have a return value, but this return value need not be used by the caller. If a function does not return a value, its actual return value is undefined.

The `return` statement returns a value from the function, and also exits the function. So, when the program flow reaches a `return` statement, control returns to the caller, without executing the remainder of the function.

The syntax of the return statement is:
`return` return_value `;`
Or, to exit from a function which does not have a return value:
`return;`

#### Variable length argument list

A special library function `va_arglist()` is used to access arguments in the variable argument list. It returns the arguments supplied for the ellipse as an array. An example illustrates:

        test(const a, ...)
        {
            decl i, args = va_arglist();

            for (i = 0; i < sizeof(args); i++)
                print (" vararg ", i, ": ", args[i]);
        }
        main()
        {
            test("tinker", "tailor", "soldier");
        }

which prints `vararg 0: tailor vararg 1: soldier`.

### Classes

A class is a collection of data objects combined with functions operating on those objects. Access to data members from outside the class is through member functions: only member functions can access data directly. All data members are private, and all function members public, using C++ parlance.

Consider a simple line class, which supports drawing lines from the current cursor position to the next, and moving the cursor:

        class Line                        // Line is the class name
        {
            decl x, y;                          // two data members
            const decl origin;                 // const data member
            static decl cLines;               // static data member
            Line(const orig);                        // constructor
            moveto(const x, const y);                // move cursor
            lineto(const x, const y);  // draw line and move cursor
            static getcLines();                  // static function
            static setcLines(c);                 // static function
        };                      // ; is optional in Ox (unlike C++)

All member names within a class must be unique. A class declaration introduces a type, and can be shared between source files through inclusion in header files. Ox accesses an object through a reference to the object which is created using the `new` operator. Data members cannot be initialized in the class, but can in the constructor function.

### Member function definitions

A member function provides access to data members of an object. It is defined as its class name, followed by `::` and the function name. The function name must have been declared in the class. Member functions cannot be declared outside a class; the class declaration contains the member function declaration. Only a member function can use data members of its own class directly.

Here are the definitions of the member functions of class `Line`:

        Line::Line(const orig)
        {
            x = y = orig;               // set cursor at the origin
            origin = orig;           // only allowed in constructor
            cLines++;               // count number of Line objects
        }
        Line::moveto(const ax, const ay)
        {
            x = ax;  y = ay;
            print("moved to ", ax, " ", ay, "\n");
            return this;
        }
        Line::lineto(const ax, const ay)
        {
                         // draw the line from (x,y) to (ax,ay) ...
            x = ax;  y = ay;
            print("line to ", ax, " ", ay, "\n");
            return this;
        }

The `new` operator creates an object of the specified class, calls the constructor function, and returns a reference to it. A member function is called through a member reference, which is a class object named followed by `->` or a dot. For example:

        lineobj = new Line(0);                 // create object and
                                             // set cursor to (0,0)
        lineobj.lineto(10, 10);            // draw line to (10, 10)
        lineobj->Line::lineto(10, 10);                 // same call
        lineobj::lineto(10, 10);            // error, needs -> or .

Since `lineobj` is of class `Line`, both calls to `lineto` are to the same function. The only difference is one of efficiency. Ox has implicit typing, so can only know the class of `lineobj` at run time. In the second case the class is specified, and the function address can be resolved at compile time.

#### Constructor and destructor functions

The member function with the same name as the class is called the constructor, and is automatically invoked when creating an object of the class. If the constructor function is absent, a default constructor function will be assumed which takes no arguments. A constructor may not be static. A constructor always returns a reference to the object for which it was called and may not specify a return value. Only the constructor function may set `const` data members. In the `Line` class, the origin is only set during construction, and not thereafter. However, each `Line` object has its own origin (unless origin is made `static`).

A destructor is called after a request to delete an object, and before the object is actually removed. It may be used to clear up any allocated objects inside the object to be deleted. A destructor function has the same name as the class, is prefixed by ~, and may neither take arguments, nor return a value. It does however receive the `this` reference.

        class Line
        {   /* ... */
            Line(const orig);                        // constructor
            ~Line();                                  // destructor
            /* ... */
        };
        test()
        {
            decl lineobj;

            lineobj = new Line(0);//create object, call constructor
            delete lineobj;       // call destructor, delete object
        }

#### The `this` reference and member scope

All non-static member functions receive a hidden argument called `this`, which points to the object for which the function is called. So the constructor function `Line` obtains in `this` a reference to the newly created object. The assignment to `x` and `y` refer to the members of the `this` object. When accessing a variable in a member function, it is determined first whether the function is a local variable or an argument. Next it is considered as a member of `this`. If all these fail, it is considered as a global variable. So local variables and arguments hide members, together these hide global variables. The following example shows how the scope resolution operator `::` may be used to resolve conflicts:

        decl x, y;                              // global variables
        extern moveto(x, y);                   // external function

        Line::moveto(const x, const y)
        {
            ::x = x;        // assign arguments to global variables
            ::y = y;
            this->x = x;        // assign arguments to data members
            this->y = y;

            ::moveto(x, y);             // call non-member function
            moveto(x, y);             // error: call to itself will
        }                                    // cause infinite loop

#### Static members

There is only one copy of a static member, shared by all objects of a class. A static member may not have the same name as the class it is in.

#### Derived classes

A class may derive from a previously declared class. A derived class will inherit all members from its base class, and can access these inherited members as its own members. However, if the derived class has members with the same name as members of the base class, the former take precedence. In this way, a class can redefine functionality of its base class. If a function is redefined, the base class name followed by `::` may be used to refer to the base class function. Deriving from the `Line` class:

        class Angle : Line                // Line is the base class
        {
            Angle();                                 // constructor
            lineto(const x, const y);     // draw dash, move cursor
        };
        Angle::Angle()
        {
            Line(0);                              // starts at zero
        }
        Angle::lineto(const ax, const ay)
        {
            Line::lineto(ax, y);                 // horizontal line
            Line::lineto(ax, ay);                  // vertical line
            print("is angle to ", ax, " ", ay, "\n");
            moveto(ax, ay);
        }

`Angle`'s constructor just calls the base class constructor, as the body may be read as `this->Line(0);`. Note that the base class constructor and destructor functions are not called automatically (unlike in C++). In the new `lineto` object, `Line::lineto` is used to make sure that we call the correct function (otherwise it would make a recursive call). For the `moveto` that is no problem, `moveto` calls the base function, as it was not redefined in the `Angle` class. Non-static member functions may be declared as virtual (that is, they can be redefined by a derived class), this is discussed in the next section.

New classes may be derived from a class which is itself derived, but Ox only supports single inheritance: a class can only derive from one other class at a time.

#### Virtual functions

Virtual functions allow a derived class to supply a new version of the virtual function in the derived class, replacing the version of the base class. When the base class calls the virtual function, it will actually use the function of the derived class. For a virtual function, the call can only be resolved at run time. Then, the object type is known, and the called function is the one first found in the object, when moving from the highest class towards the base class.

## Statements

The executable part of a program consists of a sequence of statements. Expression statements are expressions or function calls. It can be a do-nothing expression, as in:

        for (i = 0; i < 10; i++)
            ;

A compound statement groups statements together in a block, e.g.:

        for (i = 0; i < 10; i++)
        {
            a = test(b);
            b = b + 10;
        }

A statement can be prefixed by a label as in:

        :L001
            for (i = 0; i < 10; i++)
                ;

Labels are the targets of `goto` statements; labels are local to a function and have a separate name space (which means that variables and labels may have the same name). Note that labels are defined in a non-standard way: the colon is prefixed, rather than suffixed as in C or C++.

### Selection statements

The conditional expression in an `if` statement is evaluated, and if it is nonzero (for a matrix: no element is zero), the statement is executed. Note that both the empty matrix (`<>`) and a missing value (`.NaN`) evaluate to false. The conditional expression may not be a declaration statement. Some examples for the `if` statement:

        if (i == 0)
            i++;                           // do only if i equals 0

        if (i >= 0)
            i = 1;                             // do only if i >= 0
        else
            i = 0;                           // set negative i to 0

        if (i == 0)
            if (k > 0)
                j = 1;               // do only if i != 0 and k > 0
            else                  // this else matches the inner if
                j = -1;             // do only if i != 0 and k <= 0

        if (i == 0)
        {   if (k > 0)
                j = 1;               // do only if i != 0 and k > 0
        }
        else                      // this else matches the outer if
            j = -1;                            // do only if i != 0

Each `else` part matches the closest previous `if`, but this can be changed by using braces. When coding nested `if`s, it is advisable to use braces to make the program more readable and avoid potential mistakes.

Further examples involving matrices are given in equality expressions.

### Iteration statements

The `while` statement excutes the substatement as long as the test expression is nonzero (for a matrix: at least one element is nonzero). The test is performed before the substatement is executed.

The `do` statement excutes the substatement, then repeats this as long as the test expression is nonzero (for a matrix: at least one element is nonzero). The test is performed after the substatement is executed. So for the `do` statement the substatement is executed one or more times, whereas for the `while` statement this is zero or more times.

The `for` expression: `for (`init_expr`;` test_expr `;` increment_expr`)` statement corresponds to:

`{`
init_expr`;`
`while (`test_expr `)`
`{`
  statement
  increment_expr`;`
`}`
`}`

Note that, when the init_expr is a declaration statement, the declaration is local to the `for` statement.

### Jump statements

A `continue` statement may only appear within an iteration statement and causes control to pass to the loop-continuation portion of the smallest enclosing iteration statement.

The use of `goto` should be kept to a minimum, but could be useful to jump out of a nested loop, jump to the end of a routine or when converting Fortran code. It is always possible to rewrite the code such that no `goto`s are required.

A `break` statement may only appear within an iteration statement and terminates the smallest enclosing iteration statement.

Two examples:

        for (i = 0; i < 10; i++)
        {
            if (test1(i))
                continue;
            test2();             // only done if test1(i) returns 0
        }
        for (i = 0; i < 10; i++)
        {
            if (test1(i) == 0)
                break;    // jump out of loop if test1(i) returns 0
            test2();
        }

### Declaration statements

Declarations at the external level were discussed before. Here we treat declaration within a block. Declaration statements create a variable for further manipulation as long as it stays within scope. The created object is removed as soon as the block in which it was created is exited. Variables can be intitialized in a declaration statement. Variables in Ox are implicitly typed, and their type can change during program execution. Non-externally declared variables must be initialized before they can be used in an expression. It is not possible to specify matrix dimension as can be done at the external level, so instead of `decl ma[3][3] = 1.5` write `decl ma = constant(1.5,3,3)`. Unlike C, declaration statements do not have to occur at the start of a block. Consider for example:

        test1(arg0)
        {
            decl k, a = arg0;
            decl ident = <1, 0; 0, 1>;
            decl identsq = ident * ident;

            print("test\n");

            decl i, j;
            for (i = 0; i < 10; i++)
            {
                test2(i);
                test3(j);                  // error: j has no value
            }

Variables declared in an inner block hide variables in the outer block.

## Expressions

Operator tables:
Operator precedence
Result from dot operators
Result from relational operators
Result from operators involving an empty matrix as argument
Result from relational operators involving missing values

### Table syn.2: Operator precedence

    Category            operators                     associativity

    primary             () :: []                      left to right
    postfix             -> . () [] ++ -- '            left to right
    power               ^ .^                          left to right
    unary               ++ -- + - ! & new delete      right to left
    multiplicative      ** * .* / ./                  left to right
    additive            + -                           left to right
    horizontal concat.  ~                             left to right
    vertical concat.    |                             left to right
    relational          < > <= >= < > <= >=           left to right
    equality            == != .== .!=                 left to right
    logical dot-and     .&&                           left to right
    logical-and         &&                            left to right
    logical dot-or      .||                           left to right
    logical-or          ||                            left to right
    conditional         ? : .? .:                     right to left
    assignment          = *= /= += -= ~= |= .*= ./=   right to left
    comma               ,                             left to right

Table syn.2 gives a summary if the operators available in Ox, together with their precedence (in order of decreasing precedence) and associativity. The precedence is in decreasing order. Operators on the same line have the same precedence, in which case the associativity gives the order of the operators. Note that the order of evaluation of expressions is not fully specified. In:

        i = a() + b();

it is unknown whether `a` or `b` is called first. Subsections below give a more comprehensive discussion. Several operators require an lvalue, which is a region of memory to which an assignment can be made. Note that an object which was declared `const` is not an lvalue. Many operators require operands of arithmetic type, that is int, double or matrix.

The most common operators are dot-operators (operating element-by-element) and relational operators (operating element by element, but returning a single boolean value). The resulting value is given Tables syn.3 and syn.4 respectively. In addition, there are special matrix operations, such as matrix multiplication and division; the result from these operators is explained below. A scalar consists of: int, double or 1 `x` 1 matrix.

### Table syn.3: Result from dot operators

    left  a        op   right b         result         computes

    int            op   int             int            a op b
    int/double     op   double          double         a op b
    double         op   int/double      double         a op b
    scalar         op   matrix  m x n   matrix m x n   a op b_{ij}
    matrix m x n   op   scalar          matrix m x n   a_{ij} op b
    matrix m x n   op   matrix  m x n   matrix m x n   a_{ij} op b_{ij}
    matrix m x n   op   matrix  m x 1   matrix m x n   a_{ij} op b_{i0}
    matrix m x n   op   matrix  1 x n   matrix m x n   a_{ij} op b_{0j}
    matrix m x 1   op   matrix  m x n   matrix m x n   a_{i0} op b_{ij}
    matrix 1 x n   op   matrix  m x n   matrix m x n   a_{0j} op b_{ij}
    matrix m x 1   op   matrix  1 x n   matrix m x n   a_{i0} op b_{0j}
    matrix 1 x n   op   matrix  m x 1   matrix m x n   a_{0j} op b_{i0}

### Table syn.4: Result from relational operators

    left  a        op   right b         result   computes

    int            op   int             int      a op b
    int/double     op   double          int      a op b
    double         op   int/double      int      a op b
    scalar         op   matrix  m x n   int      a op b_{ij}
    matrix m x n   op   scalar          int      a_{ij} op b
    matrix m x n   op   matrix  m x n   int      a_{ij} op b_{ij}
    matrix m x n   op   matrix  m x 1   int      a_{ij} op b_{i0}
    matrix m x n   op   matrix  1 x n   int      a_{ij} op b_{0j}
    matrix m x 1   op   matrix  m x n   int      a_{i0} op b_{ij}
    matrix 1 x n   op   matrix  m x n   int      a_{0j} op b_{ij}
    string         op   string          int      a op b

### Table syn.5: Result from operators involving an empty matrix as argument

    operator   either argument empty      both arguments empty
    ==               FALSE                        TRUE
    !=               TRUE                         FALSE
    >=               FALSE                        TRUE
    >                FALSE                        FALSE
    <=               FALSE                        TRUE
    <                FALSE                        FALSE
    other            <>                           <>

### Table syn.6: Result from relational operators involving missing values

    operator   either argument .NaN      both arguments .NaN
    ==                0                       1
    !=                0                       1
    >=                0                       1
    >                 0                       0
    <=                0                       0
    <                 1                       0

### Primary expressions

An expression in parenthesis is a primary expression. Its main use is to change the order of evaluation, or clarify the expression.

An expression in curly braces creates an array of the comma-separated expressions.

All types of constants form a primary expression.

The operator `::` followed by an identifier references a variable declared externally. Examples are given. A class name followed by `::` and a function member of that class references a static function member, or any function member if preceded by an object reference.

The `this` reference is only available inside non-static class member functions, and points to the object for which the function was called.

#### Multiple assignment

A comma-separated list of lvalues in square brackets can be used for multiple assignments. When the right-hand side is an array, each array value in turn is assigned to the next value of the left-hand side. The return value of a multiple assignment expression is zero (the examples below illustrate). When there is one lvalue in the square brackets, the right-hand side need not be an array. Few array elements on the right than lvalues on the left leads to a runtime error. The converse is no problem. A multiple assignment expression can be used to implement multiple returns from a function.

The following examples illustrate multiple assignments:

        decl x1, x2, x3, x4, as;
        as = {"a", <10,11>, "b"};
        [x1, x2, x3] = as;
        println("x1=", x1, " x2=", x2, "x3=", x3);

        [x1] = 10;
        [x2, x3] = {11,12,13};
        //[x2, x3, x4] = {11,12};     // error
        println("x1=", x1, " x2=", x2, " x3=", x3);

        x3 = 10 + ([x1, x2] = as[<0,2>]);
        println("x1=", x1, " x2=", x2, " x3=", x3);

        x1=<1,2,3,4>;
        [x1[0], x1[3]] = {-1, -3};
        println("x1=", x1);

Which prints:

        x1=a x2=
               10.000       11.000
        x3=b
        x1=10 x2=11 x3=12
        x1=a x2=b x3=10
        x1=
              -1.0000      2.0000      3.0000     -3.0000

### Postfix expressions

#### Member reference

The `->` operator selects a member from an object reference. The left-hand expression must evaluate to a reference to an object, the right-hand expression must result in a member of that object. See classes.

#### Function calls

A function call is a postfix expression consisting of the function name, followed in parenthesis by a possibly empty, comma-separated list of assignment expressions. All argument passing is by value, but when an array is passed, its contents may be changed by the function (unless they are `const`). The order of evaluation of the arguments is unspecified; all arguments are evaluated before the function is entered. Recursive function calls are allowed. A function must be declared before it can be called, and the number of arguments in the call must coincide with the number in the declaration, unless the declaration has `...` as the last argument.

Some examples:

        func1(a0, a1, a2, a3)
        {   print("func1(", a0, ",", a1, ",", a2, ",", a3, ")\n");
        }
        func2()
        {   return 0;
        }
        func3(a0)
        {   a0[0] = 1;
        }
        test1()
        {   decl a, b;

            a = 1;
            func1(a, b = 10, func2(), a != 0);   // func1(1,10,0,1)
            a = func2();                                   // a = 0
            func3(&a);                                     // a = 1
            func3(a);                                      // error
        }

In the latter example `a` will have been changed by `func3`. Function arguments are passed by giving the name of the function:

        func4(a0, a1)
        {   a1(a0);                           // make function call
        }
        func5(a0)
        {   print("func5(", a0, ")\n");
        }
        test2()
        {   decl a = func5;

            func4(1, func5);                   // prints "func5(1)"
            func4(1, a);                       // prints "func5(1)"
            func4(1, func5(a));         // error: requires function
            func4(1, func2);        // error: func2 takes incorrect
        }                           //          number of arguments

Note that the parentheses in `func5()` indicate that it is a function call, whereas lack of brackets just passes the function itself.

#### Explicit type conversion

Explicit type conversion has the same syntax as a function call, using types `int`, `double`, `matrix` and `string`:

                int     double    matrix        string
                v=0;    v=0.6;    v=<0.6,1>;    v="tinker";
    matrix(v)   <0>     <0.6>     v             <97>
    double(v)   0.0     v         0.6           see below
    int(v)      v       0         0             97

Use `double("tinker")` to store the string in a double value. Since a double is 8 bytes, the string is truncated at 8 characters (or padded by null characters). Conversely, `string(dbl)` extracts the string from a double value `dbl` (a null character is automatically appended). Storing strings in doubles or matrix elements is better avoided: more flexibility is offered by the string type.

#### Indexing vector and array types

Vector types (that is, string or matrix) and array types are indexed by postfixing square brackets. A matrix can have one or two indexes, a string only one. For an array type it depends on the level of indirection. Note that indexing always starts at zero. So a 2 by 3 matrix has elements:

         [0][0]   [0][1]   [0][2]
         [1][0]   [1][1]   [1][2]

Three ways of indexing are distinguished:

    indexing type   matrix, string   array    example
    scalar               yes          yes     m[0][0]
    matrix               yes          yes     m[0][<0,1,2>]
    range                yes          yes     m[][1:]

In the first indexing case (allowed for all non-scalar types), the expression inside square brackets must have scalar type, whereby double is converted to integer.

Vector types may also be indexed by a matrix or have a range expression inside the brackets. In a matrix index to a string the first column of the matrix specifies the selected elements of the string.

It is possible to use only one index to a matrix. If a matrix `x` is a column or row vector, `x[i]` it will pick the ith element from the vector. If `x` is a matrix, it will treat the matrix as a vector (row by row, which corresponds to the `vecr`).

If a matrix is used as an index to a matrix, then each element (row by row, i.e. the `vecr` of the argument) is used as an index. As a consequence, indexing by a column vector or its transpose (a row vector) have the same effect. A matrix in the first index selects rows, a matrix in the second index selects columns. The resulting matrix is the intersection of those rows and columns.

A range index has the form start-index `:` end-index. Either the start-index or the end-index may be missing, which results in the lower-bound or upper-bound being used respectively. An empty index selects all elements. The resulting type from a range or empty index is always a vector type.

Indexing beyond the end will result in a fatal run-time error. An exception is indexing a string for reference: this can be done one position beyond the end, which returns 0. For example, `i=s[sizeof(s)]` sets `i` to 0.

Some examples:

        decl mat = < 0:3; 10:13 >, d, m;
        decl str = "tinkertailor", s;
        decl arr = { "tinker", "tailor", "soldier" };

                                    // mat = <0,1,2,3; 10,11,12,13>
        d = mat[0][0];                                     // d = 0
        d = mat[1][2];                                    // d = 12
        m = mat[1][];                          // m = <10,11,12,13>

        d = m[1];                                       // d = <11>
        d = m'[1];                            // the same: d = <11>
        d = mat[5];                                     // d = <11>

        m = mat[][2];                                // m = <2; 12>
        m = mat[][];                           // same as: m = mat;
        m = mat[0][<1:3>];   // matrix indexes columns: m = <1,2,3>
        m = mat[<1,0,1>][<1,3>];       // m = < 11,13; 1,3; 11,13 >
        mat[0][1:3] = 9;                  // range indexes columns:
                                    // mat = <0,9,9,9; 10,11,12,13>
        s = str[6:11];                              // s = "tailor"
        str[6:11] = 'a';                    // str = "tinkeraaaaaa"
        s = arr[1];                                 // s = "tailor"
        arr[1][0] = 'a';                       // arr[1] = "aailor"

#### Postfix incrementation

A postfix expression followed by `++` or `--` leads to the value of the expression being evaluated and then incremented or decremented by 1. The operand must be an lvalue and must have arithmetic type. For a matrix the operator is applied to each element separately. The result of the expression is the value prior to the increment/decrement operation.

#### Transpose

The postfix operator `'` takes the transpose of a matrix. It has no effect on other arithmetic types of operands. Note that the single quote is also used in a character constant; the context avoids any ambiguity:

        mat = m' * a';
        mat = m'a';                       // interpreted as m' * a'
        mat = m'';                             // two '' cancel out
        mat = m + 'a';               // 'a' is a character constant

### Power expressions

The operands of the power operator must have arithmetic type, and the result is given in the table. If the first operand is not a matrix .^ and ^ are the same.

    left  a      operator  right b        result         computes

    int            ^  .^   int or double  int            a^b
    int/double     ^  .^   double         double         a^b
    double         ^  .^   scalar         double         a^b
    scalar         ^  .^   matrix  m x n  matrix m x n   a^{b_{ij}}
    matrix m x n   .^      int/scalar     matrix m x n   a_{ij}^b
    matrix m x n   .^      matrix  m x n  matrix m x n   a_{ij}^{b_{ij}}
    matrix m x m   ^       scalar         matrix m x m   a^int(b)

When a and b are integers, then `a ^ b` is an integer if b >= 0 and if the result can be represented as a 32 bit signed integer. If b < 0 and a != 0 or the integer result would lead to overflow, the return type is double, giving the outcome of the floating point power operation.

The first line in the example shows that power has higher precedence than unary minus:

        i = - 2 ^ 2;                                      // i = -4
        decl r, m1 = <1,2; 2,1>, m2 = <2,3; 3,2>;
        r = m1 .^ 3;                                  // <1,8; 8,1>
        r = m1 .^ 3.7;                      // <1,12.996; 12.996,1>
        r =  3 .^ m1;                                 // <3,9; 9,3>
        r =  3 ^  m1;                                 // <3,9; 9,3>
        r = m1 .^ m2;                                 // <1,8; 8,1>
        r = m1 ^  3;                              // <13,14; 14,13>
        r = m1 ^  3.7;                            // <13,14; 14,13>
        r = m1 ^  -3;           // equivalent to: r = (1 / m1) ^ 3;
        r = m1 ^  m2;                                      // error

### Unary expressions

#### Prefix incrementation

A prefix expression preceded by `++` or `--` leads to the lvalue being incremented or decremented by 1. This new value is the result of the operation. The operand must be an lvalue and must have arithmetic type. For a matrix the operator is applied to each element separately.

#### Unary minus and plus

The operand of the unary minus operator must have arithmetic type, and the result is the negative of the operand. For a matrix each element is set to its negative. Unary plus is ignored.

#### Logical negation

The operand of the logical negation operator must have arithmetic type, and the result is 1 if the operand is equal to 0 and 0 otherwise. For a matrix, logical negation is applied to each element. Negating a missing value returns 0, and negating an empty matrix returns an empty matrix.

        j = 0;  k = 10;
        i = !j;                                            // i = 1
        i = !k;                                            // i = 0

#### Address operator

The operand of the address operator `&` must be an lvalue. In addition, it must be an object: it is possible to take the address of a class object or a function, but not of an array element, or matrix element. The result is an array of one element, pointing to the region of space occupied by the lvalue. Referencing works through arrays; unlike C and C++ (but like the Java programming language), Ox does not have pointers. Some examples were in the section on function calls.

#### New and delete

The `new` operator can be used to create an object of a class, or to create a matrix, string or array. The `delete` operator removes an object created by `new`. Note that matrices, strings and arrays are automatically removed when they go out of scope. Only one array level at a time can be created by `new`; however, `delete` removes all sublevels. A string created by `new` consists of null characters, a matrix will have all elements zero. Matrix, string and array objects with dimension zero are allowed (this can be useful to start concatenation in an iterative loop; remember that an empty matrix constant is `<>`, and an empty array `{}`). Matrices and arrays can be created with either one or two dimensions.

Examples involving objects of classes are given.

### Multiplicative expressions

The operators `**`, `*`, `.*`, `/`, and `./` group left-to-right and require operands of arithmetic type. These operators conform to Table syn.3, except for:

    left   a     operator  right b        result          computes
    matrix m x n    *      matrix  n x p  matrix m x p    a_{i.}b_{.k}
    matrix m x n    **     matrix  p x q  matrix mp x nq  a_{ij}b
    scalar          *      matrix  n x p  matrix n x p    ab_{ij}
    matrix m x n    *      scalar         matrix m x n    a_{ij}
    matrix m x n    /      matrix  p x n  matrix p x m    a_{i.}b_{.k}^{+}
    scalar          /      matrix  m x n  matrix n x m    ab_{ij}^{+}
    matrix m x n    /      scalar         matrix m x n    a_{ij}/b
    scalar          / ./   scalar         double          a/b

This implies that `* **` are the same as `.*` when one or both arguments are scalar, and similarly for `/` and `./` when the right-hand operand is not a matrix.

Kronecker product is denoted by `**`. If neither operand is a matrix, this is identical to normal multiplication.

The binary `*` operator denotes multiplication. If both operands are a matrix, this is matrix multiplication and the number of columns of the first operand has to be identical to the number of rows of the second operand.

The `.*` operator defines element by element multiplication. It is only different from `*` if both operands are a matrix (these must have identical dimensions, however, if one or both of the arguments is a 1 `x` 1 matrix, `*` is equal to `.*`).

The product of two integers remains an integer. This means that overflow could occur (when it would not occur in operations where one of the argument is a double). For example `5000 * 50000` fits in an integer and yields 250,000,000, but `50000 * 50000` overflows, yielding -1.794,967,296. When using double arithmetic: `50000.0 * 50000` = 2500,000,000.0.

The binary `/` operator denotes division. If the second operand is a matrix, this is identical to post-multiplication by the inverse (if the matrix is square the matrix is inverted using the `invert()` library function; if that fails, or the matrix is non-square, the generalized inverse is used). If the second operand is a scalar, each element of the first is divided by it. If the first operand is a scalar, it is multiplied by the inverse of the second argument.

The `./` operator defines element by element division. If either argument is not a matrix, this is identical to normal division. It is only different from `/` if both operands are a matrix (these must have identical dimensions).

Note that `/` does not support integer division (such as e.g. 3 / 2 resulting in 1). In Ox, the result of dividing two integers is a double (3 / 2 gives 1.5). Integer division can be performed using the `idiv` library function. The remainder operator (`%` in C and C++) is supported through the library function `imod`. Multiplication of two integers returns an integer.

Some examples of multiplication and division involving matrices:

        decl m1 = <1,2; 2,1>, m2 = <2,3; 3,2>;

        r = m1 * 2.;                                  // <2,4; 4,2>
        r = 2. * m2;                                  // <4,6; 6,4>
        r = m1 * m2;                                  // <8,7; 7,8>
        r = m1 .* m2;                                 // <2,6; 6,2>
        r = m1 .* <2,3>;                               // <2,6;6,2>
        r = m1 ** m2;       // <2,3,4,6; 3,2,6,4; 4,6,2,3; 6,4,3,2>
        r = 2 / 3;                                      // 0.666667
        r = 2 / 3.;                                     // 0.666667
        r = m1 / 2.;                              // <0.5,1; 1,0.5>
        r = m1 ./ <2;3>;              // <0.5,1; 0.666667,0.333333>
        r = 2./ m2;                          // <0.8,1.2; 1.2,-0.8>
        r = 2 ./ m2;                    // <1,0.666667; 0.666667,1>
        r = m2 / m2;                      // <1,-2.22045e-016; 0,1>

        r = 1/<1;2>;                                   // <0.2,0.4>
        r = 1/<1,2>;                                  // <0.2; 0.4>
        r = 1/<0,0;0,0>;                              // <0,0; 0,0>

Notice the difference between `2./ m2` and `2 ./ m2`. In the first case, the dot is interpreted as part of the real number `2.`, whereas in the second case it is part of the `./` dot-division operator. The white space is used here to change the syntax (as in the example in transpose); it would be more clear to write the second case as `2.0 ./ m2`. The same difference applies for dot-multiplication, but note that `2.0*m2` and `2.0.*m2` give the same result.

### Additive expressions

The additive operators `+` and `-` are dot-operators, conforming to Table syn.3. Both operators group left-to-right. They respectively return the sum and the difference of the operands, which must both have arithmetic type. Matrices must be conformant in both dimensions, and the operator is applied element by element. For example:

        decl m1 = <1,2; 2,1>, m2 = <2,3; 3,2>;

        r = 2 - m2;                                 // <0,-1; -1,0>
        r = m1 - m2;                              // <-1,-1; -1,-1>

### Concatenation expressions

    left        operator   right           result
    int/double     ~       int/double      matrix 1 x 2
    int/double     ~       matrix  m x n   matrix m x (1+n)
    matrix m x n   ~       int/double      matrix m x (n+1)
    matrix m x n   ~       matrix  p x q   matrix max(m,p) x (n+q)
    int/double     |       int/double      matrix 2 x 1
    int/double     |       matrix  m x n   matrix (1+m) x n
    matrix m x n   |       int/double      matrix (m+1) x n
    matrix m x n   |       matrix  p x q   matrix (m+p) x max(n,q)
    int            ~  |    string          string
    string         ~  |    int             string
    string         ~  |    string          string
    array          ~  |    array           array
    array          ~  |    any basic type  array

If both operands have arithmetic type, the concatenation operators are used to create a larger matrix out of the operands. If both operands are scalar the result is a row vector (for ~) or a column vector (for `|`). If one operand is scalar, and the other a matrix, an extra column (~) or row (`|`) is pre/appended. If both operands are a matrix, the matrices are joined. Note that the dimensions need not match: missing elements are set to zero (however, a warning is printed of non-matching matrices are concatenated). Horizontal concatenation has higher precedence than vertical concatenation.

Two strings or an integer and a string can be concatenated, resulting in a longer string. Both horizontal and vertical concatenation yield the same result.

The result is most easily demonstrated by examples:

        print(1 ~ 2 ~ 3 | 4 ~ 5 ~ 6);             // <1,2,3; 4,5,6>
        print("tinker" ~ '&' ~ "tailor" );       // "tinker&tailor"
        print(<1,0; 0,1> ~ 2);                    // <1,0,2; 0,1,2>
        print(2 | <1,0; 0,1>);                   // <2,2; 1,0; 0,1>
        print(<2> ~ <1,0; 0,1>);                  // <2,1,0; 0,0,1>

The first two lines could have been written as:

        print(<1,2,3; 4,5,6>);
        print("tinker" "&" "tailor" );

In the latter case, the matrix and string are created at compile time, whereas in the former case this is done at run time. Clearly, the compile time evaluation is more efficient. However, only the concatenation expressions can involve non-constant variables:

        decl  i1 = 1, i2 = 2, s1 = "tinke";

        print(i1 ~ i2);                                    // <1,2>
        print(s1 ~ 'r');                                // "tinker"

Array concatenation results in an array with combined size, with assignment of each member of both arrays to the new array.

        decl  i, a1 = {"tinker", "tailor"}, a2 = {"soldier"};

        a1 ~= a2;
        print(a1);

This prints:

        [0] = tinker
        [1] = tailor
        [2] = soldier

Often, concatenation is required in a loop. In that case, it is convenient to start from a matrix of dimension zero, for example:

        decl m, i;

        for (i = 0, m = <>; i < 4; ++i)
            m ~= i;
        print(m);                           // m = <0, 1, 2, 3>

### Relational expressions

The relational operators are `<`, `<=`, `>`, `>=`, standing for `less', `less or equal', `greater', `greater or equal'. They all yield 0 if the specified relation is false, and 1 if it is true. The type of the result is always an integer, see Table syn.4. If both operands are a matrix the return value is true if the relation holds for each element. where it is false. If one of the operands is of scalar-type, and the other of matrix-type, each element in the matrix is compared to the scalar, and the result is true if each comparison is true.

The dot relational operators are `.<`, `.<=`, `.>`, `.>=`, standing for `dot less', `dot less or equal', `dot greater', `dot greater or equal'. They conform to Table syn.3, except when both arguments are a string, in which case the result is as for the non-dotted versions.

If both arguments are scalar, the result type inherits the higher type, so `1 >= 1.5` yields a double with value `0.0`. If both operands are a matrix the return value is a matrix with a 1 in each position where the relation is true and zero where it is false. If one of the operands is of scalar-type, and the other of matrix-type, each element in the matrix is compared to the scalar returning a matrix with 1 at each position where the relation holds.

String-type operands can be compared in a similar way. If both operands are a string, the results is int with value 1 or 0, depending on the case sensitive string comparison. Examples are given in the next section.

### Equality expressions

The `==` (is equal to), `!=` (is not equal to), `.==` (is dot equal to) and `.!=` (is not dot equal to) are analogous to the relational operators, but have lower precedence. The non-dotted versions conform to Table syn.4.

The dotted versions conform to Table syn.3, except when both arguments are a string, in which case the result is as for the non-dotted versions.

For example:

        decl m1 = <1,2; 2,1>, m2 = <2,3; 3,2>, s1 = "tinke";

        print(m1 == 1);                                        // 0
        print(m1 != 1);                                        // 0
        print(!(m1 == 1));                                     // 1
        print(m1 > m2);                                        // 0
        print(m1 < m2);                                        // 1
        print(s1 <= "tinker");                                 // 1
        print(s1 <= "tink"  );                                 // 0
        print(s1 == "tinker");                                 // 0
        print(s1 >= "tinker");                                 // 0
        print(s1 == "Tinke");                                  // 0

        print(m1 .== 1);                               // <1,0; 0,1>
        print(m1 .!= 1);                               // <0,1; 1,0>
        print(m1 .> m2);                               // <0,0; 0,0>
        print(m1 .< m2);                               // <1,1; 1,1>

The non-dotted versions only return true if the relation holds for each element. In the first two examples neither `m1 == 1` nor `m1 != 1` is true for each element, hence the return value 0. The third example shows how to test if a matrix is not equal to a value. The parenthesis are necessary, because `!` has higher precedence than `==`, and `!m1 == 1` results in `<0,0; 0,0> == 1` which is false.

The last four examples use dot-relational expressions, resulting in a matrix of zeros and ones. In `if` statements, it is possible to use such matrices. Remember that a matrix is true if all elements are true (i.e. no element is zero).

The `any` library function evaluates to TRUE if any element is TRUE, e.g.

                        evaluates to         leads to
    if (any(m1 .== 1))  if (any(<1,0;0,1>))  if part
    if (any(m1 .!= 1))  if (any(<0,1;1,0>))  if part
    if (m1 == 1)        if (0)               else part
    if (m1 != 1)        if (0)               else part

### Logical dot-AND expressions

The `.&&` operator returns 1 if both of its operands compare unequal to 0, 0 otherwise. Both operands must have arithmetic type. Handling of matrix-type is as for dot-relational operators: if one or both operands is a matrix, the result is a matrix of zeros and ones. Unlike the non-dotted version, both operands will always be executed. For example, in the expression `func1() .&& func2()` the second function is called, regardless of the return value of `func1()`.

### Logical-AND expressions

The `&&` operator returns the integer 1 if both of its operands compare unequal to 0, and the integer 0 otherwise. Both operands must have arithmetic type. First the left operand is evaluated, if it is false (for a matrix: there is at least one zero element), the result is false, and the right operand will not be evaluated. So in the expression `func1() && func2()` the second function will not be called if the first function returned false.

### Logical dot-OR expressions

The `.||` operator returns 1 if either of its operands compares unequal to 0, 0 otherwise. Both operands must have arithmetic type. Handling of matrix-type is as for dot-relational operators: if one or both operands is a matrix, the result is a matrix of zeros and ones. Unlike the non-dotted version, both operands will always be executed. For example, in the expression `func1() .|| func2()` the second function is called, regardless of the return value of `func1()`.

### Logical-OR expressions

The `||` operator returns the integer 1 if either of its operands compares unequal to 0, integer value 0 otherwise. Both operands must have arithmetic type. First the left operand is evaluated, it it is true (for a matrix: no element is zero), the result is true, and the right operand will not be evaluated. So in the expression `func1() .|| func2()` the second function will not be called if the first function returned true.

### Conditional expression

Both the conditional and the dot-conditional expression are ternary expressions. For the conditional expression, the first expression (before the `?`) is evaluated. If it is unequal to 0, the result is the second expression, otherwise the third expression.

The dot-conditional expression only differs from the conditional expression if the first expression evaluates to a matrix, here called the test matrix. In that case the result is a matrix of the same size as the test matrix, and the test matrix can be seen as a filter: non zero elements get a value corresponding to the second expression, zero elements corresponding to the third expression. If the second or third expression is scalar, each matrix element will get the appropriate scalar value. If it is a matrix, the corresponding matrix element will be used, unless the matrix is too small, in which case the value 0. will be used. Note that in the dot-conditional expression both parts are executed, whereas in the conditional expression only one of the two parts is executed.

        decl r, m2;

        r = <1,0; 0,1> ? 4 : 5;  // 5, matrix is true if no element is 0
        r = <1,0; 0,1> .? 4 .: 5;                          // <4,5; 5,4>
        m2 = <1>;
        r = r .== 4 .? m2 .: 0;                            // <1,0; 0,0>

### Assignment expressions

The assignment operators are the `= *= /= += -= ~= |= .*= ./=` symbols. An lvalue is required as the left operand. The type of an assignment is that of its left operand. The combined assignment l op`=` r is equivalent to l `=` l op (r).

If the left-hand side is a comma-separated list in square brackets, the statement is a Multiple assignment expression.

The following code:

        decl i, k;
        for (i = 0, k = 1; i < 5; i += 2)
            k *= 2, print("i = ", i, " k = ", k, "\n");

writes:

        i = 0 k = 2
        i = 2 k = 4
        i = 4 k = 8

### Comma expression

A pair of expressions separated by a comma is evaluated left to right, and the value of the left expression is discarded. The result will have type and value corresponding to the right operand. The example in the previous section has two instances of the comma operator in the for loop: `i = 0, k = 1`.

### Constant expressions

An expression that evaluates to a constant is required in initializers and certain preprocessor expressions. A constant expression can have the operators `* / + -`, but only if the operands have scalar type. Some examples were given in sections on enumerations and external declarations.

## Preprocessing

Preprocessing in Ox is primarily used for inclusion of files and conditional compilation of code. As such it is more restricted than the options available in C or C++. Escape sequences in strings literals are interpreted when used in preprocessor statements.

### File inclusion

A line of the form

    #include "filename"

will insert the contents of the specified file at that position. The file is searched for as follows:

- in the directory containing the source file (if just a filename, or a filename with a relative path is specified), or in the specified directory (if the filename has an absolute path);
- the directories specified on the compiler command line (if any);
- the directories specified in the `OX3PATH` environment string (if any).
- in the current directory.

A line of the form

    #include <filename>

will skip the first step, and search as follows:

- the directories specified on the compiler command line (if any);
- the directories specified in the `OX3PATH` environment string (if any);
- in the current directory.

The quoted form is primarily for inclusion of user created header or code files, whereas the second form will be mainly for system and library files. Note that escape sequences are interpreted in the include string, but not in the version which uses `<`...`>` (so in `#include "dir\nheader.h"`, the `\n` is replaced by a newline character). Both forward and backslashes are allowed (use `#include "dir/nheader.h"`, to avoid the newline character).

### Import of modules

The `#import` preprocessor statement makes it easier to import compiled code modules. The statement can only happen at the external level, and has the form:

`#import <`modulename`>`

For example

`#import <pcnaive>`

has the following effect:

`#include <pcnaive.h>`
The header file is inserted at that location.
link the `pcnaive.oxo` file when the program is run, or if this is not found:
compile and link the `pcnaive.ox` file when the program is run.

Similarly:

`#import "pcnaive"`

has the following effect:

`#include "pcnaive.h"`
The header file is inserted at that location.
link `pcnaive.oxo` (or `pcnaive.ox` if the `.oxo` file is not found) when the program is run.

The import statement marks the file for linking, but that linking only happens when the file is executed. Even when a module is imported multiple times, it will only be linked in once. Similarly, the header file will not be included more than once in the same source code file. When a relative path is included, that path will be searched when trying to find a DLL or loading a data file into Ox. If the import name ends in a backward/forward slash, no header file is included, but the path will be searched.

### Conditional compilation

The first step in conditional compilation is to define (or undefine) identifiers:

`#define` identifier
`#undef` identifier

Identifiers so defined only exist during the scanning process of the input file, and can subsequently be used by `#ifdef` and `#ifndef` preprocessor statements:

`#ifdef` identifier
`#ifndef` identifier
`#else`
`#endif`

As an example, consider the following header file:

        #ifndef OXSTD_INCLUDED
        #define OXSTD_INCLUDED

        // header statements

        #endif

Now multiple inclusion of the header file into a source code file will only once include the actual header statements; on second inclusion, `OXSTD_INCLUDED` will be defined, and the code skipped.

### Pragmas

Pragmas influence the parsing process of the Ox compiler. Pragmas may only occur at the level of external declarations. Defined is:

`#pragma array_base(`integer`)`

As discussed at various points, indices in matrices, arrays and strings always start at 0. This is the C and C++ convention. Ox, however, allows circumventing this convention by using the `array_base` pragma. Library functions which return a set of indices, are aware of the `array_base` settings, and will return appropriate values. It is recommended to adopt the zero-based convention, and not use the `array_base` pragma.

## Difference with ANSI C and C++

This section lists some of the differences between Ox and C/C++ which might cause confusion:

- /* */ type comments can be nested in Ox.
- `sizeof` is a function in Ox, not an operator (and not a reserved word).
- Labels (targets of `goto` statements) have the colon prefixed, rather than suffixed.
- All data members of a class are private, all function members public.
- The base class constructor and destructor functions are not called automatically.
- Integer division is not used, so `1 / 2` yields 0.5, instead of 0. Use `idiv(1, 2)` for integer division of 1 by 2.
- The preprocessor does not allow: `#define XXX value`, for integer constants, `enum`s could be used, but more convenient is: `const decl XXX = value;`.

Ox version 3.00. © JA Doornik This file last changed
.