Contents

Preliminaries
Initial Definitions
Statement
    Declaration Statement
        Object
            Constructor
            Common Member
        Method Prototype
        Function Prototype
    Definition Statement
        Namespace
        Type Constructors
            Class
            Struct
            Task
            Frame
            Module
                Native Class Module
                Native Task Module
                Foreign Module
            Union
            Bitfields
            Enumeration
            Collection
            Function Type
        Typedef
        Function Definition
        Template Pattern
        Template Type
        Template Typedef
        Graphical Interface
    Plain Statement
        Expression
           Identifier
            Constructor
            Cast
            New
            Size
            Operator
            Call
            Conditional
            Signal
            Hear
        Action
            Jump
                Return
                Break
                Continue
                Resume
                Repeat
            Delete
            Destroy
            Raise
            Signal
            Tell
            Using
            Endusing
        Database
            Select
            Fetch
            Free
            Insert
            Update
            Remove
    Control Statement
        If
        Switch
        Select
        For
        Do
        While
        Exception Layer

Operator Associativity and Precedence

Preliminaries

A program consists of one or more source files. The notion of space is with regard to Linker's view of a program.

The global space (of a program) is the disjoint union of an unnamed space and possibly one or more named spaces. When the set of named spaces is empty, the unnamed space coincides with the global space. The latter case is the reason for referring to the unnamed space as the global space. We will continue to use the term unnamed space for clarity.

Each source file intersects the unnamed/named spaces of the program they constitute. This intersection is called the file space. Compiler's view of space is limited to file space of the file it is compiling. Clearly, Linker's global space is the union of all the file spaces of source files in a program. For instance, the union of unnamed spaces of all files spaces covers the Linker's unnamed space.

The unnamed space is always present. In particular, the definitions of named spaces, as well as the entry points of a program, must appear in the unnamed space.

An engineer writes a program very much the same way a story or a novel is written. Therefore, an important measure of the kinds of stories that an engineer can write is the variety of statements in the language (as well as parts of a statement, such as expressions). The first rule (repeated here) enumerates the kinds of statement.

statement --->>> +--> declaration-statement ---+--->
                 |                             |
                 +--> definition-statement ---->
                 |                             |
                 +--> plain-statement --------->
                 |                             |
                 +--> control-statement ------->

A space (named/unnamed) can only contain statements of kind definition-statement and declaration-statement. In fact, a definition-statement can only appear in a space (named/unnamed).

We will use the term space to mean either the unnamed space or a specific named space.

Consider the definition of a class type as a representative for defining any type. The part of definition between 'class' and 'end' is usually understood as the definition of the class type. So, we know this part must appear in a space. What we call the implementation of a class is actually the definitions of its methods. So, the implementation of a class must also appear in the same space. This is not an issue when the program consists of a single file.

However, when a program consists of several source files, only one of the files can contain the implementation of the class. Compare this to an extern object. An extern object can only be initialized in one of the files. The initialization of an extern object is equivalent to providing the implementation of a class. Thus, all class definitions in files that do not contain the class implementation are implicitly extern. Implicit extern could have been applied to objects as well. However, historically it was allowed to use the same identifier for objects in the unnamed (global) space of different source files, without any connection among those objects. As mentioned earlier, we are retaining this usage, for the entire global space (named/unnamed).

In any space (named/unnamed) the Linker only considers the identifier for a type. That means, all class definitions in all files of a program must be identical. Verification of this matter takes a great deal of Linker's time, and is not done. However, it is an extremely unlikely error to use another definition for the same class in a different file. In particular, if it is really a different class, the implementation must also be provided, in which case Linker will trap that as a redefinition of the same type.

The order of initializing and extern object and using it is insignificant. Consider the following statements.

extern int i;
int j = i;

Eventually the Linker will visit something like "int i = 7" in some file, otherwise you will get an error. The integer j will be correctly initialized to 7, regardless of, in which file the Linker finds the definition "int i = 7". This is true for user-defined types, like class.

Initial Definitions

The symbol <<<>>> defines a terminal. That is, the string on the left of the symbol is a terminal being defined by the right of the symbol. For definition of none-terminals we use the symbol

--->>>

Terminals of grammar are shown in all upper-case letters. However, Z++ keywords are in lower case. Terminals that are keywords are shown as BOLD. For instance, the terminal PUBLIC is the Z++ keyword public.

Z++ Compiler is case-sensitive. By a LETTER (of alphabet) we mean either an upper-case letter from 'A' to 'Z', or a lower-case letter from 'a' to 'z'.

A DIGIT is one of decimal digits from '0' to '9'.

The under-score symbol '_' is obtained by holding shift key down and pressing the minus sign. To avoid confusion, we show '_' with terminal UNDERSCORE.

Names of types, objects, namespaces, etc. are referred to as IDENTIFIER.


IDENTIFIER <<<>>> LETTER --+-----------------------------+---> | | +--+--+--> LETTER ------+--+--> ^ | | | | +--> DIGIT -------> | | | | | | +--> UNDERSCORE --> | | | <-----------------------+

Remark. A preprocessor identifier can also begin with any number of UNDERSCORE.

A literal value of any type, in general, is called a LITERAL.

DISCRETE-NUMERIC is a LITERAL of numeric types without a decimal point.

NUMERIC-LITERAL is either a DISCRETE-NUMERIC, or contains a decimal point. A NUMERIC-LITERAL may begin with + or - signs.

Literal values presented in the definition of an enumeration type are called ENUM-LITERAL, and must begin with UNDERSCORE.

ENUM-LITERAL <<<>>> UNDERSCORE ---> IDENTIFIER

A CHAR-LITERAL is an ASCII charactor (on a typewriter) between single-quotes. Thus, 'A' is a CHAR-LITERAL. With ECSAPE-CHARACTER, a CHAR-LITERAL will have two charactors. For instance, the new-line charator is: '\n'. Special charactors are also indicated with ECSAPE-CHARACTOR: '\'' is just the quote charactor, and '\"' is the double-quote charactor.

A STRING-LITERAL is a sequence of ASCII charactors, between double-quotes. For instance, "A%&k=}" is a STRING-LITERAL. In a STRING-LITERAL, the ECSAPE-CHARACTOR has its usual meaning, same as it does for CHAR-LITERAL. However, the single-quote in a STRING-LITERAL does not need the ECSAPE-CHARACTOR.

QUOTE <<<>>> the symbol ' as in '\''

DOUBLE-QUOTE <<<>>> '"'

COLON <<<>>> ':'

SEMI-COLON <<<>>> ';'

COMMA <<<>>> ','

DOT <<<>>> '.'

LESS <<<>>> '<'

MORE <<<>>> '>'

RESOLVER <<<>>> "::"

ARROW <<<>>> "->"

DOUBLE-ARROW <<<>>> "->>"

Remark. DOUBLE-ARROW is for reaching a base of a pointer to an object, similar to the ARROW for reaching a member.


BACK-ARROW <<<>>> "<-"

Remark. BACK-ARROW is for signaling.



BELONG-OPERATOR <<<>>> +---> MEMBER-OPERATOR ---+--> | | +---> BASE-OPERATOR -----> MEMBER-OPERATOR <<<>>> +--> DOT ------------+---> | | +--> ARROW ----------> BASE-OPERATOR <<<>>> +--> RESOLVER -------> | | +--> DOUBLE-ARROW --->

There are two literal values for the boolean type: TRUE, FALSE. The actual literal values in a Z++ program are 'True' and 'False'.

Statement

statement --->>> +--> declaration-statement ---+--->
                 |                             |
                 +--> definition-statement ---->
                 |                             |
                 +--> plain-statement --------->
                 |                             |
                 +--> control-statement ------->



statement-block --->>> --+---+--> declaration-statement ---+---+--->
                         ^   |                             |   |
                         |   +--> plain-statement --------->   |
                         |   |                             |   |
                         |   +--> control-statement ------->   |
                         |                                     |
                         <-------------------------------------+


Remark. A statement-block is a subspace which allows declarations. For instance the body of a function is a statement-block. An object declared in a statement-block is said to have the scope of the subspace in which it is declared. Specifically, within the subspace, its identifier overlays all identical identifiers is spaces that contain that subspace. statement-blocks can be nested to any depth. For instance legs of a control-statement are themselves statement-blocks.

plain-statement --->>> +---> expression-statement ---+--->
                       |                             |
                       +---> action-statement ------->
                       |                             |
                       +---> database-statement ----->


Declaration


declaration-statement --->>> +---> object-declaration --+--> SEMI-COLON
                             |                          |
                             +---> method-prototype ---->
                             |                          |
                             +---> function-prototype -->


object-declaration --->>> +-------> regular-declaration --------+---> | | +-----> constructor-declaration ------> | |
+---> common-member-initialization --->
regular-declaration --->>> declaration-head --+--> declaration-body --+--> | | <------- COMMA <--------+ declaration-head --->>> +------------------------------+--> declaration-type ----> | | +---> EXTERN ---+--------------> | | | +---------------+---> CONST ---> declaration-type --->>> --+--> scope-space ----> defined-type --------+--> | | +------------> instantiated-type -----------> | | +------------> fundamental-type ------------>


Remark. defined-type is the type-name appearing in one of previously visited forms of type-definition statements.


fundamental-type --->>> --+---> CHAR -----+---> | | +---> UCHAR ----> | | +---> SHORT ----> | | +---> USHORT ---> | | +---> INT ------> | | +---> UINT -----> | | +---> LONG -----> | | +---> ULONG ----> | | +---> FLOAT ----> | | +---> DOUBLE ---> | | +---> STRING ---> | | +--> BOOLEAN ---> | | +---> MUTEX ---->

Remark. void is also a built-in type, shown as VOID in rules. Objects of type void cannot be created.



<-------------------------------+
| |
+--+--> space-name ---> RESOLVER --+-->
| |
scope-space --->>> +-+-------------------------------------+--+-->
| |
+----------------> RESOLVER -------------->


Remark. RESOLVER, by itself, indicates the unnamed space portion of global space. space-name is an IDENTIFIER, name of a defined namespace.

declaration-body --->>> +----------+---+-----------+--> object-name ---> declaration-tail --->
                        |          |   |           |
                        +-+-> * -+->   +---> & ----> 
                          |      |
                          <------+

Remark. object-name is an IDENTIFIER.

declaration-tail --->>> -+-----------------------+--+-------------------+-->
                         |                       |  |                   |
                         +--> array-modifier ---->  +--> initializer --->


array-modifier --->>> +--> [ ---> array-index ---> ] --+--+----------+--+----------+--->
                      |                                |  |          |  |          |
                      <--------------------------------+  +-+-> * -+->  +---> & --->
                                                            |      |
                                                            <------+


array-index --->>> +------------------------+---->
                   |                        |
                   +---> DISCRETE-NUMERIC--->
                   |                        |
                   +---> DECLARED-OBJECT --->


Remark. The empty case is for degenerate array kind. DECLARED-OBJECT is an IDENTIFIER for a previously declared object.

initializer --->>> expression-statement


Remark. Array of references is not permissible. However, a reference to an array is allowed, in which case the reference symbol & must come after array index. A reference always requires an initializer.


constructor-declaration --->>> declaration-type ---> object-name ---> ( --+--> argument --+--> ) ---> | | <--- COMMA -----+ argument --->>> expression-statement

Remark. A constructor declaration requires arguments. The default constructor is invoked via regular declaration, without the use of ().

Examples

// Below, k is a reference to j, p points to k, q is a reference to p.

int i = 5, j = i + 2, &k = j, *p = &k, *&q = p;

// The following three declarations are equivalent.

double d = 4.7;
double d = double(4.7);
double d(4.7);  // constructor declaration

short s; // default initializer is 0

// Below, all cells of static array a are initialized to 97.
// r is a reference to array a, and q points to r.

int a[2][3] = 97, r[2][3]& = a, q[2][3]* = &r;

// Operator [] has higher priority than *. So, to output a cell use parentheses.
// Otherwise, you will be derefencing the cell at [0][1], instead of the array.

output << (*q)[0][1] << '\n';

// Reference and pointer to a dynamic array must be degenerate, without dimensions.

int m = 3, n = 5;
int a[m][n] = 97, r[][]& = a, p[][]* = &r, q[][]*& = &r;

// q is a reference to a pointer to an array. So, at the end, it is a pointer
// to an array, making the use of parentheses necessary as previous example.

output << (*q)[0][1] << '\n';

// For a none-trivial constructor declaration, consider the following definition.

struct example
	int* p;

	example(int*);
end;

// Below is a constructor declaration, using new.

example e(new int(7));


Definition Statements


definition-statement --->>> +--> namespace-definition ---+-->
| |
+--> entity-definition ------>


entity-definition --->>> +--> type-definition ----------------->
| |
+--> typedef-definition -------------->
| |
+--> function-definition ------------->
| |
+--> pattern-definition -------------->
| |
+--> template-type-definition -------->
| |
+--> template-function-definition ---->
| |
+--> template-typedef-definition ----->
| |
+--> graphical-interface-definition -->


Remark. A definition-statement can only appear in global space. More specifically, namespace-definition can only appear in the unnamed global space, while entity-definition can also apear in a named space. Basically, namespace definitions cannot be nested.


NameSpace

A namespace definition can also include the definition of functions and methods.It is also possible to split the definition of a namespace, and put the definition of functions and methods in the implementation part of a namespace. This is useful when a project consists of several source files which use the same namespace. In that case the implementation part of namespace needs to be included in only one of the source files.

namespace-definition --->>> +--> namespace-main-definition ---------------+---->
                            |                                             |
                            +--> namespace-implementation-definition ----->

namespace-main-definition --->>> --+----------------+--> NAMESPACE --> namespace-name --+---------------------------+--> namespace-body --> ENDSPACE --> SEMI-COLON
                                   |                |                                   |                           |
                                   +--> PROTECTED -->                                   +--> namespace-derivation -->



Remark. namespace-name is an IDENTIFIER for name of namespace being defined. A protected namespace can only be derived from. It cannot be opened directly.

namespace-derivation --->>> COLON --+--+------------------------+--> previously-defined-namespace --+-->
| | | |
| +--> derivation-access --> |
| |
<-------------------- COMMA <---------------------------------+


derivation-access --->>> +--> PRIVATE -----+---> | | +--> PUBLIC ------>

Remark. previously-defined-namespace is an IDENTIFIER, for namespace-name of an already defined namespace. Default derivation-access is public.


namespace-body --->>> ---+--+---> declaration-statement --+--+--->
^ | | |
| +---> entity-definition ------> |
| | | |
| +---> access ---> COLON ------> |
| |
<-----------------------------------+


access --->>> +--> PRIVATE -----+---> | | +--> PROTECTED ---> | | +--> PUBLIC ------>

Remark. Default access for namespace is public.



namespace-implementation-definition --->>> IMPLEMENTATION --+-------------------------+--> namespace-name ---> implementation-body --> ENDSPACE --+-------------------------+--> SEMI-COLON
| | | |
+--> LESS TEMPLATE MORE --> +--> LESS TEMPLATE MORE -->


Remark. namespace-name is the IDENTIFIER that appeared as namespace-name in namespace-main-definition for this namespace. When the implementation of a namespace contains template definitions, it takes the form: implementation<template> ... endspace<template>;


implementation-body --->>> --+--+--> function-definition ------------+--+--->
| | | |
| +--> template-function-definition ---> |
| |
<------------------------------------------+

Type Constructors

A type constructor is a mechanism for defining new types. For instance, class, task etc. are type constructor mechanisms.

Function types are defined via prototype mechanism.


type-definition --->>> +--> class-definition ---------+---> END --+---> SEMI-COLON
                       |                              |           ^
                       +--> struct-definition -------->           |
                       |                              |           |
                       +--> task-definition ---------->           |
                       |                              |           |
                       +--> frame-definition --------->           |
                       |                              |           |
                       +--> module-definition -------->           |
                       |                              |           |
                       +--> union-definition --------->           |
                       |                              |           |
                       +--> bitfields-definition ----->           |
                       |                                          |
                       +--> enumeration-definition --------------->
                       |                                          |
                       +--> collection-definition ---------------->
| |
+--> function-type-definition ------------->


class-definition --->>> CLASS --> type-name --+-----------------+-> class-body -->
                                              |                 |
                                              +--> derivation -->
 

Remark. type-name is an IDENTIFIER for name of the type being defined.

derivation --->>> COLON --+--+------------------------+--> declaration-type --+-->
                          |  |                        |                       |
                          |  +--> derivation-access -->                       |
                          |                                                   |
                          <---------------------  COMMA  <--------------------+


Remark. Default derivation-access is public.


class-body --->>> --+---+----------------------------+--+--->
                    ^   |                            |  |
                    |   +---> access ---> COLON ----->  |
                    |   |                            |  |
                    |   +---> class-method ---------->  |
                    |   |                            |  |
                    |   +---> type-member ----------->  |
                    |   |                            |  |
                    |   +---> invariant-statement --->  |
                    |                                   |
                    <-----------------------------------+



Remark. Default access for class is private.

type-member --->>> +--> regular-member --+-->
                   |                     |
                   +--> friend-member --->
                   |                     |
                   +--> common-member --->



regular-member --->>> member-head ---> declaration-type --+----------+--> member-name --> member-tail --> SEMI-COLON
                                                          |          |
                                                          +-+-> * -+->
                                                            |      |
                                                            <------+

member-head --->>> --+------------+-->
                     |            |
                     +--> CONST -->

Remark. member-name is an IDENTIFIER for the name of a data member of the type being defined.

member-tail --->>> --+-------------------+--+------------------------------+--->
                     |                   |  |                              |
                     +--> member-array -->  +-----> LESS VISIBLE MORE ----->
 

Remark. A private/protected visible member can be accessed as read-only.

member-array --->>> +--> [ ---> member-array-index ---> ] --+--+----------+--->
                    |                                       |  |          |
                    <---------------------------------------+  +-+-> * -+->
                                                                 |      |
                                                                 <------+

member-array-index --->>> +------------------------+---->
                          |                        |
                          +---> DISCRETE-NUMERIC -->


Remark. Dynamic array members use empty index, [], for each dimension. A dynamic array member must be initialized via constructors. In presence of dynamic array members, Compiler requires constructors to be defined by user.

friend-member --->>> FRIEND --> regular-member


Remark. Methods of a friend member have the same access permission as methods of the type being defined.



common-member --->>> COMMON --> regular-member --+-----------------------------------+---> | | +--> COLON --> authorized-methods --> authorized-methods --->>> --+--> pure-prototype --+--> | | <------- COMMA -------+

