import sys import os import re import xml.etree.ElementTree as ET from generateVars import map_type_to_pt, get_iq_define, type_map from enum import IntEnum from scanVars import * from generateVars import * def make_absolute_path(path, base_path): if not os.path.isabs(path) and os.path.isdir(base_path): try: return os.path.abspath(os.path.join(base_path, path)) except Exception: pass # На случай сбоя в os.path.join или abspath elif os.path.isabs(path): return os.path.abspath(path) else: return path def make_relative_path(abs_path, base_path): abs_path = os.path.abspath(abs_path) base_path = os.path.abspath(base_path) # Разбиваем на списки директорий abs_parts = abs_path.split(os.sep) base_parts = base_path.split(os.sep) # Проверяем, является ли base_path настоящим префиксом пути (по папкам) if abs_parts[:len(base_parts)] == base_parts: rel_parts = abs_parts[len(base_parts):] return "/".join(rel_parts) # Иначе пробуем relpath try: return os.path.relpath(abs_path, base_path).replace("\\", "/") except Exception: return abs_path.replace("\\", "/") def parse_vars(filename, typedef_map=None): root, tree = safe_parse_xml(filename) if root is None: return [] if typedef_map is None: typedef_map = {} vars_list = [] variables_elem = root.find('variables') if variables_elem is not None: for var in variables_elem.findall('var'): name = var.attrib.get('name', '') var_type = var.findtext('type', 'unknown').strip() # Вычисляем pt_type и iq_type pt_type = var.findtext('pt_type') if not pt_type: pt_type = map_type_to_pt(var_type, name, typedef_map) iq_type = var.findtext('iq_type') if not iq_type: iq_type = get_iq_define(var_type) # Записываем iq_type в XML iq_type_elem = var.find('iq_type') if iq_type_elem is None: iq_type_elem = ET.SubElement(var, 'iq_type') iq_type_elem.text = iq_type # Вычисляем pt_type и iq_type pt_type = var.findtext('pt_type') if not pt_type: pt_type = map_type_to_pt(var_type, name, typedef_map) # Записываем pt_type в XML pt_type_elem = var.find('pt_type') if pt_type_elem is None: pt_type_elem = ET.SubElement(var, 'pt_type') pt_type_elem.text = pt_type vars_list.append({ 'name': name, 'show_var': var.findtext('show_var', 'false'), 'enable': var.findtext('enable', 'false'), 'shortname': var.findtext('shortname', name), 'pt_type': pt_type, 'iq_type': iq_type, 'return_type': var.findtext('return_type', 'int'), 'type': var_type, 'file': var.findtext('file', ''), 'extern': var.findtext('extern', 'false') == 'true', 'static': var.findtext('static', 'false') == 'true', }) indent_xml(root) ET.ElementTree(root).write(filename, encoding="utf-8", xml_declaration=True) return vars_list # 2. Парсим structSup.xml def parse_structs(filename): root, tree = safe_parse_xml(filename) if root is None: return {}, {} structs = {} typedef_map = {} def parse_struct_element(elem): fields = {} for field in elem.findall("field"): fname = field.attrib.get("name") ftype = field.attrib.get("type", "") # Проверка на вложенную структуру nested_struct_elem = field.find("struct") if nested_struct_elem is not None: # Рекурсивно парсим вложенную структуру и вставляем её как подсловарь nested_fields = parse_struct_element(nested_struct_elem) # Оборачиваем в dict с ключом 'type' для хранения типа из XML fields[fname] = { 'type': ftype, # здесь тип, например "BENDER_ERROR" **nested_fields # развёрнутые поля вложенной структуры } else: # Обычное поле fields[fname] = ftype return fields structs_elem = root.find("structs") if structs_elem is not None: for struct in structs_elem.findall("struct"): name = struct.attrib.get("name") if name and name not in structs: fields = parse_struct_element(struct) structs[name] = fields # typedefs без изменений typedefs_elem = root.find("typedefs") if typedefs_elem is not None: for typedef in typedefs_elem.findall("typedef"): name = typedef.attrib.get('name') target_type = typedef.attrib.get('type') if name and target_type: typedef_map[name.strip()] = target_type.strip() return structs, typedef_map def safe_parse_xml(xml_path): """ Безопасно парсит XML-файл. Возвращает кортеж (root, tree) или (None, None) при ошибках. """ if not xml_path or not os.path.isfile(xml_path): #print(f"Файл '{xml_path}' не найден или путь пустой") return None, None try: if os.path.getsize(xml_path) == 0: return None, None tree = ET.parse(xml_path) root = tree.getroot() return root, tree except ET.ParseError as e: print(f"Ошибка парсинга XML файла '{xml_path}': {e}") return None, None except Exception as e: print(f"Неожиданная ошибка при чтении XML файла '{xml_path}': {e}") return None, None def expand_struct_recursively(prefix, type_str, structs, typedefs, var_attrs, depth=0): if depth > 10: return [] # Если type_str — словарь структуры if isinstance(type_str, dict): fields = type_str else: base_type = strip_ptr_and_array(type_str) fields = structs.get(base_type) if not isinstance(fields, dict): return [] children = [] for field_name, field_value in fields.items(): # Пропускаем поле 'type', оно служит для хранения имени типа if field_name == 'type': continue # Определяем разделитель между prefix и полем if prefix.endswith('*'): separator = '->' # Для красоты можно убрать пробелы у указателя # например, если prefix="ptr*" -> "ptr->field" full_name = f"{prefix[:-1]}{separator}{field_name}" else: separator = '.' full_name = f"{prefix}{separator}{field_name}" if isinstance(field_value, dict): # Если вложенная структура — берем её имя типа из поля 'type' или пустую строку type_name = field_value.get('type', '') child = { 'name': full_name, 'type': type_name, 'pt_type': '', 'iq_type': '', 'return_type': '', 'file': var_attrs.get('file'), 'extern': var_attrs.get('extern'), 'static': var_attrs.get('static'), } if '*' in type_name and not full_name.endswith('*'): full_name += '*' # Рекурсивно раскрываем вложенные поля subchildren = expand_struct_recursively(full_name, field_value, structs, typedefs, var_attrs, depth + 1) if subchildren: child['children'] = subchildren else: # Простое поле — строка типа # Пропускаем указатели на функции if isinstance(field_value, str) and "(" in field_value and "*" in field_value and ")" in field_value: continue child = { 'name': full_name, 'type': field_value, 'pt_type': '', 'iq_type': '', 'return_type': '', 'file': var_attrs.get('file'), 'extern': var_attrs.get('extern'), 'static': var_attrs.get('static'), } children.append(child) return children def expand_vars(vars_list, structs, typedefs): """ Раскрывает структуры и массивы структур в деревья. """ expanded = [] for var in vars_list: pt_type = var.get('pt_type', '') raw_type = var.get('type', '') base_type = strip_ptr_and_array(raw_type) fields = structs.get(base_type) if pt_type.startswith('pt_ptr_') and isinstance(fields, dict): new_var = var.copy() new_var['children'] = expand_struct_recursively(var['name']+'*', raw_type, structs, typedefs, var) expanded.append(new_var) if pt_type.startswith('pt_arr_') and isinstance(fields, dict): new_var = var.copy() new_var['children'] = expand_struct_recursively(var['name'], raw_type, structs, typedefs, var) expanded.append(new_var) elif pt_type == 'pt_struct' and isinstance(fields, dict): new_var = var.copy() new_var['children'] = expand_struct_recursively(var['name'], raw_type, structs, typedefs, var) expanded.append(new_var) elif pt_type == 'pt_union' and isinstance(fields, dict): new_var = var.copy() new_var['children'] = expand_struct_recursively(var['name'], raw_type, structs, typedefs, var) expanded.append(new_var) else: expanded.append(var) return expanded