Анализатор PHP, который может удалить все циклические операторы и операторы ветвления и выполнять другие
PHP коды, например: —
вход
<?php
if(1){
echo "hello";
}
while(1){
echo "world";
}
выход
<?php
echo "hello";
echo "world";
Это очень трудно сделать без полноценного парсера языка.
Вы можете сделать это с система трансформации программ (PTS). Это инструменты, которые могут анализировать исходный код в структурах данных компилятора (часто это — деревья абстрактного синтаксиса [AST]), могут вносить изменения в AST и затем восстанавливать действительный исходный текст из модифицированных структур данных компилятора.
Слабый PTS только позволит вам пройтись по дереву / осмотреть / изменить его процедурно, классическим способом, которым это делает компилятор. При таком подходе вы должны быть близко знакомы со структурами данных (например, вы должны знать точную структуру дерева), а для реального языка нужно знать много деталей и правильно их понять. Это работает, если у вас много энтузиазма.
Хороший PTS позволит вам предоставить преобразования источник-источник, которые он будет использовать для поиска / изменения дерева. Такие переписки выглядят так:
when you see *thispattern*, replace it by *thatpattern*, if *condition*
где thispattern а также thatpattern шаблоны, написанные на исходном языке, который трансформируется. PTS позаботится о преобразовании их в соответствующие структуры данных компилятора, чтобы вы могли обойтись с гораздо меньшими затратами.
В случае OP ему нужен PTS, который может анализировать и преобразовывать PHP.
Единственный «хороший» PTS, который я знаю, который может сделать это в готовом виде — это наш DMS Software Reengineering Toolkit с этими PHP интерфейс.
Вы должны написать короткую метапрограмму DMS, чтобы открыть и прочитать файл, получить преобразования и применить их, а затем просто распечатать результат (немного упрощая для ясности):
(define main
(action (procedure void)
(= AST (Registry:Parse PHPDomain `my_file.php'))
(Registry:ApplyTransforms AST (. `my_rewrite_rules.rsl') (. `strip_control_flow'))
(local (= [os OutputStream:Stream] (OutputSteam:Open `updated_my_file.php'))=
(Registry:PrettyPrint os PHPDomain AST))
(= os (OutputStream:Close os))
)local
)action
)define
Основная часть работы выполняется с помощью правил перезаписи DMS в файле «my_rewrite_rules.rsl»:
domain PHP~PHP5.
rule strip if_then(c: expression, s: statement):
statement -> statement =
" if (\c) \s" -> "\s".
rule strip if_then_else(c: expression, s1: statement, s2: statement):
statement -> statement =
" if (\c) \s1 else \s2" -> " { \s1 \s2 } ".
rule strip while(c: expression, s: statement):
statement -> statement =
" while (\c) \s" -> "\s".
rule strip catch( b1: statements, l: catch_clauses, t: type, e: expression, b2: statements):
statement -> statement =
" try { \b1 } \l catch ( \t \e ) { \b2 } "-> " { try { \b1 } \l ; \b2 } ".
rule strip_trivial_try( b1: statements):
statement -> statement =
" try { \b1 } " -> "{ \b1 }".
rule strip_useless_block( b:statements, s: statements):
statements -> statements =
" { \b } \s " -> " \b \s ".
ruleset strip_control_flow = {
strip_if_then,
strip_if_then_else,
strip_while,
strip_catch,
strip_trivial_try,
strip_useless_block }
и т.д. Я не охватил все случаи, но должно быть очевидно, как поступить.
Чтобы объяснить вышесказанное: правила перезаписи DMS принимают форму
rule rulename ( pattern_variable_declarations):
syntaxcategory -> syntaxcategory
"thispattern" -> "thatpattern".
thispattern а также thatpattern написаны внутри MetaQuotes «…» которые отличают текст шаблона исходной программы от синтаксиса самого языка правил перезаписи. С мета-цитатами можно найти
текст на исходном языке, смешанный с переменными шаблона \Икс чья синтаксическая категория объявлена как х: категория в объявлениях переменных шаблона.
Вы должны знать основные синтаксические категории языка (например, «оператор» против «операторы» против «выражение»), но вы не знаете обо всей внутренней структуре цикла while.
Набор правил группирует набор интересных именованных правил в удобный пакет, который можно применять в пакете; вы можете видеть, как этот набор правил упоминается в метапрограмме DMS.
Уловка, используемая при написании этого набора правил, состоит в том, чтобы каждое правило обрезало свои элементы управляемого содержимого в блок {…}, потому что блоки приемлемы как операторы. Затем правило очистки strip_useless_blocks избавляет от любых вопиющих блоков, которые были созданы.
Вы можете подробнее о том, как правила перезаписи DMS написаны здесь.
Эти правила перезаписи будут постепенно преобразовывать программу OP через серию следующих этапов (вы можете распечатать полные AST после каждого преобразования, чтобы увидеть это):
Начните:
<?php
if(1){
echo "hello";
}
while(1){
echo "world";
}
после strip_if_then:
<?php
{
echo "hello";
}
while(1){
echo "world";
}
после полосы
<?php
{
echo "hello";
}
{
echo "world";
}
после 1-го применения strip_useless_block:
<?php
echo "hello";
{
echo "world";
}
после 2-го применения strip_useless_block:
<?php
echo "hello";
echo "world";
и у нас есть желаемый результат ОП. Это намного более впечатляюще для большого файла.
Таким образом, задачу OP довольно легко выполнить с хорошим PTS.
Я признаю, что понятия не имею, почему кто-то хотел бы лишить поток управления таким образом. Но смысл PTS в том, что вы можете настроить выполнение задач произвольного изменения кода, которые трудно выполнить вручную.
Других решений пока нет …