我(故意)遗漏了真正的单元测试和语法推导;)
看起来只有当 Spirit 已经检测到规则适用(从一开始)时,Excpetations 才相关,否则解析将会失败
它是一个简单的 C-Identifier 规则和一个 Identfier:Identifier 规则,跳过空格以显示我的误解
// #define BOOST_SPIRIT_DEBUG
#include <boost/fusion/include/io.hpp>
#include <boost/phoenix.hpp>
#include <boost/spirit/include/qi.hpp>
#include <iomanip>
namespace qi = boost::spirit::qi;
namespace Ast
{
struct Identifier : std::string
{
};
struct A_B
{
Identifier a;
Identifier b;
};
} // namespace Ast
BOOST_FUSION_ADAPT_STRUCT( Ast::A_B, a, b )
using Iter = std::string_view::const_iterator;
template <typename ValueType, typename RuleType>
void printing_parse_test( const RuleType& rule_, const std::vector<std::string>& tests )
{
for( std::string_view test : tests )
{
try
{
std::cout << "Parsing: '" << test << "'\n";
Iter f = test.begin(), l = test.end();
// ">> qi::omit[*qi::space]" at end to eat in-between rest spaces ...
ValueType v;
const bool ok = qi::parse( f, l, rule_ >> qi::omit[*qi::space], v );
std::cout << "parse-result: " << ( ok ? "ok" : "failed" ) << "\n";
const std::string left( f, l );
if( ok )
{
if( !left.empty() )
{
std::cout << "FAIL: parsed someway but left this '" << left << "'\n ";
}
else
{
std::cout << "OK: all parsed\n";
}
}
else
{
if( !left.empty() )
{
std::cout << "FAIL: parse failed left this: '" << left << "'\n";
}
}
}
catch( qi::expectation_failure<Iter> const& ef )
{
auto f = begin( test );
auto p = ef.first - test.begin();
auto bol = test.find_last_of( "\r\n", p ) + 1;
auto line = std::count( f, f + bol, '\n' ) + 1;
auto eol = test.find_first_of( "\r\n", p );
std::cout << " -> EXPECTED " << ef.what_ << " in line:" << line << " col:" << ( p - bol ) << "\n"
<< test.substr( bol, eol - bol ) << "\n"
<< std::setw( p - bol ) << ""
<< "^--- here" << std::endl;
}
std::cout << "--------------------\n";
}
std::cout << "============\n";
}
int main()
{
qi::rule<Iter, Ast::Identifier()> identifier_rule = qi::char_( "a-zA-Z_" ) > *qi::char_( "a-zA-Z0-9_" );
identifier_rule.name( "identifier_rule" );
printing_parse_test<Ast::Identifier>( identifier_rule, { " test blib ", "", "23434", "a$", "test blub" } );
qi::rule<Iter, Ast::A_B()> A_B_rule = qi::skip( qi::space )[( identifier_rule > ":" > identifier_rule )];
A_B_rule.name( "A_B_rule" );
printing_parse_test<Ast::A_B>( A_B_rule, { "e$:bd", "a", "", "23434", "a$", "a:$" } );
return 0;
}
输出:
Parsing: ' test blib '
parse-result: failed
FAIL: parse failed left this: ' test blib '
--------------------
Parsing: ''
parse-result: failed
--------------------
Parsing: '23434'
parse-result: failed
FAIL: parse failed left this: '23434'
--------------------
Parsing: 'a$'
parse-result: ok
FAIL: parsed someway but left this '$'
--------------------
Parsing: 'test blub'
parse-result: ok
FAIL: parsed someway but left this 'blub'
--------------------
============
Parsing: 'e$:bd'
-> EXPECTED ":" in line:1 col:1
e$:bd
^--- here
--------------------
Parsing: 'a'
-> EXPECTED ":" in line:1 col:1
a
^--- here
--------------------
Parsing: ''
parse-result: failed
--------------------
Parsing: '23434'
parse-result: failed
FAIL: parse failed left this: '23434'
--------------------
Parsing: 'a$'
-> EXPECTED ":" in line:1 col:1
a$
^--- here
--------------------
Parsing: 'a:$'
-> EXPECTED <identifier_rule> in line:1 col:2
a:$
^--- here
--------------------
============
期望:
为什么在使用这两个规则解析“23434”或空字符串等时我没有得到预期的
还有一个问题是,为什么“a$”只产生预期的“:”,而不是标识符文字也可以的附加信息(或者这更像是一个提示?)
找到了
qi::eps
就是答案 - 这样我从一开始就得到了预期的序列
const bool ok = qi::parse( f, l, qi::eps > rule_ >> qi::omit[*qi::space], v );
在启动时也给我执行