vak: (Default)
[personal profile] vak
Приходится ли вам сравнивать файлы? Риторический вопрос: очевидно, приходится. Я лично команду "git diff" выдаю тысячу раз за день. Всем классический diff хорош, кроме одного: не различает перестановку фрагмента. Показывает только удаления и вставки. Если же часть текста переехала в другое место, diff учитывает его дважды: и как удаление, и как вставку.

Для некоторых применений такое не годится. Представьте, что вы хранитель коллекции ценных документов. И вдруг с одним файлом что-то случилось. Стандартный diff говорит, что всё пропало, документ полностью испорчен. А просто строки перемешались, ничего на самом деле не потеряно. Надо только порядок восстановить. В эпоху перфокарт такое сплошь и рядом происходило, когда колоду рассыпали и собрали впопыхах. Или кто-то решил навести порядок и переставил главы в тексте.

45 лет назад мой коллега Рид Котлер сделал утилиту сравнения файлов: "Text File Comparator". Трудился он тогда молодым студентом на компанию Intermetrics по контракту NASA. Сохранилось упоминание на странице 117 журнала NASA Tech Briefs Winter 1982 Vol. 7, No. 2: https://ntrs.nasa.gov/api/citations/20100028127/downloads/20100028127.pdf

Программа сравнивает два файла и выводит список их различий.

Программа сравнения файлов IFCOMP — это сравнение текстовых файлов для систем, совместимых с IBM OS/VS. IFCOMP принимает на вход два текстовых файла и выводит список их различий в форме псевдообновления. Все различия представлены в виде строк, которые следует удалить, заменить, вставить или переместить в первом входном файле для преобразования его во второй входной файл. Также выводится сводка с указанием количества строк, затронутых каждым типом изменений.

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

Программа IFCOMP написана на языке XPL (расширенный язык PLI, для которого поставляются исполняемые файлы компилятора) для пакетного выполнения и была реализована на компьютере IBM серии 370 с объёмом центральной памяти около 46 КБ 8-битных байт. IFCOMP была разработана в 1979 году.

Эта программа была написана Ридом С. Котлером из Intermetrics, Inc. для Космического центра имени Джонсона. Для получения дополнительной информации обведите кружком S на карточке запроса COSMIC.
Алгоритм подробно описан в статье: "A Technique for Isolating Differences Between Files", Paul Heckel 1978. 

Исходники на языке XPL утеряны, увы. Но сохранился вариант, переписанный Томом Пенелло на Си. Его я и решил поковырять. С ним Рид мне прислал четыре теста, и они работали. Но на некоторых других файлах программа выдавала внутреннюю ошибку или циклилась. Ошибка там неочевидная.

Я подумал: хороший случай применить ИИ для отладки. Интересно, как неестественный ум справится, скажем Cursor или Cline. Получился увлекательный сеанс. 😀

В целом программирование с помощью современного AI-агента напоминает походовую стратегическую игру. Если помните первую Empire, ещё в текстовом виде. Из неё потом выросла Civilization. Здесь нечто похожее, только без карты и в диалоге. Стратегически плодите и размещаете юнит тесты, и постепенно боретесь за расширение функционала и покрытия.

Благо, ИИ агент теперь удобно встроен в VS Code. Работает с файлами прямо в вашем локальном git-репозитории. Или даже прямо на Гитхабе, вам решать. Компилирует, запускает, пишет документацию, находит причины ошибок посредством юнит тестов, чинит, и по новому кругу. Вы внимательно наблюдаете за "сражением" и адресно вмешиваетесь в критические моменты.

Первый "подход к штанге" мы с Курсором продули. 😀 Для начала насоздавали несколько десятков юнит тестов, из которых больше половины не проходили. Хорошо, значит покрытие приемлемое. После этого несколько часов бились все эти тесты пройти. Курсор кромсал код без жалости. Объём Си-шных текстов увеличился вдвое, но справиться с глюками не удавалось. Стало понятно, что зашли в тупик.

Второй подход я распланировал иначе. Сначала переписываем всё с Си на Си++, чтобы уменьшить базовую сложность кода. Вместо доморощенных строк и примитивного выделения памяти переходим на стандартные строки и контейнеры из библиотеки Си++. После этого начинаем покрывать юнит тестами и отлаживать размеренно, по стадиям. Благо алгоритм имеет чёткое разделение на восемь проходов: от pass1() до pass8().

Главная бага обнаружилась на стадии pass6(). При слиянии двух блоков криво обновлялось дерево. Но проявлялся глюк только на уровне pass8(). Тесты уровней pass6 и pass7 багу не ловили. Курсор пытался "чинить" сначала уровень pass8, потом догадывался вернуться и сделать что-то с pass7, и даже заглядывал с сомнением в pass6, но тут его чутья не хватало. Как только я догадался скомандовать создать юнит тест, воспроизводящий нужную багу на уровне pass6, дело пошло на лад. Починка остального была уже делом техники.

Все исходники здесь: github.com/sergev/ifcomp

Date: 2025-11-02 07:36 (UTC)
juan_gandhi: (Default)
From: [personal profile] juan_gandhi
Классно. И как оно сравнивает теперь?

Date: 2025-11-02 08:48 (UTC)
lxe: (Default)
From: [personal profile] lxe
Я делал сравнятор бинарников с учётом перестановки. Вошел в Bakebread.

Date: 2025-11-03 02:23 (UTC)
lxe: (Default)
From: [personal profile] lxe
Я с его помощью успешно символизировал в gdb (стек, код, переменные) мини-дампы, удаленно снятые на "прям почти таких же, но немножко все-таки других" прошивках, чем удавалось подобрать на XDA Forums. Где технически тот же код, вариации семантики минимальны, а основной шум вносится параллельным сдвигом и перестановками.

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

Date: 2025-11-03 02:27 (UTC)
lxe: (Default)
From: [personal profile] lxe
Вылезали реально монстровые вещи. Например, существенный процент наших падений in vivo был связан с нестандартным возвращаемым значением memmove в одном из региональных (корейских) диалектов AOSP.

Date: 2025-11-02 16:34 (UTC)
From: [personal profile] sassa_nf
Did you try to ask it to explain the algorithm in plain words? I noticed that AI can explain the code and compare explanation to the code.

Date: 2025-11-02 17:51 (UTC)
From: [personal profile] sassa_nf
No, I meant to use that before fixing the bugs

Date: 2025-11-03 01:55 (UTC)
nepilsonis: (Default)
From: [personal profile] nepilsonis
Для структурированных текстов есть https://difftastic.wilfred.me.uk/

Date: 2025-11-03 23:52 (UTC)
From: [personal profile] ymz5
Дуже цікаво, дякую! Я з XPL тісно працював, купивши років 15 тому книгу з описом компілятора (у оранжевій обкладинці). Вирішив переписати першу частину програми ("ANALYSIS") на Паскалі, чітко слідуючи оригінальному аналізатору, і у мене все вийшло :) . Але далі особливо не заглиблювався.

Може Вам буде цікаво почитати про досвід одного пана, який створив компілятор XPL для архітектури FreeBSD/i486 (!). Найцікавіша стадія була, звісно, на етапі проблеми "курки і яйця".

Це може викликати у Вас спогади про ті легендарні часи, коли Ви адаптували C для екзотичних архітектур :)