c++ - 是否可以在 Boost.Spirit 中创建自定义解析器?

标签 c++ boost-spirit-qi

我试图在 Boost.Spirit (2.3) 中创建自定义解析器类,但没有成功。代码是:

template <class Iter>
class crule : public boost::spirit::qi::parser<crule<Iter> >
{
  rule<Iter> r_;
public:
  crule(const rule<Iter>& r) : r_(r) {}
  template <class T>
  crule(const T& t) : r_(t) {}
  template<class Ctx, class Skip>
  bool parse(Iter& f, const Iter& l, Ctx& context, Skip& skip, typename rule<Iter>::template attribute<Ctx, Iter>::type& attr) const {
    return r_.parse(f, l, context, skip, attr);
  }
  template <class Ctx>
  boost::spirit::info what(Ctx& context) const {
    return r_.what(context);
  }
  template <class Context, class It>
  struct attribute {
    typedef typename rule<Iter>::template attribute<Context, It>::type type;
  };
};

虽然我已经(至少我认为我已经)完成了所有 requirements ,当我尝试在解析表达式中使用此类时出现错误:

shell_grammar.h:134: error: no match for 'operator!' in '!shell_grammar<Iter>::token(boost::spirit::qi::rule<Iter, boost::fusion::unused_type, boost::fusion::unused_type, boost::fusion::unused_type>) [with Iter = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >](boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, boost::fusion::unused_type, boost::fusion::unused_type, boost::fusion::unused_type>(((const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, boost::fusion::unused_type, boost::fusion::unused_type, boost::fusion::unused_type>&)((const boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, boost::fusion::unused_type, boost::fusion::unused_type, boost::fusion::unused_type>*)(&((shell_grammar<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >*)this)->shell_grammar<__gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::reserved_words)))))'

shell_grammar.h:134: note: candidates are: operator!(bool) <built-in>

我试图查看其他解析集的实现(例如 not_predicate),但无法弄清楚使它起作用的区别是什么。

动机

我这样做的原因与this question有关.我想解析具有特殊词法规则的 POSIX shell 语言。特别是,即使在词素中也必须应用“skipper parser”,但它必须不同于“phrase level”skipper parser。这是 lexeme 指令不能做的,skip 不会预先跳过(AFAIK),这也是我需要的。所以我想创建一个函数

something token(std::string);

这将返回匹配 token 的规则。一种方法是创建我自己的 rule 包装器作为终端(因为 rule 不能单独用于其引用语义),另一种方法是创建一个新的解析器(即将是 proto 中的非终结符),并在其中实现 shell 的 token 解析。

最佳答案

这是很有可能的,但我发现它比手动编写我自己的词法分析器和递归下降解析器需要更多的工作(而且更难调试)。即使是相当小的 Spirit 语法也会让我花费数周时间与编译器较量。

您收到的这条错误消息显示了您遇到的问题类型。任何时候你得到一个错误,它是来自 Spirit 深处的一些模板实例化的错误,添加了许多进一步的模板实例化层来混淆事情。为了有破译错误消息的希望,您几乎必须了解整个设施的代码。

我讨厌批评,因为 Spirit 是一项值得付出的努力。我的硕士论文是关于实现 object-oriented compiler-generator ,所以我是这个概念的粉丝。我真的很想喜欢它,但是 Spirit 太难了,除了认真的 C++ 专家之外,任何人都无法使用。

要比较可以做什么,请查看 Ada OpenToken项目。 Spirit 可能更灵活,但编译错误在 OpenToken 中更为敏感,浏览该页面上的版本历史记录会发现他们已经投入了很大一部分精力来帮助用户调试错误。

关于c++ - 是否可以在 Boost.Spirit 中创建自定义解析器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3502568/

相关文章:

c++ - 如何让 std::thread 对传递给它的函数的参数进行一般构造?

c++ - 在 C++ Win32 应用程序中,我如何确定私有(private)字节、工作集和虚拟大小

c++ - C++中的循环负数生成

c++ - boost::spirit::qi 文法使用不同迭代器类型的文法

c++ - 灵气 : Error when replacing sequence with expectation operator

c++ - 提升精神期望失败

c++ - 将现有 C 项目转换为 WPF

c++ - Qt 在其他范围内访问 TextEdit 的文本

c++ - 在 Boost.Spirit 中解析开头之前的短语结尾

c++ - 解析灵气中双大括号修饰字符串的规则语法