执行 php 脚本,其中没有循环或分支语句

execute php script without loops or branching statement in it

一个PHP解析器,可以剥离所有循环语句和分支语句并执行其他

PHP 代码例如:-

输入

<?php
if(1){
echo "hello";
}
while(1){
echo "world";
}

输出

<?php
echo "hello";
echo "world";

如果没有完整的语言解析器,这很难做到。

您可以使用 program transformation system (PTS) 来做到这一点。这些工具可以将源代码解析为编译器数据结构(通常是抽象语法树 [AST]),可以对 AST 进行更改,然后可以从修改后的编译器数据结构中重新生成有效的源文本。

弱的 PTS 只会让你以程序的方式遍历 tree/inspect/change 它,这是编译器的经典方式。使用这种方法,您必须非常熟悉数据结构(例如,您必须知道树的精确结构),并且对于真正的语言,有很多细节需要了解并正确处理。如果你有很大的热情,这会奏效。

一个好的 PTS 可以让您提供源到源的转换,它将用于 search/change 树。这样的重写看起来像:

  when you see *thispattern*, replace it by *thatpattern*, if *condition*

其中 thispatternthatpattern 是用要转换的源语言编写的模式。 PTS 负责将它们转换为相应的编译器数据结构,因此您可以使用更少的知识。

在OP的情况下,他需要一个可以解析和转换的PTS PHP。

我所知道的唯一 "good" PTS 是我们的 DMS Software Reengineering Toolkit with its PHP front end.

您必须编写一个简短的 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".

thispatternthatpattern 写在 metaquotes ".. . 区分源程序模式文本和重写规则语言本身的语法。使用元引号,人们会发现 与模式变量 \x 混合的源语言文本,其语法类别在模式变量声明中声明为 x: category。 您确实必须了解该语言的主要语法类别(例如,"statement" 与 "statements" 与 "expression",但您并不了解 while 循环的所有内部结构。

规则集将一组有趣的命名规则组合成一个方便的包,可以批量应用;您可以看到 DMS 元程序中是如何提及此规则集的。

编写此规则集时使用的一个技巧是让每个规则将其受控内容元素剥离到块 { ... } 中,因为块作为语句是可接受的。清理规则 strip_useless_blocks 然后会删除所有创建的异常块。

你可以see more about how DMS rewrite rules are written here.

这些重写规则将通过随后的一系列阶段逐步转换 OP 的程序(您可以在每次转换后打印完整的 AST 以查看此内容):

开始:

<?php
if(1){
echo "hello";
}
while(1){
echo "world";
}

在strip_if_then之后:

<?php
{
echo "hello";
}
while(1){
echo "world";
}

在 strip_while 之后:

<?php
{
echo "hello";
}
{
echo "world";
}

第一次应用 strip_useless_block 后:

<?php
echo "hello";
{
echo "world";
}

第二次应用 strip_useless_block 后:

<?php
echo "hello";
echo "world";

我们得到了 OP 想要的结果。这在大文件上更加壮观。

所以,OP 的任务很容易用一个好的 PTS 来完成。

我承认我不知道为什么有人想要像这样剥离控制流。但 PTS 的重点是您可以配置以执行难以手动完成的任意代码更改任务。