previous page next page reference home emBASIC home page

3.5 Expressions

This chapter explains the meaning of the elements of expressions in emBASIC.

Elements of expressions are one of either literal, variable reference, or another expression, possibly in parenthesis.

A variable reference is the name of a simple variable. Reference to an array element is the name of an array followed by a list of expressions in square brackets.

temperature, matrix[2 * x + 1, y div 2]

3.5.1 Arithmetic conversions

Generally, emBASIC performs automatic type conversion and it is not needed to specify conversion explicitly. Numeric operands are converted to the same type automatically. Shorter types are converted to longer ones, unsigned to signed, integer types to float ones LONG and DWORD are converted directly to DOUBLE. There is no automatic conversion between numbers and strings. In common cases, the numbers are converted to a common type and then the operation is applied.
However, to produce an explicit type conversion you may use a datatype name in parenthesis prefixed to an expression as shown below:

(INT)2.5 // The result will be 2 of datatype integer.
(LONG)(3*(1.5/22) // Converts all operands to long before operation.


3.5.2 Atoms

Atoms are the most basic elements of expressions. The simplest atoms are identifiers or literals. Identifiers enclosed in parentheses, brackets or braces are also categorized syntactically as atoms.

3.5.3 Primaries

Primaries represent the most tightly bound operations of the language. A primary can be either an atom, an attribute reference (e.g. structure or message), an array subscript, or a function call.


3.5.3.1 Attribute references

An attribute reference (for example a reference to a member of a structure) is a primary followed by a period and a name:

myMotorMsg.element
myStructure.val

The primary must evaluate to an object of a type that supports attribute references, e.g., a structure or a message instance. This object is then asked to produce the attribute whose name is the identifier. If this attribute is available, the type and value of the object produced is determined by the object.

3.5.3.2 Subscripts

A subscript selects an item of an array:

array[ expression ]
array[ expression, expression ]

a[3,4] // an array with 4x5 elements

If the primary is an array, the expression must evaluate to an unsigned integer. Generally, the resulting value must be a nonnegative integer less than the number of items in the array, and the subscription selects the item whose index is that value. Arrays count from zero in emBASIC.

3.5.3.3 Range

A range selects a consecutive number of items in an array. Ranges may be used as expressions or as targets in assignment statements. The syntax for a range is:

array[expression .. expression]

a[2..4] = {"M3","M4","M5"}

The semantics for a simple range is as follows. The primary must evaluate to an array object. The lower and upper bound expressions must evaluate to unsigned integers; defaults are zero and 65535, respectively.

The range now selects all items with index k such that i <= k < j where i and j are the specified lower and upper bounds. This may be an empty array. It is not an error if i or j lie outside the range of valid indexes (such items don't exist so they aren't selected).

3.5.3.4 Calls

A call calls a callable object (e.g., a function) with a possibly empty series of arguments. The primary must evaluate to a callable object (user-defined functions, built-in functions or external function). All argument expressions are evaluated before the call is attempted.

printlabel(partno,qty,size)

A call always returns some value. How this value is computed depends on the type of the callable object. If it is

-   a user-defined function:
The code block for the function is executed, passing it the argument list. The first thing the code block will do is bind the formal parameters to the arguments. When the code block executes a return statement, this specifies the return value of the function call.

-   a built-in function:
The result is up to the interpreter; see the Built-in Functions chapter for the descriptions of built-in functions and methods.

-   an external user function:
The result is up to this function. C-programming defines which value this function should return.


3.5.4 Power operator

The power operator (**) binds more tightly than unary operators on its left.. Thus, in an unparenthesized sequence of power and unary operators, the operators are evaluated from right to left (this does not constrain the evaluation order for the operands).
The power operator yields its left argument raised to the power of its right argument. The numeric arguments are first converted to a common type.

3.5.5 Unary arithmetic operators

All unary arithmetic (and bit-wise) operations have the same priority.
The unary - (minus) operator yields the negation of its numeric argument.
The unary + (plus) operator yields its numeric argument unchanged.
The unary ~ (invert) or its BNOT equivalent operator yields the bit-wise inversion of its plain or long integer argument. It only applies to integral numbers. In all cases, if the argument does not have the proper type, a type conversion error is raised.

DECL A AS BYTE
A = ~0x55
PRINT USING “%x”, A

Will produce result 0xAA.

 

3.5.6 Binary arithmetic operators

The binary arithmetic operations have the conventional priority levels. Note that some of these operations also apply to certain non-numeric types.

      / The / (division) operator yields the quotient of its arguments. The numeric arguments are first converted to a common type. Plain or long integer division yields an integer of the same type
  DIV Integer division. Yields a rounded integer result of the division of two arbitrary numbers. In other words A DIV B is equivalent to (INT)(A/B)
  % or MOD Modulo. Valid for all numeric operands. The modulo operator yields the remainder from the division of the first argument by the second. The numeric arguments are first converted to a common type
  * The * (multiplication) operator is valid for all numeric operands. It yields the product of its arguments. The arguments must both be numbers. In common case, the numbers are converted to a common type and then multiplied together.
  + The + (addition) operator yields the sum of its arguments. The arguments must either both be numbers or both strings. In the former case, the numbers are converted to a common type and then added together. In the latter case, the strings are concatenated.
  - The - (subtraction) operator yields the difference of its arguments. The numeric arguments are first converted to a common type.

 

3.5.7 Shift operators

The shift operators have lower priority than the arithmetic operators:

expression >> expression
expression << expression

These operators accept plain or long integers as arguments. The arguments are converted to a common type. They shift the first argument to the left or right by the number of bits given by the second argument.
Negative shift counts behavior is defined by hardware. Below the examples for the TSMCPU32H2:

PRINT 2 >> -1 // produces 0
PRINT 4 >> -1 // produces 0
PRINT 2 << -1 // produces 0
PRINT 4 << -1 // produces 0
PRINT 1 << -1 // produces -32768

 

3.5.8 Binary bit-wise operators

Each of the three bitwise operators has a different priority level.

The & (or BAND) operator yields the bitwise AND of its arguments, which must be plain or long integers. The arguments are converted to a common type. This operator has a higher priority then bitwise OR operator, but has the same priority as bitwise XOR operator.

The ^ (or BXOR) operator yields the bitwise XOR (exclusive OR) of its arguments, which must be plain or long integers. The arguments are converted to a common type. This operator has a higher priority then bitwise OR operator, but has the same priority as bitwise AND operator.

The | (or BOR) operator yields the bitwise (inclusive) OR of its arguments, which must be plain or long integers. The arguments are converted to a common type. This operator has a lower priority then AND and XOR operators.

 

3.5.9 Comparisons

All comparison operators in emBASIC have a left association and a priority lower than that of any arithmetic, shifting or bitwise operation.

"<" ">" "==" ">=" "<=" "<>"

The forms <> and != are equivalent; for consistency with C, != is preferred; where != is mentioned below <> is also accepted. The <> spelling is considered deprecated.

The operators <, >, ==, >=, <=, and != compare the values of two objects. The objects need not have the same type. If both are numbers, they are converted to a common type.

Comparison of objects of the same type depends on the type:
Numbers are compared arithmetically, strings are compared lexicographically using the numeric equivalents.

3.5.10 Boolean operations

Boolean operations have the lowest priority of all emBASIC operations:
In the context of Boolean operations, and also when expressions are used by control flow statements, the following values are interpreted as false: numeric zero of all types and strings. All other values are interpreted as true.

The operator ! (or NOT) yields 1 if its argument is false, 0 otherwise.

The expression x && y (or x AND y) first evaluates x; if x is false, its value is returned; otherwise, y is evaluated and the resulting value is returned.

The expression x || y (or x OR y) first evaluates x; if x is true, its value is returned; otherwise, y is evaluated and the resulting value is returned.

3.5.11 Expression lists

An expression containing at least one comma yields a list. The length of the list is the number of expressions in the list. The expressions are evaluated from left to right:

expression_list ::= [“{“] expression “,” expression * [“}”]

Expression lists are used to assign values to lists of variables and multiple array elements to arrays or ranges within an array. Examples:

var1, var2, name = 10, 300, “Alex”
arr[3..6] = {20, 22.5, 25, 27.5}

 

4 Simple statements

Simple statements are comprised within a single logical line. Several simple statements may occur on a single line separated by semicolons.

FOR i = 1 TO 4; a[i] = i*2; NEXT i

 

4.1 Expression statements

Expression statements are used to compute and write a value, or to call a procedure (a function that returns no meaningful result; in emBASIC, procedures return the value void

4.2 Assignment statements

Assignment statements are used to (re)bind names to values and to modify attributes or values of system variables.

An assignment statement evaluates the expression list (remember that this can be a single expression or a comma-separated list, the latter yielding a value list) and assigns the single resulting object to each of the target lists, from left to right.

Assignment is defined recursively depending on the form of the target (list). When a target is part of a mutable object (an attribute reference, array subscription or slicing), the mutable object must ultimately perform the assignment and decide about its validity, and may raise a parse error if the assignment is unacceptable.

Assignment of inexistent enumeration values to the target raises a runtime error.

Assignment of an object to a target list is recursively defined as follows.

  ·  If the target list is a single target The object is assigned to that target
  ·  If the target list is a comma-separated list of targets The object must be an array with the same number of items as there are targets in the target list, and the items are assigned, from left to right, to the corresponding targets

Assignment of an object to a single target is recursively defined as follows:

  ·  If the target is an identifier (name) If the name does not occur in a DECL PUBLIC statement in the current task: the name is bound to the object in the local namespace or the current task. Otherwise: the name is bound to the object in the global namespace.
The name is rebound if it was already bound.
  ·  If the target is an attribute reference The primary expression in the reference is evaluated. It should yield an object with assignable attributes; if this is not the case, error is raised. That object is then asked to assign the assigned object to the given attribute; if it cannot perform the assignment, it raises an error.
  ·  If the target is a subscript

The primary expression in the reference is evaluated. It should yield an array object. Next, the subscript expression is evaluated:

If the primary is an array object, the subscript must yield an unsigned integer. The resulting value must be a nonnegative integer less than the array's length, and the array is asked to assign the assigned object to its item with that index. If the index is out of range, runtime error will be is raised, there are no boundary checks performed in interactive mode (assignment to a subscripted array cannot add new items to it).

  ·  If the target is a range The primary expression in the reference is evaluated. It should yield an array object. The assigned object should be an array of the same type. Next, the lower and upper bound expressions are evaluated, insofar they are present; defaults are zero and the array's length. The bounds should evaluate to unsigned integers. The resulting bounds are clipped to lie between zero and the sequence's length, inclusive. Finally, the sequence object is asked to replace the range with the items of the assigned array. The length of the range may be different from the length of the assigned array, but changing the length of the target array is not allowed and raises an error.

Examples:

a = 10
b = “string”
a,b = 10, “string”
a[1],b = 12, “string
a[1..3] = {12,13,14}

 

4.3 Combined assignment statements

Combined assignment is the combination, in a single statement, of a binary operation and an assignment statement. Combined operators are:

"+=" "-=" "*=" "/=" "%=" "**=" "&=" "^=" "|="

A combined assignment evaluates the target and the expression list, performs the binary operation specific to the type of assignment on the two operands, and assigns the result to the original target. The target is only evaluated once.