Remark. A common member is shared by all instances of the type. A common member can only be modified by an authorized method. Thus, if no authorized method is listed for a common member, it is implicitly constant. A common member cannot be public. A common member cannot be initialized/destroyed by an instance of the type.

common-member-initialization --->>> declaration-type ---> common-name = ---> initializer --->

common-name --->>> scope-space ---> type-name ---> RESOLVER ---> member-name --->

Remark. member-name is IDENTIFIER for name of common member, and type-name is IDENTIFIER for the name of type that owns the common member.
A common member is destroyed when the global space ends. However, when a common member is dynamically initialized, it must be deleted/destroyed explicitly.
The rule common-member-initialization is not needed. However, it shows common-name more clearly.


Example

#include<iostream.h>
using namespace ioSpace;

// Put definitions in a namespace

namespace CommonSpace

// CommonBase has two simple common members

class CommonBase
common int dc<visible> : changeCommon(int);
double d<visible>;
common int* cptr<visible> : changePtr(int*);

public:

CommonBase(double);
void changeCommon(int);
void changePtr(int*);

end;

// CommonOwner has CommonBase as a common member

class CommonOwner

common CommonBase cbm<visible>;
double d;

public:

CommonOwner(double);
void changeCommon(int);
end;

// Definitions of methods

CommonOwner::CommonOwner(double b)
d = b;
end;

CommonBase::CommonBase(double b)
d = b;
end;

void CommonBase::changeCommon(int b)
dc = b;
end;

void CommonBase::changePtr(int* p)
cptr = p;
end;

void CommonOwner::changeCommon(int b)
cbm.changeCommon(b);
end;

// Initializing common members inside namespace

int CommonBase::dc = 47;
int* CommonBase::cptr = new int(7);

endspace;

// Initializing common member outside of namespace

CommonSpace::CommonBase CommonSpace::CommonOwner::cbm = CommonSpace::CommonBase(44.77);

//---------------------------------------------------------------------------//

entry void main(void)

output << "Hello World!\n";

output << CommonSpace::CommonOwner(13.5).cbm.dc << '\n';

CommonSpace::CommonOwner(1.5).changeCommon(97);

int cmn = CommonSpace::CommonOwner(13.5).cbm.dc;
output << cmn << '\n';

CommonSpace::CommonOwner CC(13.5);

output << *CC.cbm.cptr << '\n';

delete CommonSpace::CommonBase::cptr;

output << "Good-bye World!\n";

end;

output of program is:

Hello World!
47
97
7
Good-bye World!



invariant-statement --->>> INVARIANT ( --> boolean-expression --> ) --> violation-action --> SEMI-COLON

Remark. boolean-expression is an expression-statement that results in an object of type boolean.
boolean-expression for invariant-statement must involve members of class.

struct-definition --->>> STRUCT --> type-name --+----------------+-> class-body -->
                                                |                |
                                                +-> derivation -->


Remark. The only difference between struct and class is that the default access for struct is public.

task-definition --->>> TASK --> type-name --+-----------------+--> task-body -->
                                            |                 |
                                            +--> derivation -->


task-body --->>>  -+---+----------------------------+--+--->
                   ^   |                            |  |
                   |   +---> access ---> COLON ----->  |
                   |   |                            |  |
                   |   +---> task-method ----------->  |
                   |   |                            |  |
                   |   +---> type-member ----------->  |
                   |   |                            |  |
                   |   +---> invariant-statement --->  |
                   |   |                            |  |
                   |   +---> accepts-list ---------->  |
                   |   |                            |  |
                   |   +---> hears-list ------------>  |
                   |                                   |
                   <-----------------------------------+


Remark. Default access for task is private.


frame-definition --->>> FRAME --> type-name --> :=  canvas-name --+-----------------+-> frame-body -->
                                                                  |                 |
                                                                  +--> derivation -->

frame-body --->>> --+---+----------------------------+--+--->
                    ^   |                            |  |
                    |   +---> access ---> COLON ----->  |
                    |   |                            |  |
                    |   +---> frame-method ---------->  |
                    |   |                            |  |
                    |   +---> type-member ----------->  |
                    |   |                            |  |
                    |   +---> invariant-statement --->  |
                    |                                   |
                    <-----------------------------------+


Remark. Default access for frame is private. A frame must have an instinct method. canvas-name is IDENTIFIER for the name of canvas associated with the frame being defined.


module-definition --->>> +---> native-class-module --+--->
                         |                           |
                         +---> native-task-module --->
                         |                           |
                         +---> foreign-module ------->



native-class-module --->>> +--> CLASS ---+--> type-name --> native-module-head -+-----------------+-> native-class-module-body -->
                           |             |                                      |                 |
                           +--> STRUCT -->                                      +--> derivation -->
native-task-module --->>> TASK --> type-name --> native-module-head -+-----------------+-> native-task-module-body --> | | +--> derivation --> native-module-head --->>> = ---> module-path --+---------------------+---> | | +--> execution-node --> module-path --->>> DOUBLE-QUOTE ---+------------------------+---> FULL-PATH-FILE-NAME ---> DOUBLE-QUOTE --> | | +--> ZPP://IP-ADDRESS/ -->

Remark. In "ZPP://IP-ADDRESS/" for module-path, the ZPP is not case-sensitive. IP-ADDRESS is location of node we wish to communicate with. FULL-PATH-FILE-NAME is relative to the node on which the module executable resides.


execution-node --->>>  LESS  ---+---> LOCAL ---+--->  MORE  --->
                                |              |
                                +---> REMOTE -->



Remark. Default for execution-node is local. execution-node is the node on which module executable will begin execution as a process of that node. Thus, module-path is the location of executable as a file, while execution-node is where the file will be loaded as a process.

The execution-node only makes sense when module-path conatains an IP-ADDRESS. In that case, local execution means downloading the executable to the local node and starting it as a local process. On the other hand, remote execution means that the remote node which has the executable, will load the executable as a (remote) process.



native-class-module-body --->>> --+---+----------------------------------+--+--> ^ | | | | +---> access ---> COLON -----------> | | | | | | +---> native-class-module-mthod ---> | | | | | | +---> type-member -----------------> | | | | | | +---> invariant-statement ---------> | | | <-----------------------------------------+ native-task-module-body --->>> --+---+----------------------------------+--+--> ^ | | | | +---> access ---> COLON -----------> | | | | | | +---> native-task-module-method ---> | | | | | | +---> type-member -----------------> | | | | | | +---> invariant-statement ---------> | | | <-----------------------------------------+

foreign-module --->>> +---> dynamic-module ---+--->
                      |                       |
                      +---> static-module ---->


dynamic-module --->>> +--> CLASS ---+--> type-name --> dynamic-module-head -+-----------------+-> dynamic-module-body -->
                      |             |                                       |                 |
                      +--> STRUCT -->                                       +--> derivation -->


dynamic-module-head --->>> foreign-specification --> load-specification --> = --> FOREIGN-LIBRARY -->


Remark. FOREIGN-LIBRARY is full-path filename to the DLL or Loadable-module to link with. It is a string literal between quotes, as in "library-name.dll".

 

foreign-specification --->>> +--> "C++" ----+--->
                             |              |
                             +--> "UNIX" --->


Remark. foreign-specification indicates the language and kind of dynamic library to link with. Currently the foreign language is C/C++. "C++" means link with DLL, and "UNIX" means link with loadable modules.

load-specification --->>> ---+----------------------------------+--->
                             |                                  |
                             +--> GENERATED --+----------------->
                                              |                 |
                                              +--> PERSISTENT -->


Remark. persistent means, load the library once, as opposed to each call to an external method. Then library is unloaded when representing object goes out of scope. generated in this context tells the compiler not to regenerate the Z++ equivalent module for the foreign dynamic library being linked with. The order of generated and persistent is not significant.


dynamic-module-body --->>> generated-statement ---> foreign-module-body --->


generated-statement --->>> GENERATED ---> LIBRARY-PATH-NAME ---> SEMI-COLON


Remark. LIBRARY-PATH-NAME is full-path and name of library (without file extension) in target language to be generated by Z++ Compiler. For instance, if linkage is with a C++ DLL, do not include the ".dll" in filename. The Z++ Compiler will add file extension as needed. LIBRARY-PATH-NAME is a string literal between quotes, as in "path-name".


foreign-module-body --->>> --+---+---------------------------------+--+-->
                             ^   |                                 |  |
                             |   +---> access ---> COLON ---------->  |
                             |   |                                 |  |
                             |   +---> foreign-module-method ------>  |
                             |   |                                 |  |
                             |   +---> type-member ---------------->  |
                             |   |                                 |  |
                             |   +---> invariant-statement -------->  |
                             |                                        |
                             <----------------------------------------+


static-module --->>> +--> CLASS ---+--> type-name --> static-module-head --+-----------------+--> static-module-body -->
                     |             |                                       |                 |
                     +--> STRUCT -->                                       +--> derivation -->


static-module-head --->>> load-specification ---> STATIC --->


Remark. The order of generated, persistent and static is not significant.


static-module-body --->>> --+------------------------+---> foreign-module-body ---> | | +--> library-statement --> library-statement --->>> LIBRARY --+--> FOREIGN-HEADER ---+--> SEMI-COLON | | <------- COMMA ------+


Remark. An example of FOREIGN-HEADER is "math.h".

Union

union-definition --->>> UNION ---> type-name --> union-members ---> union-tail --->


union-members --->>> --+--> member-type ---> member-name ---> SEMI-COLON --+-->
                       |                                                   |
                       <---------------------------------------------------+


union-tail --->>> --+--+------------------------+--+-->
                    |  |                        |  |
                    |  +--> access --> COLON --->  |
                    |  |                        |  |
                    |  +--> union-method ------->  |
                    |                              |
                    <------------------------------+


union-method --->>> +---> regular-prototype -------+-->
                    |                              |
                    +---> constructor-prototype --->
                    |                              |
                    +---> destructor-prototype ---->
                    |                              |
                    +---> conversion-prototype ---->


Remark. member-type is either a numeric fundamental type, or pointer to any type. Default access for union is public.

Bitfields

bitfields-definition --->>> BITFIELDS --> type-name --> bitfields-members --> bitfields-tail --->


bitfields-members --->>> --+--> member-name ---> member-bits ---> SEMI-COLON --+-->
                           |                                                   |
                           <---------------------------------------------------+


bitfields-tail --->>> union-tail


Remark. member-bits is a none-zero literal of fundamental type uint. Default access for bitfields is public.

Enumeration

enumeration-definition --->>> ENUM ---> type-name --+--------------------------+--> { --> enum-value-list --> } -->
                                                    |                          |
+--> COLON --> enum-base -->


enum-base --->>> scope-space ---> enum-base-type --->

 
enum-value-list --->>> --+--> enum-value --+--> | | <----- COMMA -----+ enum-value --->>> ENUM-LITERAL --+-----------------------------+---> | | +--> = --> DISCRETE-NUMERIC -->

Remarks. enum-base-type is a previously defined enumeration type, which will be included in the new enumeration type being defined. However, an extended type cannot contain values of its base type. Default DISCRETE-NUMERIC for the first ENUM-LITERAL of an enumeration type without a base is 0, with default increment of 1 for succeding values.

Numeric values assigned by user must be in increasing order. The default integer value for the first ENUM-LITERAL of an extended type is 1 more than the last (largest) integer values of its base.

ENUM-LITERAL of an enumeration type can be reused in defining other unrelated enumeration types.

Collection


collection-definition --->>> COLLECTION --> type-name --> collection-head --> { --> collection-tail --> } --> collection-head --->>> LESS --> collection-enum --> MORE -+--------------------------------+--> | | +--> COLON --> collection-base --> collection-enum --->>> scope-space ---> enum-type --+---------------------------+--> | | +--> collection-enum-tail --> collection-enum-tail --->>> COLON +--> tag-value-access --+-------------------------+--+--> | | | | | +--> COMMA ---> VISIBLE --> | | | +--> VISIBLE --+----------------------------------+--> | | +--> COMMA ---> tag-value-access --> tag-value-access --->>> +--> PROTECTED ---+---> | | +--> PUBLIC ------> collection-base --->>> scope-space ---> collection-type --->

Remarks. enum-type is a previously defined enumeration type. collection-type is a previously defined collection type. The collection-enum of a derived collection must be an extension of the collection-enum of its collection-base.

The term tag refers to the instance or the current value of collection-enum, maintained internally by the instance of collection. On the other hand, the term value refers to an index-value, defined below.

The default access for tag and value is public, therefore they are visible unless made protected.

collection-tail --->>> collection-index-value ---> collection-body --->


collection-index-value --->>> --+--> ENUM-LITERAL ---> LESS ---> index-value ---> MORE --+-->
| |
<---------------------- COMMA <--------------------------+


Remark. ENUM-LITERAL are values of collection-enum. All literals of collection-enum must have an index-value.
An index-value is an IDENTIFIER for the name of a class/struct type. So, collection-index-value defines a one-to-many correspondence, associating a class type to each value of collection enumeration.

An index-value is the class type associated to an ENUM-LITERAL of collection-enum.




collection-body --->>> --+--+------------------------+--+--+-----------------------+--+--+------------------------+--+--> | | | | | | | | | | | +--> access --> COLON ---> | +--> SHARED --> COLON --> | +--> access --> COLON ---> | | | | | | | | | | +--> union-method -------> | | +--> union-method -------> | | | | | <------------------------------+ <------------------------------+

 

Remark. Once shared has been visited, the shared section begins and extends to end of definition. Default access for collection is public.

Example: Collection Type Constructor


#include<iostream.h>
using namespace ioSpace;


///////////////////////////////////////////////////////////////////////////////
// This example shows some the uses of the type constructor collection. The
// mechanism allows defining enumerations which can take on class types for
// their values, rather than just integers.
//---------------------------------------------------------------------------//
// Collections can be derived from one another. In this example we will define
// three collection types as follows.
//
// basicFiguresType starting base
// moreFiguresType derived from basicFiguresType
// mostFiguresType derived from moreFiguresType
//
///////////////////////////////////////////////////////////////////////////////

//---------------------------------------------------------------------------//
// A collection is associated with an enumeration. First we define an enum, and
// then we define three classes, Square, Rectangle and Triangle to set as
// values for the enumeration literals.
//---------------------------------------------------------------------------//

enum basicFigures {_square, _rectangle, _triangle};

//---------------------------------------------------------------------------//
// We derive all figures from class Shape, for simplicity.
//---------------------------------------------------------------------------//

class Shape

protected:

double firstDim;
double secondDim;

public:

Shape(double, double);
double area(void);
end;


//---------------------------------------------------------------------------//

Shape::Shape(double f, double s)
firstDim = f;
secondDim = s;
end;

double Shape::area(void)
return firstDim * secondDim;
end;

///////////////////////////////////////////////////////////////////////////////
// The value Square for collection.
//---------------------------------------------------------------------------//

class Square : Shape

public:

Square(double);
double area(void);
double ShowArea(void);
end;


//---------------------------------------------------------------------------//

Square::Square(double d) : Shape(d, d)
end;

double Square::area(void)
return Shape::area();
end;

double Square::ShowArea(void)
double myArea = Shape::area();
output << "I am Square and my area is: " << myArea << '\n';
return myArea;
end;

///////////////////////////////////////////////////////////////////////////////
// The value Rectangle for collection.
//---------------------------------------------------------------------------//

class Rectangle : Shape

public:

Rectangle(double, double);
double area(void);
double ShowArea(void);
end;


//---------------------------------------------------------------------------//

Rectangle::Rectangle(double f, double s) : Shape(f, s)
end;

double Rectangle::area(void)
return Shape::area();
end;

double Rectangle::ShowArea(void)
double myArea = Shape::area();
output << "I am Rectangle and my area is: " << myArea << '\n';
return myArea;
end;


///////////////////////////////////////////////////////////////////////////////
// The value Triangle for collection.
//---------------------------------------------------------------------------//

class Triangle : Shape

public:

Triangle(double, double);
double area(void);
double ShowArea(void);
end;


//---------------------------------------------------------------------------//

Triangle::Triangle(double f, double s) : Shape(f, s)
end;

double Triangle::area(void)
return Shape::area()/2;
end;

double Triangle::ShowArea(void)
double myArea = Shape::area()/2;
output << "I am Triangle and my area is: " << myArea << '\n';
return myArea;
end;

///////////////////////////////////////////////////////////////////////////////
// Now that we have all the ingredients, we can define the collection type.
//---------------------------------------------------------------------------//
// The type collection being defined is "basicFiguresType", and its enumeration
// is basicFigures. To each enum literal, we associate a class.
//---------------------------------------------------------------------------//
// Collection can also have its own methods. A shared method is invoked on all
// values of collection.
///////////////////////////////////////////////////////////////////////////////

collection basicFiguresType<basicFigures> {
_square<Square>,
_rectangle<Rectangle>,
_triangle<Triangle>

basicFiguresType(double, double, double, double);
basicFiguresType& operator=(const basicFiguresType&);
boolean operator==(const basicFiguresType&) const;

shared:

double ShowArea(void);

};


//---------------------------------------------------------------------------//

basicFiguresType& basicFiguresType::operator=(const basicFiguresType& e)
self[_square] = e[_square];
self[_rectangle] = e[_rectangle];
self[_triangle] = e[_triangle];
return self;
end;

//---------------------------------------------------------------------------//

boolean basicFiguresType::operator==(const basicFiguresType& e)
if (self[_square] != e[_square]) return False;
elsif (self[_rectangle] != e[_rectangle]) return False;
elsif (self[_triangle] != e[_triangle]) return False;
else return True;
endif;
end;


//---------------------------------------------------------------------------//

basicFiguresType::basicFiguresType(double s, double l, double w, double h)
: Square(s), Rectangle(l, w), Triangle(l, h)
end;

///////////////////////////////////////////////////////////////////////////////
// Now we want to derive a new collection type from basicFiguresType. To do so
// we first derive a new enum from the enum of basicFiguresType.
///////////////////////////////////////////////////////////////////////////////

enum moreFigures : basicFigures {_parallelogram, _diamond};

///////////////////////////////////////////////////////////////////////////////
// Next, we define two classes for the values of the derived collection.
//---------------------------------------------------------------------------//

class Parallelogram : Shape

public:

Parallelogram(double, double);
double area(void);
double ShowArea(void);
end;


//---------------------------------------------------------------------------//

