Expressions
===========
M.U.G.E.N, (c) Elecbyte 2001
Documentation for version 2001.04.01

Beta-release documentation (incomplete)
Updated 18 November 2000



====================================================================
0. Contents
====================================================================

MUGEN supports the use of arithmetic expressions in the CNS and CMD 
files. This document gives a complete description of
expression syntax.

I.    Data types: Ints and Floats
II.   Arithmetic operators
III.  Precedence and associativity of operators
IV.   Expression syntax
V.    Triggers
VI.   Trigger redirection
VII.  SC values
VIII. More on function-type triggers
IX.   Expressions in state and state controller parameters
X.    (Advanced) Optimizing for speed



====================================================================
I. Data types: Ints and Floats
====================================================================

An int is a whole number, such as 0, 1, -4, etc. Ints can assume 
values
between about -2 billion and 2 billion. A float is a real number which
has a "decimal part", such as 5.24, or -4247.44. Note that a whole 
number such as 55 can also be represented as a float, thus: 55.0. 
Floats offer only 7 significant figures of precision.

The behavior of arithmetic expressions depends heavily on the 
underlying data types used to represent numbers. Also, state 
controllers may expect their input to be given as a certain type, and 
will give errors if the wrong type is supplied.



====================================================================
II. Arithmetic operators
====================================================================

In addition to the familiar arithmetic operators like +, -, *, and /,
several other operators exist which act on their input values in
different ways. This section describes the behavior of these 
operators.

+   
The familiar addition operator. x + y evaluates to an int if x and y
are both ints, or a float if x and y are both floats. If one of x or y 
is a float, then both are converted to floats (with possible loss 
of precision in the process) and then x + y is evaluated as a sum
of floats.

-  
The familiar subtraction operator. As with addition, x - y evaluates 
to an int if x and y are both ints, or a float if they are both 
floats.
If one of x or y is a float, they are both converted to floats and the
subtraction is performed as a subtraction of floats.

-  
If - appears in a context where the subtraction operator is not 
appropriate, it is interpreted as the negation operator. That is, 
given 
input x, "-x" represents the value -x. Returns the same type as x's.

*  
The multiplication operator. The behavior is similar to the + and -
operators.

/ 
The division operator. If x and y are both ints, then x/y gives the
number of times that y goes evenly into x. For instance, 7/2 = 3,
because 2 goes into 7 three times (with a remainder of 1 which is
discarded). If x and y are both floats, then x/y returns a float. For
instance, 7.0/2.0 = 3.5. Finally, if one of x or y is a float, they 
are
both converted to floats before evaluation.
The result of a division by zero will be discussed in the section on 
SC values.

% 
The remainder or mod operator. If x and y are both ints, x%y returns
an int representing the remainder after performing a division x/y. For
instance, 7%2 = 1, and 23 % 17 = 6. It is an error to use the % 
operator on float values, or to compute x%0. The result of such 
operations will be discussed in the section on SC values.

** 
The exponentiation operator. If x and y are both ints >= 0, then x**y
gives an int representing x raised to the power of y (we define 0**0 =
1). Otherwise, x**y is computed as an exponentiation of real numbers
(converting x and y to floats first if necessary). The result of an
invalid exponentiation such as -1^.5 will be discussed in the section 
on SC values.

! 
The logical NOT operator. !x evaluates to 0 (int) if x is nonzero,
and 1 (int) if x is zero.

&& 
The logical AND operator. x && y evaluates to 1 (int) if x and y
are both nonzero, and to 0 (int) otherwise.

|| 
The logical OR operator. x || y evaluates to 1 (int) if one or more
of x and y is nonzero, and to 0 (int) otherwise.

^^
The logical XOR operator. x ^^ y evaluates to 1 (int) if exactly one
of x and y is nonzero, and to 0 (int) otherwise.

~ 
The bitwise NOT operator. ~x inverts the bits of x's binary (two's 
complement) representation. It is an error to apply this to a float --
for the result of such an operation, see the section on SC values.

& 
The bitwise AND operator. The nth bit of x&y is set if and only if the
nth bits of both x and y are set. Returns an SC value if either of x 
or y is a float.

