助推精神:“语义行为是邪恶的”?

阅读并观看此演示文稿: http : //boost-spirit.com/home/2011/06/12/ast-construction-with-the-universal-tree/
我发现了这个说法 – 基本上我们build议不要使用语义动作。

我必须承认,我已经有这样的感觉:具有语义行为的语法实际上看起来有点丑陋。 而当我需要扩展/改变它们的时候,它恰恰在语义上采取了很多“微观pipe理”。 在演示中演示的具有属性语法的方法似乎更加优雅和有前途。

所以我想问一下:这是一个“官方”的观点吗? 我应该学习如何使用属性语法,并更详细地避免语义操作? 如果是这样,我想要求一些基本的(甚至可能是微不足道的)例子,说明这种方法–LISP解释器对我来说太复杂了。

我相信哈特穆特会在第二时间回答。 那么,这是我的承担:

,这不是一个官方的观点。

语义操作有一些缺点

  • 语义动作最简单的缺点关注点分离的风格概念。 你想在一个地方expression句法,在另一个地方expression语义 。 这有助于可维护性(特别是在编译精神语法的冗长编译时间方面)

  • 更复杂的影响,如果他们有副作用(往往是这种情况)。 想象一下,当语义动作有副作用时,从parsing的节点回溯:parsing器状态将被恢复,但外部效应不会被恢复。

    从某种意义上说, 仅仅使用属性就像在函数式程序中使用确定性的纯函数一样,当仅纯函数组成时,就更容易推理程序的正确性(或在这种情况下是语法状态机)。

  • 语义行为有一个倾向(但不一定如此)引入更多的价值复制; 这与大量的回溯相结合可能会降低性能 。 当然,如果语义行为是“沉重的”,这本身就会阻碍parsing的性能。


语义动作对于各种目的都是有好处的。 事实上,如果你需要用上下文敏感的方式来parsing非重要的语法,你不能逃避它们。

  1. 考虑使用qi::locals<>inheritance的属性Mini XML - ASTs!示例中的代码 ) – 它们涉及语义操作:

     xml = start_tag [at_c<0>(_val) = _1] >> *node >> end_tag(at_c<0>(_val)) // passing the name from the // ... start_tag as inherited attribute ; 

    或者使用qi :: locals :

     rule<char const*, locals<char> > rl; rl = alpha[_a = _1] >> char_(_a); // get two identical characters test_parser("aa", rl); // pass test_parser("ax", rl); // fail 

    国际海事组织(IMO),这些语义行为通常不会造成什么问题,因为当他们回溯时,下一次执行(相同)语义行为时, 本地将被新的正确的值覆盖。

  2. 另外,有些工作真的很“肮脏”,不保证使用utree或手动的ASTtypes:

      qi::phrase_parse(first, last, // imagine qi::istream_iterator... intesting_string_pattern // we want to match certain patterns on the fly [ log_interesting_strings ], // and pass them to our logger noise_skipper // but we skip all noise ); 

    这里,语义动作是parsing器function的核心 。 这是有效的,因为在语义动作的节点层面不涉及回溯。

  3. 语义行为是“精神噶玛”中语义行为的镜像,通常构成的问题比气中的要less; 所以即使仅仅为了接口/ API的一致性,语义行为也是“好事”,并且提高了Boost Spirit作为一个整体的可用性。

Interesting Posts