Анализатор Lark не может проанализировать символы, даже если они определены в регулярном выражении правила - PullRequest
2 голосов
/ 09 ноября 2019

Я пытаюсь написать анализатор SMTP и взял некоторую информацию для строк в кавычках из rfc . Итак, у меня есть следующая грамматика (вычеркнутые все части, которые работают, фокусируясь на том, что не работает):

quoted_string  : /[\x22]/ qcontentsmtp* /[\x22]/
qcontentsmtp   : qtextsmtp | quoted_pairsmtp
quoted_pairsmtp  : /[\x5C\x5C]/ /[\x20-\x7E]/
qtextsmtp      : /[\x20-\x21|\x23-\x5B|\x5D-\x7E]/

command : [ quoted_string ]

с единственным start для синтаксического анализатора, являющимся правилом command.

Когда я введу "quoted_string", я ожидаю, что он будет проанализирован следующим образом:

command -> quoted_string -> qcontentsmtp -> qtextsmtp

Как видите, qtextsmtp содержит буквенно-цифровые символы, закодированные как регулярное выражение,как показано в РФС. Однако, когда я пытаюсь разобрать его, я получаю это сообщение:

input = '"quoted_string"'
....
####### Parsing Failed
No terminal defined for 'q' at line 1 col 2

"quoted_string"
 ^

, когда я вводю только "", оно работает как положено.

Когда я меняю правило qtextsmtp изамените регулярное выражение на "a" и сделайте входное значение '"a"', оно также работает.

Я определил все правила как функции в моем преобразователе, очень простые, например:

class StringsTransformer(Transformer):
# externals
def quoted_string(self, args):
    return "".join(args)

# internals
def qcontentsmtp(self, args):
    return "".join(args)

def quoted_pairsmtp(self, args):
    return "".join(args)

def qtextsmtp(self, args):
    return "".join(args)

Но я даже не дохожу до этих правил, потому что, как я уже сказал, он даже не будет анализироваться.

Я не совсем уверен, почему регулярное выражение не работает. Я использую этот тип правил в других частях, и они прекрасно работают, просто с этим он не работает.

Ответы [ 2 ]

0 голосов
/ 10 ноября 2019

Кажется, что синтаксический анализатор регулярных выражений Ларка путается с цитированием [ и ] как \x5b и \x5d соответственно, а буква q просто не соответствует регулярному выражению. После замены \x5b на \[ и \x5d на \] грамматика анализирует предоставленный ввод, как показано в следующей программе:

import lark

grammar = r"""
quoted_string  : /[\x22]/ qcontentsmtp* /[\x22]/
qcontentsmtp   : qtextsmtp | quoted_pairsmtp
quoted_pairsmtp  : /[\x5C\x5C]/ /[\x20-\x7E]/
qtextsmtp      : /[\x20-\x21\x23-\[\]-\x7E]/

command : [ quoted_string ]
"""

parser = lark.Lark(grammar, start='command')

print(parser.parse('"quoted_string"'))

(Обратите внимание, что | является лишним внаборы символов, он интерпретируется как просто другой символ для сопоставления.)

Это не общее ограничение регулярных выражений Python, которые вполне способны принимать [ и ], экранированные в шестнадцатеричном виде:

>>> re.compile(r'[\x23-\x5b\x5d-\x7e]').match('q')
<re.Match object; span=(0, 1), match='q'>

Теперь я сообщил о проблеме сопровождающим Ларк.

0 голосов
/ 10 ноября 2019

Я бы рекомендовал использовать строковые литералы в терминалах, если вы можете;даже если они не будут соответствовать RFC одинаково, они, безусловно, работают в существующей реализации анализатора lark. (Ваш пример мне тоже не удался, но использование приведенного ниже работает. Не уверен, что я понимаю подкрепления относительно почему .)

DOUBLE_QUOTED_STRING  : /"[^"]*"/

ссылка от the lark src .

Как вы определяете свою грамматику? Вам может потребоваться экранировать \ обратную косую черту, если вы определяете ее встроенным в коде (вместо чтения из файла).

...