解析右关联运算符(指数)

时间:2018-08-31 17:48:14

标签: python parsing token right-to-left

我一直在为自己的语言编写一个词法分析器/解析器/解释器,到目前为止,所有方法都可以正常工作。我一直在关注Ruslan Spivak's blog(每个文章的Github链接)中的示例。

我想将语言语法扩展到文章中所写的内容之外,以包括更多的运算符,例如比较(<>=等)以及指数(**或{ {1}}(用我的语言)。我有这个语法:

^

在解析令牌方面,我使用与Ruslan博客中相同的方法。这是一个将解析expression : exponent ((ADD | SUB) exponent)* exponent : term ((POWER) term)* # this one is right-associative (powers **) term : comparison ((MUL | DIV) comparison)* comparison : factor ((EQUAl | L_EQUAL | LESS N_EQUAL | G_EQUAL | GREATER) factor)* # these are all binary operations factor : NUM | STR | variable | ADD factor | SUB factor | LPAREN expr RPAREN # different types of 'base' types like integers # also contains parenthesised expressions which are evalutaed first 行的示例,尽管它的名字也可以处理加法和减法,因为语法表明表达式被解析为 exponent

exponent_expr (+ / -) exponent_expr

现在,此方法可以很好地解析左关联标记(因为令牌流自然地从左到右),但是我仍在研究如何解析右关联指数。查看此预期的输入/输出以供参考:

def exponent(self):
    node = self.term()
    while self.current_token.type in (ADD, SUB):
        token = self.current_token

        if token.type == ADD:
            self.consume_token(ADD)
        elif token.type == SUB:
            self.consume_token(SUB)

        node = BinaryOperation(left_node=node,
                               operator=token,
                               right_node=self.term())

    return node

为解决此问题,我尝试切换>>> 2 ** 3 ** 2 # should be parsed as... >>> 2 ** (3 ** 2) # which is... >>> 2 ** 9 # which returns... 512 # Mine, at the moment, parses it as... >>> (2 ** 3) ** 2 # which is... >>> 8 ** 2 # which returns... 64 构造函数的左右节点,以使当前节点为右,而新节点为左,但这仅使BinaryOperation()解析为{{1} },这给了我2**5而不是预期的5**2

有什么可以尝试的方法吗?

1 个答案:

答案 0 :(得分:0)

您的exponent函数实际上解析expression的事实应该是一个危险信号。实际上,您需要一个expression函数来解析表达式,而一个exponent函数来解析指数。

您还混淆了取幂和乘法(以及其他运算)的优先顺序,因为2 * x ** 4并不意味着(2 * x) ** 4(可能是16x⁴),而是{{ 1}}。同样,2 * (x ** 4)并不意味着x * 3 < 17,这就是语法解析的方式。

通常,算术的优先级如下所示:

x * (3 < 17)

(如果您有诸如函数调用之类的后缀运算符,它们将介于取幂和原子之间。)

以这种形式重新编写语法后,指数分析器将如下所示:

 comparison     <, <=, ==, ... ( lowest precedence)
 additive       +, -
 multiplicative *, /, %
 unary          +, -
 exponentiation **
 atoms          numbers, variables, parenthesized expressions, etc.

最后的递归调用产生正确的关联性。在这种情况下,递归是可以接受的,因为左操作数和运算符已经被消耗掉了。因此,递归调用无法产生无限循环。