C++ Spirit X3,ascii::cntrl为什么与std::ISCONTRL存在差异?

C++ Spirit X3,ascii::cntrl为什么与std::ISCONTRL存在差异?,c++,boost-spirit,boost-spirit-x3,C++,Boost Spirit,Boost Spirit X3,我将重点检查使用Spirit X3的解析器设计中的错误条件。其中之一是字符类别检查,如isalpha或ispunct。根据X3文档,它们应该匹配C++提供的“代码> STD::ISAlpals和 STD::ISToCT

我将重点检查使用Spirit X3的解析器设计中的错误条件。其中之一是字符类别检查,如
isalpha
ispunct
。根据X3文档,它们应该匹配C++提供的“代码> STD::ISAlpals和<代码> STD::ISToCT<<代码>。然而,通过下面显示的代码演示,我确实得到了不同的结果

#包括
#包括
#包括
#包括
#包括
#包括
#包括
命名空间客户端::解析器
{
名称空间x3=boost::spirit::x3;
名称空间ascii=boost::spirit::x3::ascii;
使用ascii::char;
使用ascii::space;
使用x3::skip;
x3::rule const main\u rule=“main\u rule”;
常量自动主规则定义=ascii::cntrl;
提升精神定义(主规则)
常量自动输入点=跳过(空格)[主规则];
}
int main()
{
printf(“Spirit X3版本:%4.4x\n”,Spirit_X3_版本);
字符输出;
布尔r=假;
boolr2=false;//根据默认的“C”语言环境进行回答
字符输入[2];
输入[1]=0;
printf(“ascii::cntrl\n”);
uint8_t i=0;
下一个字符:
输入[0]=(字符)i;
r=parse((char*)输入,输入+1,client::parser::entry\u point,output);
r2=(bool)std::iscntrl((无符号字符)i);
printf(“%2.2x:%d%d”,i、r、r2);
如果(i==0x7f){goto exit_loop;}
++一,;
if(i%8){putchar(''');}else{putchar('\n');}
转到下一个字符;
退出循环:
返回0;
}
输出为:

spiritx3版本:3004
ascii::cntrl
00:11 01:11 02:11 03:11 04:11 05:11 06:11 07:11
08:11 09:01 0a:01 0b:01 0c:01 0d:01 0e:11 0f:11
10:11 11:11 12:11 13:11 14:11 15:11 16:11 17:11
18:11 19:11 1a:11 1b:11 1c:11 1d:11 1e:11 1f:11
20:00 21:00 22:00 23:00 24:00 25:00 26:00 27:00
28:00 29:00 2a:00 2b:00 2c:00 2d:00 2e:00 2f:00
30:00 31:00 32:00 33:00 34:00 35:00 36:00 37:00
38:00 39:00 3a:00 3b:00 3c:00 3d:00 3e:00 3f:00
40:00 41:00 42:00 43:00 44:00 45:00 46:00 47:00
48:00 49:004A:004B:004C:004D:004E:004F:00
50:00 51:00 52:00 53:00 54:00 55:00 56:00 57:00
58:00 59:00 5a:00 5b:00 5c:00 5d:00 5e:00 5f:00
60:00 61:00 62:00 63:00 64:00 65:00 66:00 67:00
68:00 69:00 6a:00 6b:00 6c:00 6d:00 6e:00 6f:00
70:00 71:00 72:00 73:00 74:00 75:00 76:00 77:00
78:0079:007A:007B:007C:007D:007E:007F:11
<> p>所以冒号后的第一位是根据X3的答案,第二位是根据C++的答案。不匹配发生在同样属于
isspace
类别的字符上。最近,我更深入地研究了库标题,但我仍然没有找到解释这种行为的部分

为什么会出现这种差异?我错过了什么吗


哦,是的,我喜欢我的goto语句。我的复古C风格。我希望你也是!即使是对于X3解析器。

您也意外地使用了skipper,它在您实际解析之前会吃掉任何空格

我简化了解析器,现在它成功了:

关于风格,请注意:没有理由这样做

  • 使用C样式的类型转换(它们很危险)
  • 使用goto编写循环(被认为是有害的)
  • 使用神秘的变量名(r,r2?)

#include <boost/spirit/home/x3/version.hpp>
#include <boost/spirit/home/x3.hpp>
#include <cctype>
#include <cstddef>
#include <cstdint>
#include <iostream>
#include <iomanip>

namespace client::parser {
    using namespace boost::spirit::x3;
    //const auto entry_point = skip(space)[ ascii::cntrl ];
    const auto entry_point = ascii::cntrl;
}

int main() {
    std::cout << std::boolalpha << std::hex << std::setfill('0');
    std::cout << "Spirit X3 version: " << SPIRIT_X3_VERSION << "\n";

    for (uint8_t i = 0; i <= 0x7f; ++i) {
        auto from_x3  = parse(&i, &i + 1, client::parser::entry_point);
        auto from_std = !!std::iscntrl(i);

        if (from_x3 != from_std) {
            std::cout << "0x" << std::setw(2) << static_cast<unsigned>(i) << "\tx3:" << from_x3 << "\tstd:" << from_std << '\n';
        }
    }

    std::cout << "Done\n";
}
改为在中注释“错误行”:

Spirit X3 version: 3000
0x09    x3:false    std:true
0x0a    x3:false    std:true
0x0b    x3:false    std:true
0x0c    x3:false    std:true
0x0d    x3:false    std:true
Done

哈。最近注意到你对时尚的评论:)哦,好吧。就说我们有不同的意见吧。我确实喜欢类似或的东西,但它有点超出了回答的范围,所以我在我的帖子中做了编辑。我删除了一个句子:“这是X3中的另一个bug”,而我错了因为使用了Skip工具。@ SEHE关于C++标签,好的,你添加它,但是因为这是精神X3特定的,为什么它与C++有共同兴趣的人有关?它只是进一步定义了一个受众(标签可以是语言不可知的)。此外,如果您想准确地使用
std::iscntrl
,它会自动使语法突出显示与语言相关-您可以使用
x3::standard::cntrl
解析器。我不知道产生分歧的原因,也许打开一个bug报告是个好主意。对于要解析的第二个参数,&i+1始终是一个有效地址吗?是的。您不能取消对它的引用,但该地址对于比较是有效的。看见
Spirit X3 version: 3000
0x09    x3:false    std:true
0x0a    x3:false    std:true
0x0b    x3:false    std:true
0x0c    x3:false    std:true
0x0d    x3:false    std:true
Done