Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/135.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用boost::spirit解析多种类型的单个值_C++_Boost_Boost Spirit - Fatal编程技术网

C++ 使用boost::spirit解析多种类型的单个值

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 %

我想使用boostspirit解析一个可以有多种类型的值;e、 g.类似于:

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);
    }
}