From d13dd89fcbd8ca0ffdfe2246f88d6c5022c117a2 Mon Sep 17 00:00:00 2001 From: Miguel Date: Fri, 2 May 2025 23:55:01 +0200 Subject: [PATCH] Agregado del grupo de Scripts para convertir LAD a SCL - Falta adaptar a logica de directorios de trabajo --- __pycache__/config_manager.cpython-312.pyc | Bin 27286 -> 32571 bytes .../ObtainIOFromProjectTia/log_x2.txt | 38 + .../ObtainIOFromProjectTia/log_x3.txt | 48 + .../ObtainIOFromProjectTia/x3.py | 9 +- .../XML Parser to SCL/esquema_group.json | 4 + .../XML Parser to SCL/esquema_work.json | 4 + .../XML Parser to SCL/generators/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 163 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 167 bytes .../generate_md_tag_table.cpython-310.pyc | Bin 0 -> 920 bytes .../generate_md_tag_table.cpython-312.pyc | Bin 0 -> 1593 bytes .../generate_md_udt.cpython-310.pyc | Bin 0 -> 2667 bytes .../generate_md_udt.cpython-312.pyc | Bin 0 -> 4315 bytes .../generate_scl_code_block.cpython-310.pyc | Bin 0 -> 7236 bytes .../generate_scl_code_block.cpython-312.pyc | Bin 0 -> 12299 bytes .../generate_scl_db.cpython-310.pyc | Bin 0 -> 2002 bytes .../generate_scl_db.cpython-312.pyc | Bin 0 -> 3204 bytes .../generator_utils.cpython-310.pyc | Bin 0 -> 6809 bytes .../generator_utils.cpython-312.pyc | Bin 0 -> 11840 bytes .../generators/generate_md_tag_table.py | 28 + .../generators/generate_md_udt.py | 46 + .../generators/generate_scl_code_block.py | 285 +++ .../generators/generate_scl_db.py | 54 + .../generators/generator_utils.py | 278 +++ .../XML Parser to SCL/parsers/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 163 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 164 bytes .../__pycache__/block_parser.cpython-310.pyc | Bin 0 -> 2421 bytes .../__pycache__/flg_parser.cpython-310.pyc | Bin 0 -> 8668 bytes .../interface_parser.cpython-310.pyc | Bin 0 -> 3144 bytes .../network_parser.cpython-310.pyc | Bin 0 -> 2749 bytes .../__pycache__/parse_lad_fbd.cpython-310.pyc | Bin 0 -> 8187 bytes .../__pycache__/parse_lad_fbd.cpython-312.pyc | Bin 0 -> 13929 bytes .../__pycache__/parse_scl.cpython-310.pyc | Bin 0 -> 5850 bytes .../__pycache__/parse_scl.cpython-312.pyc | Bin 0 -> 9888 bytes .../__pycache__/parse_stl.cpython-310.pyc | Bin 0 -> 8976 bytes .../__pycache__/parse_stl.cpython-312.pyc | Bin 0 -> 14457 bytes .../__pycache__/parser_utils.cpython-310.pyc | Bin 0 -> 9570 bytes .../__pycache__/parser_utils.cpython-312.pyc | Bin 0 -> 15849 bytes .../__pycache__/scl_parser.cpython-310.pyc | Bin 0 -> 3014 bytes .../__pycache__/stl_parser.cpython-310.pyc | Bin 0 -> 5231 bytes .../parsers/parse_lad_fbd.py | 548 +++++ .../XML Parser to SCL/parsers/parse_scl.py | 253 +++ .../XML Parser to SCL/parsers/parse_stl.py | 526 +++++ .../XML Parser to SCL/parsers/parser_utils.py | 467 ++++ .../XML Parser to SCL/processors/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 163 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 167 bytes .../__pycache__/process_add.cpython-310.pyc | Bin 0 -> 2366 bytes .../__pycache__/process_add.cpython-312.pyc | Bin 0 -> 3492 bytes .../process_blkmov.cpython-310.pyc | Bin 0 -> 3108 bytes .../process_blkmov.cpython-312.pyc | Bin 0 -> 4408 bytes .../__pycache__/process_call.cpython-310.pyc | Bin 0 -> 2757 bytes .../__pycache__/process_call.cpython-312.pyc | Bin 0 -> 4152 bytes .../__pycache__/process_coil.cpython-310.pyc | Bin 0 -> 2402 bytes .../__pycache__/process_coil.cpython-312.pyc | Bin 0 -> 3556 bytes .../process_comparison.cpython-310.pyc | Bin 0 -> 2154 bytes .../process_comparison.cpython-312.pyc | Bin 0 -> 3348 bytes .../process_contact.cpython-310.pyc | Bin 0 -> 1473 bytes .../process_contact.cpython-312.pyc | Bin 0 -> 2112 bytes .../process_convert.cpython-310.pyc | Bin 0 -> 2302 bytes .../process_convert.cpython-312.pyc | Bin 0 -> 3303 bytes .../process_counter.cpython-310.pyc | Bin 0 -> 2666 bytes .../process_counter.cpython-312.pyc | Bin 0 -> 3967 bytes .../process_edge_detector.cpython-310.pyc | Bin 0 -> 2352 bytes .../process_edge_detector.cpython-312.pyc | Bin 0 -> 3380 bytes .../__pycache__/process_eq.cpython-310.pyc | Bin 0 -> 1797 bytes .../__pycache__/process_eq.cpython-312.pyc | Bin 0 -> 2656 bytes .../__pycache__/process_math.cpython-310.pyc | Bin 0 -> 2468 bytes .../__pycache__/process_math.cpython-312.pyc | Bin 0 -> 3678 bytes .../__pycache__/process_mod.cpython-310.pyc | Bin 0 -> 2234 bytes .../__pycache__/process_mod.cpython-312.pyc | Bin 0 -> 3277 bytes .../__pycache__/process_move.cpython-310.pyc | Bin 0 -> 2173 bytes .../__pycache__/process_move.cpython-312.pyc | Bin 0 -> 3080 bytes .../__pycache__/process_not.cpython-310.pyc | Bin 0 -> 1360 bytes .../__pycache__/process_not.cpython-312.pyc | Bin 0 -> 1821 bytes .../__pycache__/process_o.cpython-310.pyc | Bin 0 -> 1637 bytes .../__pycache__/process_o.cpython-312.pyc | Bin 0 -> 2183 bytes .../__pycache__/process_rcoil.cpython-310.pyc | Bin 0 -> 2145 bytes .../__pycache__/process_rcoil.cpython-312.pyc | Bin 0 -> 2903 bytes .../__pycache__/process_scoil.cpython-310.pyc | Bin 0 -> 2140 bytes .../__pycache__/process_scoil.cpython-312.pyc | Bin 0 -> 2898 bytes .../__pycache__/process_sd.cpython-310.pyc | Bin 0 -> 2016 bytes .../__pycache__/process_sd.cpython-312.pyc | Bin 0 -> 2819 bytes .../__pycache__/process_se.cpython-310.pyc | Bin 0 -> 2617 bytes .../__pycache__/process_se.cpython-312.pyc | Bin 0 -> 3881 bytes .../__pycache__/process_timer.cpython-310.pyc | Bin 0 -> 2175 bytes .../__pycache__/process_timer.cpython-312.pyc | Bin 0 -> 3248 bytes .../processor_utils.cpython-310.pyc | Bin 0 -> 5905 bytes .../processor_utils.cpython-312.pyc | Bin 0 -> 11001 bytes .../symbol_manager.cpython-310.pyc | Bin 0 -> 1965 bytes .../symbol_manager.cpython-312.pyc | Bin 0 -> 2919 bytes .../processors/process_add.py | 87 + .../processors/process_blkmov.py | 118 + .../processors/process_call.py | 131 ++ .../processors/process_coil.py | 82 + .../processors/process_comparison.py | 87 + .../processors/process_contact.py | 60 + .../processors/process_convert.py | 90 + .../processors/process_counter.py | 110 + .../processors/process_edge_detector.py | 85 + .../processors/process_eq.py | 64 + .../processors/process_math.py | 91 + .../processors/process_mod.py | 75 + .../processors/process_move.py | 75 + .../processors/process_not.py | 54 + .../XML Parser to SCL/processors/process_o.py | 69 + .../processors/process_rcoil.py | 74 + .../processors/process_scoil.py | 74 + .../processors/process_sd.py | 77 + .../processors/process_se.py | 112 + .../processors/process_timer.py | 85 + .../processors/processor_utils.py | 310 +++ .../processors/symbol_manager.py | 58 + .../script_groups/XML Parser to SCL/readme.md | 160 ++ .../XML Parser to SCL/x0_main.py | 561 +++++ .../XML Parser to SCL/x1_to_json.py | 493 +++++ .../XML Parser to SCL/x2_process.py | 576 +++++ .../XML Parser to SCL/x3_generate_scl.py | 199 ++ .../XML Parser to SCL/x4_cross_reference.py | 661 ++++++ .../XML Parser to SCL/x5_aggregate.py | 137 ++ config_manager.py | 181 +- data/log.txt | 1970 +---------------- 123 files changed, 7604 insertions(+), 1990 deletions(-) create mode 100644 backend/script_groups/ObtainIOFromProjectTia/log_x2.txt create mode 100644 backend/script_groups/ObtainIOFromProjectTia/log_x3.txt create mode 100644 backend/script_groups/XML Parser to SCL/esquema_group.json create mode 100644 backend/script_groups/XML Parser to SCL/esquema_work.json create mode 100644 backend/script_groups/XML Parser to SCL/generators/__init__.py create mode 100644 backend/script_groups/XML Parser to SCL/generators/__pycache__/__init__.cpython-310.pyc create mode 100644 backend/script_groups/XML Parser to SCL/generators/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/script_groups/XML Parser to SCL/generators/__pycache__/generate_md_tag_table.cpython-310.pyc create mode 100644 backend/script_groups/XML Parser to SCL/generators/__pycache__/generate_md_tag_table.cpython-312.pyc create mode 100644 backend/script_groups/XML Parser to SCL/generators/__pycache__/generate_md_udt.cpython-310.pyc create mode 100644 backend/script_groups/XML Parser to SCL/generators/__pycache__/generate_md_udt.cpython-312.pyc create mode 100644 backend/script_groups/XML Parser to SCL/generators/__pycache__/generate_scl_code_block.cpython-310.pyc create mode 100644 backend/script_groups/XML Parser to SCL/generators/__pycache__/generate_scl_code_block.cpython-312.pyc create mode 100644 backend/script_groups/XML Parser to SCL/generators/__pycache__/generate_scl_db.cpython-310.pyc create mode 100644 backend/script_groups/XML Parser to SCL/generators/__pycache__/generate_scl_db.cpython-312.pyc create mode 100644 backend/script_groups/XML Parser to SCL/generators/__pycache__/generator_utils.cpython-310.pyc create mode 100644 backend/script_groups/XML Parser to SCL/generators/__pycache__/generator_utils.cpython-312.pyc create mode 100644 backend/script_groups/XML Parser to SCL/generators/generate_md_tag_table.py create mode 100644 backend/script_groups/XML Parser to SCL/generators/generate_md_udt.py create mode 100644 backend/script_groups/XML Parser to SCL/generators/generate_scl_code_block.py create mode 100644 backend/script_groups/XML Parser to SCL/generators/generate_scl_db.py create mode 100644 backend/script_groups/XML Parser to SCL/generators/generator_utils.py create mode 100644 backend/script_groups/XML Parser to SCL/parsers/__init__.py create mode 100644 backend/script_groups/XML Parser to SCL/parsers/__pycache__/__init__.cpython-310.pyc create mode 100644 backend/script_groups/XML Parser to SCL/parsers/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/script_groups/XML Parser to SCL/parsers/__pycache__/block_parser.cpython-310.pyc create mode 100644 backend/script_groups/XML Parser to SCL/parsers/__pycache__/flg_parser.cpython-310.pyc create mode 100644 backend/script_groups/XML Parser to SCL/parsers/__pycache__/interface_parser.cpython-310.pyc create mode 100644 backend/script_groups/XML Parser to SCL/parsers/__pycache__/network_parser.cpython-310.pyc create mode 100644 backend/script_groups/XML Parser to SCL/parsers/__pycache__/parse_lad_fbd.cpython-310.pyc create mode 100644 backend/script_groups/XML Parser to SCL/parsers/__pycache__/parse_lad_fbd.cpython-312.pyc create mode 100644 backend/script_groups/XML Parser to SCL/parsers/__pycache__/parse_scl.cpython-310.pyc create mode 100644 backend/script_groups/XML Parser to SCL/parsers/__pycache__/parse_scl.cpython-312.pyc create mode 100644 backend/script_groups/XML Parser to SCL/parsers/__pycache__/parse_stl.cpython-310.pyc create mode 100644 backend/script_groups/XML Parser to SCL/parsers/__pycache__/parse_stl.cpython-312.pyc create mode 100644 backend/script_groups/XML Parser to SCL/parsers/__pycache__/parser_utils.cpython-310.pyc create mode 100644 backend/script_groups/XML Parser to SCL/parsers/__pycache__/parser_utils.cpython-312.pyc create mode 100644 backend/script_groups/XML Parser to SCL/parsers/__pycache__/scl_parser.cpython-310.pyc create mode 100644 backend/script_groups/XML Parser to SCL/parsers/__pycache__/stl_parser.cpython-310.pyc create mode 100644 backend/script_groups/XML Parser to SCL/parsers/parse_lad_fbd.py create mode 100644 backend/script_groups/XML Parser to SCL/parsers/parse_scl.py create mode 100644 backend/script_groups/XML Parser to SCL/parsers/parse_stl.py create mode 100644 backend/script_groups/XML Parser to SCL/parsers/parser_utils.py create mode 100644 backend/script_groups/XML Parser to SCL/processors/__init__.py create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/__init__.cpython-310.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/process_add.cpython-310.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/process_add.cpython-312.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/process_blkmov.cpython-310.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/process_blkmov.cpython-312.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/process_call.cpython-310.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/process_call.cpython-312.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/process_coil.cpython-310.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/process_coil.cpython-312.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/process_comparison.cpython-310.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/process_comparison.cpython-312.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/process_contact.cpython-310.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/process_contact.cpython-312.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/process_convert.cpython-310.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/process_convert.cpython-312.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/process_counter.cpython-310.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/process_counter.cpython-312.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/process_edge_detector.cpython-310.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/process_edge_detector.cpython-312.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/process_eq.cpython-310.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/process_eq.cpython-312.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/process_math.cpython-310.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/process_math.cpython-312.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/process_mod.cpython-310.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/process_mod.cpython-312.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/process_move.cpython-310.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/process_move.cpython-312.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/process_not.cpython-310.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/process_not.cpython-312.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/process_o.cpython-310.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/process_o.cpython-312.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/process_rcoil.cpython-310.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/process_rcoil.cpython-312.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/process_scoil.cpython-310.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/process_scoil.cpython-312.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/process_sd.cpython-310.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/process_sd.cpython-312.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/process_se.cpython-310.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/process_se.cpython-312.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/process_timer.cpython-310.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/process_timer.cpython-312.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/processor_utils.cpython-310.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/processor_utils.cpython-312.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/symbol_manager.cpython-310.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/__pycache__/symbol_manager.cpython-312.pyc create mode 100644 backend/script_groups/XML Parser to SCL/processors/process_add.py create mode 100644 backend/script_groups/XML Parser to SCL/processors/process_blkmov.py create mode 100644 backend/script_groups/XML Parser to SCL/processors/process_call.py create mode 100644 backend/script_groups/XML Parser to SCL/processors/process_coil.py create mode 100644 backend/script_groups/XML Parser to SCL/processors/process_comparison.py create mode 100644 backend/script_groups/XML Parser to SCL/processors/process_contact.py create mode 100644 backend/script_groups/XML Parser to SCL/processors/process_convert.py create mode 100644 backend/script_groups/XML Parser to SCL/processors/process_counter.py create mode 100644 backend/script_groups/XML Parser to SCL/processors/process_edge_detector.py create mode 100644 backend/script_groups/XML Parser to SCL/processors/process_eq.py create mode 100644 backend/script_groups/XML Parser to SCL/processors/process_math.py create mode 100644 backend/script_groups/XML Parser to SCL/processors/process_mod.py create mode 100644 backend/script_groups/XML Parser to SCL/processors/process_move.py create mode 100644 backend/script_groups/XML Parser to SCL/processors/process_not.py create mode 100644 backend/script_groups/XML Parser to SCL/processors/process_o.py create mode 100644 backend/script_groups/XML Parser to SCL/processors/process_rcoil.py create mode 100644 backend/script_groups/XML Parser to SCL/processors/process_scoil.py create mode 100644 backend/script_groups/XML Parser to SCL/processors/process_sd.py create mode 100644 backend/script_groups/XML Parser to SCL/processors/process_se.py create mode 100644 backend/script_groups/XML Parser to SCL/processors/process_timer.py create mode 100644 backend/script_groups/XML Parser to SCL/processors/processor_utils.py create mode 100644 backend/script_groups/XML Parser to SCL/processors/symbol_manager.py create mode 100644 backend/script_groups/XML Parser to SCL/readme.md create mode 100644 backend/script_groups/XML Parser to SCL/x0_main.py create mode 100644 backend/script_groups/XML Parser to SCL/x1_to_json.py create mode 100644 backend/script_groups/XML Parser to SCL/x2_process.py create mode 100644 backend/script_groups/XML Parser to SCL/x3_generate_scl.py create mode 100644 backend/script_groups/XML Parser to SCL/x4_cross_reference.py create mode 100644 backend/script_groups/XML Parser to SCL/x5_aggregate.py diff --git a/__pycache__/config_manager.cpython-312.pyc b/__pycache__/config_manager.cpython-312.pyc index 263e6e1c42fe7fd86393d776fb9b1bbf9b64d37a..058fdb0bd16cedff2686ec9a815fd4efbc4cdc45 100644 GIT binary patch delta 6813 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 Associating Network 'ETHERNET_1' with PLC 'PLC' (via Node 'E1' Addr: 10.1.33.11) + Mapping Device/Node 'P1' (NodeID:5aff409b-2573-485f-82bf-0e08c9200086, Addr:1) to Network 'PROFIBUS_1' + --> Associating Network 'PROFIBUS_1' with PLC 'PLC' (via Node 'P1' Addr: 1) + Mapping Device/Node 'PB1' (NodeID:c796e175-c770-43f0-8191-fc91996c0147, Addr:12) to Network 'PROFIBUS_1' + Mapping Device/Node 'PB1' (NodeID:0b44f55a-63c1-49e8-beea-24dc5d3226e3, Addr:20) to Network 'PROFIBUS_1' + Mapping Device/Node 'PB1' (NodeID:25cfc251-f946-40c5-992d-ad6387677acb, Addr:21) to Network 'PROFIBUS_1' + Mapping Device/Node 'PB1' (NodeID:57999375-ec72-46ef-8ec2-6c3178e8acf8, Addr:22) to Network 'PROFIBUS_1' + Mapping Device/Node 'PB1' (NodeID:54e8db6a-9443-41a4-a85b-cf0722c1d299, Addr:10) to Network 'PROFIBUS_1' + Mapping Device/Node 'PB1' (NodeID:4786bab6-4097-4651-ac19-6cadfc7ea735, Addr:8) to Network 'PROFIBUS_1' + Mapping Device/Node 'PB1' (NodeID:1f08afcb-111f-428f-915e-69363af1b09a, Addr:40) to Network 'PROFIBUS_1' +Data extraction and structuring complete. +Generating JSON output: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\IOExport\SAE196_c0.2_CAx_Export.hierarchical.json +JSON data written successfully. + +Markdown summary written to: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\IOExport\SAE196_c0.2_CAx_Export_Hardware_Tree.md + +IO upward debug tree written to: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\IOExport\SAE196_c0.2_CAx_Export_IO_Upward_Debug.md + +Script finished. + +--- ERRORES (STDERR) --- +Ninguno +--- FIN DEL LOG --- diff --git a/backend/script_groups/ObtainIOFromProjectTia/x3.py b/backend/script_groups/ObtainIOFromProjectTia/x3.py index 833b91d..9233729 100644 --- a/backend/script_groups/ObtainIOFromProjectTia/x3.py +++ b/backend/script_groups/ObtainIOFromProjectTia/x3.py @@ -6,6 +6,7 @@ generar un archivo Markdown con la información. import os import sys +import tkinter as tk from tkinter import filedialog import traceback from lxml import etree as ET @@ -732,9 +733,9 @@ def generate_markdown_tree(project_data, md_file_path): end_byte = start_byte + length_bytes - 1 prefix = "P?" if io_type.lower() == "input": - prefix = "PE" + prefix = "EW" elif io_type.lower() == "output": - prefix = "PA" + prefix = "AW" siemens_addr = f"{prefix} {start_byte}..{end_byte}" except Exception: # Catch any error during calc/format siemens_addr = ( @@ -963,8 +964,8 @@ def select_cax_file(initial_dir=None): # Add initial_dir parameter root = tk.Tk() root.withdraw() file_path = filedialog.askopenfilename( - title="Select CAx Export File (XML)", - filetypes=[("XML Files", "*.xml"), ("AML Files", "*.aml"), ("All Files", "*.*")], # Added AML + title="Select CAx Export File (AML)", + filetypes=[ ("AML Files", "*.aml"), ("All Files", "*.*")], # Added AML initialdir=initial_dir # Set the initial directory ) root.destroy() diff --git a/backend/script_groups/XML Parser to SCL/esquema_group.json b/backend/script_groups/XML Parser to SCL/esquema_group.json new file mode 100644 index 0000000..1c9e43a --- /dev/null +++ b/backend/script_groups/XML Parser to SCL/esquema_group.json @@ -0,0 +1,4 @@ +{ + "type": "object", + "properties": {} +} \ No newline at end of file diff --git a/backend/script_groups/XML Parser to SCL/esquema_work.json b/backend/script_groups/XML Parser to SCL/esquema_work.json new file mode 100644 index 0000000..1c9e43a --- /dev/null +++ b/backend/script_groups/XML Parser to SCL/esquema_work.json @@ -0,0 +1,4 @@ +{ + "type": "object", + "properties": {} +} \ No newline at end of file diff --git a/backend/script_groups/XML Parser to SCL/generators/__init__.py b/backend/script_groups/XML Parser to SCL/generators/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/script_groups/XML Parser to SCL/generators/__pycache__/__init__.cpython-310.pyc b/backend/script_groups/XML Parser to SCL/generators/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bcc9ca1f3da1db1449ae61514641e8881e98da33 GIT binary patch literal 163 zcmd1j<>g`kf{8C#GC=fW5P=LBfgA@QE@lA|DGb33nv8xc8Hzx{2;!Gpid9TNQGR7= za!G!1OmK2hWfs%>&W7i6xoI3K70O3IT~l#i>Ox>8W|CMTsT(Ma41k@tJv< cCGqik1(mlrY;yBcN^?@}K;{=S0SOic0C3PK6#xJL literal 0 HcmV?d00001 diff --git a/backend/script_groups/XML Parser to SCL/generators/__pycache__/__init__.cpython-312.pyc b/backend/script_groups/XML Parser to SCL/generators/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8d577a711c37473936c5924b3ba3e711e2c7575c GIT binary patch literal 167 zcmX@j%ge<81QTDfWPs?$AOanHW&w&!XQ*V*Wb|9fP{ah}eFmxd<(6U<6Ht_2nVMXZ zUmO#hT$EW*0;Drjb5rv`bZ%lvX0k$rua81NVo`BwQA~PjUTRTdNq$jrOniK1US>&r kyk0@&Ee@O9{FKt1RJ$Tpps|cVTnu7-WM*V!EMf+-0P9LB`2YX_ literal 0 HcmV?d00001 diff --git a/backend/script_groups/XML Parser to SCL/generators/__pycache__/generate_md_tag_table.cpython-310.pyc b/backend/script_groups/XML Parser to SCL/generators/__pycache__/generate_md_tag_table.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bb2358fb3fabde0d6b63ee12d0d0889ac89f7651 GIT binary patch literal 920 zcmY*Y&uiN-6qaN=aolA6xn0(S#$a0x?bx*&Wu=8()(}VsBV?qirKYB_?8z=AM!D_3 zD23#>e@WN<13MQ6ds5P_6TJ7n_xb6)PqLl0S`mWPcoAHz`Uw59$>T*J`3P1t!Ewa# z57bAT^ibQ2F;Mr*cCjUgV8w56BQ(Vt&0q&7b223kdm{wc(|CrtugML%C3B3C%L9iz zHFjC;fv+$4BlPY4)Ym?A40!{(1P(_I*BoB4IN#^ZY2D?mIi7|(R9zj;2!Fy?=LF&! zZ_bItJeW4zq;(zKAikk%&ey?j>IV3&+lHO|z5PfX?k%)FeNeYh4Sf4q_3o39LNOX= zvJ^7m89ip|l4sYF<_!2N$!N*W#*A_SU{vgy=xm(DmqW=?(O>-{FC`S8u+a%r3FF(E zs`Zir0|wL{HK=;6X$R`5rbnz~DQRQiRS_P-j`n2+Gs0cLQ?qu!^^gO$goFa#L3#AG27rBjek#CQSKooJdjhBYPvl-GH(moAKb(3O+@o0_$p) zTUn|aDt4_xV16RC0pYI4_Xb^+O+;K~#h@3fBrhQ*01 z%1jmaPz*r}%mf1=yZOXCUlxgf^e|n%Nh_>)1I{N++{9}n!ai7pL&zWpw2fbZ_k-w< ieWtdcxYNciI?<2ZCOk9Yhcx3?W3g}lr^4Pr)B6i~cKIm) literal 0 HcmV?d00001 diff --git a/backend/script_groups/XML Parser to SCL/generators/__pycache__/generate_md_tag_table.cpython-312.pyc b/backend/script_groups/XML Parser to SCL/generators/__pycache__/generate_md_tag_table.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5af10f6e9c1b826089f2a5c19c037c0a49af952a GIT binary patch literal 1593 zcma)+&ube;6vtCAe9iRqe?D0`j}%N7o}2(I=wjL9}xJ~Q)d*(R)Yn7Ftcyod}ii5 z?=AD(=W_#Ut`8g!{2~Ca*`RM+&pBd91wim4_!{hRQ9jk5VStx5fwm)yXH*&#I2&vX z5{#k-Imkbz46_11gb~ueOJklU>VwBISDHL@R zksV8<986|28ZwBRWdwCIfZ1O|w>wPs+hxZL*m_pa_<-T$Jx z*z~+#j2(*JpW;8n_j9%7+I%DQNlTn=_d<&;G5pHuX-jAK{JZ`}WT7Q39uGclNfUnu z!=>x(pj??P&sJw@SDL|SDb@~;Rkq99RjYob8J;fPXv^0m;R7vo?I?1 zwa4E3ZT#2qTC_PfQM&op&Aa=XFXiY9IaeKRvYKn{`B7I_&_MqIRjh)Cc4VEq;nlN z@P>-N1#>9U)J5vhpwfffa_L9js*6h$}QqHg!0IFK35*yfrd zl^H6Ii6O9nU2JTG{t#YmZ>ww{8uTKW$B!f7}Ij@nsFD#E3(4h zl9dUe73xh1)KyxW7E+!h6N}cR^*N#qSpwRWj-f8lCFucOeqNnojLdp1Sg$Ipybts2 zv?Qw%)0NBUl*}boL82yW{9n?^>!~B1w0uhVN79+NQ#7g2OH<50O1(*yuECi1_uACT z8?pfsjY*wep5jSkit_rxxz?Xsdi89LUZERjNY*CJDcI%|=S}(w-8@6-l59?vr_f`1 zm;Qp{rj63p$(I=E7shMFc)s*E6yswgm%z4uzAS5U`3lNgvSlpz4Op-x>oW_kES%x0 zTn00$w8SrqFLJfvyv92NQ!h!$S2Y>Y63%Fo>_rSO(O}IE`S$|0TW14nH zC(64;!$AtB9NoU652v-)&Wboc9$x1Hj07)Q%*1%v6w1{Jxg_c^?%w%d7%hnh}C$&_+`CN zDN2qRSDuMqaU7|u%-h=yaA*}T)d7wyoR@M2WrjR@UG(}+=7=t z*}$)27v44OWAYChn-wm^q&9&r+PUK2Kn~C+5S4JhU`pUl!G^b}4Ltc6O)xD<{5g7V z(A~6cgY$&{&a@oe`X}0l`-Zw_fQA!NATve_(t7<$h~VZy)H{G0?lz0>83}W<{3vU< znqJj#^%-ZSwzN+1yx%UkokFVd^Zs@-+nQnWAc-MlLz?^qm&dV&0xyHLvhp=O=cb?4I-R=(^xo`rE|^%Sz4n^UVzCLtq`jA8Pze4e z&dph*e;a4yw%^A56%d@|zp|q+W?$f*3xTXzQ3Qs@0lp4o3yJ}NO~B%L9s-ulacTjZ z=83N=fTxV_>uk2SlbB`RwQK$Z185?9UHaQ#0KkEJv%3b^9sSo*;5xKs`uZ|kmN#zP zxKOgK?Zltup}(JuW9o;opB@%B-hAV3yTmoZ8g&5-Mp2j+8frtCaBbVl*4JIn)e0G> zR5f?*2K`S~*yByj8F0MxUyYzsQfPZ^k`3I&tB@?K@HTYfkk$V{dfbFTu)X;9o9*3O!-S3_c3UqbG+4N#hCNc-`~fw3)&>9o literal 0 HcmV?d00001 diff --git a/backend/script_groups/XML Parser to SCL/generators/__pycache__/generate_md_udt.cpython-312.pyc b/backend/script_groups/XML Parser to SCL/generators/__pycache__/generate_md_udt.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..77122fa95a0961a475ea3234554c6239fb4964e2 GIT binary patch literal 4315 zcmb7HT}&HS7QQnc|KMM+4Z)Cx2_ys)h5R*jmZn5WfI!oj#QY>7fN?wnjPVb9XZV|r zl~k(KM2Z%oeF#w%#nooDM0u#AU8y|m1AW+*XjkgEo(gA_l`2(Qsc+e`+THYN@3lQZ zQmDFDaPPVIoO{l>=iIsH^IvT?GeGU%w0`WI1%U7HL~CS`SgS|GUBCc_h=P8=kc=)$ z#K?Y<0E~g5J|y~ejQ&H=Pt6iuEcF7KFBzvTKgQrnUg=R1E zhPJjbYMv%-KbyH7_jQ^U0+ayB8mZaPp;4NyRxsz7D-G*75GDsvbOz9kPdbvN!fs7c za%kG5(%+J|T@*-`n}Nd(s>2k9-js?x+`Fs@K%ey zvuvD&A$o+1hIsmX2#zy}={P+RLTfROja`EYo@Q9Ox3!0EfNXdY^4wIy+ay-j$FK1d zZ~wGcsdy;HiaP(nQ>uvx2_a#2f>kY>o<|j^#&9AQW8;EKNFq5Psf1Z2Xpxj?l^7QF z!?Z*XixeJ2l9p6cc#MlOkc~rpc~yG|!q9Axjj~t;FBjj6lM%uZE74C9N_mS zMo{N%XlnF+j~`IcyV=>shR!%AaG@yOho5ZT+lZ`bf1-V}=DzSUge#Wylz!D z$_fxY+~_cnors3QtZE2NOt5iAHLx=R9^V+v2UlQ&v0`9@F%(i324P~FSIr#H#Zg@1 zXseDFpsJ51rdg<(^ReQmIblpCA*M zSP(zTs$)~$f-p4w>cU7&P%Xt&VlKqh7UC}omg3#cYayNu;tLQ&l`_boh{K(jL5!=! zlRkkV0<#hLN2U23(h0K!a5F$kz;01aYY2Gt$7#n1TxLz2aw*f{dk^f9=HG# zvus#M@B`gp6eaCt%9E|wf76nQ zPN&~r^}U<%y}NQ$zR;8P^{)B`GrmE2=$g!oD!wr}d42Ix&g7W0-?A?_7upw&rw*rj zQtgX-)22mnseI|W+|soo$URr(?g4pVNZt`tOv5>s=Wg?z=7mVs<-KWoW^v75x;u1d zNZE60xnZSE?&*EnncdT;lwZnuY93VGtCIJ;ne`mIX;&?tTy3Llt9f2pwQ&4lw^Hg| z9Q!o>D4uO4B{0@_hL-wjoXtHqbZcngTB;&tk{d3{I|GWX`vs}9cN4khj@4#=rrEDF zUr_2UW|}WN*^}O#zWDIWBJsQS#Z#Yj%FP$%Ych2gpZnffO02d7GA)5@OON8~&DQs2 ze7))25BbHzzn_wQy>eNdT;KQI&ZhYtxoYp?zD)HILkt0%fLC%UpHE}|RoHGM?31%BiYpGJIJi=GPjdm&lL7eNro<1lUH7+9aWafo-G=o29mbiCWo4<(ev% zYxE5wki4~bMv2<&9V+0J6e^ra>KFOBb>vLkIuP74vL&PId<4w(@Ymb;X5Mtxt-aqI zv#ljIgWatqtgl$v0#FO<;8$AzDe%gkt+M`#XWiT7-1h(K$-^6zooV2;i}gha5>CWX z)#RAOYcOOoj?qVxYQ7dtgvWyzU8v^X_;?%v6~s_&h4o??g7}!Cu@3KPrbTOGxP@Wdgw%MLX6Z=xu1w~LX?ZMJjCEW zUuV1qmBQdjHK8Ju=cy)CiwdW=V5)dtmBL(zkuQ&nQ=uHfV_0+fI{v^LGz$hfK0CcZf$^YQt9Qn_}fEM2){p7#!tc%Rq zopWQi#^&EoozB|#t=jiz?E4qn(`e$marT+fo->usIc_-?tcq!GYUU5uKe?WU%D(2} zvRv7wnA%rNUpbyS7=HCR7}<1T3k1}Ug&_uHFxmVLAmO* zVm`Bc`ODzvLAm#m(sntA`7eJc13r<+$Ncld)omWiOF;A(1C(3*lS*~0BZ}apz(x5y zRxAJsoPbAQ4fUXqDAS2pf|-o6EwCM};fJ2zfw~tuf*{rmfH40Z99^TT2-n(iE8&K1 Gi1$BgZ490O literal 0 HcmV?d00001 diff --git a/backend/script_groups/XML Parser to SCL/generators/__pycache__/generate_scl_code_block.cpython-310.pyc b/backend/script_groups/XML Parser to SCL/generators/__pycache__/generate_scl_code_block.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b46f21819f7b34f2fcc40eb2f732b9f7e6de00d9 GIT binary patch literal 7236 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 literal 0 HcmV?d00001 diff --git a/backend/script_groups/XML Parser to SCL/generators/__pycache__/generate_scl_code_block.cpython-312.pyc b/backend/script_groups/XML Parser to SCL/generators/__pycache__/generate_scl_code_block.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..590b9aa07d733a3489d30c99069f21c08a2e59d3 GIT binary patch literal 12299 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 literal 0 HcmV?d00001 diff --git a/backend/script_groups/XML Parser to SCL/generators/__pycache__/generate_scl_db.cpython-310.pyc b/backend/script_groups/XML Parser to SCL/generators/__pycache__/generate_scl_db.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..44c220204bab40c635bf6b3f3ec4a8effdd52c1f GIT binary patch literal 2002 zcmZuy&2HO95aupPS(0U2PK@RUX}b-I+5%c71p*i_T%-O&U^I~f+X)K6EkSYDGHZ%t zcUNw#(kBOKd+4F(Ab@?$p{G28U!Z4Rd+ICX)S0C$+eHcN?Ci|$&g^_M!(?KjYQa~V zclXbM`x_TmKMISlVW`i6aEp`3>XA0-(KaO(r`&#JwQcTj7iNc-_!!JCFK=6o%0C2- zG-y7vm&l&4y+dDyekT%M?Ds@|rz>J1eJwl{L>?DGJ zhWjB-H(GhM6D7fcr;k#Rk3EkM;^e3JLTG|j8wyu&UtTM=$NgSM$b6z$1xc?bVx3!q zsRs|3*~oU_!UZMxy!a3uMCB$7bq`1v z@c6EJOyKp9A^3WX^B?p_3a=vr7c4N=AbH78QxS8>2-I+i-?F3Iq1-({(EwN@X60? zd*0hjb=V6Bf_uwBAe3SYU$NPpt>^2r?07KoVts3SW3$B;*u&_g0khu8HMsG3WuIjZD%%z0^-i^Cc%vs zN{(1@MMDF?f-o|Z;D#%sHp677^dEtd$ENUEd=bBM%r-Y3`_;uCGipra*4ewcT)++8%{nsyd@AG;xF&u{wW~sab=#1jZzhm z8{7@#x2{7zy5klcRA>@WcL4Pnn9H;Z93cK7D6S!ntrUkryaNm(uCbw#qM@D;Xrl$r z&?rv|+)-LVaxTXb3q(4I?h%kSA<=^$Dzc zX(V(~fZvbVWw|v?4YVu6&bPMGu8bbtc30LPZ?pz;j6ri*gD4gaPqBUfP_P)ldntmx z#=i~N;G#W=AYESGC`oJu1y*;F!`d+6GSC5xAE01_jl?)h>~{YJ=H|6l0>3(scV=Oq zx&g$YbyBA_TBp?l5-L9eaSMunYIqI~^mQ1i!XZqRE56|7D+Vvqp}g2jcs~+LSPBXo MMcppj<$A6DFKl@KPXGV_ literal 0 HcmV?d00001 diff --git a/backend/script_groups/XML Parser to SCL/generators/__pycache__/generate_scl_db.cpython-312.pyc b/backend/script_groups/XML Parser to SCL/generators/__pycache__/generate_scl_db.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2ef5cc7b5d9d0ee8c68af0f2190d17653c763eb2 GIT binary patch literal 3204 zcmai0TWs6Z8@C_O?7bY;^`19))|?R*%Xsz=h-wj&#{cm{g0XV$R3z^ znTOeX&l~go#sWCT+5NXQk`@hNNhFGxOkqJ4)7TzZz$zx9fdySk2{M*aBJ31R)upO6 zYSa&x2d<~L;B=i?V3xT&vq&}X8Zs+$4_wJ*PYaAk=4%+f1;+cp)xPX)f$+)xnigN4 zTcrN&8gd}-`IPyLtLkEzJfCOpjxY@AZz0i^=XXhXTVjKG?=Gy5jJMF+-r$38(Ywo0 z*gkNNCYewC61Tue-1}jMS@yTk*OB)(+Fs*6-p_-~vLD{D`M2;lc+ectnP)#`B;T}#BQS|EY@tDWD+JYh0G(*!Anh>OydzEz!AEEOGcAwam?hdhEE$@9BOwtbW58X(@QLUh zQiCF)>(iIftVncBZn%j-BYJh|=7{8Q=APXz>_{AUuqb0fAYh$TpmCIZG``6!DduKx^Buo9rSEjf4 zt}-7g@}Z6HLhydx44<_4*SGvVt2cl2zjS}TeE3xH@G0|j!koKlCIoZjmUUQs?C)Eh zFNcPTp&>Ii`smD~VKXvig)Tn!_pdIN!;xY*Vjg+Z3ZFIAkN#p9jlIDAQMvs|Z&Tb; zh8bfoRt~2)^Y-Gm!SdLZ;@A~)?mctS!b>=1Ka(Na zB2Y>onq~;HLTvx}_@n^%>>S|7sU zSBr!Nno!6f#rIK2yY9R$Z3}dr3ej{yLiEwTogA;JATPqxeQ@b{n5s1IMdjW@#oj~r zuNO$E_r%Jj$Nt`}KyNuPPz(%g9JT^zySlRuy!PJ*{$s;~lx3N&hLR46^1M&(qE2L`Mv0~(2DO+rJ^DO+a1AUsL+oH3Fvg!d>Cy!v zjz%k16PJ4MKDbL;Ztgxyw)7~4B>{=!r|7exrl<|IU5 zr5x+%j<|%83W5J2ma+!zOTmVW?JgSNb>%T1p?|It=g-jyZ^cQaJhW`BHey;>Wi`1MAn6Onx`P%R$=v#cjI5HIm2hOB5Ih(?7k)!a4 hMv8s_rr$j*%l;K$*lG5OuagZwK`=c<-E7#A{THbs&D#I~ literal 0 HcmV?d00001 diff --git a/backend/script_groups/XML Parser to SCL/generators/__pycache__/generator_utils.cpython-310.pyc b/backend/script_groups/XML Parser to SCL/generators/__pycache__/generator_utils.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..83c2eb2c759c60ace4b0dbf6479ff7353fa5b974 GIT binary patch literal 6809 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%0DA07``oY5we|r?09TM=jT!JwWOKbs%zR9+-yD? zZ$6r6?n%@ge`2oQR$%5|^KG!u{@7_5E}?#Wuy|On{)xE)(m!z*4i_qaN>GrF>vfox zw2$Z%PqZXZxQ)d?>Y&RiZF0CMWVlfvq9)A2?bx&zUWzgvHWJdCNd_r8pDs$<4A@)12aRFTlq*kv$0%*D zL|wo1J*;$J$9)~Q3~yx8Z~|L27?a zXns!UeomNwPH4B4g=G1&LhGt?#ktzL(z;&#J?96`@3nr=8f!>YA4(J+zI`SI*AX{X zZmhnu^3M9LM9ChoQL3n9bz)^=_0q~E1TJzmQPgvLFr_M58@+$w-i5fTE~U}mwcWAZ zt-MnScPN8NP1C>0_kLC}N|F=g=RwLtkwsr@pOF!2%V&g^EPpE3AT67e&q#^Rq {line}") for line in udt_comment.splitlines()]; md_lines.append("") + members = data.get("interface", {}).get("None", []) + if members: + md_lines.append("## Members"); md_lines.append("") + md_lines.append("| Name | Datatype | Start Value | Comment |"); md_lines.append("|---|---|---|---|") + md_lines.extend(generate_markdown_member_rows(members)) + md_lines.append("") + else: md_lines.append("No members found in the UDT interface."); md_lines.append("") + return md_lines \ No newline at end of file diff --git a/backend/script_groups/XML Parser to SCL/generators/generate_scl_code_block.py b/backend/script_groups/XML Parser to SCL/generators/generate_scl_code_block.py new file mode 100644 index 0000000..f5c5a47 --- /dev/null +++ b/backend/script_groups/XML Parser to SCL/generators/generate_scl_code_block.py @@ -0,0 +1,285 @@ +# ToUpload/generators/generate_scl_code_block.py +# -*- coding: utf-8 -*- +import re +import os # Importar os +from .generator_utils import format_variable_name, generate_scl_declarations + +SCL_SUFFIX = "_sympy_processed" + + +# ... (_generate_scl_header sin cambios)... +def _generate_scl_header(data, scl_block_name): + scl_output = [] + block_type = data.get("block_type", "Unknown") + block_name = data.get("block_name", "UnknownBlock") + block_number = data.get("block_number") + block_comment = data.get("block_comment", "") + scl_block_keyword = "FUNCTION_BLOCK" + if block_type == "FC": + scl_block_keyword = "FUNCTION" + elif block_type == "OB": + scl_block_keyword = "ORGANIZATION_BLOCK" + scl_output.append(f"// Block Type: {block_type}") + if block_name != scl_block_name: + scl_output.append(f"// Block Name (Original): {block_name}") + if block_number: + scl_output.append(f"// Block Number: {block_number}") + original_net_langs = set( + n.get("language", "Unknown") for n in data.get("networks", []) + ) + scl_output.append( + f"// Original Network Languages: {', '.join(l for l in original_net_langs if l != 'Unknown')}" + ) + if block_comment: + scl_output.append(f"// Block Comment:") + [scl_output.append(f"// {line}") for line in block_comment.splitlines()] + scl_output.append("") + if block_type == "FC": + return_type = "Void" + interface_data = data.get("interface", {}) + if interface_data.get("Return"): + return_member = interface_data["Return"][0] + return_type_raw = return_member.get("datatype", "Void") + return_type = ( + return_type_raw[1:-1] + if isinstance(return_type_raw, str) + and return_type_raw.startswith('"') + and return_type_raw.endswith('"') + else return_type_raw + ) + if return_type != return_type_raw and not ( + isinstance(return_type_raw, str) + and return_type_raw.lower().startswith("array") + ): + return_type = f'"{return_type}"' + else: + return_type = return_type_raw + scl_output.append(f'{scl_block_keyword} "{scl_block_name}" : {return_type}') + else: + scl_output.append(f'{scl_block_keyword} "{scl_block_name}"') + scl_output.append("{ S7_Optimized_Access := 'TRUE' }") + scl_output.append("VERSION : 0.1") + scl_output.append("") + return scl_output + + +# Modificar _generate_scl_interface para pasar project_root_dir +def _generate_scl_interface(interface_data, project_root_dir): # <-- Nuevo argumento + """Genera las secciones VAR_* de la interfaz SCL para FC/FB/OB.""" + scl_output = [] + section_order = [ + "Input", + "Output", + "InOut", + "Static", + "Temp", + "Constant", + "Return", + ] # Incluir Return + declared_temps = set() # Para _generate_scl_temp_vars + + for section_name in section_order: + vars_in_section = interface_data.get(section_name, []) + if vars_in_section: + scl_section_keyword = f"VAR_{section_name.upper()}" + end_keyword = "END_VAR" + if section_name == "Static": + scl_section_keyword = "VAR_STAT" + if section_name == "Temp": + scl_section_keyword = "VAR_TEMP" + if section_name == "Constant": + scl_section_keyword = "CONSTANT" + end_keyword = "END_CONSTANT" + if section_name == "Return": + scl_section_keyword = "VAR_OUTPUT" + # Retorno va en Output para FB/OB, implícito en FC + + # Para FC, la sección Return no se declara explícitamente aquí + if ( + interface_data.get("parent_block_type") == "FC" + and section_name == "Return" + ): + continue + + scl_output.append(scl_section_keyword) + # Pasar project_root_dir a generate_scl_declarations + scl_output.extend( + generate_scl_declarations( + vars_in_section, indent_level=1, project_root_dir=project_root_dir + ) + ) # <-- Pasar ruta raíz + scl_output.append(end_keyword) + scl_output.append("") + + if section_name == "Temp": + declared_temps.update( + format_variable_name(v.get("name")) + for v in vars_in_section + if v.get("name") + ) + return scl_output, declared_temps + + +# ... (_generate_scl_temp_vars y _generate_scl_body sin cambios) ... +def _generate_scl_temp_vars(data, declared_temps): + scl_output = [] + temp_vars_detected = set() + temp_pattern = re.compile(r'"?(#\w+)"?') + for network in data.get("networks", []): + for instruction in network.get("logic", []): + scl_code = instruction.get("scl", "") + edge_update_code = instruction.get("_edge_mem_update_scl", "") + code_to_scan = ( + (scl_code if scl_code else "") + + "\n" + + (edge_update_code if edge_update_code else "") + ) + if code_to_scan: + found_temps = temp_pattern.findall(code_to_scan) + [temp_vars_detected.add(t) for t in found_temps if t] + additional_temps = sorted(list(temp_vars_detected - declared_temps)) + if additional_temps: + print(f"INFO: Detectadas {len(additional_temps)} VAR_TEMP adicionales.") + temp_section_exists = any( + "VAR_TEMP" in s for s in data.get("generated_scl", []) + ) # Check if VAR_TEMP already exists + if not temp_section_exists and not declared_temps: + scl_output.append("VAR_TEMP") # Only add if no temps were declared before + for temp_name in additional_temps: + scl_name = format_variable_name(temp_name) + inferred_type = "Bool" + scl_output.append( + f" {scl_name} : {inferred_type}; // Auto-generated temporary" + ) + if not temp_section_exists and not declared_temps: + scl_output.append("END_VAR") + scl_output.append("") + return scl_output + + +def _generate_scl_body(networks): + scl_output = ["BEGIN", ""] + network_logic_added = False + for i, network in enumerate(networks): + network_title = network.get("title", f'Network {network.get("id", i+1)}') + network_comment = network.get("comment", "") + network_lang = network.get("language", "LAD") + scl_output.append( + f" // Network {i+1}: {network_title} (Original Language: {network_lang})" + ) + if network_comment: + [ + scl_output.append(f" // {line}") + for line in network_comment.splitlines() + ] + scl_output.append("") + network_has_code = False + logic_in_network = network.get("logic", []) + if not logic_in_network: + scl_output.append(f" // Network {i+1} has no logic elements.") + scl_output.append("") + continue + if network_lang == "STL": + if logic_in_network and logic_in_network[0].get("type") == "RAW_STL_CHUNK": + network_has_code = True + raw_stl_code = logic_in_network[0].get( + "stl", "// ERROR: STL code missing" + ) + scl_output.append(f" // --- BEGIN STL Network {i+1} ---") + scl_output.append(f" ```stl ") + [ + scl_output.append(f" {stl_line}") # scl_output.append(f" // {stl_line}") + for stl_line in raw_stl_code.splitlines() + ] + scl_output.append(f" ``` ") + scl_output.append(f" // --- END STL Network {i+1} ---") + scl_output.append("") + else: + scl_output.append( + f" // ERROR: Contenido STL inesperado en Network {i+1}." + ) + scl_output.append("") + else: + for instruction in logic_in_network: + instruction_type = instruction.get("type", "") + scl_code = instruction.get("scl", "") + is_grouped = instruction.get("grouped", False) + edge_update_scl = instruction.get("_edge_mem_update_scl", "") + if is_grouped: + continue + code_to_print = [] + if scl_code: + code_to_print.extend(scl_code.splitlines()) + if edge_update_scl: + code_to_print.extend( + edge_update_scl.splitlines() + ) # Append edge update SCL + if code_to_print: + is_only_comment = all( + line.strip().startswith("//") + for line in code_to_print + if line.strip() + ) + is_if_block = any( + line.strip().startswith("IF") for line in code_to_print + ) + if ( + not is_only_comment + or is_if_block + or "_error" in instruction_type + or instruction_type + in [ + "UNSUPPORTED_LANG", + "UNSUPPORTED_CONTENT", + "PARSING_ERROR", + "RAW_SCL_CHUNK", + ] + ): # Print RAW_SCL chunks too + network_has_code = True + [scl_output.append(f" {line}") for line in code_to_print] + scl_output.append("") + if not network_has_code and network_lang != "STL": + scl_output.append(f" // Network {i+1} did not produce printable SCL code.") + scl_output.append("") + if network_has_code: + network_logic_added = True # Mark if any network had code + # Add a default comment if no logic was generated at all + if not network_logic_added: + scl_output.append(" // No executable logic generated by script.") + scl_output.append("") + return scl_output + + +# Modificar generate_scl_for_code_block para aceptar y pasar project_root_dir +def generate_scl_for_code_block(data, project_root_dir): # <-- Nuevo argumento + """Genera el contenido SCL completo para un FC/FB/OB.""" + scl_output = [] + block_type = data.get("block_type", "Unknown") + scl_block_name = format_variable_name(data.get("block_name", "UnknownBlock")) + scl_block_keyword = "FUNCTION_BLOCK" # Default for FB + if block_type == "FC": + scl_block_keyword = "FUNCTION" + elif block_type == "OB": + scl_block_keyword = "ORGANIZATION_BLOCK" + + scl_output.extend(_generate_scl_header(data, scl_block_name)) + + interface_data = data.get("interface", {}) + interface_data["parent_block_type"] = block_type # Ayuda a _generate_scl_interface + # Pasar project_root_dir a _generate_scl_interface + interface_lines, declared_temps = _generate_scl_interface( + interface_data, project_root_dir + ) # <-- Pasar ruta raíz + scl_output.extend(interface_lines) + + # Generar VAR_TEMP adicionales (no necesita project_root_dir) + scl_output.extend(_generate_scl_temp_vars(data, declared_temps)) + + # Generar cuerpo (no necesita project_root_dir) + scl_output.extend(_generate_scl_body(data.get("networks", []))) + scl_output.append(f"END_{scl_block_keyword}") + + # Guardar SCL generado en data para _generate_scl_temp_vars + data["generated_scl"] = scl_output + + return scl_output diff --git a/backend/script_groups/XML Parser to SCL/generators/generate_scl_db.py b/backend/script_groups/XML Parser to SCL/generators/generate_scl_db.py new file mode 100644 index 0000000..595f64a --- /dev/null +++ b/backend/script_groups/XML Parser to SCL/generators/generate_scl_db.py @@ -0,0 +1,54 @@ +# ToUpload/generators/generate_scl_db.py +# -*- coding: utf-8 -*- +# No necesita importar json/os aquí, lo hará generate_scl_declarations +from .generator_utils import format_variable_name, generate_scl_declarations + +# Modificar _generate_scl_header si es necesario, pero parece ok +def _generate_scl_header(data, scl_block_name): + # ... (código sin cambios) ... + scl_output = [] + block_type = data.get("block_type", "Unknown") + block_name = data.get("block_name", "UnknownBlock") + block_number = data.get("block_number") + block_comment = data.get("block_comment", "") + scl_output.append(f"// Block Type: {block_type}") + if block_name != scl_block_name: scl_output.append(f"// Block Name (Original): {block_name}") + if block_number: scl_output.append(f"// Block Number: {block_number}") + if block_comment: scl_output.append(f"// Block Comment:"); [scl_output.append(f"// {line}") for line in block_comment.splitlines()] + scl_output.append(""); scl_output.append(f'DATA_BLOCK "{scl_block_name}"'); scl_output.append("{ S7_Optimized_Access := 'TRUE' }") + scl_output.append("VERSION : 0.1"); scl_output.append("") + return scl_output + +# Modificar _generate_scl_interface para pasar project_root_dir +def _generate_scl_interface(interface_data, project_root_dir): # <-- Nuevo argumento + """Genera la sección VAR para DB (basada en 'Static').""" + scl_output = [] + static_vars = interface_data.get("Static", []) + if static_vars: + scl_output.append("VAR") + # Pasar project_root_dir a generate_scl_declarations + scl_output.extend(generate_scl_declarations(static_vars, indent_level=1, project_root_dir=project_root_dir)) # <-- Pasar ruta raíz + scl_output.append("END_VAR") + else: + print("Advertencia: No se encontró sección 'Static' o está vacía en la interfaz del DB.") + scl_output.append("VAR\nEND_VAR") # Añadir vacío + scl_output.append("") + return scl_output + +# Modificar generate_scl_for_db para aceptar y pasar project_root_dir +def generate_scl_for_db(data, project_root_dir): # <-- Nuevo argumento + """Genera el contenido SCL completo para un DATA_BLOCK.""" + scl_output = [] + scl_block_name = format_variable_name(data.get("block_name", "UnknownDB")) + + scl_output.extend(_generate_scl_header(data, scl_block_name)) + + interface_data = data.get("interface", {}) + # Pasar project_root_dir a _generate_scl_interface + scl_output.extend(_generate_scl_interface(interface_data, project_root_dir)) # <-- Pasar ruta raíz + + scl_output.append("BEGIN") + scl_output.append(" // Data Blocks have no executable code") + scl_output.append("END_DATA_BLOCK") + + return scl_output \ No newline at end of file diff --git a/backend/script_groups/XML Parser to SCL/generators/generator_utils.py b/backend/script_groups/XML Parser to SCL/generators/generator_utils.py new file mode 100644 index 0000000..5644a58 --- /dev/null +++ b/backend/script_groups/XML Parser to SCL/generators/generator_utils.py @@ -0,0 +1,278 @@ +# ToUpload/generators/generator_utils.py +# -*- coding: utf-8 -*- +import re +import os +import json +import traceback # Para depuración si es necesario +import sys + +# --- Importar format_variable_name desde processors --- +try: + # Asumiendo que este script está en 'generators' y 'processors' está al mismo nivel + current_dir = os.path.dirname(os.path.abspath(__file__)) + project_base_dir = os.path.dirname(current_dir) + processors_dir = os.path.join(project_base_dir, 'processors') + if processors_dir not in sys.path: + sys.path.insert(0, processors_dir) # Añadir al path si no está + from processor_utils import format_variable_name +except ImportError: + print("Advertencia: No se pudo importar 'format_variable_name' desde processors.processor_utils.") + print("Usando una implementación local básica.") + def format_variable_name(name): # Fallback + if not name: return "_INVALID_NAME_" + if name.startswith('"') and name.endswith('"'): return name + prefix = "#" if name.startswith("#") else "" + if prefix: name = name[1:] + if name and name[0].isdigit(): name = "_" + name + name = re.sub(r"[^a-zA-Z0-9_]", "_", name) + return prefix + name +# --- Fin Fallback --- + +# --- format_scl_start_value (Sin cambios respecto a la versión anterior) --- +def format_scl_start_value(value, datatype): + if value is None: return None + # Convertir complex dict a string para procesar + if isinstance(value, dict): + # Si tiene 'value', usar ese. Si no, representar el dict como comentario + value_to_process = value.get('value') + if value_to_process is None: + return f"/* Init: {json.dumps(value)} */" # Representar dict como comentario + value = value_to_process # Usar el valor interno + + datatype_lower = datatype.lower() if isinstance(datatype, str) else "" + value_str = str(value) + + # Determinar si es tipo complejo (no estrictamente básico) + is_complex_type = ( + ('"' in datatype_lower) or ('array' in datatype_lower) or ('struct' in datatype_lower) or + datatype_lower not in { + "bool", "int", "dint", "sint", "usint", "uint", "udint", "lint", "ulint", + "byte", "word", "dword", "lword", "real", "lreal", "time", "ltime", + "s5time", "date", "dt", "dtl", "tod", "string", "char", "wstring", "wchar", "variant", + "timer", "counter", "iec_timer", "iec_counter", "iec_sfc", "iec_ld_timer" # Añadir otros tipos IEC comunes + } + ) + + if is_complex_type: + # Para tipos complejos, solo permitir constantes simbólicas o inicializadores básicos (0, FALSE, '') + if re.match(r'^[a-zA-Z_][a-zA-Z0-9_]*$', value_str): return value_str # Constante simbólica + if value_str == '0': return '0' # Cero numérico + if value_str.lower() == 'false': return 'FALSE' # Booleano Falso + if value_str == "''" or value_str == "": return "''" # String vacío + # Ignorar otros valores iniciales para tipos complejos (incluye JSON de arrays) + # print(f"INFO: Start value '{value_str}' for complex type '{datatype}' skipped.") + return None + + # Quitar comillas simples/dobles externas si las hay + value_str_unquoted = value_str + if len(value_str) > 1: + if value_str.startswith('"') and value_str.endswith('"'): value_str_unquoted = value_str[1:-1] + elif value_str.startswith("'") and value_str.endswith("'"): value_str_unquoted = value_str[1:-1] + + # Formateo por tipo básico + if any(t in datatype_lower for t in ["int","byte","word","dint","dword","lint","lword","sint","usint","uint","udint","ulint"]): + try: return str(int(value_str_unquoted)) + except ValueError: return value_str_unquoted if re.match(r'^[a-zA-Z_][a-zA-Z0-9_]*$', value_str_unquoted) else None # Permitir constante simbólica + elif "bool" in datatype_lower: + val_low = value_str_unquoted.lower(); + if val_low in ['true', '1']: return "TRUE" + elif val_low in ['false', '0']: return "FALSE" + else: return value_str_unquoted if re.match(r'^[a-zA-Z_][a-zA-Z0-9_]*$', value_str_unquoted) else "FALSE" # Default FALSE + elif "string" in datatype_lower or "char" in datatype_lower: + escaped_value = value_str_unquoted.replace("'", "''") # Escapar comillas simples + prefix = "WSTRING#" if "wstring" in datatype_lower else ("WCHAR#" if "wchar" in datatype_lower else "") + return f"{prefix}'{escaped_value}'" # Usar comillas simples SCL + elif "real" in datatype_lower or "lreal" in datatype_lower: + try: + f_val = float(value_str_unquoted) + s_val = "{:.7g}".format(f_val) # Notación científica si es necesario, precisión limitada + return s_val + (".0" if "." not in s_val and "e" not in s_val.lower() else "") # Añadir .0 si es entero + except ValueError: return value_str_unquoted if re.match(r'^[a-zA-Z_][a-zA-Z0-9_]*$', value_str_unquoted) else None # Permitir constante simbólica + elif "time" in datatype_lower: # Incluye TIME, LTIME, S5TIME + prefix, val_to_use = "", value_str_unquoted + # Extraer prefijo si ya existe (T#, LT#, S5T#) + match_prefix = re.match(r"^(T#|LT#|S5T#)(.*)", val_to_use, re.IGNORECASE) + if match_prefix: prefix, val_to_use = match_prefix.groups() + # Validar formato del valor de tiempo (simplificado) + if re.match(r'^-?(\d+d_)?(\d+h_)?(\d+m_)?(\d+s_)?(\d+ms)?$', val_to_use, re.IGNORECASE): + target_prefix = "S5T#" if "s5time" in datatype_lower else ("LT#" if "ltime" in datatype_lower else "T#") + return f"{target_prefix}{val_to_use}" + elif re.match(r'^[a-zA-Z_][a-zA-Z0-9_]*$', value_str_unquoted): return value_str_unquoted # Constante simbólica + else: return None # Formato inválido + elif any(t in datatype_lower for t in ["date", "dtl", "dt", "tod", "time_of_day"]): + val_to_use = value_str_unquoted; prefix = "" + # Extraer prefijo si ya existe (DTL#, D#, DT#, TOD#) + match_prefix = re.match(r"^(DTL#|D#|DT#|TOD#)(.*)", val_to_use, re.IGNORECASE) + if match_prefix: prefix, val_to_use = match_prefix.groups() + # Determinar prefijo SCL correcto + target_prefix="DTL#" if "dtl" in datatype_lower or "date_and_time" in datatype_lower else ("DT#" if "dt" in datatype_lower else ("TOD#" if "tod" in datatype_lower or "time_of_day" in datatype_lower else "D#")) + # Validar formato (simplificado) + if re.match(r'^\d{4}-\d{2}-\d{2}(-\d{2}:\d{2}:\d{2}(\.\d+)?)?$', val_to_use) or re.match(r'^\d{2}:\d{2}:\d{2}(\.\d+)?$', val_to_use): + return f"{target_prefix}{val_to_use}" + elif re.match(r'^[a-zA-Z_][a-zA-Z0-9_]*$', value_str_unquoted): return value_str_unquoted # Constante simbólica + else: return None # Formato inválido + else: # Otros tipos o desconocidos + return value_str if re.match(r'^[a-zA-Z_][a-zA-Z0-9_]*$', value_str) else None # Solo permitir constantes simbólicas + + +# <-- MODIFICADO: generate_scl_declarations --> +def generate_scl_declarations(variables, indent_level=1, project_root_dir=None): + """ + Genera líneas SCL para declarar variables, manejando UDTs, FBs (InstanceOfName), + Arrays y Structs. + """ + scl_lines = [] + indent = " " * indent_level + # Lista de tipos básicos simples (en minúsculas) - ampliada + basic_types = { + "bool", "int", "dint", "sint", "usint", "uint", "udint", "lint", "ulint", + "byte", "word", "dword", "lword", "real", "lreal", "time", "ltime", + "s5time", "date", "dt", "dtl", "tod", "time_of_day", # TOD sinónimos + "char", "wchar", "variant", + # Tipos IEC comunes + "timer", "counter", "iec_timer", "iec_counter", "iec_sfc", "iec_ld_timer" + } + + # Patrones para tipos básicos parametrizados (ignorando mayúsculas/minúsculas) + string_pattern = re.compile(r"^(W?STRING)(\[\s*\d+\s*\])?$", re.IGNORECASE) + array_pattern = re.compile(r'^(Array\[.*\]\s+of\s+)(.*)', re.IGNORECASE) + + for var in variables: + var_name_scl = format_variable_name(var.get("name")) + var_dtype_raw = var.get("datatype", "VARIANT") + # <-- NUEVO: Obtener instance_of_name --> + instance_of_name = var.get("instance_of_name") # Puede ser None + # <-- FIN NUEVO --> + var_comment = var.get("comment") + start_value_raw = var.get("start_value") + children = var.get("children") # Para STRUCT anidados + array_elements = var.get("array_elements") # Para inicialización de ARRAY + + declaration_dtype = var_dtype_raw # Tipo a usar en la declaración SCL + base_type_for_init = var_dtype_raw # Tipo base para formatear valor inicial + is_array = False + is_struct_inline = bool(children) # Es un STRUCT definido inline + is_potential_udt_or_fb = False # Flag para comprobar si buscar archivo .json + type_to_check = None # Nombre limpio del tipo a buscar (UDT o FB) + + # --- Lógica Principal de Determinación de Tipo --- + if is_struct_inline: + # Si tiene hijos, se declara como STRUCT ... END_STRUCT + declaration_dtype = "STRUCT" + base_type_for_init = "STRUCT" # Valor inicial no aplica a STRUCT directamente + elif isinstance(var_dtype_raw, str): + # 1. Comprobar si es FB Instance usando InstanceOfName + if instance_of_name: + # Si InstanceOfName existe, usarlo como tipo (entre comillas) + declaration_dtype = f'"{instance_of_name}"' + base_type_for_init = instance_of_name # Usar nombre limpio para init/check + is_potential_udt_or_fb = True # Marcar para buscar archivo FB + type_to_check = instance_of_name + else: + # 2. No es FB Instance directo, comprobar si es Array + array_match = array_pattern.match(var_dtype_raw) + if array_match: + is_array = True + array_prefix_for_decl = array_match.group(1) + base_type_raw = array_match.group(2).strip() + base_type_for_init = base_type_raw # Tipo base para init/check + + # Limpiar tipo base para comprobar si es básico/UDT/String + base_type_clean = base_type_raw[1:-1] if base_type_raw.startswith('"') and base_type_raw.endswith('"') else base_type_raw + base_type_lower = base_type_clean.lower() + + # ¿El tipo base es UDT/FB conocido o un tipo básico/paramétrico? + if (base_type_lower not in basic_types and + not string_pattern.match(base_type_clean)): + # Asumir UDT/FB si no es básico ni String[N]/Char + declaration_dtype = f'{array_prefix_for_decl}"{base_type_clean}"' # Poner comillas + is_potential_udt_or_fb = True # Marcar para buscar archivo UDT/FB + type_to_check = base_type_clean + else: + # Es básico o String[N]/Char + declaration_dtype = f'{array_prefix_for_decl}{base_type_raw}' # Usar como viene (puede tener comillas si era así) + else: + # 3. No es FB ni Array, ¿es UDT, String, Char o Básico? + base_type_clean = var_dtype_raw[1:-1] if var_dtype_raw.startswith('"') and var_dtype_raw.endswith('"') else var_dtype_raw + base_type_lower = base_type_clean.lower() + base_type_for_init = base_type_clean # Tipo base para init/check + + if (base_type_lower not in basic_types and + not string_pattern.match(base_type_clean)): + # Asumir UDT/FB si no es básico ni String[N]/Char + declaration_dtype = f'"{base_type_clean}"' # Poner comillas + is_potential_udt_or_fb = True # Marcar para buscar archivo UDT/FB + type_to_check = base_type_clean + else: + # Es básico o String[N]/Char + declaration_dtype = var_dtype_raw # Usar como viene + + # --- Búsqueda Opcional de Archivo de Definición (UDT o FB) --- + if is_potential_udt_or_fb and type_to_check and project_root_dir: + # Buscar tanto en 'PLC data types' como en 'Program blocks' + found_path = None + type_scl_name = format_variable_name(type_to_check) + possible_paths = [ + os.path.join(project_root_dir, 'PLC data types', 'parsing', f'{type_scl_name}_processed.json'), + os.path.join(project_root_dir, 'Program blocks', 'parsing', f'{type_scl_name}_processed.json') + # Añadir más rutas si la estructura del proyecto varía + ] + for path in possible_paths: + if os.path.exists(path): + found_path = path + break + + if found_path: + print(f" INFO: Definición '{type_to_check}' localizada en: '{os.path.relpath(found_path, project_root_dir)}'") + else: + print(f" WARNING: No se encontró definición para '{type_to_check}'. Se buscó en directorios estándar.") + + # --- Construir Línea de Declaración SCL --- + declaration_line = f"{indent}{var_name_scl} : {declaration_dtype}" + init_value_scl_part = "" + + if is_struct_inline: + # Generar STRUCT anidado + scl_lines.append(declaration_line) # Añade "VarName : STRUCT" + # Llamada recursiva para los hijos + scl_lines.extend(generate_scl_declarations(children, indent_level + 1, project_root_dir)) + scl_lines.append(f"{indent}END_STRUCT;") + # Añadir comentario al END_STRUCT si existe + if var_comment: scl_lines[-1] += f" // {var_comment}" + scl_lines.append("") # Línea en blanco después del struct + continue # Pasar a la siguiente variable del nivel actual + + # --- Manejo de Valor Inicial (para no-STRUCTs) --- + init_value_scl = None + if is_array and array_elements: + # Inicialización de Array + init_values = [] + try: # Intentar ordenar índices numéricamente + indices_numeric = {int(k): v for k, v in array_elements.items()} + sorted_indices_str = [str(k) for k in sorted(indices_numeric.keys())] + except ValueError: # Ordenar como strings si no son numéricos + print(f"Advertencia: Índices array no numéricos para '{var_name_scl}', ordenando como strings.") + sorted_indices_str = sorted(array_elements.keys()) + + for idx_str in sorted_indices_str: + val_info = array_elements[idx_str] # val_info puede ser dict o valor directo + # Formatear valor usando el tipo base del array + formatted_val = format_scl_start_value(val_info, base_type_for_init) + # Usar 'NULL' o comentario si el formateo falla o es complejo + init_values.append(formatted_val if formatted_val is not None else f"/* Array[{idx_str}] unsupported init */") + + if init_values: init_value_scl = f"[{', '.join(init_values)}]" + elif not is_array and not is_struct_inline and start_value_raw is not None: + # Inicialización de variable simple + init_value_scl = format_scl_start_value(start_value_raw, base_type_for_init) + + # Añadir parte del valor inicial si existe + if init_value_scl is not None: + init_value_scl_part = f" := {init_value_scl}" + + # Combinar todo para la línea final + declaration_line += f"{init_value_scl_part};" + if var_comment: declaration_line += f" // {var_comment}" + scl_lines.append(declaration_line) + + return scl_lines \ No newline at end of file diff --git a/backend/script_groups/XML Parser to SCL/parsers/__init__.py b/backend/script_groups/XML Parser to SCL/parsers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/script_groups/XML Parser to SCL/parsers/__pycache__/__init__.cpython-310.pyc b/backend/script_groups/XML Parser to SCL/parsers/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..245171fdd8d15837b8e5565386a7f40aa2c05164 GIT binary patch literal 163 zcmd1j<>g`kf{8C#GC=fW5P=LBfgA@QE@lA|DGb33nv8xc8Hzx{2;!Gpid9TNQGR7= za!G!1OmK2hWfs%>&W7i6xoI3K70O3IT~l#i>Ox6^8M-`6;D2sl_qz@tJv< YCGqik1(mlrY#^d`AoGivfCLKz0B7qb+yDRo literal 0 HcmV?d00001 diff --git a/backend/script_groups/XML Parser to SCL/parsers/__pycache__/__init__.cpython-312.pyc b/backend/script_groups/XML Parser to SCL/parsers/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..79a9abc209bb79cd968f96c43848f6bb09d87cdc GIT binary patch literal 164 zcmX@j%ge<81QTDfWPs?$AOanHW&w&!XQ*V*Wb|9fP{ah}eFmxd<(y&_6Ht_2nVMXZ zUmO#hT$EW*0;Drjb5rv`bZ%lvX0k$rua81NVo`BwQA`1tDvpVd&&F(O_~5S~L$GC!G4EM_ZH{vLr67ArcGY;{pdT>6R#Kf;FA>0wr7YLRP}}qCg${1+ zGWiwY#!<@4aE4m4)QF>wYYE>9LLORu=>;9H@A?)8(Uu=RkA*eAx_r%AZCta~psh4) zO9c4Cqx<)qpCD_Qbq>b8h2%rvZ}P$XQ*UvqEY8?{ee4%Xj^7%k@{@ z4_a%?J(cMC_-E+uND2Eb%i}l7>x2tdGqfTB=61qB$>ZPAYT=8X2vlfE_xMe6?wE_C zmM>kiM(2(5^Pz1^RyYbq`JzC+Lnu1AUjz^ueOz zIM#gc_-LThwo93@*9Rjr1H-N|UAf(CtSeM!+w-{;L8klARYVYjEv^!_kue#Ds#S%| z=P0{HE@5GKqcYu%NR zkehp7w0j|seGzRIJM?q8)8Ee~pLqdq_gpV%=SyYSAi4q_(=^K7GGnN1j^P?s^0B~GCp$!m&rctm$}tW>V;YI26_8wAD-#)@W!wmIg=5REMUjzJFBP%})c7yOmU^9t6$c%5BP_Gi*m{sx$#rn0i zY!F+Z1JRl&q5xL4aW#)>(M{oh6Ob!KG}>yvFEAPrE|?ml6A*&pg)m$KVF%qle2|b$ zXn7c_kgyz_4Nd3lS9YL7P&5ciEk)NObs9jOEM=0XjF)D~fsq;@ErYa_mgLp6gwoga zhy*&2pgBvhUnDuI0;qB_k(T8RrKM#=9?}5zL%Lif-;4Jp#SrbyRQ1zitNio;nDk)LK7^i|S|JWRE; zQrH8l7ho06YtJN$clMNY1rTRsxk`FlG1Si)H;c&H$7Jb*$YiecFvEsy?Z_GMYcnG@ z%NPbND?#~g37MI`8+2p0E3z{DiN7Y3PW`qjHW2rqm~$pgYEB(P zS2L6%w;x;TG~oOehh<0|6crZU{_G z+mOhYnE~hY`k9WDSN+cQW07AQ5-)7KDlZ~tPz0FOt;?9@y^-D8=$Q7iIOt?mcj&&T zHFG-7iLsqmPz8krQC2V-h17(Q4AwCy#c+BMm3)@}^6z@PnA72);!byq@QR7hy_&93 zd`o|uB}S_{0}`wP8CHQJkrKzL_O=QnIYG_0Q#uf4j+xS!CO?DUo5=6}UeC`NBInM$ fa`VLzTaepjP5|a&LDx%oS8xH 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 Q56RB>bVmbWaQp}V1)Pem8~^|S literal 0 HcmV?d00001 diff --git a/backend/script_groups/XML Parser to SCL/parsers/__pycache__/network_parser.cpython-310.pyc b/backend/script_groups/XML Parser to SCL/parsers/__pycache__/network_parser.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a914f3e2f80db608143a3ddeebb063a5bc8cdcb5 GIT binary patch literal 2749 zcma)8&2QX96!+(@*V&JJHEq*Cr=^f?X?I&Lh^R$PlhRhCX_QS=WLg<_XR>wUwO8ZW zl324B!Vx6yv=TjXM&gXbl|KMk2nit}l>;2O0TR3!d$&n@sV$Gk^S*xX&3n%iRVuau z*Yxkk{g0*<%w4uO~Jbe&k{WG58xG7z5;Kar~{qr zafPW^+Y?^tEkV(+0ThE9be3z}z~)h9PYn%R;QE)!V{Kqco+9uRc!8b;o#`qY$&d216{zMs+GU@{jm$`~7pKF6MFM~{3a13m~ zR~5E#jh6s{A+U0to4m+N9R-g+G6xl2!V?b_`W?5i-dE^nATudtri2Wher!q)5Ah0~ zxv0Q+7|yjtYqba@p!o7Oc%mYsa$n z5lYa>s}SqM9p#B8tP0z(R>E`J8vQRv`xAa1*DG19@vHbaMvwF%K5j#dPUJDF;gf@L zUZa1q0E+Bm%wBl`!Koa<>ww^m=Mc>22qy69 z!6csm`SYyECo&9s8mtZDJJP}@_iKT8)#bjNkx_dy-<`8^e?^@3$NF53q=B1K=KNzF zUwDS7{#Fv&2(C3zOCIWnhy=0@BGkIwxDrI|?YOZNb$fn5HbbACMVK(sW*+dNfP|gC z_kc(ZyC?{}u7|t;$-<@F2xd{p z==a~CedbW?hv>#~1GT(>c_EG(tI4@Wvw5>0FhB5x`CxMM)O z$y}qkMxze(x?MoD;t5n8(qw?^bUm4BG@(T;#TxteU$8XnlS^|e1{k<#8j(Kf; zaqW6Cc9qhIE=aYBhE69(>oTrk1hx*~Y9zAs|odh5pO zHTUZJ`mOc4mKtogM^eKNx1!{T$S7$vONEhBiMD_oy|uLB7%;d_Wqt9sD`rdAH&@?J zjyIc`*up_rLj-j_t@(LphkbVYKBg1WTWIql&@o$R$-dvG1dF^#&VWiVfM8C&w#W{& z81N8Q`Ee>P3`!ur>2Zc^=9FfiEH*QniuHY=&{aCm3LDxb+ZIV{^6TI^!^IuC3i# z-?+N$t}L!zOG?9RL`hZpI+EV+6P*O_>Q<_E2usZ#^+R~=^gMPyHQ_(%_tJvb>yZ#s zLxjN;LqUj4rR6XyELXIRR14#D7L>T%ef8;zLU6bGVcW5X+&*?HGLxkol$TQ(lH{^e z%M*M=uMO!r!Kr$~N_53P+nMe?t3h`d8fR)K7R$nOMM9?~L6*}O=u*{`Y+!hJrf{*x zJjaGAcA=kvXU=qXx)52Gc_-956Z=jUK!BWdrbg!q2{N(}(o&IPv{;eJ5kJ3~ja=G*A)rjv5&Lcm1# zcKgu2EwB=Q0)uTDs-+sLZOp2+J`HaJz6`YrPg$MR1a(@|3{B1M!atT}sWW0#HO`cO zw1Ddf+{UT#pN*5&FBVYdRAa9Co6s_@!TgZ@hn=m~s(%@3L9L2aYv$jodP+4kdIDgq z)=Q}o>~sSvj*D50GY4dIJ literal 0 HcmV?d00001 diff --git a/backend/script_groups/XML Parser to SCL/parsers/__pycache__/parse_lad_fbd.cpython-310.pyc b/backend/script_groups/XML Parser to SCL/parsers/__pycache__/parse_lad_fbd.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a21cabb2510af5ba0ea0b0c7f2b087c0ad930d3b GIT binary patch literal 8187 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 literal 0 HcmV?d00001 diff --git a/backend/script_groups/XML Parser to SCL/parsers/__pycache__/parse_lad_fbd.cpython-312.pyc b/backend/script_groups/XML Parser to SCL/parsers/__pycache__/parse_lad_fbd.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6c7f5452227429bef48c714b54c8ae195bc9eed5 GIT binary patch literal 13929 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 literal 0 HcmV?d00001 diff --git a/backend/script_groups/XML Parser to SCL/parsers/__pycache__/parse_scl.cpython-312.pyc b/backend/script_groups/XML Parser to SCL/parsers/__pycache__/parse_scl.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1895929614c44d3fd0426ee02bb348bdcd4f545c GIT binary patch literal 9888 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 UQKAiB&Z@0w{Z}KX3eC##zgFZ;!~g&Q literal 0 HcmV?d00001 diff --git a/backend/script_groups/XML Parser to SCL/parsers/__pycache__/parse_stl.cpython-310.pyc b/backend/script_groups/XML Parser to SCL/parsers/__pycache__/parse_stl.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3f07d4685ddecad7405ec0dcf44de7c809489261 GIT binary patch literal 8976 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 HIY$3Kjw>#9 literal 0 HcmV?d00001 diff --git a/backend/script_groups/XML Parser to SCL/parsers/__pycache__/parser_utils.cpython-310.pyc b/backend/script_groups/XML Parser to SCL/parsers/__pycache__/parser_utils.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0f1fdf0d37e8b1dbaad768887ef67565315858be GIT binary patch literal 9570 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 J#uLS*{{=rce{KK( literal 0 HcmV?d00001 diff --git a/backend/script_groups/XML Parser to SCL/parsers/__pycache__/parser_utils.cpython-312.pyc b/backend/script_groups/XML Parser to SCL/parsers/__pycache__/parser_utils.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cb34e068ad80a3e4109910794c8347c701355839 GIT binary patch literal 15849 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 literal 0 HcmV?d00001 diff --git a/backend/script_groups/XML Parser to SCL/parsers/__pycache__/scl_parser.cpython-310.pyc b/backend/script_groups/XML Parser to SCL/parsers/__pycache__/scl_parser.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..305f2eefd661a6e3021d1ae29a961eddf460104b GIT binary patch literal 3014 zcmaJ@O>Eo973K^{Nv37lvgO}64sEA(-$EN%|X~eDlIExdV4F0S_V(* z)mMN@MHH(x^=-Q*^J#L;!G8vBE(<OsXGpe#f_r>5$+C1oN>-+ccC7f7OF7Xdq#l+c1HgI&ERPbFzK+C4tMCM# zT+jO8F+NBBUxf9c4vI1)&oZA$WcZ~V^+6008A;;P#H^6a`k4mnFw@BBB+tTFBF{oz z2B^le&rwO*ukGO|7Y(vOh<5&h!~E0iS2`KaKSC3EcoHrheJG~Z=9`7KFIS`@wR0WGMI;?furZLn$Hu;)lgtvGZ%31CLS$k= z?9`9hWP7k9fhRvt}O5$nVIl9x|OE?+WA( zXdg@U$3TDxK{92=&c_L{eQiXm zy`SuIUdYzC>}ArOV&9>fqG_n=t7J5qAwP<)vFUc6cM#O~?MP=j->GPp&7R|6?-(qjm;D!Hajl*7<4mao$CfGY?j;wf5iwGHUz^O zUwvDOW;ip+K^X6u!WO`X^QvGvsoNNTj@+oWor(zTm< zE3jPR>8{nVgQiup1N}@tXt^~VVB2@CCBe287MGXxvhRETivA{t?s`D%dQ?B~S}s}A z!qn1oKvx#w?9^V<#%k3&wp~Nvc4Nsd%y9Lrm+#w!Hp=&S$0b%Asvy=6b$th;uM zG$XZM1CN4Ot<=1x9p;x8&GPQ93GtXhVurH0xE%HigO#(!BhLv3#AJg9Z@JXx++i+} zHJYAlyEIm|AY4NeWEEmi=7HSxJjb@&bxQsEqZYLv-r=j? zU$}1tAGSPd2Mhbl6oR@@j1|bPeSzjL&|KnFm!`(OxV-rLCk6Ki+~OT{2=9;mOoXV! z&|q3o;tLt*=RYm z?$q7GmgSh-E0b?#jNQP`gT0IUWMyy1_s;AZ^@6=h&965p{MYRU@WFq>qV<~ovkx}) z9m@}FfA92dv*D4JV+VWOdQ(W3nrE@L>eK^T^BT>ycX%W`tO+Sx{y+XMtvX)Ka)LD& zT&}%94=>Qo3$!0jzOiv1Sx(DN@)}OO0aeeMmxz%|_He6G{b+sDjFm^QTX6~sA98Sk z7DBwR5G%DK%ZJUWH|!8s=M5Ed1Vecf#;M?zm?)K7)%jQ<76qNsyde|ngi5KpIS(HM zG?YuAD^rhzN_D$5AE!6G2BeG{{k&F_Nhse~)I(WcEQT_)ONe#7s2EClt7IDLPqwNL zHe;o{St%PTJRjUE%Fqq>%UcF6Z5w#|o_`%u2n*zU+q;JP)B6uL%Z9SCUMa_^-SSR( zy;>ZJ)zhX$k9?l&SpAR}Vk}eZFzyqXKy5&|XJ8sUt<$48<@3xm z<38JMHEbV(jaA2cYWuMU?c&p}mh#xEyRq6;Ra-#k$7$bgI&eOKxarh^xM7_Z=Zthf zO@09Qz( z$SMlXVGZZdG|r$QG>4`TewIN6ltmiSj*~sAc)I>(JowKkP5UbW2Ok~4b$tFL8m@6x)oRRQOyfFFe4tr6 zH@Jy^f+u+g{svF2X@&Gxpw=PMNsuJq2_+@g?y2e=#&of@?z)Nv^MQSafGlPG1j=Rwah@5##1)0-P^dUx00<6*#QnIp5D=0 zDcJ$)OiZ1YY455`6OZl0j>bD5>aC1SZ5uobd7U!JlMfA1l;*a{yLPZbnepFMSY2$$ zPJe^vWa@o}K2f0miN7z-K7tlao2|PnnC?KOAGb+nA9U(<6JtuVoL>!KQ4l zzumE;xr`6CdS$oxgY0gP$NhNxNUKlwD%*@c)Wx6pQQ7y2_KbEV!X5+m&;0mv*b~5h z$xl9q%>(-neyWY_i&r!jYuYdSKVl*&`_+EXj*aiA{l}_L$20?S05lCb5YwFDXR)h; zZFquD0v>9^1^xoy;Wqpoeh%Y4tK;BxD>DMq&)eNE~ezkcy$H-iqd`$j#ig%kH5-a!}zJ@ z2Ut!18&`9#H6~B-?>*F^(=YkO)|fjC__Bh3!(Rm44fyrzNq;2C<@Garhgl~+9`eOe6&+!b^fx%twQOZe3#+T8nYp=zwY5@cu9dyI)67m?@Pq2* zwXNEQSN)8I8P~2ke%;1Y!63QW9TCiVwYuj*VrVRbBFrdeb2pY&O3gXj1$p3!%a@5) zBv-MW^}MQMyE8!`DjSW!xpSQ+U!8c<_HQ=4!0{*UT_D{j3!#D4IlF8;WK+9rY&X^` z;#DS1_8y7`Ccb`r{t%k`*r$6PEf#2!eW*Rvf2KdeUGNzNkpBBlP_mUBN+hQQ{R(=h zPhGV1ijC#!t}nX4WA{yd`R*LMNh-J~_$qv9zbyqRT4+7PC^T&V4Mv z5zWNR>a>-ftpqnVH+?4v*+t8k5sn?|^Rt$DtHOf^A$#|$6pYf;SH_#>%J}rubjW5y zb}MA_1=C7ka%jwM1x{$(@&pf)^Il`4>R3k6bMNo6>1J1?*9_-41b$PWo(>IKuVs+G ziE;22r_q3!IZrGsV}8*MEMwKNtCq1216ca}It>>U$}B3JS&WE_L~Q(DR&?OaiKd}AMBXy0$Q}z*I zN5#j92W__Ea_32W2>=b3#bp(CsS6c{Dw>*l->yczbO4LBRe-fhgb34$z63HWQ>6o; zNUSd6M@Jw66T-P~Wjy8jxNC%E*yQ`>WAb||vr!33(V*420SDg)Fi>$zgtNNqrA<%Z zzS$d1tJ$TRUAHn(xBS2sR@RREKa!l==dA>H(Wp{gff)rxYNSXf#V$oR7eQ8fgFLK+ z9S(Ew#wxVg^dipY1{r`>N|#XCDY+hZ)TJqU$PxRf$)V}M=YNbQt7lkFH&`FO9+qV} zHo!8hkDWuCW5BZ!rvDKA1kv=dJl>)BH867sUy}9cJ(%6Yra;}pM)B@rb>N6My*Z3z z73WD{={*h3(R|_!4Rod7p*n)<2UHIlMOU8=)ZsefJ=75r6$GjWUFu>`>fA);&vuX( zP^D2wHeXtJ5(wK-vDb@3Zn5GzI8@}>c`v`$gZJ7|3>L$X)a;Fp;yMCSe0vL0Ma5g3 z`&X!c1x+ClcEjI^o7#%K^I~OGETeshqF1yVv=QL|g_*rcdm+!ph@V80)oCxpI=Y9f zF$x52pRz_C5$m8eP$yA6wQmvBQ>d8!-BJ}4H(N<*U^E%q3pEr*M_Q?X$&_SI^%iO; z@tRC;>pL1oGN_yM?F8?T8OqV9>UnhjQC{%?y|Q^HxMpRiaAhY?qiWN5CLZaMUE&?t zMOfrWozHZli)pek4eA}p$+o&te|15NZqkBey{fg6k8D&`4b)HxiOLOi8tI;kXZApD zFRGwlp$dWoRCnFH2U%U8?Bl(tNj_GZqr!sDy}nCbrgap!APO(Re8a(uHBQggZ@j&*T(U9?ODpTQOU1?I1tb(V zmX;Ql*LPW3WU*z<8wb|>Z5kaQJ7}7(skO`UAyO zimM=a9r={iQ*kRn1u;EF_!eajwJ;mQsv5A`5Y63->l}M(rK1>6Av_NElyX?P2;F9C zR;g?CQfw5BGWkI%pk1-L526$sg^%RsqW(S`Di>;2=YiZP%)|iA?T-8H2`M1d(y)Yv z5ELM22~ixNdPYU%a15DAR5v0)AyaM&uZB)+NHX>V5c{iWvIy2WmO_hvB87lzuoDQ= z6r?F+(|ZCG5!{0?l2sUlWkr#T$1{l`gkXesRJvfhTrfkU`lMDBR0l;qKt7@d59qtE Xbm~e}S6!o`&!<8mtEY^VmF@T+Qnl-V literal 0 HcmV?d00001 diff --git a/backend/script_groups/XML Parser to SCL/parsers/parse_lad_fbd.py b/backend/script_groups/XML Parser to SCL/parsers/parse_lad_fbd.py new file mode 100644 index 0000000..f3e7ad9 --- /dev/null +++ b/backend/script_groups/XML Parser to SCL/parsers/parse_lad_fbd.py @@ -0,0 +1,548 @@ +# ToUpload/parsers/parse_lad_fbd.py +# -*- coding: utf-8 -*- +from lxml import etree +from collections import defaultdict +import copy +import traceback + +# Importar desde las utilidades del parser +from .parser_utils import ( + ns, + parse_access, + parse_part, + parse_call, + get_multilingual_text, +) + +# Sufijo usado en x2 para identificar instrucciones procesadas (útil para EN/ENO) +SCL_SUFFIX = "_sympy_processed" # Asumimos que este es el sufijo de x2 + + +def parse_lad_fbd_network(network_element): + """ + Parsea una red LAD/FBD/GRAPH, extrae lógica y añade conexiones EN/ENO implícitas. + Devuelve un diccionario representando la red para el JSON. + """ + if network_element is None: + return { + "id": "ERROR", + "title": "Invalid Network Element", + "logic": [], + "error": "Input element was None", + } + + network_id = network_element.get("ID") + # Usar get_multilingual_text de utils + title_element = network_element.xpath( + ".//iface:MultilingualText[@CompositionName='Title']", namespaces=ns + ) + network_title = ( + get_multilingual_text(title_element[0]) + if title_element + else f"Network {network_id}" + ) + comment_element = network_element.xpath( + "./ObjectList/MultilingualText[@CompositionName='Comment']", namespaces=ns + ) # OJO: Path relativo a CompileUnit? + if not comment_element: # Intentar path alternativo si el anterior falla + comment_element = network_element.xpath( + ".//MultilingualText[@CompositionName='Comment']", namespaces=ns + ) # Más genérico dentro de la red + network_comment = ( + get_multilingual_text(comment_element[0]) if comment_element else "" + ) + + # --- Determinar Lenguaje (ya que este parser maneja varios) --- + network_lang = "Unknown" + attr_list_net = network_element.xpath("./AttributeList") + if attr_list_net: + lang_node_net = attr_list_net[0].xpath("./ProgrammingLanguage/text()") + if lang_node_net: + network_lang = lang_node_net[0].strip() + + # --- Buscar FlgNet --- + # Buscar NetworkSource y luego FlgNet (ambos usan namespace flg) + network_source_node = network_element.xpath(".//flg:NetworkSource", namespaces=ns) + flgnet = None + if network_source_node: + flgnet_list = network_source_node[0].xpath("./flg:FlgNet", namespaces=ns) + if flgnet_list: + flgnet = flgnet_list[0] + else: # Intentar buscar FlgNet directamente si no hay NetworkSource + flgnet_list = network_element.xpath(".//flg:FlgNet", namespaces=ns) + if flgnet_list: + flgnet = flgnet_list[0] + + if flgnet is None: + return { + "id": network_id, + "title": network_title, + "comment": network_comment, + "language": network_lang, + "logic": [], + "error": "FlgNet not found inside NetworkSource or CompileUnit", + } + + # 1. Parse Access, Parts, Calls (usan utils) + access_map = {} + # Corregir XPath para buscar Access dentro de FlgNet/Parts + for acc in flgnet.xpath(".//flg:Parts/flg:Access", namespaces=ns): + acc_info = parse_access(acc) + if acc_info and acc_info.get("uid") and "error" not in acc_info.get("type", ""): + access_map[acc_info["uid"]] = acc_info + elif acc_info: + print( + f"Advertencia: Ignorando Access inválido o con error UID={acc_info.get('uid')} en red {network_id}" + ) + + parts_and_calls_map = {} + # Corregir XPath para buscar Part y Call dentro de FlgNet/Parts + instruction_elements = flgnet.xpath( + ".//flg:Parts/flg:Part | .//flg:Parts/flg:Call", namespaces=ns + ) + for element in instruction_elements: + parsed_info = None + tag_name = etree.QName(element.tag).localname + if tag_name == "Part": + parsed_info = parse_part(element) # Usa utils + elif tag_name == "Call": + parsed_info = parse_call(element) # Usa utils + + if ( + parsed_info + and parsed_info.get("uid") + and "error" not in parsed_info.get("type", "") + ): + parts_and_calls_map[parsed_info["uid"]] = parsed_info + elif parsed_info: + # Si parse_call/parse_part devolvió error, lo guardamos para tener el UID + print( + f"Advertencia: {tag_name} con error UID={parsed_info.get('uid')} en red {network_id}. Error: {parsed_info.get('error')}" + ) + parts_and_calls_map[parsed_info["uid"]] = ( + parsed_info # Guardar aunque tenga error + ) + + # 2. Parse Wires (lógica compleja, mantener aquí) + wire_connections = defaultdict(list) # destination -> [source1, source2] + source_connections = defaultdict(list) # source -> [dest1, dest2] + eno_outputs = defaultdict(list) + qname_powerrail = etree.QName(ns["flg"], "Powerrail") + qname_identcon = etree.QName( + ns["flg"], "IdentCon" + ) # Conexión a/desde Access (variable/constante) + qname_namecon = etree.QName( + ns["flg"], "NameCon" + ) # Conexión a/desde Part/Call (pin con nombre) + qname_openbranch = etree.QName( + ns["flg"], "Openbranch" + ) # Rama abierta (normalmente ignorada o tratada como TRUE?) + qname_opencon = etree.QName( + ns["flg"], "OpenCon" + ) # Conexión abierta (pin no conectado) + + # Corregir XPath para buscar Wire dentro de FlgNet/Wires + for wire in flgnet.xpath(".//flg:Wires/flg:Wire", namespaces=ns): + children = wire.getchildren() + if len(children) < 2: + continue # Necesita al menos origen y destino + + source_elem = children[0] + source_uid, source_pin = None, None + + # Determinar origen + if source_elem.tag == qname_powerrail: + source_uid, source_pin = "POWERRAIL", "out" + elif source_elem.tag == qname_identcon: # Origen es una variable/constante + source_uid = source_elem.get("UId") + source_pin = "value" # Salida implícita de un Access + elif source_elem.tag == qname_namecon: # Origen es pin de instrucción + source_uid = source_elem.get("UId") + source_pin = source_elem.get("Name") + elif source_elem.tag == qname_openbranch: + # ¿Cómo manejar OpenBranch como fuente? Podría ser TRUE o una condición OR implícita + source_uid = "OPENBRANCH_" + wire.get( + "UId", "Unknown" + ) # UID único para la rama + source_pin = "out" + print( + f"Advertencia: OpenBranch encontrado como fuente en Wire UID={wire.get('UId')} (Red {network_id}). Tratando como fuente especial." + ) + # No lo añadimos a parts_and_calls_map, get_sympy_representation necesitará manejarlo + # Ignorar OpenCon como fuente (no tiene sentido) + if source_uid is None or source_pin is None: + # print(f"Advertencia: Fuente de wire inválida o no soportada: {source_elem.tag} en Wire UID={wire.get('UId')}") + continue + + source_info = (source_uid, source_pin) + + # Procesar destinos + for dest_elem in children[1:]: + dest_uid, dest_pin = None, None + + if ( + dest_elem.tag == qname_identcon + ): # Destino es una variable/constante (asignación) + dest_uid = dest_elem.get("UId") + dest_pin = "value" # Entrada implícita de un Access + elif dest_elem.tag == qname_namecon: # Destino es pin de instrucción + dest_uid = dest_elem.get("UId") + dest_pin = dest_elem.get("Name") + # Ignorar Powerrail, OpenBranch, OpenCon como destinos válidos de conexión lógica principal + + if dest_uid is not None and dest_pin is not None: + dest_key = (dest_uid, dest_pin) + if source_info not in wire_connections[dest_key]: + wire_connections[dest_key].append(source_info) + + # Mapa inverso: source -> list of destinations + source_key = (source_uid, source_pin) + dest_info = (dest_uid, dest_pin) + if dest_info not in source_connections[source_key]: + source_connections[source_key].append(dest_info) + + # Trackear salidas ENO específicamente si la fuente es una instrucción + if source_pin == "eno" and source_uid in parts_and_calls_map: + if dest_info not in eno_outputs[source_uid]: + eno_outputs[source_uid].append(dest_info) + + # 3. Build Initial Logic Structure (incorporando errores) + all_logic_steps = {} + # Lista de tipos funcionales (usados para inferencia EN) + # Estos son los tipos *originales* de las instrucciones + functional_block_types = [ + "Move", + "Add", + "Sub", + "Mul", + "Div", + "Mod", + "Convert", + "Call", # Call ya está aquí + "TON", + "TOF", + "TP", + "CTU", + "CTD", + "CTUD", + "BLKMOV", # Añadidos + "Se", + "Sd", # Estos son tipos LAD que se mapearán a timers SCL + ] + # Lista de generadores RLO (usados para inferencia EN) + rlo_generators = [ + "Contact", + "O", + "Eq", + "Ne", + "Gt", + "Lt", + "Ge", + "Le", + "And", + "Xor", + "PBox", + "NBox", + "Not", + ] + + # Iterar sobre UIDs válidos (los que se pudieron parsear, aunque sea con error) + valid_instruction_uids = list(parts_and_calls_map.keys()) + + for instruction_uid in valid_instruction_uids: + instruction_info = parts_and_calls_map[instruction_uid] + # Hacer copia profunda para no modificar el mapa original + instruction_repr = copy.deepcopy(instruction_info) + instruction_repr["instruction_uid"] = instruction_uid # Asegurar UID + instruction_repr["inputs"] = {} + instruction_repr["outputs"] = {} + + # Si la instrucción ya tuvo un error de parseo, añadirlo aquí + if "error" in instruction_info: + instruction_repr["parsing_error"] = instruction_info["error"] + # No intentar poblar inputs/outputs si el parseo base falló + all_logic_steps[instruction_uid] = instruction_repr + continue + + original_type = instruction_repr.get("type", "") # Tipo de la instrucción + + # --- Poblar Entradas --- + # Lista base de pines posibles (podría obtenerse de XSDs o dinámicamente) + possible_input_pins = set(["en", "in", "in1", "in2", "pre"]) + # Añadir pines dinámicamente basados en el tipo de instrucción + if original_type in ["Contact", "Coil", "SCoil", "RCoil", "SdCoil"]: + possible_input_pins.add("operand") + elif original_type in [ + "Add", + "Sub", + "Mul", + "Div", + "Mod", + "Eq", + "Ne", + "Gt", + "Lt", + "Ge", + "Le", + ]: + possible_input_pins.update(["in1", "in2"]) + elif original_type in ["TON", "TOF", "TP"]: + possible_input_pins.update(["IN", "PT"]) # Pines SCL + elif original_type in ["Se", "Sd"]: + possible_input_pins.update(["s", "tv", "timer"]) # Pines LAD + elif original_type in ["CTU", "CTD", "CTUD"]: + possible_input_pins.update(["CU", "CD", "R", "LD", "PV"]) # Pines SCL/LAD + elif original_type in ["PBox", "NBox"]: + possible_input_pins.update( + ["bit", "clk", "in"] + ) # PBox/NBox usa 'in' y 'bit' + elif original_type == "BLKMOV": + possible_input_pins.add("SRCBLK") + elif original_type == "Move": + possible_input_pins.add("in") + elif original_type == "Convert": + possible_input_pins.add("in") + elif original_type == "Call": + # Para Calls, los nombres de los parámetros reales se definen en el XML + # El Xpath busca Parameter DENTRO de CallInfo, que está DENTRO de Call + call_xml_element_list = flgnet.xpath( + f".//flg:Parts/flg:Call[@UId='{instruction_uid}']", namespaces=ns + ) + if call_xml_element_list: + call_xml_element = call_xml_element_list[0] + call_info_node_list = call_xml_element.xpath( + "./flg:CallInfo", namespaces=ns + ) + if call_info_node_list: + call_param_names = call_info_node_list[0].xpath( + "./flg:Parameter/@Name", namespaces=ns + ) + possible_input_pins.update(call_param_names) + # print(f"DEBUG Call UID={instruction_uid}: Params={call_param_names}") + else: # Fallback si no hay namespace (menos probable) + call_info_node_list_no_ns = call_xml_element.xpath("./CallInfo") + if call_info_node_list_no_ns: + possible_input_pins.update( + call_info_node_list_no_ns[0].xpath("./Parameter/@Name") + ) + + # Iterar sobre pines posibles y buscar conexiones + for pin_name in possible_input_pins: + dest_key = (instruction_uid, pin_name) + if dest_key in wire_connections: + sources_list = wire_connections[dest_key] + input_sources_repr = [] + for source_uid, source_pin in sources_list: + source_repr = None + if source_uid == "POWERRAIL": + source_repr = {"type": "powerrail"} + elif source_uid.startswith("OPENBRANCH_"): + source_repr = { + "type": "openbranch", + "uid": source_uid, + } # Fuente especial + elif source_uid in access_map: + source_repr = copy.deepcopy(access_map[source_uid]) + elif source_uid in parts_and_calls_map: + source_instr_info = parts_and_calls_map[source_uid] + source_repr = { + "type": "connection", + "source_instruction_type": source_instr_info.get( + "type", "Unknown" + ), # Usar tipo base + "source_instruction_uid": source_uid, + "source_pin": source_pin, + } + else: + # Fuente desconocida (ni Access, ni Part/Call válido) + print( + f"Advertencia: Fuente desconocida UID={source_uid} conectada a {instruction_uid}.{pin_name}" + ) + source_repr = {"type": "unknown_source", "uid": source_uid} + input_sources_repr.append(source_repr) + + # Guardar la representación de la entrada (lista o dict) + instruction_repr["inputs"][pin_name] = ( + input_sources_repr[0] + if len(input_sources_repr) == 1 + else input_sources_repr + ) + + # --- Poblar Salidas (simplificado: solo conexiones a Access) --- + possible_output_pins = set( + [ + "out", + "out1", + "Q", + "q", + "eno", + "RET_VAL", + "DSTBLK", + "rt", + "cv", + "QU", + "QD", + "ET", # Añadir pines de salida estándar SCL + ] + ) + if original_type == "BLKMOV": + possible_output_pins.add("DSTBLK") + if ( + original_type == "Call" + ): # Para Calls, las salidas dependen del bloque llamado + call_xml_element_list = flgnet.xpath( + f".//flg:Parts/flg:Call[@UId='{instruction_uid}']", namespaces=ns + ) + if call_xml_element_list: + call_info_node_list = call_xml_element_list[0].xpath( + "./flg:CallInfo", namespaces=ns + ) + if call_info_node_list: + # Buscar parámetros con Section="Output" o "InOut" o "Return" + output_param_names = call_info_node_list[0].xpath( + "./flg:Parameter[@Section='Output' or @Section='InOut' or @Section='Return']/@Name", + namespaces=ns, + ) + possible_output_pins.update(output_param_names) + + for pin_name in possible_output_pins: + source_key = (instruction_uid, pin_name) + if source_key in source_connections: + if pin_name not in instruction_repr["outputs"]: + instruction_repr["outputs"][pin_name] = [] + for dest_uid, dest_pin in source_connections[source_key]: + if ( + dest_uid in access_map + ): # Solo registrar si va a una variable/constante + dest_operand_copy = copy.deepcopy(access_map[dest_uid]) + if ( + dest_operand_copy + not in instruction_repr["outputs"][pin_name] + ): + instruction_repr["outputs"][pin_name].append( + dest_operand_copy + ) + + all_logic_steps[instruction_uid] = instruction_repr + + # 4. Inferencia EN (modificado para usar tipos originales) + processed_blocks_en_inference = set() + try: + # Ordenar UIDs numéricamente si es posible + sorted_uids_for_en = sorted( + all_logic_steps.keys(), + key=lambda x: ( + int(x) if isinstance(x, str) and x.isdigit() else float("inf") + ), + ) + except ValueError: + sorted_uids_for_en = sorted(all_logic_steps.keys()) # Fallback sort + + ordered_logic_list_for_en = [ + all_logic_steps[uid] for uid in sorted_uids_for_en if uid in all_logic_steps + ] + + for i, instruction in enumerate(ordered_logic_list_for_en): + part_uid = instruction["instruction_uid"] + # Usar el tipo original para la lógica de inferencia + part_type_original = ( + instruction.get("type", "").replace(SCL_SUFFIX, "").replace("_error", "") + ) + + # Inferencia solo para tipos funcionales que no tengan EN explícito + if ( + part_type_original in functional_block_types + and "en" not in instruction.get("inputs", {}) + and part_uid not in processed_blocks_en_inference + and "error" not in part_type_original + ): # No inferir para errores + + inferred_en_source = None + # Buscar hacia atrás en la lista ordenada + if i > 0: + for j in range(i - 1, -1, -1): + prev_instr = ordered_logic_list_for_en[j] + if "error" in prev_instr.get("type", ""): + continue # Saltar errores previos + + prev_uid = prev_instr["instruction_uid"] + prev_type_original = ( + prev_instr.get("type", "") + .replace(SCL_SUFFIX, "") + .replace("_error", "") + ) + + if prev_type_original in rlo_generators: # Fuente RLO encontrada + inferred_en_source = { + "type": "connection", + "source_instruction_uid": prev_uid, + "source_instruction_type": prev_type_original, # Tipo original + "source_pin": "out", + } + break # Detener búsqueda + elif ( + prev_type_original in functional_block_types + ): # Bloque funcional previo + # Comprobar si este bloque tiene salida ENO conectada + if (prev_uid, "eno") in source_connections: + inferred_en_source = { + "type": "connection", + "source_instruction_uid": prev_uid, + "source_instruction_type": prev_type_original, # Tipo original + "source_pin": "eno", + } + # Si no tiene ENO conectado, el flujo RLO se detiene aquí + break # Detener búsqueda + elif prev_type_original in [ + "Coil", + "SCoil", + "RCoil", + "SdCoil", + "SetCoil", + "ResetCoil", + ]: + # Bobinas terminan el flujo RLO + break # Detener búsqueda + + # Si no se encontró fuente, conectar a PowerRail + if inferred_en_source is None: + inferred_en_source = {"type": "powerrail"} + + # Actualizar la instrucción EN el diccionario principal + if part_uid in all_logic_steps: + # Asegurar que inputs exista + if "inputs" not in all_logic_steps[part_uid]: + all_logic_steps[part_uid]["inputs"] = {} + all_logic_steps[part_uid]["inputs"]["en"] = inferred_en_source + processed_blocks_en_inference.add(part_uid) + + # 5. Lógica ENO (añadir destinos ENO si existen) + for source_instr_uid, eno_destinations in eno_outputs.items(): + if source_instr_uid in all_logic_steps and "error" not in all_logic_steps[ + source_instr_uid + ].get("type", ""): + all_logic_steps[source_instr_uid]["eno_destinations"] = eno_destinations + + # 6. Ordenar y Devolver + final_logic_list = [ + all_logic_steps[uid] for uid in sorted_uids_for_en if uid in all_logic_steps + ] + + return { + "id": network_id, + "title": network_title, + "comment": network_comment, + "language": network_lang, # Lenguaje original de la red + "logic": final_logic_list, + # No añadir 'error' aquí a menos que el parseo completo falle + } + + +# --- Función de Información del Parser --- +def get_parser_info(): + """Devuelve la información para este parser.""" + # Este parser maneja LAD, FBD y GRAPH + return { + "language": ["LAD", "FBD", "GRAPH"], # Lista de lenguajes soportados + "parser_func": parse_lad_fbd_network, # Función a llamar + } diff --git a/backend/script_groups/XML Parser to SCL/parsers/parse_scl.py b/backend/script_groups/XML Parser to SCL/parsers/parse_scl.py new file mode 100644 index 0000000..b88e779 --- /dev/null +++ b/backend/script_groups/XML Parser to SCL/parsers/parse_scl.py @@ -0,0 +1,253 @@ +# ToUpload/parsers/parse_scl.py +# -*- coding: utf-8 -*- +from lxml import etree +import re + +# Importar desde las utilidades del parser +from .parser_utils import ns, get_multilingual_text + +def reconstruct_scl_from_tokens(st_node): + """ + Reconstruye SCL desde , mejorando el manejo de + variables, constantes literales, tokens básicos, espacios y saltos de línea. + """ + if st_node is None: + return "// Error: StructuredText node not found.\n" + + scl_parts = [] + # Usar st:* para obtener todos los elementos hijos dentro del namespace st + children = st_node.xpath("./st:*", namespaces=ns) + + for elem in children: + tag = etree.QName(elem.tag).localname + + if tag == "Token": + scl_parts.append(elem.get("Text", "")) + elif tag == "Blank": + # Añadir espacios solo si es necesario o más de uno + num_spaces = int(elem.get("Num", 1)) + if not scl_parts or not scl_parts[-1].endswith(" "): + scl_parts.append(" " * num_spaces) + elif num_spaces > 1: + scl_parts.append(" " * (num_spaces -1)) + + elif tag == "NewLine": + # Quitar espacios finales antes del salto de línea + if scl_parts: + scl_parts[-1] = scl_parts[-1].rstrip() + scl_parts.append("\n") + elif tag == "Access": + scope = elem.get("Scope") + access_str = f"/*_ERR_Scope_{scope}_*/" # Placeholder + + # --- Variables --- + if scope in [ + "GlobalVariable", "LocalVariable", "TempVariable", "InOutVariable", + "InputVariable", "OutputVariable", "ConstantVariable", + "GlobalConstant", "LocalConstant" # Añadir constantes simbólicas + ]: + symbol_elem = elem.xpath("./st:Symbol", namespaces=ns) + if symbol_elem: + components = symbol_elem[0].xpath("./st:Component", namespaces=ns) + symbol_text_parts = [] + for i, comp in enumerate(components): + name = comp.get("Name", "_ERR_COMP_") + if i > 0: symbol_text_parts.append(".") + + # Check for HasQuotes attribute (adjust namespace if needed) + # El atributo está en el Component o en el Access padre? Probar ambos + has_quotes_comp = comp.get("HasQuotes", "false").lower() == "true" # Check directly on Component + has_quotes_access = False + access_parent = comp.xpath("ancestor::st:Access[1]", namespaces=ns) # Get immediate Access parent + if access_parent: + has_quotes_attr = access_parent[0].xpath("./st:BooleanAttribute[@Name='HasQuotes']/text()", namespaces=ns) + has_quotes_access = has_quotes_attr and has_quotes_attr[0].lower() == 'true' + + has_quotes = has_quotes_comp or has_quotes_access + is_temp = name.startswith("#") + + # Apply quotes based on HasQuotes or if it's the first component and not temp + if has_quotes or (i == 0 and not is_temp and '"' not in name): # Avoid double quotes + symbol_text_parts.append(f'"{name}"') + else: + symbol_text_parts.append(name) + + # --- Array Index Access --- + index_access_nodes = comp.xpath("./st:Access", namespaces=ns) + if index_access_nodes: + # Llamada recursiva para cada índice + indices_text = [reconstruct_scl_from_tokens(idx_node) for idx_node in index_access_nodes] + # Limpiar saltos de línea dentro de los corchetes + indices_cleaned = [idx.replace('\n', '').strip() for idx in indices_text] + symbol_text_parts.append(f"[{','.join(indices_cleaned)}]") + + access_str = "".join(symbol_text_parts) + else: + access_str = f"/*_ERR_NO_SYMBOL_IN_{scope}_*/" + + # --- Constantes Literales --- + elif scope == "LiteralConstant": + constant_elem = elem.xpath("./st:Constant", namespaces=ns) + if constant_elem: + val_elem = constant_elem[0].xpath("./st:ConstantValue/text()", namespaces=ns) + type_elem = constant_elem[0].xpath("./st:ConstantType/text()", namespaces=ns) + const_type = type_elem[0].strip().lower() if type_elem and type_elem[0] is not None else "" + const_val = val_elem[0].strip() if val_elem and val_elem[0] is not None else "_ERR_CONSTVAL_" + + # Formatear según tipo + if const_type == "bool": access_str = const_val.upper() + elif const_type.lower() == "string": + replaced_val = const_val.replace("'", "''") + access_str = f"'{replaced_val}'" + elif const_type.lower() == "char": + replaced_val = const_val.replace("'", "''") + access_str = f"'{replaced_val}'" + elif const_type == "wstring": + replaced_val = const_val.replace("'", "''") + access_str = f"WSTRING#'{replaced_val}'" + elif const_type == "wchar": + replaced_val = const_val.replace("'", "''") + access_str = f"WCHAR#'{replaced_val}'" + elif const_type == "time": access_str = f"T#{const_val}" + elif const_type == "ltime": access_str = f"LT#{const_val}" + elif const_type == "s5time": access_str = f"S5T#{const_val}" + elif const_type == "date": access_str = f"D#{const_val}" + elif const_type == "dtl": access_str = f"DTL#{const_val}" + elif const_type == "dt": access_str = f"DT#{const_val}" + elif const_type == "tod": access_str = f"TOD#{const_val}" + elif const_type in ["int", "dint", "sint", "usint", "uint", "udint", "real", "lreal", "word", "dword", "byte"]: + # Añadir .0 para reales si no tienen decimal + if const_type in ["real", "lreal"] and '.' not in const_val and 'e' not in const_val.lower(): + access_str = f"{const_val}.0" + else: + access_str = const_val + else: # Otros tipos (LWORD, etc.) o desconocidos + access_str = const_val + else: + access_str = "/*_ERR_NOCONST_*/" + + # --- Llamadas a Funciones/Bloques (Scope=Call) --- + elif scope == "Call": + call_info_node = elem.xpath("./st:CallInfo", namespaces=ns) + if call_info_node: + ci = call_info_node[0] + call_name = ci.get("Name", "_ERR_CALLNAME_") + call_type = ci.get("BlockType") # FB, FC, etc. + + # Parámetros (están como Access o Token dentro de CallInfo/Parameter) + params = ci.xpath("./st:Parameter", namespaces=ns) + param_parts = [] + for p in params: + p_name = p.get("Name", "_ERR_PARAMNAME_") + # El valor del parámetro está dentro del nodo Parameter + p_value_node = p.xpath("./st:Access | ./st:Token", namespaces=ns) # Buscar Access o Token + p_value_scl = "" + if p_value_node: + p_value_scl = reconstruct_scl_from_tokens(p) # Parsear el contenido del parámetro + p_value_scl = p_value_scl.replace('\n', '').strip() # Limpiar SCL resultante + param_parts.append(f"{p_name} := {p_value_scl}") + + # Manejar FB vs FC + if call_type == "FB": + instance_node = ci.xpath("./st:Instance/st:Component/@Name", namespaces=ns) + if instance_node: + instance_name = f'"{instance_node[0]}"' + access_str = f"{instance_name}({', '.join(param_parts)})" + else: # FB sin instancia? Podría ser STAT + access_str = f'"{call_name}"({", ".join(param_parts)}) (* FB sin instancia explícita? *)' + elif call_type == "FC": + access_str = f'"{call_name}"({", ".join(param_parts)})' + else: # Otros tipos de llamada + access_str = f'"{call_name}"({", ".join(param_parts)}) (* Tipo: {call_type} *)' + else: + access_str = "/*_ERR_NO_CALLINFO_*/" + + # Añadir más scopes si son necesarios (e.g., Address, Label, Reference) + + scl_parts.append(access_str) + + elif tag == "Comment" or tag == "LineComment": + # Usar get_multilingual_text del parser_utils + comment_text = get_multilingual_text(elem) + if tag == "Comment": + scl_parts.append(f"(* {comment_text} *)") + else: + scl_parts.append(f"// {comment_text}") + # Ignorar otros tipos de nodos si no son relevantes para el SCL + + full_scl = "".join(scl_parts) + + # --- Re-indentación Simple --- + output_lines = [] + indent_level = 0 + indent_str = " " # Dos espacios + for line in full_scl.splitlines(): + trimmed_line = line.strip() + if not trimmed_line: + # Mantener líneas vacías? Opcional. + # output_lines.append("") + continue + + # Reducir indentación ANTES de imprimir para END, ELSE, etc. + if trimmed_line.upper().startswith(("END_", "UNTIL", "}")) or \ + trimmed_line.upper() in ["ELSE", "ELSIF"]: + indent_level = max(0, indent_level - 1) + + output_lines.append(indent_str * indent_level + trimmed_line) + + # Aumentar indentación DESPUÉS de imprimir para IF, FOR, etc. + # Ser más específico con las palabras clave que aumentan indentación + # Usar .upper() para ignorar mayúsculas/minúsculas + line_upper = trimmed_line.upper() + if line_upper.endswith(("THEN", "DO", "OF", "{")) or \ + line_upper.startswith(("IF ", "FOR ", "WHILE ", "CASE ", "REPEAT", "STRUCT")) or \ + line_upper == "ELSE": + # Excepción: No indentar después de ELSE IF + if not (line_upper == "ELSE" and "IF" in output_lines[-1].upper()): + indent_level += 1 + + return "\n".join(output_lines) + + +def parse_scl_network(network_element): + """ + Parsea una red SCL extrayendo el código fuente reconstruido. + Devuelve un diccionario representando la red para el JSON. + """ + network_id = network_element.get("ID", "UnknownSCL_ID") + network_lang = "SCL" # Sabemos que es SCL + + # Buscar NetworkSource y luego StructuredText + network_source_node = network_element.xpath(".//flg:NetworkSource", namespaces=ns) + structured_text_node = None + if network_source_node: + structured_text_node_list = network_source_node[0].xpath("./st:StructuredText", namespaces=ns) + if structured_text_node_list: + structured_text_node = structured_text_node_list[0] + + reconstructed_scl = "// SCL extraction failed: StructuredText node not found.\n" + if structured_text_node is not None: + reconstructed_scl = reconstruct_scl_from_tokens(structured_text_node) + + # Crear la estructura de datos para la red + parsed_network_data = { + "id": network_id, + "language": network_lang, + "logic": [ # SCL se guarda como un único bloque lógico + { + "instruction_uid": f"SCL_{network_id}", # UID sintético + "type": "RAW_SCL_CHUNK", # Tipo especial para SCL crudo + "scl": reconstructed_scl, # El código SCL reconstruido + } + ], + # No añadimos error aquí, reconstruct_scl_from_tokens ya incluye comentarios de error + } + return parsed_network_data + +# --- Función de Información del Parser --- +def get_parser_info(): + """Devuelve la información para este parser.""" + return { + 'language': ['SCL'], # Lista de lenguajes soportados + 'parser_func': parse_scl_network # Función a llamar + } \ No newline at end of file diff --git a/backend/script_groups/XML Parser to SCL/parsers/parse_stl.py b/backend/script_groups/XML Parser to SCL/parsers/parse_stl.py new file mode 100644 index 0000000..19c8d2b --- /dev/null +++ b/backend/script_groups/XML Parser to SCL/parsers/parse_stl.py @@ -0,0 +1,526 @@ +# ToUpload/parsers/parse_stl.py +# -*- coding: utf-8 -*- +from lxml import etree +import traceback +import re # Needed for substitutions in get_access_text_stl + +# Importar desde las utilidades del parser +# ns y get_multilingual_text son necesarios +from .parser_utils import ns, get_multilingual_text + +# --- Funciones Auxiliares de Reconstrucción STL --- + + +def get_access_text_stl(access_element): + """ + Reconstruye una representación textual simple de un Access en STL. + Intenta manejar los diferentes tipos de acceso definidos en el XSD. + """ + if access_element is None: + return "_ERR_ACCESS_" + + # --- Símbolo (Variable, Constante Simbólica) --- + # Busca dentro del usando el namespace stl + symbol_elem = access_element.xpath("./stl:Symbol", namespaces=ns) + if symbol_elem: + components = symbol_elem[0].xpath("./stl:Component", namespaces=ns) + parts = [] + for i, comp in enumerate(components): + name = comp.get("Name", "_ERR_COMP_") + # Comprobar HasQuotes (puede estar en el Access o Componente, priorizar Componente) + has_quotes_comp = comp.get("HasQuotes", "false").lower() == "true" + has_quotes_access = False + access_parent = comp.xpath("ancestor::stl:Access[1]", namespaces=ns) + if access_parent: + has_quotes_attr = access_parent[0].xpath( + "./stl:BooleanAttribute[@Name='HasQuotes']/text()", namespaces=ns + ) + has_quotes_access = ( + has_quotes_attr and has_quotes_attr[0].lower() == "true" + ) + + has_quotes = has_quotes_comp or has_quotes_access + is_temp = name.startswith("#") + + if i > 0: + parts.append(".") # Separador para estructuras + + # Aplicar comillas si es necesario + if has_quotes or ( + i == 0 and not is_temp and '"' not in name and "." not in name + ): + # Añadir comillas si HasQuotes es true, o si es el primer componente, + # no es temporal, no tiene ya comillas, y no es parte de una DB (ej. DB10.DBX0.0) + parts.append(f'"{name}"') + else: + parts.append(name) + + # Índices de Array (Access anidado dentro de Component) + index_access = comp.xpath("./stl:Access", namespaces=ns) + if index_access: + indices = [get_access_text_stl(ia) for ia in index_access] + # Limpiar índices (quitar saltos de línea, etc.) + indices_cleaned = [idx.replace("\n", "").strip() for idx in indices] + parts.append(f"[{','.join(indices_cleaned)}]") + + return "".join(parts) + + # --- Constante Literal --- + # Busca dentro del usando el namespace stl + constant_elem = access_element.xpath("./stl:Constant", namespaces=ns) + if constant_elem: + # Obtener valor y tipo + val_elem = constant_elem[0].xpath("./stl:ConstantValue/text()", namespaces=ns) + type_elem = constant_elem[0].xpath("./stl:ConstantType/text()", namespaces=ns) + const_type = ( + type_elem[0].strip().lower() + if type_elem and type_elem[0] is not None + else "" + ) + const_val = ( + val_elem[0].strip() + if val_elem and val_elem[0] is not None + else "_ERR_CONST_" + ) + + # Añadir prefijos estándar STL + if const_type == "time": + return f"T#{const_val}" + if const_type == "s5time": + return f"S5T#{const_val}" + if const_type == "date": + return f"D#{const_val}" + if const_type == "dt": + return f"DT#{const_val}" + if const_type == "time_of_day" or const_type == "tod": + return f"TOD#{const_val}" + if const_type == "ltime": + return f"LT#{const_val}" # Añadido LTIME + if const_type == "dtl": + return f"DTL#{const_val}" # Añadido DTL + + # Strings y Chars (Escapar comillas simples internas) + if const_type == "string": + replaced_val = const_val.replace("'", "''") + return f"'{replaced_val}'" + if const_type == "char": + replaced_val = const_val.replace("'", "''") + return f"'{replaced_val}'" + if const_type == "wstring": + replaced_val = const_val.replace("'", "''") + return f"WSTRING#'{replaced_val}'" + if const_type == "wchar": + replaced_val = const_val.replace("'", "''") + return f"WCHAR#'{replaced_val}'" + + # Tipos numéricos con prefijo opcional (Hexadecimal) + if const_val.startswith("16#"): + if const_type == "byte": + return f"B#{const_val}" + if const_type == "word": + return f"W#{const_val}" + if const_type == "dword": + return f"DW#{const_val}" + if const_type == "lword": + return f"LW#{const_val}" # Añadido LWORD + + # Formato Real (añadir .0 si es necesario) + if ( + const_type in ["real", "lreal"] + and "." not in const_val + and "e" not in const_val.lower() + ): + # Verificar si es un número antes de añadir .0 + try: + float(const_val) # Intenta convertir a float + return f"{const_val}.0" + except ValueError: + return const_val # No es número, devolver tal cual + # Otros tipos numéricos o desconocidos + return const_val # Valor por defecto + + # --- Etiqueta (Label) --- + # Busca