# expressions

Expressions apply operators to numeric and string operands, and return a result. They can be used in $[...] expression subs, the condition of /if and /while statements, the condition of /def -E, and as arguments to /return, /result, and /test commands.

## Operands

Operands can be any of:

- Integer constants (e.g., `42`).
- Real decimal point constants ("reals", for short) containing a decimal point (e.g., `12.3456789`) or exponent (e.g., `1e-2`) or both (e.g., `1.23e4`).
- Time values of the form hours:minutes, hours:minutes:seconds, or seconds (where seconds may contain a decimal point followed by up to 6 digits), will be interpreted as real seconds (e.g., 0:01:02.3 == 62.3), and can be used anywhere a number is expected.
- Strings of characters, surrounded with quotes (", ', or `, with the same kind of quote on each end), like `"hello world"`.
- Variable references (see below) like `visual`.
- Variable substitutions (see below) like `{visual}` and `{1}`.
- Macro substitutions like `${COMPRESS_SUFFIX}`.
- Command substitutions like `$(/listworlds -s)`.

Named variables may be accessed by simply using their name (with no leading '%'). This is called a variable reference, and is the preferred way of using a variable in an expression. The special substitutions (*, ?, #, n, Ln, Pn, R) may not be used this way.

Variable substitutions of the form "{selector}" and "{selector-default}" may be used. They follow the same rules as variable substitution in macros, except that there is no leading '%', and the '{' and '}' are required. The special substitutions (*, ?, #, n, Ln, Pn, R) are allowed.

Macro-style variable substitutions beginning with '%' may also be used, but are not recommended, since the multiple '%'s required in nested macros can quickly get confusing. It always easier to use one of the above methods.

## Operators

In the following list, operators are listed in groups, from highest to lowest precedence. Operators listed together have equal precedence. The letters in the table below correspond to the type of objects acted on by the operators: n for numeric (integer or real); s for string; e for any expression. All operators group left-to-right except assignment, which groups right-to-left. If any binary numeric operator is applied to two integers, the result will be an integer, unless the result would overflow, in which case it is converted to real. If either operand is a real, the other will be converted to real if it is not already a real, and the result will be a real.

(e)
  Parentheses, for grouping.
func(args)
  Perform function func on arguments args. (see: functions).
!n
  Boolean NOT (1 if n==0, otherwise 0).
+n
  Unary positive (useful for converting a string to a number).
-n
  Unary negative.
++v
  Equivalent to `(v := v + 1)`.
--v
  Equivalent to `(v := v - 1)`.
n1 * n2
  Numeric multiplication.
n1 / n2
  Numeric division. Remember, if both operands are type integer, the result will be truncated to integer.
n1 + n2
  Numeric addition.
n1 - n2
  Numeric subtraction.
n1 = n2
  Numeric equality (but easily confused with assignment; you are advised to use `==` instead).
n1 == n2
  Numeric equality.
n1 != n2
  Numeric inequality.
s1 =~ s2
  String equality (case sensitive, attribute insensitive).
s1 !~ s2
  String inequality (case sensitive, attribute insensitive).
s1 =/ s2
  String s1 matches glob pattern s2.
s1 !/ s2
  String s1 does not match glob pattern s2.
n1 < n2
  Numeric less than.
n1 <= n2
  Numeric less than or equal.
n1 > n2
  Numeric greater than.
n1 >= n2
  Numeric greater than or equal.
n1 & n2
  Boolean AND. n2 will be evaluated if and only if n1 is nonzero.
n1 | n2
  Boolean OR. n2 will be evaluated if and only if n1 is zero.
n ? e1 : e2
n ? : e2
  Conditional. If n is nonzero, the result is the value of expression e1; otherwise it is the value of expression e2. If e1 is omitted, the value of n is used in its place. Note that digits followed by a colon is interpreted as a time value, so if the e2 operand of the ?: operator is an integer, you must separate it from the colon (with a space or parenthesis, for example).
v := e
  Assignment. The identifier "v" refers to the variable in the nearest scope. If not found, a new variable is created at the global level, as if by /set. If v is a special variable, the value of e may need to be converted to the type of v, or the assignment may fail altogther if the value is not legal for v. The value of the assignment expression is the new value of v.
v += n
  Equivalent to `v := v + (n)`.
v -= n
  Equivalent to `v := v - (n)`.
v *= n
  Equivalent to `v := v * (n)`.
v /= n
  Equivalent to `v := v / (n)`.
e1 , e2
  Comma. Expressions e1 and e2 are evaluated; the result is the value of e2. Only useful if e1 has some side effect.

The comparison operators return 0 for false, nonzero for true. The boolean operators (& and |) stop evaluating as soon as the value of the expression is known ("short-circuit"), and return the value of the last operand evaluated. This does not affect the value of the expression, but is important when the second operand performs side effects.

Normal (non-enumerated) Variables set with any of the assignment operators keep the type of the expression assigned to them. This is different than /set and /let, which always assign a string value to the variables. This distinction is important for real numeric values, which lose precision if converted to a string and back.

All operands will be automatically converted to the type expected by the operator.

- String to numeric: leading signs, digits, colons, and exponents are interpreted as an integer, decimal (real), or time (real) value; e.g., "12abc" becomes 12, "12.3junk" becomes 12.3, "0:01:02.3" becomes 62.3, and "xyz" becomes 0.
- Integer to real: straightforward.
- Real to integer: the fractional part is truncated.
- Enumerated variable to string: straightforward string value.
- Enumerated variable to numeric: one integer stands for each of the allowed values. "Off" is always 0, "on" is always 1, etc. This makes `(!visual)` and `(visual == 0)` the same as `(visual =~ 'off')`.
- Integer to string: straightforward.
- Real to string: decimal notation if the exponent is greater than -5 and less than %sigfigs, otherwise exponential notation.
- Normal (non-enumerated) variables are treated as whatever type their value has.

## Examples

Given the variables

        /set X=5
        /set name=Hawkeye
        /set visual=1

here are some expressions and their values:

        Expression		   Value   Comments
        ----		   -----   --------
        3 + X * 2		      13   3 + (5 * 2) = 13.
        "foo" =~ "bar"	       0   "foo" is not identical to "bar".
        name =/ 'hawk*'	       1   "Hawkeye" matches the glob "hawk*".
        X =~ "+5"		       0   X is interpreted as string "5".
        X == "+5"		       1   string "+5" is converted to integer 5.
        visual & (X > 0)	       1   visual is nonzero, AND %X is positive.

See: functions, /test, evaluation, patterns

Back to index
Back to tf home page

Copyright © 1995, 1996, 1997, 1998, 1999, 2002, 2003, 2004 Ken Keys