Parallelogram::Parallelogram(double f, double s) : Shape(f, s)
end;

double Parallelogram::area(void)
return Shape::area();
end;

double Parallelogram::ShowArea(void)
double myArea = Shape::area();
output << "I am Parallelogram and my area is: " << myArea << '\n';
return myArea;
end;


///////////////////////////////////////////////////////////////////////////////
// The value Diamond for collection.
//---------------------------------------------------------------------------//

class Diamond : Shape

public:

Diamond(double, double);
double area(void);
double ShowArea(void);
end;


//---------------------------------------------------------------------------//

Diamond::Diamond(double f, double s) : Shape(f, s)
end;

double Diamond::area(void)
return Shape::area();
end;

double Diamond::ShowArea(void)
double myArea = Shape::area();
output << "I am Diamond and my area is: " << myArea << '\n';
return myArea;
end;

///////////////////////////////////////////////////////////////////////////////
// Now we are ready to derive moreFiguresType from collection basicFiguresType.
//---------------------------------------------------------------------------//
// The enum associated with moreFiguresType is moreFigures, and we only need
// to associate values to the new enum literals of moreFigures.
//---------------------------------------------------------------------------//
// The methods of a collection are virtual, just as they are for classes. That
// includes shared methods.
///////////////////////////////////////////////////////////////////////////////

collection moreFiguresType<moreFigures> : basicFiguresType {
_parallelogram<Parallelogram>,
_diamond<Diamond>

moreFiguresType(double s, double l, double w, double h, double r);

};


//---------------------------------------------------------------------------//

moreFiguresType::moreFiguresType(double s, double l, double w, double h, double r)
: basicFiguresType(s, l, w, h), Parallelogram(w, r), Diamond(h, r)
end;


///////////////////////////////////////////////////////////////////////////////
// For our next level of derivation we will only add one more value.
///////////////////////////////////////////////////////////////////////////////

enum mostFigures : moreFigures {_circle};

///////////////////////////////////////////////////////////////////////////////

class Circle : Shape

public:

Circle(double);
double area(void);
double ShowArea(void);
end;


//---------------------------------------------------------------------------//

Circle::Circle(double r) : Shape(r, r)
end;

double Circle::area(void)
return Shape::area() * 3.14;
end;

double Circle::ShowArea(void)
double myArea = Shape::area() * 3.14;
output << "I am Circle and my area is: " << myArea << '\n';
return myArea;
end;


///////////////////////////////////////////////////////////////////////////////
// Now we derive the next level of collection, mostFiguresType.
//---------------------------------------------------------------------------//
// This collection has a new method of its own, PrintAtTag().
//---------------------------------------------------------------------------//

collection mostFiguresType<mostFigures> : moreFiguresType {
_circle<Circle>

mostFiguresType(double, double, double, double, double, double);

void PrintAtTag(void);
};


//---------------------------------------------------------------------------//

mostFiguresType::mostFiguresType(double s, double l, double w, double h, double r, double c)
: moreFiguresType(s, l, w, h, r), Circle(c)
end;


//---------------------------------------------------------------------------//
// This method illustrates how to use collection in a manner similar to a tagged
// union. However, values in a collection are distinct objects.
//---------------------------------------------------------------------------//
// The expression [self] is the current literal value of the enumeration associated
// to the collection, which we are refering to as the tag of the collection.
//---------------------------------------------------------------------------//
// The bracket function applied to a collection object evaluates to the literal
// value of its associated enumeration value. In this example we are applying
// the bracket function to "self", which refers to the collection owning the
// method we are in.
//---------------------------------------------------------------------------//
// Another use of [] for collection is similar to array index. For instance,
// "self[_squaer]" used below evaluates to the instance of class (value) of
// collection at index (tag) _square. In this example this value is the instance
// of class Square that was initialized by constructor of collection.
//---------------------------------------------------------------------------//

void mostFiguresType::PrintAtTag(void)
output << "Area at current tag.\n";
switch([self])
case _square:
output << "Area of square is : " << self[_square].area() << '\n';
case _rectangle:
output << "Area of rectangle is : " << self[_rectangle].area() << '\n';
case _triangle:
output << "Area of triangle is : " << self[_triangle].area() << '\n';
case _parallelogram:
output << "Area of parallelogram is : " << self[_parallelogram].area() << '\n';
case _diamond:
output << "Area of diamond is : " << self[_diamond].area() << '\n';
case _circle:
output << "Area of circle is : " << self[_circle].area() << '\n';
else output << "Somehow got here.\n";
endswitch;
end;


///////////////////////////////////////////////////////////////////////////////
// The entry point main().
///////////////////////////////////////////////////////////////////////////////

entry void main(void)

output << "Hello World!\n";

mostFiguresType Figures(12, 11, 10, 8, 4, 4);

Figures.ShowArea();
// The shared method is applied to all values

output << "Good-bye World!\n";

end;


The output of this example is as follows.

Hello World!
I am Circle and my area is: 50.24
I am Parallelogram and my area is: 40
I am Diamond and my area is: 32
I am Square and my area is: 144
I am Rectangle and my area is: 110
I am Triangle and my area is: 44
Good-bye World!


Function Type


function-type-definition --->>> TYPE --+--> regular-function-type -------+--> SEMI-COLON | | +--> instantiated-function-type --> regular-function-type --->>> TYPE ---> function-prototype ---> SEMI-COLON

Remark. Note that function-prototype can have THREAD, THROWS, ACCEPTS and HEARS. However, identifiers for names of parameters are not accepted for TYPE. The name of function-prototype becomes the name of function pointer type.


Example

type int MyFunType(int, long); // define a function pointer type

// receiver() will accept a function pointer, and use it to make a call.

void receiver(MyFunType f)
	f(2, 3);
end;

// We will use globalFun to initialize a function pointer.
 
int globalFun(int i, long g)
	// some statements
	return i;
end;

MyFunType MyFun = globalFun; //make and initialize an instance of MyFunType

receiver(MyFun); //pass the instance of MyFunType to a function


instantiated-function-type --->>> function-name --+------------------------------+--> instantiated-function-call --> SEMI-COLON
                                                  |                              |
                                                  +--> COMMA --> function-type -->


Remark. function-name and function-type are IDENTIFIERs, and function-type is optional.
Generally, we are interested in function-name, which allows us to make function calls without the instantiation syntax. That is similar to typedef. However, if we also provide function-type, the statement will create a function pointer type as in function-type-definition.


Example

#include<iostream.h>
using namespace ioSpace;

// Define template functions with same name and signature, one in a namespace and
// the other in global space.

namespace myspace

	template<type U> U fun(U n)
		return n += 3;
	end;

endspace;

template<type U> U fun(U n)
	return n *= 3;
end;

// Suppose we want to instantiate function types in different namespaces.
// spaceFun is the name of instantiated function pointer, and spaceFunType
// is its type.
// myspace::fun<int> is an example for instantiated-function-call.

namespace firstSpace
	type spaceFun , spaceFunType myspace::fun<int>;
endspace;

// globalFun is the name of instantiated function pointer, and globalFunType
// is its type.
// fun<int> is an example for instantiated-function-call.

namespace secondSpace
	type globalFun , globalFunType fun<int>;
endspace;

// Using function pointer types, we defined the following two functions.

void firstFun(firstSpace::spaceFunType f)
	output << "In firstFun...\n";
	output << f(7) << '\n'; // 10
end;

void secondFun(secondSpace::globalFunType f)
	output << "In secondFun...\n";
	output << f(7) << '\n'; // 21
end;

// ------------------------------------------------------------------------- //

entry void main(void)

	output << "Hello World!\n";

// First, we call function pointers directly, Generally, this is how they are used.

	output << firstSpace::spaceFun(7) << '\n'; // 10
	output << secondSpace::globalFun(7) << '\n'; // 21

// Next, we pass the function pointers as argument to the functions we defined earlier.

	firstFun(firstSpace::spaceFun);
	secondFun(secondSpace::globalFun);

	output << "Good-bye World!\n";

end;
The output of the example is:

Hello World!
10
21
In firstFun...
10
In secondFun...
21
Good-bye World!


Typedef Definition


typedef-definition --->>> TYPEDEF ---> typedef-name ---> typedef-type ---> SEMI-COLON

Remark. typedef-name is an IDENTIFIER, which is used in a declaration as a name for typedef-type.


                                       <----------------------------------------------------------+
                                       |                                                          |
typedef-type --->>> declaration-type --+--+----------+---+-------------------------------------+--+-->
                                          |          |   |                                     |
                                          +-+-> * -+->   +-+--> [ ---> array-index ---> ] --+-->
                                            |      |       |                                |
                                            <------+       <--------------------------------+

 

Function Definition


function-definition --->>> +--> global-function-definition ---+-->
                           |                                  |
                           +--> method-definition ------------>



global-function-definition --->>> function-prototype-declaration ---> statement-block ---> END ---> SEMI-COLON


Remark. Unlike methods, global functions are not required to have a prototype prior to their definition. In such cases, function-tail can appear at the definition of global functions. However, when a prototype exists, function-tail must only appear at prototype. When prototype and definition are separated, parameter initializers can only appear in prototype, not the definition of function.


method-definition --->>> type-name --> RESOLVER --> shortened-method-prototype --> statement-block --> END


Remark. The rule shortened-method-prototype is easier to describe rather than listing a long set of rules.
Begin with rule method-prototype, for any type of method, such as regular-prototype, constructor-prototype, etc.
Cut the rule right after the closing parenthesis for parameter-list. That is, method-definition does not take specifiers like CONST, CAST, throws-list, etc.
Parameter initializers cannot appear in method-definition. Initializers can only appear in method-prototype.
External-methods do not have explicit definition. Compiler generates their definitions implicitly.
Friend-prototypes are not recorded as methods. The definition for a friend-prototype is just global-function-definition.


Template Pattern


A template pattern is used to specify types that are allowed to instantiate a template type.


pattern-definition --->>> PATTERN --> pattern-parameter --> pattern-name --> pattern-body --> END --> SEMI-COLON


Remark. pattern-name is an IDENTIFIER for name of pattern being defined.


pattern-parameter --->>> TEMPLATE --> LESS --> pattern-parameter-id --> MORE -->


Remark. pattern-parameter-id is an IDENTIFIER. All occurrence of pattern-parameter-id within the definition of a pattern are to the one in pattern-parameter. A pattern has only a single parameter.


pattern-body --->>> --+--> pattern-type-body ----+--->
| |
+--> pattern-method-body -->

pattern-type-body --->>>> --+--> pattern-parameter-id --> COLON --+--> declaration-type --+---> SEMI-COLON --+-->
                            |                                     |                       |                  |
                            |                                     <--------- COMMA <------+                  |
| |
<--------------------------------------------------------------------------------+


pattern-method-body --->>> --+--> pattern-method ---> SEMI-COLON --+--> | | <-------------------------------------+ pattern-method --->>> +--> pattern-type --> pattern-method-name --> pattern-method-parameter-list --+-> | | +---> OPERATOR ---> pattern-method-parameter-list ---> ( ---> VOID ---> ) ----> pattern-type --->>> --+------------+--+-----> declaration-type ---+--> parameter-specifier ---> | | | | +--> CONST --> +--> pattern-parameter-id --> pattern-method-name --->>> +--> IDENTIFIER -----------------------+--> | | +---> OPERATOR ---> operator-symbol ---> | | +------> ? -------------------------->

Remark. The ? means the name of method is irrelevant. Thus, ? is a wild symbol. The name of a constructor is indicated with ?. Thus, ?(void) requires the instantiator type to define a default constructor. Currently, it is not possible to specify the requirement of a copy constructor.



pattern-method-parameter-list --->>> ( --+---------------------------+---> ) | | +--+---> pattern-type ---+--> | | <------- COMMA -------+

Example

#include<iostream.h>
using namespace ioSpace;

///////////////////////////////////////////////////////////////////////////////
// First we define two patterns. Type_Pattern specifies acceptable types for
// instantiating a template. Method_Pattern lists the methods required by the
// type instantiating a template.
// ------------------------------------------------------------------------- //

pattern template<T> Type_Pattern
T : int, long;
T : short*;
end;

pattern template<T> Method_Pattern
long fun(int, double);
int ?(long, short);
//function name is wild
void operator+(int);
const T& ?(int);
//function name is wild, return is template
operator int(void) cast; //conversion operator, with explicit cast
?(short) cast; //constructor with explicit cast
?(void); //default constructor
end;

///////////////////////////////////////////////////////////////////////////////
// This is a simple template showing how pattern specification is attached to
// a template parameter. Here, Type_Pattern is attached to U, and Method_Pattern
// specifies instantiator for template parameter V.
// ------------------------------------------------------------------------- //

template<type U : Type_Pattern, type V : Method_Pattern>
struct example
U i;
V d;
end;


///////////////////////////////////////////////////////////////////////////////
// The type patternType is used to instantiate the above template, in the second
// parameter, namely V. It therefore must contain all methods listed in pattern
// Method_Pattern.
// ------------------------------------------------------------------------- //

struct patternType
short s;

patternType(void);
patternType(short) cast;
long fun(int, double);
void operator+(int);
int wild(long, short);
const patternType& wild(int);
operator int(void) cast;
end;

patternType::patternType(void)
s = 0;
end;

patternType::patternType(short h)
s = h;
end;

long patternType::fun(int i, double d)
return i;
end;

void patternType::operator+(int n)
end;

int patternType::wild(long l, short h)
return int(l);
end;

const patternType& patternType::wild(int n)
return self;
end;

patternType::operator int(void)
return int(s);
end;


///////////////////////////////////////////////////////////////////////////////

entry void main(void)
output << "Hello World!\n";

example<short*, patternType> ext;
// patterns are checked at instantiation

short j = 7;
ext.i = &j;
output << *ext.i << '\n';

output << "Good-bye World!\n";

end;


The output is as follows.

Hello World!
7
Good-bye World!

Template Type Definition


template-type-definition --->>> template-parameters-declaration --+--> class-definition ---+--> END --> SEMI-COLON
                                                                  |                        |
                                                                  +--> struct-definition -->
                                                                  |                        |
                                                                  +--> task-definition ---->


Remark. There is no syntactic differences in defining, say a class and a template class. However, note the following as an example.
In derivation, for class-definition, we see user-defined-type. The right of user-defined-type includes instantiated-type. Now, when dealing with templates, a previously defined template used in the definition of another template must be instantiated with type names of template-parameter-id, shown in following rules.


template-parameters-declaration --->>> TEMPLATE -->  LESS  --> template-placeholders -->  MORE  -->


template-placeholders --->>> --+--> TYPE --> template-parameter-id --+-----------------------------+--+-->
                               |                                     |                             |  |
                               |                                     +--> COLON --> pattern-name -->  |
                               |                                                                      |
                               <-------------------------------  COMMA  ------------------------------+


Remark. template-parameter-id is an IDENTIFIER, which is specified as type within the scope of template-parameters-declaration. pattern-name is the name of a previously defined template pattern. A template-parameter-id with a pattern can only be instantiated with types that satisfy the conditions of the pattern.


Example


We are going to define a template task, with hears() specification, named HearingTask. The method definitions will be given as an example for next rule: template-function-definition.

// Definition of template for type of first member of HearingTask

template<type U> struct firstMember U i; firstMember(U); end; template<type U> firstMember::firstMember(U n) i = n; end;

// Definition of template for type of second member of HearingTask

template<type U> struct secondMember U d; secondMember(U); end; template<type U> secondMember::secondMember(U b) d = b; end;
// Definition of template task: HearingTask
// Within the definition of HearingTask, the types firstMember<U> and secondMember<V> // are instantiations of template types firstMember and secondMember.

template<type U, type V> task HearingTask firstMember<U> ti; secondMember<V> di; hears(_SIGNAL_telling_1<firstMember<U>, secondMember<V> >, _SIGNAL_telling_2); void FirstHearHandler(void)<_SIGNAL_telling_1 : ti, di>; void SecondHearHandler(void)<_SIGNAL_telling_2>; public: HearingTask(U, V); end;

Template Function Definition


template-function-definition --->>> template-parameters-declaration --> function-definition


Remark. Inside function-definition, for a template-function-definition, template-parameter-id are parsed as instantiators (previously-defined types). As in case of template-type-definition, previously-defined template types are parsed as template instantiation.


Example


The definition of methods for HearingTask of example for previous rule is given here.

// The constructor. U and V are parsed as previously defined types. firstMember<U> and
// secondMember<V> are parsed as instantiations of previously defined template types.
 
template<type U, type V>
HearingTask::HearingTask(U u, V v)
	ti = firstMember<U>(u);
	di = secondMember<V>(v);
end;

// These are the handlers for signals for template task HearingTask.

template<type U, type V>
void HearingTask::FirstHearHandlerOne(void)
	// statements
end;

template<type U, type V>
void HearingTask::SecondHearHandlerOne(void)
	// statements
end;


Template Typedef


template-typedef-definition --->>> TEMPLATE LESS TYPE --> template-parameter-id --> MORE --> typedef-definition


Remark. template-typedef-definition can only have a single template-parameter-id, without a pattern. The template-parameter-id in the typedef-type is parsed as a previously defined type.


Examples


template<type T> typedef myTypedef T[5];   // definition
myTypedef<int>* intArrayPointer;           // an instantiation as "int[5]*"

// Suppose you are defining a new template class that needs a degenerate // array pointer. First the typedef. template<type T> typedef degenerateArray T[]; // definition // Now, among class members, you include the following member. arrayPointer // is a degenerate array pointer on type T. degenerateArray<T>* arrayPointer;


Graphical Interface Definition

Graphical User Interface entities are created with Graphic Maker Tool. The Tool generates a resource file for Linker, and an include file. The terms menubar, menu and canvas are Z++ reserved words that appear in the generated include files. All other terms, such as Button, Radiobutton, Checkbox are NOT reserved words.

The rules discussed here, though automatically generated by Tool, are Z++ language rules. The general idea is that, a menubar can only contain a list of menus. A menu contains a list of commands and submenus. Finally, a canvas can contain a menubar, and other entities like Combobox, Groupbox, Checkbox etc.



graphical-interface-definition --->>> +--> menu-definition -----+---> | | +--> menubar-definition --> | | +--> canvas-definition --->

Remark. menu-name, menubar-name, item-name and canvas-name in the following rules are IDENTIFIERs.
An interface-item is a control such as a TextArea, Button, List etc.

