我问过相关问题here和here,现在我有了一个新问题,但我真的要求一些一般的思考规则。
这是语法:
grammar post2;
post2: action_cmd+
;
action_cmd
: cmd_name action_cmd_def
;
action_cmd_def
: (cmd_chars | cmd_literal)+ Semi_colon
;
cmd_name
: 'a'..'z' ('a'..'z' | '0'..'9' | '_' )*
;
cmd_chars
: ('a'..'z' | 'A'..'Z' | '0'..'9' | '_' | '.' | ':' | '-' |'\\')
;
cmd_literal
: SINGLE_QUOTE ~(SINGLE_QUOTE | '\n' | '\r') SINGLE_QUOTE
;
SINGLE_QUOTE
: '\''
;
Semi_colon
: ';'
;
WS : ('\t' | ' ')+ {$channel = HIDDEN;};
New_Line : ('\r' | '\n')+ {$channel = HIDDEN;};
我收到此错误并不奇怪 -
warning(200): post2.g:16:45:
Decision can match input such as "'_'" using multiple alternatives: 1, 2
As a result, alternative(s) 2 were disabled for that input
错误与规则“cmd_name”有关。
我相信原因是,正如Bart在另一个帖子中指出的那样,当输入“abc__”时,可以将其解析为“abc _”(cmd_name)和“_”(action_cmd_def / cmd_chars)或“abc__” “(cmd_name)。
以下是我的问题: 1)如何解决?我尝试在cmd_name前添加“options {greedy = true;}”,但错误仍然存在。
2)我知道如果我将cmd_name和action_cmd_def组合成一个,那么问题就会消失,这就会导致语法粒度问题。由于ANTLR具有如此强大的词法分析器/解析器功能,我真的很喜欢使用语法来过滤掉有意义的字符串输出,在这种情况下,我知道“action_cmd”的输入数据必须以命令名字符串开头然后跟着一些凌乱东西,所以我喜欢把语法分开来做两部分;否则我将不得不使用目标语言(在我的情况下为C)编写动作部分,但是更深入的粒度会带来很多麻烦,我怀疑我是否处于错误的轨道。
有了这个,我想问一下,从语法粒度来看,你的经验法则是什么?我疯狂地使用语法吗?
答案 0 :(得分:-1)
这是一种真正的歧义,但贪婪的选择对你有用。也许它需要处于子规则级别?看看是否有效:
cmd_name
: 'a'..'z' (options {greedy=true;} : 'a'..'z' | '0'..'9' | '_' )*
至于问题的第二部分,我认为您的规则粒度很好。如果存在歧义需要的不仅仅是要解决的贪婪标志,您还可以使用语法谓词。它在ANTLR 3书中有详细记载,但在网站上却不太好。
它等于尝试在句法上匹配谓词。如果它成功,那么它匹配它是真的,如果它失败然后它使用其他选择。例如,在C中你不知道你是否有一个函数声明或定义,直到你看到声明的结尾,它的长度没有下限。所以你使用一个句法谓词说“让我们看看它是否是一个声明,如果是,那么将它与真实匹配,如果不是,那么尝试其他选择。”
externalDef
: ( "typedef" | declaration )=> declaration
| functionDef
| asm_expr
;