Источник к источнику манипуляций - PullRequest
4 голосов
/ 15 августа 2011

Мне нужно сделать некоторые манипуляции от источника к источнику в ядре Linux.Я пытался использовать Clang для этой цели, но есть проблема.Clang выполняет предварительную обработку исходного кода, то есть макроса, и включает расширение.Это приводит к тому, что clang иногда создает неработающий код на языке C с точки зрения ядра Linux.Я не могу сохранить все изменения вручную, так как ожидаю иметь тысячи изменений на один файл.

Я пробовал ANTLR, но доступные общедоступные грамматики неполны и не подходят для таких проектов, как ядро ​​Linux.

Поэтому мой вопрос заключается в следующем.Существуют ли способы выполнения манипуляций с исходным кодом для кода C без предварительной обработки?

Итак, предположим следующий код.

#define AAA 1
void f1(int a){
    if(a == AAA)
        printf("hello");
}

После применения манипуляции от источника к источнику я хочу получить это

#define AAA 1
void f1(int a){
    if(functionCall(a == AAA))
        printf("hello");
}

Но Clang, например, производит следующий код, который не соответствует моим требованиям, то есть расширяетсямакрос AAA

#define AAA 1
void f1(int a){
    if(functionCall(a == 1))
        printf("hello");
}

Надеюсь, я был достаточно ясен.

Редактировать

Приведенный выше код является только примером.Манипуляции источник-источник, которые я хочу сделать, не ограничиваются подстановкой операторов if(), но также вставляют унарный оператор перед выражением, заменяют арифметическое выражение его положительным или отрицательным значением и т. Д.

Решение

Есть одно решение, которое я нашел для себя.Я использую gcc для получения предварительно обработанного исходного кода, а затем применяю Clang.Тогда у меня нет проблем с расширением макросов и включением, так как эта работа выполняется gcc.Спасибо за ответы!

Ответы [ 5 ]

4 голосов
/ 15 августа 2011

Вы можете рассмотреть http://coccinelle.lip6.fr/: это обеспечивает хорошую семантику исправления фреймворка.

2 голосов
/ 15 августа 2011

Идея состояла бы в том, чтобы заменить все вхождения

if(a == AAA)

на

if(functionCall(a == AAA))

Вы можете сделать это легко, например, с помощью инструмента sed.

Если у вас есть конечная коллекция шаблонов, которые нужно заменить, вы можете написать сценарий sed для выполнения замены.

Это решит вашу проблему?

0 голосов
/ 31 октября 2016

Я бы посоветовал прибегнуть к Rose framework. Источник доступен на github.

0 голосов
/ 19 августа 2011

Clang содержит чрезвычайно точную информацию об исходном коде.

В частности, SourceManager может определить, был ли данный токен раскрыт из макроса или записан как есть, и Чандлер Карут недавно внедрил диагностику макросов, которая способна отображать фактический стек расширения макроса (на различных этапы расширений) прослеживание до фактического написанного кода (3.0).

Таким образом, можно использовать сгенерированный AST, а затем переписать исходный код, сохранив все его макросы. Вам нужно было бы сделать запрос практически к каждому узлу, чтобы узнать, происходит ли он от расширения макроса или нет, и получает ли он исходный код расширения, но все же это кажется возможным.

  • В Clang есть модуль перезаписи
  • Вы можете найти код Чендлера в стеке диагностики макросов

Так что, я думаю, у вас должно быть все, что вам нужно :) (И надеюсь, потому что я больше не смогу помочь: p)

0 голосов
/ 15 августа 2011

Обработка препроцессора является одной из самых сложных проблем при применении преобразований к коду C (и C ++).

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

Это делается путем разрешения действий препроцессора в «хорошо структурированных» местах. Примеры: #defines разрешены там, где могут появляться объявления или операторы, вызовы макросов и условные выражения в качестве замены для многих нетерминалов в языке (например, заголовок функции, выражение, оператор, объявления) и во многих неструктурированных местах, которые люди обычно размещают их (например, #if fooif (...) {#endif). Он анализирует исходный код и директивы препроцессора, как если бы они были частью одного языка (они являются ARE, он называется «C»), и создает соответствующие AST, которые можно преобразовать и правильно восстановить с захваченными директивами препроцессора. [Этот уровень возможностей отлично подходит для примера OP.]

Некоторые директивы плохо размещены (как в смысле синтаксиса, например, в нескольких фрагментах языка, так и в смысле понятности «ты, должно быть, шутишь»). Эти DMS обрабатывают, расширяя их, под руководством опытного инженера («всегда расширяйте этот макрос»). Менее удовлетворительный подход состоит в том, чтобы вручную преобразовать неструктурированные условные выражения / макропроцессоры препроцессора в структурированные; это немного болезненно, но более выполнимо, чем можно было ожидать, поскольку плохие случаи встречаются значительно реже, чем хорошие.

Чтобы сделать это лучше, нужно иметь таблицы символов и анализ потока, которые учитывают условия препроцессора и фиксируют все условия препроцессора. Мы проделали некоторую экспериментальную работу с DMS для захвата условных объявлений в таблице символов (кажется, работает нормально), и мы только начинаем работу над схемой для последней.

Не просто быть зеленым.

...