优化 boost::spirit::qi 解析器

2024-03-18

我有一个解析器,它基本上打印出堆栈机的操作,并根据给定的运算符优先级给出一些表达式。我的目标是尽可能优化速度。我读过了一篇关于 qi 优化的文章 https://code.google.com/p/scribblings-by-apoch/wiki/OptimizingBoostSpirit提供这个示例代码 https://code.google.com/p/scribblings-by-apoch/wiki/BoostSpiritDeferredConstructor。我了解主文章中描述的优化要点,但我不清楚如何将其集成到我的代码中。

这是我的解析器的以下工作示例。我已经尝试过使用它来优化它raw[]提供基本迭代器。 phoenix 操作调用必须给出字符串或迭代器,通过它们可以创建字符串;这些函数的真实版本并不简单,它们的功能尚无法在解析时评估:

#include <iostream>
#include <vector>
#include <string>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/qi_char.hpp>
#include <boost/spirit/include/qi_parse.hpp>
#include <boost/spirit/include/phoenix_bind.hpp>
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
using std::endl;
using std::cout;
using std::string;
using std::vector;

void fPushOp(const char* op){
  cout << "PushOp: " << op << endl;
}

void fPushInt(const boost::iterator_range<string::const_iterator>& my_str){
  cout << "PushInt: " << my_str << endl;
}

template<typename Iterator, typename Skipper = qi::space_type>
struct Calculator : public qi::grammar<Iterator, Skipper> {

  qi::rule<Iterator, Skipper>  
    expression, logical_or_expression, logical_and_expression, negate_expression, series_expression,
    single_expression, inclusive_or_expression, exclusive_or_expression, and_expression, equality_expression, 
    relational_expression, shift_expression, additive_expression, multiplicative_expression, 
    term, complement_factor, factor, result, integer, variable, variable_combo, word, prefix;

