boost Spirit x3分裂后奇怪的语义行为

2023-12-01

在我将语法分成推荐的语法后,我遇到了 boostspirit x3 的奇怪行为parser.hpp, parser_def.hpp, parser.cpp文件。 我的示例语法解析某种简单的枚举:

enum = "enum" > identifier > "{" > identifier % "," > "}

这是我的枚举语法。 当我不将枚举和标识符解析器拆分为推荐的文件时,一切正常,尤其是字符串"enum {foo, bar}"正如预期的那样,抛出预期失败。 这个例子可以在这里找到:未分割的工作示例

但是当我将完全相同的语法分成不同的文件时,解析器会抛出

terminate called after throwing an instance of 'std::logic_error'
  what():  basic_string::_M_construct null not valid

尝试解析相同的字符串"enum {foo, bar}"

这个例子可以在这里找到:分裂奇怪的例子

  1. ast.hpp

    #pragma once
    
    #include <vector>
    #include <string>
    #include <boost/fusion/include/adapt_struct.hpp>
    
    
    
    namespace ast{
    
    namespace x3 = boost::spirit::x3;
    
    struct Enum {
        std::string _name;
        std::vector<std::string> _elements;
    };
    
    
    }
    
    BOOST_FUSION_ADAPT_STRUCT(ast::Enum, _name, _elements)
    
  2. 配置文件

    #pragma once 
    
    #include <boost/spirit/home/x3.hpp>
    
    namespace parser{
    
        namespace x3 = boost::spirit::x3;
    
        typedef std::string::const_iterator iterator_type;
        typedef x3::phrase_parse_context<x3::ascii::space_type>::type context_type;
    
    }
    
  3. enum.cpp

    #include "enum_def.hpp"
    #include "config.hpp"
    
    namespace parser { namespace impl {
         BOOST_SPIRIT_INSTANTIATE(enum_type, iterator_type, context_type)
    }}
    
    namespace parser {
    
    const impl::enum_type& enum_parser()
    {
        return impl::enum_parser;
    }
    
    }
    
  4. 枚举_def.hpp

    #pragma once
    
    #include "identifier.hpp"
    #include "enum.hpp"
    #include "ast.hpp"
    
    namespace parser{ namespace impl{
    
        namespace x3=boost::spirit::x3;
    
        const enum_type enum_parser = "enum";
    
        namespace{
            const auto& identifier = parser::identifier();
        }
        auto const enum_parser_def =
            "enum"
            > identifier
            > "{"
            > identifier % ","
            >"}";
    
        BOOST_SPIRIT_DEFINE(enum_parser)
    }}
    
  5. enum.hpp

    #pragma once
    
    #include <boost/spirit/home/x3.hpp>
    #include "ast.hpp"
    
    namespace parser{ namespace impl{
        namespace x3=boost::spirit::x3;
    
        typedef x3::rule<class enum_class, ast::Enum> enum_type;
    
        BOOST_SPIRIT_DECLARE(enum_type)
    
    }}
    
    namespace parser{
        const impl::enum_type& enum_parser();
    }
    
  6. 标识符.cpp

    #include "identifier_def.hpp"
    #include "config.hpp"
    
    namespace parser { namespace impl {
         BOOST_SPIRIT_INSTANTIATE(identifier_type, iterator_type, context_type)
    }}
    
    namespace parser {
    
    const impl::identifier_type& identifier()
    {
        return impl::identifier;
    }
    
    }
    
  7. 标识符_def.hpp

    #pragma once
    #include <boost/spirit/home/x3.hpp>
    #include "identifier.hpp"
    
    namespace parser{ namespace impl{
    
        namespace x3=boost::spirit::x3;
    
        const identifier_type identifier = "identifier";    
    
        auto const identifier_def = x3::lexeme[
            ((x3::alpha | '_') >> *(x3::alnum | '_'))
        ];
    
        BOOST_SPIRIT_DEFINE(identifier)
    }}
    
  8. 标识符.hpp

    #pragma once
    #include <boost/spirit/home/x3.hpp>
    
    namespace parser{ namespace impl{
        namespace x3=boost::spirit::x3;
    
        typedef x3::rule<class identifier_class, std::string> identifier_type;
    
        BOOST_SPIRIT_DECLARE(identifier_type)
    }}
    
    
    namespace parser{
        const impl::identifier_type& identifier();
    }
    
  9. main.cpp

    #include <boost/spirit/home/x3.hpp>
    #include "ast.hpp"
    #include "enum.hpp"
    
    namespace x3 = boost::spirit::x3;
    
    template<typename Parser, typename Attribute>
    bool test(const std::string& str, Parser&& p, Attribute&& attr)
    {
        using iterator_type = std::string::const_iterator;
        iterator_type in = str.begin();
        iterator_type end = str.end();
    
        bool ret = x3::phrase_parse(in, end, p, x3::ascii::space, attr);
        ret &= (in == end);
        return ret;
    
    }
    
    int main(){
        ast::Enum attr;
        test("enum foo{foo,bar}", parser::enum_parser(), attr);
        test("enum {foo,bar}", parser::enum_parser(), attr);    
    }
    

