Since the computational model of QPLs is that of a classical computer with a quantum oracle, QCL contains all features of a classical universal programming language, such as variables, loops, subroutines and conditional branching.
The syntactic structure of a QCL program is described by a context free LALR(1) grammar (see appendix A) with statements and definitions as top symbols:
Statements range from simple commands, over procedure-calls to complex control-structures and are executed when they are encountered.
qcl> if random()>=0.5 { print "red"; } else { print "black"; } : red |
Definitions are not executed but bind a value (variable- or constant-definition) or a block of code (routine-definition) to a symbol (identifier).
qcl> int counter=5; qcl> int fac(int n) { if n<=0 {return 1;} else {return n*fac(n-1);} } |
Many statements and routines take arguments of certain data types. These expressions can be composed of literals, variable references and sub-expressions combined by operators and function calls.
qcl> print "5 out of 10:",fac(10)/fac(5)^2,"combinations." : 5 out of 10: 252 combinations. |
The classic data-types of QCL are the arithmetic types int, real and complex and the general types boolean and string.
Frequently used values can be defined as symbolic constants. The syntax of a constant declaration is
const pi=3.141592653589793238462643383279502884197; |
The definition of variables in QCL is analogous to C:
qcl> complex z; // declare complex variable z qcl> print z; // z was initialized with 0 : (0.000000,0.000000) qcl> z=(0,1); // setting z to i qcl> print z; : (0.000000,1.000000) qcl> z=exp(z*pi); // assignment to z may contain z qcl> print z; : (-1.000000,0.000000) qcl> input z; // ask for user input ? complex z [(Re,Im)] ? (0.8,0.6) qcl> print z; : (0.800000,0.600000) |
Table 3.2 shows all QCL operators ordered from high to low precedence.3.1All binary operators are left associative, thus . Explicit grouping can be achieved by using parentheses.
Arithmetic operators generally work on all arithmetic data types and return the most general type (operator overloading), e.g.
qcl> print 2+2; // evaluates to int : 4 qcl> print 2+2.0; // evaluates to real : 4.000000 qcl> print 2+(2,0); // evaluates to complex : (4.000000,0.000000) |
^
for integer bases is only
defined for non-negative, integer exponents.
For real exponents, the base must be non-negative.
QCL expressions may also contain calls to built-in or user defined functions. Table 3.3 shown all built-in unary arithmetic functions.
|
In addition to the above, QCL also contains -ary functions such as minimum or , conversion functions and the the pseudo function random() (table 3.4). As the latter is no function in the mathematical sense, it may not be used within the definition of user-functions and quantum operators.
The value of any classic variable can be set by the assignment operator =. The right-hand value must be of the same type as the variable. In contrast to arithmetic operators and built-in functions, no implicit typecasting is performed.
qcl> complex z; qcl> z=pi; // no typecast ! type mismatch: invalid assignment qcl> z=conj(pi); // implicit typecast |
The call of a procedure has the syntax
Due to the potential side-effects on the program state, procedure-call may not occur within the definition of functions or operators.
The input command prompts for user input and assigns the value to the variable . Optionally a prompt string can be given instead of the standard prompt which indicates the type and the name of the variable.
qcl> real n; qcl> input "Enter Number of iterations:",n; ? Enter Number of iterations: 1000 |
The print command takes a comma separated list of expressions and prints them to the console. Each output is prepended by a colon and terminated with newline.
qcl> int i=3; real x=pi; complex z=(0,1); boolean b; qcl> print i,x,z,b; : 3 3.141593 (0.000000,1.000000) false |
All flow control statements operate on blocks of code. A block is a list of statements enclosed in braces:
The if and if-else statements allow for the conditional execution of blocks, depending on the value of a boolean expression.
for-loops take a counter of type integer which is incremented from to . The loop body is executed for each value of .
qcl> int i; qcl> for i=10 to 2 step -2 { print i^2; } : 100 : 64 : 36 : 16 : 4 qcl> for i=1 to 10 { i=i^2; } // i is constant in body ! unknown symbol: Unknown variable i |
QCL supports two types of conditional loops:
User defined functions may be of any classical type and may take an arbitrary number of classical parameters. The value of the function is passed to the invoking expression by the return statement. Local variables can be defined at the top of the function body.
int Fibonacci(int n) { // calculate the n-th int i; // Fibonacci number int f; // by iteration for i = 1 to n { f = 2*f+i; } return f; } |
QCL requires functions to have mathematical semantics, so their value has to be deterministic and their execution must not have any side-effects on the program state.
qcl> int randint(int n) { return floor(n*random()); } ! in function randint: illegal scope: function random is not allowed in this scope qcl> int foo=4711; qcl> int bar(int n) { foo=foo+n; return foo; } ! in function bar: unknown symbol: Unknown local variable foo |
Functions can call other functions within their body. Recursive calls are also allowed.
int fac(int n) { // calculate n! if n<2 { // by recursion return 1; } else { return n*fac(n-1); } } |
Procedures are the most general routine type and used to implement the classical control structures of quantum algorithms which generally involve evaluation loops, the choice of applied operators, the interpretation of measurements and classical probabilistic elements.
With the exception of routine declarations, procedures allow the same operations as are available in global scope (e.g. at the shell prompt) allowing arbitrary changes to both the program and the machine state. Operations exclusive to procedures are