我对antlr3语法中的空格处理有疑问。这是语法的精简版本:
grammar SLiMScript;
inputFile :
NEWLINE*
sectionOutput?
;
sectionOutput : '#OUTPUT' NEWLINE+ outputLine+ ;
outputLine : (output_all) NEWLINE+ ;
output_all : NUMBER 'A' STRING? ;
NEWLINE : ('\r'? '\n') ;
NUMBER : ('0' | (DIGIT_1 DIGIT_0*)) ('.' DIGIT_0*)? EXPONENT? ;
fragment EXPONENT : ('e'|'E') ('+'|'-')? DIGIT_0+ ;
fragment DIGIT_0 : '0'..'9' ;
fragment DIGIT_1 : '1'..'9' ;
STRING : '"' (~('"'|'\n'|'\r'|'\\'))* '"' ;
WS : ( ' ' | '\t' ) { skip(); } ;
这是一个简单的输入文件:
#OUTPUT
1000 A "foo bar baz"
一般来说,我希望空白被剥离;因此,语法结束时的空白规则。但是,我确实需要在令牌之间需要空格。例如,如果查看输出文件,我不希望1000A"foo"
合法;我想要令牌之间的空格。但是,必须明确指出语法中的任何地方都会非常痛苦。而我也不能吃蛋糕而且也吃它。如果我保留我的空白剥离规则,那么我就不能将我的陈述规则改为:
output_all : NUMBER WS 'A' (WS STRING)? ;
因为空格标记已经被剥离了;没有空格可供规则匹配。也许我别无选择,除了去除隐式空格剥离,而是在整个语法中的每一对标记之间放置WS
引用,以获得我想要的行为。但肯定有更好的方法......?
像C这样的语言是如何做到的?你可以写static int foo
但不能写staticintfoo
;为什么不?这些语言的语法如何强制这样的标记之间的空白?我猜它是因为staticintfoo
被标记为标识符,大概是因为该规则是第一个;该字符串也会匹配令牌static
,int
和(标识符)foo
,但在此之前,它们会被作为单个大标识符吞噬,这会导致错误因为没有定义该标识符。有没有办法在我的情况下做类似的事情?通过使无空白版本导致另一种导致错误的解释,隐式地要求令牌之间的空格?我并没有真正看到这样做的优雅方式。
我已经阅读了Parr的书籍语言实现模式和最终的ANTLR参考,我认为我或多或少地理解它们,但我觉得我缺乏对如何为各种具体设计实际语法的良好回顾应用情况。某种书如The Art of LL(*)Grammar Design。那里有这样的书吗?
答案 0 :(得分:1)
没有更好的方法。你想要的空格是否被剥离。你不能同时弄湿并保持干爽。
如果你真的想在(某些)令牌之间强制执行空格,那么你必须在任何地方接受WS,没有办法解决这个问题。虽然,我怀疑你的意图。通常它可以很好地简单地忽略空格,除了一些奇怪定义的语言,如Python或FORTRAN,其中缩进是语言的一部分。
作为一种解决方法,并且只有当您想要避免的特定情况(例如1000A
)时,您才能定义一个特定于此输入匹配的词法规则,并让它返回一个无效的令牌,在解析器中导致语法错误。