Вы можете сделать это с помощью Program Transformation System (PTS). Это инструменты, которые анализируют исходный код на внутренние формы (обычно абстрактные деревья синтаксиса) и позволяют применять преобразования исходного кода в исходный код для изменения этих форм (деревьев). После того, как все изменения были сделаны, они могут регенерировать исходный код из модифицированного АСТ.
Некоторые PTS предназначены для работы только на одном конкретном языке (часто на одном диалекте). Более общие из них описывают язык программирования, который будет использоваться в качестве параметра, и поэтому могут использоваться для задач на многих языках.
Трансформации, как правило, записывается в виде,
if you see *this*, replace it by *that* when *condition*
где это и что являются модели выражены на языке источника, представляющего интерес, и состояние является дополнительным предикатом управления ли конкретной трансформации должен применяться. [Рассмотрим «если вы видите x/x, замените его на 1, когда x не равно 0» в качестве мотивационного примера для условного выражения]. Это обычно означает, что вы можете написать эти преобразования, не зная точную детализацию АСТ ... и вы можете прочитать эти преобразования после, которые вы их написали.
В качестве примера наш DMS Software Reengineering Toolkit с его JavaScript front end может выполнять операцию OP. Передняя часть JavaScript содержит точную грамматику для JavaScript, гарантируя, что исходный код правильно разбирается с AST; он также содержит атрибут AST для текста, используемый для регенерации текста в качестве конечного результата.
Мы предполагаем, что правила грамматики для отчетности за ECMAScript были отмечены как ассоциативно:
[associative] StatementList = StatementList Statement;
Это означает, что вы можете вставить заявление в середине такого списка, не изменяя его (ассоциативный) список похожее свойство.
Вот (непроверенные, но очень близко к правой) правила для DMS, чтобы сделать работу:
domain ECMAScript~MicrosoftNetscape; -- establish language/dialect of interest
rule break_up_complex_var1(vdl: VariableDeclarationList, i: Identifier): StatementList -> StatementList =
"var \vdl, \i;" -> "var \vdl; var \i;"
rule break_up_complex_var2(vdl: VariableDeclarationList, i: Identifier, e: Expression): StatementList -> StatementList =
"var \vdl, \i=\e;" -> "var \vdl; var \i=\e;"
ruleset break_up_complex_var =
{ break_up_complex_var1,
break_up_complex_var2 };
DMS переписывать правила имеют имена (например, break_up_complex_var1 и ... var2), и работают над шаблонами, написанными в метафорами «....», которые используются для выделения синтаксиса целевого языка (например, ECMAScript) из синтаксиса правил перезаписи DMS.В метакаре цитированный элемент представляет собой переменную соответствия шаблону , которая представляет собой подфразу языка, описанную в заголовке правила, например, «\ i» относится к идентификатору. Каждое правило имеет шаблон (это) и замену (, что), каждый из которых написан в метаконах. Смешное -> операторское средство заменено на. Переменные соответствия шаблонов привязаны по левой стороне; связанное значение неявно заменяется в правильном шаблоне, если здесь упоминается переменная шаблона. Эти конкретные правила не требуют условий. Подробнее о DMS Rewrite Rule formalism can be found here.
Мы предоставляем два правила: один для обработки случая объявления переменной, который не инициализирован, и один для обработки случая, когда объявление выполняется с инициализацией. В обоих случаях мы указываем, что мы хотим забрать то, что составляет последнее объявление в инструкции var, и сделать отдельный оператор var для этой последней декларации. В наборе говорится, что DMS рассматривает эти два правила как набор; легко заставить DMS применять этот набор правил повсюду (не показано в этом ответе). После применения правил DMS отпечатывает модифицированные АСТ. Вуаля.
Это довольно простое применение DMS, но оно будет полностью надежным. Узоры точны; они не могут сопоставлять ничего, кроме того, что они описывают. Замены требуются для синтаксически хорошо сформированного DMS; это не гарантирует правильность, но является необходимым условием правильности, которое также ловит множество глупых ошибок при определении правил. В этом случае правила семантически правильны, и это должно быть очевидным путем проверки (например, вы можете читать правила после того, как их кто-то написал).
Учитывая, что инициализатор выражение («контекст бесплатно») может быть сколь угодно сложным и содержать вложенный() {} и [], вы не можете осуществить это с текстом хакерством или даже текстом взлома с регулярными выражениями. ПТС - это правильный способ сделать это.
Обычно мы делаем более сложные вещи с помощью DMS, но это хороший простой пример. (Я не уверен, что эта задача мотивирует фактически использовать DMS для достижения специфического эффекта OP). Более интересные задачи включают в себя использование десятков преобразований (и часто некоторые дополнительные анализы кода, не обсуждаемые здесь), все последовательности для решения сложных массивных задач рефакторинга. Должно быть ясно, что эти более сложные задачи не могут быть выполнены путем хакерства строк с помощью регулярных выражений.
Мне нравится downvoters. Это напрямую отвечает на вопрос ОФ. –