Expressions¶
This public entry covers operator precedence, expression forms, reference operators, and debugger/watch expression constraints.
Use the full spec below when you need precise precedence, type-check rules, or documented expression-level extensions.
Related: Statements, Semantic Rules
Expressions¶
IEC 61131-3 Edition 3.0 (2013) - Section 7.3.2
This specification defines expression syntax and operator precedence for trust-syntax parser and trust-hir type checking.
1. Expression Overview¶
An expression is a construct which, when evaluated, yields a value corresponding to one of the data types.
Expression Components¶
Expressions are composed of: 1. Operands: Literals, enumerated values, variables, function calls, method calls 2. Operators: Arithmetic, logical, comparison, etc. 3. Parentheses: For grouping and precedence control
Maximum Length¶
The maximum allowed length of expressions is Implementer specific.
2. Operators (Table 71, Section 7.3.2)¶
Complete Operator Table with Precedence¶
| Precedence | Operation | Symbol | Example | Associativity |
|---|---|---|---|---|
| 11 (highest) | Parentheses | (expr) |
(A+B)/C |
N/A |
| 10 | Function/Method call | name(args) |
SIN(X), obj.method(Y) |
Left-to-right |
| 9 | Dereference (§4.4) | ^ |
ptr^ |
Left-to-right |
| 8 | Unary operators (§4.1, §4.3) | -, +, NOT |
-A, +B, NOT C |
Right-to-left |
| 7 | Exponentiation (§4.1) | ** |
A**B |
Left-to-right |
| 6 | Multiplicative (§4.1) | *, /, MOD |
A*B, A/B, A MOD B |
Left-to-right |
| 5 | Additive (§4.1) | +, - |
A+B, A-B |
Left-to-right |
| 4 | Comparison (§4.2) | <, >, <=, >=, =, <> |
A<B, A=B |
Left-to-right |
| 3 | Boolean AND (§4.3) | &, AND |
A&B, A AND B |
Left-to-right |
| 2 | Boolean XOR (§4.3) | XOR |
A XOR B |
Left-to-right |
| 1 (lowest) | Boolean OR (§4.3) | OR |
A OR B |
Left-to-right |
3. Evaluation Rules¶
Rule 1: Precedence¶
Operators with higher precedence are applied first.
A + B - C * ABS(D)
// Evaluated as: A + B - (C * ABS(D))
// With A=1, B=2, C=3, D=4: 1 + 2 - 12 = -9
(A + B - C) * ABS(D)
// Evaluated as: ((A + B) - C) * ABS(D)
// With A=1, B=2, C=3, D=4: (1 + 2 - 3) * 4 = 0
Rule 2: Left-to-Right for Equal Precedence¶
A + B + C
// Evaluated as: (A + B) + C
A / B / C
// Evaluated as: (A / B) / C
Rule 3: Left Operand First¶
When an operator has two operands, the leftmost operand is evaluated first.
SIN(A) * COS(B)
// 1. Evaluate SIN(A)
// 2. Evaluate COS(B)
// 3. Multiply results
Rule 4: Short-Circuit Evaluation (Implementer-Specific)¶
Boolean expressions MAY be evaluated only to the extent necessary.
(A > B) & (C < D)
// If A <= B, the result is FALSE
// Evaluation of (C < D) may be skipped (Implementer-specific)
Note: The extent of short-circuit evaluation is Implementer-specific.
Rule 5: Function/Method in Expressions¶
Functions and methods with return values can be elements of expressions.
Result := SIN(X) + COS(Y) * 2.0;
Distance := obj.GetLength() + offset;
Rule 5a: Debug/Watch Expressions (IEC-Aligned)¶
Debugger expressions (watch conditions, breakpoint conditions, hover) are parsed using the standard expression grammar and operator precedence in Table 71. Only expression forms are permitted; no statement constructs are allowed, and evaluation must be side-effect free. (IEC 61131-3 Ed.3, §7.3.2, Table 71)
Rules:
- Use the same operator precedence and associativity as Table 71. (IEC 61131-3 Ed.3, Table 71)
- Disallow assignments, control-flow statements, and function block/method invocations.
- Allow only an explicit whitelist of pure standard functions for evaluation; see
docs/IEC_DEVIATIONS.md for the permitted set and rationale.
Rule 6: Type Conversion¶
When operands require conversion, implicit conversion rules apply.
// Implicit widening
RealVar := IntVar + 5; // IntVar promoted to REAL
// Explicit required for narrowing
IntVar := REAL_TO_INT(RealVar);
4. Operator Categories¶
4.1 Arithmetic Operators¶
| Operator | Symbol | Left Operand | Right Operand | Result | Notes |
|---|---|---|---|---|---|
| Add | + |
ANY_NUM | ANY_NUM | ANY_NUM | Also TIME+TIME |
| Subtract | - |
ANY_NUM | ANY_NUM | ANY_NUM | Also TIME-TIME |
| Multiply | * |
ANY_NUM | ANY_NUM | ANY_NUM | Also TIME*ANY_NUM |
| Divide | / |
ANY_NUM | ANY_NUM | ANY_NUM | Also TIME/ANY_NUM |
| Modulo | MOD |
ANY_INT | ANY_INT | ANY_INT | |
| Exponent | ** |
ANY_REAL | ANY_NUM | ANY_REAL | |
| Negate | - |
- | ANY_NUM | ANY_NUM | Unary |
| Plus | + |
- | ANY_NUM | ANY_NUM | Unary (identity) |
4.2 Comparison Operators¶
| Operator | Symbol | Left Operand | Right Operand | Result |
|---|---|---|---|---|
| Less than | < |
ANY_ELEMENTARY | ANY_ELEMENTARY | BOOL |
| Greater than | > |
ANY_ELEMENTARY | ANY_ELEMENTARY | BOOL |
| Less or equal | <= |
ANY_ELEMENTARY | ANY_ELEMENTARY | BOOL |
| Greater or equal | >= |
ANY_ELEMENTARY | ANY_ELEMENTARY | BOOL |
| Equal | = |
ANY_ELEMENTARY | ANY_ELEMENTARY | BOOL |
| Not equal | <> |
ANY_ELEMENTARY | ANY_ELEMENTARY | BOOL |
Notes: - Operands must be compatible types - String comparison is lexicographic
4.3 Logical/Boolean Operators¶
| Operator | Symbol | Left Operand | Right Operand | Result | Notes |
|---|---|---|---|---|---|
| AND | AND, & |
BOOL | BOOL | BOOL | Bitwise for ANY_BIT |
| OR | OR |
BOOL | BOOL | BOOL | Bitwise for ANY_BIT |
| XOR | XOR |
BOOL | BOOL | BOOL | Bitwise for ANY_BIT |
| NOT | NOT |
- | BOOL | BOOL | Bitwise for ANY_BIT |
Bitwise Operations (when applied to ANY_BIT types):
AND,&,OR, andXORoperate on bit strings and produce the wider operand type when widths differ.NOTpreserves the operand bit-string type.
// BYTE operations
B1 := 16#F0;
B2 := 16#0F;
Result := B1 AND B2; // Result = 16#00
Result := B1 OR B2; // Result = 16#FF
Result := B1 XOR B2; // Result = 16#FF
Result := NOT B1; // Result = 16#0F
4.4 Reference Operators¶
| Operator | Symbol | Operand | Result | Notes |
|---|---|---|---|---|
| Dereference | ^ |
REF_TO T | T | Access referenced value |
| Reference | REF(x) |
T | REF_TO T | Function, get reference |
VAR
myInt: INT := 42;
pInt: REF_TO INT;
END_VAR
pInt := REF(myInt); // Get reference
pInt^ := 100; // Dereference and assign
5. Expression Types¶
5.1 Constant Expressions¶
Expressions that can be evaluated at compile time:
CONST_VAL := 3.14159 * 2.0; // Compile-time constant
ARRAY_SIZE := 10 + 5; // Used in declarations
5.2 Primary Expressions¶
Basic building blocks:
42 // Integer literal
3.14 // Real literal
TRUE // Boolean literal
'Hello' // String literal
T#1s500ms // Duration literal
MyVar // Variable reference
MyEnum#Value // Enumerated value
#LocalVar // Siemens SCL local reference (extension, DEV-034)
5.2.1 Literal typing (implementer-specific)¶
- Untyped integer literals default to the smallest integer type that can represent the value.
- Decimal literals prefer signed types (SINT → INT → DINT → LINT).
- Based literals (
2#,8#,16#) prefer unsigned types (USINT → UINT → UDINT → ULINT). - Untyped real literals default to
LREAL. - Typed literal prefixes (e.g.,
INT#,REAL#,WORD#) always override. - In assignments, returns, and call arguments, untyped numeric literals are coerced to the expected integer/real type when compatible.
IEC 61131-3 Ed.3 §6.3.3 and Tables 5–9 define literal forms but do not mandate a single default integer type; this project follows the smallest‑fit policy (see IEC‑DEC‑014).
5.2.2 Siemens SCL local-reference prefix (extension)¶
#identifier is accepted as a NameRef in expression and statement contexts
for Siemens SCL compatibility; see docs/IEC_DEVIATIONS.md DEV-034.
5.3 Postfix Expressions¶
arr[5] // Array subscript
struct.field // Member access
func(a, b) // Function call
fb.method(x) // Method call
ptr^ // Dereference
5.4 Parenthesized Expressions¶
(A + B) * C // Grouping
((A > B) AND (C < D)) OR E
6. Type Checking Rules¶
6.1 Arithmetic Operations¶
| Left Type | Operator | Right Type | Result Type |
|---|---|---|---|
| ANY_INT | +, -, *, / | ANY_INT | Widest INT type |
| ANY_REAL | +, -, *, / | ANY_REAL | Widest REAL type |
| ANY_INT | +, -, *, / | ANY_REAL | REAL (promoted) |
| TIME | +, - | TIME | TIME |
| TIME | * | ANY_NUM | TIME |
| ANY_INT | MOD | ANY_INT | Widest INT type |
| ANY_REAL | ** | ANY_NUM | REAL/LREAL |
6.2 Comparison Operations¶
| Left Type | Right Type | Valid |
|---|---|---|
| ANY_NUM | ANY_NUM | Yes (with promotion) |
| STRING | STRING | Yes (lexicographic) |
| TIME | TIME | Yes |
| DATE | DATE | Yes |
| BOOL | BOOL | Yes (= and <> only) |
| STRUCT | STRUCT | No (not an elementary type) |
6.3 Boolean Operations¶
| Operation | Operand Types | Result |
|---|---|---|
| AND, OR, XOR | BOOL | BOOL |
| AND, OR, XOR | ANY_BIT | Wider of operands |
| NOT | BOOL | BOOL |
| NOT | ANY_BIT | Same bit width |
7. Error Conditions¶
7.1 Runtime Errors¶
- Division by zero: Attempt to divide by zero
- Overflow: Result exceeds type range
- Null dereference: Dereferencing NULL reference
7.2 Compile-time Errors¶
- Type mismatch: Operands not compatible
- Invalid operand: Wrong type for operator
- Undefined identifier: Variable not declared
- Invalid call: Function signature mismatch
8. Complex Expression Examples¶
Arithmetic¶
// Quadratic formula discriminant
D := B * B - 4.0 * A * C;
// Distance calculation
Distance := SQRT(DX**2 + DY**2);
// Time calculation
TotalTime := BaseTime + T#1s * COUNT;
Logical¶
// Complex condition
Valid := (Temp > MinTemp) AND (Temp < MaxTemp)
AND NOT Error
AND (Mode = Auto OR Override);
// Bit manipulation
Flags := (Flags AND NOT Mask) OR NewBits;
Mixed¶
// Conditional with function calls
Result := SEL(Condition, ValueIfFalse, ValueIfTrue);
// Bounded value
Output := MIN(MAX(Input, LowLimit), HighLimit);
// String comparison
Match := (Name = 'ADMIN') OR (Name = 'ROOT');
Implementation Notes¶
Parser Requirements¶
- Use precedence climbing or Pratt parsing for operator precedence.
- Handle both symbols (
&) and keywords (AND) for the same operator family. - Keep unary operators (
-,+,NOT) right-associative. - Support chained comparisons such as
A < B < Cwith left-to-right evaluation. - Treat function/method calls as primary expressions.
AST Node Types¶
Expression
├── Literal (integer, real, string, bool, time, date)
├── Identifier
├── BinaryOp (operator, left: Expression, right: Expression)
├── UnaryOp (operator, operand: Expression)
├── FunctionCall (name, arguments: [Expression])
├── MethodCall (object: Expression, method, arguments: [Expression])
├── ArrayAccess (array: Expression, index: Expression)
├── FieldAccess (object: Expression, field)
├── Dereference (operand: Expression)
└── Parenthesized (inner: Expression)
Type Checker Requirements¶
- Determine the type of each operand.
- Apply promotion rules before evaluating operator compatibility.
- Verify operator compatibility and determine the result type.
- Report the specific operator, operand types, and precise source location.