6

我正在尝试使用 Menhir 解析器(类似于 Ocamlyacc)解析运算符具有动态属性(优先级和优先级)的语言。在词法分析阶段,所有运算符都填充一个OP:string标记(因此“+”变成(OP "+"),等等)。

运算符属性在解析时确定并填充关联运算符及其属性的表。鉴于此表,我如何指示 Menhir 根据此表的数据动态更改解析运算符的规则的优先级?

谢谢,查理P。

4

1 回答 1

13

我很抱歉回答“你做错了”这样的评论。我有三个反对意见,我希望是建设性的,按相关性降序排列:

  1. Menhir 不适用于动态语法更新。如果您坚持在解析时更改语法,则应使用提供此功能的工具,例如 GLR 解析器Dypgen。Dypgen 手册提到了以受限方式动态更新运算符优先级的可能性(似乎您可以添加新运算符和相应的优先级,但不能更改现有运算符的优先级),这可能符合您的需求,也可能不符合您的需求。请参阅Dypgen 手册 (PDF)的第 6.6 节,第... 42 页。

  2. 我认为,动态更新 CFG 语法并不是处理用户定义的运算符优先级的最佳方式。Agda 有非常通用的用户定义的 mixfix 运算符,它们的解决方案大致如下:使用您的 CFG 解析器来解析静态已知的语法结构,但是对于可能使用花哨的优先级和关联性的表达式,只需将它们解析成一个列表令牌。例如,let x = if foo then x + y * z else bar将被解析为类似Let(x, If(foo, Expr(x, +, y, *, z), bar). 稍后的专用通道可以收集所需的信息,以将这些信息后解析为Expr节点,使其成为专用结构。使用解析器生成器来处理它们擅长的事情(静态已知的富 CFG),并对复杂、定义不明确的动态内容使用后处理过程。例如,Agda 家伙有一些关于该主题的文献解析 Mixfix 运算符,Danielsson 和 Norell,2009 年。

    从设计的角度来看,我强烈建议您将您的词法分析和解析分成几个不同的通道,每个通道都经过良好定义,并且仅使用在先前结构上收集的信息,而不是尝试动态地改变其自身的行为。您将拥有更简单、更强大的东西。

  3. 在我看来,动态或用户定义的优先级和优先级有点邪恶。OCaml 有一个不同的系统,其中运算符的优先级由它们的前几个字符确定(例如@@@并且@+都是右关联的)。对于选择中缀运算符的人来说,这有点限制,但让代码阅读者的生活更加舒适,因为他们只需要学习一套语法规则,而不必动态地让他们的眼睛适应任何新的代码。如果您想允许插入具有完全不同语法的狂野的外来代码,引用机制(例如 camlp4 <:foo< ... >>)比摆弄操作员级别的关联性和优先级要强大得多,而且解析起来也更简单。

    也就是说,项目有不同的需求,如果您坚持让某些我不知道的应用程序动态更改运算符优先级和关联性,我会完全理解。请记住,这不是唯一的方法,有时一致性和简单性比绝对的灵活性更好。

于 2012-07-02T08:30:47.383 回答