### Детальное описание и техническое задание (ТЗ) для предоставленного кода

#### **Общее описание программы**

Данный код представляет собой инструмент для анализа и обработки исходного кода на языке C с целью автоматического извлечения повторяющихся фрагментов кода (макросов) и их замены на макроопределения. Программа работает в двух режимах:

1. **Режим извлечения (`extract`)**: Анализирует исходные файлы C/C++ в указанной директории, находит повторяющиеся последовательности лексем, формирует макроопределения и сохраняет их в файл.
2. **Режим применения (`apply`)**: Использует сохранённые макроопределения для замены соответствующих фрагментов кода в исходных файлах на вызовы макросов.

Программа использует лексический анализ для преобразования исходного кода в последовательность лексем, что позволяет работать с кодом на уровне токенов, а не текста. Это делает инструмент устойчивым к различиям в форматировании (пробелы, переносы строк и т.д.).

---

### **Функциональные требования**

#### **1. Режим извлечения (`extract`)**
- **Входные данные**:
  - Путь к директории с исходными файлами C/C++ (`.c`, `.h`).
  - Путь к файлу, в который будут записаны макроопределения.
  - Опциональные списки исключений: директории и файлы, которые не должны анализироваться.
- **Процесс**:
  1. Сканирование указанной директории и всех её поддиректорий (с учётом исключений) для поиска файлов с расширениями `.c` и `.h`.
  2. Лексический анализ содержимого файлов с преобразованием текста в последовательность лексем.
  3. Поиск повторяющихся последовательностей лексем (макросов) с учётом их ранга (экономии).
  4. Фильтрация найденных последовательностей для исключения "странных" или неэффективных макросов.
  5. Генерация макроопределений в формате `@def(macro_name, (params), body)` и запись их в указанный файл.
- **Выходные данные**:
  - Файл с макроопределениями, где каждая строка представляет собой определение макроса, а также комментарий с рангом и количеством вхождений.

#### **2. Режим применения (`apply`)**
- **Входные данные**:
  - Путь к директории с исходными файлами C/C++ (`.c`, `.h`).
  - Путь к файлу с макроопределениями.
- **Процесс**:
  1. Чтение файла с макроопределениями.
  2. Сканирование указанной директории и всех её поддиректорий для поиска файлов с расширениями `.c` и `.h`.
  3. Лексический анализ содержимого файлов с преобразованием текста в последовательность лексем.
  4. Замена найденных в исходном коде последовательностей лексем на вызовы соответствующих макросов.
  5. Сохранение изменённого содержимого обратно в исходные файлы.
- **Выходные данные**:
  - Модифицированные исходные файлы, в которых повторяющиеся фрагменты кода заменены на вызовы макросов.

---

### **Нефункциональные требования**

1. **Производительность**:
   - Программа должна эффективно обрабатывать большие проекты (тысячи файлов, миллионы строк кода).
   - Использование памяти должно быть оптимизировано (например, использование `array('I')` для хранения лексем).

2. **Надёжность**:
   - Корректная обработка ошибок (например, отсутствие директории, пустые файлы, ошибки чтения/записи).
   - Устойчивость к некорректному форматированию исходного кода (пробелы, переносы строк).

3. **Расширяемость**:
   - Возможность добавления новых типов операторов и правил фильтрации макросов.
   - Лёгкость интеграции с другими инструментами (например, через командную строку).

4. **Совместимость**:
   - Поддержка кодировки UTF-8 для чтения и записи файлов.
   - Совместимость с Python 3.x.

---

### **Описание структуры кода**

#### **1. Зависимости и импорты**
- **Стандартные библиотеки**:
  - `os`: Для работы с файловой системой (сканирование директорий, чтение/запись файлов).
  - `sys`: Для вывода сообщений об ошибках и завершения программы.
  - `argparse`: Для обработки аргументов командной строки.
  - `array`: Для эффективного хранения последовательностей лексем в виде массива целых чисел (`array('I')`).

- **Пользовательские модули**:
  - `lexer`: Модуль для лексического анализа, предоставляющий функции преобразования текста в лексемы, проверки типов лексем, фильтрации пробелов и т.д.
  - `macro_storage`: Модуль для управления хранилищем макросов (инициализация, вывод, список макросов).
  - `seq`: Модуль для работы с последовательностями (инициализация).

#### **2. Константы и глобальные переменные**
- **Константы для структуры макроса**:
  - `M_RANK`, `M_BODY`, `M_POSITIONS`, `M_PARAMS`, `M_FACT_PARAMS`, `M_NAME_MACRO`: Индексы для доступа к элементам кортежа, представляющего макрос.
- **Типы операторов**:
  - `OP_BITWISE`, `OP_POINTER`, `OP_ARRAY`, `OP_ARITHMETIC`, `OP_COMPARISON`, `OP_OTHER`: Константы для классификации операторов.
- **Глобальные словари**:
  - `g_classify_oper`: Словарь для классификации операторов (инициализируется функцией `init_classify_oper`).

#### **3. Основные функции**

