如何使用Flex实施两遍扫描仪?

时间:2020-03-06 14:27:34  来源:igfitidea点击:

作为一个宠物项目,我想尝试实现自己设计的基本语言,该语言可以用作网络脚本语言。将C ++程序作为Apache CGI运行很简单,因此真正的工作在于如何解析包含非代码(HTML / CSS标记)和服务器端代码的输入文件。

在我的本科编译器课程中,我们使用Flex和Bison生成了用于简单语言的扫描器和解析器。我们得到了语法的副本,并编写了一个解析器,将简单的语言转换为虚拟机的简单程序集。 Flex扫描器将输入标记化,然后将标记传递给Bison解析器。

那和我想做的事情之间的区别是,像PHP一样,这种语言可以具有简单的HTML标记,而脚本语言则像下面这样散布:

<p>Hello,
<? echo "World ?>
</p>

我是否认为按如下所述解析输入文件会比较有效,这是不正确的吗?

  • 控制权返回到继续该常规模式的第一台扫描仪。

基本上,第一个扫描器仅区分标记(未经修改直接返回到浏览器)和代码,后者传递给第二个扫描器,后者依次标记代码并将标记传递给解析器。

如果这不是可靠的设计模式,那么PHP之类的语言如何有效地处理扫描输入和解析代码?

解决方案

PHP不会区分扫描和标记。在标记模式下,它仅输出到缓冲区,而在代码模式下,则切换到解析。我们不需要两遍扫描仪,只需一个flex lexer即可完成此操作。

如果我们对PHP本身的工作方式感兴趣,请下载源代码(尝试使用PHP4源代码更容易理解)。我们要查看的是Zend目录" zend_language_scanner.l"。

写过类似的文章后,我真的建议我们重新考虑走Flex和Bison路线,并选择类似Antlr的现代语言。它更容易,更容易理解(lex语法中使用的宏变得非常混乱且难以阅读),并且具有内置的调试器(AntlrWorks),因此我们不必花费数小时来查看3个Meg调试文件。它还支持多种语言(Java,c#,C,Python,Actionscript),并且有一本出色的书和一个很好的网站,应该能够立即使我们启动并运行。

我们想查看开始条件。例如:

"<?"            { BEGIN (PHP); }
<PHP>[a-zA-Z]*  { return PHP_TOKEN; }
<PHP>">?"       { BEGIN (0); }
[a-zA-Z]*       { return HTML_TOKEN; }

我们从状态0开始,使用BEGIN宏更改状态。
要仅在处于特定状态时匹配RE,请在RE前面加上由尖括号括起来的状态名称。

在上面的示例中," PHP"为状态。 " PHP_TOKEN"和" HTML_TOKEN"是yacc文件所定义的_%token_s。