我在隐藏 channel 中使用正常的空格分隔,但我有一个规则,我想包含任何空格以供以后处理,但我发现的任何示例都需要一些非常奇怪的手动编码。
从多个 channel 读取是否没有简单的选项,例如从一开始就将空格放在那里的选项。
前任。这是 WhiteSpace 词法分析器规则
WS : ( ' '
| '\t'
| '\r'
| '\n'
) {$channel=HIDDEN;}
;
这是我想包含空格的规则
raw : '{'? (~('{'))*;
基本上,它是一个捕获所有规则,用于捕获与要由另一个模式处理的其他规则不匹配的任何内容,因此我需要原始流。
我希望有一个
{$channel==DEFAULT || $channel==HIDDEN}
语法示例,但找不到任何。我的目标是 C#,但如果需要,我可以重写 Java 示例。
最佳答案
AFAIK,这是不可能的。但是,您可以扩展 UnbufferedTokenStream
更改 channel
在解析过程中。您不能使用 CommonTokenStream
因为它缓冲了可变数量的 token (并且缓冲区中可能有 token 位于错误的 channel 上!)。请注意,您至少需要 ANTLR 3.3:在以前的版本中 UnbufferedTokenStream
尚未包括在内。
假设您要解析(并显示)小写或大写字母。大写字母放在 HIDDEN
上 channel ,因此默认情况下,只会解析小写字母。但是,当解析器偶然发现小写字母 "q"
时,我们要改成 HIDDEN
channel 。一旦在 HIDDEN
上解析 channel ,我们想要 "Q"
让我们回到 DEFAULT_CHANNEL
再次。
所以在解析源码时"aAbBcqCdDQeE"
, 第一 "a"
, "b"
和 "c"
被打印,然后 channel 改变,然后"C"
和 "D"
打印出来,然后再换 channel ,最后"e"
打印到控制台。
这是执行此操作的 ANTLR 语法:
channel 演示.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;}
;
这是自定义 token 流类:
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 类来测试它:
主程序
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 Main
3 (Windows)
java -cp .;antlr-3.3.jar Main
which will cause the following to be printed to the console:
a b c C D e
EDIT
You can include the class in your grammar file like this:
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;}
;
从上述语法生成的解析器将在遇到
"*"
时启用从所有 channel 读取。 .所以在解析"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();
}
}
打印以下内容:
一种
乙
C
C
d
D
电子
乙
关于antlr - 如何获取 Antlr 解析器规则以从默认和隐藏 channel 读取,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5741829/