主要问题
是否有一种简单的方法可以从解析器规则类ParserRuleContext
中获得令牌列表(理想情况下是TokenStream
的形式)?
在listener - ANTLR4中使用ParserRuleContext遍历令牌的问题的答案中出现了这个解决方案:
ParserRuleContext pctx = ctx.getParent();
List<TerminalNode> nodes = pctx.getTokens(pctx.getStart(), pctx.getStop());
但在ANTLRv4中没有ParserRuleContext::getTokens(Token, Token)
签名的方法。
我考虑通过使用TokenStream:get(index: int)
方法从TokenStream
检索令牌列表,其中index
值将设置为给定ParserRuleContext
启动/停止令牌的一系列索引。
是否有一种方法可以从TokenStream
中获得另一个TokenStream
形式的令牌子集?
所以,我忽略了ANTLRv4 API中的一些类和它们的接口。
回答主要问题
上述方案是正确的。BufferedTokenStream
和CommonTokenStream
类也有方法public List<Token> getTokens(int start, int stop)
,它允许从给定范围(特别是从ParserRuleContext
类的开始令牌和停止令牌之间的范围)检索令牌列表
回答附加问题
可以利用ListTokenSource
类实现TokenSource
接口。然后通过ListTokenSource
创建CommonTokenStream
类。
ParserRuleRewriter代码示例
我将上面的想法封装到ParserRuleRewriter
的小代码示例中——TokenStreamRewriter
只重写给定的解析器规则。代码中的tokenStream
参数是一个完整程序的令牌流。
import org.antlr.v4.runtime.*;
import java.util.List;
public class ParserRuleRewriter {
private TokenStreamRewriter rewriter;
public ParserRuleRewriter(ParserRuleContext parserRule, CommonTokenStream tokenStream) {
Token start = parserRule.getStart();
Token stop = parserRule.getStop();
List<Token> ruleTokens = tokenStream.getTokens(start.getTokenIndex(), stop.getTokenIndex());
ListTokenSource tokenSource = new ListTokenSource(ruleTokens);
CommonTokenStream commonTokenStream = new CommonTokenStream(tokenSource);
commonTokenStream.fill();
rewriter = new TokenStreamRewriter(commonTokenStream);
}
public void replace(Token token, ParserRuleContext rule) {
rewriter.replace(token, rule.getText());
}
@Override
public String toString() {
return rewriter.getText();
}
}