| 
The bitwise OR operator. The nth bit of x|y is set if and only if the
nth bit of either x or of y (or both) is set. Returns an SC value if 
either of x or y is a float.

^ 
The bitwise XOR operator. The nth bit of x^y is set if and only if the
nth bit of exactly one of x and y is set. Returns a SC value if either 
of x or y is a float.

= 
The equality operator. If x and y are both ints or both floats, x = y 
evaluates to 1 (int) if x and y are equal, and 0 otherwise. If exactly
one of x or y is a float, then they are both converted to floats 
before
testing for equality.

:= 
The assignment operator. An unredirected variable name (var(n) or 
fvar(n) for suitable values of n) must appear on the left-hand side. 
If the left-hand side contains an integer variable, then the right-
hand side is truncated to an integer before assignment. If the left-
hand side contains a float variable, then the right-hand side is 
converted to float if necessary before assignment. In both cases, the 
value of the expression is the value that is assigned to the variable.

!= 
The inequality operator. If x and y are both ints or both floats, 
x != y evaluates to 1 (int) if x and y are not equal, and 0 otherwise.
If exactly one of x or y is a float, then they are both converted to
floats before testing for equality.

< 
The less-than operator. If x and y are both ints or both floats, x <
y evaluates to 1 (int) if x < y, and 0 otherwise. If exactly one of x 
or
y is a float, then they are both converted to floats before testing 
for
equality.

<= 
Similar to <, with the exception that if x = y, then x <= y returns 
1 (int).

> 
The greater-than operator. If x and y are both ints or both floats,
x > y evaluates to 1 (int) if x > y, and 0 (int) otherwise. If exactly
one of x or y is a float, then they are both converted to floats 
before
testing for equality.

>= 
Similar to >, with the exception that if x = y, then x >= y returns 
1 (int).

=[,]
!=[,]
=[,)
!=[,)
=(,]
!=(,]
=(,)
!=(,)
Interval operators. These take three arguments, x, y, and z. If any of
x, y, or z is a float, they are all converted to floats. After 
conversion if necessary, x = [y,z] is equivalent to (x >= y) && (x <= 
z). Similarly, x = (y,z) is equivalent to (x > y) && (x < z). The 
half-open intervals have the obvious meaning.

The negated interval operators work as follows: x != [y,z] is 
equivalent (after conversion if necessary) to (x < y) || (x > z). 
x != (y,z) is equivalent to (x <= y) || (x >= z). The half-open 
intervals again have the obvious meaning. 

You can view the interval operators as producing the appropriate open, 
closed, or half-open intervals on the ints or the floats. The = symbol 
means set membership in this context.

Some restrictions apply on where intervals may be placed in an
expression. See the section on syntax for details.



====================================================================
III. Precedence and associativity of operators
====================================================================

If you consider an expression like 3+2*5, the result is different
depending if you evaluate the * first (yielding 13) or if you evaluate
the + first (yielding 25). To disambiguate expressions such as this,
operators are assigned distinct precedence levels. In this case, the
precedence of * is higher than the precedence of +, so the * is
evaluated first, then the + is applied to the result. So the correct
answer is 13.

If two operators share the same precedence, then the expression is
evaluated from left to right, except for the unary operators and the 
assignment operator, which associate right to left. For instance, * 
and / share the same precedence, so 5.0*5/6 evaluates to 25.0/6, which 
evaluates to 4.166667.  On the other hand, 5/6*5.0 evaluates to 0*5.0, 
which evaluates to 0.0.  In contrast, because unary operators 
associate right to left, -!0 is grouped as -(!0), which evaluates to -
(1), which then evaluates to -1.

If part of an expression is grouped in parentheses (), then that part 
of the expression is evaluated first. For instance, in the expression
(3+2)*5, the + is evaluated first, giving 5*5, which then evaluates to
25. If parentheses are nested, the innermost parentheses are evaluated 
first.

Operator precedence is basically the same as in C. The complete list 
of 
operator precedence, from highest to lowest, is as follows:

! ~ -  (Unary operators)
**
* / %
+ -
> >= < <=
= != intervals
:=
&
^
|
&&
^^
||