For a menu, the term command is not a reserved word, which is why it is not colored. The name for a command is a string like Open, Close, Exit Application, etc. The name for the menu itself is something like File, Edit, etc.



<--------------- SEMI-COLON <---------------+
| |
menu-definition --->>> menu --> menu-name --+--+--> command -------> command-name --+---+--> end ---> SEMI-COLON
| |
+-------> menu ---> menu-name ------->


menubar-definition --->>> menubar ---> menubar-name --+--> menu ---> menu-name --+--> end --> SEMI-COLON
| |
<------ SEMI-COLON <-------+



canvas-definition --->>> canvas ---> canvas-name --+----------------------------------+--+--> iterface-item ---> item-name --+--> end --> SEMI-COLON
| | | |
+---> menubar ---> menubar-name ---> <--------- SEMI-COLON <-------------+


Below is an example of a generated include file containing menus. Comments are manuaaly added for illustration.


menu File
command Open;
command Save;
command Exit;
end;

menu Select // This will be used as submenu below
command Bold;
command Underline;
end;

menu Edit
command Find;
menu Select; // This is the menu defined above, serving as submenu here
end;

menubar EditorMenu
menu File;
menu Edit;
end;

canvas Editor
menubar EditoMenu
TextArea Text;
end;



Below is an example of a generated canvas for a diaglog window.


canvas Personal
GroupBox Gender;
Label Last;
Label Name;
Button Done;
ComboBox Food;
TextArea LastName;
TextArea FirstName;
RadioButton Male;
RadioButton Female;
end;


Type Instantiation


instantiated-type --->>> scope-space --> type-name ---> LESS --+--> typedef-type --+--> MORE ---> 
                                                               |                   |
                                                               <------ COMMA ------+


Remark. instantiated-type is the result of instantiating a template-type-definition. The type-name is the same IDENTIFIER used in template-type-definition. Since typedef-type can include instantiated-type, this is recursive.


Example


Following is a complete program using nested template definitions. Notice the space between two consecutive >.

#include<iostream.h>
using namespace ioSpace;

// member will be used to defined nested template
template<type U, type V> struct member
	U t;
	V s;

	member(U, V);
end;

template<type U, type V>
member::member(U i, V j)
	t = i;
	s = j;
end;

// owner has two nested template type members: m and n.

template<type U, type V> struct owner member<member<U, V>, V> m; member<U, member<U, V> > n; owner(member<member<U, V>, V>, member<U, member<U, V> >); member<U, V> leftOfFirst(void); member<U, V> rightOfSecond(void); end; template<type U, type V> owner::owner(member<member<U, V>, V> i, member<U, member<U, V> > j) m = i; n = j; end; template<type U, type V> member<U, V> owner::leftOfFirst(void) return m.t; end; template<type U, type V> member<U, V> owner::rightOfSecond(void) return n.s; end;
//---------------------------------------------------------------------------//
entry void main(void) output << "Hello World!\n";
 
owner<int, double> w(member<member<int, double>, double>(member<int, double>(4, 9.3), 77.47), member<int, member<int, double> >(47, member<int, double>(8, 8.1)) ); output << w.m.t.t << '\n'; // 4 output << w.m.t.s << '\n'; // 9.3 output << w.m.s << '\n'; // 77.47 output << w.n.t << '\n'; // 47 output << w.n.s.t << '\n'; // 8 output << w.n.s.s << '\n'; // 8.1 output << w.leftOfFirst().t << '\n'; // 4 output << w.rightOfSecond().s << '\n'; // 8.1

output << "Good-bye World!\n"; end;


The output of the program is:

Hello World!
4
9.3
77.47
47
8
8.1
4
8.1
Good-bye World!


Method Prototype


The rule parameter-list defined in this section is used in rules for defining prototypes.


parameter-type --->>> --+------------+-> declaration-type ---> parameter-specifier
                        |            |
                        +--> CONST -->


parameter-specifier --->>> +----------+---+-----------+--> array-modifier
                           |          |   |           |
                           +-+-> * -+->   +---> & ----> 
                             |      |
                             <------+


return-type --->>> parameter-type


parameter --->>> parameter-type --+------------------------------------------------+-->
                                  |                                                |
                                  +---> parameter-name ---+------------------------>
                                                          |                        |
                                                          +--> = --> initializer -->


Remark. When a parameter has an initializer, all parameters after that must also have initializers. parameter-name is an IDENTIFIER.


parameter-list --->>> ( --+----------------------+---> )
                          |                      |
                          +--+--> parameter --+-->
                             |                |
                             <----  COMMA ----+



method-prototype --->>> +---> class-method ---+---> SEMI-COLON | | +---> task-method ---->
| | +---> frame-method ---> | | +---> module-method --> class-method --->>> +---> regular-prototype -------+--> | | +---> constructor-prototype ---> | | +---> destructor-prototype ----> | | +---> conversion-prototype ----> | | +---> friend-prototype --------> task-method --->>> +---> class-method --------+--> | | +---> idler-prototype -----> | | +---> handler-prototype ---> frame-method --->>> +---> class-method ---------+--> | | +---> instinct-prototype ---> module-method --->>> +---> native-class-module-method ---+--> | | +---> native-task-module-method ----> | | +---> foreign-module-method --------> native-class-module-method --->>> +---> class-method ---------+--> | | +---> external-prototype ---> native-task-module-method --->>> +---> task-method ----------+---> | | +---> external-prototype ---> foreign-module-method --->>> +---> class-method ---------+--> | | +---> external-prototype --->
regular-prototype --->>> method-head ---> method-tail ---> SEMI-COLON


method-head --->>> return-type --+--> method-name --------------------+--> parameter-list --->
                                 |                                    |
                                 +---> OPERATOR --> operator-symbol -->


Remark. method-name is an IDENTIFIER for the name of the method being prototyped.
operator-symbol is the operator being overloaded. In general, this is just the operator symbol like '+' or '+='. When overloading array indexing the symbol is '[]'. For function call, the symbol is '()'.
There are two additional symbols that are only used for overloading. Post-script operators ++ and -- use a different symbol for their prototype and definition. However, the call to these overloaded operators uses the normal symbols ++ or -- apearing after the object-name on which they are invoked.
Post-script ++ uses '+@', and post-script -- uses '-@'.

method-tail --->>> +--+---------------+---> tail-specifiers --->
                      |               |
                      +---> CONST ---->


tail-specifiers --->>> +------------------+--+----------------------------------+-->
                       |                  |  |                                  |
                       +--> throws-list -->  +--> { --> constraint-list --> } -->


constructor-prototype --->>> constructor-prototype-head -+-----------+--+------------------+-> constructor-tail --> SEMI-COLON | | | | +--> CAST --> +--> throws-list --> constructor-prototype-head --->>> type-name ---> parameter-list ---> constructor-tail --->>> +------------------------------------------------------+--> | | +-> COLON -+---+--> member-name -+-> parameter-list ---> | | | | | +--> base-name ---> | | | <----------------- COMMA <-----------------+

Remark. base-name is an IDENTIFIER for name of a base used in derivation for definition of this type.


destructor-prototype --->>> ~ ---> type-name ---> ( --+-----------+--> ) --->
| |
+--> VOID -->


idler-prototype --->>> @ ---> type-name ---> ( --+-----------+--> ) --->
| |
+--> VOID -->

Remark. Idler is optional for a task. When a task has an idler, the idler is automatically invoked whenever task has no requests or signals to handle.


instinct-prototype --->>> $ ---> type-name ---> ( interfaceEventType ---> & ---> ) --->


Remark. The type interfaceEventType is defined in system include file "interface.h". The instinct method of a frame automatically receives events intended for the instance of the frame. Event is passed by-reference. See select-statement.


handler-prototype --->>> VOID ---> IDENTIFIER ---> ( -+----------+--> ) ---> handler-tail ---> SEMI-COLON | | +-> VOID -->


Remark. IDENTIFIER is the name of the handler.



handler-tail --->>> LESS ---> handler-signal ---> MORE ---> handler-signal --->>> +---> SIGNAL-LITERAL --+--> | | +---> ACCEPT-SIGNAL ---|
| | +---> handler-hear ----> handler-hear --->>> HEAR-SIGNAL --+------------------------------+---> | | +--> COLON -+-> member-name -+-> | | <--- COMMA <---+

Remark. All signals are defined in system include file "exception.h".
HEAR-SIGNAL is a literal of tellSignalType, or its extension.

conversion-prototype --->>> OPERATOR --> return-type --> ( --+----------+--> ) --> conversion-specifiers --> SEMI-COLON
                                                             |          |
                                                             +-> VOID -->


conversion-specifiers --->>> +--------------------------------+--->
                             |                                |
                             +---> CONST ---+-------------+--->
                                            |             |
                                            +---> CAST --->


friend-prototype --->>> FRIEND ---> method-head ---> SEMI-COLON


external-prototype --->>> EXTERNAL ---> method-head ---> SEMI-COLON

Remark. A friend-prototype is not recorded as a method of the type being defined. It is just a global function that has same access to members of the type as its own methods do. In order to reach members of the type, a friend-prototype needs a parameter of the type it is friend with.

An external method does not have a user-defined definition. The Compiler generates the body (definition) of an external method.


throws-list --->>> THROWS ---> ( --+--> EXCEPTION-LITERAL ---+--> )
                                   |                         |
                                   <--------- COMMA <--------+


Remark. EXCEPTION-LITERAL is a literal of exceptionEventType, or its extension. Exceptions are defined in system include file "exception.h".


constraint-list --->>> +--+--> constraint ---+-->
                          |                  |
                          <------------------+


constraint --->>> ( ---> boolean-expression ---> ) ---> violation-action ---> SEMI-COLON


violation-action --->>> +--> EXCEPTION-LITERAL --+--> | | +--------> trigger ------>
 

Remark. trigger is pure-prototype (defined below) of a none-public method.


pure-prototype --->>> +--> method-name ---------------------+--> prototype-parameter-list --->
                      |                                     |
                      +----> OPERATOR --> operator-symbol -->


prototype-parameter-list --->>> ( --+---------------------------+---> )
                                    |                           |
                                    +--+--> parameter-type --+-->
                                       |                     |
                                       <------ COMMA --------+


Remark. Unlike methods, global functions are not required to have a prototype prior to their definition. In such cases, function-tail can appear at the definition of global functions. However, when a prototype exists, function-tail must only appear at prorotype. When prototype and definition are separated, parameter initializers can only appear in prototype, not the definition of function.


function-prototype --->>> function-prototype-declaration ---> SEMI-COLON


function-prototype-declaration --->>> return-type --> IDENTIFIER --> parameter-list -+-------------------+->
                                                                                     |                   |
                                                                                     +-> function-tail -->



Remark. Instead of IDENTIFIER for the name of function, you can use OPERATOR followed by an operator symbol, for globally overloading that operator. However, the Compiler will not allow globally overloading an operator for fundamental types. At least one parameter must be of user-defined type.
The compiler will also attempt to detect infinite recursion when the same operator is used in its definition.

Globally overloading should only be used on user-defined types in cases where such overloading was not possible via method-overloading due to the order of definitions of those types.


function-tail --->>> +-------------------------------------------------------------------+--> throws-list --> | | +--> thread-specifier --+-------------------+--+-----------------+--> | | | | +--> accepts-list --> +--> hears-list -->

Remark. The order of accepts-list, hears-list and throws-list is not significant.
Note that only threads can have accepts-list and/or hears-list.


thread-specifier --->>>  LESS ---> THREAD --+--------------------------------------+-->  MORE
                                            |                                      |
                                            +--> COLON --+--> DISENGAGE-SIGNAL --+->
                                                         |                       |
                                                         <------- COMMA <--------+


Remark. DISENGAGE-SIGNAL is a literal of signalEventType, or its extension. Similarly, HEAR-SIGNAL is a literal of tellSignalType or its extension. Signals are defined in system include file "exception.h".



accepts-list --->>> ACCEPTS ---> ( --+--> ACCEPT-SIGNAL --+--> ) | | <------ COMMA <------+



hears-list --->>> HEARS ---> ( --+--> hear-element --+--> ) | | <------ COMMA <-----+
hear-element --->>> HEAR-SIGNAL --+-----------------------------------------------+--> | | +--> LESS -+-> declaration-type -+-> MORE --> | | <------- COMMA <------+


Structure Statements


control-statement --->>> +---> selection-statement ---+---> SEMI-COLON
                         |                            |
                         +---> iteration-statement --->
                         |                            |
                         +---> layer-statement ------->


selection-statement --->>> +---> if-statement -----------+--->
                           |                             |
                           +---> switch-statement ------->
                           |                             |
                           +---> select-statement ------->


iteration-statement --->>> +---> for-statement ----------+--->
                           |                             |
                           +---> do-statement ----------->
                           |                             |
                           +---> while-statement -------->

 
if-statement --->>> IF --> ( --> boolean-expression --> ) --> statement-block --> elsif-block --> else-block --> ENDIF -->


elsif-block --->>> --+--------------------------------------------------------------------------+--->
                     |                                                                          |
                     +--+--> ELSIF  --> ( --> boolean-expression --> ) --> statement-block --+-->
                        |                                                                    |
                        <--------------------------------------------------------------------+


else-block --->>> --+--------------------------------+-->
                    |                                |
                    +--> ELSE --> statement-block --->




switch-statement --->>> SWITCH --> ( --> switch_argument --> ) --+----------------------+--> switch-body --> ENDSWITCH --> | | +--> statement-block --> switch_argument --->>> expression-statement


Remark. The type of object resulting from switch_argument must be, string, enumeration, char or DISCRETE-NUMERIC.


switch-body --->>> case-list --+---------------+--->
                               |               |
                               +--> else-leg -->


case-list --->>> --+--> case-leg --+--->
                   |               |
                   <---------------+


case-leg --->>> CASE ---> case-argument ---> COLON ---> statement-block --->


case-argument --->>> +---> single-argument -----+--->
                     |                          |
                     +---> sequence-argument --->
                     |                          |
                     +---> range-argument ------>


single-argument --->>> LITERAL


Remark. The type of LITERAL must match the type of switch_argument.


sequence-argument --->>> single-argument ---> COMMA --+--> single-argument --+--->
                                                      |                      |
                                                      <------- COMMA <-------+


range-argument --->>> single-argument ---> .. ---> single-argument --->

Remark. A range of values contains the start and end values, along with all values in between.
Two consecutive dots (with no space in between) is the symbol for range.


else-leg --->>> ELSE ---> statement-block --->



for-statement --->>> FOR --> ( --> for-determinant --> ) --> statement-block --> ENDFOR -->


for-determinant --->>> --+-------------------------+--> SEMI-COLON --+-------------------------+--> SEMI-COLON --+---------------------+--> | | | | | | +--> for-initialization --> +--> boolean-expression --> +--> expression-leg -->


for-initialization --->>> +--+--> regular-for-declaration ---+---+---> ^ | | | | +--> constructor-declaration ---> | | | <--------------- COMMA ----------------+ regular-for-declaration --->>> declaration-type --+----------+---> object-name --+-------------------------+--> | | | | +-+-> * -+-> +--> = --> initializer ---> | | <------+

 
expression-leg --->>> --+--> expression-statement --+--> | | <---------- COMMA ----------+

Remark. expression-leg is a comma-separated sequence of expressions. The object resulting from an expression-leg is the object resulting from the last expression in the sequence.


do-statement --->>> DO ---> statement-block ---> ENDDO --+-------------------------------------+--->
                                                         |                                     |
                                                         +--> ( --> boolean-expression --> ) -->



Remark. Without (boolean-expression), a do loop becomes an infinite loop. Otherwise, a do loop will terminate when boolean-expression evaluates to TRUE.


while-statement --->>> WHILE --> ( --> boolean-expression --> ) --> statement-block --> ENDWHILE -->


Instinct Method Select


A frame must have an instinct method for processing signals. Signals, such as mouse-click, for entities (button etc) of the canvas associated with the (instance of) frame are deliverd to its instinct method. The select-statement is the structure for handling and processing signals (events) passed to the instinct method.

The system include file "interface.h" defines graphical interface events. The enumeration type interfaceEventSignals lists events such as mouse-click.

When an event, such as a mouse-click is generated for a canvas, Z47 invokes the instinct method of the frame associated with that canvas and passes an instance of the following structure to it.

struct interfaceEventType
    ushort x;                         // horizontal coordinate
    ushort y;                         // vertical coordinate
    ushort entity;                  // button-name, menu-item, menubar-name, etc.
    interfaceEventSignals Event;   // mouse-click, etc.
end;

Suppose the IDENTIFIER for the argument passed to the instinct method is "event". Then, select-argument in the rule below will be event.entity, which evaluates to an identifier such as "STOP", used as label for a BUTTON entity in the canvas. In this example the entity-name for a case will be "STOP".



select-statement --->>> SELECT --> ( --> select-argument --> ) ---> select-body --> ENDSELECT -->


select-body --->>> select-cases --+----------------+--->
| |
+--> else-leg --->


select-cases --->>> --+--> CASE --> entity-name --> COLON --> statement-block --+-->
| |
<---------------------------------------------------------+


Remark. select-argument and entity-name are explained just before the rules. An entity-name could be name (label) of a control (like a button, a list etc), or an IDENTIFIER for menu-item or a menu-bar.

Example


First we use the GUI Maker and create a canvas. Once the canvas is made, we tell the GUI Maker to generate the following include file for the canvas.


// Person.h

// Generated by Z++ GUI Maker

canvas Personal
GroupBox Gender;
Label Last;
Label Name;
Button Done;
ComboBox Food;
TextArea LastName;
TextArea FirstName;
RadioButton Male;
RadioButton Female;
end;

The source file below is an example using the above canvas.


//Person.zpp

#include<interface.h>
using namespace interfaceSpace;

#include<exception.h>
using namespace exceptionSpace;

#include"Person.h"
// Generated by GUI Maker

// Definition of frame

frame personFrame := Personal
public:
personFrame(void);
$personFrame(interfaceEventType&);
// This is the instinct method
end;

// The constructor

personFrame::personFrame(void)
end;


// The instinct method is automatically invoked when there is
// an event associated with the canvas of the frame. The envent
// e is also passed to the instinct method.

personFrame::$personFrame(interfaceEventType& e)

switch(e.Event)

case _IES_Draw_Signal:
// generated in main() via $PF

// Put a few items in the ComboBox Food of canvas Personal

Personal::Food + "Pizza";
Personal::Food + "Steak";
Personal::Food + "Rice and Chicken";
Personal::Food << 0;

