有没有比lex/flex更现代化的工具用于生成C++的标记解析器?

24

我最近为一个现有工具添加了源代码文件解析功能,该工具能够从复杂的命令行参数生成输出文件。

由于命令行参数变得非常复杂,我们开始允许将它们作为文件提供,以便像处理非常长的命令行一样进行解析,但语法仍然很笨拙。因此,我增加了使用更合理的语法来解析源文件的功能。

我在Windows平台上使用了flex 2.5.4来生成该自定义源文件格式的标记器,并且它有效地工作。但是我讨厌这个代码。全局变量,奇怪的命名约定,以及它生成的C++代码都很糟糕。现有的代码生成后端与flex的输出粘合在一起,我不使用yacc或bison。

我即将深入研究这个代码,并且想使用一个更好/更现代的工具。有人知道这样的工具吗?

  • 在Windows命令提示符中运行(Visual Studio集成可行,但我使用make文件构建)
  • 生成适当封装的C++标记器。(没有全局变量)
  • 使用正则表达式描述标记规则(兼容lex语法的加分项)
  • 不强制我使用C运行时(或伪造它)进行文件读取。(从内存中解析)
  • 当我的规则强制标记器回溯时,警告我(或自动修复)
  • 允许我完全控制变量和方法名称(以便符合我的现有命名约定)
  • 允许我将多个解析器链接到单个.exe中,避免名称冲突
  • 如果需要,可以生成UNICODE(16位UCS-2)解析器
  • 不是集成的标记器+解析器生成器(我想要一个lex替代方案,而不是lex + yacc替代方案)

如果只有生成标记表的工具,我可能可以找到一种方法来解决。


3
Boost.Spirit、Boost.Proto 和 Boost.Xpressive 不是可选项吗? - Konrad Rudolph
@Konrad:他们可能是,但我不熟悉。生成模板而不是C++类的东西是可以接受的。 - John Knoeller
5个回答

11

Ragel: http://www.complang.org/ragel/,它符合大多数你的要求。

  • 它可以在Windows上运行
  • 它不会声明变量,因此你可以根据需要将它们放在类或函数内部。
  • 它有很好的工具来分析正则表达式,以查看它们何时会回溯。(我不太清楚这一点,因为我从未使用Ragel中会创建回溯解析器的语法。)
  • 变量名不能更改。
  • 表名以机器名称为前缀,并且它们被声明为“const static”,因此您可以在同一程序中的不同文件中放置多个相同名称的表。
  • 您可以将变量声明为任何整数类型,包括UChar(或您偏好的任何UTF-16类型)。它不会自动处理代理对。它也没有Unicode的特殊字符类(我想)。
  • 它只能处理正则表达式...没有bison/yacc功能。

它生成的代码对程序干扰很小。该代码速度非常快,而且Ragel语法比我见过的任何东西都更灵活和易读。它是一个非常稳定的软件。它可以生成基于表的解析器或基于goto的解析器。


我自己使用并强烈赞同。同一作者还有Kelbt用于解析 - 它不是发布版本,有些怪异(特别是它不执行结合性或优先级消歧),但我仍在使用它,我遇到的唯一崩溃都是编译时由代码错误引起的(在解析操作中引用不存在的标记)。 - user180247
我也使用treecc进行AST节点定义,结合Kelbt和Ragel进行多分发操作。如今,我有了自己的替代方案,并增加了一些额外的技巧(例如AST遍历迭代器类)——也许有一天我会发布它... - user180247
@Steve314:请告诉我们您是否这样做。 - John Knoeller

6

Flex也有C++输出选项。
结果是一组执行解析的类。

只需将以下内容添加到lex文件的头部:

%option C++
%option yyclass="Lexer"

然后在你的源代码中:

std::fstream  file("config");
Lexer         lexer(&file)
while(int token = lexer.yylex())
{
}

是的,我尝试过这个,我认为它甚至比C代码更糟糕,但它确实解决了全局变量和多实例问题。 - John Knoeller
2
由于您不维护所生成的代码,因此其美学上的细节并不重要。您的源文件是词法分析器文件。只要代码能够正常工作且不污染全局命名空间,实现细节就不重要了。注意1:不要构建源文件,只构建目标文件和头文件(即立即删除源文件)。将目标文件和词法分析器文件之间的依赖关系建立起来,而不是源文件。注意:它们看起来很混乱,是为了使其更有效率。 - Martin York

6
Boost.Spirit.Qi(解析器-标记化器)或Boost.Spirit.Lex(仅分词器)。我非常喜欢Qi,而Lex也不错,但我倾向于使用Qi来满足我的解析需求... Qi唯一的真正缺点是会增加编译时间,并且运行速度比手写解析代码稍慢。但通常比使用正则表达式解析要快得多。请参阅http://www.boost.org/doc/libs/1_41_0/libs/spirit/doc/html/index.html获取更多信息。

谢谢,我会看一下Boost.Spirit.Lex。 - John Knoeller

5

我想起了两个工具,虽然你需要自己找出哪一个更合适:AntlrGoldParser。这两个工具都有语言绑定可用,可以插入到C++运行环境中。


说到这个,当我去谷歌搜索时,显然有一个使用boost库的flex/bison面向对象版本 - 点击这里查看http://dudka.cz/vyp08 - t0mm13b
我已经了解了Antler并发现它不太适合。它是一个解析器生成器,需要安装Java运行时环境,而在我的经验中,这在Windows上不稳定且令人烦恼。GoldParser看起来很有前途 - 谢谢。 - John Knoeller
@tommeib75:dudka.cz不错的发现。也许他有更好的方法将flex输出整理成干净的代码。 - John Knoeller
对于ANTLR,点赞+1(希望能多一些)。ANTLRworks非常适合可视化您的工作和调试步骤,http://www.antlr.org/works/screenshots/editor.jpg - Mawg says reinstate Monica
Goldparser很好,但是它非常慢。即使在速度优化的C++代码中,它解析15000行代码需要10秒钟。如果与PHP解析器的速度相比,这非常慢。 - Elmue

2

Boost.SpiritYard parser是我想到的。请注意,使用词法分析器生成器的方法已被C++内部DSL(领域特定语言)所替代,用于指定标记。这是因为它是你的代码的一部分,而不需要使用外部实用程序,只需遵循一系列规则来指定语法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接