Programmers are encouraged to parenthesize as necessary to maintain 
clarity. Otherwise, bugs due to subtle misunderstanding of operator
precedence are almost assured.



====================================================================
IV. Expression syntax
====================================================================

Basically, any normal arithmetic expression is allowable. In addition, 
since the relational operators (>, <=, etc.) are viewed as returning 
ints, it is possible to operate on their return values, giving some
unusual-looking expressions like

1.0 = (2 = (1 > 0) + !(0 < 1))

The 1 > 0 term evaluates to 1, and the 0 < 1 term evaluates to 0. 
Hence
!(0 < 1) evaluates to 1, so the expression simplifies to

1.0 = (2 = 1 + 1)

Since 2 = 1 + 1, the term in parentheses evaluates to 1, so the
expression further simplifies (after type conversion) to

1.0 = 1.0

which evaluates to 1 (int), since the equality holds.

A notable restriction in expression syntax is that interval operators
are only allowed to appear on the rightmost side of an expression. If
part of an expression is enclosed in parentheses, then that part is
considered a subexpression, and an interval is allowed to appear on 
the
right side of that subexpression. So the following is a well-formed
expression, which evaluates to 0:

(1 = [0,2]) = (0,1)

But the following is not well-formed:

1 = [0,2] = (0,1)

In addition, no operator symbols other than = or != may appear before 
an interval. So an expression like 5 > [0,2], or 4 + [1,4), is not 
allowed.

In comma-separated parameter lists, such as the arguments to some 
function-type triggers or parameters to state controllers, each 
expression in the list is considered a separate subexpression, and 
therefore intervals may appear at the end of those subexpressions.



====================================================================
V. Triggers
====================================================================

For historical reasons, two distinct constructs are both called
"triggers." The first is what might be more properly called a
condition-type trigger, and the second is what might be more properly
called a function-type trigger. For instance, in the CNS, a typical 
state controller might look like

[State 1234, 5]
type = ChangeState
trigger1 = time = 0
value = 0

The entire line "trigger1 = time = 0" is a condition-type trigger. If
the expression "time = 0" evaluates to a nonzero value, then the
ChangeState controller is executed. If the expression "time = 0"
evaluates to zero, then the ChangeState controller is not executed.
Thus whether the condition is zero or nonzero affects whether the 
controller is triggered.

On the other hand, the word "time" appearing in the expression is a
function-type trigger. It returns a value, namely, the amount of time
that the player has been in state 1234. Note that a function-type
trigger doesn't "trigger" anything. It just gives a value that can be
acted on within the expression.

To further illustrate the difference, let us consider a different 
state
controller:

[State 1234, 5]
type = VarSet
trigger1 = 1
v = 0
value = time + 5

Note that the condition-type trigger "trigger1 = 1" now contains no
function-type triggers within it. Since the expression "1" always
evaluates to 1, the controller will be triggered every frame. To
determine what value to assign var0, the expression "time + 5" is
evaluated. The function-type trigger "time" returns the player's
statetime. Then 5 is added and the result is stored in var0.

A complete list of function-type triggers can be found in trigger.doc.

In general, which of the two types of triggers is meant is clear from
context. Where there is some ambiguity, the terms "condition-type
trigger" and "function-type trigger" will be used.



====================================================================
VI. Trigger redirection
====================================================================

In the above example, the time trigger returned the statetime of the
player. But sometimes, one might wish to check the statetime of the
player's target, or the player's parent (if the player is a helper),
etc. This can be accomplished by preceding the trigger name by a 
keyword indicating whose information should be returned. This process 
is known as trigger redirection. For example,

5 + parent, time

returns 5 + the player's parent's statetime.

The complete list of redirection keywords is the following:

*) parent
Redirects the trigger to the player's parent. (Player must be a 
helper.)
*) root
Redirects the trigger to the root. 
*) helper
Redirects the trigger to the first helper found.
*) helper(ID)
ID should be a well-formed expression that evaluates to a positive 
integer. The trigger is then redirected to a helper with the 
corresponding 
ID number.
*) target
Redirects the trigger to the first target found.
*) target(ID)
ID should be a well-formed expression that evaluates to a non-negative
integer. The trigger is then redirected to a target with the
corresponding targetID.

