C++ 解析器生成器的选择

C++ 解析器生成器的选择,c++,parsing,bison,lex,parser-generator,C++,Parsing,Bison,Lex,Parser Generator,好的,我理解这个问题听起来可能是基于观点的,但是因为我有几个具体的选择标准,我认为它非常适合这样做。所以,我在这里 我在过去从事过很多编译器/解释器的构建工作(显然大部分是作为一种爱好),出于某种原因,我坚持使用Lex/Yacc(或者Flex/Bison,我对他们现在如何称呼他们感到非常困惑……哈哈) 然而,由于我发现自己目前正在玩另一个业余译员项目,我想我应该尝试一些不同的东西,也许是为了避免我不喜欢Lex/Yacc的地方 So,即: 更好的C++友好型(比C友好型) 好的文档(最好是已经实

好的,我理解这个问题听起来可能是基于观点的,但是因为我有几个具体的选择标准,我认为它非常适合这样做。所以,我在这里

我在过去从事过很多编译器/解释器的构建工作(显然大部分是作为一种爱好),出于某种原因,我坚持使用Lex/Yacc(或者Flex/Bison,我对他们现在如何称呼他们感到非常困惑……哈哈)

然而,由于我发现自己目前正在玩另一个业余译员项目,我想我应该尝试一些不同的东西,也许是为了避免我不喜欢Lex/Yacc的地方

So,即:

  • 更好的C++友好型(比C友好型)
  • 好的文档(最好是已经实现了一些现有语法+关于如何编译/使用它们的说明-听起来很明显,是吧?)
  • 可以是LALR,LL(*),递归下降,我并不在乎(注意:输入您喜欢哪种类型以及哪种类型的实现会很好;老实说,我从来没有真正理解过它们的优缺点,尽管我知道它们指的是什么)
  • 将Lexer部分和解析器语法组合到一个文件中一点也不坏;从来没有真正明白为什么它必须一分为二
  • 最后但并非最不重要的一点是:我一直与。。。问题。我的意思是-至少对于Lex/Yacc来说,解析错误消息或多或少都是神秘的(
    语法错误
    …Yuhuu!),它们很少帮助诊断问题。(好吧,除非你是开发口译员的人……哈哈)。那么,在错误报告方面有什么比Lex/Yacc更好的吗

好吧,我希望那不是太冗长。我洗耳恭听!:-)

有趣的问题-我不确定我对你的实际问题有一个很好的答案,但我的“评论”太长了,不适合评论

我在Pascal编译器中工作,我已经写了差不多1100行的Loxer-ToKisher和解析器(包括生成AST,进入LVVM的代码生成器),如果我可以这么说的话,我自己的“C++”代码非常好。它对生成好的错误消息更加友好,并且有助于减少错误。缺少了几个位,在我的编译器完成之前,我还有很多工作要做,但我可以编译一些相当复杂的代码


我承认,我从来没有用过Lex/Yacc或Flex/Bison来做任何真实的事情。我有时会查看它,但我发现很难使用这些工具,您要么接受生成的代码并对其进行修改(使用自动生成的代码是个坏主意),要么错误处理很差,而且很难在此基础上调试代码。但是,我只花了大约两个小时试图找到由于过早“吃”分号而导致的错误,从而导致解析器在令牌流中丢失

我只想回答最后一个问题,稍加修改:

至少就Lex/Yacc而言,解析错误消息或多或少是神秘的(语法错误…Yuhuu!),它们很少帮助诊断问题。(好吧,除非你是开发口译员的人……哈哈)。那么,关于错误报告,还有什么比使用Lex/Yacc更好的方法吗

好的,首先使用bison的现代版本,它有一个相当完整的在线版本(并且很可能安装了可执行文件,具体取决于您如何安装bison)。特别是,从以下声明开始:

%define parse.error verbose
%define parse.lac full
这将至少用“预期”令牌类型列表替换神秘的“语法错误”错误

然后确保您的令牌类型具有有意义的名称,因为它们将作为错误消息的一部分呈现给用户。如果您习惯使用
标识符
作为终端,那么您可能还可以,但是消息“Expected TOK_YY_ID”有点古怪。您可以在
类型
声明中声明终端的可读性:

%type TOK_YY_ID "identifier"
那只会让你走这么远。在许多情况下,知道“预期”的内容就足以理解语法错误,但有时更明确一些是有用的。在这种情况下,定义
error
规则非常有用。正确处理这些错误与其说是一门科学,不如说是一门艺术,但所有错误报告/恢复方法都是如此;关键是尽量明确错误的语法是什么样子的,不要过于具体


一种有趣的错误报告方法是使用当前解析器状态和前瞻标记(在错误报告时两者都可见)查找自定义错误消息(如果存在)。我认为这种方法已经成为编译器民间传说的一部分很长一段时间了,我相信几十年来我已经看过几篇关于它的文章。这是作者最近的一篇文章。

我自1969年以来一直在构建解析器生成器和解析器

递归下降、YACC和JavaCC是您听到的典型答案

这些是你爷爷的解析器生成器,它们在语法上受到限制。总是(尤其是在堆栈溢出时),一些可怜的灵魂会问“我如何解决这个移位/减少”问题(对于像YACC这样的LR解析器生成器)或“我如何消除左递归”(对于递归下降或像JavaCC这样的LL解析器生成器)。更糟糕的是,它们不能处理那些真正具有语法歧义的语法,就像在大多数复杂语言中一样

(和GLL)解析器允许您编写上下文无关的语法。。。并分析它们,不必大惊小怪。这是真正的生产力提高。这是有代价的:你最终可能会得到模棱两可的解析,但有办法解决这个问题。(见此)

野牛(可广泛获得)有一个;用它!最近的多语言程序操作工具似乎都使用GLL或GLR。我们的DMS软件再工程工具包使用GLR和解析C++(完全)