我正在编写一个程序,要求我创建我的第一个真正的,有点复杂的解析器。我想了解解析算法的存在,以及如何创建"语法"。所以我的问题如下:
1)如何创建解析器可以理解的正式语法?语法的基本组成部分是什么?
2)存在哪些解析算法,以及在解析时各自超出哪种输入?
3)鉴于上述问题的广泛性,我可以阅读哪些好的参考资料来理解问题1和2的答案?
我正在寻找更多关于我需要的关键字/主题领域的概述,以便我自己查看详细信息。谢谢大家!
答案 0 :(得分:2)
您通常会编写无上下文语法 G
来描述某种形式语言 L
(例如,所有语法上有效的C语言集)程序)这只是一组特定字母表上的字符串(想想所有格式良好的C程序;或者所有格式良好的HTML文档;或者所有格式良好的MARKDOWN帖子;所有这些都是有限字符串集合ASCII字符集的某些子集)。之后,您为给定的语法提出了解析器 - 也就是说,给定字符串w
的算法决定是否可以派生字符串w
通过语法G
。 (例如,grammar of the C11 language描述了所有格式良好的C程序集。)
某些类型的语法允许简单实现解析器。在实践中经常使用的语法示例是LL grammars。 LL
语法的一个特殊子集,称为LL(1)
语法,具有以线性时间运行的解析器(在我们解析的字符串长度中是线性的)。
有更多通用的解析算法 - 最值得注意的是Early parser和CYK algorithm ---将inpuit作为字符串w
和语法G
和及时决定O(|w|^3)
字符w
是否可由语法G
推导出来。 (请注意这是多么酷:算法将语法作为一种方法。但我不认为这是在实践中使用。)
我前段时间用Java实现了Early parser。如果您有兴趣,则代码为available on GitHub。
有关整个过程的具体示例,请考虑括号()
,(())
,((()))()(())()
等所有平衡字符串的语言。我们可以使用以下语境对其进行描述 - 自由语法:
S -> (S) | SS | eps
其中eps
是空产品。例如,我们可以按如下方式派生字符串(())()
:S => SS => (S)S => ((S))S => (())S => (())(S) => (())()
。我们可以轻松地为这个语法实现一个解析器(左为练习: - )。
很好的参考是所谓的龙书:Aho等人的Compilers: Principles, Techniques, and Tools。它涵盖了所有重要主题。另一个很好的参考是Hopcroft等人的经典着作Introduction to Automata Theory, Languages, and Computation 。