Boost Spirit:“语义行为是邪恶的”?

发布于 2024-12-17 20:48:04 字数 459 浏览 4 评论 0 原文

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

我必须承认,我已经有这样的感觉:带有语义动作的语法实际上看起来有点丑陋。而且,当我需要扩展/更改它们时,需要进行大量的“微观管理”和语义操作。演示中演示的属性语法方法似乎更加优雅和有前途。

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

Reading and watching this presentation:
http://boost-spirit.com/home/2011/06/12/ast-construction-with-the-universal-tree/
I've discovered this statement -- basically we are suggested not to use semantic actions.

I must admit, that I've already felt something like that: grammars with semantic actions actually look kinda ugly. and, when I needed to extend/change them, it took a lot of "micromanagement" exactly with semantic actions. The approach with attribute grammar, demonstrated in the presentation, seems to be much more elegant and promising.

So I'd like to ask: is this is an "official" point? Should I learn how to work with attribute grammar and avoid semantic actions in more detail? If so -- I'd like to = ask for some basic (maybe even trivial) examples, demonstrating such an approach -- the LISP interpreter is too complex for me to chew...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

小女人ら 2024-12-24 20:48:04

我相信哈特穆特很快就会回答。到那时,这是我的看法:

这不是官方观点。

语义操作有一些缺点

  • 语义操作最简单的缺点关注点分离的风格概念。您希望在一个地方表达语法,并在另一个地方表达语义。这有助于可维护性(特别是在编译 Spirit Grammars 的编译时间过长方面)

  • 如果它们有副作用(通常是这种情况),则含义会更复杂。想象一下,当语义操作有副作用时,从已解析的节点进行回溯:解析器状态将被恢复,但外部效果不会。

    在某种程度上,使用属性就像在函数式程序中使用确定性的纯函数一样,更容易推断程序的正确性(或者,在本例中语法状态机),当它仅由纯函数组成时。

  • 语义操作有一种倾向(但不一定如此)通过值引入更多的复制;这与大量回溯相结合,可能会降低性能。当然,如果语义动作很“重”,这本身就会阻碍解析的性能。


语义动作有多种用途。事实上,如果您需要解析具有上下文敏感性的重要语法,您就无法逃避它们。

  1. 考虑使用qi::locals继承属性(代码来自迷你 XML - AST! 示例) - 他们涉及语义动作:

    <前><代码>xml =
    开始标记 [at_c<0>(_val) = _1]
    >>> *节点
    >>> end_tag(at_c<0>(_val)) // 传递名称
    // ... start_tag 作为继承属性
    ;

    或者使用qi: :本地人

    rule; > RL;
    rl = alpha[_a = _1] >>> char_(_a); // 获取两个相同的字符
    test_parser("aa", rl); // 经过
    test_parser(“ax”, rl); // 失败
    

    IMO,这些语义操作通常不会造成什么问题,因为当它们回溯时,下次执行传递(相同的)语义操作时,本地将被新的语义操作覆盖,正确,值。

  2. 此外,有些工作确实“快速而肮脏”,并且不保证使用utree或手动滚动的 AST 类型:

     qi::phrase_parse(first, last, // 想象 qi::istream_iterator... 
         intesting_string_pattern // 我们想要动态匹配某些模式
                [ log_interesting_strings ], // 并将它们传递给我们的记录器
         Noise_skipper // 但我们跳过所有噪音
     );
    

    这里,语义动作是解析器函数的核心。它有效,因为在具有语义操作的节点级别不涉及回溯。

  3. 语义动作是精神业力中语义动作的镜像,它们通常比气中带来的问题要少;因此,即使只是为了接口/API 的一致性,语义操作也是“一件好事”,并且增强了 Boost Spirit 的整体可用性。

I'm sure Hartmut will answer in a second. Till then, this is my take:

No that is not an official point.

Semantic actions have some drawbacks

  • The simplest disadvantage of semantic actions is the stylistic notion of separation of concerns. You want to express syntax in one place, and semantics in another. This helps maintainability (especially with regards to the lengthy compile times for compiling Spirit Grammars)

  • More complicated implications if they have side-effects (which is frequently the case). Imagine backtracking from a parsed node when the semantic action had a side-effect: the parser state will be reverted, but the external effects aren't.

    In a way, using attributes only is like using deterministic, pure functions in a functional program, it is easier to reason about the correctness of a program (or, in this case the grammar state machine) when it is composed of pure functions only.

  • Semantic actions have a tendency (but not necessarily so) to introduce more copying around by value; this, in combination with heavy backtracking, could reduce performance. Of course, if the semantic action is 'heavy' this, in itself, is going to hinder performance of parsing.


Semantic actions are good for various purposes. In fact, if you need to parse non-trivial grammars with context sensitivity you cannot escape them.

  1. Consider the use of qi::locals<> and inherited attributes (code from the Mini XML - ASTs! sample) - they involve semantic actions:

    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
    ;
    

    Or one using 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, these semantic action pose less of a problem usually, because when they get backtracked, the next time execution passes (the same) semantic action, the local will just get overwritten by the new, correct, value.

  2. Also, some jobs are really 'quick-and-dirty' and don't warrant the use of utree or a hand-rolled AST type:

     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
     );
    

    Here, the semantic action is the core of the parsers function. It works, because no backtracking is involved at the level of nodes with semantic actions.

  3. The semantic actions are a mirror-image of semantic actions in Spirit Karma, where they usually pose less of the problems than in Qi; so even if only for interface/API consistency, semantic actions are 'a good thing' and enhance the usability of Boost Spirit as a whole.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文