Spirit X3,如何让属性类型匹配规则类型?

2023-12-15

对于 Spirit X3 解析器的开发,我想使用语义操作(脚注 1)。对我来说,控制如何将属性存储到 STL 容器中非常重要。

这个问题是关于如何控制解析器属性: _attr( ctx ) 与规则类型: _val( ctx ) 匹配,以便可以正确分配它。也许这个问题归结为如何应用无证变换属性特征。但请和我一起阅读,看看这是否真的是示例代码中为我解决的问题。

打印对象/变量的类型

当我尝试不同的语法表达式时,我发现非常有用的是能够在语义操作中打印 _attr( ctx ) 和 _val( ctx ) 的类型。

所以根据答案霍华德·希南特,我编写了一个实用程序头文件来根据我的喜好提供类似的功能。

code below is to be put in a file named utility.h

#include <string>
#include <type_traits>
#include <typeinfo>
#include <cxxabi.h>

namespace utility
{

template<typename T>
std::string type2string()
{
  std::string r;
  typedef typename std::remove_reference<T>::type TR;

  std::string space = "";
  if ( std::is_const<TR>::value )
    { r = "const"; space = " "; }
  if ( std::is_volatile<TR>::value )
    { r += space + " volatile"; space = " "; }

  int status;
  char* demangled =
    abi::__cxa_demangle( typeid(TR).name(), nullptr, nullptr, &status );
  switch ( status )
  {
    case  0: { goto proceed; }
    case -1: { r = "type2string failed: malloc failure"; goto fail; }
    case -2: { r = "type2string failed: " + std::string(typeid(TR).name()) +
      " nonvalid C++ ABI name"; goto fail; }
    case -3: { r = "type2string failed: invalid argument(s)"; goto fail; }
    default: { r = "type2string failed: unknown status " +
      status; goto fail; }
  }
  proceed:
  r += space + demangled;
  free( demangled );

  /* references are without a space */
  if ( std::is_lvalue_reference<T>::value ) { r += '&'; }
  if ( std::is_rvalue_reference<T>::value ) { r += "&&"; }

  fail:
  return r;
}

}

现在是实际工作示例代码:

#include <cstddef>
#include <cstdio>
#include <cstdint>

#define BOOST_SPIRIT_X3_DEBUG
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/home/x3.hpp>

#include <string>
#include <vector>
#include <utility> // this is for std::move
#include "utility.h" // to print types

namespace client
{
  namespace x3 = boost::spirit::x3;
  namespace ascii = boost::spirit::x3::ascii;

  namespace semantic_actions
  {
    using x3::_val;  // assign to _val( ctx )
    using x3::_attr; // from _attr( ctx )    

    struct move_assign
    {  
      template <typename Context>
      void operator()(const Context& ctx) const
      {
        printf( "move_assign\n" );
        _val( ctx ) = std::move( _attr( ctx ) );
      }
    };

    struct print_type
    {
      template <typename Context>
      void operator()(const Context& ctx) const
      {
        printf( "print_type\n" );

        std::string str;
        str = utility::type2string< decltype( _attr( ctx ) ) >();
        printf( "_attr type: %s\n", str.c_str() );

        // reuse str
        str = utility::type2string< decltype( _val( ctx ) ) >();
        printf( "_val type: %s\n", str.c_str() );
      }
    };
  }

  namespace parser
  {
    using x3::char_;
    using x3::lit;
    using namespace semantic_actions;

    x3::rule<struct main_rule_class, std::string> main_rule_ = "main_rule";

    const auto main_rule__def = (*( !lit(';') >> char_) >> lit(';'))[print_type()][move_assign()];

    BOOST_SPIRIT_DEFINE( main_rule_ )

    const auto entry_point = x3::skip(x3::space)[ main_rule_ ];
  }
}

