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');

这样解析成功。现在我想更改语法以强制分隔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这正是我想要发生的。唯一美中不足的是,Inaccessible symbol: wordSTDERR 上有一条烦人的消息,因为word在实际语法中没有使用词位。

我看到Marpa::R2::Grammar我可以在构造函数选项中声明wordinaccessible_ok但我不能在Marpa::R2::Scanless.

我也可以做类似以下的事情:

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

然后使用 apause使用自定义代码检查实际的词位值并根据值返回适当的词位。

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

4

1 回答 1

4

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

:default ::= action => ::array

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

Ws ::= [\s]+

:discard ~ whitespace
whitespace ~ [\s]+

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

  • 当它们都是最长的标记时,词位既可以被丢弃也可以被要求。这就是为什么:discardandWs规则不会相互干扰的原因。玛尔巴不介意这种“模棱两可”。
  • Ws规则包含在括号中,它会丢弃该值 - 以保持生成的解析树干净。
  • 您通常不希望使用幻象词位之类的技巧来误导解析器。那就是破损。
  • 当每一位空格都很重要时,您可能想要摆脱:discard ~ whitespace. 这意味着例如用于空格传统上无关紧要的类 C 语言。
于 2013-09-08T23:35:35.453 回答