cybot
Language Specification for Cycle

Cycle is a simple Java (or C/C++) un-typed programming language for producing programs for Cybot from Ultimate Real Robots. It is a direct alternative to using the graphical programming "language" supplied on the CDs and the compiler produces .03p files compatible with Programmer 03 on CD2.

Keywords
There are a number of reserved words in Cycle, which may not be used as identifiers. These are:

block
break
case
class
const
default
do
else
false
for
if
include
input
output
proc
process
return
switch
true
while

Operators
There are also a number of operators in Cycle. These are:

+
-
*
/
==
!=
>
>=
<
<=
+=
-=
*=
/=
++
--

Comments
There are two types of comment in Cycle. One is the line (or C++ style) comment, which begins with a double forward slash and ends at the next newline:

  // This is a line comment.

The other is the block (or C style) comment. This starts with a forward slash followed by an asterisk and ends with an asterisk followed by a forward slash. It can contain newlines:

  /* This
     is a block
     comment. */

Numbers
Numbers are used as values to be sent to outputs and processes or to be read from inputs. They are also use in the manipulation of variables using assignments and conditions. A number may be any positive or negative integer, including zero. There is no defined maximum or minimum number, but it is sensible to keep in the range -127 to 127. Numbers can be defined with a regular expression:

    "-"[0-9]+   or   [0-9]+

Strings
Strings are used as values to be sent to blocks in member definitions and also as filenames to include directives. A string consists of a double-quote, followed by any sequence of characters until another double-quote is encountered. There is no escaping of characters in Cycle, so it is not possible to include a double-quote as part of a string. Strings may also not contain newlines. Strings can be defined with a regular expression:

    \"[^\"\n]\"

The value of a string is the characters enclosed in the quotes (not including the quotes themselves).

Identifiers
Identifiers are used to give names to variables, procedures, classes and instances. Identifiers consist of a letter or an underscore followed by any number of letters, underscores or numbers. As a regular expression, this would be:

    [A-Za-z_][A-Za-z0-9_]*

Identifiers are case-sensitive i.e Foo and foo are not the same.

Types of Arguments
Classes and members in Cycle may take parameters. The formal declaration of the parameters a class and member may take is called an argument list. This is simply a list of identifiers, one for each parameter and the identifiers is used as a name through which the value of the parameter can be accessed. As Cycle is un-typed, you can pass either a number or a string as a parameter and Cycle will accept it. There are however no attempts to convert numbers to strings or vice versa - this is simply not necessary as the values out output verbatim.

Include Directive
An include is simply the keyword include followed by a string and a semicolon (';'):

    include string ;

All the definitions in the file named by the string are included as through they were defined at the point of the include directive. This is the only way to re-used code between files in Cycle.

Classes
Classes declare an aspect of a robot. A class starts with the class keyword and if followed by an identifier (the class name). Classes must have a name which has not already been defined as either another class or as an instance or procedure. By convention class names start with an uppercase letter e.g. Sonar. This is then followed by an optional argument list, in which by convention each class argument name begins with a lowercase letter. This is then followed by the class body.

A class body consists of an opening brace ('{') followed by a sequence of member definitions, followed by a closing brace ('}').

    class identifier [ ( identifier [ , identifier ... ] ) ]
    {
        member-list
    }

A member is one of: an input; an output; a process; or a constant. These consist of the one of the keywords input, output, process or const, followed by an identifier (the member name). constants are just an equals (=) followed by a value (either a number or a string) and the others all have a (possibly empty) argument list, followed by a colon (:) and a member-definition. All are terminated by a semicolon (;).

  •   input [ { min , max } ] identifier ( [identifier [ , identifier ... ] ] ) : member-definition ;
  •   output identifier ( [identifier [ , identifier ... ] ] ) : member-definition ;
  •   process identifier ( [identifier [ , identifier ... ] ] ) : member-definition ;
  •   const identifier = number-or-string ;

Member names must be unique within the class that they are declared. Thus, a constant may not have the same name as an input member for example. By convention, member names begin with a lowercase letter e.g. getRange, except for constants which are written entirely in uppercase e.g. OUTOFRANGE. Also by convention member argument names begin with a lowercase letter.

