Boost.Spirit.Karma 自定义directive
需求:给定一个参数,若它为1,则不输出;若为1,则输出且追加乘法运算符。
分析:这个需求是很容易满足的,一个if语句就可以了。即便是用karma,只需要eps + alternative。这里主要研究如何自定义directive来完成这个任务。自定义generator是类似的,可以参照karma中的源码。
实现步骤:
- 设计directive的名字,取名为coef_。希望的使用方法coef_[generator]或coef_("*")[generator]。
- 使用BOOST_SPIRIT_TERMINAL_NAME_EX宏定义标签
BOOST_SPIRIT_TERMINAL_NAME_EX(coef_, coef_type);
- 然后特化use_directive定义使用方法
template<>struct use_directive<karma::domain, tag::coef_> : mpl::true_ {};template<typename Arg>struct use_directive < karma::domain, terminal_ex <tag::coef_, fusion::vector1<Arg>>> : traits::is_string<Arg> {};
其中的fusion::vector1<Arg> 表明()运算符的参数只有一个。
- 接下来定义directive的具体规则。规则由一个类实现,然后再将标签(coef_)和实现(coef_directive)关联起来。
- 因为要定义的是一个作用在单个generator上的directive(即[]运算符只有一个参数),所以从unary_generator类继承。
template <typename Subject>struct coef_directive : unary_generator<coef_directive<Subject> > {};
- 接下来需要定义三个嵌套类型,subject_type,properties和attribute。
using subject_type = Subject;using properties = typename Subject::properties;template <typename Context, typename Iterator = unused_type>struct attribute : traits::attribute_of<subject_type, Context, Iterator> {};
- 然后定义directive的构造函数。很明显,需要两个参数:generator和乘法运算符。
coef_directive(Subject subject, std::string string) :subject{ std::move(subject) }, string{ std::move(string) }{}Subject subject;std::string string;
- 最后是关键的generate函数,它决定了directive如何进行工作。
template <typename OutputIterator, typename Context, typename Delimiter, typename Attribute>bool generate(OutputIterator& sink, Context& ctx, Delimiter const& d, Attribute const& attr) const {using attribute_type = typename attribute<Context>::type;if (!traits::has_optional_value(attr)) return false;traits::IsOne<Attribute> IsOne;if (IsOne(traits::extract_from<attribute_type>(attr, ctx))) return true;returnsubject.generate(sink, ctx, d, attr) &&string_generate(sink, string) &&delimit_out(sink, d);}
- 然后是一个不太重要的函数what。
template <typename Context>info what(Context& context) const {return info("coefficient", subject.what(context));}
- 因为要定义的是一个作用在单个generator上的directive(即[]运算符只有一个参数),所以从unary_generator类继承。
- 最后需要将coef_和coef_directive关联起来。因为有两种用法,所以需要两次特化。
template <typename Subject, typename Modifiers>struct make_directive<tag::coef_, Subject, Modifiers> {using result_type = coef_directive<Subject>;result_type operator()(unused_type, Subject const& subject, unused_type) const {return result_type{ subject, "" };}};template <typename Subject, typename Arg, typename Modifiers>struct make_directive<terminal_ex <tag::coef_, fusion::vector1<Arg>>, Subject, Modifiers,typename enable_if<traits::is_string<Arg>>::type> {using result_type = coef_directive<Subject>;template <typename Terminal>result_type operator()(Terminal const& term, Subject const& subject, unused_type) const {return result_type{ subject, fusion::at_c<0>(term.args) };}};
- 剩下一点点工作。其中IsOne是这里coef_directive用到的一个traits
template <typename Subject>struct has_semantic_action<karma::coef_directive<Subject> > : unary_has_semantic_action<Subject> {};template <typename Subject, typename Attribute, typename Context, typename Iterator>struct handles_container<karma::coef_directive<Subject>, Attribute, Context, Iterator>: unary_handles_container<Subject, Attribute, Context, Iterator> {};template<typename T>struct IsOne {bool operator()(T const& t) const {return t == 1;}};
完整代码:
#include <boost/spirit/home/support/terminal.hpp>
#include <boost/spirit/home/support/handles_container.hpp>
#include <boost/spirit/home/support/has_semantic_action.hpp>
#include <boost/spirit/home/karma/delimit_out.hpp>
#include <boost/spirit/home/karma/meta_compiler.hpp>
#include <boost/spirit/home/karma/detail/attributes.hpp>
#include <string>namespace boost {namespace spirit {BOOST_SPIRIT_TERMINAL_NAME_EX(coef_, coef_type);template<>struct use_directive<karma::domain, tag::coef_> : mpl::true_ {};template<typename Arg>struct use_directive < karma::domain, terminal_ex <tag::coef_, fusion::vector1<Arg>>> : traits::is_string<Arg> {};namespace karma {using spirit::coef_;using spirit::coef_type;template <typename Subject>struct coef_directive : unary_generator<coef_directive<Subject> > {using subject_type = Subject;using properties = typename Subject::properties;template <typename Context, typename Iterator = unused_type>struct attribute : traits::attribute_of<subject_type, Context, Iterator> {};coef_directive(Subject subject, std::string string) :subject{ std::move(subject) }, string{ std::move(string) }{}template <typename OutputIterator, typename Context, typename Delimiter, typename Attribute>bool generate(OutputIterator& sink, Context& ctx, Delimiter const& d, Attribute const& attr) const {using attribute_type = typename attribute<Context>::type;if (!traits::has_optional_value(attr)) return false;traits::IsOne<Attribute> IsOne;if (IsOne(traits::extract_from<attribute_type>(attr, ctx))) return true;returnsubject.generate(sink, ctx, d, attr) &&string_generate(sink, string) &&delimit_out(sink, d);}template <typename Context>info what(Context& context) const {return info("coefficient", subject.what(context));}Subject subject;std::string string;};template <typename Subject, typename Modifiers>struct make_directive<tag::coef_, Subject, Modifiers> {using result_type = coef_directive<Subject>;result_type operator()(unused_type, Subject const& subject, unused_type) const {return result_type{ subject, "" };}};template <typename Subject, typename Arg, typename Modifiers>struct make_directive<terminal_ex <tag::coef_, fusion::vector1<Arg>>, Subject, Modifiers,typename enable_if<traits::is_string<Arg>>::type> {using result_type = coef_directive<Subject>;template <typename Terminal>result_type operator()(Terminal const& term, Subject const& subject, unused_type) const {return result_type{ subject, fusion::at_c<0>(term.args) };}};}namespace traits {template <typename Subject>struct has_semantic_action<karma::coef_directive<Subject> > : unary_has_semantic_action<Subject> {};template <typename Subject, typename Attribute, typename Context, typename Iterator>struct handles_container<karma::coef_directive<Subject>, Attribute, Context, Iterator>: unary_handles_container<Subject, Attribute, Context, Iterator> {};template<typename T>struct IsOne {bool operator()(T const& t) const {return t == 1;}};}}
}
测试代码:
#include <boost/spirit/include/karma.hpp>
#include <boost/fusion/include/std_pair.hpp>
#include <iostream>
int main() {std::vector<std::pair<int, int>> v{ {1,1},{2,2},{3,3} };namespace karma = boost::spirit::karma;std::cout << karma::format((karma::coef_("*")[karma::auto_] << karma::auto_) % " + ", v) << "\n";return 0;
}
运行结果:
Boost.Spirit.Karma 自定义directive相关推荐
- boost::spirit::karma::real_generator相关的测试程序
boost::spirit::karma::real_generator相关的测试程序 实现功能 C++实现代码 实现功能 boost::spirit::karma::real_generator相关 ...
- boost::spirit::karma::detail::format_manip相关的测试程序
boost::spirit::karma::detail::format_manip相关的测试程序 实现功能 C++实现代码 实现功能 boost::spirit::karma::detail::fo ...
- 【BOOST C++字串专题11】Boost.Spirit(一)
目录 一.Boost.Spirit库介绍 二. boost::spirit::qi::parse()解析格式 三.解析器 一.Boost.Spirit库介绍 本章介绍库 Boost.Spirit. B ...
- boost spirit ——编译器,语法解析器
Spirit 是什么 简单来说,Spirit 是一个 parser generator,功能与 Yacc,ANTLR 类似,且也是基于 EBNF 来描述文法,再基于文法生成 parser,但与前面这些 ...
- boost::spirit模块实现自定义karma计数器的测试程序
boost::spirit模块实现自定义karma计数器的测试程序 实现功能 C++实现代码 实现功能 boost::spirit模块实现自定义karma计数器的测试程序 C++实现代码 #inclu ...
- boost::spirit模块实现自定义用作容器数据的测试程序
boost::spirit模块实现自定义用作容器数据的测试程序 实现功能 C++实现代码 实现功能 boost::spirit模块实现自定义用作容器数据的测试程序 C++实现代码 #include & ...
- boost::spirit模块实现自定义嵌入式容器数据的测试程序
boost::spirit模块实现自定义嵌入式容器数据的测试程序 实现功能 C++实现代码 实现功能 boost::spirit模块实现自定义嵌入式容器数据的测试程序 C++实现代码 #include ...
- boost::spirit模块实现演示自定义的、用户定义的类型如何作为标记值类型轻松地与词法分析器集成
boost::spirit模块实现演示自定义的.用户定义的类型如何作为标记值类型轻松地与词法分析器集成 实现功能 C++实现代码 实现功能 boost::spirit模块实现演示自定义的.用户定义的类 ...
- boost::spirit模块实现利用 Karma 生成器的替代方案和内置匹配功能的测试程序
boost::spirit模块实现利用 Karma 生成器的替代方案和内置匹配功能的测试程序 实现功能 C++实现代码 实现功能 boost::spirit模块实现利用 Karma 生成器的替代方案和 ...
最新文章
- ORB_SLAM2局部建图线程
- 自然语言处理数据集免费资源开放(附学习资料)
- 医学影像AI:全球市场展望
- 动易SiteFactory CMS自动采集器 V2.0
- MYSQL电脑客户端免安装教程以及出现问题解决方案
- hbase1.1.1 连接集群_Hadoop2.7.1+Hbase1.1.2集群环境搭建(10) hadoop hbase kerberos
- ASP.net 省市级联(用户控件)适用用framework3.5以上版本
- redis的简单安装和配置文件的参数
- springboot学习笔记-3 整合redismongodb
- 软考计算机网络初级试题答案,2015年下半年中级软考《计算机网络—网络工程师》试题及答案...
- Gerber文件总结
- 双绞线的线序568A与568B
- linux虚拟机界面菜单栏和任务栏不见了,已解决
- 剧院在线选座票务系统
- PHP微信怎么计步数,微信运动怎么关注好友步数(微信运动计步功能使用方法介绍)...
- debug命令(debug命令的使用)
- 人工智能:智慧环保(上海AI智慧环保,绿色新时代)
- signed integer overflow: -2147483648 - 1 cannot be represented in type ‘int‘
- Spring cloud报错com.netflix.hystrix.exception.HystrixRuntimeException
- 【多线程】多线程基础知识
热门文章
- 射影几何----著名的帕斯卡定理的证明
- Supporting Online Material for Lab Experiments for the Study of Social-Ecological Systems
- SQL注入--报错和盲注
- [附源码]Python计算机毕业设计服装销售商城系统
- 计算机OSI七层参考模型
- 【Neuralink 与大脑的神奇未来】Part 4:Neuralink 的挑战
- HTML5 CSS控制Table内外边框、颜色、大小示例
- 是面试官放水,还是公司实在是太缺人?这都没挂,字节原来这么容易进...
- 机器学习实战 支持向量机SVM 代码解析
- WTD测试框架(一)框架功能模块