2010-03-11 1 views
5

я искал инструмент, который может преобразовывать выражения кода C для формы:C: Конвертировать A? B: 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; 
+0

Это кричит «потрясающий, отрывочный макрос!». мне. –

+1

Это только один файл? Если это возможно, вы можете сделать это со сложным регулярным выражением и функцией замены поиска редактора, который может это сделать. –

+23

Почему? Вы должны учитывать, что существуют ситуации, когда семантический эквивалент отсутствует. Нет ничего плохого в тернарном операторе. – GManNickG

ответ

12

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

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

EDIT: Пример семантической пластыря:

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

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

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

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

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

0

Я не знаю, как троичный оператор встроен в спецификации языка как ярлык для логики 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; 
0

Если заявления очень регулярно, как это почему бы не запускать файлы через небольшой скрипт на 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

Это не работает для: a = ((A)? B: C) -> b; – tur1ng

+0

Я предупреждал вас, что это было только для примера, который вы предоставили. :) Вместо того, чтобы пытаться написать какое-нибудь регулярное выражение uber, вы могли бы сделать этот второй случай elsif довольно легко: m/(\ S +) \ s * = \ s * \ (\ s * \ ((\ s * \ S + \ s *) \) \ s * \? \ s * (\ S +) \ s *: \ s * (\ S +) \ s * \) \ s * -> \ s * (\ S +) \ s *;/- - вызов разыменования - это группа соответствия $ 4. –

+1

@ tur1ng: Я думаю, что пример с the->, вероятно, не может остаться без временной переменной. –

3

Следующий семантический патч для 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

DMS Software Reengineering Toolkit может это сделать, применяя программные преобразования.

Конкретного преобразование 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).