Cod sursa(job #1296724)

Utilizator alexandru70Ungurianu Alexandru alexandru70 Data 21 decembrie 2014 14:20:09
Problema Bool Scor 30
Compilator cpp Status done
Runda Arhiva de probleme Marime 6.73 kb
#include <fstream>
#include <iostream>
#include <vector>
#include <cctype>
#include <string>

enum class TokenType {
    Variable,
    And,
    Or,
    Not,
    OpenParanthesis,
    ClosedParanthesis,
    Undefined
};

struct Var {
    char key;
    bool value;

    void flip() {
        value = !value;
    }
};

struct Token {
    TokenType type;
    Var* var;

    Token() : Token(TokenType::Undefined) {}
    Token(TokenType type) : Token(type,nullptr) {}
    Token(TokenType type, Var* var) :
          type(type) , var(var) {}
};

std::vector<Var> variables;
Var True{'t',true};
Var False{'f',false};

class Tokenizer {

    std::vector<Token> tokens;
    unsigned index;
    std::string text;

private:
    void SkipWhitespace() {
        while(isspace(text[index]))index++;
    }

    Token getConstant() {
        std::string rT("TRUE");
        std::string rF("FALSE");

        unsigned myIndex = index;
        while(myIndex-index < rT.size() && rT[myIndex-index] == text[myIndex]) myIndex++;
        if(myIndex-index == rT.size()) {
            index = myIndex;
            return Token(TokenType::Variable,&True);
        }

        myIndex = index;
        while(myIndex-index < rF.size() && rF[myIndex-index] == text[myIndex]) myIndex++;
        if(myIndex-index == rF.size()) {
            index = myIndex;
            return Token(TokenType::Variable,&False);
        }
        return Token(TokenType::Undefined);

    }

    Token getVariable() {
        return Token(TokenType::Variable,&(variables[text[index++]-'A']));
    }

    Token getOperator() {
        std::vector<std::pair<Token,std::string>>
        operators {{Token(TokenType::Not),std::string("NOT")},
                   {Token(TokenType::And),std::string("AND")},
                   {Token(TokenType::Or),std::string("OR")}};

        for(const auto & op:operators) {
            unsigned myIndex = index;
            while(myIndex-index < op.second.size() && op.second[myIndex-index] == text[myIndex]) myIndex++;
            if(myIndex-index == op.second.size()) {
                index = myIndex;
                return op.first;
            }
        }

        return Token(TokenType::Undefined);
    }

    Token getToken() {

        SkipWhitespace();
        if(text[index] == '(') {
            index++;
            return Token(TokenType::OpenParanthesis);
        }
        else if(text[index] == ')') {
            index++;
            return Token(TokenType::ClosedParanthesis);
        }
        else {
            Token t = getConstant();
            if(t.type == TokenType::Undefined)
                t = getOperator();
            if(t.type == TokenType::Undefined)
                t = getVariable();
            return t;
        }
    }

public:
    std::vector<Token> Tokenize(const std::string & text) {
        this->index = 0;
        this->text = text;
        while(index < this->text.size()) {
            tokens.push_back(getToken());
        }
        return tokens;
    }

};

enum class ASTNodeType {
    Undefined,
    OperatorOr,
    OperatorAnd,
    OperatorNot,
    Variable
};

struct ASTNode {
    ASTNodeType type;
    Var * var;
    ASTNode * left;
    ASTNode * right;

    ASTNode() : ASTNode(ASTNodeType::Undefined, nullptr, nullptr) {}

    ASTNode(ASTNodeType type, ASTNode * left, ASTNode * right):
        type(type), left(left),right(right) {}
};

class Parser {
    std::vector<Token>::iterator currentToken;

private:
    ASTNode * Atom() {
        ASTNode * atm = new ASTNode();
        switch(currentToken->type) {
            case TokenType::OpenParanthesis:
                currentToken++;
                atm = Expression();
                currentToken++;
                break;
            case TokenType::Not:
                atm->type = ASTNodeType::OperatorNot;
                currentToken++;
                atm->left = Expression();
                break;
            case TokenType::Variable:
                atm->type = ASTNodeType::Variable;
                atm->var = currentToken->var;
                currentToken++;
                break;
        }

        return atm;
    }

    ASTNode * Expression() {
        ASTNode * atom = Atom();
        ASTNodeType type = ASTNodeType::Undefined;

        switch(currentToken->type){
            case TokenType::And :
                type = ASTNodeType::OperatorAnd;
                currentToken++;
                break;
            case TokenType::Or :
                type = ASTNodeType::OperatorOr;
                currentToken++;
                break;
            default :
                return atom;
        }

        ASTNode * expr = Expression();

        return new ASTNode(type,atom,expr);
    }

public:
    ASTNode * Parse(std::vector<Token>::iterator begin) {
        currentToken = begin;
        return Expression();
    }
};

void initVars() {
    variables.resize('Z'-'A');
    for(unsigned i = 0; i < 'Z'-'A'; i++) {
        variables[i].key = static_cast<char>('A' + i);
        variables[i].value = false;
    }
}

std::string GetRepr(ASTNodeType type) {
    switch(type)
    {
        case ASTNodeType::OperatorOr:
            return "OperatorOr";
        case ASTNodeType::OperatorAnd:
            return "OperatorAnd";
        case ASTNodeType::OperatorNot:
            return "OperatorNot";
        case ASTNodeType::Variable:
            return "Variable";
    }
}

std::ifstream in("bool.in");

void printAST(ASTNode * node, unsigned depth=0) {
    if(node->type == ASTNodeType::Variable) {
        std::cerr << depth << ".Variable{ " << node->var->key << " };\n";
        return;
    }
    std::cerr << depth << "." << GetRepr(node->type) << "{ Left:" << GetRepr(node->left->type);
    if(node->right)
        std::cerr << ", "<< "Right: " << GetRepr(node->right->type);
    std::cerr << "};\n";
    if(node->left)
        printAST(node->left, depth+1);
    if(node->right)
        printAST(node->right, depth+1);
}

class Evaluator {

public:
    bool Evaluate(ASTNode * ast) {
        switch(ast->type) {
            case ASTNodeType::Variable:
                return ast->var->value;
            case ASTNodeType::OperatorNot:
                return !Evaluate(ast->left);
            case ASTNodeType::OperatorAnd:
                return Evaluate(ast->left) && Evaluate(ast->right);
            case ASTNodeType::OperatorOr:
                return Evaluate(ast->left) || Evaluate(ast->right);
        }
    }
};


std::ofstream out("bool.out");
int main() {
    initVars();

    Tokenizer t;
    std::string text;
    getline(in,text);
    std::vector<Token> tokens = t.Tokenize(text);
    Parser p;
    ASTNode * ast = p.Parse(tokens.begin());
    Evaluator e;

    unsigned changes;
    in >> changes;
    in.ignore();
    for(int i = 0; i < changes; ++i) {
        char c;
        in >> c;
        variables[c-'A'].flip();
        out << e.Evaluate(ast);
    }
}