Expression Evaluation in Scripts

From C4 Engine Wiki
Jump to navigation Jump to search

A script in the C4 Engine can contain methods of the type Evaluate Expression, sometimes called an expression method for short. An expression method holds a text string representing a mathematical expression that gets evaluated when script execution reaches the method.

For an expression method, a text box is displayed on the left side of the Method Info window where a textual expression may be entered. (The Method Info window is opened by selecting a method and then typing Ctrl-I.) A field for designating an output variable also appears in the lower-left corner of the Method Info window.

If there is a syntax error in an expression, then the method is colored yellow in the script viewport.

Operators

Expressions can use any of the operators from the following list. They are listed in order of evaluation precedence, which matches the precedence rules for C++. Parentheses can be used to group subexpressions.

Operator

Description

Variable types accepted

Notes

.

Member Access

color, vector, point

Returns a scalar component of type float.

For colors, one of r, g, b, or a can appear to the right of the dot operator.

For vectors and points, one of x, y, or z can appear to the right of the dot operator.

~

Bitwise NOT

boolean, integer

This is a unary operator.

*

Multiply

boolean, integer, float, color, vector, point

Colors can only be multiplied by other colors or by floating-point, integer, or boolean scalar values.

Vectors and points can only be multiplied by other vectors and points or by floating-point, integer, or boolean scalar values.

Multiplication is componentwise for colors, vectors, and points.

/

Divide

boolean, integer, float, color, vector, point

A color, vector, or point type can only appear as the left operand, and they can be divided by floating-point, integer, or boolean scalar values.

Integer division by zero is defined to be zero.

%

Modulo

boolean, integer

If the right operand is zero, then the result is defined to be zero.

+

Plus

boolean, integer, float, string, color, vector, point

Colors can only be added to other colors.

Vectors and points can only be added to other vectors and points.

A unary plus is accepted and performs no operation.

Minus or Negate

boolean, integer, float, color, vector, point

Colors can only be subtracted from other colors.

Vectors and points can only be subtracted from other vectors and points.

<<

Shift Left

boolean, integer


>>

Shift Right

boolean, integer

The shift is always signed.

<

Less Than

boolean, integer, float

Always returns a boolean result.

>

Greater Than

boolean, integer, float

Always returns a boolean result.

<=

Less Than or Equal

boolean, integer, float

Always returns a boolean result.

>=

Greater Than or Equal

boolean, integer, float

Always returns a boolean result.

==

Equal

boolean, integer, float, string

Always returns a boolean result.

!=

Not Equal

boolean, integer, float, string

Always returns a boolean result.

&

Bitwise AND

boolean, integer


^

Bitwise XOR

boolean, integer


|

Bitwise OR

boolean, integer


Note that the logical operators && and || are not present in the table. These were intentionally left out of the scripting language because they are not necessary. The same results can be attained by using the & and | operators instead. If the evaluation semantics of && and || are needed, then you can use conditional execution to evaluate the expression in pieces.

Operands

Each operand in an expression can be any of the following:

  • The boolean value true or false.
  • An integer literal value using any features from the OpenDDL syntax. This includes underscores separating digits, support for binary, octal, and hexadecimal literals (using the prefixes 0b, 0o, and 0x, respectively), and character literals enclosed in single quotes. Integers are always stored as signed 32-bit quantities.
  • A floating-point literal value matching the OpenDDL syntax, with the exception that it must be decimal and contain one of the characters '.', 'e', or 'E' (decimal point or exponent indicator). Floats are always stored as 32-bit quantities.
  • A literal string matching the OpenDDL syntax. Escape characters and Unicode are supported.
  • The name of any variable defined for the script, possibly followed by the dot operator to access an individual component of a color, vector, or point.

In any binary operation appearing in an expression, a mismatch between the types of the two operands causes one of the operands to be promoted to the type of the other. The possible promotions are those in the following list:

  • Boolean can be promoted to integer, float, or string.
  • Integer can be promoted to float or string.
  • Float can be promoted to string.

Result

An expression always produces an output value, and the boolean result for the expression method reflects the value of the expression. If the output value is not stored in a variable, then the boolean result is still valid. If the value of the expression is not boolean, then one of the following conversions is made to arrive at a boolean result:

  • For an integer, the value 0 becomes false, and any other value becomes true.
  • For a float, the value 0.0 becomes false, and any other value becomes true.
  • For a string, the empty string becomes false, and any other string becomes true.

Expression Grammar

The following grammar provides a formal description of exactly how expressions are parsed.

identifier                 ::= [A-Za-z_] [0-9A-Za-z_]*

hex-digit                  ::= [0-9A-Fa-f]

escape-char                ::= '\"' | "\'" | "\?" | "\\" | "\a" | "\b" | "\f" | "\n" | "\r" | "\t" | "\v"
                             | "\x" hex-digit hex-digit

bool-literal               ::= "false" | "true"

decimal-literal            ::= [0-9] ("_"? [0-9])*

hex-literal                ::= ("0x" | "0X") hex-digit ("_"? hex-digit)*

octal-literal              ::= ("0o" | "0O") [0-7] ("_"? [0-7])*

binary-literal             ::= ("0b" | "0B") ("0" | "1") ("_"? ("0" | "1"))*

char-literal               ::= "'" ([#x20-#x26#x28-#x5B#x5D-#x7E] | escape-char)+ "'"

integer-literal            ::= decimal-literal | hex-literal | octal-literal | binary-literal | char-literal

float-literal              ::= (([0-9] ("_"? [0-9])* "." ([0-9] ("_"? [0-9])*)? | ([0-9] ("_"? [0-9])*)? "." [0-9] ("_"? [0-9])*)
                                   (("e" | "E") ("+" | "-")? [0-9] ("_"? [0-9])*)?
                             | [0-9] ("_"? [0-9])* ("e" | "E") ("+" | "-")? [0-9] ("_"? [0-9])*)

string-literal             ::= ('"' ([#x20-#x21#x23-#x5B#x5D-#x7E#xA0-#xD7FF#xE000-#xFFFD#x010000-#x10FFFF] | escape-char
                             | "\u" hex-digit hex-digit hex-digit hex-digit
                             | "\U" hex-digit hex-digit hex-digit hex-digit hex-digit hex-digit)* '"')+

primary-expression         ::= ("+" | "-" | "~")? (identifier ("." identifier)? | integer-literal | float-literal | string-literal | "(" or-expression ")")

multiplicative-expression  ::= (multiplicative-expression "*" | multiplicative-expression "/" | multiplicative-expression "%")? primary-expression

additive-expression        ::= (additive-expression "+" | additive-expression "-")? multiplicative-expression

shift-expression           ::= (shift-expression "<<" | shift-expression ">>")? additive-expression

relational-expression      ::= (relational-expression "<" | relational-expression ">" | relational-expression "<<" | relational-expression ">>")? shift-expression

equality-expression        ::= (equality-expression "==" | equality-expression "!=")? relational-expression

and-expression             ::= (and-expression "&")? equality-expression

xor-expression             ::= (xor-expression "^")? and-expression

or-expression              ::= (or-expression "|")? xor-expression

See Also