Language: C++

#include <functional>
#include <iostream>
#include <string>
#include <unordered_set>
#include <vector>
#define loop(i, a, n) for (int i = (a); i < (n); i++)
#define rep(i, n) loop(i, 0, n)
template<typename A> using F = std::function<A>;
using namespace std;
 
template<typename T> struct ParseResult {
  bool succeeded;
  T object;
  int pos;
  ParseResult(const bool succeeded, const T &object, const int pos) : succeeded(succeeded), object(object), pos(pos) {}
  friend std::ostream &operator<<(std::ostream &os, const ParseResult<T> &p) { return os << '{' << (p.succeeded ? "true" : "false") << ',' << p.object << ',' << p.pos << '}'; }
};
 
template<typename T> using Parser = std::function<ParseResult<T>(const std::string&, int)>;
 
Parser<std::string> token(std::string s) {
  const auto n = s.size();
  return [n = std::move(n), s = std::move(s)](const std::string &target, const int pos) {
    if (target.size() < n) return ParseResult<std::string>(false, {}, pos);
    return target.substr(pos, n) == s ? ParseResult<std::string>(true, s, pos + n) : ParseResult<std::string>(false, {}, pos);
  };
}
 
template<typename T> Parser<T> operator||(Parser<T> p1, Parser<T> p2) {
  return [p1 = std::move(p1), p2 = std::move(p2)](const std::string &target, const int pos) {
    auto r = p1(target, pos);
    if (r.succeeded) return r;
    r = p2(target, pos);
    if (r.succeeded) return r;
    return ParseResult<T>(false, {}, pos);
  };
}
 
template<typename T1, typename T2> Parser<std::pair<T1, T2>> operator+(Parser<T1> p1, Parser<T2> p2) {
  return[p1 = std::move(p1), p2 = std::move(p2)](const std::string &target, const int pos) {
    auto r1 = p1(target, pos);
    if (!r1.succeeded) return ParseResult<std::pair<T1, T2>>(false, {}, pos);
    auto r2 = p2(target, r1.pos);
    if (!r2.succeeded) return ParseResult<std::pair<T1, T2>>(false, {}, pos);
    return ParseResult<std::pair<T1, T2>>(true, {r1.object, r2.object}, r2.pos);
  };
}
 
template<typename T1, typename T2> Parser<T2> operator>>(Parser<T1> p1, Parser<T2> p2) {
  return [p1 = std::move(p1), p2 = std::move(p2)](const std::string &target, const int pos) {
    auto r1 = p1(target, pos);
    if (!r1.succeeded) return ParseResult<T2>(false, {}, pos);
    auto r2 = p2(target, r1.pos);
    if (!r2.succeeded) return ParseResult<T2>(false, {}, pos);
    return ParseResult<T2>(true, r2.object, r2.pos);
  };
}
 
template<typename T1, typename T2> Parser<T1> operator<<(Parser<T1> p1, Parser<T2> p2) {
  return [p1 = std::move(p1), p2 = std::move(p2)](const std::string &target, const int pos) {
    auto r1 = p1(target, pos);
    if (!r1.succeeded) return ParseResult<T1>(false, {}, pos);
    auto r2 = p2(target, r1.pos);
    if (!r2.succeeded) return ParseResult<T1>(false, {}, pos);
    return ParseResult<T1>(true, r1.object, r2.pos);
  };
}
 
Parser<char> oneOf(const std::string &s) {
  std::unordered_set<char> d;
  for (auto &c : s) d.insert(c);
  return [d = std::move(d)](const std::string &target, const int pos) {
    if (target.size() <= pos) return ParseResult<char>(false, {}, pos);
    char c = target[pos];
    return d.count(c) ? ParseResult<char>(true, c, pos + 1) : ParseResult<char>(false, {}, pos);
  };
}
 
template<typename T, typename S, typename F> Parser<S> fmap(Parser<T> p, F &&f) {
  return [p = std::move(p), f = std::forward<F>(f)](const std::string &target, const int pos) {
    auto r = p(target, pos);
    return r.succeeded ? ParseResult<S>(true, f(r.object), r.pos) : ParseResult<S>(false, {}, r.pos);
  };
}
 
