AFAIK, this is not possible. However, you can extend UnbufferedTokenStream to change channel during parsing. You cannot use CommonTokenStream since it buffers a variable number of tokens (and there may be tokens in the buffer that are on the wrong channel!). Please note that you need at least ANTLR 3.3: in previous versions, UnbufferedTokenStream was not yet included.
Suppose you want to parse (and display) lowercase or uppercase letters. Uppercase letters are placed in the HIDDEN channel, so only lowercase letters are processed by deafness. However, when the parser stumbles upon the lowercase "q" , we want to switch to the HIDDEN channel. After parsing the HIDDEN channel, we want "q" to return us to DEFAULT_CHANNEL again.
So, when analyzing the source "aAbBcqCdDQeE" first "a" , "b" and "c" "aAbBcqCdDQeE" are printed, then the channel changes, then "c" and "D" are printed, then the channel changes again, and finally, "e" is output to console.
Here is the ANTLR grammar that does this:
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;} ;
And here is the custom token stream class:
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; } }
And a small main class for testing everything:
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(); } }
Finally, generate lexer / parser (1), compile all the source files (2) and run the Main class (3):
1
java -cp antlr-3.3.jar org.antlr.Tool ChannelDemo.g
2
javac -cp antlr-3.3.jar * .java
3 (* nix)
java -cp.: antlr-3.3.jar Main
3 (Windows)
java -cp.; antlr-3.3.jar Main
which will output the following to the console:
a
b
c
C
D
e
EDIT
You can include the class in your grammar file as follows:
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;} ;
A parser that is generated from the above grammar will allow reading through all channels when it encounters "*" . Therefore, when analyzing "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(); } }
the following is printed:
a
b
c
C
d
D
e
E