  qi::rule<Iterator> number;
  Calculator() : Calculator::base_type(result)
  {
    number = 
        qi::raw[
            ("0x" >> +qi::char_("0-9a-fA-F"))     
          | ("0b" >> +qi::char_("0-1"))
          | ("0" >>  +qi::char_("0-7"))
          | (+qi::char_("0-9"))
        ] [phx::bind(&fPushInt, qi::_1)]
        ;

    integer = 
          number
        | ('-' >> number) [phx::bind(&fPushOp, "OP_UNARY_MINUS")]
        ;

    variable =
          ((qi::alpha | qi::char_('_')) 
              >> *(qi::alnum | qi::char_('_')) 
              >> '['
              >>  (+(qi::alnum | qi::char_('_') | qi::char_(',')) 
                | ('\'' >> *~qi::char_('\'') >> '\'')) 
              >> ']')
        | ((qi::alpha | qi::char_('_')) >> *(qi::alnum | qi::char_('_')))
        ;

    variable_combo =
        qi::raw [
          variable >> *(qi::char_('.') >> variable)
        ] [phx::bind(&fPushInt, qi::_1)]
        ;

    word = 
        qi::raw[
          variable
        ] [phx::bind(&fPushInt, qi::_1)]
        ;

    factor =
            ("ceil(" >> expression >> ')')                                                      [phx::bind(&fPushOp, "OP_CEIL")]
        |   ("wrap(" >> expression >> ')')                                                      [phx::bind(&fPushOp, "OP_WRAP")]
        |   ("abs(" >> expression >> ')')                                                       [phx::bind(&fPushOp, "OP_ABS")]
        |   ("count1(" >> expression >> ')')                                                    [phx::bind(&fPushOp, "OP_COUNT1")]
        |   ("pick(" >> expression >> ')')                                                      [phx::bind(&fPushOp, "OP_PICK")]
        |   ("defined(" >> expression >> ')')                                                   [phx::bind(&fPushOp, "OP_DEF")]
        |   ("string_equal(" >> word >> ',' >> word >> ')')                                     [phx::bind(&fPushOp, "OP_STREQ")]
        |   ("string_contains(" >> word >> ',' >> word >> ')')                                  [phx::bind(&fPushOp, "OP_STRCON")]
        |   ("lsl(" >> single_expression >> ',' >> single_expression >> ',' >> number >> ')')   [phx::bind(&fPushOp, "OP_LSL")]
        |   ("lsr(" >> single_expression >> ',' >> single_expression >> ')')                    [phx::bind(&fPushOp, "OP_LSR")]
        |   ("asr(" >> single_expression >> ',' >> single_expression >> ',' >> number >> ')')   [phx::bind(&fPushOp, "OP_ASR")]
        |   ("ror(" >> single_expression >> ',' >> single_expression >> ',' >> number >> ')')   [phx::bind(&fPushOp, "OP_ROR")]
        |   ("rrx(" >> single_expression >> ',' >> single_expression >> ',' >> single_expression >> ',' >> number >> ')')[phx::bind(&fPushOp, "OP_RRX")]
        |   ('(' >> expression >> ')')
        |   variable_combo
        |   integer
        ;
    complement_factor = factor
        | ('~' >> factor) [phx::bind(&fPushOp, "OP_COMPLEMENT")]
        ;
    term = complement_factor
      >> *( (".." >> complement_factor) [phx::bind(&fPushOp, "OP_LEGER")]
          | ('\\' >> complement_factor) [phx::bind(&fPushOp, "OP_MASK")]
          ); 
    multiplicative_expression = term
      >> *( ('/' >> term) [phx::bind(&fPushOp, "OP_DIV")]
          | ('%' >> term) [phx::bind(&fPushOp, "OP_MOD")]
          | ('*' >> term) [phx::bind(&fPushOp, "OP_MUL")]
          );
    additive_expression = multiplicative_expression
      >> *( ('+' >> multiplicative_expression)  [phx::bind(&fPushOp, "OP_ADD")]
          | ('-' >> multiplicative_expression)  [phx::bind(&fPushOp, "OP_SUB")]
          );
    shift_expression = additive_expression
      >> *( (">>" >> additive_expression) [phx::bind(&fPushOp, "OP_SRL")]
          | ("<<" >> additive_expression) [phx::bind(&fPushOp, "OP_SLL")]
          );
    relational_expression = shift_expression
      >> *( ('<' >> shift_expression) [phx::bind(&fPushOp, "OP_LT")]
          | ('>' >> shift_expression) [phx::bind(&fPushOp, "OP_GT")]
          | ("<=" >> shift_expression)[phx::bind(&fPushOp, "OP_LET")]
          | (">=" >> shift_expression)[phx::bind(&fPushOp, "OP_GET")]
          );
    equality_expression = relational_expression 
      >> *( ("==" >> relational_expression)[phx::bind(&fPushOp, "OP_EQ")]
          | ("!=" >> relational_expression)[phx::bind(&fPushOp, "OP_NEQ")] 
          );
    and_expression = equality_expression 
      >> *(('&' >> equality_expression)     [phx::bind(&fPushOp, "OP_AND")]); 
    exclusive_or_expression = and_expression 
      >> *(('^' >> and_expression)          [phx::bind(&fPushOp, "OP_XOR")]); 
    inclusive_or_expression = exclusive_or_expression 
      >> *(('|' >> exclusive_or_expression) [phx::bind(&fPushOp, "OP_OR")]); 
    single_expression = inclusive_or_expression;
    series_expression = inclusive_or_expression 
      >> *((',' >> inclusive_or_expression) [phx::bind(&fPushOp, "OP_SERIES")]);
    negate_expression = series_expression
        | ('!' >> series_expression)        [phx::bind(&fPushOp, "OP_NEGATE")];
    logical_and_expression = negate_expression
      >> *(("&&" >> negate_expression)      [phx::bind(&fPushOp, "OP_LOGICAL_AND")]); 
    logical_or_expression = logical_and_expression 
      >> *(("||" >> logical_and_expression) [phx::bind(&fPushOp, "OP_LOGICAL_OR")]);
    expression = logical_or_expression;

    result = expression;
  }
};

