解析 – 用户定义的中缀运算符的解析器

我正在为一种语言编写一个解释器,其中函数可以用作运算符.但是,函数内容只能在运行时知道.

为此,我考虑了两个解决方案:

>使用函数的运行时信息在运行时完成解析
>所有用户定义的运算符都使用默认值来表示优先级和关联性.

我选择了后者,因为我看到了分别解析到执行的许多优点.

现在谈到实现,我有兴趣看看有哪些选项.我最初的想法是一个shift reduce parser,但我在构造解析器方面没什么经验.

例:

LHS op RHS : LHS * RHS     /* define a binary operator 'op' */
var : 3                    /* define a variable */
print 5 op var             /* should print 15 */

LHS op RHS : LHS / RHS     /* Re-define op */
print var op var           /* Should print 1 */

在最后一种情况下,解析器将从词法分析器获取:“id id id id”.只有在运行时我才知道’op’id是一个运算符.

最佳答案 (根据要求发布评论结果.)

解决方案#1绝对是丑陋的,实现起来很复杂,而且不需要,我同意.解决方案#2到目前为止更容易实现和理解.您也可以允许运算符的自定义关联性和优先级,只要这些是静态已知的.主要的是这些事实在解析时是已知的.

至于实际解析,大多数解析器都可以正常工作,因为围绕id的任何两个表达式都是自定义中缀运算符的应用程序(如果允许自定义优先级和关联性,则不太正确,在这种情况下,您需要一个允许确定的算法在解析时基于每个操作符的那些).无论哪种情况,我个人最喜欢的是“Top Down Operator Precedence Parser”或Pratt解析器.我发现以下资源(按照对我有用的顺序,YMMV)描述得很好:

> Simple Top-Down Parsing in Python
> Pratt Parsers: Expression Parsing Made Easy
> Top Down Operator Precedence

算法的两个属性使它非常适合这个问题:

>对每个标记动态发生关联性(“绑定能力”)的查找(允许解析器允许用户为其运算符定义优先级).
>手写[*]非常简单,你可能不得不这样做,因为这种程度的动态超出了大多数(至少我所知道的)解析器生成器的范围.

[*]我亲自为一个非常大的(只缺少案例,多维数组,也许是一些模糊的细微之处)编写了一个解析器,它包含了500行Python中的Pascal和2-3天的工作,剩下的只是因为其他它当时使用的软件部分更有趣,我没有理由实现其余部分.

点赞