Существует ли инструмент командной строки для извлечения typedef, структуры, перечисления, переменной, функции из файла C или C++?
Мне нужен инструмент командной строки для извлечения определения или объявления (typedef, структура, перечисление, переменная или функция) из исходного файла C или C++. Также был бы удобен способ замены существующего определения / объявления (после преобразования извлеченного определения с помощью пользовательского сценария). Имеется ли такой общий инструмент или есть какое-то достаточно близкое приближение к такому инструменту?
Здесь важна возможность написания сценариев и возможность подключения к созданным пользователем сценариям или программам, хотя мне также любопытны академические программы. Решения с открытым исходным кодом для лагеря Unix/Linux предпочтительны (хотя мне также интересны инструменты для Windows и OS X). Основными интересами языка являются C и C++, но более общее решение было бы еще лучше (я думаю, что нам не нужны сверхточные возможности синтаксического анализа для поиска, извлечения и замены определения в исходном файле программы).
Примеры использования (дополнительно - для любопытных):
- Учитывая глубоко вложенные
struct
s и инициализации переменных (массивов) этих типов, предположим, что необходимо изменить определение структуры, добавив или переупорядочив поля или переписав определения переменных / массивов в более удобочитаемом формате без ошибок, возникающих в результате ручного труда. Это будет работать путем извлечения старых инициализаций с последующим использованием сценария / программы для записи новых инициализаций для замены старых. - Для реализации инструмента просмотра кода - извлеките определение.
- Генерация декоративного кода (например, регистрация / возврат записей функций).
- Сценарий структурирования кода (например, извлечь то и это и поместить в другое место без изменений - комментарий коммита управления версиями может задокументировать команду для выполнения этой операции, чтобы сделать очевидным и проверяемым, что ничего не изменилось).
Альтернативная проблема: если есть инструмент для определения местоположения определения (будет достаточно начальной и конечной строки - мы можем даже предположить, что все интересующие нас определения / объявления находятся в отдельной строке), тогда это будет просто выполнение ловкость пальцев, чтобы написать программу
- извлекать определения,
- заменить определения или даже
извлечь определение, запустить программу, указанную в параметрах командной строки (или редактор), чтобы
- получить желаемые извлеченные определения из
stdin
(или из временного файла), - выполнить преобразование (редактирование) и
- вывести новые определения в
stdout
(или сохраните их в указанном временном файле)
быть замененным исполняющей программой.
- получить желаемые извлеченные определения из
Таким образом, главная, более сложная проблема - найти начало и конец определения.
Примечание о тегах: более точный тег, чем code-generation
было бы code-transformation
но его не существует.
3 ответа
Наш DMS Software Reengineering Toolkit пытается быть тем инструментом, о котором вы мечтаете. Но это продвигает современное состояние и не инструмент стиля нирваны. Это достаточно хорошо, чтобы делать настоящую, интересную работу.
DMS предоставляет общие средства для анализа, анализа и преобразования исходного кода.
Он использует явные грамматики для определения языков (таких как C и C++); грамматики управляют синтаксическими анализаторами, которые создают абстрактные синтаксические деревья (AST). Множество примитивов анализа предоставляют а) средства ["грамматики атрибутов" ATG] для сбора информации по древовидным путям информационных потоков, которые точно соответствуют форме AST, б) построение использования символов для карт определения символов ["таблиц символов"] c) контроль и анализ потока данных с использованием фактов, извлеченных ATG; d) анализ дальности; e) точечный анализ как локального, так и глобального. Эти примитивные анализаторы могут использоваться для составления фактов из AST, чтобы сделать выводы о коде, представленном AST (например, "это утверждение изменяет эти переменные"). Внешний интерфейс langauge объединяет грамматику и анализаторы для конкретного языка в многоразовый пакет. DMS имеет такие языковые интерфейсы разного уровня глубины и зрелости для самых разных языков.
[РЕДАКТИРОВАНИЕ 6/27: Внешние интерфейсы C и C++ поддерживают определенные диалекты C и C++: ANSIC, C99, GCC3/4 C, MS Visual C, ANSI C++98, ANSI C++11, GCC3/4. C++, MS Visual C++ 2005/2008/2010. Если вы хотите точного анализа кода, вы должны использовать "правильный" диалект для обработки вашего кода.]
Но "анализ" не в этом. Целью анализа является стимулирование изменений. DMS обеспечивает дополнительную поддержку для процедурного изменения AST, для изменения AST с помощью правил перезаписи от источника к источнику, написанных в поверхностном синтаксисе языка (оба обусловлены некоторым выбранным результатом анализа), или для группировки наборов процедурных и исходных данных. исходные тексты переписывают вместе, чтобы составлять сложные сложные переписки, которые могут нести огромные изменения кода, такие как реорганизация и т. д. После преобразования AST их можно использовать для регенерации ("prettyprint") синтаксически правильного кода в соответствующем конечный язык / диалект. [Изменяя AST для одного языка по кусочкам, пока у вас не появится AST для другого, вы можете создавать переводчики, но это не так просто, как подразумевает это предложение].
Все это работает в значительной степени, но все еще несколько блокируется некоторыми языковыми осложнениями. Для C и C++ известным усложнением является препроцессор; произвольно редактируя текст программы, условные выражения препроцессора могут сделать исходный код неразборчивым с помощью чего-либо, напоминающего стандартную технологию синтаксического анализа. Внешние интерфейсы DMS C и C++ несколько улучшают это и могут анализировать код с хорошо структурированными директивами препроцессора, включая некоторые странные случаи, которые большинство людей не называют структурированными, но это обычно происходит:
#IF cond
if (abc) {
#ELSE
if (def) {
#ENDIF
Мы добились интересного прогресса в разборе кода с произвольным размещением условий препроцессора. Но как только вы это сделаете, теперь все ваши анализаторы внезапно должны будут принять во внимание условия препроцессора, и мы внезапно окажемся в дураках, которые люди компилятора на самом деле не посетили.
DMS использовался для больших архитектурных сдвигов в больших программах на C++, преобразования из не-CORBA-стиля в CORBA-стиль с огромным количеством перемешивания кода, для извлечения кода по произвольным путям потока управления для генерации API в стиле SOW для существующего кода C, вставлять инструментарий в большие программы на Си для обнаружения ошибок указателя и т. д. [Он был применен к другим задачам во многих из этих других языков].
По нашему опыту, его все еще довольно сложно использовать. По нашему мнению, это в том же смысле, что демократия является худшей из всех систем правления, за исключением всех остальных; YMMV. На сайте есть много инструментов и дискуссий, основанных на DMS.
Фактически оно использовалось для извлечения функций (упражнение SOW гораздо более общее, чем это) и вставки функций (это обобщенный случай инструментирования).
Такие инструменты, как GCC-XML, являются тенями возможностей DMS. GCC-XML анализирует, создает таблицы символов и выводит объявления данных (не код), но не может вносить какие-либо изменения в код. Лязг лучше; он анализирует C и C++ в AST, может выполнять анализ промежуточного представления LLVM и имеет какой-то механизм выделения дополнительных исправлений для последующего применения к исходному тексту, вдохновленный желаемым изменением дерева. Я не знаю, может ли Clang выполнять масштабные преобразования кода, особенно те, в которых результат одного преобразования снова преобразуется (как вы модифицируете дерево для отложенного текстового патча?). DMS может делать это в течение всего дня, и может делать это для многих языков, кроме C и C++, и может делать это для произвольной смеси известных им языков.
До тех пор, пока проблема препроцессора с условными выражениями не будет решена, анализ / преобразование кода C и C++ не будет легким. Мы выполняем эти задачи на этих языках только благодаря силе воли и использованию самых мощных инструментов, которые мы можем создать. (У Java таких проблем нет, и DMS, соответственно, лучше анализирует / трансформирует).
При серьезном риске высокомерия, я считаю, что DMS - лучший инструмент для общего анализа и преобразования. Как его архитектор, я считаю своей долгосрочной работой сделать ее еще более сильной для этой задачи.
Вы можете рассматривать GCC-XML как основу для разработки инструментов, подобных тем, о которых вы говорите. Я использовал его в сочетании с pygccxml для автоматического извлечения глубоко вложенных членов структуры. Это не сделает вашу работу совсем несложной, но вам, безусловно, будет лучше, чем в противном случае.
Я также слышал, что другие упоминают о Clang в качестве основы для написания таких инструментов, но у меня не было возможности самому вникнуть в него.
Вы можете проверить Clang. У них есть нетривиальные библиотеки обработки исходного кода.