数値

chlitstrlit などと同じように、数値パーサもまたプリミティブパーサである。 重要なビルディングブロックである数値パーサにはそれ独自の節を設けて、より焦点が当たるようにしている。 このフレームワークは符号付き/符号無し整数や実数を構文解析するためのいくつかの定義済みオブジェクトを含んでいる。 これらのパーサは完全にパラメータ化されている。 数値の構文解析における重要な側面のほとんどは、適切なものになるよう細かく調整できる。 これには、基数、許容される数字の最小および最大値、指数、分数などが含まれる。 実数パーサの振る舞いはポリシーによって制御される。 最も一般的な実数フォーマットをカバーするいくつかのポリシーがあらかじめ定義されているが、必要であればユーザが独自のものを提供できる。

uint_parser

このクラスは数値パーサパッケージの一員としては最も単純なものである。 uint_parser は任意の長さとサイズの符号無し整数を構文解析する。 uint_parser パーサは普通の C / C++ 整数プリミティブはおろか、 bigint(無限精度整数)のようなユーザ定義スカラの構文解析にも使うことができる。 Spirit のほとんどのクラスと同様、 uint_parser はテンプレートクラスである。 テンプレート引数はその振る舞いを微調整する。 uint_parser は柔軟であるため、他の数値パーサはこれをバックボーンに利用して実装されている。

    template <
        typename T = unsigned,
        int Radix = 10,
        unsigned MinDigits = 1,
        int MaxDigits = -1>
    struct uint_parser { /*...*/ };
uint_parser のテンプレート引数
T 数値パーサの潜在的な型。 デフォルトはunsigned int
Radix 基数。 2 (二進数)、 8 (八進数)、 10 (十進数)および 16 (十六進数)のいずれか。 デフォルトは 10 、つまり十進数である。
MinDigits 許容される数値の最小値
MaxDigits 許容される数値の最大値。 これが -1 であれば、上限は無制限になる

定義済みの uint_parser
bin_p uint_parser<unsigned, 2, 1, -1> const
oct_p uint_parser<unsigned, 8, 1, -1> const
uint_p uint_parser<unsigned, 10, 1, -1> const
hex_p uint_parser<unsigned, 16, 1, -1> const

次の例は、三桁ごとに区切られた数値を構文解析するために uint_parser をどのように使うかを示している。 この例は、例えば 1,234,567,890 のような数値列を正しく構文解析できる。

    uint_parser<unsigned, 10, 1, 3> uint3_p;        //  1 〜 3 桁
    uint_parser<unsigned, 10, 3, 3> uint3_3_p;      //  きっちり三桁
    ts_num_p = (uint3_p >> *(',' >> uint3_3_p));    //  三桁ごとで区切られた数値のパーサ

bin_poct_puint_p それに hex_p は式の中で使うために用意されパーサジェネレータ・オブジェクトである。 次の例は、カンマで区切られた数値のリストを構文解析するルールである(これは以前に紹介した):

    list_of_numbers = real_p >> *(',' >> real_p);

数値パーサによって構文解析された実際の数字を取り出す方法は、後述の 特殊化されたアクションの節で紹介する。

int_parser

int_parser は任意の長さとサイズを持った符号付整数を構文解析できる。 これはほとんど uint_parser と同じものである。 唯一の違いは、数値に先行する '+''-' といった符号を構文解析するという作業が加わっている点である。 クラスのインタフェースは uint_parser と同じである。

定義済みの int_parser
int_p int_parser<int, 10, 1, -1> const

real_parser

real_parser は、基盤となっている(underlying)パラメータ型 T によって制限された任意の長さとサイズを持つ実数を構文解析できる。 real_parser は二つのテンプレート引数を持ったテンプレートクラスである。 以下は real_parser のテンプレートインタフェースである:

    template<
        typename T = double,
        typename RealPoliciesT = ureal_parser_policies<T> >
    struct real_parser;

最初のテンプレート引数は基盤となっている型 T である。デフォルトは double である。

特殊な数値型の構文解析

パーサの基盤データ型である T はユーザが指定できる点に注意して欲しい。これはつまり、数値パーサが fixed_point (固定小数点実数)や bigint (無限精度整数)などのユーザ定義数値型の構文解析にも使えることを意味している。

