Syntax

Open GENIE commands fall into two obvious groupings, those used primarily in interactive mode and which are complete within a single line, and those used mainly to build procedures and whose effect spans several lines. The former are termed "single-line" and the latter "multi-line" commands. Single line commands also fall into a further division between commands which are expressed in an algebraic or functional notation and commands which are accessed as a simple keyword type command.

Micro-syntax ( some preliminaries about Open GENIE syntax )
Comments
Intervals
Line extending
Single-line commands
Keyword Commands ( of the form Display w )
Function Commands ( of the form x = sin(y) )
Multi-line commands
IF - ELSE - ENDIF
CASE - ENDCASE
LOOP - ENDLOOP
PROCEDURE - ENDPROCEDURE

Micro-syntax

This section describes a few minor but important parts of the syntax of Open GENIE command language.

Comments

Comments in Open GENIE may be placed anywhere on a line as long as they are preceded by a "#". The rest of the line is then treated as a comment and ignored. There is no mechanism for commenting out multiple lines in Open GENIE without putting a "#" at the beginning of each line, this avoids the risk of commenting out sections of code inadvertently.

Intervals (and Ranges)

Intervals are a means by which groups of indices can be specified within Open GENIE. The most common usage for intervals is in slicing parts out of arrays and in specifying groups of spectra. The basic syntax is

j : k [ @ m ]

where "j" is an integer start value, "k" is an integer end value and "m" is an optional step value. An interval such as 1:4 specifies all the numbers between 1 and 4 ie 1 2 3 4. If the step value is used, the interval selects only those numbers which fall in multiples of step from the starting value, so 2:12@3 will specify the numbers 2 5 8 11. If required, the values specified in an interval can be variables but it is necessary to surround each variable name in parentheses so instead of writing start:stop@step it is necessary to write (start):(stop)@(step).

Note that some spectrum manipulation functions in Open GENIE take a "Range" data type which is either an Integer array or an Interval. The Integer array form is more general than the interval syntax but the interval syntax is more convenient.

Examples

# reads every third spectrum into a multi-dimensional workspace
# starting from the first spectrum.
>> maxspec = get("NSP1")
>> a = get( 1:(maxspec)@3 )
# copy selected elements of the array "myarray" to make a new array called "slice"
>> slice = myarray(34:50)
# Create a Range in an integer array equivalent to
# the interval 4:20@2
>> my_range=Dimensions(9)
>> fill my_range 4 2
>> set/file "myfile.raw"
>> printn get(my_range) = get(4:20@2)
true

Line extending

Open GENIE uses similar rules to FORTRAN in that single line statements are assumed to terminate at the end of the physical line. Sometimes however, it is useful to be able to extend a single logical line over several physical lines. In Open GENIE the line extension character is an "&", it must be used at the end of the line being extended. All white space following the "&" is ignored. If necessary, strings can also be extended in an unbroken fashion. There is no limit to the number of continuation lines which may be created in this way.

Conversely, several logically separate single-lines may be placed on one physical line by using the ";" character as a separator. This is just provided as a convenience which can be used to make a program more readable.

Examples

>> long_string = "My very long string is being broken&
in two"
IF a = b; printn "yes, a = b"; ELSE; printn "no, a !=b"; ENDIF

Note that in the first example, any spaces before the start of the following line WILL get included in the string.

Single-line commands

The term "single-line" refers to a single logical line containing one keyword command or assignment.

Single-line commands consist of keyword commands and assignments. Any Open GENIE procedure may be invoked as a keyword command. Any Open GENIE procedure which returns a result can be invoked either as a keyword command (in which case the value is ignored) or as an expression using the function syntax.

In some cases it is useful to know in which way a procedure has been invoked

whilst within the procedure, for this the Called_as_function() command can be used.

Keyword commands

Open GENIE keyword commands start off with a keyword followed by a list of parameters and qualifiers. As a general rule, the keyword specifies the basic command, the qualifiers modify the action of the command and the parameters supply the values which the command operates on. An example of a keyword command is

