Expression Grammar

Expressions are used for queries, for defaults of card items, and for printing expressions into cards. They are set in Database Edit mode; a normal user does not deal with expressions directly.

Expressions deal with two data types, strings and numbers. Expressions or sub-expressions returning strings are enclosed in braces; expressions or sub-expressions returning numbers are enclosed in parentheses. There are many built-in operators and functions; most of them can be used only in either string or numeric context.

Numbers begin with a numerical digit or a period, and are in standard integer, floating-point, or exponential notation. String literals are enclosed in double quotes. Conversions from numbers to strings use the %g format (unless printf is used); conversions from strings to numbers skips leading blanks and converts like atof. Trailing non-numeric characters are ignored.

Expressions are interpreted, not compiled. This means that all parts of the expression are evaluated, ?:, &&, and || do not short-circuit.

In the following tables, n stands for a number ot a numerical expression, and s stands for a literal string or a string expression. Note that some operators, such as == and date, appear in both contexts.

Numerical Operations

Divisions by zero return 1. Arithmetic operators use standard C precedences. Bitwise operations operate on 32 bits only.

operatortypeoperation
(n) n Number
{s} n In number context, convert string to a number
n ? n : n n If the first number is nonzero, return the second number; otherwise, return the third number
n , n n Evaluate both numbers, return second
- n n Unary minus
! n n Unary boolean NOT
~ n n Unary bitwise NOT
n + n n Add two numbers
n - n n Subtract two numbers
n * n n Multiply two numbers
n / n n Divide two numbers
n % n n Calculate modulo of two numbers
n & n n Calculate bitwise AND of two numbers
n && n n Calculate boolean AND of two numbers
n | n n Calculate bitwise OR of two numbers
n || n n Calculate boolean OR of two numbers
n ^ n n Calculate bitwise XOR of two numbers
n << n n Calculate bitwise left shift
n >> n n Calculate bitwise right shift
n == n n 1 if both numbers are equal, 0 otherwise
n != n n 1 if both numbers are not equal, 0 otherwise
n < n n 1 if the first number is less than the second, 0 otherwise
n > n n 1 if the first number is greater than the second, 0 otherwise
n <= n n 1 if the first number is less than or equal to the second, 0 otherwise
n >= n n 1 if the first number is greater than or equal to the second, 0 otherwise
sqrt(n) n Square root of a number
exp(n) n Exponential function, en
log(n) n Decimal logarithm, log10 n
ln(n) n Natural logarithm, loge n
pow(n, n) n First number raised to the second, nm
sin(n) n Sine of a number, sin x
cos(n) n Cosine of a number, cos x
tan(n) n Tangent of a number, tan x
asin(n) n Arc sine of a number, sin-1 x
acos(n) n Arc cosine of a number, cos-1 x
atan(n) n Arctangent of a number, tan-1 x
atan2(n, n) n Quadrant-aligned arc tangent
len(s) n Length of a string
bound(n, n, n) n The first number bounded by a minimum (second number) and a maximum (third number)

String Operations

Note that string comparisons return strings, and must be enclosed in braces {...} if && or || or other numerical operators are used on the result.

operatortypeoperation
{s} s String
(n) s In string context, convert number to a string
s ; s s Evaluate both strings, return second
s . s s Concatenate strings
s ? s : s s If the numeric value of the first string is nonzero, return the second string; otherwise, return the third string
s == s s Return "1" if the two strings match; otherwise, return "0"
s != s s Return "1" if the two strings do not match; otherwise, return "0"
s < s s Return "1" if the first string is lexicographically less than the second string; otherwise, return "0"
s > s s Return "1" if the first string is lexicographically greater than the second string; otherwise, return "0"
s <= s s Return "1" if the first string is lexicographically less than or equal to the second string; otherwise, return "0"
s >= s s Return "1" if the first string is lexicographically greater than or equal to the second string; otherwise, return "0"
s in s s Return "1" if the first string is contained in the second string; otherwise, return "0"
chop(s) s Return the string with the trailing newline, if any, removed
substr(s, n, n) s Return a substring of the first string. The first number is the start index and the second the length. A negative index counts from the end.
printf(args) s Format and return a string; args is a comma-separated list of expressions. Compound expressions must be enclosed in ( ) or { }.

