强制马尔帕语法中的单词之间的间隙



我正在尝试设置一种语法,要求如果[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词法。

我看到Marpa::R2::Grammar我可以在构造函数选项中将word声明为 inaccessible_ok,但我不能在 Marpa::R2::Scanless 中这样做。

我也可以做如下的事情:

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

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

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

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

:default ::= action => ::array
:start ::= Rule
Rule ::= '9' (Ws) 'september'
Ws ::= [s]+
:discard ~ whitespace
whitespace ~ [s]+

然后9september失败,但9 september被解析。注意事项:

  • 词素既可以丢弃,也可以是必需的,当它们都是最长的标记时。这就是为什么:discardWs规则不会相互干扰的原因。玛尔巴并不介意这种"暧昧"。
  • Ws规则包含在 paren 中,这会丢弃该值,以保持生成的解析树干净。
  • 您通常不希望使用像幻像词素这样的技巧来误导解析器。那条路就是破损。
  • 当每一点空格都很重要时,您可能希望摆脱:discard ~ whitespace。例如,这意味着用于传统上空格无关紧要的类 C 语言。

相关内容

  • 没有找到相关文章

最新更新