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 import scanVars import myXML 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 = myXML.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', ''), 'type': var_type, 'file': var.findtext('file', ''), 'extern': var.findtext('extern', 'false') == 'true', 'static': var.findtext('static', 'false') == 'true', }) myXML.fwrite(root, filename) return vars_list # 2. Парсим structSup.xml def parse_structs(filename): root, tree = myXML.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 parse_array_dims(type_str): """Возвращает базовый тип и список размеров массива""" dims = list(map(int, re.findall(r'\[(\d+)\]', type_str))) base_type = re.sub(r'\[\d+\]', '', type_str).strip() return base_type, dims def generate_array_names(prefix, dims, depth=0): """Рекурсивно генерирует имена для всех элементов многомерного массива""" if not dims: return [prefix] result = [] for i in range(dims[0]): new_prefix = f"{prefix}[{i}]" children = generate_array_names(new_prefix, dims[1:], depth + 1) result.append({ 'name': new_prefix, 'children': children if len(dims) > 1 else None }) return result def flatten_array_tree(array_tree): """Разворачивает дерево массивов в линейный список с вложенными children""" result = [] for node in array_tree: entry = {'name': node['name']} if node['children']: entry['children'] = flatten_array_tree(node['children']) result.append(entry) return result def expand_struct_recursively(prefix, type_str, structs, typedefs, var_attrs, depth=0): if depth > 10: return [] # Вспомогательная функция для обработки массивов def process_array(prefix, type_str, structs, typedefs, var_attrs, depth=0): base_type, array_dims = parse_array_dims(type_str) if not array_dims: return [] # На текущем уровне берем первый размер массива current_dim = array_dims[0] # Оставшиеся размеры — все, кроме первого remaining_dims = array_dims[1:] # Для создания типа с оставшимися размерами: if remaining_dims: # Формируем строку типа для оставшихся измерений массива, например int[16] remaining_type_str = f"{base_type}{''.join(f'[{d}]' for d in remaining_dims)}" else: remaining_type_str = base_type array_tree = [] for i in range(current_dim): name = f"{prefix}[{i}]" # Для каждого элемента передаем уже оставшийся тип массива children = expand_struct_recursively(name, remaining_type_str, structs, typedefs, var_attrs, depth + 1) node = { 'name': name, 'type': remaining_type_str if remaining_dims else base_type, 'pt_type': '', 'iq_type': '', 'return_type': '', 'file': var_attrs.get('file'), 'extern': var_attrs.get('extern'), 'static': var_attrs.get('static'), } if children: node['children'] = children array_tree.append(node) return array_tree # Если type_str — уже распарсенная структура (dict) if isinstance(type_str, dict): fields = type_str else: # Проверяем, массив ли это base_type, array_dims = parse_array_dims(type_str) if array_dims: return process_array(prefix, type_str, structs, typedefs, var_attrs, depth) # Ищем структуру по имени типа base_type = scanVars.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(): if field_name == 'type': continue # Формируем полное имя поля if prefix.endswith('*'): separator = '->' full_name = f"{prefix[:-1]}{separator}{field_name}" else: separator = '.' full_name = f"{prefix}{separator}{field_name}" # Определяем тип поля if isinstance(field_value, dict) and isinstance(field_value.get('type'), str): field_type_str = field_value['type'] elif isinstance(field_value, str): field_type_str = field_value else: field_type_str = None if '*' in field_type_str: full_name_prefix = full_name + '*' else: full_name_prefix = full_name # Обработка, если поле — строка (тип или массив) if field_type_str: base_subtype, sub_dims = parse_array_dims(field_type_str) if sub_dims: # Массив — раскрываем элементы array_parent = { 'name': full_name, 'type': field_type_str, 'pt_type': '', 'iq_type': '', 'return_type': '', 'file': var_attrs.get('file'), 'extern': var_attrs.get('extern'), 'static': var_attrs.get('static'), } array_children = [] flat_names = generate_array_names(full_name, sub_dims) for node in flat_names: # node — dict с ключом 'name' и (возможно) 'children' sub_items = expand_struct_recursively(node['name'], base_subtype, structs, typedefs, var_attrs, depth + 1) child_node = { 'name': node['name'], 'type': base_subtype, 'pt_type': '', 'iq_type': '', 'return_type': '', 'file': var_attrs.get('file'), 'extern': var_attrs.get('extern'), 'static': var_attrs.get('static'), } if sub_items: child_node['children'] = sub_items array_children.append(child_node) array_parent['children'] = array_children children.append(array_parent) continue # Игнорируем указатели на функции if "(" in field_type_str and "*" in field_type_str and ")" in field_type_str: continue if isinstance(field_value, dict): # Это одиночная структура — раскрываем рекурсивно sub_items = expand_struct_recursively(full_name_prefix, field_value, structs, typedefs, var_attrs, depth + 1) child = { 'name': full_name, 'type': field_type_str, 'pt_type': '', 'iq_type': '', 'return_type': '', 'file': var_attrs.get('file'), 'extern': var_attrs.get('extern'), 'static': var_attrs.get('static'), } if sub_items: child['children'] = sub_items children.append(child) else: # Обычное поле (int, float, etc.) child = { 'name': full_name, 'type': field_type_str, 'pt_type': '', 'iq_type': '', 'return_type': '', 'file': var_attrs.get('file'), 'extern': var_attrs.get('extern'), 'static': var_attrs.get('static'), } children.append(child) continue # Если поле — dict без 'type' или со сложной структурой, обрабатываем как вложенную структуру if isinstance(field_value, dict): 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'), } subchildren = expand_struct_recursively(full_name_prefix, field_value, structs, typedefs, var_attrs, depth + 1) if subchildren: child['children'] = subchildren 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', '') if var['name'] == 'project': a = 1 if pt_type.startswith('pt_ptr_'): 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_'): 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': 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': 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