令牌解析器语义动作

发布于 2024-10-28 14:46:39 字数 1927 浏览 0 评论 0原文

我已经根据 spirit lex 示例 4

我的规则之一如下所示

    set_name 
        =   (   tok.set_ >> tok.name_ >> tok.identifier )
            [
                std::cout << val("set name statement to: ") << _3 << "\n"
            ]
        ;

这效果很好。当呈现

SET NAME xyz

它时,输出如我所料

将名称语句设置为:xyz

现在我想做一些有用的事情,将找到的名称存储到一个类中。使用 解析器语义示例 我编写了这段代码,

  class writer
    {
    public:
        void print(string const& s) const
        {
            std::cout << s << std::endl;
        }
    };

  writer w;

  ...

    set_name 
        =   (   tok.set_ >> tok.name_ >> tok.identifier )
            [
                boost::bind( &writer::print, &w, ::_3 )
            ]
        ;

但它无法编译。

1>C:\Program Files\boost\boost_1_44\boost/bind/bind.hpp(318) : error C2664: 'R boost::_mfi::cmf1::operator ()(const U &,A1) const' : cannot convert parameter 2 from 'bool' to 'const std::basic_string '
1>        with
1>        [
1>            R=void,
1>            T=eCrew::rule::writer,
1>            A1=const std::string &,
1>            U=eCrew::rule::writer *
1>        ]
1>        and
1>        [
1>            _Elem=char,
1>            _Traits=std::char_traits,
1>            _Ax=std::allocator
1>        ]
1>        Reason: cannot convert from 'bool' to 'const std::string'
1>        No constructor could take the source type, or constructor overload resolution was ambiguous

为什么编译器会抱怨尝试从 bool 转换为 string?我看不到任何布尔值。

I have written a working token parser based on the code shown at spirit lex example 4

One of my rules looks like this

    set_name 
        =   (   tok.set_ >> tok.name_ >> tok.identifier )
            [
                std::cout << val("set name statement to: ") << _3 << "\n"
            ]
        ;

This works well. When presented with

SET NAME xyz

it outputs as I expect

set name statement to: xyz

Now I want to do something useful, store the name found into a class. Working from parser semantic examples I write this code

  class writer
    {
    public:
        void print(string const& s) const
        {
            std::cout << s << std::endl;
        }
    };

  writer w;

  ...

    set_name 
        =   (   tok.set_ >> tok.name_ >> tok.identifier )
            [
                boost::bind( &writer::print, &w, ::_3 )
            ]
        ;

This does not compile

1>C:\Program Files\boost\boost_1_44\boost/bind/bind.hpp(318) : error C2664: 'R boost::_mfi::cmf1::operator ()(const U &,A1) const' : cannot convert parameter 2 from 'bool' to 'const std::basic_string '
1>        with
1>        [
1>            R=void,
1>            T=eCrew::rule::writer,
1>            A1=const std::string &,
1>            U=eCrew::rule::writer *
1>        ]
1>        and
1>        [
1>            _Elem=char,
1>            _Traits=std::char_traits,
1>            _Ax=std::allocator
1>        ]
1>        Reason: cannot convert from 'bool' to 'const std::string'
1>        No constructor could take the source type, or constructor overload resolution was ambiguous

Why is the compiler complaining about a trying to convert from bool to string? There is no bool that I can see.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

地狱即天堂 2024-11-04 14:46:39

中的占位

std::cout << val("set name statement to: ") << _3 << "\n"

符指的是 boost::spirit::_3,它是一个 boost.phoenix v2 占位符。中的占位符

boost::bind(&writer::print, &w, ::_3)

是 boost.bind 占位符(自然)。

这些占位符具有相同的行为,甚至引用相同的数据。 _N 形式的 Phoenix 占位符指的是解析器的第 N 个子属性,而绑定占位符具有不同的含义:

  • _1 指的是整个解析器的属性
  • _2 指的是解析器的上下文
  • _3 指的是bool& 'hit' 参数

您的情况最简单的解决方案是使用 boost::phoenix::bind 而不是 boost::bind,这样您就可以继续使用 _3 来引用解析器的第三个子属性,而不必在 writer::print 内部手动挑选它。

或者,仅将语义操作附加到 tok.identifier ,以便 boost.bind 的 ::_1 按您的预期工作:

set_name
  = tok.set_
    >> tok.name_
    >> tok.identifier[boost::bind(&writer::print, &w, ::_1)]
;

The placeholder in

std::cout << val("set name statement to: ") << _3 << "\n"

refers to boost::spirit::_3, which is a boost.phoenix v2 placeholder. The placeholder in

boost::bind(&writer::print, &w, ::_3)

is a boost.bind placeholder (naturally).

These placeholders do not share the same behavior, or even refer to the same data. Phoenix placeholders of the form _N refer to the Nth subattribute of your parser, while bind placeholders have a different meaning:

  • _1 refers to your parser's attribute as a whole
  • _2 refers to the parser's context
  • _3 refers to a bool& 'hit' parameter

The easiest solution in your case is to use boost::phoenix::bind instead of boost::bind, so that you can continue using _3 to refer to the third subattribute of your parser instead of having to pick it out manually inside of writer::print.

Alternatively, only attach the semantic action to tok.identifier so that boost.bind's ::_1 works as you expect:

set_name
  = tok.set_
    >> tok.name_
    >> tok.identifier[boost::bind(&writer::print, &w, ::_1)]
;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文