return;

case _IES_Erase_Signal:
// generated by "case Done"
$self; // This will erase the canvas
return;

// The signal is generated when user clicks an entity on canvas.

case _IES_Mouse_Click_Signal:

// For the given signal (_IES_Mouse_Click_Signal) the select statement
// processes the signal for the entity of canvas "e.entity"

select(e.entity)

case Male:
Personal::Food << 0;

case Female:
int index = 3;
// cause an exception

layer<exceptionEventType>
Personal::Food << index;
handler
case _EXCEPTION_GUI_IndexOutOfRange:
index = 2;
// repair the cause of exception
repeat; // and start over
endlayer;

case Done: // user clicked Done button
Personal <- _IES_Erase_Signal;

endselect;

endswitch;

end;


// The main() entry point

entry void main(void)

personFrame PF; //create an instance of frame
$PF; // draw the canvas (generates _IES_Draw_Signal)

end;


Exception Layer


System exceptions are defined in system include file "exception.h". The type of system exceptions is exceptionEventType. User-defined exceptions are objtained by extending the system exceptions.

The layer statements catches explicitly. as well as implicitly raised exceptions, such as those raised by invariants.

For resuming after handling an exception see Resumption.



layer-statement --->>> layer-head --> layer-body --> handler-section ---> ENDLAYER --> SEMI-COLON

layer-head --->>> LAYER --> LESS --> exception-type --> MORE


Remark. The exception-type between < and > specifies the type of exceptions that the layer statement will handle in its handler section. The exception-type is either the system exceptions exceptionEventType or a user-defined extension of it.

layer-body --->>> statement-block


Remark. Exceptions occuring in layer-body are caught in the handler-section.


handler-section --->>> HANDLER --> case-list --+------------------+---> | | +--> else-leg -----> | | +--> elsall-leg --->


elsall-leg --->>> ELSALL --> statement-block



Remark. Literals for the case-list must be exception literals.
The else-leg will catch all exceptions of type exception-type specified in layer-head that do not appear in case-list.
The elsall-leg will catch all system/user-defined exceptions that do not appear in case-list.


Example


The example defines three user-defined exceptions, and uses three nested layer statements.



#include<iostream.h> using namespace ioSpace; #include<exception.h> using namespace exceptionSpace;

// Extend system exceptions to user-defined types MyExceptions, YourExceptions and HisExceptions.

enum MyExceptions : exceptionEventType {
	_EXCEPTION_FirstUserException,
	_EXCEPTION_SecondUserException,
	_EXCEPTION_ThirdUserException,
	_EXCEPTION_FourthUserException
};

enum YourExceptions : MyExceptions {
	_EXCEPTION_FifthUserException,
	_EXCEPTION_SixthUserException,
	_EXCEPTION_SeventhUserException,
	_EXCEPTION_EighthUserException
};


enum HisExceptions : YourExceptions {
	_EXCEPTION_NinethUserException,
	_EXCEPTION_TenthUserException,
	_EXCEPTION_EleventhUserException,
	_EXCEPTION_TwelfthUserException
};


// The main() entry point.
 
entry void main(void) throws(_EXCEPTION_TwelfthUserException)

output << "Hello World!\n"; layer<HisExceptions> output << "In HisExceptions layer.\n"; layer<YourExceptions> output << "In YourExceptions layer.\n"; layer<MyExceptions> output << "In MyExceptions layer, raising _EXCEPTION_TwelfthUserException.\n";

// Let us explicitly raise an exception.

raise(_EXCEPTION_TwelfthUserException);
// The next output will not be reached because of above exception. output << "In MyExceptions layer, after raising _EXCEPTION_TwelfthUserException.\n"; handler case _EXCEPTION_FirstUserException: output << "In MyExceptions Handler.\n"; // The else leg will not be entered becasue else only refers to exceptions // of type MyExceptions, which does not include _EXCEPTION_TwelfthUserException. else output << "In MyExceptions else.\n"; endlayer; handler case _EXCEPTION_FirstUserException: output << "In YourExceptions Handler.\n"; // elsall refers to all exceptions in exceptionEventType, and its extensions. So, in this case, the // elsall leg will be entered. elsall output << "In YourExceptions elsall, handling _EXCEPTION_TwelfthUserException.\n"; endlayer; output << "In HisExceptions, _EXCEPTION_TwelfthUserException already handled.\n"; // _EXCEPTION_TwelfthUserException was already handled so the handler will not be entered. handler case _EXCEPTION_TwelfthUserException: output << "In HisExceptions Handler.\n"; endlayer; output << "Good-bye World!\n"; end;
The output of this example is as follows.

Hello World! In HisExceptions layer. In YourExceptions layer. In MyExceptions layer, raising _EXCEPTION_TwelfthUserException. In YourExceptions elsall, handling _EXCEPTION_TwelfthUserException. In HisExceptions, _EXCEPTION_TwelfthUserException already handled. Good-bye World!

Expression Statement


The execution of an expression results in an object. In other words, an expression always evaluates to an object.
Making a call may or may not result in an object. The function or method being invoked may have a void return.
When an expression ends with a SEMI-COLON, the object resulting from that expression is simply ignored.


expression-statement --->>> --+--> ( --> expression-statement --> ) ---> expression-statement-tail ---+-->
                              |                                                                       |
                              +--> expression-statement ---> OPERATION ---> expression-statement ----->
                              |                                                                       |
                              +--> plain-expression -------------------------------------------------->


Remark. OPERATION is a binary operator.


                                   <------------------------------------------------+
                                   |                                                |
expression-statement-tail --->>> --+--+--> BELONG-OPERATOR --> plain-method-call ---+--->
                                      |                                             |
                                      +--> identifier-expression-tail -------------->



Remark. Not all paths of the rule expression-statement-tail are semantically correct. For instance, when identifier-expression-tail ends in a base and we turn around, the BELONG-OPERATOR can only be the RESOLVER. But then, one may incorrectly invoke a method on an object whose type does not define that method. Compiler is responsible for semantic analysis once the parser accepts the syntax.


plain-expression --->>>  +--> LITERAL -------------------------+--->
                         |                                     |
                         +--> identifier-expression -----------+
                         |                                     |
                         +---> constructor-expression --------->
                         |                                     |
                         +---> cast-expression ---------------->
                         |                                     |
                         +---> new-expression ----------------->
                         |                                     |
                         +---> size-expression ---------------->
                         |                                     |
                         +---> operator-expression ------------>
                         |                                     |
                         +---> call-expression ---------------->
                         |                                     |
                         +---> conditional-expression --------->
| |
+---> signal-expression -------------->
| |
+---> hear-expression ---------------->

 

identifier-expression --->>> +------------------+--> IDENTIFIER ---+---------------------------------+---> | | | | +--> scope-space --> +--> identifier-expression-tail -->

Remark. The IDENTIFIER in the rule is name of an object, or pointer to an object.

identifier-expression-tail --->>> +--> identifier-member-tail ---+--->
                                  |                              |
                                  +--> identifier-base-tail ----->


                                <--------------------------------------------------------------+
                                |                                                              |
identifier-member-tail --->>> --+--+-----------------+--+--> MEMBER-OPERATOR --> member-name --+--+--------------------------------------+-->
                                   |                 |  |                                         |                                      |
                                   +--> array-cell -->  |                                         +--> BASE-OPERATOR --> space-base --+-->
                                                        |                                                                             |
                                                        <------------------------------- RESOLVER ------------------------------------+




                              <---------------------------------------------------------------------------------------------------------------------------------------------+
                              |                                                                                                                                             |
identifier-base-tail --->>> --+--+-----------------+--> BASE-OPERATOR ---> space-base --+--------------------------------------------------------------------------------+--+-->
                                 |                 |                                    |                                                                                |
                                 +--> array-cell -->                                    +--> RESOLVER --> member-name --+---------------------------------------------+-->
| |
+--+--> MEMBER-OPERATOR --> member-name ---+--> | | <---------------------------------------+

Remark. identifier-member-tail begins with MEMBER-OPERATOR to reach a member, but identifier-base-tail begins with BASE-OPERATOR. However, they both end by reaching either a base or a member.


array-cell --->>> --+--> [ --> expression-statement --> ] ---+--->
                    |                                        |
                    <----------------------------------------+


space-base --->>> --+------------------------------------------+--> base-name ---+-->
                    |                                          |                 |
                    +---> space-name --+----> RESOLVER -----+-->                 |
                    |                  |                    |                    |
                    |                  <---- space-name <---+                    |
                    |                                                            |
                    <---------------------- RESOLVER <---------------------------+

constructor-expression --->>> declaration-type --->  ( ---> argument-list ---> ) --->



argument-list --->>> ---+-----------------------+--> | | +--+--> argument ---+---> | | <--- COMMA <-----+

Remark. constructor-expression can be viewed as the literal representation of an instance of a type. For instance, 'type-name(some-arg, 35, 7.8)' is an instance of type-name, with its literal value shown via three arguments. Similarly, int(4) is an object of type int with value of 4.


Casting


The special cases of full-cast can be done with simpler forms of casting, the simple-cast and the pointer-cast, with identical semantics. However, the full-cast can do more (examples follow):
1. Moving up/down in a derivation tree.
2. Casting away or adding const to reference return of conversion operator.


cast-expression --->>> +--> full-cast ------+--->
                       |                    |
                       +--> simple-cast ---->
                       |                    |
                       +--> pointer-cast --->


full-cast --->>> CAST ---> ( ---> full-cast-type ---> COMMA ---> expression-statement ---> ) --->



full-cast-type --->>> ---+--------------+--> typedef-type --+----------+-->
                         |              |                   |          |
                         +---> CONST --->                   +---> & --->


Examples

1. Moving up/down in a derivation tree.

First we need to define the following types (lefBase, rightBase, middle, derived)


// Definition of leftBase

struct lefBase int i; lefBase(int); end; lefBase::lefBase(int n) i = n; end;
// Definition of rightBase

struct rightBase double d; rightBase(double); end; rightBase::rightBase(double b) d = b; end;
// Definition of middle

struct middle : lefBase, rightBase short s; middle(short, int, double); end; middle::middle(short t, int n, double b) : lefBase(n), rightBase(b) s = t; end;
// Definition of derived
struct derived : middle string g; derived(string, short, int, double); end; derived::derived(string h, short t, int n, double b) : middle(t, n, b) g = h; end;
// Now the sample code. derived drv("Hello", 7, 47, 97.47);
// Since conversion operator cannot return a base, cast is useful in getting // a copy of base. lefBase lbs = cast(lefBase, drv); output << lbs.i << '\n'; // prints 47
// Without pointer, cannot move down to a derived type. Only up to a base type. //middle mdl = cast(middle, lbs); // error
// Pointers can move up or down. Moving up to a base. derived* drvp = new derived("Hello", 7, 47, 97.47); lefBase* lbsp = cast(lefBase*, drvp); output << lbsp->i << '\n'; // prints 47
// From that base, moving down to a derived. middle* mdlp = cast(middle*, lbsp); output << mdlp->s << '\n'; // prints 7
// And from there again up to the other base. rightBase* rbsp = cast(rightBase*, mdlp); output << rbsp->d << '\n'; // prints 97.47

Remark. Casting unrelated pointers via full-cast is identical to pointer-cast, which is the same as C-casting.


2. Casting away or adding const to reference return of conversion operator.

When conversion operator returns a const reference, you can cast away the const.
For instance, let the following be a conversion operator for some type.


operator const member& (void) cast;

First, the cast specification does not allow implicit conversion. For that reason you will need to use explicit cast. Second, with or without the cast specification you can remove the const from the return of the conversion operator.

cast(member&, object);

The above will invoke the conversion operator on the object, and return a none-const reference to member.
On the other hand, if the return of conversion operator was not const, you could make it const.

cast(const member&, object);

The above will make the return const, even if conversion operator simply returns a reference (not constant).


simple-cast --->>> declaration-type ---> ( ---> expression-statement ---> ) --->


Remark. Unlike constructor-expression simple-cast takes exactly one argument. So in this respect simple-cast is a special case of constructor-expression. However, simple-cast is a conversion and goes in both directions. When its argument provides a conversion operator, it will invoke that operator. The expression 'int(4.7)' is a simple-cast which results in an object of type int with literal value of 4. On the other hand, 'int(4)' is a constructor-expression.


pointer-cast --->>> ( ---> pointer-cast-type ---> ) ---> expression-statement --->


pointer-cast-type --->>> ---+--------------+--> typedef-type --+--------------+--->
                            |              |                   |              |
                            +---> CONST --->                   +--+--> * ---+->
                                                                  |         |
                                                                  <---------+


Remark. Here, pointer-cast-type must evaluate to a pointer type. pointer-cast is C-style of casting for pointer types only. Thus, the object resulting from expression-statement must be of pointer type. Also note that a pointer of requested type is returned, pointing to the same address. That means, the object pointed to is not changed.


size-expression --->>> SIZE --> ( --> size-arguments --> ) -->


size-arguments --->>> +--> expression-statement ---+-------------------------------------+--> | | | | +--> COMMA --> expression-statement --> | | +--> TYPE-ID ------------------------------------------------------> | | +--> canvas-name ---> RESOLVER ---> entity-name ------------------->


Remark. entity-name is an IDENTIFIER for a control in canvas, such as a list or a combo-box.
TYPE-ID is name of a numeric fundamental-type (from char to double).
Exmaples below illustrate the use of size.


1. size ( expression-statement ). The argument must evaluate to a string object.
   The length of string is returned as an int object.

string s = "Hello"; int length = size(s);

2. size ( expression-statement , expression-statement ). The first argument is a dynamic array, and the second its dimension. The size of requested dimension is returned, as an int object. The first dimension is 0, second is 1, etc.
int m = 3, n = 5;
// Create a two-dimensional dynamic array of doubles, and initialize all cells // with 47.97.

double da[m][n](47.97); if (size(da, 1) > size(da, 0)) output << "second dimension is bigger\n"; endif;
3. size ( numeric-type ). For instance, size(long) is 8.
4. size ( canvas-name :: entity-name ). If entity is a list or a combo-box that belongs to the canvas, size() will return the number of elements in the entity.


new-expression --->>> NEW ---> typedef-type ---+----------------------------------+---> | | +--> ( ---> argument-list ---> ) -->


operator-expression --->>> ---+---------------------------+--> expression-statement ---+----------------------+---> | | | | +--+--> UNARY-OPERATOR --+--> +--> UNARY-OPERATOR ---> | | <---------------------+


Remark. Simple examples for operator-expression are "*p++" and "++*p", where identifier p is the expression-statement.


call-expression --->>> call-statement ---+---------------------------------+--->
                                         |                                 |
                                         +--> expression-statement-tail --->


call-statement --->>> +--> function-call ---+--->
                      |                     |
                      +--> method-call ----->


function-call --->>> +--> regular-function-call --------+--->
                     |                                  |
                     +--> instantiated-function-call --->


regular-function-call --->>> scope-space ---> function-name ---> ( ---> argument-list ---> ) --->


Remark. function-name is an IDENTIFIER for name of a previously defined function.


instantiated-function-call --->>> scope-space ---> function-name ---> instantiation-list ---> ( ---> argument-list ---> ) --->


instantiation-list --->>> LESS --+--> declaration-type ---+--> MORE --->
                                 |                        |
                                 <-------- COMMA ---------+



Remark. instantiated-function-call corresponds to template-function-definition. For an example of instantiated-function-call, see instantiated-function-type.


method-call --->>> +--> plain-method-call ------+--->
                   |                            |
                   +--> self-method-call ------->
                   |                            |
                   +--> regular-method-call ---->
                   |                            |
                   +--> object-method-call ----->



plain-method-call --->>> +--> method-name --------------------+--> ( ---> argument-list ---> ) --->
                         |                                    |
                         +--> OPERATOR ---> operator-symbol -->


self-method-call --->>> SELF --> DOT --> plain-method-call -->


Remark. plain-method-call is calling a method of the type, within another method of the type, and is equivalent to self-method-call. Syntactically, plain-method-call is same as regular-function-call.

regular-method-call --->>> identifier-expression ---> BELONG-OPERATOR ---> plain-method-call --->


Remark. When calling a method of a base, identifier-expression would be the name of the base on which the method is called.


object-method-call --->>> IDENTIFIER ---> ( ---> argument-list ---> ) --->


Remark. IDENTIFIER is the object on which the overloaded () is called. The syntax is same as regular-function-call, and is therefore not a new syntactic construct. However, the IDENTIFIER here is the name of an instance of a type, making the semnatics significantly different. Note that, operator() can also be invoked as in regular-method-call, as shown below.

"objectName.operator()(arguments)" or "objectName->operator()(arguments)"




conditional-expression --->>> boolean-expression ---> QUESTION ---> expression-leg ---> COLON ---> expression-leg --->

Remark. The type of object resulting from the two expression-legs must be the same. When boolean-expression evalutes to True, the object resulting from the expression-leg of QUESTION will be the object for the conditional-expression. Otherwise, the object for the conditional-expression will be the one resulting from the expression-leg of COLON.

The object resulting from conditional-expression can be of any type, including dynamic array of structural types, so long as assignment is permissible for the type. For instance, task and mutex cannot be assigned.


Action Statements


action-statement --->>> +---> jump-statement ------+---> SEMI-COLON
| |
+---> delete-statement ---->
| |
+---> destroy-statement --->
| |
+---> raise-statement ----->
| |
+---> signal-statement ---->
| |
+---> tell-statement ------>
| |
+---> using-statement ----->
| |
+---> endusing-statement -->




Deleting Objects



delete-statement --->>> DELETE ---> identifier-expression -->

destroy-statement --->>> DESTROY ---> identifier-expression -->


Reamrk. A common member is initialized using common-name as in common-member-initialization. Delete and destroy also use common-name for their argument. Note that common-name is included in identifier-expression.

Remark. The identifier expression for argument of delete and destroy must evaluate to a pointer object.
Delete will raise exception when deleting a null pointer.
Destroy will ignore a null pointer. In addition, destroy applies delete recursively, as shown in example below.


Example

// Example illustrates the recursive action of destroy.

#include<iostream.h>
using namespace ioSpace;

// Define a structure

struct value
int i;

value(int);
~value(void);
end;

value::value(int n)
// constructor
i = n;
end;

value::~value(void)
// destructor
output << "In value::~value(void)\n";
end;

// typedefs for declaring array object vip

typedef valuePointer value*;
typedef valuePointerPointer value**;
typedef ArrayValuePtr valuePointerPointer[3];

