    #include <string>
    #include <map>
    #include <iostream>

    using namespace std;

    class Okolina
    {
    public:
    	double VrednostPromenljive( const string& s ) const
    		{
    		map<string,double>::const_iterator
    			f = _Promenljive.find(s);
    		if( f != _Promenljive.end() )
    			return f->second;
    		else{
    			// ovde bi trebalo da se napravi izuzetak
    			return 0;
    			}
    		}

    	bool DefinisanaPromenljiva( const string& s ) const
    		{
    		map<string,double>::const_iterator
    			f = _Promenljive.find(s);
    		return f != _Promenljive.end();
    		}

    	void DodajPromenljivu( const string& s, double v )
    		{ _Promenljive[s] = v; }

    private:
    	map<string,double> _Promenljive;
    };

    class Izraz
    {
    public:
    	virtual ~Izraz()
    		{}
    	virtual double Vrednost( const Okolina& o ) const = 0;
    	virtual void Ispisi( ostream& ostr ) const = 0;
    	virtual Izraz* Kopija() const = 0;
    	virtual Izraz* Uprosti( const Okolina& o ) const = 0;
    	virtual bool JesteKonstanta() const
    		{ return false; }
    	virtual Izraz* IzvodPo( const string& s ) const = 0;

    	static Izraz* Procitaj( istream& istr );
    };

    ostream& operator << ( ostream& ostr, const Izraz& i )
    {
    	i.Ispisi( ostr );
    	return ostr;
    }

    class Konstanta : public Izraz
    {
    public:
    	Konstanta( double d )
    		: _Vrednost(d)
    		{}

    	double Vrednost( const Okolina& o ) const
    		{ return _Vrednost; }

    	void Ispisi( ostream& ostr ) const
    		{ ostr << _Vrednost; }

    	Konstanta* Kopija() const
    		{ return new Konstanta(*this); }

    	Izraz* Uprosti( const Okolina& o ) const
    		{ return Kopija(); }

    	bool JesteKonstanta() const
    		{ return true; }

    	Izraz* IzvodPo( const string& s ) const
    		{ return new Konstanta(0); }

    private:
    	double _Vrednost;
    };

    class Promenljiva : public Izraz
    {
    public:
    	Promenljiva( const string& s )
    		: _Naziv(s)
    		{}

    	double Vrednost( const Okolina& o ) const
    		{ return o.VrednostPromenljive( _Naziv ); }

    	void Ispisi( ostream& ostr ) const
    		{ ostr << _Naziv; }

    	Promenljiva* Kopija() const
    		{ return new Promenljiva(*this); }

    	Izraz* Uprosti( const Okolina& o ) const
    		{
    		if( o.DefinisanaPromenljiva(_Naziv) )
    			return new Konstanta( o.VrednostPromenljive(_Naziv));
    		else
    			return Kopija();
    		}

    	Izraz* IzvodPo( const string& s ) const
    		{ return new Konstanta( s==_Naziv ? 1 : 0); }

    private:
    	string _Naziv;
    };

    class BinarniOperator : public Izraz
    {
    public:
    	BinarniOperator( Izraz* i1, Izraz* i2 )
    		: _I1(i1), _I2(i2)
    		{}

    	~BinarniOperator()
    		{
    		delete _I1;
    		delete _I2;
    		}

    	BinarniOperator( const BinarniOperator& z )
    		: _I1( z._I1->Kopija() ),
    		  _I2( z._I2->Kopija() )
    		{}

    	BinarniOperator& operator = ( const BinarniOperator& z )
    		{
    		if( this != &z ){
    			delete _I1;
    			delete _I2;
    			_I1 = z._I1->Kopija();
    			_I2 = z._I2->Kopija();
    			}
    		return *this;
    		}

    	double Vrednost( const Okolina& o ) const
    		{ return Izracunaj( _I1->Vrednost(o), _I2->Vrednost(o)); }

    	Izraz* Uprosti( const Okolina& o ) const
    		{
    		Izraz* i1 = _I1->Uprosti(o);
    		Izraz* i2 = _I2->Uprosti(o);
    		if( i1->JesteKonstanta() && i2->JesteKonstanta() ){
    			Izraz* r = new Konstanta( Izracunaj( i1->Vrednost(o), i2->Vrednost(o)) );
    			delete i1;
    			delete i2;
    			return r;
    			}
    		else
    			return NapraviNovi( i1, i2 );
    		}

    	void Ispisi( ostream& ostr ) const
    		{ ostr << "( " << Naziv() << ' ' << *_I1 << ' ' << *_I2 << " )"; }

    protected:
    	virtual double Izracunaj( double x, double y ) const = 0;
    	virtual Izraz* NapraviNovi( Izraz* i1, Izraz* i2 ) const = 0;
    	virtual string Naziv() const = 0;
    	const Izraz* Levi() const
    		{ return _I1; }
    	const Izraz* Desni() const
    		{ return _I2; }

    private:
    	Izraz *_I1, *_I2;
    };

    class Zbir : public BinarniOperator
    {
    public:
    	Zbir( Izraz* i1, Izraz* i2 )
    		: BinarniOperator( i1, i2 )
    		{}

    	Zbir* Kopija() const
    		{ return new Zbir(*this); }

    	Izraz* IzvodPo( const string& s ) const
    		{ return new Zbir( Levi()->IzvodPo(s), Desni()->IzvodPo(s)); }

    protected:
    	double Izracunaj( double x, double y ) const
    		{ return x + y; }

    	Izraz* NapraviNovi( Izraz* i1, Izraz* i2 ) const
    		{ return new Zbir( i1, i2 ); }

    	string Naziv() const
    		{ return "PLUS"; }
    };

    class Razlika : public BinarniOperator
    {
    public:
    	Razlika( Izraz* i1, Izraz* i2 )
    		: BinarniOperator( i1, i2 )
    		{}

    	Razlika* Kopija() const
    		{ return new Razlika(*this); }

    	Izraz* IzvodPo( const string& s ) const
    		{ return new Razlika( Levi()->IzvodPo(s), Desni()->IzvodPo(s)); }

    protected:
    	double Izracunaj( double x, double y ) const
    		{ return x - y; }

    	Izraz* NapraviNovi( Izraz* i1, Izraz* i2 ) const
    		{ return new Razlika( i1, i2 ); }

    	string Naziv() const
    		{ return "MINUS"; }
    };

    class Proizvod : public BinarniOperator
    {
    public:
    	Proizvod( Izraz* i1, Izraz* i2 )
    		: BinarniOperator( i1, i2 )
    		{}

    	Proizvod* Kopija() const
    		{ return new Proizvod(*this); }

    	Izraz* IzvodPo( const string& s ) const
    		{
    		return new Zbir(
    				new Proizvod( Levi()->IzvodPo(s), Desni()->Kopija() ),
    				new Proizvod( Levi()->Kopija(), Desni()->IzvodPo(s))
    				);
    		}

    protected:
    	double Izracunaj( double x, double y ) const
    		{ return x * y; }

    	Izraz* NapraviNovi( Izraz* i1, Izraz* i2 ) const
    		{ return new Proizvod( i1, i2 ); }

    	string Naziv() const
    		{ return "PUTA"; }
    };

    class Kolicnik : public BinarniOperator
    {
    public:
    	Kolicnik( Izraz* i1, Izraz* i2 )
    		: BinarniOperator( i1, i2 )
    		{}

    	Kolicnik* Kopija() const
    		{ return new Kolicnik(*this); }

    	Izraz* IzvodPo( const string& s ) const
    		{
    		return
    		new Kolicnik(
    			new Razlika(
    				new Proizvod( Levi()->IzvodPo(s), Desni()->Kopija() ),
    				new Proizvod( Levi()->Kopija(), Desni()->IzvodPo(s))
    				),
    			new Proizvod(
    				Desni()->Kopija(),
    				Desni()->Kopija()
    				)
    			);
    		}

    protected:
    	double Izracunaj( double x, double y ) const
    		{ return x / y; }

    	Izraz* NapraviNovi( Izraz* i1, Izraz* i2 ) const
    		{ return new Kolicnik( i1, i2 ); }

    	string Naziv() const
    		{ return "PODELJENO"; }
    };

    Izraz* Izraz::Procitaj( istream& istr )
    {
    	Izraz* i = 0;
    	istr >> ws;
    	char c = istr.peek();
    	if( c == '(' ){
    		istr.get();
    		string op;
    		istr >> ws >> op;
    		Izraz* op1 = Procitaj( istr );
    		Izraz* op2 = Procitaj( istr );
    		if( op1 && op2 ){
    			if( op=="PLUS" )
    				i = new Zbir( op1, op2 );
    			else if( op=="MINUS" )
    				i = new Razlika( op1, op2 );
    			else if( op=="PUTA" )
    				i = new Proizvod( op1, op2 );
    			else if( op=="PODELJENO" )
    				i = new Kolicnik( op1, op2 );
    		}
    		if( !i ){
    			delete op1;
    			delete op2;
    		}
    		istr >> ws;
    		istr.get();
    	}else if( (c>='a' && c<='z') || (c>='A' && c<='Z') ){
    		string s;
    		istr >> s;
    		if( istr )
    			i = new Promenljiva(s);
    	}else{
    		double f;
    		istr >> f;
    		if( istr )
    			i = new Konstanta(f);
    	}
    	return i;
    }

    main()
    {
    	Okolina o;
    	o.DodajPromenljivu( "x", 5 );

    	// izraz (x/2)+(y-(3.14*z))
    /*
    	Izraz* i1 = new Kolicnik( new Promenljiva("x"), new Konstanta(2));
    	Izraz* i2 = new Proizvod( new Konstanta(3.14), new Promenljiva("z"));
    	Izraz* i3 = new Razlika( new Promenljiva("y"), i2 );
    	Izraz* i4 = new Zbir( i1, i3 );
    	cout << (*i4) << " = " << i4->Vrednost( o ) << endl;

    	Izraz* i5 = i4->Uprosti(o);
    	cout << (*i4) << " -> " << (*i5) << endl;

    	Izraz* i6 = i4->IzvodPo("x");
    	Izraz* i7 = i6->Uprosti(o);
    	cout << (*i4) << " ' = " << (*i6) << " = " << *i7 << endl;

    	delete i4;
    	delete i5;
    	delete i6;
    	delete i7;
    */
    	Izraz* i = Izraz::Procitaj( cin );
    	Izraz* iz = i->IzvodPo("x");
    	Izraz* u = iz->Uprosti(o);

    	cout << (*i) << " ' = " << (*iz) << " = " << *u << endl;

    	delete u;
    	delete iz;
    	delete i;

    	return 0;
    }