>> Display/Line w1
>>

The Display() command is used to plot a histogram on the graphics screen. The /Line qualifier modifies the command to do the plot as a polyline rather than a histogram, the parameter w1 is the workspace being displayed.

Specifying parameters

Parameters are generally specified by the position on the command line which they occupy. For example, with the Display() command the first parameter is the workspace to be displayed, the next two are the low and high X limits for the plot and the final two the low and high Y limits. An example is

>> Display w1 0 100 -35 70 
>>

All the parameters except for the workspace are optional and where omitted a default value will apply. Unfortunately, identifying parameters by position alone is not sufficient. If the Y limits need specifying but the X limits should be defaulted it is necessary to tell Open GENIE that the parameters on the line are the Y limits and not X limits. This is done by giving each parameter a keyword which uniquely identifies it amongst other parameters on the line. The command with defaulted X values could then be specified

>> Display w1 ymin=-35 ymax=70 
>>

The parameters to a command may be expressions or function invocations themselves so commands such as

>> Display w1-background 0 xmax/100.0 ymin=Min(w1.y) ymax=Max(w1.y) 
>>

or

>> Display sqrt(w1)
>>

are perfectly legal. Occasionally it may be necessary to bracket an expression to make the meaning obvious.

Anonymous placeholders

Another mechanism to avoid the problem referred to above is to use anonymous placeholders. In Open GENIE the "_" character is used. The example given above could also be written.

>> Display w1 _ _ -35 70
>>

Although a little less readable it is quicker to type!

Qualifiers

Qualifiers in Open GENIE are defined as switches which in some way modify the action of a command. Taking the Display() command as an example, the default action is to display a spectrum as a histogram rather than a line plot. It wouldn't be sensible to change the name of the command completely to get a line plot because in all other senses the command is the same. Qualifiers allow this modification to be achieved in an obvious way. The command to display a line plot is Display/Line. Further qualifiers may be added to the command to modify the action further. For example Display/Errors would display the spectrum as a line plot with error bars. Sometimes a qualifier will require some modification to the parameter list, this is permissible but qualifiers which require this are mutually exclusive.

Abbreviations

Many keywords can be abbreviated as long as there exists an acceptable unique abbreviation by using the Alias() command. The native commands are allocated abbreviations as they are defined in Open GENIE. This means that in general, user defined commands will have longer abbreviations than the native commands. Qualifiers may be abbreviated as much as is allowed by other qualifiers used with the command. Note, it is quite possible to obscure a command by abbreviating something else to it!

Assignments

Apart from keyword commands there is one other sort of single-line command, the assignment.

<destination-location> = <expression>

Assignments are made using the "=" symbol. The left hand side of an assignment specifies a destination variable or possibly one element of a compound variable. Any value already in <destination-location> is replaced by a copy of the value of the expression on the right hand side.

Expressions

Expressions can be used anywhere a value is required, for example, on the RHS of an assignment or in the parameter list of a function call. An expression is made up from one or more sub-expressions built from the parts listed below.

A literal value. e.g. 5.6 or "Hello".
A variable, or part of a variable. e.g. TwoTheta or w1.npts.
A bracketed expression e.g. ( x - 7 ).
A function invocation e.g. Sin(Pi). See Function commands.
An unary expression e.g. -value or NOT logAxes. The unary operators are " - + NOT" and are evaluated before any binary operators.
A binary expression e.g. 4.5 + 8.0 or 5 <= 6. The binary operators are given below, the operators with the highest precedence first. Where two operators with the same precedence are used at the same bracketing level in an expression the leftmost sub-expression will be evaluated first.

^
AND * / |
OR + -
&
> < = >= <= !=

For details of how these operators are interpreted for different Open GENIE variable types and combinations of types (see Storage).

Function commands

The Open GENIE function syntax provides a method for calling Open GENIE procedures as functions. The function/procedure result can then be assigned to a variable. Commands which return a value can be used interchangeably as statements or as value returning functions in an expression. For example

