├── plcrex ├── models │ ├── st │ │ ├── __init__.py │ │ └── st_model.cp39-win_amd64.pyd │ ├── fbd │ │ ├── __init__.py │ │ └── dummy_model.cp39-win_amd64.pyd │ ├── pim │ │ ├── __init__.py │ │ └── dummy_model.cp39-win_amd64.pyd │ ├── qrz │ │ ├── __init__.py │ │ └── qrz_model.cp39-win_amd64.pyd │ ├── scl │ │ ├── __init__.py │ │ └── scl_model.cp39-win_amd64.pyd │ ├── smt │ │ ├── __init__.py │ │ └── z3py │ │ │ ├── __init__.py │ │ │ └── dummy_model.cp39-win_amd64.pyd │ └── smv │ │ ├── __init__.py │ │ ├── nusmv │ │ ├── __init__.py │ │ └── dummy_model.cp39-win_amd64.pyd │ │ └── nusmvi │ │ ├── __init__.py │ │ └── dummy_model.cp39-win_amd64.pyd ├── tools │ ├── fbd2x │ │ ├── __init__.py │ │ ├── pyd │ │ │ └── fbd_optimizer.cp39-win_amd64.pyd │ │ └── call_fbd_optimizer.py │ ├── misc │ │ ├── __init__.py │ │ └── generic_functions.py │ ├── st2qrz │ │ ├── __init__.py │ │ ├── pyd │ │ │ └── st2qrz_compiler.cp39-win_amd64.pyd │ │ └── call_st2qrz_compiler.py │ ├── st2scl │ │ ├── __init__.py │ │ ├── pyd │ │ │ └── st2scl_compiler.cp39-win_amd64.pyd │ │ └── call_st2scl_compiler.py │ ├── fbdia │ │ ├── pyd │ │ │ └── io_analysis.cp39-win_amd64.pyd │ │ ├── __init__.py │ │ └── call_io_analysis.py │ ├── tcgen │ │ ├── pyd │ │ │ └── test_case_gen.cp39-win_amd64.pyd │ │ ├── __init__.py │ │ └── call_test_case_gen.py │ ├── fbd2st │ │ ├── pyd │ │ │ └── fbd2st_compiler.cp39-win_amd64.pyd │ │ ├── __init__.py │ │ └── call_fbd2st_compiler.py │ ├── stp │ │ ├── __init__.py │ │ ├── call_st_parser.py │ │ └── st_parser.py │ ├── ieccheck │ │ ├── __init__.py │ │ ├── iec_checker.py │ │ └── call_iec_checker.py │ ├── xmlval │ │ ├── __init__.py │ │ ├── call_xml_validator.py │ │ └── xml_validator.py │ └── __init__.py ├── data │ ├── grammars │ │ ├── __init__.py │ │ ├── DOTgrammar.lark │ │ ├── scl_grammar.lark │ │ ├── scl_grammar_EOL.lark │ │ ├── st_grammar.lark │ │ └── qrz_grammar.lark │ ├── __init__.py │ └── tc6 │ │ └── __init__.py ├── __init__.py └── __main__.py ├── bin └── .gitignore ├── run.bat ├── tests ├── st_to_synchr_models │ ├── __init__.py │ ├── TC01.st │ ├── TC02.st │ ├── TC03.st │ ├── TC06.st │ ├── TC07.st │ ├── TC17.st │ ├── TC20.st │ ├── TC04.st │ ├── TC05.st │ ├── TC09.st │ ├── TC18.st │ ├── TC19.st │ ├── TC11.st │ ├── TC14.st │ ├── TC15.st │ ├── TC21.st │ ├── TC10.st │ ├── TC16.st │ ├── TC12.st │ ├── TC13.st │ └── TC08.st ├── other_examples │ ├── TC001_wrong_file.txt │ ├── DOT.dot │ └── __init__.py ├── st_examples │ ├── TC083.st │ ├── _TC001.st │ ├── TC014.st │ ├── TC015.st │ ├── TC016.st │ ├── TC017.st │ ├── TC013.st │ ├── TC018.st │ ├── TC025.st │ ├── TC026.st │ ├── TC003.st │ ├── TC006.st │ ├── TC020.st │ ├── TC054.st │ ├── TC055.st │ ├── TC056.st │ ├── TC057.st │ ├── TC060.st │ ├── TC061.st │ ├── TC005.st │ ├── TC012.st │ ├── TC019.st │ ├── TC021.st │ ├── TC022.st │ ├── TC023.st │ ├── TC058.st │ ├── TC059.st │ ├── TC062.st │ ├── TC063.st │ ├── TC009.st │ ├── TC024.st │ ├── TC064.st │ ├── TC010.st │ ├── TC079.st │ ├── TC070.st │ ├── TC027.st │ ├── TC028.st │ ├── TC029.st │ ├── TC030.st │ ├── TC031.st │ ├── TC032.st │ ├── TC033.st │ ├── TC034.st │ ├── TC035.st │ ├── TC036.st │ ├── TC037.st │ ├── TC038.st │ ├── TC039.st │ ├── TC040.st │ ├── TC050.st │ ├── TC051.st │ ├── TC052.st │ ├── TC075.st │ ├── TC076.st │ ├── TC077.st │ ├── TC078.st │ ├── TC041.st │ ├── TC042.st │ ├── TC043.st │ ├── TC044.st │ ├── TC045.st │ ├── TC046.st │ ├── TC047.st │ ├── TC048.st │ ├── TC049.st │ ├── TC053.st │ ├── TC069.st │ ├── TC071.st │ ├── TC073.st │ ├── TC074.st │ ├── TC080.st │ ├── TC011.st │ ├── TC072.st │ ├── TC065.st │ ├── TC004.st │ ├── TC007.st │ ├── TC001.st │ ├── TC008.st │ ├── TC002.st │ ├── TC066.st │ ├── TC067.st │ ├── TC068.st │ ├── TC085.st │ ├── TC006_fbd.st │ ├── TC081.st │ ├── TC005_fbd.st │ ├── __init__.py │ ├── TC084.st │ └── TC082.st ├── __init__.py ├── plcopen_examples │ └── __init__.py ├── real_world_FBDs │ └── __init__.py ├── test_help.py ├── test_st2qrz.py ├── test_fbdia.py ├── test_tcgen.py ├── test_xmlval.py ├── test_version.py ├── test_st2scl.py ├── test_stp.py ├── test_ieccheck.py ├── test_fbd2st.py └── test_fbd2x.py ├── .gitattributes ├── docs ├── fig │ ├── TC005.png │ ├── TC006.png │ ├── TC21.png │ ├── TC081_AST.png │ ├── TC081_AST3.png │ ├── TC006_result.png │ ├── edge_opt_example.png │ ├── no_opt_example.png │ ├── coverage_comparison.png │ ├── fbd_optimizer_designflow_HL.png │ └── Pollutant_Indicator_WITH_ERROR.png ├── source │ ├── contact.rst │ ├── __init__.py │ ├── install.rst │ ├── publications.rst │ ├── index.rst │ ├── impact_analysis.rst │ ├── st_to_qrz.rst │ ├── st_to_scl.rst │ ├── xml_validator.rst │ ├── cli.rst │ ├── st_to_sctx.rst │ ├── iec_checker.rst │ ├── fbd_to_st_ext.rst │ ├── conf.py │ ├── fbd_to_sctx.rst │ ├── fbd_to_st.rst │ └── st_parser.rst ├── requirements.txt ├── Makefile └── make.bat ├── install-windows.bat ├── MANIFEST.in ├── requirements.txt ├── .readthedocs.yaml ├── .gitignore └── pyproject.toml /plcrex/models/st/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /plcrex/models/fbd/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /plcrex/models/pim/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /plcrex/models/qrz/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /plcrex/models/scl/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /plcrex/models/smt/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /plcrex/models/smv/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /plcrex/tools/fbd2x/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /plcrex/tools/misc/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /plcrex/tools/st2qrz/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /plcrex/tools/st2scl/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /bin/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /plcrex/models/smt/z3py/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /plcrex/models/smv/nusmv/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /plcrex/models/smv/nusmvi/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /run.bat: -------------------------------------------------------------------------------- 1 | cmd /k venv\Scripts\activate -------------------------------------------------------------------------------- /tests/st_to_synchr_models/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/other_examples/TC001_wrong_file.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.st linguist-language=StructuredText 2 | -------------------------------------------------------------------------------- /docs/fig/TC005.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwern/PLCreX/HEAD/docs/fig/TC005.png -------------------------------------------------------------------------------- /docs/fig/TC006.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwern/PLCreX/HEAD/docs/fig/TC006.png -------------------------------------------------------------------------------- /docs/fig/TC21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwern/PLCreX/HEAD/docs/fig/TC21.png -------------------------------------------------------------------------------- /docs/fig/TC081_AST.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwern/PLCreX/HEAD/docs/fig/TC081_AST.png -------------------------------------------------------------------------------- /docs/fig/TC081_AST3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwern/PLCreX/HEAD/docs/fig/TC081_AST3.png -------------------------------------------------------------------------------- /docs/fig/TC006_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwern/PLCreX/HEAD/docs/fig/TC006_result.png -------------------------------------------------------------------------------- /docs/fig/edge_opt_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwern/PLCreX/HEAD/docs/fig/edge_opt_example.png -------------------------------------------------------------------------------- /docs/fig/no_opt_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwern/PLCreX/HEAD/docs/fig/no_opt_example.png -------------------------------------------------------------------------------- /install-windows.bat: -------------------------------------------------------------------------------- 1 | python -m venv venv && venv\Scripts\activate && python -m pip install -r requirements.txt -------------------------------------------------------------------------------- /docs/fig/coverage_comparison.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwern/PLCreX/HEAD/docs/fig/coverage_comparison.png -------------------------------------------------------------------------------- /docs/source/contact.rst: -------------------------------------------------------------------------------- 1 | Contact 2 | ======= 3 | 4 | .. contact: 5 | 6 | Marcel C. Werner, plcrex.info@gmail.com -------------------------------------------------------------------------------- /docs/fig/fbd_optimizer_designflow_HL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwern/PLCreX/HEAD/docs/fig/fbd_optimizer_designflow_HL.png -------------------------------------------------------------------------------- /tests/st_to_synchr_models/TC01.st: -------------------------------------------------------------------------------- 1 | PROGRAM TC01//_program 2 | VAR 3 | x0 : INT; 4 | END_VAR 5 | 6 | x0 := 0; 7 | END_PROGRAM -------------------------------------------------------------------------------- /docs/fig/Pollutant_Indicator_WITH_ERROR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwern/PLCreX/HEAD/docs/fig/Pollutant_Indicator_WITH_ERROR.png -------------------------------------------------------------------------------- /plcrex/models/st/st_model.cp39-win_amd64.pyd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwern/PLCreX/HEAD/plcrex/models/st/st_model.cp39-win_amd64.pyd -------------------------------------------------------------------------------- /plcrex/models/qrz/qrz_model.cp39-win_amd64.pyd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwern/PLCreX/HEAD/plcrex/models/qrz/qrz_model.cp39-win_amd64.pyd -------------------------------------------------------------------------------- /plcrex/models/scl/scl_model.cp39-win_amd64.pyd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwern/PLCreX/HEAD/plcrex/models/scl/scl_model.cp39-win_amd64.pyd -------------------------------------------------------------------------------- /plcrex/models/fbd/dummy_model.cp39-win_amd64.pyd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwern/PLCreX/HEAD/plcrex/models/fbd/dummy_model.cp39-win_amd64.pyd -------------------------------------------------------------------------------- /plcrex/models/pim/dummy_model.cp39-win_amd64.pyd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwern/PLCreX/HEAD/plcrex/models/pim/dummy_model.cp39-win_amd64.pyd -------------------------------------------------------------------------------- /tests/st_to_synchr_models/TC02.st: -------------------------------------------------------------------------------- 1 | FUNCTION_BLOCK TC02//_functionBlock 2 | VAR 3 | x0 : INT; 4 | END_VAR 5 | 6 | x0 := 0; 7 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_to_synchr_models/TC03.st: -------------------------------------------------------------------------------- 1 | PROGRAM TC03 //_import 2 | VAR 3 | fb1 : TC04; 4 | END_VAR 5 | 6 | fb1(x0 := 2, x1 := 3); 7 | END_PROGRAM -------------------------------------------------------------------------------- /plcrex/models/smt/z3py/dummy_model.cp39-win_amd64.pyd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwern/PLCreX/HEAD/plcrex/models/smt/z3py/dummy_model.cp39-win_amd64.pyd -------------------------------------------------------------------------------- /plcrex/models/smv/nusmv/dummy_model.cp39-win_amd64.pyd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwern/PLCreX/HEAD/plcrex/models/smv/nusmv/dummy_model.cp39-win_amd64.pyd -------------------------------------------------------------------------------- /plcrex/tools/fbdia/pyd/io_analysis.cp39-win_amd64.pyd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwern/PLCreX/HEAD/plcrex/tools/fbdia/pyd/io_analysis.cp39-win_amd64.pyd -------------------------------------------------------------------------------- /plcrex/models/smv/nusmvi/dummy_model.cp39-win_amd64.pyd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwern/PLCreX/HEAD/plcrex/models/smv/nusmvi/dummy_model.cp39-win_amd64.pyd -------------------------------------------------------------------------------- /plcrex/tools/fbd2x/pyd/fbd_optimizer.cp39-win_amd64.pyd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwern/PLCreX/HEAD/plcrex/tools/fbd2x/pyd/fbd_optimizer.cp39-win_amd64.pyd -------------------------------------------------------------------------------- /plcrex/tools/tcgen/pyd/test_case_gen.cp39-win_amd64.pyd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwern/PLCreX/HEAD/plcrex/tools/tcgen/pyd/test_case_gen.cp39-win_amd64.pyd -------------------------------------------------------------------------------- /plcrex/tools/fbd2st/pyd/fbd2st_compiler.cp39-win_amd64.pyd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwern/PLCreX/HEAD/plcrex/tools/fbd2st/pyd/fbd2st_compiler.cp39-win_amd64.pyd -------------------------------------------------------------------------------- /plcrex/tools/st2qrz/pyd/st2qrz_compiler.cp39-win_amd64.pyd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwern/PLCreX/HEAD/plcrex/tools/st2qrz/pyd/st2qrz_compiler.cp39-win_amd64.pyd -------------------------------------------------------------------------------- /plcrex/tools/st2scl/pyd/st2scl_compiler.cp39-win_amd64.pyd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwern/PLCreX/HEAD/plcrex/tools/st2scl/pyd/st2scl_compiler.cp39-win_amd64.pyd -------------------------------------------------------------------------------- /tests/st_to_synchr_models/TC06.st: -------------------------------------------------------------------------------- 1 | FUNCTION_BLOCK TC06 //_in_outputs 2 | VAR_IN_OUT 3 | y0 : INT; 4 | y1 : INT; 5 | END_VAR 6 | 7 | y0 := y1; 8 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_to_synchr_models/TC07.st: -------------------------------------------------------------------------------- 1 | FUNCTION_BLOCK TC07 //_localVariables 2 | VAR 3 | x0 : INT; 4 | x1 : INT := 6; 5 | END_VAR 6 | 7 | x0 := x1; 8 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_to_synchr_models/TC17.st: -------------------------------------------------------------------------------- 1 | FUNCTION_BLOCK TC17 //_singleAssignment_1 2 | VAR 3 | x : INT := 2; 4 | y : INT; 5 | END_VAR 6 | 7 | y := x; 8 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_to_synchr_models/TC20.st: -------------------------------------------------------------------------------- 1 | FUNCTION_BLOCK TC20//_delayedAssignment 2 | VAR 3 | x0 : INT := 2; 4 | y : INT := 1; 5 | END_VAR 6 | 7 | y := y + x0; 8 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC083.st: -------------------------------------------------------------------------------- 1 | PROGRAM TC083 2 | VAR_ACCESS 3 | Var1 : DINT; 4 | Var2 : DINT; 5 | Var3 : DINT; 6 | END_VAR 7 | 8 | Var1 := 19 / 0; 9 | Var2 := Var1 / 1; 10 | END_PROGRAM -------------------------------------------------------------------------------- /tests/st_examples/_TC001.st: -------------------------------------------------------------------------------- 1 | 2 | PROGRAM TC001 3 | VAR_INPUT 4 | x1:INT; 5 | END_VAR 6 | VAR_OUTPUT 7 | x2:INT; 8 | END_VAR 9 | VAR 10 | x3:INT:=3; 11 | END_VAR 12 | x2:=x1+x3; 13 | END_PROGRAM 14 | -------------------------------------------------------------------------------- /tests/st_to_synchr_models/TC04.st: -------------------------------------------------------------------------------- 1 | FUNCTION_BLOCK TC04 //_inputs 2 | VAR_INPUT 3 | x0 : INT; 4 | x1 : INT := 6; 5 | END_VAR 6 | VAR 7 | x2 : INT; 8 | END_VAR 9 | 10 | x2 := x1; 11 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_to_synchr_models/TC05.st: -------------------------------------------------------------------------------- 1 | FUNCTION_BLOCK TC05 //_outputs 2 | VAR_OUTPUT 3 | y0 : INT; 4 | y1 : INT := 6; 5 | END_VAR 6 | VAR 7 | x2 : INT; 8 | END_VAR 9 | 10 | y0 := x2; 11 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_to_synchr_models/TC09.st: -------------------------------------------------------------------------------- 1 | FUNCTION_BLOCK TC09 //_constants 2 | VAR 3 | x0 : BOOL; 4 | x1 : BOOL := TRUE; 5 | x2 : BOOL := FALSE; 6 | END_VAR 7 | 8 | x0 := x1; 9 | x0 := x2; 10 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_to_synchr_models/TC18.st: -------------------------------------------------------------------------------- 1 | FUNCTION_BLOCK TC18//_singleAssignment_2 2 | VAR 3 | x0 : INT := 2; 4 | x1 : INT := 2; 5 | y0 : INT; 6 | y1 : INT; 7 | END_VAR 8 | 9 | y0 := x0; 10 | y1 := x1; 11 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/other_examples/DOT.dot: -------------------------------------------------------------------------------- 1 | digraph G {rankdir=LR;graph [pad="0.5", nodesep="1", ranksep="4"]; splines=spline;node [shape=rect fillcolor=white style=filled];subgraph cluster_1{label=" TC001 "; style=rounded;bgcolor=beige;fontsize = 42; A->a A->b C->a}} 2 | -------------------------------------------------------------------------------- /tests/st_to_synchr_models/TC19.st: -------------------------------------------------------------------------------- 1 | FUNCTION_BLOCK TC19//_multipleAssignment 2 | VAR 3 | x0 : INT := 2; 4 | x1 : INT := 2; 5 | x2 : INT := 2; 6 | y1 : INT; 7 | END_VAR 8 | 9 | y1 := x0; 10 | y1 := x1; 11 | y1 := x2; 12 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_to_synchr_models/TC11.st: -------------------------------------------------------------------------------- 1 | FUNCTION_BLOCK TC11 // _inEquality 2 | VAR 3 | x0 : BOOL; 4 | x1 : BOOL := TRUE; 5 | x2 : BOOL := FALSE; 6 | END_VAR 7 | 8 | x0 := x1 = x2; 9 | x0 := EQ(x1,x2); 10 | x0 := x1 <> x2; 11 | x0 := NE(x1,x2); 12 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_to_synchr_models/TC14.st: -------------------------------------------------------------------------------- 1 | FUNCTION_BLOCK TC14 //_conditional 2 | VAR 3 | x0 : BOOL; 4 | x1 : BOOL := TRUE; 5 | END_VAR 6 | 7 | IF x1 THEN 8 | x0:=TRUE; 9 | ELSE 10 | x0:= FALSE; 11 | END_IF; 12 | 13 | x0 := SEL(x1,TRUE,FALSE); 14 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC014.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Data Types: INT 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC014 6 | VAR 7 | x1 : INT; 8 | END_VAR 9 | 10 | x1:=5; 11 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC015.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Data Types: DINT 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC015 6 | VAR 7 | x1 : DINT; 8 | END_VAR 9 | 10 | x1:=5; 11 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC016.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Data Types: UINT 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC016 6 | VAR 7 | x1 : UINT; 8 | END_VAR 9 | 10 | x1:=5; 11 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC017.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Data Types: REAL 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC017 6 | VAR 7 | x1 : REAL; 8 | END_VAR 9 | 10 | x1:=5.0; 11 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_to_synchr_models/TC15.st: -------------------------------------------------------------------------------- 1 | FUNCTION_BLOCK TC15 //_loop1 2 | VAR 3 | x0 : INT := 0; 4 | x1 : INT := 1; 5 | y : INT; 6 | i : INT; 7 | i0 : INT := 0; 8 | i1 : INT := 10; 9 | END_VAR 10 | 11 | i:=i0; 12 | WHILE i<=i1 DO 13 | y := x0; 14 | i := i+1; 15 | END_WHILE; 16 | y := x1; 17 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC013.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Data Types: BOOL 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC013 6 | VAR 7 | x1 : BOOL; 8 | END_VAR 9 | 10 | x1:=TRUE; 11 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC018.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Data Types: TIME 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC018 6 | VAR 7 | x1 : TIME; 8 | END_VAR 9 | 10 | x1:=t#5000ms; 11 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC025.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Expressions: FALSE 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC025 6 | VAR 7 | x1 : BOOL; 8 | END_VAR 9 | 10 | x1:=FALSE; 11 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC026.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Expressions: TRUE 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC026 6 | VAR 7 | x1 : BOOL; 8 | END_VAR 9 | 10 | x1:=TRUE; 11 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_to_synchr_models/TC21.st: -------------------------------------------------------------------------------- 1 | FUNCTION_BLOCK TC21 2 | VAR_OUTPUT 3 | y : INT; 4 | END_VAR 5 | VAR 6 | x : INT := 1; 7 | i : INT; 8 | i0 : INT := 0; 9 | i1 : INT := 10; 10 | END_VAR 11 | 12 | i:=i0; 13 | REPEAT 14 | y := i; 15 | i := i+1; 16 | UNTIL i>i1 17 | END_REPEAT; 18 | y := x; 19 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_to_synchr_models/TC10.st: -------------------------------------------------------------------------------- 1 | FUNCTION_BLOCK TC10 //Boolean Operators 2 | VAR 3 | x0 : BOOL; 4 | x1 : BOOL := TRUE; 5 | x2 : BOOL := FALSE; 6 | END_VAR 7 | 8 | x0 := NOT(x1); 9 | x0 := x1 AND x2; 10 | x0 := AND(x1,x2); 11 | x0 := x1 OR x2; 12 | x0 := OR(x1,x2); 13 | x0 := x1 XOR x2; 14 | x0 := XOR(x1,x2); 15 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_to_synchr_models/TC16.st: -------------------------------------------------------------------------------- 1 | FUNCTION_BLOCK TC16 // _loop2 2 | VAR 3 | x0 : INT := 0; 4 | x1 : INT := 1; 5 | y : INT; 6 | i : INT; 7 | i0 : INT := 0; 8 | i1 : INT := 10; 9 | END_VAR 10 | 11 | i:=i0; 12 | REPEAT 13 | y := x0; 14 | i := i+1; 15 | UNTIL i>i1 16 | END_REPEAT; 17 | y := x1; 18 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC003.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Program Organization Units: FUNCTION 3 | // ******************************************************************************** 4 | 5 | FUNCTION TC003 6 | VAR_OUTPUT 7 | x1 : BOOL; 8 | END_VAR 9 | 10 | x1 := TRUE; 11 | END_FUNCTION -------------------------------------------------------------------------------- /tests/st_examples/TC006.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Variable Declaration List: VAR 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC006 6 | VAR 7 | x1 : BOOL := FALSE; 8 | END_VAR 9 | 10 | x1:= TRUE; 11 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC020.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Data Types: ARRAY OF INT 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC020 6 | VAR 7 | x1 : ARRAY [1..2] OF INT; 8 | END_VAR 9 | 10 | x1[1]:= 1; 11 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC054.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Expressions: -Tau 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC054 6 | VAR 7 | x1 : INT; 8 | x2 : INT := 5; 9 | END_VAR 10 | 11 | x1 := -x2; 12 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC055.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Expressions: -Tau 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC055 6 | VAR 7 | x1 : INT; 8 | x2 : INT := 5; 9 | END_VAR 10 | 11 | x1 := -(2); 12 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC056.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Expressions: * 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC056 6 | VAR 7 | x1 : INT; 8 | x2 : INT :=5; 9 | END_VAR 10 | 11 | x1:=x2*3; 12 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC057.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Expressions: / 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC057 6 | VAR 7 | x1 : INT; 8 | x2 : INT :=5; 9 | END_VAR 10 | 11 | x1:=x2/3; 12 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC060.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Expressions: + 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC060 6 | VAR 7 | x1 : INT; 8 | x2 : INT :=5; 9 | END_VAR 10 | 11 | x1:=x2 + 3; 12 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC061.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Expressions: - 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC061 6 | VAR 7 | x1 : INT; 8 | x2 : INT :=5; 9 | END_VAR 10 | 11 | x1:=x2 - 3; 12 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC005.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Program Organization Units: FUNCTION_BLOCK 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC005 6 | VAR 7 | x1 : BOOL; 8 | END_VAR 9 | 10 | x1:= TRUE; 11 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC012.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Interface Declaration List: VAR_IN_OUT 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC012 6 | VAR_IN_OUT 7 | x1 : BOOL; 8 | END_VAR 9 | 10 | x1:=TRUE; 11 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC019.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Data Types: ARRAY OF BOOL 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC019 6 | VAR 7 | x1 : ARRAY [1..2] OF BOOL; 8 | END_VAR 9 | 10 | x1[1]:= TRUE; 11 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC021.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Data Types: ARRAY OF DINT 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC021 6 | VAR 7 | x1 : ARRAY [1..2] OF DINT; 8 | END_VAR 9 | 10 | x1[1]:= 1; 11 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC022.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Data Types: ARRAY OF UINT 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC022 6 | VAR 7 | x1 : ARRAY [1..2] OF UINT; 8 | END_VAR 9 | 10 | x1[1]:= 1; 11 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC023.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Data Types: ARRAY OF REAL 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC023 6 | VAR 7 | x1 : ARRAY [1..2] OF REAL; 8 | END_VAR 9 | 10 | x1[1]:= 1.0; 11 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC058.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Expressions: / 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC058 6 | VAR 7 | x1 : REAL; 8 | x2 : REAL :=5.0; 9 | END_VAR 10 | 11 | x1:=x2/3.0; 12 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC059.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Expressions: MOD 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC059 6 | VAR 7 | x1 : INT; 8 | x2 : INT :=5; 9 | END_VAR 10 | 11 | x1:=x2 MOD 3; 12 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC062.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Expressions: () 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC062 6 | VAR 7 | x1 : INT; 8 | x2 : INT :=5; 9 | END_VAR 10 | 11 | x1:= (1+7) / 3; 12 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC063.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Expressions: () 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC063 6 | VAR 7 | x1 : INT; 8 | x2 : INT :=5; 9 | END_VAR 10 | 11 | x1:= (1-7) / 3; 12 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_to_synchr_models/TC12.st: -------------------------------------------------------------------------------- 1 | FUNCTION_BLOCK TC12 //_numericRelations 2 | VAR 3 | x0 : BOOL; 4 | x1 : INT := 1; 5 | x2 : INT := 2; 6 | END_VAR 7 | 8 | x0 := x1 < x2; 9 | x0 := LT(x1, x2); 10 | x0 := x1 <= x2; 11 | x0 := LE(x1, x2); 12 | x0 := x1 > x2; 13 | x0 := GT(x1, x2); 14 | x0 := x1 >= x2; 15 | x0 := GE(x1, x2); 16 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC009.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Interface Declaration List: VAR_OUTPUT 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC009 6 | VAR_OUTPUT 7 | x1 : BOOL; 8 | END_VAR 9 | 10 | x1 := TRUE; 11 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC024.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Data Types: ARRAY OF TIME 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC024 6 | VAR 7 | x1 : ARRAY [1..2] OF TIME; 8 | END_VAR 9 | 10 | x1[1]:= t#5000ms; 11 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC064.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Expressions: () 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC064 6 | VAR 7 | x1 : REAL; 8 | x2 : INT :=5; 9 | END_VAR 10 | 11 | x1:= (1.0-7) / 3.0; 12 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC010.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Interface Declaration List: VAR_OUTPUT 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC010 6 | VAR_OUTPUT 7 | x1 : BOOL := FALSE; 8 | END_VAR 9 | 10 | x1 := TRUE; 11 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC079.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Assignment: := 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC079 6 | VAR 7 | x1 : INT; 8 | x2 : INT; 9 | x3 : INT; 10 | END_VAR 11 | 12 | x1:=x1+1; 13 | 14 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC070.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Bounded Loops: FOR 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC070 6 | VAR 7 | x2 : INT; 8 | END_VAR 9 | 10 | FOR x1:=0 TO 10 DO 11 | x2 := x1; 12 | END_FOR; 13 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC027.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Expressions: = 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC027 6 | VAR 7 | x1 : INT := 4; 8 | x2 : INT := 6; 9 | x3 : BOOL; 10 | END_VAR 11 | 12 | x3:=x1 = x2; 13 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC028.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Expressions: = 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC028 6 | VAR 7 | x1 : INT := 6; 8 | x2 : INT := 6; 9 | x3 : BOOL; 10 | END_VAR 11 | 12 | x3:=x1 = x2; 13 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC029.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Expressions: <> 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC029 6 | VAR 7 | x1 : INT := 4; 8 | x2 : INT := 6; 9 | x3 : BOOL; 10 | END_VAR 11 | 12 | x3:=x1 <> x2; 13 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC030.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Expressions: <> 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC030 6 | VAR 7 | x1 : INT := 6; 8 | x2 : INT := 6; 9 | x3 : BOOL; 10 | END_VAR 11 | 12 | x3:=x1 <> x2; 13 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC031.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Expressions: < 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC031 6 | VAR 7 | x1 : INT := 4; 8 | x2 : INT := 6; 9 | x3 : BOOL; 10 | END_VAR 11 | 12 | x3:=x1 < x2; 13 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC032.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Expressions: < 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC032 6 | VAR 7 | x1 : INT := 6; 8 | x2 : INT := 6; 9 | x3 : BOOL; 10 | END_VAR 11 | 12 | x3:=x1 < x2; 13 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC033.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Expressions: > 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC033 6 | VAR 7 | x1 : INT := 4; 8 | x2 : INT := 6; 9 | x3 : BOOL; 10 | END_VAR 11 | 12 | x3:=x1 > x2; 13 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC034.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Expressions: > 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC034 6 | VAR 7 | x1 : INT := 6; 8 | x2 : INT := 6; 9 | x3 : BOOL; 10 | END_VAR 11 | 12 | x3:=x1 > x2; 13 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC035.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Expressions: <= 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC035 6 | VAR 7 | x1 : INT := 4; 8 | x2 : INT := 6; 9 | x3 : BOOL; 10 | END_VAR 11 | 12 | x3:=x1 <= x2; 13 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC036.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Expressions: <= 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC036 6 | VAR 7 | x1 : INT := 6; 8 | x2 : INT := 6; 9 | x3 : BOOL; 10 | END_VAR 11 | 12 | x3:=x1 <= x2; 13 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC037.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Expressions: >= 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC037 6 | VAR 7 | x1 : INT := 4; 8 | x2 : INT := 6; 9 | x3 : BOOL; 10 | END_VAR 11 | 12 | x3:=x1 >= x2; 13 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC038.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Expressions: >= 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC038 6 | VAR 7 | x1 : INT := 6; 8 | x2 : INT := 6; 9 | x3 : BOOL; 10 | END_VAR 11 | 12 | x3:=x1 >= x2; 13 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC039.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Expressions: NOT 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC039 6 | VAR 7 | x1 : BOOL := TRUE; 8 | x2 : BOOL; 9 | END_VAR 10 | 11 | x1:=NOT x1; 12 | x2 := TRUE; 13 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC040.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Expressions: NOT 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC040 6 | VAR 7 | x1 : BOOL := FALSE; 8 | x2 : BOOL; 9 | END_VAR 10 | 11 | x1:=NOT x1; 12 | x2 := TRUE; 13 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC050.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Expressions: OR 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC050 6 | VAR 7 | x1 : BOOL := TRUE; 8 | x2 : BOOL := FALSE; 9 | x3 : BOOL; 10 | END_VAR 11 | 12 | x3:=x1 OR x2; 13 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC051.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Expressions: OR 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC051 6 | VAR 7 | x1 : BOOL := FALSE; 8 | x2 : BOOL := TRUE; 9 | x3 : BOOL; 10 | END_VAR 11 | 12 | x3:=x1 OR x2; 13 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC052.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Expressions: OR 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC052 6 | VAR 7 | x1 : BOOL := TRUE; 8 | x2 : BOOL := TRUE; 9 | x3 : BOOL; 10 | END_VAR 11 | 12 | x3:=x1 OR x2; 13 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC075.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Assignment: := 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC075 6 | VAR 7 | x1 : INT; 8 | x2 : INT; 9 | x3 : INT; 10 | END_VAR 11 | 12 | x1:=x1+2; 13 | x2:=1; 14 | 15 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC076.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Assignment: := 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC076 6 | VAR 7 | x1 : INT; 8 | x2 : INT; 9 | x3 : INT; 10 | END_VAR 11 | 12 | x1:=2; 13 | x1:=3; 14 | 15 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC077.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Assignment: := 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC077 6 | VAR 7 | x1 : INT; 8 | x2 : INT; 9 | x3 : INT; 10 | END_VAR 11 | 12 | x1:=x2; 13 | x2:=1; 14 | 15 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC078.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Assignment: := 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC078 6 | VAR 7 | x1 : INT; 8 | x2 : INT; 9 | x3 : INT; 10 | END_VAR 11 | 12 | x1:=1; 13 | x2:=x1; 14 | 15 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | myst-parser==2.0.0 2 | sphinx-press-theme==0.8.0 3 | rst2pdf==0.101 4 | Sphinx==7.2.6 5 | sphinx-markdown-tables==0.0.17 6 | sphinx-rtd-theme==2.0.0 7 | sphinxcontrib-applehelp==1.0.7 8 | sphinxcontrib-devhelp==1.0.5 9 | sphinxcontrib-htmlhelp==2.0.4 10 | sphinxcontrib-jquery==4.1 11 | sphinxcontrib-jsmath==1.0.1 12 | sphinxcontrib-qthelp==1.0.6 13 | sphinxcontrib-serializinghtml==1.1.9 -------------------------------------------------------------------------------- /tests/st_examples/TC041.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Expressions: AND 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC041 6 | VAR 7 | x1 : BOOL := FALSE; 8 | x2 : BOOL := FALSE; 9 | x3 : BOOL; 10 | END_VAR 11 | 12 | x3:=x1 AND x2; 13 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC042.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Expressions: AND 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC042 6 | VAR 7 | x1 : BOOL := TRUE; 8 | x2 : BOOL := FALSE; 9 | x3 : BOOL; 10 | END_VAR 11 | 12 | x3:=x1 AND x2; 13 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC043.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Expressions: AND 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC043 6 | VAR 7 | x1 : BOOL := FALSE; 8 | x2 : BOOL := TRUE; 9 | x3 : BOOL; 10 | END_VAR 11 | 12 | x3:=x1 AND x2; 13 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC044.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Expressions: AND 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC044 6 | VAR 7 | x1 : BOOL := FALSE; 8 | x2 : BOOL := TRUE; 9 | x3 : BOOL; 10 | END_VAR 11 | 12 | x3:=x1 AND x2; 13 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC045.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Expressions: XOR 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC045 6 | VAR 7 | x1 : BOOL := FALSE; 8 | x2 : BOOL := FALSE; 9 | x3 : BOOL; 10 | END_VAR 11 | 12 | x3:=x1 XOR x2; 13 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC046.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Expressions: XOR 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC046 6 | VAR 7 | x1 : BOOL := TRUE; 8 | x2 : BOOL := FALSE; 9 | x3 : BOOL; 10 | END_VAR 11 | 12 | x3:=x1 XOR x2; 13 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC047.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Expressions: XOR 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC047 6 | VAR 7 | x1 : BOOL := FALSE; 8 | x2 : BOOL := TRUE; 9 | x3 : BOOL; 10 | END_VAR 11 | 12 | x3:=x1 XOR x2; 13 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC048.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Expressions: XOR 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC048 6 | VAR 7 | x1 : BOOL := TRUE; 8 | x2 : BOOL := TRUE; 9 | x3 : BOOL; 10 | END_VAR 11 | 12 | x3:=x1 XOR x2; 13 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC049.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Expressions: OR 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC049 6 | VAR 7 | x1 : BOOL := FALSE; 8 | x2 : BOOL := FALSE; 9 | x3 : BOOL; 10 | END_VAR 11 | 12 | x3:=x1 OR x2; 13 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC053.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Expressions: EXPT Macro 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC053 6 | VAR 7 | x1 : REAL := 1.0; 8 | x2 : REAL := 2.0; 9 | x3 : REAL; 10 | END_VAR 11 | 12 | x3:=EXPT(x1,x2); 13 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC069.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Bounded Loops: FOR 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC069 6 | VAR 7 | x1 : INT; 8 | x2 : INT; 9 | END_VAR 10 | 11 | FOR x1:=0 TO 10 BY 2 DO 12 | x2 := x1+5; 13 | END_FOR; 14 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC071.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Bounded Loops: WHILE 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC071 6 | VAR 7 | x1 : INT; 8 | x2 : INT; 9 | END_VAR 10 | 11 | WHILE x1 <= 10 DO 12 | x1 := x2 + x1; 13 | END_WHILE; 14 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC073.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Assignment: := 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC073 6 | VAR 7 | x1 : INT; 8 | x2 : INT; 9 | x3 : INT; 10 | END_VAR 11 | 12 | x1:=1; 13 | x2:=1; 14 | x3:=1; 15 | 16 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC074.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Assignment: := 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC074 6 | VAR 7 | x1 : INT; 8 | x2 : INT; 9 | x3 : INT; 10 | END_VAR 11 | 12 | x1:=1; 13 | x2:=1; 14 | x1:=2; 15 | 16 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC080.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Real POU 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC080 6 | VAR_INPUT 7 | S1 : BOOL; 8 | R : BOOL; 9 | END_VAR 10 | VAR_OUTPUT 11 | Q1 : BOOL; 12 | END_VAR 13 | 14 | Q1 := S1 XOR (Q1 AND NOT R); 15 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC011.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Interface Declaration List: VAR_EXTERNAL 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC011 6 | VAR_EXTERNAL 7 | global : BOOL; 8 | END_VAR 9 | VAR 10 | x1 : BOOL; 11 | END_VAR 12 | 13 | x1 := global; 14 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC072.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Bounded Loops: REPEAT UNTIL 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC072 6 | VAR 7 | x1 : INT; 8 | x2 : INT; 9 | END_VAR 10 | 11 | REPEAT 12 | x1 := 5 + x2; 13 | UNTIL x1 > 10 14 | END_REPEAT; 15 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC065.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Conditional Statements: IF ELSE 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC065 6 | VAR 7 | x1 : BOOL := TRUE; 8 | x2 : INT := 5; 9 | x3 : INT; 10 | END_VAR 11 | 12 | IF x1 THEN 13 | x3:=x2; 14 | END_IF; 15 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC004.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Program Organization Units: FUNCTION : DATATYPE 3 | // ******************************************************************************** 4 | 5 | FUNCTION TC004 : BOOL 6 | VAR_INPUT 7 | x1 : BOOL; 8 | END_VAR 9 | VAR 10 | x2: BOOL := FALSE; 11 | END_VAR 12 | 13 | TC004 := x2; 14 | END_FUNCTION -------------------------------------------------------------------------------- /tests/st_examples/TC007.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Interface Declaration List: VAR_INPUT 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC007 6 | VAR_INPUT 7 | x1 : BOOL; 8 | END_VAR 9 | VAR 10 | x2 : BOOL := FALSE; 11 | x3 : BOOL := FALSE; 12 | END_VAR 13 | 14 | x2:=x1; 15 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC001.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Program Organization Units: PROGRAM 3 | // ******************************************************************************** 4 | 5 | PROGRAM TC001 6 | VAR_INPUT 7 | x1 : INT; 8 | END_VAR 9 | VAR_OUTPUT 10 | x2 : INT; 11 | END_VAR 12 | VAR 13 | x3 : INT := 3; 14 | END_VAR 15 | 16 | x2:=x1+x3; 17 | END_PROGRAM -------------------------------------------------------------------------------- /tests/st_examples/TC008.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Interface Declaration List: VAR_INPUT 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC008 6 | VAR_INPUT 7 | x1 : BOOL := FALSE; 8 | END_VAR 9 | VAR 10 | x2 : BOOL := FALSE; 11 | x3 : BOOL := FALSE; 12 | END_VAR 13 | 14 | x2:=x1; 15 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC002.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Program Organization Units: PROGRAM 3 | // ******************************************************************************** 4 | 5 | PROGRAM TC002 6 | VAR_INPUT 7 | x1 : INT; 8 | END_VAR 9 | VAR_OUTPUT 10 | x2 : INT; 11 | END_VAR 12 | VAR 13 | x3 : INT := 3; 14 | END_VAR 15 | 16 | x2:=x1 +(x3*x1); 17 | END_PROGRAM -------------------------------------------------------------------------------- /tests/st_examples/TC066.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Conditional Statements: IF ELSE 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC066 6 | VAR 7 | x1 : BOOL := TRUE; 8 | x2 : INT := 5; 9 | x3 : INT; 10 | END_VAR 11 | 12 | IF x1 THEN 13 | x3:=x2; 14 | ELSE 15 | x3:= -x2; 16 | END_IF; 17 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC067.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Conditional Statements: IF ELSE 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC067 6 | VAR 7 | x1 : BOOL := TRUE; 8 | x2 : INT := 5; 9 | x3 : INT; 10 | END_VAR 11 | 12 | IF x1 THEN 13 | x3:=x2; 14 | ELSIF x2 = 5 THEN 15 | x3:=-x2; 16 | END_IF; 17 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_to_synchr_models/TC13.st: -------------------------------------------------------------------------------- 1 | FUNCTION_BLOCK TC13 //_arithmeticOperators 2 | VAR 3 | x0 : REAL; 4 | x1 : REAL := 1.0; 5 | x2 : REAL := 2.0; 6 | x3 : INT := 1; 7 | x4 : INT := 2; 8 | x5 : INT; 9 | END_VAR 10 | 11 | x0 := x1 + x2; 12 | x0 := ADD(x1, x2); 13 | x0 := x1 - x2; 14 | x0 := SUB(x1, x2); 15 | x0 := x1 * x2; 16 | x0 := MUL(x1, x2); 17 | x0 := x1 / x2; 18 | x0 := DIV(x1, x2); 19 | x0 := EXPT(x1, x2); 20 | x5 := MOD(x3, x4); 21 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC068.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Conditional Statements: IF ELSE 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC068 6 | VAR 7 | x1 : BOOL := TRUE; 8 | x2 : INT := 5; 9 | x3 : INT; 10 | END_VAR 11 | 12 | IF x1 THEN 13 | x3:=x2; 14 | ELSIF x2 = 5 THEN 15 | x3:=-x2; 16 | ELSE 17 | x3:=2*x2; 18 | END_IF; 19 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | prune bin 2 | prune docs 3 | prune tests 4 | prune venv 5 | prune PLCreX_outputs 6 | prune exports 7 | include plcrex/data/grammars/*.lark 8 | include plcrex/data/tc6/*.xsd 9 | include plcrex/tools/fbd2st/pyd/*.pyd 10 | include plcrex/tools/fbd2x/pyd/*.pyd 11 | include plcrex/tools/fbdia/pyd/*.pyd 12 | include plcrex/tools/st2qrz/pyd/*.pyd 13 | include plcrex/tools/st2scl/pyd/*.pyd 14 | include plcrex/tools/tcgen/pyd/*.pyd 15 | include plcrex/models/st/*.pyd 16 | include plcrex/models/scl/*.pyd 17 | include plcrex/models/qrz/*.pyd -------------------------------------------------------------------------------- /tests/st_examples/TC085.st: -------------------------------------------------------------------------------- 1 | PROGRAM TC085 2 | VAR_INPUT 3 | a: INT; 4 | b: INT; 5 | END_VAR 6 | VAR_OUTPUT 7 | gcd:INT; 8 | END_VAR 9 | VAR 10 | c: INT; 11 | d: INT; 12 | END_VAR 13 | 14 | c:=a; 15 | d:=b; 16 | 17 | IF (c=0) THEN 18 | gcd := d; 19 | 20 | ELSE 21 | WHILE (d <>0) DO 22 | IF (c>d) THEN 23 | c := c-d; 24 | ELSE 25 | d := d-c; 26 | END_IF; 27 | END_WHILE; 28 | gcd := c; 29 | END_IF; 30 | END_PROGRAM -------------------------------------------------------------------------------- /tests/st_to_synchr_models/TC08.st: -------------------------------------------------------------------------------- 1 | FUNCTION_BLOCK TC08 // _datatypes 2 | VAR 3 | x0 : BOOL; 4 | x1 : BOOL := TRUE; 5 | x2 : INT; 6 | x3 : INT := 2; 7 | x4 : REAL; 8 | x5 : REAL := 1.23; 9 | x7 : TIME; 10 | x8 : TIME := t#5s; 11 | x9 : ARRAY [1..2] OF BOOL; 12 | x10 : ARRAY [1..2] OF INT; 13 | x11 : ARRAY [1..2] OF REAL; 14 | x12 : ARRAY [1..2] OF TIME; 15 | END_VAR 16 | 17 | x0 := x1; 18 | x2 := x3; 19 | x4 := x5; 20 | x7 := x8; 21 | x9[0]:=TRUE; 22 | x10[0]:=2; 23 | x11[0]:=1.23; 24 | x12[0]:=t#2s; 25 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | attrs==23.1.0 2 | click==8.1.6 3 | colorama==0.4.5 4 | coverage==6.5.0 5 | coverage-badge==1.1.0 6 | dd==0.5.7 7 | dicttoxml2==2.1.0 8 | elementpath==3.0.2 9 | exceptiongroup==1.2.0 10 | iniconfig==2.0.0 11 | lark==1.1.7 12 | markdown-it-py==3.0.0 13 | mdurl==0.1.2 14 | packaging==23.2 15 | pluggy==1.3.0 16 | pydot==1.4.2 17 | pyeda==0.29.0 18 | Pygments==2.17.2 19 | pyparsing==3.1.1 20 | pytest==7.2.0 21 | rich==13.5.1 22 | termcolor==2.3.0 23 | tomli==2.0.1 24 | typer==0.9.0 25 | typing_extensions==4.8.0 26 | xmlschema==2.1.1 27 | z3-solver==4.12.2.0 -------------------------------------------------------------------------------- /tests/st_examples/TC006_fbd.st: -------------------------------------------------------------------------------- 1 | FUNCTION_BLOCK TC006 2 | VAR_INPUT 3 | i1 : BOOL; 4 | i2 : BOOL; 5 | END_VAR 6 | VAR_OUTPUT 7 | o1 : BOOL; 8 | o2 : BOOL; 9 | o3 : BOOL; 10 | END_VAR 11 | VAR 12 | l1 : BOOL; 13 | l2 : TIME := T#5s; 14 | TON0 : TON; 15 | AND1_OUT : BOOL; 16 | XOR3_OUT : BOOL; 17 | OR13_OUT : BOOL; 18 | END_VAR 19 | 20 | AND1_OUT := AND(i1, i2); 21 | TON0(AND1_OUT, l2); 22 | XOR3_OUT := XOR(AND1_OUT, TON0.Q); 23 | l1 := XOR3_OUT; 24 | o1 := TON0.Q; 25 | o2 := i1; 26 | OR13_OUT := OR(i2, l1); 27 | o3 := OR13_OUT; 28 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC081.st: -------------------------------------------------------------------------------- 1 | FUNCTION_BLOCK TC081 2 | VAR_INPUT 3 | IN1 : INT; 4 | IN2 : INT; 5 | IN3 : INT; 6 | IN4 : BOOL; 7 | END_VAR 8 | VAR_OUTPUT 9 | Wrn : BOOL; 10 | Err : BOOL; 11 | Ctr : INT; 12 | iOut2 : INT; 13 | END_VAR 14 | VAR 15 | SR1 : SR; 16 | TON1 : TON; 17 | TON2 : TON; 18 | END_VAR 19 | 20 | SR1(((((20*IN1)+(6*IN2)+IN3))=(100*2)) AND (IN1+IN2+IN3=100),IN4); 21 | TON1((((((20*IN1)+(6*IN2)+IN3))=(100*2)) AND (IN1+IN2+IN3=100)),2); 22 | TON2(IN1+IN2+IN3=42 AND SR1.Q,3); 23 | Ctr := TON2.ET; 24 | Err := TON1.Q; 25 | Wrn := SR1.Q; 26 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /tests/st_examples/TC005_fbd.st: -------------------------------------------------------------------------------- 1 | PROGRAM TC005 2 | VAR_INPUT 3 | i1 : BOOL; 4 | i2 : BOOL := FALSE; 5 | i3 : TIME; 6 | END_VAR 7 | VAR_OUTPUT 8 | o1 : BOOL := FALSE; 9 | o2 : BOOL := FALSE; 10 | END_VAR 11 | VAR 12 | o4 : BOOL; 13 | TON0 : TON; 14 | AND1_OUT : BOOL; 15 | XOR3_OUT : BOOL; 16 | END_VAR 17 | 18 | AND1_OUT := AND(i1,i2); 19 | TON0(AND1_OUT,i3); 20 | XOR3_OUT := XOR(AND1_OUT,TON0.Q); 21 | o1 := XOR3_OUT; 22 | o4 := TON0.Q; 23 | o2 := i1; 24 | END_PROGRAM -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yaml 2 | # Read the Docs configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | # Required 6 | version: 2 7 | 8 | # Set the version of Python and other tools you might need 9 | build: 10 | os: ubuntu-22.04 11 | tools: 12 | python: "3.11" 13 | 14 | # Build documentation in the docs/ directory with Sphinx 15 | sphinx: 16 | configuration: docs/source/conf.py 17 | 18 | # If using Sphinx, optionally build your docs in additional formats such as PDF 19 | formats: 20 | - pdf 21 | 22 | # Optionally declare the Python requirements required to build your docs 23 | python: 24 | install: 25 | - requirements: docs/requirements.txt -------------------------------------------------------------------------------- /docs/source/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of PLCreX (https://github.com/marwern/PLCreX). 3 | # 4 | # Copyright (c) 2022-2024 Marcel C. Werner. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | -------------------------------------------------------------------------------- /plcrex/tools/stp/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of PLCreX (https://github.com/marwern/PLCreX). 3 | # 4 | # Copyright (c) 2022-2024 Marcel C. Werner. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | -------------------------------------------------------------------------------- /plcrex/data/grammars/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of PLCreX (https://github.com/marwern/PLCreX). 3 | # 4 | # Copyright (c) 2022-2024 Marcel C. Werner. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | -------------------------------------------------------------------------------- /plcrex/tools/fbd2st/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of PLCreX (https://github.com/marwern/PLCreX). 3 | # 4 | # Copyright (c) 2022-2024 Marcel C. Werner. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | -------------------------------------------------------------------------------- /plcrex/tools/fbdia/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of PLCreX (https://github.com/marwern/PLCreX). 3 | # 4 | # Copyright (c) 2022-2024 Marcel C. Werner. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | -------------------------------------------------------------------------------- /plcrex/tools/ieccheck/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of PLCreX (https://github.com/marwern/PLCreX). 3 | # 4 | # Copyright (c) 2022-2024 Marcel C. Werner. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | -------------------------------------------------------------------------------- /plcrex/tools/tcgen/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of PLCreX (https://github.com/marwern/PLCreX). 3 | # 4 | # Copyright (c) 2022-2024 Marcel C. Werner. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | -------------------------------------------------------------------------------- /plcrex/tools/xmlval/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of PLCreX (https://github.com/marwern/PLCreX). 3 | # 4 | # Copyright (c) 2022-2024 Marcel C. Werner. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of PLCreX (https://github.com/marwern/PLCreX). 3 | # 4 | # Copyright (c) 2022-2024 Marcel C. Werner. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | -------------------------------------------------------------------------------- /plcrex/data/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of PLCreX (https://github.com/marwern/PLCreX). 3 | # 4 | # Copyright (c) 2022-2024 Marcel C. Werner. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | -------------------------------------------------------------------------------- /plcrex/data/tc6/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of PLCreX (https://github.com/marwern/PLCreX). 3 | # 4 | # Copyright (c) 2022-2024 Marcel C. Werner. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | -------------------------------------------------------------------------------- /plcrex/tools/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of PLCreX (https://github.com/marwern/PLCreX). 3 | # 4 | # Copyright (c) 2022-2024 Marcel C. Werner. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | -------------------------------------------------------------------------------- /tests/other_examples/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of PLCreX (https://github.com/marwern/PLCreX). 3 | # 4 | # Copyright (c) 2022-2024 Marcel C. Werner. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | -------------------------------------------------------------------------------- /tests/st_examples/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of PLCreX (https://github.com/marwern/PLCreX). 3 | # 4 | # Copyright (c) 2022-2024 Marcel C. Werner. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | -------------------------------------------------------------------------------- /tests/plcopen_examples/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of PLCreX (https://github.com/marwern/PLCreX). 3 | # 4 | # Copyright (c) 2022-2024 Marcel C. Werner. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | -------------------------------------------------------------------------------- /tests/real_world_FBDs/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of PLCreX (https://github.com/marwern/PLCreX). 3 | # 4 | # Copyright (c) 2022-2024 Marcel C. Werner. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # .idea folder 2 | .idea/ 3 | 4 | # Byte-compiled / optimized 5 | __pycache__/ 6 | *.py[co] 7 | 8 | # Unit test / coverage reports 9 | htmlcov/ 10 | .tox/ 11 | .nox/ 12 | .coverage 13 | .coverage.* 14 | .cache 15 | nosetests.xml 16 | coverage.xml 17 | *.cover 18 | *.py,cover 19 | .hypothesis/ 20 | .pytest_cache/ 21 | 22 | # Sphinx documentation 23 | docs/build/ 24 | 25 | # PyBuilder 26 | target/ 27 | 28 | # pyenv 29 | .python-version 30 | 31 | # Environments 32 | .env 33 | .venv 34 | env/ 35 | venv/ 36 | ENV/ 37 | env.bak/ 38 | venv.bak/ 39 | 40 | # Spyder project settings 41 | .spyderproject 42 | .spyproject 43 | 44 | # Rope project settings 45 | .ropeproject 46 | 47 | # mkdocs documentation 48 | /site 49 | 50 | # mypy 51 | .mypy_cache/ 52 | .dmypy.json 53 | dmypy.json 54 | 55 | # Pyre type checker 56 | .pyre/ 57 | -------------------------------------------------------------------------------- /tests/st_examples/TC084.st: -------------------------------------------------------------------------------- 1 | FUNCTION dead_code_after_return : INT 2 | VAR 3 | counter : INT := 0; 4 | some_var : INT; 5 | END_VAR 6 | counter := counter + 1; 7 | counter := 2 + 2; 8 | RETURN; 9 | some_var := SQRT(16#42); (* UnreachableCode error *) 10 | some_var := 16#42; (* No additional warnings *) 11 | some_var := 19; 12 | END_FUNCTION 13 | 14 | PROGRAM dead_code_in_the_loops 15 | VAR a : INT; i : INT; END_VAR 16 | WHILE i < 10 DO 17 | IF i = 5 THEN 18 | i := i + 1; 19 | EXIT; 20 | i := 19; (* UnreachableCode error *) 21 | i := 42; (* No additional warnings *) 22 | i := 42; 23 | ELSIF i = 6 THEN 24 | CONTINUE; 25 | i := 3; (* UnreachableCode error *) 26 | i := 44; (* No additional warnings *) 27 | i := 19; 28 | END_IF; 29 | i := i + 2; 30 | END_WHILE; 31 | I := 0; 32 | END_PROGRAM -------------------------------------------------------------------------------- /plcrex/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of PLCreX (https://github.com/marwern/PLCreX). 3 | # 4 | # Copyright (c) 2022-2024 Marcel C. Werner. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | __app_name__ = "plcrex" 20 | __version__ = "2.0.0" 21 | __owner__ = "Marcel C. Werner" 22 | __copyright__ = "2022-2024, " + __owner__ -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | 13 | 14 | if "%1" == "" goto help 15 | 16 | %SPHINXBUILD% >NUL 2>NUL 17 | if errorlevel 9009 ( 18 | echo. 19 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 20 | echo.installed, then set the SPHINXBUILD environment variable to point 21 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 22 | echo.may add the Sphinx directory to PATH. 23 | echo. 24 | echo.If you don't have Sphinx installed, grab it from 25 | echo.http://sphinx-doc.org/ 26 | exit /b 1 27 | ) 28 | 29 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 30 | goto end 31 | 32 | :help 33 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 34 | 35 | :end 36 | popd 37 | -------------------------------------------------------------------------------- /plcrex/__main__.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of PLCreX (https://github.com/marwern/PLCreX). 3 | # 4 | # Copyright (c) 2022-2024 Marcel C. Werner. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | from plcrex import cli 20 | from plcrex import __app_name__ 21 | 22 | def main(): 23 | cli.app(prog_name=__app_name__) 24 | 25 | if __name__ == "__main__": 26 | main() -------------------------------------------------------------------------------- /tests/test_help.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of PLCreX (https://github.com/marwern/PLCreX). 3 | # 4 | # Copyright (c) 2022-2024 Marcel C. Werner. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | from typer.testing import CliRunner 20 | 21 | from plcrex import cli 22 | 23 | runner = CliRunner() 24 | 25 | 26 | def test_help(): 27 | result = runner.invoke(cli.app, ["--help"]) 28 | assert result.exit_code == 0 29 | -------------------------------------------------------------------------------- /tests/st_examples/TC082.st: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Real POU 3 | // ******************************************************************************** 4 | 5 | FUNCTION_BLOCK TC082 6 | VAR_INPUT 7 | IN : BOOL; 8 | PT : INT; 9 | END_VAR 10 | VAR_OUTPUT 11 | Q : BOOL; 12 | ET : INT; 13 | END_VAR 14 | VAR 15 | CYCLE : INT; 16 | TIMER : INT; 17 | TIMERN : INT; 18 | GE7_OUT : BOOL; 19 | ADD8_OUT : INT; 20 | SEL3_OUT : INT; 21 | SEL5_OUT : INT; 22 | SEL2_OUT : INT; 23 | SEL6_OUT : INT; 24 | SEL1_OUT : BOOL; 25 | SEL4_OUT : BOOL; 26 | END_VAR 27 | 28 | GE7_OUT := GE(TIMER, PT); 29 | ADD8_OUT := ADD(TIMER, CYCLE); 30 | SEL3_OUT := SEL(GE7_OUT, TIMER, ADD8_OUT); 31 | SEL5_OUT := SEL(IN, SEL3_OUT, 0); 32 | SEL2_OUT := SEL(GE7_OUT, PT, TIMER); 33 | SEL6_OUT := SEL(IN, SEL2_OUT, 0); 34 | SEL1_OUT := SEL(GE7_OUT, true, false); 35 | SEL4_OUT := SEL(IN, SEL1_OUT, false); 36 | Q := SEL4_OUT; 37 | ET := SEL6_OUT; 38 | TIMERN := SEL5_OUT; 39 | TIMER := TIMERN; 40 | END_FUNCTION_BLOCK -------------------------------------------------------------------------------- /plcrex/tools/st2qrz/call_st2qrz_compiler.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of PLCreX (https://github.com/marwern/PLCreX). 3 | # 4 | # Copyright (c) 2022-2024 Marcel C. Werner. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | from plcrex.tools.st2qrz.pyd.st2qrz_compiler import * 20 | from plcrex.tools.misc.generic_functions import * 21 | 22 | 23 | def cli( 24 | source: Path, 25 | export: Path, 26 | ): 27 | print_header( 28 | ST2QRZ.__tool__, 29 | ST2QRZ.__version__, 30 | ST2QRZ.__author__ 31 | ) 32 | ST2QRZ().run(source, export) 33 | print_footer() 34 | -------------------------------------------------------------------------------- /plcrex/tools/st2scl/call_st2scl_compiler.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of PLCreX (https://github.com/marwern/PLCreX). 3 | # 4 | # Copyright (c) 2022-2024 Marcel C. Werner. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | from plcrex.tools.st2scl.pyd.st2scl_compiler import * 20 | from plcrex.tools.misc.generic_functions import * 21 | 22 | 23 | def cli( 24 | source: Path, 25 | export: Path, 26 | kicodia: Path, 27 | mode: str 28 | ): 29 | print_header( 30 | ST2SCL.__tool__, 31 | ST2SCL.__version__, 32 | ST2SCL.__author__ 33 | ) 34 | ST2SCL().run(source, export, kicodia, mode) 35 | print_footer() 36 | -------------------------------------------------------------------------------- /plcrex/tools/tcgen/call_test_case_gen.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of PLCreX (https://github.com/marwern/PLCreX). 3 | # 4 | # Copyright (c) 2022-2024 Marcel C. Werner. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | from plcrex.tools.tcgen.pyd.test_case_gen import * 20 | from plcrex.tools.misc.generic_functions import * 21 | 22 | 23 | def cli( 24 | formula: str, 25 | sc: bool, 26 | dc: bool, 27 | mcdc: bool, 28 | mcc: bool 29 | ): 30 | print_header( 31 | TestCaseGen.__tool__, 32 | TestCaseGen.__version__, 33 | TestCaseGen.__author__ 34 | ) 35 | TestCaseGen(formula, sc, dc, mcdc, mcc).create() 36 | print_footer() 37 | -------------------------------------------------------------------------------- /tests/test_st2qrz.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of PLCreX (https://github.com/marwern/PLCreX). 3 | # 4 | # Copyright (c) 2022-2024 Marcel C. Werner. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | from typer.testing import CliRunner 20 | from plcrex import cli 21 | 22 | runner = CliRunner() 23 | 24 | 25 | def test_help1(): 26 | result = runner.invoke(cli.app, ["st-to-qrz", "--help"]) 27 | assert result.exit_code == 0 28 | 29 | def test_tc01_22(): 30 | for i in range(1, 22): 31 | if i != 3: 32 | result = runner.invoke(cli.app, 33 | ["st-to-qrz", fr"tests/st_to_synchr_models/TC{i:02}.st", 34 | fr"exports/TC{i:02}.qrz"]) 35 | assert result.exit_code == 0 36 | assert f"Success!" in result.stdout 37 | -------------------------------------------------------------------------------- /plcrex/data/grammars/DOTgrammar.lark: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // Start 3 | // ******************************************************************************** 4 | start: digraph 5 | 6 | // ******************************************************************************** 7 | // Header inlcuding POU name 8 | // ******************************************************************************** 9 | name: NAME 10 | digraph: "digraph G {rankdir=LR;graph [pad=\"0.5\", nodesep=\"1\", ranksep=\"2\"]; splines=spline;node [shape=oval fillcolor=white style=filled];subgraph cluster_1{label=\"POU-Name:\n"name"\"; style=rounded;bgcolor=slategray1;fontsize = 30;" dependencies "}}" 11 | 12 | // ******************************************************************************** 13 | // Header inlcuding POU name 14 | // ******************************************************************************** 15 | dependencies: entry* 16 | entry: NAME "->" NAME ("," NAME)* 17 | 18 | 19 | // ******************************************************************************** 20 | // Generic statements 21 | // ******************************************************************************** 22 | %ignore " " 23 | MULTI_LINE_COMMENT: /\(\*.*?\*\)/s 24 | SINGLE_LINE_COMMENT: /\s*/ "//" /[^\n]/* 25 | %ignore WS 26 | %ignore MULTI_LINE_COMMENT 27 | %ignore SINGLE_LINE_COMMENT 28 | %import common.WS 29 | NAME: /[a-zA-Z_]\w*/ -------------------------------------------------------------------------------- /docs/source/install.rst: -------------------------------------------------------------------------------- 1 | Installation 2 | ============ 3 | 4 | .. install: 5 | 6 | Prerequisites 7 | ------------- 8 | 9 | * Python v3.9 [`.url `_] 10 | * Operating System: Windows 11 | * Microsoft Build Tools 2015 [`.url `_] 12 | 13 | PLCreX Installation via PyPI 14 | ---------------------------- 15 | Run the following command to get the latest PLCreX from PyPI.org [`.url `_] 16 | 17 | .. code:: console 18 | 19 | pip install plcrex 20 | 21 | PLCreX Installation via GitHub 22 | ------------------------------ 23 | 1. Download or clone PLCreX's GitHub repository [`.url `_] 24 | 2. Run the following batch script to automatically create a virtual environment (venv) and install dependencies 25 | 26 | .. code:: console 27 | 28 | install-windows.bat 29 | 30 | External tools called by PLCreX 31 | ------------------------------- 32 | 1. IEC-Checker - Static analysis of IEC 61131-3 programs 33 | - Download v0.4 via GitHub [`.url `_] 34 | 2. NuSMV - Symbolic Model Checker 35 | - Download v2.6.0 via NuSMV's homepage [`.url `_] 36 | 3. Kicodia 37 | - Download v122798884 via KIELER's download page [`.url `_] -------------------------------------------------------------------------------- /plcrex/tools/ieccheck/iec_checker.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of PLCreX (https://github.com/marwern/PLCreX). 3 | # 4 | # Copyright (c) 2022-2024 Marcel C. Werner. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | from plcrex.tools.misc.generic_functions import * 20 | from pathlib import Path 21 | from subprocess import run 22 | 23 | 24 | class IECChecker: 25 | __version__ = "2.0.0" 26 | __author__ = "Marcel C. Werner" 27 | __tool__ = "IEC-Checker" 28 | 29 | def __init__( 30 | self, 31 | src: Path, 32 | exe: Path, 33 | option: str, 34 | dest: Path 35 | ): 36 | self.src = src 37 | self.exe = exe 38 | self.option = option 39 | self.dest = dest 40 | 41 | def run_checker(self): 42 | run([rf'{self.exe}', self.src, self.option], stdout=open(self.dest, 'w')) 43 | return 44 | -------------------------------------------------------------------------------- /plcrex/tools/stp/call_st_parser.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of PLCreX (https://github.com/marwern/PLCreX). 3 | # 4 | # Copyright (c) 2022-2024 Marcel C. Werner. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | from plcrex.tools.stp.st_parser import * 20 | from pathlib import Path 21 | import os 22 | 23 | 24 | def cli(source: Path, export: Path, filename: str, txt: bool, dot: bool, beckhoff: bool): 25 | print_header( 26 | STParser.__tool__, 27 | STParser.__version__, 28 | STParser.__author__ 29 | ) 30 | if source.is_file() and source.suffix == '.st': 31 | dir_path = Path(fr'{export}\PLCreX_outputs') 32 | # Ensure the directory exists 33 | os.makedirs(dir_path, exist_ok=True) 34 | STParser(source, dir_path, filename, txt, dot, beckhoff).translate() 35 | else: 36 | raise RuntimeError("no ST file found") 37 | print_footer() 38 | -------------------------------------------------------------------------------- /tests/test_fbdia.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of PLCreX (https://github.com/marwern/PLCreX). 3 | # 4 | # Copyright (c) 2022-2024 Marcel C. Werner. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | from typer.testing import CliRunner 20 | 21 | from plcrex import cli 22 | 23 | runner = CliRunner() 24 | 25 | def test_help(): 26 | result = runner.invoke(cli.app, ["impact-analysis", "--help"]) 27 | assert result.exit_code == 0 28 | 29 | 30 | def test_wrong_file(): 31 | result = runner.invoke(cli.app, ["impact-analysis", r".\tests\other_examples\TC001_wrong_file.txt", r".\exports\st2ia1"]) 32 | assert result.exit_code == 1 33 | 34 | #test_bwd_noformal_io_analysis 35 | def test_bwd_noformal_io_analysis(): 36 | result = runner.invoke(cli.app, ["impact-analysis", r".\tests\plcopen_examples\TC006_FBD.xml", r".\exports\st2ia2"]) 37 | assert result.exit_code == 0 38 | assert f"Success!" in result.stdout 39 | -------------------------------------------------------------------------------- /plcrex/tools/fbd2st/call_fbd2st_compiler.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of PLCreX (https://github.com/marwern/PLCreX). 3 | # 4 | # Copyright (c) 2022-2024 Marcel C. Werner. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | from plcrex.tools.fbd2st.pyd.fbd2st_compiler import * 20 | from plcrex.tools.misc.generic_functions import * 21 | from pathlib import Path 22 | import os 23 | 24 | def cli(source:Path, export:Path, filename:str, bwd:bool, formal:bool): 25 | print_header( 26 | FBD2ST.__tool__, 27 | FBD2ST.__version__, 28 | FBD2ST.__author__ 29 | ) 30 | if source.is_file() and source.suffix == '.xml': 31 | dir_path = Path(fr'{export}\PLCreX_outputs') 32 | # Ensure the directory exists 33 | os.makedirs(dir_path, exist_ok=True) 34 | FBD2ST(source, dir_path, filename, bwd, formal).translate() 35 | else: 36 | raise RuntimeError("no xml file found") 37 | print_footer() 38 | -------------------------------------------------------------------------------- /docs/source/publications.rst: -------------------------------------------------------------------------------- 1 | Publications 2 | ============ 3 | 4 | .. publications: 5 | 6 | - M.C. Werner and K. Schneider, *From Imperative Sequential Structured Text Models to Synchronous Quartz and Sequentially Constructive Models*, Methoden und Beschreibungssprachen zur Modellierung und Verifikation von Schaltungen und Systemen (MBMV), 2024 7 | 8 | .. |1| unicode:: U+0020 9 | 10 | - M.C. Werner and K. Schneider, *PLCreX -- Open-Source Project for Simplification, Transformation, Analysis, and Validation of Programmable Logic Controllers*, Methoden und Beschreibungssprachen zur Modellierung und Verifikation von Schaltungen und Systemen (MBMV), 2024 11 | 12 | .. |2| unicode:: U+0020 13 | 14 | - M.C. Werner and K. Schneider, *Formal Methods-based Optimization of Dataflow Models with Translation to Synchronous Models*, Forum on Specification and Design Languages (FDL), 2023 15 | 16 | .. |3| unicode:: U+0020 17 | 18 | - M.C. Werner and K. Schneider, *From IEC 61131-3 Function Block Diagrams to Sequentially Constructive Statecharts*, Forum on Specification and Design Languages (FDL), 2022 19 | 20 | .. |4| unicode:: U+0020 21 | 22 | - M.C. Werner and K. Schneider, *Translation of Continuous Function Charts to Imperative Synchronous Quartz Programs*, Formal Methods and Models for Codesign (MEMOCODE), 2021 23 | 24 | .. |5| unicode:: U+0020 25 | 26 | - M.C. Werner and K. Schneider, *Reengineering Programmable Logic Controllers Using Synchronous Programming Languages*, Forum on Specification and Design Languages (FDL), 2020 27 | 28 | .. |6| unicode:: U+0020 -------------------------------------------------------------------------------- /plcrex/tools/xmlval/call_xml_validator.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of PLCreX (https://github.com/marwern/PLCreX). 3 | # 4 | # Copyright (c) 2022-2024 Marcel C. Werner. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | from plcrex.tools.xmlval.xml_validator import * 20 | from pathlib import Path 21 | from plcrex.tools.misc.generic_functions import * 22 | 23 | 24 | def cli(source: Path, v201: bool): 25 | print_header( 26 | XMLValidation.__tool__, 27 | XMLValidation.__version__, 28 | XMLValidation.__author__ 29 | ) 30 | if source.is_file() and source.suffix == '.xml': 31 | if v201: 32 | # tc6_xml_v201.xsd (https: // plcopen.org / downloads / plcopen-xml-version-201-xsd-file-0) 33 | XMLValidation(source, "tc6_xml_v201.xsd").validate() 34 | else: 35 | # tc6_xml_v10.xsd (Beremiz v1.2) 36 | XMLValidation(source, "tc6_xml_v10.xsd").validate() 37 | else: 38 | raise RuntimeError("no xml file found") 39 | print_footer() 40 | -------------------------------------------------------------------------------- /plcrex/tools/xmlval/xml_validator.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of PLCreX (https://github.com/marwern/PLCreX). 3 | # 4 | # Copyright (c) 2022-2024 Marcel C. Werner. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | from pathlib import Path 20 | from plcrex.tools.misc.generic_functions import * 21 | import xmlschema 22 | 23 | 24 | class XMLValidation: 25 | __version__ = "2.0.0" 26 | __author__ = "Marcel C. Werner" 27 | __tool__ = "XML-Validator" 28 | 29 | def __init__(self, 30 | xml_file: Path, 31 | validation_file: str 32 | ): 33 | self.xml_file = xml_file 34 | self.validation_file = validation_file 35 | #logging.debug( 36 | # f"Module: {self.__tool__}, Version: {self.__version__}, Author: {self.__author__}") 37 | 38 | 39 | 40 | def validate(self): 41 | xsd_file = get_file(fr'plcrex\data\tc6\{self.validation_file}') 42 | 43 | # create validation scheme 44 | scheme = xmlschema.XMLSchema(xsd_file) 45 | 46 | # validate PLCopen xml file 47 | scheme.validate(self.xml_file) 48 | -------------------------------------------------------------------------------- /tests/test_tcgen.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of PLCreX (https://github.com/marwern/PLCreX). 3 | # 4 | # Copyright (c) 2022-2024 Marcel C. Werner. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | from typer.testing import CliRunner 20 | 21 | from plcrex import cli 22 | 23 | runner = CliRunner() 24 | 25 | 26 | def test_help(): 27 | result = runner.invoke(cli.app, ["test-case-gen", "--help"]) 28 | assert result.exit_code == 0 29 | 30 | 31 | def test_ds2ts_001(): 32 | result = runner.invoke(cli.app, ["test-case-gen", "a&b"]) 33 | assert result.exit_code == 0 34 | assert f"Success!" in result.stdout 35 | 36 | def test_ds2ts_002(): 37 | result = runner.invoke(cli.app, ["test-case-gen", "--sc", "a&b"]) 38 | assert result.exit_code == 0 39 | assert f"Success!" in result.stdout 40 | 41 | def test_ds2ts_003(): 42 | result = runner.invoke(cli.app, ["test-case-gen", "--mcdc", "a&b"]) 43 | assert result.exit_code == 0 44 | assert f"Success!" in result.stdout 45 | 46 | def test_ds2ts_004(): 47 | result = runner.invoke(cli.app, ["test-case-gen", "--mcc", "a&b"]) 48 | assert result.exit_code == 0 49 | assert f"Success!" in result.stdout -------------------------------------------------------------------------------- /plcrex/tools/fbdia/call_io_analysis.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of PLCreX (https://github.com/marwern/PLCreX). 3 | # 4 | # Copyright (c) 2022-2024 Marcel C. Werner. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | from plcrex.tools.fbdia.pyd.io_analysis import * 20 | from plcrex.tools.fbd2st import call_fbd2st_compiler 21 | from pathlib import Path 22 | from plcrex.tools.misc.generic_functions import * 23 | import os 24 | 25 | def cli(source: Path, export: Path, filename: str): 26 | print_header( 27 | IOAnalysis.__tool__, 28 | IOAnalysis.__version__, 29 | IOAnalysis.__author__ 30 | ) 31 | if source.is_file() and source.suffix == '.xml': 32 | dir_path = Path(fr'{export}\PLCreX_outputs') 33 | # Ensure the directory exists 34 | os.makedirs(dir_path, exist_ok=True) 35 | 36 | # 1. FBD-to-ST, backward + no-formal 37 | call_fbd2st_compiler.cli(source, export, filename, True, False) 38 | 39 | # 2. ST-to-I/O Dependency 40 | IOAnalysis(Path(fr'{dir_path}\{filename}.st'), dir_path, filename).data_flow_analysis_st() 41 | else: 42 | raise RuntimeError("no xml file found") 43 | print_footer() 44 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools>=61.0", "wheel"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | [project] 6 | name = "plcrex" 7 | version = "2.0.0" 8 | requires-python = ">=3.9" 9 | authors = [ 10 | { name="Marcel C. Werner", email="plcrex.info@gmail.com" }, 11 | ] 12 | description = "PLCreX - Simplification, Transformation, Analysis, and Validation of IEC 61131-3 Programmable Logic Controllers" 13 | readme = "README.md" 14 | classifiers = [ 15 | "Programming Language :: Python :: 3.9", 16 | "Operating System :: Microsoft :: Windows", 17 | ] 18 | license = {file = "LICENSE"} 19 | keywords = ["PLC", "SPS", "IEC-61131", "FBD", "ST", "testing", "development", "verification"] 20 | dependencies = [ 21 | "attrs==23.1.0", 22 | "click==8.1.6", 23 | "colorama==0.4.5", 24 | "coverage==6.5.0", 25 | "coverage-badge==1.1.0", 26 | "dd==0.5.7", 27 | "dicttoxml2==2.1.0", 28 | "elementpath==3.0.2", 29 | "exceptiongroup==1.2.0", 30 | "iniconfig==2.0.0", 31 | "lark==1.1.7", 32 | "markdown-it-py==3.0.0", 33 | "mdurl==0.1.2", 34 | "packaging==23.2", 35 | "pluggy==1.3.0", 36 | "pydot==1.4.2", 37 | "pyeda==0.29.0", 38 | "Pygments==2.17.2", 39 | "pyparsing==3.1.1", 40 | "pytest==7.2.0", 41 | "rich==13.5.1", 42 | "termcolor==2.3.0", 43 | "tomli==2.0.1", 44 | "typer==0.9.0", 45 | "typing_extensions==4.8.0", 46 | "xmlschema==2.1.1", 47 | "z3-solver==4.12.2.0", 48 | ] 49 | 50 | [tool.setuptools] 51 | #packages = ["plcrex"] 52 | include-package-data = true 53 | 54 | [tool.setuptools.packages] 55 | find = {} # Scan the project directory with the default parameters 56 | 57 | [project.urls] 58 | "Homepage" = "https://github.com/marwern/PLCreX" 59 | "Bug Tracker" = "https://github.com/marwern/PLCreX/issues" 60 | -------------------------------------------------------------------------------- /tests/test_xmlval.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of PLCreX (https://github.com/marwern/PLCreX). 3 | # 4 | # Copyright (c) 2022-2024 Marcel C. Werner. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | from typer.testing import CliRunner 20 | 21 | from plcrex import cli 22 | 23 | runner = CliRunner() 24 | 25 | 26 | def test_help(): 27 | result = runner.invoke(cli.app, ["xml-validator", "--help"]) 28 | assert result.exit_code == 0 29 | 30 | 31 | def test_v201_passed(): 32 | result = runner.invoke(cli.app, ["xml-validator", "--v201", r".\tests\plcopen_examples\TC001.xml"]) 33 | assert result.exit_code == 0 34 | assert f"Success!" in result.stdout 35 | 36 | 37 | def test_v201_failed(): 38 | result = runner.invoke(cli.app, ["xml-validator", "--v201", r".\tests\plcopen_examples\TC001_failed.xml"]) 39 | assert result.exit_code == 1 40 | 41 | #TODO 42 | #def test_v10_passed(): 43 | 44 | def test_v10_failed(): 45 | result = runner.invoke(cli.app, ["xml-validator", r".\tests\plcopen_examples\TC001.xml"]) 46 | assert result.exit_code == 1 47 | 48 | 49 | def test_wrong_file(): 50 | result = runner.invoke(cli.app, ["xml-validator", r".\tests\other_examples\TC001_wrong_file.txt"]) 51 | assert result.exit_code == 1 52 | -------------------------------------------------------------------------------- /tests/test_version.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of PLCreX (https://github.com/marwern/PLCreX). 3 | # 4 | # Copyright (c) 2022-2024 Marcel C. Werner. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | from typer.testing import CliRunner 20 | from plcrex import cli 21 | from plcrex import __app_name__, __version__ 22 | 23 | runner = CliRunner() 24 | 25 | 26 | def test_version_1(): 27 | result = runner.invoke(cli.app, ["--version"]) 28 | assert result.exit_code == 0 29 | assert fr""" 30 | PLCreX-{__version__}, plcrex.info@gmail.com 31 | 32 | Copyright (c) 2022-2024 Marcel C. Werner. 33 | 34 | This program is free software: you can redistribute it and/or modify 35 | it under the terms of the GNU General Public License as published by 36 | the Free Software Foundation, version 3. 37 | 38 | This program is distributed in the hope that it will be useful, but 39 | WITHOUT ANY WARRANTY; without even the implied warranty of 40 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 41 | General Public License for more details. 42 | 43 | You should have received a copy of the GNU General Public License 44 | along with this program. If not, see . 45 | """ in result.stdout 46 | -------------------------------------------------------------------------------- /tests/test_st2scl.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of PLCreX (https://github.com/marwern/PLCreX). 3 | # 4 | # Copyright (c) 2022-2024 Marcel C. Werner. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | from typer.testing import CliRunner 20 | from plcrex import cli 21 | 22 | runner = CliRunner() 23 | 24 | 25 | def test_help1(): 26 | result = runner.invoke(cli.app, ["st-to-scl", "--help"]) 27 | assert result.exit_code == 0 28 | 29 | def test_help2(): 30 | result = runner.invoke(cli.app, ["st-to-sctx", "--help"]) 31 | assert result.exit_code == 0 32 | 33 | def test_tc01_22_scl(): 34 | for i in range(1, 22): 35 | if i != 3: 36 | result = runner.invoke(cli.app, 37 | ["st-to-scl", fr"tests/st_to_synchr_models/TC{i:02}.st", 38 | fr"exports/TC{i:02}.scl"]) 39 | assert result.exit_code == 0 40 | assert f"Success!" in result.stdout 41 | 42 | def test_tc01_22_sctx(): 43 | for i in range(1, 22): 44 | if i != 3: 45 | result = runner.invoke(cli.app, 46 | ["st-to-sctx", fr"tests/st_to_synchr_models/TC{i:02}.st", 47 | fr"exports/TC{i:02}.sctx", r".\bin\kicodia-win.bat"]) 48 | assert result.exit_code == 0 49 | assert f"Success!" in result.stdout 50 | -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | PLCreX - Simplification, Transformation, Analysis, and Validation of IEC 61131-3 Programmable Logic Controllers 2 | =============================================================================================================== 3 | 4 | .. index: 5 | 6 | About PLCreX 7 | ------------ 8 | 9 | PLCreX is a modular command-line interface application tailored for IEC 61131-3 Programmable Logic Controllers (PLCs) and beyond. It's designed with a focus on issues such as review, redesign, reuse, and reliability, among others. This project is driven by our ongoing research and we're committed to progressively integrating new features. PLCreX serves as a comprehensive suite of analysis and reuse capabilities for existing IEC 61131-3 Program Organization Units (POUs) implemented in Function Block Diagrams (FBDs) or Structured Text (ST). 10 | 11 | .. figure:: ../fig/overview.svg 12 | :align: center 13 | 14 | | 15 | 16 | 17 | .. 18 | .. toctree:: 19 | :glob: 20 | :titlesonly: 21 | 22 | * 23 | 24 | .. toctree:: 25 | :maxdepth: 2 26 | :caption: Getting Started 27 | :hidden: 28 | 29 | install 30 | test 31 | 32 | .. toctree:: 33 | :maxdepth: 2 34 | :caption: Usage 35 | :hidden: 36 | 37 | cli 38 | 39 | .. toctree:: 40 | :maxdepth: 2 41 | :caption: Validation 42 | :hidden: 43 | 44 | xml_validator 45 | 46 | .. toctree:: 47 | :maxdepth: 2 48 | :caption: Analysis 49 | :hidden: 50 | 51 | iec_checker 52 | impact_analysis 53 | st_parser 54 | test_case_gen 55 | 56 | .. toctree:: 57 | :maxdepth: 2 58 | :caption: Transformation & Simplification 59 | :hidden: 60 | 61 | fbd_to_st 62 | fbd_to_st_ext 63 | fbd_to_sctx 64 | st_to_qrz 65 | st_to_scl 66 | st_to_sctx 67 | 68 | .. toctree:: 69 | :maxdepth: 2 70 | :caption: Additional Resources 71 | :hidden: 72 | 73 | publications 74 | 75 | contact -------------------------------------------------------------------------------- /plcrex/tools/fbd2x/call_fbd_optimizer.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of PLCreX (https://github.com/marwern/PLCreX). 3 | # 4 | # Copyright (c) 2022-2024 Marcel C. Werner. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | from plcrex.tools.fbd2x.pyd.fbd_optimizer import * 20 | from plcrex.tools.fbd2st.pyd.fbd2st_compiler import * 21 | from plcrex.tools.misc.generic_functions import * 22 | from pathlib import Path 23 | import os 24 | 25 | 26 | def cli( 27 | source: Path, 28 | export: Path, 29 | filename: str, 30 | exe: Path, 31 | edge_opt: bool, 32 | var_opt: bool, 33 | op_opt: bool, 34 | target_format: str 35 | ): 36 | print_header( 37 | FBDOptimizer.__tool__, 38 | FBDOptimizer.__version__, 39 | FBDOptimizer.__author__ 40 | ) 41 | if source.is_file() and source.suffix == '.xml': 42 | dir_path = Path(fr'{export}\PLCreX_outputs') 43 | # Ensure the directory exists 44 | os.makedirs(dir_path, exist_ok=True) 45 | 46 | # 1. FBD-to-ST Translation (backward + formal) 47 | FBD2ST(source, dir_path, filename, True, True).translate() 48 | 49 | # 2. ST-to-X Translation 50 | FBDOptimizer(Path(fr'{dir_path}\{filename}.st'), 51 | dir_path, filename, exe, 52 | edge_opt, var_opt, op_opt, edge_opt or var_opt or op_opt, target_format).translate() 53 | 54 | else: 55 | raise RuntimeError("no xml file found") 56 | print_footer() 57 | -------------------------------------------------------------------------------- /tests/test_stp.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of PLCreX (https://github.com/marwern/PLCreX). 3 | # 4 | # Copyright (c) 2022-2024 Marcel C. Werner. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | from typer.testing import CliRunner 20 | 21 | from plcrex import cli 22 | 23 | runner = CliRunner() 24 | 25 | 26 | def test_help(): 27 | result = runner.invoke(cli.app, ["st-parser", "--help"]) 28 | assert result.exit_code == 0 29 | 30 | 31 | def test_dot_txt(): 32 | result = runner.invoke(cli.app, ["st-parser", r".\tests\st_examples\TC081.st", r".\exports\st2ast1"]) 33 | assert result.exit_code == 0 34 | assert f"Success!" in result.stdout 35 | 36 | 37 | def test_dot(): 38 | result = runner.invoke(cli.app, ["st-parser", r".\tests\st_examples\TC081.st", r".\exports\st2ast2", "--no-txt"]) 39 | assert result.exit_code == 0 40 | assert f"Success!" in result.stdout 41 | 42 | 43 | def test_txt(): 44 | result = runner.invoke(cli.app, ["st-parser", r".\tests\st_examples\TC081.st", r".\exports\st2ast3", "--no-dot"]) 45 | assert result.exit_code == 0 46 | assert f"Success!" in result.stdout 47 | 48 | def test_beckhoff_txt_dot(): 49 | result = runner.invoke(cli.app, ["st-parser", r".\tests\st_examples\TC079.st", r".\exports\st2ast4", "--beckhoff"]) 50 | assert result.exit_code == 0 51 | assert f"Success!" in result.stdout 52 | 53 | def test_wrong_file(): 54 | result = runner.invoke(cli.app, ["st-parser", r".\tests\other_examples\TC001_wrong_file.txt", r".\exports\st2ast5"]) 55 | assert result.exit_code == 1 56 | -------------------------------------------------------------------------------- /plcrex/tools/ieccheck/call_iec_checker.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of PLCreX (https://github.com/marwern/PLCreX). 3 | # 4 | # Copyright (c) 2022-2024 Marcel C. Werner. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | from plcrex.tools.misc.generic_functions import * 20 | from plcrex.tools.ieccheck.iec_checker import * 21 | from pathlib import Path 22 | import os 23 | 24 | 25 | def cli(source: Path, exe: Path, verbose: bool, export: Path, filename: str, help_: bool): 26 | print_header( 27 | IECChecker.__tool__, 28 | IECChecker.__version__, 29 | IECChecker.__author__ 30 | ) 31 | if source.is_file(): 32 | if exe.is_file(): 33 | dir_path = Path(fr'{export}\PLCreX_outputs') 34 | # Ensure the directory exists 35 | os.makedirs(dir_path, exist_ok=True) 36 | dest = Path(fr'{dir_path}\{filename}.log') 37 | if source.is_file() and (source.suffix == '.st' or source.suffix == '.xml'): 38 | # call iec-checker with ONE supported OPTIONS (only a subset is covered) 39 | if help_: 40 | IECChecker(source, exe, '--help', dest).run_checker() 41 | elif not verbose: 42 | IECChecker(source, exe, '--quiet', dest).run_checker() 43 | elif verbose: 44 | IECChecker(source, exe, '--verbose', dest).run_checker() 45 | with open(dest, 'rt') as file: 46 | print(file.read()) 47 | file.close() 48 | else: 49 | raise RuntimeError("no ST/xml file found") 50 | else: 51 | raise RuntimeError(rf"no .exe found at {exe}") 52 | print_footer() 53 | -------------------------------------------------------------------------------- /plcrex/tools/stp/st_parser.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of PLCreX (https://github.com/marwern/PLCreX). 3 | # 4 | # Copyright (c) 2022-2024 Marcel C. Werner. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | from lark import Lark, tree 20 | from pathlib import Path 21 | from plcrex.tools.misc.generic_functions import * 22 | 23 | class STParser: 24 | __version__ = "2.0.0" 25 | __author__ = "Marcel C. Werner" 26 | __tool__ = "ST-Parser" 27 | 28 | def __init__( 29 | self, 30 | src: Path, 31 | dir_path: Path, 32 | filename: str, 33 | txt: bool = False, 34 | dot: bool = False, 35 | beckhoff: bool = False 36 | ): 37 | self.src = src 38 | self.dir_path = dir_path 39 | self.filename = filename 40 | self.txt = txt 41 | self.dot = dot 42 | self.beckhoff = beckhoff 43 | 44 | def read_src(self, src_dir: Path): 45 | f = open(src_dir, 'rt') 46 | src_txt = f.read() 47 | f.close() 48 | return src_txt 49 | 50 | def translate(self): 51 | 52 | if self.beckhoff: 53 | grammar = get_file(r'plcrex\data\grammars\STgrammar_Beckhoff.lark') 54 | else: 55 | grammar = get_file(r'plcrex\data\grammars\STgrammar.lark') 56 | 57 | parser = Lark(grammar, maybe_placeholders=False, keep_all_tokens=False) 58 | source = self.read_src(self.src) 59 | 60 | # write (pretty) tree as .txt 61 | if self.txt: 62 | txt_export = open(fr'{self.dir_path}\{self.filename}.txt', "w") 63 | txt_export.write(str(parser.parse(source).pretty())) 64 | txt_export.close() 65 | 66 | # write tree as .dot file 67 | if self.dot: 68 | tree.pydot__tree_to_dot(parser.parse(source), fr'{self.dir_path}\{self.filename}.dot') 69 | -------------------------------------------------------------------------------- /docs/source/impact_analysis.rst: -------------------------------------------------------------------------------- 1 | I/O-Impact Analysis 2 | =================== 3 | 4 | .. impact_analysis: 5 | 6 | The I/O-Impact Analysis feature identifies the dependencies between POU outputs and inputs. 7 | 8 | **Usage** 9 | 10 | .. code-block:: console 11 | 12 | python -m plcrex impact-analysis --help 13 | 14 | 15 | .. code:: console 16 | 17 | Usage: plcrex impact-analysis [OPTIONS] SOURCE EXPORT 18 | 19 | I/O-Impact Analysis *.xml → *.dot 20 | 21 | ╭─ Arguments ──────────────────────────────────────────────────────────────────────────────────╮ 22 | │ * source PATH source path [default: None] [required] │ 23 | │ * export PATH export path [default: None] [required] │ 24 | ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ 25 | ╭─ Options ────────────────────────────────────────────────────────────────────────────────────╮ 26 | │ --help Show this message and exit. │ 27 | ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ 28 | 29 | 30 | .. 31 | .. figure:: ../fig/impact_analysis_demo.png 32 | :align: center 33 | :width: 600px 34 | 35 | | 36 | 37 | POU ``TC006_FBD.xml`` 38 | --------------------- 39 | 40 | The following POU was manually implemented using Beremiz [`.url `_]. 41 | 42 | .. figure:: ../fig/TC006.png 43 | :align: center 44 | :width: 450px 45 | 46 | | 47 | 48 | Example 1 49 | --------- 50 | 51 | **Command** 52 | 53 | .. code-block:: console 54 | 55 | python -m plcrex impact-analysis ".\tests\plcopen_examples\TC006_FBD.xml" ".\exports\01" 56 | 57 | **Results** 58 | 59 | ``01.dot`` 60 | 61 | .. code-block:: console 62 | 63 | ... 64 | digraph G { 65 | rankdir=LR; 66 | graph [pad="0.5", nodesep="1", ranksep="2"]; 67 | splines=spline; 68 | node [shape=oval fillcolor=white style=filled]; 69 | subgraph cluster_1{ 70 | label="POU-Name:\nTC006"; 71 | style=rounded;bgcolor=slategray1;fontsize = 30; 72 | i1->o1 i2->o1 i1->o2 i2->o3 i1->o3 i3->o4 73 | } 74 | } 75 | ... 76 | 77 | .. figure:: ../fig/TC006_result.png 78 | :align: center 79 | :width: 300px 80 | 81 | | -------------------------------------------------------------------------------- /docs/source/st_to_qrz.rst: -------------------------------------------------------------------------------- 1 | ST-to-Quartz Compiler 2 | ===================== 3 | 4 | .. st_to_qrz: 5 | 6 | The ST-to-Quartz Compiler translates imperative sequential ST models to imperative synchronous Quartz models. 7 | The results are intended for reuse in model-based design and formal verification using `Averest `_ [1,2]. 8 | 9 | **Usage** 10 | 11 | .. code-block:: console 12 | 13 | python -m plcrex st-to-qrz --help 14 | 15 | 16 | .. code:: console 17 | 18 | Usage: plcrex st-to-qrz [OPTIONS] SOURCE EXPORT 19 | 20 | ST-to-Quartz Compiler *.st → *.qrz 21 | 22 | ╭─ Arguments ──────────────────────────────────────────────────────────────────────────────────╮ 23 | │ * source PATH source path [default: None] [required] │ 24 | │ * export PATH export path [default: None] [required] │ 25 | ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ 26 | ╭─ Options ────────────────────────────────────────────────────────────────────────────────────╮ 27 | │ --help Show this message and exit. │ 28 | ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ 29 | 30 | | 31 | 32 | Example: ``REPEAT-UNTIL`` loop 33 | ------------------------------------------ 34 | 35 | The following POU was manually implemented using Beremiz [`.url `_]. 36 | 37 | .. code-block:: console 38 | 39 | FUNCTION_BLOCK TC21 40 | VAR_OUTPUT 41 | y : INT; 42 | END_VAR 43 | VAR 44 | x : INT := 1; 45 | i : INT; 46 | i0 : INT := 0; 47 | i1 : INT := 10; 48 | END_VAR 49 | 50 | i:=i0; 51 | REPEAT 52 | y := i; 53 | i := i+1; 54 | UNTIL i>i1 55 | END_REPEAT; 56 | y := x; 57 | END_FUNCTION_BLOCK 58 | 59 | | 60 | 61 | 62 | **Command** 63 | 64 | .. code-block:: console 65 | 66 | python -m plcrex st-to-qrz "tests/st_to_synchr_models/TC21.st" "exports/TC21.qrz" 67 | 68 | **Result** 69 | 70 | ``TC21.qrz`` 71 | 72 | .. code-block:: console 73 | 74 | //--- This file was generated by PLCreX --- 75 | //--- https://github.com/marwern/PLCreX --- 76 | //----------------------------------------- 77 | 78 | module TC21(int !y){ 79 | int x; 80 | int i; 81 | int i0; 82 | int i1; 83 | x=1; 84 | i0=0; 85 | i1=10; 86 | i=i0; 87 | do{ 88 | y=i; 89 | next(i)=i+1; 90 | pause; 91 | }while(!(i>i1)); 92 | y=x; 93 | } 94 | -------------------------------------------------------------------------------- /docs/source/st_to_scl.rst: -------------------------------------------------------------------------------- 1 | ST-to-SCL Compiler 2 | ================== 3 | 4 | .. st_to_scl: 5 | 6 | The ST-to-SCL Compiler translates imperative sequential ST models to Sequentially Constructive Language (SCL) models. 7 | The results are intended for reuse in model-based design and formal verification using `KIELER `_ [1,2]. 9 | 10 | **Usage** 11 | 12 | .. code-block:: console 13 | 14 | python -m plcrex st-to-scl --help 15 | 16 | 17 | .. code:: console 18 | 19 | Usage: plcrex st-to-scl [OPTIONS] SOURCE EXPORT 20 | 21 | ST-to-SCL Compiler *.st → *.scl 22 | 23 | ╭─ Arguments ──────────────────────────────────────────────────────────────────────────────────╮ 24 | │ * source PATH source path [default: None] [required] │ 25 | │ * export PATH export path [default: None] [required] │ 26 | ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ 27 | ╭─ Options ────────────────────────────────────────────────────────────────────────────────────╮ 28 | │ --help Show this message and exit. │ 29 | ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ 30 | 31 | | 32 | 33 | Example: ``REPEAT-UNTIL`` loop 34 | ------------------------------------------ 35 | 36 | The following POU was manually implemented using Beremiz [`.url `_]. 37 | 38 | .. code-block:: console 39 | 40 | FUNCTION_BLOCK TC21 41 | VAR_OUTPUT 42 | y : INT; 43 | END_VAR 44 | VAR 45 | x : INT := 1; 46 | i : INT; 47 | i0 : INT := 0; 48 | i1 : INT := 10; 49 | END_VAR 50 | 51 | i:=i0; 52 | REPEAT 53 | y := i; 54 | i := i+1; 55 | UNTIL i>i1 56 | END_REPEAT; 57 | y := x; 58 | END_FUNCTION_BLOCK 59 | 60 | | 61 | 62 | 63 | **Command** 64 | 65 | .. code-block:: console 66 | 67 | python -m plcrex st-to-scl "tests/st_to_synchr_models/TC21.st" "exports/TC21.scl" 68 | 69 | **Result** 70 | 71 | ``TC21.scl`` 72 | 73 | .. code-block:: console 74 | 75 | //--- This file was generated by PLCreX --- 76 | //--- https://github.com/marwern/PLCreX --- 77 | //----------------------------------------- 78 | 79 | module TC21{ 80 | output int y; 81 | int x=1; 82 | int i; 83 | int i0=0; 84 | int i1=10; 85 | i=i0; 86 | do: 87 | y=i; 88 | pause; 89 | i=i+1; 90 | if(!(i>i1)){ 91 | goto do; 92 | }else{ 93 | y=x; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /docs/source/xml_validator.rst: -------------------------------------------------------------------------------- 1 | XML-Validator 2 | ============= 3 | 4 | .. xml_validator: 5 | 6 | The PLCopen XML-Validator feature uses ``tc6_xml_v201.xsd`` and ``tc6_xml_v10.xsd`` to validate that the PLCopen XML exchange format conforms to the PLCopen specification [`.url `_]. 7 | 8 | 9 | **Usage** 10 | 11 | .. code-block:: console 12 | 13 | python -m plcrex xml-validator --help 14 | 15 | .. code:: console 16 | 17 | Usage: plcrex xml-validator [OPTIONS] SOURCE 18 | 19 | XML-Validator *.xml → stdout 20 | 21 | ╭─ Arguments ──────────────────────────────────────────────────────────────────────────────────╮ 22 | │ * source PATH source path [default: None] [required] │ 23 | ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ 24 | ╭─ Options ────────────────────────────────────────────────────────────────────────────────────╮ 25 | │ --v201 --no-v201 use tc6_xml_v201.xsd [default: no-v201] │ 26 | │ --help Show this message and exit. │ 27 | ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ 28 | 29 | 30 | .. 31 | .. figure:: ../fig/xml_validator_demo.png 32 | :align: center 33 | :width: 600px 34 | 35 | | 36 | 37 | Example 1: ``--v201`` (PASSED) 38 | ------------------------------ 39 | 40 | **Command** 41 | 42 | .. code-block:: console 43 | 44 | python -m plcrex xml-validator --v201 ".\tests\plcopen_examples\TC001.xml" 45 | 46 | 47 | **Results** 48 | 49 | .. code-block:: console 50 | 51 | Success! 52 | 53 | 54 | Example 2: ``--v201`` (FAILED) 55 | ------------------------------ 56 | 57 | **Command** 58 | 59 | .. code-block:: console 60 | 61 | python -m plcrex xml-validator --v201 ".\tests\plcopen_examples\TC001_failed.xml" 62 | 63 | 64 | **Results** 65 | 66 | .. code-block:: console 67 | 68 | ... 69 | XMLSchemaDecodeError: failed validating '2022-09-01 14:53:16' with 70 | XsdAtomicBuiltin(name='xs:dateTime'): 71 | 72 | Reason: attribute modificationDateTime='2022-09-01 14:53:16': Invalid datetime string '2022-09-01 73 | 14:53:16' for 74 | 75 | Schema: 76 | 77 | 79 | 80 | 81 | 82 | ... -------------------------------------------------------------------------------- /tests/test_ieccheck.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of PLCreX (https://github.com/marwern/PLCreX). 3 | # 4 | # Copyright (c) 2022-2024 Marcel C. Werner. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | from typer.testing import CliRunner 20 | 21 | from plcrex import cli 22 | 23 | runner = CliRunner() 24 | 25 | 26 | def test_help(): 27 | result = runner.invoke(cli.app, ["iec-check", "--help"]) 28 | assert result.exit_code == 0 29 | 30 | 31 | def test_help_iec_checker(): 32 | result = runner.invoke(cli.app, ["iec-check", r".\tests\st_examples\TC001.st", r".\bin\iec_checker_Windows_x86_64_v0.4.exe", "--help_iec_checker", r".\exports\iec_checker1"]) 33 | assert result.exit_code == 0 34 | assert f"Success!" in result.stdout 35 | 36 | 37 | def test_verbose_st(): 38 | result = runner.invoke(cli.app, ["iec-check", r".\tests\st_examples\TC001.st", r".\bin\iec_checker_Windows_x86_64_v0.4.exe", "--verbose", r".\exports\iec_checker2"]) 39 | assert result.exit_code == 0 40 | assert f"Success!" in result.stdout 41 | 42 | 43 | def test_quiet_st(): 44 | result = runner.invoke(cli.app, ["iec-check", r".\tests\st_examples\TC001.st", r".\bin\iec_checker_Windows_x86_64_v0.4.exe", r".\exports\iec_checker3"]) 45 | assert result.exit_code == 0 46 | assert f"Success!" in result.stdout 47 | 48 | 49 | def test_wrong_file(): 50 | result = runner.invoke(cli.app, ["iec-check", r".\tests\other_examples\TC001_wrong_file.txt", r".\bin\iec_checker_Windows_x86_64_v0.4.exe", r".\exports\iec_checker4"]) 51 | assert result.exit_code == 1 52 | 53 | 54 | def test_verbose_xml(): 55 | result = runner.invoke(cli.app, ["iec-check", r".\tests\plcopen_examples\TC001.xml", r".\bin\iec_checker_Windows_x86_64_v0.4.exe", "--verbose", r".\exports\iec_checker5"]) 56 | assert result.exit_code == 0 57 | assert f"Success!" in result.stdout 58 | 59 | 60 | def test_quiet_xml(): 61 | result = runner.invoke(cli.app, ["iec-check", r".\tests\plcopen_examples\TC001.xml", r".\bin\iec_checker_Windows_x86_64_v0.4.exe", r".\exports\iec_checker6"]) 62 | assert result.exit_code == 0 63 | assert f"Success!" in result.stdout 64 | 65 | def test_wrong_exe(): 66 | result = runner.invoke(cli.app, ["iec-check", r".\tests\plcopen_examples\TC001.xml", r".\bin\_.exe", r".\exports\iec_checker7"]) 67 | assert result.exit_code == 1 68 | -------------------------------------------------------------------------------- /docs/source/cli.rst: -------------------------------------------------------------------------------- 1 | Command Line Interface 2 | ====================== 3 | 4 | .. cli: 5 | 6 | 7 | .. code:: console 8 | 9 | Usage: plcrex [OPTIONS] COMMAND [ARGS]... 10 | 11 | ╭─ Options ────────────────────────────────────────────────────────────────────────────────────╮ 12 | │ --version │ 13 | │ --install-completion [bash|zsh|fish|powershell|pwsh] Install completion for the │ 14 | │ specified shell. │ 15 | │ [default: None] │ 16 | │ --show-completion [bash|zsh|fish|powershell|pwsh] Show completion for the │ 17 | │ specified shell, to copy it or │ 18 | │ customize the installation. │ 19 | │ [default: None] │ 20 | │ --help Show this message and exit. │ 21 | ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ 22 | ╭─ Commands ───────────────────────────────────────────────────────────────────────────────────╮ 23 | │ fbd-to-sctx FBD-to-SCCharts Compiler (Data-Flow) *.xml → *.sctx │ 24 | │ fbd-to-st FBD-to-ST Compiler *.xml → *.st │ 25 | │ fbd-to-st-ext FBD-to-ST Compiler (extended) *.xml → *.st │ 26 | │ iec-check IEC-Checker *.st → *.log │ 27 | │ impact-analysis I/O-Impact Analysis *.xml → *.dot │ 28 | │ st-parser ST-Parser *.st → *.dot/*.txt │ 29 | │ st-to-qrz ST-to-Quartz Compiler *.st → *.qrz │ 30 | │ st-to-scl ST-to-SCL Compiler *.st → *.scl │ 31 | │ st-to-sctx ST-to-SCCharts Compiler (Control-Flow) *.st → *.sctx │ 32 | │ test-case-gen Test-Case-Generator stdin → stdout │ 33 | │ xml-validator XML-Validator *.xml → stdout │ 34 | ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ 35 | 36 | 37 | | 38 | 39 | Installed via PyPI 40 | ------------------ 41 | 42 | 1. Run the following command to call PLCreX's help 43 | 44 | .. code:: console 45 | 46 | python -m plcrex --help 47 | 48 | Installed via GitHub 49 | -------------------- 50 | 51 | 1. Run the following command to activate virtual environment (venv) 52 | 53 | .. code:: console 54 | 55 | run.bat 56 | 57 | 2. Run the following command to call PLCreX's help 58 | 59 | .. code-block:: console 60 | 61 | python -m plcrex --help -------------------------------------------------------------------------------- /docs/source/st_to_sctx.rst: -------------------------------------------------------------------------------- 1 | ST-to-SCCharts Compiler 2 | ======================= 3 | 4 | .. st_to_sctx: 5 | 6 | The ST-to-SCCharts Compiler translates imperative sequential ST models to Sequentially Constructive Statecharts (SCCharts). 7 | The results are intended for reuse in model-based design and formal verification using `KIELER `_ [1,2]. 9 | 10 | **Usage** 11 | 12 | .. code-block:: console 13 | 14 | python -m plcrex st-to-sctx --help 15 | 16 | 17 | .. code:: console 18 | 19 | Usage: plcrex st-to-sctx [OPTIONS] SOURCE EXPORT BAT_DIR 20 | 21 | ST-to-SCCharts Compiler (Control-Flow) *.st → *.sctx 22 | 23 | ╭─ Arguments ──────────────────────────────────────────────────────────────────────────────────╮ 24 | │ * source PATH source path [default: None] [required] │ 25 | │ * export PATH export path [default: None] [required] │ 26 | │ * bat_dir PATH kicodia-win.bat path [default: None] [required] │ 27 | ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ 28 | ╭─ Options ────────────────────────────────────────────────────────────────────────────────────╮ 29 | │ --help Show this message and exit. │ 30 | ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ 31 | 32 | | 33 | 34 | Example: ``REPEAT-UNTIL`` loop 35 | ------------------------------------------ 36 | 37 | The following POU was manually implemented using Beremiz [`.url `_]. 38 | 39 | .. code-block:: console 40 | 41 | FUNCTION_BLOCK TC21 42 | VAR_OUTPUT 43 | y : INT; 44 | END_VAR 45 | VAR 46 | x : INT := 1; 47 | i : INT; 48 | i0 : INT := 0; 49 | i1 : INT := 10; 50 | END_VAR 51 | 52 | i:=i0; 53 | REPEAT 54 | y := i; 55 | i := i+1; 56 | UNTIL i>i1 57 | END_REPEAT; 58 | y := x; 59 | END_FUNCTION_BLOCK 60 | 61 | | 62 | 63 | 64 | **Command** 65 | 66 | .. code-block:: console 67 | 68 | python -m plcrex st-to-sctx "tests/st_to_synchr_models/TC21.st" "exports/TC21.sctx" "./bin\kicodia-win.bat" 69 | 70 | **Result** 71 | 72 | ``TC21.sctx`` 73 | 74 | .. code-block:: console 75 | 76 | scchart TC21 { 77 | output int y 78 | int x 79 | int i 80 | int i0 81 | int i1 82 | 83 | region region0 { 84 | initial state state1 85 | immediate do i1 = 10; i0 = 0; x = 1; i = i0 go to state5 86 | 87 | state state5 88 | immediate do y = i go to state6 89 | 90 | state state6 91 | do i = i + 1 go to state9 92 | 93 | state state9 94 | immediate if !(i > i1) go to state5 95 | immediate do y = x go to finalState10 96 | 97 | final state finalState10 98 | } 99 | } 100 | 101 | .. figure:: ../fig/TC21.png 102 | :align: center 103 | :width: 300px 104 | 105 | 106 | | -------------------------------------------------------------------------------- /docs/source/iec_checker.rst: -------------------------------------------------------------------------------- 1 | IEC-Checker 2 | =========== 3 | 4 | .. iec_checker: 5 | 6 | The IEC-Checker is an external tool for static code analysis of IEC 61131-3 POUs and called via PLCreX. Among other things, it checks the following issues [`.url `_]: 7 | 8 | * PLCopen Guidelines 9 | 10 | * CP1: Access to a member shall be by name 11 | * CP2: All code shall be used in the application 12 | * CP3: All variables shall be initialized before being used 13 | * CP4: Direct addressing should not overlap 14 | * CP6: Avoid external variables in functions, function blocks and classes 15 | * CP8: Floating point comparison shall not be equality or inequality 16 | * CP9: Limit the complexity of POU code 17 | * CP13: POUs shall not call themselves directly or indirectly 18 | * CP25: Data type conversion should be explicit 19 | * CP28: Time and physical measures comparisons shall not be equality or inequality 20 | * L10: Usage of CONTINUE and EXIT instruction should be avoided 21 | * L17: Each IF instruction should have an ELSE clause 22 | * Declaration analysis for derived types 23 | * Intraprocedural control flow analysis: detection of unreachable code blocks inside the POUs 24 | * Detection of unused variables 25 | 26 | .. note:: 27 | IEC-Checker can only work with IEC 61131-3 ST supported by the matiec compiler [`.url `_]. 28 | Most likely, it will fail on the source code containing non-standard language extensions. 29 | 30 | 31 | **Usage** 32 | 33 | .. code-block:: console 34 | 35 | python -m plcrex iec-check --help 36 | 37 | .. code:: console 38 | 39 | Usage: plcrex iec-check [OPTIONS] SOURCE EXE EXPORT 40 | 41 | IEC-Checker *.st → *.log 42 | 43 | ╭─ Arguments ──────────────────────────────────────────────────────────────────────────────────╮ 44 | │ * source PATH source path [default: None] [required] │ 45 | │ * exe PATH iec_checker_Windows_x86_64_v0.4.exe path [default: None] [required] │ 46 | │ * export PATH export path [default: None] [required] │ 47 | ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ 48 | ╭─ Options ────────────────────────────────────────────────────────────────────────────────────╮ 49 | │ --verbose --no-verbose print full log [default: no-verbose] │ 50 | │ --help_iec_checker call iec-check help │ 51 | │ --help Show this message and exit. │ 52 | ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ 53 | 54 | 55 | .. 56 | .. figure:: ../fig/iec_checker_demo.png 57 | :align: center 58 | :width: 600px 59 | 60 | | 61 | 62 | POU ``TC083.st`` 63 | ---------------- 64 | 65 | .. code-block:: console 66 | 67 | PROGRAM TC083 68 | VAR_ACCESS 69 | Var1 : DINT; 70 | Var2 : DINT; 71 | Var3 : DINT; 72 | END_VAR 73 | 74 | Var1 := 19 / 0; 75 | Var2 := Var1 / 1; 76 | END_PROGRAM 77 | 78 | 79 | Example 1 80 | --------- 81 | 82 | **Command** 83 | 84 | .. code-block:: console 85 | 86 | python -m plcrex iec-check --verbose ".\tests\st_examples\TC083.st" "./bin/iec_checker_Windows_x86_64_v0.4.exe" ".\exports\01" 87 | 88 | **Results** 89 | 90 | ``01.log`` 91 | 92 | .. code-block:: console 93 | 94 | ... 95 | Running check for program TC083 96 | 5:8 UnusedVariable: Found unused local variable: VAR3 97 | 8:12 ZeroDivision: Constant 19 is divided by zero! 98 | 3:8 PLCOPEN-CP3: Variable VAR1 shall be initialized before being used 99 | 4:8 PLCOPEN-CP3: Variable VAR2 shall be initialized before being used 100 | ... -------------------------------------------------------------------------------- /docs/source/fbd_to_st_ext.rst: -------------------------------------------------------------------------------- 1 | FBD-to-ST Compiler (extended) 2 | ============================= 3 | 4 | .. fbd_to_st_ext: 5 | 6 | The extended FBD-to-ST Compiler represents a feature for optimizing FBDs, where the behavior of instantiated function blocks can be unknown. The optimization approach is shown in figure below and involves configuration with respect 7 | to Halstead’s metrics N (number of edges) ``--edge-opt``, N1 (number of operators) ``--op-opt``, and N2 (variable accesses) ``--var-opt`` [3]. 8 | 9 | .. figure:: ../fig/fbd_optimizer_designflow_HL.png 10 | :align: center 11 | :width: 400px 12 | 13 | 14 | **Usage** 15 | 16 | .. code-block:: console 17 | 18 | python -m plcrex fbd-to-st-ext --help 19 | 20 | 21 | .. code:: console 22 | 23 | Usage: plcrex fbd-to-st-ext [OPTIONS] SOURCE EXE EXPORT 24 | 25 | FBD-to-ST Compiler (extended) *.xml → *.st 26 | 27 | ╭─ Arguments ──────────────────────────────────────────────────────────────────────────────────╮ 28 | │ * source PATH source path [default: None] [required] │ 29 | │ * exe PATH NuSMV.exe path [default: None] [required] │ 30 | │ * export PATH export path [default: None] [required] │ 31 | ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ 32 | ╭─ Options ────────────────────────────────────────────────────────────────────────────────────╮ 33 | │ --edge-opt --no-edge-opt optimize edges [default: no-edge-opt] │ 34 | │ --var-opt --no-var-opt optimize variables [default: no-var-opt] │ 35 | │ --op-opt --no-op-opt optimize operators [default: no-op-opt] │ 36 | │ --help Show this message and exit. │ 37 | ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ 38 | 39 | | 40 | 41 | POU ``Pollutant_Indicator_WITH_ERROR.xml`` 42 | ------------------------------------------ 43 | 44 | The following POU was manually implemented using Beremiz [`.url `_]. 45 | 46 | .. figure:: ../fig/Pollutant_Indicator_WITH_ERROR.png 47 | :align: center 48 | :width: 450px 49 | 50 | | 51 | 52 | 53 | Example 1: ``--no-edge-opt``, ``--no-var-opt``, ``--no-op-opt`` 54 | ---------------------------------------------------------------- 55 | 56 | **Command** 57 | 58 | .. code-block:: console 59 | 60 | python -m plcrex fbd-to-st-ext "tests/real_world_FBDs/Pollutant_Indicator_WITH_ERROR.xml" "bin/NuSMV.exe" ".\exports\01" 61 | 62 | **Results** 63 | 64 | ``01_no_opt.st`` 65 | 66 | .. code-block:: console 67 | 68 | //--- This file was generated by PLCreX --- 69 | //--- https://github.com/marwern/PLCreX --- 70 | //----------------------------------------- 71 | 72 | FUNCTION_BLOCK 73 | Pollutant_Indicator 74 | VAR_INPUT 75 | IN1:BOOL; 76 | IN2:BOOL; 77 | IN3:BOOL; 78 | END_VAR 79 | VAR_OUTPUT 80 | OUT1:BOOL; 81 | OUT2:BOOL; 82 | OUT3:BOOL; 83 | END_VAR 84 | OUT1:=OR(AND(NOT(IN3),NOT(IN2),IN1),AND(NOT(IN3),IN2,NOT(IN1),AND(IN3,NOT(IN2),NOT(IN1)))); 85 | OUT2:=OR(AND(NOT(IN3),IN2,IN1),AND(IN3,NOT(IN2),IN1),AND(IN3,IN2,NOT(IN1))); 86 | OUT3:=AND(IN1,IN2,IN3); 87 | END_FUNCTION_BLOCK 88 | 89 | | 90 | 91 | 92 | Example 2: ``--edge-opt`` 93 | -------------------------- 94 | 95 | **Command** 96 | 97 | .. code-block:: console 98 | 99 | python -m plcrex fbd-to-st-ext --edge-opt "tests/real_world_FBDs/Pollutant_Indicator_WITH_ERROR.xml" "bin/NuSMV.exe" ".\exports\01" 100 | 101 | **Results** 102 | 103 | ``01_edge_opt.st`` 104 | 105 | .. code-block:: console 106 | 107 | //--- This file was generated by PLCreX --- 108 | //--- https://github.com/marwern/PLCreX --- 109 | //----------------------------------------- 110 | 111 | FUNCTION_BLOCK 112 | Pollutant_Indicator 113 | VAR_INPUT 114 | IN1:BOOL; 115 | IN2:BOOL; 116 | IN3:BOOL; 117 | END_VAR 118 | VAR_OUTPUT 119 | OUT1:BOOL; 120 | OUT2:BOOL; 121 | OUT3:BOOL; 122 | END_VAR 123 | OUT1:=AND(IN1,NOT(IN2),NOT(IN3)); 124 | OUT2:=SEL(IN1,XOR(IN2,IN3),AND(IN2,IN3)); 125 | OUT3:=AND(IN1,IN2,IN3); 126 | END_FUNCTION_BLOCK 127 | 128 | | 129 | -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of PLCreX (https://github.com/marwern/PLCreX). 3 | # 4 | # Copyright (c) 2022-2024 Marcel C. Werner. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | import os 20 | import sys 21 | #import tomllib #need Python 3.11 22 | import time 23 | 24 | try: 25 | import tomllib 26 | except ModuleNotFoundError: 27 | import tomli as tomllib 28 | 29 | with open("../../pyproject.toml", "rb") as f: 30 | _META = tomllib.load(f) 31 | 32 | PROJ_NAME = _META["project"]["name"] 33 | VERSION = _META["project"]["version"] 34 | AUTHOR = _META["project"]["authors"][0]["name"] 35 | 36 | sys.path.insert(0, os.path.abspath("../")) 37 | 38 | # -- Project information 39 | project = "PLCreX" #PROJ_NAME 40 | copyright = f'{time.strftime("%Y")}, {AUTHOR}' 41 | version = VERSION 42 | release = VERSION 43 | author = AUTHOR 44 | show_authors = True 45 | 46 | # -- General configuration 47 | extensions = [ 48 | 'sphinx.ext.duration', 49 | 'sphinx.ext.doctest', 50 | 'sphinx.ext.autodoc', 51 | 'sphinx.ext.autosummary', 52 | 'sphinx.ext.intersphinx', 53 | 'sphinx.ext.napoleon', 54 | 'sphinx_rtd_theme', 55 | 'myst_parser', 56 | 'rst2pdf.pdfbuilder', 57 | 'sphinx_markdown_tables', 58 | ] 59 | 60 | # The name of the Pygments (syntax highlighting) style to use. 61 | pygments_style = 'sphinx' 62 | 63 | #intersphinx_mapping = { 64 | # 'python': ('https://docs.python.org/3/', None), 65 | # 'sphinx': ('https://www.sphinx-doc.org/en/master/', None), 66 | #} 67 | #intersphinx_disabled_domains = ['std'] 68 | 69 | templates_path = ['_templates'] 70 | 71 | # -- Options for HTML output 72 | html_theme = 'sphinx_rtd_theme' #sphinx_pdj_theme #press #sphinx_rtd_theme 73 | 74 | # Theme options are theme-specific and customize the look and feel of a theme 75 | # further. For a list of options available for each theme, see the 76 | # documentation. 77 | # 78 | html_theme_options = { 79 | 'prev_next_buttons_location': 'both' 80 | } 81 | 82 | #needed for alabaster theme 83 | #html_theme_options = { 84 | # 'collapse_navigation': True, 85 | # 'sticky_navigation': True, 86 | # 'navigation_depth': 4, 87 | # 'includehidden': True, 88 | # 'titles_only': False 89 | #} 90 | 91 | # The markdown parser 92 | #source_parsers = {'.md': 'recommonmark.parser.CommonMarkParser'} 93 | 94 | # The suffix(es) of source filenames. 95 | # You can specify multiple suffix as a list of string: 96 | # 97 | source_suffix = ['.rst', '.md'] 98 | # source_suffix = { 99 | # '.rst': 'restructuredtext', 100 | # '.md': 'markdown' 101 | # } 102 | 103 | # The master toctree document. 104 | master_doc = 'index' 105 | 106 | pdf_documents = [(master_doc, u'plcrex-doc', u'PLCreX', author),] 107 | #pdf_stylesheets = ['autumn','kerning','a4-landscape'] 108 | 109 | # -- Options for EPUB output 110 | epub_show_urls = 'footnote' 111 | 112 | # -- Options for HTML output ---------------------------------------------- 113 | 114 | # Theme options are theme-specific and customize the look and feel of a theme 115 | # further. For a list of options available for each theme, see the 116 | # documentation. 117 | # 118 | # html_theme_options = {} 119 | 120 | # Add any paths that contain custom static files (such as style sheets) here, 121 | # relative to this directory. They are copied after the builtin static files, 122 | # so a file named "default.css" will overwrite the builtin "default.css". 123 | html_static_path = [] 124 | 125 | # Custom sidebar templates, must be a dictionary that maps document names 126 | # to template names. 127 | # 128 | # This is required for the alabaster theme 129 | # refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars 130 | #html_sidebars = { 131 | #'**': [ 132 | # 'relations.html', # needs 'show_related': True theme option to display 133 | # 'searchbox.html', 134 | # 'globaltoc.html', 135 | # 'navigation.html', 136 | # ] 137 | #} -------------------------------------------------------------------------------- /tests/test_fbd2st.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of PLCreX (https://github.com/marwern/PLCreX). 3 | # 4 | # Copyright (c) 2022-2024 Marcel C. Werner. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | from typer.testing import CliRunner 20 | 21 | from plcrex import cli 22 | 23 | runner = CliRunner() 24 | 25 | 26 | def test_help(): 27 | result = runner.invoke(cli.app, ["fbd-to-st", "--help"]) 28 | assert result.exit_code == 0 29 | 30 | 31 | def test_wrong_file(): 32 | result = runner.invoke(cli.app, ["fbd-to-st", r".\tests\other_examples\TC001_wrong_file.txt", r".\exports\fbd2st1.st"]) 33 | assert result.exit_code == 1 34 | 35 | 36 | # TC004 Function Block 37 | 38 | # test_nobwd_noformal1 39 | def test_nobwd_noformal1(): 40 | result = runner.invoke(cli.app, ["fbd-to-st", r".\tests\plcopen_examples\TC004.xml", r".\exports\fbd2st2.st"]) 41 | assert result.exit_code == 0 42 | assert f"Success!" in result.stdout 43 | 44 | 45 | # test_nobwd_noformal2 46 | def test_nobwd_noformal2(): 47 | result = runner.invoke(cli.app, ["fbd-to-st", r".\tests\plcopen_examples\TC005_FB.xml", r".\exports\fbd2st3.st"]) 48 | assert result.exit_code == 0 49 | assert f"Success!" in result.stdout 50 | 51 | 52 | # test_nobwd_noformal3 53 | def test_nobwd_noformal3(): 54 | result = runner.invoke(cli.app, ["fbd-to-st", r".\tests\plcopen_examples\TC005_FUN.xml", r".\exports\fbd2st4.st"]) 55 | assert result.exit_code == 0 56 | assert f"Success!" in result.stdout 57 | 58 | 59 | # test_nobwd_noformal4 60 | def test_nobwd_noformal4(): 61 | result = runner.invoke(cli.app, ["fbd-to-st", r".\tests\plcopen_examples\TC005_PRG.xml", r".\exports\fbd2st5.st"]) 62 | assert result.exit_code == 0 63 | assert f"Success!" in result.stdout 64 | 65 | 66 | # test_nobwd_formal1 67 | def test_nobwd_formal1(): 68 | result = runner.invoke(cli.app, ["fbd-to-st", r".\tests\plcopen_examples\TC004.xml", r".\exports\fbd2st62.st", "--formal"]) 69 | assert result.exit_code == 0 70 | assert f"Success!" in result.stdout 71 | 72 | 73 | # test_nobwd_formal2 74 | def test_nobwd_formal2(): 75 | result = runner.invoke(cli.app, 76 | ["fbd-to-st", r".\tests\plcopen_examples\TC005_PRG.xml", r".\exports\fbd2st7.st", "--formal"]) 77 | assert result.exit_code == 0 78 | assert f"Success!" in result.stdout 79 | 80 | 81 | # formal + stp not supported by stp 82 | 83 | # test_bwd_noformal1 84 | def test_bwd_noformal1(): 85 | result = runner.invoke(cli.app, ["fbd-to-st", r".\tests\plcopen_examples\TC004.xml", r".\exports\fbd2st8.st", "--bwd"]) 86 | assert result.exit_code == 0 87 | assert f"Success!" in result.stdout 88 | 89 | 90 | # test_bwd_noformal2 91 | def test_bwd_noformal2(): 92 | result = runner.invoke(cli.app, ["fbd-to-st", r".\tests\plcopen_examples\TC005_PRG.xml", r".\exports\fbd2st9.st", "--bwd"]) 93 | assert result.exit_code == 0 94 | assert f"Success!" in result.stdout 95 | 96 | 97 | # test_bwd_formal1 98 | def test_bwd_formal1(): 99 | result = runner.invoke(cli.app, 100 | ["fbd-to-st", r".\tests\plcopen_examples\TC004.xml", r".\exports\fbd2st10.st", "--bwd", "--formal"]) 101 | assert result.exit_code == 0 102 | assert f"Success!" in result.stdout 103 | 104 | 105 | # test_bwd_formal2 106 | def test_bwd_formal2(): 107 | result = runner.invoke(cli.app, ["fbd-to-st", r".\tests\plcopen_examples\TC005_PRG.xml", r".\exports\fbd2st11.st", "--bwd", 108 | "--formal"]) 109 | assert result.exit_code == 0 110 | assert f"Success!" in result.stdout 111 | 112 | 113 | # test_bwd_noformal_st2ast 114 | def test_bwd_noformal_st2ast(): 115 | result = runner.invoke(cli.app, ["fbd-to-st", r".\tests\plcopen_examples\TC004.xml", r".\exports\fbd2st12.st", "--bwd"]) 116 | assert result.exit_code == 0 117 | assert f"Success!" in result.stdout 118 | #result = runner.invoke(cli.app, 119 | # ["st-parser", r".\PLCreX_outputs\fbd2st12.st", r".\exports\fbdst13", "--txt"]) 120 | #assert result.exit_code == 0 121 | assert f"Success!" in result.stdout 122 | -------------------------------------------------------------------------------- /docs/source/fbd_to_sctx.rst: -------------------------------------------------------------------------------- 1 | FBD-to-SCCharts Compiler 2 | ======================== 3 | 4 | .. fbd_to_sctx: 5 | 6 | The FBD-to-SCCharts Compiler represents a feature for optimizing FBDs, where the behavior of instantiated function blocks can be unknown. The optimization approach is shown in figure below and involves configuration with respect 7 | to Halstead’s metrics N (number of edges) ``--edge-opt``, N1 (number of operators) ``--op-opt``, and N2 (variable accesses) ``--var-opt``. Furthermore, this feature translates FBDs into Sequentially Constructive Statecharts (SCCharts) for reuse in model-based design of reactive systems and formal verification [3]. 8 | 9 | .. figure:: ../fig/fbd_optimizer_designflow_HL.png 10 | :align: center 11 | :width: 400px 12 | 13 | 14 | **Usage** 15 | 16 | .. code-block:: console 17 | 18 | python -m plcrex fbd-to-sctx --help 19 | 20 | 21 | .. code:: console 22 | 23 | Usage: plcrex fbd-to-sctx [OPTIONS] SOURCE EXE EXPORT 24 | 25 | FBD-to-SCCharts Compiler (Data-Flow) *.xml → *.sctx 26 | 27 | ╭─ Arguments ──────────────────────────────────────────────────────────────────────────────────╮ 28 | │ * source PATH source path [default: None] [required] │ 29 | │ * exe PATH NuSMV.exe path [default: None] [required] │ 30 | │ * export PATH export path [default: None] [required] │ 31 | ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ 32 | ╭─ Options ────────────────────────────────────────────────────────────────────────────────────╮ 33 | │ --edge-opt --no-edge-opt optimize edges [default: no-edge-opt] │ 34 | │ --var-opt --no-var-opt optimize variables [default: no-var-opt] │ 35 | │ --op-opt --no-op-opt optimize operators [default: no-op-opt] │ 36 | │ --help Show this message and exit. │ 37 | ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ 38 | 39 | .. 40 | .. figure:: ../fig/fbd_optimizer_demo.png 41 | :align: center 42 | :width: 600px 43 | 44 | | 45 | 46 | POU ``Pollutant_Indicator_WITH_ERROR.xml`` 47 | ------------------------------------------ 48 | 49 | The following POU was manually implemented using Beremiz [`.url `_]. 50 | 51 | .. figure:: ../fig/Pollutant_Indicator_WITH_ERROR.png 52 | :align: center 53 | :width: 450px 54 | 55 | | 56 | 57 | 58 | Example 1: ``--no-edge-opt``, ``--no-var-opt``, ``--no-op-opt`` 59 | ---------------------------------------------------------------- 60 | 61 | **Command** 62 | 63 | .. code-block:: console 64 | 65 | python -m plcrex fbd-to-sctx "tests/real_world_FBDs/Pollutant_Indicator_WITH_ERROR.xml" "bin/NuSMV.exe" ".\exports\01" 66 | 67 | **Results** 68 | 69 | ``01_no_opt.sctx`` 70 | 71 | .. code-block:: console 72 | 73 | //--- This file was generated by PLCreX --- 74 | //--- https://github.com/marwern/PLCreX --- 75 | //----------------------------------------- 76 | 77 | scchart Pollutant_Indicator{ 78 | input bool IN1 79 | input bool IN2 80 | input bool IN3 81 | output bool OUT1 82 | output bool OUT2 83 | output bool OUT3 84 | dataflow{ 85 | OUT1=((!(IN3)&!(IN2)&IN1)|(!(IN3)&IN2&!(IN1)&(IN3&!(IN2)&!(IN1)))) 86 | seq 87 | OUT2=((!(IN3)&IN2&IN1)|(IN3&!(IN2)&IN1)|(IN3&IN2&!(IN1))) 88 | seq 89 | OUT3=(IN1&IN2&IN3) 90 | seq}} 91 | 92 | .. figure:: ../fig/no_opt_example.png 93 | :align: center 94 | :width: 300px 95 | 96 | 97 | | 98 | 99 | 100 | Example 2: ``--edge-opt`` 101 | -------------------------- 102 | 103 | **Command** 104 | 105 | .. code-block:: console 106 | 107 | python -m plcrex fbd-to-sctx --edge-opt "tests/real_world_FBDs/Pollutant_Indicator_WITH_ERROR.xml" "bin/NuSMV.exe" ".\exports\01" 108 | 109 | **Results** 110 | 111 | ``01_edge_opt.sctx`` 112 | 113 | .. code-block:: console 114 | 115 | //--- This file was generated by PLCreX --- 116 | //--- https://github.com/marwern/PLCreX --- 117 | //----------------------------------------- 118 | 119 | scchart Pollutant_Indicator{ 120 | input bool IN1 121 | input bool IN2 122 | input bool IN3 123 | output bool OUT1 124 | output bool OUT2 125 | output bool OUT3 126 | dataflow{ 127 | OUT1=(IN1&!(IN2)&!(IN3)) 128 | seq 129 | OUT2=((IN1)?(((IN2)^(IN3))):((IN2&IN3))) 130 | seq 131 | OUT3=(IN1&IN2&IN3) 132 | seq}} 133 | 134 | .. figure:: ../fig/edge_opt_example.png 135 | :align: center 136 | :width: 300px 137 | 138 | 139 | | 140 | -------------------------------------------------------------------------------- /docs/source/fbd_to_st.rst: -------------------------------------------------------------------------------- 1 | FBD-to-ST Compiler 2 | ================== 3 | 4 | .. fbd_to_st: 5 | 6 | The FBD-to-ST Compiler translates IEC 61131-3 FBDs stored in PLCopen XML format into ST POUs. In this context, PLCreX supports the translation in different formats. In general, PLCreX distinguishes between a **formal** representation of the parameter list of instantiated POUs, 7 | for example ``TONx(IN := A, PT := B);`` and a **non formal** representation, ``TONx(A,B);``. Furthermore, we distinguish between a **forward** translation strategy and a **backward** translation strategy. 8 | 9 | .. warning:: 10 | The backward translation strategy can change the semantics because the variables are updated at the end of a cycle. In contrast, without database, additional local variables needed for forward translation are declared as ``BOOL`` by default, 11 | unless the data type is implicit given by connected component. 12 | 13 | 14 | **Usage** 15 | 16 | .. code-block:: console 17 | 18 | python -m plcrex fbd-to-st --help 19 | 20 | 21 | .. code:: console 22 | 23 | Usage: plcrex fbd-to-st [OPTIONS] SOURCE EXPORT 24 | 25 | FBD-to-ST Compiler *.xml → *.st 26 | 27 | ╭─ Arguments ──────────────────────────────────────────────────────────────────────────────────╮ 28 | │ * source PATH source path [default: None] [required] │ 29 | │ * export PATH export path [default: None] [required] │ 30 | ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ 31 | ╭─ Options ────────────────────────────────────────────────────────────────────────────────────╮ 32 | │ --bwd --no-bwd use backward translation [default: no-bwd] │ 33 | │ --formal --no-formal formal parameter list [default: no-formal] │ 34 | │ --help Show this message and exit. │ 35 | ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ 36 | 37 | 38 | .. 39 | .. figure:: ../fig/fbd_to_st_demo.png 40 | :align: center 41 | :width: 600px 42 | 43 | | 44 | 45 | POU ``TC005_PRG.xml`` 46 | --------------------- 47 | 48 | The following POU was manually implemented using Beremiz [`.url `_]. 49 | 50 | .. figure:: ../fig/TC005.png 51 | :align: center 52 | :width: 450px 53 | 54 | | 55 | 56 | Example 1: ``--no-formal`` ``--no-bwd`` 57 | --------------------------------------- 58 | 59 | **Command** 60 | 61 | .. code-block:: console 62 | 63 | python -m plcrex fbd-to-st --no-formal --no-bwd ".\tests\plcopen_examples\TC005_PRG.xml" ".\exports\01" 64 | 65 | **Results** 66 | 67 | ``01.st`` 68 | 69 | .. code-block:: console 70 | 71 | ... 72 | AND1_OUT := AND(i1,i2); 73 | TON0(AND1_OUT,i3); 74 | XOR3_OUT := XOR(AND1_OUT,TON0.Q); 75 | o1 := XOR3_OUT; 76 | o4 := TON0.Q; 77 | o2 := i1; 78 | ... 79 | 80 | Example 2: ``--no-formal`` ``--bwd`` 81 | ------------------------------------ 82 | 83 | **Command** 84 | 85 | .. code-block:: console 86 | 87 | python -m plcrex fbd-to-st --no-formal --bwd ".\tests\plcopen_examples\TC005_PRG.xml" ".\exports\02" 88 | 89 | **Results** 90 | 91 | ``02.st`` 92 | 93 | .. code-block:: console 94 | 95 | ... 96 | TON0(AND(i1,i2),i3); 97 | o1 := XOR(AND(i1,i2),TON0.Q); 98 | o4 := TON0.Q; 99 | o2 := i1; 100 | ... 101 | 102 | Example 3: ``--formal`` ``--no-bwd`` 103 | ------------------------------------ 104 | 105 | **Command** 106 | 107 | .. code-block:: console 108 | 109 | python -m plcrex fbd-to-st --formal --no-bwd ".\tests\plcopen_examples\TC005_PRG.xml" ".\exports\03" 110 | 111 | **Results** 112 | 113 | ``03.st`` 114 | 115 | .. code-block:: console 116 | 117 | ... 118 | AND1_OUT := AND(i1,i2); 119 | TON0(IN := AND1_OUT,PT := i3); 120 | XOR3_OUT := XOR(AND1_OUT,TON0.Q); 121 | o1 := XOR3_OUT; 122 | o4 := TON0.Q; 123 | o2 := i1; 124 | ... 125 | 126 | 127 | Example 4: ``--formal`` ``--bwd`` 128 | --------------------------------- 129 | 130 | **Command** 131 | 132 | .. code-block:: console 133 | 134 | python -m plcrex fbd-to-st --formal --bwd ".\tests\plcopen_examples\TC005_PRG.xml" ".\exports\04" 135 | 136 | **Results** 137 | 138 | ``04.st`` 139 | 140 | .. code-block:: console 141 | 142 | ... 143 | TON0(IN := AND(i1,i2),PT := i3); 144 | o1 := XOR(AND(i1,i2),TON0.Q); 145 | o4 := TON0.Q; 146 | o2 := i1; 147 | ... -------------------------------------------------------------------------------- /tests/test_fbd2x.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of PLCreX (https://github.com/marwern/PLCreX). 3 | # 4 | # Copyright (c) 2022-2024 Marcel C. Werner. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | from typer.testing import CliRunner 20 | 21 | from plcrex import cli 22 | 23 | runner = CliRunner() 24 | 25 | 26 | def test_help1(): 27 | result = runner.invoke(cli.app, ["fbd-to-st-ext", "--help"]) 28 | assert result.exit_code == 0 29 | 30 | def test_help2(): 31 | result = runner.invoke(cli.app, ["fbd-to-sctx", "--help"]) 32 | assert result.exit_code == 0 33 | 34 | def test_wrong_file1(): 35 | result = runner.invoke(cli.app, ["fbd-to-st-ext", "--edge-opt", r".\tests\other_examples\TC001_wrong_file.txt", "bin/NuSMV.exe", r".\exports\st2x1.st"]) 36 | assert result.exit_code == 1 37 | 38 | def test_wrong_file2(): 39 | result = runner.invoke(cli.app, ["fbd-to-sctx", "--edge-opt", r".\tests\other_examples\TC001_wrong_file.txt", "bin/NuSMV.exe", r".\exports\st2x1.sctx"]) 40 | assert result.exit_code == 1 41 | 42 | def test_edge_opt1_st(): 43 | result = runner.invoke(cli.app, ["fbd-to-st-ext", "--edge-opt", r"tests/real_world_FBDs/Antivalence_3x.xml", "bin/NuSMV.exe", r".\exports\st2x2.st"]) 44 | assert result.exit_code == 0 45 | assert f"Success!" in result.stdout 46 | 47 | def test_edge_opt1_sctx(): 48 | result = runner.invoke(cli.app, ["fbd-to-sctx", "--edge-opt", r"tests/real_world_FBDs/Antivalence_3x.xml", "bin/NuSMV.exe", r".\exports\st2x2.sctx"]) 49 | assert result.exit_code == 0 50 | assert f"Success!" in result.stdout 51 | 52 | def test_edge_opt2_st(): 53 | result = runner.invoke(cli.app, ["fbd-to-st-ext", "--edge-opt", r"tests/real_world_FBDs/Bending_Machine_Control.xml", "bin/NuSMV.exe", r".\exports\st2x4.st"]) 54 | assert result.exit_code == 0 55 | assert f"Success!" in result.stdout 56 | 57 | def test_edge_opt2_sctx(): 58 | result = runner.invoke(cli.app, ["fbd-to-sctx", "--edge-opt", r"tests/real_world_FBDs/Bending_Machine_Control.xml", "bin/NuSMV.exe", r".\exports\st2x4.sctx"]) 59 | assert result.exit_code == 0 60 | assert f"Success!" in result.stdout 61 | 62 | def test_edge_opt3_st(): 63 | result = runner.invoke(cli.app, ["fbd-to-st-ext", "--edge-opt", r"tests/real_world_FBDs/Cylinder_Control_System.xml", "bin/NuSMV.exe", r".\exports\st2x6.st"]) 64 | assert result.exit_code == 0 65 | assert f"Success!" in result.stdout 66 | 67 | def test_edge_opt3_sctx(): 68 | result = runner.invoke(cli.app, ["fbd-to-sctx", "--edge-opt", r"tests/real_world_FBDs/Cylinder_Control_System.xml", "bin/NuSMV.exe", r".\exports\st2x6.sctx"]) 69 | assert result.exit_code == 0 70 | assert f"Success!" in result.stdout 71 | 72 | def test_edge_opt4_st(): 73 | result = runner.invoke(cli.app, ["fbd-to-st-ext", "--edge-opt", r"tests/real_world_FBDs/KV_Diagram_optimized_Chart.xml", "bin/NuSMV.exe", r".\exports\st2x8.st"]) 74 | assert result.exit_code == 0 75 | assert f"Success!" in result.stdout 76 | 77 | def test_edge_opt4_sctx(): 78 | result = runner.invoke(cli.app, ["fbd-to-sctx", "--edge-opt", r"tests/real_world_FBDs/KV_Diagram_optimized_Chart.xml", "bin/NuSMV.exe", r".\exports\st2x8.sctx"]) 79 | assert result.exit_code == 0 80 | assert f"Success!" in result.stdout 81 | 82 | def test_var_opt_st(): 83 | result = runner.invoke(cli.app, ["fbd-to-st-ext", "--var-opt", r"tests/real_world_FBDs/Antivalence_3x.xml", "bin/NuSMV.exe", r".\exports\st2x10.st"]) 84 | assert result.exit_code == 0 85 | assert f"Success!" in result.stdout 86 | 87 | def test_var_opt_sctx(): 88 | result = runner.invoke(cli.app, ["fbd-to-sctx", "--var-opt", r"tests/real_world_FBDs/Antivalence_3x.xml", "bin/NuSMV.exe", r".\exports\st2x10.sctx"]) 89 | assert result.exit_code == 0 90 | assert f"Success!" in result.stdout 91 | 92 | def test_op_opt_st(): 93 | result = runner.invoke(cli.app, ["fbd-to-st-ext", "--var-opt", r"tests/real_world_FBDs/Antivalence_3x.xml", "bin/NuSMV.exe", r".\exports\st2x12.st"]) 94 | assert result.exit_code == 0 95 | assert f"Success!" in result.stdout 96 | 97 | def test_op_opt_sctx(): 98 | result = runner.invoke(cli.app, ["fbd-to-sctx", "--var-opt", r"tests/real_world_FBDs/Antivalence_3x.xml", "bin/NuSMV.exe", r".\exports\st2x12.sctx"]) 99 | assert result.exit_code == 0 100 | assert f"Success!" in result.stdout -------------------------------------------------------------------------------- /plcrex/tools/misc/generic_functions.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of PLCreX (https://github.com/marwern/PLCreX). 3 | # 4 | # Copyright (c) 2022-2024 Marcel C. Werner. 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, version 3. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | import time 20 | import datetime 21 | from lark import Tree, Lark 22 | import os 23 | import site 24 | import typer 25 | import logging 26 | 27 | # ANSI escape sequences for terminal colors 28 | class ColorCodes: 29 | RED = '\033[91m' 30 | GREEN = '\033[92m' 31 | YELLOW = '\033[93m' 32 | BLUE = '\033[94m' 33 | RESET = '\033[0m' 34 | 35 | 36 | # Custom formatter class 37 | class CustomFormatter(logging.Formatter): 38 | format = "%(asctime)s - %(levelname)s - %(filename)s:%(lineno)d\n%(message)s" 39 | 40 | FORMATS = { 41 | logging.DEBUG: ColorCodes.BLUE + format + ColorCodes.RESET, 42 | logging.INFO: ColorCodes.GREEN + format + ColorCodes.RESET, 43 | logging.WARNING: ColorCodes.YELLOW + format + ColorCodes.RESET, 44 | logging.ERROR: ColorCodes.RED + format + ColorCodes.RESET, 45 | logging.CRITICAL: ColorCodes.RED + format + ColorCodes.RESET, 46 | } 47 | 48 | def format(self, record): 49 | log_fmt = self.FORMATS.get(record.levelno) 50 | formatter = logging.Formatter(log_fmt) 51 | return formatter.format(record) 52 | 53 | format_cli = "%(asctime)s - %(levelname)s - %(filename)s:%(lineno)d\n%(message)s" 54 | logging.basicConfig(format=format_cli) 55 | 56 | # Configure logging 57 | #logging.basicConfig(level=logging.DEBUG) 58 | #logger = logging.getLogger() 59 | #handler = logger.handlers[0] 60 | #handler.setFormatter(CustomFormatter()) 61 | 62 | def parse_src(grammar, source: str, debug_flag): 63 | src_parser = Lark( 64 | get_file(fr'plcrex\data\grammars\{grammar}.lark'), 65 | maybe_placeholders=True, 66 | keep_all_tokens=False, 67 | debug=False) 68 | src_ast = src_parser.parse(source) 69 | #print(src_ast) if debug_flag else None 70 | return src_ast 71 | 72 | 73 | def find_1st_parent_tree(tree, target_node): 74 | if not isinstance(tree, Tree): 75 | return None 76 | 77 | for child in tree.children: 78 | if child == target_node: 79 | return tree 80 | parent = find_1st_parent_tree(child, target_node) 81 | if parent is not None: 82 | return parent 83 | return None 84 | 85 | 86 | def find_all_parent_trees(tree, target_node, parent_list=None): 87 | if parent_list is None: 88 | parent_list = [] 89 | 90 | if not isinstance(tree, Tree): 91 | return parent_list 92 | 93 | for child in tree.children: 94 | if child == target_node: 95 | parent_list.append(tree) 96 | else: 97 | find_all_parent_trees(child, target_node, parent_list) 98 | 99 | return parent_list 100 | 101 | 102 | def get_file(rel_path: str): 103 | # initialize grammar 104 | f = "" 105 | 106 | # Get the list of all global site-packages directories 107 | site_packages_dirs = site.getsitepackages() 108 | 109 | # Iterate over all site-packages directories 110 | for dir in site_packages_dirs: 111 | # Create an absolute path to the file 112 | abs_file_path = os.path.join(dir, rel_path) 113 | 114 | # Check if the file exists at this path 115 | if os.path.isfile(abs_file_path): 116 | #print(abs_file_path) 117 | # If the file exists, open it 118 | with open(abs_file_path, 'rt') as file: 119 | f = file.read() 120 | #logging.warning(f"Ignoring data from local developer package! > {rel_path}") 121 | typer.echo(typer.style(f"WARNING: Ignoring data from local developer package! > {rel_path}", 122 | fg=typer.colors.YELLOW, bold=True)) 123 | #file.close() 124 | return f 125 | 126 | # if plcrex is not installed via pip, use local dir 127 | if f == "": 128 | with open(rel_path, 'rt') as file: 129 | f = file.read() 130 | #logging.warning(f"Ignoring data from global site-package! > {rel_path}") 131 | typer.echo( 132 | typer.style(f"WARNING: Ignoring data from global site-package! > {rel_path}", fg=typer.colors.YELLOW, 133 | bold=True)) 134 | #file.close() 135 | return f 136 | 137 | 138 | def print_header(script_name:str, version:str, author:str): 139 | 140 | global start_time 141 | start_time = time.time() 142 | current_time = datetime.datetime.now().strftime("%H:%M:%S") 143 | 144 | typer.echo("--------------------------------------------------") 145 | typer.echo(f"Tool:\t\t{script_name}") 146 | typer.echo(f"Version:\t{version}") 147 | typer.echo(f"Author:\t\t{author}") 148 | typer.echo(f"Start:\t\t{current_time} {datetime.date.today()}") 149 | typer.echo("--------------------------------------------------") 150 | 151 | 152 | def print_footer(): 153 | typer.echo("--------------------------------------------------") 154 | typer.echo(f"Runtime: %s seconds" % format((time.time() - start_time), ".3f")) 155 | -------------------------------------------------------------------------------- /docs/source/st_parser.rst: -------------------------------------------------------------------------------- 1 | ST-Parser 2 | ========= 3 | 4 | .. st-parser: 5 | 6 | The ST-Parser includes an executable grammar for IEC 61131-3 ST POUs as well as the possibility to save the 7 | resulting syntax tree visually or as plain text and reuse it for subsequent analysis. The embedded default grammar covers the following constructs and the ``--beckhoff`` grammar contains almost all ST constructs: 8 | 9 | * IEC 61131-3 POU-Types: ``Program``, ``Functionblock``, ``Function`` 10 | * Sections (each available only once): ``VAR_INPUT``, ``VAR``, ``VAR_OUTPUT``, ``VAR_IN_OUT``, ``VAR_EXTERNAL`` 11 | * Data types: ``BOOL``, ``INT``, ``DINT``, ``UINT``, ``REAL``, ``TIME``, ``ARRAY`` 12 | * Operators: ``*``, ``/``, ``MOD``, ``+``, ``-``, ``NOT``, ``AND``, ``XOR``, ``OR``, ``<=``, ``>=``, ``<``, ``>``, ``=``, ``<>``, ``FALSE``, ``TRUE``, ``external function/functionblocks``, ``variable``, ``constant```` 13 | * Statements: ``assignments``, ``if/else``, ``case``, ``macro``, ``for``, ``while``, ``repeat``, ``exit``, ``return`` 14 | * Parameter list: informal, e.g. ``TONx(A,B);`` instead of ``TONx(IN := A, PT := B);`` 15 | 16 | 17 | **Usage** 18 | 19 | .. code-block:: console 20 | 21 | python -m plcrex st-parser --help 22 | 23 | 24 | .. code:: console 25 | 26 | Usage: plcrex st-parser [OPTIONS] SOURCE EXPORT 27 | 28 | ST-Parser *.st → *.dot/*.txt 29 | 30 | ╭─ Arguments ──────────────────────────────────────────────────────────────────────────────────╮ 31 | │ * source PATH source path [default: None] [required] │ 32 | │ * export PATH export path [default: None] [required] │ 33 | ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ 34 | ╭─ Options ────────────────────────────────────────────────────────────────────────────────────╮ 35 | │ --txt --no-txt tree export as *.txt [default: txt] │ 36 | │ --dot --no-dot tree export as *.dot [default: dot] │ 37 | │ --beckhoff --no-beckhoff use Beckhoff TwinCAT ST grammar [default: no-beckhoff] │ 38 | │ --help Show this message and exit. │ 39 | ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ 40 | 41 | 42 | .. 43 | .. figure:: ../fig/st_parser_demo.png 44 | :align: center 45 | :width: 600px 46 | 47 | | 48 | 49 | POU ``TC081.st`` 50 | ---------------- 51 | 52 | .. code-block:: console 53 | 54 | FUNCTION_BLOCK TC081 55 | VAR_INPUT 56 | IN1 : INT; 57 | IN2 : INT; 58 | IN3 : INT; 59 | IN4 : BOOL; 60 | END_VAR 61 | VAR_OUTPUT 62 | Wrn : BOOL; 63 | Err : BOOL; 64 | Ctr : INT; 65 | iOut2 : INT; 66 | END_VAR 67 | VAR 68 | SR1 : SR; 69 | TON1 : TON; 70 | TON2 : TON; 71 | END_VAR 72 | 73 | SR1(((((20*IN1)+(6*IN2)+IN3))=(100*2)) AND (IN1+IN2+IN3=100),IN4); 74 | TON1((((((20*IN1)+(6*IN2)+IN3))=(100*2)) AND (IN1+IN2+IN3=100)),2); 75 | TON2(IN1+IN2+IN3=42 AND SR1.Q,3); 76 | Ctr := TON2.ET; 77 | Err := TON1.Q; 78 | Wrn := SR1.Q; 79 | END_FUNCTION_BLOCK 80 | 81 | 82 | Example 1 ``--no-beckhoff`` 83 | --------------------------- 84 | 85 | **Command** 86 | 87 | .. code-block:: console 88 | 89 | python -m plcrex st-parser ".\tests\st_examples\TC081.st" ".\exports\01" 90 | 91 | **Results** 92 | 93 | ``01.dot`` 94 | 95 | .. code-block:: console 96 | 97 | digraph G { 98 | rankdir=LR; 99 | 0 [label="Token('NAME', 'TC081')"]; 100 | 1 [fillcolor="#aec5e0", label=name, style=filled]; 101 | 1 -> 0; 102 | ... 103 | 104 | ``01.txt`` 105 | 106 | .. code-block:: console 107 | 108 | start 109 | module 110 | name TC081 111 | idcl 112 | var_input 113 | dcllist 114 | declaration 115 | variable IN1 116 | datatype INT 117 | declaration 118 | variable IN2 119 | datatype INT 120 | declaration 121 | variable IN3 122 | datatype INT 123 | declaration 124 | variable IN4 125 | ... 126 | 127 | .. figure:: ../fig/TC081_AST.png 128 | :align: center 129 | :width: 600px 130 | 131 | | 132 | 133 | Example 2 ``--beckhoff`` 134 | --------------------------- 135 | 136 | **Command** 137 | 138 | .. code-block:: console 139 | 140 | python -m plcrex st-parser --beckhoff ".\tests\st_examples\TC081.st" ".\exports\02" 141 | 142 | **Results** 143 | 144 | ``02.dot`` 145 | 146 | .. code-block:: console 147 | 148 | digraph G { 149 | rankdir=LR; 150 | 0 [label="Token('FUNCTION_BLOCK', 'FUNCTION_BLOCK')"]; 151 | 1 [label="Token('IDENTIFIER', 'TC081')"]; 152 | 2 [label="Token('IDENTIFIER', 'IN1')"]; 153 | 3 [fillcolor="#b9d2eb", label=variable_name, style=filled]; 154 | 3 -> 2; 155 | 4 [fillcolor="#8e96ea", label=var1, style=filled]; 156 | 4 -> 3; 157 | 5 [fillcolor="#dea4f6", label=var1_list, style=filled]; 158 | 5 -> 4; 159 | ... 160 | 161 | ``02.txt`` 162 | 163 | .. code-block:: console 164 | 165 | iec_source 166 | function_block_type_declaration 167 | FUNCTION_BLOCK 168 | TC081 169 | input_declarations 170 | var1_init_decl 171 | var1_list 172 | var1 173 | variable_name IN1 174 | simple_spec_init 175 | simple_specification INT 176 | var1_init_decl 177 | var1_list 178 | var1 179 | variable_name IN2 180 | simple_spec_init 181 | simple_specification INT 182 | ... 183 | 184 | .. figure:: ../fig/TC081_AST3.png 185 | :align: center 186 | :width: 600px 187 | 188 | | -------------------------------------------------------------------------------- /plcrex/data/grammars/scl_grammar.lark: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // POU Declaration List 3 | // ******************************************************************************** 4 | ?start: type pou "{" (idcl | vdcl )* statlist? "}" -> module 5 | pou: NAME -> name 6 | 7 | type: TYPE 8 | TYPE: "module" 9 | 10 | 11 | // ******************************************************************************** 12 | // Interface/Variable Declaration List 13 | // ******************************************************************************** 14 | idcl: (var_input | var_output | var_in_out)* -> idcl 15 | 16 | vdcl: var_local -> vdcl 17 | 18 | dcllist: declaration 19 | 20 | declaration: 21 | | datatype variable ";" 22 | | datatype variable "=" _expr ";" 23 | | datatype variable array ";" 24 | 25 | var_input: "input" dcllist 26 | 27 | var_output: "output" dcllist 28 | 29 | var_in_out: "input output" dcllist 30 | 31 | var_local: dcllist 32 | 33 | 34 | // ******************************************************************************** 35 | // Datatypes 36 | // ******************************************************************************** 37 | datatype: TYPE_BOOL | TYPE_INT | TYPE_REAL | TYPE_TIME | macro_name 38 | 39 | TYPE_BOOL: "bool" 40 | TYPE_INT: "int" 41 | TYPE_REAL: "float" 42 | TYPE_TIME: "int" 43 | array: "[" constant_int "]" 44 | macro_name: MACRO_NAME 45 | 46 | 47 | // ******************************************************************************** 48 | // Functions/User-POUs 49 | // ******************************************************************************** 50 | macro: 51 | | MACRO_NAME "." macro_out 52 | | MACRO_NAME "(" macro_assignment ("," macro_assignment)* ");" 53 | macro_out: MACRO_NAME 54 | 55 | 56 | // ******************************************************************************** 57 | // Arithmetic operators 58 | // ******************************************************************************** 59 | multiply_with: _expr "*" _expr 60 | divide_by: _expr "/" _expr 61 | modulo: _expr "%" _expr 62 | adding: _expr "+" _expr 63 | subtracting: _expr "-" _expr 64 | expt: "EXPT(" _expr "," _expr ")" 65 | unaryminus: "-" _expr 66 | 67 | 68 | // ******************************************************************************** 69 | // Boolean operators 70 | // ******************************************************************************** 71 | not_op: "!(" _expr ")" 72 | and_op: _expr "&&" _expr 73 | xor_op: _expr "^" _expr 74 | or_op: _expr "||" _expr 75 | 76 | 77 | // ******************************************************************************** 78 | // Numeric operators 79 | // ******************************************************************************** 80 | less_or_equal.1: _expr "<=" _expr 81 | greater_or_equal.1: _expr ">=" _expr 82 | less_than: _expr "<" _expr 83 | greater_than: _expr ">" _expr 84 | 85 | 86 | // ******************************************************************************** 87 | // Equality 88 | // ******************************************************************************** 89 | equality: _expr EQ _expr | "EQ(" _expr "," _expr ")" 90 | EQ:/[==]/ 91 | inequality: _expr NEQ _expr | "NE(" _expr "," _expr ")" 92 | NEQ:/[!=]/ 93 | 94 | // ******************************************************************************** 95 | // General expressions 96 | // ******************************************************************************** 97 | _expr: 98 | | equality 99 | | variable ("[" constant_int "]")* 100 | | multiply_with 101 | | divide_by 102 | | modulo 103 | | adding 104 | | subtracting 105 | | "(" _expr ")" 106 | | expt 107 | | constant 108 | | constant_time 109 | | not_op 110 | | and_op 111 | | xor_op 112 | | or_op 113 | | inequality 114 | | less_or_equal 115 | | greater_or_equal 116 | | less_than 117 | | greater_than 118 | | false 119 | | true 120 | | unaryminus 121 | | if_statement_short 122 | 123 | false: FALSE 124 | FALSE: "false" 125 | true: TRUE 126 | TRUE: "true" 127 | 128 | 129 | // ******************************************************************************** 130 | // Statementlist 131 | // ******************************************************************************** 132 | constant_time.2: MS_DURATION 133 | constant.1: UINT | REAL 134 | constant_int.1: UINT 135 | UINT: /[0-9]+/ 136 | REAL: /[0-9][.]?[0-9]*/ 137 | MS_DURATION: UINT 138 | //NUMBER: /[+-]?[0-9]+/ 139 | 140 | statlist: statement* 141 | 142 | statement: 143 | | immediate_assignment 144 | | if_statement 145 | | while_statement 146 | | repeat_statement 147 | | macro 148 | | macro_assignment 149 | 150 | 151 | // ******************************************************************************** 152 | // Assignments 153 | // ******************************************************************************** 154 | immediate_assignment: variable("["constant_int"]")* "=" _expr ";" 155 | 156 | macro_assignment: variable "=" _expr 157 | 158 | 159 | // ******************************************************************************** 160 | // selection statement 161 | // ******************************************************************************** 162 | if_statement: "if(" _expr "){" statlist "}else{" statlist "}" 163 | 164 | if_statement_short: "(" _expr "?" _expr ":" _expr ")" 165 | 166 | 167 | 168 | // ******************************************************************************** 169 | // iteration statements 170 | // ******************************************************************************** 171 | while_statement: "while(" _expr "){" statlist "pause;" statlist "}" 172 | //statlist_while: statement* "pause;" statement -> statlist 173 | 174 | repeat_statement: "do:" statlist "pause;" statlist "if(!(" _expr ")){" "goto do;" "}else{" statlist "}" 175 | 176 | 177 | // ******************************************************************************** 178 | // Additional Terminals and_op rules 179 | // ******************************************************************************** 180 | variable: NAME 181 | 182 | 183 | // ******************************************************************************** 184 | // Lark statements 185 | // ******************************************************************************** 186 | MULTI_LINE_COMMENT: /\(\*.*?\*\)/s 187 | SINGLE_LINE_COMMENT: /\s*/ "//" /[^\n]/* 188 | 189 | %ignore WS 190 | %ignore MULTI_LINE_COMMENT 191 | %ignore SINGLE_LINE_COMMENT 192 | %import common.WS 193 | NAME: /[_]?(?!(true|false|BOOL|INT|REAL|ARRAY\b))[a-zA-Z0-9_]\w*/ 194 | MACRO_NAME: /[_]?(?!(true|false|BOOL|INT|REAL|ARRAY\b))[a-zA-Z_]\w*/ -------------------------------------------------------------------------------- /plcrex/data/grammars/scl_grammar_EOL.lark: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // POU Declaration List 3 | // ******************************************************************************** 4 | ?start: "_LINEBREAK_" type pou "{" "_LINEBREAK_" (idcl | vdcl)* statlist? "}" -> module 5 | pou: NAME -> name 6 | 7 | type: TYPE 8 | TYPE: "module" 9 | 10 | 11 | // ******************************************************************************** 12 | // Interface/Variable Declaration List 13 | // ******************************************************************************** 14 | idcl: (var_input | var_output | var_in_out)* -> idcl 15 | 16 | vdcl: var_local -> vdcl 17 | 18 | dcllist: declaration 19 | 20 | declaration: 21 | | datatype variable ";" "_LINEBREAK_" 22 | | datatype variable "=" _expr ";" "_LINEBREAK_" 23 | | datatype variable array ";" "_LINEBREAK_" 24 | 25 | var_input: "input" dcllist 26 | 27 | var_output: "output" dcllist 28 | 29 | var_in_out: "input output" dcllist 30 | 31 | var_local: dcllist 32 | 33 | 34 | // ******************************************************************************** 35 | // Datatypes 36 | // ******************************************************************************** 37 | datatype: TYPE_BOOL | TYPE_INT | TYPE_REAL | TYPE_TIME | macro_name 38 | 39 | TYPE_BOOL: "bool" 40 | TYPE_INT: "int" 41 | TYPE_REAL: "float" 42 | TYPE_TIME: "int" 43 | array: "[" constant_int "]" 44 | macro_name: MACRO_NAME 45 | 46 | 47 | // ******************************************************************************** 48 | // Functions/User-POUs 49 | // ******************************************************************************** 50 | macro: 51 | | MACRO_NAME "." macro_out 52 | | MACRO_NAME "(" macro_assignment ("," macro_assignment)* ");" 53 | macro_out: MACRO_NAME 54 | 55 | 56 | // ******************************************************************************** 57 | // Arithmetic operators 58 | // ******************************************************************************** 59 | multiply_with: _expr "*" _expr 60 | divide_by: _expr "/" _expr 61 | modulo: _expr "%" _expr 62 | adding: _expr "+" _expr 63 | subtracting: _expr "-" _expr 64 | expt: "exp(" _expr "," _expr ")" 65 | unaryminus: "-" _expr 66 | 67 | 68 | // ******************************************************************************** 69 | // Boolean operators 70 | // ******************************************************************************** 71 | not_op: "!(" _expr ")" 72 | and_op: _expr "&&" _expr 73 | xor_op: "(" _expr ")" "^" "(" _expr ")" 74 | or_op: _expr "||" _expr 75 | 76 | 77 | // ******************************************************************************** 78 | // Numeric operators 79 | // ******************************************************************************** 80 | less_or_equal.1: _expr "<=" _expr 81 | greater_or_equal.1: _expr ">=" _expr 82 | less_than: _expr "<" _expr 83 | greater_than: _expr ">" _expr 84 | 85 | 86 | // ******************************************************************************** 87 | // Equality 88 | // ******************************************************************************** 89 | equality.1: _expr "==" _expr 90 | inequality.1: _expr "!=" _expr 91 | 92 | 93 | // ******************************************************************************** 94 | // General expressions 95 | // ******************************************************************************** 96 | _expr: 97 | | equality 98 | | variable ("[" constant_int "]")* 99 | | multiply_with 100 | | divide_by 101 | | modulo 102 | | adding 103 | | subtracting 104 | | "(" _expr ")" 105 | | expt 106 | | constant 107 | | constant_time 108 | | not_op 109 | | and_op 110 | | xor_op 111 | | or_op 112 | | inequality 113 | | less_or_equal 114 | | greater_or_equal 115 | | less_than 116 | | greater_than 117 | | false 118 | | true 119 | | unaryminus 120 | | if_statement_short 121 | 122 | false: FALSE 123 | FALSE: "false" 124 | true: TRUE 125 | TRUE: "true" 126 | 127 | 128 | // ******************************************************************************** 129 | // Statementlist 130 | // ******************************************************************************** 131 | constant_time.2: MS_DURATION 132 | constant.1: UINT | REAL 133 | constant_int.1: UINT 134 | UINT: /[0-9]+/ 135 | REAL: /[0-9][.]?[0-9]*/ 136 | MS_DURATION: UINT 137 | //NUMBER: /[+-]?[0-9]+/ 138 | 139 | statlist: statement* 140 | 141 | statement: 142 | | immediate_assignment "_LINEBREAK_" 143 | | if_statement "_LINEBREAK_" 144 | | while_statement "_LINEBREAK_" 145 | | repeat_statement "_LINEBREAK_" 146 | | macro 147 | | macro_assignment 148 | 149 | 150 | // ******************************************************************************** 151 | // Assignments 152 | // ******************************************************************************** 153 | immediate_assignment.1: variable("["constant_int"]")* "=" _expr ";" 154 | 155 | macro_assignment: variable "=" _expr 156 | 157 | 158 | // ******************************************************************************** 159 | // selection statement 160 | // ******************************************************************************** 161 | if_statement: "if(" _expr "){" statlist "}else{" statlist "}" 162 | 163 | if_statement_short: "(" _expr "?" _expr ":" _expr ")" 164 | 165 | 166 | 167 | // ******************************************************************************** 168 | // iteration statements 169 | // ******************************************************************************** 170 | while_statement: "while(" _expr "){" "_LINEBREAK_" statlist "pause;" "_LINEBREAK_" statlist "}" 171 | //statlist_while: statement* "pause;" "_LINEBREAK_" statement -> statlist 172 | 173 | repeat_statement: "do:" "_LINEBREAK_" statlist "pause;" "_LINEBREAK_" statlist "if(!(" _expr ")){" "_LINEBREAK_" "goto do;" "_LINEBREAK_" "}else{" "_LINEBREAK_" statlist "}" 174 | 175 | 176 | // ******************************************************************************** 177 | // Additional Terminals and_op rules 178 | // ******************************************************************************** 179 | variable: NAME 180 | 181 | 182 | // ******************************************************************************** 183 | // Lark statements 184 | // ******************************************************************************** 185 | MULTI_LINE_COMMENT: /\(\*.*?\*\)/s 186 | SINGLE_LINE_COMMENT: /\s*/ "//" /[^\n]/* 187 | 188 | %ignore WS 189 | %ignore MULTI_LINE_COMMENT 190 | %ignore SINGLE_LINE_COMMENT 191 | %import common.WS 192 | NAME: /[_]?(?!(true|false|BOOL|INT|REAL|ARRAY\b))[a-zA-Z0-9_]\w*/ 193 | MACRO_NAME: /[_]?(?!(true|false|BOOL|INT|REAL|ARRAY\b))[a-zA-Z_]\w*/ -------------------------------------------------------------------------------- /plcrex/data/grammars/st_grammar.lark: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // POU Declaration List 3 | // ******************************************************************************** 4 | ?start: type pou (idcl | vdcl )* statlist? end_type -> module 5 | pou: NAME -> name 6 | 7 | type: TYPE 8 | TYPE: "PROGRAM" | "FUNCTION_BLOCK" 9 | 10 | end_type: END_TYPE 11 | END_TYPE: "END_PROGRAM" | "END_FUNCTION_BLOCK" 12 | 13 | 14 | // ******************************************************************************** 15 | // Interface/Variable Declaration List 16 | // ******************************************************************************** 17 | idcl: (var_input | var_output | var_in_out)* -> idcl 18 | 19 | vdcl: var_local -> vdcl 20 | 21 | dcllist: declaration* 22 | 23 | declaration: 24 | | variable ":" datatype ";" 25 | | variable ":" datatype ":=" _expr ";" 26 | | variable ":" array ";" 27 | 28 | var_input: "VAR_INPUT" dcllist "END_VAR" 29 | 30 | var_output: "VAR_OUTPUT" dcllist "END_VAR" 31 | 32 | var_in_out: "VAR_IN_OUT" dcllist "END_VAR" 33 | 34 | var_local: "VAR" dcllist "END_VAR" 35 | 36 | 37 | // ******************************************************************************** 38 | // Datatypes 39 | // ******************************************************************************** 40 | datatype: TYPE_BOOL | TYPE_INT | TYPE_REAL | TYPE_TIME | macro_name 41 | 42 | TYPE_BOOL: "BOOL" 43 | TYPE_INT: "INT" 44 | TYPE_REAL: "REAL" 45 | TYPE_TIME: "TIME" 46 | array: "ARRAY" "[1.." constant_int "] OF" datatype 47 | macro_name: MACRO_NAME 48 | 49 | 50 | // ******************************************************************************** 51 | // Functions/User-POUs 52 | // ******************************************************************************** 53 | macro: 54 | | MACRO_NAME "." macro_out 55 | | MACRO_NAME "(" macro_assignment ("," macro_assignment)* ");" 56 | | MACRO_NAME "(" _expr ("," _expr )* ");" 57 | macro_out: MACRO_NAME 58 | 59 | 60 | // ******************************************************************************** 61 | // Arithmetic operators 62 | // ******************************************************************************** 63 | multiply_with.1: _expr "*" _expr | "MUL(" _expr "," _expr ")" 64 | divide_by.1: _expr "/" _expr | "DIV(" _expr "," _expr ")" 65 | modulo.1: _expr "MOD" _expr | "MOD(" _expr "," _expr ")" 66 | adding.1: _expr "+" _expr | "ADD(" _expr "," _expr ")" 67 | subtracting.1: _expr "-" _expr | "SUB(" _expr "," _expr ")" 68 | expt.1: "EXPT(" _expr "," _expr ")" 69 | unaryminus.1: "-" _expr 70 | 71 | 72 | // ******************************************************************************** 73 | // Boolean operators 74 | // ******************************************************************************** 75 | not_op: "NOT" _expr 76 | and_op: _expr "AND" _expr | "AND(" _expr "," _expr ")" 77 | xor_op: _expr "XOR" _expr | "XOR(" _expr "," _expr ")" 78 | or_op: _expr "OR" _expr | "OR(" _expr "," _expr ")" 79 | 80 | 81 | // ******************************************************************************** 82 | // Numeric operators 83 | // ******************************************************************************** 84 | less_or_equal.3: _expr "<=" _expr | "LE(" _expr "," _expr ")" 85 | greater_or_equal.3: _expr ">=" _expr | "GE(" _expr "," _expr ")" 86 | less_than.1: _expr "<" _expr | "LT(" _expr "," _expr ")" 87 | greater_than.1: _expr ">" _expr | "GT(" _expr "," _expr ")" 88 | 89 | 90 | // ******************************************************************************** 91 | // Equality 92 | // ******************************************************************************** 93 | equality: _expr "=" _expr | "EQ(" _expr "," _expr ")" 94 | inequality.2: _expr "<>" _expr | "NE(" _expr "," _expr ")" 95 | 96 | // ******************************************************************************** 97 | // General expressions 98 | // ******************************************************************************** 99 | _expr: 100 | | equality 101 | | variable ("[" constant_int "]")* 102 | | multiply_with 103 | | divide_by 104 | | modulo 105 | | adding 106 | | subtracting 107 | | "(" _expr ")" 108 | | expt 109 | | constant 110 | | constant_time 111 | | not_op 112 | | and_op 113 | | xor_op 114 | | or_op 115 | | inequality 116 | | less_or_equal 117 | | greater_or_equal 118 | | less_than 119 | | greater_than 120 | | false 121 | | true 122 | | unaryminus 123 | | if_statement_short 124 | 125 | false: FALSE 126 | FALSE: "FALSE" 127 | true: TRUE 128 | TRUE: "TRUE" 129 | 130 | 131 | // ******************************************************************************** 132 | // Statementlist 133 | // ******************************************************************************** 134 | constant_time.2: "t#" MS_DURATION "s" 135 | constant.1: UINT | REAL 136 | constant_int.1: UINT 137 | UINT: /[0-9]+/ 138 | REAL: /[0-9][.]?[0-9]*/ 139 | MS_DURATION: UINT 140 | //NUMBER: /[+-]?[0-9]+/ 141 | 142 | statlist: statement* 143 | 144 | statement: 145 | | immediate_assignment 146 | | if_statement 147 | | while_statement 148 | | repeat_statement 149 | | macro 150 | | macro_assignment 151 | 152 | 153 | // ******************************************************************************** 154 | // Assignments 155 | // ******************************************************************************** 156 | immediate_assignment.1: variable("["constant_int"]")* ":=" _expr ";" 157 | 158 | macro_assignment: variable ":=" _expr 159 | 160 | 161 | // ******************************************************************************** 162 | // selection statement 163 | // ******************************************************************************** 164 | if_statement: "IF" _expr "THEN" statlist "ELSE" statlist "END_IF;" 165 | 166 | if_statement_short: "SEL(" _expr "," _expr "," _expr ")" 167 | 168 | 169 | 170 | // ******************************************************************************** 171 | // iteration statements 172 | // ******************************************************************************** 173 | while_statement: "WHILE" _expr "DO" statlist "END_WHILE;" 174 | 175 | repeat_statement: "REPEAT" statlist "UNTIL" _expr "END_REPEAT;" 176 | 177 | 178 | // ******************************************************************************** 179 | // Additional Terminals and_op rules 180 | // ******************************************************************************** 181 | variable: NAME 182 | 183 | 184 | // ******************************************************************************** 185 | // Lark statements 186 | // ******************************************************************************** 187 | MULTI_LINE_COMMENT: /\(\*.*?\*\)/s 188 | SINGLE_LINE_COMMENT: /\s*/ "//" /[^\n]/* 189 | 190 | %ignore WS 191 | %ignore MULTI_LINE_COMMENT 192 | %ignore SINGLE_LINE_COMMENT 193 | %import common.WS 194 | NAME: /[_]?(?!(TRUE|FALSE|BOOL|INT|REAL|ARRAY\b))[a-zA-Z0-9_]\w*/ 195 | MACRO_NAME: /[_]?(?!(BOOL|INT|REAL|ARRAY\b))[a-zA-Z_]\w*/ -------------------------------------------------------------------------------- /plcrex/data/grammars/qrz_grammar.lark: -------------------------------------------------------------------------------- 1 | // ******************************************************************************** 2 | // POU Declaration List 3 | // ******************************************************************************** 4 | ?start: 5 | | ("import" NAME ".*;")* type pou "("")" "{" (vdcl | statlist)* "}" -> module 6 | | ("import" NAME ".*;")* type pou "(" idcl ")" "{" (vdcl | statlist)* "}" -> module 7 | pou: NAME -> name 8 | 9 | type: TYPE 10 | TYPE: "module" 11 | 12 | 13 | // ******************************************************************************** 14 | // Interface/Variable Declaration List 15 | // ******************************************************************************** 16 | idcl: (var_input | var_output | var_in_out) ("," var_input | "," var_output | "," var_in_out)* -> idcl 17 | 18 | vdcl: var_local -> vdcl 19 | 20 | dcllist: declaration 21 | 22 | declaration: 23 | | variable ";" 24 | 25 | var_input: datatype "?" variable 26 | 27 | var_output: datatype "!" variable 28 | 29 | var_in_out: datatype variable 30 | 31 | var_local: 32 | | datatype dcllist 33 | | array datatype dcllist 34 | 35 | 36 | // ******************************************************************************** 37 | // Datatypes 38 | // ******************************************************************************** 39 | datatype: TYPE_BOOL | TYPE_INT | TYPE_REAL | TYPE_TIME | macro_name 40 | 41 | TYPE_BOOL: "bool" 42 | TYPE_INT: "int" 43 | TYPE_REAL: "real" 44 | TYPE_TIME: "nat" 45 | array: "[" constant_int "]" 46 | macro_name: MACRO_NAME 47 | 48 | 49 | // ******************************************************************************** 50 | // Functions/User-POUs 51 | // ******************************************************************************** 52 | macro: 53 | | MACRO_NAME "." macro_out 54 | | MACRO_NAME ":" NAME "(" _expr ("," _expr)* ");" 55 | macro_out: MACRO_NAME 56 | 57 | 58 | // ******************************************************************************** 59 | // Arithmetic operators 60 | // ******************************************************************************** 61 | multiply_with: _expr "*" _expr 62 | divide_by: _expr "/" _expr 63 | modulo: _expr "%" _expr 64 | adding: _expr "+" _expr 65 | subtracting: _expr "-" _expr 66 | expt: "exp(" _expr "," _expr ")" 67 | unaryminus: "-" _expr 68 | 69 | 70 | // ******************************************************************************** 71 | // Boolean operators 72 | // ******************************************************************************** 73 | not_op: "!(" _expr ")" 74 | and_op: _expr "and" _expr 75 | xor_op: _expr "xor" _expr 76 | or_op: _expr "or" _expr 77 | 78 | 79 | // ******************************************************************************** 80 | // Numeric operators 81 | // ******************************************************************************** 82 | less_or_equal.1: _expr "<=" _expr 83 | greater_or_equal.1: _expr ">=" _expr 84 | less_than: _expr "<" _expr 85 | greater_than: _expr ">" _expr 86 | 87 | 88 | // ******************************************************************************** 89 | // Equality 90 | // ******************************************************************************** 91 | equality: _expr "==" _expr | "EQ(" _expr "," _expr ")" 92 | inequality.1: _expr "!=" _expr | "NE(" _expr "," _expr ")" 93 | 94 | // ******************************************************************************** 95 | // General expressions 96 | // ******************************************************************************** 97 | _expr: 98 | | equality 99 | | variable ("[" constant_int "]")* 100 | | multiply_with 101 | | divide_by 102 | | modulo 103 | | adding 104 | | subtracting 105 | | "(" _expr ")" 106 | | expt 107 | | constant 108 | | not_op 109 | | and_op 110 | | xor_op 111 | | or_op 112 | | inequality 113 | | less_or_equal 114 | | greater_or_equal 115 | | less_than 116 | | greater_than 117 | | false 118 | | true 119 | | unaryminus 120 | | if_statement_short 121 | 122 | false: FALSE 123 | FALSE: "false" 124 | true: TRUE 125 | TRUE: "true" 126 | 127 | 128 | // ******************************************************************************** 129 | // Statementlist 130 | // ******************************************************************************** 131 | constant.1: UINT | MS_DURATION | REAL 132 | constant_int.1: UINT 133 | UINT: /[0-9]+/ 134 | REAL: /[0-9][.]?[0-9]*/ 135 | MS_DURATION: "t#"UINT"s" 136 | //NUMBER: /[+-]?[0-9]+/ 137 | 138 | statlist: statement* 139 | 140 | statement: 141 | | immediate_assignment 142 | | if_statement 143 | | while_statement 144 | | repeat_statement 145 | | macro 146 | | pause_statement 147 | | next_statement 148 | 149 | // ******************************************************************************** 150 | // Next 151 | // ******************************************************************************** 152 | next_statement: "next(" variable("["constant_int"]")* ")" "=" _expr ";" 153 | 154 | // ******************************************************************************** 155 | // Pause 156 | // ******************************************************************************** 157 | pause_statement: PAUSE ";" 158 | PAUSE: "pause" 159 | 160 | // ******************************************************************************** 161 | // Assignments 162 | // ******************************************************************************** 163 | immediate_assignment: variable("["constant_int"]")* "=" _expr ";" 164 | 165 | 166 | // ******************************************************************************** 167 | // selection statement 168 | // ******************************************************************************** 169 | if_statement: "if(" _expr "){" statlist "}else{" statlist "}" 170 | 171 | if_statement_short: "(" _expr "?" _expr ":" _expr ")" 172 | 173 | 174 | 175 | // ******************************************************************************** 176 | // iteration statements 177 | // ******************************************************************************** 178 | while_statement: "while(" _expr "){" statlist "pause;" "}" 179 | 180 | repeat_statement: "do{" statlist "pause;" "}" "while(!(" _expr "));" 181 | 182 | 183 | // ******************************************************************************** 184 | // Additional Terminals and_op rules 185 | // ******************************************************************************** 186 | variable: NAME 187 | 188 | 189 | // ******************************************************************************** 190 | // Lark statements 191 | // ******************************************************************************** 192 | MULTI_LINE_COMMENT: /\(\*.*?\*\)/s 193 | SINGLE_LINE_COMMENT: /\s*/ "//" /[^\n]/* 194 | 195 | %ignore WS 196 | %ignore MULTI_LINE_COMMENT 197 | %ignore SINGLE_LINE_COMMENT 198 | %import common.WS 199 | NAME: /[_]?(?!(and|or|xor|pause|true|false|int|real\b))[a-zA-Z0-9_]\w*/ 200 | MACRO_NAME: /[_]?(?!(and|or|xor|pause|true|false|int|real\b))[a-zA-Z_]\w*/ --------------------------------------------------------------------------------