antlr4 C++入门 - antlr4 访问器和监听器计算结果

环境:

antlr4: 4.13.2 (2024-08-04)
java: jdk 11.0.27 LTS (2025-04-15, EOL:2032-01)
编译器:vs2022/g++ 12

前言

上节中介绍了在C++中输出算数表达式的解析树,本文将使用访问器和监听器两种方式计算结果。

1. 访问器模式visitor计算结果

#include <iostream>

#include "antlr4-runtime.h"
#include "calculatorLexer.h"
#include "calculatorParser.h"

#include "calculatorBaseVisitor.h" // visitor

using namespace itas109;
using namespace antlr4;

class myCalculatorVisitor : public calculatorBaseVisitor
{
    virtual std::any visitProgram(calculatorParser::ProgramContext *ctx) override
    {
        return visit(ctx->expr());
    }

    virtual std::any visitMulDivExpr(calculatorParser::MulDivExprContext *ctx) override
    {
        int left = std::any_cast<int>(visit(ctx->expr(0)));
        int right = std::any_cast<int>(visit(ctx->expr(1)));
        if (ctx->Mul())
        {
            return left * right;
        }
        else if (ctx->Div())
        {
            return left / right;
        }

        return 0;
    }

    virtual std::any visitParensExpr(calculatorParser::ParensExprContext *ctx) override
    {
        return visit(ctx->expr());
    }

    virtual std::any visitAddSubExpr(calculatorParser::AddSubExprContext *ctx) override
    {
        int left = std::any_cast<int>(visit(ctx->expr(0)));
        int right = std::any_cast<int>(visit(ctx->expr(1)));
        if (ctx->Add())
        {
            return left + right;
        }
        else if (ctx->Sub())
        {
            return left - right;
        }

        return 0;
    }

    virtual std::any visitIntegerLiteral(calculatorParser::IntegerLiteralContext *ctx) override
    {
        return std::atoi(ctx->getText().c_str());
    }
};

int main(int argc, const char *argv[])
{
    const char *sourceCode = "1+2*3";
    ANTLRInputStream input(sourceCode);
    calculatorLexer lexer(&input);
    CommonTokenStream tokens(&lexer);

    calculatorParser parser(&tokens);
    tree::ParseTree *tree = parser.program();

    std::string stringTree = tree->toStringTree(&parser);
    printf("Input: %s\nParse Tree: %s\n", sourceCode, stringTree.c_str());

    myCalculatorVisitor visitor;
    int result = std::any_cast<int>(visitor.visit(tree));
    printf("result(visitor): %d\n", result);

    printf("\nPress Enter To Continue\n");
    (void)getchar();

    return 0;
}

结果

Input: 1+2*3
Parse Tree: (program (expr (expr 1) + (expr (expr 2) * (expr 3))) <EOF>)
result(visitor): 7

2. 监听器模式listener计算结果

这里使用ParseTreeProperty类标记语法树,也可以使用栈临时存储(但不推荐)。

main.cpp

#include <iostream>

#include "antlr4-runtime.h"
#include "calculatorLexer.h"
#include "calculatorParser.h"

#include "ParseTreeProperty.h" // annotate

#include "calculatorBaseListener.h" // listener

using namespace itas109;
using namespace antlr4;

class myCalculatorListener : public calculatorBaseListener
{
public:
    // annotate parse tree
    tree::ParseTreeProperty<int> result;
    void setValues(tree::ParseTree *node, int value)
    {
        result.put(node, value);
    }
    int getValues(tree::ParseTree *node)
    {
        return result.get(node);
    }

    virtual void exitProgram(calculatorParser::ProgramContext *ctx) override
    {
        setValues(ctx, getValues(ctx->expr()));
    }

    virtual void exitMulDivExpr(calculatorParser::MulDivExprContext *ctx) override
    {
        int left = getValues(ctx->expr(0));
        int right = getValues(ctx->expr(1));
        if (ctx->Mul())
        {
            setValues(ctx, left * right);
        }
        else if (ctx->Div())
        {
            setValues(ctx, left / right);
        }
    }

    virtual void exitParensExpr(calculatorParser::ParensExprContext *ctx) override
    {
        setValues(ctx, getValues(ctx->expr()));
    }

    virtual void exitAddSubExpr(calculatorParser::AddSubExprContext *ctx) override
    {
        int left = getValues(ctx->expr(0));
        int right = getValues(ctx->expr(1));
        if (ctx->Add())
        {
            setValues(ctx, left + right);
        }
        else if (ctx->Sub())
        {
            setValues(ctx, left - right);
        }
    }

    virtual void exitIntegerLiteral(calculatorParser::IntegerLiteralContext *ctx) override
    {
        setValues(ctx, std::atoi(ctx->getText().c_str()));
    }
};

int main(int argc, const char *argv[])
{
    const char *sourceCode = "1+2*3";
    ANTLRInputStream input(sourceCode);
    calculatorLexer lexer(&input);
    CommonTokenStream tokens(&lexer);

    calculatorParser parser(&tokens);
    tree::ParseTree *tree = parser.program();

    std::string stringTree = tree->toStringTree(&parser);
    printf("Input: %s\nParse Tree: %s\n", sourceCode, stringTree.c_str());

    myCalculatorListener listener;
    antlr4::tree::ParseTreeWalker::DEFAULT.walk(&listener, tree);
    printf("result(listener): %d\n", listener.getValues(tree));

    printf("\nPress Enter To Continue\n");
    (void)getchar();

    return 0;
}

结果

Input: 1+2*3
Parse Tree: (program (expr (expr 1) + (expr (expr 2) * (expr 3))) <EOF>)
result(listener): 7
Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