>> integral = Integrate( W1, 100.0, 200.0 )
>>

or

>> Integrate w1 100.0 200.0
>>

are both valid single-line commands.

When the Integrate() command is used here as a function, the assignment places the result of the integration in the user defined variable "integral". When used with the keyword syntax, the result of the integration is lost.

Specifying parameters

The parameters to an Open GENIE command invoked as a function are supplied in a similar format to that used in the keyword command syntax. Default values for parameters will be supplied if the parameter is omitted. Parameter names may also be used as in a keyword command if desired. For example

>> V6 = Integrate( w1, High=200.0 )
>>

An important point to note is that Open GENIE commands being invoked as functions must always specify a parameter list, even if it is empty e.g. " look_no_parameters()". This allows Open GENIE to distinguish between function commands and ordinary variables.

Qualifiers

Qualifiers may be specified in the functional notation by placing a colon separated list of qualifiers after the function name and before the parentheses delimiting the parameter list. For example,

>> W2 = Asciifile:array( "My_ascii_file.raw" )
>>

Here the equivalent keyword command would be Asciifile/Array but there would be no way to return the workspace without the assignment.

Abbreviations

Abbreviations are allowed in function commands as with keyword commands and the same rules apply.

Multi-line commands

These statements provide all the program flow control in Open GENIE. The keywords beginning the constructs may not be abbreviated and must be written in uppercase to distinguish them from ordinary commands. Open GENIE procedures should avoid names which clash with these keywords.

IF statement

The IF statement provides for a choice between two actions. A boolean condition is tested and the clause following the IF is executed if the condition is true. If the condition is false the clause following the ELSE statement is executed. In the absence of the ELSE part, no action is taken on a false condition.

    IF <Condition1>
        <Statement1>
  [ ELSEIF <Condition2>
        <Statement2> ]
  [ ELSE
        <Statement3> ]
    ENDIF

In the example <Condition1> and <Condition2> are expressions evaluating to true or false. If <Condition1> evaluates to true <Statement1> is executed. If <Condition1> and <Condition2> are false then <Statement3> is executed. <Statement1> and <Statement2> may consist of several Single-line or Multi-line Open GENIE commands. In multiply nested IF statements, one ENDIF is required for each opening IF statement.

Examples

# Initialise and zero an array that may or may not exist yet.
IF NOT Defined(A4)
    A4 = Dimensions(1000)   # Create a 1000 element long array
    Fill A4 0.0             # initialises each element to 0.0
ELSE
    A4=A4*0.0               # Shorthand way of zeroing array
ENDIF
# Multi line commands can be reduced to a
# single physical line by using semicolons
IF a >= 0; Printn "a=" sqrt(a); ELSE; Printn "complex"; ENDIF

CASE statement

The CASE statement allows a selection of alternative actions to be specified depending on the value of an expression. This is similar in operation to the FORTRAN computed GOTO statement.

    CASE <expression>
        IS <value1> [ TO <Range1> ]
            <Statement1>
        ...
        IS <valueN> [ TO <RangeN> ]
            <StatementN>
        OTHERWISE
            <StatementN+1>
    ENDCASE

The expression after the CASE statement is evaluated and then compared with the expression or optional range after each IS statement. The statement after the first matching IS statement is executed and all others are ignored. If no values or ranges match, the statement following the OTHERWISE statement is executed. In the absence of an OTHERWISE statement no action is taken.

Examples

#CASE My_mode()             		# User heck for batch mode operation
    IS "BATCH"
        Hardcopy devtype="PS"   		# Save postscript plots if in batch
    IS "INTERACTIVE"
        Device/Open devtype="XW"	# X-windows if interactive
    OTHERWISE
        Printn "Invalid mode - No plot device open"
ENDCASE
CASE energy                		# a real number
    IS 0.0
        Printn "No data"   		# energy = 0.0
    IS 0.0 TO 500.0
        Myplot/positive    		# 0.0 < energy <= 500.0
    IS -500.0 TO 0.0
        Myplot/negative    		# -500 <= energy < 0.0 
    OTHERWISE
        Printn "Energy out of range"
