如何使用qi :: symbols解析器来匹配使用no_case的灵魂词法分子的标记?

时间:2012-08-08 19:01:04

标签: boost-spirit boost-spirit-qi boost-spirit-lex

我有一个基于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'转换 to non-scalar type 'boost :: spirit :: lex :: lexertl :: token&lt; boost :: spirit :: line_pos_iterator&lt; boost :: spirit :: multi_pass&lt; std :: istreambuf_iterator&lt; char,std :: char_traits&lt ;炭&GT; &gt;,boost :: spirit :: iterator_policies :: default_policy&lt; boost :: spirit :: iterator_policies :: ref_counted,boost :: spirit :: iterator_policies :: buf_id_check,boost :: spirit :: iterator_policies :: buffering_input_iterator,boost ::精神:: iterator_policies :: split_std_deque&GT; &GT; &gt;,boost :: mpl :: vector&lt; std :: basic_string&lt; char,std :: char_traits&lt; char&gt ;,std :: allocator&lt; char&gt; &gt;,boost :: spirit :: basic_string&lt; std :: basic_string&lt; char,std :: char_traits&lt; char&gt ;,std :: allocator&lt; char&gt; &gt;,symbol_type&gt;,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&gt;,mpl _ :: bool_&lt; true&gt ;,long unsigned int&gt;' request

tst.hpp中的第80行是:

                c = filter(*i);

我确实认为它正在尝试将我的词法分析器转换为char,我理解这是symbols<char, int>表中的字符类型。一时兴起,我确实尝试symbols<ident, int> - 其中ident是我的令牌类型 - 但这显然不是记录的symbols<> API,并且可以预测不起作用。

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

从根本上说,我认为我的问题是:是否可以通过这种方式使用qi::symbols<>来匹配灵魂词法分析器中的令牌?

1 个答案:

答案 0 :(得分: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,并将结果作为标记值提供。

可以找到完整的示例here