Ответ 1
Pyparsing всегда будет иметь несколько плохих сообщений об ошибках, потому что он отступает. Сообщение об ошибке генерируется в последнем правиле, которое пытается выполнить парсер. Парсер не может знать, где ошибка на самом деле, он знает только, что не существует соответствующего правила.
Для хороших сообщений об ошибках вам нужен парсер, который рано встает. Эти синтаксические анализаторы менее гибки, чем Pyparsing, но большинство обычных языков программирования могут анализироваться с помощью таких синтаксических анализаторов. (С++ и Scala IMHO не могут.)
Чтобы улучшить сообщения об ошибках в Pyparsing, используйте оператор -
, он работает как оператор +
, но он не отступает. Вы бы использовали его следующим образом:
assignment = Literal("let") - varname - "=" - expression
Вот небольшая статья об улучшении отчетности об ошибках, автор Pyparsing:
http://pyparsing.wikispaces.com/message/view/home/30875955#30901387
Edit
Вы также можете генерировать хорошие сообщения об ошибках для недопустимых чисел в действиях синтаксического анализа, которые выполняют проверку. Если номер недействителен, вы вызываете исключение, которое не попадает в Pyparsing. Это исключение может содержать хорошее сообщение об ошибке.
Действия анализа могут иметь три аргумента [1]:
- s = исходная строка, обрабатываемая (см. примечание ниже)
- loc = расположение соответствующей подстроки
- toks = список совпадающих токенов, упакованных как объект
ParseResults
Существует также три полезных вспомогательных метода для создания хороших сообщений об ошибках [2]:
-
lineno(loc, string)
- функция, указывающая номер строки в строке; первая строка - строка 1, новые строки запускают новые строки. -
col(loc, string)
- функция для указания номера столбца местоположения внутри строки; первый столбец - столбец 1, новые строки reset номер столбца - 1. -
line(loc, string)
- функция для получения строки текста, представляющейlineno(loc, string)
. Полезно при печати диагностических сообщений для исключений.
Ваше действие синтаксического анализа будет выглядеть следующим образом:
def validate_odd_number(s, loc, toks):
value = toks[0]
value = int(value)
if value % 2 == 0:
raise MyFatalParseException(
"not an odd number. Line {l}, column {c}.".format(l=lineno(loc, s),
c=col(loc, s)))
[1] http://pythonhosted.org/pyparsing/pyparsing.pyparsing.ParserElement-class.html#setParseAction
[2] http://pyparsing.wikispaces.com/HowToUsePyparsing
Edit
Здесь [3] - улучшенная версия вопроса current (2013-4-10) script. Он правильно отображает примеры ошибок, но другая ошибка указана в неправильном положении. Я считаю, что есть ошибки в моей версии Pyparsing ( "1.5.7" ), но, возможно, я просто не понимаю, как работает Pyparsing. Проблемы:
- ParseFatalException, похоже, не всегда является фатальным. script работает как ожидалось, когда я использую свое собственное исключение.
- Оператор
-
, похоже, не работает.