Java 有没有办法让ANTLR4对生成的令牌使用枚举?
在ANTLR4中,Java中生成的lexer包含每个令牌的公共字段,其中字段的类型为简单的“int”。ANTLR4不使用枚举是有原因的,还是有选项让它使用枚举 这是我脑海中一个简单的例子 x、 g4 XLexer.javaJava 有没有办法让ANTLR4对生成的令牌使用枚举?,java,enums,antlr4,Java,Enums,Antlr4,在ANTLR4中,Java中生成的lexer包含每个令牌的公共字段,其中字段的类型为简单的“int”。ANTLR4不使用枚举是有原因的,还是有选项让它使用枚举 这是我脑海中一个简单的例子 x、 g4 XLexer.java public class XLexer extends Lexer{ public static final int A = 1, B = 2; } 我更希望XLexer包含 public class XLexer extends Lexer{ public st
public class XLexer extends Lexer{
public static final int A = 1, B = 2;
}
我更希望XLexer包含
public class XLexer extends Lexer{
public static enum Token{
A(1), B(2)
}
}
这对于转储令牌时的调试非常有用。现在不打印令牌名称,而是只提供整数表示
[@-1,0:0='a',<1>,1:0]
更具可读性的版本将取代
这是我目前的解决办法。我创建一个自定义令牌,并通过向XLexer提供一个令牌工厂
lexer.setTokenFactory(new MyTokenFactory());
我在token类中重写了toString方法
public class MyToken extends Token{
@Override
public String toString(){
StringBuilder out = new StringBuilder();
out.append("[");
out.append("'").append(getText()).append("'");
out.append(" type ").append(getName()); //getName() is implemented by this class
int start = getCharPositionInLine();
int end = start + getText().length();
out.append(" at ").append(getLine()).append(":").append(start).append("-").append(end);
out.append("]");
return out.toString();
}
其中,类使用getName将整数转换为字符串,而不是显示类型的整数
// inside the token class
private String getName(){
switch (getType()){
case XLexer.A: return "A";
case XLexer.B: return "B";
default: throw new RuntimeException("unknown token " + getType());
}
}
这将产生以下输出
['A' type A at 1:5-6]
这个解决方案有点脆弱,因为必须更新getName以与g4文件定义的当前令牌保持同步。无法强制执行此属性,因为编译器无法知道是否所有令牌类型都在getName内的开关中处理。以下是我当前的解决方法。我创建一个自定义令牌,并通过向XLexer提供一个令牌工厂
lexer.setTokenFactory(new MyTokenFactory());
我在token类中重写了toString方法
public class MyToken extends Token{
@Override
public String toString(){
StringBuilder out = new StringBuilder();
out.append("[");
out.append("'").append(getText()).append("'");
out.append(" type ").append(getName()); //getName() is implemented by this class
int start = getCharPositionInLine();
int end = start + getText().length();
out.append(" at ").append(getLine()).append(":").append(start).append("-").append(end);
out.append("]");
return out.toString();
}
其中,类使用getName将整数转换为字符串,而不是显示类型的整数
// inside the token class
private String getName(){
switch (getType()){
case XLexer.A: return "A";
case XLexer.B: return "B";
default: throw new RuntimeException("unknown token " + getType());
}
}
这将产生以下输出
['A' type A at 1:5-6]
这个解决方案有点脆弱,因为必须更新getName以与g4文件定义的当前令牌保持同步。无法强制执行此属性,因为编译器无法知道是否所有令牌类型都在getName内的开关中处理。ANTLR4使用ints而不是ENUM的原因是简单性和性能
出于调试目的,您可以修改令牌的字符串表示形式,如下所示:
创建您自己的令牌实现,扩展CommonToken。根据需要定义toString方法
创建一个TokenFactory实现,它返回自定义类型的令牌
设置令牌工厂和
另见:
关于堆栈溢出
关于GitHub
编辑,解决您在回答中提到的问题
为了避免手动将令牌名称与.g4保持同步,您可以从XLexer构建映射 ANTLR4使用整数而不是枚举的原因是简单性和性能
出于调试目的,您可以修改令牌的字符串表示形式,如下所示:
创建您自己的令牌实现,扩展CommonToken。根据需要定义toString方法
创建一个TokenFactory实现,它返回自定义类型的令牌
设置令牌工厂和
另见:
关于堆栈溢出
关于GitHub
编辑,解决您在回答中提到的问题
为了避免手动将令牌名称与.g4保持同步,您可以从XLexer构建映射 要将int标记类型转换为其符号值,只需使用
String tokenName = YourLexer.VOCABULARY.getSymbolicName(type);
要将int标记类型转换为其符号值,只需使用
String tokenName = YourLexer.VOCABULARY.getSymbolicName(type);
您能否进一步介绍一下简单性和性能,以及枚举如何不满足这些属性?反射将不起作用,因为XLexer类中有多种类型的字段声明为“public static final int”。其中只有一个子集是令牌类型。例如,lexer模式变成int字段,其值与令牌值重叠。假设g4语法中有一个附加的lexer模式,名为ZZ。XLexer类将具有“int A=1”;int ZZ=1;'@据我所知,您正在广泛使用ANTLR并定义复杂语法。你试过调试吗?你能谈谈简单性和性能,以及枚举如何不满足这些属性吗?反射不会起作用,因为XLexer类中有多种类型的字段声明为“public static final int”。其中只有一个子集是令牌类型。例如,lexer模式变成int字段,其值与令牌值重叠。假设g4语法中有一个附加的lexer模式,名为ZZ。XLexer类将具有“int A=1”;int ZZ=1;'@据我所知,您正在广泛使用ANTLR并定义复杂语法。您尝试过调试吗?前面已经讨论过了:根据这一讨论,生成的lexer类可能最简单的方法是包含一个数组,该数组将令牌的整数值映射到字符串名,例如已经对modename和rulename进行了映射。有一个tokenNames数组,但它包含一组看似随机的字符。也许这只是一个bug,前面已经讨论过了:根据这个讨论,对于生成的lexer类来说,包含一个映射t的整数值的数组可能是最简单的 他对字符串名称进行标记,如modename和rulename已经完成的标记。有一个tokenNames数组,但它包含一组看似随机的字符。也许这只是一个bug。