免责声明:我对元解析一无所知,对原型也知之甚少。以下代码是我尝试(主要通过反复试验)修改此示例以执行与您想要的类似的操作。
代码可以很容易地分为几个部分:
1. 语法
1.1代币定义
typedef token < lit_c < 'a' > > arg1_token;
typedef token < lit_c < 'b' > > arg2_token;
typedef token < lit_c < 'c' > > arg3_token;
token<Parser>
:
token 是一个解析器组合器,用于Parser
解析输入,然后使用(并丢弃)所有空格。解析的结果是Parser
.
lit_c<char>
:
lit_c 匹配特定char
的并且解析的结果是相同的字符。在语法中,这个结果被always
.
typedef token < keyword < _S ( "true" ), bool_<true> > > true_token;
typedef token < keyword < _S ( "false" ), bool_<false> > > false_token;
keyword<metaparse_string,result_type=undefined>
:
关键字匹配特定的metaparse_string
(_S("true")
返回
metaparse::string<'t','r','u','e'>
Metaparse 在内部使用它来发挥它的魔力)并且解析的结果是result_type
.
typedef token < keyword < _S ( "&&" ) > > and_token;
typedef token < keyword < _S ( "||" ) > > or_token;
typedef token < lit_c < '!' > > not_token;
在 and 的情况下,and_token
结果or_token
是未定义的,并且在下面的语法中它被忽略。
1.2语法的“规则”
struct paren_exp;
首先paren_exp
是前向声明。
typedef one_of<
paren_exp,
transform<true_token, build_value>,
transform<false_token, build_value>,
always<arg1_token, arg<0> >,
always<arg2_token, arg<1> >,
always<arg3_token, arg<2> >
>
value_exp;
one_of<Parsers...>
:
one_of 是一个解析器组合器,它尝试将输入与其参数之一匹配。结果是匹配的第一个解析器返回的结果。
transform<Parser,SemanticAction>
:
transform 是匹配的解析器组合器Parser
。结果类型是Parser
转换后的结果类型SemanticAction
。
always<Parser,NewResultType>
:
匹配Parser
,返回NewResultType
。
等效的精神规则是:
value_exp = paren_exp [ _val=_1 ]
| true_token [ _val=build_value(_1) ]
| false_token [ _val=build_value(_1) ]
| argN_token [ _val=phx::construct<arg<N>>() ];
typedef one_of<
transform<last_of<not_token, value_exp>, build_not>,
value_exp
>
not_exp;
typedef
foldl_start_with_parser<
last_of<and_token, not_exp>,
not_exp,
build_and
> and_exp; // and_exp = not_exp >> *(omit[and_token] >> not_exp);
typedef
foldl_start_with_parser<
last_of<or_token, and_exp>,
and_exp,
build_or
> or_exp; // or_exp = and_exp >> *(omit[or_token] >> and_exp);
foldl_start_with_parser<RepeatingParser,InitialParser,SemanticAction>
:
这个解析器组合器匹配InitialParser
然后RepeatingParser
多次匹配直到它失败。结果类型是 的结果mpl::fold<RepeatingParserSequence, InitialParserResult, SemanticAction>
,其中RepeatingParserSequence
是每个应用程序的结果类型的序列RepeatingParser
。如果RepeatingParser
从未成功,则结果类型为 simple InitialParserResult
。
我相信(xd)等效的精神规则是:
or_exp = and_exp[_a=_1]
>> *( omit[or_token] >> and_exp [ _val = build_or(_1,_a), _a = _val ]);
struct paren_exp: middle_of < lit_c < '(' > , or_exp, lit_c < ')' > > {};
// paren_exp = '(' >> or_exp >> ')';
middle_of<Parsers...>
:
这匹配的序列Parsers
和结果类型是在中间的解析器的结果。
typedef last_of<repeated<space>, or_exp> expression;
//expression = omit[*space] >> or_exp;
repeated<Parser>
:
这个解析器组合器尝试匹配Parser
多次。结果是解析器的每个应用程序的结果类型的序列,如果解析器第一次尝试失败,则结果是一个空序列。此规则只是删除任何前导空格。
typedef build_parser<entire_input<expression> > function_parser;
这一行创建了一个接受输入字符串并返回解析结果的元函数。
2. 表达式的构建
让我们看一个构建表达式的示例演练。这分两步完成:首先,语法构造一个依赖于build_or
、build_and
、build_value
和build_not
的树arg<N>
。获得该类型后,您可以使用proto_type
typedef 获得原型表达式。
“一个||!b”
我们开始or_expr
:
or_expr
: 我们试试它的 InitialParser,它是and_expr
.
and_expr
: 我们试试它的 InitialParser,它是not_expr
.
not_expr
: not_token 失败,所以我们尝试value_expr
。
value_expr
: arg1_token 成功。返回类型是arg<0>
,我们回到not_expr
.
not_expr
:此步骤不修改返回类型。我们回到and_expr
.
and_expr
: 我们尝试了它的RepeatingParser,它失败了。and_expr 成功,它的返回类型是它的 InitialParser: 的返回类型arg<0>
。我们回到or_expr
.
or_expr
: 我们试试它的 RepeatingParser,or_token 匹配,我们试试and_expr
。
and_expr
: 我们试试它的 InitialParser not_expr
。
not_expr
: not_token 成功了,我们试试value_expr
。
value_expr
: arg2_token 成功。返回类型是arg<1>
,我们回到not_expr
.
not_expr
:返回类型通过使用 build_not: build_not::apply< arg<1> >进行转换。我们回到and_expr
.
and_expr
: 我们尝试了它的RepeatingParser,它失败了。and_expr 成功并返回build_not::apply< arg<1> >。我们回到or_expr
.
or_expr
:RepeatingParser 成功,foldlp 使用 build_orbuild_not::apply< arg<1> >
和arg<0>
,获得build_or::apply< build_not::apply< arg<1> >, arg<0> >
.
一旦我们构建了这棵树,我们就会得到它proto_type
:
build_or::apply< build_not::apply< arg<1> >, arg<0> >::proto_type;
proto::logical_or< arg<0>::proto_type, build_not::apply< arg<1> >::proto_type >::type;
proto::logical_or< proto::terminal< placeholder<0> >::type, build_not::apply< arg<1> >::proto_type >::type;
proto::logical_or< proto::terminal< placeholder<0> >::type, proto::logical_not< arg<1>::proto_type >::type >::type;
proto::logical_or< proto::terminal< placeholder<0> >::type, proto::logical_not< proto::terminal< placeholder<1> >::type >::type >::type;
#include <iostream>
#include <vector>
#include <boost/metaparse/repeated.hpp>
#include <boost/metaparse/sequence.hpp>
#include <boost/metaparse/lit_c.hpp>
#include <boost/metaparse/last_of.hpp>
#include <boost/metaparse/middle_of.hpp>
#include <boost/metaparse/space.hpp>
#include <boost/metaparse/foldl_start_with_parser.hpp>
#include <boost/metaparse/one_of.hpp>
#include <boost/metaparse/token.hpp>
#include <boost/metaparse/entire_input.hpp>
#include <boost/metaparse/string.hpp>
#include <boost/metaparse/transform.hpp>
#include <boost/metaparse/always.hpp>
#include <boost/metaparse/build_parser.hpp>
#include <boost/metaparse/keyword.hpp>
#include <boost/mpl/apply_wrap.hpp>
#include <boost/mpl/front.hpp>
#include <boost/mpl/back.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/proto/proto.hpp>
#include <boost/fusion/include/at.hpp>
#include <boost/fusion/include/make_vector.hpp>
using boost::metaparse::sequence;
using boost::metaparse::lit_c;
using boost::metaparse::last_of;
using boost::metaparse::middle_of;
using boost::metaparse::space;
using boost::metaparse::repeated;
using boost::metaparse::build_parser;
using boost::metaparse::foldl_start_with_parser;
using boost::metaparse::one_of;
using boost::metaparse::token;
using boost::metaparse::entire_input;
using boost::metaparse::transform;
using boost::metaparse::always;
using boost::metaparse::keyword;
using boost::mpl::apply_wrap1;
using boost::mpl::front;
using boost::mpl::back;
using boost::mpl::bool_;
struct build_or
{
typedef build_or type;
template <class C, class State>
struct apply
{
typedef apply type;
typedef typename boost::proto::logical_or<typename State::proto_type, typename C::proto_type >::type proto_type;
};
};
struct build_and
{
typedef build_and type;
template <class C, class State>
struct apply
{
typedef apply type;
typedef typename boost::proto::logical_and<typename State::proto_type, typename C::proto_type >::type proto_type;
};
};
template<bool I>
struct value //helper struct that will be used during the evaluation in the proto context
{};
struct build_value
{
typedef build_value type;
template <class V>
struct apply
{
typedef apply type;
typedef typename boost::proto::terminal<value<V::type::value> >::type proto_type;
};
};
struct build_not
{
typedef build_not type;
template <class V>
struct apply
{
typedef apply type;
typedef typename boost::proto::logical_not<typename V::proto_type >::type proto_type;
};
};
template<int I>
struct placeholder //helper struct that will be used during the evaluation in the proto context
{};
template<int I>
struct arg
{
typedef arg type;
typedef typename boost::proto::terminal<placeholder<I> >::type proto_type;
};
#ifdef _S
#error _S already defined
#endif
#define _S BOOST_METAPARSE_STRING
typedef token < keyword < _S ( "&&" ) > > and_token;
typedef token < keyword < _S ( "||" ) > > or_token;
typedef token < lit_c < '!' > > not_token;
typedef token < keyword < _S ( "true" ), bool_<true> > > true_token;
typedef token < keyword < _S ( "false" ), bool_<false> > > false_token;
typedef token < lit_c < 'a' > > arg1_token;
typedef token < lit_c < 'b' > > arg2_token;
typedef token < lit_c < 'c' > > arg3_token;
struct paren_exp;
typedef
one_of< paren_exp, transform<true_token, build_value>, transform<false_token, build_value>, always<arg1_token, arg<0> >, always<arg2_token, arg<1> >, always<arg3_token, arg<2> > >
value_exp; //value_exp = paren_exp | true_token | false_token | arg1_token | arg2_token | arg3_token;
typedef
one_of< transform<last_of<not_token, value_exp>, build_not>, value_exp>
not_exp; //not_exp = (omit[not_token] >> value_exp) | value_exp;
typedef
foldl_start_with_parser <
last_of<and_token, not_exp>,
not_exp,
build_and
>
and_exp; // and_exp = not_exp >> *(and_token >> not_exp);
typedef
foldl_start_with_parser <
last_of<or_token, and_exp>,
and_exp,
build_or
>
or_exp; // or_exp = and_exp >> *(or_token >> and_exp);
struct paren_exp: middle_of < lit_c < '(' > , or_exp, lit_c < ')' > > {}; //paren_exp = lit('(') >> or_exp >> lit('(');
typedef last_of<repeated<space>, or_exp> expression; //expression = omit[*space] >> or_exp;
typedef build_parser<entire_input<expression> > function_parser;
template <typename Args>
struct calculator_context
: boost::proto::callable_context< calculator_context<Args> const >
{
calculator_context ( const Args& args ) : args_ ( args ) {}
// Values to replace the placeholders
const Args& args_;
// Define the result type of the calculator.
// (This makes the calculator_context "callable".)
typedef bool result_type;
// Handle the placeholders:
template<int I>
bool operator() ( boost::proto::tag::terminal, placeholder<I> ) const
{
return boost::fusion::at_c<I> ( args_ );
}
template<bool I>
bool operator() ( boost::proto::tag::terminal, value<I> ) const
{
return I;
}
};
template <typename Args>
calculator_context<Args> make_context ( const Args& args )
{
return calculator_context<Args> ( args );
}
template <typename Expr, typename ... Args>
int evaluate ( const Expr& expr, const Args& ... args )
{
return boost::proto::eval ( expr, make_context ( boost::fusion::make_vector ( args... ) ) );
}
#ifdef LAMBDA
#error LAMBDA already defined
#endif
#define LAMBDA(exp) apply_wrap1<function_parser, _S(exp)>::type::proto_type{}
int main()
{
using std::cout;
using std::endl;
cout << evaluate ( LAMBDA ( "true&&false" ) ) << endl;
cout << evaluate ( LAMBDA ( "true&&a" ), false ) << endl;
cout << evaluate ( LAMBDA ( "true&&a" ), true ) << endl;
cout << evaluate ( LAMBDA ( "a&&b" ), true, false ) << endl;
cout << evaluate ( LAMBDA ( "a&&(b||c)" ), true, false, true ) << endl;
cout << evaluate ( LAMBDA ( "!a&&(false||(b&&!c||false))" ), false, true, false ) << endl;
}
/*int main(int argc , char** argv)
{
using std::cout;
using std::endl;
bool a=false, b=false, c=false;
if(argc==4)
{
a=(argv[1][0]=='1');
b=(argv[2][0]=='1');
c=(argv[3][0]=='1');
}
LAMBDA("a && b || c") expr;
cout << evaluate(expr, true, true, false) << endl;
cout << evaluate(expr, a, b, c) << endl;
return 0;
}*/