Phantasmal MUD Lib for DGD

Phantasmal Site > DGD > DGD Reference Manual > LPC > Expressions

Expressions

An expression is an instruction or set of instructions that results in a value. A variable is an expression since it yields its contents as a result. a + b is a valid expression, because a and b are variables (expressions) and + is an operator that takes two expressions to make another expression. a = b + c; is a full statement ending in a ;. Because the = operator returns a value, a = b + c is an expression, but when you add a ;, it becomes a statement. It's like when you add a period to the end of a bunch of words and suddenly you have a sentence.

Function calls are valid expressions. They are written simply as the name followed by a set of parentheses with the arguments that the functions uses listed inside. Take the simple function max() for example, that returns the maximum of the two floating-point arguments. To determine the maximum of 4.0 and 10.0, you would write max(4.0, 10.0) as the expression. The result of the function call must be stored or used in an expression, or it is lost. That's fine if you're calling the function because of some other effect it has, such as write_file().

Operator expressions

The LPC language defines a large set of operator expressions. These are simply expressions that operate on other expressions. What follows here is a list of them. This section uses condensed notation to save space and reduce complexity.

E
Any expression, including compound expressions.
V
A variable.

Miscellaneous operators

(E)
The expression inside the parentheses is evaluated before anything outside the parenthesis. This is useful for isolating expressions that need to be done in a specific order. It's also useful when you are uncertain about operator precedence, or when you want to make it obvious to readers of your code what the precedence is.
E1, E2
The first expression is evaluated first and the result stored, then E2 is evaluated and the result is thrown away. Finally, the stored result of E1 is returned as the value of the entire expression. The statement a = 1, 2, 3; will set 'a' to contain '1'.
V = E
The variable is given the value of the expression. The resulting value of this entire expression is also the value of E. For instance, a = b = 4; will set a and b to be 4. It can also be written a = (b = 4) to illustrate the order of execution.

Arithmetic operators

E1 + E2

The expressions are evaluated and the results added to each other. You can add integers, floats, strings, arrays and mappings. Strings, arrays and mappings are simply concatenated - pasted together to the end of the first argument.

It's also possible to add integers to strings, they will then be converted to strings and pasted to the end of the string.

E1 - E2

E2 is subtracted from E1. You can subtract integers, floats and any type from arrays of the same type. For arrays the item, if it exists in the array it is subtracted from, is removed from the array. If it doesn't exist in the array, the array is returned intact.

E1 * E2
E1 is multiplied by E2. This only works on integers and floats.
E1 / E2
E1 is divided by E2. This only works on integers and floats.
E1 % E2
The remainder (also called the modulus) of the expression 'E1 / E2' is returned. This only works with integers. For instance, 14 % 3 will yield 2 as the remainder.
-E
Return E, negated arithmetically. This only works on integers and floats. For either one, the value returned is equal to zero minus E, or negative E.
E++, ++E

The expression E is incremented by one. If the operator is in front of the expression (called "prefix") then the incremented value is returned, otherwise the previous value is. For instance, if the variable ctr is equal to 3 then ++ctr would return 4 and ctr++ would return 3. This only works on integers.

The value of ++a is also an lvalue, which means it can be assigned to. If you don't immediately know what that means, don't do that.

'a = 3; b = ++a;' will yield the result 'a = 4, b = 4', while
'a = 3; b = a++;' will yield the result 'a = 4, b = 3'.
E--, --E
The expression 'E' is decremented by one. If the operator is in front of the expression, the decrement is done before the value is returned, otherwise afterwards. This only works on integers.
'a = 3; b = --a;' will yield the result 'a = 2, b = 2', while
'a = 3; b = a--;' will yield the result 'a = 2, b = 3'.

Boolean operators

Boolean operators are applicable only to integers with the exception of the & and | operators, which also work on arrays. Internally an integer is 32 bits long. However, in the following examples I will only show the ten last bits as the others are 0 and can be ignored with the one exception of the ~-operator.

