Какой самый простой способ автоматической вставки кода в существующий код C ++? - PullRequest
3 голосов
/ 09 июля 2011

Например, я хочу вставить вызов функции после каждой строки.Например:

for (int i = 0; i < n; ++i)
{
   double d = 2*i;
}

станет

for (int i = 0; i < n; ++i)
{
   myFuncCall();
   double d = 2*i;
   myFuncCall();
}
myFuncCall();

Я исследовал обобщенные парсеры c ++, но они либо кажутся а) коммерческими, б) неполными или в) трудными в использовании

Компиляторы - не моя жизнь, и это средство для достижения цели, поэтому я ищу самое быстрое решение

РЕДАКТИРОВАТЬ: причина Я хочу сделать это, мыпреследуют кошмарную ошибку, когда код падает в режиме выпуска, но не в режиме отладки.По независящим от нас причинам мы не можем скомпилировать код выпуска с символами отладки, поэтому мы пытаемся добиться прогресса с помощью произвольных операторов печати.Если бы я мог сделать эту работу, мы бы по крайней мере сразу знали бы , где код падает, потому что вставленные операторы будут действовать как след.

Спасибо, Эндрю

Ответы [ 2 ]

6 голосов
/ 09 июля 2011

Просто чтобы задать очевидный вопрос: вы можете скомпилировать режим выпуска с отдельным файлом символов?

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

4 голосов
/ 09 июля 2011

Наш инструментарий реинжиниринга программного обеспечения DMS с C ++ Front End может сделать это довольно легко.Да, он коммерческий, но я не думаю, что есть много некоммерческих реальных решений для вашей задачи.

DMS - это механизм преобразования программ , который анализирует, анализирует и преобразует код в соответствии спредоставленное определение языка.Его интерфейс C ++ является определением языка для различных диалектов C ++.Как часть процесса синтаксического анализа для C ++, DMS может создавать таблицы символов с точностью до компилятора.Это необходимо для задачи OP, чтобы отличить неоднозначный синтаксис, который может быть заявлением, от альтернативных объявлений, которые может представлять такой синтаксис.(См. Почему C ++ не может быть проанализирован с помощью синтаксического анализатора LR (1)? для примеров этого).

Значение в DMS для этой задачи состоит в том, что она разрешает источник висходные преобразования, применяемые к абстрактным синтаксическим деревьям, создаваемым синтаксическим анализом.Следующее правило DMS, написанное в синтаксисе DMS rule , вероятно, будет очень близко к тому, что нужно OP:

  domain Cpp~ANSI;

  rule instrument_statements(s: executable_statement):
       executable_statement->executable_statement
  " \s " ->  " { \s ; post_statement_call(); } "

Текст внутри meta quotes " ... " - это целевой домен синтаксис, в данном случае ANSI C ++. \ - это meta escape; \ s представляет любой исполняемый оператор .Это правило выполняет сопоставление всех синтаксических executeable_statements и заменяет их блоком из двух операторов, первый из которых является исходным оператором, а второй - тем, что OP хочет сделать после каждого оператора.Я предполагал, что OP просто хотел вызвать функцию, но он может захотеть чего-то более сложного, например, печати номеров строк, имен функций или параметров функций [требующих некоторых дополнительных правил преобразования].

Сопоставление с шаблоном и преобразование выполняются с использованием синтаксических синтаксических деревьев, поэтому его нельзя спутать с наличием чего-либо, похожего на код в строке, или комментария, или на самом деле не исполняемого и не исполняемогооператор (например, декларация) и т. д. [Есть небольшая деталь, которую я замаскировал, чтобы предотвратить рекурсивное применение этого правила к его результатам, но эта деталь легко управляется с помощью API-интерфейсов DMS]. После преобразования измененное синтаксическое деревопреобразован в скомпилированный исходный текст C ++.OP скомпилирует и запустит этот код вместо своего исходного кода.

Обратите внимание, что post_statement фактически не должен ничего печатать.Если он вызывает центральную функцию, OP может кодировать любые предикаты / операторы печати, которые он хочет контролировать, количество вывода / накладных расходов, которое использует post_statement.По сути, это может выступать в качестве программируемой точки останова.

Эта базовая идея вставки проб с помощью трансформационных методов используется в нашей линейке инструментов для тестирования покрытия и профилирования COTS, все из которых основаны непосредственно на DMS, включая нашу C ++ Test Coverage Tool .Для получения более подробной информации см. http://www.semdesigns.com/Company/Publications/TestCoverage.pdf

OP, вероятно, может найти использование нашего инструмента покрытия теста простым способом сделать что-то довольно близкое, но более легкое в выполнении. Инструмент тестирования покрытия вставляет специальные операторы захвата данных трассировки в начало каждого блока (безусловного) кода, а не после каждого отдельного оператора. Этот сбор данных трассировки на самом деле является вызовом макроса, код которого мы предоставляем в виде исходного кода как часть продукта покрытия тестирования. Хотя это и не предполагаемое использование, можно просто заменить этот макро-вызов на желаемую трассировку, и инструмент покрытия тестов фактически вставит желаемый код туда, где он поместил бы зонды. Вероятно, он все еще может зафиксировать имя функции и уникальную кодовую точку [инструмент тестирования покрытия производит их] в качестве замены для номера строки. То, что он не мог сделать, - это более сложные задачи, которые были бы возможны с собственно DMS. Например, нет никакого способа, которым макрос трассировки может получить в свои руки исходный номер строки; это теряется к тому времени, когда макрос вводится инструментом покрытия теста. (С DMS это не потеряно). Но есть способ преобразовать «уникальную кодовую точку» обратно в точную информацию о местоположении источника.

РЕДАКТИРОВАТЬ 7/10/2011: ОП может даже обнаружить, что запуск тестового покрытия в качестве инструмента тестового покрытия также может помочь ему. Если приложение, скомпилированное с тестовым покрытием, выполняется и не дает сбоя, «покрытый код» этого выполнения выполнялся хотя бы один раз и, следовательно, с меньшей вероятностью является источником проблемы. (Никаких гарантий: просто потому, что вы казнили, это не значит, что это правильно). Но намек на то, что проблема в другом месте; это может привести к устранению кода, который не является проблемой.

...