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

时间:2014-10-23 08:41:49

标签: antlr antlr4

我想在调用令牌的文本属性时保留空格,有没有办法做到这一点? 情况如下: 我们有以下代码

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;

3 个答案:

答案 0 :(得分:6)

这是我用于此目的的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是相同的。

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

答案 1 :(得分:2)

@Lucas solution,但是在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()));
}

答案 2 :(得分:0)

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

适用于this grammar

不适用于现代 groovy grammar(由于某种原因 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:我在第一个实现中使用了访问者模式