AFAIK,这是不可能的。但是,您可以扩展以在解析期间UnbufferedTokenStream
更改。channel
您不能使用,CommonTokenStream
因为它缓冲了可变数量的令牌(并且缓冲区中可能有位于错误通道上的令牌!)。请注意,您至少需要 ANTLR 3.3:在以前的版本UnbufferedTokenStream
中尚未包含。
假设您要解析(并显示)小写或大写字母。大写字母放在HIDDEN
通道上,因此默认情况下,只会解析小写字母。但是,当解析器偶然发现小写时"q"
,我们想更改为HIDDEN
通道。HIDDEN
一旦在频道上解析,我们希望"Q"
将我们带回到另一端DEFAULT_CHANNEL
。
所以在解析 source 时"aAbBcqCdDQeE"
,首先打印"a"
, ,然后改变频道,然后"b"
打印and ,然后再次改变频道,最后打印到控制台。"c"
"C"
"D"
"e"
这是一个执行此操作的 ANTLR 语法:
ChannelDemo.g
grammar ChannelDemo;
@parser::members {
private void handle(String letter) {
if("Q".equals(letter)) {
((ChangeableChannelTokenStream)input).setChannel(Token.DEFAULT_CHANNEL);
}
else if("q".equals(letter)) {
((ChangeableChannelTokenStream)input).setChannel(HIDDEN);
}
else {
System.out.println(letter);
}
}
}
parse
: any* EOF
;
any
: letter=(LOWER | UPPER) {handle($letter.getText());}
;
LOWER
: 'a'..'z'
;
UPPER
: 'A'..'Z' {$channel=HIDDEN;}
;
这是自定义令牌流类:
ChangeableChannelTokenStream.java
import org.antlr.runtime.*;
public class ChangeableChannelTokenStream extends UnbufferedTokenStream {
public ChangeableChannelTokenStream(TokenSource source) {
super(source);
}
public Token nextElement() {
Token t = null;
while(true) {
t = super.tokenSource.nextToken();
t.setTokenIndex(tokenIndex++);
if(t.getChannel() == super.channel) break;
}
return t;
}
public void setChannel(int ch) {
super.channel = ch;
}
}
还有一个小的 Main 类来测试这一切:
主.java
import org.antlr.runtime.*;
public class Main {
public static void main(String[] args) throws Exception {
ANTLRStringStream in = new ANTLRStringStream("aAbBcqCdDQeE");
ChannelDemoLexer lexer = new ChannelDemoLexer(in);
ChangeableChannelTokenStream tokens = new ChangeableChannelTokenStream(lexer);
ChannelDemoParser parser = new ChannelDemoParser(tokens);
parser.parse();
}
}
最后,生成一个词法分析器/解析器 (1),编译所有源文件 (2) 并运行 Main 类 (3):
1
java -cp antlr-3.3.jar org.antlr.Tool ChannelDemo.g
2
javac -cp antlr-3.3.jar *.java
3 (*尼克斯)
java -cp .:antlr-3.3.jar 主要
3(窗口)
java -cp .;antlr-3.3.jar 主要
这将导致以下内容打印到控制台:
一种
b
C
C
D
e
编辑
您可以像这样在语法文件中包含该类:
grammar ChannelDemo;
@parser::members {
private void handle(String letter) {
if("Q".equals(letter)) {
((ChangeableChannelTokenStream)input).setChannel(Token.DEFAULT_CHANNEL);
}
else if("q".equals(letter)) {
((ChangeableChannelTokenStream)input).setChannel(HIDDEN);
}
else {
System.out.println(letter);
}
}
public static class ChangeableChannelTokenStream extends UnbufferedTokenStream {
private boolean anyChannel;
public ChangeableChannelTokenStream(TokenSource source) {
super(source);
anyChannel = false;
}
@Override
public Token nextElement() {
Token t = null;
while(true) {
t = super.tokenSource.nextToken();
t.setTokenIndex(tokenIndex++);
if(t.getChannel() == super.channel || anyChannel) break;
}
return t;
}
public void setAnyChannel(boolean enable) {
anyChannel = enable;
}
public void setChannel(int ch) {
super.channel = ch;
}
}
}
parse
: any* EOF
;
any
: letter=(LOWER | UPPER) {handle($letter.getText());}
| STAR {((ChangeableChannelTokenStream)input).setAnyChannel(true);}
;
STAR
: '*'
;
LOWER
: 'a'..'z'
;
UPPER
: 'A'..'Z' {$channel=HIDDEN;}
;
从上面的语法生成的解析器将在遇到"*"
. 所以在解析时"aAbB*cCdDeE"
:
import org.antlr.runtime.*;
public class Main {
public static void main(String[] args) throws Exception {
ANTLRStringStream in = new ANTLRStringStream("aAbB*cCdDeE");
ChannelDemoLexer lexer = new ChannelDemoLexer(in);
ChannelDemoParser.ChangeableChannelTokenStream tokens =
new ChannelDemoParser.ChangeableChannelTokenStream(lexer);
ChannelDemoParser parser = new ChannelDemoParser(tokens);
parser.parse();
}
}
打印以下内容:
一种
b
C
C
d
D
e
乙