用于解析 C++ 中的许多小文本的最佳解析器生成器?
-
27-10-2019 - |
题
出于性能原因,我将 C# 库移植到 C++。在正常操作期间,该库除其他事项外,还需要解析大约 150,000 个平均长度小于 150 个字符的数学表达式(例如 Excel 公式)。
在C#版本中,我使用GOLD解析器来生成解析代码。它可以在一秒内解析所有 150,000 个表达式。
因为我们正在考虑扩展我们的语言,所以我认为转向 C++ 可能是转向 ANTLR 的好机会。我已将(简单)语法移植到 ANTLR 并从中生成了 C 代码。解析 150'000 个表达式需要超过 12 秒,因为对于每个表达式,我需要创建一个新的 ANTL3_INPUT_STREAM、令牌流、词法分析器和解析器 - 至少在版本 3.4 中,无法重用它们。
如果有人能给我一个建议,我将不胜感激 - GOLD 当然是一个选项,尽管生成 C++ 或 C 代码似乎比 C# 代码复杂得多。我的语法与 LALR 和 LL(1) 兼容。最重要的是解析小输入的性能。
解决方案
我会尝试boost :: spirit。它通常非常快(即使是解析整数之类的简单事物,它也可能比atoi http://alexott.blogspot.com/2010/01/boostspirit2-vs-atoi.html )
它有很多优点:仅标头,因此具有依赖关系,具有自由许可证。
但是请注意,学习曲线很困难。它是现代的C ++(没有指针,但是有很多模板,并且编译错误非常令人沮丧),因此来自C或C#的人可能不太舒服。
其他提示
如果要分析的语法很简单,则可以手动编写解析器。
大多数解析器生成器旨在简化运行中的解析器,因此执行时间通常会受到影响。
我在解析中看到的最佳性能来自Boost.Spirit.Qi,它使用元模板编程来表达C ++的语法。但这不是为了胆小的人。
这将需要很好地隔离,并且包含解析器的文件的编译时间将增加到几秒钟(因此最好确保那里的文件越少越好)。
代替 expr
让你语法识别 sequence-of-expr
.
编辑:
而不是(野牛语法):
start: expr { process_expr ($1); }
;
有:
start: expr_seq ;
expr_seq: expr { process_expr ($1); }
| expr_seq expr { process_expr ($2); }
;
我编写了许多解析器,而手工编码的递归下降就是我这样做的方式。它们易于编写,并且几乎是最佳选择。
也就是说,如果您追求的是速度,那么无论您写什么,都将有足够的空间来加快速度。 这些将使您感到惊讶,因为您可以想到的任何事情,您都已经做到了。
下面是显示的 幻灯片组 怎么做。