简体   繁体   English

使用Boost.Spirit.Lex和Boost.Spirit.Qi解析“true”和“false”

[英]Parsing “true” and “false” using Boost.Spirit.Lex and Boost.Spirit.Qi

As the first stage of a larger grammar using Boost.Spirit I'm trying to parse "true" and "false" to produce the corresponding bool values, true and false . 作为使用Boost.Spirit的更大语法的第一阶段,我试图解析“true”和“false”以产生相应的bool值, truefalse

I'm using Spirit.Lex to tokenize the input and have a working implementation for integer and floating point literals (including those expressed in a relaxed scientific notation), exposing int and float attributes. 我正在使用Spirit.Lex来标记输入,并为整数和浮点文字(包括以放松的科学记数法表示的那些)提供工作实现,暴露intfloat属性。

Token definitions 令牌定义

#include <boost/spirit/include/lex_lexertl.hpp>

namespace lex = boost::spirit::lex;

typedef boost::mpl::vector<int, float, bool> token_value_type;

template <typename Lexer>
struct basic_literal_tokens : lex::lexer<Lexer> {
    basic_literal_tokens() { 
        this->self.add_pattern("INT", "[-+]?[0-9]+");
        int_literal = "{INT}";
        // To be lexed as a float a numeric literal must have a decimal point
        // or include an exponent, otherwise it will be considered an integer.
        float_literal = "{INT}(((\\.[0-9]+)([eE]{INT})?)|([eE]{INT}))";

        literal_true = "true";
        literal_false = "false";
        this->self = literal_true | literal_false | float_literal | int_literal;
    }

    lex::token_def<int> int_literal;
    lex::token_def<float> float_literal;
    lex::token_def<bool> literal_true, literal_false;
};

Testing parsing of float literals 测试浮点文字的解析

My real implementation uses Boost.Test, but this is a self-contained example. 我真正的实现使用Boost.Test,但这是一个自包含的示例。

#include <string>
#include <iostream>
#include <cmath>
#include <cstdlib>
#include <limits>

bool parse_and_check_float(std::string const & input, float expected) {
    typedef std::string::const_iterator base_iterator_type;
    typedef lex::lexertl::token<base_iterator_type,
                token_value_type
            > token_type;
    typedef lex::lexertl::lexer<token_type> lexer_type;

    basic_literal_tokens<lexer_type> basic_literal_lexer;
    base_iterator_type input_iter(input.begin());

    float actual;

    bool result = lex::tokenize_and_parse(input_iter, input.end(),
                                          basic_literal_lexer,
                                          basic_literal_lexer.float_literal,
                                          actual);
    return result && std::abs(expected - actual) < std::numeric_limits<float>::epsilon();
}

int main(int argc, char *argv[]) {
    if (parse_and_check_float("+31.4e-1", 3.14)) {
        return EXIT_SUCCESS;
    } else {
        return EXIT_FAILURE;
    }
}

Parsing "true" and "false" 解析“真实”和“虚假”

My problem is when trying to parse "true" and "false". 我的问题是在尝试解析“true”和“false”时。 This is the test code I'm using (after removing the Boost.Test parts): 这是我正在使用的测试代码(删除Boost.Test部分后):

bool parse_and_check_bool(std::string const & input, bool expected) {
    typedef std::string::const_iterator base_iterator_type;
    typedef lex::lexertl::token<base_iterator_type,
                token_value_type
            > token_type;
    typedef lex::lexertl::lexer<token_type> lexer_type;

    basic_literal_tokens<lexer_type> basic_literal_lexer;
    base_iterator_type input_iter(input.begin());

    bool actual;
    lex::token_def<bool> parser = expected ? basic_literal_lexer.literal_true
                                           : basic_literal_lexer.literal_false;
    bool result = lex::tokenize_and_parse(input_iter, input.end(),
                                          basic_literal_lexer, parser,
                                          actual);
    return result && actual == expected;
}

but compilation fails with: 但编译失败了:

boost/spirit/home/qi/detail/assign_to.hpp: In function ‘void boost::spirit::traits::assign_to(const Iterator&, const Iterator&, Attribute&) [with Iterator = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, Attribute = bool]’:
boost/spirit/home/lex/lexer/lexertl/token.hpp:434:   instantiated from ‘static void boost::spirit::traits::assign_to_attribute_from_value<Attribute, boost::spirit::lex::lexertl::token<Iterator, AttributeTypes, HasState>, void>::call(const boost::spirit::lex::lexertl::token<Iterator, AttributeTypes, HasState>&, Attribute&) [with Attribute = bool, Iterator = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, AttributeTypes = boost::mpl::vector<int, float, bool, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na>, HasState = mpl_::bool_<true>]’

... backtrace of instantiation points ....

boost/spirit/home/qi/detail/assign_to.hpp:79: error: no matching function for call to ‘boost::spirit::traits::assign_to_attribute_from_iterators<bool, __gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, void>::call(const __gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >&, const __gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >&, bool&)’
boost/spirit/home/qi/detail/construct.hpp:64: note: candidates are: static void boost::spirit::traits::assign_to_attribute_from_iterators<bool, Iterator, void>::call(const Iterator&, const Iterator&, char&) [with Iterator = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >]

My interpretation of this is that Spirit.Qi doesn't know how to convert a string to a bool - surely that's not the case? 我对此的解释是,Spirit.Qi不知道如何将字符串转换为bool - 当然不是这样吗? Has anyone else done this before? 有没有其他人这样做过? If so, how? 如果是这样,怎么样?

You want something like 你想要的东西

qi::rule<Iterator, bool> true_false_parser;
a = qi::lexeme[ qi::no_case[ qi::eps > ( qi::lit("true")[ _val=true] | qi::lit("false")[ _val=false] ) ] ];

This will throw iff the token is not "true" or "false" 如果令牌不是“true”或“false”,这将抛出iff

To default false do 默认为false

qi::rule<Iterator, bool> true_false_parser;
a = qi::lexeme[ qi::no_case[ ( qi::lit("true")[ _val=true] ) | (*qi::char_)[_val=false] ] ];

This actually looks like it is a bug in Spirit 2.4.1 which has already been fixed in subversion. 这看起来好像是精神2.4.1中的一个错误,已经在颠覆中得到修复。 The log message is "Spirit: Fixing cut&paste error, adding missing specializations for assign_to_attribute_from_iterators<>." 日志消息是"Spirit: Fixing cut&paste error, adding missing specializations for assign_to_attribute_from_iterators<>." (r66624 checked in by hkaiser on 2010-11-18). (r66624由hkaiser于2010-11-18签到)。

The code you provided compiles fine for me using Spirit V2.4.1 (as released with oost V1.45). 你提供的代码使用Spirit V2.4.1编译好(与oost V1.45一起发布)。 It seems you're suffering from a bug, which already has been fixed in the newest version. 看起来你正在遭遇一个已经在最新版本中修复过的bug。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM