减少野牛的订单

Reduce order in Bison

我正在使用 Bison 编写一个编译器,并且我正在尝试将相同的函数与 while 和 repeat 循环一起使用。我需要解析器在“statements_off”之前减少“condition”。 ¿我可以指定减少订单吗?

这是循环的代码:

loop_stmt:
        WHILE line condition DO ENDL line statements_off DONE
            { $$ = process_while($<elem>3, $<elem>7, $<ival>2, $<ival>6); }
    |   REPEAT ENDL line statements_off UNTIL line condition    
            { $$ = process_not($<elem>7);
              $$ = process_while($$, $<elem>4, $<ival>6, $<ival>3);  }
    |   FOR for_condition DO ENDL statements_off DONE
            { $$ = process_for($<elem>5, $<ival>2); }
    ;

condition: '(' expr_bool_or ')' { validate_bool_condition($<elem>2); $$ = $<elem>2; }
    ;

野牛的减少是自下而上和从左到右评估的。这是算法的重要组成部分。

这给了你一点自由度——有时你可以写一个语法,这样自下而上的归约会产生从右到左的效果——但你真的不应该这样做。当您解析为 AST(理想情况下独立于动作评估的顺序)然后根据需要和方便地遍历 AST 时,语义分析效果最佳。

通过将语言直接线性化为三地址代码来编写一次性编译器,这看起来像是一种简化或优化。但它最终会感觉更像一件紧身衣,因为很难将设计用于生成树的过程转变为线性控制流。

一次性编译器——我想到了 Lua 编译器——通常最终不得不重新排序生成的代码块,这既是因为这个问题的构造,也是为了实现非窥孔优化。

(将 whilefor 语句中的预测试打乱到循环末尾实际上是很常见的,这似乎与这里考虑的相反。)


要清楚这些可能性,请考虑以下两者之间的区别:

expressions: 
           | expressions expression     { printf("%d\n", ); }

expressions:
           | expression expressions     { printf("%d\n", ); }

这两个都是从左到右减少 expression,但是 expressions 自下而上的减少导致第二个摘录以相反的顺序打印表达式的值。如果 expression 不是递归的(几乎可以肯定是),您可以将其分解到 expressions 产生式中,从而使表达式本身的归约与自下而上的逻辑相对应。但是这种转换非常有限,因为它只会在你遇到递归产生式之前起作用,而且几乎所有有趣的产生式都是递归的。 (statementexpression 只是两个例子。)