Вам нужна система трансформации программы (PTS).
Это инструменты, которые считывают исходный код, создают структуры данных компилятора (почти всегда включая как минимум AST), выполняют индивидуальный анализ и модификацию структур данных компилятора, а затем регенерируют исходный текст (для измененной программы) из этих измененных структур данных. .
Многие из PTS позволят вам выражать изменения в коде непосредственно в форме исходного кода в виде правил, выраженных в терминах синтаксиса языка, метапеременных и т. д. Смысл такого языка правил в том, чтобы позволить вам более точно выражать сложные преобразования кода. без труда.
Наш набор инструментов для реинжиниринга программного обеспечения DMS является таким PTS. Вы можете легко упростить код с помощью логических выражений, содержащих логические константы, со следующими простыми правилами:
default domain Java~v7;
simplify_not_true(): primary -> primary
" ! true" -> "false";
simplify_not_false(): primary -> primary
" ! false" -> "true";
simplify_not_not(x: primary): primary -> primary
" ! ! \x " -> "\x";
simplify_and_right_true(x: term): conjunction -> conjunction ;
" \x && true " -> "\x";
simplify_and_left_true(x: term): conjunction -> conjunction ;
" true && \x " -> "\x";
simplify_and_left_false(x: term): conjunction -> conjunction ;
" false && \x " -> "false";
simplify_and_right_false(x: term): conjunction -> conjunction ;
" \x && false " -> "false"
if no_side_effects_or_exceptions(x); -- note additional semantic check here
simplify_or_right_false(x: term): disjunction -> disjunction ;
" \x || false " -> "\x";
simplify_or_left_false(x: term): disjunction -> disjunction ;
" false || \x " -> "\x";
simplify_or_right_true(x: term): disjunction -> disjunction ;
" \x || true " -> "true"
if no_side_effects_or_exceptions(x);
simplify_or_left_true(x: term): disjunction -> disjunction ;
" true || \x " -> "true";
(Имена грамматик «термин», «первичный», «союз», «дизъюнкция» взяты непосредственно из BNF, используемого для анализа исходного кода Java.)
Вместе эти правила будут принимать логические выражения, включающие известные логические константы, и иногда упрощать их до просто «истина» или «ложь».
Чтобы исключить операторы if, выражения которых являются булевыми константами, можно было бы написать следующее:
simplify_if_true(b: block): statement -> statement
" if (true) \b" -> " \b ";
simplify_if_false(b: block): statement -> statement
" if (false) \b" -> ";" -- null statement
Вместе с логическим упрощением эти два правила избавят вас от условных выражений для заведомо истинных или заведомо ложных условных выражений.
Сделать то, что вы хотите, немного сложнее, потому что вы хотите распространять информацию из одного места в программе в другое место, возможно, «далеко». Для этого вам нужен анализ потока данных, показывающий, куда могут попасть значения из их назначений:
default domain Java~v7;
rule propagate_constant_variables(i:IDENTIFIER): term -> term
" \i " -> construct_reaching_constant()
if constant_reaches(i);
Это правило зависит от встроенного анализа, предоставляющего факты о потоках данных, и пользовательской функции интерфейса «constant_reaches», которая проверяет эти данные. (DMS имеет это для C, C++, Java и COBOL и поддерживает это для других языков; насколько мне известно, ни один из других PTS, упомянутых в статье Википедии, не имеет этих доступных фактов о потоке). Также зависит от пользовательского конструктора "contruct_reaching_constant" для построения узла примитивного дерева, содержащего константу достижения. Они будут закодированы на базовом языке метапрограммирования DMS и потребуют нескольких десятков строк кода. Аналогично рассмотренному ранее специальному условию "no_side_effects_or_exceptions"; это может быть намного сложнее, так как вопрос о побочных эффектах может потребовать анализа всей программы.
Есть такие инструменты, как Clang, которые могут до некоторой степени преобразовывать код C++, но Clang не имеет правил перезаписи, как в PTS, это действительно компилятор с дополнительными хуками.
person
Ira Baxter
schedule
13.04.2014