2013-09-08 5 views
1

Я пытаюсь настроить грамматику, которая требует, чтобы символы [\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 нет разрыва, что я и хочу. Единственная муха в мазе состоит в том, что на STDERR есть раздражающее сообщение Inaccessible symbol: word, потому что лексема word не используется в фактической грамматике.

Я вижу, что в Marpa::R2::Grammar я мог бы объявлен word как inaccessible_ok в опции конструктора, но я не могу сделать это в Marpa::R2::Scanless.

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

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

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

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

+0

В P :: RD я бы сделал '/ \ w +/{$ item [0] eq 'keyword'}'. Там также '/ 9 \ b /' – ikegami

ответ

4

Ну, очевидное решение - потребовать пробелов между ними (на уровне 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-подобных языков, где традиционно нет пробелов.
+0

Да, требуя пробела между ними, очевидно, и все же я не думал об этом! Интересно, будет ли это распространяться на общий случай в большей грамматике. –