Jason
Jason

Reputation: 2671

Correct way to walk a ParseTree ANTLR4

I am trying to implement a TSql parser using ANTLR4 with a C++ target. I grabbed the grammar files here. The jar was used to make the corresponding source files (and changed all NULL to null in TSqlParser.cpp because of conflict). I am following the doc example (and every other example on the net) which shows how to implement a single rule and listener which works fine. The problem occurs when implementing multiple rules.

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;
}

listener.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;
};

listener.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";
}

And here is a little test sql file:

SELECT TOP 1 NAME
FROM MYTABLE
WHERE SEQ = 6

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

output:

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

If I switch the SQL statements around, I will get just Hello Update so I think it is just gobbling up the entire input. It all just seems like I need to hard code everything to get what I want. My question is, how do I get the correct listeners to call themselves when I parse the file? I feel like I am missing something very key here to ANTLR. I don't really need a full answer here, I just need someone to point me in the right direction. It could be an API page... It has been a while since I wrote any Java, but it translates well enough that I can figure it out from there.

Upvotes: 2

Views: 3088

Answers (1)

Jonas
Jonas

Reputation: 1847

If you construct your tree by

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

you are only using a subset of your grammar, because your entry point is tsql_file. The update_statement is the rule for the SQL keyword UPDATE, so it doesnt know what to do with SELECT.

Instead you should construct your tree by

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

Upvotes: 3

Related Questions