使用boost::spirit解析单个值的多种类型
Using boost::spirit to parse multiple types of single value
我想使用boost spirit来解析可以有多个类型的单个值;例如:
singleValueToBeParsed %= (double_ | int_ | bool_ | genericString);
genericString %= +(char_("a-zA-Z"));
解析为整型或双精度类型的情况似乎相当简单:
使用boost spirit (longest_d)解析int或double
. .但我不确定如何扩展这一点,以纳入其他类型,包括通用字符串和bool .
任何想法?
谢谢,
本。编辑:所以根据答案,我更新了我的语法如下:
genericString %= +(char_("a-zA-Z"));
intRule %= int_;
doubleRule %= (&int_ >> (double_ >> 'f'))
| (!int_ >> double_ >> -lit('f'));
boolRule %= bool_;
,其中每个qi规则有一个string、int、double或bool迭代器
然后我有一个规则
add %= string("add") >> '('
>> (intRule | doubleRule | genericString) >> ','
>> (intRule | doubleRule | genericString) >> ','
>> genericString
>> ')' >> ';';
期望使用语法add(5, 6.1, result);或者add(a, b, result);但到目前为止,它只解析前两个参数是整数的情况。
注意添加规则指定为:
qi::rule<Iterator, Function(), ascii::space_type> add;
和Function指定为:
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:现在解析正确了。参见http://liveworkspace.org/code/3asg0X%247,由llonesmiz提供。欢呼。
这是一个有趣的练习。
当然,一切都取决于输入语法,而您很容易无法指定输入语法。
然而,为了演示,让我们假设字面量语法(非常)松散地基于c++字面量,我们可以提出以下方法来解析十进制(带符号)整数值、浮点值、bool字面量和简单的字符串字面量:
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_('"') >> '"';
查看测试用例输出的实时演示链接:http://liveworkspace.org/code/goPNP
注意只有一个测试输入("invalid")应该失败。其余部分应解析为文本,可选地留下未解析的剩余输入。
带有测试的完整演示
#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 << "successn";
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 << "------nn";
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
" 0n ", // whitespace is fine
"42n.0", // but not considered as part of a literal
})
{
testcase(s);
}
}
相关文章:
- 允许对单个值进行隐式转换
- 连接 OpenCV 垫和单个值
- 将大小为编译时常量的数组初始化为单个值
- 线程安全 std::map:锁定整个映射和单个值
- 在C 中,将单个值写入一个非初始化的指针
- 擦除C++映射中包含单个值的密钥
- 初学者C++:返回单个值。问题:我的金额四舍五入,我不希望它四舍五入
- 使用单个值初始化std::vector-repeative或push_back()
- 在C++中将所有TLS(线程本地存储)变量设置为新的单个值
- 如何从文本中的数组中打印单个值
- C++ 从链表中返回单个值
- C++使用单个值填充空缓冲区
- 如何向多个进程(但不是所有进程)广播或发送单个值
- 读取构造函数的R列表会引发错误:应为单个值
- gcc是否将uint8_t转换为单个值的int ?
- 只产生单个值的迭代器
- ADODB/C++:"执行"返回单个值时返回什么?
- 将单个值解析为带有容器的ast节点
- 如何将一种类型的多个值合并为另一种类型中的单个值
- 使用boost::spirit解析单个值的多种类型