我想定义一个语法,该语法应解析与度量单位相关的单词,例如公斤:'kg','KG','千克','公斤','l','升','升'等。
我已经在使用Java enum
类来做类似的事情,以验证应该代表度量单位的输入字符串。
我想知道是否可以在ANTLR语法文件中的enum类中重用已定义的度量单位。基本上我想在 .g4 语法文件中设置 lexer ,如:
UNITS: UnitMeasures.values()
.values()
方法返回UnitMeasures
枚举Java类中的枚举值,这与“ANTLR语法词法分析器”相同“
UNITS: ('kg' | 'KG' | 'kilograms' | 'l' | 'litres' | 'liters' );
原因我尝试这样做的原因是:
是否有可能以某种方式避免此代码重复?
答案 0 :(得分:2)
如果您的程序中尚未存在枚举,我建议根据语法本身生成运行时工件。
由于您已经定义了枚举,因此在使用AbstractParseTreeVisitor解析完成后,让我们实现单元识别。
1)
添加units
解析器规则并概括您的UNITS
词法分析器规则:
...
unit : ID
;
...
ID: [a-zA-Z_0-9]+ ; // whatever you want/need
...
现在你的语法不会复制任何代码,但你的单位规则太笼统了。我们将在java方面解决这个问题。
2)
生成访问者并覆盖visitUnit(UnitContext)
。
@Override
public Object visitUnit(UnitContext ctx) {
String unitId = ctx.ID();
try{
// Next line will throw exception if unitId is not
// the name of one of your enums.
UnitMeasures unit = UnitMeasures.valueOf(unitId);
// do something maybe?
} catch (IllegalArgumentException(e) {
throw new RuntimeException("Invalid unit: " + unitId);
}
return super.visitUnit(ctx);
}
这将消除任何代码重复。现在,无论何时向UnitMeasures
添加新的枚举,您都不必改变语法。您甚至不需要重新生成解析器。
另一种选择:
这将为您的语法添加一个java依赖项,但您可以在unit
规则之后立即添加一些操作,如果ID
不是基于您的enum
的有效单位,则可以做出相应的响应
unit : ID
{
try {
UnitMeasures.valueOf($unit.text);
}
catch(IllegalArgumentException e) {
//report invalid unit
}
}
;