带有调试输出的 X3 解析器段错误 (BOOST_SPIRIT_X3_DEBUG)

2023-12-25

Update

这个问题涉及两个问题(如接受的答案 https://stackoverflow.com/a/43688320/2428220),这两个问题都存在于 Boost Spirit X3 随 Boost 1.64 一起提供的版本中,但在撰写本文时(2017-04-30),这两个问题现在都已在开发分支中修复(或至少在编译时检测到) )。

我已经更新了MCVE项目 https://github.com/sigbjornlo/spirit_fruit_mcve反映我使用开发分支而不是最新的 boost 版本所做的更改,希望它可以帮助面临类似问题的其他人。


原来的问题

我正在尝试学习如何将 Spirit X3 解析器分解为单独的可重用语法,正如示例代码 https://github.com/boostorg/spirit/tree/develop/example/x3/(特别是 reexpr_full 和 calc)以及来自2015年中国石油化工大会 https://www.youtube.com/watch?v=xSBWklPLRvw and BoostCon https://www.youtube.com/watch?v=ZeeR7pQ6Le4.

我有一个符号表(本质上将不同类型映射到我支持的类型的枚举类),我想在多个解析器中重用它。我能找到的符号表的唯一示例是罗马数字示例,它位于单个源文件中。

当我尝试以更结构化示例的样式将符号表移动到自己的 cpp/h 文件中时,如果我尝试解析不在符号表中的任何字符串,我的解析器将出现段错误。如果符号表是在与使用它的解析器相同的编译单元中定义的,则会抛出期望异常(这就是我期望它做的事情)。

定义 BOOST_SPIRIT_X3_DEBUG 后,我得到以下输出:

<FruitType>
  <try>GrannySmith: Mammals</try>
  <Identifier>
    <try>GrannySmith: Mammals</try>
    <success>: Mammals</success>
    <attributes>[[
Process finished with exit code 11

我做了一个小项目,它展示了我正在努力实现的目标,可以在这里找到:https://github.com/sigbjornlo/spirit_fruit_mcve https://github.com/sigbjornlo/spirit_fruit_mcve

我的问题:

  • 为什么在这种情况下将符号解析器移动到单独的编译单元会导致分段错误?
  • 使符号表在多个解析器中可重用的推荐方法是什么? (在 MCVE 中我显然只使用fruit另一个解析器中的解析器,但在我的完整项目中,我想在其他几个解析器中使用它。)

以下是 MCVE 项目的代码:

main.cpp

#include <iostream>

#define BOOST_SPIRIT_X3_DEBUG
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/adapt_struct.hpp>

#include "common.h"
#include "fruit.h"

namespace ast {
    struct FruitType {
        std::string identifier;
        FRUIT fruit;
    };
}

BOOST_FUSION_ADAPT_STRUCT(ast::FruitType, identifier, fruit);

namespace parser {
    // Identifier
    using identifier_type = x3::rule<class identifier, std::string>;
    const auto identifier = identifier_type {"Identifier"};
    const auto identifier_def = x3::raw[x3::lexeme[(x3::alpha | '_') >> *(x3::alnum | '_')]];
    BOOST_SPIRIT_DEFINE(identifier);

    // FruitType
    struct fruit_type_class;
    const auto fruit_type = x3::rule<fruit_type_class, ast::FruitType> {"FruitType"};

    // Using the sequence operator creates a grammar which fails gracefully given invalid input.
    // const auto fruit_type_def = identifier >> ':' >> make_fruit_grammar();

    // Using the expectation operator causes EXC_BAD_ACCESS exception with invalid input.
    // Instead, I would have expected an expectation failure exception.
    // Indeed, an expectation failure exception is thrown when the fruit grammar is defined here in this compilation unit instead of in fruit.cpp.
    const auto fruit_type_def = identifier > ':' > make_fruit_grammar();

    BOOST_SPIRIT_DEFINE(fruit_type);
}

int main() {
    std::string input = "GrannySmith: Mammals";
    parser::iterator_type it = input.begin(), end = input.end();

    const auto& grammar = parser::fruit_type;
    auto result = ast::FruitType {};

    bool successful_parse = boost::spirit::x3::phrase_parse(it, end, grammar, boost::spirit::x3::ascii::space, result);
    if (successful_parse && it == end) {
        std::cout << "Parsing succeeded!\n";
        std::cout << result.identifier << " is a kind of " << to_string(result.fruit) << "!\n";
    } else {
        std::cout << "Parsing failed!\n";
    }

    return 0;
}

std::string to_string(FRUIT fruit) {
    switch (fruit) {
        case FRUIT::APPLES:
            return "apple";
        case FRUIT::ORANGES:
            return "orange";
    }
}

common.h

#ifndef SPIRIT_FRUIT_COMMON_H
#define SPIRIT_FRUIT_COMMON_H

namespace x3 = boost::spirit::x3;

enum class FRUIT {
    APPLES,
    ORANGES
};

std::string to_string(FRUIT fruit);

namespace parser {
    using iterator_type = std::string::const_iterator;
    using context_type = x3::phrase_parse_context<x3::ascii::space_type>::type;
}

#endif //SPIRIT_FRUIT_COMMON_H

fruit.h

#ifndef SPIRIT_FRUIT_FRUIT_H
#define SPIRIT_FRUIT_FRUIT_H

#include <boost/spirit/home/x3.hpp>

#include "common.h"

namespace parser {
    struct fruit_class;
    using fruit_grammar = x3::rule<fruit_class, FRUIT>;

    BOOST_SPIRIT_DECLARE(fruit_grammar)

    fruit_grammar make_fruit_grammar();
}


#endif //SPIRIT_FRUIT_FRUIT_H

水果.cpp

#include "fruit.h"

namespace parser {
    struct fruit_symbol_table : x3::symbols<FRUIT> {
        fruit_symbol_table() {
            add
                    ("Apples", FRUIT::APPLES)
                    ("Oranges", FRUIT::ORANGES);
        }
    };

    struct fruit_class;
    const auto fruit = x3::rule<fruit_class, FRUIT> {"Fruit"};
    const auto fruit_def = fruit_symbol_table {};
    BOOST_SPIRIT_DEFINE(fruit);

    BOOST_SPIRIT_INSTANTIATE(fruit_grammar, iterator_type, context_type);

    fruit_grammar make_fruit_grammar() {
        return fruit;
    }
}

复制器的工作非常好。这让我想起了我的公关https://github.com/boostorg/spirit/pull/229 https://github.com/boostorg/spirit/pull/229(看这里的分析boost Spirit x3分裂后奇怪的语义行为 https://stackoverflow.com/questions/41770375/strange-semantic-behaviour-of-boost-spirit-x3-after-splitting/41785268#41785268).

问题是静态初始化顺序失败,在初始化规则之前复制规则的调试名称。

事实上,禁用调试信息确实可以消除崩溃,并正确地引发预期失败。

开发分支也发生了同样的情况,所以要么有另一个类似的事情,要么我错过了一个地方。现在,您可以禁用调试输出。如果我找到位置,我会发布更新。

UPDATE:

我没有错过任何一个地方。有一个单独的问题call_rule_definition它参数化的地方context_debug<>具有实际属性类型而不是转换后的属性类型的辅助类:

#if defined(BOOST_SPIRIT_X3_DEBUG)
                typedef typename make_attribute::type dbg_attribute_type;
                context_debug<Iterator, dbg_attribute_type>
                dbg(rule_name, first, last, dbg_attribute_type(attr_), ok_parse);
#endif

该评论似乎表明这种行为是所期望的:它尝试在转换之前打印属性。但是,除非合成的属性类型与实际的属性类型匹配,否则它完全不起作用。在这种情况下,它使得context_debug采用对临时转换属性的悬空引用,导致未定义的行为 https://en.wikipedia.org/wiki/Undefined_behavior.

事实上,这也是工作案例中未定义的行为。我只能假设在内联定义的情况下事情发生得很好,使得事情看起来像预期的那样。

据我所知,这将是一个干净的修复,可以防止任何不必要的转换以及随之而来的临时转换:

#if defined(BOOST_SPIRIT_X3_DEBUG)
                context_debug<Iterator, transform_attr>
                dbg(rule_name, first, last, attr_, ok_parse);
#endif

我为此创建了拉取请求:https://github.com/boostorg/spirit/pull/232 https://github.com/boostorg/spirit/pull/232


¹ 开发分支 https://github.com/boostorg/spirit/tree/develop似乎没有合并到1.64 http://www.boost.org/users/history/version_1_64_0.html release

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

带有调试输出的 X3 解析器段错误 (BOOST_SPIRIT_X3_DEBUG) 的相关文章

  • C - 计算文件中的单词、字符和行数。字符数

    我必须用 C 编写一段代码 输出给定文件中的字符数 行数和单词数 任务看起来很简单 但我现在真的不确定出了什么问题 所以 这是代码 include
  • 为什么使用数组索引循环数组比指针访问慢?

    我正在读Kochan的书 Programming in C 在第 14 页的 指针和数组 部分中 264 他说 一般来说 索引数组的过程比执行索引过程花费更多的时间 访问指针内容的过程 其实这也是主要原因之一 为什么使用指针来访问数组的元素
  • 表达式访问者仅为某些 lambda 表达式调用 VisitParameter

    我希望能够使用嵌套扩展方法将 EF 中的实体投影到相应的视图模型 参见我之前的问题使用扩展方法在 EF 中投影单个实体 https stackoverflow com questions 39585427 projection of sin
  • C++:字符串流有什么好处?

    谁能告诉我一些在 C 中使用字符串流的实际例子 即使用流插入和流提取运算符输入和输出到字符串流 您可以使用字符串流来转换任何实现operator lt lt 到一个字符串 include
  • 为什么 fgets 接受 int 而不是 size_t?

    功能如strcpy malloc strlen 和其他各种接受他们的参数或返回值作为size t代替int or an unsigned int出于显而易见的原因 一些文件功能 例如fread and fwrite use size t以及
  • C 链表销毁函数

    我正在尝试学习 C 和很多人一样 我对指针有点困惑 无论如何 我创建了一个递归函数来销毁我的链表 但是正如我调试的那样 当我从函数返回时 列表的头部不应该为空 所以我猜这是对指针的一些基本误解 这是函数 void destroy struc
  • 如何在Unity Inspector中创建多维数组?

    如何在 Unity Inspector 中创建枚举多维数组并使其可序列化 以便我可以从不同的脚本调用它 public enum colors red blue green yellow cyan white purple public in
  • 用 OpenCL C 编写快速线性系统求解器

    我正在编写一个 OpenCL 内核 它将涉及求解线性系统 目前我的内核太慢了 提高线性系统部分的性能似乎是一个不错的起点 我还应该注意 我并没有尝试使我的线性求解器并行 我正在研究的问题在宏观层面上已经是令人尴尬的并行 以下是我编写的 C
  • 可以通过模板间接访问基类中的私有类型

    我试图在编译时根据类型是否在给定范围内公开可用来选择要使用的类型 最好直接看代码 include
  • _MM_TRANSPOSE4_PS 在 GCC 中导致编译器错误?

    我第一次在 GCC 而不是 MSVC 中编译我的数学库 并经历了所有的小错误 我遇到了一个根本没有意义的错误 Line 284 error lvalue required as left operand of assignment 284号
  • 是否自初始化 'A a = a;'允许吗?

    此代码在运行时在复制构造函数中失败 但编译器 MSVS2008 没有发出警告 您能解释一下 最好引用标准 这段代码是否非法或什么 我理解 A a a 永远不应该写在第一位 但我正在寻找理论背景 class A public A p new
  • 使用信号和槽更新指针

    我对 Qt 很陌生 请帮我解决这个问题 我正在使用线程在后台执行密集操作 同时我想更新 UI 所以我使用 SIGNALS 和 SLOTS 为了更新 UI 我发出一个信号并更新 UI 让我们考虑下面的示例代码 struct sample QS
  • 从 AuthorizeAttribute 继承的属性不起作用

    我目前正在尝试根据用户角色在新的 ASP MVC 5 应用程序中实现安全性 目标是防止用户在没有特定角色 或更高角色 的情况下访问某些控制器或控制器方法 根据到目前为止我所读到的问题 我创建了一个继承 AuthorizeAttribute
  • 如何解决 boost::multi precision::cpp_dec_float 除法错误

    除以boost multiprecision cpp dec float有某种舍入误差 如下 include
  • 如何在realm-dotnet中存储System.Collections.Generic.Dictionary

    我正在尝试将 Realm NET 集成到我的 uwp 项目中 我想知道是否有任何方法可以在 Realm dotnet 库中存储 System Collections Generic Dictionary 我试过这个 public class
  • 使用 DataGridViewCheckboxCell 真正禁用 DataGridView 中的复选框

    有谁知道如何使用 DataGridViewCheckboxCell 禁用 DataGridView 中的复选框 我可以将其设置为只读 并设置背景颜色 但我无法让复选框本身显示为禁用状态 有什么想法吗 Guess 你必须自己画 http so
  • 如何使用 .NET 捕获我的桌面视频?

    我想知道是否有任何方法可以使用 NET 捕获我的桌面的视频 截屏视频 我并不是在寻找截屏软件 而只是在寻找一种可以让我自己生成桌面视频的技术 我想过拍摄多个屏幕截图 但我不确定如何以编程方式生成带有图像序列的视频 有人有主意吗 Thanks
  • 调用泛型类的方法

    这是上下文 我尝试编写一个映射器来动态地将域模型对象转换为 ViewModel 对象 我遇到的问题是 当我尝试通过反射调用泛型类的方法时 出现此错误 System InvalidOperationException 无法对 Contains
  • 打印任何类型的数组和列表的通用方法[重复]

    这个问题在这里已经有答案了 每当我调试一段涉及整数 双精度 字符串等数组或列表的代码时 有时我更喜欢打印它们 我为此所做的是为不同类型编写重载的 printArray printList 方法 for e g 我可能有这 3 种方法来打印各
  • 如何使用实体框架设置连接字符串

    我将 EF6 与 MySQL 结合使用 并有一个用于多个数据库的模型 我希望能够在我的表单中设置连接设置 如何以编程方式设置模型的连接字符串 你应该使用EntityConnectionFactory这就是您所需要的 public strin

随机推荐

  • 如何获取 msvc 所需的运行时库的位置

    我有 CMake 的自定义包装器 它为各种平台 win32 SunOS 等 和不同的编译器执行配置 编译和创建发行版 我需要将所有需要的运行时库放入 distrib 中 nix 的 libgcc s so libstdc so 如 OS m
  • ViewController 内的 UINavigationController,视图顶部的间隙

    我正在开发一个通用应用程序 并尝试在 iPhone 和 iPad 版本之间共享尽可能多的代码 我需要使用 TabBarController 作为我的根视图控制器 虽然我想在每个选项卡中使用 SplitViewController 但 Spl
  • gitignore 根本不起作用。我无法让它忽略 .DS_Store 和 .gitignore 文件

    I have gitignored DS Store and gitignore文件 但仍然可以在 git status 中看到它们 有人可以向我解释如何确保在检查状态时我试图忽略的文件不会出现吗 git status Untracked
  • Tango Trees 有实际应用吗?

    平衡二叉搜索树 http en wikipedia org wiki Self balancing binary search tree给出一个O log n 保证搜索时间 探戈树 https en wikipedia org wiki T
  • 在Perl中,如何“跳过”某些文本并在剩余部分中进行搜索和替换? [复制]

    这个问题在这里已经有答案了 文本中多次出现pattern 在进行正则表达式查找和替换时 我想跳过文本的某些片段并替换pattern在剩下的部分 例如 在代码中 usr bin env perl use strict use warnings
  • 实时策略游戏如何在 PHP 中运行?

    一些 MMO 实时策略游戏 例如 Travian 或 oGame 是用 PHP 编码的 您能简单解释一下这样的游戏在幕后是如何运作的吗 游戏如何在没有玩家请求的情况下进行实时数据库更新 另外 当运行 Travian 等拥有 1000 名活跃
  • IE 兼容性问题:

    内的

    我有以下 HTML CSS 其中只有一个 span 标签样式为float right里面一个 h2 tag h2 H2 Test span SPAN text span h2 在 Firefox 上一切都运行良好 我怀疑其他好的浏览器 如

  • 带 2 补码的二进制减法

    我需要帮助使用 2 的表示形式进行二进制减法 并为每个数字使用 5 位 1 9 7 有溢出吗 9 01001 2 的补码 10111 和 7 00111 2 的补码 11001 现在我们需要添加 因为我们使用的是 2 的补码 10111 1
  • centos 7安装pymssql时出错

    我在虚拟机 Centos 7 中安装 pymssql 时遇到了这个问题 我安装的python版本是2 7 6 用于安装 pymssql 的命令 pip intall pymssql 错误信息 root dpitstsvr013 magend
  • 有没有办法对 Powershell cmdlet 的结果进行自动换行?

    简单 可能是愚蠢 的问题 我是 Powershell 新手 主要使用它来实例化托管库 因此当我需要使用其中的成员时 我不必编写小应用程序 其中一些库很旧 并且其方法签名又长又痛苦 在使用 new object 实例化后使用 get memb
  • 我可以使用哪些 March/mtune 选项?

    有没有办法让 gcc 输出可用的 march arch 选项 我遇到构建错误 尝试过 march x86 64 我不知道我的选择是什么 我使用的编译器是 gcc 的专有包装器 它似乎不喜欢 march skylake 标志应该是相同的 所以
  • 如何用XMPP实现聊天列表

    我有 Ejabberd 服务器和移动 iOS Android 应用程序 我想构建一个简单的聊天应用程序 有两个屏幕 聊天列表 带有特定聊天消息的屏幕 我对聊天列表的实现有疑问 我用XEP 0313 消息存档管理 https xmpp org
  • 在 Android Studio 中,构建 Android Wear 项目,如何在两个模块中包含相同的文件

    我成功地在移动设备上构建了 Android Wear 表盘和连接的应用程序 问题是我有几个资源和类文件在两个文件中都被引用mobile and wear模块 我构建这个的骨架应用程序还创建了一个 非构建 DigitalWatch模块 我猜我
  • WebDav 请求的 Httphandler

    我正在尝试编写一个 asp net httphandler 来使用 IIS 处理 webdav 请求 我正在扩展 IHttpHandler 接口并实现 ProcessRequest public class clsMyHandler IHt
  • 更改 TabNine 在建议窗口中的优先级

    我在 VSCode 中使用 TabNine 已经有一段时间了 它非常棒 除了当我必须选择函数 其他名称而不是 TabNine 的建议时 My question is Can we change any setting such that a
  • WebAssembly 使用什么引擎?

    在 Chrome 中 JavaScript 运行在 V8 引擎上 但是运行 WebAssembly 代码的引擎是什么 浏览器如何突然能够通过 WebAssembly 提供改进的性能 此 WebAssembly 引擎在浏览器中始终可用 还是最
  • 将字符串保存到文件

    我有一个迭代 在我看来 email protected cdn cgi l email protection i each do i doing things bigtable lt lt result 0 result length 2
  • .well 类中的垂直居中 bootstrap btn

    我有一个链接 我想将其垂直居中 well来自引导框架的类并且正在使用该类btn btn danger在锚标签上 这是下面的图片 我尝试使用vertical align middle 但这似乎不起作用 您可以看到井上的空间甚至不包括顶部和底部
  • 代码隐藏中带有转换器的数据模板

    我正在尝试在代码隐藏中加载 DataTemplate 但是如果我删除转换器 它就可以正常工作 但是一旦我将其放入其中 它就会崩溃 现在 我确实将我的状态设置为我的命名空间 并将对我的转换器的引用放置在 XAML 中 例如
  • 带有调试输出的 X3 解析器段错误 (BOOST_SPIRIT_X3_DEBUG)

    Update 这个问题涉及两个问题 如接受的答案 https stackoverflow com a 43688320 2428220 这两个问题都存在于 Boost Spirit X3 随 Boost 1 64 一起提供的版本中 但在撰写