template<typename T, typename F> Parser<T> lazy(const F &f) {
  bool instantiated = false;
  Parser<T> p;
  return [f = std::move(f), p = std::move(p), instantiated = std::move(instantiated)](const std::string &target, const int pos) mutable {
    if (!instantiated) {
      p = f();
      instantiated = true;
    }
    return p(target, pos);
  };
}
template<typename T> Parser<T> make_view(Parser<T> &&f) {
  return [f = std::make_shared<T>(std::move(f))](const std::string &target, const int pos) {
    return f(target, pos);
  };
}
 
struct SyntaxTree {
  string op;
  char value;
  vector<SyntaxTree> children;
  SyntaxTree() {}
  SyntaxTree(const string &op, const char value, const vector<SyntaxTree> &children) : op(op), value(value), children(children) {}
};
 
int main() {
  Parser<SyntaxTree> formulaP = make_view<SyntaxTree>([&]() {
    auto andP = fmap<pair<SyntaxTree, SyntaxTree>, SyntaxTree>((token("(") >> formulaP << token("*")) + (formulaP << token(")")), [](auto &o) { return SyntaxTree("*", {}, {o.first, o.second}); });
    auto orP = fmap<pair<SyntaxTree, SyntaxTree>, SyntaxTree>((token("(") >> formulaP << token("+")) + (formulaP << token(")")), [](auto &o) { return SyntaxTree("+", {}, {o.first, o.second}); });
    auto impP = fmap<pair<SyntaxTree, SyntaxTree>, SyntaxTree>((token("(") >> formulaP << token("->")) + (formulaP << token(")")), [](auto &o) { return SyntaxTree("->", {}, {o.first, o.second}); });
    auto notP = fmap<SyntaxTree, SyntaxTree>(token("-") >> formulaP, [](auto &o) { return SyntaxTree("-", {}, {o}); });
    auto valP = fmap<char, SyntaxTree>(oneOf("abcdefghijkTF"), [](char x) { return SyntaxTree({}, x, {}); });
    return andP || orP || impP || notP || valP;
  }());
  auto equationP = (formulaP << token("=")) + formulaP;
  string s;
  while (cin >> s, s != "#") {
    auto r = equationP(s, 0);
    bool isValid = true;
    rep(i, 1 << 11) {
      auto toBool = [&](char c) -> bool {
        if (c == 'T') return true;
        if (c == 'F') return false;
        return i >> (c - 'a') & 1;
      };
      F<bool(const SyntaxTree&)> evalF = [&](const SyntaxTree &f) {
        switch (f.children.size()) {
          case 0: return toBool(f.value);
          case 1: return !evalF(f.children[0]);
          case 2:
            if (f.op == "*") return evalF(f.children[0]) && evalF(f.children[1]);
            if (f.op == "+") return evalF(f.children[0]) || evalF(f.children[1]);
            if (f.op == "->") return !evalF(f.children[0]) || evalF(f.children[1]);
        }
      };
      isValid &= evalF(r.object.first) == evalF(r.object.second);
    }
    cout << (isValid ? "YES" : "NO") << endl;
  }
}

Compiler output:
a.cc: In function 'Parser<T> make_view(Parser<T>&&)':
a.cc:98:20: error: 'make_shared' is not a member of 'std'
   98 |   return [f = std::make_shared<T>(std::move(f))](const std::string &target, const int pos) {
      |                    ^~~~~~~~~~~
a.cc:5:1: note: 'std::make_shared' is defined in header '<memory>'; this is probably fixable by adding '#include <memory>'
    4 | #include <unordered_set>
  +++ |+#include <memory>
    5 | #include <vector>
a.cc:98:33: error: expected primary-expression before '>' token
   98 |   return [f = std::make_shared<T>(std::move(f))](const std::string &target, const int pos) {
      |                                 ^
a.cc: In lambda function:
a.cc:140:7: warning: control reaches end of non-void function [-Wreturn-type]
  140 |       };
      |       ^