Ни одна из ваших строк ввода не является синтаксически действительной сама по себе.Они формируют синтаксически допустимую программу только при анализе в целом.Поэтому вам нужно вызывать parse
один раз для строки, содержащей всю программу, а не один раз для каждой строки.
Это можно сделать, просто вызвав file.read()
в своем коде обработки файлов вместо использования while
loop.
Синтаксическая ошибка, с которой вы сталкиваетесь после исправления, связана с тем, как перекрывающиеся лексические правила обрабатываются в PLY.В здравомыслящих генераторах лексеров побеждает правило, дающее самое длинное совпадение, и, если оба дают одинаковое совпадение, побеждает то, которое стоит первым в коде.Однако в PLY побеждает тот, у кого самое длинное регулярное выражение.Из-за этого поведения нельзя использовать отдельные правила для сопоставления идентификаторов и ключевых слов с помощью PLY.В этом случае правило t_OTHERS
используется, даже если, скажем, t_INCLUDE
также совпадает.
Вместо в документации PLY рекомендуется следующий способ сопоставления идентификаторов и ключевых слов:
Чтобы обработать зарезервированные слова, вы должны написать одно правило для соответствия идентификатору и выполнить специальный поиск имени в функции, подобной этой:
reserved = {
'if' : 'IF',
'then' : 'THEN',
'else' : 'ELSE',
'while' : 'WHILE',
...
}
tokens = ['LPAREN','RPAREN',...,'ID'] + list(reserved.values())
def t_ID(t):
r'[a-zA-Z_][a-zA-Z_0-9]*'
t.type = reserved.get(t.value,'ID') # Check for reserved words
return t
Этот подход значительно сокращает количествоправила регулярных выражений, которые могут немного ускорить процесс.
Примечание. Следует избегать написания отдельных правил для зарезервированных слов.Например, если вы напишите правила, подобные этим,
t_FOR = r'for'
t_PRINT = r'print'
, эти правила будут срабатывать для идентификаторов, которые включают эти слова в качестве префикса, таких как «забыть» или «напечатано».Это, вероятно, не то, что вам нужно.
Опять же, следует отметить, что ни одна из упомянутых проблем не существует в генераторах лексеров, которые используют правило максимального жука.
В общем, как отлаживать проблемы синтаксических ошибок с PLY?
Первым шагом будет изменение p_error
для вывода некоторой полезной информации (например, какой тип токенав какой строке вызвала синтаксическая ошибка) вот так:
def p_error(p):
if p == None:
token = "end of file"
else:
token = f"{p.type}({p.value}) on line {p.lineno}"
print(f"Syntax error: Unexpected {token}")