#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Convertidor simplificado de LAD TwinCAT a pseudocódigo estructurado """ import re class SimpleLadConverter: """Convertidor simplificado de LAD a código estructurado""" def __init__(self): self.networks = [] self.current_network_id = 0 def parse_file(self, file_path): """Parse el archivo LAD""" with open(file_path, 'r', encoding='utf-8', errors='ignore') as f: content = f.read() # Encontrar sección LAD lad_start = content.find('_LD_BODY') if lad_start == -1: print("No se encontró _LD_BODY") return # Extraer contenido LAD lines = content[lad_start:].split('\n') self._parse_networks(lines) def _parse_networks(self, lines): """Parse todas las redes""" i = 0 while i < len(lines): if lines[i].strip() == '_NETWORK': self.current_network_id += 1 i = self._parse_network(lines, i) else: i += 1 def _parse_network(self, lines, start_idx): """Parse una red individual""" network = { 'id': self.current_network_id, 'comment': '', 'contacts': [], 'assignments': [], 'outputs': [] } i = start_idx + 1 # Parse comentario if i < len(lines) and lines[i].strip() == '_COMMENT': i, comment = self._parse_comment(lines, i) network['comment'] = comment # Parse contenido de la red current_assignment = { 'conditions': [], 'target': '', 'expression': '', 'function_block': '', 'operator': '', 'operands': [] } while i < len(lines): line = lines[i].strip() if line == '_NETWORK': break elif line == '_LD_ASSIGN': if current_assignment['target'] or current_assignment['function_block']: network['assignments'].append(current_assignment.copy()) current_assignment = { 'conditions': [], 'target': '', 'expression': '', 'function_block': '', 'operator': '', 'operands': [] } i += 1 elif line == '_LD_CONTACT': i += 1 if i < len(lines): contact_name = lines[i].strip() i += 1 negated = False if i < len(lines) and lines[i].strip() == '_NEGATIV': negated = True i += 1 current_assignment['conditions'].append({ 'name': contact_name, 'negated': negated }) elif line.startswith('_FUNCTIONBLOCK'): i += 1 if i < len(lines): current_assignment['function_block'] = lines[i].strip() i += 1 elif line.startswith('_OPERATOR'): i += 1 # Buscar operador y operandos while i < len(lines) and not lines[i].strip().startswith('_OUTPUT'): subline = lines[i].strip() if subline in ['ADD', 'SUB', 'MUL', 'DIV', 'AND', 'OR', 'LT', 'GT', 'EQ', 'SEL', 'MOVE']: current_assignment['operator'] = subline elif subline.startswith('_OPERAND'): i += 2 # Saltar _EXPRESSION y _POSITIV if i < len(lines): operand = lines[i].strip() current_assignment['operands'].append(operand) i += 1 continue elif line.startswith('_OUTPUT'): # Buscar variable de salida i += 1 while i < len(lines) and lines[i].strip().startswith('_'): i += 1 if i < len(lines): current_assignment['target'] = lines[i].strip() i += 1 elif not line.startswith('_') and line and 'ENABLELIST' not in line: if not current_assignment['expression']: current_assignment['expression'] = line i += 1 else: i += 1 # Agregar última asignación si existe if current_assignment['target'] or current_assignment['function_block']: network['assignments'].append(current_assignment) self.networks.append(network) return i def _parse_comment(self, lines, start_idx): """Parse comentario""" i = start_idx + 1 comment_lines = [] while i < len(lines): line = lines[i].strip() if line == '_END_COMMENT': break if line and not line.startswith('_'): comment_lines.append(line) i += 1 return i + 1, ' '.join(comment_lines) def convert_to_structured(self): """Convertir a código estructurado""" output = [] output.append("// Código pseudo estructurado generado desde LAD TwinCAT") output.append("// Compatible con IEC61131-3") output.append("PROGRAM Input_Converted") output.append("") for network in self.networks: output.append(f" // Red {network['id']}") if network['comment']: output.append(f" // {network['comment']}") for assignment in network['assignments']: structured_line = self._convert_assignment(assignment) if structured_line: if assignment['conditions']: # Construir condición conditions = [] for cond in assignment['conditions']: if cond['negated']: conditions.append(f"NOT {cond['name']}") else: conditions.append(cond['name']) condition_str = " AND ".join(conditions) output.append(f" IF {condition_str} THEN") output.append(f" {structured_line};") output.append(" END_IF;") else: output.append(f" {structured_line};") output.append("") output.append("END_PROGRAM") return '\n'.join(output) def _convert_assignment(self, assignment): """Convertir una asignación a código estructurado""" target = assignment['target'] expression = assignment['expression'] function_block = assignment['function_block'] operator = assignment['operator'] operands = assignment['operands'] if function_block: params = ", ".join(operands) if operands else "" if target: return f"{target} := {function_block}({params})" else: return f"{function_block}({params})" elif operator and operands: if len(operands) >= 2: if operator == "SEL": return f"{target} := SEL({operands[0]}, {operands[1]}, condition)" else: return f"{target} := {operands[0]} {operator} {operands[1]}" elif len(operands) == 1: if operator == "MOVE": return f"{target} := {operands[0]}" else: return f"{target} := {operator}({operands[0]})" elif expression and target: return f"{target} := {expression}" return None def save_to_file(self, output_path): """Guardar código estructurado""" structured_code = self.convert_to_structured() with open(output_path, 'w', encoding='utf-8') as f: f.write(structured_code) print(f"Código guardado en: {output_path}") return structured_code def main(): """Función principal""" converter = SimpleLadConverter() try: print("=== Convertidor LAD Simplificado ===") print("Parseando archivo INPUT.EXP...") converter.parse_file(".example/_PUMPCONTROL.EXP") print(f"Redes encontradas: {len(converter.networks)}") # Mostrar algunas estadísticas for i, network in enumerate(converter.networks[:5]): print(f"Red {network['id']}: {len(network['assignments'])} asignaciones") if network['comment']: print(f" Comentario: {network['comment']}") # Convertir y guardar print("\nGenerando código estructurado...") structured_code = converter.save_to_file("simple_output.txt") # Mostrar primeras líneas lines = structured_code.split('\n') print(f"\nPrimeras {min(30, len(lines))} líneas:") for i, line in enumerate(lines[:30]): print(f"{i+1:3d}: {line}") print(f"\n✓ Conversión completada! Total de líneas: {len(lines)}") except Exception as e: print(f"Error: {e}") import traceback traceback.print_exc() if __name__ == "__main__": main()