C: конвертировать A? B: C в, если (A) B еще C - PullRequest
5 голосов
/ 11 марта 2010

Я искал инструмент, который может конвертировать выражения кода C для формы:

a = (A) ? B : C;

в синтаксис «по умолчанию» с if / else операторами:

if (A)
  a = B
else
  a = C

Кто-нибудь знает инструмент, способный на такое преобразование?

Я работаю с GCC 4.4.2 и создаю предварительно обработанный файл с -E, но не хочу, чтобы в нем были такие структуры.

Edit: Также необходимо преобразовать следующий код:

a = ((A) ? B : C)->b;

Ответы [ 5 ]

12 голосов
/ 11 марта 2010

Coccinelle может сделать это довольно легко.

Coccinelle - программа соответствия и двигатель трансформации, который обеспечивает язык SmPL (семантический патч Язык) для указания желаемого совпадения и преобразования в C-коде. Coccinelle изначально была мишенью на выполнение залога Эволюция в Linux. Такие эволюции включают в себя изменения, которые необходимы в коде клиента в ответ на эволюции в библиотечных API, и может включить модификации, такие как переименование функция, добавив аргумент функции чья ценность как-то контекстно-зависимый, и реорганизация структура данных. Вне залога эволюция, Coccinelle успешно используется (нами и другими) для поиска и исправление ошибок в системном коде.

EDIT: Пример семантического патча:

@@ expression E; constant C; @@
(
  !E & !C
|
- !E & C
+ !(E & C)
)

Из документации:

Шаблон! X & y. Выражение этой формы почти всегда бессмысленно, потому что оно объединяет логический оператор с битовым оператором. В частности, если самый правый бит у равен 0, результат всегда будет равен 0. Этот семантический патч фокусируется на случае, когда у - константа.

У вас есть хороший набор примеров здесь .

Список рассылки действительно активен и полезен.

3 голосов
/ 13 марта 2010

Следующий семантический патч для Coccinelle выполнит преобразование.

@@
expression E1, E2, E3, E4;
@@

- E1 = E2 ? E3 : E4;
+ if (E2)
+   E1 = E3;
+ else
+   E1 = E4;

@@
type T;
identifier E5;
T *E3;
T *E4;
expression E1, E2;
@@

- E1 = ((E2) ? (E3) : (E4))->E5;
+ if (E2)
+   E1 = E3->E5;
+ else
+   E1 = E4->E5;


@@
type T;
identifier E5;
T E3;
T E4;
expression E1, E2;
@@

- E1 = ((E2) ? (E3) : (E4)).E5;
+ if (E2)
+   E1 = (E3).E5;
+ else
+   E1 = (E4).E5;
1 голос
/ 23 апреля 2010

Инструментарий реинжиниринга программного обеспечения DMS может сделать это путем применения программных преобразований.

Конкретное преобразование DMS, соответствующее вашему конкретному примеру:

domain C.

rule ifthenelseize_conditional_expression(a:lvalue,A:condition,B:term,C:term):
stmt -> stmt
=  " \a = \A ? \B : \C; "
-> " if (\A) \a = \B;  else \a=\C ; ".

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

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

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

Как заметили другие, это довольно простой случай, потому что вы указали, что он работает на уровне полного утверждения. Если вы хотите избавить код от любого назначения, похожего на этот оператор, с такими назначениями, встроенными в различные контексты (инициализаторы и т. Д.), Вам может понадобиться больший набор преобразований для обработки различного набора особых случаев, и вы можете необходимо создавать другие структуры кода (например, временные переменные соответствующего типа). Хорошая вещь о таком инструменте, как DMS, заключается в том, что он может явно вычислять символический тип для произвольного выражения (таким образом, объявление типа любых необходимых временных переменных) и что вы можете написать такой большой набор довольно просто и применить все из них.

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

Очевидно, что регулярные изменения в целом имеют смысл.

(DMS может применять программные преобразования от источника к источнику для многих языков, включая C, C ++, Java, C # и PHP).

0 голосов
/ 11 марта 2010

Если операторы такие регулярные, как этот, почему бы не запустить ваши файлы с помощью небольшого Perl-скрипта? Основная логика для поиска и преобразования проста для вашего примера строки. Вот голый подход:

use strict;
while(<>) {
    my $line = $_;
    chomp($line);
    if ( $line =~ m/(\S+)\s*=\s*\((\s*\S+\s*)\)\s*\?\s*(\S+)\s*:\s*(\S+)\s*;/ ) {
        print "if(" . $2 . ")\n\t" . $1 . " = " . $3 . "\nelse\n\t" . $1 . " = " . $4 . "\n";
    } else {
        print $line . "\n";
    }
}
exit(0);

Вы бы запустили это так:

perl transformer.pl < foo.c > foo.c.new

Конечно, становится все сложнее, если текстовый шаблон не такой регулярный, как тот, который вы опубликовали. Но бесплатно, быстро и легко попробовать.

0 голосов
/ 11 марта 2010

Мне неизвестно о такой вещи, как троичный оператор встроен в спецификации языка как ярлык для логики if ... единственный способ, которым я могу думать об этом, - вручную искать эти строки и переписать его в форму, где используется if ... в качестве общего согласия, троичный оператор работает так

expr_is_true ? exec_if_expr_is_TRUE : exec_if_expr_is_FALSE;

Если выражение оценено как истинное, выполнить часть между ? и :, в противном случае выполнить последнюю часть между : и ;. Было бы наоборот, если выражение оценивается как ложное

expr_is_false ? exec_if_expr_is_FALSE : exec_if_expr_is_TRUE;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...