ENDCASE

LOOP statement

The LOOP statement provides a means of controlled loop execution in an Open GENIE program. The LOOP statement provides for conditional and/or counted loops.

    LOOP [ <variable> FROM <Start> TO <End> [ STEP <Step-size> ] ]
        <Statements>
      [ EXITIF <Condition> ]
        <Statements>
    ENDLOOP

Statements in the loop are executed until <condition> after the EXITIF statement becomes true, or until the optional counting variable has reached or exceeded the final value. If the loop has neither a counter nor an EXITIF statement it will continue to loop indefinitely.

Only one EXITIF statement may be directly contained in any loop. It must not be used inside any other form of control construct within the loop (doing this will generate a syntax error). In the case of nested loops, the exit is to the end of the loop directly containing the EXITIF statement.

For counted loops, the values of <start> and <end> can be real or integer values and they may be positive or negative. Any sensible combination of start and end values will work as long as <step> has the correct sign to progress the counter to (or past) the end value. If it does not, the loop is guaranteed not to execute any statements. If the STEP part is omitted the step interval defaults to one.

The counter for the loop does NOT need to be declared anywhere else. It only has a valid value within the body of the loop and will shadow the value of any other variable of the same name for the duration of the loop.

Examples

# print some squares
LOOP i FROM 1 TO 10 STEP 1
    Print i^2 " "                	# print squares
    IF i = 10; Printn; ENDIF     	# print a newline
ENDLOOP
# something a little more complicated
cubic=0; square=0; y=0
LOOP i FROM -10.0 TO 10.0 STEP 0.01
    y = i
    cubic = y^3 - 5
    square = y^2
    EXITIF cubic > square    		# stop at +ve intersection
ENDLOOP
Printn "cubic=" cubic ", square=" square " for y=" y
# Dimension an array of strings
position = 0
sr = Dimensions(10)
sr[8] = "Find me"        		# and hide a string in it
sr[5] = "Decoy"
LOOP i FROM 1 TO Length(sr)
    position = i
    EXITIF sr[i] = "Find me"
ENDLOOP
Printn "Found at position " position

PROCEDURE statement

The PROCEDURE statement provides a method for writing Open GENIE programs. Most of Open GENIE is built using procedures which are loaded each time it is run, usually this is transparent to the user. By writing procedures it is possible to customise Open GENIE for a specific task or for a specific group of data manipulation and display operations.

  [ FORWARD <name> ]

    PROCEDURE <name>
  [ QUALIFIERS /<Qname1> /<Qname2> ... /<QnameN> ]
  [ PARAMETERS <parname1>=<partype1> ... ]
  [ RESULT <resname>=<default-value> ]

  [ GLOBAL <gloabalvar1> [ = <initial-value> ] ... ]
  [ LOCAL <localvar1> [ = <initial-value> ] ... ]

        <Statements>
      [ RETURN ]

    ENDPROCEDURE

The PROCEDURE statement defines a command to be known to the whole of Open GENIE. Once defined, the procedure may be invoked at the " >>" prompt using either the keyword or function syntax (see Single-line commands). This section describes the individual parts of a procedure definition as shown above.

Occasionally it is necessary to use a procedure before it can be defined, this is likely if any routines use recursion, or when groups of commands stored in multiple GCL command files are interdependent. In this circumstance, a procedure can be forward declared with the FORWARD statement, generally this will not be needed if files are loaded so that procedures are declared before they are used.

<Statements> consists of any number of single-line or multi-line Open GENIE commands just as would be typed at the terminal in an interactive session. An optional RETURN statement can also be used to allow the procedure to return to the calling procedure before control reaches the ENDPROCEDURE line.

The major difference from typing commands interactively is that all variables used in the procedure must be defined before they can be used, this is the purpose of the five optional declaration statements at the start of each procedure.

