Изменить: Я сделал первую версию, и Эйке помог мне немного продвинуться. Я теперь придерживаюсь более конкретной проблемы, о которой я расскажу ниже. Вы можете посмотреть исходный вопрос в истории
Я использую 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
), он перестает создавать правильные сообщения об ошибках.
Любая идея?