| Crates.io | iecst |
| lib.rs | iecst |
| version | 0.5.1 |
| created_at | 2025-12-03 11:14:41.108817+00 |
| updated_at | 2025-12-11 11:00:49.849828+00 |
| description | IEC 61131-3 Structured Text parser for PLC programming |
| homepage | https://github.com/radevgit/plc |
| repository | https://github.com/radevgit/plc |
| max_upload_size | |
| id | 1963868 |
| size | 195,443 |
⚠️ DEPRECATED: This crate is deprecated in favor of
iec61131, which provides complete IEC 61131-3 support for all 5 programming languages (ST, IL, LD, FBD, SFC) based on the official specification. New projects should useiec61131instead.
IEC 61131-3 Structured Text parser for Rust.
iecst is a parser for IEC 61131-3 Structured Text (ST), the high-level programming language used in PLC (Programmable Logic Controller) programming.
winnow for parsing)Add to your Cargo.toml:
[dependencies]
iecst = "0.5"
use iecst::{parse_statement, parse_expression};
// Parse a statement
let stmt = parse_statement("x := 1 + 2;").unwrap();
// Parse an expression
let expr = parse_expression("a AND b OR c").unwrap();
For untrusted input, use security limits to prevent DoS attacks:
use iecst::{Parser, security::ParserLimits};
// Use strict limits for untrusted input
let limits = ParserLimits::strict();
let parser = Parser::new_with_limits(source, limits)?;
// Available profiles:
// - ParserLimits::strict() - For untrusted input (10 MB, 64 levels)
// - ParserLimits::balanced() - For typical files (100 MB, 256 levels)
// - ParserLimits::relaxed() - For trusted files (500 MB, 512 levels)
+, -, *, /, MOD, **, AND, OR, XOR, comparisons-, NOTSIN(x), MAX(a, b)arr[i], arr[i, j]struct.fieldx := expr;use iecst::parse_pou;
let code = r#"
FUNCTION_BLOCK Counter
VAR_INPUT
Reset : BOOL;
END_VAR
VAR_OUTPUT
Count : INT;
END_VAR
VAR
_count : INT := 0;
END_VAR
IF Reset THEN
_count := 0;
ELSE
_count := _count + 1;
END_IF;
Count := _count;
END_FUNCTION_BLOCK
"#;
let pou = parse_pou(code).unwrap();
println!("Parsed: {:?}", pou.name);
use iecst::{parse_pou, analyze_pou};
let code = "FUNCTION Test : INT VAR x : INT; END_VAR x := 1; Test := x; END_FUNCTION";
let pou = parse_pou(code).unwrap();
let diagnostics = analyze_pou(&pou);
for diag in diagnostics {
println!("[{}] {}", diag.severity, diag.message);
}
Build a CFG from ST statements to analyze control flow and calculate complexity:
use iecst::{parse_statements, CfgBuilder};
let code = r#"
IF x > 0 THEN
y := 1;
ELSIF x < 0 THEN
y := -1;
ELSE
y := 0;
END_IF;
"#;
let stmts = parse_statements(code).unwrap();
let cfg = CfgBuilder::new().build(&stmts);
// Calculate cyclomatic complexity
let complexity = cfg.cyclomatic_complexity();
println!("Cyclomatic complexity: {}", complexity); // Output: 3
// Export to Graphviz DOT format for visualization
let dot = cfg.to_dot();
println!("{}", dot);
Detect deeply nested control structures:
use iecst::{parse_statements, max_nesting_depth};
let code = r#"
IF a THEN
FOR i := 1 TO 10 DO
WHILE b DO
x := x + 1;
END_WHILE;
END_FOR;
END_IF;
"#;
let stmts = parse_statements(code).unwrap();
let depth = max_nesting_depth(&stmts);
println!("Max nesting depth: {}", depth); // Output: 3
cfg.cyclomatic_complexity() using edge formula (E - N + 2)cfg.cyclomatic_complexity_decisions() counting branch pointscfg.unreachable_nodes() finds dead codecfg.has_path(from, to) checks reachabilitycfg.to_dot() for Graphviz visualization