java - ANTLR4 - 使用 Visitor 将语法树转换为 AST

标签 java antlr antlr4

我的任务是实现一个访问者,它将以下计算算术表达式的语法转换为 AST:

grammar SmallC;


program :   exp
;

exp :   lexp ((op = '>' | op = '<' |op = '>=' | op = '<=' | op = '!=' | op = '==') lexp)?
;

lexp :  term ((op = '+'|op = '-') term)*
;

term:   factor((op = '%'| op = '\*'| op = '/') factor)*
;

factor  :   Number
;

Number  : [0-9]+
;    

目前,ANTLR 为表达式“3*6”创建以下树:

程序 -> exp -> lexp -> 项 -> (因子 * 因子) -> 数字 -> ( 3 * 6)

我想要的是这样的:

程序 -> 乘法(3,6)

我尝试通过实现一个访问者函数来开始此操作,该函数将遍历树并输出一些数据结构,但它失败了。这是我的类(class):

Main.Java

import org.antlr.v4.runtime.*;

public class Main {

public static void main(String[] args) {

ANTLRInputStream input = new ANTLRInputStream("3*6");
SmallCLexer lexer = new SmallCLexer(null);
lexer.setInputStream(input);

CommonTokenStream tokens = new CommonTokenStream(lexer);
tokens.fill();

SmallCParser parser = new SmallCParser(null);
parser.setBuildParseTree(true);
parser.setTokenStream(tokens);

ParserRuleContext tree = parser.program();
MyVisitor visitor = new MyVisitor();
visitor.visit(tree);

}

}

MyVisitor.java

import org.antlr.v4.runtime.*;


public class MyVisitor extends SmallCBaseVisitor<SmallCNode> {


@Override public SmallCNode visitExp(SmallCParser.ExpContext ctx)  {
    if ( ctx.lexp().size() == 2) {
        SmallCLexp lhs = (SmallCLexp) ctx.lexp(0).accept(this);
        SmallCLexp rhs = (SmallCLexp) ctx.lexp(1).accept(this);
        String op = ctx.op.getText();
        return new SmallCExp(lhs,rhs,op);
    } else {
        visitLexp(ctx.lexp(0));
    }


}

@Override public SmallCNode visitLexp(SmallCParser.LexpContext ctx) {
    if ( ctx.term().size() == 2) {
        SmallCTerm lhs = (SmallCTerm) ctx.term(0).accept(this);
        SmallCTerm rhs = (SmallCTerm) ctx.term(1).accept(this);
        String op = ctx.op.getText();
        return new SmallCLexp(lhs,rhs,op);
    } else {
        visitTerm(ctx.term(0));
    }


}

@Override public SmallCNode visitTerm(SmallCParser.TermContext ctx) {
    if (ctx.factor().size() == 2) {
        SmallCFactor lhs = (SmallCFactor) ctx.factor(0).accept(this);
        SmallCFactor rhs = (SmallCFactor) ctx.factor(1).accept(this);
        String op = ctx.op.getText();
        return new SmallCTerm(lhs,rhs,op);
    } else {
        visitFactor(ctx.factor(0));
    }



}

@Override public SmallCNode visitFactor(SmallCParser.FactorContext ctx) {
        String fc = ctx.getText();
        return new SmallCFactor(fc);
}

这是我的节点类:

public class SmallCNode {

}


public class SmallCExp extends SmallCNode{
    SmallCLexp lhs;
    SmallCLexp rhs;
    String op;
    public SmallCExp(SmallCLexp lhs, SmallCLexp rhs, String op) {
        super();
        this.lhs = lhs;
        this.rhs = rhs;
        this.op = op;
    }
}

public class SmallCLexp extends SmallCNode {
    SmallCTerm lhs;
    SmallCTerm rhs;
    String op;
    public SmallCLexp(SmallCTerm lhs, SmallCTerm rhs, String op) {
        super();
        this.lhs = lhs;
        this.rhs = rhs;
        this.op = op;
    }
}

public class SmallCTerm extends SmallCNode{
    SmallCFactor lhs;
    SmallCFactor rhs;
    String op;
    public SmallCTerm(SmallCFactor lhs, SmallCFactor rhs, String op) {
        super();
        this.lhs = lhs;
        this.rhs = rhs;
        this.op = op;
}

}

public class SmallCFactor extends SmallCNode {
    String factor;

    public SmallCFactor(String factor) {
        super();
        this.factor = factor;
}

}

当我运行 Main.java 时,出现此错误:

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
    This method must return a result of type SmallCNode

    at MyVisitor.visitExp(MyVisitor.java:8)
    at MyVisitor.visitExp(MyVisitor.java:1)
    at SmallCParser$ExpContext.accept(SmallCParser.java:151)
    at org.antlr.v4.runtime.tree.AbstractParseTreeVisitor.visitChildren(AbstractParseTreeVisitor.java:70)
    at SmallCBaseVisitor.visitProgram(SmallCBaseVisitor.java:20)
    at SmallCParser$ProgramContext.accept(SmallCParser.java:103)
    at org.antlr.v4.runtime.tree.AbstractParseTreeVisitor.visit(AbstractParseTreeVisitor.java:42)
    at Main.main(Main.java:20)

现在,我对这件事很陌生,我意识到我可能缺少很多东西。我不知道如何从这里继续,如果我能得到我缺少的东西的列表,我将非常感激:)

最佳答案

代码中的许多 else block 不会返回 SmallCNode,而它们必须返回

不应该是:

@Override public SmallCNode visitTerm(SmallCParser.TermContext ctx) {
if (ctx.factor().size() == 2) {
    SmallCFactor lhs = (SmallCFactor) ctx.factor(0).accept(this);
    SmallCFactor rhs = (SmallCFactor) ctx.factor(1).accept(this);
    String op = ctx.op.getText();
    return new SmallCTerm(lhs,rhs,op);
} else {
    visitFactor(ctx.factor(0));
}

但是:

@Override public SmallCNode visitTerm(SmallCParser.TermContext ctx) {
if (ctx.factor().size() == 2) {
    SmallCFactor lhs = (SmallCFactor) ctx.factor(0).accept(this);
    SmallCFactor rhs = (SmallCFactor) ctx.factor(1).accept(this);
    String op = ctx.op.getText();
    return new SmallCTerm(lhs,rhs,op);
} else {
    return visitFactor(ctx.factor(0));
}

关于java - ANTLR4 - 使用 Visitor 将语法树转换为 AST,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28395623/

相关文章:

java - 如何使用共享服务器正确反向代理 swagger

java - 如果在某个固定时间后挂起,则停止 Spring Scheduled 执行

java - JButton自定义问题

python - 导入后ANTLR4语法标记识别错误

c# - 使用 ANTLR 和 Antlr CSharp 目标为 DSL 构建编译器

go - 如何在 antlr 的 go target 中编写自定义错误报告器

java - 如何从 "(GMT+10:00) Brisbane"或 "(GMT+01:00) Brussels, Copenhagen, Madrid, Paris"等区域名称获取 Java 中的 TimeZone 对象

java - 使用 ANTLR 语法编译文件

java - Antlr4 - 语法解析日志文件

java - ANTLR-4.7.1 :The type ANTLRInputStream is deprecated