// typedef is for operand of new operator

typedef ArrayValuePtrPointer ArrayValuePtr*;

// The main() entry point

entry void main(void)

output << "Hello World!\n";

// sizes for a two dimensional dynamic array

int first = 3, second = 2;

// vip is a two dimensional dynamic array. Cells of vip are two-level
// pointers to ArrayValuePtr, which is a static array of two-level
// pointers to objects of type value.

ArrayValuePtr** vip[first][second];

// Initialize vip

for (int one = 0; one < first; one++)
for (int two = 0; two < second; two++)

vip[one][two] = new ArrayValuePtrPointer(new ArrayValuePtr);

for (int index = 0; index < 3; index++)
(**vip[one][two])[index] = new valuePointer(new value(777));
endfor;

endfor;
endfor;

// Having used vip, now we can delete all objects, recursively. The
// following will call the destructor of value 18 times as can be
// seen from the output of destructor.

output << "\nStart of destroy.\n\n";

destroy vip;

output << "\nGood-bye World!\n";

end;


The output of this example is as follows.

Hello World!

Start of destroy.

In value::~value(void)
In value::~value(void)
In value::~value(void)
In value::~value(void)
In value::~value(void)
In value::~value(void)
In value::~value(void)
In value::~value(void)
In value::~value(void)
In value::~value(void)
In value::~value(void)
In value::~value(void)
In value::~value(void)
In value::~value(void)
In value::~value(void)
In value::~value(void)
In value::~value(void)
In value::~value(void)

Good-bye World!



Signaling and Exception



raise-statement --->>> RAISE --> ( --> EXCEPTION-LITERAL --> ) -->


Remark. For an example of raising an exception see the example for layer-statement.



signal-statement --->>> SIGNAL ---> BACK-ARROW ---> EVENT-LITERAL -->


signal-expression --->>> SIGNAL ---> ? ---> EVENT-LITERAL -->


Signals. The kind of signals that can be generated via the signal statement are defined in system include file "exception.h", and are as follows.
signalEventType, universalEventType, threadEntireEventType, processEntireEventType.

Literals of signalEventType and universalEventType will be indicated as SIGNAL-LITERAL.

Catching signals of threadEntireEventType and processEntireEventType requires registeration via accepts() statement. Literals of these kind of signals will be indicated as ACCEPT-SIGNAL.

When referring to either kind of signal, a literal will be indicated by EVENT-LITERAL.

Remark. signal-expression is an expression evaluating to True or False. The expression evaluates to True only when the signal has arrived.


Example


// The main thread and a global thread communicate via signals.

#include<iostream.h>
using namespace ioSpace;

#include<exception.h>
using namespace exceptionSpace;

// Make singals for communication between threads

enum userSignals : signalEventType {
_SIGNAL_FirstActionSignal,
_SIGNAL_SecondActionSignal,
_SIGNAL_TerminationSignal,
_SIGNAL_CompletionSignal
};

// Define a global thread

void globalThread(double d, string& s)<thread>

output << "Thread is waiting for action...\n";

// Wait until a signal arrives, and when it does perform the action

do
if (signal ? _SIGNAL_FirstActionSignal)
output << "Value of double is: " << d << '\n';
elsif (signal ? _SIGNAL_SecondActionSignal)
output << "The string is: " << s << '\n';
elsif (signal ? _SIGNAL_TerminationSignal)
output << "Terminating...\n";
break;
endif;
enddo;

// Tell main() we are done

signal <- _SIGNAL_CompletionSignal;

end;

// The main() entry point

entry void main(void)

output << "Hello World!\n";

string announcement = "All is well!";

output << "main(): starting the thread...\n";

// Start the global thread
globalThread(4.7, announcement);

// Tell thread to do action one

signal <- _SIGNAL_FirstActionSignal;

// Tell thread to do action two

signal <- _SIGNAL_SecondActionSignal;

// Tell thread to terminate

signal <- _SIGNAL_TerminationSignal;

// Wait until thread terminates

do enddo(signal ? _SIGNAL_CompletionSignal);

output << "\nGood-bye World!\n";

end;


The output of this example is as follows.

Hello World!
main(): starting the thread...
Thread is waiting for action...
Value of double is: 4.7
The string is: All is well!
Terminating...

Good-bye World!


Tell and Hear


Tell and Hear signaling is intended for distributed signaling with data transfer. The object hear-signal in following rules is of type tellSignalType defined in system header file "exception.h".

A process intending to catch a (tell) hear signal must have one of its threads register the signal via hears-list.



tell-statement --->>> TELL --> BACK-ARROW --> hear-signal --> tell-tail --->


Remark. tell-statement sends signals. Before the signal and its associated data are sent, local Z47 Processor informs the remote Z47 that it is going to send it the signal. If a process on the remote Z47 has registered the signal, it will accept the request. Otherwise the remote Z47 will reject the signal. If a signal is rejected, the local Z47 will raise the exception _EXCEPTION_SIGNAL_SignalNotRegistered.



tell-tail --->>> +-------------------+--+---------------------------+--+-----------------------------+-->
| | | | | |
+---> $ ---> URL ---> +---> COMMA ---> PROCESS ---> +--> COLON --+--> OBJECT --+-->
| |
<--- COMMA <--+

Remark. URL is the IP address of remote process. PROCESS is the name of process to receive the signal.

OBJECT is an IDENTIFIER for name of an object being sent along with the signal. The type of object must match the type indicated in hears-list. The order and type of objects must be same as those indicated in hear-list, the same way a function is called. In case of type mismatch the signal will not be sent and the local Z47 raises exception _EXCEPTION_SIGNAL_TellOperandTypeMismatch.




hear-expression --->>> HEAR ---> ? ---> hear-signal --+-----------------------------+-->
| |
+--> COLON --+--> OBJECT --+-->
| |
<--- COMMA <--+


Remark. hear-expression catches signals sent by a tell-statement. When hear-expression catches an arrived signal it evaluates to True. Otherwise, hear-expression evaluates to False.
OBJECT is an IDENTIFIER as explained in above remark for tell-tail.


Example


This example consists of two source files: Tell.zpp runs on local node, and Hear.zpp runs on the remote node. The header file TellHear.h is included in both source files.
It is important that  the program Hear.zpp starts as a remote process (Hear.zxe) before the local process Tell.zxe begins. The remote process must register the signals before it can catch them.


// TellHear.h

#include<iostream.h>
using namespace ioSpace;

#include<exception.h>
using namespace exceptionSpace;

// Make some plain signals

enum MyOwnSignals : signalEventType {
_SIGNAL_Thread_started,
_SIGNAL_Thread_ended
};

// Define a few tell/hear signals

enum MyTellSignals : tellSignalType {
_SIGNAL_telling_1,
_SIGNAL_telling_2,
_SIGNAL_telling_3,
_SIGNAL_telling_4,
_SIGNAL_telling_5,
_SIGNAL_telling_6,
_SIGNAL_telling_7
};

// Types of object to be sent along with signal

enum simpleEnum { // an enumeration
_SIMPLE_enum_1,
_SIMPLE_enum_2,
_SIMPLE_enum_3
};

struct argumentType
// a simple structure
int n;
double d;

argumentType(void);
argumentType(int, double);
end;

argumentType::argumentType(void)
n = 2;
d = 8.9;
end;

argumentType::argumentType(int nn, double dd)
n = nn;
d = dd;
end;

struct imbeddedType
// a structure with string/enumeration members
simpleEnum e;
string s;

imbeddedType(void);
imbeddedType(simpleEnum, string);
end;

imbeddedType::imbeddedType(void)
e = _SIMPLE_enum_1;
s = "I am member of imbeddedType";
end;

imbeddedType::imbeddedType(simpleEnum ee, string ss)
e = ee;
s = ss;
end;


The source for the local example.



//Tell.zpp

#include "TellHear.h"

string url = "192.168.1.64";
// The IP of remote Z47

// The main() entry point

entry void main(void)
output << "Teller: Hello World!\n";

// Declare objects for sending with signal

string s = "I am sent by teller.";
simpleEnum se = _SIMPLE_enum_2;
argumentType at(777, 22.33);

// Send signals

tell <- _SIGNAL_telling_3 $ url: at;
tell <- _SIGNAL_telling_4 $ url: se, s;

// Declare and set values for objects to send

se = _SIMPLE_enum_3;
imbeddedType it(se, "Teller string.");

// Send the signal

tell <- _SIGNAL_telling_5 $ url: it;

output << "Teller: Good-bye World!\n";
end;



The source for the remote example.


// Hear.zpp

#include "TellHear.h"

// The thread that registers to receive signals

void hearFun(void)<thread>
hears(
_SIGNAL_telling_3<argumentType>,
_SIGNAL_telling_4<simpleEnum, string>,
_SIGNAL_telling_5<imbeddedType>)

// Declare objects to receive data associated with signal _SIGNAL_telling_3.

argumentType at;

do enddo(hear ? _SIGNAL_telling_3 : at);

output << "(hearFun) Values received for _SIGNAL_telling_3 ...\n";
output << "argumentType.n is: " << at.n << '\n';
output << "argumentType.d is: " << at.d << '\n';

output.flush();

// Declare objects to receive data associated with signal _SIGNAL_telling_4.

simpleEnum se;
string s;

do enddo(hear ? _SIGNAL_telling_4 : se, s);

output << "(hearFun) Values received for _SIGNAL_telling_4 ...\n";
output << "simpleEnum is: " << [se] << '\n';
output << "string is: " << s << '\n';

output.flush();

// Declare objects to receive data associated with signal _SIGNAL_telling_5.

imbeddedType it;

do enddo(hear ? _SIGNAL_telling_5 : it);

output << "(hearFun) Values received for _SIGNAL_telling_5 ...\n";
output << "imbeddedType.e is: " << [it.e] << '\n';
output << "imbeddedType.s is: " << it.s << '\n';

output.flush();

// Inform main() we are done

signal <- _SIGNAL_Thread_ended;

end;

// The main() entry point

entry void main(void)

output << "Hearer: Hello World!\n";

hearFun();
// begin thread to register and catch signals

// Wait until thread informs us that it is done.

do enddo(signal ? _SIGNAL_Thread_ended);

output << "Hearer: Good-bye World!\n";

end;




Using Statement


Using statement can open an entire namespace, exporting all its public items. It can also be used for exporting specific items. Endusing closes an opened namespace, or ends the exportation of an item.


using-statement --->>> USING --+--> NAMESPACE ---> space-name ----------------+-->
| |
+--> space-name --> RESOLVER --> export-item -->


endusing-statement --->>> ENDUSING --+--> NAMESPACE ---> space-name ----------------+-->
| |
+--> space-name --> RESOLVER --> export-item -->


Remark. space-name is an IDENTIFIER for name of a previously defined namespace.


export-item --->>> +---> declaration-type ----+--->
| |
+---> typedef-name -------->
| |
+---> export-function ----->
| |
+---> function-pointer ---->
| |
+---> export-object ------->


Remark. Only public items that belong to a namespace can be eported. For instance declaration-type includes fundamental types, which do not belong to any namespace and therefore cannot be exported.

typedef-name is the IDENTIFIER in typedef-definition for the name of typedef.

function-pointer is IDENTIFIER for function-name in function-type-definition, as explained there. For instance, for regular-function-type this is just the name of the function-prototype.

export-object is an IDENTIFIER for an object declared in the namespace.


export-function --->>> function-name ---> prototype-parameter-list -->

Remark. Methods and global operators defined in a namespace cannot be exported. In order to export a function its pure prototype, as shown by above rule must be used because the name of the function may be overloaded. function-name is the IDENTIFIER used in the definition or the prototype of the funtion.


Example


The following example illustrates exporting namespace items.



#include<iostream.h>
using namespace ioSpace;

// Define a namespace for exporting some instantiated items.

namespace templateSpace

template<type T> struct test
T t;

test(T);
T method(T);
end;

template<type T> test::test(T u)
t = u;
end;

template<type T> T test::method(T u)
return t + u;
end;

typedef dblTest test<double>;
// typedef an instantiation

template<type T> T templateFun(T t)
return t + 7;
end;

type instantiatedFunPointer templateFun<int>;

endspace;

// Define a namespace for exporting various items.

namespace someSpace

int i = 55;

int fun(int n, double b)
return ++n;
end;

type int funPtrType(int, double);
// define a function pointer

funPtrType funPtrObject = fun; // create an initialized instance

struct check
int i;

check(int);
int method(int);
end;

check::check(int n)
i = n;
end;

int check::method(int n)
return i += n;
end;

check checkInstance(45);

typedef CheckType check;

endspace;

// The main() emtry point.

entry void main(void)

output << "Hello World!\n";

// Exporting instantiated typedef

using templateSpace::dblTest;
dblTest DT(4.7);
output << DT.method(1.3) << '\n';
endusing templateSpace::dblTest;

// Exporting instantiated call

using templateSpace::instantiatedFunPointer;
output << instantiatedFunPointer(3) << '\n';
endusing templateSpace::instantiatedFunPointer;

// Exporting an instance of funcamental type

using someSpace::i;
output << i << '\n';

// Exporting a function

using someSpace::fun(int, double);
output << fun(i, 2.1) << '\n';

endusing someSpace::i;
endusing someSpace::fun(int, double);

// Exporting an instance of a user-defined type

using someSpace::checkInstance;
output << checkInstance.method(5) << '\n';
endusing someSpace::checkInstance;

// Exporting typedef

using someSpace::CheckType;
CheckType CT(47);
output << CT.method(50) << '\n';
endusing someSpace::CheckType;

// Exporting a function pointer

using someSpace::funPtrObject;
output << funPtrObject(7, 2.1) << '\n';
endusing someSpace::funPtrObject;

// Exporting a function, and a function pointer type

using someSpace::fun(int, double);
using someSpace::funPtrType;
funPtrType localFun = fun;
output << localFun(7, 2.1) << '\n';
endusing someSpace::fun(int, double);
endusing someSpace::funPtrType;

output << "\nGood-bye World!\n";

end;

The output of this example is as follows.

Hello World!
6
10
55
56
50
97
8
8

Good-bye World!

Jump Statements



jump-statement --->>> +---> return-statement -----+--->
| |
+---> break-statement ------>
| |
+---> continue-statement --->
| |
+---> resume-statement ----->
| |
+---> repeat-statement ----->



return-statement --->>> RETURN --+----------------------------+--->
| |
+--> expression-statement --->


Remark. The return statement ends execution of a function/method and returns to caller.



break-statement --->>> BREAK --+-------------------------------------+--->
| |
+--> ( --> boolean-expression --> ) -->


Remark. The break statement without boolean-expression can only appear in an iteration-statement. It exits the iteration statement in which it appears and passes control to the statement following the iteration statement.

The break statement with boolean-expression will only execute during a debug execution. When the boolean expression becomes true, execution will stop, acting like a break point has been visited.




continue-statement --->>> CONTINUE


Remark. The continue statement can only appear in an iteration-statement. When continue is visited, control goes to the start of iteration statement, skipping all the statements within iteration statement that follow the continue statement. However, n case of for-loop, continue does not skip the third section, usually used for incremment or decrementing the loop-counter.



Resumption


The resume and repeat statements can only appear in the handler section of a layer-statement. They return control to the body of layer-statement.


resume-statement --->>> RESUME

Remark. The resume statement returns control to the statement after the one that caused exception to occur.


repeat-statement --->>> REPEAT


Remark. The repeat statement return control to the statement that caused the exception.


Example

// This example contains nested layers. The inner layer statement uses resume.
// The outer layer uses repeat for resumption.

#include<iostream.h>
using namespace ioSpace;

#include<exception.h>
using namespace exceptionSpace;

// A function for raising exception _EXCEPTION_DivisionByZero.

int globalFun(int f, int s)
f /= s; // raises exception when s == 0
return 47;
end;

// The main() entry point.

entry void main(void)
output << "Hello World!\n";

int i = 10;
int j = 0;

layer<exceptionEventType>

output << "Starting layer.\n";

int ret = 777;

// Next statement will cause _EXCEPTION_DivisionByZero to happen.
// Then, repeat will come back here and make the function call again.

ret = globalFun(i, j);

// Will not execute first round

output << "ret is: " << ret << '\n';

handler

case _EXCEPTION_DivisionByZero:

// This is a nested layer inside of a case leg.
// resume and repeat within each handler go to the body
// of the layer containing them.

int k;

layer<exceptionEventType>

k = 0;
i / k;
// raises exception

// resume comes back here, skipping the above statement

output << "Succeeded in nested layer.\n";

handler

case _EXCEPTION_DivisionByZero:
output << "Caught _EXCEPTION_DivisionByZero in nested layer\n";

// We go back and resume at statement after the one that raised
// exception, i.e. after the statement "i / k".

resume;

endlayer;

output << "Caught _EXCEPTION_DivisionByZero\n";

// Repair cause of exception and repeat the call to globalFun()
// in the outer layer.

j = 5;
repeat;

endlayer;

output << "Good-bye World!\n";
end;


The output of this example is as follows.


Hello World!
Starting layer.
Caught _EXCEPTION_DivisionByZero in nested layer
Succeeded in nested layer.
Caught _EXCEPTION_DivisionByZero
ret is: 47
Good-bye World!


Database


A Z++ program can simultaneously interact with multiple databases, and multiple users can interact with each database.
The system include file "Database.h" defines all needed types. For each database connection, an instance of databaseType and databaseUserType must be created. Z++ database statements use the instance of databaseUserType.

The following terminology is used with regard to database statements.

Table is name of a table in a database.
Field is name of a column in a Table.
Pure-Expression is a Z++ expression free of database Tables and Fields. In a database statement, a Pure-Expression must be enclosed between {}. The Compiler will replace a Pure-Expression with its resulting object before sending it to the database.

Consider a database query. The result of query is a set of rows in a Table. Now, think of a container class, such as a List Template Class. Ideally, we want the query to insert all the rows into an instantiation of the List.
The type of instantiator for List would be a class, with members that match the Fields of a row. We refer to the instantiator as the Catalyser. The instantiated instance of the List template is the Container object. The method of Container that we user to insert instances of Catalyser into the Container is the Filler-Method. Note that Catalyser is a type (an instantiator).

A Z++ query uses the following mapping-clause.


mapping-clause --->>> --+--> Table --> DOT --> Field ---> LESS ---> catalyser-member ---> MORE --+-->
| |
<----------------------------- COMMA <-----------------------------------+


