This specification is dedicated to the public domain. Its authors waive all rights to the work worldwide under copyright law, including all related and neighboring rights, as specified in the Creative Commons Public Domain Dedication (CC0 1.0).
Grammar and command syntax below. A valid checktestdata program consists of a list of commands. All commands are uppercase, while variables are lowercase with non-leading digits. Lines starting with '#' are comments and ignored.
The following grammar sub-elements are defined:
integer := 0|-?[1-9][0-9]* float := -?[0-9]+(\.[0-9]+)?([eE][+-]?[0-9]+)? string := ".*" varname := [a-z][a-z0-9]* variable := <varname> | <varname> '[' <expr> [',' <expr> ...] ']' value := <integer> | <float> | <string> | <variable> compare := '<' | '>' | '<=' | '>=' | '==' | '!=' logical := '&&' | '||' expr := <term> | <expr> [+-] <term> term := <term> [*%/] <factor> | <factor> factor := <value> | '-' <term> | '(' <expr> ')' | <factor> '^' <factor> test := '!' <test> | <test> <logical> <test> | '(' <test> ')' | <expr> <compare> <expr> | <testcommand>
That is, variables can take integer, floating point as well as string
values. No dynamic casting is performed, except that integers can be
cast into floats. Integers and floats of arbitrary size and precision
are supported, as well as the arithmetic operators +-*%/^
with the usual rules of precedence. An expression is integer if all
its sub-expressions are integer. Integer division is used on integers.
The exponentiation operator ^
only allows non-negative
integer exponents that fit in an unsigned long. String-valued
variables can only be compared (lexicographically), no operators are
supported.
Within a string, the backslash acts as escape character for the following expressions:
\[0-7]{1,3}
denotes an octal escape for a character\n, \t, \r, \b
denote linefeed, tab, carriage return and backspace\"
and \\
denote " and \Tests can be built from comparison operators, the usual logical
operators ! && ||
(not, and, or) and a number of test
commands that return a boolean value. These are:
MATCH(<string> str)
Returns whether the next character matches any of the characters in 'str'.
ISEOF
Returns whether end-of-file has been reached.
UNIQUE(<varname> a [,<varname> b ...])
Checks for uniqueness of tuples of values in the combined (array)
variables a, b, ... That is, it is checked that firstly all
arguments have precisely the same set of indices defined, and
secondly that the tuples formed by evaluating (a,b,...) at these
indices are unique. For example, if x,y are 1D arrays containing
coordinates, then UNIQUE(x,y)
checks that the points
(x[i],y[i]) in the plane are unique.
INARRAY(<value> val, <varname> array)
Checks if val occurs in one of the indices of array.
The following commands are available:
SPACE
/ NEWLINE
No-argument commands matching a single space (0x20) or newline respectively.
EOF
Matches end-of-file. This is implicitly added at the end of each program and must match exactly: no extra data may be present.
INT(<expr> min, <expr> max [, <variable> name])
Match an arbitrary sized integer value in the interval [min,max] and optionally assign the value read to variable 'name'.
FLOAT(<expr> min, <expr> max [, <variable> name [, option]])
Match a floating point number in the range [min,max] and optionally assign the value read to the variable 'name'. When the option 'FIXED' or 'SCIENTIFIC' is set, only accept floating point numbers in fixed point or scientific notation, respectively.
STRING(<value> str)
Match the string (variable) 'str'.
REGEX(<string> str [, <variable> name])
Match the extended regular expression 'str'. Matching is performed greedily. Optionally assign the matched string to variable 'name'.
ASSERT(<test> condition)
Assert that 'condition' is true, fail otherwise.
SET(<variable> name '=' <expr> value])
Assign 'value' to variable 'name'.
UNSET(<varname> a [,<varname> b ...])
Unset all values for variables a, b, ... This includes all values for array indexed variables with these names. This command should typically be inserted at the end of a loop after using UNIQUE or INARRAY, to make sure that no old variables are present anymore during the next iteration.
REP(<expr> count [,<command> separator]) [<command>...] END
REPI(<variable> i, <expr> count [,<command> separator]) [<command>...] END
Repeat the commands between the 'REP() ... END' statements count times and optionally match 'separator' command (count-1) times in between. The value of count must fit in an unsigned 32 bit int. The second command 'REPI' does the same, but also stores the current iteration (counting from zero) in the variable 'i'.
WHILE(<test> condition [,<command> separator]) [<command>...] END
WHILEI(<variable> i, <test> condition [,<command> separator]) [<command>...] END
Repeat the commands as long as 'condition' is true. Optionally match 'separator' command between two consecutive iterations. The second command 'WHILEI' does the same, but also stores the current iteration (counting from zero) in the variable 'i'.
IF(<test> cond) [<command> cmds1...] [ELSE [<command> cmds2...]] END
Executes cmds1 if cond is true. Otherwise, executes cmds2 if the else statement is available.