{"id":20687632,"url":"https://github.com/klauer/blark","last_synced_at":"2025-04-06T14:10:55.272Z","repository":{"id":39004146,"uuid":"239225139","full_name":"klauer/blark","owner":"klauer","description":"Beckhoff TwinCAT ST (IEC 61131-3) code parsing in Python using Lark (Earley)","archived":false,"fork":false,"pushed_at":"2025-01-31T16:54:22.000Z","size":6884,"stargazers_count":49,"open_issues_count":7,"forks_count":5,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-03-30T13:08:00.426Z","etag":null,"topics":["iec61131-3","sphinx-domain","structured-text","twincat"],"latest_commit_sha":null,"homepage":"https://klauer.github.io/blark/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/klauer.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-02-09T00:35:54.000Z","updated_at":"2025-03-19T15:53:07.000Z","dependencies_parsed_at":"2023-10-11T11:03:41.655Z","dependency_job_id":"1adf6465-0222-4288-9ec4-2b7ecd32fae8","html_url":"https://github.com/klauer/blark","commit_stats":{"total_commits":384,"total_committers":3,"mean_commits":128.0,"dds":"0.20572916666666663","last_synced_commit":"ff52682f4608db879458093bdb462dfa9f1894ab"},"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/klauer%2Fblark","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/klauer%2Fblark/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/klauer%2Fblark/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/klauer%2Fblark/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/klauer","download_url":"https://codeload.github.com/klauer/blark/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247492513,"owners_count":20947544,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["iec61131-3","sphinx-domain","structured-text","twincat"],"created_at":"2024-11-16T22:57:50.532Z","updated_at":"2025-04-06T14:10:55.246Z","avatar_url":"https://github.com/klauer.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Beckhoff TwinCAT IEC 61131-3 Lark-based Structured Text Tools\n\nOr for short, blark.  B(eckhoff)-lark. It sounded good in my head, at least.\n\n## The Grammar\n\nThe [grammar](blark/iec.lark) uses Lark's Earley parser algorithm.\n\nThe grammar itself is not perfect.  It may not reliably parse your source code\nor produce useful Python instances just yet.\n\nSee [issues](https://github.com/klauer/blark/issues) for further details.\n\nAs a fun side project, blark isn't at the top of my priority list.  For\nan idea of where the project is going, see the issues list.\n\n## Requirements\n\n* [lark](https://github.com/lark-parser/lark) (for grammar-based parsing)\n* [lxml](https://github.com/lxml/lxml) (for parsing TwinCAT projects)\n\n## Capabilities\n\n* TwinCAT source code file parsing (``*.TcPOU`` and others)\n* TwinCAT project and solution loading\n* ``lark.Tree`` generation of any supported source code\n* Python dataclasses of supported source code, with introspection and code refactoring\n\n### Works-in-progress\n\n* Sphinx API documentation generation (a new Sphinx domain)\n* Code reformatting\n* \"Dependency store\" - recursively parse and inspect project dependencies\n* Summary generation - a layer on top of dataclasses to summarize source code details\n* Rewriting source code directly in TwinCAT source code files\n\n## Installation\n\nInstallation is quick with Pip.\n\n```bash\npip install --upgrade blark\n```\n\n### Quickstart (pip / virtualenv with venv)\n\n1. Set up an environment using venv:\n  ```bash\n  $ python -m venv blark_venv\n  $ source blark_venv/bin/activate\n  ```\n2. Install the library with pip:\n  ```bash\n  $ python -m pip install blark\n  ```\n\n### Quickstart (Conda)\n\n1. Set up an environment using conda:\n  ```bash\n  $ conda create -n blark-env -c conda-forge python=3.10 pip blark\n  $ conda activate blark-env\n  ```\n2. Install the library from conda:\n  ```bash\n  $ conda install blark\n  ```\n\n### Development install\n\nIf you run into issues or wish to run an unreleased version of blark, you may\ninstall directly from this repository like so:\n```bash\n$ python -m pip install git+https://github.com/klauer/blark\n```\n\n## Sample runs\n\nRun the parser or experimental formatter utility.  Current supported file types\ninclude those from TwinCAT3 projects ( ``.tsproj``, ``.sln``, ``.TcPOU``,\n``.TcGVL``) and plain-text ``.st`` files.\n\n```bash\n$ blark parse --print-tree blark/tests/POUs/F_SetStateParams.TcPOU\nfunction_declaration\n  None\n  F_SetStateParams\n  indirect_simple_specification\n    None\n    simple_specification        BOOL\n  input_declarations\n    None\n    var1_init_decl\n      var1_list\n... (clipped) ...\n```\n\nTo interact with the Python dataclasses directly, make sure IPython is\ninstalled first and then try:\n\n```\n$ blark parse --interactive blark/tests/POUs/F_SetStateParams.TcPOU\n# Assuming IPython is installed, the following prompt will come up:\n\nIn [1]: results[0].identifier\nOut[1]: 'F_SetStateParams/declaration'\n\nIn [2]: results[1].identifier\nOut[2]: 'F_SetStateParams/implementation'\n```\n\nDump out a parsed and reformatted set of source code:\n\n```bash\n$ blark format blark/tests/source/array_of_objects.st\n{attribute 'hide'}\nMETHOD prv_Detection : BOOL\n    VAR_IN_OUT\n        currentChannel : ARRAY [APhase..CPhase] OF class_baseVector(SIZEOF(vector_t), 0);\n    END_VAR\nEND_METHOD\n```\n\nblark supports rewriting TwinCAT source code files directly as well:\n\n```bash\n$ blark format blark/tests/POUs/F_SetStateParams.TcPOU\n\n\u003cTcPlcObject Version=\"1.1.0.1\" ProductVersion=\"3.1.4024.0\"\u003e\n  \u003cPOU Name=\"F_SetStateParams\" Id=\"{f9611d23-4bb5-422d-9f11-2cc94e61fc9e}\" SpecialFunc=\"None\"\u003e\n    \u003cDeclaration\u003e\u003c![CDATA[FUNCTION F_SetStateParams : BOOL\n    VAR_INPUT\n        nStateRef : UDINT;\n        rPosition : REAL;\n        rTolerance : REAL;\n        stBeamParams : ST_BeamParams;\n\n... (clipped) ...\n```\n\nIt is also possible to parse the source code into a tokenized ``SourceCode``\ntree which supports code introspection and rewriting:\n\n```python\nIn [1]: import blark\n\nIn [2]: parsed = blark.parse_source_code(\n   ...:     \"\"\"\n   ...: PROGRAM ProgramName\n   ...:     VAR_INPUT\n   ...:         iValue : INT;\n   ...:     END_VAR\n   ...:     VAR_ACCESS\n   ...:         AccessName : SymbolicVariable : TypeName READ_WRITE;\n   ...:     END_VAR\n   ...:     iValue := iValue + 1;\n   ...: END_PROGRAM\n   ...: \"\"\"\n   ...: )\n\n# Access the lark Tree here:\nIn [3]: parsed.tree.data\nOut[3]: Token('RULE', 'iec_source')\n\n# Or the transformed information:\nIn [3]: transformed = parsed.transform()\n\nIn [4]: program = transformed.items[0]\n\nIn [5]: program.declarations[0].items[0].variables[0].name\nOut[5]: Token('IDENTIFIER', 'iValue')\n```\n\nThe supported starting grammar rules for the reusable parser include:\n\n```\n\"iec_source\"\n\"action\"\n\"data_type_declaration\"\n\"function_block_method_declaration\"\n\"function_block_property_declaration\"\n\"function_block_type_declaration\"\n\"function_declaration\"\n\"global_var_declarations\"\n\"program_declaration\"\n\"statement_list\"\n```\n\nOther starting rules remain possible for advanced users, however a new parser\nmust be created in that scenario and transformations are not supported.\n\nAdditionally, please note that you should avoid creating parsers on-the-fly as\nthere is a startup cost to re-parsing the grammar. Utilize the provided parser\nfrom ``blark.get_parser()`` whenever possible.\n\n```\nIn [1]: import blark\n\nIn [2]: parser = blark.new_parser(start=[\"any_integer\"])\n\nIn [3]: Tree('hex_integer', [Token('HEX_STRING', '1010')])\n```\n\n## Adding Test Cases\n\nPresently, test cases are provided in two forms. Within the `blark/tests/`\ndirectory there are `POUs/` and `source/` directories.\n\nTwinCAT source code files belong in ``blark/tests/POUs``.\nPlain-text source code files (e.g., ``.st`` files) belong in\n``blark/tests/source``.\n\nFeel free to contribute your own test cases and we'll do our best to ensure\nthat blark parses them (and continues to parse them) without issue.\n\n## Acknowledgements\n\nOriginally based on Volker Birk's IEC 61131-3 grammar\n[iec2xml](https://fdik.org/iec2xml/) (GitHub fork\n[here](https://github.com/klauer/iec2xml)) and [A Syntactic\nSpecification for the Programming Languages of theIEC 61131-3\nStandard](https://www.researchgate.net/publication/228971719_A_syntactic_specification_for_the_programming_languages_of_the_IEC_61131-3_standard)\nby Flor Narciso et al.  Many aspects of the grammar have been added to,\nmodified, and in cases entirely rewritten to better support lark grammars and\ntransformers.\n\nSpecial thanks to the blark contributors:\n\n- @engineerjoe440\n\n## Related, Similar, or Alternative Projects\n\nThere are a number of similar, or related projects that are available.\n\n- [\"MATIEC\"](https://github.com/nucleron/matiec) - another IEC 61131-3 Structured\nText parser which supports IEC 61131-3 second edition, without classes,\nnamespaces and other fancy features. An updated version is also\n[available on Github](https://github.com/sm1820/matiec)\n- [OpenPLC Runtime Version 3](https://github.com/thiagoralves/OpenPLC_v3) -\nAs stated by the project:\n  \u003e OpenPLC is an open-source Programmable Logic Controller that is based on easy to use software. Our focus is to provide a low cost industrial solution for automation and research. OpenPLC has been used in many research papers as a framework for industrial cyber security research, given that it is the only controller to provide the entire source code.\n- [RuSTy](https://github.com/PLC-lang/rusty)\n[documentation](https://plc-lang.github.io/rusty/intro_1.html) - Structured text\ncompiler written in Rust. As stated by the project:\n  \u003e RuSTy is a structured text (ST) compiler written in Rust. RuSTy utilizes the LLVM framework to compile eventually to native code.\n- [IEC Checker](https://github.com/jubnzv/iec-checker) - Static analysis tool\nfor IEC 61131-3 logic. As described by the maintainer:\n  \u003e iec-checker has the ability to parse ST source code and dump AST and CFG to JSON format, so you can process it with your language of choice.\n- [TcBlack](https://github.com/Roald87/TcBlack) - Python black-like code formatter for TwinCAT code.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fklauer%2Fblark","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fklauer%2Fblark","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fklauer%2Fblark/lists"}