Marpa:我可以明确禁止将关键字作为标识符吗?

时间:2014-11-24 16:47:51

标签: perl parsing marpa

我在Marpa实施了一个新的DSL(来自Regexp :: Grammars),我感到非常满意。我的语言支持一堆一元和二元运算符,带有C风格标识符的对象和使用熟悉的点符号的方法调用。例如:

foo.has(bar == 42 AND baz == 23)

我找到了Marpa的语法描述语言提供的prioritized rules功能,并且已经开始依赖它了,所以我几乎只有一个G1规则Expression。摘录(许多替代方案,为简洁省略了语义操作):

Expression ::=
      NumLiteral
    | '(' Expression ')'             assoc => group
   || Expression ('.') Identifier
   || Expression ('.') Identifier Args
    | Expression ('==') Expression
   || Expression ('AND') Expression

Args     ::= ('(') ArgsList (')')
ArgsList ::= Expression+             separator => [,]

Identifier         ~ IdentifierHeadChar IdentifierBody
IdentifierBody     ~ IdentifierBodyChar*
IdentifierHeadChar ~ [a-zA-Z_]
IdentifierBodyChar ~ [a-zA-Z0-9_]

NumLiteral ~ [0-9]+

如您所见,我使用的是Scanless界面(SLIF)。我的问题是,这也解析,例如:

foo.AND(5)

Marpa知道点后面只能有一个标识符,因此它甚至不会考虑AND可能是关键字的事实。我知道我可以通过单独的lexing阶段来明确地将AND标识为关键字来避免这个问题,但是那个小小的剪纸并不值得付出努力。

SLIF中是否有办法仅将Identifier规则限制为非关键字标识符?

2 个答案:

答案 0 :(得分:2)

我不知道如何在语法中表达这样的东西。您可以为标识符引入一个中间非终端,它将检查条件,但是:

#!/usr/bin/perl
use warnings;
use strict;
use Syntax::Construct qw{ // };

use Marpa::R2;

my %reserved = map { $_ => 1 } qw( AND );

my $grammar = 'Marpa::R2::Scanless::G'->new(
    { bless_package => 'main',
      source => \( << '__GRAMMAR__'),

:default ::= action => store

:start ::= S
S ::= Id
  | Id NumLiteral
Id ::= Identifier action => allowed

Identifier         ~ IdentifierHeadChar IdentifierBody
IdentifierBody     ~ IdentifierBodyChar*
IdentifierHeadChar ~ [a-zA-Z_]
IdentifierBodyChar ~ [a-zA-Z0-9_]

NumLiteral ~ [0-9]+

:discard ~ whitespace
whitespace ~ [\s]+

__GRAMMAR__
    });

for my $value ('ABC', 'ABC 42', 'AND 1') {
    my $value = $grammar->parse(\$value, 'main');
    print $$value, "\n";
}


sub store {
    my (undef, $id, $arg) = @_;
    $arg //= 'null';
    return "$id $arg";
}

sub allowed {
    my (undef, $id) = @_;
    die "Reserved keyword $id" if $reserved{$id};
    return $id
}

答案 1 :(得分:2)

你可以使用专门用于此类事情的lexeme优先级,例如在Marpa :: R2测试套件中here

基本上,你声明<AND keyword> ~ 'AND' lexeme并给它优先级1,以便它优先于Identifier。这必须做到这一点。

P.S。我稍微修改了上面的脚本以举例 - codeoutput