boost.spirit -- action

7       action

action是用来解析完成以后执行某种动作的类,所有的action类使用起来的形式为parser[action]

 

一望而知,parser类必定实现了一个operator[]。这个函数实现在基类parser中,被所有的parser继承。

 

        template <typename ActionT>

        action<DerivedT, ActionT>

        operator[](ActionT const& actor) const

        {

            return action<DerivedT, ActionT>(derived(), actor);

        }

 

parser::operator[]有一个参数actor,就是解析成功以后调用的动作函数,是一个function object

 

返回模板类action的一个对象。

 

7.1    action template class

action模板类实际上是一个标准的装饰器(decorator)模式的实现。回想一下decorator的定义:继承一个类的接口,并给这个类动态透明的添加职责。

 

 

对于parser来说,它是完全无须知道action的存在的。action本身继承自parser,实现了parse接口,在parse中,在调用了parser本身的parse功能以后,以parse_result为参数调用actor.operator()(result)

 

 

 

看看action::parse的实现:

 

        template <typename ScannerT>

        typename parser_result<self_t, ScannerT>::type

        parse(ScannerT const& scan) const

        {

            typedef typename ScannerT::iterator_t iterator_t;

            typedef typename parser_result<self_t, ScannerT>::type result_t;

 

            scan.at_end(); // allow skipper to take effect

            iterator_t save = scan.first;

//调用subject(parser)parse方法做解析工作。

            result_t hit = this->subject().parse(scan);

//如果解析成功,执行actor动作。通过调用scan.do_action方法实现,具体实现见后。

            if (hit)

            {

                typename result_t::return_t val = hit.value();

                scan.do_action(actor, val, save, scan.first);

            }

            return hit;

        }

 

7.2    scanner::do_action

 

可以看出,actionparser添加的职责是调用scanner::do_action来实现的,可以回忆一下scanneraction_policy 实际上,scanner是通过继承action_policy类来继承do_action方法的。

 

 

    struct action_policy

    {

        template <typename ActorT, typename AttrT, typename IteratorT>

        void

        do_action(

            ActorT const&       actor,

            AttrT&              val,

            IteratorT const&    first,

            IteratorT const&    last) const

        {

            attributed_action_policy<AttrT>::call(actor, val, first, last);

        }

};

 

调用流转到了模板类attributed_action_policy,这个模板类有两个特化版本:

 

// 对于有Attributeparser而言,(比如primitives)可以推导出确定AttrT,调用这个版本。最终调用actor.operator()(val)。这个时候,需要提供的actor是接受一个确定类型参数(parser解析得到的结果类型)function object

    template <typename AttrT>

    struct attributed_action_policy

    {

        template <typename ActorT, typename IteratorT>

        static void

        call(

            ActorT const& actor,

            AttrT& val,

            IteratorT const&,

            IteratorT const&)

        {

            actor(val);

        }

    };

 

//对于没有Attributeparser(比如composite)AttrT=nil_t,调用这个版本,这个时候调用actor.operator(first, last);这个时候,需要提供的actor是接受一对迭代器的function object

    template <>

    struct attributed_action_policy<nil_t>

    {

        template <typename ActorT, typename IteratorT>

        static void

        call(

            ActorT const& actor,

            nil_t,

            IteratorT const& first,

            IteratorT const& last)

        {

            actor(first, last);

        }

    };

 

 

7.3    actors

 

 

 

spirit中定义了很多actors,这个actor都实现了operator(AttrT)或是operator(IteratorT, IteratorT)

 

spirit实现了5actor

 

 

实际上,这5actor都是模板类,都有一个模板参数ActionT,而且都从ActionT继承。actorActionT的功能完全正交;actor的功能是决定如何操作三类对象,而ActionT提供实际的操作方式。

 

actor要操作的三类对象有:

1.  目的对象(actor操作的对象):这个对象一般作为actor的成员

2.  源对象(parse的结果):这个对象一般作为operator()函数的参数

3.  其他对象(这些对象作为function object的附加参数):这些对象一般作为actor的成员

 

通过继承模板参数类的方式:

template <typename ActionT>

struct any_actor : public ActionT { /*…*/ };

 

ActionT的功能混入(mixin) actor中;通过用不同的ActionT实例化actor类,使actor得到不同的操作能力。各种ActionT与各种actor之间的任意混合,我们只需实现nactormActionT,就能得到n*mactor<ActionT>类。

 

 

 

1.  ref_actor:只持有目的对象,在operator()中忽略源对象。适合混入只操作一个单一引用的ActionT,比如increment_action

2.  ref_value_actor:最为常用,持有目的对象,并在operator()中引用源对象;适合混入标准ActionT,操作两个引用对象。比如assign_action

3.  ref_const_ref_actor:持有目的和其他对象,在operator()忽略源对象。当然源对象也可以作为其他对象使用,不过需要在构造的时候传入,并不是在operator()中引用。混入的ActionT需要接受两个引用参数。

4.  ref_const_ref_value_actor:持有目的对象和其他对象,并且在operator()中引用源对象,混入的ActionT接受三个参数。

5.  ref_const_ref_const_ref_actor:持有目的对象和两个其他对象,但是在operator()忽略源对象,混入的ActionT需接受三个参数。

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值