#include <iostream>
#include <string>
#include <map>
#include <memory>
#include <stdexcept>

// --------------------- Context ---------------------
// Stores variable-to-boolean mappings for terminal expressions.
class Context {
    std::map<std::string, bool> variables;
public:
    void assign(const std::string& var, bool value) {
        variables[var] = value;
    }

    bool lookup(const std::string& var) const {
        auto it = variables.find(var);
        if (it != variables.end())
            return it->second;
        throw std::runtime_error("Undefined variable: " + var);
    }
};

// --------------------- Abstract Expression ---------------------
class BooleanExp {
public:
    virtual ~BooleanExp() = default;
    virtual bool evaluate(Context& ctx) = 0;
};

// --------------------- Terminal Expression ---------------------
// Represents a variable whose value is obtained from the context.
class VariableExp : public BooleanExp {
    std::string name;
public:
    explicit VariableExp(const std::string& name) : name(name) {}
    bool evaluate(Context& ctx) override {
        return ctx.lookup(name);
    }
};

// --------------------- Nonterminal Expressions ---------------------
// AND operation
class AndExp : public BooleanExp {
    std::shared_ptr<BooleanExp> left, right;
public:
    AndExp(std::shared_ptr<BooleanExp> l, std::shared_ptr<BooleanExp> r)
        : left(std::move(l)), right(std::move(r)) {}

    bool evaluate(Context& ctx) override {
        return left->evaluate(ctx) && right->evaluate(ctx);
    }
};

// OR operation
class OrExp : public BooleanExp {
    std::shared_ptr<BooleanExp> left, right;
public:
    OrExp(std::shared_ptr<BooleanExp> l, std::shared_ptr<BooleanExp> r)
        : left(std::move(l)), right(std::move(r)) {}

    bool evaluate(Context& ctx) override {
        return left->evaluate(ctx) || right->evaluate(ctx);
    }
};

// NOT operation
class NotExp : public BooleanExp {
    std::shared_ptr<BooleanExp> operand;
public:
    explicit NotExp(std::shared_ptr<BooleanExp> op)
        : operand(std::move(op)) {}

    bool evaluate(Context& ctx) override {
        return !operand->evaluate(ctx);
    }
};

// --------------------- Client ---------------------
int main() {
    // Build expression: (x AND y) OR (NOT z)
    auto x = std::make_shared<VariableExp>("x");
    auto y = std::make_shared<VariableExp>("y");
    auto z = std::make_shared<VariableExp>("z");

    auto notZ  = std::make_shared<NotExp>(z);
    auto xAndy = std::make_shared<AndExp>(x, y);
    auto expr  = std::make_shared<OrExp>(xAndy, notZ);   // (x && y) || !z

    // Create context and assign values
    Context ctx;
    ctx.assign("x", false);
    ctx.assign("y", true);
    ctx.assign("z", true);

    std::cout << std::boolalpha;
    std::cout << "Expression: (x AND y) OR (NOT z)\n\n";

    // Scenario 1
    bool result = expr->evaluate(ctx);
    std::cout << "When x=false, y=true, z=true  => " << result << "\n";

    // Scenario 2: change x and re-evaluate
    ctx.assign("x", true);
    result = expr->evaluate(ctx);
    std::cout << "When x=true,  y=true, z=true  => " << result << "\n";

    // Scenario 3: change z and re-evaluate
    ctx.assign("z", false);
    result = expr->evaluate(ctx);
    std::cout << "When x=true,  y=true, z=false => " << result << "\n";

    return 0;
}

results matching ""

    No results matching ""