在 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))
目标
我一直在尝试编写一个简单的逐步简化算法,它可以简化给定的逻辑方程并显示简化步骤。首先,我决定减少括号。要检索所有嵌套括号,我使用 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))