我正在学习编译器的构造,并且已经设法创建了可以解释简单代码行的小型Python脚本。但是,我正在努力实现提供非终端产品选择的EBNF语句的正确方法。让我们以这个EBNF为例:
expression ::= term
| expression '+' term
| expression '-' term
term ::= factor
| term '*' factor
| term '/' factor
factor ::= NUMBER
| '(' expression ')'
这是EBNF,用于解释简单的数学表达式,例如5 *(3 + 4)。
从编译器文献中,我了解了使用if
语句识别终端符号(令牌)的基本方法,对于非终端生产,我们将其称为子函数。有了这些知识,我就能编写解释factor
的函数:
def factor():
if token.type == 'NUMBER':
number = token.value
eat('NUM')
return number
elif token.type == '(':
eat('(')
expr = self.expression()
eat(')')
return expr
实现expression
和term
非终端的推荐方法是什么?我使用了peek()
函数来向前看一个令牌:
def expression():
next_token = peek()
if token.type in ['NUMBER', '('] and next_token.type == '+':
expression = expression(token)
eat('+')
term = term()
return (expression, '+', term)
elif token.type in ['NUMBER', '('] and next_token.type == '-':
expression = expression(token)
eat('-')
term = term()
return (expression, '-', term)
elif token.type in ['NUMBER', '(']:
term = term()
return term
我感到很奇怪,我必须查看两个级别的EBNF(term
和factor
)以找到可以用来决定在{ {1}}(与expression
中一样)。我不确定的另一件事是,if token.type in ['NUMBER', '('] and next_token.type == '+':
上方的方法需要最后测试。这意味着测试EBNF中非终端生产的顺序变得很重要。这是正确的方法吗?