Table and Field are IDENTIFIERS for items in the database, and "Table.Field" is a column in the table. catalyser-member is an IDENTIFIER for the name of a member of Catalyser. A mapping-clause tells the query which Fields of the row are mapped to which members of the Catalyser.



argument-clause --->>> LESS ---> database-object ---> COMMA ---> Catalyser ---> COLON --+--> Table --+--> MORE --->
| |
<-- COMMA <--+


Remark. When multiple Tables are used, query will be on the join of tables.
database-object is an instance of library class databaseUserType.


using-clause --->>> USING --> Container --> COMMA --> Filler-Method -->


Remark. The following, where and set clauses, are SQL language clauses used in Z++ statements.



where-clause --->>> WHERE ---> ( ---> database-expression ---> ) --->


Remark. database-expression is an SQL expression, which can contain Z++ Pure-Expressions.




set-clause --->>> SET ---+---> Field ---> = ---> value ---+-->
| |
<------------ COMMA <------------+


Remark. Value is a literal, or a Z++ Pure-Expression. Literals are NUMERIC-LITERAL, CHAR-LITERAL or STRING-LITERAL.


Database Statements



database-stament --->>> +---> database-select ---+-->
| |
+---> database-fetch ---->
| |
+---> database-free ----->
| |
+---> database-insert --->
| |
+---> database-update --->
| |
+---> database-remove --->



Database Select Statement


The database select statement performs a query and inserts the result of query into a container.



database-select --->>> DATABASESELECT ---> argument-clause ---> mapping-clause --+-------------------+--> using-clause -->
| |
+--> where-clause -->


Remark. The key word DATABASESELECT is spelled with a single upper-case letter "databaseSelect".



databseSelect Example


The following example illustrates the syntax and the terminology. The example uses a Postgres database.


// Include some needed system header files.

#include<Iterator.h> // For List template and Iterator

#include<iostream.h>
using namespace ioSpace;

#include<database.h>
// For database library objects
using namespace databaseSpace;

#include<exception.h>
using namespace exceptionSpace;


// The following parameters need to be set for connecting to a Postgres Server.

string dbServerIP = "127.0.0.1"; // IP address of Server
int dbPort = 5432; // port number
string databaseName = "database-name"; // Database name
string userName = "your-user-name"; // User login name
string userPassWD = ""; // password if needed

// ------------------------------------------------------------------------- //
// We assume, for this example, that there is a table in the database called
// "users", which has six fields: Name, Last, height, Weight, Gender, Age.
// ------------------------------------------------------------------------- //
// We use this structure for mapping the six fields of the table mentioned
// above to members of a Z++ object. You can define any class with methods to
// do whatever you like. This is only an illustration.
// ------------------------------------------------------------------------- //

struct element
string first;
// maps to Name
string last; // Last
float height; // height
double weight; // Weight
char sex; // Gender
short age; // Age
end;

///////////////////////////////////////////////////////////////////////////////
// Start of main() entry point.
// ------------------------------------------------------------------------- //
// _EXCEPTION_EmptyContainer may be raised by Template Library.
// ------------------------------------------------------------------------- //

entry void main(void) throws(_EXCEPTION_EmptyContainer)

using namespace ztlListIteratorSpace;
//open List, Stack and Queue namespaces

List<element> elementList; //instantiate list template with type element (catalyser)

boolean executionFailure = False;

// Outermost exception layer for database connection etc.

layer<exceptionEventType>

databaseType Dbase(dbServerIP, dbPort, databaseName, "", _Database_Kind_Postgres);
databaseUserType Duser(Dbase, userName, userPassWD);

Iterator<element> I;
// Define an Iterator

-elementList; // empty the container before select populates it

// Exception layer for databaseSelect statement.

layer<exceptionEventType>

// Duser was created above. All database statements use this object.
// element is the catalyser.
// users is the table in the database.
// "users.Name<first>" maps the field "Name" of table "users" to "first", and so on
// for the remaining fields.
// The where clause is a database clause.
// Finally, the using clause tells Z++ compiler to use the method "append" of container
// "elementList" to put the rows resulting from query into the container.

databaseSelect<Duser, element : users> // argument-clause
users.Name<first>, // start of mappig-clause
users.Last<last>,
users.height<height>,
users.Weight<weight>,
users.Gender<sex>,
users.Age<age>
// end of mapping-clause
where (Weight < {2 * value}) // Z++ pure-expression enclosed by {}
using elementList, append; // using-clause

handler

case _EXCEPTION_DATABASE_SelectQueryFailed:
executionFailure = True;

case _EXCEPTION_DATABASE_InsufficientMemoryForQueryResult:
executionFailure = True;

case _EXCEPTION_DATABASE_FetchFailed:
executionFailure = True;

endlayer;

if (executionFailure)
output << "Select statement failed.\n";
else
for (I = elementList; I; I++)
output << "Person : ";
output << I.Current().first << ' ';
output << I.Current().last << ' ';
output << I.Current().height << ' ';
output << I.Current().weight << ' ';
output << I.Current().sex << ' ';
output << I.Current().age << '\n';
endfor;
endif;

handler
// This is the handler section for outermost exception layer

case _EXCEPTION_DATABASE_UnsupportedDatabaseKind:
output << "Caught _EXCEPTION_DATABASE_UnsupportedDatabaseKind\n";
executionFailure = True;

case _EXCEPTION_DATABASE_LibraryInitializationFailed:
output << "Caught _EXCEPTION_DATABASE_LibraryInitializationFailed\n";
executionFailure = True;

case _EXCEPTION_DATABASE_ConnectionToServerFailed:
output << "Caught _EXCEPTION_DATABASE_ConnectionToServerFailed\n";
executionFailure = True;

endlayer;

if (executionFailure)
output << "Terminating program due to exception.\n";
else output << "Program ended succefully.\n";
endif;

-elementList;
// empty the container for cleanup

end;



Database Fetch and Free


There are times we do not wish to get the entire result of a query into a container. Instead, we want to examine or process, say 10 rows at a time, and may decide to stop at some point and ignore the remaining rows. For instance, this is useful when using a small handheld device. In this case, we can tell select to populate the container with the first 10 rows, and then use the fetch statement to retrieve 10 rows at a time. Finally, at any point we can use the free statement to discard the remaining rows, if any.
The reason for using fetch is mainly the lack of space on a device, like a smart-phone. The result of a query needs to be downloaded on the device. Thus, getting the result of a query and populating a container are two distinct operations. In case of a handheld device, it is possible to use a Proxy for getting the result of the query, and then retrieving a certain number of rows at a time on a smaller device.



database-fetch --->>> DATABASEFETCH ---> argument-clause ---> mapping-clause ---> using-clause --->


Remark. The keyword DATABASEFETCH is spelled "databaseFetch".
The arguments and operands of fetch are the same as its associated select, except fetch does not need to use a where-clause.
databaseFetch is a boolean expression. It evaluates to False when there are no more rows to fetch. Otherwise it evaluates to True.


database-free ---> DATABASEFREE ---> LESS ---> database-object ---> MORE --->


Remark. The keyword DATABASEFREE is spelled "databaseFree".
database-object is an instance of library class databaseUserType, as used in argument-clause of database select and fetch.


Database Fetch Example


In this example we use the same database table and fields as in the example for select statement. However, we use an Ingres database server and a Proxy. The Proxy is just the Z++ Internet Server.



// Include some needed header files.

#include<Iterator.h>

#include<iostream.h>
using namespace ioSpace;

#include<database.h>
using namespace databaseSpace;

#include<exception.h>
using namespace exceptionSpace;

// Set up parameters for connecting to an Ingres Server.

string dbServerIP = "127.0.0.1"; // Set to IP address of Database Server
int dbPort = 21064; // port number
string databaseName = "database-name"; // Database name
string userName = "your-user-name"; // login name
string userPassWD = ""; // password if needed

systemDatabaseKinds dbKind = _Database_Kind_Ingres;

string vnode = "vnode-name"; // name of virtual node
int FetchSize = 5; // number of rows to fetch

string ZppServerIP = "127.0.0.1"; // IP of Proxy (Z++ Internet Server)

// ------------------------------------------------------------------------- //
// The catalyser for instantiating container (the list elementList).


struct element
string first;
string last;
float height;
double weight;
short age;
char sex;
end;

///////////////////////////////////////////////////////////////////////////////
// The main() entry point.
// ------------------------------------------------------------------------- //

entry void main(void) throws(_EXCEPTION_EmptyContainer)

using namespace ztlListIteratorSpace; //open List, Stack and Queue namespaces
List<element> elementList; //instantiate list template with type element (catalyser).

// Note that we are passing a none-zero FetchSize. This affects select statement
// as explained below. Also since we are providing the last argument for proxy,
// the ZppServerIP, calls will go through a proxy.

databaseType Dbase(dbServerIP, dbPort, databaseName, vnode,
dbKind, FetchSize, ZppServerIP);

databaseUserType Duser(Dbase, userName, userPassWD); // session begins here

// When FetchSize is 0 (default), select statement gets the entire result of the
// query in one pass, and puts it into the container elementList using its method
// append. For any positive value, select will only get as many rows. The remaining
// rows must be gotten using fetch, as illustrated later below.

databaseSelect<Duser, element : users>
users.Name<first>,
users.Last<last>,
users.Age<age>,
users.Gender<sex>,
users.height<height>,
users.Weight<weight>
using elementList, append;

element et;

// Now, for each iteration of the do loop, we output the values we have gotten in
// the container. Note that, method Head() removes the object from the container
// elementList, and that operator+() gets the number of elements in the container.

do

output << "Printing fetched rows.\n\n";

while (+elementList > 0)
et = elementList.Head();
output << "Person : ";
output << et.first << ' ';
output << et.last << ' ';
output << et.age << ' ';
output << et.sex << ' ';
output << et.height << ' ';
output << et.weight << '\n';
endwhile;

// After emptying the container, we fetch the next set of rows. Fetch will get as
// many rows as the number FetchSize. When there is nothing to fetch, the fetch
// expression returns False.
// Fetch uses the exact same syntax and operand as its associated select.
// However, select can also have a where-clause, but not fetch.

if (!databaseFetch<Duser, element : users>
users.Name<first>,
users.Last<last>,
users.Age<age>,
users.Gender<sex>,
users.height<height>,
users.Weight<weight>
using elementList, append)
break;
endif;

enddo;

// Since we are repeating fetch until all data is retrieved, the following
// is not needed. However, if used, must only come after fetch, in particular
// when we do not intended to retrieve the remaining rows. Free simply discards
// the remaining rows.

databaseFree<Duser>;

end;


Database Insert, Update and Remove


Remark. The mapping-clause only needs to map the fields used in the following statements. This also true for select statement. However, select normally uses more fields.



database-insert --->>> DATABASEINSERT ---> argument-clause ---> mapping-clause ---> USING ---> catalyser-instance --->


Remark. DATABASEINSERT is spelled "databaseInsert". catalyser-instance is explained in the example, below.



database-update --->>> DATABASEUPDATE ---> argument-clause ---> mapping-clause ---> set-clause --+-------------------+-->
| |
+--> where-clause -->


Remark. DATABASEUPDATE is spelled "databaseUpdate".



database-remove --->>> DATABASEREMOVE ---> argument-clause ---> mapping-clause --+--------------------+--->
| |
+--> where-clause --->



Remark. DATABASEREMOVE is spelled "databaseRemove". Without a where-clause nothing will be removed.



Insert, Update and Remove Examples


We use databaseSelect Example, and only illustrate the statements as they would appear there.


// In all three examples, elementList is an instantiation of List template
// using element (catalyser) as instantiator.
// I is an Iterator.

//////////// databaseInsert

for (I = elementList; I; I++)

layer<exceptionEventType>

// The using leg for insert is not the same using-clause of select. After "using" we need
// an object, an instance of element (the catalyser). "I.Current()" is the object in the
// container currently pointed to, by the Iterator I.

databaseInsert<Duser, element : users> // argument-clause
users.Name<first>, // mapping-clause
users.Last<last>,
users.height<height>,
users.Weight<weight>,
users.Gender<sex>,
users.Age<age>
using I.Current(); // using for insert

handler

case _EXCEPTION_DATABASE_InsertRequestFailed:
output << "Insertion of " << I.Current().first << " failed\n";
resume; // continue with next insert

endlayer;

endfor;


//////////// databaseUpdate

layer<exceptionEventType>

for (I = elementList; I; I++)

if (I.Current().first == "Cheeta")

// For mapping-clause, we only need to specify the fields we need for the database statement.
// The where-clause uses pure-expression (a Z++ expression enclosed with {}).

databaseUpdate<Duser, element : users> // argument-clause
users.Name<first>, // mapping-clause
users.Last<last>

set Name = "Jack", Last = "Jackson" // set-clause
where (Name == {I.Current().first}); // where-clause

endif;

endfor;

handler

case _EXCEPTION_DATABASE_UpdateRequestFailed:
output << "Update of " << I.Current().first << " failed\n";
resume; // continue with next update

endlayer;


//////////// databaseRemove


layer<exceptionEventType>

for (I = elementList; I; I++)

// The mapping-clause has only one field. The where-clause uses pure-expression, enclosed with {}.

if (I.Current().first == "Tarzan" ||
I.Current().first == "Jane" ||
I.Current().first == "Jack")

databaseRemove<Duser, element : users> // argument-clause
users.Name<first> // mapping-clause
where (Name == {I.Current().first}); // where-clasue

endif;

endfor;

handler

case _EXCEPTION_DATABASE_RemoveRequestFailed:
output << "Removal of " << I.Current().first << " failed\n";
resume; // continue with next delete

endlayer;



Operator Precedence

This section illustrates various categories of Z++ operators, their associativity and precedence.

The rules of associativity and precedence simplify expressions by reducing the use of parentheses. Precedence applies to the order of evaluation between two different operators, while associativity applies to consecutive occurrences of same operator.

Two different operators of same precedence are evaluated from left to right, except assignment operators.

Associativity implies that the order of evaluation of several occurrences of the same operator does not change the result. For instance,
     a + (b + c)  is the same as  (a + b) + c.
However, we use the term associativity to imply that several consecutive occurrences of an operator can appear in an expression. Furthermore, in order to indicate the order of evaluation taken by the compiler, we say an operator is left-associative or right-associative.

All associative operators are left-associative except assignment operators, which are right-associative.

Consider the following example.

int i = 5, j = 7, k = 11;
j = k = i; // all objects are set to 5, the value of i

The same result could be obtained by the following declaration.


int i = j = k = 5; // all are set to 5

Binary assignment operators, like +=, are also right-associative, discussed further below.

The following links take you to subsections.


Unary Operators () [] and BELONG-OPERATORS.
Enumeration Bracket Function.
Collection Bracket Function.
Unary Operators.
Arithmetic Operators.
Bitwise Operators.
Relational Operators.
Logical Operators.
Assignment Operators.
Pointer Operators.
Graphic Operators.




1. Unary Operators () and []. and BELONG-OPERATORs, have the highest precedence.

Consider a function call, fun(m, n). First, the expressions m and n are evaluated to reach objects for passing to the call. Once this has been done, only then the operator () is applied to fun (the call is made). Thus, () is a (complex) unary operator.

Similarly, when reaching a cell of an array, say X[n+1], first the expression n+1 is evaluated, and only then the operator [] is applied to the array X. Thus, operator [] is also a (complex) unary operator.

Both of these operators are postfix, appearing on the right of the object to which they are applied. When both operators are applied to the same object, the order of evaluation is from left to right. Also, when the same operator is applied two or more times, the order of evaluation is from left to right. In case of array we usually envisage a multidimensional array, rather than order of evaluation of [].


// Example

#include<iostream.h>
using namespace ioSpace;

// Define a structure with operator() overloaded.

struct CallOverload
int n;
double d;

CallOverload(int, double);
int operator()(int);
double operator()(double);
end;

CallOverload::CallOverload(int t, double b)
n = t;
d = b;
end;

int CallOverload::operator()(int t)
return n+t;
end;

double CallOverload::operator()(double b)
return d + b;
end;

// The main() entry point.

entry void main(void)
output << "Hello World!\n";

int IntArg = 3;
double DoubleArg = 1.3;

// Declare an array of CallOverload.

CallOverload CO[3](47, 7.97);

// First array operator [] is evaluated, then operator () is applied to the cell.

output << CO[1](IntArg) << '\n'; // prints 50
output << CO[0](DoubleArg) << '\n'; // prints 9.27

output << "Good-bye World!\n";
end;


1.1. Other meanings of the operator [].

Operator [] is internally overloaded for other purposes, which we illustrate here. These functions of operator [] are referred to as the bracket function.

1.1.A. The enumeration bracket function, and double-bracket function.

The bracket function applied to an enumeration object evaluates to its integer value.
The bracket function applied to an enumeration type evaluates to an enumeration object with the lowest value.
The double-bracket function applied to an enumeration type evaluates to an enumeration object with the highest value.

Example: Enumeration Bracket Functions

#include<iostream.h>
using namespace ioSpace;

//---------------------------------------------------------------------------//

enum EnumTest {_First = 3, _Second = 5, _Third = 7, _Fourth = 11, _Fifth = 13};

///////////////////////////////////////////////////////////////////////////////

entry void main(void)
output << "Hello World!\n";

// et is initialized with _First, the value of object returned by [EnumTest].
// [[EnumTest]] evaluates to an object with value _Fifth.
// et++ moves to the successor.
// [et] is the integer value of the enumeration object et.

for (EnumTest et = [EnumTest]; et <= [[EnumTest]]; et++)
output << [et] << '\n';
endfor;

output << "\nGood-bye World!\n";
end;


The output of this example is as follows.

Hello World!
3
5
7
11
13

Good-bye World!


1.1.B. The collection bracket function, and collection index.

For a collection object Col, the bracket function [Col] evaluates to a reference to the tag object of collection. This allows changing the value of collection tag (when not specified protected).

The operator [] is also used as collection index, the same way it is used for array index. For a collection object Col, "Col[tag_value]" evaluates to the index-value associated with the ENUM-LITERAL "tag_value" of collection tag.

For an example of these uses of operator [] see Collection-Example, at the definition of method:

"void mostFiguresType::PrintAtTag(void)"

1.1.C. BELONG-OPERATORS.

Belong operators, like operators () and [], are immediately applied to the object on their left.

Consider the expression "X[...](...)->m", where ... is a placehoder for arguments.
First, [...] is applied to object X, yeilding the object "X[...]".
Next, operator (...) is applied to the object "X[...]", returning the object "X[...](...)".
Finally, operator -> is applied to the returned object to reach the member m.

