我正在Marpa中实现一个新的DSL(来自
Regexp :: Grammars)我非常满意.我的语言支持一堆一元和二元运算符,带有C风格标识符的对象和使用熟悉的点符号的方法调用.例如:
foo.has(bar == 42 AND baz == 23)
我发现了Marpa的语法描述语言提供的prioritized rules功能,并且已经开始依赖于它,所以我几乎只有一个G1规则表达式.摘录(为简洁省略了许多替代方案和语义操作):
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中是否有办法仅将标识符规则限制为非关键字标识符?
解决方法
我不知道如何在语法中表达这样的东西.您可以为标识符引入一个中间非终端,它将检查条件,但是:
#!/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 }
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。