1.介绍

本系列文章参照该教程学习总结,欢迎查看原文。我个人的学习代码已经放到我的github
词法分析、语法分析、语义分析等定义请参考编译器解释器中的词法分析、语法分析、语义分析

英文原作者所有源代码查看

2. 更多的AST

本节作者继续深化前一章的内容,增加一些一元操作。
这里再来复习下一元操作符和二元操作符的概念:

  1. 一元运算符:一元运算符只对一个表达式执行操作,该表达式可以是数值数据类型类别中的任何一种数据类型。例如一元的 '-'表示对表达式取反
  2. 二元运算符:二元运算是由两个元素形成第三个元素的一种规则。例如数的加法及乘法;更一般地,由两个集合形成第三个集合的产生方法,或构成规则称为二次运算

一元加减号的例子:


看了以上例子后,我们重新修改文法的规则。这里注意一元运算的优先级比我们之前的二元运算的优先级要高。

之前的文法规则是这样的:


现在的文法规则是:
从这个规则可以看出来,在这条产生式的右端(主体部分)增加了一元运算符的判断。这个判断需要放在其他INTEGER等基本表达式的前面优先判断。这里在主体中又引入了factor规则本身,用于递归。这样可以表达类似”----2“ 这样的表达式

完整的文法规则如下所示:

3. 修改代码

根据之前修改后得到的文法,我们需要引入更多的ASTNode类,在这里试一元运算符

class UnaryOp(AST):
    def __init__(self, op, expr):
        self.token = self.op = op
        self.expr = expr

此外根据文法,我们还要修改factor这条规则:

def factor(self):
    """factor : (PLUS | MINUS) factor | INTEGER | LPAREN expr RPAREN"""
    token = self.current_token
    if token.type == PLUS:
        self.eat(PLUS)
        node = UnaryOp(token, self.factor())
        return node
    elif token.type == MINUS:
        self.eat(MINUS)
        node = UnaryOp(token, self.factor())
        return node
    elif token.type == INTEGER:
        self.eat(INTEGER)
        return Num(token)
    elif token.type == LPAREN:
        self.eat(LPAREN)
        node = self.expr()
        self.eat(RPAREN)
        return node

同样的,我们也需要增加相应访问节点的方法:

def visit_UnaryOp(self, node):
    op = node.op.type
    if op == PLUS:
        return +self.visit(node.expr)
    elif op == MINUS:
        return -self.visit(node.expr)