
Manager: "How long have you been juggling?"
Candidate: "Well, about six years old."
Manager: “Can you juggle with three, four, five balls?”
Candidate: "Yes, yes and yes."
Manager: "Do you work with burning objects?"
Candidate: “Of course.”
Manager: "... knives, axes, open boxes with cigars, soft wide-brimmed hats?"
Candidate: "I do not care how to juggle."
Manager: “Do you know any funny patter?”
Candidate: "Onabespodobna".
Manager: “Well, I like it. I think we will take you. ”
Candidate: “Ahhh ... You don't want to see how I juggle?”
Manager: "Hmm, somehow it did not occur to me."
#include <string>
#include <cassert>
#include <memory>
#include <stdexcept>
#include <vector>
#include <iostream>
#include <cstdio>
using namespace std;
struct Token {
        enum Type { value, operation, opening_bracket, closing_bracket};
        Type type;
        string text;
};
struct Tokenizer {
        //I am too lazy to write real tokenizer, it is very simple. I hope formula generator for fake tokenizer will be ok. 
public:
        Tokenizer() { content=generate(); pos=content.begin(); } ;
        const Token* peek() { return pos!=content.end() ?&*pos:0; } ;
        const Token* get() { if (pos!=content.end()) { cout << pos->text << " "; } return pos!=content.end()?&*pos++:0; } ;
private:
    vector<Token> generate(int level=0);
    
private:
        vector<Token>::iterator pos;
        vector<Token> content;
};
//To be honest using classes for expression parsing is a bit overkill, old style could save some code. 
class Expression;
typedef struct auto_ptr<Expression> ExpressionPtr;
//Represents abstract expression
class Expression {
public:
        Expression() {}
        virtual ~Expression() {}
        //actually this static parse functions should be constructor in most classes. I.e. this is violation of principle 'Resource Acquisition Is Initialization'.
        //but some functions return different classes depending on context, i.e. this is some kind of 'virtual constructor' (see Operation::parse for example)
        //so I made decision to make static construction function in all classes, just for uniformity
        static ExpressionPtr parse(Tokenizer& tokens);
        virtual float calc()=0;
        virtual void debug(string prefix)=0;
};
//Represents single value: for example 3.1415
class Value: public Expression {
public:
        Value() {}
        virtual ~Value() {}
        static bool isItYou(Tokenizer& tokens);
        static ExpressionPtr parse(Tokenizer& tokens);
        virtual float calc() { return _value; }
        virtual void debug(string prefix) { cout << prefix << "Value(" <<  calc() <<"): " << _value << endl; } 
protected:
        float _value;
};
//Represents operation: + or -
class Operation: public Expression {
public:
        Operation() {};
        virtual ~Operation() {}
        static ExpressionPtr parse(Tokenizer& tokens, ExpressionPtr& l);
        virtual float calc();
        virtual void debug(string prefix) { cout << prefix << "Operation(" <<  calc() <<"): " << _operation << endl; if ( _left.get() ) _left->debug(prefix + "\t"); if ( _right.get() ) _right->debug(prefix + "\t"); } 
protected:
        std::auto_ptr<Expression> _left;
        std::auto_ptr<Expression> _right;
        string _operation;
};
//Represents operation: * or /
class PriorityOperation: public Operation {
public:
        PriorityOperation() {};
        virtual ~PriorityOperation() {}
        static ExpressionPtr parse(Tokenizer& tokens, ExpressionPtr& left);
        //virtual float calc(); inherit it
        virtual void debug(string prefix) { cout << prefix << "PriorityOperation(" <<  calc() <<"): " << _operation << endl; if ( _left.get() ) _left->debug(prefix + "\t"); if ( _right.get() ) _right->debug(prefix + "\t"); } 
};
//Represents bracketed expression: (expr)
class BracketExpression: public Expression {
public:
        static bool isItYou(Tokenizer& tokens);
        static ExpressionPtr parse(Tokenizer& tokens);
        virtual float calc() { return _internal->calc(); } ;
        virtual void debug(string prefix) { cout << prefix << "Brackets(" <<  calc() <<"): "  << endl; _internal->debug(prefix + "\t"); } 
protected:
        std::auto_ptr<Expression> _internal; 
};
ExpressionPtr Expression::parse(Tokenizer& tokens)
{
    //cout << "Expression::parse" << endl;
    
        if (!tokens.peek()) return ExpressionPtr();
        if ( BracketExpression::isItYou(tokens) )
        {
                return BracketExpression::parse(tokens);
        }
        else
        if ( Value::isItYou(tokens) )
        {        
                return Value::parse(tokens);
        }
        else
        {
                throw logic_error("(Expression) Wtf is that: " + tokens.peek()->text );
        }
}
bool Value::isItYou(Tokenizer& tokens) 
{
        const Token* t = tokens.peek();
        if ( !t || t->type != Token::value ) return false; 
        char* endptr;
        strtod( t->text.c_str(), &endptr);
        return *endptr == 0;
}
ExpressionPtr Value::parse(Tokenizer& tokens)
{
    //cout << "Value::parse" << endl;
    
        std::auto_ptr<Value> foo( new Value );
        const Token* t=tokens.get();
        assert( t && t->type == Token::value ); 
        char* endptr;
        foo->_value = strtod( t->text.c_str(), &endptr);
        return ExpressionPtr(foo.release()); //lack of heterosexual auto_ptr conversions is killing me
}
bool BracketExpression::isItYou(Tokenizer& tokens) 
{
        return tokens.peek() && tokens.peek()->type == Token::opening_bracket;
}
ExpressionPtr BracketExpression::parse(Tokenizer& tokens)
{
    //cout << "BracketExpression::parse" << endl;
        const Token* t=tokens.get();
        assert ( t->type == Token::opening_bracket );
        auto_ptr<BracketExpression> result ( new BracketExpression );
        ExpressionPtr null;
        result->_internal = Operation::parse(tokens, null);
        t = tokens.get();
        if ( t ==0 || t->type != Token::closing_bracket )
        {
                throw logic_error("(BracketExpression) mismatched brackets ");
        }
        return ExpressionPtr(result.release());
}
ExpressionPtr Operation::parse(Tokenizer& tokens, ExpressionPtr& l)
{
    //cout << "Operation::parse:" << l.get() << endl;
        ExpressionPtr left;
        if (l.get()) 
        {
                left=l;
                // left is assigned for us.
        }
        else
        {
                left=Expression::parse(tokens);
        }        
        const Token *t=tokens.peek();
        if (!t || t->type == Token::closing_bracket  ) return left; //just return Value, sorry no operation guys
        if (t->type == Token::operation && (t->text=="*" || t->text=="/") )
        {
                ExpressionPtr result = PriorityOperation::parse(tokens, left);                 
                //we got exit after priority operations will end, parse position will be on + or - or at end
                left = result;        
                t=tokens.peek();
                if (!t || t->type == Token::closing_bracket  ) return left; //just return Value, sorry no operation guys
        }
    //cout << "Operation::parse again" << endl;
        if (t->type == Token::operation && (t->text=="+" || t->text=="-") )
        {
                tokens.get(); //just commit previous peek
                auto_ptr<Operation> result ( new Operation );
                result->_operation = t->text;
                result->_left=left; //smart ptr giveup ownership
        
        //cout << "Operation::parse before token" << endl;
        ExpressionPtr foo=Expression::parse(tokens);
        //cout << "Operation::parse after expression" << endl;
        
        const Token *t=tokens.peek();
        
        if (t != 0 && (t->text=="*" || t->text=="/"))
        {
            //cout << "Operation::parse to priority" << endl;
            foo = PriorityOperation::parse(tokens,foo);
        }
        
        result->_right=foo;
        
        ExpressionPtr bar(result.release());
        return Operation::parse(tokens, bar);
                
        }
        else
        {
                throw logic_error("(Operation) Wtf is that: " + tokens.peek()->text);
        }
}
ExpressionPtr PriorityOperation::parse(Tokenizer& tokens, ExpressionPtr& left)
{
    //cout << "PriorityOperation::parse" << endl;
    
    // left is already assigned for priority operation
        const Token *t=tokens.peek();
        if (!t || t->type == Token::closing_bracket  ) return left; //just return Value, sorry no operation guys
        if (t->type == Token::operation && (t->text=="*" || t->text=="/") )
        {
                tokens.get(); //commit previuos peek
                auto_ptr<PriorityOperation> result ( new PriorityOperation ); 
                result->_operation = t->text;
                result->_left=left;
                result->_right=Expression::parse(tokens);
                ExpressionPtr rs(result.release());
                return PriorityOperation::parse(tokens, rs);
        }
        else if (t->type == Token::operation && (t->text=="+" || t->text=="-") )
        {
                return left;
        }
        else
        {
                throw logic_error("(PriorityOperation) Wtf is that: " + tokens.peek()->text );
        }
}
float Operation::calc()
{
        if (_operation == "+")
        {
                float l=_left.get()?_left->calc():0.0f;
                float r=_right.get()?_right->calc():0.0f;
                return l+r;
        }
        else
        if (_operation == "-")
        {
                float l=_left.get()?_left->calc():0.0f;
                float r=_right.get()?_right->calc():0.0f;
                return l-r;
        }        
        else
        if (_operation == "*")
        {
                float l=_left.get()?_left->calc():1.0f;
                float r=_right.get()?_right->calc():1.0f;
                return  l*r; 
        }        
        else
        if (_operation == "/")
        {
                float l = _left.get()?_left->calc():1.0f;
                float r = _right.get()?_right->calc():1.0f;
                return l/r;
        }
        else
        {
                throw logic_error("Wft: operation udefined");
        }                
}
//returning vector by value, will be slow( O(n*n) actually ), but it is just testing code.
vector<Token> Tokenizer::generate(int level)
{
    //be careful with this value - formula size is approx 2^level
    if (level > 6)
    {
        Token t;
        char f[100];
        snprintf(f,100,"%d",int(rand() % 100));
        t.text=f;
        t.type=Token::value;
        return vector<Token>(&t,&t+1);
    }
    if (rand() % 10 == 0)
    {
            vector<Token> result;
            Token t1,t2;
            t1.type=Token::opening_bracket;
            t1.text="(";
            t2.type=Token::closing_bracket;
            t2.text=")";
            result.push_back(t1);
            vector<Token> r=generate(level+1);
            result.insert(result.end(),r.begin(),r.end());
            result.push_back(t2);
            return result;
    }        
    char op = "+-*/"[rand()%4];
    Token t;
    t.type=Token::operation;
    t.text=op;
    vector<Token> result=generate(level+1);
    result.push_back(t);
    vector<Token> r2=generate(level+1);
    result.insert(result.end(),r2.begin(),r2.end());
    return result;
}
int main()
{        
        try
        {
                //create fake tokenizer
                Tokenizer tk;
                //parse it
                ExpressionPtr null;
                ExpressionPtr foo = Operation::parse(tk,null);
                cout << endl;
                foo->debug("");
                float result = foo->calc();        
                cout << "result = " << result << endl;
        }
        catch(exception& e)
        {
                cout << e.what() << endl;
                return 1;                  
        }
        return 0;
}#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <string>
#include <vector>
#include <stdexcept>
struct token {
    enum { E_UNDEF, E_NUMBER, E_OPERATOR, E_LEVEL  } type;
    union {
        double d_val;
        int i_val;
        char c_val;
    } data;
    token() {
        type = E_UNDEF;
    }
    token(double val) : type(E_NUMBER) {
        data.d_val = val;
    }
    token(int val) : type(E_LEVEL) {
        data.i_val = val;
    }
    token(char val) : type(E_OPERATOR) {
        data.c_val = val;
    }
};
typedef std::vector<token> tokens;
void push_level(tokens &pr, int level) {
    if (pr.empty() || pr.back().type != token::E_LEVEL) {
        pr.push_back(token(level));
    } else {
        pr.back().data.i_val += level;
    }
}
void push_operator(tokens &pr, char op) {
    pr.push_back(token(op));
}
void push_number(tokens &pr, int num) {
    if (pr.empty() || pr.back().type == token::E_LEVEL || (pr.back().type == token::E_OPERATOR && pr.size() > 1 && pr[pr.size() - 2].type == token::E_NUMBER) ) {
        pr.push_back(token((double)num));
    } else if (pr.back().type == token::E_OPERATOR && (pr.size() == 1 || pr[pr.size() - 2].type == token::E_LEVEL) ) {
        if (pr.back().data.c_val == '*' || pr.back().data.c_val == '/') {
            throw std::domain_error("unexpected operator");
        }
        if (pr.back().data.c_val == '-') {
            num = -num;
        }
        pr.pop_back();
        pr.push_back(token((double)num));
    } else {
        throw std::domain_error("unexpected number");
    }
}
token calc3(tokens &pr) {
    token s2 = pr.back(); pr.pop_back();
    token op = pr.back(); pr.pop_back();
    token s1 = pr.back(); pr.pop_back();
    if (s1.type != token::E_NUMBER || op.type != token::E_OPERATOR || s2.type != token::E_NUMBER) {
        throw std::domain_error("unexpected closing brace");
    }
    switch (op.data.c_val) {
        case '+':
            s1.data.d_val += s2.data.d_val;
            break;
        case '-':
            s1.data.d_val -= s2.data.d_val;
            break;
        case '*':
            s1.data.d_val *= s2.data.d_val;
            break;
        case '/':
            s1.data.d_val /= s2.data.d_val;
            break;
        default:
        throw std::domain_error("internal error");
    }
    return s1;
}
void pop_level(tokens &pr, int level) {
    if (level == 0) {
        if (pr.size() > 3) {
            pr.push_back(calc3(pr));
        }
        return;
    }
    if (pr.empty() || pr.back().type == token::E_LEVEL || pr.back().type == token::E_OPERATOR) {
        throw std::domain_error("unexpected closing brace");
    } else if (pr.size() > 1 && pr[pr.size() - 2].type == token::E_LEVEL) {
        if (pr[pr.size() - 2].data.i_val > level) {
            pr[pr.size() - 2].data.i_val -= level;
        } else {
            int delta = level - pr[pr.size() - 2].data.i_val;
            token tmp = pr.back();
            pr.pop_back(); pr.pop_back();
            pr.push_back(tmp);
            pop_level(pr, delta);
        }
    } else if (pr.size() > 3) {
        token s1 = calc3(pr);
        if (pr.back().type == token::E_LEVEL) {
            if (pr.back().data.i_val > level) {
                pr.back().data.i_val -= level;
                pr.push_back(s1);
            } else {
                int delta = level - pr.back().data.i_val;
                pr.pop_back();
                pr.push_back(s1);
                pop_level(pr, delta);
            }
        } else if (pr.back().type == token::E_OPERATOR) {
            pr.push_back(s1);
            pop_level(pr, level);
        } else {
            throw std::domain_error("unexpected closing brace");
        }
    } else {
        throw std::domain_error("unexpected closing brace");
    }
}
double process(const std::string &str) {
    tokens program;
    push_level(program, 3);
    for (std::string::const_iterator cit = str.begin(); cit != str.end(); ++cit) {
        switch (*cit) {
            case '(':
                push_level(program, 3);
                break;
            case ')':
                pop_level(program, 3);
                break;
            case '*':
            case '/':
                pop_level(program, 1);
                push_operator(program, *cit);
                push_level(program, 1);
                break;
            case '+':
            case '-':
                if (cit == str.begin() || strchr("(+/-*", *(cit-1))) {
                    push_operator(program, *cit);
                } else {
                    pop_level(program, 2);
                    push_operator(program, *cit);
                    push_level(program, 2);
                }
                break;
            case ' ':
                break;
            case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
                {
                    int curnum = 0;
                    while (cit != str.end()) {
                        curnum = 10*curnum + (*cit - '0');
                        if ((cit + 1) == str.end() || !isdigit(*(cit+1))) {
                            break;
                        }
                        ++cit;
                    }
                    push_number(program, curnum);
                }
                break;
            default:
                throw std::domain_error("unexpected symbol");
        }
    }
    pop_level(program, 3);
    if (program.size() == 0 || program.size() > 1) {
        throw std::domain_error("incomplete expression");
    }
    return program.back().data.d_val;
}
int main() {
    std::string line;
    while (!std::cin.eof()) {
        std::getline(std::cin, line);
        if (line.length() > 0) {
            try {
                std::cout << process(line) << std::endl;
            } catch (std::exception &e) {
                std::cout << "error: " << e.what() << std::endl;
            }
        }
    }
    return 0;
}
Source: https://habr.com/ru/post/206234/
All Articles