POU Declarations¶
Declaration lookup for FUNCTION, FUNCTION_BLOCK, PROGRAM, class,
interface, method, property, action syntax, inheritance rules, and
execution-control parameters.
Related: Variables, Statements
IEC 61131-3 Edition 3.0 (2013) - Section 6.6
This specification defines POU declarations for trust-hir.
1. Overview¶
Program Organization Units (POUs) are the building blocks of IEC 61131-3 programs:
| POU Type | Keyword | Instances | State | Return Value |
|---|---|---|---|---|
| Function | FUNCTION |
N/A (call) | No | Optional |
| Function Block | FUNCTION_BLOCK |
Yes | Yes | Via outputs |
| Program | PROGRAM |
Yes | Yes | Via outputs |
| Class | CLASS |
Yes | Yes | N/A |
| Interface | INTERFACE |
N/A | N/A | N/A |
| Method | METHOD |
N/A | No | Optional |
Parser acceptance contract¶
The parser accepts an empty source buffer without parse diagnostics. This editor-oriented acceptance does not claim a syntax-tree shape or that an empty project is runnable.
The canonical minimal PROGRAM name END_PROGRAM form and a
FUNCTION_BLOCK containing a complete VAR_INPUT ... END_VAR section and no
body statements parse successfully when their required names and matching
terminators are present. Semantic declaration and project validation remain
separate.
For a POU with top-level executable statements, the parser preserves those
statements under one StmtList child of the owning POU. Nested methods,
properties, and actions own their own bodies; their statements are not folded
into the enclosing function-block statement list.
Implementation Extension: Test POUs¶
truST accepts TEST_PROGRAM and TEST_FUNCTION_BLOCK as documented
test-oriented, non-IEC declaration forms.
TEST_PROGRAM name
...
END_TEST_PROGRAM
TEST_FUNCTION_BLOCK name
...
END_TEST_FUNCTION_BLOCK
Current parser/HIR behavior:
- TEST_PROGRAM is parsed with PROGRAM structure and collected as SymbolKind::Program.
- TEST_FUNCTION_BLOCK is parsed with FUNCTION_BLOCK structure and collected as SymbolKind::FunctionBlock.
- Mismatched end markers produce actionable diagnostics (expected END_TEST_PROGRAM / expected END_TEST_FUNCTION_BLOCK).
- End-of-file before the matching test-POU terminator produces the same
actionable required-terminator diagnostic; an unterminated TEST_PROGRAM
reports expected END_TEST_PROGRAM.
2. FUNCTION Declaration (Table 19, Section 6.6.2)¶
Syntax¶
FUNCTION function_name : return_type
// Variable declarations
VAR_INPUT ... END_VAR
VAR_OUTPUT ... END_VAR
VAR_IN_OUT ... END_VAR
VAR_EXTERNAL ... END_VAR
VAR_EXTERNAL CONSTANT ... END_VAR
VAR ... END_VAR
VAR_TEMP ... END_VAR
// Statements
END_FUNCTION
Examples¶
// Function with return value
FUNCTION Square : INT
VAR_INPUT
X: INT;
END_VAR
Square := X * X;
END_FUNCTION
// Function without return value (procedure-like)
FUNCTION LogMessage
VAR_INPUT
Message: STRING;
END_VAR
// Implementation
END_FUNCTION
Rules (Section 6.6.1.2)¶
- No state retention: Variables in VAR/VAR_TEMP are re-initialized each call (VAR and VAR_TEMP are equivalent in functions/methods)
- Return value: Assigned through the IEC function-name result variable or
through the truST value-bearing RETURN extension recorded as
DEV-022 - VAR_IN_OUT and VAR_EXTERNAL: May be modified inside the function; VAR_EXTERNAL CONSTANT shall not be modified
- CONSTANT restriction: Function block instances shall not be declared in variable sections with CONSTANT qualifier
- Return type: the declared type names a data type of specification 02.
The IEC dialect rejects a
VOIDreturn declaration (E207): IEC 61131-3 knows noVOIDdata type. Under the CODESYS profile (DEV-043indocs/IEC_DEVIATIONS.md)FUNCTION name : VOIDdeclares a function without a result: the function carries no return slot, a call captures no result, the body may exit early with a value-lessRETURN;, and aRETURNwith a value staysE207.
POU initializer contract¶
The variable-initialization rules in IEC 61131-3 Ed.3 §6.5.1.3 and Annex A apply independently of POU declaration order:
- function and method inputs, outputs, ordinary locals, temporary locals, and static locals may carry compatible literal or constant-expression initializers;
- function and method ordinary and temporary locals, plus outputs, are reinitialized for every call;
- function and method static locals are initialized once and persist, with method static storage isolated by receiver;
- function-block inputs, outputs, ordinary variables, and static variables are initialized with their instance, while temporary variables are initialized for each invocation;
- program inputs, outputs, ordinary variables, and static variables are initialized with their program instance, while temporary variables are initialized for each cycle; and
- in-out and external declarations do not accept initializers.
Every accepted initializer is resolved from the declaration site's complete
constant graph before POU storage is exposed. Textual section order and project
source order do not change the selected constant, but lexical POU scope,
namespace qualification, and USING ambiguity remain binding. Detailed
eligibility, omitted-input, output-copy, and failure rules are specified in
03-variables.md; runtime materialization is specified in
10-runtime-semantics.md §7.9.
Variable-section legality¶
IEC 61131-3 Ed.3 Table 19 and the Annex A function production permit
VAR_INPUT, VAR_OUTPUT, VAR_IN_OUT, VAR_EXTERNAL, VAR, and
VAR_TEMP in a function. A method has the same variable-section set under the
Annex A method production. truST additionally accepts VAR_STAT in both as
the documented persistent-static extension.
Neither owner accepts VAR_GLOBAL, VAR_ACCESS, or VAR_CONFIG. Encountering
one of those sections rejects the complete function or method declaration;
the compiler must not silently discard the section and return a partial POU.
Variable-section ownership and qualifier placement are independent closed
checks. The matrix in 03-variables.md permits CONSTANT on each legal
function/method storage section, but permits restart policy only on truST
VAR_STAT; ordinary variables and parameters are reinitialized per call and
cannot own RETAIN, NON_RETAIN, or PERSISTENT. A qualifier never makes an
otherwise forbidden section legal.
Function Call (Section 6.6.1.7)¶
| No. | Call Type | Example |
|---|---|---|
| 1 | Formal call | Y := Square(X := 5); |
| 2 | Non-formal call | Y := Square(5); |
| 3 | Procedure call | LogMessage('Hello'); |
IEC 61131-3 Ed.3 section 6.6.1.4.2 defines formal and non-formal parameter
lists as separate call forms. truST also accepts a mixed convenience form when
all positional arguments precede all formal arguments, for example
Add(1, b := 2). This is the intentional extension recorded as
DEV-018;
portable source should use one IEC call form throughout.
EN/ENO Mechanism (Section 6.6.1.6)¶
EN and ENO are optional parameters on FUNCTION/FUNCTION_BLOCK declarations and calls:
EN:BOOLinput with an effective default ofTRUEENO:BOOLoutput initialized toTRUEfor an enabled call
| EN | Execution | ENO |
|---|---|---|
| FALSE | No other actual or writable target is evaluated; POU body is not executed | FALSE |
| TRUE | POU body executes normally | TRUE unless the POU sets it FALSE |
| TRUE | POU body encounters an execution error | FALSE; call transfer is not committed |
EN and ENO are execution-control parameters, not ordinary positional
parameters. They may be connected only by name. EN uses :=; ENO uses
=>. EN is evaluated before every other actual even if written later in the
formal list. A false value short-circuits evaluation and binding of every other
actual. The only caller write made by the skipped call is FALSE to a
connected ENO target. A skipped function or value-returning method produces
its declared type default; a skipped function block or void method preserves
its instance state.
For an enabled call, ENO is set to TRUE before the body and may be assigned
only inside that POU. A normally returning body commits its result and connected
outputs even when it explicitly leaves ENO false. A runtime execution error
reports the error and commits no result/output/in-out/instance-state transfer.
REF(EN) and REF(ENO) are invalid. These implementer-specific choices are
recorded in
IEC_DECISIONS.md.
FUNCTION SafeDiv : REAL
VAR_INPUT
EN: BOOL := TRUE;
Num, Den: REAL;
END_VAR
VAR_OUTPUT
ENO: BOOL;
END_VAR
IF Den = 0.0 THEN
ENO := FALSE;
SafeDiv := 0.0;
ELSE
SafeDiv := Num / Den;
END_IF;
END_FUNCTION
Result := SafeDiv(EN := Cond, Num := A, Den := B, ENO => Valid);
Return Value (Table 20)¶
FUNCTION Max : INT
VAR_INPUT
A, B: INT;
END_VAR
IF A > B THEN
Max := A; // Assign to function name
ELSE
Max := B;
END_IF;
END_FUNCTION
Or using RETURN:
FUNCTION Max : INT
VAR_INPUT
A, B: INT;
END_VAR
IF A > B THEN
RETURN A;
ELSE
RETURN B;
END_IF;
END_FUNCTION
3. FUNCTION_BLOCK Declaration (Table 40, Section 6.6.3)¶
Syntax¶
FUNCTION_BLOCK fb_name
// Variable declarations
VAR_INPUT ... END_VAR
VAR_OUTPUT ... END_VAR
VAR_IN_OUT ... END_VAR
VAR ... END_VAR
VAR_TEMP ... END_VAR
VAR_EXTERNAL ... END_VAR
// Methods (optional)
METHOD ... END_METHOD
// Statements
END_FUNCTION_BLOCK
Example¶
FUNCTION_BLOCK Counter
VAR_INPUT
Reset: BOOL;
CountUp: BOOL R_EDGE;
END_VAR
VAR_OUTPUT
Count: INT;
Overflow: BOOL;
END_VAR
VAR
InternalCount: INT := 0;
END_VAR
IF Reset THEN
InternalCount := 0;
ELSIF CountUp THEN
IF InternalCount < 32767 THEN
InternalCount := InternalCount + 1;
ELSE
Overflow := TRUE;
END_IF;
END_IF;
Count := InternalCount;
END_FUNCTION_BLOCK
Rules¶
- State retention: Internal variables persist across calls
- Instantiation required: Must be declared as instance to use
- Instance isolation: Each instance has independent state
- Can contain methods: OOP-style methods allowed
- Can inherit: Using EXTENDS (if supported)
- EXTENDS targets: Function blocks may EXTENDS a FUNCTION_BLOCK or CLASS; extending an INTERFACE is invalid (Table 40, IEC 61131-3 Ed.3 §6.6.3.4)
- Inherited parameters: a derived function block inherits its base's input,
output and in-out variables (IEC 61131-3 Ed.3 §6.6.5.3), so a call of the derived
block binds them like its own, for example
Block(Value := 7, Gain := 3, Result => R)whereGainandResultare declared in the base. The base's parameters come first in positional order, then the derived block's, each in declaration order; under the CODESYS profile the positional association covers the input and in-out formals only, and an output formal binds only by name with=>(IEC_DEVIATIONS.mdDEV-044). - A base in a namespace is written qualified (
EXTENDS Lib.Base) or found throughUSING; both give the same inheritance (IEC 61131-3 Ed.3 Tables 64–66). - Calling a derived function block runs only its own body; the base's body does not run.
- Can implement interfaces: A function block declaration may use
IMPLEMENTSwith one or more interface names; the parser preserves the complete ordered interface list for semantic validation (IEC 61131-3 Ed.3 §6.6.7.1, Table 52). - Who assigns an input: the caller assigns a function block's input, in
the call or separately before it (
fbInst.input := value; IEC 61131-3 Ed.3 Figure 13 rule 2b). Under the IEC rules the block's own body does not assign its input (rule 2a). Under a CODESYSvendor_profile(specification 14) the body of a function block or program may assign its ownVAR_INPUTmembers between calls, as CODESYS does (IEC_DEVIATIONS.mdDEV-029). Function and method parameters remain call-local and read-only under both, and pointer/reference input slots stay read-only per the truST indirect-write policy (02-data-types.mdsection 4.4). Assignments through an input-parameter slot (fbInput.field := valuewherefbInputis aVAR_INPUTfunction-block instance) remain rejected. - Default access of a function block's members: under the IEC rules
plain
VAR,VAR_STAT, methods, and properties of a function block without an access specifier are PROTECTED: reachable inside the block and the blocks derived from it, not through an instance from outside (IEC 61131-3 Ed.3 §6.6.3.2 item 11 makes them private; §6.6.5.9-6.6.5.10). Under a CODESYSvendor_profilethey are PUBLIC and reachable through the instance name (fbInst.member), as CODESYS does (IEC_DEVIATIONS.mdDEV-028); an explicit access specifier keeps its meaning, andVAR_IN_OUT,VAR_TEMP, andVAR_EXTERNALmembers stay restricted because they only mean something inside the POU. CLASS members keep the PROTECTED default under both rules.
Table 40 permits input, output, in-out, external, ordinary, and temporary
sections. truST also accepts VAR_STAT as ordinary persistent instance
storage. A function block rejects VAR_GLOBAL, VAR_ACCESS, and
VAR_CONFIG; those owners belong to program/configuration assembly and cannot
be ignored inside the function-block declaration.
Function-block ordinary/static variables, inputs, and outputs may own one
restart policy. In-outs, temporaries, and external aliases may not. The same
sections may be CONSTANT where allowed by 03-variables.md, but a constant
section cannot also declare a restart policy.
Table 40 edge-qualified BOOL inputs are a function-block-body surface, not
ordinary parameters visible to methods. Each R_EDGE or F_EDGE declaration
creates independent hidden trigger state and exposes its one-invocation pulse
to the body. The complete declaration, qualifier, restart, and rejection
contract is in 03-variables.md.
Function Block Instance Declaration (Table 41)¶
VAR
MyCounter: Counter; // Simple instance
Timers: ARRAY[1..10] OF TON; // Array of instances
HeaterPID: PID := (Kp := 2.5, Ti := T#10s); // With initialization
END_VAR
Function Block Call (Table 42)¶
| No. | Call Type | Example |
|---|---|---|
| 1 | Complete formal | MyCounter(Reset := FALSE, CountUp := TRUE); |
| 2 | Incomplete formal | MyCounter(CountUp := Trigger); |
| 3 | Output access | Value := MyCounter.Count; |
| 4 | With EN/ENO | MyFB(EN := Cond, ENO => Success); |
| 5 | Separate input assignment | MyCounter.CountUp := Trigger; MyCounter(); |
| 6 | Call on an instance array element | Timers[i](IN := Start, PT := T#5s); |
An element of an instance array is called and read through its subscript and runs its own instance (IEC 61131-3 Ed.3 §6.6.3.4.1, example e). Outside an instance, an input may be assigned through the instance and takes effect with the next call; inside the function block, the block does not assign its own inputs (IEC 61131-3 Ed.3 §6.6.3.4.2, Figure 13 row 2).
A positional actual associates with the block's formal parameters in their
declaration order, an output formal included (IEC 61131-3 Ed.3 §6.6.3.4,
Table 42). Under the CODESYS profile a function block invocation instead
binds positionally to its input and in-out formals only, in declaration order
base-first through the EXTENDS chain; an output formal binds only by name
with => and positional actuals beyond the input and in-out formals are
rejected (DEV-044).
Functions and methods keep the full positional association.
4. PROGRAM Declaration (Table 47, Section 6.6.4)¶
Syntax¶
PROGRAM program_name
// Variable declarations
VAR_INPUT ... END_VAR
VAR_OUTPUT ... END_VAR
VAR ... END_VAR
VAR_EXTERNAL ... END_VAR
VAR_TEMP ... END_VAR
VAR_ACCESS ... END_VAR
// Statements
END_PROGRAM
Example¶
PROGRAM MainControl
VAR_INPUT
EmergencyStop: BOOL;
END_VAR
VAR_OUTPUT
SystemRunning: BOOL;
END_VAR
VAR
StartupSequence: INT := 0;
ProcessTimer: TON;
END_VAR
VAR_EXTERNAL
GlobalConfig: Configuration;
END_VAR
IF EmergencyStop THEN
SystemRunning := FALSE;
StartupSequence := 0;
ELSE
// Main control logic
END_IF;
END_PROGRAM
Rules¶
- Similar to FUNCTION_BLOCK but with additional capabilities
- Can be associated with TASKs
- Can have VAR_ACCESS declarations
- Typically represents a complete control application
- Instantiated in CONFIGURATION/RESOURCE
IEC Table 47 permits the function-block-like input, output, in-out, external,
ordinary, and temporary sections and additionally permits program-local
VAR_GLOBAL and VAR_ACCESS. truST accepts VAR_STAT as ordinary persistent
program-instance storage. VAR_CONFIG remains configuration-owned and is
rejected inside a program declaration.
Program ordinary/static variables, inputs, outputs, and globals may own one restart policy. In-outs, temporaries, external aliases, and access declarations may not. Qualifier conflicts and duplicate qualifier tokens reject the complete program declaration.
Table 47 adopts the Table 40 textual edge-input form for programs. A program
samples each edge-qualified BOOL input once per executed program cycle and
the program body observes only the resulting one-cycle pulse.
Program methods (e!COCKPIT dialect): a program may declare methods, and
the program body calls them by bare name without a THIS qualifier. truST
imports vendor method metadata attached to program POUs exactly like
function-block methods and resolves the self-calls against them. The textual
file grammar accepts METHOD ... END_METHOD declarations inside the program
body — like ACTION ... END_ACTION, at any position between the var sections
and END_PROGRAM — with access modifiers, return type, and var sections per
the §7 method grammar. PROPERTY declarations remain rejected in program
bodies. The runtime build compiles a program's method as a function on the
variables of the program instance it is called on: a bare-name call in the
program's body runs it on the instance that runs the body, and
ProgramName.method_name(...) on the program instance of that name, which
only the CODESYS profile provides (docs/IEC_DEVIATIONS.md DEV-030). Its
VAR_STAT variables lie in the program instance, one of each per instance
and method, as a function-block method's lie in its instance (specification
01 §3); they are retained as a variable of the program is.
Program-singleton access (CODESYS profile)¶
PROGRAM Main
seen := Producer.counter; // read another program's member
Consumer.setpoint := 5; // write another program's member
I18nConfig(); // invoke another program body
END_PROGRAM
CODESYS treats task programs as implicit singletons: a program's name is its
one instance. Under a CODESYS vendor_profile truST accepts the same access
shape. Under the IEC rules both forms are errors: programs are instantiated
only in resources and their variables are reached through access paths (IEC
61131-3 Ed.3 §6.6.4 items 2 and 3; IEC_DEVIATIONS.md DEV-030).
- A program name used as the qualifier of a field expression resolves the member (variable, function-block instance, or action) among that program's own declarations, including across files. The program name alone in value position remains rejected ("program cannot be used as a value").
- A program name invoked as a statement (
Name();) invokes the program body. A program call produces no value; using the call result is rejected like a void call.VAR_INPUTarguments are accepted and checked like function-block input bindings (positional or named), matching the CODESYS calling convention; arguments against a program without matching inputs are an argument diagnostic. - The runtime build reaches the program's instance of the same name: its variables, its function block instances, and its body run on it, with the arguments bound as a function block call binds them. A project without a CONFIGURATION has one instance of each program's name (specification 18 §2.2); a project whose CONFIGURATION gives the program no instance of its name is refused with that reason.
5. CLASS Declaration (Table 48, Section 6.6.5)¶
Syntax¶
CLASS class_name
// Variable declarations
VAR ... END_VAR
// Methods
METHOD ... END_METHOD
END_CLASS
With Inheritance and Interface¶
CLASS class_name EXTENDS base_class IMPLEMENTS interface1, interface2
// ...
END_CLASS
Example¶
CLASS Motor
VAR PUBLIC
Speed: INT;
Running: BOOL;
END_VAR
VAR PRIVATE
InternalState: INT;
END_VAR
METHOD PUBLIC Start
Running := TRUE;
InternalState := 1;
END_METHOD
METHOD PUBLIC Stop
Running := FALSE;
Speed := 0;
InternalState := 0;
END_METHOD
METHOD PUBLIC SetSpeed
VAR_INPUT
NewSpeed: INT;
END_VAR
IF Running THEN
Speed := NewSpeed;
END_IF;
END_METHOD
END_CLASS
Class Modifiers¶
| Modifier | Description |
|---|---|
FINAL |
Cannot be extended |
ABSTRACT |
Cannot be instantiated, must be extended |
CLASS ABSTRACT BaseController
METHOD PUBLIC ABSTRACT Execute;
END_CLASS
CLASS FINAL SpecificController EXTENDS BaseController
METHOD PUBLIC OVERRIDE Execute
// Implementation
END_METHOD
END_CLASS
Rules¶
- Classes cannot have VAR_INPUT, VAR_OUTPUT, VAR_IN_OUT
- External member access is through methods, truST properties, or
PUBLICvariables;PROTECTED,PRIVATE, andINTERNALaccess follows the closed matrix in03-variables.md - Instantiation:
VAR MyMotor: Motor; END_VAR - Cannot be associated with TASKs directly
- EXTENDS must reference a CLASS type; FINAL classes cannot be extended (Table 48, IEC 61131-3 Ed.3 §6.6.5.5.4)
Table 48 and §6.6.5.2 permit ordinary VAR and VAR_EXTERNAL class
declarations and explicitly forbid VAR_INPUT, VAR_OUTPUT, VAR_IN_OUT,
and VAR_TEMP. truST accepts VAR_STAT only as its documented ordinary
instance-storage extension. Classes also reject VAR_GLOBAL, VAR_ACCESS,
and VAR_CONFIG. Rejection occurs before a class type or field set is exposed
to runtime assembly.
Class VAR and truST VAR_STAT may own one restart policy; class
VAR_EXTERNAL may be CONSTANT but cannot own one. A qualifier does not
expand the class section set.
Class ordinary variables, methods, and truST properties default to
PROTECTED. PRIVATE members are not inherited. INTERNAL members are
inherited only within the exact declaring namespace. An overriding method must
be accessible to the derived class and repeat the inherited method's exact
access specifier (IEC §6.6.5.5.2-6.6.5.5.3).
6. INTERFACE Declaration (Table 51, Section 6.6.6)¶
Syntax¶
INTERFACE interface_name
METHOD method_name
// Parameter declarations only, no body
END_METHOD
END_INTERFACE
An interface declaration owns method prototypes, not storage. No VAR,
VAR_STAT, VAR_TEMP, directional parameter, external, global, access, or
configuration variable section is legal directly under INTERFACE. The
input/output/in-out declarations of each method prototype remain children of
that prototype and follow the method signature grammar.
Example¶
INTERFACE IControllable
METHOD Start
END_METHOD
METHOD Stop
END_METHOD
METHOD GetStatus : INT
END_METHOD
END_INTERFACE
CLASS Pump IMPLEMENTS IControllable
VAR PRIVATE
IsRunning: BOOL;
END_VAR
METHOD PUBLIC Start
IsRunning := TRUE;
END_METHOD
METHOD PUBLIC Stop
IsRunning := FALSE;
END_METHOD
METHOD PUBLIC GetStatus : INT
IF IsRunning THEN
GetStatus := 1;
ELSE
GetStatus := 0;
END_IF;
END_METHOD
END_CLASS
Interface Inheritance¶
INTERFACE IAdvancedControl EXTENDS IControllable
METHOD Pause
END_METHOD
METHOD Resume
END_METHOD
END_INTERFACE
Interface as Variable Type¶
VAR
MyPump: Pump;
Controller: IControllable; // Reference to any implementing class
END_VAR
Controller := MyPump; // Assign implementing instance
Controller.Start(); // Call through interface
Rules¶
- Interfaces contain only method prototypes (no implementation) per IEC 61131-3 Ed.3 §6.6.6.1. Property signatures are accepted as a documented truST extension.
- Every method prototype is implicitly
PUBLIC; writing an explicit access specifier on a prototype is an error (IEC §6.6.5.9 and §6.6.6.3) - Classes implementing interface MUST implement all methods
- Interfaces can extend other interfaces
- A class can implement multiple interfaces
- Interface variables are references and shall be assigned before use; they shall not be VAR_IN_OUT
- Interface variables can be assigned NULL (default) and compared for equality (IEC 61131-3 Ed.3 §6.6.6.5.1)
- EXTENDS must reference INTERFACE types; cyclic interface inheritance is invalid (Table 51, IEC 61131-3 Ed.3 §6.6.6.3)
7. METHOD Declaration (Sections 6.6.5.4 and 6.6.7.2)¶
IEC 61131-3 scopes method declarations to classes (6.6.5.4) and function blocks (6.6.7.2). truST additionally accepts program-scoped methods as the e!COCKPIT dialect extension defined in §4; all §7 rules apply unchanged.
Syntax¶
METHOD access_specifier method_name : return_type
VAR_INPUT ... END_VAR
VAR_OUTPUT ... END_VAR
VAR_IN_OUT ... END_VAR
VAR ... END_VAR
VAR_TEMP ... END_VAR
// Statements
END_METHOD
Example¶
METHOD PUBLIC Calculate : REAL
VAR_INPUT
A, B: REAL;
END_VAR
VAR_TEMP
Temp: REAL;
END_VAR
Temp := A * A + B * B;
Calculate := SQRT(Temp);
END_METHOD
Method Modifiers¶
| Modifier | Description |
|---|---|
OVERRIDE |
Overrides base class method |
FINAL |
Cannot be overridden in derived classes |
ABSTRACT |
No implementation, must be overridden |
CLASS Base
METHOD PUBLIC Process
// Default implementation
END_METHOD
END_CLASS
CLASS Derived EXTENDS Base
METHOD PUBLIC OVERRIDE Process
SUPER.Process(); // Call base implementation
// Additional processing
END_METHOD
END_CLASS
Access Specifiers for Methods¶
| Specifier | Permitted call sites |
|---|---|
PUBLIC |
Anywhere the containing type is accessible |
PROTECTED |
The defining class/FB and derived classes/FBs (default) |
PRIVATE |
The defining class/FB only; not inherited |
INTERNAL |
POUs in the exact declaring namespace |
The matrix is normative for class methods under IEC §6.6.5.9 and is adopted for function-block methods by §§6.6.7.2.5 and 6.6.7.6. Improper use is an error. The following inheritance rules are part of the same contract:
- a derived POU may override only an inherited
PUBLIC,PROTECTED, or same-namespaceINTERNALmethod; - an override repeats the exact access specifier of the inherited method;
PRIVATEmethods are not inherited, so a same-named derived method is a new method and must not carryOVERRIDE;- an
INTERNALmethod is neither inherited nor overrideable across a namespace boundary; and - a containing
INTERNALnamespace or type restriction may prevent an otherwisePUBLICcall.
THIS and SUPER Keywords¶
METHOD PUBLIC Example
THIS.Speed := 100; // Access own member
SUPER.Initialize(); // Call base class method
END_METHOD
truST PROPERTY access extension¶
PROPERTY, GET, and SET are a documented truST language extension; IEC
61131-3 Ed.3 does not define those keywords. A class/FB property uses the same
PUBLIC/PROTECTED/PRIVATE/INTERNAL access matrix and PROTECTED
default as a method. The access check occurs before the getter/setter
capability check: an inaccessible getter or setter remains inaccessible even
when that accessor exists.
An interface property signature is implicitly PUBLIC, matching an IEC
interface method prototype. An explicit access token on an interface property
signature is rejected. An implementing property must be PUBLIC or
INTERNAL, must match the declared type, and must provide every accessor
required by the interface signature.
8. ACTION Declaration (Table 56, Table 72; Section 6.7.4)¶
truST compiles textual ACTION ... END_ACTION declarations as same-instance
sub-bodies of their owning PROGRAM or FUNCTION_BLOCK (CODESYS semantics):
the body runs against the owner's own variables when invoked, with no
parameters, no return value, and no storage of its own. IEC step/action
association, action control, and action qualifiers remain outside the
textual profile; see sfc-profile.md.
Syntax¶
ACTION action_name:
// Statements
END_ACTION
Rules¶
- The colon after
action_nameis required by the IEC grammar forAction(IEC 61131-3 Ed.3 Annex A, Tables 54-64). - A textual action declaration may be a direct child of a
PROGRAMorFUNCTION_BLOCK. It is rejected at file/namespace scope and inside aFUNCTION,CLASS,METHOD,PROPERTY, anotherACTION, or any statement block. - An action name is an identifier and is case-insensitive. Two textual action declarations in the same owner may not have the same name. Actions with the same name in different owners are independent.
- IEC permits a Boolean variable to act as an action name. Consequently, a
textual action declaration does not reserve the ordinary variable namespace:
an enclosing
BOOLvariable may have the same spelling. That variable and the textual action declaration remain distinct semantic facts. - An action body is an ST statement list. It does not declare its own
VAR...END_VARsections and it cannot contain another action declaration. - The action body shares the enclosing POU's variable, type, function, and
function-block visibility. An action in a function block also has the
enclosing receiver context, including valid
THISandSUPERaccess. - Semantic analysis checks every action body exactly like the owner body. Invalid assignments, unresolved names, invalid calls, invalid loop control, and other statement errors must not be hidden merely because the body only runs on invocation.
- Labels and
JMPtargets form a scope for each action body. A jump cannot enter or leave an action body, matching IEC 61131-3 Ed.3 §8.1.6. - A bare
RETURN;in an action body has the containing program or function block as its IEC control context. A return value is invalid because neither kind of owner returns a value. - Textual action invocation (CODESYS vendor extension): an action is
callable by its bare name inside its owning POU's body, or through a
function-block instance (
instance.action_name()). An action call takes no arguments, returns no value, and is invalid in value position. An action name does not participate in ordinary variable resolution: a variable with the same spelling keeps shadowing the action for value and assignment contexts, and the action remains invocable by name in call position. SFC action association and qualifiers remain in the unsupported textual-SFC profile, and the runtime compiler still does not implement action control. Calling a program's action through the program's name (POU.action_name()) is program-singleton access, which only the CODESYS profile provides (docs/IEC_DEVIATIONS.mdDEV-030).
Parser acceptance and recovery boundary¶
The parser recognizes ACTION, END_ACTION, and the required punctuation
case-insensitively. It requires exactly one identifier followed by exactly one
colon, accepts an empty body or a complete ST statement list, and retains each
action body in its own syntax node even when one owner declares several
actions. Ordinary owner statements before and after an action remain in the
owner's statement list. An ordinary owner variable may use the same spelling
as an action, and the same action spelling may be used independently by two
different owners.
The parser emits a visible error for a missing or reserved-keyword name, a
missing, doubled, or semicolon-substituted colon, a missing END_ACTION, a
local VAR...END_VAR section, a nested action, or an action in an owner/scope
not permitted by rule 2. Textual STEP and TRANSITION forms are not accepted
as ST statements inside an action body under the current front-end analysis
profile. These failures may retain a bounded partial syntax tree for tooling;
they do not create a valid action declaration or authorize execution.
Compilation boundary¶
- The runtime build compiles each textual action of a
PROGRAMorFUNCTION_BLOCKas a method of its owner without parameters, result, locals or statics (specification 44 §6.4). It shares the owner's variables, receiver, and visibility: a call by the bare name inside the owner's body runs the action on the instance that runs the body,instance.action_name()on that function block instance, andPOU.action_name()on the program instance of that name (rule 10). - Action bodies must not be appended to, interleaved with, or executed as part of the owner's ordinary statement list: the owner body runs exactly its own statements, those before and after an action declaration in source order, and action statements run only on invocation.
RETURNin an action body ends the action; its caller continues after the call.- No action-local state, scheduling, qualifier, step association, activation, or scan-cycle semantics are defined. The runtime implements invocation only; SFC action control remains unsupported in the textual profile.
- Visual-SFC artifacts remain executable through their generated companion
function block and wrapper
PROGRAMdescribed by17-visual-editors-runtime-unification.md; they do not gain execution semantics by embedding textual action declarations.
9. NAMESPACE Declaration (Tables 64-66, Section 6.9)¶
Syntax¶
NAMESPACE namespace_name
// Type declarations
// POU declarations
END_NAMESPACE
Nested Namespaces¶
NAMESPACE Company
NAMESPACE Project
NAMESPACE Module
FUNCTION_BLOCK MyFB
// ...
END_FUNCTION_BLOCK
END_NAMESPACE
END_NAMESPACE
END_NAMESPACE
USING Directive¶
USING Company.Project.Module;
USING Standard.Timers, Standard.Counters;
VAR
FB1: MyFB; // Can use without full qualification
END_VAR
Qualified Access¶
VAR
FB1: Company.Project.Module.MyFB; // Full qualification
END_VAR
Rules¶
- Namespaces can be nested
- USING may appear in the global namespace, inside a namespace, or immediately after a POU header (IEC 61131-3 Ed.3, Section 6.9.4, Table 66)
- USING brings names from the referenced namespace into scope (direct members only)
- Qualified names can always be used
- Name conflicts resolved by qualification
- INTERNAL access specifier limits scope to namespace
Namespace implementation notes¶
- USING directives are parsed and resolved for global, namespace, and POU scopes; only direct members of the imported namespace are made available. (IEC 61131-3 Ed.3, Section 6.9.4, Table 66)
- INTERNAL access specifier is enforced at namespace boundaries. (IEC 61131-3 Ed.3, Tables 64-66)
Implementation Notes for trust-hir¶
Syntax-tree POU semantic owners¶
The POU-like semantic-owner classifier contains Program, Function,
FunctionBlock, Class, Method, Property, and Interface.
PropertyGet, PropertySet, ProgramConfig, Namespace, Configuration,
and Resource are not independent owners in this classifier. The listed order
is the canonical iteration order of the shared classifier constant. This is an
internal truST syntax/HIR ownership boundary, and “POU-like” here does not
redefine the IEC POU taxonomy.
POU Symbol Requirements¶
- Name: Unique identifier
- Kind: Function, FB, Program, Class, Interface, Method
- Parameters: Input, output, in-out lists
- Return type: For functions and methods
- Body: Statement list
- Scope: Containing namespace/POU
- Modifiers: FINAL, ABSTRACT, access specifiers
Semantic Checks¶
- Duplicate definition: Same POU name in scope
- Missing implementation: ABSTRACT method not overridden
- Interface compliance: All methods implemented
- Override without base: OVERRIDE on non-virtual method
- FINAL violation: Extending FINAL class/overriding FINAL method
- Access violation: Calling PRIVATE/PROTECTED inappropriately
- Return value: Function/method must assign return value
- Parameter matching: Call arguments match declaration
Error Conditions¶
- Undefined POU reference
- Missing return value assignment
- Type mismatch in call
- Invalid inheritance (circular, FINAL violation)
- Interface method not implemented
- Abstract class instantiation
- Invalid use of THIS/SUPER
- OVERRIDE without matching base method