Diagnostic Codes
Reference for PLC diagnostics with minimal examples that trigger each code.
This page lists the diagnostic codes emitted by the language server and plccheck. The examples are intentionally minimal. Most SCL examples are fragments that should be placed inside a normal block body or declaration section, and project-wide diagnostics may require the companion file or PLC-root setup described in the example.
SCL Lexer And Parser
| Code | Meaning | Minimal trigger example |
|---|---|---|
SCL_LEX_UNTERMINATED_STRING |
A single-quoted string literal is not closed. | #Name := 'open; |
SCL_LEX_UNEXPECTED_HASH |
A # local marker is not followed by an identifier. |
# := TRUE; |
SCL_LEX_UNEXPECTED_TOKEN |
The lexer found a character that is not valid at that position. | #Value := @; |
SCL_LEX_UNTERMINATED_ATTRIBUTE_BLOCK |
A Siemens attribute block starts with { and never closes. |
{ S7_Optimized_Access := 'TRUE' |
SCL_LEX_UNTERMINATED_QUOTED_IDENTIFIER |
A double-quoted identifier is not closed. | "OpenName := 1; |
SCL_PARSE_DECL_INIT_UNEXPECTED_TOKEN |
A declaration initializer has mismatched delimiters. | VAR x : ARRAY[1..2] OF INT := [1, 2); END_VAR |
SCL_PARSE_EXPECTED_TOKEN |
A required punctuation token is missing. | VAR x INT; END_VAR |
SCL_PARSE_EXPECTED_KEYWORD |
A required keyword is missing. | FUNCTION_BLOCK FB VAR x : INT; END_VAR |
SCL_PARSE_EXPECTED_IDENTIFIER |
A declaration or construct expected an identifier. | FUNCTION_BLOCK ; END_FUNCTION_BLOCK |
SCL_PARSE_UNEXPECTED_TOKEN |
A token appears where the parser recovery set does not allow it. | FUNCTION_BLOCK FB BEGIN ; END_FUNCTION_BLOCK |
SCL_PARSE_TITLE_SEPARATOR |
A TITLE header line has no : or = after TITLE. |
TITLE Block name on the line after FUNCTION_BLOCK Demo. |
SCL_PARSE_BLOCK_STORAGE_ATTRIBUTE |
S7_BlockNumber, S7_Optimized or S7_Optimized_Access has an invalid value or conflicts with an earlier setting on the same block. |
DATA_BLOCK D { S7_Optimized := "sometimes" } BEGIN END_DATA_BLOCK |
SCL_EXPR_TRAILING_TOKEN |
Expression parsing finished but extra tokens remained. | #Value := 1 2; |
SCL Type Definitions
| Code | Meaning | Minimal trigger example |
|---|---|---|
SCL_TYPEDEF_EXPECTED_DECL_SEMICOLON |
A type declaration is not terminated with ;. |
TYPE T : INT T2 : INT; END_TYPE |
SCL_TYPEDEF_UNTERMINATED_TYPE_SECTION |
A TYPE section is missing END_TYPE. |
TYPE T : INT; |
SCL_TYPEDEF_EXPECTED_TYPE_REF |
A type alias, field, or array element is missing its referenced type. | TYPE T : ; END_TYPE |
SCL_TYPEDEF_EXPECTED_FIELD_COLON |
A STRUCT field is missing : after its name. |
TYPE T : STRUCT Field INT; END_STRUCT; END_TYPE |
SCL_TYPEDEF_EXPECTED_FIELD_SEMICOLON |
A STRUCT field declaration is missing ;. |
TYPE T : STRUCT Field : INT Next : INT; END_STRUCT; END_TYPE |
SCL_TYPEDEF_UNTERMINATED_STRUCT |
A STRUCT declaration is missing END_STRUCT. |
TYPE T : STRUCT Field : INT; END_TYPE |
SCL_TYPEDEF_ARRAY_BOUNDS_UNTERMINATED |
An ARRAY[ bounds list is missing ]. |
TYPE T : ARRAY[1..10 OF INT; END_TYPE |
SCL_TYPEDEF_ARRAY_EXPECT_OF |
An array type is missing OF. |
TYPE T : ARRAY[1..10] INT; END_TYPE |
SCL Semantic Checks
| Code | Meaning | Minimal trigger example |
|---|---|---|
SCL_SEM_AT_UNDECLARED_TARGET |
A symbolic AT target does not exist. |
VAR_TEMP Overlay AT Missing.Target : BOOL; END_VAR |
SCL_SEM_AT_INVALID_TARGET_PATH |
A symbolic AT target exists but the member path is invalid. |
VAR_TEMP Base : STRUCT Ok : BOOL; END_STRUCT; Overlay AT Base.Missing : BOOL; END_VAR |
SCL_SEM_AT_READ_ONLY_TARGET |
An AT overlay targets a project constant instead of writable storage. |
VAR_TEMP Overlay AT AXIS_COUNT : DINT; END_VAR |
SCL_SEM_ASSIGN_UNDECLARED_TARGET |
An assignment writes to an undeclared target. | Missing := 1; |
SCL_SEM_ASSIGN_READ_ONLY_TARGET |
An assignment or FOR control variable tries to write to a project constant. |
AXIS_COUNT := 4; |
SCL_SEM_INVALID_DESIGNATOR_PATH |
A designator path references a member or index that cannot exist. | #StructValue.Missing := 1; |
SCL_SEM_ABSOLUTE_ADDRESS |
An absolute address is malformed or not supported. | #Flag := %DB1.DBX0.8; |
SCL_SEM_DB_OPTIMIZED |
An absolute DB operand such as %DB7.DBX0.0 or P#DB7.DBX0.0 refers to a DB with optimized access. |
#q := %DB7.DBX0.0; with DATA_BLOCK D { S7_BlockNumber := 7; S7_Optimized := TRUE } |
SCL_SEM_DB_AMBIGUOUS |
An absolute DB operand refers to a DB number that more than one DB in the PLC declares. | %DB7.DBX0.0 when two data blocks both declare S7_BlockNumber := 7. |
SCL_SEM_DB_UNVERIFIED |
Warns that an absolute DB operand refers to a DB whose block number or access mode the PLC sources do not declare. | %DB7.DBX0.0 with DATA_BLOCK D { S7_BlockNumber := 7 } and no S7_Optimized setting. |
SCL_SEM_REFERENCE_UNDECLARED_LOCAL |
An expression references an undeclared local symbol. | #Out := #Missing; |
SCL_SEM_ARRAY_INDEX_COUNT |
An array is indexed with the wrong number of dimensions. | #Arr[1, 2] := 0; |
SCL_SEM_ARRAY_INDEX_TYPE |
An array index is not integer-compatible. | #Arr[TRUE] := 0; |
SCL_SEM_ARRAY_INDEX_BOUNDS |
A constant array index is outside the declared bounds. | #Arr[99] := 0; |
SCL_SEM_ASSIGN_PRECISION_LOSS |
An assignment is allowed but may lose sign or precision. | #SmallInt := #RealValue; |
SCL_SEM_ASSIGN_TYPE |
An assignment is not type-compatible. | #RealValue := T#1s; |
SCL_SEM_INVALID_TIME_LITERAL |
A T#/TIME# literal does not parse (e.g. a us/ns component) or is outside the TIME range. |
#t := T#25d; |
SCL_SEM_INVALID_LTIME_LITERAL |
An LT#/LTIME# literal does not parse or is outside the signed 64-bit nanosecond range. |
#lt := LT#106751d23h47m16s854ms775us808ns; |
SCL_SEM_INSTANCE_METHOD_MISMATCH |
A timer/counter instruction is called on an intrinsic instance that does not provide it. | #C.CTD(...) with C : CTU_INT |
SCL_SEM_DURATION_ARITHMETIC |
TIME/LTIME arithmetic outside the TIA operand table (e.g. duration * duration, integer - duration, TIME + LINT). | #t := #t * T#2s; |
SCL_SEM_INVALID_DTL_LITERAL |
A DTL#... literal has an invalid calendar date, time, fraction, or supported range. |
#Stamp := DTL#2002-02-29-00:00:00; |
SCL_SEM_INVALID_S5TIME_LITERAL |
An S5T#/S5TIME# literal does not parse, is negative, or exceeds 2h46m30s. |
#Preset := S5TIME#3h; |
SCL_SEM_INVALID_BYTE_LITERAL |
A B#/BYTE# literal does not parse or does not fit in 8 bits. |
#b := BYTE#256; |
SCL_SEM_INVALID_WORD_LITERAL |
A W#/WORD# literal does not parse or does not fit in 16 bits. |
#w := W#16#1_0000; |
SCL_SEM_INVALID_DWORD_LITERAL |
A DW#/DWORD# literal does not parse or does not fit in 32 bits. |
#d := DW#16#1_0000_0000; |
SCL_SEM_INVALID_LWORD_LITERAL |
An LW#/LWORD# literal does not parse or does not fit in 64 bits. |
#lw := LWORD#18446744073709551616; |
SCL_SEM_INVALID_POINTER_LITERAL |
A P# pointer literal is malformed or out of range. |
#p := P#M0.8; |
SCL_SEM_CALL_STATEMENT_ONLY |
A memory-write, bit packing or block transfer instruction is used as an expression, but these instructions return no value. | #word := GATHER(IN := #bits, OUT => #word); |
SCL_SEM_LIMIT_UNSUPPORTED |
A typed LIMIT_<type> call has the wrong inputs or an input type the runtime cannot adapt. |
#i := LIMIT_INT(0, #r, 10); where #r is REAL. |
SCL_SEM_NUMERIC_INSTRUCTION_UNSUPPORTED |
A numeric instruction such as MIN, SEL, MUX, ABS, SQRT or ROUND has malformed inputs or operand types it does not support. |
#u := ABS(#u); where #u is UINT. |
SCL_SEM_SHL_UNSUPPORTED |
A SHL call has malformed inputs, an IN that is not an integer or bit string, or an N count the runtime cannot convert. |
#w := SHL(TRUE, 1); |
SCL_SEM_SHR_UNSUPPORTED |
A SHR call fails the same checks as SCL_SEM_SHL_UNSUPPORTED. |
#w := SHR(IN := #w); |
SCL Call-Site Checks
| Code | Meaning | Minimal trigger example |
|---|---|---|
SCL_CALL_UNKNOWN_PIN |
A named call argument does not match a pin on the target FB or FC. | #Motor(NotAPin := TRUE); |
SCL_CALL_PIN_DIR_MISMATCH |
A named call argument uses := or => against the wrong pin direction. |
#Motor(Done := TRUE); |
SCL_CALL_PIN_TYPE |
A named call argument has a type that cannot be assigned to or from the pin. | #Motor(Start := 1.5); |
SCL_CALL_INVALID_PIN |
A call mixes positional and named arguments, omits a required native input, or uses an association the callee does not support, such as EN/ENO on a native instruction. |
#Motor(TRUE, Stop := FALSE); |
SCL_CALL_DUPLICATE_PIN |
A call assigns the same pin more than once. | #Motor(Start := TRUE, Start := FALSE); |
SCL_CALL_PIN_TARGET |
An output or in-out pin is connected to something that is not writable storage, or to an absolute address where the instruction needs symbolic storage. | #Motor(Done => 1); |
SCL_DUPLICATE_INSTANCE_CALL |
The same stateful FB instance is called more than once in one block. | #Timer(IN := TRUE); #Timer(IN := FALSE); |
PLC Tag Tables
| Code | Meaning | Minimal trigger example |
|---|---|---|
TAGTABLE_DUPLICATE_TAG_NAME |
Two XML tag-table rows use the same tag name. | <Member Name="Start" /><Member Name="Start" /> |
TAGTABLE_DUPLICATE_GLOBAL_NAME |
Tags or project constants in one XML table reuse the same global name. | A tag and project constant are both named HAND. |
TAGTABLE_TYPE_UNDEFINED |
A tag or project constant references a datatype not known in the PLC scope. | A project constant uses MissingType. |
TAGTABLE_GLOBAL_NAME_CONFLICT |
A tag or project constant conflicts with a global declaration in another file. | HAND is declared in both Default tag table.xml and CONSTANTS.xml. |
Project Library Resolution
| Code | Meaning | Minimal trigger example |
|---|---|---|
PLCLIB_LINK_PARSE |
A .liblink placeholder cannot be parsed. |
Program blocks/Library/Foo.liblink contains malformed metadata. |
PLCLIB_MISSING_TYPES_ROOT |
A .plc.json library path points to a missing or non-directory types root. |
.plc.json contains "libraries": ["../missing-types"]. |
PLCLIB_TYPE_GUID_NOT_FOUND |
A .liblink references a type GUID that no discovered .libinfo provides. |
A copied .liblink points to a library version that is not present under the configured Types root. |
PLCLIB_VERSION_GUID_AMBIGUOUS |
The type GUID exists, but the requested version cannot be selected unambiguously. | Two .libinfo files share the same type GUID but do not match the .liblink version GUID. |
PLCLIB_METADATA_PARSE |
A .libinfo or .libint sidecar cannot be parsed. |
Types/Library/Foo.libinfo contains malformed metadata. |
PLCLIB_SOURCE_MISSING |
Library metadata resolves, but the expected source file is missing. | Foo.libint lists Foo.scl, but Foo.scl is not present next to the sidecar files. |
S7RES And S7DCL Resource Links
| Code | Meaning | Minimal trigger example |
|---|---|---|
S7RES_MISSING_DCL |
A .s7res file has no same-basename .s7dcl sibling. |
Motor.s7res exists, but Motor.s7dcl does not. |
S7RES_DCL_DUPLICATE_REFS |
The sibling .s7dcl references the same resource ID more than once. |
Motor.s7dcl contains two S7_NetworkTitle := "N01" assignments. |
S7RES_COUNT_MISMATCH |
The number of .s7res entries does not match unique .s7dcl references. |
.s7res has N01 and N02, but .s7dcl only references N01. |
S7RES_ID_NOT_REFERENCED |
An .s7res ID is not referenced by the sibling .s7dcl. |
.s7res contains - id: N99, but .s7dcl never references N99. |
S7RES_MISSING_ID |
A .s7dcl resource ID reference has no .s7res entry. |
.s7dcl references S7_NetworkTitle := "N02" while .s7res only defines N01. |
S7DCL_MISSING_ID |
A .s7dcl resource ID reference is missing from an existing sibling .s7res. |
Motor.s7dcl references S7_NetworkComment := "C01" while Motor.s7res lacks C01. |
S7RES_EMPTY_ID |
A MultiLingualTexts entry has an empty id. |
- id: |
S7RES_BAD_ID |
A resource ID is suspicious and not a simple alphanumeric identifier. | - id: N-01 |
S7RES_MISSING_HEADER |
A .s7res file lacks the expected MultiLingualTexts: header. |
.s7res starts directly with - id: N01. |
S7RES_EMPTY |
A .s7res file has the header but no entries. |
MultiLingualTexts: with no - id: rows. |
S7DCL Network Inventory
| Code | Meaning | Minimal trigger example |
|---|---|---|
S7DCL_NETWORK_LANGUAGE_UNKNOWN |
A NETWORK declares an unsupported explicit S7_Language. |
{ S7_Language := "GRAPH" } NETWORK END_NETWORK |
S7DCL Embedded SCL Networks
| Code | Meaning | Minimal trigger example |
|---|---|---|
S7DCL_SCL_META_UNTERMINATED |
Metadata before an SCL NETWORK has an unterminated {...} block. |
{ S7_Language := "SCL" NETWORK |
S7DCL_SCL_UNTERMINATED_NETWORK |
An SCL NETWORK is missing END_NETWORK. |
{ S7_Language := "SCL" } NETWORK #x := TRUE; |
S7DCL_SCL_NETWORK_PARSE |
Fallback for an embedded SCL parser diagnostic that did not include a specific code. | { S7_Language := "SCL" } NETWORK malformed SCL END_NETWORK |
S7DCL_SCL_NETWORK_<SCL code> |
Embedded SCL lexer/parser diagnostics are downgraded to warnings and prefixed with S7DCL_SCL_NETWORK_. |
Missing ; inside an SCL NETWORK can produce S7DCL_SCL_NETWORK_SCL_PARSE_EXPECTED_TOKEN. |
S7DCL FBD Network Syntax
Examples in this section assume an .s7dcl FBD network body, for example { S7_Language := "FBD" } NETWORK ... END_NETWORK.
| Code | Meaning | Minimal trigger example |
|---|---|---|
S7DCL_FBD_META_UNTERMINATED |
Metadata before or inside an FBD network has an unterminated {...} block. |
{ S7_Language := "FBD" NETWORK |
S7DCL_FBD_EXPECT_NETWORK |
The FBD parser was asked to parse a section that does not start with NETWORK. |
FBD metadata is followed by RUNG TRUE instead of NETWORK. |
S7DCL_FBD_UNTERMINATED_NETWORK |
An FBD NETWORK is missing END_NETWORK. |
NETWORK RUNG TRUE END_RUNG |
S7DCL_FBD_DUP_WIRE_PRODUCER |
Two rungs produce the same wire. | END_RUNG wire#w1 appears on two rungs. |
S7DCL_FBD_UNEXPECTED |
The FBD network contains a token other than RUNG or END_NETWORK. |
NETWORK BOX END_NETWORK |
S7DCL_FBD_EXPECT_RUNG |
The FBD rung parser was asked to parse a section that does not start with RUNG. |
NETWORK A(in2 := #Start) END_NETWORK |
S7DCL_FBD_UNTERMINATED_RUNG |
An FBD RUNG is missing END_RUNG. |
NETWORK RUNG TRUE A(in2 := #Start) END_NETWORK |
S7DCL_FBD_EXPECT_LPAREN |
An FBD element or pin list is missing (. |
RUNG TRUE A in2 := #Start) END_RUNG |
S7DCL_FBD_UNTERMINATED_EXPR |
An FBD element, coil, or pin expression is missing a closing delimiter. | RUNG TRUE Coil(#Out END_RUNG |
S7DCL_FBD_UNTERMINATED_PINLIST |
A call or boolean operator pin list is not closed. | RUNG TRUE A(in2 := #Start END_RUNG |
S7DCL_FBD_EXPECT_PIN |
A pin list entry does not start with a valid pin name. | RUNG TRUE A(1 := #Start) END_RUNG |
S7DCL_FBD_EXPECT_PIN_OP |
A pin name is not followed by := or =>. |
RUNG TRUE A(in2 #Start) END_RUNG |
S7DCL_FBD_BOOL_OP_MISSING_OUTPUT_CONNECTOR |
A boolean operator is missing a valid left-side BOOL connector. | RUNG A(in2 := #Start) A(in2 := #Other) END_RUNG |
S7DCL_FBD_COMPARE_CONTACT_AFTER_BOOL |
A comparison contact follows an existing Boolean element in the same rung, a shape TIA may compile but cannot reopen graphically. | RUNG #Enable EQ_Contact(in1 := #Value, in2 := 1) END_RUNG |
S7DCL_FBD_CHAINED_COMPARE_CONTACT |
Multiple comparison contacts appear in series in one rung, a shape TIA cannot reopen graphically. | RUNG GT_Contact(...) LT_Contact(...) END_RUNG |
S7DCL_FBD_PIN_INLINE_BOOL_EXPR |
An FBD input pin contains a compound expression instead of a connected instruction block. | RUNG TRUE MyFB(in1 := #Count > 0) END_RUNG |
S7DCL_FBD_PIN_COMMENT |
A line or block comment in an FBD pin, between the pin name and the end of its expression. TIA rejects comments anywhere in a rung on import; each pin is reported once. | RUNG TRUE MyFB(in1 := (* why *) #Start) END_RUNG |
S7DCL_FBD_RUNG_COMMENT |
A line or block comment between NETWORK and END_NETWORK in an FBD network, outside a pin (S7DCL_FBD_PIN_COMMENT covers those): in a rung, between rungs, or on the NETWORK or END_RUNG line. TIA rejects these on import; comments outside NETWORK ... END_NETWORK are fine. |
RUNG TRUE (* why *) Coil(#Out) END_RUNG |
S7DCL_FBD_META_MULTIPLE |
An FBD element has more than one metadata block in front of it. TIA rejects that on import even when each block is valid, so merge them into one block that lists each attribute once (TIA also rejects an attribute given twice). | { S7_GenerateENO := "TRUE" } { S7_Templates := "time_type := Time" } #t.TON(PT := T#5s) |
S7DCL_FBD_PIN_PARENTHESIZED_NOT |
An FBD pin inverts its operand with NOT (...); exported FBD pins spell inversion as NOT #operand without parentheses. |
RUNG TRUE MyFB(in1 := NOT (#Start)) END_RUNG |
S7DCL_FBD_RUNG_HEADER_NOT |
An FBD rung starts with a negated operand. TIA's import requires an instruction or call after NOT, so negate the first element instead. |
RUNG NOT #Start Coil(#Out) END_RUNG |
S7DCL_FBD_CALL_WIRE_PRODUCER_BEFORE_CONSUMER |
A call consumes a wire whose producer rung appears before the consuming call. | First rung produces wire#w1; later call uses in1 := wire#w1. |
S7DCL_FBD_ALTERNATIVE_PATH |
Branches from one graphical source rejoin at different inputs of the same call or Boolean operator. | An AND output feeds both REQ := wire#w1 and PERMIT := wire#w1 on one call, directly or through further Boolean boxes. |
S7DCL_FBD_WIRE_NO_PRODUCER |
A wire is consumed but no rung produces it. | RUNG TRUE MyFB(in1 := wire#w9) END_RUNG |
S7DCL FBD Semantic Checks
LAD networks run the same checks where they apply and report them with the S7DCL_LAD_ prefix, for example S7DCL_LAD_SEM_PIN_TARGET or S7DCL_LAD_DUPLICATE_INSTANCE_CALL.
| Code | Meaning | Minimal trigger example |
|---|---|---|
S7DCL_FBD_DUPLICATE_INSTANCE_CALL |
The same stateful FB instance is called more than once in one block. | Two FBD elements call #Timer(...) in the same enclosing block. |
S7DCL_FBD_SEM_PIN_UNKNOWN |
An FBD call uses a pin that is not defined by the resolved FB/FC interface. | PID_Compact(NotAPin := TRUE) |
S7DCL_FBD_SEM_PIN_DIR_MISMATCH |
An FBD call uses := or => against the wrong resolved pin direction. |
PID_Compact(Output := #Out) |
S7DCL_FBD_SEM_PIN_NEGATION_INVALID |
A standalone NOT (an inverted, unconnected pin) is used on a pin that is not a BOOL input. |
MyFB(Count := NOT) where Count is INT. |
S7DCL_FBD_SEM_PIN_MISSING |
An FBD call omits a required pin from the resolved FB/FC interface. | PID_Compact(Setpoint := #SP) with other required pins omitted. |
S7DCL_FBD_SEM_PIN_INPUT_TYPE |
An input pin receives an incompatible expression type. | MyFB(IntPin := TRUE) where IntPin expects INT. |
S7DCL_FBD_SEM_PIN_OUTPUT_TYPE |
An output pin writes to a target with an incompatible type. | MyFB(Done => #Counter) where Done is BOOL and #Counter is INT. |
S7DCL_FBD_SEM_PIN_TARGET |
An FBD output or in-out pin is connected to an expression without writable storage. | MyFC(Result => 1) or MyFC(State := #A + #B) for an in-out State. |
S7DCL_FBD_SEM_UNRESOLVED_CALL |
A dotted FBD call cannot be resolved enough for pin validation. | #Unknown.Nested(in1 := TRUE) |
S7DCL_FBD_SEM_RUNG_HEADER_TYPE |
A rung header expression is not BOOL. |
RUNG #Counter where #Counter is INT. |
S7DCL_FBD_SEM_INVALID_PATH |
A local or quoted designator path has an invalid member or index. | Coil(#StructValue.Missing) |
S7DCL_FBD_SEM_UNDECLARED_LOCAL |
An FBD expression references an undeclared local. | Coil(#MissingLocal) |
S7DCL_FBD_SEM_COIL_TARGET_TYPE |
A coil or S_SR operand target is not BOOL. |
Coil(#Counter) where #Counter is INT. |
S7DCL_FBD_SEM_EDGE_MEMORY_TYPE |
The edge memory operand of P_Trig or N_Trig is not BOOL. |
P_Trig(#Counter) where #Counter is INT. |
S7DCL_FBD_SEM_BOOL_OP_ARG_TYPE |
A boolean operator has a bad input pin name or non-BOOL input type. | A(in1 := #Start) or A(in2 := #Counter) |
S7DCL_FBD_SEM_BUILTIN_PIN_UNKNOWN |
A builtin FBD call uses a pin name that the builtin does not define. | TON(BadPin := TRUE) |
S7DCL_FBD_SEM_BUILTIN_PIN_TYPE |
A builtin FBD pin has the wrong direction or type. | TON(IN => #Start) or TON(PT := TRUE) |
S7DCL_FBD_SEM_BUILTIN_OPERAND_TARGET |
S_SR uses an operand that is not an assignable designator. |
S_SR(operand := TRUE) |
S7DCL FBD Transpile Diagnostics
| Code | Meaning | Minimal trigger example |
|---|---|---|
S7DCL_FBD_TX_BLOCK_MAPPING |
Transpiling one .s7dcl file produces more than one SCL block output name. |
A single .s7dcl file declares two blocks. |
S7DCL_FBD_TX_EMPTY_NETWORK |
An FBD network has no emitted statements. | NETWORK RUNG TRUE END_RUNG END_NETWORK |
S7DCL_FBD_TX_EXPR_FALLBACK |
The FBD-to-SCL transpiler cannot parse an expression and emits a fallback. | MyFB(in1 := #A + ) |
S7DCL_FBD_TX_WIRE_CYCLE_FIXED_POINT |
Wires exported with END_RUNG wire#... feed each other in a cycle, so the transpiler emits a bounded fixed-point loop. |
RUNG wire#w2 END_RUNG wire#w1 and RUNG wire#w1 Coil(#out1) END_RUNG wire#w2 |
S7DCL_FBD_TX_WIRE_CYCLE |
Wires in a network with boxes, calls with wire outputs or inline wires depend on each other in a cycle, so the network has no execution order. | RUNG wire#w1 #c.CTU(pv := 2) END_RUNG wire#w1 |
S7DCL_FBD_TX_UNDRIVEN_WIRE |
A network with boxes, calls with wire outputs or inline wires reads a wire that nothing in the network writes. | RUNG wire#w1 #c.CTU(pv := 2) END_RUNG with no producer of wire#w1. |
S7DCL_FBD_TX_TIMER_INSTANCE_UNRESOLVED |
A TONR call does not resolve to a TONR_TIME or IEC_TIMER instance. |
#t.TONR(IN := #Start, PT := T#5s) where #t is undeclared or a TON_TIME. |
S7DCL_FBD_TX_COUNTER_INSTANCE_UNRESOLVED |
The instance type of a dotted counter call cannot be resolved. | #c.CTU(pv := 2) where #c is undeclared. |
S7DCL LAD Network Syntax
Examples in this section assume an .s7dcl LAD network body, for example { S7_Language := "LAD" } NETWORK ... END_NETWORK.
| Code | Meaning | Minimal trigger example |
|---|---|---|
S7DCL_LAD_META_UNTERMINATED |
Metadata before or inside a LAD network has an unterminated {...} block. |
{ S7_Language := "LAD" NETWORK |
S7DCL_LAD_EXPECT_NETWORK |
The LAD parser was asked to parse a section that does not start with NETWORK. |
LAD metadata is followed by RUNG instead of NETWORK. |
S7DCL_LAD_UNTERMINATED_NETWORK |
A LAD NETWORK is missing END_NETWORK. |
NETWORK RUNG TRUE END_RUNG |
S7DCL_LAD_UNEXPECTED |
The LAD network contains a token other than RUNG or END_NETWORK. |
NETWORK Contact(#Start) END_NETWORK |
S7DCL_LAD_EXPECT_RUNG |
The LAD rung parser was asked to parse a section that does not start with RUNG. |
NETWORK WIRE w1 END_NETWORK |
S7DCL_LAD_UNTERMINATED_RUNG |
A LAD RUNG is missing END_RUNG. |
NETWORK RUNG Contact(#Start) END_NETWORK |
S7DCL_LAD_EXPECT_WIRE_ID |
A WIRE token is missing its wire ID. |
RUNG WIRE END_RUNG |
S7DCL_LAD_EXPECT_LPAREN |
A LAD element is missing ( after its name. |
RUNG Contact #Start) END_RUNG |
S7DCL_LAD_UNTERMINATED_EXPR |
A LAD element expression is missing ). |
RUNG Contact(#Start END_RUNG |
S7DCL_LAD_RUNG_COMMENT |
A line or block comment between NETWORK and END_NETWORK in a LAD network: in a rung, between rungs, or on the NETWORK or END_RUNG line. TIA rejects these on import; comments outside NETWORK ... END_NETWORK are fine. |
RUNG wire#powerrail (* why *) Coil(#Out) END_RUNG |
S7DCL_LAD_META_MULTIPLE |
A LAD element has more than one metadata block in front of it. TIA rejects that on import even when each block is valid, so merge them into one block that lists each attribute once (TIA also rejects an attribute given twice). | { S7_GenerateENO := "TRUE" } { S7_Templates := "time_type := Time" } TON_Coil(timer => #t, pt := T#5s) |
S7DCL LAD Semantic Checks
LAD networks also report the checks listed under S7DCL FBD Semantic Checks, with the S7DCL_LAD_ prefix.
| Code | Meaning | Minimal trigger example |
|---|---|---|
S7DCL_LAD_SEM_CONTACT_TYPE |
A contact operand is neither BOOL nor a legacy TIMER. |
Contact(#Counter) where #Counter is INT. |
S7DCL_LAD_SEM_EDGE_INPUT_TYPE |
The operand input of a P_Contact or N_Contact combines non-Boolean operands. |
P_Contact(operand := #Flag AND #Counter, bit := #Mem) where #Counter is INT. |
S7DCL LAD Transpile Diagnostics
| Code | Meaning | Minimal trigger example |
|---|---|---|
S7DCL_LAD_TX_BLOCK_MAPPING |
Transpiling one .s7dcl file produces more than one SCL block output name. |
A single .s7dcl file declares two blocks. |
S7DCL_LAD_TX_EMPTY_NETWORK |
A LAD network has no emitted statements. | NETWORK RUNG TRUE END_RUNG END_NETWORK |
S7DCL_LAD_TX_EXPR_FALLBACK |
The LAD-to-SCL transpiler cannot parse an expression and emits a fallback. | Contact(#A + ) |
S7DCL_LAD_TX_WIRE_CYCLE |
LAD wires depend on each other in a cycle, so the network has no execution order. | RUNG wire#w1 P_Trig(#Mem) END_RUNG wire#w1 |
S7DCL_LAD_TX_UNDRIVEN_WIRE |
A rung reads a wire that nothing in the network writes. | RUNG wire#w1 P_Trig(#Mem) END_RUNG with no producer of wire#w1. |
S7DCL_LAD_TX_COMPARISON_OPERANDS |
A comparison contact is missing IN1 or IN2. |
EQ_Contact(in1 := #a) |
S7DCL_LAD_TX_TIMER_INSTANCE_UNRESOLVED |
A TONR call does not resolve to a TONR_TIME or IEC_TIMER instance. |
#t.TONR(IN := #Start, PT := T#5s) where #t is undeclared or a TON_TIME. |
S7DCL_LAD_TX_COUNTER_INSTANCE_UNRESOLVED |
The instance type of a dotted counter call cannot be resolved. | #c.CTU(pv := 2) where #c is undeclared. |
S7DCL_LAD_TX_TIMER_RESET_OPERAND |
An RT_Coil operand is not a single IEC timer instance, the coil is negated, or a project declaration shadows RESET_TIMER. |
RT_Coil(#Counter) where #Counter is INT. |
S7DCL_LAD_TX_<instruction>_OPERAND |
A legacy timer coil or box has an unsupported, duplicate or negated pin, or an operand of the wrong kind. <instruction> is the element name: SD_COIL, SE_COIL, SD, SS or SF. IEC timer coils report S7DCL_<lang>_TX_<coil>_OPERAND. |
SD_Coil(Q => #Done) reports S7DCL_LAD_TX_SD_COIL_OPERAND. |
S7DCL_LAD_TX_LABEL_INVALID |
A LAD network has more than one Label, a Label after its rungs, or a label that is not an identifier. |
NETWORK Label(a) Label(b) END_NETWORK |
S7DCL_LAD_TX_LABEL_DUPLICATE |
Two networks in one block use the same label, ignoring case. | Label(END) in one network and Label(end) in another. |
S7DCL_LAD_TX_JUMP_TARGET_INVALID |
A JumpCoil target is missing or is not a plain label identifier. |
JumpCoil(#a) |
S7DCL_LAD_TX_JUMP_TARGET_UNKNOWN |
A jump target is not a label in the same block. | JumpCoil(missing) |
S7DCL_LAD_TX_JUMP_PLACEMENT |
A network has more than one jump, a jump is not the last element of its rung, is negated or has an output wire, or an I_JumpCoil has no preceding logic. |
RUNG wire#powerrail JumpCoil(a) Coil(#q) END_RUNG |
S7DCL_LAD_TX_SWITCH_PLACEMENT |
A network has more than one Switch jump distributor, or the Switch does not end the network's last rung. |
A Switch(...) followed by Coil(#q). |
S7DCL_LAD_TX_SWITCH_<code> |
A Switch jump distributor is malformed. <code> is PINS, TARGET_INVALID, TARGET_UNKNOWN, TYPE_UNSUPPORTED or COMPARISON. |
Switch(k := 1, case0 := 1, dst0 => missing) with no Label(missing) in the block reports S7DCL_LAD_TX_SWITCH_TARGET_UNKNOWN. |
S7DCL_LAD_TX_FLOW_LOOP_CONTROL |
A block with LAD jumps has EXIT or CONTINUE outside an SCL loop. |
A block with a JumpCoil also has an SCL network with a top-level EXIT;. |
S7DCL FBD And LAD Instruction Lowering
These codes come from lowering instruction boxes in FBD and LAD networks. <lang> is FBD or LAD, so the same check reports S7DCL_FBD_TX_CONVERT_PINS in an FBD network and S7DCL_LAD_TX_CONVERT_PINS in a LAD network. Most families share these suffixes: TEMPLATE for an S7_Templates type the lowering does not take (a missing one is S7DCL_<lang>_TX_TEMPLATE_MISSING, one not in the form TIA exports S7DCL_<lang>_TX_TEMPLATE_SYNTAX, one that does not match the operands _TEMPLATE_MISMATCH or _TEMPLATE_CONVERSION), UNSUPPORTED for a type that is not implemented, PINS for missing, duplicate, unknown, misdirected or unwritable pins, and OPERAND_TYPE for an operand that does not match the instruction type.
| Code | Meaning | Minimal trigger example |
|---|---|---|
S7DCL_<lang>_TX_CONVERT_<code> |
A Convert box cannot be lowered. <code> is UNSUPPORTED, PINS or OPERAND_TYPE. UNSUPPORTED also covers pairs with a bit string other than DWord/Real and LWord/LReal, which TIA does not compile; for a bit string with an integer or another bit string, and for Char with Byte, the message points to Move. |
Convert(IN := #value, OUT => #result) with { S7_Templates := "[SrcType := Int, DestType := Byte]" } reports S7DCL_FBD_TX_CONVERT_UNSUPPORTED. |
S7DCL_<lang>_TX_DIV_<code> |
A Div box with SrcType := DInt cannot be lowered. <code> is PINS or OPERAND_TYPE. |
Div(IN1 := #a, OUT => #q) with SrcType := DInt reports S7DCL_FBD_TX_DIV_PINS for the missing IN2. |
S7DCL_<lang>_TX_LIMIT_<code> |
A Limit box cannot be lowered. <code> is TEMPLATE, PINS or OPERAND_TYPE. |
Limit(MN := 0, IN := #v, OUT => #q) with value_type := Int reports S7DCL_FBD_TX_LIMIT_PINS for the missing MX. |
S7DCL_<lang>_TX_WORD_LOGIC_<code> |
A word AND or OR box cannot be lowered. <code> is TEMPLATE (a SrcType other than Byte, Word, DWord or LWord), PINS or OPERAND_TYPE. |
And(IN1 := #a, OUT => #q) with SrcType := Word reports S7DCL_FBD_TX_WORD_LOGIC_PINS for the missing IN2. |
S7DCL_<lang>_TX_<shift>_<code> |
A SHL or SHR box cannot be lowered. <shift> is SHL or SHR, and <code> is UNSUPPORTED (a SrcType other than a bit string or integer type), PINS or OPERAND_TYPE. |
SHL(IN := #v, N := 1, OUT => #q) with SrcType := Real reports S7DCL_FBD_TX_SHL_UNSUPPORTED. |
S7DCL_<lang>_TX_<op>_<code> |
An Add or Mul box evaluated as DInt or Real cannot be lowered. <op> is ADD or MUL, and <code> is PINS or OPERAND_TYPE. |
ADD(IN1 := TRUE, IN2 := 1, OUT => #Result) with SrcType := DInt reports S7DCL_FBD_TX_ADD_OPERAND_TYPE. |
S7DCL_<lang>_TX_MOVE_OPERAND_TYPE |
A MOVE box reads or writes a BOOL operand, which TIA does not compile ("Data type Bool is not permitted here."). |
MOVE(IN := FALSE, OUT1 => #flag) where #flag is BOOL. |
S7DCL_<lang>_TX_<op>_PINS |
A selection, math or rounding box has an invalid pin or no connected output, or a Mux or Demux box has no ELSE pin, which TIA's import requires (the pin may be blank, and TIA accepts it in either direction). <op> is the box name: SEL, MUX, DEMUX, MIN, MAX, MOD, ABS, SQR, SQRT, LN, EXP, FRAC, EXPT, ROUND, TRUNC, CEIL, FLOOR, NORMALIZE, SCALE_X or SCALE. |
MIN(IN1 := #a, IN2 := #b) with value_type := Int reports S7DCL_FBD_TX_MIN_PINS. |
S7DCL_<lang>_TX_INSTRUCTION_NAME |
A box uses a name that TIA's import does not accept as an instruction: a conversion function such as USINT_TO_REAL, INT_TO_BOOL or CHAR_TO_INT (the message names the Convert templates or Move where TIA compiles one of them for the pair and plccheck lowers it, and no replacement otherwise; neither takes Bool), Norm_X (use Normalize), or In_Range/Out_Range (use InRange/OutRange). A project block named Norm_X, In_Range or Out_Range is called as a block instead. TIA reads conversion names with a string or date/time side, such as INT_TO_STRING, as S_Conv and T_Conv, so they are not reported, except those with a Bool side (BOOL_TO_STRING, TIME_TO_BOOL) and WCHAR_TO_STRING, which TIA does not read that way. |
USINT_TO_REAL(IN := #small, OUT => #value) |
S7DCL_<lang>_TX_BIT_PACKING_TYPE |
The template type of a GATHER or SCATTER box is not BYTE, WORD, DWORD or LWORD, or does not match the packed operand. |
GATHER with dest_type := Word writes OUT to a DWORD. |
S7DCL_<lang>_TX_EDGE_OPERANDS |
An edge instruction has no single edge memory operand, or a P_Contact/N_Contact is missing its operand or bit pin. |
P_Trig(#a AND #b) |
S7DCL_<lang>_TX_LATCH_OPERANDS |
An S_SR or S_RS latch is missing operand or its second input, uses a non-designator operand, or has extra pins. |
S_RS(operand := #a) |
S7DCL_<lang>_TX_WIRE_OUTPUT_TYPE |
A call output pin of a type other than BOOL is connected to a wire. |
MyFB(Count => wire#w1) where Count is INT. |
S7DCL_<lang>_TX_TEMPLATE_MISSING |
A box has no S7_Templates value for a key TIA requires (or NotChosen or ???), so TIA asks to select a data type. SrcType on comparison contacts, InRange, OutRange, Mux, Demux, Abs, Neg, Sqr, Sqrt, Ln, Exp, Sin, Cos, Tan, Asin, Acos, Atan, Frac, And, Or, Xor, Inv, Shl, Shr, Rol, Ror and Swap; SrcType and DestType on Expt, Round, Trunc, Ceil, Floor, Convert, Normalize and Scale_X; value_type on Sel, Min, Max, Limit and CTU, CTD and CTUD instance calls. Add, Sub, Mul, Div and Mod need SrcType only when every input is an untyped literal; with a typed input TIA infers the type when there is no template or one that sets SrcType (even to NotChosen), and a template without SrcType is reported. Also reported for any key besides value_type on Min and Max. Counter calls in safety blocks are not checked. |
Abs(in := #r, out => #q) without { S7_Templates := "SrcType := Real" } before it. |
S7DCL_<lang>_TX_TEMPLATE_MISMATCH |
A box template does not match its operands, and TIA fails the compile: the SrcType of a comparison contact, InRange or OutRange that a typed input does not convert to without losing its sign or accuracy (Int for a UInt or Real input, Real for an LReal one), a SrcType or DestType of Convert, Round, Trunc, Ceil or Floor other than the type of a numeric IN or OUT (DInt for an Int input; a bit-string IN or OUT passes a SrcType or DestType of its width, Word for Int and DWord for Real), an integer SrcType of any of these with a real literal on its pins, which TIA reads as LReal (1.5 with SrcType := DInt), an integer SrcType of a comparison contact, InRange or OutRange too small for an integer literal on its pins (40000 with SrcType := Int), a Convert whose SrcType and DestType are the same Real, LReal, bit-string, Char or WChar type (TIA: "both data types are the same"; integer pairs compile), a value_type on a CTU, CTD or CTUD call that does not select the instance type (Int for CTU_INT and IEC_COUNTER), a Bool or bit-string SrcType on Add, Sub, Mul, Div or Mod (SrcType := Word), or a Real or LReal template on any box with an untyped integer literal on its pins, since TIA takes no integer literal on a Real pin (write 0.0). Other untyped literals and inputs of other or unknown types are not checked. |
EQ_Contact(in1 := #a, in2 := #b) with { S7_Templates := "SrcType := Int" } where #a is UInt. |
S7DCL_<lang>_TX_TEMPLATE_CONVERSION |
Warning. The SrcType of Abs, Add or Mux, or the value_type of Min, Max, Sel or Limit, does not take a typed input without losing its sign or accuracy. TIA compiles the box and converts the input to the template type. plccheck tests convert it too, except on Add with a SrcType other than DInt or Real. A Real or LReal template with an integer literal on its pins is _TEMPLATE_MISMATCH instead. |
Abs(in := #r, out => #q) with { S7_Templates := "SrcType := Int" } where #r is Real. |
S7DCL_<lang>_TX_TEMPLATE_SYNTAX |
An S7_Templates on any FBD or LAD element is not in the form TIA exports: "Key := Type" or "[Key := Type, Key := Type]", double-quoted and spaced exactly like that, each key once in TIA's case (time_type, not TIME_TYPE; SrcType, not srctype). plccheck is stricter than TIA, which accepts or repairs some other forms. |
{ S7_Templates := "time_type:=Time" } before #t.TON(PT := T#1s). |
S7DCL_<lang>_TX_<coil>_OPERAND |
An IEC timer coil has an unsupported, duplicate or negated pin, an operand of the wrong kind, a timer instance that does not resolve or is not an IEC timer type providing its instruction, or a negation: any in LAD, a postfix NOT in FBD (a prefix NOT inverts the timer's IN). <coil> is the element name: TP_COIL, TON_COIL, TOF_COIL, TONR_COIL or PT_COIL. |
TON_Coil(Q => #Done) reports S7DCL_FBD_TX_TON_COIL_OPERAND in FBD; the coil only has TIMER and PT pins (or OPERAND := and VALUE :=). |
S7DCL_<lang>_TX_TIMER_TEMPLATE |
A TP, TON, TOF or TONR call or TP_Coil, TON_Coil, TOF_Coil or TONR_Coil on an IEC timer instance has a time_type TIA rejects. On every CPU: an S7_Templates with other keys but no time_type, which fails the import of a call and the compile of a coil (other keys next to time_type are fine). On coils on every CPU, and on calls when .plc.json sets cpuFamily to S7-1500 or S7-1200 G2 outside safety blocks: no S7_Templates, time_type := NotChosen (or ???), or a time_type that does not match the instance: Time for IEC_TIMER and the _TIME types, LTime for IEC_LTIMER and the _LTIME types. |
#t.TON(PT := T#1s) on a TON_TIME instance without { S7_Templates := "time_type := Time" } before it. |
SCL Test Parser
| Code | Meaning | Minimal trigger example |
|---|---|---|
SCLTEST_PARSE_EXPECT_TEST_CASE |
The parser expected a TEST_CASE declaration. |
SET UUT.Start := TRUE; |
SCLTEST_PARSE_DUPLICATE_TARGET |
A file declares TEST_TARGET more than once. |
TEST_TARGET "FB1"; TEST_TARGET "FB2"; |
SCLTEST_PARSE_TARGET_ENTRY_CONFLICT |
TEST_TARGET is combined with TEST_ENTRY. |
TEST_TARGET "FB1"; TEST_ENTRY "OB1"; |
SCLTEST_PARSE_DUPLICATE_ENTRY |
A file declares TEST_ENTRY more than once. |
TEST_ENTRY "OB1"; TEST_ENTRY "OB2"; |
SCLTEST_PARSE_ENTRY_TARGET_CONFLICT |
TEST_ENTRY is combined with TEST_TARGET. |
TEST_ENTRY "OB1"; TEST_TARGET "FB1"; |
SCLTEST_PARSE_TARGET_EXPECT_SYMBOL |
TEST_TARGET is missing its target symbol. |
TEST_TARGET ; |
SCLTEST_PARSE_ENTRY_EXPECT_SYMBOL |
TEST_ENTRY is missing its entry symbol. |
TEST_ENTRY ; |
SCLTEST_PARSE_TARGET_EXPECT_SEMICOLON |
TEST_TARGET is missing ;. |
TEST_TARGET "FB1" |
SCLTEST_PARSE_ENTRY_EXPECT_SEMICOLON |
TEST_ENTRY is missing ;. |
TEST_ENTRY "OB1" |
SCLTEST_PARSE_TARGET_AFTER_CASE |
TEST_TARGET appears after a test case has started. |
TEST_CASE "A" END_TEST_CASE TEST_TARGET "FB1"; |
SCLTEST_PARSE_ENTRY_AFTER_CASE |
TEST_ENTRY appears after a test case has started. |
TEST_CASE "A" END_TEST_CASE TEST_ENTRY "OB1"; |
SCLTEST_PARSE_EXPECT_END_TEST_CASE |
A test case is missing END_TEST_CASE. |
TEST_CASE "A" SET UUT.Start := TRUE; |
SCLTEST_PARSE_EXPECT_CASE_NAME |
TEST_CASE is missing its name. |
TEST_CASE SET UUT.Start := TRUE; END_TEST_CASE |
SCLTEST_PARSE_UNKNOWN_STEP |
A test case contains an unknown step keyword. | TEST_CASE "A" POKE UUT.Start := TRUE; END_TEST_CASE |
SCLTEST_PARSE_SET_EXPECT_TARGET |
SET is missing the target expression. |
TEST_CASE "A" SET := TRUE; END_TEST_CASE |
SCLTEST_PARSE_SET_EXPECT_ASSIGN |
SET is missing :=. |
TEST_CASE "A" SET UUT.Start TRUE; END_TEST_CASE |
SCLTEST_PARSE_SET_EXPECT_VALUE |
SET is missing the value expression. |
TEST_CASE "A" SET UUT.Start := ; END_TEST_CASE |
SCLTEST_PARSE_SET_EXPECT_SEMICOLON |
SET is missing ;. |
TEST_CASE "A" SET UUT.Start := TRUE END_TEST_CASE |
SCLTEST_PARSE_HOLD_EXPECT_TARGET |
HOLD is missing the target expression. |
TEST_CASE "A" HOLD := TRUE; END_TEST_CASE |
SCLTEST_PARSE_HOLD_EXPECT_ASSIGN |
HOLD is missing :=. |
TEST_CASE "A" HOLD UUT.Start TRUE; END_TEST_CASE |
SCLTEST_PARSE_HOLD_EXPECT_VALUE |
HOLD is missing the value expression. |
TEST_CASE "A" HOLD UUT.Start := ; END_TEST_CASE |
SCLTEST_PARSE_HOLD_EXPECT_SEMICOLON |
HOLD is missing ;. |
TEST_CASE "A" HOLD UUT.Start := TRUE END_TEST_CASE |
SCLTEST_PARSE_RELEASE_EXPECT_TARGET |
RELEASE is missing the target expression. |
TEST_CASE "A" RELEASE ; END_TEST_CASE |
SCLTEST_PARSE_RELEASE_EXPECT_SEMICOLON |
RELEASE is missing ;. |
TEST_CASE "A" RELEASE UUT.Start END_TEST_CASE |
SCLTEST_PARSE_RELEASE_ALL_EXPECT_SEMICOLON |
RELEASE_ALL is missing ;. |
TEST_CASE "A" RELEASE_ALL END_TEST_CASE |
SCLTEST_PARSE_WAIT_CYCLES_EXPECT_COUNT |
WAIT_CYCLES is missing the count expression. |
TEST_CASE "A" WAIT_CYCLES ; END_TEST_CASE |
SCLTEST_PARSE_WAIT_CYCLES_EXPECT_SEMICOLON |
WAIT_CYCLES is missing ;. |
TEST_CASE "A" WAIT_CYCLES 1 END_TEST_CASE |
SCLTEST_PARSE_WAIT_TIME_EXPECT_DURATION |
WAIT_TIME is missing the duration expression. |
TEST_CASE "A" WAIT_TIME ; END_TEST_CASE |
SCLTEST_PARSE_WAIT_TIME_EXPECT_SEMICOLON |
WAIT_TIME is missing ;. |
TEST_CASE "A" WAIT_TIME T#1s END_TEST_CASE |
SCLTEST_PARSE_WAIT_UNTIL_EXPECT_LEFT |
WAIT_UNTIL is missing the left expression. |
TEST_CASE "A" WAIT_UNTIL = TRUE TIMEOUT T#1s; END_TEST_CASE |
SCLTEST_PARSE_WAIT_UNTIL_EXPECT_OPERATOR |
WAIT_UNTIL is missing its comparison operator. |
TEST_CASE "A" WAIT_UNTIL UUT.Done TRUE TIMEOUT T#1s; END_TEST_CASE |
SCLTEST_PARSE_WAIT_UNTIL_EXPECT_RIGHT |
WAIT_UNTIL is missing the right expression. |
TEST_CASE "A" WAIT_UNTIL UUT.Done = TIMEOUT T#1s; END_TEST_CASE |
SCLTEST_PARSE_WAIT_UNTIL_EXPECT_TIMEOUT |
WAIT_UNTIL is missing the TIMEOUT keyword. |
TEST_CASE "A" WAIT_UNTIL UUT.Done = TRUE T#1s; END_TEST_CASE |
SCLTEST_PARSE_WAIT_UNTIL_EXPECT_TIMEOUT_DURATION |
WAIT_UNTIL TIMEOUT is missing the duration expression. |
TEST_CASE "A" WAIT_UNTIL UUT.Done = TRUE TIMEOUT ; END_TEST_CASE |
SCLTEST_PARSE_WAIT_UNTIL_EXPECT_SEMICOLON |
WAIT_UNTIL is missing ;. |
TEST_CASE "A" WAIT_UNTIL UUT.Done = TRUE TIMEOUT T#1s END_TEST_CASE |
SCLTEST_PARSE_ASSERT_EXPECT_EXPR |
ASSERT is missing its boolean expression. |
TEST_CASE "A" ASSERT ; END_TEST_CASE |
SCLTEST_PARSE_ASSERT_EXPECT_SEMICOLON |
ASSERT is missing ;. |
TEST_CASE "A" ASSERT UUT.Done = TRUE END_TEST_CASE |
SCLTEST_PARSE_ASSERT_NEAR_EXPECT_LEFT |
ASSERT_NEAR is missing its actual expression. |
TEST_CASE "A" ASSERT_NEAR := 1 TOLERANCE 0.1; END_TEST_CASE |
SCLTEST_PARSE_ASSERT_NEAR_EXPECT_ASSIGN |
ASSERT_NEAR is missing :=. |
TEST_CASE "A" ASSERT_NEAR UUT.Value 1 TOLERANCE 0.1; END_TEST_CASE |
SCLTEST_PARSE_ASSERT_NEAR_EXPECT_RIGHT |
ASSERT_NEAR is missing its expected expression. |
TEST_CASE "A" ASSERT_NEAR UUT.Value := TOLERANCE 0.1; END_TEST_CASE |
SCLTEST_PARSE_ASSERT_NEAR_EXPECT_TOLERANCE |
ASSERT_NEAR is missing TOLERANCE. |
TEST_CASE "A" ASSERT_NEAR UUT.Value := 1 0.1; END_TEST_CASE |
SCLTEST_PARSE_ASSERT_NEAR_EXPECT_TOLERANCE_EXPR |
ASSERT_NEAR TOLERANCE is missing its tolerance expression. |
TEST_CASE "A" ASSERT_NEAR UUT.Value := 1 TOLERANCE ; END_TEST_CASE |
SCLTEST_PARSE_ASSERT_NEAR_EXPECT_SEMICOLON |
ASSERT_NEAR is missing ;. |
TEST_CASE "A" ASSERT_NEAR UUT.Value := 1 TOLERANCE 0.1 END_TEST_CASE |
SCL Test Semantic Checks
| Code | Meaning | Minimal trigger example |
|---|---|---|
SCLTEST_SEM_UNDECLARED |
A test expression references an undeclared symbol. | ASSERT Missing = TRUE; |
SCLTEST_SEM_INVALID_PATH |
A test expression uses an invalid designator path. | ASSERT UUT.StructValue.Missing = 1; |
SCLTEST_SEM_ASSIGN_TYPE |
SET or HOLD assigns an incompatible type. |
SET UUT.RealValue := T#1s; |
SCLTEST_SEM_RELEASE_WITHOUT_HOLD |
RELEASE targets a variable that was not previously held. |
RELEASE UUT.Start; |
SCLTEST_SEM_ASSERT_TYPE |
ASSERT is not a BOOL expression or compares incompatible types. |
ASSERT UUT.Count; |
SCLTEST_SEM_WAIT_CYCLES_TYPE |
WAIT_CYCLES does not receive an integer-compatible expression. |
WAIT_CYCLES T#1s; |
SCLTEST_SEM_WAIT_TIME_TYPE |
WAIT_TIME does not receive TIME or LTIME. |
WAIT_TIME 10; |
SCLTEST_SEM_TIMEOUT_TYPE |
WAIT_UNTIL TIMEOUT does not receive TIME or LTIME. |
WAIT_UNTIL UUT.Done = TRUE TIMEOUT 10; |
SCLTEST_SEM_COMPARE_TYPE |
WAIT_UNTIL compares incompatible expression types. |
WAIT_UNTIL UUT.Done = 1 TIMEOUT T#1s; |
SCLTEST_SEM_ASSERT_NEAR_TYPE |
ASSERT_NEAR lacks an equality comparison or uses non-numeric operands/tolerance. |
ASSERT_NEAR UUT.Done := TRUE TOLERANCE FALSE; |
SCLTEST_SEM_UNKNOWN_TARGET |
TEST_TARGET does not resolve in the PLC scope. |
TEST_TARGET "Missing_FB"; |
SCLTEST_SEM_TARGET_KIND |
TEST_TARGET resolves to something other than a function or function block, or function metadata cannot load. |
TEST_TARGET "SomeDataBlock"; |
LSP And Workspace Fallbacks
| Code | Meaning | Minimal trigger example |
|---|---|---|
LSP_ANALYZE_PIPELINE_ERROR |
The LSP analysis pipeline failed before normal diagnostics could be published. | Internal failure while analyzing an opened PLC document. |
WORKSPACE_SCOPE_ERROR |
A PLC workspace scope could not be resolved. | A broken .plc.json or unreadable scoped file prevents workspace indexing. |
PLCJSON_CPU_FAMILY_INVALID |
.plc.json sets a cpuFamily other than S7-1200, S7-1200 G2, S7-1500 or S7-300/400. The family is treated as unknown, so CPU-specific checks are skipped. check reports it as an error, and test, generate, compile and run print it as a warning. |
"cpuFamily": "S7 1500" |