If the trigger is redirected to an invalid destination (for instance, 
if it is retargeted to a helper when none exist), then an error is 
returned. See the section on SC values.

Note: multiple redirection (e.g.,  root,target,time) is not currently 
supported.


====================================================================
VII. SC values
====================================================================

There are several sources of unrecoverable error in expressions. For
instance, one could attempt to divide by 0, evaluate the square root 
of
a negative number, or attempt to redirect a trigger to a nonexistent
destination. In these situations, SC values are used as a way to 
complete expression evaluation gracefully. 

An SC value is a special kind of int which can only take on the values 
1 or 0, called SC true (STrue) and SC false (SFalse). The result of 
any operation or trigger evaluation on an SC value is that SC value. 
(In other words, you can think of the SC values as variants on the 
"bottom" element in computation theory. Semantically speaking, CNS 
expression evaluation is strict in bottom.) If two SC values are given 
to the same operator, then the leftmost one takes priority. 

For instance, the expression

4 + (1/0)*2

evaluates to 4 + (SFalse) * 2, which evaluates to 4 + SFalse, which
evaluates to SFalse. On the other hand,

STrue / SFalse

would evaluate to STrue, because STrue comes on the left. Finally,

helper, time

would evaluate to SFalse if called with no helpers.

Currently, STrue is unused. Only SFalse is returned in error 
conditions. This means that any condition-type trigger that causes an 
error during evaluation will not trigger. So, in

type = ChangeState
trigger1 = helper, statetype = A 
value = 0

the ChangeState controller would never be executed if no helpers
existed, because the expression "helper, statetype = A" would evaluate
to SFalse, which is 0.

The documentation on function-type triggers explains exactly when 
those
triggers will return SFalse.

SC values were originally called short-circuit values, because 
evaluation on an SC value "short-circuits" and does not act as normal. 
However, this nomenclature had the potential to cause confusion with 
short-circuit logical evaluation, so it had to be changed, though not 
so drastically as to cause further confusion. Hence short-circuit 
values became SC values. At the moment, SC officially stands for "skip 
and carry", because when an SC value is encountered, normal 
calculation is skipped and the SC value is simply carried on. Other 
possibilities for SC include "semantic codomain" and "so-called". We 
welcome better suggestions for what SC should stand for.


====================================================================
VIII. More on function-type triggers
====================================================================

Most function-type triggers either take no arguments or take arguments
in a parameter list. For instance, the time trigger takes no 
arguments,
whereas the ifelse trigger takes three arguments

ifelse(exp1,exp2,exp3)

where exp1, exp2, and exp3 are all valid expressions. In this kind of
situation, exp1, exp2, and exp3 are all considered separate 
subexpressions, so intervals can appear on the rightmost end of each 
of those subexpressions. The order of evaluation of parameter lists is 
from left to right.

Due to irregular syntax, some old function-type triggers cannot take
expressions as their arguments. Because of this, they cannot be
integrated into expressions in the standard manner. For nonstandard
triggers of this type, the triggers can only appear with certain sets 
of operators and arguments (which are outlined in trigger.doc). In
particular, these triggers cannot take expressions as their arguments. 
For instance,

trigger1 = AnimElem = (1+1)

is an invalid expression.

Old-style function-type triggers appear only in "clauses" (trigger, 
relational operator, argument). These clauses are treated as a single 
unit (specifically, a single nullary trigger) for the purposes of 
expression evaluation. This means, among other things, that the 
concept of operator precedence is not applicable to operators 
appearing within an old-style function-type trigger clause. For 
instance, in

trigger1 = AnimElem = 5 + 4

the expression is broken down into three units:
{AnimElem=5} {+} {4}
The "AnimElem=5" unit is treated as the name of a nullary trigger, 
hence the + operator does not have precedence over the = appearing 
within the name "AnimElem=5". In other words, this expression means 
something like "Execute the trigger called `AnimElem=5', then add 4 to 
the result."

The list of old-style function-type triggers, and expression-capable 
replacements if applicable, is as follows:

AnimElem, superseded by AnimElemTime
P1Name, P2Name, P3Name, P4Name
StateType, P2StateType
Command
MoveType, P2MoveType
TimeMod, superseded by the % operator
ProjHit, ProjContact, ProjGuarded; superseded by ProjHitTime, 
  ProjContactTime, and ProjGuardedTime



