Загрузка данных


// FormulaCalculator.cpp
#include "FormulaCalculator.h"
#include <QDebug>
#include <cmath>
#include <QMapIterator>
#include <QStringList>

// Token implementation
Token::Token(Type type, const QString& value) : m_type(type), m_value(value) {}

Token::Type Token::getType() const { return m_type; }
QString Token::getValue() const { return m_value; }

// CalculationResult implementation
CalculationResult::CalculationResult(double value, const QString& table) 
    : m_value(value), m_table(table) {}

double CalculationResult::getValue() const { return m_value; }
QString CalculationResult::getTable() const { return m_table; }
bool CalculationResult::hasTable() const { return !m_table.isEmpty(); }

// FormulaCalculator implementation
FormulaCalculator::FormulaCalculator() {
    // Инициализация зависимостей (вариант 4 - Dependency)
    m_variables = std::make_unique<QMap<QString, double>>();
    m_functions = std::make_unique<QMap<QString, std::function<double(double)>>>();
    m_binaryOperators = std::make_unique<QMap<QString, std::function<double(double, double)>>>();
    
    // Регистрация стандартных функций из math.h
    (*m_functions)["sin"] = [](double x) { return sin(x); };
    (*m_functions)["cos"] = [](double x) { return cos(x); };
    (*m_functions)["tan"] = [](double x) { return tan(x); };
    (*m_functions)["asin"] = [](double x) { return asin(x); };
    (*m_functions)["acos"] = [](double x) { return acos(x); };
    (*m_functions)["atan"] = [](double x) { return atan(x); };
    (*m_functions)["sinh"] = [](double x) { return sinh(x); };
    (*m_functions)["cosh"] = [](double x) { return cosh(x); };
    (*m_functions)["tanh"] = [](double x) { return tanh(x); };
    (*m_functions)["exp"] = [](double x) { return exp(x); };
    (*m_functions)["log"] = [](double x) { return log(x); };
    (*m_functions)["log10"] = [](double x) { return log10(x); };
    (*m_functions)["sqrt"] = [](double x) { return sqrt(x); };
    (*m_functions)["fabs"] = [](double x) { return fabs(x); };
    (*m_functions)["ceil"] = [](double x) { return ceil(x); };
    (*m_functions)["floor"] = [](double x) { return floor(x); };
    
    // Регистрация операторов
    (*m_binaryOperators)["+"] = [](double a, double b) { return a + b; };
    (*m_binaryOperators)["-"] = [](double a, double b) { return a - b; };
    (*m_binaryOperators)["*"] = [](double a, double b) { return a * b; };
    (*m_binaryOperators)["/"] = [](double a, double b) { return a / b; };
    (*m_binaryOperators)["^"] = [](double a, double b) { return pow(a, b); };
}

FormulaCalculator::~FormulaCalculator() = default;

void FormulaCalculator::setVariable(const QString& name, double value) {
    (*m_variables)[name] = value;
}

double FormulaCalculator::getVariable(const QString& name) const {
    return m_variables->value(name, 0.0);
}

bool FormulaCalculator::hasVariable(const QString& name) const {
    return m_variables->contains(name);
}

QMap<QString, double> FormulaCalculator::getAllVariables() const {
    return *m_variables;
}

void FormulaCalculator::clearVariables() {
    m_variables->clear();
}

bool FormulaCalculator::isNumber(const QString& token) const {
    bool ok;
    token.toDouble(&ok);
    return ok;
}

bool FormulaCalculator::isVariable(const QString& token) const {
    // Переменная должна начинаться с буквы и содержать только буквы, цифры и _
    if (token.isEmpty() || !token[0].isLetter())
        return false;
    
    for (const QChar& ch : token) {
        if (!ch.isLetterOrNumber() && ch != '_')
            return false;
    }
    return true;
}

bool FormulaCalculator::isOperator(const QString& token) const {
    return m_binaryOperators->contains(token);
}

bool FormulaCalculator::isFunction(const QString& token) const {
    return m_functions->contains(token);
}

