Ответ 1
Я очень далек от эксперта по Parsimonious, но я считаю, что проблема заключается в том, что ~".+"
жадно сопоставляет весь остаток входной строки, не оставляя ничего, чтобы соответствовать остальной части производства. Я сначала протестировал эту идею, изменив регулярное выражение на rvalue
на ~"[a-z0-9\\-]+"
, то же самое, что и у lvalue
. Теперь он анализирует и (удивительно) различает контекст между двумя одинаково определенными токенами lvalue
и rvalue
.
from parsimonious.grammar import Grammar
grammar = Grammar(
"""
program = expr*
expr = _ "{" lvalue (rvalue / expr)* "}" _
lvalue = _ ~"[a-z0-9\\-]+" _
rvalue = _ ~"[a-z0-9\\-]+" _
_ = ~"[\\n\\s]*"
"""
)
print(grammar.parse( "{ do-something some-argument }"))
Если вы имеете в виду для rvalue
для соответствия любой последовательности символов без пробелов, вам нужно что-то большее:
rvalue = _ ~"[^\\s\\n]+" _
Но крики!
{ foo bar }
"}"
является закрывающей фигурной скобкой, но также является последовательностью одного или нескольких символов без пробелов. Это "}"
или rvalue
? Грамматика говорит, что следующим токеном может быть любой из них. Одна из этих интерпретаций является сильной, а другая - нет, но Parsimonious просто говорит, что это шпинат и ад. Я не знаю, рассмотрит ли синтаксический анализ maven, что законный способ разрешить двусмысленность (например, может быть, такая грамматика может привести к случаям с двумя возможными интерпретациями, которые анализируются) или насколько практично это реализовать. В любом случае Parsimonious не делает этого звонка.
Итак, нам нужно отталкивать границы по фигуре. Я думаю, что эта грамматика делает то, что вы хотите:
from parsimonious.grammar import Grammar
grammar = Grammar(
"""
program = expr*
expr = _ "{" lvalue (expr / rvalue)* "}" _
lvalue = _ ~"[a-z0-9\\-]+" _
rvalue = _ ~"[^{}\\n\\s]+" _
_ = ~"[\\n\\s]*"
"""
)
print(grammar.match( "{ do-something some-argument 23423 {foo bar} &^%$ }"))
Я также исключил открытую фигурную скобку, потому что как бы вы ожидали, что эта строка будет tokenize?
{foo bar{baz poo}}
Я ожидал бы
"{" "foo" "bar" "{" "baz" "poo" "}" "}"
... потому что если "poo}"
ожидается tokenize как "poo"
"}"
, а "{foo"
ожидается tokenize как "{"
"foo"
, тогда обработка bar{baz
как "bar{baz"
или "bar{"
"baz"
- это невменяемый противоречивый.
Теперь я помню, как моя горькая ненависть к Якку привела меня к одержимости этим.