c++ - 遍历 ParseTree ANTLR4 的正确方法

标签 c++ antlr4 parse-tree

我正在尝试使用 ANTLR4 和 C++ 目标来实现 TSql 解析器。我捕获了语法文件here 。该jar用于制作相应的源文件(由于冲突,将TSqlParser.cpp中的所有NULL更改为null)。我正在关注doc example (以及网上的所有其他示例),它展示了如何实现工作正常的单个规则和监听器。实现多个规则时会出现问题。

main.cpp:

#include <iostream>
#include <antlr4-runtime/antlr4-runtime.h>
#include "TSqlParser.h"
#include "TSqlLexer.h"

#include "listener.h"


int main(int argc, const char* argv[])
{
    std::ifstream stream;
    stream.open(argv[1]);

    antlr4::ANTLRInputStream input(stream);
    TSqlLexer lexer(&input);
    antlr4::CommonTokenStream tokens(&lexer);
    TSqlParser parser(&tokens);

    TreeShapeListener listener;

    //antlr4::tree::ParseTree *select_tree = parser.select_statement();
    antlr4::tree::ParseTree *update_tree = parser.update_statement();

    //antlr4::tree::ParseTreeWalker::DEFAULT.walk(&listener, select_tree);
    antlr4::tree::ParseTreeWalker::DEFAULT.walk(&listener, update_tree);

    return 0;
}

监听器.h:

#include <antlr4-runtime/antlr4-runtime.h>
#include "TSqlParserBaseListener.h"

class TreeShapeListener : public TSqlParserBaseListener
{
public:

    void enterSelect_statement(TSqlParser::Select_statementContext*) override;
    void enterUpdate_statement(TSqlParser::Update_statementContext*) override;
};

监听器.cpp:

#include "listener.h"

void TreeShapeListener::enterSelect_statement(TSqlParser::Select_statementContext *ctx)
{
    std::cout << "Hello Select\n";
}

void TreeShapeListener::enterUpdate_statement(TSqlParser::Update_statementContext *ctx)
{
    std::cout << "Hello Update\n";
}

这是一个小测试 sql 文件:

SELECT TOP 1 NAME
FROM MYTABLE
WHERE SEQ = 6

UPDATE MYTABLE
SET NAME = 'Bob'
WHERE SEQ = 5

输出:

line 1:0 mismatched input 'SELECT' expecting {'UPDATE', 'WITH'}
Hello Update

如果我切换 SQL 语句,我只会得到 Hello Update 所以我认为它只是吞噬了整个输入。看起来我需要对所有内容进行硬编码才能得到我想要的东西。我的问题是,在解析文件时如何让正确的监听器调用自己?我觉得我错过了 ANTLR 的一些非常关键的东西。我在这里并不需要完整的答案,我只需要有人为我指明正确的方向。它可能是一个 API 页面...自从我编写 Java 以来已经有一段时间了,但它翻译得很好,我可以从那里弄清楚它。

最佳答案

如果你构建你的树

antlr4::tree::ParseTree *update_tree = parser.update_statement();

您仅使用语法的子集,因为您的入口点是tsql_fileupdate_statement 是 SQL 关键字 UPDATE 的规则,因此它不知道如何处理 SELECT

相反,你应该通过以下方式构建你的树

antlr4::tree::ParseTree *tsql_file_tree = parser.tsql_file();

关于c++ - 遍历 ParseTree ANTLR4 的正确方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52654712/

相关文章:

c++ - 将线程移植到 Windows。关键部分非常慢

c# - Antlr4.3语法中的NoViableAltException

parsing - 如何将 token 流转换为解析树

c++ - 如何在 Qt 项目(.pro)文件中指定 Linux 架构?

c++ - 构建 cpp-netlib 共享库

java - 读取 ANTLR 中的多行值,直到出现特殊符号

java - ANTLR4 Lexer getTokens() 返回 0 个标记

prolog - 寻找一个好的俄语语义解析器

python - 仅删除嵌套括号中的括号

c++ - COM:创建 BSTR 的 SafeArray 的访问冲突