我坚持使用非常简单的语法。谷歌搜索和书籍阅读没有帮助。我最近开始使用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类型?我认为检测到令牌的方式仅取决于语法中词法分析器规则的优先级。当然,它不应该依赖于跟踪令牌。
感谢您的帮助!
P.S。我可以使用词法分析器选项filter = true - 令牌将获得正确的类型,但这种方法需要在令牌定义中进行额外的工作。说实话,我不想使用这种类型的词法分析器。
答案 0 :(得分:1)
ANTLR将字符流从顶部规则向下标记为,尝试尽可能匹配。所以,是的,我也希望为TEST_COMMENT
和"/* TEST */"
创建"/* TEST */ "
。您可以随时查看生成的词法分析器的源代码,以了解为何选择为第二个输入创建ML_COMMENT
。
无论这是一个错误还是预期的行为,我都不会使用看起来像这样的单独的词法分析器规则。你能解释一下你在这里要解决的问题吗?
user776872写道:
我可以使用词法分析器选项filter = true - 令牌将获得正确的类型,但这种方法需要在令牌定义中进行额外的工作。说实话,我不想使用这种类型的词法分析器。
我不太明白这句话。您是否只对输入源的一部分感兴趣?在这种情况下,filter=true
肯定是一个不错的选择。如果要对所有输入源进行标记,则不应使用filter=true
。
如果要区分多行注释和Javadoc注释,最好将它们保存在同一规则中,如果它以/**
开头,则更改令牌的类型:
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:~/Programming/ANTLR/Demos/T$ java -cp antlr-3.3.jar org.antlr.Tool T.g bart@hades:~/Programming/ANTLR/Demos/T$ javac -cp antlr-3.3.jar *.java bart@hades:~/Programming/ANTLR/Demos/T$ java -cp .:antlr-3.3.jar TParser COMMENT :: /**/ COMMENT :: /*foo*/ DOC_COMMENT :: /**bar*/