====================================================================
IX. Expressions in state and state controller parameters
====================================================================

For the most part, any parameter to the statedef or a state controller
can be an expression. The exceptions are parameters that are given as
strings. For instance, hit attributes, guardflags, etc. cannot be
specified as expressions. Also, the ForceFeedback controller, as well 
as the ignorehitpause and persistent parameters to all controllers, 
are 
irregular in that they cannot take expressions.

State controller parameters are evaluated at the time the controller 
is
triggered, and are not subsequently re-evaluated unless the controller 
is triggered again. Parameters that are given as comma-separated lists 
are evaluated from left to right. To achieve continual evaluation of 
controller parameters, the controller must be continually triggered. 

In the case of certain controllers such as HitDef, it is not always 
wise to use continual triggering, since this decreases performance and 
also may lead to undesired behavior. In this case, the programmer may 
wish to try to delay triggering the HitDef as long as possible, so as 
to evaluate the HitDef parameters right before they are used.



====================================================================
X. (Advanced) Optimizing for speed
====================================================================

MUGEN evaluates condition-type triggers for a state controller in the 
following order: First it evaluates triggeralls, from top to bottom. 
If any of the triggeralls evaluates to 0, the rest of the triggers are 
skipped and evaluation proceeds to the next controller. If all the 
triggeralls evaluate to nonzero, then the engine starts to evaluate 
trigger1's, from top to bottom. If any of these evaluate to 0, then 
evaluation skips to the first trigger2, and so on. If all the triggers 
in a block (besides triggerall) evaluate to nonzero, then the state 
controller parameters are evaluated and the controller is triggered.

In other words, the logical evaluation of triggers is short-circuited. 
In C-like notation, this setup might be denoted

  triggerall,1 && triggerall,2 && ... && ((trigger1,1 && trigger1,2 
    && ...) || (trigger2,1 && trigger2,2 && ...) || ... )

where (e.g.) trigger1,2 denotes the second trigger1 line, trigger2,1  
denotes the first trigger2 line, etc. The logical evaluation of this 
trigger group would then be short-circuited as in C.

Because of this system, considerable performance gains can be attained 
by organizing expressions so that the condition-type triggers are as 
simple, and as few in number, as possible. The bulk of the "work" can 
be offloaded to the state controller parameters, which are only 
evaluated once at trigger time, instead of every frame that the player 
is in the state. For instance,

[State -1]
type = ChangeState
trigger1 = command = "a"
trigger1 = power < 1000
value = 3000

[State -1]
type = ChangeState
trigger1 = command = "a"
trigger1 = power >= 1000
value = 3001

[State -1]
type = ChangeState
trigger1 = command = "a"
trigger1 = power >= 2000
value = 3002

could be more compactly expressed as 

[State -1]
type = ChangeState
trigger1 = command = "a"
value = 3000 + (power >= 1000) + (power >= 2000)

Further speedups are possible if triggeralls that are most likely to 
be false are placed highest in the triggerall block. Similarly, the 
trigger1 block should be the most likely block to trigger, but within 
the trigger1 block itself, the triggers that are most likely to 
evaluate to 0 should be placed highest. For state controllers with 
many triggers containing duplicated conditions, it may be faster to 
break the controllers up into two separate blocks, each with its own 
set of triggeralls.

If you have a complex condition which is being used as the trigger 
condition for many consecutive state controllers, you may wish to save 
the value of the condition in a variable, then use that variable as a 
trigger to the subsequent controllers. For instance,

trigger1 = (command="abc" && command!="holddown" && power>=1000) ||       
           (command="abc" && command!="holddown" && var(5)) || 
           ((command != "abc" || command = "holddown") && power>=2000)

could be written as (assuming var(0) is available):

trigger1 = (var(0):=(command="abc" && command !="holddown") && power>=
           1000) || (var(0) && var(5)) || (!var(0) && power>=2000)

Finally, since the expression parser performs no optimization on 
expressions, an expression like

trigger1 = ctrl

is slightly faster than

trigger1 = ctrl = 1
