Cha*_*ieP 6 parsing ocaml operator-precedence ocamlyacc menhir
我正在尝试使用Menhir解析器(类似于Ocamlyacc)解析运算符具有动态属性(优先级和优先级)的语言.在lexing阶段,所有操作员都填充一个OP:string令牌(所以"+"变成(OP "+")等等).
运算符属性在解析时确定,并填充关联运算符及其属性的表.鉴于此表,我如何指示Menhir根据此表的数据动态更改解析运算符的规则的优先级?
谢谢,CharlieP.
gas*_*che 12
我很抱歉回答"你做错了"的评论.我有三个反对意见,我希望它们具有建设性,按相关性递减顺序排列:
Menhir不适用于动态语法更新; 如果您坚持在分析时更改语法,则应使用提供此功能的工具,例如GLR解析器Dypgen.Dypgen手册提到了以一种受约束的方式动态更新运营商优先级的可能性(似乎你可以添加新的运营商和相应的优先级,但不能改变现有运营商的优先级),这可能会或可能不符合您的需求.参见Dypgen手册第6.6节(PDF),第42页.
我认为,动态更新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的人有一些关于这个主题的文献,例如Parsing Mixfix Operators,Danielsson和Norell,2009.
从设计的角度来看,我强烈建议你在几个不同的传递中分离你的lexing和解析,每个传递都是明确定义的,并且只使用在前一个结构上收集的信息,而不是试图动态地改变它自己的行为.你会有更简单,更强大的东西.
在我看来,动态或用户定义的优先级和优先级有点邪恶.OCaml有一个不同的系统,其中运算符优先级优先级由它们的前几个字符确定(例如@,@@并且@+都是正确关联的).这对于选择中缀运算符的人来说有点限制,但是使代码阅读器的生活更加舒适,因为他们只需要学习一套语法规则,而不必动态地使他们的眼睛适应任何新的代码.如果你想允许插入具有完全不同语法的狂野的,外来的代码片段,引用机制(例如camlp4 <:foo< ... >>)比摆弄运算符级别的关联性和优先级要强得多,而且解析起来也要简单得多.
也就是说,项目有不同的需求,我完全理解你是否坚持为我不知道的某些应用程序动态改变运算符的优先级和关联性.请记住,这不是唯一的方法,有时一致性和简单性优于绝对灵活性.