Your IP : 216.73.216.48


Current Path : /usr/X11R6/share/epic5/help/7_Docs/
Upload File :
Current File : //usr/X11R6/share/epic5/help/7_Docs/Expressions

Expression Syntax in EPIC                                                   

About "expression mode" and "text mode"
---------------------------------------
EPIC has two "modes" it executes your code in.  "Text mode" is the standard
mode that every command starts out in.

Text mode				    Expression mode
----------				    ----------------
* Everything is plain text		    * Everything is operator or operand
* First word is command, rest is arg list   * Can escape to text mode with []s
* $'s start "expandos" (macro substitution) * $'s are not permitted before vars

"Expression mode" occurs in all of the following text-mode commands:
(Technically, @ and parenthesis are not really commands, they just 
look like it)

	@ ...			(return value is ignored -- see below)
	(...)			(return value is ignored -- see below)
	${...}			(may be used anywhere in text mode)
	IF (...)
	UNLESS (...)
	WHILE (...) 
	UNTIL (...) 
	DO {<commands>} WHILE (...)
	FOR (<command>, ... ,<command>)
	REPEAT (...)

When you are in an expression, you can escape to 'text mode' by using
the square brackets operator ('[' and ']')


OPERATORS AND OPERANDS
----------------------
When EPIC evaluates an expression, it breaks the entire expression into 
"operators" and "operands".  Operators are the mathematical actions that
you want to do (+, -, *, /, &&, ||, etc).  Operands are the "arguments" 
to the operators.  Some operators are unary (take only one operand) and
some operators are binary (take two operands), and one operator is 
tertiary (takes three operands)

The process of evaluating an expression is figuring out which operator you
want to execute ("reduce" is the fancy term) first.  That operator takes
one or two operands, performs some mathematical action, and "reduces" to 
a new operand.  For example, 3 + 4 reduces to 7.  Operators are reduced,
one at a time, until there is one operand and no operators left.  This last
remaining operand is the "return value" of the expression.


LIST OF OPERATORS AND ASSOCIATIVITY
-----------------------------------
Without trying to be confusing, EPIC has two expression parsers.  The
default one is the historical (legacy) ircII expression parser, which has
some problems.  There is a new experimental parser that tries to fix all
of the problems.  You can turn the new experimental parser on by using the
command /XDEBUG NEW_MATH.

This list of operators documents the behavior of the new experimental
math parser.  Differences between the new math parser and the legacy parser
are noted by foot notes which are explained at the bottom of this list.

It is critically important to understand that in the legacy parser, all 
operators have right-to-left associativity.  Only the experimental parser
has the ability to do left-to-right associativity.

OPERATOR                USAGE                 REDUCES TO      ASSOC 	NOTES
-----------           ------------           ------------    -------   -------
Sub-expression          ( <op> )       	        <op>          L->R

Logical NOT		! <bool>                <bool>        R->L
Bitwise NOT		~ <int>                 <int>         R->L
Prefix Decrement	-- <lval>      	        <int>         R->L
Prefix Increment	++ <lval>      	        <int>         R->L
Unary Plus		+ <float>      	        <float>       R->L
Unary Minus		- <float>               <float>       R->L
String length		@ [<op>]                <int>         R->L	[1] [4]
Word Count		# [<op>]                <int>         R->L	[1] [4]
Variable Dereference	* [<op>]                <op>          R->L	[2] [4]

Exponent		<float> ** <float>      <float>       R->L

Multiplication		<float> * <float>    	<float>       L->R
Division		<float> / <float>    	<float>       L->R
Modulus			<float> % <int>    	<float>       L->R

Addition                <float> + <float>    	<float>       L->R
Subtraction             <float> - <float>    	<float>       L->R
String Catenation       <op> ## <op>   	        <op>          L->R

Bitwise shift left      <int> << <int>          <int>         L->R
Bitwise shift right     <int> >> <int>          <int>         L->R

