perl6, не уверен в некотором синтаксисе в примере - программирование
Подтвердить что ты не робот

perl6, не уверен в некотором синтаксисе в примере

Я все еще изучаю perl6, и я читаю пример по грамматике с этой страницы: http://examples.perl6.org/categories/parsers/SimpleStrings.html; Я читал документацию по регулярному выражению несколько раз, но есть еще некоторый синтаксис, который я не понимаю; Может ли кто-нибудь просветить меня? Большое спасибо !!!

token string { <quote> {} <quotebody($<quote>)> $<quote> }

Вопрос 1: что это такое? {} "В токене? Маркеры захвата <()>, а структуры вложенности - tilda '(' ~ ')'; но что такое {}?

token quotebody($quote) { ( <escaped($quote)> | <!before $quote> . )* }

Вопрос 2a: escaped ($ quote) внутри <> будет регулярной функцией, правильно? И он принимает $ quote в качестве аргумента и возвращает другое регулярное выражение?

Вопрос 2b: Если я хочу указать "char, который не до цитирования", следует использовать ". <! Before $ quote>" вместо "<! Before $ quote>". ??

token escaped($quote) { '\\' ( $quote | '\\' ) } # I think this is a function;

Большое спасибо !!!

lisprog

4b9b3361

Ответ 1

TL; DR @briandfoy предоставил легко усвоенный ответ. Но вот драконы, о которых он не упоминал. И симпатичные бабочки тоже. Этот ответ идет глубоко.

Вопрос 1: что это {} в токене?

Это кодовый блок 1,2,3,4.

Он пуст и был вставлен просто для того, чтобы заставить $<quote> в quotebody($<quote>) оценить значение, полученное с помощью <quote> в начале регулярного выражения.

Причина, по которой $<quote> не содержит правильного значения без вставки кодового блока, является ограничением компилятора Rakudo Perl 6 или ошибкой, связанной с "публикацией переменных соответствия".

"Публикация" переменных соответствия Rakudo

Мориц Ленц заявляет в сообщении об ошибке Rakudo, что "механизм регулярных выражений не публикует переменные соответствия, если это не считается необходимым".

Под "regex engine" он подразумевает механизм регулярного выражения/грамматики в NQP, часть компилятора Rakudo Perl 6. 3

Под "переменными соответствия" он означает переменные, которые хранят результаты совпадений:

  • текущая переменная соответствия $/;

  • нумерованные переменные подзаголовка $0, $1 и т. д.;

  • именованные переменные совпадения формы $<foo>.

Под "публикацией" он означает, что механизм регулярных выражений/грамматик делает все, что требуется, чтобы любые упоминания любых переменных в регулярном выражении (токен также является регулярным выражением) оценивали значения, которые они должны иметь, когда они должны имейте их. В данном регулярном выражении, спичечные переменные должны содержать Match объект, соответствующий тому, что был захвачен в плен для них на любом данном этапе при обработке этого регулярного выражения, или Nil, если ничего не было захвачено.

Под "считающимся необходимым" он означает, что механизм регулярных выражений/грамматик делает консервативный вызов о том, стоит ли делать публикацию после каждого шага в процессе сопоставления. Под "консервативным" я подразумеваю, что двигатель часто избегает публикации, потому что он замедляет работу и обычно не нужен. К сожалению, это иногда слишком оптимистично, когда публикация действительно необходима. Следовательно, необходимо, чтобы программисты иногда вмешивались, явно вставляя блок кода, чтобы принудительно опубликовать сопоставимые переменные (и другие методы для других переменных 5). Возможно, что с этой точки зрения система регулярного выражения/грамматики будет улучшаться в этом отношении, сокращая сценарии, в которых требуется ручное вмешательство. Если вы хотите помочь в прогрессе, создайте тестовые примеры, которые вам важны для существующих связанных ошибок. 5

"Публикация" значения $<quote>

Здесь приведен пример названного захвата $<quote>.

Насколько я могу судить, все переменные совпадения правильно ссылаются на их захваченное значение, когда они записываются непосредственно в регулярное выражение без окружающей конструкции. Это работает:

