【问题标题】:How do I use a qi::symbols parser to match tokens from a spirit lexer using no_case?如何使用 qi::symbols 解析器来匹配来自使用 no_case 的精神词法分析器的标记?
【发布时间】:2012-08-05 23:10:27
【问题描述】:

我有一个基于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<:spirit::line_pos_iterator std::char_traits>>, boost::spirit::iterator_policies::default_policy<: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<:basic_string std::char_traits>, std::allocator >, boost::spirit: :basic_string<:basic_string std::char_traits>, std::allocator >, 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_, long unsi gned int>' 已请求

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

                c = filter(*i);

在我看来,它确实在尝试将我的词法分析器标记转换为char,我知道这是symbols&lt;char, int&gt; 表中的字符类型。一时兴起,我确实尝试了symbols&lt;ident, int&gt; — 其中ident 是我的令牌类型 — 但这显然不是记录在案的symbols&lt;&gt; API,并且可以预见地不起作用。

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

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

【问题讨论】:

  • 有趣的是,如果我删除规则中 mode_table 子句周围的 no_case[] 指令,它确实编译,但随后无法匹配任何内容,无论是否不是 lex 的标记实际上在符号表中。
  • 如果不修改 qi::symbols,我看不出这将如何得到支持。您可以在[spirit-general] 邮件列表中询问

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


【解决方案1】:

不可能像您一样直接使用symbols 实例...但是通过使用Phoenix 语义操作可以做到这一点,但代价是增加了冗长。如果你有一个token_def&lt;std::string&gt; 代表你希望在符号表中查找的值,你可以将它集成到这样的规则中:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-18
    • 1970-01-01
    • 2016-02-02
    相关资源
    最近更新 更多