LoginSignup
1
1

More than 3 years have passed since last update.

boost::spirit::x3 Unicode対応メモ

Last updated at Posted at 2020-12-04

探したけど、x3版の対応方法は出てこなかったのでメモ。

はじめに

boost::spiritは、特に指定しなければx3::standardに定義された文字エンコードが使われる。

char.hpp
namespace standard
    {
        typedef any_char<char_encoding::standard> char_type;
        constexpr auto char_ = char_type{};

        constexpr literal_char<char_encoding::standard, unused_type>
        lit(char ch)
        {
            return { ch };
        }

        constexpr literal_char<char_encoding::standard, unused_type>
        lit(wchar_t ch)
        {
            return { ch };
        }

    }

    //ここで、boost::spirit::x3 (標準の名前空間)に展開される。
    using standard::char_type;
    using standard::char_;
    using standard::lit;

これは、次の通りの定義になっている。

standard.hpp
    struct standard
    {
        //エンコードに使われるchar型
        typedef char char_type;
        typedef unsigned char classify_type;

        // ------中略----------

        // 文字判定部分
        static bool
        ischar(int ch)
        {
            // uses all 8 bits
            // we have to watch out for sign extensions
            return (0 == (ch & ~0xff) || ~0 == (ch | 0xff)) != 0;
        }

        //--------中略----------
    };

C++におけるchar型はUnicodeに対応しておらず、
判定部分でも、0xffを超えるコードポイントの文字は範囲外とされてしまう(文字と判定されない)。

これは日本語や、中国語などの一部外国語がパースできないことを指し、特に文字列をデータとしてハードコードするDSLを作成する場合、ローカライズ対応する際に非常に困る。

そこで、boost::spiritにはunicode対応の文字セットが用意されている。

方法

利用方法はシンプルで、BOOST_SPIRIT_X3_UNICODEマクロを定義してやるだけで良い。

//unicode対応マクロ
#define BOOST_SPIRIT_X3_UNICODE

//対応マクロ宣言のあとに、ヘッダを読む
#include <boost/spirit/home/x3.hpp>

namespace parser
{
    using x3::unicode::alpha;
    using x3::unicode::alnum;
    using x3::unicode::char_;

    //識別子のパース
    auto const identifier_def
        = raw[lexeme[(alpha | '_') >> *(alnum | '_')]];
    //文字列のパース
    auto const string_literal_def = '"' >> lexeme[*(~char_('"'))] >> '"';
}

※前バージョンのboost::spirit::qiを使う場合は、BOOST_SPIRIT_UNICODEマクロになる。

unicodeの定義は次の通り

unicode.hpp
    struct unicode
    {
        typedef ::boost::uint32_t char_type;
        typedef ::boost::uint32_t classify_type;

        static bool
        ischar(char_type ch)
        {
            // unicode code points in the range 0x00 to 0x10FFFF
            return ch <= 0x10FFFF;
        }
    };

文字判定の部分の範囲が0x10FFFF(unicodeの最大範囲)まで広がっており、char_typeも32bitに広がっていることがわかる。
(boost::uint32_tとやらが、UTF-32を保証する型なのかは調べてないんですが、どうなんですかね…。詳しい人教えて下さい)

参考

1
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1