my regex quote { <['"]> }
say so '"aa"' ~~ / <quote> aa $<quote> /; # True

Я думаю, что 6$<quote> получает правильное значение, потому что оно анализируется как конструкция с регулярным выражением. 4

Напротив, если {} были удалены из

token string { <quote> {} <quotebody($<quote>)> $<quote> }

то $<quote> в quotebody($<quote>) не будет содержать значения, снятые при открытии <quote>.

Я думаю, это потому, что $<quote> в этом случае анализируется как главная конструкция сленга.

Вопрос 2a: escaped($quote) внутри <> будет регулярной функцией, правильно? И в качестве аргумента требуется $quote

Это хорошее первое приближение.

Более конкретно, атомы регулярных выражений вида <foo(...)> являются вызовами метода foo.

Все регулярные выражения - объявленные с помощью token, regex, rule, /.../ или любая другая форма - являются методами. Но методы, объявленные с помощью method, не являются регулярными выражениями:

say Method ~~ Regex; # False
say WHAT token { . } # (Regex)
say Regex ~~ Method; # True
say / . / ~~ Method; # True

Когда <escaped($quote)> атом регулярного выражения встречается, регулярное выражение/грамматика двигатель не знает или не заботится, если escaped регулярное выражение или нет, ни о деталях методы отправки внутри регулярного выражения или грамматиков. Он просто вызывает отправку метода, при этом объект invocant установлен в объект Match который создается встроенным регулярным выражением.

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

и возвращает другое регулярное выражение

Нет, атом регулярных выражений формы <escaped($quote)> не возвращает другое регулярное выражение.

Вместо этого он вызывает метод, который должен/должен возвращать объект Match.

Если вызванный метод был регулярным выражением, P6 будет гарантировать, что регулярное выражение генерирует и автоматически заполняет объект Match.

Если вызванный метод не был регулярным выражением, а вместо этого просто обычным методом, тогда код метода должен был создать вручную и возвратил объект Match. Мориц показывает пример в своем ответе на вопрос SO. Могу ли я изменить сленг Perl 6 внутри метода? ,

Объект Match возвращается в "механизм регулярных выражений/грамматик", который управляет регулярным выражением регулярных выражений/грамматики. 3

Затем двигатель решает, что делать дальше в соответствии с результатом:

  • Если совпадение было успешным, движок обновляет общий объект соответствия, соответствующий вызывающему регулярному выражению. Обновление может включать сохранение возвращаемого объекта Match в качестве подсумного захвата вызывающего регулярного выражения. Так создается дерево совпадений/синтаксиса.

  • Если матч не увенчался успехом, двигатель может отступить, отменив предыдущие обновления; таким образом дерево синтаксического анализа может динамически расти и сокращаться по мере совпадения.

Вопрос 2b: Если я хочу указать "char, который не до цитирования", следует использовать . <!before $quote> . <!before $quote> вместо <!before $quote>. ??

Да.

Но это не то, что необходимо для регулярного выражения quotebody, если это то, о чем вы говорите.

В то время как на последней теме, в ответе @briandfoy, он предлагает использовать конструкцию "Матч... ничего, что не цитата", а не делать негативный взгляд вперед (<!before $quote>). Его точка зрения заключается в том, что совпадение "не цитата" гораздо легче понять, чем "не мы ли перед цитатой, а затем сопоставляем любой символ".

Тем не менее, отнюдь не прямолинейно это делать, когда котировка представляет собой переменную, значение которой задано для захвата вводной цитаты. Эта сложность связана с ошибками в Rakudo. Я разработал то, что, по моему мнению, является самым простым способом, но думаю, что лучше всего просто придерживаться использования <!before $quote>. если/до тех пор, пока эти давние ошибки Rakudo не будут исправлены. 5

token escaped($quote) { '\\' ( $quote | '\\' ) } # я think this is a function;

Это токен, который является Regex, которое является Method, который является Routine:

say token { . } ~~ Regex;   # True
say Regex       ~~ Method;  # True
say Method      ~~ Routine; # True

Код внутри тела (бит {... }) регулярного выражения (в этом случае код является одиноким . В token {. }, Который является атомом регулярного выражения, который соответствует одному символу) записывается в регулярное выражение P6 "сленг", тогда как код, используемый внутри тела method записывается в основной "сленг" P6. 4

Используя ~

Оператор regex tilde (~) специально разработан для такого синтаксического анализа в примере, о котором идет речь. Он читается лучше, поскольку он мгновенно распознается и сохраняет открывающиеся и закрывающие кавычки вместе. Гораздо важнее то, что в случае сбоя может появиться человеческое понятное сообщение об ошибке, поскольку оно может сказать, какие закрывающие разделители (-ы) они ищут.

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

token foo { <quote> ~ $<quote> {} <quotebody($<quote>) }

будет соответствовать паре <quote> между которыми нет ничего. (И затем попытайтесь сопоставить <quotebody...>.)

Напротив, здесь можно дублировать поведение сопоставления символа string в грамматике String::Simple::Grammar:

token string { <quote> ~ $<quote> [ {} <quotebody($<quote>) ] }

Сноски

1 В 2002 году Ларри Уолл написал: "Для регулярного выражения должно быть так же просто вызвать код Perl, как и код Perl для вызова регулярного выражения". , Ученые-компьютерщики отмечают, что вы не можете иметь процедурный код в середине традиционного регулярного выражения. Но Perls давно привел переход к нетрадиционным регулярным выражениям, а P6 пришел к логическому завершению - простой {...} - это все, что требуется для вставки произвольного процедурного кода в середине регулярного выражения. Конструкция языка и реализация механизма регулярного выражения/грамматики 3 гарантируют, что традиционные декларативные регионы традиционного стиля в пределах регулярного выражения распознаются, так что формальная теория и оптимизация регулярных выражений могут быть применены к ним, но, тем не менее, может быть вставлен произвольный регулярный процедурный код. Простое использование включает в себя логику соответствия и отладку. Но небо - предел.

2 Первый процедурный элемент регулярного выражения, если таковой имеется, завершает то, что называется "декларативным префиксом" регулярного выражения. Общей причиной вставки пустого кодового блока ({}) является намеренное завершение декларативного префикса регулярного выражения, когда он предоставляет требуемую семантику соответствия для заданного наиболее длительного чередования в регулярном выражении. (Но это не причина его включения в токен, который вы пытаетесь понять.)

3 Говоря свободно, механизм регулярных выражений/грамматики в NQP соответствует P6, что PCRE относится к P5.

Ключевым отличием является то, что язык регулярных выражений, а также связанный с ним механизм регулярных выражений/грамматик и основной язык, с которым он сотрудничает, который в случае Rakudo является Perl 6, совмещены с контролем. Это реализация Larry Wall оригинального видения 2002 года для интеграции между регулярными выражениями и "богатыми языками". Каждый язык/время выполнения может звонить другому и общаться через FFI высокого уровня. Таким образом, они могут казаться, могут вести себя как и в самом деле как единую систему взаимодействующих языков и сотрудничать с временем выполнения.

(Конструкция Р6 такова, что все языки могут быть явно предназначены, или быть ретро установлено, к сотрудничеству в "богатом" способе, с помощью двух взаимодополняющих P6 FFIs: метамодели FFI 6model и/или С соглашением о вызовах FFI NativeCall.)

4 Язык P6 на самом деле представляет собой сборник подязыков - aka slangs -, которые используются вместе. Когда вы читаете или пишете код P6, вы читаете или пишете исходный код, который начинается в одном сленге, но имеет разделы, написанные в других. Первая строка в файле использует главный сленг. Скажем, это аналогично английскому. Режимы написаны в другом сленге; скажем так, как испанский. Таким образом, в случае грамматики String::Simple::Grammar код начинается на английском языке (инструкция use v6;), а затем возвращается на испанский язык (после { rule TOP {), то есть ^ <string> $ бит, а затем возвращается обратно на английский (комментарий начинается с # Note...). Затем он возвращается на испанский язык для <quote> {} <quotebody($<quote>)> $<quote> и посередине этого испанского, в {} codeblock, он снова переводится на другой уровень английского языка. Так что английский на испанском языке по-английски. Конечно, блок кода пуст, поэтому ему нравится писать/читать ничего на английском языке, а затем сразу отбрасывать обратно на испанский язык, но важно понять, что эта рекурсивная укладка языков/времени выполнения - это то, как работает P6, как одиночный общий язык/время выполнения и при взаимодействии с другими языками/версиями не-P6.

5 Я столкнулся с несколькими ошибками, перечисленными в конце этой сноски, в процессе применения двух потенциальных улучшений. (Как упоминалось в briandfoy ответ и этот.) Два "улучшения" являются использование из ~ построить, и "не цитата" построить вместо использования <!before foo>. , Конечный результат, плюс упоминание соответствующих ошибок:

grammar String::Simple::Grammar {
  rule TOP {^ <string> $}
  token string {
    :my $*not-quote;
    <quote> ~ $<quote>
    [
      { $*not-quote = "<-[$<quote>]>" }
      <quotebody($<quote>)>
    ]
  }
  token quote { '"' | "'" }
  token quotebody($quote) { ( <escaped($quote)> | <$*not-quote> )* }
  token escaped($quote) { '\\' ( $quote | '\\' ) }
}

Если кто-нибудь знает более простой способ сделать это, я хотел бы услышать об этом в комментарии ниже.

Я закончил поиск базы данных ошибок RT для всех ошибок регулярных выражений. Я знаю, что SO не является базой ошибок, но я считаю разумным отметить следующие. Aiui первые два непосредственно взаимодействуют с проблемой публикации переменных соответствия.

6 Этот вопрос и мой ответ подтолкнули меня к внешним пределам моего понимания амбициозного и сложного аспекта Р6. Я планирую в скором времени получить более полное представление о точных взаимодействиях между nqp и полным P6, а также о взаимосвязи между их сленгами регулярных выражений и главными сленгами, как описано в сносках выше. (Мои надежды в настоящее время в основном опираются на то, что они просто купили запятую.) Я обновлю этот ответ, если/когда у меня появятся некоторые результаты.

Ответ 2

{} - пустой блок кода. Это процедурный (а не декларативный) элемент грамматики. Вы можете разместить обычный код Perl 6, чтобы он что-то делал.

В этом шаблоне он выполняет другую работу. Он предоставляет точку последовательности, в которой движок грамматики знает, что ему нужно делать разные вещи для продолжения. Это включает в себя заполнение значений для переменных захвата (например, $<quote>). Следующая часть шаблона должна гарантировать, что $<quote> имеет свое значение, поэтому ему нужно что-то, чтобы обеспечить доступность значения.

$<quote> на самом деле является единственным элементом доступа к объекту Match $/. Как хэш-подобная вещь, это действительно $/<quote> где вещь между угловыми скобками - это "ключ". Perl 6 любит быть немного умным, поэтому он позволяет вам оставить / чтобы получить $<quote>. Другие аналогичные переменные, такие как $1 являются ярлыками.

Для вашего последнего вопроса это поможет увидеть некоторые образцы данных, которые вы пытаетесь сопоставить. Perl 6 Grammars имеет множество функций для соответствия сбалансированному тексту, что, вероятно, делает задачу тривиальной. См., Например, Тильда для вложенных структур в документации Regexp:

 / '(' ~ ')' <expression> /

Вот краткий пример в REPL. Там строка, в которой есть какой-то цитируемый текст:

$ perl6
To exit type 'exit' or '^D'
> my $s = Q/abcdf "Hello" xyz/
abcdf "Hello" xyz

~ В регулярном выражении находится между разделителями. Вещь, которая приходит после конечного разделителя, - это то, что вы ожидаете от того, где находится ~:

> $s ~~ m/ '"' ~ '"' .+ /
「"Hello"」

Вы могли бы сопоставить открывающую вещь и захватить ее (теперь она в $0), чтобы вы могли использовать ту же самую вещь, что и разделитель закрытия:

> $s ~~ m/ (<["']>) ~ $0 .+ /
「"Hello"」
 0 => 「"」

В этом конкретном примере я думаю, что есть более простой способ. Сопоставьте бегущую цитату или что-нибудь, что не цитата, а не взгляд вокруг и любой символ. Это не совсем так, как изгиб ума.