【发布时间】:2015-03-28 01:23:34
【问题描述】:
我有一个关于 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 的书 Language Implementation Patterns 和 The Definitive ANTLR Reference ,我认为我或多或少地理解了它们,但我觉得我对如何为各种特定的实际设计实用语法缺乏一个很好的回顾应用的情况。某种书,例如 LL(*) 语法设计的艺术。有这样的书吗?
【问题讨论】:
-
C 示例的工作方式是词法分析器倾向于吃掉与标记匹配的最大可能字符串。所以
staticintfoo是一个标识符,而不是三个标记,“static”、“int”、“foo”。然后错误消息将是staticintfoo是一个未声明的标识符,而不是存在语法错误。