Можно ли *
использовать в sym
токены для более чем одного символа?... Пример для sym
показывает *
(WhateverCode
), заменяющий один символ
Это не WhateverCode
или Whatever
. 1
<...>
в foo:sym<...>
- это конструктор кавычек, поэтому ...
- это просто буквенная строка.
Вот почему это работает:
grammar g { proto token foo {*}; token foo:sym<*> { <sym> } }
say g.parse: '*', rule => 'foo'; # matches
Что касается P6, *
в foo:sym<*>
- это просто случайная строка.Это может быть abracadabra
.Я предполагаю, что автор выбрал *
для представления ментального понятия «что угодно», потому что оно соответствует понятию P6 Whatever
.Возможно, они были слишком милыми.
В остальной части этого ответа я напишу JJ
вместо *
, где последний является просто произвольной строкой в отношении P6.
*
в прото - это Whatever
.Но это совершенно не связано с вашим вопросом:
grammar g { proto token foo {*}; token foo:sym<JJ> { '*' } }
say g.parse: '*', rule => 'foo'; # matches
В теле правила (токены и регулярные выражения являются правилами), имя которого включает в себя часть :sym<...>
, вы можете написать <sym>
, и оно будет соответствоватьстрока между углами :sym<...>
:
grammar g { proto token foo {*}; token foo:sym<JJ> { <sym> } }
say g.parse: 'JJ', rule => 'foo'; # matches
Но вы можете написать все что угодно в теле правила / токена / регулярного выражения.A .
соответствует одному символу:
grammar g { proto token foo {*}; token foo:sym<JJ> { . } }
say g.parse: '*', rule => 'foo'; # matches
Однако он потерпит неудачу, если мы используем его вместо символа, состоящего из нескольких букв
Нет.Это потому, что вы изменили грамматику.
Если вы измените грамматику обратно на исходную кодировку (кроме более длинных letter:sym<...>
с), она работает нормально:
grammar Foo {
token TOP { <letter>+ }
proto token letter {*}
token letter:sym<come> { <sym> }
token letter:sym<bebe> { <sym> }
token letter:sym<JJ> { . }
}.parse(
"come bebe ama",
actions => class { method TOP($/) { make $<letter>.grep(*.<sym>).join } })
.made.say; # OUTPUT: «comebebe»
Обратите внимание, что вИсходно, токен letter:sym<JJ>
ждет своего часа, чтобы соответствовать любому отдельному символу - и он включает в себя один пробел, поэтому он соответствует тем, с которыми они имеют дело.
Но в вашей модификации вы добавили требуется пробел между токенами в TOP
токене.Это имело два эффекта:
Это соответствовало пробелу после "come" и после "bebe";
После того, как "a" было сопоставленона letter:sym<JJ>
отсутствие пробела между "a" и "m" означало, что общее совпадение в этой точке не удалось.
sym
, само по себе,работает с символами с более чем одним символом
Да.Все, что token foo:sym<bar> { ... }
делает, это добавляет:
Многократная альтернатива foo
;
Токен sym
, лексически ограниченный длятело токена foo
, которое соответствует 'bar'
.
как мы можем определить токен sym
по умолчанию, который соответствует набору символов?
Вы можете написать такой sym
токен, но, для ясности, потому что вы не хотите, чтобы он соответствовал фиксированной строке, он не может использовать <sym>
в теле (потому что <sym>
должна быть фиксированной строкой.) Если вы все еще хотите захватить под ключом sym
, тогда вы можете написать $<sym>=
в теле токена, как Хокон показал в комментарии под своим ответом.Но это также может быть letter:whatever
с $<sym>=
в теле.
Я запишу его как letter:default
токен, чтобы подчеркнуть, что значение :sym<something>
не имеет никакого значения.(Как объяснено выше, :sym<something>
является альтернативой, наряду с другими :baz<...>
s и :bar<...>
s, с единственным добавлением, что если это :sym<something>
, то это также делает доступным подправило <sym>
в теле связанного правила, которое, если оно используется, соответствует фиксированной строке 'something'
.)
Победная отправка среди всех альтернатив rule foo:bar:baz:qux<...>
выбирается в соответствии с логика LTM среди правил, начинающихся с foo
.Таким образом, вам нужно написать такой токен, который не выигрывает как самый длинный префикс токена, но совпадает только в том случае, если ничего не совпадает.
Чтобы немедленно перейти к задней части пакета в гонке LTMвставьте {}
в начало тела правила 2 :
token letter:default { {} \w+ }
Теперь, из задней части пакета, если это правило получит шанс, оно будет соответствоватьшаблон \w+
, который останавливает токен при попадании в несловесный символ.
Немного о том, чтобы оно совпадало с , если ничего не совпадает с , может означать, что оно будет последним.Итак:
grammar Foo {
token TOP { <letter>+ % ' ' }
proto token letter {*}
token letter:sym<come> { <sym> } # matches come
token letter:sym<bebe> { <sym> } # matches bebe
token letter:boo { {} \w**6 } # match 6 char string except eg comedy
token letter:default { {} \w+ } # matches any other word
}.parse(
"come bebe amap",
actions => class { method TOP($/) { make $<letter>.grep(*.<sym>).join } })
.made.say; # OUTPUT: «comebebe»
это просто не может быть причиной, вызывающей это ... "давай-бе-ама" не должно работать в твоей грамматике
Кодбыли ошибки, которые я сейчас исправил и извиняюсь за.Если вы запустите его, вы обнаружите, что он работает как рекламируется.
Но ваш комментарий подтолкнул меня к расширению моего ответа.Надеюсь, теперь он правильно отвечает на ваш вопрос.
Сноска
1 Не то, чтобы что-либо из этого имело какое-либо отношение к тому, что на самом деле происходит, но ... В P6 a *
в «term position» (на английском языке, где существительное принадлежит, в общем языковом программировании, где значение): Whatever
, а не WhateverCode
.Даже когда *
написано с оператором, например.+*
или * + *
, а не *
являются все еще просто Whatever
с, но большинство таких комбинаций автоматически превращает одну или несколько *
содин или несколько операторов в подкласс Code
, называемый WhateverCode
.(Исключения перечислены в таблице здесь .)
2 См. Сноску 2 в мой ответ на SO "грамматике perl6, не уверен в некотором синтаксисе впример ".