int main()
{
  printf( "Give me a string to test rule.\n" );
  printf( "Type [q or Q] to quit.\n" );

  std::string input_str;
  std::string output_str;

  while (getline(std::cin, input_str))
  {
    if ( input_str.empty() || input_str[0] == 'q' || input_str[0] == 'Q')
    { break; }

    auto first = input_str.begin(), last = input_str.end();

    if ( parse( first, last, client::parser::entry_point, output_str) )
    {
      printf( "Parsing succeeded\n" );
      printf( "input:  \"%s\"\n", input_str.c_str() );
      printf( "output: \"%s\"\n", output_str.c_str() );
    }
    else
    {
      printf( "Parsing failed\n" );
    }
  }

  return 0;
}

输入始终是:abcd;

output:

Give me a string to test rule.
Type [q or Q] to quit.
<main_rule>
  <try>abcd;</try>
print_type
_attr type: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&
_val type: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&
move_assign
  <success></success>
  <attributes>[a, b, c, d]</attributes>
</main_rule>
Parsing succeeded
input:  "abcd;"
output: "abcd"

好的,到目前为止一切都很好,但假设我想在解析结果中包含分号。我将语法行更改为:

const auto main_rule__def = (*( !lit(';') >> char_) >> char_(";"))[print_type()];

注意:我删除了语义操作 [move_assign()],因为它由于 _attr 和 _val 类型不兼容而无法编译。 现在输出是:

Give me a string to test rule.
Type [q or Q] to quit.
<main_rule>
  <try>abcd;</try>
print_type
_attr type: boost::fusion::deque<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, char>&
_val type: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&
  <success></success>
  <attributes>[]</attributes>
</main_rule>
Parsing succeeded
input:  "abcd;"
output: ""

现在 boost::fusion::deque 的 _attr 类型不是我想要的,我只是 std::string 。我不明白为什么如果我在语义动作括号内拥有语法赋值的完整右侧,_attr 仍然不是 _val 类型。 X3 功能transform_attribute 在这里有帮助吗?我应该如何应用它?或者解决这个问题的另一种好方法是什么,而无需使用 boost fusion 类接口或其他实现细节。

目前的解决方法

我当前的解决方法是定义另一个规则,仅使用语义操作从第一个规则分配。只有 _attr 是 std::string 类型。

  namespace parser
  {
    using x3::char_;
    using x3::lit;
    using namespace semantic_actions;

    x3::rule<struct main_rule_class, std::string> main_rule_ = "main_rule";
    x3::rule<struct main_rule2_class, std::string> main_rule2_ = "main_rule2";

    const auto main_rule__def = *( !lit(';') >> char_) >> char_(";");
    const auto main_rule2__def = main_rule_[print_type()][move_assign()];

    BOOST_SPIRIT_DEFINE( main_rule_, main_rule2_ )

    const auto entry_point = x3::skip(x3::space)[ main_rule2_ ];
  }

output:

Give me a string to test rule.
Type [q or Q] to quit.
<main_rule2>
  <try>abcd;</try>
  <main_rule>
    <try>abcd;</try>
    <success></success>
    <attributes>[a, b, c, d, ;]</attributes>
  </main_rule>
print_type
_attr type: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&
_val type: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&
move_assign
  <success></success>
  <attributes>[a, b, c, d, ;]</attributes>
</main_rule2>
Parsing succeeded
input:  "abcd;"
output: "abcd;"

我希望有一种方法,无需制定另一个规则即可使 _attr 的类型与 _val 匹配。

(1) 我不欣赏作者在这个库中隐藏的聪明才智。因为仅仅一个看似无害的更改就可能会破坏应用程序。而更明确和详尽的方法将更清楚地传达正在发生的事情。我必须把这件事说出来。


直接回答

