4

我有一个基于它的词法分析器,spirit::lexertl它产生用lex::token_def<std::string>. 我想使用一个qi::symbols<>表来匹配该表中的标记,使用符号表中的关联数据作为规则中的属性。像这样的东西[从实际代码中浓缩]:

qi::symbols<char, int> mode_table;
mode_table.add("normal", 0)("lighten", 1)("darken", 2);

rule<Iterator, int()> mode = raw_token(tok.kMode) >> ':' >> ascii::no_case[mode_table];

但是,当我编译它时,我收到以下错误:

/Users/tim/Documents/src/tr_libs/boost/boost_1_49_0/boost/spirit/home/qi/string/detail/tst.hpp:80:错误:从“char”转换为非标量类型'boost::spirit::lex::lexertl::token<boost::spirit::line_pos_iterator<boost::spirit::multi_pass<std::istreambuf_iterator<char, std::char_traits<char>>, boost:: Spirit::iterator_policies::default_policy<boost::spirit::iterator_policies::ref_counted, boost::spirit::iterator_policies::buf_id_check, boost::spirit::iterator_policies::buffering_input_iterator, boost::spirit::iterator_policies:: split_std_deque> > >, boost::mpl::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, boost::spirit::basic_string<std::basic_string<字符、std::char_traits<char>、std::allocator<char> >、symbol_type>、double、mpl_::na、mpl_::na、mpl_::na、mpl_::na、mpl_::na、mpl_ ::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na,mpl_::na, mpl_::na>, mpl_::bool_<true>, long unsigned int>'请求

tst.hpp 中的第 80 行是这样的:

                c = filter(*i);

在我看来,它确实正在尝试将我的词法分析器标记转换为 a char,我理解它是symbols<char, int>表中的字符类型。一时兴起,我确实尝试了symbols<ident, int>——ident我的令牌类型在哪里——但这显然不是记录在案的symbols<>API,而且可以预见的是它不起作用。

(你可能会问为什么我不让词法分析器将这些标识符作为令牌 ID 发出,就像kMode上面的示例一样。在这种特殊情况下我可能会这样做,但我真的很好奇集成符号的一般情况带有词法分析器的语法中的表。)

从根本上说,我认为我的问题是:是否可以以qi::symbols<>这种方式使用来匹配来自 Spirit 词法分析器的标记?

4

1 回答 1

2

不可能symbols像您一样直接使用实例......但是通过使用 Phoenix 语义动作可以完成,但会增加冗长。如果您有一个token_def<std::string>表示您希望在符号表中查找的值,则可以将其集成到如下规则中:

qi::rule<Iterator, locals<int const*>, int()> modename;
using namespace boost::phoenix;
// disambiguate symbols::find method (there are two!)
typedef const symtab_t::value_type * (symtab_t::*findfn_t)(std::string const&) const;
modename = tok.modeName[_a = bind(static_cast<findfn_t>(&symtab_t::find),
                                  cref(mode_table), _1),
                        _pass = _a,
                        if_(_a)[_val = *_a]];

它在符号表中手动查找令牌的字符串值,如果不存在则失败,否则将找到的整数值复制到规则的结果属性。

处理不区分大小写也可以通过语义操作来完成,要么在解析器中(通过在执行查找之前转换为小写),要么通过在词法分析器中创建标记时进行转换。后一种方法可以这样处理:

this->self +=
     modeName[ 
        let(_a = construct<std::string>(_start, _end)) [
            bind(&to_lower<std::string>, ref(_a),
                 // must supply even defaulted arguments
                 construct<std::locale>()),
            _val = _a
            ]
         ];

这将创建基础范围的副本并调用to_lower它,将结果作为令牌值提供。

一个完整的例子可以在这里找到

于 2015-04-11T20:40:25.843 回答