A member-definition is simply the keyword block followed by a list of block-parameters in parenthesis. The first parameter is always a number, which identifies the kind of block being generated (see Appendix A).

    block ( number [ , block-parameter [ , block-parameter ... ] ] )

Each block-parameter may be:

  • a number
  • a string
  • the identifier of a class or member argument

Instances
Instances declare as specific use of a class. Instances consist of the identifier of a previously declared class, followed by an identifier (the instance name) and an optional parameter list in parenthesis and a semicolon (;). The parameter list must match the argument list in the class declaration.

    identifier identifier [ ( parameter-expression [ , parameter-expression ... ] ) ] ;

The name of the instance must not have already been defined as either another instance or as a class or procedure. By convention instance names start with a lowercase letter e.g. sonar.

Procedures
Procedures group a set of statements into a convenient re-usable block. All programs must contain at least one procedure called main. A procedure starts with the keyword proc followed by an identifier (the procedure name) and a list of zero or more argument identifiers in parenthesis. All this is followed by a procedure body in braces, which is simply a list of statements. A procedure must not have the same name as either another procedure, a class or an instance. By convention, all procedure names start with a lowercase letter e.g. main.

    proc identifier ( identifier [ , identifier ... ] )
    {
        statement-list
    }

Statements
A statement is one of the following (each defined separately):

  • if or if/else statement
  • while or do/while loop statement
  • for loop statement
  • switch statement
  • assignment statement
  • member-call statement
  • procedure-call statement (not yet implemented)

As a rule, statements are either terminated by a semicolon (';') or finish with a block delimited by braces ('{' and '}'). Unlike C/C++ or Java, braces are mandatory on if, if/else, while, do/while and for statements. This eliminates what is known as "the dangling else problem" and makes the code easier to read (and parse).

If And If/Else Statement
An if statement consists of the keyword if followed by a condition-expression in parenthesis, followed by an opening brace ('{'), as list of statements and a closing brace ('{').

    if ( condition-expression )
    {
        statement-list
    }

An if/else statement is exactly the same as an if statement, but contains an else part:

    if ( condition-expression )
    {
        statement-list
    }
    else
    {
        statement-list
    }

The execution of an if statement is such that if the condition-express (defined later) evaluates to true, then the part in braces following the if is executed, and execution resumes after the closing brace of the if. If the condition-expression evaluates to false, then the block following the if is skipped, and execution once again resumes after the closing brace.

The execution of an if/else statement is exactly the same if the condition-expression evaluates to true, but if condition-expression evaluates to false, the statements in the block following the else are executed. In both cases, the execution resumes after the closing brace of the block for the else part.

There is also another form of if/else, which is allowed, but which does not conform to the rule that the else part must be surrounded by braces. This allows another if to be tagged onto the end to provide the else if functionality found in many languages:

    if ( condition-expression )
    {
        statement-list
    }
    else if( condition-expression )
    {
        statement-list
    }

While and Do/While Loop Statement

A while statement consists of the keyword while, followed by a condition-expression in parenthesis and list of statements in braces:

    while ( condition-expression )
    {
        statement-list
    }

A do/while statement consists of the keyword do, followed by a list of statements in braces, then the keyword while and a condition-expression in parenthesis, terminated by a semicolon (';'):

    do
    {
        statement-list
    } while ( condition-expression ) ;

Both forms of while loop work in exactly the same, and differ only in the point at which their condition-expression is evaluated. In the case of the while loop, the condition-expression is evaluated at the start of every repetition of the loop, so the code in the block can be executed zero or more times. With the do/while loop, the condition-expression is evaluated at the end, so the code in the block can be executed one or more times. In both cases the loop carries on repeating whilst the condition-expression is true.

For Loop Statement
The for statement is similar to the while statement in that it is written with the condition at the top (and can therefore be executed zero or more times), followed by a block of statements which are repeated whilst the condition-expression remains true. The only difference between a for statement and a while statement is that a for statement also has initial assignment and increment assignment statements within the parentheses of the for:

    for ( assignment-statement ; condition-expression ; assignment-statement )
    {
        statement-list
    }