bool FormulaCalculator::isCommand(const QString& token) const {
    return token == "table" || token == "clear";
}

bool FormulaCalculator::isSpecialSymbol(const QChar& ch) const {
    return ch == '(' || ch == ')' || ch == ',' || ch == '=';
}

QVector<Token> FormulaCalculator::tokenize(const QString& formula) {
    QVector<Token> tokens;
    QString current;
    int i = 0;
    
    while (i < formula.length()) {
        QChar ch = formula[i];
        
        // Пропускаем пробелы
        if (ch.isSpace()) {
            i++;
            continue;
        }
        
        // Числа (включая десятичные точки)
        if (ch.isDigit() || ch == '.') {
            current.clear();
            while (i < formula.length() && (formula[i].isDigit() || formula[i] == '.' || 
                   formula[i] == 'e' || formula[i] == 'E' || formula[i] == '+' || formula[i] == '-')) {
                if ((formula[i] == '+' || formula[i] == '-') && !current.isEmpty() && 
                    !current.contains('e') && !current.contains('E')) {
                    break;
                }
                current += formula[i];
                i++;
            }
            tokens.append(Token(Token::Type::NUMBER, current));
            continue;
        }
        
        // Идентификаторы (переменные, функции, команды)
        if (ch.isLetter()) {
            current.clear();
            while (i < formula.length() && (formula[i].isLetterOrNumber() || formula[i] == '_')) {
                current += formula[i];
                i++;
            }
            
            if (isCommand(current)) {
                tokens.append(Token(Token::Type::COMMAND, current));
            } else if (isFunction(current)) {
                tokens.append(Token(Token::Type::FUNCTION, current));
            } else if (isVariable(current)) {
                tokens.append(Token(Token::Type::VARIABLE, current));
            } else {
                // Неизвестный идентификатор
                tokens.append(Token(Token::Type::VARIABLE, current));
            }
            continue;
        }
        
        // Операторы и спецсимволы
        if (isOperator(QString(ch)) || isSpecialSymbol(ch)) {
            tokens.append(Token(Token::Type::OPERATOR, QString(ch)));
            i++;
            continue;
        }
        
        // Неизвестный символ
        tokens.append(Token(Token::Type::SPECIAL, QString(ch)));
        i++;
    }
    
    return tokens;
}

double FormulaCalculator::applyFunction(const QString& funcName, double arg) {
    if (m_functions->contains(funcName)) {
        return (*m_functions)[funcName](arg);
    }
    throw std::runtime_error("Unknown function: " + funcName.toStdString());
}

double FormulaCalculator::applyOperator(const QString& op, double left, double right) {
    if (m_binaryOperators->contains(op)) {
        return (*m_binaryOperators)[op](left, right);
    }
    throw std::runtime_error("Unknown operator: " + op.toStdString());
}

int FormulaCalculator::getPrecedence(const QString& op) const {
    if (op == "+" || op == "-") return 1;
    if (op == "*" || op == "/") return 2;
    if (op == "^") return 3;
    return 0;
}

bool FormulaCalculator::isRightAssociative(const QString& op) const {
    return op == "^";
}

double FormulaCalculator::parseExpression(const QVector<Token>& tokens, int& pos) {
    double left = parseTerm(tokens, pos);
    
    while (pos < tokens.size()) {
        Token token = tokens[pos];
        if (token.getType() == Token::Type::OPERATOR) {
            QString op = token.getValue();
            if (op == "+" || op == "-") {
                pos++;
                double right = parseTerm(tokens, pos);
                left = applyOperator(op, left, right);
                continue;
            }
        }
        break;
    }
    
    return left;
}

double FormulaCalculator::parseTerm(const QVector<Token>& tokens, int& pos) {
    double left = parseFactor(tokens, pos);
    
    while (pos < tokens.size()) {
        Token token = tokens[pos];
        if (token.getType() == Token::Type::OPERATOR) {
            QString op = token.getValue();
            if (op == "*" || op == "/") {
                pos++;
                double right = parseFactor(tokens, pos);
                left = applyOperator(op, left, right);
                continue;
            }
        }
        break;
    }
    
    return left;
}