Less Than                <op> < <op>            <int>         L->R
Less than or equal to    <op> <= <op>           <int>         L->R
Greater than             <op> > <op>            <int>         L->R
Greater than or equal to <op> >= <op>           <int>         L->R

Pattern match            <op> =~ <op>           <bool>        L->R
Pattern doesn't match    <op> !~ <op>           <bool>        L->R

Equal to                 <op> == <op>           <bool>        L->R
Not equal to             <op> != <op>           <bool>        L->R

Bitwise AND              <int> & <int>          <int>         L->R

Exclusive OR             <int> ^ <int>          <int>         L->R

Bitwise OR               <int> | <int>          <int>         L->R

Logical AND              <bool> && <bool>       <bool>        L->R	[3]

Logical XOR              <bool> ^^ <bool>       <bool>        L->R

Logical OR               <bool> || <bool>       <bool>        L->R	[3]

If-then-else             <bool> ? <op> : <op>  	<op>          R->L

Assignment		 <lval> = <op>	         <op>         R->L
Addition-assign          <lval> += <float>       <float>      R->L
Subtraction-assign       <lval> -= <float>       <float>      R->L
Multiplication-assign    <lval> *= <float>       <float>      R->L
Division-assign          <lval> /= <float>       <float>      R->L
Modulus-assign           <lval> %= <float>       <float>      R->L
Bitwise AND-assign       <lval> &= <int>         <int>        R->L
Exclusive OR-assign      <lval> ^= <int>         <int>        R->L
Bitwise OR-assign        <lval> |= <int>         <int>        R->L
Bitshift left-assign     <lval> <<= <int>        <int>        R->L	[2]
Bitshift right-assign    <lval> >>= <int>        <int>        R->L	[2]
Logical AND-assig        <lval> &&= <bool>       <bool>       R->L	[2]
Logical OR-assign        <lval> ||= <bool>       <bool>       R->L	[2]
Logical XOR-assign       <lval> ^^= <bool>       <bool>       R->L	[2]
Exponent-assign          <lval> **= <float>      <float>      R->L	[2]
strcat-assign            <lval> #= <op>          <op>         R->L
String prefix-assign     <lval> #~ <op>          <op>         R->L
Swap values		 <lval> <=> <lval>       <lval>       R->L	[2]

last                     <op> , <op>	         <op>         L->R

Suffix Decrement         <lval> --	         <int>        R->L
Suffix Increment         <lval> ++	         <int>        R->L

[1] The operand must be an <lval>
[2] Operator not available in legacy parser
[3] Short circuit operator.
[4] You do not have to give an explicit operand.  If you omit the operand,
    then [$*] is used as the operand.

HOW OPERANDS ARE HANDLED
------------------------

ESCAPES TO TEXT MODE
--------------------
[...]
{...}


EPIC-ONLY OPERATORS
-------------------


OPERATORS THAT BEHAVE DIFFERENT IN EPIC
---------------------------------------


HOW ERRORS IN EXPRESSIONS ARE HANDLED
-------------------------------------


===============================================================================
The string concatenation operators, ##, #=, and #~, are a special case, as they
are not present in C or C++.  As their name indicates, they are used to join
two or more strings together, end to end.  For example:

   @ foo  = [foo] ## [bar]              /* sets $foo to "foobar" */
   @ foo #= [blah]                      /* sets $foo to "foobarblah" */
   @ foo #~ [hmm]                       /* sets $foo to "hmmfoobarblah" */

Also like C/C++, parentheses may be used to force certain parts of the
expression to be evaluated first (mainly in the event that the user wishes
for it to evaluate in an order other than that of operator precedence).
Parentheses may be nested.  For example, if some variable $foo is set to 3:

   foo * 4 + 5                          /* returns 17 */
   foo * (4 + 5)                        /* returns 27 */
   4 + ((foo + 9) / 3)                  /* returns 8 */

