创建自定义PHP语法分析器

时间:2012-10-03 21:19:13

标签: php javascript syntax

我正在考虑如何为我为CSS和JS找到的几个库创建PHP等价物。

一个是Less CSSdynamic stylesheet languageLess CSS背后的基本思想是,它允许您创建更多动态CSS规则,其中包含“常规”CSS不支持的实体,例如mixinsfunctions等,然后是最终的{{ 1}} 将这些语法编译成常规CSS。

另一个有趣的JS库,其行为类似于一种类似的模式Less CSS,您可以在其中编写“更整洁,更简单”的代码,然后将编译转换为常规Javascript。< / p>

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

CoffeeScript

假设我想让用户将类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(); 写为(仅用于示例):

b

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

1 个答案:

答案 0 :(得分:5)

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

您提供的示例可以通过preg_replace非常轻松地实现,该[a]查找类定义并将extends a替换为$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( /* ... */ ) ) ) );

但更复杂的功能需要一个转码器,这是一套较小的逻辑代码。

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

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

但是关于行话的说法已经足够让我们谈论转码器了:

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

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

tokenizer创建一个包含它找到的所有标记的平面列表,并将其提供给解析器。

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

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

{{1}}

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

真正棘手的部分是解析器(取决于您正在解析的语言的复杂性)可能需要回溯算法或其他形式的模式匹配来区分相似的案例。

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

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