Конечно. Ознакомьтесь с Инструментами преобразования программы (PTS). Такие инструменты предоставляют средства для определения грамматики, использования этой грамматики для синтаксического анализа исходного текста в AST и точной печати AST обратно в текст. Что еще более важно, одна и та же грамматика используется для чтения правил преобразования от источника к источнику, что позволяет напрямую выражать преобразования (или выражать составные преобразования в терминах наборов перезаписи). Такие преобразования используют выраженные шаблоны для сопоставления с AST и модифицируют AST; эти преобразования, основанные на структуре, не путаются из-за макета или пробелов.
Например, наш набор инструментов для реинжиниринга программного обеспечения DMS позволяет вам писать правила в форме если вы видите это, замените это на это, принимая общую форму:
rule rule_name(pattern_variables)
: pattern_syntax_category -> replacement_syntax_category
= metaquote pattern_text_in_specified_language metaquote
=> metaquote replacement_text_in_specified_language metaquote
if condition_over_bound_pattern_variables;
куда
- правило – это синтаксис, вводящий правило.
- rule_name дает правилу имя, отличающее его от других правил,
- pattern_variables — это список пар n:c имени переменной шаблона n и синтаксической категории c, которые n должно удовлетворять,
- pattern_syntax_category – это синтаксическая категория, которой должен удовлетворять pattern_text.
- replacement_syntax_category – это синтаксическая категория, которой должен удовлетворять replacement_text. Обычно и во всех приведенных здесь примерах совпадает с pattern_syntax_category ; при использовании правил перезаписи для перевода между языками они часто отличаются, потому что категории синтаксиса в языках различаются.
- метакавычка – это символ ", который отделяет синтаксис языка правил от синтаксиса шаблона или замещающего языка.
- text_pattern_in_specified_language – это правильно сформированный фрагмент исходного языка, содержащий переменные шаблона n, записанные как \n; любое совпадение шаблона связывает переменные шаблона с поддеревьями. Если \n встречается в шаблоне дважды, оба экземпляра должны быть идентичными.
- replacement_text_in_specified_language — правильно сформированный фрагмент целевого языка. Найденный шаблон заменяется заменой, при этом любые переменные шаблона в замене заменяются значением связанной переменной шаблона.
- if — это синтаксис, вводящий условие
- condition_over_bound_pattern_variables – это ограничение, которому должны удовлетворять переменные шаблона после того, как будет найдено совпадение с шаблоном. Это часто используется для проверки условий контекста, которые должны быть удовлетворены.
DMS позволит вам написать и применить следующие примеры преобразований (включая некоторые примеры OP):
default domain Java~v8; -- specify v8 dialect of Java to manipulate
rule reduce_strength_squared(e: term):
:product -> product
= "\e ^ 2 " ==> "\e * \e "
if no_side_effects(e);
rule optimize_divide_by_self(e: term):
:product -> product
= " \e / \e " => " 1 " if is_not_zero(e);
rule accumulate_string(n: IDENTIFIER, a: expression, b: left_hand_side)
: statement -> statement
= "for (String \s: \a) { \b.add(\s); }"
=> "\b.addAll(\a);";
rule eliminate_useless_if(x: expression, s: statement)
: statement -> statement
= "if (\x) \s; else \s; " -- generalizes OP's example
=> "\s;";
rule left_factor_ternary(x: expression; t: left_hand_side; a: expression; b:expression)
: statement -> statement
= "if (\x) { \t = \a;} else {\t = \b;} "
=> "\t = \x ? \a : \b ";
rule convert_to_diamond( T1: qualified_path, T2: qualified_path,
C: qualified_path,
i: IDENTIFIER, a: arglist)
:statement -> statement
= "\T1<\T2> \i = new \C<\T2>(\a);"
=> "\T1<\T2> \i = new \C<>(\a);"
rule merge_multi_catch( b:body, i1: IDENTIFIER, e1: qualified_path,
i2: IDENTIFIER, eh: body )
:statement -> statement
= "try { \b }
catch ( \i1: \e1 ) { \eh }
catch ( \i2: \e1 ) { \eh }";
=> "try { \b }
catch ( \i1, \i2: \e1 ) { \eh }";
Возможны более сложные преобразования, включая те, которые затрагивают части программы, находящиеся далеко друг от друга и даже за границами исходного файла. Обычно это требует некоторого дополнительного метапрограммирования (здесь не обсуждается) и часто дополнительных проверок контекста, например, правильности типа идентификаторов и т. д. [Для поддержки этого в DMS есть полные таблицы символов для Java].
Другие PTS могут выражать правила аналогичным образом. Большинство из них не обеспечивают поддержку более глубоких семантических фактов, таких как таблицы символов или типы, хотя утверждается, что вы можете запрограммировать их самостоятельно. Опыт показывает, что это много работы, и вы действительно хотите, чтобы все было правильно. (Кто хочет, чтобы их преобразование повредило код из-за того, что он работает с неверной информацией?).
person
Ira Baxter
schedule
29.01.2015