##### **3.1. `find_repeated(lexems)`**
- **Описание**: Находит повторяющиеся последовательности лексем в массиве `lexems`.
- **Входные данные**: Массив лексем (`array('I')`).
- **Выходные данные**: Список кортежей, представляющих макросы, с элементами: ранг, тело, позиции, параметры, фактические параметры, имя макроса.
- **Алгоритм**:
  1. Фильтрация лексем, которые не могут быть началом последовательности (например, пробелы, скобки, ключевые слова).
  2. Построение словаря позиций для каждой допустимой начальной лексемы.
  3. Итеративное расширение последовательностей, добавляя по одной лексеме и проверяя, встречается ли новая последовательность более одного раза.
  4. Вычисление ранга для каждой последовательности (функция `rank`).
  5. Сортировка последовательностей по убыванию ранга.

##### **3.2. `remove_shorter_macros(seqs)`**
- **Описание**: Удаляет более короткие макросы, если их позиции совпадают с позициями более длинных макросов.
- **Входные данные**: Список макросов.
- **Выходные данные**: Отфильтрованный список макросов.
- **Алгоритм**:
  1. Сортировка макросов по убыванию длины тела.
  2. Пропуск макросов, чьи позиции уже встречались в более длинных макросах.

##### **3.3. `init_classify_oper()`**
- **Описание**: Инициализирует словарь `g_classify_oper` для классификации операторов.
- **Входные данные**: Отсутствуют.
- **Выходные данные**: Заполненный словарь `g_classify_oper`.

##### **3.4. `extract_macros(directory, macro_file, exclude_dirs, exclude_files)`**
- **Описание**: Основная функция режима извлечения макросов.
- **Входные данные**:
  - `directory`: Путь к директории с исходными файлами.
  - `macro_file`: Путь к файлу для записи макроопределений.
  - `exclude_dirs`, `exclude_files`: Списки исключений.
- **Выходные данные**: Файл с макроопределениями.
- **Алгоритм**:
  1. Сканирование директории с учётом исключений.
  2. Чтение и лексический анализ файлов `.c` и `.h`.
  3. Объединение всех лексем в один массив.
  4. Поиск повторяющихся последовательностей (`find_repeated`).
  5. Поиск последовательных паттернов (`find_sequential_patterns`).
  6. Фильтрация и сортировка макросов.
  7. Генерация и запись макроопределений.

##### **3.5. `generate_macro_definition(pattern, counter)`**
- **Описание**: Генерирует строку определения макроса.
- **Входные данные**:
  - `pattern`: Кортеж, представляющий макрос.
  - `counter`: Счётчик для генерации уникальных имён макросов.
- **Выходные данные**: Строка в формате `@def(macro_name, (params), body)`.

##### **3.6. `rank(t)`**
- **Описание**: Вычисляет ранг экономии для макроса.
- **Входные данные**: Кортеж, представляющий макрос.
- **Выходные данные**: Числовое значение ранга.
- **Алгоритм**:
  1. Подсчёт общего количества лексем в макросе (длина тела × количество позиций).
  2. Вычитание затрат на определение макроса (имя, тело, параметры, скобки, запятые).
  3. Нормализация ранга с учётом количества позиций.

##### **3.7. `find_sequential_patterns(seqs, lexems, max_gap)`**
- **Описание**: Находит последовательные макросы с небольшим промежутком между ними.
- **Входные данные**:
  - `seqs`: Список макросов.
  - `lexems`: Массив всех лексем.
  - `max_gap`: Максимальный допустимый промежуток между последовательностями.
- **Выходные данные**: Список новых макросов, представляющих объединённые последовательности.

##### **3.8. `generator_apply_macros(directory, macro_file)`**
- **Описание**: Основная функция режима применения макросов.
- **Входные данные**:
  - `directory`: Путь к директории с исходными файлами.
  - `macro_file`: Путь к файлу с макроопределениями.
- **Выходные данные**: Модифицированные исходные файлы.
- **Алгоритм**:
  1. Чтение файла с макроопределениями.
  2. Сканирование директории и обработка файлов `.c` и `.h`.
  3. Замена фрагментов кода на вызовы макросов (`generator_replace_macros`).
  4. Сохранение изменённого содержимого.

##### **3.9. `generator_replace_macros(lexems, macros)`**
- **Описание**: Заменяет повторяющиеся блоки кода на вызовы макросов.
- **Входные данные**:
  - `lexems`: Массив лексем исходного файла.
  - `macros`: Список макроопределений.
- **Выходные данные**: Новый массив лексем с заменёнными фрагментами.

##### **3.10. `main()`**
- **Описание**: Точка входа в программу, обрабатывает аргументы командной строки и запускает соответствующий режим.
- **Аргументы командной строки**:
  - `command`: Режим работы (`extract` или `apply`).
  - `--directory`: Путь к директории.
  - `--macro-file`: Путь к файлу с макроопределениями.
  - `--exclude-dirs`, `--exclude-files`: Списки исключений (для режима `extract`).

---

### **Техническое задание (ТЗ)**

#### **1. Цель проекта**
Разработать инструмент для автоматического анализа исходного кода на языке C/C++ с целью извлечения повторяющихся фрагментов кода и их замены на макроопределения, что позволит уменьшить дублирование кода и упростить его поддержку.

