fix: Correct array index access in FB_HMI_Interlock and enhance debugging for array parsing
This commit is contained in:
parent
75cdf080f5
commit
24ae05cc75
|
@ -54,7 +54,7 @@ BEGIN
|
||||||
// Cancel the actual use after timeout
|
// Cancel the actual use after timeout
|
||||||
#Status.HMI_InUse := FALSE;
|
#Status.HMI_InUse := FALSE;
|
||||||
FOR #i:=0 TO 7 DO
|
FOR #i:=0 TO 7 DO
|
||||||
#Status.o_HMI_CanBeUsedBy[] := FALSE;
|
#Status.o_HMI_CanBeUsedBy[#i] := FALSE;
|
||||||
END_FOR;
|
END_FOR;
|
||||||
END_IF;
|
END_IF;
|
||||||
IF NOT #Status.HMI_InUse THEN
|
IF NOT #Status.HMI_InUse THEN
|
||||||
|
@ -65,7 +65,7 @@ BEGIN
|
||||||
END_IF;
|
END_IF;
|
||||||
IF #Status.HMI_CanBeUsedBy > 0 AND #Status.i_Request[#Status.HMI_CanBeUsedBy] THEN
|
IF #Status.HMI_CanBeUsedBy > 0 AND #Status.i_Request[#Status.HMI_CanBeUsedBy] THEN
|
||||||
// Return that the actual request is active and can use the HMI
|
// Return that the actual request is active and can use the HMI
|
||||||
#Status.o_HMI_CanBeUsedBy[] := TRUE;
|
#Status.o_HMI_CanBeUsedBy[#Status.HMI_CanBeUsedBy] := TRUE;
|
||||||
#Status.HMI_InUse := TRUE;
|
#Status.HMI_InUse := TRUE;
|
||||||
END_IF;
|
END_IF;
|
||||||
END_IF;
|
END_IF;
|
||||||
|
@ -73,7 +73,7 @@ BEGIN
|
||||||
// request on every cycle until is granted.
|
// request on every cycle until is granted.
|
||||||
//
|
//
|
||||||
FOR #i:=0 TO 7 DO
|
FOR #i:=0 TO 7 DO
|
||||||
#Status.i_Request[] := FALSE;
|
#Status.i_Request[#i] := FALSE;
|
||||||
END_FOR;
|
END_FOR;
|
||||||
#Status.o_HMI_CanBeUsedBy[0] := NOT #Status.HMI_InUse;
|
#Status.o_HMI_CanBeUsedBy[0] := NOT #Status.HMI_InUse;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,218 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Script de debugging para entender por qué los índices de array simples como [#i] no funcionan
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from lxml import etree
|
||||||
|
|
||||||
|
# Agregar el directorio del script al path
|
||||||
|
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
sys.path.append(script_dir)
|
||||||
|
|
||||||
|
from parsers.parse_scl import reconstruct_scl_from_tokens
|
||||||
|
from parsers.parser_utils import ns
|
||||||
|
|
||||||
|
|
||||||
|
def debug_array_parsing():
|
||||||
|
"""Función para debug del parsing de arrays"""
|
||||||
|
|
||||||
|
# Cargar el archivo XML problemático
|
||||||
|
xml_path = r"D:\Trabajo\VM\45 - HENKEL - VM Auto Changeover\ExportTia\PLC_TL27_Q1\ProgramBlocks_XML\FB HMI Interlock.xml"
|
||||||
|
|
||||||
|
print(f"Cargando XML: {xml_path}")
|
||||||
|
|
||||||
|
# Cargar y parsear el XML
|
||||||
|
with open(xml_path, "r", encoding="utf-8") as f:
|
||||||
|
content = f.read()
|
||||||
|
|
||||||
|
root = etree.fromstring(content)
|
||||||
|
|
||||||
|
# Buscar todas las instancias de i_Request
|
||||||
|
print("\n=== Buscando todas las instancias de i_Request ===")
|
||||||
|
|
||||||
|
# Buscar elementos Component con Name="i_Request"
|
||||||
|
components = root.xpath("//Component[@Name='i_Request']")
|
||||||
|
|
||||||
|
print(f"Encontrados {len(components)} componentes i_Request")
|
||||||
|
|
||||||
|
# Si no encontramos nada, buscar de manera más amplia
|
||||||
|
if len(components) == 0:
|
||||||
|
print("No se encontraron con XPath directo, buscando de manera recursiva...")
|
||||||
|
components = []
|
||||||
|
for elem in root.iter():
|
||||||
|
if elem.tag.endswith("Component") and elem.get("Name") == "i_Request":
|
||||||
|
components.append(elem)
|
||||||
|
print(
|
||||||
|
f"Encontrados {len(components)} componentes i_Request con búsqueda recursiva"
|
||||||
|
)
|
||||||
|
|
||||||
|
for i, comp in enumerate(components):
|
||||||
|
print(f"\n--- Componente {i+1} (UId={comp.get('UId')}) ---")
|
||||||
|
|
||||||
|
# Obtener todos los hijos
|
||||||
|
children = comp.xpath("./*")
|
||||||
|
print(f"Número de hijos: {len(children)}")
|
||||||
|
|
||||||
|
for j, child in enumerate(children):
|
||||||
|
tag = etree.QName(child.tag).localname
|
||||||
|
print(f" Hijo {j}: {tag}")
|
||||||
|
if tag == "Token":
|
||||||
|
print(f" Text: '{child.get('Text')}'")
|
||||||
|
elif tag == "Access":
|
||||||
|
print(f" Scope: '{child.get('Scope')}'")
|
||||||
|
# Buscar Symbol dentro del Access
|
||||||
|
symbols = child.xpath(".//Symbol")
|
||||||
|
if symbols:
|
||||||
|
symbol_components = symbols[0].xpath(".//Component")
|
||||||
|
for sc in symbol_components:
|
||||||
|
print(f" Component: '{sc.get('Name')}'")
|
||||||
|
|
||||||
|
# Verificar si este componente tiene patrón de array
|
||||||
|
has_array_pattern = False
|
||||||
|
bracket_start_idx = -1
|
||||||
|
bracket_end_idx = -1
|
||||||
|
|
||||||
|
# Buscar los tokens [ y ]
|
||||||
|
for idx, child in enumerate(children):
|
||||||
|
tag = etree.QName(child.tag).localname
|
||||||
|
if tag == "Token":
|
||||||
|
text = child.get("Text")
|
||||||
|
if text == "[" and bracket_start_idx == -1:
|
||||||
|
bracket_start_idx = idx
|
||||||
|
elif text == "]" and bracket_start_idx != -1:
|
||||||
|
bracket_end_idx = idx
|
||||||
|
break
|
||||||
|
|
||||||
|
if bracket_start_idx != -1 and bracket_end_idx != -1:
|
||||||
|
has_array_pattern = True
|
||||||
|
print(
|
||||||
|
f" Corchetes encontrados en índices: {bracket_start_idx} y {bracket_end_idx}"
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f" Tiene patrón de array: {has_array_pattern}")
|
||||||
|
|
||||||
|
if has_array_pattern:
|
||||||
|
print(" >>> Este componente debería ser procesado como array <<<")
|
||||||
|
|
||||||
|
# Simular el procesamiento manual del Access del medio
|
||||||
|
for middle_idx in range(bracket_start_idx + 1, bracket_end_idx):
|
||||||
|
middle_child = children[middle_idx]
|
||||||
|
child_tag = etree.QName(middle_child.tag).localname
|
||||||
|
print(f" Procesando elemento medio {middle_idx}: {child_tag}")
|
||||||
|
if child_tag == "Access":
|
||||||
|
scope = middle_child.get("Scope")
|
||||||
|
print(f" Scope: {scope}")
|
||||||
|
|
||||||
|
if scope == "LocalVariable":
|
||||||
|
print(" >>> Es LocalVariable, procesando manualmente <<<")
|
||||||
|
|
||||||
|
# Debug: mostrar toda la estructura del Access
|
||||||
|
print(" Estructura completa del Access:")
|
||||||
|
|
||||||
|
def print_xml_structure(elem, indent=" "):
|
||||||
|
tag = etree.QName(elem.tag).localname
|
||||||
|
attrs = dict(elem.attrib)
|
||||||
|
print(f"{indent}{tag}: {attrs}")
|
||||||
|
for child in elem:
|
||||||
|
print_xml_structure(child, indent + " ")
|
||||||
|
|
||||||
|
print_xml_structure(middle_child)
|
||||||
|
|
||||||
|
# Buscar Symbol con diferentes métodos
|
||||||
|
symbol_elem_ns = middle_child.xpath(
|
||||||
|
"./st:Symbol", namespaces=ns
|
||||||
|
)
|
||||||
|
symbol_elem_no_ns = middle_child.xpath("./Symbol")
|
||||||
|
symbol_elem_recursive = []
|
||||||
|
for child in middle_child:
|
||||||
|
if etree.QName(child.tag).localname == "Symbol":
|
||||||
|
symbol_elem_recursive.append(child)
|
||||||
|
|
||||||
|
print(f" Symbol con namespace: {len(symbol_elem_ns)}")
|
||||||
|
print(f" Symbol sin namespace: {len(symbol_elem_no_ns)}")
|
||||||
|
print(
|
||||||
|
f" Symbol recursivo manual: {len(symbol_elem_recursive)}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Usar el método que funcione
|
||||||
|
symbol_elem = None
|
||||||
|
if symbol_elem_ns:
|
||||||
|
symbol_elem = symbol_elem_ns
|
||||||
|
print(" Usando Symbol con namespace")
|
||||||
|
elif symbol_elem_no_ns:
|
||||||
|
symbol_elem = symbol_elem_no_ns
|
||||||
|
print(" Usando Symbol sin namespace")
|
||||||
|
elif symbol_elem_recursive:
|
||||||
|
symbol_elem = symbol_elem_recursive
|
||||||
|
print(" Usando Symbol recursivo manual")
|
||||||
|
|
||||||
|
if symbol_elem:
|
||||||
|
print(
|
||||||
|
f" Procesando Symbol (total: {len(symbol_elem)})"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Buscar componentes dentro del Symbol
|
||||||
|
components_inner_ns = symbol_elem[0].xpath(
|
||||||
|
"./st:Component", namespaces=ns
|
||||||
|
)
|
||||||
|
components_inner_no_ns = symbol_elem[0].xpath("./Component")
|
||||||
|
components_inner_manual = []
|
||||||
|
for child in symbol_elem[0]:
|
||||||
|
if etree.QName(child.tag).localname == "Component":
|
||||||
|
components_inner_manual.append(child)
|
||||||
|
|
||||||
|
print(
|
||||||
|
f" Componentes con namespace: {len(components_inner_ns)}"
|
||||||
|
)
|
||||||
|
print(
|
||||||
|
f" Componentes sin namespace: {len(components_inner_no_ns)}"
|
||||||
|
)
|
||||||
|
print(
|
||||||
|
f" Componentes manual: {len(components_inner_manual)}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Usar el método que funcione
|
||||||
|
components_inner = None
|
||||||
|
if components_inner_ns:
|
||||||
|
components_inner = components_inner_ns
|
||||||
|
print(" Usando componentes con namespace")
|
||||||
|
elif components_inner_no_ns:
|
||||||
|
components_inner = components_inner_no_ns
|
||||||
|
print(" Usando componentes sin namespace")
|
||||||
|
elif components_inner_manual:
|
||||||
|
components_inner = components_inner_manual
|
||||||
|
print(" Usando componentes manual")
|
||||||
|
|
||||||
|
if components_inner:
|
||||||
|
print(
|
||||||
|
f" Componentes internos encontrados: {len(components_inner)}"
|
||||||
|
)
|
||||||
|
result_parts = []
|
||||||
|
for k, comp_inner in enumerate(components_inner):
|
||||||
|
name = comp_inner.get("Name", "_ERR_COMP_")
|
||||||
|
print(f" Componente {k}: '{name}'")
|
||||||
|
if k == 0:
|
||||||
|
result_parts.append(f"#{name}")
|
||||||
|
print(f" -> Se convertirá en: #{name}")
|
||||||
|
else:
|
||||||
|
result_parts.append(f".{name}")
|
||||||
|
print(f" -> Se convertirá en: .{name}")
|
||||||
|
final_result = "".join(result_parts)
|
||||||
|
print(
|
||||||
|
f" >>> RESULTADO FINAL: '{final_result}' <<<"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
print(" ERROR: No se encontraron componentes")
|
||||||
|
else:
|
||||||
|
print(
|
||||||
|
" ERROR: No se encontró Symbol dentro del Access"
|
||||||
|
)
|
||||||
|
|
||||||
|
print("\n=== Fin del análisis ===")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
debug_array_parsing()
|
|
@ -140,146 +140,139 @@ def reconstruct_scl_from_tokens(st_node):
|
||||||
|
|
||||||
# --- Array Index Access ---
|
# --- Array Index Access ---
|
||||||
# Verificar si este componente tiene hijos que indican acceso de array
|
# Verificar si este componente tiene hijos que indican acceso de array
|
||||||
# Buscar estructura: <Token Text="["/> <Access.../> <Token Text="]"/>
|
# Buscar estructura: [algún contenido] <Token Text="["/> <Access.../> <Token Text="]"/>
|
||||||
children = comp.xpath("./*") # Todos los hijos directos
|
children = comp.xpath("./*") # Todos los hijos directos
|
||||||
|
|
||||||
if len(children) >= 3:
|
# Buscar los tokens [ y ] en cualquier posición
|
||||||
# Verificar patrón: primer hijo es Token "[", último es Token "]"
|
bracket_start_idx = -1
|
||||||
first_child = children[0]
|
bracket_end_idx = -1
|
||||||
last_child = children[-1]
|
|
||||||
first_is_open_bracket = (
|
|
||||||
etree.QName(first_child.tag).localname == "Token"
|
|
||||||
and first_child.get("Text") == "["
|
|
||||||
)
|
|
||||||
last_is_close_bracket = (
|
|
||||||
etree.QName(last_child.tag).localname == "Token"
|
|
||||||
and last_child.get("Text") == "]"
|
|
||||||
)
|
|
||||||
|
|
||||||
if first_is_open_bracket and last_is_close_bracket:
|
for idx, child in enumerate(children):
|
||||||
# Hay acceso de array - procesar los elementos entre los corchetes
|
child_tag = etree.QName(child.tag).localname
|
||||||
indices_parts = []
|
if child_tag == "Token":
|
||||||
|
text = child.get("Text")
|
||||||
|
if text == "[" and bracket_start_idx == -1:
|
||||||
|
bracket_start_idx = idx
|
||||||
|
elif text == "]" and bracket_start_idx != -1:
|
||||||
|
bracket_end_idx = idx
|
||||||
|
break
|
||||||
|
|
||||||
# Mark the bracket tokens and middle elements as processed
|
if bracket_start_idx != -1 and bracket_end_idx != -1:
|
||||||
first_uid = first_child.get("UId")
|
# Hay acceso de array - procesar los elementos entre los corchetes
|
||||||
last_uid = last_child.get("UId")
|
indices_parts = []
|
||||||
if first_uid:
|
|
||||||
processed_elements.add(first_uid)
|
|
||||||
if last_uid:
|
|
||||||
processed_elements.add(last_uid)
|
|
||||||
|
|
||||||
for middle_child in children[
|
# Mark the bracket tokens and middle elements as processed
|
||||||
1:-1
|
start_token = children[bracket_start_idx]
|
||||||
]: # Todo excepto primer y último hijo
|
end_token = children[bracket_end_idx]
|
||||||
middle_uid = middle_child.get("UId")
|
start_uid = start_token.get("UId")
|
||||||
if middle_uid:
|
end_uid = end_token.get("UId")
|
||||||
processed_elements.add(middle_uid)
|
if start_uid:
|
||||||
|
processed_elements.add(start_uid)
|
||||||
|
if end_uid:
|
||||||
|
processed_elements.add(end_uid)
|
||||||
|
|
||||||
child_tag = etree.QName(middle_child.tag).localname
|
for middle_idx in range(
|
||||||
if child_tag == "Access":
|
bracket_start_idx + 1, bracket_end_idx
|
||||||
# Procesar el Access para obtener el índice
|
):
|
||||||
scope = middle_child.get("Scope")
|
middle_child = children[middle_idx]
|
||||||
if scope == "LiteralConstant":
|
middle_uid = middle_child.get("UId")
|
||||||
# Buscar el valor de la constante - tanto con namespace como sin namespace
|
if middle_uid:
|
||||||
|
processed_elements.add(middle_uid)
|
||||||
|
|
||||||
|
child_tag = etree.QName(middle_child.tag).localname
|
||||||
|
if child_tag == "Access":
|
||||||
|
# Procesar el Access para obtener el índice
|
||||||
|
scope = middle_child.get("Scope")
|
||||||
|
if scope == "LiteralConstant":
|
||||||
|
# Buscar el valor de la constante - tanto con namespace como sin namespace
|
||||||
|
constant_elem = middle_child.xpath(
|
||||||
|
"./st:Constant", namespaces=ns
|
||||||
|
)
|
||||||
|
if not constant_elem:
|
||||||
constant_elem = middle_child.xpath(
|
constant_elem = middle_child.xpath(
|
||||||
"./st:Constant", namespaces=ns
|
"./Constant"
|
||||||
)
|
)
|
||||||
if not constant_elem:
|
|
||||||
constant_elem = middle_child.xpath(
|
|
||||||
"./Constant"
|
|
||||||
)
|
|
||||||
|
|
||||||
if constant_elem:
|
if constant_elem:
|
||||||
# Buscar ConstantValue tanto con namespace como sin namespace
|
# Buscar ConstantValue tanto con namespace como sin namespace
|
||||||
|
val_nodes = constant_elem[0].xpath(
|
||||||
|
"./st:ConstantValue", namespaces=ns
|
||||||
|
)
|
||||||
|
if not val_nodes:
|
||||||
val_nodes = constant_elem[0].xpath(
|
val_nodes = constant_elem[0].xpath(
|
||||||
"./st:ConstantValue", namespaces=ns
|
"./ConstantValue"
|
||||||
)
|
)
|
||||||
if not val_nodes:
|
|
||||||
val_nodes = constant_elem[0].xpath(
|
|
||||||
"./ConstantValue"
|
|
||||||
)
|
|
||||||
|
|
||||||
if val_nodes and val_nodes[0].text:
|
if val_nodes and val_nodes[0].text:
|
||||||
indices_parts.append(
|
indices_parts.append(
|
||||||
val_nodes[0].text.strip()
|
val_nodes[0].text.strip()
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
# Para otros tipos de acceso, procesar manualmente en lugar de recursión
|
# Para otros tipos de acceso, procesar manualmente en lugar de recursión
|
||||||
if (
|
if middle_child.get("Scope") == "LocalVariable":
|
||||||
middle_child.get("Scope")
|
# Procesar LocalVariable manualmente
|
||||||
== "LocalVariable"
|
symbol_elem = middle_child.xpath(
|
||||||
):
|
"./st:Symbol", namespaces=ns
|
||||||
# Procesar LocalVariable manualmente
|
)
|
||||||
|
if not symbol_elem:
|
||||||
symbol_elem = middle_child.xpath(
|
symbol_elem = middle_child.xpath(
|
||||||
"./st:Symbol", namespaces=ns
|
"./Symbol"
|
||||||
)
|
)
|
||||||
if not symbol_elem:
|
|
||||||
symbol_elem = middle_child.xpath(
|
|
||||||
"./Symbol"
|
|
||||||
)
|
|
||||||
|
|
||||||
if symbol_elem:
|
if symbol_elem:
|
||||||
|
components = symbol_elem[0].xpath(
|
||||||
|
"./st:Component", namespaces=ns
|
||||||
|
)
|
||||||
|
if not components:
|
||||||
components = symbol_elem[0].xpath(
|
components = symbol_elem[0].xpath(
|
||||||
"./st:Component", namespaces=ns
|
"./Component"
|
||||||
)
|
)
|
||||||
if not components:
|
|
||||||
components = symbol_elem[
|
|
||||||
0
|
|
||||||
].xpath("./Component")
|
|
||||||
|
|
||||||
# Construir la variable manualmente
|
# Construir la variable manualmente
|
||||||
var_parts = []
|
var_parts = []
|
||||||
for i, comp in enumerate(
|
for i, comp in enumerate(components):
|
||||||
components
|
name = comp.get(
|
||||||
):
|
"Name", "_ERR_COMP_"
|
||||||
name = comp.get(
|
)
|
||||||
"Name", "_ERR_COMP_"
|
if i == 0:
|
||||||
)
|
var_parts.append(
|
||||||
if i == 0:
|
f"#{name}"
|
||||||
var_parts.append(
|
) # Primer componente con #
|
||||||
f"#{name}"
|
|
||||||
) # Primer componente con #
|
|
||||||
else:
|
|
||||||
var_parts.append(
|
|
||||||
f".{name}"
|
|
||||||
) # Componentes subsecuentes con .
|
|
||||||
|
|
||||||
idx_result = "".join(var_parts)
|
|
||||||
if idx_result:
|
|
||||||
indices_parts.append(idx_result)
|
|
||||||
else:
|
else:
|
||||||
indices_parts.append(
|
var_parts.append(
|
||||||
"/*_ERR_EMPTY_VAR_*/"
|
f".{name}"
|
||||||
)
|
) # Componentes subsecuentes con .
|
||||||
|
|
||||||
|
idx_result = "".join(var_parts)
|
||||||
|
if idx_result:
|
||||||
|
indices_parts.append(idx_result)
|
||||||
else:
|
else:
|
||||||
indices_parts.append(
|
indices_parts.append(
|
||||||
"/*_ERR_NO_SYMBOL_*/"
|
"/*_ERR_EMPTY_VAR_*/"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
# Para otros scopes, usar recursión como fallback
|
indices_parts.append(
|
||||||
idx_result = (
|
"/*_ERR_NO_SYMBOL_*/"
|
||||||
reconstruct_scl_from_tokens(
|
|
||||||
middle_child
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
if idx_result and idx_result.strip():
|
else:
|
||||||
indices_parts.append(
|
# Para otros scopes, usar recursión como fallback
|
||||||
idx_result.strip()
|
idx_result = reconstruct_scl_from_tokens(
|
||||||
)
|
middle_child
|
||||||
else:
|
)
|
||||||
indices_parts.append(
|
if idx_result and idx_result.strip():
|
||||||
"/*_ERR_RECURSIVE_EMPTY_*/"
|
indices_parts.append(idx_result.strip())
|
||||||
)
|
else:
|
||||||
elif child_tag == "Token":
|
indices_parts.append(
|
||||||
# Token de separación (como ",")
|
"/*_ERR_RECURSIVE_EMPTY_*/"
|
||||||
token_text = middle_child.get("Text", "")
|
)
|
||||||
if token_text.strip():
|
elif child_tag == "Token":
|
||||||
indices_parts.append(token_text)
|
# Token de separación (como ",")
|
||||||
|
token_text = middle_child.get("Text", "")
|
||||||
|
if token_text.strip():
|
||||||
|
indices_parts.append(token_text)
|
||||||
|
|
||||||
if indices_parts:
|
if indices_parts:
|
||||||
symbol_text_parts.append(
|
symbol_text_parts.append(f"[{','.join(indices_parts)}]")
|
||||||
f"[{','.join(indices_parts)}]"
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
# No es acceso de array, buscar Access anidados de la forma tradicional
|
# No es acceso de array, buscar Access anidados de la forma tradicional
|
||||||
index_access_nodes = comp.xpath(
|
index_access_nodes = comp.xpath(
|
||||||
|
|
Loading…
Reference in New Issue