强迫Marpa语法中的单词之间存在差距

时间:2013-09-08 23:21:03

标签: perl parsing marpa

我正在尝试设置一个语法,要求[\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');

这成功解析。现在我想更改语法以强制9september之间的分隔。我想通过引入一个与[\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.

也就是说,由于9september之间没有差距,这个解析失败了,这正是我想要发生的事情。美中不足的是,STDERR上有一条恼人的Inaccessible symbol: word消息,因为实际语法中没有使用word lexeme。

我在Marpa::R2::Grammar中看到,我可以在构造函数选项中将word声明为inaccessible_ok,但我无法在Marpa::R2::Scanless中执行此操作。

我也可以做以下事情:

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

然后使用pause来使用自定义代码来检查实际的lexeme值并根据值返回相应的lexeme。

构建使用关键字或数字和单词的语法的最佳方法是什么,但是不允许相邻的词汇一起运行而没有空格或标点分隔它们?

1 个答案:

答案 0 :(得分:4)

嗯,显而易见的解决方案是在两者之间需要一些空白(在G1级别)。当我们使用以下语法时

:default ::= action => ::array

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

Ws ::= [\s]+

:discard ~ whitespace
whitespace ~ [\s]+

然后9september失败,但解析了9 september。需要注意的重点:

  • Lexemes既可以被丢弃也可以被要求,当它们都是最长的令牌时。这就是:discardWs规则不会相互干扰的原因。马尔巴并不介意这种“含糊不清”。
  • Ws规则包含在parens中,丢弃值 - 以保持生成的解析树清洁。
  • 您通常不想使用幻像词汇等技巧来误导解析器。那种方式就是破产。
  • 当空白的每一点都很重要时,你可能想摆脱:discard ~ whitespace。这意味着要用于例如对于类似C语言而言,传统上空白无关紧要。