Variables

Variables are letters a through z and A through Z that can hold strings or numbers. When a variable is assigned to, the result of the assignment is returned. All variables a...z are reset to the empty string (or 0) when a database is loaded from disk; variables A...Z are never automatically cleared.

operatortypeoperation
var s,n Value of a variable
var = s s Assign string value to a variable
var = n n Assign numeric value to a variable
var .= s s Append string to a variable
var += n n Add a number to a variable
var -= n n Subtract a number from a variable
var *= n n Multiply a variable by a number
var /= n n Divide a variable by a number
var %= n n Assign modulo with a number to variable
var &= n n Perform logical AND with a variable
var |= n n Perform logical OR with a variable
var++ n Post-increment variable
var-- n Post-decrement variable
++var n Pre-increment variable
--var n Pre-decrement variable

Database Access

Database rows (cards) can be accessed by providing an index in brackets. Without brackets, the current card (this) is assumed. Database columns are named. The name must always be prefixed with an underscore (_). In place of the name, the field can be selected with a column number (which must also be prefixed with an underscore), beginning at 0. Only fields that store data in the database can be accessed (types Input, Time, Flag, and Choice); this excludes fields of type Label and Print. Fields can also be assigned to using the ``='' sign; the assignment returns the assigned value. Avoid assigning to fields in default and Print and other expressions that are evaluated when redrawing the card; the card is not re-redrawn if the redrawing itself changed it. It is recommended to use field assignments only in button action expressions.

The avg, dev, min, max, and sum operators differ from all other operators: they don't reference a field in the current or any single card, they operate on a field in all cards by accessing an entire column of the database. These operators are also available as qavg, qdev, qmin, qmax, and qsum, which apply the calculation only to the result of the last query (i.e., to the cards displayed in the summary). Finally, the savg, sdev, smin, smax, and qsum variations are applied to all cards in the current section; if there are no sections or if all sections are selected, all cards are considered.