The expression "*p.m" is evaluated by first reaching the member m, and then applying
the operator * to the member m. If instead, you want to apply operator * to p, you need
to use parentheses: "(*p).m", which is equivalent to "p->m".



2. Unary operators have next highest precedence.

Unary operators, with one exception, appear in front of object they are applied to, to which we shall refer as prefix notation. When several unary operators appear in prefix notation, the order of application is from object to its left. That is, first the operator closest to object is applied, then the next operator to its left is applied to the resulting object, etc.

Operators ++ and -- also have a postfix notation (to the right of object). The postfix notation has a special meaning. The postfix operator ++ and -- are applied after the object has been used in the evaluation of the expression in which it appears, or assignment has been done. However, note that postfix ++ and -- are still applied to the object on their left. For instanc, "*p++" means that  ++ is later applied to p, not to "*p". That is not the same thing as "(*p)++", which will apply ++ to "*p".

The meaning of postfix ++ and -- is retained when applied to arrays, and when these operators are overloaded. These will be illustrated by examples.

Below is the list of unary operators and their meaning. Only ++ and -- change their operand. All other operators return the result of applying the operator without changing their operand.

Operators ++ and -- increment/decrement the value of their operand.
For discrete numeric objects, ++ adds one to its operand, and -- subtracts one from its operand.
For pointer operands, ++ moves pointer forward and -- moves it backwards. The distance moved is the size of object pointed to.
For enumeration types, ++ is moves the value of object to its successor, and -- moves its value to its predecessor.

Remark. In general, by "returning a value" we mean " returning an object with given literal value".
The following operators do not change the value of their operand.

Operator ! is logical operator returning the negation of its boolean operand.

Operator * returns the object pointed to by its operand.

Operator & returns the address of its operand (returns a pointer object pointing to its operand).

Operator ~ returns the bit-inverted values of its operand.

Operator - returns the negative value of its operand.

Operator + returns the value of its operand. In general, this operator does nothing.

For numeric literals the + or - are taken as the sign of the literal value. For instance, -5 is just that, negative 5.


// Example Pointers

#include<iostream.h>
using namespace ioSpace;

entry void main(void)
output << "Hello World!\n";


// Declare two arrays of integers.
// by default all cells are initialized to 0.

int a[5];
int b[5];

// Change values of cells of array b.

b[0] = 5;
b[1] = 12;
b[2] = 17;
b[3] = 21;
b[4] = 33;

// Declare two pointers pointing to first cell of arrays.

int* p = &a[0];
int* q = &b[0];

p--;
// move p backwards

// Illustrating "*++p = *q++".
// First pointer p is moved forward (incremented).
// Then, * is applied to pointer (++p) reaching a cell of array a.
// Next, * is applied to pointer q reaching a cell of array b.
// The assignment is performed, using the value (*q).
// Finally, ++ moves pointer q forward.

for (int i = 0; i < 5; i++)
*++p = *q++;
endfor;

for (int i = 0; i < 5; i++)
output << a[i] << '\n';
// prints the values of array b.
endfor;

// Reset the values of p and q.

p = &a[0];
q = &b[0];

for (int i = 0; i < 5; i++)
a[i] = 0;
// make all cells of a 0
endfor;

// Illustrating "*p++ = *q++".
// First * is applied to p, reaching a cell of array a.
// Next, * is applied to pointer q reaching a cell of array b.
// The assignment is performed, before applying ++ on either side.
// Finally, ++ is applied to pointers p and q.

for (int i = 0; i < 5; i++)
*p++ = *q++;
endfor;

for (int i = 0; i < 5; i++)
output << a[i] << '\n';
// prints the values of array b.
endfor;

output << "Good-bye World!\n";
end;



Below is a more complex example.



// Example Overloading and Arrays of structures.
//---------------------------------------------------------------------------//
// Keep in mind that when an overloaded operator is applied to an array of
// structures (class/struct, etc), it always returns an array object with
// the operator applied to each cell. Invoking a method on an array of
// structures works the same way.

#include<iostream.h>
using namespace ioSpace;

//---------------------------------------------------------------------------//

struct PostInc
int n;

PostInc(int);
int operator-(void);
int operator+@(void);
// overloading postfix ++
PostInc& operator+(const PostInc&);
end;

PostInc::PostInc(int t)
n = t;
end;

int PostInc::operator-(void)
return n = -n;
end;

// Overloaded postfix ++. When applying the operator to an instance
// use the ordinary ++ token.

int PostInc::operator+@(void)
return ++n;
end;

PostInc& PostInc::operator+(const PostInc& e)
n += e.n;
return self;
end;

///////////////////////////////////////////////////////////////////////////////
// The entry point main().

entry void main(void)

output << "Hello World!\n";

output << "\nStatic array of struct ...\n\n";

PostInc PIA[3];

for (int i = 0; i < 3; i++)
PIA[i].n = 5 * i;
endfor;


// For all cells of array PIACopy, the member n of PostInc will be 0.

PostInc PIACopy[3];

// First, -PIA makes an array with member n of cells becomes 0, -5, -10.
// Next, -PIA is copied to PIACopty.
// Finally, the postfix ++ acts on original PIA, incrementing the member n: 1, 6, 11.

PIACopy = -PIA++;

for (int i = 0; i < 3; i++)
output << PIA[i].n << '\n';
output << PIACopy[i].n << '\n';
endfor;

output << "\nDynamic array of structure ...\n\n";

int dim = 3;
PostInc DIA[dim];
PostInc DIA2[dim](13);
// initializes n == 13 for all cells.

// size(DIA, 0) evaluates to the size of first (0-th) dimension of dynamic array
// DIA, which is this case is 3.


for (int i = 0; i < size(DIA, 0); i++)
DIA[i].n = 5 * i;
endfor;

// First -DIA returns an array which is used as argument to the overloaded
// operator +. Finally, postfix ++ is applied to the original DIA.

DIA2 + -DIA++;

for (int i = 0; i < size(DIA, 0); i++)
output << DIA[i].n << '\n';
// 1, 6, 11
output << DIA2[i].n << '\n'; // 13, 8, 3
endfor;

output << "\nGood-bye World!\n";
end;



The output of this example is as follows.



Hello World!

Static array of struct ...

1
0
6
-5
11
-10

Dynamic array of structure ...

1
13
6
8
11
3

Good-bye World!


3. Arithmetic Operators have the next highest precedence.

Arithmetic operators are as follows.


+ Addition
- Subtraction
* Multiplication
/ Division
% Remainder (Modulo)
*^ Power (raising to a power)

Power has the highest precedence among arithmetic operators.
Operators Multiplication, Division and Remainder have the next highest precedence.
Addition and Subtraction have the lowest precedence.

For instance, "a + b * c *^ d" means "a + (b * (c *^ d))".
First Power is evaluated.
The result is used in evaluating multiplication.
Then, the result is used in evaluating addition, as illustrated below.

double a = 5, b = 4, c = 3, d = 2;
double e = a + b * c *^ d;
output << e << '\n';
// prints 41


Remark. For numeric types, the type of right operand of an arithmetic operator is coerced to the type of its left operand before the operation is carried out.

The output of following example is 5.
When evaluating b, d is coerced to int (of value 2).
Note that d is not changed as a result of coercion.

int i = 10;
double d = 2.5;
double b = i / d;
output << b << '\n';


4. Bitwise (arithmetic) operators have the next highest precendence.

Operands of these operators must be of discrete numeric types. Note that char and uchar are among discrete numeric types. Bitwise operators are as follows.


& And
| Or
^ Exclusive Or
<< Shift-left
>> Shift-right

Shift operators have higher precedence over the other three operator. In an expression, operators And, Or and Exclusive Or are evaluated from left to right relative to one another (they have equal level of precedence).

a << b & c means (a << b) & c
a | b >> c means a | (b >> c)

5. Relational operators have the next highest precedence.

Relational operators are binary and of equal precedence. They are as follows.


== Equal
!= Inequal
< Smaller (Less than)
<= Smaller or Equal
> Greater (More than)
>= Greater or Equal

As an example: a ^ b < c >> d + e means (a ^ b) < (c >> (d + e))

5.1. Chaining relational operators.

Relational operators can be chained. Less/Greater than must be in same direction in a chain.

a < b < c         means   (a < b) && (b < c)
a >= b == c > d means (a >= b) && (b == c) && (c > d)


6. Logical operators have next highest precedence.

Remark. The logical operator ! (negation) is unary, with same high precedence as unary operators.
The operands for logical operators must be of type boolean. The operators are as follows.

!    Negation
&& (Short) And
|| (Short) OR
<> Long And
^^ Exclusive OR (is long logical operator)
>< Long Or

Remark. The short logical operators do not necessarily evaluate all their operands. For instance, when X, Y and Z are expressions involving function calls, and X evaluates to false in "X && Y && Z", the calls in Y and Z will not be made. However, the operands of the other three long logical operator are evaluated (e.g. function call are made) before applying the operators.

Operator && has the highest precedence. Operator || has next highest precedence.
Operators <> and ^^ have equal precedence after ||. Operator >< has the lowest precedence.

Example: Logical, relatinal operator precedence.


#include<iostream.h>
using namespace ioSpace;

//---------------------------------------------------------------------------//

int fun(int n)
output << "In fun, n is: " << n << '\n';
return n;
end;

///////////////////////////////////////////////////////////////////////////////

entry void main(void)

output << "Hello World!\n";

//---------------------------------------------------------------------------//

int a = 2, b = 3;

// In boolean expression of if, logical operators have the lowest precedence.
// Short and && has higher precedence over the long and <>.
// So we begin with operator &&. Its left operand is "a + b > a * b".
// Relational operator > has higher precedence over of &&.
// Since operators + and * have higher precedence over > they are computed first.
// The expression "a + b > a * b" is false. So, && does not need to compute its
// right operand. Thus, the function fun() is not called, nor b is incremented.
// Now we have the left operand for long and <>, which is false.
// However, long and does compute both its operands, even though is this case
// the overall result is false. So, at the end a will be incremented.

if (a + b > a * b && a < fun(b++) <> a++ == b)
output << "Was true\n";
else
output << a << '\n';
output << b << '\n';
endif;

//---------------------------------------------------------------------------//

output << "\nGood-bye World!\n";
end;

The output of this example is as follows.

Hello World!
3
3

Good-bye World!

7. Binary assignment operators have the lowest precedence, just above assignment itself.

The assignment operator = is right-associative and has the very lowest precedence. Binary assignment operators have higher precedence over the assignment only. All binary assignment operators are of equal precedence, and are evaluated from right-to-left. Below is the list of binary assignment operators.


Arithmetic operators:

+=
-=
*=
/=
%=
*^=

Bitwise operators

&=
|=
^=
<<=
>>=
~=

All binary assignment operators, except ~=, use both their operands in computing the result. The result is always assigned to the left operand. That is, bianry assignment operators change their left operand.

Operator ~= only inverts bits of its right operand, and assigns that to its left operand. It is equivalent to "a = ~a". Note that in contrast, operator -= will perform a subtraction using both of its operands before assigning the result to its left operand.


Example: binary assignment operators

#include<iostream.h>
using namespace ioSpace;

///////////////////////////////////////////////////////////////////////////////

entry void main(void)

output << "Hello World!\n";

int a = 2, b = 3, c = 4, d = 5;

// First "c + d" is done, getting 9.
// Then operator += is done making b == 12
// Finally, operator *= is done making a == 24.

a *= b += c + d;

output << "a is: " << a << '\n';
output << "b is: " << b << '\n';
output << "c is: " << c << '\n';
output << "d is: " << d << '\n';

output << "\nGood-bye World!\n";
end;


The output of this example is as follows.

Hello World!
a is: 24
b is: 12
c is: 4
d is: 5

Good-bye World!

The following example may be more helpful. Suppose we have the following declaration.


int n, a = 2, b = 4, c = 5, d = 3, e = 8;

Then, the following statement:


n = a += b * c += a + d *= e / a;

is computed as if parentheses were inserted as follows:


n = (a += ((b * c) += ((a + d) *= (e / a))));

If we print the values of objects, we find:


output << "a is: " << a << '\n'; // 42
output << "b is: " << b << '\n'; // 4
output << "c is: " << c << '\n'; // 5
output << "d is: " << d << '\n'; // 3
output << "e is: " << e << '\n'; // 8
output << "n is: " << n << '\n'; // 42

So, first (b * c), (a + d) and (e / a) are computed, and their results are stored in termporaries created by the Compiler. Then, assignment operators are done, from right-to-left.


8. Pointer operators.

Pointers can be compared using all relational operators. In addition, following operators can be used on pointers.

++
--
+=
-=
+ // binary add
- // binary subtract
= // assignment
* // unary prefix, dereference pointer
& // unary prefix, take address of pointer

The right operand of bnary operators must be of discrete numeric type. The amount by which a pointer is moved forward or backward is the product of right-operand and the size of object to which the pointer is pointing.
The only literal value that can be assigned directly to a pointer is 0 (zero). Otherwise, the address operator provides pointer literal values.


int n = 5;
int* p = &n; // &n is a pointer literal value
output << *p << '\n'; // prints 5

9. Graphic operators.

Operators simplify the notation for general actions such as drawing/erasing graphic entities. At Instinc Method Select, graphic events (signals), and other graphic-related concepts are illustrated. Here, we discuss operators for peforming graphic operations.

The labels (names) of entities in a canvas can be used as cases for select statement, only. For instance, suppose in a canvas named "People" there is a button named "STOP". The string STOP is used as a case label for select statement, but when applying an operator to that same button, it must be identified with its canvas: "People::STOP".

Similarly, menus and menubars must be identified with their canvas. To reach submenus and/or menu cammands, use the RESOLVER, recursively. For instance, "People::PeopleBar::File::Open", where PeopleBar is the menubar in canvas, File is the name of a menu item, and Open is a menu-command.

Below is the rule illustrated above. Note that operators can also be applied to menubar, menu and canvas itself. Entities in a  canvas other than menubar and menu are usually called "control", e.g. a Checkbox is a control.

On the right-hand-side of the rule, all terms with suffix of "name" are IDENTIFIERS, except command-name, which is a string (may include spaces, etc.).

gui-entity --->>> canvas-name --+--------------------------------------------------------------------------------------------------------+-->
| |
+--> RESOLVER --+--> control-name --+-----------------------------------+-------------------------------->
| | | |
+--> menubar-name --+--+--> RESOLVER --> menu-name --+--+--> RESOLVER --> command-name -->
| |
<-----------------------------+

Unary Prefix Operators

9.1. Draw/Erase operator $

This is the only operator that can also be applied to the frame. When an instance of a frame is declared, it is created just like an instance of a class is declared, and nothing else happens. Applying operator $ to the instance,draws the canvas of the frame and enters gui-input-mode. In gui-input-mode, Z47 looks for user actions such as mouse-click, and delivers them to the instinct method of the frame. See the example for Instinct Method Select.

Inside the instinct method, $self will erase the canvas and end gui-input-mode for the frame. Note that the self refers to the instance of frame.
For all other cases "$gui-entity" is a toggle action. It draw gui-entity, or if already drawn, it will erase it.

9.2. Enable/Disable operator !

A disabled gui-entity is greyed out, and does not respond to mouse-click, etc. The statement "!gui-entity" is a toggle action for enbling and disabling a gui-entity.

9.3. Focus operator @

Events (signals) are delivered to the gui-entity whih currently has the focus. When clicking a control it automatically gets focus. The statement "@gui-entity" sets focus to the gui-entity.

9.4. Check operators ?  ^  &

These operators return a boolean.
"?gui-entity" evaluates to true if gui-entity is drawn (showing), otherwise it evaluates to false.
"^gui-entity" evaluates to true if gui-entity is enabled, otherwise evaluates to false.
"&gui-entity" evaluates to true if gui-entity has focus, otherwise evaluates to false.

9.5. Clear operator ~

For a Field (test area) ~gui-entity clears the contents. For List and ComboBox it deletes all elements making them empty.

Binary Operators

9.6. Signal operators BACK-ARROW and double back-arrow

Suppose "canvas-name" is a canvas associated with some frame. The statement

	canvas-name <- some-event;

sends the signal some-event to the canvas, while the statement


canvas-name <<- some-event; // double back-arrow

sends the signal to the parent canvas. For instance, when type of member of a frame, is also frame, then the canvas of the frame is the parent canvas for the canvas of its member. The signals sent to a canvas can be anything from erase/draw to mouse-click, etc.

9.7. Operator <<

For a menu item, RadioButton and Checkbox the expression on right-hand side must evaluate to an object of boolean type. Sending True will make the entity on the left checked, and sending Flase with make it unchecked: "gui-entity << expression;".

When gui-entity is Field, Label or Button, expression must evaluate to a string. For a ComboBox the expression must evaluate to an integer (discrete numeric) object.

For Field, the string is appended to its contents.
For ComboBox the integer is used as index (0-based) for setting its current selection.
For Label and Button entities, the string becomes their labels (names like STOP for a button, or text of the Label).

9.7. Operator >>

This is the opposite of operator <<. For menu item, RadioButton and CheckBox it makes its operand True when the entity is checked and Flase otherwise.
For Field, the string returned is the contents of the Field.
For ComboBox returns an integer for the index of its current selection.
For Label and Button it returns the label (name) of entity.

9.9. Operator =

For a Field "gui-entity = expression;" the expression must evaluate to a string, which replaces the contents of Field.
For RadioButton and CheckBox, the string becomes their lables (names).
For ComboBox, the string is appended to its list, if not already there, and becomes its selection.

9.10. Operator +

This operator appends a string to a List/ComboBox: "gui-entity + expression;".

9.11. Operator -

The gui-entity must be a ComboBox/List, and expression must evaluate to a string object. Then, "gui-entity - expression;" will remove the string from gui-entity. If the string is not in gui-entity, nothing happens.

9.12. Operator []

For an integer n, "gui-entity[n]" becomes a reference to the n-th element in a List/ComboBox. Note that the first element is at index 0. The reference can be used to change the string value of the element, just like array cells: gui-entity[n] = "New Value";

9.13. Operator ?

When gui-entity is a List/Combobox, and expression results in a string, "gui-entity ? expression;" returns the index of string in gui-entity. The index count starts with 0 for the first element, etc.

9.14. Size of list

The expression "size(gui-entity)" evaluates to the number of elements in gui-entity for a List or ComboBox.