Task: Truth table


C++: #include <iostream>
#include <stack>
#include <string>
#include <sstream>
#include <vector>

struct var {
    char name;
    bool value;
};
std::vector<var> vars;

template<typename T>
T pop(std::stack<T> &s) {
    auto v = s.top();
    s.pop();
    return v;
}

bool is_operator(char c) {
    return c == '&' || c == '|' || c == '!' || c == '^';
}

bool eval_expr(const std::string &expr) {
    std::stack<bool> sob;
    for (auto e : expr) {
        if (e == 'T') {
            sob.push(true);
        } else if (e == 'F') {
            sob.push(false);
        } else {
           auto it = std::find_if(vars.cbegin(), vars.cend(), [e](const var &v) { return v.name == e; });
           if (it != vars.cend()) {
               sob.push(it->value);
           } else {
               int before = sob.size();
               switch (e) {
               case '&':
                   sob.push(pop(sob) & pop(sob));
                   break;
               case '|':
                   sob.push(pop(sob) | pop(sob));
                   break;
               case '!':
                   sob.push(!pop(sob));
                   break;
               case '^':
                   sob.push(pop(sob) ^ pop(sob));
                   break;
               default:
                   throw std::exception("Non-conformant character in expression.");
               }
           }
        }
    }
    if (sob.size() != 1) {
        throw std::exception("Stack should contain exactly one element.");
    }
    return sob.top();
}

void set_vars(int pos, const std::string &expr) {
    if (pos > vars.size()) {
        throw std::exception("Argument to set_vars can't be greater than the number of variables.");
    }
    if (pos == vars.size()) {
        for (auto &v : vars) {
            std::cout << (v.value ? "T  " : "F  ");
        }
        std::cout << (eval_expr(expr) ? 'T' : 'F') << '\n'; 
    } else {
        vars[pos].value = false;
        set_vars(pos + 1, expr);
        vars[pos].value = true;
        set_vars(pos + 1, expr);
    }
}


std::string process_expr(const std::string &src) {
    std::stringstream expr;

    for (auto c : src) {
        if (!isspace(c)) {
            expr << (char)toupper(c);
        }
    }

    return expr.str();
}

int main() {
    std::cout << "Accepts single-character variables (except for 'T' and 'F',\n";
    std::cout << "which specify explicit true or false values), postfix, with\n";
    std::cout << "&|!^ for and, or, not, xor, respectively; optionally\n";
    std::cout << "seperated by whitespace. Just enter nothing to quit.\n";

    while (true) {
        std::cout << "\nBoolean expression: ";

        std::string input;
        std::getline(std::cin, input);

        auto expr = process_expr(input);
        if (expr.length() == 0) {
            break;
        }

        vars.clear();
        for (auto e : expr) {
            if (!is_operator(e) && e != 'T' && e != 'F') {
                vars.push_back({ e, false });
            }
        }
        std::cout << '\n';
        if (vars.size() == 0) {
            std::cout << "No variables were entered.\n";
        } else {
            for (auto &v : vars) {
                std::cout << v.name << "  ";
            }
            std::cout << expr << '\n';

            auto h = vars.size() * 3 + expr.length();
            for (size_t i = 0; i < h; i++) {
                std::cout << '=';
            }
            std::cout << '\n';

            set_vars(0, expr);
        }
    }

    return 0;
}



Go: package main

import (
    "bufio"
    "errors"
    "fmt"
    "go/ast"
    "go/parser"
    "go/token"
    "os"
    "reflect"
)

func main() {
    in := bufio.NewScanner(os.Stdin)
    for {
        fmt.Print("Expr:  ")
        in.Scan()
        if err := in.Err(); err != nil {
            fmt.Println(err)
            return
        }
        if !tt(in.Text()) {
            return
        }
    }
}

func tt(expr string) bool {
    
    tree, err := parser.ParseExpr(expr)
    if err != nil {
        fmt.Println(err)
        return false
    }
    
    e := &evaluator{nil, map[string]bool{}, tree}
    
    
    ast.Walk(e, tree)
    
    for _, n := range e.names {
        fmt.Printf("%-6s", n)
    }
    fmt.Println(" ", expr)
    
    e.evalVar(0)
    return true
}

type evaluator struct {
    names []string        
    val   map[string]bool 
    tree  ast.Expr        
}



func (e *evaluator) Visit(n ast.Node) ast.Visitor {
    if id, ok := n.(*ast.Ident); ok {
        if !e.val[id.Name] {
            e.names = append(e.names, id.Name)
            e.val[id.Name] = true
        }
    }
    return e
}





func (e *evaluator) evalVar(nx int) bool {
    if nx == len(e.names) {
        
        v, err := evalNode(e.tree, e.val)
        if err != nil {
            fmt.Println(" ", err)
            return false
        }
        
        for _, n := range e.names {
            fmt.Printf("%-6t", e.val[n])
        }
        
        fmt.Println(" ", v)
        return true
    }
    
    for _, v := range []bool{false, true} {
        e.val[e.names[nx]] = v
        if !e.evalVar(nx + 1) {
            return false
        }
    }
    return true
}


func evalNode(nd ast.Node, val map[string]bool) (bool, error) {
    switch n := nd.(type) {
    case *ast.Ident:
        return val[n.Name], nil
    case *ast.BinaryExpr:
        x, err := evalNode(n.X, val)
        if err != nil {
            return false, err
        }
        y, err := evalNode(n.Y, val)
        if err != nil {
            return false, err
        }
        switch n.Op {
        case token.AND:
            return x && y, nil
        case token.OR:
            return x || y, nil
        case token.XOR:
            return x != y, nil
        default:
            return unsup(n.Op)
        }
    case *ast.UnaryExpr:
        x, err := evalNode(n.X, val)
        if err != nil {
            return false, err
        }
        switch n.Op {
        case token.XOR:
            return !x, nil
        default:
            return unsup(n.Op)
        }
    case *ast.ParenExpr:
        return evalNode(n.X, val)
    }
    return unsup(reflect.TypeOf(nd))
}

func unsup(i interface{}) (bool, error) {
    return false, errors.New(fmt.Sprintf("%v unsupported", i))
}