0

我正在尝试使用 Flex + Lemon 编写一个“玩具”解释器,它支持非常基本的“let”语法,其中变量 X 临时绑定到表达式。例如,“letx 3 + 4 in x + 8”应计算为 15。

本质上,我“喜欢”的规则是:

expr(E) ::= LETX expr(N) IN expr(O). {
                                         environment->X = N;  
                                         E = O; 
                                     }

但这不起作用,因为在分配O之前进行了评估。X = N

我知道通常的解决方案是中间规则行动。Lemon 没有明确支持这一点,但我在其他地方读到过无论如何都只是语法糖

因此,我尝试制定一个中期规则行动,X = N在解释之前完成我的任务O

midruleaction ::=  /* mid rule */.                   { environment->X = N; }    
expr(E)  ::= LETX expr(N) IN midruleaction expr(O).  {  E = O; }

但这不起作用,因为midruleaction规则无法访问N,或者至少我在柠檬文档/示例中看不到。

我想我在这里遗漏了一些东西。我知道我可以建造一棵树,然后再走一遍。我可能最终会这样做,但我想先了解如何更直接地解决这个问题。

有什么建议么?

4

1 回答 1

1

在解析器中立即评估确实不是一个非常可扩展的解决方案。见下文。

确实,中间规则动作(大部分)是语法糖。然而,在大多数情况下,它们不是“标记”(右侧为空的非终结符)的语法糖,而是表示生产前缀的非终结符。例如,您可以这样编写letx规则:

expr(E)     ::= letx_prefix IN expr(O). { E = O; }
letx_prefix ::= LETX expr(N).           { environment->X = N; }  

或者你可以这样做:

expr(E)       ::= LETX assigned_expr IN expr(O). { E = O; }
assigned_expr ::= expr(N).                       { environment->X = N; }

第一个是前缀desugaring;第二个是我会使用的,因为我觉得它可以更好地分离关注点。重要的一点是该environment->X = N;动作需要访问 RHS 前缀的语义值,因此它必须是前缀规则(至少包括其语义值需要的符号)的一部分,而不是具有根本不访问任何语义值。

说了这么多,解析期间的立即评估是一种非常有限的策略。它无法处理需要延迟评估的大量构造,例如循环和函数定义。它不能干净地处理可能抑制评估的结构,例如条件和短路运算符。(这些可以使用 MRA 和包含评估抑制标志的有状态环境来处理,但这非常难看。)

另一个问题是,在发现语法错误之前,可能会对语法错误的表达式进行部分评估,并且对于用户来说,表达式的哪些部分已经被评估和没有被评估可能不会立即显而易见。

总的来说,您最好在解析期间构建一个易于评估的 AST,并在解析成功完成时评估 AST。

于 2015-06-06T19:39:00.077 回答