二つ目のテンプレートパラメータはすべてのポリシーをグループ化したものであり、デフォルトは ureal_parser_policies<T> である。 既に述べたように、ポリシーは実数値を構文解析する際の振る舞いを制御する。 デフォルトで提供されているポリシーは、 C / C++ 形式の実数値を構文解析するよう設計されている。 これは nnn.fff.Eeee という形をしている。ここで nnn は自然数部、 fff は小数部、 E'e' または 'E' である。 eee は指数で、前に '-''+' が付くこともある。 デフォルトでは小数点のない素の整数も受け付けられる点を除けば、これは以下の文法に対応する。

    floatingliteral
        =   fractionalconstant >> !exponentpart
        |  +digit_p >> exponentpart
        ;

    fractionalconstant
        =  *digit_p >> '.' >> +digit_p
        |  +digit_p >> '.'
        ;

    exponentpart
        =   ('e' | 'E') >> !('+' | '-') >> +digit_p
        ;

デフォルトのポリシーはもっとも良くあるケースを解決する。 実数を表現する方法は様々なので、構文解析も様々な方法がある。 ほとんどの場合、 real_parser のデフォルトの設定は満足できるもので、 箱から出したままで使える(can be used straight out of the box)。 実際、すぐに使えるように四つの real_parser があらかじめ用意されている:

定義済みの real_parser
ureal_p real_parser<double, ureal_parser_policies<double> > const
real_p real_parser<double, real_parser_policies<double> > const
strict_ureal_p real_parser<double, strict_ureal_parser_policies<double> > const
strict_real_p real_parser<double, strict_real_parser_policies<double> > const

real_p についてはすでに紹介した。 ureal_p はその符号無しバージョンである。

整数値は実数値のサブセットと考えられる。そのため、 real_p および ureal_p は 整数値(ドットのないもの)を実数値として認識する。 strict_real_pstrict_ureal_p は等価なパーサであるが、与えられた数値のマッチにドットを必要とする。

上級者向け: real_parser ポリシー

パーサポリシーは実数値の構文解析を六つのステップに分解する:

1 parse_sign 前置された符号を構文解析する
2 parse_n 小数点の左にある整数を構文解析する
3 parse_dot 小数点を構文解析する
4 parse_frac_n 小数点の後の小数を構文解析する
5 parse_exp 後置された指数記号を構文解析する(例、'e')
6 parse_exp_n 実際の指数部を構文解析する

そしてこれらの補助的な構文解析タスクの相互作用がさらに次の三つのポリシーで制御される:

1 allow_leading_dot 数字の前のドットを許可する( ".1" は "0.1" と等価になる)
2 allow_trailing_dot 数字の後のドットを許可する( "1." は "1.0" と等価になる)
3 expect_dot ドットを要求する( "1" が "1.0" と等価であるとは認めない)

これ以降を読む場合、 スキャナ詳細:パーサおよび詳細:スキャナ を読んでおく必要がある。 ]

sign_parser と sign_p

先に進む前に、 '-''+' 符号の構文解析を容易にするために小さなユーティリティパーサを導入しよう。 次のように書くのは簡単だが:

    sign_p = (ch_p('+') | '-');

これでは、セマンティックアクションの力を借りなければ実際の符号(正か負)を取り出すことはできない。 sign_p パーサは bool 属性を持っており、これはマッチオブジェクトによって、構文解析後に呼び出し側に返される。これは構文解析された符号が負の場合に true にセットされる。この属性は負の符号が構文解析されたかどうかを検出するのに使うことができる。例えば:

    bool is_negative;
    r = sign_p[assign(is_negative)];

あるいは単に…

    // マッチ結果の値から直接結果を取り出す
    bool is_negative = sign_p.parse(scan).value(); 

sign_p パーサは、取り付けられたセマンティックアクションのシグネチャが次のいずれかと互換であることを期待する:

関数のシグネチャ:

    void func(bool is_negative);

ファンクタのシグネチャ:

    struct ftor
    {
        void operator()(bool is_negative) const;
    };
(より詳しくは特殊化アクションを参照)