这是一个错误,我错过了什么,还是这是一个预期的行为?

EDIT: here是我的存储库,其中包含一个抛出异常的示例std::logic_error而不是expectation_failure


我已经找到了错误的原因。

该错误在于,expect 指令按值获取主题解析器,该值位于parser::impl::identifier初始化程序运行。

为了形象化,想象一下静态初始化器parser::impl::enum_parser之前运行parser::impl::identifier。这对于编译器来说是有效的。

因此,该副本具有未初始化的name场,一旦期望点试图构建x3::expectation_failurewhich_成员,因为构建一个std::string from a nullptr是非法的。

总而言之,我担心这里的根本原因是静态初始化顺序惨败。我会看看是否可以修复它并提交 PR。

解决方法:

一个直接的解决方法是反向列出源文件的顺序,以便在定义之后使用:

set(SOURCE_FILES 
    identifier.cpp
    enum.cpp 
    main.cpp 
)

请注意,如果这在您的编译器上修复了它(它在我的编译器上修复了),那么它是实现定义的。该标准没有指定跨编译单元的静态初始化的顺序。

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

boost Spirit x3分裂后奇怪的语义行为 的相关文章

随机推荐

  • 每次注销后 RVM 设置都会丢失

    我按照以下说明在 ubuntu 上使用 RVM 安装了 ruby rails 和 gemset http railstutorial org ruby on rails tutorial book sec rubygems 现在的问题是 每
  • 如何在android中用标记显示地图

    我正在开发 Android 应用程序 而且我在这方面完全是新手 所以我想知道如何在地图中显示标记以及如何在特定时间更改他的位置 例如定义线程或背景中的任何内容 这些内容将发送纬度和经度值并且标记在该位置上移动 如果您只想展示单个项目 Map
  • GCP Dataflow 2.0 PubSub 到 GCS

    我很难理解 TextIO write 的 withFileNamePolicy 的概念 对于像指定 GCS 存储桶来写入流式文件这样简单的事情来说 提供 FileNamePolicy 的要求似乎非常复杂 在较高级别上 我将 JSON 消息传
  • 如何运行依赖于 Android 库模块的单元测试?

    每当我尝试对应用程序模块中依赖于库模块中的类的类运行单元测试时 我都会得到以下信息 java lang NoClassDefFoundError de ivu junittest DummyData at de ivu junittest
  • 删除列表中某些连续的重复项

    我有一个这样的字符串列表 foo bar bar baz 我想更换 与单个 但离开 bar bar 完好无损的 IE 替换任意连续的数字 与一个 我当前的代码如下所示 p foo bar bar baz np p 0 for pi in r
  • 将 bash 变量作为模式传递给 awk

    我想知道如何通过bash variable as a pattern to awk 我读过几个问答 它们往往回答同一个问题 但是 它们都没有解决我的问题 可能 我错过了一些东西 我有几个这样的文件 1 9909 23121 1 23121
  • Cronjob 但适用于 jQuery/Javascript

    我正在尝试开发一个主要使用 PHP 的 Web 应用程序 但我正在使用 jQuery Javascript 从人们的 URL 中获取他们的推文 问题是想要运行 PHP cron 作业来获取已注册我的应用程序的人的最新推文 但我不知道如何用
  • Scip 与 Pyomo 接口的问题

    我正在尝试使用 Pyomo 解决非线性优化问题 首先 我尝试了 Ipopt 求解器 并且运行起来了 然后我想尝试一下求解器Scip由于 Ipopt 是局部求解器 因此尝试进行全局优化 但是 我在使用它时遇到了我无法理解的错误 让 Scip
  • SSIS 包将不再在 Visual Basic 中执行 - 而是通过“构建”

    我是一个超级初学者 使用 Visual Studio 2017 创建我的第一个 SSIS 包 此包打开一个平面文件 csv 并将其添加到 SQL 服务器上的表中 当我按下 开始 按钮 在 Visual Studio 中 时 SSIS 包可以
  • 相对位置的顶部未按预期工作

    为什么 top 属性不起作用 img 当标签 img 是兄弟姐妹 p 但是如果我删除标签 p p 这有效 html body height 100 img position relative top 40 p p Lorem ipsum d
  • 以编程方式将 ipython 笔记本保存为脚本

    优秀的ipython笔记本有一个方便的 script命令行标志自动将笔记本的副本保存为 py脚本文件 删除任何标题和 Markdown 单元格 有没有办法在笔记本打开后从笔记本内部打开此功能 显然 此选项无法访问 config magic
  • 使用jna消费按键事件

    在我正在编写的应用程序之一中 我需要使用某些关键事件 以便其他应用程序不处理它们 在我的代码中 我创建了一个 com sun jna platform win32 WinUser LowLevelKeyboardProc 如下所示 impo
  • 在 Java 中从键盘读取 double

    如何在 Java 中从键盘读取双精度变量 我正在尝试解决这个问题 但没有成功 它说 线程 main 中的异常 java util InputMismatchException 在 java util Scanner throwFor Sca
  • 正则表达式重复字符计数

    如果我有一组像 abcdefghij 这样的字符并使用这些字符 我会使用这些字符随机生成一个密码 例如 生成的密码可以有 6 个字符 如何使用正则表达式验证密码 以使相邻字符不相同并且字符不会重复两次以上 你可以使用类似的东西 1 neig
  • 我可以在 C# 项目上使用 .rc 资源文件吗?

    我有一个 C 解决方案 我需要更新资源文件中的版本 resx 文件是 xml 文件 我已经在 C 资源文件 不是 xml 文件 中完成了它 我想知道是否可以使用类似的东西在我的 C 项目中 您无法直接从 Visual Studio 执行此操
  • 如何通过 Azure 上传小文件 API 在 Yammer API 上上传文件

    如何随 Yammer 消息一起上传附件 任何遗留方法通过attachment1等领域 messages json端点将不再工作 新方法没有很好的记录 https developer yammer com docs upload files
  • com.sun.faces.context.PartialViewContextImpl.createPartialResponseWriter 处的 java.lang.NullPointerException

    我在 JBoss AS 7 1 上的 JSF 2 应用程序中有一个带有延迟加载的 PrimeFaces 5 1 数据表 它在页面加载时排序 所以我知道我的排序实现有效 但是当我单击列进行排序时 它会抛出以下异常 17 48 34 855 E
  • UIWebView 中的 Javascript 回调到 C/Objective-C

    当在 UIWebView 中检测到特定事件时 有没有办法获得对 Objective C 的回调 Javascript 可以向 Objective C 发送回调吗 更新 不再使用 UIWebView 使用 WKWebView 或更好的 Saf
  • 使用本机函数计算 Google 表格的分层标签

    使用 Google Sheets 我想自动对行进行编号 如下所示 关键是我想要这个使用内置函数 only 我有一个实现 其中子项位于单独的列中 例如 Foo 位于 B 列中 Bar 位于 C 列中 Baz 位于 D 列中 但是 它使用自定义
  • boost Spirit x3分裂后奇怪的语义行为

    在我将语法分成推荐的语法后 我遇到了 boostspirit x3 的奇怪行为parser hpp parser def hpp parser cpp文件 我的示例语法解析某种简单的枚举 enum enum gt identifier gt