double FormulaCalculator::parseFactor(const QVector<Token>& tokens, int& pos) {
    if (pos >= tokens.size()) {
        throw std::runtime_error("Unexpected end of expression");
    }
    
    Token token = tokens[pos];
    pos++;
    
    if (token.getType() == Token::Type::NUMBER) {
        return token.getValue().toDouble();
    }
    
    if (token.getType() == Token::Type::VARIABLE) {
        QString varName = token.getValue();
        if (hasVariable(varName)) {
            return getVariable(varName);
        }
        throw std::runtime_error("Undefined variable: " + varName.toStdString());
    }
    
    if (token.getType() == Token::Type::FUNCTION) {
        if (pos < tokens.size() && tokens[pos].getValue() == "(") {
            pos++; // пропускаем (
            double arg = parseExpression(tokens, pos);
            if (pos < tokens.size() && tokens[pos].getValue() == ")") {
                pos++; // пропускаем )
                return applyFunction(token.getValue(), arg);
            }
        }
        throw std::runtime_error("Invalid function syntax");
    }
    
    if (token.getType() == Token::Type::OPERATOR && token.getValue() == "(") {
        double expr = parseExpression(tokens, pos);
        if (pos < tokens.size() && tokens[pos].getValue() == ")") {
            pos++;
            return expr;
        }
        throw std::runtime_error("Missing closing parenthesis");
    }
    
    if (token.getType() == Token::Type::OPERATOR && token.getValue() == "-") {
        return -parseFactor(tokens, pos);
    }
    
    throw std::runtime_error("Unexpected token: " + token.getValue().toStdString());
}

double FormulaCalculator::evaluate(const QVector<Token>& tokens, CalculationResult& result) {
    int pos = 0;
    double value = parseExpression(tokens, pos);
    
    // Проверка на команды в конце
    while (pos < tokens.size()) {
        if (tokens[pos].getType() == Token::Type::COMMAND) {
            QString cmd = tokens[pos].getValue();
            if (cmd == "table") {
                // Ожидается таблица для переменной x
                // Формат: выражение table x start end steps
                // Упрощенная реализация
                result = CalculationResult(value, generateTable("x", "x", -10, 10, 20));
            } else if (cmd == "clear") {
                clearVariables();
            }
        }
        pos++;
    }
    
    return value;
}

QString FormulaCalculator::generateTable(const QString& formula, const QString& variable,
                                          double start, double end, int steps) {
    QString table;
    table += QString("Table for %1 from %2 to %3 (%4 steps):\n")
             .arg(formula).arg(start).arg(end).arg(steps);
    table += "----------------------------------------\n";
    table += QString("%1\t|\tValue\n").arg(variable);
    table += "----------------------------------------\n";
    
    double step = (end - start) / steps;
    for (int i = 0; i <= steps; i++) {
        double x = start + i * step;
        // Сохраняем текущее значение переменной
        double oldValue = getVariable(variable);
        setVariable(variable, x);
        
        try {
            QVector<Token> tokens = tokenize(formula);
            CalculationResult tempResult;
            double result = evaluate(tokens, tempResult);
            table += QString("%1\t|\t%2\n").arg(x).arg(result);
        } catch (const std::exception& e) {
            table += QString("%1\t|\tError: %2\n").arg(x).arg(e.what());
        }
        
        // Восстанавливаем значение
        if (oldValue != 0.0 || hasVariable(variable)) {
            setVariable(variable, oldValue);
        } else {
            clearVariables();
        }
    }
    
    return table;
}

CalculationResult FormulaCalculator::parseAndCalculate(const QString& formula) {
    try {
        QVector<Token> tokens = tokenize(formula);
        CalculationResult result;
        double value = evaluate(tokens, result);
        if (!result.hasTable()) {
            result = CalculationResult(value);
        }
        return result;
    } catch (const std::exception& e) {
        return CalculationResult(0.0, QString("Error: %1").arg(e.what()));
    }
}