2026-05-02 23:04:46 +03:00
|
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
|
|
|
|
"""
|
2026-05-23 18:56:43 +03:00
|
|
|
|
Второй проход КВС (упрощённый)
|
|
|
|
|
|
- Собирает адреса всех приводящих меток из колонки 'виртуальный_адрес'
|
2026-05-23 08:52:52 +03:00
|
|
|
|
- Заменяет заглушки в уводящих адресах на реальные адреса
|
|
|
|
|
|
- Записывает рассчитанные значения в колонку 'рассчитанный_уводящий_адрес' (файловое смещение)
|
2026-05-23 18:56:43 +03:00
|
|
|
|
- Формирует команду с подставленными виртуальными адресами в колонку 'команда_со_значениями'
|
2026-05-02 23:04:46 +03:00
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
import sys
|
2026-05-23 08:52:52 +03:00
|
|
|
|
import csv
|
|
|
|
|
|
from collections import Counter
|
2026-05-02 23:04:46 +03:00
|
|
|
|
|
|
|
|
|
|
|
2026-05-23 08:52:52 +03:00
|
|
|
|
def read_csv(csv_file):
|
|
|
|
|
|
"""Читает CSV файл и возвращает список записей и заголовки"""
|
|
|
|
|
|
entries = []
|
|
|
|
|
|
headers = []
|
2026-05-02 23:04:46 +03:00
|
|
|
|
|
2026-05-23 08:52:52 +03:00
|
|
|
|
with open(csv_file, 'r', encoding='utf-8') as f:
|
|
|
|
|
|
reader = csv.reader(f, delimiter=';')
|
|
|
|
|
|
headers = next(reader)
|
|
|
|
|
|
for row in reader:
|
|
|
|
|
|
entries.append(row)
|
2026-05-02 23:04:46 +03:00
|
|
|
|
|
2026-05-23 08:52:52 +03:00
|
|
|
|
return headers, entries
|
2026-05-02 23:04:46 +03:00
|
|
|
|
|
2026-05-17 15:18:35 +03:00
|
|
|
|
|
2026-05-23 18:56:43 +03:00
|
|
|
|
def collect_labels(entries, headers):
|
2026-05-23 08:52:52 +03:00
|
|
|
|
"""
|
|
|
|
|
|
Собирает адреса всех приводящих меток.
|
2026-05-23 18:56:43 +03:00
|
|
|
|
Использует колонку 'виртуальный_адрес' для получения адреса метки.
|
|
|
|
|
|
Возвращает словарь: имя метки -> виртуальный адрес
|
2026-05-23 08:52:52 +03:00
|
|
|
|
"""
|
2026-05-23 18:56:43 +03:00
|
|
|
|
labels = {}
|
2026-05-17 15:18:35 +03:00
|
|
|
|
|
2026-05-23 08:52:52 +03:00
|
|
|
|
try:
|
|
|
|
|
|
label_idx = headers.index('приводящая_метка')
|
2026-05-23 18:56:43 +03:00
|
|
|
|
virt_addr_idx = headers.index('виртуальный_адрес')
|
2026-05-23 08:52:52 +03:00
|
|
|
|
except ValueError as e:
|
|
|
|
|
|
print(f"Ошибка: не найдена нужная колонка в CSV: {e}")
|
|
|
|
|
|
sys.exit(1)
|
2026-05-17 15:18:35 +03:00
|
|
|
|
|
2026-05-23 08:52:52 +03:00
|
|
|
|
for row in entries:
|
|
|
|
|
|
label_str = row[label_idx].strip()
|
|
|
|
|
|
if label_str:
|
2026-05-23 18:56:43 +03:00
|
|
|
|
virt_addr_str = row[virt_addr_idx].strip()
|
|
|
|
|
|
if virt_addr_str.startswith('0x'):
|
|
|
|
|
|
virt_addr = int(virt_addr_str, 16)
|
2026-05-23 08:52:52 +03:00
|
|
|
|
|
|
|
|
|
|
for label_name in label_str.split(','):
|
|
|
|
|
|
label_name = label_name.strip()
|
|
|
|
|
|
if label_name:
|
2026-05-23 18:56:43 +03:00
|
|
|
|
labels[label_name] = virt_addr
|
|
|
|
|
|
|
|
|
|
|
|
# Выводим статистику собранных меток
|
|
|
|
|
|
print(f"\n{'='*80}")
|
|
|
|
|
|
print(f"СОБРАННЫЕ ПРИВОДЯЩИЕ МЕТКИ (всего: {len(labels)})")
|
|
|
|
|
|
print(f"{'='*80}")
|
|
|
|
|
|
print(f"\n{'Имя метки':<35} {'Виртуальный адрес':<22}")
|
|
|
|
|
|
print(f"{'-'*57}")
|
|
|
|
|
|
|
|
|
|
|
|
for name in sorted(labels.keys()):
|
|
|
|
|
|
virt_addr = labels[name]
|
|
|
|
|
|
print(f"{name:<35} 0x{virt_addr:08x} ({virt_addr})")
|
2026-05-23 08:52:52 +03:00
|
|
|
|
|
2026-05-23 18:56:43 +03:00
|
|
|
|
return labels
|
2026-05-17 15:18:35 +03:00
|
|
|
|
|
2026-05-02 23:04:46 +03:00
|
|
|
|
|
2026-05-23 18:56:43 +03:00
|
|
|
|
def resolve_targets(entries, headers, labels):
|
2026-05-23 08:52:52 +03:00
|
|
|
|
"""
|
|
|
|
|
|
Заменяет уводящие адреса-заглушки на реальные адреса
|
2026-05-23 18:56:43 +03:00
|
|
|
|
- рассчитанный_уводящий_адрес: файловое смещение (берём из колонки 'адрес')
|
2026-05-23 08:52:52 +03:00
|
|
|
|
- команда_со_значениями: виртуальный адрес
|
|
|
|
|
|
"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
target_idx = headers.index('уводящий_адрес')
|
|
|
|
|
|
calc_target_idx = headers.index('рассчитанный_уводящий_адрес')
|
|
|
|
|
|
source_idx = headers.index('исходная_команда')
|
|
|
|
|
|
source_with_values_idx = headers.index('команда_со_значениями')
|
2026-05-23 18:56:43 +03:00
|
|
|
|
addr_idx = headers.index('адрес')
|
2026-05-23 08:52:52 +03:00
|
|
|
|
except ValueError as e:
|
|
|
|
|
|
print(f"Ошибка: не найдена нужная колонка в CSV: {e}")
|
|
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
2026-05-23 18:56:43 +03:00
|
|
|
|
resolved = []
|
|
|
|
|
|
unresolved = []
|
2026-05-02 23:04:46 +03:00
|
|
|
|
|
2026-05-23 08:52:52 +03:00
|
|
|
|
for row in entries:
|
|
|
|
|
|
target = row[target_idx].strip()
|
2026-05-02 23:04:46 +03:00
|
|
|
|
|
2026-05-23 08:52:52 +03:00
|
|
|
|
if target and target.startswith('ЗАГЛУШКА '):
|
|
|
|
|
|
label_name = target.replace('ЗАГЛУШКА ', '').strip()
|
2026-05-17 15:18:35 +03:00
|
|
|
|
|
2026-05-23 18:56:43 +03:00
|
|
|
|
if label_name in labels:
|
|
|
|
|
|
virt_addr = labels[label_name]
|
2026-05-23 08:52:52 +03:00
|
|
|
|
virt_hex = f"0x{virt_addr:08x}"
|
2026-05-02 23:04:46 +03:00
|
|
|
|
|
2026-05-23 18:56:43 +03:00
|
|
|
|
# Файловое смещение берём из колонки 'адрес' текущей строки
|
|
|
|
|
|
addr_str = row[addr_idx].strip()
|
|
|
|
|
|
if addr_str.startswith('0x'):
|
|
|
|
|
|
file_addr = int(addr_str, 16)
|
|
|
|
|
|
file_hex = f"0x{file_addr:08x}"
|
|
|
|
|
|
row[calc_target_idx] = file_hex
|
|
|
|
|
|
resolved.append((label_name, file_addr, virt_addr))
|
|
|
|
|
|
else:
|
|
|
|
|
|
row[calc_target_idx] = ""
|
|
|
|
|
|
resolved.append((label_name, 0, virt_addr))
|
2026-05-02 23:04:46 +03:00
|
|
|
|
|
2026-05-23 18:56:43 +03:00
|
|
|
|
# Подставляем виртуальный адрес в команду
|
2026-05-23 08:52:52 +03:00
|
|
|
|
source_cmd = row[source_idx].strip()
|
|
|
|
|
|
if source_cmd:
|
|
|
|
|
|
cmd_with_addr = source_cmd.replace(label_name, virt_hex)
|
|
|
|
|
|
row[source_with_values_idx] = cmd_with_addr
|
2026-05-02 23:04:46 +03:00
|
|
|
|
else:
|
2026-05-23 08:52:52 +03:00
|
|
|
|
unresolved.append(label_name)
|
|
|
|
|
|
row[calc_target_idx] = ""
|
2026-05-02 23:04:46 +03:00
|
|
|
|
|
2026-05-23 18:56:43 +03:00
|
|
|
|
# Выводим статистику разрешённых заглушек
|
|
|
|
|
|
print(f"\n{'='*80}")
|
|
|
|
|
|
print(f"РАЗРЕШЁННЫЕ ЗАГЛУШКИ (всего: {len(resolved)})")
|
|
|
|
|
|
print(f"{'='*80}")
|
2026-05-23 08:52:52 +03:00
|
|
|
|
|
|
|
|
|
|
if resolved:
|
|
|
|
|
|
unique_resolved = {}
|
|
|
|
|
|
for name, file_addr, virt_addr in resolved:
|
|
|
|
|
|
if name not in unique_resolved:
|
|
|
|
|
|
unique_resolved[name] = (file_addr, virt_addr)
|
|
|
|
|
|
|
2026-05-23 18:56:43 +03:00
|
|
|
|
print(f"\nУникальных меток: {len(unique_resolved)}")
|
|
|
|
|
|
print(f"\n{'Имя метки':<35} {'Файловое смещение':<22} {'Виртуальный адрес':<22}")
|
|
|
|
|
|
print(f"{'-'*79}")
|
|
|
|
|
|
|
|
|
|
|
|
for name in sorted(unique_resolved.keys()):
|
|
|
|
|
|
file_addr, virt_addr = unique_resolved[name]
|
|
|
|
|
|
if file_addr:
|
|
|
|
|
|
print(f"{name:<35} 0x{file_addr:08x} ({file_addr:<10}) 0x{virt_addr:08x} ({virt_addr})")
|
|
|
|
|
|
else:
|
|
|
|
|
|
print(f"{name:<35} {'(не известно)':<22} 0x{virt_addr:08x} ({virt_addr})")
|
|
|
|
|
|
else:
|
|
|
|
|
|
print("\n--- НЕТ РАЗРЕШЁННЫХ ЗАГЛУШЕК ---")
|
|
|
|
|
|
|
|
|
|
|
|
# Выводим статистику неразрешённых заглушек
|
|
|
|
|
|
print(f"\n{'='*80}")
|
|
|
|
|
|
print(f"НЕРАЗРЕШЁННЫЕ ЗАГЛУШКИ (всего: {len(unresolved)})")
|
|
|
|
|
|
print(f"{'='*80}")
|
2026-05-23 08:52:52 +03:00
|
|
|
|
|
|
|
|
|
|
if unresolved:
|
|
|
|
|
|
unresolved_counts = Counter(unresolved)
|
2026-05-23 18:56:43 +03:00
|
|
|
|
print(f"\nУникальных неразрешённых имён: {len(unresolved_counts)}")
|
|
|
|
|
|
print(f"\n{'Имя метки':<35} {'Количество вхождений':<20}")
|
|
|
|
|
|
print(f"{'-'*55}")
|
|
|
|
|
|
|
|
|
|
|
|
for name, count in sorted(unresolved_counts.items(), key=lambda x: x[1], reverse=True):
|
|
|
|
|
|
print(f"{name:<35} {count}")
|
|
|
|
|
|
else:
|
|
|
|
|
|
print("\n--- НЕТ НЕРАЗРЕШЁННЫХ ЗАГЛУШЕК ---")
|
|
|
|
|
|
|
|
|
|
|
|
return resolved, unresolved
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def save_csv(csv_file, headers, entries):
|
|
|
|
|
|
"""Сохраняет обновлённый CSV файл"""
|
|
|
|
|
|
with open(csv_file, 'w', newline='', encoding='utf-8') as f:
|
|
|
|
|
|
writer = csv.writer(f, delimiter=';')
|
|
|
|
|
|
writer.writerow(headers)
|
|
|
|
|
|
writer.writerows(entries)
|
2026-05-23 08:52:52 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
|
|
if len(sys.argv) != 2:
|
|
|
|
|
|
print("Использование: python kvs_pass2.py <входной.csv>")
|
2026-05-02 23:04:46 +03:00
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
2026-05-23 08:52:52 +03:00
|
|
|
|
csv_file = sys.argv[1]
|
|
|
|
|
|
|
2026-05-23 18:56:43 +03:00
|
|
|
|
print(f"\n=== ВТОРОЙ ПРОХОД КВС (упрощённый) ===")
|
2026-05-23 08:52:52 +03:00
|
|
|
|
print(f"Чтение CSV: {csv_file}")
|
|
|
|
|
|
|
|
|
|
|
|
headers, entries = read_csv(csv_file)
|
2026-05-02 23:04:46 +03:00
|
|
|
|
|
2026-05-23 18:56:43 +03:00
|
|
|
|
print(f"\n--- СБОР ПРИВОДЯЩИХ МЕТОК ---")
|
|
|
|
|
|
labels = collect_labels(entries, headers)
|
2026-05-02 23:04:46 +03:00
|
|
|
|
|
2026-05-23 18:56:43 +03:00
|
|
|
|
print(f"\n--- РАЗРЕШЕНИЕ УВОДЯЩИХ АДРЕСОВ ---")
|
|
|
|
|
|
resolved, unresolved = resolve_targets(entries, headers, labels)
|
2026-05-23 08:52:52 +03:00
|
|
|
|
|
2026-05-23 18:56:43 +03:00
|
|
|
|
print(f"\n{'='*80}")
|
|
|
|
|
|
print(f"ОБЩАЯ СТАТИСТИКА")
|
|
|
|
|
|
print(f"{'='*80}")
|
|
|
|
|
|
print(f" Приводящих меток в CSV: {len(labels)}")
|
|
|
|
|
|
print(f" Разрешено заглушек: {len(resolved)}")
|
|
|
|
|
|
print(f" Не разрешено заглушек: {len(unresolved)}")
|
|
|
|
|
|
print(f"{'='*80}")
|
2026-05-23 08:52:52 +03:00
|
|
|
|
|
|
|
|
|
|
save_csv(csv_file, headers, entries)
|
2026-05-23 18:56:43 +03:00
|
|
|
|
print(f"\nCSV сохранён: {csv_file}")
|
2026-05-23 08:52:52 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
|
main()
|