在 ANTLR 4 解析树中获取令牌的正确 StopIndex 的问题

Problem with getting correct StopIndex of a Token in ANTLR 4 Parse Tree

目标

我一直在尝试编写一个简单的逐步简化算法,它可以简化给定的逻辑方程并显示简化步骤。首先,我决定减少括号。要检索所有嵌套括号,我使用 ANTLR.

材料

我为试图使用 ANTLRv4 的左递归特性的逻辑表达式写了一个简单的语法

Binary.g4

grammar Binary;

expr
    : LPAREN expr RPAREN   #ParExpr
    | NOT expr             #NotBlock
    | expr AND expr        #AndBlock
    | expr OR expr         #OrBlock
    | expr IMP expr        #ImplBlock
    | expr EQ expr         #EqualBlock
    | expr XOR expr        #XorBlock
    | INT                  #Int
    | VAR                  #Var
    | WS                   #WS
    ;

NOT: '¬';

AND: '∧';

OR: '∨';

IMP: '⇒';

EQ: '≡';

XOR: '⊕';

LPAREN: '(';

RPAREN: ')';

INT: '0' | '1';

VAR: ('a' .. 'z' | 'A' .. 'Z') ('a' .. 'z' | 'A' .. 'Z')*;

WS: [ \r\n\t] + -> skip;

我的想法是用一个监听器遍历由 ANTLR 生成的解析树,并在退出 ParExpr 节点时触发我的事件。在那里我将使用 CharStream 检索括号的内容并简化它。

ParenthesisListener.java

public class ParenthesisListener extends BinaryBaseListener {

    private boolean changed = false;

    @Override
    public void exitParExpr(BinaryParser.ParExprContext ctx) {
        final CharStream input = ctx.start.getInputStream();

        if (!changed) {
            final int a = ctx.start.getStartIndex();
            final int b = ctx.stop.getStopIndex();

            final Interval interval = new Interval(a, b);

            final String branch = input.getText(interval);


            // Simplifying value in "branch"
            // If "branch" value changes, make "changed" variable true
       }

       System.out.println(input.getText(new Interval(ctx.start.getStartIndex(), ctx.stop.getStopIndex())));
    }

}

问题

出乎意料的是,使用 CharStream 检索 ParExprContext 的内容似乎有问题。调试代码后,ctx.stop.getStopIndex() 中似乎存在问题,因为它 returns 的值低于需要的值。

例如,通过给出这样的代码表达式

((A∧B)∨((A∧B)∧B))⇒B

它产生这样的结果:

(A∧B)
((A∧B)∨((A∧B
(((A∧B)∨((A∧B)

问题

所以想请教一下,给定Intervals的索引怎么取对?我猜我的语法有错误,导致了这些意想不到的结果。上面表达式的 AST 是:

我已准备好提供所需的任何额外材料。

我拿了你的语法和监听器代码,写了一个程序给运行它。我还为您的输入打印了令牌流和解析树。它产生的正是人们所期望的。但是,如下所示,我从监听器输出中的 println() 输出中获得的内容与您在问题中提供的内容不同。我的程序的输出与 Java 和 C# 的结果相同,令牌索引从 0 到 19(EOF 令牌)。我只能认为也许您使用的是旧工具和 运行 时间。确保您使用的是 4.8 的 Antlr 工具和 运行time.

parse completed.
Token 0 7 channel DEFAULT_TOKEN_CHANNEL (
Token 1 7 channel DEFAULT_TOKEN_CHANNEL (
Token 2 10 channel DEFAULT_TOKEN_CHANNEL A
Token 3 2 channel DEFAULT_TOKEN_CHANNEL ∧
Token 4 10 channel DEFAULT_TOKEN_CHANNEL B
Token 5 8 channel DEFAULT_TOKEN_CHANNEL )
Token 6 3 channel DEFAULT_TOKEN_CHANNEL ∨
Token 7 7 channel DEFAULT_TOKEN_CHANNEL (
Token 8 7 channel DEFAULT_TOKEN_CHANNEL (
Token 9 10 channel DEFAULT_TOKEN_CHANNEL A
Token 10 2 channel DEFAULT_TOKEN_CHANNEL ∧
Token 11 10 channel DEFAULT_TOKEN_CHANNEL B
Token 12 8 channel DEFAULT_TOKEN_CHANNEL )
Token 13 2 channel DEFAULT_TOKEN_CHANNEL ∧
Token 14 10 channel DEFAULT_TOKEN_CHANNEL B
Token 15 8 channel DEFAULT_TOKEN_CHANNEL )
Token 16 8 channel DEFAULT_TOKEN_CHANNEL )
Token 17 4 channel DEFAULT_TOKEN_CHANNEL ⇒
Token 18 10 channel DEFAULT_TOKEN_CHANNEL B
Token 19 -1 channel DEFAULT_TOKEN_CHANNEL <EOF>

( implBlock
  ( parExpr
    ( DEFAULT_TOKEN_CHANNEL i=0 txt=( tt=7
    )
    ( orBlock
      ( parExpr
        ( DEFAULT_TOKEN_CHANNEL i=1 txt=( tt=7
        )
        ( andBlock
          ( var
            ( DEFAULT_TOKEN_CHANNEL i=2 txt=A tt=10
          ) )
          ( DEFAULT_TOKEN_CHANNEL i=3 txt=∧ tt=2
          )
          ( var
            ( DEFAULT_TOKEN_CHANNEL i=4 txt=B tt=10
        ) ) )
        ( DEFAULT_TOKEN_CHANNEL i=5 txt=) tt=8
      ) )
      ( DEFAULT_TOKEN_CHANNEL i=6 txt=∨ tt=3
      )
      ( parExpr
        ( DEFAULT_TOKEN_CHANNEL i=7 txt=( tt=7
        )
        ( andBlock
          ( parExpr
            ( DEFAULT_TOKEN_CHANNEL i=8 txt=( tt=7
            )
            ( andBlock
              ( var
                ( DEFAULT_TOKEN_CHANNEL i=9 txt=A tt=10
              ) )
              ( DEFAULT_TOKEN_CHANNEL i=10 txt=∧ tt=2
              )
              ( var
                ( DEFAULT_TOKEN_CHANNEL i=11 txt=B tt=10
            ) ) )
            ( DEFAULT_TOKEN_CHANNEL i=12 txt=) tt=8
          ) )
          ( DEFAULT_TOKEN_CHANNEL i=13 txt=∧ tt=2
          )
          ( var
            ( DEFAULT_TOKEN_CHANNEL i=14 txt=B tt=10
        ) ) )
        ( DEFAULT_TOKEN_CHANNEL i=15 txt=) tt=8
    ) ) )
    ( DEFAULT_TOKEN_CHANNEL i=16 txt=) tt=8
  ) )
  ( DEFAULT_TOKEN_CHANNEL i=17 txt=⇒ tt=4
  )
  ( var
    ( DEFAULT_TOKEN_CHANNEL i=18 txt=B tt=10
) ) )

Start 1 Stop 5 (A∧B)
Start 8 Stop 12 (A∧B)
Start 7 Stop 15 ((A∧B)∧B)
Start 0 Stop 16 ((A∧B)∨((A∧B)∧B))