int main(){
  Calculator<string::const_iterator> calc;
  const string expr("0xff0000 >> 3 && 3 + (!9) | (0,200)");
  cout << "Expression: " << expr << endl;

  string::const_iterator it = expr.begin();
  phrase_parse(it, expr.end(), calc, qi::space);

  cout << "Remaining: " << (string(it,expr.end())) << endl;
  return 0;
}

另外,我读到此 pdf 中有关 utree 的幻灯片 https://github.com/boostcon/2011_presentations/raw/master/fri/utree_talk.pdf我正在尝试找出如果可能的话如何使用utree输出而不是语义动作,因为显然这样的事情是邪恶的。有人可以提供或向我指出一个关于如何构建utree然后可以将其送入堆栈机以按顺序打印出操作?


优化取决于您想要实现的目标。因此,我认为你的优化过早了。

例如。解析一个variable_combo as a raw[]如果您想稍后解释符号,输入序列没有任何意义(因为您必须解析变量组合again,你甚至必须预见其中的空白:"foo . bar .tux"此处是有效的变量组合)。

我有很多关于优化 Boost Spirit 的帖子(开始here https://stackoverflow.com/search?q=user%3A85371+%5Bboost-spirit%5D+optimization例如。)。快速观察:

  • 考虑回溯下的正确性;通过语法解析 'ceil(3.7') 你会得到:

    Expression: ceil(3.7)
    PushInt: 3
    PushInt: ceil
    Remaining: (3.7)
    

    请注意当解析失败时它如何发出操作码。另请注意,它会发出wrong操作码

    • 它推动3代替3.7
    • 它推动ceil作为 PushInt?

    因此,它不仅检测到解析失败为时已晚,而且还忽略了括号,无法发现函数调用并错误地解析了数字。

    关于过早的评估,我将指出这个流行的答案:Boost Spirit:“语义行为是邪恶的”? https://stackoverflow.com/questions/8259440/boost-spirit-semantic-actions-are-evil

    除此之外,我只是证实我的怀疑,即您正在进行过早的优化。考虑做

    #define BOOST_SPIRIT_DEBUG
    

    然后,在语法构造函数中:

    BOOST_SPIRIT_DEBUG_NODES(
            (expression)(logical_or_expression)(logical_and_expression)(negate_expression)(series_expression)(single_expression)
            (inclusive_or_expression)(exclusive_or_expression)(and_expression)(equality_expression)(relational_expression)
            (shift_expression)(additive_expression)(multiplicative_expression)(term)(complement_factor)(factor)(result)(integer)
            (variable)(variable_combo)(word)(prefix)
    

    真正了解解析器的行为方式。

  • 考虑 qi::symbols 例如:

    qi::symbols<char,const char*> unary_function;
    
    unary_function.add
        ("ceil",    "OP_CEIL")
        ("wrap",    "OP_WRAP")
        ("abs",     "OP_ABS")
        ("count1",  "OP_COUNT1")
        ("pick",    "OP_PICK")
        ("defined", "OP_DEF");
    
    unary_call = (unary_function >> "(" >> expression >> ')') [phx::bind(&fPushOp, qi::_1)];
    
  • 特征可能会为编译器在内联后优化留下更多潜力(与语义操作相反,因为模板实例化的多个级别可能会掩盖某些情况,特别是当bind参与了)

您可能希望在此处驱动运算符优先级表,如一些精神示例所示。使用规则层次结构来强制执行优先级的传统方法会使语法变得复杂。这有两个主要缺点:

  • 每条规则都引入了虚拟调度(Spirit X3以后可能不再有这个限制)
  • 你的语法变得如此复杂,以至于你已经失去了概述(见第一个项目符号)

建议

我建议

  1. 由于语义操作变得笨拙,并且在面对(后期)回溯(甚至解析器失败)时很难正确处理,因此不再在解析期间进行评估;后者可以很容易地检测到,但回溯也可以是良性的并且当语义动作有副作用时很难纠正)。

  2. 从最简单的规则开始构建语法,随着添加测试用例逐渐构建它

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

