/
javapractice
/
java-practice-antlr4
Обзор
Документация
Войти
/
javapractice
/
java-practice-antlr4
Код
Запросы
0
Задачи
Пакеты
0
Релизы
0
CI/CD
Аналитика
master
src/main/java/com/example/calc/EvalVisitor.java
132 строки
5 KB
Кузьма Даждъбогин
Javadoc на классах, методах и unit-тестах
08 авг 2026, 11:37
08 авг 2026, 11:37
e717695
Код
Авторство
О чём код?
package com.example.calc; import org.antlr.v4.runtime.Token; /** * Вычислитель выражения по дереву разбора: метод на каждую метку * альтернативы грамматики {@code Calc.g4}, каждый узел возвращает * значение типа {@code double}. * * <p>Принятые конвенции (см. docs/analitic.md, раздел 3):</p> * <ul> * <li>степень {@code ^} правоассоциативна: {@code 2^3^2} = 512;</li> * <li>унарный минус связывает сильнее степени: * {@code -2^2} = {@code (-2)^2} = 4;</li> * <li>небесконечный результат обязателен: деление на ноль и переполнение * степени дают {@link CalcException}, а не Infinity/NaN.</li> * </ul> */ public class EvalVisitor extends CalcBaseVisitor<Double> { /** * Вычисляет стартовое правило: значение всего выражения до якоря EOF. * * @param ctx контекст правила {@code prog} * @return значение выражения */ @Override public Double visitProg(CalcParser.ProgContext ctx) { return visit(ctx.expr()); } /** * Унарный минус: {@code -x}. * * @param ctx контекст альтернативы {@code UnaryMinus} * @return значение операнда с обратным знаком */ @Override public Double visitUnaryMinus(CalcParser.UnaryMinusContext ctx) { return -visit(ctx.expr()); } /** * Возведение в степень {@code ^} через {@link Math#pow}. * * @param ctx контекст альтернативы {@code Power} * @return результат возведения в степень * @throws CalcException если результат не является конечным числом */ @Override public Double visitPower(CalcParser.PowerContext ctx) { double left = visit(ctx.expr(0)); double right = visit(ctx.expr(1)); return checkFinite(Math.pow(left, right), ctx.POW().getSymbol()); } /** * Умножение и деление, левоассоциативно. * * @param ctx контекст альтернативы {@code MulDiv} * @return результат операции * @throws CalcException при делении на ноль или переполнении */ @Override public Double visitMulDiv(CalcParser.MulDivContext ctx) { double left = visit(ctx.expr(0)); double right = visit(ctx.expr(1)); if (ctx.op.getType() == CalcParser.MUL) { return checkFinite(left * right, ctx.op); } return checkFinite(left / right, ctx.op); } /** * Сложение и вычитание, левоассоциативно. * * @param ctx контекст альтернативы {@code AddSub} * @return результат операции * @throws CalcException при переполнении */ @Override public Double visitAddSub(CalcParser.AddSubContext ctx) { double left = visit(ctx.expr(0)); double right = visit(ctx.expr(1)); if (ctx.op.getType() == CalcParser.ADD) { return checkFinite(left + right, ctx.op); } return checkFinite(left - right, ctx.op); } /** * Скобки: возвращает значение вложенного выражения. * * @param ctx контекст альтернативы {@code Parens} * @return значение выражения в скобках */ @Override public Double visitParens(CalcParser.ParensContext ctx) { return visit(ctx.expr()); } /** * Литерал числа: целые и дробные числа разбираются единообразно * через {@link Double#parseDouble}, разделитель — точка, без влияния * системной локали. * * @param ctx контекст альтернативы {@code Number} * @return числовое значение литерала */ @Override public Double visitNumber(CalcParser.NumberContext ctx) { return Double.parseDouble(ctx.NUMBER().getText()); } /** * Проверяет, что результат операции — конечное число. * * @param value результат операции * @param op токен оператора для позиции в сообщении об ошибке * @return {@code value}, если оно конечно * @throws CalcException если результат Infinity или NaN */ private static double checkFinite(double value, Token op) { if (!Double.isFinite(value)) { throw new CalcException("Evaluation error at position " + op.getCharPositionInLine() + ": result of '" + op.getText() + "' is not a finite number" + " (division by zero or overflow)"); } return value; } }