#include <stack>
#include <string>
#include <iostream>
#include <array>
#include <iomanip>
#include <utility>
std::string quote(std::string s)
{
return '"' + s + '"';
}
template <typename T>
T pop_top(std::stack<T>& stack)
{
T result = stack.top();
stack.pop();
return result;
}
// returns a bool/index pair. If .first is true, then the parens balance, and .second
// should be ignored. If .first is false, then the parens don't balance, and .second
// is the "index" where the offending paren was found, or if more parens were required
// it is one past the end.
std::pair<bool, std::size_t> parens_balance(const std::string& s)
{
unsigned left_paren_count = 0;
unsigned right_paren_count = 0;
// char expression = 'a' ;
std::stack<char> stack;
auto ss = s.begin();
while (ss != s.end())
{
char ch = *ss++;
if (ch == '(')
{
stack.push(ch);
// stack.push(expression++);
++left_paren_count;
}
else if (ch == ')')
{
if (++right_paren_count > left_paren_count || stack.empty())
return std::make_pair(false, ss - s.begin() - 1);
// auto indent_level = left_paren_count - right_paren_count;
while (!stack.empty() && (ch = pop_top(stack)) != '(')
/*std::cout << std::string(indent_level, ' ') << ch << '\n'*/;
}
}
std::size_t index = s.size();
if (stack.empty() && left_paren_count < right_paren_count)
--index;
return std::make_pair(stack.empty() && left_paren_count == right_paren_count, index);
}
void report_unbalanced_parens(const std::string& expr, std::size_t index)
{
std::cout << "Unbalanced parentheses detected in " << quote(expr) << ":\n\t";
std::cout << expr << "\n\t";
std::cout << std::string(index, ' ') << "^\n";
}
int main()
{
std::array<std::string, 10> expressions =
{
"(()(()))()(()", // invalid
"(()(()))()(())", // valid
"()", // valid
")", // invalid
"(", // invalid
"()()()", // valid
"(((()))((())))", // valid
"))((", // invalid
"())(", // invalid
"(()(", // invalid
};
for (auto& expression : expressions)
{
auto ret = parens_balance(expression);
if (ret.first)
std::cout << quote(expression) << " has balanced parentheses.\n";
else
report_unbalanced_parens(expression, ret.second);
std::cout << '\n';
}
}
I2luY2x1ZGUgPHN0YWNrPgojaW5jbHVkZSA8c3RyaW5nPgojaW5jbHVkZSA8aW9zdHJlYW0+CiNpbmNsdWRlIDxhcnJheT4KI2luY2x1ZGUgPGlvbWFuaXA+CiNpbmNsdWRlIDx1dGlsaXR5PgoKc3RkOjpzdHJpbmcgcXVvdGUoc3RkOjpzdHJpbmcgcykKewogICAgcmV0dXJuICciJyArIHMgKyAnIic7Cn0KCnRlbXBsYXRlIDx0eXBlbmFtZSBUPgpUIHBvcF90b3Aoc3RkOjpzdGFjazxUPiYgc3RhY2spCnsKICAgIFQgcmVzdWx0ID0gc3RhY2sudG9wKCk7CiAgICBzdGFjay5wb3AoKTsKICAgIHJldHVybiByZXN1bHQ7Cn0KCi8vIHJldHVybnMgYSBib29sL2luZGV4IHBhaXIuICBJZiAuZmlyc3QgaXMgdHJ1ZSwgdGhlbiB0aGUgcGFyZW5zIGJhbGFuY2UsIGFuZCAuc2Vjb25kCi8vIHNob3VsZCBiZSBpZ25vcmVkLiAgSWYgLmZpcnN0IGlzIGZhbHNlLCB0aGVuIHRoZSBwYXJlbnMgZG9uJ3QgYmFsYW5jZSwgYW5kIC5zZWNvbmQKLy8gaXMgdGhlICJpbmRleCIgd2hlcmUgdGhlIG9mZmVuZGluZyBwYXJlbiB3YXMgZm91bmQsIG9yIGlmIG1vcmUgcGFyZW5zIHdlcmUgcmVxdWlyZWQKLy8gaXQgaXMgb25lIHBhc3QgdGhlIGVuZC4Kc3RkOjpwYWlyPGJvb2wsIHN0ZDo6c2l6ZV90PiBwYXJlbnNfYmFsYW5jZShjb25zdCBzdGQ6OnN0cmluZyYgcykKewogICAgdW5zaWduZWQgbGVmdF9wYXJlbl9jb3VudCA9IDA7CiAgICB1bnNpZ25lZCByaWdodF9wYXJlbl9jb3VudCA9IDA7CiAgICAvLyBjaGFyIGV4cHJlc3Npb24gPSAnYScgOwoKICAgIHN0ZDo6c3RhY2s8Y2hhcj4gc3RhY2s7CgogICAgYXV0byBzcyA9IHMuYmVnaW4oKTsKICAgIHdoaWxlIChzcyAhPSBzLmVuZCgpKQogICAgewogICAgICAgIGNoYXIgY2ggPSAqc3MrKzsKCiAgICAgICAgaWYgKGNoID09ICcoJykKICAgICAgICB7CiAgICAgICAgICAgIHN0YWNrLnB1c2goY2gpOwogICAgICAgICAgICAvLyBzdGFjay5wdXNoKGV4cHJlc3Npb24rKyk7CgogICAgICAgICAgICArK2xlZnRfcGFyZW5fY291bnQ7CiAgICAgICAgfQogICAgICAgIGVsc2UgaWYgKGNoID09ICcpJykKICAgICAgICB7CiAgICAgICAgICAgIGlmICgrK3JpZ2h0X3BhcmVuX2NvdW50ID4gbGVmdF9wYXJlbl9jb3VudCB8fCBzdGFjay5lbXB0eSgpKQogICAgICAgICAgICAgICAgcmV0dXJuIHN0ZDo6bWFrZV9wYWlyKGZhbHNlLCBzcyAtIHMuYmVnaW4oKSAtIDEpOwoKICAgICAgICAgICAgLy8gYXV0byBpbmRlbnRfbGV2ZWwgPSBsZWZ0X3BhcmVuX2NvdW50IC0gcmlnaHRfcGFyZW5fY291bnQ7CgogICAgICAgICAgICB3aGlsZSAoIXN0YWNrLmVtcHR5KCkgJiYgKGNoID0gcG9wX3RvcChzdGFjaykpICE9ICcoJykKICAgICAgICAgICAgICAgIC8qc3RkOjpjb3V0IDw8IHN0ZDo6c3RyaW5nKGluZGVudF9sZXZlbCwgJyAnKSA8PCBjaCA8PCAnXG4nKi87CiAgICAgICAgfQogICAgfQoKICAgIHN0ZDo6c2l6ZV90IGluZGV4ID0gcy5zaXplKCk7CiAgICBpZiAoc3RhY2suZW1wdHkoKSAmJiBsZWZ0X3BhcmVuX2NvdW50IDwgcmlnaHRfcGFyZW5fY291bnQpCiAgICAgICAgLS1pbmRleDsKCiAgICByZXR1cm4gc3RkOjptYWtlX3BhaXIoc3RhY2suZW1wdHkoKSAmJiBsZWZ0X3BhcmVuX2NvdW50ID09IHJpZ2h0X3BhcmVuX2NvdW50LCBpbmRleCk7Cn0KCnZvaWQgcmVwb3J0X3VuYmFsYW5jZWRfcGFyZW5zKGNvbnN0IHN0ZDo6c3RyaW5nJiBleHByLCBzdGQ6OnNpemVfdCBpbmRleCkKewogICAgc3RkOjpjb3V0IDw8ICJVbmJhbGFuY2VkIHBhcmVudGhlc2VzIGRldGVjdGVkIGluICIgPDwgcXVvdGUoZXhwcikgPDwgIjpcblx0IjsKICAgIHN0ZDo6Y291dCA8PCBleHByIDw8ICJcblx0IjsKICAgIHN0ZDo6Y291dCA8PCBzdGQ6OnN0cmluZyhpbmRleCwgJyAnKSA8PCAiXlxuIjsKfQoKaW50IG1haW4oKQp7CiAgICBzdGQ6OmFycmF5PHN0ZDo6c3RyaW5nLCAxMD4gZXhwcmVzc2lvbnMgPSAKICAgIHsgCiAgICAgICAgIigoKSgoKSkpKCkoKCkiLCAgICAgICAgLy8gaW52YWxpZAogICAgICAgICIoKCkoKCkpKSgpKCgpKSIsICAgICAgIC8vIHZhbGlkCiAgICAgICAgIigpIiwgICAgICAgICAgICAgICAgICAgLy8gdmFsaWQKICAgICAgICAiKSIsICAgICAgICAgICAgICAgICAgICAvLyBpbnZhbGlkCiAgICAgICAgIigiLCAgICAgICAgICAgICAgICAgICAgLy8gaW52YWxpZAogICAgICAgICIoKSgpKCkiLCAgICAgICAgICAgICAgIC8vIHZhbGlkCiAgICAgICAgIigoKCgpKSkoKCgpKSkpIiwgICAgICAgLy8gdmFsaWQKICAgICAgICAiKSkoKCIsICAgICAgICAgICAgICAgICAvLyBpbnZhbGlkCiAgICAgICAgIigpKSgiLCAgICAgICAgICAgICAgICAgLy8gaW52YWxpZAogICAgICAgICIoKCkoIiwgICAgICAgICAgICAgICAgIC8vIGludmFsaWQKICAgIH07CgogICAgZm9yIChhdXRvJiBleHByZXNzaW9uIDogZXhwcmVzc2lvbnMpCiAgICB7CiAgICAgICAgYXV0byByZXQgPSBwYXJlbnNfYmFsYW5jZShleHByZXNzaW9uKTsKICAgICAgICBpZiAocmV0LmZpcnN0KQogICAgICAgICAgICBzdGQ6OmNvdXQgPDwgcXVvdGUoZXhwcmVzc2lvbikgPDwgIiBoYXMgYmFsYW5jZWQgcGFyZW50aGVzZXMuXG4iOwogICAgICAgIGVsc2UKICAgICAgICAgICAgcmVwb3J0X3VuYmFsYW5jZWRfcGFyZW5zKGV4cHJlc3Npb24sIHJldC5zZWNvbmQpOwoKICAgICAgICBzdGQ6OmNvdXQgPDwgJ1xuJzsKICAgIH0KfQ==