我试图写一个"玩具"使用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并没有明确地支持这一点,但我已经在其他地方阅读了syntactic sugar无论如何。
因此,在尝试解释X = N
之前,我已尝试整理一项中等规则的操作,以便完成O
的任务:
midruleaction ::= /* mid rule */. { environment->X = N; }
expr(E) ::= LETX expr(N) IN midruleaction expr(O). { E = O; }
但这不会起作用,因为midruleaction
规则无法访问N
,或者至少我无法在柠檬文档/示例中看到。< / p>
我想我在这里遗漏了一些东西。我知道我可以建造一棵树,然后在第二次通过时走。我最终可能会这样做,但我想先了解如何更直接地解决这个问题。
有什么建议吗?
答案 0 :(得分:1)
在解析器中立即评估它并不是一个非常可扩展的解决方案。见下文。
确实,中规则行动(大多数)是句法糖。然而,在大多数情况下,它们不是#34;标记物的语法糖。 (具有空右侧的非终端),而非代表生产前缀的非终端。例如,您可以像这样编写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。