优化 boost::spirit::qi 解析器 的相关文章

  • 如何保证对象只有一个线程

    我有以下代码 class Service public void start creates thread which creates window and goes to message loop void stop sends WM C
  • 使用 Enumerable.OfType() 或 LINQ 查找特定类型的所有子控件

    Existed MyControl1 Controls OfType
  • 更改 Qt OpenGL 窗口示例以使用 OpenGL 3.3

    我正在尝试更改 Qt OpenGL 示例以使用更现代的 opengl 版本 330 似乎合适 所以我做了 在 main cpp 上设置版本和配置文件 设置着色器版本 更改着色器以使用统一 它现在构建没有任何错误 但我只看到一个空白窗口 我错
  • 如何在 C# / .NET 中创建内存泄漏[重复]

    这个问题在这里已经有答案了 可能的重复 托管代码中是否可能存在内存泄漏 特别是 C 3 0 https stackoverflow com questions 6436620 is it possible to have a memory
  • 在 Xamarin 中隐藏软键盘

    如何隐藏软键盘以便在聚焦时显示Entry在 Xamarin forms 便携式表单项目中 我假设我们必须为此编写特定于平台的渲染器 但以下内容不起作用 我创建自己的条目子类 public class MyExtendedEntry Entr
  • EF Core 通过完全替换断开集合导航属性的更新

    使用 EF Core 5 0 我有一个 SPA 页面 可以加载Group实体及其集合Employee来自 API 的实体 var groupToUpdate await context Groups Include g gt g Emplo
  • 防止 boost::asio::io_context 在空轮询调用时停止

    此代码调用发布的句柄 boost asio io context ioc boost asio post ioc std cout lt lt lol lt lt std endl ioc poll 而这并没有 boost asio io
  • 根据 N 个值中最小的一个返回不同的结果

    不确定如何使标题更具描述性 所以我只是从一个例子开始 我使用下面的代码位 它从枚举中选择一个方向 具体取决于四个轴中哪一个与给定方向相比形成最小角度 static Direction VectorToDirection Vector2 di
  • ASP.Net Core 内容配置附件/内联

    我正在从 WebAPI 控制器返回一个文件 Content Disposition 标头值自动设置为 附件 例如 处置 附件 文件名 30956 pdf 文件名 UTF 8 30956 pdf 当它设置为附件时 浏览器将要求保存文件而不是打
  • vs2008 c#:Facebook.rest.api如何使用它来获取好友列表?

    如何在此基础上取得进一步的进步 获取好友列表的下一步是什么 string APIKey ConfigurationManager AppSettings API Key string APISecret ConfigurationManag
  • 如何获取 QTableView 的标题列表?

    我有一个QTableView我的对话框中的对象 我需要访问该表的水平标题并将它们放入QStringList object 尽管进行了大量搜索 但我在 Qt 文档中找不到如何获取此标头列表 编辑 我发现的最接近的地方是this https w
  • 单例模式和 std::unique_ptr

    std unique ptr唯一地控制它指向的对象 因此不使用引用计数 单例确保利用引用计数只能创建一个对象 那么会std unique ptr与单例执行相同 单例确保只有一个实例属于一种类型 A unique ptr确保只有一个智能指针到
  • C# 构建一个 webservice 方法,它接受 POST 方法,如 HttpWebRequest 方法

    我需要一个接受 POST 方法的 Web 服务 访问我的服务器正在使用 POST 方法 它向我发送了一个 xml 我应该用一些 xml 进行响应 另一方面 当我访问他时 我已经使用 HttpWebRequest 类进行了管理 并且工作正常
  • 如何从文本文件读取整数到数组

    这就是我想做的 我对此有些不满 但我希望你能容忍我 这对我来说是一个非常新的概念 1 在我的程序中 我希望创建一个包含 50 个整数的数组来保存来自文件的数据 我的程序必须获取用户的文档文件夹的路径 2 文件的名称为 grades txt
  • AES 输出是否小于输入?

    我想加密一个字符串并将其嵌入到 URL 中 因此我想确保加密的输出不大于输入 AES 是可行的方法吗 不可能创建任何始终会创建比输入更小的输出的算法 但可以将任何输出反转回输入 如果您允许 不大于输入 那么基本上您只是在谈论同构算法alwa
  • 我可以让 ungetc 取消阻止阻塞的 fgetc 调用吗?

    我想在收到 SIGUSR1 后使用 ungetc 将 A 字符重新填充到标准输入中 想象一下我有充分的理由这样做 调用 foo 时 stdin 中的阻塞读取不会被收到信号时的 ungetc 调用中断 虽然我没想到它会按原样工作 但我想知道是
  • 矩阵到数组 C#

    这将是转换方阵的最有效方法 例如 1 2 3 4 5 6 7 8 9 into 1 2 3 4 5 6 7 8 9 in c 我在做 int array2D new int 1 2 3 4 5 6 7 8 9 int array1D new
  • xsi:type 属性搞乱了 C# XML 反序列化

    我使用 XSD exe 根据 XML 架构 xsd 文件 自动生成 C 对象 我正在反序列化 OpenCover 输出 但其中一个部分类未正确生成 这是导致异常的行
  • 从 JavaScript 中的 OnClientClick 事件中阻止 C# 中的 asp:Button OnClick 事件?

    我有一个asp Button在我的网页上 它调用 JavaScript 函数和代码隐藏方法 后者进行调用以导航到另一个页面 在 JavaScript 函数中 我正在检查条件 如果不满足这个条件 我想中止导航 以便OnClick方法未被调用
  • Java 和/C++ 在多线程方面的差异

    我读过一些提示 多线程实现很大程度上取决于您正在使用的目标操作系统 操作系统最终提供了多线程能力 比如Linux有POSIX标准实现 而windows32有另一种方式 但我想知道编程语言水平的主要不同 C似乎为同步提供了更多选择 例如互斥锁

