尝试使用 ANTLR 来制作我的编译器的 AST 并获取返回值 null

问题描述 投票:0回答:1

我有一个项目,我必须使用ANTLR和java制作一个编译器来制作一个类似计算器的程序,该程序执行以下操作:加法减法乘法除法幂正弦余弦正切余切mod NOT AND OR XOR NAND对数阶乘Pi根e。 在尝试使用自定义访问者创建 AST 时(我已经使用 antlr 和我的语法(g4 文件)生成了 neseccery 文件,我不断收到以下错误:发生错误:无法调用“java.lang.Double.doubleValue( )”,因为“EvaluateExpressionVisitor.visit(ExpressionNode)”的返回值为 null。

我能够确定返回值是否为空,因此我们将不胜感激。 下面是我的主文件,评估表达式访问者和 ASTNodes。

import org.antlr.v4.runtime.ANTLRFileStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;

import java.io.IOException;

public class Main {
    public static void main(String[] args) {
        try {
            MTmathLexer lexer = new MTmathLexer(new ANTLRFileStream("input.txt"));
            MTmathParser parser = new MTmathParser(new CommonTokenStream(lexer));
            ParseTree cst = parser.r();
            ExpressionNode ast = new BuildAstVisitor().visit(cst);
            double value = new EvaluateExpressionVisitor().visit(ast);

            System.out.println("= " + value);
        } catch (IOException e) {
            System.err.println("Error reading input file: " + e.getMessage());
        } catch (Exception e) {
            System.err.println("An error occurred: " + e.getMessage());
        }
    }
}
 abstract class ExpressionNode {}

 abstract class BinaryExpressionNode extends ExpressionNode {
    protected ExpressionNode left;
    protected ExpressionNode right;

    public BinaryExpressionNode(ExpressionNode left, ExpressionNode right) {
        this.left = left;
        this.right = right;
    }

    public ExpressionNode getLeft() {
        return left;
    }

    public ExpressionNode getRight() {
        return right;
    }
}

 class AdditionNode extends BinaryExpressionNode {
    public AdditionNode(ExpressionNode left, ExpressionNode right) {
        super(left, right);
    }
}

 class SubtractionNode extends BinaryExpressionNode {
    public SubtractionNode(ExpressionNode left, ExpressionNode right) {
        super(left, right);
    }
}

  class MultiplicationNode extends BinaryExpressionNode {
        public MultiplicationNode(ExpressionNode left, ExpressionNode right) {
            super(left, right);
        }
    }

     class DivisionNode extends BinaryExpressionNode {
        public DivisionNode(ExpressionNode left, ExpressionNode right) {
            super(left, right);
        }
    }

     class PowerNode extends BinaryExpressionNode {
        public PowerNode(ExpressionNode left, ExpressionNode right) {
            super(left, right);
        }
    }

     class ModNode extends BinaryExpressionNode {
        public ModNode(ExpressionNode left, ExpressionNode right) {
            super(left, right);
        }
    }

     class NotNode extends ExpressionNode {
        private ExpressionNode expression;

        public NotNode(ExpressionNode expression) {
            this.expression = expression;
        }

        public ExpressionNode getExpression() {
            return expression;
        }
    }

     class AndNode extends BinaryExpressionNode {
        public AndNode(ExpressionNode left, ExpressionNode right) {
            super(left, right);
        }
    }

     class OrNode extends BinaryExpressionNode {
        public OrNode(ExpressionNode left, ExpressionNode right) {
            super(left, right);
        }
    }

     class XorNode extends BinaryExpressionNode {
        public XorNode(ExpressionNode left, ExpressionNode right) {
            super(left, right);
        }
    }

     class NandNode extends BinaryExpressionNode {
        public NandNode(ExpressionNode left, ExpressionNode right) {
            super(left, right);
        }
    }

     class LogNode extends ExpressionNode {
        private ExpressionNode expression;

        public LogNode(ExpressionNode expression) {
            this.expression = expression;
        }

        public ExpressionNode getExpression() {
            return expression;
        }
    }

     class FactorialNode extends ExpressionNode {
        private ExpressionNode expression;

        public FactorialNode(ExpressionNode expression) {
            this.expression = expression;
        }

        public ExpressionNode getExpression() {
            return expression;
        }
    }

     class PiNode extends ExpressionNode {}

     class SquareRootNode extends ExpressionNode {
        private ExpressionNode expression;

        public SquareRootNode(ExpressionNode expression) {
            this.expression = expression;
        }

        public ExpressionNode getExpression() {
            return expression;
        }
    }

     class ENode extends ExpressionNode {}

     class SinNode extends ExpressionNode {
        private ExpressionNode expression;

        public SinNode(ExpressionNode expression) {
            this.expression = expression;
        }

        public ExpressionNode getExpression() {
            return expression;
        }
    }

     class CosNode extends ExpressionNode {
        private ExpressionNode expression;

        public CosNode(ExpressionNode expression) {
            this.expression = expression;
        }

        public ExpressionNode getExpression() {
            return expression;
        }
    }

     class TanNode extends ExpressionNode {
        private ExpressionNode expression;

        public TanNode(ExpressionNode expression) {
            this.expression = expression;
        }

        public ExpressionNode getExpression() {
            return expression;
        }
    }

     class CotNode extends ExpressionNode {
        private ExpressionNode expression;

        public CotNode(ExpressionNode expression) {
            this.expression = expression;
        }

        public ExpressionNode getExpression() {
            return expression;
        }
    }

 class NumberNode extends ExpressionNode {
    private int value;

    public NumberNode(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }
}
public class EvaluateExpressionVisitor extends ASTVisitor<Double> {
    @Override
    public Double visit(AdditionNode node) {
        return visit(node.getLeft()) + visit(node.getRight());
    }

    @Override
    public Double visit(SubtractionNode node) {
        return visit(node.getLeft()) - visit(node.getRight());
    }


    @Override
    public Double visit(NumberNode node) {
        return (double) node.getValue();
    }

    @Override
    public Double visit(PiNode node) {
        return Math.PI;
    }

    @Override
    public Double visit(SquareRootNode node) {
        double argument = visit(node.getExpression());
        return Math.sqrt(argument);
    }

    @Override
    public Double visit(ENode node) {
        return Math.E;
    }

    @Override
    public Double visit(MultiplicationNode node) {
        double leftValue = visit(node.getLeft());
        double rightValue = visit(node.getRight());
        return leftValue * rightValue;
    }


    @Override
    public Double visit(DivisionNode node) {
        double leftValue = visit(node.getLeft());
        double rightValue = visit(node.getRight());
        if (rightValue == 0) {
            throw new ArithmeticException("Division by zero");
        }
        return leftValue / rightValue;
    }

    @Override
    public Double visit(PowerNode node) {
        double baseValue = visit(node.getLeft());
        double exponentValue = visit(node.getRight());
        return Math.pow(baseValue, exponentValue);
    }

    @Override
    public Double visit(ModNode node) {
        double leftValue = visit(node.getLeft());
        double rightValue = visit(node.getRight());
        return leftValue % rightValue;
    }

    @Override
    public Double visit(NotNode node) {
        double value = visit(node.getExpression());
        if (value == 0) {
            return 1.0; // Return 1 if the value is 0 (false)
        } else if (value == 1) {
            return 0.0; // Return 0 if the value is 1 (true)
        } else {
            throw new IllegalArgumentException("Invalid value for 'not' operation: " + value);
        }
    }


    @Override
    public Double visit(AndNode node) {
        double leftValue = visit(node.getLeft());
        double rightValue = visit(node.getRight());
        if (leftValue == 1 && rightValue == 1) {
            return 1.0; // Return 1 if both values are true
        } else {
            return 0.0; // Return 0 otherwise
        }
    }

    @Override
    public Double visit(OrNode node) {
        double leftValue = visit(node.getLeft());
        double rightValue = visit(node.getRight());
        if (leftValue == 1 || rightValue == 1) {
            return 1.0; // Return 1 if either value is true
        } else {
            return 0.0; // Return 0 otherwise
        }
    }

    @Override
    public Double visit(XorNode node) {
        double leftValue = visit(node.getLeft());
        double rightValue = visit(node.getRight());
        if ((leftValue == 1 && rightValue == 0) || (leftValue == 0 && rightValue == 1)) {
            return 1.0; // Return 1 if one value is true and the other is false
        } else {
            return 0.0; // Return 0 otherwise
        }
    }

    @Override
    public Double visit(NandNode node) {
        double leftValue = visit(node.getLeft());
        double rightValue = visit(node.getRight());
        if (leftValue == 1 && rightValue == 1) {
            return 0.0; // Return 0 if both values are true
        } else {
            return 1.0; // Return 1 otherwise
        }
    }

    @Override
    public Double visit(LogNode node) {
        double value = visit(node.getExpression());
        if (value <= 0) {
            throw new IllegalArgumentException("Logarithm can only be computed for positive numbers");
        }
        return Math.log(value);
    }

    @Override
    public Double visit(FactorialNode node) {
        int value = visit(node.getExpression()).intValue();
        if (value < 0) {
            throw new IllegalArgumentException("Factorial can only be computed for non-negative integers");
        }
        double result = 1;
        for (int i = 2; i <= value; i++) {
            result *= i;
        }
        return result;
    }

    @Override
    public Double visit(CosNode node) {
        double radians = Math.toRadians(visit(node.getExpression()));
        return Math.cos(radians);
    }

    @Override
    public Double visit(TanNode node) {
        double radians = Math.toRadians(visit(node.getExpression()));
        return Math.tan(radians);
    }

    @Override
    public Double visit(CotNode node) {
        double radians = Math.toRadians(visit(node.getExpression()));
        return 1.0 / Math.tan(radians);
    }

    @Override
    public Double visit(SinNode node) {
        double radians = Math.toRadians(visit(node.getExpression()));
        return Math.sin(radians);
    }


}
public class BuildAstVisitor extends MTmathBaseVisitor<ExpressionNode> {
    @Override
    public ExpressionNode visitPlus_op(MTmathParser.Plus_opContext ctx) {
        ExpressionNode left = visit(ctx.NUM(0));
        ExpressionNode right = visit(ctx.NUM(1));
        return new AdditionNode(left, right);
    }

    @Override
    public ExpressionNode visitMinus_op(MTmathParser.Minus_opContext ctx) {
        ExpressionNode left = visit(ctx.NUM(0));
        ExpressionNode right = visit(ctx.NUM(1));
        return new SubtractionNode(left, right);
    }

    // Implement visit methods for other binary operations similarly

    //@Override
    //public ExpressionNode visitNUM(MTmathParser.NUMContext ctx) {
      //  int value = Integer.parseInt(ctx.getText());
       // return new NumberNode(value);
    //}
    @Override
    public ExpressionNode visitMultiply_op(MTmathParser.Multiply_opContext ctx) {
        ExpressionNode left = visit(ctx.NUM(0));
        ExpressionNode right = visit(ctx.NUM(1));
        return new MultiplicationNode(left, right);
    }

    @Override
    public ExpressionNode visitDivide_op(MTmathParser.Divide_opContext ctx) {
        ExpressionNode left = visit(ctx.NUM(0));
        ExpressionNode right = visit(ctx.NUM(1));
        return new DivisionNode(left, right);
    }

    @Override
    public ExpressionNode visitPower_op(MTmathParser.Power_opContext ctx) {
        ExpressionNode left = visit(ctx.NUM(0));
        ExpressionNode right = visit(ctx.NUM(1));
        return new PowerNode(left, right);
    }

    @Override
    public ExpressionNode visitMod_op(MTmathParser.Mod_opContext ctx) {
        ExpressionNode left = visit(ctx.NUM(0));
        ExpressionNode right = visit(ctx.NUM(1));
        return new ModNode(left, right);
    }

    @Override
    public ExpressionNode visitNot_op(MTmathParser.Not_opContext ctx) {
        ExpressionNode expression = visit(ctx.NUM());
        return new NotNode(expression);
    }

    @Override
    public ExpressionNode visitAnd_op(MTmathParser.And_opContext ctx) {
        ExpressionNode left = visit(ctx.NUM(0));
        ExpressionNode right = visit(ctx.NUM(1));
        return new AndNode(left, right);
    }

    @Override
    public ExpressionNode visitOr_op(MTmathParser.Or_opContext ctx) {
        ExpressionNode left = visit(ctx.NUM(0));
        ExpressionNode right = visit(ctx.NUM(1));
        return new OrNode(left, right);
    }

    @Override
    public ExpressionNode visitXor_op(MTmathParser.Xor_opContext ctx) {
        ExpressionNode left = visit(ctx.NUM(0));
        ExpressionNode right = visit(ctx.NUM(1));
        return new XorNode(left, right);
    }

    @Override
    public ExpressionNode visitNand_op(MTmathParser.Nand_opContext ctx) {
        ExpressionNode left = visit(ctx.NUM(0));
        ExpressionNode right = visit(ctx.NUM(1));
        return new NandNode(left, right);
    }

    @Override
    public ExpressionNode visitLog_op(MTmathParser.Log_opContext ctx) {
        ExpressionNode expression = visit(ctx.NUM());
        return new LogNode(expression);
    }

    @Override
    public ExpressionNode visitFactorial_op(MTmathParser.Factorial_opContext ctx) {
        ExpressionNode expression = visit(ctx.NUM());
        return new FactorialNode(expression);
    }
    @Override
    public ExpressionNode visitPi_op(MTmathParser.Pi_opContext ctx) {
        return new PiNode();
    }

    @Override
    public ExpressionNode visitRoot_op(MTmathParser.Root_opContext ctx) {
        ExpressionNode argument = visit(ctx.NUM());
        return new SquareRootNode(argument);
    }

    @Override
    public ExpressionNode visitE_op(MTmathParser.E_opContext ctx) {
        return new ENode();
    }
    @Override
    public ExpressionNode visitSine_op(MTmathParser.Sine_opContext ctx) {
        ExpressionNode expression = visit(ctx.NUM());
        return new SinNode(expression);
    }

    @Override
    public ExpressionNode visitCosine_op(MTmathParser.Cosine_opContext ctx) {
        ExpressionNode expression = visit(ctx.NUM());
        return new CosNode(expression);
    }

    @Override
    public ExpressionNode visitTangent_op(MTmathParser.Tangent_opContext ctx) {
        ExpressionNode expression = visit(ctx.NUM());
        return new TanNode(expression);
    }

    @Override
    public ExpressionNode visitCotangent_op(MTmathParser.Cotangent_opContext ctx) {
        ExpressionNode expression = visit(ctx.NUM());
        return new CotNode(expression);
    }
}
grammar MTmath;

r : calculations + EOF ; // expression syntax

NUM : [0-9]+;
WS : [ \t\r\n]+ -> skip ; // skip spaces, tabs, newlines

ADD : '+';
MINUS : '-';
MULTIPLY : '*';
DIVIDE : '/';
POWER : '^';
MOD : '%';
NOT : '!';
AND : '&&';
OR : '||';
XOR : '^&'; // kanonika o symbolismos toy xor einai to "^" ALLA epidh 8a exei ton idio symbolismo methn dyname (power) 8a to orisoyme me "^&"
NAND : '!&'; // kanonika o symbolismos toy nand einai to "!" ALLA epidh 8a exei ton idio symbolismo methn not 8a to orisoyme me "!&"
SEMICOLON : ';';
LEFTPAR : '(';
RIGHTPAR : ')';
PI : 'pi';
E : 'e';
FACTORIAL : 'f!';

plus_op : NUM ADD NUM SEMICOLON;
minus_op : NUM MINUS NUM SEMICOLON;
multiply_op : NUM MULTIPLY NUM SEMICOLON;
divide_op : NUM DIVIDE NUM SEMICOLON;
power_op : NUM POWER NUM SEMICOLON;
mod_op : NUM MOD NUM SEMICOLON;
not_op : NOT NUM SEMICOLON;
and_op : NUM AND NUM SEMICOLON;
or_op : NUM OR NUM SEMICOLON;
xor_op : NUM XOR NUM SEMICOLON;
nand_op : NUM NAND NUM SEMICOLON;
log_op : 'log' LEFTPAR NUM RIGHTPAR SEMICOLON;
factorial_op : NUM FACTORIAL SEMICOLON;
pi_op : PI SEMICOLON;
root_op : 'sqrt' LEFTPAR NUM RIGHTPAR SEMICOLON;
e_op : E SEMICOLON;

trig_op : sine_op | cosine_op | tangent_op | cotangent_op;
sine_op : 'sin' LEFTPAR NUM RIGHTPAR SEMICOLON;
cosine_op : 'cos' LEFTPAR NUM RIGHTPAR SEMICOLON;
tangent_op : 'tan' LEFTPAR NUM RIGHTPAR SEMICOLON;
cotangent_op : 'cot' LEFTPAR NUM RIGHTPAR SEMICOLON;

calculations : plus_op | minus_op | multiply_op | divide_op | power_op | mod_op | not_op | and_op | or_op | xor_op | nand_op | log_op | factorial_op | pi_op | root_op | e_op | trig_op;
java compiler-construction antlr antlr4
1个回答
0
投票

正如评论中提到的:仍然缺少代码供其他人重现您提到的错误。

在解析树的叶子上,您应该停止

visit
树,并返回“原子”节点(在您的情况下为
NumberNode
)。毕竟,当你遇到
NUM
令牌时,就没有什么可访问的了。

而不是这样做:

@Override
public ExpressionNode visitPlus_op(MTmathParser.Plus_opContext ctx) {
  ExpressionNode left = visit(ctx.NUM(0));
  ExpressionNode right = visit(ctx.NUM(1));
  return new AdditionNode(left, right);
}

尝试这样的事情:

@Override
public ExpressionNode visitPlus_op(MTmathParser.Plus_opContext ctx) {
  ExpressionNode left = new NumberNode(Integer.valueOf(ctx.NUM(0).getText()));
  ExpressionNode right = new NumberNode(Integer.valueOf(ctx.NUM(1).getText()));
  return new AdditionNode(left, right);
}
© www.soinside.com 2019 - 2024. All rights reserved.