如何通过Antlr PLSQL Parser获取表达式的字符位置
如何在ANTLR PL/SQL Parser中获取特定表达式的字符位置?
我正在使用ANTLR PL/SQL Parser处理来自Oracle Forms的SQL代码,已经生成了所需的Java类,主代码运行正常(代码如下),能获取语法错误数量和解析树子节点,但不知道如何获取特定表达式的字符位置,已知ANTLR具备该能力,特此求助。
CharStream charStream = CharStreams.fromString("CREATE FUNCTION totalCustomers \r\n" + "RETURN number IS \r\n" + " total number(2) := 0; \r\n" + "BEGIN \r\n" + " SELECT count(*) into total \r\n" + " FROM customers; \r\n" + " RETURN total; \r\n" + "END; "); PlSqlLexer plSqlLexer = new PlSqlLexer(charStream); // 注:原代码中charStream2应为charStream CommonTokenStream commonTokenStream = new CommonTokenStream(plSqlLexer); PlSqlParser plSqlParser = new PlSqlParser(commonTokenStream); PlSqlParser.Create_function_bodyContext sql_scriptContext = plSqlParser.create_function_body();
解决方案:利用ANTLR上下文对象的位置方法
ANTLR生成的所有解析树上下文类(比如Create_function_bodyContext、各类子节点上下文)都继承自ParserRuleContext,该类提供了获取起始和结束位置的核心方法:
getStart():返回对应规则/表达式的起始TokengetStop():返回对应规则/表达式的结束Token
每个Token对象包含以下关键位置信息:
getLine():行号(从1开始计数)getCharPositionInLine():行内列号(从0开始计数)getStartIndex():在原始字符流中的起始偏移量(从0开始)getStopIndex():在原始字符流中的结束偏移量(包含该位置字符)
示例:获取count(*)的字符位置
以你的代码为例,若要获取SELECT count(*) ...中count(*)的位置,可按以下步骤操作:
// 从根上下文定位到SELECT语句节点 PlSqlParser.Select_statementContext selectStmtCtx = sql_scriptContext.select_statement(); // 从SELECT语句定位到函数调用节点(对应count(*)) PlSqlParser.Function_callContext funcCallCtx = selectStmtCtx.select_list() .select_list_element() .expression() .function_call(); // 获取起始位置信息 Token startToken = funcCallCtx.getStart(); int startLine = startToken.getLine(); int startCol = startToken.getCharPositionInLine(); int startOffset = startToken.getStartIndex(); // 获取结束位置信息 Token stopToken = funcCallCtx.getStop(); int endLine = stopToken.getLine(); int endCol = stopToken.getCharPositionInLine(); int endOffset = stopToken.getStopIndex(); // 输出结果 System.out.println("count(*) 位置信息:"); System.out.println("起始行:" + startLine + ",起始列:" + startCol); System.out.println("结束行:" + endLine + ",结束列:" + endCol); System.out.println("字符偏移范围:[" + startOffset + ", " + endOffset + "]");
额外提示
- 若需要更细粒度的位置(比如
count(*)中的*),可以继续深入子节点(比如funcCallCtx.getChild(...)),重复上述位置获取步骤 - 可以通过
charStream.getText(startOffset, endOffset)获取对应位置的原始文本,验证位置是否正确 - 解析树节点的层级关系可参考ANTLR生成的
PlSqlParser.java文件中的上下文类定义,或使用ANTLR可视化工具查看解析树结构
内容的提问来源于stack exchange,提问作者Alena
相关产品推荐
相关产品推荐

