助推精神:“语义行为是邪恶的”?
阅读并观看此演示文稿: http : //boost-spirit.com/home/2011/06/12/ast-construction-with-the-universal-tree/
我发现了这个说法 – 基本上我们build议不要使用语义动作。
我必须承认,我已经有这样的感觉:具有语义行为的语法实际上看起来有点丑陋。 而当我需要扩展/改变它们的时候,它恰恰在语义上采取了很多“微观pipe理”。 在演示中演示的具有属性语法的方法似乎更加优雅和有前途。
所以我想问一下:这是一个“官方”的观点吗? 我应该学习如何使用属性语法,并更详细地避免语义操作? 如果是这样,我想要求一些基本的(甚至可能是微不足道的)例子,说明这种方法–LISP解释器对我来说太复杂了。
我相信哈特穆特会在第二时间回答。 那么,这是我的承担:
不 ,这不是一个官方的观点。
语义操作有一些缺点
-
语义动作最简单的缺点是关注点分离的风格概念。 你想在一个地方expression句法,在另一个地方expression语义 。 这有助于可维护性(特别是在编译精神语法的冗长编译时间方面)
-
更复杂的影响,如果他们有副作用(往往是这种情况)。 想象一下,当语义动作有副作用时,从parsing的节点回溯:parsing器状态将被恢复,但外部效应不会被恢复。
从某种意义上说, 仅仅使用属性就像在函数式程序中使用确定性的纯函数一样,当仅由纯函数组成时,就更容易推理程序的正确性(或在这种情况下是语法状态机)。
-
语义行为有一个倾向(但不一定如此)引入更多的价值复制; 这与大量的回溯相结合可能会降低性能 。 当然,如果语义行为是“沉重的”,这本身就会阻碍parsing的性能。
语义动作对于各种目的都是有好处的。 事实上,如果你需要用上下文敏感的方式来parsing非重要的语法,你不能逃避它们。
-
考虑使用
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),这些语义行为通常不会造成什么问题,因为当他们回溯时,下一次执行(相同)语义行为时, 本地将被新的正确的值覆盖。
-
另外,有些工作真的很“肮脏”,不保证使用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的核心 。 这是有效的,因为在语义动作的节点层面不涉及回溯。
-
语义行为是“精神噶玛”中语义行为的镜像,通常构成的问题比气中的要less; 所以即使仅仅为了接口/ API的一致性,语义行为也是“好事”,并且提高了Boost Spirit作为一个整体的可用性。