私の知る限り、それは不可能です。ただし、 を拡張して、解析中にUnbufferedTokenStream
を変更できます。可変量のトークンをバッファリングするため、channel
を使用することはできません(バッファ内に間違ったチャネルのトークンが存在する可能性があります!)。CommonTokenStream
少なくとも ANTLR 3.3 が必要であることに注意してください。以前のバージョンでは、UnbufferedTokenStream
はまだ含まれていませんでした。
小文字または大文字のいずれかを解析 (および表示) したいとします。大文字がHIDDEN
チャネルに配置されるため、デフォルトでは小文字のみが解析されます。ただし、パーサーが小文字の に出くわした場合は、チャネル"q"
に変更する必要があります。HIDDEN
チャネルで解析したら、再び に戻してHIDDEN
もらいたいと思います。"Q"
DEFAULT_CHANNEL
したがって、ソースを解析すると"aAbBcqCdDQeE"
、最初"a"
に"b"
と"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 クラス:
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 (*nix)
java -cp .:antlr-3.3.jar メイン
3 (ウィンドウズ)
java -cp .;antlr-3.3.jar メイン
これにより、以下がコンソールに出力されます。
a
b
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();
}
}
以下が出力されます。
a
b
c
ハ
d
D
e
え