Se modificó el script `x1_lad_converter.py` para cambiar el manejo de los objetivos de red, pasando de un solo objetivo a una lista de objetivos. Se implementaron mejoras en la lógica de análisis de redes, permitiendo la recopilación de múltiples salidas y optimizando la generación de código SCL. Además, se actualizaron los mensajes de depuración y se mejoró la estructura del código para una mayor claridad y mantenimiento.
This commit is contained in:
parent
ffc686e140
commit
164667bc2f
|
@ -366,7 +366,7 @@ class SimpleLadConverter:
|
||||||
"id": self.current_network_id,
|
"id": self.current_network_id,
|
||||||
"comment": "",
|
"comment": "",
|
||||||
"logic": None,
|
"logic": None,
|
||||||
"target": "",
|
"targets": [],
|
||||||
"calls": [], # NUEVO: para almacenar llamadas a FB/FUN
|
"calls": [], # NUEVO: para almacenar llamadas a FB/FUN
|
||||||
"function_blocks": [],
|
"function_blocks": [],
|
||||||
}
|
}
|
||||||
|
@ -417,13 +417,31 @@ class SimpleLadConverter:
|
||||||
# Continuar buscando
|
# Continuar buscando
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
|
elif line.startswith("_OUTPUTS"):
|
||||||
|
num_outputs = int(line.split(":")[1].strip())
|
||||||
|
i += 1
|
||||||
|
for _ in range(num_outputs):
|
||||||
|
while i < len(lines) and not lines[i].strip().startswith("_OUTPUT"):
|
||||||
|
i += 1
|
||||||
|
if i >= len(lines):
|
||||||
|
break
|
||||||
|
i += 1 # past _OUTPUT
|
||||||
|
|
||||||
|
while i < len(lines) and lines[i].strip().startswith("_"): # flags
|
||||||
|
i += 1
|
||||||
|
if i < len(lines):
|
||||||
|
var_name = lines[i].strip()
|
||||||
|
if var_name:
|
||||||
|
network["targets"].append(var_name)
|
||||||
|
i += 1
|
||||||
|
|
||||||
elif line.startswith("_OUTPUT"):
|
elif line.startswith("_OUTPUT"):
|
||||||
# Buscar variable de salida
|
# Buscar variable de salida
|
||||||
i += 1
|
i += 1
|
||||||
while i < len(lines) and lines[i].strip().startswith("_"):
|
while i < len(lines) and lines[i].strip().startswith("_"):
|
||||||
i += 1
|
i += 1
|
||||||
if i < len(lines) and lines[i].strip() and "ENABLELIST" not in lines[i]:
|
if i < len(lines) and lines[i].strip() and "ENABLELIST" not in lines[i]:
|
||||||
network["target"] = lines[i].strip()
|
network["targets"].append(lines[i].strip())
|
||||||
i += 1
|
i += 1
|
||||||
else:
|
else:
|
||||||
i += 1
|
i += 1
|
||||||
|
@ -442,7 +460,7 @@ class SimpleLadConverter:
|
||||||
print(f" 🎯 Función reconocida: {call['name']}")
|
print(f" 🎯 Función reconocida: {call['name']}")
|
||||||
else:
|
else:
|
||||||
print(f" 📋 Llamada: {call['type']} - {call['name']}")
|
print(f" 📋 Llamada: {call['type']} - {call['name']}")
|
||||||
print(f" Target: '{network['target']}'")
|
print(f" Targets: '{network['targets']}'")
|
||||||
return i
|
return i
|
||||||
|
|
||||||
def _parse_lad_expression(self, lines, start_idx):
|
def _parse_lad_expression(self, lines, start_idx):
|
||||||
|
@ -1030,7 +1048,7 @@ class SimpleLadConverter:
|
||||||
"id": self.current_network_id,
|
"id": self.current_network_id,
|
||||||
"comment": f'Llamada a función: {function_logic.get("name", "unknown")}',
|
"comment": f'Llamada a función: {function_logic.get("name", "unknown")}',
|
||||||
"logic": function_logic,
|
"logic": function_logic,
|
||||||
"target": target_name,
|
"targets": [target_name],
|
||||||
"function_blocks": [],
|
"function_blocks": [],
|
||||||
"calls": [function_logic], # ✅ Añadir la llamada al array calls
|
"calls": [function_logic], # ✅ Añadir la llamada al array calls
|
||||||
}
|
}
|
||||||
|
@ -1134,18 +1152,19 @@ class SimpleLadConverter:
|
||||||
if condition_str:
|
if condition_str:
|
||||||
output.append(" END_IF;")
|
output.append(" END_IF;")
|
||||||
|
|
||||||
elif network["target"]:
|
elif network["targets"]:
|
||||||
# Red sin llamadas pero con target
|
# Red sin llamadas pero con target(s)
|
||||||
if condition_str:
|
if condition_str:
|
||||||
output.append(f" IF {condition_str} THEN")
|
output.append(f" IF {condition_str} THEN")
|
||||||
output.append(f" {network['target']} := TRUE;")
|
for target in network["targets"]:
|
||||||
|
output.append(f" {target} := TRUE;")
|
||||||
output.append(" ELSE")
|
output.append(" ELSE")
|
||||||
output.append(f" {network['target']} := FALSE;")
|
for target in network["targets"]:
|
||||||
|
output.append(f" {target} := FALSE;")
|
||||||
output.append(" END_IF;")
|
output.append(" END_IF;")
|
||||||
else:
|
else:
|
||||||
output.append(
|
for target in network["targets"]:
|
||||||
f" {network['target']} := TRUE; // Sin condición"
|
output.append(f" {target} := TRUE; // Sin condición")
|
||||||
)
|
|
||||||
|
|
||||||
output.append("")
|
output.append("")
|
||||||
|
|
||||||
|
@ -1301,6 +1320,8 @@ class SimpleLadConverter:
|
||||||
# Asegurar que el campo 'calls' existe
|
# Asegurar que el campo 'calls' existe
|
||||||
if "calls" not in network:
|
if "calls" not in network:
|
||||||
network["calls"] = []
|
network["calls"] = []
|
||||||
|
if "targets" not in network:
|
||||||
|
network["targets"] = []
|
||||||
|
|
||||||
output.append(f" // Red {network['id']}")
|
output.append(f" // Red {network['id']}")
|
||||||
if network["comment"]:
|
if network["comment"]:
|
||||||
|
@ -1325,18 +1346,21 @@ class SimpleLadConverter:
|
||||||
call_str = self._convert_call_to_string(call, indent)
|
call_str = self._convert_call_to_string(call, indent)
|
||||||
output.append(call_str)
|
output.append(call_str)
|
||||||
|
|
||||||
elif network["target"]:
|
elif network["targets"]:
|
||||||
output.append(f"{indent}{network['target']} := TRUE;")
|
for target in network["targets"]:
|
||||||
|
output.append(f"{indent}{target} := TRUE;")
|
||||||
|
|
||||||
if condition_str:
|
if condition_str:
|
||||||
if not network_calls and network["target"]:
|
if not network_calls and network["targets"]:
|
||||||
output.append(" ELSE")
|
output.append(" ELSE")
|
||||||
output.append(f" {network['target']} := FALSE;")
|
for target in network["targets"]:
|
||||||
|
output.append(f" {target} := FALSE;")
|
||||||
output.append(" END_IF;")
|
output.append(" END_IF;")
|
||||||
|
|
||||||
elif network["target"]:
|
elif network["targets"]:
|
||||||
|
for target in network["targets"]:
|
||||||
output.append(
|
output.append(
|
||||||
f" {network['target']} := TRUE; // Sin condición, solo target"
|
f" {target} := TRUE; // Sin condición, solo target"
|
||||||
)
|
)
|
||||||
|
|
||||||
output.append("")
|
output.append("")
|
||||||
|
@ -1461,7 +1485,7 @@ class SimpleLadConverter:
|
||||||
print(f"\nRed {network['id']}:")
|
print(f"\nRed {network['id']}:")
|
||||||
if network["comment"]:
|
if network["comment"]:
|
||||||
print(f" Comentario: {network['comment']}")
|
print(f" Comentario: {network['comment']}")
|
||||||
print(f" Target: {network['target']}")
|
print(f" Targets: {network['targets']}")
|
||||||
|
|
||||||
if network["logic"]:
|
if network["logic"]:
|
||||||
print(f" Lógica: {self._debug_logic_string(network['logic'])}")
|
print(f" Lógica: {self._debug_logic_string(network['logic'])}")
|
||||||
|
@ -1652,7 +1676,7 @@ class SimpleLadConverter:
|
||||||
for network in self.networks:
|
for network in self.networks:
|
||||||
if (
|
if (
|
||||||
network["logic"]
|
network["logic"]
|
||||||
and network["target"]
|
and network["targets"]
|
||||||
and network["id"] in self.sympy_expressions
|
and network["id"] in self.sympy_expressions
|
||||||
):
|
):
|
||||||
groupable_networks.append(network)
|
groupable_networks.append(network)
|
||||||
|
@ -1892,45 +1916,57 @@ class SimpleLadConverter:
|
||||||
print(f"Total ACTIONs: {len(self.actions)}")
|
print(f"Total ACTIONs: {len(self.actions)}")
|
||||||
|
|
||||||
def _parse_action_lad(self, action_name, action_content):
|
def _parse_action_lad(self, action_name, action_content):
|
||||||
"""Parsear una ACTION que contiene código LAD"""
|
# We create a completely new, isolated instance of the converter to parse the action's LAD code.
|
||||||
# Crear un convertidor temporal para esta ACTION
|
# This prevents any state (like network counts) from leaking between the main program and the action parsing.
|
||||||
action_converter = SimpleLadConverter()
|
action_converter = SimpleLadConverter(self.function_registry)
|
||||||
action_converter.symbol_manager = self.symbol_manager # Compartir símbolos
|
|
||||||
|
|
||||||
# Encontrar sección LAD
|
# Extract just the LAD body from the action content
|
||||||
lad_start = action_content.find("_LD_BODY")
|
lad_body_match = re.search(r"_LD_BODY(.*)", action_content, re.DOTALL)
|
||||||
if lad_start != -1:
|
if lad_body_match:
|
||||||
# Extraer contenido LAD hasta el final
|
lad_content = lad_body_match.group(1)
|
||||||
lad_content = action_content[lad_start:]
|
lines = lad_content.strip().split("\n")
|
||||||
lines = lad_content.split("\n")
|
|
||||||
|
# The parse_networks method will process all networks it finds in the provided lines.
|
||||||
action_converter._parse_networks(lines)
|
action_converter._parse_networks(lines)
|
||||||
|
|
||||||
return {
|
# The parsed networks are stored in the temporary converter's `networks` list.
|
||||||
"type": "LAD",
|
# We return this list as the logic for the action.
|
||||||
"networks": action_converter.networks,
|
return {"type": "LAD", "networks": action_converter.networks}
|
||||||
"raw_content": action_content,
|
|
||||||
}
|
# If no LAD body is found, return an empty structure.
|
||||||
|
return {"type": "LAD", "networks": []}
|
||||||
|
|
||||||
def _extract_st_code(self, content):
|
def _extract_st_code(self, content):
|
||||||
"""Extraer código ST del programa principal"""
|
"""Extraer código ST del programa principal"""
|
||||||
# Buscar desde después de END_VAR hasta ACTION o END_PROGRAM
|
# Buscar desde después de END_VAR hasta ACTION o END_PROGRAM
|
||||||
var_end = content.rfind("END_VAR")
|
var_end_match = re.search(r"END_VAR", content)
|
||||||
if var_end == -1:
|
if not var_end_match:
|
||||||
|
self.st_main_code = None
|
||||||
return
|
return
|
||||||
|
|
||||||
# Buscar el final del código principal
|
start_index = var_end_match.end()
|
||||||
action_start = content.find("\nACTION", var_end)
|
|
||||||
end_program = content.find("\nEND_PROGRAM", var_end)
|
|
||||||
|
|
||||||
code_end = action_start if action_start != -1 else end_program
|
# Buscar el final del código principal
|
||||||
if code_end == -1:
|
action_start_match = re.search(r"\nACTION", content[start_index:])
|
||||||
code_end = len(content)
|
end_program_match = re.search(r"\nEND_PROGRAM", content[start_index:])
|
||||||
|
|
||||||
|
end_index = -1
|
||||||
|
|
||||||
|
if action_start_match:
|
||||||
|
end_index = start_index + action_start_match.start()
|
||||||
|
|
||||||
|
if end_program_match:
|
||||||
|
program_end = start_index + end_program_match.start()
|
||||||
|
if end_index == -1 or program_end < end_index:
|
||||||
|
end_index = program_end
|
||||||
|
|
||||||
|
if end_index == -1:
|
||||||
|
end_index = len(content)
|
||||||
|
|
||||||
# Extraer código ST
|
# Extraer código ST
|
||||||
st_code = content[var_end + 7 : code_end].strip() # +7 para saltar "END_VAR"
|
st_code = content[start_index:end_index].strip()
|
||||||
|
|
||||||
if st_code:
|
if st_code:
|
||||||
# Almacenar código ST para usar en la generación
|
|
||||||
self.st_main_code = st_code
|
self.st_main_code = st_code
|
||||||
print(f"Código ST principal extraído: {len(st_code)} caracteres")
|
print(f"Código ST principal extraído: {len(st_code)} caracteres")
|
||||||
else:
|
else:
|
||||||
|
@ -2121,144 +2157,132 @@ def collect_function_interfaces(input_directory, debug_mode=False):
|
||||||
return function_registry, function_files
|
return function_registry, function_files
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def run_debug_mode(debug_file_arg):
|
||||||
"""Función principal - Convierte todos los archivos .EXP a .SCL con dos pasadas"""
|
"""Ejecuta el convertidor en modo debug para un solo archivo."""
|
||||||
try:
|
|
||||||
import time
|
|
||||||
|
|
||||||
timestamp = time.strftime("%Y-%m-%d %H:%M:%S")
|
|
||||||
print("=== SCRIPT VERIFICADO Y EJECUTÁNDOSE CORRECTAMENTE ===")
|
|
||||||
print(f"🕒 Timestamp: {timestamp}")
|
|
||||||
print("=== INICIANDO CONVERTIDOR SCRIPT (2 PASADAS) ===")
|
|
||||||
|
|
||||||
# Verificar si se pasó un archivo específico como parámetro para debug
|
|
||||||
debug_file = None
|
|
||||||
if len(sys.argv) > 1:
|
|
||||||
debug_file = sys.argv[1]
|
|
||||||
print(f"=== MODO DEBUG: Procesando archivo específico ===")
|
print(f"=== MODO DEBUG: Procesando archivo específico ===")
|
||||||
print(f"Archivo: {debug_file}")
|
print(f"Archivo: {debug_file_arg}")
|
||||||
print("🔧 VERIFICACIÓN: Script modificado y ejecutándose en tiempo real")
|
print("🔧 VERIFICACIÓN: Script modificado y ejecutándose en tiempo real")
|
||||||
|
|
||||||
|
# Determinar el path absoluto del archivo de debug.
|
||||||
|
# Esto permite que el script se ejecute desde cualquier lugar.
|
||||||
|
debug_file_path = os.path.abspath(debug_file_arg)
|
||||||
|
|
||||||
|
if not debug_file_path.endswith(".EXP"):
|
||||||
|
debug_file_path += ".EXP"
|
||||||
|
|
||||||
|
if not os.path.exists(debug_file_path):
|
||||||
|
print(f"Error: No se encontró el archivo de debug: {debug_file_path}")
|
||||||
|
# Intenta buscarlo en el directorio relativo ExportTwinCat por si acaso
|
||||||
|
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
export_dir_path = os.path.join(
|
||||||
|
script_dir, "..", "ExportTwinCat", os.path.basename(debug_file_path)
|
||||||
|
)
|
||||||
|
if os.path.exists(export_dir_path):
|
||||||
|
debug_file_path = os.path.abspath(export_dir_path)
|
||||||
|
print(f"Archivo encontrado en path alternativo: {debug_file_path}")
|
||||||
else:
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
|
# El directorio de entrada y salida es el del archivo de debug
|
||||||
|
input_directory = os.path.dirname(debug_file_path)
|
||||||
|
scl_output_dir = input_directory
|
||||||
|
|
||||||
|
print(f"Directorio de análisis para interfaces: {input_directory}")
|
||||||
|
print(f"Directorio de salida para .SCL: {scl_output_dir}")
|
||||||
|
|
||||||
|
# PRIMERA PASADA: Recopilar interfaces de TODOS los archivos .EXP en el directorio
|
||||||
|
function_registry, _ = collect_function_interfaces(input_directory, debug_mode=True)
|
||||||
|
|
||||||
|
if function_registry.functions or function_registry.function_blocks:
|
||||||
|
print("\n🔧 REGISTRY DE FUNCIONES PARA EL DEBUG:")
|
||||||
|
function_registry.print_summary()
|
||||||
|
|
||||||
|
# SEGUNDA PASADA: Procesar solo el archivo de debug
|
||||||
|
print("\n=== SEGUNDA PASADA (DEBUG): CONVIRTIENDO ARCHIVO ÚNICO ===")
|
||||||
|
filename = os.path.basename(debug_file_path)
|
||||||
|
base_name = os.path.splitext(filename)[0]
|
||||||
|
scl_filename = f"{base_name}.scl"
|
||||||
|
scl_output_path = os.path.join(scl_output_dir, scl_filename)
|
||||||
|
|
||||||
|
print(f"{'='*60}")
|
||||||
|
print(f"Procesando: {filename}")
|
||||||
|
print(f"Salida: {scl_output_path}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
converter = SimpleLadConverter(function_registry)
|
||||||
|
converter.parse_file(debug_file_path)
|
||||||
|
|
||||||
|
print(f" ✓ Redes encontradas: {len(converter.networks)}")
|
||||||
|
print(f" ✓ Secciones de variables: {list(converter.var_sections.keys())}")
|
||||||
|
print(f" ✓ ACTIONs encontradas: {list(converter.actions.keys())}")
|
||||||
|
|
||||||
|
converter.print_debug_info()
|
||||||
|
converter.optimize_expressions()
|
||||||
|
converter.group_common_conditions()
|
||||||
|
|
||||||
|
print(f" Generando código SCL...")
|
||||||
|
structured_code = converter.save_to_file(scl_output_path)
|
||||||
|
|
||||||
|
# Mostrar código por stdout como fue solicitado
|
||||||
|
print("\n\n=== CÓDIGO SCL GENERADO (STDOUT) ===")
|
||||||
|
print(structured_code)
|
||||||
|
print("====================================")
|
||||||
|
|
||||||
|
print(f"\n ✓ Guardado en: {scl_output_path}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f" ✗ Error procesando {filename}: {e}")
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
print(f"\n✓ Proceso de debug finalizado.")
|
||||||
|
|
||||||
|
|
||||||
|
def run_mass_conversion():
|
||||||
|
"""Ejecuta el convertidor en modo masivo usando la configuración global."""
|
||||||
print("=== Convertidor Masivo LAD a SCL con SymPy (2 Pasadas) ===")
|
print("=== Convertidor Masivo LAD a SCL con SymPy (2 Pasadas) ===")
|
||||||
|
|
||||||
# Cargar configuración
|
# Cargar configuración
|
||||||
configs = load_configuration()
|
configs = load_configuration()
|
||||||
|
|
||||||
# Verificar que se cargó correctamente
|
|
||||||
if not configs:
|
if not configs:
|
||||||
print(
|
print("Error: No se pudo cargar la configuración. Abortando.")
|
||||||
"Advertencia: No se pudo cargar la configuración, usando valores por defecto"
|
return
|
||||||
)
|
|
||||||
working_directory = "./"
|
|
||||||
scl_output_dir = "scl"
|
|
||||||
debug_mode = True
|
|
||||||
show_optimizations = True
|
|
||||||
show_generated_code = False
|
|
||||||
max_display_lines = 50
|
|
||||||
force_regenerate = False
|
|
||||||
level1_config = {}
|
|
||||||
level2_config = {}
|
|
||||||
level3_config = {}
|
|
||||||
else:
|
|
||||||
# Obtener configuraciones
|
# Obtener configuraciones
|
||||||
working_directory = configs.get("working_directory", "./")
|
working_directory = configs.get("working_directory", "./")
|
||||||
level1_config = configs.get("level1", {})
|
level1_config = configs.get("level1", {})
|
||||||
level2_config = configs.get("level2", {})
|
level2_config = configs.get("level2", {})
|
||||||
level3_config = configs.get("level3", {})
|
level3_config = configs.get("level3", {})
|
||||||
|
|
||||||
# Parámetros de configuración
|
|
||||||
debug_mode = level1_config.get("debug_mode", True)
|
debug_mode = level1_config.get("debug_mode", True)
|
||||||
show_optimizations = level1_config.get("show_optimizations", True)
|
show_optimizations = level1_config.get("show_optimizations", True)
|
||||||
scl_output_dir = level2_config.get("scl_output_dir", "scl")
|
scl_output_dir = level2_config.get("scl_output_dir", "scl")
|
||||||
backup_existing = level2_config.get("backup_existing", True)
|
|
||||||
show_generated_code = level2_config.get("show_generated_code", False)
|
show_generated_code = level2_config.get("show_generated_code", False)
|
||||||
max_display_lines = level2_config.get("max_display_lines", 50)
|
max_display_lines = level2_config.get("max_display_lines", 50)
|
||||||
|
force_regenerate = level2_config.get("force_regenerate", False)
|
||||||
|
input_directory = level3_config.get("twincat_exp_directory", working_directory)
|
||||||
sympy_optimization = level3_config.get("sympy_optimization", True)
|
sympy_optimization = level3_config.get("sympy_optimization", True)
|
||||||
group_analysis = level3_config.get("group_analysis", True)
|
group_analysis = level3_config.get("group_analysis", True)
|
||||||
force_regenerate = level2_config.get(
|
|
||||||
"force_regenerate", False
|
|
||||||
) # Nueva opción
|
|
||||||
|
|
||||||
# Directorio de entrada para archivos .EXP
|
|
||||||
# En modo debug, usar el directorio actual si no hay configuración específica
|
|
||||||
if debug_file:
|
|
||||||
# Modo debug: usar directorio actual donde están los archivos EXP
|
|
||||||
input_directory = os.path.dirname(os.path.abspath(__file__))
|
|
||||||
# Buscar directorio ExportTwinCat si existe
|
|
||||||
export_dir = os.path.join(input_directory, "../ExportTwinCat")
|
|
||||||
if os.path.exists(export_dir):
|
|
||||||
input_directory = os.path.abspath(export_dir)
|
|
||||||
print(f"Detectado directorio ExportTwinCat: {input_directory}")
|
|
||||||
else:
|
|
||||||
print(f"Usando directorio actual: {input_directory}")
|
|
||||||
else:
|
|
||||||
# Modo normal: usar configuración
|
|
||||||
input_directory = level3_config.get(
|
|
||||||
"twincat_exp_directory", working_directory
|
|
||||||
)
|
|
||||||
|
|
||||||
# Verificar directorio de trabajo
|
|
||||||
if not os.path.exists(working_directory):
|
if not os.path.exists(working_directory):
|
||||||
print(f"Error: El directorio de trabajo no existe: {working_directory}")
|
print(f"Error: El directorio de trabajo no existe: {working_directory}")
|
||||||
return
|
return
|
||||||
|
|
||||||
# Verificar directorio de entrada
|
|
||||||
if not os.path.exists(input_directory):
|
if not os.path.exists(input_directory):
|
||||||
print(f"Error: El directorio de entrada no existe: {input_directory}")
|
print(f"Error: El directorio de entrada no existe: {input_directory}")
|
||||||
return
|
return
|
||||||
|
|
||||||
# Crear directorio de salida SCL
|
|
||||||
full_scl_path = os.path.join(working_directory, scl_output_dir)
|
full_scl_path = os.path.join(working_directory, scl_output_dir)
|
||||||
if not os.path.exists(full_scl_path):
|
if not os.path.exists(full_scl_path):
|
||||||
os.makedirs(full_scl_path)
|
os.makedirs(full_scl_path)
|
||||||
print(f"Directorio creado: {full_scl_path}")
|
print(f"Directorio creado: {full_scl_path}")
|
||||||
|
|
||||||
# PRIMERA PASADA: Recopilar interfaces de funciones
|
# PRIMERA PASADA: Recopilar interfaces de funciones
|
||||||
# IMPORTANTE: Siempre hacer primera pasada, incluso en modo debug
|
function_registry, _ = collect_function_interfaces(input_directory, debug_mode)
|
||||||
print(f"Directorio para primera pasada: {input_directory}")
|
|
||||||
function_registry, function_files = collect_function_interfaces(
|
|
||||||
input_directory, debug_mode
|
|
||||||
)
|
|
||||||
|
|
||||||
# Determinar archivos a procesar
|
# SEGUNDA PASADA: Procesar todos los archivos
|
||||||
if debug_file:
|
|
||||||
# Modo debug - archivo específico
|
|
||||||
if not debug_file.endswith(".EXP"):
|
|
||||||
debug_file += ".EXP"
|
|
||||||
|
|
||||||
debug_file_path = os.path.join(input_directory, debug_file)
|
|
||||||
if not os.path.exists(debug_file_path):
|
|
||||||
print(f"Error: No se encontró el archivo {debug_file_path}")
|
|
||||||
return
|
|
||||||
|
|
||||||
exp_files = [debug_file_path]
|
|
||||||
print(f"🔍 MODO DEBUG ACTIVADO")
|
|
||||||
print(f"Procesando archivo específico: {debug_file}")
|
|
||||||
print(f"Directorio de entrada: {input_directory}")
|
|
||||||
print(f"Directorio de salida SCL: {full_scl_path}")
|
|
||||||
print(f"Funciones en registry: {len(function_registry.functions)}")
|
|
||||||
print(
|
|
||||||
f"Function Blocks en registry: {len(function_registry.function_blocks)}"
|
|
||||||
)
|
|
||||||
|
|
||||||
# En modo debug, forzar regeneración y mostrar más información
|
|
||||||
force_regenerate = True
|
|
||||||
debug_mode = True
|
|
||||||
show_generated_code = True
|
|
||||||
max_display_lines = 100
|
|
||||||
|
|
||||||
# Mostrar información detallada del registry en modo debug
|
|
||||||
if function_registry.functions:
|
|
||||||
print("\n🔧 FUNCIONES DETECTADAS:")
|
|
||||||
for name, func_info in function_registry.functions.items():
|
|
||||||
print(f" ✓ {name}: {func_info.return_type}")
|
|
||||||
if func_info.inputs:
|
|
||||||
print(f" IN: {[f'{n}:{t}' for n, t in func_info.inputs]}")
|
|
||||||
if func_info.outputs:
|
|
||||||
print(f" OUT: {[f'{n}:{t}' for n, t in func_info.outputs]}")
|
|
||||||
print()
|
|
||||||
else:
|
|
||||||
# Modo normal - todos los archivos
|
|
||||||
exp_pattern = os.path.join(input_directory, "*.EXP")
|
exp_pattern = os.path.join(input_directory, "*.EXP")
|
||||||
exp_files = glob.glob(exp_pattern)
|
exp_files = glob.glob(exp_pattern)
|
||||||
|
|
||||||
|
@ -2266,15 +2290,11 @@ def main():
|
||||||
print(f"No se encontraron archivos .EXP en: {input_directory}")
|
print(f"No se encontraron archivos .EXP en: {input_directory}")
|
||||||
return
|
return
|
||||||
|
|
||||||
print(f"Encontrados {len(exp_files)} archivos .EXP en: {input_directory}")
|
print(f"\nEncontrados {len(exp_files)} archivos .EXP en: {input_directory}")
|
||||||
print(f"Directorio de salida SCL: {full_scl_path}")
|
print(f"Directorio de salida SCL: {full_scl_path}")
|
||||||
|
print("\n=== SEGUNDA PASADA: CONVERSIÓN CON INTERFACES CONOCIDAS ===")
|
||||||
|
|
||||||
print()
|
successful_conversions, failed_conversions = 0, 0
|
||||||
print("=== SEGUNDA PASADA: CONVERSIÓN CON INTERFACES CONOCIDAS ===")
|
|
||||||
|
|
||||||
# Procesar cada archivo
|
|
||||||
successful_conversions = 0
|
|
||||||
failed_conversions = 0
|
|
||||||
|
|
||||||
for exp_file in exp_files:
|
for exp_file in exp_files:
|
||||||
filename = os.path.basename(exp_file)
|
filename = os.path.basename(exp_file)
|
||||||
|
@ -2282,50 +2302,29 @@ def main():
|
||||||
scl_filename = f"{base_name}.scl"
|
scl_filename = f"{base_name}.scl"
|
||||||
scl_output_path = os.path.join(full_scl_path, scl_filename)
|
scl_output_path = os.path.join(full_scl_path, scl_filename)
|
||||||
|
|
||||||
# Verificar si ya existe el archivo SCL (exportación progresiva)
|
|
||||||
if os.path.exists(scl_output_path) and not force_regenerate:
|
if os.path.exists(scl_output_path) and not force_regenerate:
|
||||||
print(f"{'='*60}")
|
|
||||||
print(f"SALTANDO: {filename} - Ya existe {scl_filename}")
|
|
||||||
print(
|
print(
|
||||||
f" (usa force_regenerate: true en configuración para forzar regeneración)"
|
f"SALTANDO: {filename} - Ya existe. (Usar 'force_regenerate: true' para sobreescribir)"
|
||||||
)
|
)
|
||||||
successful_conversions += 1 # Contar como exitoso
|
successful_conversions += 1
|
||||||
continue
|
continue
|
||||||
|
|
||||||
print(f"{'='*60}")
|
print(f"\n{'='*60}")
|
||||||
print(f"Procesando: {filename}")
|
print(f"Procesando: {filename} -> {scl_filename}")
|
||||||
print(f"Salida: {scl_filename}")
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Crear nuevo convertidor para cada archivo CON el registry de funciones
|
|
||||||
converter = SimpleLadConverter(function_registry)
|
converter = SimpleLadConverter(function_registry)
|
||||||
|
|
||||||
# Parsear archivo
|
|
||||||
converter.parse_file(exp_file)
|
converter.parse_file(exp_file)
|
||||||
|
|
||||||
print(f" ✓ Redes encontradas: {len(converter.networks)}")
|
|
||||||
print(
|
|
||||||
f" ✓ Secciones de variables: {list(converter.var_sections.keys())}"
|
|
||||||
)
|
|
||||||
print(f" ✓ ACTIONs encontradas: {list(converter.actions.keys())}")
|
|
||||||
|
|
||||||
# Mostrar información de debug si está habilitado
|
|
||||||
if debug_mode:
|
if debug_mode:
|
||||||
converter.print_debug_info()
|
converter.print_debug_info()
|
||||||
|
|
||||||
# Optimizar expresiones con SymPy si está habilitado
|
|
||||||
if sympy_optimization and show_optimizations:
|
if sympy_optimization and show_optimizations:
|
||||||
converter.optimize_expressions()
|
converter.optimize_expressions()
|
||||||
|
|
||||||
# Analizar agrupación de condiciones si está habilitado
|
|
||||||
if group_analysis and show_optimizations:
|
if group_analysis and show_optimizations:
|
||||||
converter.group_common_conditions()
|
converter.group_common_conditions()
|
||||||
|
|
||||||
# Convertir y guardar
|
|
||||||
print(f" Generando código SCL...")
|
|
||||||
structured_code = converter.save_to_file(scl_output_path)
|
structured_code = converter.save_to_file(scl_output_path)
|
||||||
|
|
||||||
# Mostrar parte del código generado si está habilitado
|
|
||||||
if show_generated_code:
|
if show_generated_code:
|
||||||
lines = structured_code.split("\n")
|
lines = structured_code.split("\n")
|
||||||
display_lines = min(max_display_lines, len(lines))
|
display_lines = min(max_display_lines, len(lines))
|
||||||
|
@ -2348,24 +2347,31 @@ def main():
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
failed_conversions += 1
|
failed_conversions += 1
|
||||||
|
|
||||||
print()
|
print(f"\n{'='*60}")
|
||||||
|
print(f"RESUMEN DE CONVERSIÓN MASIVA:")
|
||||||
# Resumen final
|
|
||||||
print(f"{'='*60}")
|
|
||||||
print(f"RESUMEN DE CONVERSIÓN:")
|
|
||||||
print(f" 📋 Funciones registradas: {len(function_registry.functions)}")
|
|
||||||
print(
|
|
||||||
f" 📋 Function Blocks registrados: {len(function_registry.function_blocks)}"
|
|
||||||
)
|
|
||||||
print(f" ✓ Exitosas: {successful_conversions}")
|
print(f" ✓ Exitosas: {successful_conversions}")
|
||||||
print(f" ✗ Fallidas: {failed_conversions}")
|
print(f" ✗ Fallidas: {failed_conversions}")
|
||||||
print(f" 📁 Directorio salida: {full_scl_path}")
|
print(f" 📁 Directorio salida: {full_scl_path}")
|
||||||
|
|
||||||
if successful_conversions > 0:
|
|
||||||
print(f"\n✓ Conversión masiva completada!")
|
def main():
|
||||||
|
"""Función principal - Despachador para modo debug o masivo."""
|
||||||
|
try:
|
||||||
|
import time
|
||||||
|
|
||||||
|
timestamp = time.strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
print("=== SCRIPT VERIFICADO Y EJECUTÁNDOSE CORRECTAMENTE ===")
|
||||||
|
print(f"🕒 Timestamp: {timestamp}")
|
||||||
|
|
||||||
|
if len(sys.argv) > 1:
|
||||||
|
# Modo debug si hay argumentos en la línea de comandos
|
||||||
|
run_debug_mode(sys.argv[1])
|
||||||
|
else:
|
||||||
|
# Modo masivo por defecto
|
||||||
|
run_mass_conversion()
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error general: {e}")
|
print(f"Error general en main: {e}")
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
5397
data/log.txt
5397
data/log.txt
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue