#include "expressionevaluator.h" namespace { // 递归下降解析器:expression := term (('+'|'-') term)* // term := factor (('*'|'/') factor)* // factor := ('+'|'-') factor | '(' expression ')' | number // 括号会先被完整求值,天然实现"优先级提升";乘除法在 term 层处理, // 天然高于 expression 层的加减法。 // 【Day3 calculator_mainwindow】与 ../calculator_designer_ext/ 版一字不差。 class Parser { public: explicit Parser(const QString& text) : m_text(text) {} ExpressionEvaluator::Result parse() { ExpressionEvaluator::Result result; skipSpaces(); if (atEnd()) { result.errorMessage = QStringLiteral("表达式为空"); return result; } bool ok = true; const double value = parseExpression(ok); skipSpaces(); if (!ok) { result.errorMessage = m_error; return result; } if (!atEnd()) { result.errorMessage = QStringLiteral("表达式包含无法识别的字符"); return result; } result.ok = true; result.value = value; return result; } private: double parseExpression(bool& ok) { double value = parseTerm(ok); while (ok) { skipSpaces(); if (peek() == QLatin1Char('+')) { advance(); value += parseTerm(ok); } else if (peek() == QLatin1Char('-')) { advance(); value -= parseTerm(ok); } else { break; } } return value; } double parseTerm(bool& ok) { double value = parseFactor(ok); while (ok) { skipSpaces(); if (peek() == QLatin1Char('*')) { advance(); value *= parseFactor(ok); } else if (peek() == QLatin1Char('/')) { advance(); const double rhs = parseFactor(ok); if (!ok) return 0.0; if (rhs == 0.0) { fail(QStringLiteral("除数不能为零"), ok); return 0.0; } value /= rhs; } else { break; } } return value; } double parseFactor(bool& ok) { skipSpaces(); if (peek() == QLatin1Char('+')) { advance(); return parseFactor(ok); } if (peek() == QLatin1Char('-')) { advance(); return -parseFactor(ok); } if (peek() == QLatin1Char('(')) { advance(); const double value = parseExpression(ok); if (!ok) return 0.0; skipSpaces(); if (peek() != QLatin1Char(')')) { fail(QStringLiteral("括号不匹配"), ok); return 0.0; } advance(); return value; } return parseNumber(ok); } double parseNumber(bool& ok) { skipSpaces(); const int start = m_pos; bool hasDigits = false; while (!atEnd() && peek().isDigit()) { advance(); hasDigits = true; } if (!atEnd() && peek() == QLatin1Char('.')) { advance(); while (!atEnd() && peek().isDigit()) { advance(); hasDigits = true; } } if (!hasDigits) { fail(QStringLiteral("表达式格式错误,缺少数字"), ok); return 0.0; } const QString token = m_text.mid(start, m_pos - start); bool numOk = false; const double value = token.toDouble(&numOk); if (!numOk) { fail(QStringLiteral("数字格式错误"), ok); return 0.0; } return value; } void skipSpaces() { while (!atEnd() && peek().isSpace()) advance(); } bool atEnd() const { return m_pos >= m_text.size(); } QChar peek() const { return atEnd() ? QChar() : m_text.at(m_pos); } void advance() { ++m_pos; } void fail(const QString& message, bool& ok) { ok = false; m_error = message; } const QString& m_text; int m_pos = 0; QString m_error; }; } // namespace ExpressionEvaluator::Result ExpressionEvaluator::evaluate(const QString& expression) { Parser parser(expression); return parser.parse(); }