【问题标题】:Spirit Qi: Completely ignoring output of some rules灵气:完全无视某些规则的输出
【发布时间】:2014-02-18 17:55:14
【问题描述】:

我正在解析一些结构模糊的输入,例如 C-ish 代码。像这样:

Name0
{
 Name1
 {
  //A COMMENT!!

  Param0 *= 2
  Param2 = "lol"
 }
}

其中一部分是 cmets,我想完全忽略它(它不起作用)。我认为有两件事是node,命名范围(category 规则)如Name0 {} 和值(param 规则)如Param0 *= 2...然后是comment。我试过这样设置:

typedef boost::variant<boost::recursive_wrapper<Category>, Param> Node;

qi::rule<Iterator, Node(), ascii::space_type> node;

所以node 规则将CategoryParam 放入variant。以下是其他规则(我省略了一些与此无关的规则):

qi::rule<Iterator> comment; //comment has no return type

qi::rule<Iterator, Category(), ascii::space_type> category;
qi::rule<Iterator, Param(), ascii::space_type> param;

以及他们的实际代码:

comment = "//" >> *(char_ - eol);

param %=
 tagstring
 >> operators
 >> value;

category %=
 tagstring
 >> '{'
 >> *node
 > '}';

node %= comment | category | param;

comment 设置为使用= 而不是%=,并且它没有返回类型。但是,无论它们出现在哪里,cmets 最终都会在我的输出 Nodes 中创建空的 Categorys。我尝试将comment 移出node 规则并进入category,如下所示:

category %=
 tagstring
 >> '{'
 >> *(comment | node)
 > '}';

还有其他各种东西,但那些空条目不断弹出。我不得不让comment 输出一个字符串并将std::string 放入我的Node variant 只是为了抓住它们,但这会破坏我在规则的其他部分中坚持评论的能力(除非我真的抓住了每个位置的字符串)。

我怎样才能完全忽略 comment 并让它不以任何方式显示在任何输出中?

编辑:您认为omit 会这样做,但似乎没有改变任何东西......

编辑 2:引用 this SO answer,我有一个不稳定的解决方案:

node %= category | param;

category %=
 tagstring
 >> '{'
 >> *comment >> *(node >> *comment)
 > '}';

但是,我想尝试将 cmets 插入各种位置(在 tagstring{ 之间,在我未显示的 root 规则中,根 categorys 之间等)。还有比这更简单的方法吗?我希望可以通过将简单的&gt;&gt; commentwrapper 插入到我想要的任何位置来完成...

【问题讨论】:

标签: c++ parsing boost boost-spirit boost-spirit-qi


【解决方案1】:

好的,所以制作自己的船长也不错。正如 Mike M 所说,它优雅地解决了这个评论问题。我在一个名为Parser 的结构中定义我的规则,该结构使用Iterator 进行模板化。必须进行一些调整才能使用船长。首先,这是在Parser 中定义的船长以及我的所有其他规则:

typedef qi::rule<Iterator> Skipper;
Skipper skipper;

所以skipperSkipper 类型的规则。这是我的Parser 结构最初的样子,它使用ascii::space_type 类型的ascii::space 规则作为其船长,它与skipper 所基于的qi::rule&lt;Iterator&gt; 类型不同!

struct Parser : qi::grammar<Iterator, std::vector<Category>(), ascii::space_type>
{
 qi::rule<Iterator, std::vector<Category>(), ascii::space_type> root;

 ...

所以规则模板中ascii::space_type 的每个实例都必须替换为Skipper!这包括除此处显示的root 之外的其他规则,例如我的问题中的paramcategory。留下旧的ascii::space_type 的任何残余都会产生隐秘的编译器错误。

struct Parser : qi::grammar<Iterator, std::vector<Category>(), qi::rule<Iterator>>
{
 typedef qi::rule<Iterator> Skipper;
 Skipper skipper;

 qi::rule<Iterator, std::vector<Category>(), Skipper> root;

 ...

原来的船长只是space,我现在是spacecomment的替代品。没有旧功能(空格跳过)丢失。

skipper = space | comment;

那么phrase_parse调用需要从这个使用ascii::space的旧版本调整:

bool r = phrase_parse(iter, end, parser, ascii::space, result);

bool r = phrase_parse(iter, end, parser, parser.skipper, result);

现在 cmets 就像空白一样容易消失。太棒了。

【讨论】:

  • 看起来不错。您还可以为船长使用模板参数,因此将来会更加灵活。 template&lt;Iterator, Skipper&gt; struct Parser : qi::grammar&lt;Iterator, data_type, Skipper&gt;
  • @MikeM 我实际上选择在结构中定义船长来整合我的规则定义,而不是在不同的函数中单独定义船长。也许这不是最好的选择,但在这种情况下对我来说似乎最方便。
猜你喜欢
  • 1970-01-01
  • 2018-08-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多