138 lines
3.8 KiB
C++
138 lines
3.8 KiB
C++
#include <cassert>
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <variant>
|
|
#include <vector>
|
|
#include <optional>
|
|
#include <stack>
|
|
|
|
|
|
struct Token {
|
|
std::variant<char, int> token;
|
|
|
|
explicit Token(char c) : token(c) {}
|
|
explicit Token(int x) : token(x) {}
|
|
|
|
[[nodiscard]] bool is_operator() const {
|
|
return std::holds_alternative<char>(token);
|
|
}
|
|
|
|
[[nodiscard]] char get_operator() const {
|
|
if (!is_operator()) { throw std::invalid_argument("Not an operator"); }
|
|
return std::get<char>(token);
|
|
}
|
|
|
|
[[nodiscard]] int get_number() const {
|
|
if (is_operator()) { throw std::invalid_argument("Is an operator"); }
|
|
return std::get<int>(token);
|
|
}
|
|
|
|
bool operator==(char c) const {
|
|
if (!is_operator()) { return false; }
|
|
return get_operator() == c;
|
|
}
|
|
|
|
bool operator==(int x) const {
|
|
if (is_operator()) { return false; }
|
|
return get_number() == x;
|
|
}
|
|
|
|
template <typename T>
|
|
bool operator!=(T x) {
|
|
return !(*this == x);
|
|
}
|
|
};
|
|
|
|
using Expression = std::vector<Token>;
|
|
|
|
Expression parse_string(const std::string& str) {
|
|
Expression expression;
|
|
std::string temp_token;
|
|
for (char c : str) {
|
|
if (!(c > '0' && c < '9')) {
|
|
if (!temp_token.empty()) {
|
|
expression.emplace_back(std::stoi(temp_token));
|
|
temp_token.clear();
|
|
}
|
|
expression.emplace_back(c);
|
|
} else {
|
|
temp_token += c;
|
|
}
|
|
}
|
|
if (!temp_token.empty()) { expression.emplace_back(std::stoi(temp_token)); }
|
|
return expression;
|
|
}
|
|
|
|
void calculate_chunk(std::stack<Token>& undealt_tokens, std::stack<Token>& ready_tokens) {
|
|
while (!undealt_tokens.empty() && undealt_tokens.top() != '(') {
|
|
ready_tokens.push(undealt_tokens.top());
|
|
undealt_tokens.pop();
|
|
}
|
|
int temp_result = ready_tokens.top().get_number();
|
|
ready_tokens.pop();
|
|
while (!ready_tokens.empty()) {
|
|
char op = ready_tokens.top().get_operator();
|
|
ready_tokens.pop();
|
|
if (op == '+') {
|
|
temp_result += ready_tokens.top().get_number();
|
|
} else if (op == '-') {
|
|
temp_result -= ready_tokens.top().get_number();
|
|
} else {
|
|
throw std::logic_error("Unexpected operator token in chunk.");
|
|
}
|
|
ready_tokens.pop();
|
|
}
|
|
if (!undealt_tokens.empty()) {
|
|
undealt_tokens.pop();
|
|
}
|
|
undealt_tokens.emplace(temp_result);
|
|
}
|
|
|
|
int calculate(const Expression& expression) {
|
|
// 策略:
|
|
// 遇到 * / 直接算(本质上是把上一个子 expression 倒栈)
|
|
// 遇到右括号 / 结尾开始倒栈
|
|
// 对于倒栈,只剩下 +- 需要处理。
|
|
std::stack<Token> undealt_tokens, ready_tokens;
|
|
std::optional<Token> temp_token;
|
|
|
|
for (const auto& token : expression) {
|
|
if (token == '*' || token == '/') {
|
|
temp_token = token;
|
|
continue;
|
|
}
|
|
if (temp_token.has_value()) {
|
|
int a = undealt_tokens.top().get_number();
|
|
undealt_tokens.pop();
|
|
undealt_tokens.emplace(
|
|
temp_token == '*' ? a * token.get_number() : a / token.get_number()
|
|
);
|
|
temp_token.reset();
|
|
continue;
|
|
}
|
|
if (token == ')') {
|
|
calculate_chunk(undealt_tokens, ready_tokens);
|
|
continue;
|
|
}
|
|
undealt_tokens.push(token);
|
|
}
|
|
calculate_chunk(undealt_tokens, ready_tokens);
|
|
assert(undealt_tokens.size() == 1);
|
|
return undealt_tokens.top().get_number();
|
|
}
|
|
|
|
int n;
|
|
std::string s;
|
|
|
|
int main() {
|
|
std::ios::sync_with_stdio(false);
|
|
std::cin.tie(nullptr);
|
|
std::cin >> n;
|
|
for (int _ = 0; _ < n; _++) {
|
|
std::cin >> s;
|
|
std::cout << calculate(parse_string(s)) << std::endl;
|
|
}
|
|
|
|
return 0;
|
|
}
|