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

C++ 我应该如何构建一个简单的LR解析器?,c++,parsing,configuration,file,C++,Parsing,Configuration,File,我正在尝试为一种模板(配置)文件构建一个简单的LR解析器,该模板(配置)文件将用于生成其他一些文件。我已经读了很多关于LR解析器的书,但我就是不明白!我知道有一个解析堆栈、一个状态堆栈和一个解析表。令牌被读取到解析堆栈上,当规则匹配时,令牌被移位或缩减,具体取决于解析表。这将递归地继续,直到所有标记都减少,然后解析完成 问题是我真的不知道如何生成解析表。我读过很多描述,但语言是技术性的,我就是不懂。有人能告诉我怎么做吗 还有,我如何存储语法规则之类的东西 是我试图解析的文件的一个示例,我试图用语

我正在尝试为一种模板(配置)文件构建一个简单的LR解析器,该模板(配置)文件将用于生成其他一些文件。我已经读了很多关于LR解析器的书,但我就是不明白!我知道有一个解析堆栈、一个状态堆栈和一个解析表。令牌被读取到解析堆栈上,当规则匹配时,令牌被移位或缩减,具体取决于解析表。这将递归地继续,直到所有标记都减少,然后解析完成

问题是我真的不知道如何生成解析表。我读过很多描述,但语言是技术性的,我就是不懂。有人能告诉我怎么做吗

还有,我如何存储语法规则之类的东西

是我试图解析的文件的一个示例,我试图用语法来解释它的语言


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

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

或者,正如gnu所称的——flex/bison

编辑:


Perl有Parse::RecDescent,这是一个递归下降解析器,但对于简单的工作来说,它可能工作得更好。

您不能像这样理解它

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

更像

函数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代码中获取有关要查找的标记的更新数据。

您需要阅读有关ANTLR的信息。

我查看了文件格式的定义,虽然我不知道为什么您需要一个LR解析器,但我的第一个想法是为什么不使用xml或json等现有格式。沿着parsergenerator路线走下去通常会有很高的启动成本,这对于您正在寻找解析的简单数据来说是没有回报的

正如paul所说,lex/yacc是一种选择,您可能还想看看

一年前,我写了一个更大的解析器,供Qt/Nokia用户使用。当我研究解析器时,这一个虽然文档很少,但它的启动空间最小(只有一个工具),但它不支持词法分析。我当时无法计算出C++的支持。
10000英里视图:一般来说,您将看到两个组件:一个lexer,它接收输入符号并将其转换为高阶令牌。为了使用标记,语法描述将声明规则,通常您将在规则中包含一些代码,当规则匹配时,将执行这些代码。编译器生成器(如yacc)将获取您对规则和代码的描述,并将其转换为可编译代码。除非你是手工操作,否则你不会自己操作桌子

在您对解析器理论的研究中,您似乎忽略了一个更实际的事实:几乎没有人会像您所讨论的那样考虑手工编写一个表驱动、自底向上的解析器。出于最实际的目的,手写解析器使用自顶向下(通常是递归下降)结构

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

显然,如果你真的想,完全可以用手来做,但几乎没有真正的意义。完全用手工制作桌子本身就非常痛苦

例如,您通常从构造NFA开始,NFA是一个大表——通常,每个解析器状态对应一行,每个可能的解析器状态对应一列。在每个单元格中,当您开始进入下一个状态时,您对该状态进行编码,然后接收该输入。这些转换中的大多数基本上是空的(也就是说,当您处于该状态时,它们只是说不允许输入)

然后逐步完成所有这些步骤,并遵循一些相当简单的规则,将NFA状态集收集在一起,成为DFA中的一个状态。这些规则非常简单,很容易将它们编程到计算机中,但您必须对NFA表中的每个单元格重复这些规则,并进行基本上完美的簿记,以生成正确工作的DFA

计算机可以而且将会很好地做到这一点——对于它来说,对NFA中的两万个细胞中的每一个应用几个简单的规则