Добавлены бета-функции для считывания переменны по адресу +фиксы багов future: - в селекторе сделать две таблички для всех переменных и для выборанных - по кнопке переносить переменные из всех в выбранные - переменные из выбранных и добавлять в основную табличку - сделать отдельный класс для таблички - который будет принимать спиоск переменных для отображения
402 lines
15 KiB
Python
402 lines
15 KiB
Python
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', 'int'),
|
||
'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 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, 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, 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
|
||
|