spirit qi 规则中添加qi::lexeme编译失败

Compilation fails when adding qi::lexeme to a rule in spirit qi

我一直在使用 Boost 库中的 Spirit Qi 用 C++ 编写语法。作为这门语言的新手,很难习惯库的语法和怪癖,但现在我有点理解它是如何工作的。

我在使用 qi::lexeme 时遇到错误。我的实际语法相当大,所以我在存在相同问题的地方制作了一个小代码片段。以下代码编译无误:

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_object.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/fusion/include/boost_tuple.hpp>

#include <set>
#include <iostream>
#include <string>
#include <complex>

namespace client
{
    namespace qi = boost::spirit::qi;
    namespace ascii = boost::spirit::ascii;

    typedef boost::tuple<char, char> range;
}

namespace client
{
    template <typename Iterator>
    struct employee_parser : qi::grammar<Iterator, range(), ascii::space_type>
    {
        employee_parser() : employee_parser::base_type(start)
        {
            using qi::lit;
            using qi::lexeme;
            using ascii::char_;

            range_rule = 
                char_("a-z") >> lit("-") >> char_("a-z")
                | char_("A-Z") >> lit("-") >> char_("A-Z")
                | char_("0-9") >> lit("-") >> char_("0-9")
                ;

            start = range_rule;
        }

        qi::rule<Iterator, range(), ascii::space_type> range_rule;
        qi::rule<Iterator, range(), ascii::space_type> start;
    };
}

int main()
{
    typedef std::string::const_iterator iterator_type;
    typedef client::employee_parser<iterator_type> employee_parser;
    employee_parser g;
    return 0;
}

现在,如果我替换行 start = range_rule; 并改用 start = lexeme[range_rule];,编译将失败。

正如我从 the docs 中读到的那样,lexeme[a] 应该保留主题解析器的属性,所以我不明白为什么它会失败。输出错误很大而且很神秘所以我没有任何线索:

In file included from /home/martin/vscode_cpp_projects/boost_1_68_0/boost/spirit/home/qi/nonterminal.hpp:14:0,
                 from /home/martin/vscode_cpp_projects/boost_1_68_0/boost/spirit/home/qi.hpp:21,
                 from /home/martin/vscode_cpp_projects/boost_1_68_0/boost/spirit/include/qi.hpp:16,
                 from cpp/tests/test2.cpp:2:
/home/martin/vscode_cpp_projects/boost_1_68_0/boost/spirit/home/qi/nonterminal/rule.hpp: In instantiation of ‘bool boost::spirit::qi::rule<Iterator, T1, T2, T3, T4>::parse(Iterator&, const Iterator&, Context&, const Skipper&, Attribute&) const [with Context = boost::spirit::context<boost::fusion::cons<boost::tuples::tuple<char, char>&, boost::fusion::nil_>, boost::fusion::vector<> >; Skipper = boost::spirit::qi::detail::unused_skipper<boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> > >; Attribute = boost::tuples::tuple<char, char>; Iterator = __gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >; T1 = boost::tuples::tuple<char, char>(); T2 = boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >, 0>; T3 = boost::spirit::unused_type; T4 = boost::spirit::unused_type]’:
/home/martin/vscode_cpp_projects/boost_1_68_0/boost/spirit/home/qi/reference.hpp:43:72:   required from ‘bool boost::spirit::qi::reference<Subject>::parse(Iterator&, const Iterator&, Context&, const Skipper&, Attribute&) const [with Iterator = __gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >; Context = boost::spirit::context<boost::fusion::cons<boost::tuples::tuple<char, char>&, boost::fusion::nil_>, boost::fusion::vector<> >; Skipper = boost::spirit::qi::detail::unused_skipper<boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> > >; Attribute = boost::tuples::tuple<char, char>; Subject = const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >, boost::tuples::tuple<char, char>(), boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >, 0>, boost::spirit::unused_type, boost::spirit::unused_type>]’
/home/martin/vscode_cpp_projects/boost_1_68_0/boost/spirit/home/qi/directive/lexeme.hpp:66:64:   required from ‘typename boost::disable_if<boost::spirit::qi::detail::is_unused_skipper<Skipper>, bool>::type boost::spirit::qi::lexeme_directive<Subject>::parse(Iterator&, const Iterator&, Context&, const Skipper&, Attribute&) const [with Iterator = __gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >; Context = boost::spirit::context<boost::fusion::cons<boost::tuples::tuple<char, char>&, boost::fusion::nil_>, boost::fusion::vector<> >; Skipper = boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >; Attribute = boost::tuples::tuple<char, char>; Subject = boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >, boost::tuples::tuple<char, char>(), boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >, 0>, boost::spirit::unused_type, boost::spirit::unused_type> >; typename boost::disable_if<boost::spirit::qi::detail::is_unused_skipper<Skipper>, bool>::type = bool]’
/home/martin/vscode_cpp_projects/boost_1_68_0/boost/spirit/home/qi/nonterminal/detail/parser_binder.hpp:43:54:   required from ‘bool boost::spirit::qi::detail::parser_binder<Parser, Auto>::call(Iterator&, const Iterator&, Context&, const Skipper&, mpl_::false_) const [with Iterator = __gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >; Skipper = boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >; Context = boost::spirit::context<boost::fusion::cons<boost::tuples::tuple<char, char>&, boost::fusion::nil_>, boost::fusion::vector<> >; Parser = boost::spirit::qi::lexeme_directive<boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >, boost::tuples::tuple<char, char>(), boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >, 0>, boost::spirit::unused_type, boost::spirit::unused_type> > >; Auto = mpl_::bool_<false>; mpl_::false_ = mpl_::bool_<false>]’
/home/martin/vscode_cpp_projects/boost_1_68_0/boost/spirit/home/qi/nonterminal/detail/parser_binder.hpp:53:24:   required from ‘bool boost::spirit::qi::detail::parser_binder<Parser, Auto>::operator()(Iterator&, const Iterator&, Context&, const Skipper&) const [with Iterator = __gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >; Skipper = boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >; Context = boost::spirit::context<boost::fusion::cons<boost::tuples::tuple<char, char>&, boost::fusion::nil_>, boost::fusion::vector<> >; Parser
= boost::spirit::qi::lexeme_directive<boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >, boost::tuples::tuple<char, char>(), boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >, 0>, boost::spirit::unused_type, boost::spirit::unused_type> > >; Auto = mpl_::bool_<false>]’
/home/martin/vscode_cpp_projects/boost_1_68_0/boost/function/function_template.hpp:138:22:   required from ‘static R boost::detail::function::function_obj_invoker4<FunctionObj, R, T0, T1, T2, T3>::invoke(boost::detail::function::function_buffer&, T0, T1, T2, T3) [with FunctionObj = boost::spirit::qi::detail::parser_binder<boost::spirit::qi::lexeme_directive<boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >, boost::tuples::tuple<char, char>(), boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >, 0>, boost::spirit::unused_type, boost::spirit::unused_type> > >, mpl_::bool_<false> >; R = bool; T0 = __gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >&; T1 = const __gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >&; T2 = boost::spirit::context<boost::fusion::cons<boost::tuples::tuple<char, char>&, boost::fusion::nil_>, boost::fusion::vector<> >&; T3 = const boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >&]’
/home/martin/vscode_cpp_projects/boost_1_68_0/boost/function/function_template.hpp:936:38:   [ skipping 2 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
/home/martin/vscode_cpp_projects/boost_1_68_0/boost/function/function_template.hpp:1074:16:   required from ‘boost::function<R(T0, T1, T2, T3)>::function(Functor, typename boost::enable_if_c<(! boost::is_integral<Functor>::value), int>::type) [with Functor = boost::spirit::qi::detail::parser_binder<boost::spirit::qi::lexeme_directive<boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >, boost::tuples::tuple<char, char>(), boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >, 0>, boost::spirit::unused_type, boost::spirit::unused_type> > >, mpl_::bool_<false> >; R = bool; T0 = __gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >&; T1 = const __gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >&; T2 = boost::spirit::context<boost::fusion::cons<boost::tuples::tuple<char, char>&, boost::fusion::nil_>, boost::fusion::vector<> >&; T3 = const boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >&; typename boost::enable_if_c<(! boost::is_integral<Functor>::value), int>::type = int]’
/home/martin/vscode_cpp_projects/boost_1_68_0/boost/function/function_template.hpp:1127:5:   required from ‘typename boost::enable_if_c<(! boost::is_integral<Functor>::value), boost::function<R(T0, T1, T2, T3)>&>::type boost::function<R(T0, T1, T2, T3)>::operator=(Functor) [with Functor = boost::spirit::qi::detail::parser_binder<boost::spirit::qi::lexeme_directive<boost::spirit::qi::reference<const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >, boost::tuples::tuple<char, char>(), boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >, 0>, boost::spirit::unused_type, boost::spirit::unused_type> > >,
mpl_::bool_<false> >; R = bool; T0 = __gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >&; T1 = const __gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >&; T2 = boost::spirit::context<boost::fusion::cons<boost::tuples::tuple<char, char>&, boost::fusion::nil_>, boost::fusion::vector<> >&; T3 = const boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >&; typename boost::enable_if_c<(! boost::is_integral<Functor>::value), boost::function<R(T0, T1, T2, T3)>&>::type = boost::function<bool(__gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >&, const __gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >&, boost::spirit::context<boost::fusion::cons<boost::tuples::tuple<char, char>&, boost::fusion::nil_>, boost::fusion::vector<> >&, const boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >&)>&]’
/home/martin/vscode_cpp_projects/boost_1_68_0/boost/spirit/home/qi/nonterminal/rule.hpp:183:19:   required from ‘static void boost::spirit::qi::rule<Iterator,
T1, T2, T3, T4>::define(boost::spirit::qi::rule<Iterator, T1, T2, T3, T4>&, const Expr&, mpl_::true_) [with Auto = mpl_::bool_<false>; Expr = boost::proto::exprns_::expr<boost::proto::tagns_::tag::subscript, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::lexeme>, 0>&, boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >, boost::tuples::tuple<char, char>(), boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >, 0>, boost::spirit::unused_type, boost::spirit::unused_type>&>, 2>; Iterator = __gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >; T1 = boost::tuples::tuple<char, char>(); T2 = boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >, 0>; T3 = boost::spirit::unused_type; T4 = boost::spirit::unused_type; mpl_::true_ = mpl_::bool_<true>]’
/home/martin/vscode_cpp_projects/boost_1_68_0/boost/spirit/home/qi/nonterminal/rule.hpp:221:32:   required from ‘boost::spirit::qi::rule<Iterator, T1, T2, T3,
T4>& boost::spirit::qi::rule<Iterator, T1, T2, T3, T4>::operator=(const Expr&) [with Expr = boost::proto::exprns_::expr<boost::proto::tagns_::tag::subscript, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::lexeme>, 0>&, boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >, boost::tuples::tuple<char, char>(), boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >, 0>, boost::spirit::unused_type, boost::spirit::unused_type>&>, 2>; Iterator = __gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >; T1 = boost::tuples::tuple<char, char>(); T2 = boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >, 0>; T3 = boost::spirit::unused_type; T4 = boost::spirit::unused_type]’
cpp/tests/test2.cpp:40:19:   required from ‘client::employee_parser<Iterator>::employee_parser() [with Iterator = __gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >]’
cpp/tests/test2.cpp:56:21:   required from here
/home/martin/vscode_cpp_projects/boost_1_68_0/boost/spirit/home/qi/nonterminal/rule.hpp:304:17: error: no match for call to ‘(const function_type {aka const boost::function<bool(__gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >&, const __gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >&, boost::spirit::context<boost::fusion::cons<boost::tuples::tuple<char, char>&, boost::fusion::nil_>, boost::fusion::vector<> >&, const boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >&)>}) (__gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >&, const __gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >&, boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >, boost::tuples::tuple<char, char>(), boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >, 0>, boost::spirit::unused_type, boost::spirit::unused_type>::context_type&, const boost::spirit::qi::detail::unused_skipper<boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> > >&)’
                 if (f(first, last, context, skipper))
                 ^~
In file included from /home/martin/vscode_cpp_projects/boost_1_68_0/boost/function/detail/maybe_include.hpp:43:0,
                 from /home/martin/vscode_cpp_projects/boost_1_68_0/boost/function/detail/function_iterate.hpp:14,
                 from /home/martin/vscode_cpp_projects/boost_1_68_0/boost/preprocessor/iteration/detail/iter/forward1.hpp:67,
                 from /home/martin/vscode_cpp_projects/boost_1_68_0/boost/function.hpp:70,
                 from /home/martin/vscode_cpp_projects/boost_1_68_0/boost/spirit/home/qi/nonterminal/rule.hpp:16,
                 from /home/martin/vscode_cpp_projects/boost_1_68_0/boost/spirit/home/qi/nonterminal.hpp:14,
                 from /home/martin/vscode_cpp_projects/boost_1_68_0/boost/spirit/home/qi.hpp:21,
                 from /home/martin/vscode_cpp_projects/boost_1_68_0/boost/spirit/include/qi.hpp:16,
                 from cpp/tests/test2.cpp:2:
/home/martin/vscode_cpp_projects/boost_1_68_0/boost/function/function_template.hpp:763:17: note: candidate: boost::function4<R, T1, T2, T3, T4>::result_type boost::function4<R, T1, T2, T3, T4>::operator()(T0, T1, T2, T3) const [with R = bool; T0 = __gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >&; T1 = const __gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >&; T2 = boost::spirit::context<boost::fusion::cons<boost::tuples::tuple<char, char>&, boost::fusion::nil_>, boost::fusion::vector<> >&; T3 = const boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >&; boost::function4<R, T1, T2, T3, T4>::result_type = bool]
     result_type operator()(BOOST_FUNCTION_PARMS) const
                 ^~~~~~~~
/home/martin/vscode_cpp_projects/boost_1_68_0/boost/function/function_template.hpp:763:17: note:   no known conversion for argument 4 from ‘const boost::spirit::qi::detail::unused_skipper<boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> > >’ to ‘const boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >&’

As I read from the docs, lexeme[a] should preserve the subject parser's attributes, so I can't understand why it fails.

是的,它保留了属性。它 NOT 保留船长(出于显而易见的原因),并且您的 range_rule 声明了一个。编译器消息包含以下信息:

BOOST_STATIC_ASSERT_MSG((is_same<skipper_type, unused_type>::value ||
            !is_same<Skipper, unused_type>::value),
            "The rule was instantiated with a skipper type but you have not pass any. "
            "Did you use `parse` instead of `phrase_parse`?");

因此,将船长从 range_rule 中删除。具有讽刺意味的是,只是删除它会隐含地使它表现得像一个词素,所以你无论如何都不需要 lexeme[] 围绕它。

另见 Boost spirit skipper issues

简而言之:

  • 无法调用需要船长而没有船长的规则
  • 可以从具有 skipper 上下文的解析器调用隐式词位规则

我通常将我的规则分组以尽可能多地表示,并在它们前面加上评论,例如:

  private:
    qi::rule<Iterator, range(), ascii::space_type> start;

    // lexmes
    qi::rule<Iterator, range()> range_rule;

但我通常也会封装 skipper,除非调用者更改 skipper 真的有意义(?!)。

另请参阅类似任务:

  • method for expand a-z to abc...xyz form

建议的修复

Live On Coliru

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_object.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/fusion/include/boost_tuple.hpp>

#include <set>
#include <iostream>
#include <string>
#include <complex>

namespace client
{
    namespace qi = boost::spirit::qi;
    typedef boost::tuple<char, char> range;
}

namespace client
{
    template <typename Iterator>
    struct employee_parser : qi::grammar<Iterator, range()>
    {
        employee_parser() : employee_parser::base_type(start)
        {
            using qi::lit;
            using qi::lexeme;
            using qi::ascii::char_;

            range_rule = 
                char_("a-z") >> lit("-") >> char_("a-z")
              | char_("A-Z") >> lit("-") >> char_("A-Z")
              | char_("0-9") >> lit("-") >> char_("0-9")
              ;

            start = qi::skip(qi::ascii::space) [ range_rule ];
        }

      private:
        qi::rule<Iterator, range()> start;

        // lexmes
        qi::rule<Iterator, range()> range_rule;
    };
}

int main()
{
    typedef std::string::const_iterator iterator_type;
    typedef client::employee_parser<iterator_type> employee_parser;
    employee_parser g;

    std::string const input("a-k");
    client::range r;
    return parse(begin(input), end(input), g, r)
        ? 0
        : 1;
}