transform_attribute is not yet记录为 X3 (https://www.boost.org/doc/libs/1_70_0/libs/spirit/doc/x3/html/index.html)但你可以在这里找到它的 Qi 对应物:https://www.boost.org/doc/libs/1_70_0/libs/spirit/doc/html/spirit/advanced/customize/transform.html.

X3 功能transform_attribute 在这里有帮助吗?我应该如何应用它?

无论如何,这是一个您可以通过使用规则轻松访问的实现细节。我喜欢使用匿名规则来帮助解决这个问题:

template <typename T>
    struct as_type {
        template <typename E>
        constexpr auto operator[](E e) const { return x3::rule<struct _, T> {} = e; }
    };

template <typename T>
    static inline constexpr as_type<T> as;

现在你可以写

const auto main_rule__def = as<std::string> [ (*(char_ - ';') >> char_(';')) ];

Live On Coliru

#include <iostream>
//#define BOOST_SPIRIT_X3_DEBUG
#include <boost/spirit/home/x3.hpp>
#include <iomanip> // std::quoted

namespace client {
    namespace x3 = boost::spirit::x3;
    namespace ascii = boost::spirit::x3::ascii;

    namespace parser {
        using x3::char_;
        using x3::lit;

        x3::rule<struct main_rule_class, std::string> main_rule_ = "main_rule";

        template <typename T>
            struct as_type {
                template <typename E>
                constexpr auto operator[](E e) const { return x3::rule<struct _, T> {} = e; }
            };

        template <typename T>
            static inline constexpr as_type<T> as;

        const auto main_rule__def = as<std::string> [ (*(char_ - ';') >> char_(';')) ];

        BOOST_SPIRIT_DEFINE(main_rule_)

        const auto entry_point = x3::skip(x3::space)[main_rule_];
    } // namespace parser
} // namespace client

int main() {
    std::string output_str;
    for(std::string const input_str : { "abcd;" }) {
        auto first = input_str.begin(), last = input_str.end();

        if (parse(first, last, client::parser::entry_point, output_str)) {
            std::cout << "Parsing succeeded\n";
            std::cout << "input:  " << std::quoted(input_str) << "\n";
            std::cout << "output:  " << std::quoted(output_str) << "\n";
        } else {
            std::cout << "Parsing failed\n";
        }
    }
}

Prints

Parsing succeeded
input:  "abcd;"
output:  "abcd;"

理论上可能会有性能开销,但我强烈怀疑所有编译器都会内联这里的所有内容,因为没有任何内容具有外部链接或 vtable,并且所有内容都是 const/constexpr。

替代方案,简化:

Use x3::raw

在这种情况下,您可以使用现有指令获得您想要的行为:x3::raw

Live On Coliru

const auto main_rule__def = x3::raw [ *(char_ - ';') >> ';' ];

不要使用rule<> always

仅当您有递归规则或需要规则的外部链接(在单独的翻译单元中定义它们)时才需要。整个程序缩小到...

Live On Coliru

#include <iostream>
#include <boost/spirit/home/x3.hpp>
#include <iomanip> // std::quoted

namespace x3 = boost::spirit::x3;
namespace client::parser {
    auto const entry_point = x3::raw [ *(x3::char_ - ';') >> ';' ];
}

int main() {
    for(std::string const input : { "abcd;" }) {
        std::string output;
        if (parse(input.begin(), input.end(), client::parser::entry_point, output)) {
            std::cout << "Parsing succeeded\n";
            std::cout << "input:  " << std::quoted(input) << "\n";
            std::cout << "output: " << std::quoted(output) << "\n";
        } else {
            std::cout << "Parsing failed\n";
        }
    }
}

最后——关于跳过

我不认为你想要char_ - ';'(或更详细的拼写方式:!lit(';') >> char_)。使用船长它将解析空白("ab c\nd ;"->“abcd;”`)。

您可能希望使规则更具限制性(例如lexeme [+(graph - ';')]甚至简单地raw[lexeme[+(alnum|'_')] or lexeme[+char_("a-zA-Z0-9_")]).

See 提升精神船长问题

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

Spirit X3,如何让属性类型匹配规则类型? 的相关文章

  • 关于逻辑/算法的想法以及如何防止线程写入 Sql Server 中的竞争

    我有以下逻辑 public void InQueueTable DataTable Table int incomingRows Table Rows Count if incomingRows gt RowsThreshold async
  • C# 中的 Stack<> 实现

    我最近一直在实现递归目录搜索实现 并且使用堆栈来跟踪路径元素 当我使用 string Join 连接路径元素时 我发现它们被颠倒了 当我调试该方法时 我查看了堆栈 发现堆栈内部数组中的元素本身是相反的 即最近 Push 的元素位于内部数组的
  • strlen() 编译时优化

    前几天我发现你可以找到编译时strlen使用这样的东西 template
  • Boost ASIO 串行写入十六进制值

    我正在使用 ubuntu 通过串行端口与设备进行通信 所有消息都必须是十六进制值 我已经在 Windows 环境中使用白蚁测试了通信设置 并得到了我期望的响应 但在使用 Boost asio 时我无法得到任何响应 以下是我设置串口的方法 b
  • 2个对象,完全相同(除了命名空间)c#

    我正在使用第三方的一组网络服务 但遇到了一个小障碍 在我手动创建将每个属性从源复制到目标的方法之前 我想我应该在这里寻求更好的解决方案 我有 2 个对象 一个是 Customer CustomerParty 类型 另一个是 Appointm
  • 使用 C# 和 ASP.NET 在电子邮件附件中发送 SQL 报告

    我正在尝试使用 ASP NET 和 C 从 sql reportserver 2008 作为电子邮件附件发送报告 到目前为止我学会了如何获取 PDF 格式的报告 http weblogs asp net srkirkland archive
  • 混合模型优先和代码优先

    我们使用模型优先方法创建了一个 Web 应用程序 一名新开发人员进入该项目 并使用代码优先方法 使用数据库文件 创建了一个新的自定义模型 这 这是代码第一个数据库上下文 namespace WVITDB DAL public class D
  • 用于在标头更改时重新编译的简单 C 项目的示例 makefile

    有谁有完整的 makefile 可以执行以下操作 如果 HEADER 文件发生更改 则重建项目 cpp 文件在 makefile 中列出 头文件未在 makefile 中列出 头文件允许与 cpp 文件具有不同的名称 部分cpp文件没有头文
  • Makefile 和 .Mak 文件 + CodeBlocks 和 VStudio

    我对整个 makefile 概念有点陌生 所以我对此有一些疑问 我正在 Linux 中使用 CodeBlocks 创建一个项目 我使用一个名为 cbp2mak 的工具从 CodeBlocks 项目创建一个 make 文件 如果有人知道更好的
  • Unity手游触摸动作不扎实

    我的代码中有一种 错误 我只是找不到它发生的原因以及如何修复它 我是统一的初学者 甚至是统一的手机游戏的初学者 我使用触摸让玩家从一侧移动到另一侧 但问题是我希望玩家在手指从一侧滑动到另一侧时能够平滑移动 但我的代码还会将玩家移动到您点击的
  • Libev,如何将参数传递给相关回调

    我陷入了 libev 中争论的境地 通常 libev 在类似的函数中接收包 接收回调 没关系 但是实际操作中 我们需要派遣一个亲戚 写回调 根据收到的包裹处理具体工作 例如 S RECV MSG pstRecvMsg S RECV MSG
  • 如何防止 Blazor NavLink 组件的默认导航

    从 Blazor 3 1 Preview 2 开始 应该可以防止默认导航行为 https devblogs microsoft com aspnet asp net core updates in net core 3 1 preview
  • Unity c# 四元数:将 y 轴与 z 轴交换

    我需要旋转一个对象以相对于现实世界进行精确旋转 因此调用Input gyro attitude返回表示设备位置的四元数 另一方面 这迫使我根据这个四元数作为默认旋转来计算每个旋转 将某些对象设置为朝上的简单方法如下 Vector3 up I
  • 如何从 Boost.PropertyTree 复制子树

    我有一些boost property tree ptree 我需要树来删除一些具有特定标签名称的元素 例如 xml 表示源ptree如下
  • 读取依赖步行者输出

    I am having some problems using one of the Dlls in my application and I ran dependency walker on it i am not sure how to
  • 使用 gcc 时在头文件中查找定义的好方法是什么?

    在使用 gcc 时 有人有推荐的方法在头文件中查找定义吗 使用 MSVC 时 我只需右键单击并选择 转到定义 这非常好 我使用过 netbeans gcc 它确实有代码帮助 包括到定义的超链接 所以这是一种选择 但是 我想知道是否有任何其他
  • 在 C# 的 WebAPI 中的 ApiController 上使用“传输编码:分块”提供数据

    我需要服务分块传输使用编码数据API控制器 因为我无权访问HttpContext or the Http请求 我有点不知道在哪里写入响应以及在哪里刷新它 设置如下 public class MyController ApiControlle
  • winform c# 中的弹出窗口

    我正在开发一个需要弹出窗口的项目 但问题是我还希望能够通过表单设计器在此弹出窗口中添加文本框等 所以基本上我有一个按钮 当您单击它时 它将打开我在表单设计器中设计的另一个窗口 我一直在谷歌搜索 但还没有找到我需要的东西 所以我希望你们能帮助
  • 如果找不到指定的图像文件,显示默认图像的最佳方式?

    我有一个普通的电子商务应用程序 我将 ITEM IMAGE NAME 存储在数据库中 有时经理会拼错图像名称 为了避免 丢失图像 IE 中的红色 X 每次显示产品列表时 我都会检查服务器中是否有与该产品相关的图像 如果该文件不存在 我会将其
  • 如何在 C# 中获取 CMD/控制台编码

    我需要指定正确的代码页来使用 zip 库打包文件 正如我所见 我需要指定控制台编码 在我的例子中为 866 C Users User gt mode Status for device CON Lines 300 Columns 130 K

随机推荐

  • 访问jar内的图像

    第一的 我知道已经存在各种关于如何访问 jar 文件内的图像的主题 第二 我尝试了很多选择 但没有一个不起作用 我当然知道我在某个地方犯了错误 你能帮助我理解我做错了什么吗 所以 我有一个名为 j 的原型项目 它只包含一个 java 类 C
  • 使用 Jackson 序列化时有条件地跳过对象

    我有一个像这样的课程 interface IHideable boolean isHidden class Address implements IHideable private String city private String st
  • Android Activity 在 4.3 设备上运行缓慢

    我开发了一个可以从网络传输视频的应用程序 我有一个活动列出了视频 包括它们的图标 标题和状态 新更新 每行都有一个视频缩略图 视频标题 然后有一个 新鲜 图标来指示它是新上传的 在模拟器中 这工作得相当好 在 2 3 和 4 0 3 HTC
  • 使用 Python 与其他程序交互

    我有一个想法 使用 Python 编写一个程序 该程序将找到我提供的歌曲的歌词 我认为整个过程应该归结为以下几件事 这些是我希望程序在运行时执行的操作 提示我输入歌曲名称 复制那个名字 打开网络浏览器 例如谷歌浏览器 将该名称粘贴到地址栏中
  • 是否还可以自定义STL向量的“参考”类型?

    是否可以定制reference of a std vector 直到 C 11 似乎可以通过Allocator模板参数 但现在不再了吗 根据文档 http en cppreference com w cpp container vector
  • 如何确定 gfortran 正在矢量化什么

    我正在尝试编写一个大规模并行蒙特卡罗代码 其中一部分将导出到 Xeon phi 协处理器 为了确保我有效地使用协处理器 我想看看编译器 当前为 gfortran 能够对代码的哪些部分进行矢量化 我知道我可以使用 ifort commane
  • Android 10 MediaStore 文件权限

    我仅在 Android 10 中遇到图像权限问题 我声明该问题仅适用于 Android 10 事实上 Android 11 和 Android 9 及更早版本都启用了写入和读取权限 在清单中我有
  • 剥离可执行文件 (Windows)

    我听说 strip 是一个可以使可执行文件变小的程序 我尝试从我的编译器 针对 Python 打开它 但是当运行 strip 时 我只是在命令提示符中看到 strip 未被识别为命令或程序 错误 那么我在哪里可以获得 Windows 版 s
  • 如何让图像看起来好像站在平台上(如果它“降落”在平台上)

    所以我正在创建我的第一个 2d java 游戏 我想知道如何让玩家看起来好像站在一个平台上 如果它落在平台上 问题在于 在我的游戏中 NINJA 始终位于屏幕中央并且从不移动 但只有背景和平台移动 关于如何解决问题有什么想法吗 r back
  • 如何调整 JTextField 的大小? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心以获得指导 如何调整 JTextFie
  • ASP.NET:向不同的 Web 表单添加限制

    我目前正在寻求一些建议和帮助 以了解如何避免人们访问页面 除非他们 1 已登录 2 具有访问该页面的正确角色 到目前为止 我已经完成了登录页面 注册页面和其他一些页面 我还有一个链接到这些页面的数据库 用于存储用户及其各自的角色 当前在注册
  • Flutter - 如何切换flutter通道而不需要每次都下载flutter & dart sdk

    目前我正在尝试 flutter web 为此我需要在 flutter master 频道上工作 但是 然后我需要处理其他项目 在他们身上 我正在开发颤振稳定通道 但是 每次我使用命令 flutter channel stable 或 flu
  • 将组合框字符串值转换为 int

    我有一个关于转换类型的问题 我想将当前选定的组合框值字符串更改为 int 但出现错误 My code int Parse age SelectedItem ToString 对于这个问题我能做什么 好的 现在我们知道错误了 您可以在尝试解析
  • xpath 查找特定根下具有特定名称的所有属性

    为了找到所有具有名称的属性myAttr在文档中我可以这样做 myAttr但是如果我想指定根并仍然在文档中查找具有该名称的所有属性怎么办 就像是 root whatever or nothing myAttribute 这样怎么样 root
  • SQL Server 中按 x 排序,然后按 y 列排序

    考虑一个像这样的表 debit credit code 0 10 5 5 0 3 0 11 2 0 15 1 7 0 6 6 0 2 5 0 1 我需要生成这样的结果集 首先借记 然后按代码列排序 debit credit code 5 0
  • 如何在 Flutter 中更改主题?

    所以我在这里尝试获取当前主题 无论是浅色还是深色 所以我可以相应地改变小部件颜色 但是 它不起作用 我使用 if 语句来知道何时是黑暗模式 但它总是 False 这是代码 顺便说一句 它在深色和浅色主题之间切换 但是当我尝试获取当前主题时
  • Subversion E160004 X的根节点的前身是Y但应该是Z

    我继承了一个大型 Subversion 存储库 74010 修订版 并且我正在尝试执行转储 加载以将存储库升级到 1 8 版本 以利用节省空间的功能 在尝试这个过程之前我跑了svnadmin verify对有问题的存储库进行检查 以确保该存
  • 在 Google 商店中将多个 Chrome 扩展程序作为单个项目发布

    Chrome 扩展程序和 Chrome 应用程序具有我需要实现某些功能的 API 但我无法仅使用扩展程序或仅使用应用程序或使用本机代码来实现此目的 所以我制作了一个扩展程序和一个应用程序 并使它们通过消息相互通信 一切正常 但现在我必须发布
  • 将表单提交到操作 php 文件

    我有一个表单 当用户单击 提交 时 我需要运行一个 php 文件 下面是表单和 php 文件
  • Spirit X3,如何让属性类型匹配规则类型?

    对于 Spirit X3 解析器的开发 我想使用语义操作 脚注 1 对我来说 控制如何将属性存储到 STL 容器中非常重要 这个问题是关于如何控制解析器属性 attr ctx 与规则类型 val ctx 匹配 以便可以正确分配它 也许这个问