在Antlr4中使用text属性时如何保留空白



我想在调用token的text属性时保留空白,有什么方法吗?情况如下:我们有以下代码

IF L > 40 THEN;
ELSE
  IF A = 20 THEN
      PUT "HELLO";

在这种情况下,我想将其转换为:

if (!(L>40){
      if (A=20)
          put "hello";
}

Antlr中的规则是:

stmt_if_block: IF expr
               THEN x=stmt
               (ELSE y=stmt)?
               {
                 if ($x.text.equalsIgnoreCase(";"))
                 {
                   WriteLn("if(!(" + $expr.text +")){");
                   WriteLn($stmt.text);
                   Writeln("}");
                 }
               }

但结果看起来像:

if(!(L>40))
{
   ifA=20put"hello";
}

原因是$stmt中的空白被去除了。我想知道是否有办法保留这些空白
非常感谢

更新:如果我添加

SPACE: [ ] -> channel(HIDDEN);

空间将被保留,结果如下所示,代币之间有许多空间:

 IF SUBSTR(WNAME3,M-1,1) = ')'             THEN                                        M = L;                                  ELSE                                        M = L - 1;

这就是我用于此目的的C#扩展方法:

public static string GetFullText(this ParserRuleContext context)
{
    if (context.Start == null || context.Stop == null || context.Start.StartIndex < 0 || context.Stop.StopIndex < 0)
        return context.GetText(); // Fallback
    return context.Start.InputStream.GetText(Interval.Of(context.Start.StartIndex, context.Stop.StopIndex));
}

由于您使用的是java,因此必须对其进行翻译,但它应该很简单——API也是一样的。

说明:获取第一个令牌,获取最后一个令牌,并从输入流中获取第一个标记的第一个字符和最后一个标记的最后一个字符之间的文本。

@Lucas解决方案,但在java中,如果您在翻译时遇到问题:

private String getFullText(ParserRuleContext context) {
    if (context.start == null || context.stop == null || context.start.getStartIndex() < 0 || context.stop.getStopIndex() < 0)
        return context.getText();
    return context.start.getInputStream().getText(Interval.of(context.start.getStartIndex(), context.stop.getStopIndex()));
}

看起来InputStream并不总是在removeLastChild/addChild操作之后更新。这个解决方案对一种语法有帮助,但对另一种语法不起作用。

适用于此语法。

不适用于现代groovy语法(由于某些原因inputStream.getText包含旧文本)。

我正在尝试实现这样的函数名称替换:

enterPostfixExpression(ctx: PostfixExpressionContext) {
   // Get identifierContext from ctx
   ...
   const token = CommonTokenFactory.DEFAULT.createSimple(GroovyParser.Identifier, 'someNewFnName');
   const node = new TerminalNode(token);
   identifierContext.removeLastChild();
   identifierContext.addChild(node);

UPD:我在第一次实现时使用了访问者模式

相关内容

  • 没有找到相关文章

最新更新