使用Java代码编写的antlr语法g4文件



我想定义一个语法,该语法应该解析与度量单位有关的单词,例如千克:'kg', 'kg', 'kg', 'kg', 'kg', 'l', '公升','升'等。

我已经使用Java enum类做了类似的事情来验证应该代表度量单位的输入字符串。

我想知道是否有可能在ANTLR语法文件内的枚举类中重用已经定义的度量单位。基本上,我想在中设置词法分析器。g4语法文件如:

UNITS: UnitMeasures.values()

其中.values()方法返回UnitMeasures枚举Java类中的枚举值,这"应该等同于"ANTLR语法词法器:

UNITS: ('kg' | 'KG' | 'kilograms' | 'l' | 'litres' | 'liters' );

原因为什么我试图这样做:

  • 我想避免枚举Java类和ANTLR语法文件之间的代码重复;
  • 我不能只使用ANTLR和删除枚举Java类,因为它已经在许多不同的地方使用;
  • 现在我正试图在一个更复杂的场景中使用度量单位,我需要解析数量,度量单位和其他相关的东西,所以我决定使用ANTLR。

是否有可能以某种方式避免这种代码重复?

如果枚举还没有出现在您的程序中,我建议基于语法本身生成运行时工件。

既然已经定义了枚举,那么让我们在使用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
         }
     }
     ;

相关内容

  • 没有找到相关文章

最新更新