从 ANTLR 解析树中提取特定标记

Extract specific token out of ANTLR Parse Tree

我正在尝试从 ANTLR 解析树中提取数据,但还没有完全掌握如何正确完成这项工作

假设我有以下两个 SQL 查询:

        // language=SQL
        val sql3 = """
        CREATE TABLE session(
            id           uuid                    not null
                constraint account_pk
                    primary key,
            created     timestamp   default now() not null
        )
        """.trimIndent()

        // language=SQL
        val sql4 = """
            CREATE TABLE IF NOT EXISTS blah(
                id           uuid                    not null
                constraint account_pk
                    primary key,
                created     timestamp   default now() not null
            )
        """.trimIndent()

现在我解析它们:

        val visitor = Visitor()
        listOf(sql3, sql4).forEach { sql ->
            val lexer = SQLLexer(CharStreams.fromString(sql))
            val parser = SQLParser(CommonTokenStream(lexer))

            visitor.visit(parser.sql())
            println(visitor.tableName)

        }

在我的访问者中,如果我访问 tableCreateStatement,我会得到解析树,但显然只抓取 child1 将适用于 sql3,但不适用于 sql4,因为 child1 在 sql4IF NOT EXISTS

class Visitor : SQLParserBaseVisitor<Unit>() {

    var tableName = ""

    override fun visitCreate_table_statement(ctx: SQLParser.Create_table_statementContext?) {
        tableName = ctx?.getChild(1)?.text ?: ""
        super.visitCreate_table_statement(ctx)
    }

}

有没有办法在解析树中找到特定的标记?

我假设负载与它有关,但由于它是 Any 类型,我不确定要检查什么

    override fun visitCreate_table_statement(ctx: SQLParser.Create_table_statementContext?) {
        ctx?.children?.forEach {
            if (it.payload.javaClass == SQLParser::Schema_qualified_nameContext) {
                tableName = it.text
            }
        }
        super.visitCreate_table_statement(ctx)
    }

编辑:.g4 文件来自 https://github.com/pgcodekeeper/pgcodekeeper/tree/master/apgdiff/antlr-src

这似乎有效

    override fun visitCreate_table_statement(ctx: SQLParser.Create_table_statementContext?) {
        ctx?.children?.forEach {
            if (it.payload.javaClass == Schema_qualified_nameContext::class.java) {
                tableName = it.text
            }
        }
        super.visitCreate_table_statement(ctx)
    }

对于分支树

    fun walkLeaves(
        childTree: ParseTree = internalTree,
        leave: (childTree: ParseTree) -> Unit) {

        if (childTree.childCount == 0) {
            if (!childTree.text?.trim().isNullOrBlank()) {
                leave(childTree)
            }
        } else {
            for (i in 0 until childTree.childCount) {
                walkLeaves(childTree = childTree.getChild(i), leave = leave)
            }
        }
    }
fun extractSQL(
    childTree: ParseTree,
    tokens: MutableList<String> = mutableListOf()
): String {

    walkLeaves(childTree = childTree) { leave ->
        tokens.add(leave.text)
    }

    ...

}