Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/136.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++_Parsing_Boost Spirit - Fatal编程技术网

C++ Boost::spirit无法识别可选表达式

C++ Boost::spirit无法识别可选表达式,c++,parsing,boost-spirit,C++,Parsing,Boost Spirit,我正在学习如何使用,即使使用非常简单的解析器,我也面临一些问题。我试图构造一个解析器,它接受由冒号分隔的数字列表(仅0或1)。列表可以有3位或4位数字。因此,0:0:0和1:0:1:0有效,而例如0:0或0:0:0无效 在下面的代码中,您可以看到我如何使用可选运算符指定第一个数字是否存在。但是,它不起作用(对序列0:0:0的解析失败)。代码中有什么错误吗?我会说这是正确的,但再一次,我刚刚开始学习精神 #include <boost/spirit/include/qi.hpp> n

我正在学习如何使用,即使使用非常简单的解析器,我也面临一些问题。我试图构造一个解析器,它接受由冒号分隔的数字列表(仅0或1)。列表可以有3位或4位数字。因此,
0:0:0
1:0:1:0
有效,而例如
0:0
0:0:0
无效

在下面的代码中,您可以看到我如何使用可选运算符指定第一个数字是否存在。但是,它不起作用(对序列
0:0:0
的解析失败)。代码中有什么错误吗?我会说这是正确的,但再一次,我刚刚开始学习精神

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

namespace qi = boost::spirit::qi;
namespace phoenix = boost::phoenix;

void parse_tuple(const std::string& tuple) {
    using qi::char_;

    auto begin = tuple.begin();
    auto end = tuple.end();

    bool r = qi::parse(begin, end,
            -(char_('0', '1') >> ':') >> 
              char_('0', '1') >> ':' >>
              char_('0', '1') >> ':' >>
              char_('0', '1')
            );
    if (!r || begin != end)
        throw std::runtime_error("wrong format");
}