ureal_parser_policies

    template <typename T>
    struct ureal_parser_policies
    {
        typedef uint_parser<T, 10, 1, -1>   uint_parser_t;
        typedef int_parser<T, 10, 1, -1>    int_parser_t;

        static const bool allow_trailing_left_dot  = true;
        static const bool allow_trailing_right_dot = true;
        static const bool expect_dot               = false;
template <typename ScannerT> static typename match_result<ScannerT, nil_t>::type parse_sign(ScannerT& scan) { return scan.no_match(); } template <typename ScannerT> static typename parser_result<uint_parser_t, ScannerT>::type parse_n(ScannerT& scan) { return uint_parser_t().parse(scan); } template <typename ScannerT> static typename parser_result<chlit<>, ScannerT>::type parse_dot(ScannerT& scan) { return ch_p('.').parse(scan); } template <typename ScannerT> static typename parser_result<uint_parser_t, ScannerT>::type parse_frac_n(ScannerT& scan) { return uint_parser_t().parse(scan); } template <typename ScannerT> static typename parser_result<chlit<>, ScannerT>::type parse_exp(ScannerT& scan) { return as_lower_d['e'].parse(scan); } template <typename ScannerT> static typename parser_result<int_parser_t, ScannerT>::type parse_exp_n(ScannerT& scan) { return int_parser_t().parse(scan); } };

デフォルトの ureal_parser_policies は作業のために低レベル整数値パーサを用いる。

real_parser_policies

    template <typename T>
    struct real_parser_policies : public ureal_parser_policies<T>
    {
        template <typename ScannerT>
        static typename parser_result<sign_parser, ScannerT>::type
        parse_sign(ScannerT& scan)
        { return sign_p.parse(scan); }
    };

real_parser_policies が、サブクラス化された元である ureal_parser_policies の parse_sign をどのように置き換えているかに注目して欲しい。 デフォルトの real_parser_policies は parse_sign ステップで、 scan.no_match() の替わりに単に sign_p を用いる。

strict_ureal_parser_policies と strict_real_parser_policies

    template <typename T>
    struct strict_ureal_parser_policies : public ureal_parser_policies<T>
    {
        static const bool expect_dot = true;
    };

    template <typename T>
    struct strict_real_parser_policies : public real_parser_policies<T>
    {
        static const bool expect_dot = true;
    };

これもまた、スーパークラスとは違うようにしたいポリシーを置き換えただけである。

他の"特殊化された"実数パーサポリシーはデフォルト値を再利用できる。これらのポリシーの一つ以上がクライアントによって置き換えられる。 例えば次の実数パーサは、小数点以下がたかだか二桁で指数部を持たない三桁区切りの数値を構文解析する:

    template <typename T>
    struct ts_real_parser_policies : public ureal_parser_policies<T>
    {
        //  これらのポリシーは小数点以下がたかだか二桁の三桁区切りの数値を構文解析できる。
        //  例. 123,456,789.01

        typedef uint_parser<int, 10, 1, 2>  uint2_t;
        typedef uint_parser<T, 10, 1, -1>   uint_parser_t;
        typedef int_parser<int, 10, 1, -1>  int_parser_t;

        //////////////////////////////////  小数点以下最大 2 桁
        template <typename ScannerT>
        static typename parser_result<uint2_t, ScannerT>::type
        parse_frac_n(ScannerT& scan)
        { return uint2_t().parse(scan); }

        //////////////////////////////////
        template <typename ScannerT>
        static typename parser_result<chlit<>, ScannerT>::type
        parse_exp(ScannerT& scan)
        { return scan.no_match(); }

        //////////////////////////////////
        template <typename ScannerT>
        static typename parser_result<int_parser_t, ScannerT>::type
        parse_exp_n(ScannerT& scan)
        { return scan.no_match(); }

        //////////////////////////////////  三桁区切りの数値
        template <typename ScannerT>
        static typename parser_result<uint_parser_t, ScannerT>::type
        parse_n(ScannerT& scan)
        {
            typedef typename parser_result<uint_parser_t, ScannerT>::type RT;
            uint_parser<unsigned, 10, 1, 3> uint3_p;
            uint_parser<unsigned, 10, 3, 3> uint3_3_p;

            if (RT hit = uint3_p.parse(scan))
            {
                T n;
                while (match<> next = (',' >> uint3_3_p[assign(n)]).parse(scan))
                {
                    hit.value() *= 1000;
                    hit.value() += n;
                    scan.concat_match(hit, next);
                }
                return hit;
            }
            return scan.no_match();
        }
    };

    // ts_real_p, 三桁区切りの数値パーサ
    real_parser<double, ts_real_parser_policies<double> > const
        ts_real_p = real_parser<double, ts_real_parser_policies<double> >();


このドキュメントの対象: Boost Version 1.30.0
最新版ドキュメント(英語)