Switch Statement
A switch statement might look quite complicated, but it is really just a multi-pronged if/else statement, which allows several values to be checked at once. It consists of the keyword switch followed in parenthesis by a member-call-expression, which is simply a call to an input member, using the same syntax as a member-call statement, but without the semicolon (';'). This then followed, in braces by a list of case clauses.

Each case clause is one or more occurrences of either the keyword case followed by a constant-expression (defined later) and a colon (':') or the keyword default followed by a colon (':'). These are then followed by an optional list of statements and the mandatory break keyword, which is always followed by a semicolon (';'):

    switch ( member-call-expression )
    {
    case constant-expression :
    [ case constant-expression :
    ... ]
        [ statement-list ]
        break ;
    [ case constant-expression :
        [ statement-list ]
        break ;
    ... ]
    [ default :
        [ statement-list ]
        break ; ]
    }

Assignment Statement
An assignment statement consists of an identifier, an operator symbol, e.g. equals ('='), usually followed by an arithmetic-expression. The statement is always terminated by a semicolon (';'). Therefore an assignment statement may be one of:

  •   identifier = arithmetic-expression ;
  •   identifier += arithmetic-expression ;
  •   identifier -= arithmetic-expression ;
  • ;  identifier *= arithmetic-expression ;
  •   identifier /= arithmetic-expression ;
  •   identifier ++ ;
  •    identifier -- ;

Assignment statements work only on Cybot's internal variables, which can be thought of as a set of boxes labeled 'a' to 'l' (lowercase 'L'). Assignments can be simple, where one box is given a copy the value that is in another box, or they can use simple arithmetic. This means that the only valid identifiers are the letters 'a' to 'l'.

To keep things simple, an arithmetic-expression may consist of at most two simple values. An arithmetic-expression can be any of the following:

  •   number-expression
  •   number-expression + number-expression
  •   number-expression - number-expression
  •   number-expression * number-expression
  •   number-expression / number-expression

Member-Call Statement
A member-call statement is the usage of an output or process member of a class via an instance. It consists of an instance identifier followed by a dot ('.') and the identifier of a member. The member must have been defined as either an output or a process. This is then followed by a list of zero or more parameters in parentheses. The whole statement is terminated by a semicolon (';').:

    identifier . identifier ( [ parameter-expression [ , parameter-expression ... ]) ;

Procedure-Call Statement
NOT IMPLEMENTED.

Parameter Expression
A number-expression is simply either a literal number e.g. 2 or a constant member which evaluates to a number:

  •   number
  •   string
  •   identifier . identifier

In the latter case, the first identifier is a class name and the second identifier is the name of a constant member of that class which can be defined to be either a string or a number

Constant Expression
A number-expression is simply either a literal number e.g. 2 or a constant member which evaluates to a number:

  •   number
  •   identifier . identifier

In the latter case, the first identifier is a class name and the second identifier is the name of a constant member of that class which must be defined to be a number

Condition Expression
A condition-expression consists of a comparison between two number-expressions. It is written as a number-expression followed by a comparison operator, followed by another number-expression. It is therefore one of:

  •   number-expression == number-expression
  •   number-expression != number-expression
  •   number-expression < number-expression
  •   number-expression <= number-expression
  •   number-expression > number-expression
  •   number-expression >= number-expression

Number Expression
A number-expression can be either of the following:

  •   number
  •   identifier

In the latter case the identifier is a letters between 'a' and 'l'.

Appendix A - Block Types
The graphical programming language for Cybot uses the following block types in its .03p files. Each block has an id number indicating its type. These values are used as the first parameter to block in member-definitions in Cycle.:

 0 = Start
 1 = If/Then/Else
 2 = Arithmetic
 3 = Delay Timer
 4 = Sound
 5 = Motors
 6 = Sonar Sensor
 7 = Jump
 8 = Land
 9 = Antennae Lights
10 = Light Sensor
11 = Line Testing (not on CD2)
12 = undefined
13 = undefined
14 = Subroutine (not on CD2)
15 = Stop
16 = Return (not on CD2)

For more information see the Basic Tutorial and the Advanced Tutorial.