我正在尝试为一种模板(配置)文件构建一个简单的LR解析器,该文件将用于生成其他一些文件。我已阅读并阅读有关LR解析器的内容,但我似乎无法理解它!我知道有一个解析堆栈,一个状态堆栈和一个解析表。令牌被读入解析堆栈,当匹配规则时,令牌被移位或减少,具体取决于解析表。这将继续递归,直到所有令牌都减少,然后解析完成。
问题是我真的不知道如何生成解析表。我已经阅读了不少描述,但语言是技术性的,我只是不明白。谁能告诉我怎么会这样呢?
另外,我如何存储像语法规则这样的东西?
http://codepad.org/oRjnKacH是我试图通过语法语法尝试解析的文件示例。
我之前从未这样做过,所以我只是在寻找一些建议,谢谢。
答案 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)将对规则和代码进行描述,并将其转换为可编译的代码。除非你手动这样做,否则你不会自己操纵这些表。