创建自定义PHP语法分析器

Und*_*ble 6 javascript php syntax

我正在考虑如何为我发现的CSS和JS的几个库创建一个PHP等价物.

一个Less CSS是一个dynamic stylesheet language.背后的基本想法Less CSS是,它可以让你创建包含实体更有活力的CSS规则,"规则" CSS并不如支持mixins,functions等等,然后最终Less CSS 编译那些语法到常规的CSS.

另一个有趣的JS库,其行为类似于一种类似的模式CoffeeScript,您可以编写"更整洁,更简单"的代码,然后将其编译为常规Javascript.

如何为PHP创建一个简单的类似界面?就像一个概念证明; 我只是想学习东西.让我们来看一个扩展类的简单用例.

class a
{
    function a_test()
    {
        echo "This is test in a ";
    }
}

class b extends a
{
    function b_test()
    {
        parent::a_test();
        echo "This is test in b";
    }
}

$b = new b();
$b->b_test();
Run Code Online (Sandbox Code Playgroud)

假设我想让用户编写类b(仅用于示例):

class b[a] //would mean b extends a
{
    function b_test()
    {
        [a_test] //would mean parent::a_test()
        echo "This is test in b";
    }
}
Run Code Online (Sandbox Code Playgroud)

然后让他们让代码"解析"到常规PHP(通常通过运行一个单独的命令/进程,我相信).我的问题是我将如何创建这样的东西.可以用PHP完成,我是否需要使用像C/C++这样的东西.如果我要去做,我应该如何处理这个问题?网上有资源吗?任何指针都非常感谢!

Mih*_*ncu 6

语言转码器并不像人们想象的那么容易.

您提供的示例可以非常轻松地实现preg_replace,查找类定义并替换[a]extends a.

但更复杂的功能需要一个代码转换器,它是一套较小的逻辑代码片段.

在大多数程序员行话中,人们错误地调用了代码转换器编译器,但编译器和代码转换之间的区别在于编译器读取源代码并输出原始二进制机器代码,而代码转换器读取源代码和输出(不同的)源代码.

例如,PHP(或JavaScript)运行时既不是编译器也不是代码转换器,它是一个解释器.

但是关于行话的足够让我们谈谈转码器:

要构建代码转换器,您必须首先构建一个标记生成器,它将源代码分解为标记,这意味着如果它看到整个单词,如"类"或类的名称或"函数"或函数的名称,它捕获该单词并将其视为令牌.当遇到另一个令牌,例如开口圆括号或开口支架或方括号等时,它会考虑另一个令牌.

幸运的是,PHP中提供的所有已识别令牌都已经被token_get_all轻松扫描,这是PHP捆绑的功能.您可能会遇到一些问题,因为PHP会假设您使用符号的方式,但总而言之,您可以使用此功能.

标记生成器创建它找到的所有标记的平面列表,并将其提供给解析器.

解析器是你的代码转换器的第二阶段,它读取令牌列表并决定诸如"如果令牌[0]是一个类而令牌[1]是一个name_value然后我们有一个类"等等.整个令牌列表我们应该有一个抽象的语法树.

抽象语法树是一种象征性地仅保留有关源代码的相关信息的结构.

$ast = array(
    'my_derived_class' => array(
        'implements' => array(
            'my_interface_1',
            'my_interface_2',
            'my_interface_3'),
        'extends' => 'my_base_class',
        'members' => array(
            'my_property_name' => 'my_default_value',
            'my_method_name' => array( /* ... */ )
        )
    )
);
Run Code Online (Sandbox Code Playgroud)

获得抽象语法树后,您需要遍历它并输出目标源代码.

真正棘手的部分是解析器(根据您正在解析的语言的复杂性)可能需要回溯算法或某种其他形式的模式匹配来区分相似的情况.

我建议在Terence Parr的书籍http://pragprog.com/book/tpdsl/language-implementation-patterns中阅读此内容,该书详细描述了编写代码转换器所需的设计模式.

在Terrence的书中,你会发现为什么某些语言(如HTML或CSS)比PHP或JavaScript更简单(结构上),以及它如何与语言分析器的复杂性相关联.

  • 如果您要在答案中添加引用“ token_get_all”的部分,则将删除答案。这是更详细的。 (2认同)
  • PHP-Parser在这里可能是有用的库:https://github.com/nikic/PHP-Parser (2认同)