Изменить: Я сделал первую версию, и Эйке помог мне немного продвинуться. Я теперь придерживаюсь более конкретной проблемы, о которой я расскажу ниже. Вы можете посмотреть исходный вопрос в истории
Я использую pyparsing для синтаксического анализа небольшого языка, используемого для запроса конкретных данных из базы данных. Он содержит множество ключевых слов, операторов и типов данных, а также логическую логику.
Я пытаюсь улучшить сообщение об ошибке, отправленное пользователю, когда он делает синтаксическую ошибку, поскольку текущий не очень полезен. Я разработал небольшой пример, похожий на то, что я делаю, с языком, упомянутым выше, но намного меньшим:
#!/usr/bin/env python
from pyparsing import *
def validate_number(s, loc, tokens):
if int(tokens[0]) != 0:
raise ParseFatalException(s, loc, "number musth be 0")
def fail(s, loc, tokens):
raise ParseFatalException(s, loc, "Unknown token %s" % tokens[0])
def fail_value(s, loc, expr, err):
raise ParseFatalException(s, loc, "Wrong value")
number = Word(nums).setParseAction(validate_number).setFailAction(fail_value)
operator = Literal("=")
error = Word(alphas).setParseAction(fail)
rules = MatchFirst([
Literal('x') + operator + number,
])
rules = operatorPrecedence(rules | error , [
(Literal("and"), 2, opAssoc.RIGHT),
])
def try_parse(expression):
try:
rules.parseString(expression, parseAll=True)
except Exception as e:
msg = str(e)
print("%s: %s" % (msg, expression))
print(" " * (len("%s: " % msg) + (e.loc)) + "^^^")
Таким образом, в основном, единственное, что мы можем сделать с этим языком, - это запись серии x = 0, соединенная вместе с and и скобкой.
Теперь есть случаи, когда используются and и скобки, где отчет об ошибках не очень хорош. Рассмотрим следующие примеры:
>>> try_parse("x = a and x = 0") # This one is actually good!
Wrong value (at char 4), (line:1, col:5): x = a and x = 0
^^^
>>> try_parse("x = 0 and x = a")
Expected end of text (at char 6), (line:1, col:1): x = 0 and x = a
^^^
>>> try_parse("x = 0 and (x = 0 and (x = 0 and (x = a)))")
Expected end of text (at char 6), (line:1, col:1): x = 0 and (x = 0 and (x = 0 and (x = a)))
^^^
>>> try_parse("x = 0 and (x = 0 and (x = 0 and (x = 0)))")
Expected end of text (at char 6), (line:1, col:1): x = 0 and (x = 0 and (x = 0 and (xxxxxxxx = 0)))
^^^
На самом деле, кажется, что если синтаксический анализатор не может разбираться (и синтаксический анализ здесь важен), то после and он больше не создает хороших сообщений об ошибках: (
И я имею в виду parse, поскольку, если он может разобрать 5, но "проверка" не выполняется в синтаксическом анализе, он все равно создает хорошее сообщение об ошибке. Но если он не может проанализировать допустимое число (например, a) или допустимое ключевое слово (например, xxxxxx), он перестает создавать правильные сообщения об ошибках.
Любая идея?