All assignment operators always return the value assigned, which allows for
the assignment of multiple variables at once.  Keep in mind that expressions
are evaluated right to left.  For example, if $foo is 12 and $bar is 11:

   @ foo += bar *= 2                    /* $bar is 22, $foo is 34 */

Since the release of the EPIC4 pre-betas, the client has been growing ever
more perlish. Like perl, the =~ and !~ operators match with wildcards. =~ is
a direct opposite of !~, where it returns true if the patterns patch, while
!~ returns false. In this example, $bar is "epic":
   
   @ foo = bar =~ [*pi*]               /* returns 1 */
   @ foo = bar !~ [*z*]                /* returns 1 */

The various bitwise operators are of special interest also. Assuming $foo is 12
and $bar is 11:

   foo & bar                            /* returns 8 */
   foo | bar                            /* returns 15 */
   foo ^ bar                            /* returns 7 */

The exponential operator takes numbers to various powers. It is especially
useful, since many script writers create a $power() function for this purpose.
It supports negative and fractional exponents as long as the system's math
library (libm) does. Assuming $foo is 9:

   foo ** 2                             /* returns 81 */
   foo ** 0.5                           /* returns 3 */

The {pre,post}fix {in,de}crement operators are big timesavers that C and C++
users everywhere swear by.  They have also been known to swear at them, for
reasons you will soon see.  Assume $foo is 5, each column shows 3 ways of
doing the same thing, from least efficient to most efficient:

   @ foo  = foo + 1                     @ foo  = foo - 1
   @ foo += 1                           @ foo -= 1
   @ foo++                              @ foo--

However, these operators have pitfalls, which are mainly discovered by those
who do not understand how they work.  Both may either prefix or postfix a
variable; prefix causes it to evaluate before the operation, postfix causes
it to evaluate aster.  For the examples shown above, it makes no difference.
However, it does make a difference in this example:

   while ( foo++ < 10 ) { ... }

The expression is evaluated for whether $foo is less than 10, and then $foo
is incremented.  If the autoincrement operator was instead used in prefix
form, $foo would be incremented before the expression was evaluated, which
would cause the loop to have one less iteration.

Another pitfall of the autoincrement and decrement operators is the
ambiguity introduced by insufficient whitespace when used in conjunction
with addition and subtraction operators.  Consider the following:

   @ foo    = 4
   @ bar    = 8
   @ foobar = foo+++bar

How should one interpret the last assignment?  Should it really look like
${foo++ + bar} or ${foo + ++bar}?  It's hard to tell.  The best solution is
to not write code that looks so silly and unreadable.  Add a couple spaces,
and there is no ambiguity.  (The answer is, the first one.)

Another popular operator familiar to most C/C++ programmers is the tertiary
operator (sometimes referred to as the alternation operator).  It performs
a function similar to IF, except is much more compact and efficient.  We'll
let $foo be 5 again:

   @ bar = foo > 3 ? 1 : 0              /* sets $bar to 1 */
   @ bar = foo > 8 ? 1 : 0              /* sets $bar to 0 */

Functions (built-in and scripted) can also be used within expressions.  The
function will be evaluated, and its return value is used in the expression:

   @ foo = pattern(b* foo bar blah)     /* sets $foo to "bar blah" */

All functions implicitly use a special operator, ().  That is, the pair of
parentheses themselves compose an operator, though of course it is somewhat
different in nature from more traditional operators like '+' or '<' or '&'.
Functions (aliases with return values) require the () to function properly.

A similar operator is [], which is used for alias and variable structures.
We've already seen that it can be used to explicitly switch the evaluation
context to text.  This can be extended to structure elements, such that
they can be expanded on the fly:

   @ foo.1.1 = [foo]
   @ foo.1.2 = [bar]
   alias blah echo $foo[1][$0]
   /blah 2                              /* expands to $foo.1.2 -> "bar" */

The same can be applied to aliases and functions as well.  Because of the
nature of the [] operator, anything may be expanded inside it, variables and
functions alike.

See Also:
   Patterns(7); Programming(7); Special_Vars(7)