问题描述
|
我坚持一个非常简单的语法。谷歌搜索和读书没有帮助。我是最近才开始使用ANTLR的,所以这可能是一个非常简单的问题。
我正在尝试使用ANTLR v3编写一个非常简单的Lexer。
grammar TestLexer;
options {
language = Java;
}
TEST_COMMENT
: \'/*\' WS? TEST WS? \'*/\'
;
ML_COMMENT
: \'/*\' ( options {greedy=false;} : .)* \'*/\' {$channel=HIDDEN;}
;
TEST : \'TEST\'
;
WS : (\' \' | \'\\t\' | \'\\n\' | \'\\r\' | \'\\f\')+ {$channel=HIDDEN;}
;
测试班:
public class TestParserInvoker {
private static void extractCommandsTokens(final String script) throws RecognitionException {
final ANTlrstringStream input = new ANTlrstringStream(script);
final Lexer lexer = new TestLexer(input);
final TokenStream tokenStream = new CommonTokenStream(lexer);
Token t;
do {
t = lexer.nextToken();
if (t != null) {
System.out.println(t);
}
} while (t == null || t.getType() != Token.EOF);
}
public static void main(final String[] args) throws RecognitionException {
final String script = \"/* TEST */\";
extractCommandsTokens(script);
}
}
因此,当测试字符串为\“ / * TEST * / \”时,词法分析器将按预期生成两个标记。一种类型为TEST_COMMENT,另一种类型为EOF。一切都好。
但是,如果测试字符串末尾包含一个额外的空格:\“ / * TEST * / \” lexer会生成三个标记:ML_COMMENT,WS和EOF。
为什么第一个令牌获取ML_COMMENT类型?我认为标记的检测方式仅取决于语法中词法分析器规则的优先级。当然,它不应该依赖于以下标记。
感谢帮助!
附言我可以使用lexer选项filter = true-令牌将获得正确的类型,但是这种方法需要在令牌定义中进行额外的工作。老实说,我不想使用这种词法分析器。
解决方法
ANTLR从最高规则开始向下标记字符流,并尝试尽可能地匹配。因此,是的,我也希望为
\"/* TEST */\"
和\"/* TEST */ \"
创建一个TEST_COMMENT
。您始终可以查看词法分析器的生成源代码,以了解为什么它选择为第二个输入创建一个“ 5”。
无论是错误还是预期的行为,我都不会使用看起来很像的单独词法分析器规则。您能在这里解释您真正要解决的问题吗?
user776872写道:
我可以使用lexer选项filter = true-令牌将获得正确的类型,但是这种方法需要在令牌定义中进行额外的工作。老实说,我不想使用这种词法分析器。
我不太明白这句话。您只对输入源的一部分感兴趣吗?在这种情况下,filter=true
无疑是一个不错的选择。如果要标记所有输入源,则不应使用filter=true
。
编辑
如果要区分多行注释和Javadoc注释,最好将它们保持在同一规则中,并以the8开头的令牌类型进行更改,如下所示:
grammar T;
// options
tokens {
DOC_COMMENT;
}
// rules
COMMENT
: \'/*\' (~\'*\' .*)? \'*/\'
| \'/**\' ~\'/\' .* \'*/\' {$type=DOC_COMMENT;}
;
请注意,在ANTLR中,默认情况下,.*
和.+
都是非贪婪的(与流行的看法相反)。
演示版
grammar T;
tokens {
DOC_COMMENT;
}
@parser::members {
public static void main(String[] args) throws Exception {
TLexer lexer = new TLexer(new ANTLRStringStream(\"/**/ /*foo*/ /**bar*/\"));
TParser parser = new TParser(new CommonTokenStream(lexer));
parser.parse();
}
}
parse
: (t=. {System.out.println(tokenNames[$t.type] + \" :: \" + $t.text);})* EOF
;
COMMENT
: \'/*\' (~\'*\' .*)? \'*/\'
| \'/**\' ~\'/\' .* \'*/\' {$type=DOC_COMMENT;}
;
SPACE
: \' \' {$channel=HIDDEN;}
;
产生:
bart @ hades:〜/编程/ ANTLR / Demos / T $ java -cp antlr-3.3.jar org.antlr.Tool T.g
bart @ hades:〜/编程/ ANTLR / Demos / T $ javac -cp antlr-3.3.jar * .java
bart @ hades:〜/编程/ ANTLR / Demos / T $ java -cp。:antlr-3.3.jar TParser
评论:: / ** /
评论:: / * foo * /
DOC_COMMENT :: / ** bar * /