java - ANTLR 4 如何处理一元/负数

标签 java antlr4

我正在尝试使用 Antlr 4 设置一个简单的计算器。

语法:

grammar calcGrammar;
input : expression EOF;
expression :
    MINUS expression #unaryMinusExpr
    | expression op=(MULTIPLY | DIVIDE) expression #multiplicationExpr
    | expression op=(MINUS | ADD) expression #additiveExpr
    | NUMBER #num
    ;

NUMBER : [0-9]+ ;
DOUBLE : NUMBER '.' NUMBER;

LPAR  : '(';
RPAR  : ')';
ADD : ('+');
MINUS : ('-');
DIVIDE : ('/');
MULTIPLY : ('*');

Java 代码:

public class Listener extends ListenerBaseVisitor {
@Override
public Object visitUnaryMinusExpr(ArithmeticGrammarParser.UnaryMinusExprContext ctx) {
System.out.println(ctx.children.get(0).getText());
}

    @Override
public Object visitAdditiveExpr(ArithmeticGrammarParser.AdditiveExprContext ctx) {
    System.out.println(ctx.children.get(0).getText());
    System.out.println(ctx.children.get(1).getText());
}

如果我的输入是 2 - -2。代码永远不会使用此输入进入此方法。请注意,输入有一个负一元运算符,这应该被视为“-2”。当我在方法中放置调试点时,永远不会进入。

根据我的语法设置,是否应该始终首先考虑一元减号?

编辑:当同时实现一元表达式和成瘾表达式时,似乎会出现此错误。在这种情况下,程序不会进入输入“2 - -2”的一元方法

最佳答案

With my grammar setup should it not be the case that it should always take into consideration the unary minus first?

是的,应该(而且确实如此)。

我猜你最近没有重新生成解析器和词法分析器类,因为考虑到你的语法(我只添加了 SPACE : [\t\r\n] ->skip;),当我运行这个类时:

import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTreeWalker;

public class Main {

    static class Listener extends calcGrammarBaseListener {

        @Override
        public void enterUnaryMinusExpr(calcGrammarParser.UnaryMinusExprContext ctx) {
            System.out.println("enterUnaryMinusExpr: " + ctx.getText());
        }

        @Override
        public void enterAdditiveExpr(calcGrammarParser.AdditiveExprContext ctx) {
            System.out.println("enterAdditiveExpr: " + ctx.getText());
        }
    }

    public static void main(String[] args) {
        String source = "2 - -2";
        calcGrammarLexer lexer = new calcGrammarLexer(CharStreams.fromString(source));
        calcGrammarParser parser = new calcGrammarParser(new CommonTokenStream(lexer));
        ParseTreeWalker.DEFAULT.walk(new Listener(), parser.input());
    }
}

打印以下内容:

enterAdditiveExpr: 2--2
enterUnaryMinusExpr: -2

对于访问者,您需要实现所有访问方法,如下所示:

import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;

public class Main {

    static class Visitor extends calcGrammarBaseVisitor<Integer> {

        @Override
        public Integer visitInput(calcGrammarParser.InputContext ctx) {
            System.out.println("visitInput: " + ctx.getText());
            return visit(ctx.expression());
        }

        @Override
        public Integer visitUnaryMinusExpr(calcGrammarParser.UnaryMinusExprContext ctx) {
            System.out.println("visitUnaryMinusExpr: " + ctx.getText());
            return -1 * visit(ctx.expression());
        }

        @Override
        public Integer visitNum(calcGrammarParser.NumContext ctx) {
            System.out.println("visitNum: " + ctx.getText());
            return Integer.parseInt(ctx.getText());
        }

        @Override
        public Integer visitMultiplicationExpr(calcGrammarParser.MultiplicationExprContext ctx) {
            System.out.println("visitMultiplicationExpr: " + ctx.getText());
            if (ctx.op.getType() == calcGrammarLexer.MULTIPLY) {
                return visit(ctx.expression(0)) * visit(ctx.expression(1));
            }
            return visit(ctx.expression(0)) / visit(ctx.expression(1));
        }

        @Override
        public Integer visitAdditiveExpr(calcGrammarParser.AdditiveExprContext ctx) {
            System.out.println("visitAdditiveExpr: " + ctx.getText());
            if (ctx.op.getType() == calcGrammarLexer.ADD) {
                return visit(ctx.expression(0)) + visit(ctx.expression(1));
            }
            return visit(ctx.expression(0)) - visit(ctx.expression(1));
        }
    }

    public static void main(String[] args) {
        String expression = "2 - -2";
        calcGrammarLexer lexer = new calcGrammarLexer(CharStreams.fromString(expression));
        calcGrammarParser parser = new calcGrammarParser(new CommonTokenStream(lexer));
        Integer answer = new Visitor().visit(parser.input());
        System.out.printf("%s = %s\n", expression, answer);
    }
}

将打印:

visitInput: 2--2<EOF>
visitAdditiveExpr: 2--2
visitNum: 2
visitUnaryMinusExpr: -2
visitNum: 2
2 - -2 = 4

这是一个表达式解析器/求值器的小演示,包括使用 ANTLR4 + 访问者的基本循环和 if 语句:https://github.com/bkiers/Mu

关于java - ANTLR 4 如何处理一元/负数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48694645/

相关文章:

java - 无法使用 PrintWriter 在文件中写入

Java CRC32 : not the same as CRC from C#

testing - Windows7 上的 Antlr4 - 当使用 -gui 开关调用 TestRig 时,解析树检查器不会弹出

antlr4-无法将 Hello 加载为词法分析器或解析器

java - 为什么解析树可视化和我的访问者/听众遍历之间存在这样的差异?

java - ANTLR 通配符运算符不消耗预期输入

java - 想要在jTable中创建一个列,该列是一个复选框,但是运行时显示为 'class java.lang.Boolean'

java - IntStream导致将数组元素错误地设置为0(JVM Bug,Java 11)

java - 计算从旋转字符串中找到原始字符串所需的旋转次数的替代方法

java - 如何使用antlr解析值中带有空格的标签?