我该如何构建一个简单的LR解析器?

时间:2010-02-23 19:23:51

标签: c++ parsing configuration file

我正在尝试为一种模板(配置)文件构建一个简单的LR解析器,该文件将用于生成其他一些文件。我已阅读并阅读有关LR解析器的内容,但我似乎无法理解它!我知道有一个解析堆栈,一个状态堆栈和一个解析表。令牌被读入解析堆栈,当匹配规则时,令牌被移位或减少,具体取决于解析表。这将继续递归,直到所有令牌都减少,然后解析完成。

问题是我真的不知道如何生成解析表。我已经阅读了不少描述,但语言是技术性的,我只是不明白。谁能告诉我怎么会这样呢?

另外,我如何存储像语法规则这样的东西?

http://codepad.org/oRjnKacH是我试图通过语法语法尝试解析的文件示例。

我之前从未这样做过,所以我只是在寻找一些建议,谢谢。

5 个答案:

答案 0 :(得分:6)

在你对解析器理论的研究中,你似乎错过了一个更实际的事实:几乎没有人会考虑像你正在讨论的那样用手写自下而上的解析器。对于大多数实际用途,手写解析器使用自上而下(通常是递归下降)结构。

使用表驱动解析器的主要原因是它允许您编写(相当)少量操作表的代码,这几乎完全是通用的(即它适用于任何解析器)。然后,将关于特定语法的所有内容编码为一个易于计算机操作的形式(即某些表格)。

显然,如果你真的想要,手动完成它将完全可能,但几乎从来没有真正的意义。完全手动生成表格本身就非常令人难以忍受。

例如,您通常首先构建一个NFA,它是一个大表 - 通常,每个解析器状态一行,每个可能一列。在每个单元格中,编码在该状态下启动时要输入的下一个状态,然后接收该输入。大多数这些转换基本上都是空的(即它们只是说当你处于那种状态时不允许输入。)

然后逐步完成所有这些操作并遵循一些相当简单的规则来收集NFA状态集合,以成为DFA中的状态。规则很简单,很容易将它们编程到计算机中,但是您必须为NFA表中的每个单元重复它们,并且基本上完成簿记以生成可用的DFA正确。

计算机可以并且将会很好地做到这一点 - 因为,对NFA状态表中的每两万个单元中应用几个简单的规则是件小事。很难想象让一个人做同样的事情 - 我很确定在联合国的指导下,那将是非法的折磨。

答案 1 :(得分:1)

经典的解决方案是lex / yacc组合:

http://dinosaur.compilertools.net/yacc/index.html

或者,正如gnu所称 - flex / bison。

编辑:

Perl有一个Parse :: RecDescent,它是一个递归下降解析器,但它可以更好地用于简单的工作。

答案 2 :(得分:1)

你需要了解ANTLR

答案 3 :(得分:0)

嗯,你无法理解它

“函数A1对对象B执行f,然后函数A2执行g到D等”

更像是

“功能A执行动作{a,b,c,d,e,f,g,h,i,j,k,l,m,n,o或p,或no-op}并切换/减少在{B,C,D,E,F或G}类型的堆栈头处对象{1-1567}的某个计数及其包含N级的对象,其可能具有{H,I,J,K或L类型在某些组合中根据规则列表“

它确实需要一个数据表(或者像数据表一样生成的代码,比如一组BNF语法数据)告诉函数该做什么。

您可以从头开始编写。你也可以用睫毛刷刷墙。您可以在运行时解释数据表。你也可以放睡眠(1000);每隔一行代码中的语句。不是我也尝试过。

编译器很复杂。因此编译器生成器。

修改

您正尝试根据文件本身的内容定义令牌。

我认为您“不想使用正则表达式”的原因是您希望能够访问文本块中不同标记的行号信息,而不仅仅是整个文本块。如果每个单词的行号是不必要的,并且整个块将适合内存,我倾向于将整个括号内的块建模为令牌,因为这可能会提高处理速度。无论哪种方式,您都需要自定义yylex功能。首先生成一个带有固定标记“[”和“]”的lex,用于内容的开始和结束,然后冻结并修改它以获取有关从yacc代码中查找哪些标记的更新数据。

答案 4 :(得分:0)

我查看了你的fileformat的定义,虽然我错过了一些你想要特定LR解析器的上下文,但我首先想到的是为什么不使用像xml或json这样的现有格式。沿着解析器生成器路由往往具有较高的启动成本,无法为您要解析的简单数据付出代价。

正如保罗所说,lex / yacc是一个选项,你可能还想看看Boost::Spirit

我曾与之合作过,一年前,Qt /诺基亚人使用QLALR编写了一个更大的解析器。当我研究解析器时,尽管这个解析器非常缺乏文档,但它的起始占用空间最小(只有1个工具),但它不支持词法分析。 IIRC我当时无法在ANTLR中找到C ++支持。

10,000英里视图:一般来说,您正在查看两个组件,即词法分析器,它采用输入符号并将其转换为更高阶令牌。为了处理令牌,你的语法描述将陈述规则,通常你会在规则中包含一些代码,这些代码将在规则匹配时执行。编译器生成器(例如yacc)将对规则和代码进行描述,并将其转换为可编译的代码。除非你手动这样做,否则你不会自己操纵这些表。