#### **2. Функциональные требования**
- **Режим извлечения (`extract`)**:
  - Сканирование директории с исходными файлами C/C++.
  - Поддержка исключений (директории и файлы).
  - Лексический анализ исходного кода с преобразованием в последовательность лексем.
  - Поиск повторяющихся последовательностей лексем с учётом ранга экономии.
  - Генерация макроопределений в формате `@def(macro_name, (params), body)`.
  - Запись макроопределений в файл с комментариями о ранге и количестве вхождений.
- **Режим применения (`apply`)**:
  - Чтение файла с макроопределениями.
  - Сканирование директории с исходными файлами C/C++.
  - Замена повторяющихся фрагментов кода на вызовы макросов.
  - Сохранение изменённого содержимого в исходные файлы.
- **Общие требования**:
  - Поддержка кодировки UTF-8.
  - Обработка ошибок (например, отсутствие директории, пустые файлы, ошибки чтения/записи).
  - Эффективное использование памяти (например, использование `array('I')`).

#### **3. Нефункциональные требования**
- **Производительность**:
  - Обработка больших проектов (тысячи файлов, миллионы строк кода) за разумное время.
  - Оптимизация использования памяти.
- **Надёжность**:
  - Устойчивость к некорректному форматированию исходного кода.
  - Корректная обработка ошибок с выводом информативных сообщений.
- **Расширяемость**:
  - Возможность добавления новых типов операторов и правил фильтрации макросов.
  - Лёгкость интеграции с другими инструментами через командную строку.
- **Совместимость**:
  - Поддержка Python 3.x.
  - Совместимость с операционными системами Windows, Linux, macOS.

#### **4. Архитектура**
- **Модули**:
  - `lexer`: Лексический анализатор (предоставляется как внешний модуль).
  - `macro_storage`: Управление хранилищем макросов (предоставляется как внешний модуль).
  - `seq`: Работа с последовательностями (предоставляется как внешний модуль).
  - Основной модуль: Логика извлечения и применения макросов.
- **Формат данных**:
  - Лексемы хранятся как целые числа в массиве `array('I')`.
  - Макросы представляются кортежами из 6 элементов: ранг, тело, позиции, параметры, фактические параметры, имя макроса.
  - Макроопределения записываются в текстовом формате `@def(macro_name, (params), body)`.

#### **5. Интерфейс командной строки**
- **Команды**:
  - `extract`: Извлечение макросов.
    - Аргументы: `--directory`, `--macro-file`, `--exclude-dirs`, `--exclude-files`.
  - `apply`: Применение макросов.
    - Аргументы: `--directory`, `--macro-file`.
- **Пример использования**:
  ```bash
  python script.py extract -d ./src -m macros.txt --exclude-dirs ./src/tests --exclude-files test.c
  python script.py apply -d ./src -m macros.txt
  ```

#### **6. Тестирование**
- **Юнит-тесты**:
  - Проверка функции `find_repeated` на тестовых данных с известными повторяющимися последовательностями.
  - Проверка функции `rank` на корректность вычисления ранга.
  - Проверка функции `generate_macro_definition` на корректность формата макроопределений.
- **Интеграционные тесты**:
  - Проверка режима `extract` на тестовом проекте с несколькими файлами.
  - Проверка режима `apply` на корректность замены фрагментов кода.
- **Тесты производительности**:
  - Обработка большого проекта (например, 1000 файлов по 1000 строк каждый).

#### **7. Документация**
- **Пользовательская документация**:
  - Описание команд и аргументов командной строки.
  - Примеры использования.
- **Техническая документация**:
  - Описание структуры кода и основных функций.
  - Описание формата данных (лексемы, макросы, макроопределения).

#### **8. Ограничения**
- Программа не поддерживает сложные макросы с переменным числом параметров.
- Программа не обрабатывает вложенные макросы (макросы внутри макросов).
- Программа не учитывает семантику кода (работает только на уровне лексем).

#### **9. Возможные улучшения**
- Поддержка семантического анализа для исключения некорректных макросов.
- Поддержка вложенных макросов.
- Интеграция с системами сборки (например, CMake, Make).
- Графический интерфейс для визуализации найденных макросов.

---

### **Пример использования**

#### **Извлечение макросов**
```bash
python script.py extract -d ./src -m macros.txt --exclude-dirs ./src/tests --exclude-files test.c
```
- Программа просканирует директорию `./src`, исключая поддиректорию `./src/tests` и файл `test.c`.
- Найденные макросы будут записаны в файл `macros.txt`.

Пример содержимого `macros.txt`:
```
@def(@macro_0, (), a + b * c)
//rank 10.0, cnt 5
@def(@macro_1, (x, y), x = y + 1)
//rank 8.0, cnt 3
```

#### **Применение макросов**
```bash
python script.py apply -d ./src -m macros.txt
```
- Программа заменит в файлах директории `./src` все вхождения `a + b * c` на `@macro_0()` и все вхождения `x = y + 1` на `@macro_1(x, y)`.

---