Я изучаю конструкцию компилятора и уже успел создать небольшие скрипты 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
), чтобы найтитерминальные символы, которые я могу использовать, чтобы решить, какой из вариантов сделать в expression
(как в if token.type in ['NUMBER', '('] and next_token.type == '+':
).Другая вещь, в которой я не уверен, заключается в том, что подход выше term
должен быть проверен последним.Это означает, что порядок проверки нетерминальных производств в EBNF становится важным.Это правильный способ сделать это?