Форсирование пробелов между словами в грамматике Марпы

Я пытаюсь настроить грамматику, которая требует, чтобы [\w] символы не могут появляться непосредственно рядом друг с другом, если они не находятся в одной лексеме. То есть слова должны быть отделены друг от друга пробелом или пунктуацией.

Рассмотрим следующую грамматику:

use Marpa::R2; use Data::Dump;

my $grammar = Marpa::R2::Scanless::G->new({source  => \<<'END_OF_GRAMMAR'});

:start ::= Rule
Rule ::= '9' 'september'

:discard ~ whitespace
whitespace ~ [\s]+

END_OF_GRAMMAR

my $recce = Marpa::R2::Scanless::R->new({grammar => $grammar});
dd $recce->read(\'9september');

Это успешно разбирает. Теперь я хочу изменить грамматику, чтобы разделить 9 а также september, Я думал сделать это, введя неиспользованную лексему, которая соответствует [\w]+:

use Marpa::R2; use Data::Dump;

my $grammar = Marpa::R2::Scanless::G->new({source  => \<<'END_OF_GRAMMAR'});

:start ::= Rule
Rule ::= '9' 'september'

:discard ~ whitespace
whitespace ~ [\s]+

word ~ [\w]+      ### <== Add unused lexeme to match joined keywords
END_OF_GRAMMAR

my $recce = Marpa::R2::Scanless::R->new({grammar => $grammar});
dd $recce->read(\'9september');

К сожалению, эта грамматика не работает с:

A lexeme is not accessible from the start symbol: word
Marpa::R2 exception at marpa.pl line 3.

Хотя это можно решить с помощью lexeme default заявление:

use Marpa::R2; use Data::Dump;

my $grammar = Marpa::R2::Scanless::G->new({source  => \<<'END_OF_GRAMMAR'});
lexeme default = action => [value]  ### <== Fix exception by adding lexeme default statement

:start ::= Rule
Rule ::= '9' 'september'

:discard ~ whitespace
whitespace ~ [\s]+

word ~ [\w]+
END_OF_GRAMMAR

my $recce = Marpa::R2::Scanless::R->new({grammar => $grammar});
dd $recce->read(\'9september');

Это приводит к следующему выводу:

Inaccessible symbol: word
Error in SLIF parse: No lexemes accepted at line 1, column 1
* String before error: 
* The error was at line 1, column 1, and at character 0x0039 '9', ...
* here: 9september
Marpa::R2 exception at marpa.pl line 16.

То есть анализ не удался из-за того, что между 9 а также september это именно то, что я хочу, чтобы произошло. Единственная ложка дегтя в том, что есть раздражающий Inaccessible symbol: word сообщение на STDERR, потому что word лексема не используется в реальной грамматике.

Я вижу это в Marpa::R2::Grammar Я мог бы заявить word как inaccessible_ok в настройках конструктора, но я не могу сделать это в Marpa::R2::Scanless,

Я также мог бы сделать что-то вроде следующего:

Rule ::= nine september
nine ~ word
september ~ word

затем использовал pause использовать пользовательский код для проверки фактического значения лексемы и вернуть соответствующую лексему в зависимости от значения.

Каков наилучший способ построения грамматики, которая использует ключевые слова или числа и слова, но запрещает запуск смежных лексем без пробелов или знаков препинания, разделяющих их?

1 ответ

Ну, очевидное решение состоит в том, чтобы потребовать некоторый пробел между ними (на уровне G1). Когда мы используем следующую грамматику

:default ::= action => ::array

:start ::= Rule
Rule ::= '9' (Ws) 'september'

Ws ::= [\s]+

:discard ~ whitespace
whitespace ~ [\s]+

затем 9september не удается, но 9 september анализируется Важные моменты, на которые следует обратить внимание:

  • Лексемы могут быть как отброшены, так и необходимы, если они оба являются самым длинным токеном. Вот почему :discard а также Ws Правило не мешает друг другу. Марпа не возражает против такой "двусмысленности".
  • Ws Правило заключено в parens, которое отбрасывает значение - чтобы сохранить результирующее дерево разбора в чистоте.
  • Обычно вы не хотите использовать такие трюки, как призрачные лексемы, чтобы ввести парсера в заблуждение. Таким образом, лежит поломка.
  • Когда важен каждый пробел, вы можете избавиться от :discard ~ whitespace, Это предназначено для использования, например, для C-подобных языков, где пробел традиционно не имеет значения.
Другие вопросы по тегам