expressions
no way to compare when less than two revisions
Differences
This shows you the differences between two versions of the page.
— | expressions [2009/06/02 15:52] (current) – created - external edit 127.0.0.1 | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ======Expression Syntax in EPIC====== | ||
+ | |||
+ | =====About " | ||
+ | EPIC has two " | ||
+ | mode that every command starts out in. | ||
+ | |||
+ | ^ Text mode | ||
+ | | Everything is plain text | ||
+ | | First word is command, rest is arg list | Can escape to text mode with []s| | ||
+ | | $'s start " | ||
+ | |||
+ | " | ||
+ | (Technically, | ||
+ | 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 {< | ||
+ | FOR (< | ||
+ | REPEAT (...) | ||
+ | |||
+ | When you are in an expression, you can escape to 'text mode' by using | ||
+ | the square brackets operator ([...]), the single quotes operator | ||
+ | (' | ||
+ | |||
+ | When you are in an expression, and you call a function, like so: | ||
+ | @foo = function(...) | ||
+ | the function parameters are always in 'text mode'. | ||
+ | |||
+ | =====Operators and operands===== | ||
+ | When EPIC evaluates an expression, it breaks the entire expression into | ||
+ | " | ||
+ | you want to do (+, -, *, /, &&, ||, etc). Operands are the " | ||
+ | to the operators. | ||
+ | some operators are binary (take two operands), and one operator is | ||
+ | tertiary (takes three operands) | ||
+ | |||
+ | The process of evaluating an expression is performing each of the operations | ||
+ | one at a time until there is only one operand and no operators left. The | ||
+ | operators have a // | ||
+ | go before any operator with precedence 2, and so on. If there is more than | ||
+ | one operator with the same precedence, you have to know whether to do the | ||
+ | right one or the left one first. | ||
+ | when there is more than one of the same operator in an expression, the left | ||
+ | one is done first, and R->L means the right one is done first. | ||
+ | |||
+ | Each operator " | ||
+ | operands and replacing it with a new operand. | ||
+ | the operators in an expression, you should have only one operand left, and | ||
+ | that is the //result// of the expression. | ||
+ | |||
+ | =====Example: | ||
+ | Let's solve the expression: | ||
+ | 3 - 4 * 5 - 7 | ||
+ | Since * has precedence of 4 and + has precedence of 5 (see the table below), | ||
+ | the * goes first. | ||
+ | 3 - 20 - 7 | ||
+ | Since there are two -'s, then we look at the associativity, | ||
+ | which means the left - is done first, which reduces to | ||
+ | < | ||
+ | -17 - 7 | ||
+ | </ | ||
+ | and performing the last operation yields | ||
+ | < | ||
+ | -24 | ||
+ | </ | ||
+ | as the result of the expression. | ||
+ | |||
+ | =====List of operators and associativity===== | ||
+ | |||
+ | ^PRECEDENCE ^OPERATOR | ||
+ | | 1 | Sub-expression | ||
+ | | 2 | Logical NOT | ! **bool** | ||
+ | | 2 | Bitwise NOT | ~ **int** | ||
+ | | 2 | Prefix Decrement | ||
+ | | 2 | Prefix Increment | ||
+ | | 2 | Suffix Decrement | ||
+ | | 2 | Suffix Increment | ||
+ | | 2 | Unary Plus | + **float** | ||
+ | | 2 | Unary Minus | ||
+ | | 2 | String length | ||
+ | | 2 | Word Count | ||
+ | | 2 | Variable Dereference | ||
+ | | 2 | Variable Dereference | ||
+ | | 2 | Double Expansion | ||
+ | | 3 | Exponent | ||
+ | | 4 | Multiplication | ||
+ | | 4 | Division | ||
+ | | 4 | Modulus | ||
+ | | 5 | Addition | ||
+ | | 5 | Subtraction | ||
+ | | 5 | String Catenation | ||
+ | | 6 | Bitwise shift left | **int** | ||
+ | | 6 | Bitwise shift right | **int** | ||
+ | | 7 | Less Than | **op** | ||
+ | | 7 | Less than or equal to | **op** | ||
+ | | 7 | Greater than | **op** | ||
+ | | 7 | Greater than or equal to | **op** | ||
+ | | 8 | Pattern match | **op** =~ **op** | ||
+ | | 8 | Pattern doesn' | ||
+ | | 9 | Equal, ignore case | **op** | ||
+ | | 9 | Not equal, ignore case | **op** | ||
+ | | 9 | Equal | **op** | ||
+ | | 9 | Not equal | **op** | ||
+ | |10 | Bitwise AND | **int** & **int** | ||
+ | |11 | Exclusive OR | **int** | ||
+ | |12 | Bitwise OR | **int** | ||
+ | |13 | Logical AND | **bool** | ||
+ | |14 | Logical XOR | **bool** | ||
+ | |15 | Logical OR | **bool** | ||
+ | |16 | If-then-else | ||
+ | |17 | Assignment | ||
+ | |17 | Addition-assign | ||
+ | |17 | Subtraction-assign | ||
+ | |17 | Multiplication-assign | ||
+ | |17 | Division-assign | ||
+ | |17 | Modulus-assign | ||
+ | |17 | Bitwise AND-assign | ||
+ | |17 | Exclusive OR-assign | ||
+ | |17 | Bitwise OR-assign | ||
+ | |17 | Bitshift left-assign | ||
+ | |17 | Bitshift right-assign | ||
+ | |17 | Logical AND-assig | ||
+ | |17 | Logical OR-assign | ||
+ | |17 | Logical XOR-assign | ||
+ | |17 | Exponent-assign | ||
+ | |17 | strcat-assign | ||
+ | |17 | String prefix-assign | ||
+ | |17 | Swap values | ||
+ | |17 | Last Value | **op** | ||
+ | |||
+ | [1] The operand must be an [[lval]]\\ | ||
+ | [3] Short circuit operator.\\ | ||
+ | [4] You do not have to give an explicit operand. | ||
+ | |||
+ | =====How operands are handled===== | ||
+ | There are four different kinds of operands | ||
+ | |||
+ | =====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 " | ||
+ | @ foo #= [blah] | ||
+ | @ foo #~ [hmm] /* sets $foo to " | ||
+ | |||
+ | 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. | ||
+ | |||
+ | 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 " | ||
+ | |||
+ | @ foo = bar =~ [*pi*] | ||
+ | @ 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' | ||
+ | library (libm) does. Assuming $foo is 9: | ||
+ | |||
+ | foo ** 2 /* returns 81 */ | ||
+ | foo ** 0.5 /* returns 3 */ | ||
+ | |||
+ | The {pre, | ||
+ | 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. | ||
+ | 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. | ||
+ | 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. | ||
+ | |||
+ | @ foo = 4 | ||
+ | @ bar = 8 | ||
+ | @ foobar = foo+++bar | ||
+ | |||
+ | How should one interpret the last assignment? | ||
+ | ${foo++ + bar} or ${foo + ++bar}? | ||
+ | to not write code that looks so silly and unreadable. | ||
+ | and there is no ambiguity. | ||
+ | |||
+ | Another popular operator familiar to most C/C++ programmers is the tertiary | ||
+ | operator (sometimes referred to as the alternation operator). | ||
+ | a function similar to IF, except is much more compact and efficient. | ||
+ | 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. | ||
+ | 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 ' | ||
+ | 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 -> " | ||
+ | |||
+ | 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. | ||
expressions.txt · Last modified: 2009/06/02 15:52 by 127.0.0.1