E1 & E2
E1 and E2. Every bit which is set in both E1 and E2 will also be set in the result. Any bit which is zero in either one will be zero in the result.
1011101001   (= 745)
1000100010 & (= 546)
------------
1000100000   (= 544) => 745 & 546 = 544
Used on two arrays, this function will return a new array that holds all elements that are members of both of the argument arrays. Thus, it performs a kind of set-intersection on the arrays.
E1 | E2
E1 or E2. Every bit which is set in either E1 or E2 will be set in the result. Any bit which is zero in both E1 and E2 will be zero in the result.
1011101001   (= 745)
1000100010 | (= 546)
------------
1011101011   (= 747) => 745 | 546 = 747
Used on two arrays, this function will return an array containing any element which is in either one of the original two arrays. If E1 and E2 share no members in common, this is the same as E1 + E2.
E1 ^ E2
E1 xor (exclusive or) E2. A bit which is zero in both or one in both is zero in the result. A bit which is set in either E1 or E2, but not both, is one in the result.
1011101001   (= 745)
1000100010 ^ (= 546)
------------
0011001011   (= 203) => 745 ^ 546 = 203
~E
1-complement of E (invert E). This is a unary operator, meaning it takes only one argument. A bit which is one in the argument will be zero in the result and vice-versa.
00000000000000000000001011101001 ~ (= 745)
----------------------------------
11111111111111111111110100010110   (= -746) => ~745 = -746
The above example might be hard to understand unless you really know your binary arithmetic. However, trust me when I say that this is not a typo, it's the way it should look. ~745 is different from -745 -- one is a one's complement and the other is a two's complement. Read about twos-complement binary arithmetic and all will be made clear.
E1 << E2
E1 is shifted left E2 steps. This multiplies the value of E1 by two to the power of E2. For instance, if E2 was three, E1 << E2 would be E1 * 8.
5 << 4 => 101(b) << 4 = 1010000(b) = 80
        
E1 >> E2
E1 is shifted right E2 steps. This divides the value of E1 by two to the power of E2, rounded down. For instance, if E2 was five, E1 >> E2 would be equal to E1 / 32.
1054 >> 5 => 10000011110(b) >> 5 = 100000(b) = 32
        

Conditional (logical) operators

E1 || E2
Returns true if E1 or E2 evaluates as true. Will not evaluate E2 if E1 is true. The fact that it won't evaluate the second argument if the first is true is called "short circuit evaluation".
E1 && E2
Returns true if both E1 and E2 evaluates as true. Will not evaluate E2 if E1 is false. The fact that it won't evaluate the second argument if the first is false is called "short circuit evaluation".
!E
Returns true if E is false and vice versa.

Comparative operators

E1 == E2
Returns true if E1 is equal to E2. This operator can be used on all types, but see the special section later on arrays and mappings. Equality works differently on them than you might think.
E1 != E2
Returns true if E1 isn't equal to E2. This operator can be used on all kinds of types, but see the special section later on arrays and mappings. It works differently on them than you might think.
E1 > E2
Returns true if E1 is greater than E2. This operator can be used on all types except arrays and mappings.
E1 < E2
Returns true if E1 is less than E2. Can be used on all types except arrays and mappings.
E1 >= E2
Returns true if E1 is greater or equal to E2. This operator can be used on all types except arrays and mappings.
E1 <= E2
Returns true if E1 is less or equal to E2. This operator can be used on all types except arrays and mappings.

Prefix allocation

All of the arithmetic and boolean operator expressions can be written in a shorter way if what you want to do is use an operator on a variable and a value (or two variables) and then store the result in the variable.

Say that what you want to do is this a = a + 5;. A much neater way of writing that is a += 5;. This does exactly the same thing with less keystrokes and less chance of error in typing. Many people also find it more readable.

You write all the others in the same way. So the result variable comes first, then the operator directly followed by = and then the value to operate on. Make sure not to put a space between the operator and the equals sign, and make sure to put the operator before the equals sign.

a >>= 5;       /* a = a >> 5; */
b %= d + 4;    /* b = b % (d + 4); */
c ^= 44 & q;   /* c = c ^ (44 & q); */

c =+ 7;      /* c = (+7), probably not what you wanted. */
c + = 7;     /* Error!  Don't use the extra space. */

Precedence and Order of evaluation

The table below summarizes the rules for precedence and associativity of all operators, including those which we have not yet discussed. Operators on the same line have the same precedence, rows are in order of decreasing precedence, so, for example, *, / and % all have the same precedence, which is higher than that of + and -.

Note that the precedence of the bitwise logical operators &, ^ and | falls below == and !=. This implies that bit-testing expressions like the one below must be fully parenthesized to give proper results.

if ((x & MASK) == 0) ...
    
() []
Left to right
! ~ ++ -- - (type) * &
Right to left
* / %
Left to right
+ -
Left to right
<< >>
Left to right
< <= > >=
Left to right
== !=
Left to right
&
Left to right
^
Left to right
|
Left to right
&&
Left to right
||
Left to right
?:
Right to left
= += == etc.
Right to left
,
Left to right

Note that in the list, (type) denotes a typecast. Note also that in every case, a unary operator is higher precedence than its binary equivalent. So the expression -7 - 5 is equal to (-7) - 5 instead of -(7-5).