随机推荐

  • 大查询中的原子插入

    当我加载超过 1 个 csv 文件时 bigquery 如何处理错误 bq 加载 max bad record 30 dbname finalsep20xyz gs sep20new abc csv gz gs sep20new xyzcs
  • 如何在 IIS 7.0 中托管 MVC 应用程序?

    我创建了一个 MVC 应用程序 它在本地主机上运行良好 我使用 Visual Studio 将项目发布到本地文件夹并将其上传到 FTP 位置 但在服务器上它不起作用 我遵循了几个教程但没有结果http haacked com archive
  • 如何使用 dom 在 XML 文件中追加元素?

    我的 XML 文件如下所示
  • 如何测试接受命令行参数的并发 Java 程序?

    我有一个 Java 程序 其主要方法 在 主类中 需要命令行参数 该程序也是并发的 使用线程和其他东西 我想对程序进行大规模重构 在开始重构之前 我想为 main 方法创建一个测试套件 我想用不同的命令行参数测试 main 方法 我希望在执
  • URL 路由 C# mvc 和 Web 表单

    所以我有一个 webforms 和一个 mvc 应用程序组合在一起 并试图让事情正确路由 我的默认路由按预期工作 但是当我单击其中一个视图中的操作链接时 它没有路由到正确的页面 这是我的路由代码 void RegisterRoutes Ro
  • Tomcat Digest 与 Manager WebApp

    我正在尝试为 tomcat 管理器应用程序设置摘要密码 我有
  • 隐藏变量在 R 中如何表现?

    是否有任何重要的 1 原因不导出名称为 fnname在 R 包中 我知道点前缀变量的主要用途是在使用以下函数搜索环境时将变量表示为隐藏ls 并表示对象或列表中的字段应被视为私有字段 如 S4 Data 字段 test env lt new
  • 读取 read_csv2(readr 包)中的行名称

    我正在尝试从这里加载示例数据集 http www agrocampus ouest fr math RforStat decathlon csv http www agrocampus ouest fr math RforStat deca
  • JavaScript 中的 split()

    我有代码 function filter var url window location alert url alert url split 1 当我启动它时 我只收到一条警报消息 http localhost 8000 index 3 1
  • 找不到 Spring MVC Neo4jConfiguration 类

    我正在学习 Spring MVC 我想扩展 Neo4jConfiguration 类 但它不可用 我导入了以下依赖项
  • 我无法登录 Tomcat Manager 应用程序

    我在 stackoverflow 上阅读了很多主题来解决我的问题 但没有一个有用 当我尝试使用很多不同的配置登录管理器应用程序 http localhost 8080 manager html 1 时 但我总是获得401 未经授权尝试使用权
  • SQL 约束/触发器 - 是否可以编写一个约束来检查“插入记录时它必须包含两个字段之一”?

    是否可以对输入的记录设置约束 触发器 以检查用户是否至少输入了三个字段之一 所有字段都可以为空 例如 我有一个数据库用于跟踪其他软件中的错误和新功能 当发现错误时 会创建一个功能记录 该记录可以具有三个外键 discoveredID fix
  • 如何匹配字符串中的第一个单词?

    我想匹配这个词 St or St or st or st 但只能作为字符串的第一个单词 例如 St Mary Church Church St 应该首先找到 St st Mary Church Church St 应该只找到 st st M
  • 为什么这个隐式函数没有被应用?

    尝试 Alexey Romanov 中提出的 TupleN 的隐式转换如何在元组之间应用隐式转换 https stackoverflow com questions 23911151 how to apply implicit conver
  • 跨不同项目设置发布/订阅订阅?

    在我的 GCP 项目 项目A 我创建了一个 Pub sub 主题 topicA 并且在此发布 订阅主题中发布的消息需要在其他 GCP 项目 项目B 通过订阅 订阅B 推荐的设置方式是什么订阅B Define 订阅B在项目 A 中 并使用适当
  • 双显示器中的 Delphi XE Form 和 Source

    有人知道我是否可以将 IDE 设置为在一个显示器和另一个显示器上显示源代码 我谈论相同的 pas 因为我可以在每个监视器中查看 2 个不同的 pas 不确定 XE 但在 2007 年你可以去Tools gt Options打开选项对话框 然
  • Windows 窗体旋转

    当您在 Net 中创建表单时 它会显示为纵向布局的对话框 通常没有人喜欢横向或颠倒地阅读 但我有一个非常充分的理由旋转表格 有人知道如何在 Windows Vista 上用 C 实现这一点吗 必须在 WinForms 中吗 在 WPF 中
  • Backbone.js 在填充集合后调用渲染

    我试图在获取集合后调用渲染 在我的初始化方法中 我有 this collection bind all this render this this collection fetch 在 IE 中 有时它似乎会在集合有数据之前尝试渲染 集合似
  • 如何将活动 Excel 工作簿附加到电子邮件

    我整个上午都在尝试获取此 VBA 脚本 将我的活动 Excel 文档附加到自动生成的 Outlook 消息中 如果我将文件路径声明为字符串并附加它 一切都会正常工作 除了我想附加当前 Excel 文档的完整文件路径而不是使用静态字符串值 这
  • 优化 boost::spirit::qi 解析器

    我有一个解析器 它基本上打印出堆栈机的操作 并根据给定的运算符优先级给出一些表达式 我的目标是尽可能优化速度 我读过了一篇关于 qi 优化的文章 https code google com p scribblings by apoch wi