<< 前 ホーム 次 >>

bakaid: 20061214

#ifndef Calcin_hh_guard
#define Calcin_hh_guard

#include <algorithm>
#include <functional>
#include <iostream>
#include <sstream>
#include <string>
#include <stdexcept>
#include <vector>

using namespace std;

class ExprNode {
public:
    virtual int getValue() = 0;
};

class NumberNode : public ExprNode {
private:
    int value;

public:
    NumberNode(vector<string>& tokens) : value(0) {
        if (tokens.empty()) throw runtime_error("missing number (NumberNode)");
        string digits = tokens[0];
        tokens.erase(tokens.begin());
        istringstream input(digits);
        input >> value;
        if (!input.good() && !input.eof()) {
            ostringstream output;
            output << "expected number, but was " << digits;
            throw runtime_error(output.str().c_str());
        }
    }

    virtual ~NumberNode() {}

    virtual int getValue() { return value; }
};

class OperatorNode : public ExprNode {
protected:
    ExprNode* left;
    ExprNode* right;

public:
    OperatorNode(ExprNode* left, ExprNode* right) : left(left), right(right) {}

    virtual ~OperatorNode() {
        delete left;
        delete right;
    }

    virtual int getValue() = 0;
};

class MulNode : public OperatorNode {
public:
    MulNode(ExprNode* left, ExprNode* right) : OperatorNode(left, right) {}

    virtual int getValue() {
        return left->getValue() * right->getValue();
    }
};

class DivNode : public OperatorNode {
public:
    DivNode(ExprNode* left, ExprNode* right) : OperatorNode(left, right) {}

    virtual int getValue() {
        return left->getValue() / right->getValue();
    }
};

class AddNode : public OperatorNode {
public:
    AddNode(ExprNode* left, ExprNode* right) : OperatorNode(left, right) {}

    virtual int getValue() {
        return left->getValue() + right->getValue();
    }
};

class SubNode : public OperatorNode {
public:
    SubNode(ExprNode* left, ExprNode* right) : OperatorNode(left, right) {}

    virtual int getValue() {
        return left->getValue() - right->getValue();
    }
};

class Calcin {
public:
    virtual int calc(string exp) {
        if (exp.empty()) return 0;
        vector<string> tokens;
        split(exp, tokens);
        ExprNode* node = expr(tokens);
        if (!tokens.empty()) {
            string msg("invalid expression: ");
            string e = join(tokens, " ");
            msg.append(e);
            throw runtime_error(msg);
        }
        return node->getValue();
    }

    virtual ExprNode* expr(vector<string>& tokens) {
        ExprNode* left = term(tokens);
        while (tokens[0] == "+" || tokens[0] == "-") {
            string op = tokens[0];
            tokens.erase(tokens.begin());
            ExprNode* right = term(tokens);
            if (op == "+") left = new AddNode(left, right);
            else left = new SubNode(left, right);
        }
        return left;
    }

    virtual ExprNode* term(vector<string>& tokens) {
        ExprNode* left = factor(tokens);
        while (tokens[0] == "*" || tokens[0] == "/") {
            string op = tokens[0];
            tokens.erase(tokens.begin());
            ExprNode* right = factor(tokens);
            if (op == "*") left = new MulNode(left, right);
            else left = new DivNode(left, right);
        }
        return left;
    }

    virtual ExprNode* factor(vector<string>& tokens) {
        if (tokens.empty()) runtime_error("missing number (factor)");
        string token = tokens[0];
        if (tokens[0] == "(") {
            tokens.erase(tokens.begin());
            ExprNode* result = expr(tokens);
            if (tokens.empty() || tokens[0] != ")") {
                throw runtime_error("missing right paren (factor)");
            }
            tokens.erase(tokens.begin());
            return result;
        }
        return new NumberNode(tokens);
    }

    virtual NumberNode* number(vector<string>& tokens) {
        return new NumberNode(tokens);
    }

    virtual void split(string str, vector<string>& out) {
        istringstream input(str);
        string s;
        while (input >> s) {
            out.push_back(s);
        }
    }

    virtual string join(vector<string>& tokens, string sep) {
        ostringstream output;
        for (size_t i = 0; i < tokens.size(); ++i) {
            output << tokens[i];
            if (i != tokens.size() - 1) output << sep;
        }
        return output.str();
    }

    virtual void prints(string str) {
        cout << str << endl;
    }
};

#endif // Calcin_hh_guard

#include <cassert>
#include <iostream>
#include <stdexcept>
#include <vector>

#include "Calcin.hh"

class CalcinTest {
private:
    Calcin target;

public:
    virtual void testOne() {
        assert(1 == target.calc("1"));
    }

    virtual void testEmpty() {
        assert(0 == target.calc(""));
    }

    virtual void test2mul3() {
        assert(6 == target.calc("2 * 3"));
    }


    virtual void test2_3() {
        try {
            target.calc("2 3");
            assert(0);
        } catch (runtime_error& e) {}
    }

    virtual void test2mul3mul4() {
        assert(24 == target.calc("2 * 3 * 4"));
    }

    virtual void test1plus2() {
        assert(3 == target.calc("1 + 2"));
    }

    virtual void test1plus2plus3() {
        assert(6 == target.calc("1 + 2 + 3"));
    }

    virtual void test1plus2mul3() {
        assert(7 == target.calc("1 + 2 * 3"));
    }

    virtual void testParen() {
        assert(9 == target.calc("( 1 + 2 ) * 3"));
    }

    virtual void test6minus3minus2() {
        assert(1 == target.calc("6 - 3 - 2"));
    }

    virtual void test24div4div2() {
        assert(3 == target.calc("24 / 4 / 2"));
    }

    virtual void testInvalidExpr() {
        try {
            target.calc("1 2 3");
        } catch (runtime_error& e) {
            string msg(e.what());
            assert(msg == "invalid expression: 2 3");
        }
    }

    virtual void testSplit() {
        vector<string> tokens;
        target.split("", tokens);
        assert(tokens.empty());

        target.split("a", tokens);
        assert(1 == tokens.size());
        assert(tokens[0] == "a");

        tokens.clear();
        target.split(" a\t\tbc  d\r\nefg\n\n", tokens);
        assert(4 == tokens.size());
        assert(tokens[0] == "a");
        assert(tokens[1] == "bc");
        assert(tokens[2] == "d");
        assert(tokens[3] == "efg");
    }

    virtual void testJoin() {
        vector<string> tokens;
        string actual = target.join(tokens, " ");
        assert(actual == "");

        tokens.push_back("a");
        actual = target.join(tokens, " ");
        assert(actual == "a");

        tokens.push_back("bc");
        actual = target.join(tokens, " ");
        assert(actual == "a bc");
    }

    virtual void run() {
        testOne();
        testEmpty();
        test2mul3();
        test2_3();
        test2mul3mul4();
        test1plus2();
        test1plus2plus3();
        test1plus2mul3();
        testParen();
        test6minus3minus2();
        test24div4div2();
        testSplit();
        testInvalidExpr();
    }
};

int
main()
{
    try {
        CalcinTest test;
        test.run();
    } catch (runtime_error& e) {
        cout << e.what() << endl;
    }
    return 0;
}

本家Permlink

<< 前 ホーム 次 >>


Copyright © 1905 tko at jitu.org

バカが征く on Rails