C++ 使用boost::spirit解析多种类型的单个值
我想使用boostspirit解析一个可以有多种类型的值;e、 g.类似于:C++ 使用boost::spirit解析多种类型的单个值,c++,boost,boost-spirit,C++,Boost,Boost Spirit,我想使用boostspirit解析一个可以有多种类型的值;e、 g.类似于: singleValueToBeParsed %= (double_ | int_ | bool_ | genericString); genericString %= +(char_("a-zA-Z")); 解析为int或double的情况似乎相当简单: ..但我不确定如何扩展它以包含其他类型,包括通用字符串和布尔 有什么想法吗 谢谢 本 编辑:根据答案,我更新了语法如下: genericString %
singleValueToBeParsed %= (double_ | int_ | bool_ | genericString);
genericString %= +(char_("a-zA-Z"));
解析为int或double的情况似乎相当简单:
..但我不确定如何扩展它以包含其他类型,包括通用字符串和布尔
有什么想法吗
谢谢
本
编辑:根据答案,我更新了语法如下:
genericString %= +(char_("a-zA-Z"));
intRule %= int_;
doubleRule %= (&int_ >> (double_ >> 'f'))
| (!int_ >> double_ >> -lit('f'));
boolRule %= bool_;
其中每个qi规则都有一个字符串、int、double或bool迭代器
那我有个规矩
add %= string("add") >> '('
>> (intRule | doubleRule | genericString) >> ','
>> (intRule | doubleRule | genericString) >> ','
>> genericString
>> ')' >> ';';
它希望采用语法add(5,6.1,result);或添加(a、b、结果);但到目前为止,只有在前两个参数是整数的情况下才能进行解析
注意:添加规则指定为:
qi::rule<Iterator, Function(), ascii::space_type> add;
typedef boost::any DirectValue;
struct Function
{
//
// name of the Function; will always be a string
//
std::string name;
//
// the function parameters which can be initialized to any type
//
DirectValue paramA;
DirectValue paramB;
DirectValue paramC;
DirectValue paramD;
DirectValue paramE;
};
BOOST_FUSION_ADAPT_STRUCT(
Function,
(std::string, name)
(DirectValue, paramA)
(DirectValue, paramB)
(DirectValue, paramC)
(DirectValue, paramD)
(DirectValue, paramE)
)
编辑2:
现在它的解析正确了。见Llonemiz提供。干杯。这是一个有趣的练习 当然,一切都取决于输入语法,您很容易无法指定输入语法
但是,为了演示,假设一个基于C++文字的松散的文法语法(非常),我们可以用下面的方法解析十进制(签名)积分值、浮点值、布尔文本和简单字符串字:
typedef boost::variant<
double, unsigned int,
long, unsigned long, int,
bool, std::string> attr_t;
// ...
start =
(
// number formats with mandatory suffixes first
ulong_rule | uint_rule | long_rule |
// then those (optionally) without suffix
double_rule | int_rule |
// and the simple, unambiguous cases
bool_rule | string_rule
);
double_rule =
(&int_ >> (double_ >> 'f')) // if it could be an int, the suffix is required
| (!int_ >> double_ >> -lit('f')) // otherwise, optional
;
int_rule = int_;
uint_rule = uint_ >> 'u' ;
long_rule = long_ >> 'l' ;
ulong_rule = ulong_ >> "ul" ;
bool_rule = bool_;
string_rule = '"' >> *~char_('"') >> '"';
typedef boost::variant<
双精度,无符号整数,
long,无符号long,int,
bool,std::string>attr\t;
// ...
开始=
(
//首先是带有强制后缀的数字格式
ulong|u规则| uint|u规则| long|u规则|
//然后是那些(可选)没有后缀的
双|规则|内|规则|
//以及简单、明确的案例
布尔规则|字符串规则
);
双U规则=
(&int_>>(double_>>'f'))//如果可以是int,则后缀是必需的
|(!int_>>double_>>-lit('f'))//否则,可选
;
int_规则=int_u;
uint_规则=uint_>>“u”;
long_rule=long_>>“l”;
ulong_规则=ulong_u>>“ul”;
布尔_规则=布尔_;
string_rule='“'>>*~char(''”)>>'”;
有关测试用例的输出,请参见链接的实时演示:
注意只有一个测试输入(“无效”)应该失败。其余的应该解析为文本,可以选择保留未解析的剩余输入
通过测试进行全面演示
#包括
#包括
名称空间qi=boost::spirit::qi;
名称空间业力=提升::精神::业力;
typedef boost::变量属性;
模板
结构分析器:qi::grammar
{
parser():parser::base_类型(开始)
{
使用名称空间qi;
开始=
(
//首先是带有强制后缀的数字格式
ulong|u规则| uint|u规则| long|u规则|
//然后是那些(可选)没有后缀的
双|规则|内|规则|
//以及简单、明确的案例
布尔规则|字符串规则
);
双U规则=
(&int_>>(double_>>'f'))//如果可以是int,则后缀是必需的
|(!int_>>double_>>-lit('f'))//否则,可选
;
int_规则=int_u;
uint_规则=uint_>>“u”;
long_rule=long_>>“l”;
ulong_规则=ulong_u>>“ul”;
布尔_规则=布尔_;
string_rule='“'>>*~char(''”)>>'”;
启动调试节点(启动);
BOOST_-SPIRIT_-DEBUG_节点(双_规则);
BOOST_-SPIRIT_-DEBUG_节点(ulong_规则);
BOOST_SPIRIT_DEBUG_节点(长规则);
BOOST\u SPIRIT\u DEBUG\u节点(uint\u规则);
BOOST_-SPIRIT_-DEBUG_节点(int_规则);
BOOST_-SPIRIT_-DEBUG_节点(bool_规则);
BOOST\u SPIRIT\u DEBUG\u节点(字符串\u规则);
}
私人:
qi::规则开始;
//这里没有船长(重要):
qi::规则双_规则;
qi::规则int_规则;
qi::规则uint_规则;
qi::规则long_规则;
qi::规则ulong_规则;
qi::规则布尔_规则;
qi::规则字符串\规则;
};
结构有效类型:boost::static\u visitor{
模板
std::string运算符()(T const&v)const{
返回typeid(v.name();
}
};
bool测试用例(const std::string和input)
{
typedef std::string::const_迭代器It;
自动f(开始(输入)),l(结束(输入));
语法分析器p;
属性数据;
尝试
{
std::cout+1回答得很好。隐式词素规则比必须将词素
放在任何地方都要好得多。我相信默认策略的行为与bool_规则
一样。噢,啊哈。我错过了删除词素
的一个点(我确实从完整样本中删除了它们):)此外,我还不知道有qi::bool
。修复…非常感谢您的回答!非常感谢:-)干杯。根据您的回答,我对我的问题进行了进一步澄清。解析仍然不正确(请参阅编辑)。我不知道这是否是唯一的问题,但在您的添加规则中,doubleRule
需要在intRule
之前。您是否尝试过启用#define BOOST\u SPIRIT\u DEBUG
以查看正在做出哪些决策?@sehe似乎起作用。我已更改了doubleRule
,替换运算符中规则的顺序在开始
(你的添加
)中。我还用一个变体更改了你的any,因为any在默认情况下不能与运算符一起工作。你能看看Spirit库吗?这是一件非常了不起的事情,你不觉得吗
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
namespace qi = boost::spirit::qi;
namespace karma = boost::spirit::karma;
typedef boost::variant<double, unsigned int, long, unsigned long, int, bool, std::string> attr_t;
template <typename It, typename Skipper = qi::space_type>
struct parser : qi::grammar<It, attr_t(), Skipper>
{
parser() : parser::base_type(start)
{
using namespace qi;
start =
(
// number formats with mandatory suffixes first
ulong_rule | uint_rule | long_rule |
// then those (optionally) without suffix
double_rule | int_rule |
// and the simple, unambiguous cases
bool_rule | string_rule
);
double_rule =
(&int_ >> (double_ >> 'f')) // if it could be an int, the suffix is required
| (!int_ >> double_ >> -lit('f')) // otherwise, optional
;
int_rule = int_;
uint_rule = uint_ >> 'u' ;
long_rule = long_ >> 'l' ;
ulong_rule = ulong_ >> "ul" ;
bool_rule = bool_;
string_rule = '"' >> *~char_('"') >> '"';
BOOST_SPIRIT_DEBUG_NODE(start);
BOOST_SPIRIT_DEBUG_NODE(double_rule);
BOOST_SPIRIT_DEBUG_NODE(ulong_rule);
BOOST_SPIRIT_DEBUG_NODE(long_rule);
BOOST_SPIRIT_DEBUG_NODE(uint_rule);
BOOST_SPIRIT_DEBUG_NODE(int_rule);
BOOST_SPIRIT_DEBUG_NODE(bool_rule);
BOOST_SPIRIT_DEBUG_NODE(string_rule);
}
private:
qi::rule<It, attr_t(), Skipper> start;
// no skippers in here (important):
qi::rule<It, double()> double_rule;
qi::rule<It, int()> int_rule;
qi::rule<It, unsigned int()> uint_rule;
qi::rule<It, long()> long_rule;
qi::rule<It, unsigned long()> ulong_rule;
qi::rule<It, bool()> bool_rule;
qi::rule<It, std::string()> string_rule;
};
struct effective_type : boost::static_visitor<std::string> {
template <typename T>
std::string operator()(T const& v) const {
return typeid(v).name();
}
};
bool testcase(const std::string& input)
{
typedef std::string::const_iterator It;
auto f(begin(input)), l(end(input));
parser<It, qi::space_type> p;
attr_t data;
try
{
std::cout << "parsing '" << input << "': ";
bool ok = qi::phrase_parse(f,l,p,qi::space,data);
if (ok)
{
std::cout << "success\n";
std::cout << "parsed data: " << karma::format_delimited(karma::auto_, ' ', data) << "\n";
std::cout << "effective typeid: " << boost::apply_visitor(effective_type(), data) << "\n";
}
else std::cout << "failed at '" << std::string(f,l) << "'\n";
if (f!=l) std::cout << "trailing unparsed: '" << std::string(f,l) << "'\n";
std::cout << "------\n\n";
return ok;
} catch(const qi::expectation_failure<It>& e)
{
std::string frag(e.first, e.last);
std::cout << e.what() << "'" << frag << "'\n";
}
return false;
}
int main()
{
for (auto const& s : std::vector<std::string> {
"1.3f",
"0.f",
"0.",
"0f",
"0", // int will be preferred
"1u",
"1ul",
"1l",
"1",
"false",
"true",
"\"hello world\"",
// interesting cases
"invalid",
"4.5e+7f",
"-inf",
"-nan",
"42 is the answer", // 'is the answer' is simply left unparsed, it's up to the surrounding grammar/caller
" 0\n ", // whitespace is fine
"42\n.0", // but not considered as part of a literal
})
{
testcase(s);
}
}