int main() {
    parse_tuple("0:0:0"); // It fails for this one
    parse_tuple("0:0:0:0");

    try { parse_tuple("0:0"); } catch (...) {
        std::cout << "expected error\n"; }
    try { parse_tuple("0:0:0:0:0"); } catch (...) {
        std::cout << "expected error\n"; }
}
#包括
名称空间qi=boost::spirit::qi;
名称空间phoenix=boost::phoenix;
void parse_tuple(const std::string和tuple){
使用qi::char\ux;
自动开始=tuple.begin();
自动结束=tuple.end();
bool r=qi::解析(开始,结束,
-(字符('0','1')>>':')>>
字符('0','1')>>':'>>
字符('0','1')>>':'>>
字符(“0”、“1”)
);
如果(!r | | begin!=end)
抛出std::runtime_错误(“错误格式”);
}
int main(){
parse_tuple(“0:0:0”);//这一个失败
解析元组(“0:0:0:0”);
尝试{parse_tuple(“0:0”);}catch(…){
std::cout这里

可选字符应该是最后一个,而不是第一个。 规则是按顺序应用的,因此当您解析“0:0:0”时,代码的第一行(可选内容)通过测试,然后您的规则要求后面跟着3位数字,而不是两位

在我看来,您应该只使用%运算符来匹配列表,然后检查是否解析了3个或4个元素

编辑 或用于提高可读性。

此处

可选字符应该是最后一个,而不是第一个。 规则是按顺序应用的,因此当您解析“0:0:0”时,代码的第一行(可选内容)通过测试,然后您的规则要求后面跟着3位数字,而不是两位

在我看来,您应该只使用%运算符来匹配列表,然后检查是否解析了3个或4个元素

编辑
或用于提高可读性。

这将是最简单的解决方案:

bool r = qi::parse(begin, end,
        char_("01") > ':' >
        char_("01") > ':' >
        char_("01") > -(':' > char_("01"))
        );
完整样本

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>

namespace qi = boost::spirit::qi;

void parse_tuple(const std::string& tuple) {
    using qi::char_;

    auto begin = tuple.begin();
    auto end = tuple.end();

    bool r = qi::parse(begin, end,
            char_("01") > ':' >
            char_("01") > ':' >
            char_("01") > -(':' > char_("01"))
            );
    if (!r || begin != end)
        throw std::runtime_error("wrong format");
}

int main() {
    parse_tuple("0:0:0"); // It fails for this one
    parse_tuple("0:0:0:0");

    try { parse_tuple("0:0"); } catch (...) {
        std::cout << "expected error\n"; }
    try { parse_tuple("0:0:0:0:0"); } catch (...) {
        std::cout << "expected error\n"; }
}
#包括
#包括
名称空间qi=boost::spirit::qi;
void parse_tuple(const std::string和tuple){
使用qi::char\ux;
自动开始=tuple.begin();
自动结束=tuple.end();
bool r=qi::解析(开始,结束,
字符(“01”)>':'>
字符(“01”)>':'>
char_uu(“01”)>-(“:”>char_uuu(“01”))
);
如果(!r | | begin!=end)
抛出std::runtime_错误(“错误格式”);
}
int main(){
parse_tuple(“0:0:0”);//这一个失败
解析元组(“0:0:0:0”);
尝试{parse_tuple(“0:0”);}catch(…){

std::cout这将是最简单的解决方案:

bool r = qi::parse(begin, end,
        char_("01") > ':' >
        char_("01") > ':' >
        char_("01") > -(':' > char_("01"))
        );
完整样本

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>

namespace qi = boost::spirit::qi;

void parse_tuple(const std::string& tuple) {
    using qi::char_;

    auto begin = tuple.begin();
    auto end = tuple.end();

    bool r = qi::parse(begin, end,
            char_("01") > ':' >
            char_("01") > ':' >
            char_("01") > -(':' > char_("01"))
            );
    if (!r || begin != end)
        throw std::runtime_error("wrong format");
}

int main() {
    parse_tuple("0:0:0"); // It fails for this one
    parse_tuple("0:0:0:0");

    try { parse_tuple("0:0"); } catch (...) {
        std::cout << "expected error\n"; }
    try { parse_tuple("0:0:0:0:0"); } catch (...) {
        std::cout << "expected error\n"; }
}
#包括
#包括
名称空间qi=boost::spirit::qi;
void parse_tuple(const std::string和tuple){
使用qi::char\ux;
自动开始=tuple.begin();
自动结束=tuple.end();
bool r=qi::解析(开始,结束,
字符(“01”)>':'>
字符(“01”)>':'>
char_uu(“01”)>-(“:”>char_uuu(“01”))
);
如果(!r | | begin!=end)
抛出std::runtime_错误(“错误格式”);
}
int main(){
parse_tuple(“0:0:0”);//这一个失败
解析元组(“0:0:0:0”);
尝试{parse_tuple(“0:0”);}catch(…){

std::我对spirit一无所知,但如果它是一个非回溯自上而下的解析器,则需要将最后一部分设置为可选:
char_uu0;('0','1')>':'>…>-(':'>>char_0;('0','1'))
@melpomene我明白了…但是,如果表达式具有位置含义呢?例如,假设我有四个开关可以设置为0(off)或者1(开)。我想让用户指定开关的状态为SW2:SW3:SW4或SW1:SW2:SW3:SW4。因此,为第一个开关指定值是可选的。在这种情况下,我不能将最后一个表达式设置为可选。那么,备用语句(a | b)是唯一的选择吗?@Melpome spirit似乎是一个回溯LL(∞) 语法分析器。我试图刷新大学里关于语法分析器的课程,并了解使用这种语法分析器对我所做的工作的影响……我对spirit一无所知,但如果它是一个非回溯自上而下的语法分析器,则需要将最后一部分设置为可选:
char_uuu0('0','1')>':'>…>-(':'>>char u0('1'))
@melpomene我明白了……但是,如果表达式带有位置含义呢?例如,假设我有四个开关可以设置为0(关闭)或1(打开)。我想让用户将开关的状态指定为SW2:SW3:SW4或SW1:SW2:SW3:SW4。因此,为第一个开关指定值是可选的。在这种情况下,我不能将最后一个表达式设置为可选。那么,备用语句(a | b)是唯一的选择吗?@melpomene spirit似乎是一个回溯LL(∞) 解析器。我正在尝试刷新大学里关于解析的课程,并了解使用这种解析器对我所要做的事情的影响。
qi::repeat
operator%
的问题是它会改变暴露的属性。如果不想存储在容器中,这可能会导致不方便的属性传播r type
qi::repeat
operator%
的问题在于它改变了暴露的属性。如果您不想存储在容器类型中,这可能会导致不方便的属性传播