Ste*_*sky 6 perl parsing marpa
我正在Marpa中实现一个新的DSL(来自Regexp :: Grammars)我非常满意.我的语言支持一堆一元和二元运算符,带有C风格标识符的对象和使用熟悉的点符号的方法调用.例如:
foo.has(bar == 42 AND baz == 23)
我发现了Marpa的语法描述语言提供的优先规则功能,并且已经开始依赖于它,所以我几乎只有一条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]+
Run Code Online (Sandbox Code Playgroud)
如您所见,我正在使用Scanless界面(SLIF).我的问题是,这也解析,例如:
foo.AND(5)
Run Code Online (Sandbox Code Playgroud)
Marpa知道点后面只能有一个标识符,因此它甚至不考虑AND
可能是关键字的事实.我知道我可以通过一个AND
明确标识为关键字的单独的lexing阶段来避免这个问题,但这个小小的剪切不值得努力.
SLIF中是否有办法仅将Identifier
规则限制为非关键字标识符?
我不知道如何用语法来表达这样的事情。不过,您可以为标识符引入一个中间非终结符来检查条件:
#!/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
}
Run Code Online (Sandbox Code Playgroud)