These declarations are used in two groups QPR (QUALIFIERS, PARAMETERS and RESULT) and GL (GLOBAL and LOCAL). Within these groups the order of the declarations is unimportant and all (except for the RESULT declaration --- for obvious reasons) can be used as often as necessary. A valid set of declarations could be ordered RQQPPPLLGLG. The only major restriction is that all members of the QPR group must come before any of the GL group, if not, a syntax error will result. The format and purpose of the individual declarations is given below.

QUALIFIERS /<Qname> ...

The QUALIFIERS statement declares any qualifiers that the procedure should respond to. In the procedure, qualifiers can be accessed by treating them as variables with a truth value i.e. true if the qualifier was specified on the command line, false otherwise. Qualifier variables can be tested with IF statements.

Examples

QUALIFIERS /Line /Markers
...
IF NOT Markers
    printn "Without markers"
ENDIF
PARAMETERS <Parname>=<Partype> ...

This PARAMETERS statement declares all the parameters which can be passed to the procedure. <Parname> specifies the name by which the parameter will be known within the procedure and also the name by which it can be specified explicitly on the command line. <Partype> specifies the type of the parameter expected by the procedure. Valid types are "Real", "Integer", "String", "Workspace" and arrays of these "RealArray", "IntegerArray", "StringArray", "WorkspaceArray". If the type fails to match the actual parameter given by the user of the procedure an error message will be generated. Within the procedure, the parameter can be used just like a normal variable. For the simple types (Real, Integer and String), the variable in the procedure is just a copy of the original parameter and cannot be passed back. For all types of arrays and workspaces however, the procedure may modify the contents of the parameters passed to it.

Examples

# A bit of data hacking
PROCEDURE Fix_results
PARAMETERS bad_point=Integer yarray=RealArray
#   zero the bad point
    yarray[bad_point] = 0.0
ENDPROCEDURE
>> # The call to this procedure could be
>> Fix_results  bad_point=100  yarray=MyThesisData
RESULT <Resname> [ = <default-value> ]

The RESULT statement declares a special variable which will be returned at the end of the procedure as a function result. This result variable may be used normally during procedure execution and assigned any value. An optional default value can be specified such that the procedure will return this as the result even if the variable is never assigned another value. Any procedure which is to be called using the function syntax should return a result. Any procedure called using the function syntax but which does not contain a RESULT statement will return the value "Undefined."

Examples

# Augmenting the standard functions with a new procedure
PROCEDURE SinD         # sind(x) for angle 0 <= x <= 360
PARAMETERS x=real
RESULT res = 999.0     # Sentinel silly value
GLOBAL $PI             # Global (defined elsewhere)

IF ( 0.0 <= x ) AND ( x <= 360.0 )
    res = Sin( x * (2.0*$PI/360.0) )
ENDIF

ENDPROCEDURE
LOCAL <Localvar> [ = <initial-value> ] ...
GLOBAL <Globalvar> [ = <initial-value> ] ...

The LOCAL and GLOBAL statements declare variables for use in the procedure.

Local variables are only accessible within the procedure, they are created on entry to the procedure and deleted on exit. If the procedure is called recursively, a new set of variables is created for each level of recursion.

Global variables may be shared with other procedures which have declared global variables of the same name. Unlike local variables, global variables last as long as the Open GENIE session. There is only ever one global variable corresponding to one name (This is in contrast to local variables where there may be several different variables under the same name in different procedures).

Both global and local variables may be initialised with a value. For local variables, this will be reset each time the declaring procedure is entered. For global variables, this will be set only when the first procedure giving an initial value is loaded. The initial value is only assigned if the global variable does not already exist.

All variables created interactively are global variables.

Examples

# use of global & local variables
PROCEDURE TestG
GLOBAL something = 45.0  anything = 50.0
LOCAL anything = 90.0

Printn something " " anything

ENDPROCEDURE
>> # Session 1
>> Testg
45.000000 90.000000
>>
>> # New session 2
>> something = 88.0    		# Override the GLOBAL
>> anything = 22.0     		# a new global variable
>> Testg
88.000000 90.000000
>>