The switch statement is legal only in Action when pressed expressions for Button-type fields in the form editor. It does nothing except as action for a button in a card. It switches grok to a new form as if the Database pulldown had been used (see the Editing Forms chapter for details about the difference between databases and forms. The first argument is the new form name, the second argument is the query expression or search string that determines which cards are displayed in the summary initially. The possible combinations are:

Because short-circuiting doesn't work, switch can't depend on a conditional, but its two arguments can. switch returns the empty string, which means that the button won't execute a command as usual; if this is overridden by appending a semicolon and another string expression, the command is executed after the database switch. To execute a script before switching, prepend a system statement and a semicolon to the switch statement (the switch is done after the expression is completely evaluated). To switch back to the previous form, use the prevform statement.

Looping over all cards in the database can be performed using the foreach statement. It takes either one or two arguments, both of which can bei either string or numeric expressions. In its one-argument form, it applies the argument expression to every card in the database. In its two-argument form, it applies the second argument expression to all cards that cause the first argument expression to evaluate to true (nonzero numeric value or string not beginning with ``f'' or ``F''). For example,

     {(a=0); foreach("{_group == 'f'", "(a++)")}

clears the variable a and then applies the expression (a++) to all cards for which {_group == 'f'} evaluates to true. The number of cards in group f is left in variable a. Note the quotes around the argument expressions; they must be passed to the foreach statement as strings. Like all strings, they can be put together using expressions, for example using the ``.'' (dot) operator. Although foreach, like switch, can only be used in string expressions it does not return anything.

operatortypeoperation
_field s,n A field from the database, current card
_field[n] s,n A field from the database, any card
_field = n n Change a field in the database, current card
_field = s s Change a field in the database, current card
_field[n] = n n Change a field in the database, any card
_field[n] = s s Change a field in the database, any card
expand(_field) s A field from the database, current card, with flag or choice value expanded to mnemonic string (*)
expand(_field[n]) s A field from the database, any card, with flag or choice value expanded to mnemonic string (*)
this n The number of the current card, 0 is first
last n The number of the last card, 0 is first
disp n The number of the currently displayed card, or -1 if none
avg(_field) n Average of a field in all cards
qavg(_field) n Average the current query result
savg(_field) n Average the current section
dev(_field) n Standard deviation of a field in all cards
qdev(_field) n Std. dev. of the current query result
sdev(_field) n Std. dev. of the current section
min(_field) n Minimum value of a field in all cards
qmin(_field) n Minimum of the current query result
smin(_field) n Minimum of the current section
max(_field) n Maximum value of a field in all cards
qmax(_field) n Maximum value of the current query result
smax(_field) n Maximum value of the current section
sum(_field) n Sum of a field in all cards
qsum(_field) n Sum of the current query result
ssum(_field) n Sum of the current section
dbase s The name of the accessed database file
form s The name of the accessed form file
section s The name of the current section, or the empty string
section n The number of the section the current card is in, or 0
section[n] s The name of section n
section[n] n The number of the section card n is in, or 0
prevform s The name of the previous accessed form file
switch(s, s) s Database switch and/or query; see above
foreach(s) s Apply expression to all cards; see above
foreach(s, s) s Apply expression to all matching cards; see above

(*) The expand keyword was introduced in grok version 1.5.

Operating System Access

operatortypeoperation
system(s) s Execute a shell command and return the result as a string
$envvar s Return the value of the environment variable envvar
host s The host name of the local host
user s The user's login name
uid n The user's numeric user ID
gid n The user's numeric group ID
access(s, n) n 1 if the file name exists (if the number is 0), or if it can be accessed for execution (1), writing (2), and/or reading (4). See access(3).
beep s Ring the terminal bell, return a null string
error(args) s Format a string like printf, print it in a window, return a null string

Time Conversion

Dates and times are stored as number of seconds since January 1, 1970. Durations are stored as number of seconds. Note that this means thata time is a significantly larger number than a duration, even if both have the same hh:mm string representation. The representation depends on the date and time format selected in the Preferences menu. A date or time of exactly 0 (January 1, 1970, 0:00 GMT) is converted to the empty string; this convention is useful for blank date fields.

operatortypeoperation
time s The current time as hh:mm or hh:mm[ap] string
time(n) s Extract time part of the number, and format as hh:mm or hh:mm[ap] string
time(s) n Convert a time string to a number of seconds
date s Today's date as dd.mm.yy or mm/dd/yy string
date n Current time in seconds since January 1, 1970
date(n) s Extract date part of the number, and format as dd.mm.yy or mm/dd/yy string
date(s) n Convert a date or date/time string to a number of seconds
duration(n) s Convert a number of seconds to a hh:mm string
duration(s) n Convert a duration string to a number of seconds
year(n) n Extract the (four-digit) year from a time
month(n) n Extract the month 1..12 from a time
day(n) n Extract the day 1..31 from a time
hour(n) n Extract the hour 0..23 from a time
minute(n) n Extract the minute 0..59 from a time
second(n) n Extract the second 0..59 from a time
julian(n) n Extract the julian date 0..365 from a time
leap(n) n 1 if the time is in a leap year, or 0 otherwise

Examples

For an action when pressed, if you want to pass arguments and run scripts etc, here is an example of a way of writing something in the ``action when pressed'' field. (It must be entered on a single line.) Note the blanks that separate arguments.

     {"/bin/mailmaker \""._receipt."\" \""._senton."\" \""._partxofy."\"; xterm -geometry 85x38+109+7 -e /bin/mailsend"}

In this example, Mailmaker is a script that takes the _receipt, _senton, and _partxofy fields as arguments and composes an email with headers and body. mailsend is a script that takes the headers and body and sends it out; it runs in an xterm so it can ask you if you really want to send that mail. (This example was contributed by Pawan <pawan@generalogic.com>).