#pragma once // #2.1.2.12 //#include #include #include #include #include "RefCounted.h" #include "IntrusivePtr.h" #include "TemplateUtil.h" #include "float.h" /// 2011.04.15 - prodongi namespace rp { /// 2011.04.15 sprintf_s를 사용하면 반올림 되기 때문에 원하지 않는 텍스트가 뽑혀 진다, 그래서 수정함- prodongi static std::string getRevisionFloat(float value, int point, std::string const& format) { static char buffer[256]; static float roundNumber[5] = { 1.0f, 10.0f, 100.0f, 1000.0f, 10000.0f }; if (5 > point) { value *= roundNumber[point]; int _value = (int)value; value = (float)_value/roundNumber[point]; } ::sprintf_s( buffer, format.c_str(), value); return buffer; } // template namespace template< typename NumericType > struct expr { typedef NumericType numeric_t; template< typename Handler, typename Key > class Parser { public: enum MODE { NORMAL, ESCAPE, }; Parser() : mMode( NORMAL ) {} virtual ~Parser() {} virtual void onNormal( const Key& expr ) = 0; virtual void onEscape( const Key& escape ) = 0; void call( const Key& expr ) { Key target( expr ); target.erase( std::remove_if( target.begin(), target.end(), Remover() ), target.end() ); if( target.empty() ) return; onNormal( target ); } void compile( std::string::const_iterator begin, std::string::const_iterator end ) { if( begin == end ) return; std::string::const_iterator it = begin; std::string::const_iterator token = begin; typedef std::vector< std::pair< std::string::const_iterator, std::string::const_iterator > > Buffer; Buffer buffer; while( it != end ) { static char escape; switch( mMode ) { case NORMAL: { if( std::binary_search( mTokens.begin(), mTokens.end(), *it ) ) { if( token != it ) call( std::string( token, it ) ); call( std::string( it, it + 1 ) ); token = ++it; continue; } else if( std::binary_search( mEscape.begin(), mEscape.end(), *it ) ) { if( token != it ) call( std::string( token, it ) ); escape = *it; token = ++it; mMode = ESCAPE; continue; } } break; case ESCAPE: { if( *it == escape ) { if( token != it ) onEscape( std::string( token, it ) ); token = ++it; mMode = NORMAL; continue; } } break; } ++it; } if( token != end ) { if( mMode == NORMAL ) call( std::string( token, end ) ); else onEscape( std::string( token, end ) ); } } void addTokens( const char* token ) { mTokens += token; std::sort( mTokens.begin(), mTokens.end() ); } void addEscape( const char* escape ) { mEscape += escape; std::sort( mEscape.begin(), mEscape.end() ); } private: typedef std::vector< std::pair< std::string::const_iterator, std::string::const_iterator > > Buffer; struct Remover { bool operator () ( const typename Key::value_type& elem ) { if( elem == ' ' || elem == '\n' ) return true; return false; } }; std::string mTokens; std::string mEscape; MODE mMode; }; class IExpression; typedef rp::intrusive_ptr< IExpression > IExpressionPtr; class CallStack { typedef std::deque< IExpressionPtr > Chunk; typedef std::deque< Chunk* > Stack; public: CallStack() : mChunk( 0 ) { bindStack(); } ~CallStack() { while( !mStack.empty() ) { Chunk* chunk = mStack.back(); delete chunk; mStack.pop_back(); } } bool valid() const { return mChunk ? true : false; } bool empty() const { return valid() && mChunk->empty(); } void bindStack() { mChunk = new Chunk(); mStack.push_back( mChunk ); } void unbindStack() { if( mStack.empty() ) return; Chunk* chunk = mStack.back(); delete chunk; mStack.pop_back(); if( mStack.empty() ) mChunk = 0; else mChunk = mStack.back(); } void push_back( IExpressionPtr expr ) { mChunk->push_back( expr ); } void pop_back() { mChunk->pop_back(); } IExpressionPtr back() { return mChunk->back(); } private: Chunk* mChunk; Stack mStack; }; class IExpression : public rp::mixin::ref_counted { public: virtual ~IExpression() {} virtual IExpressionPtr create() = 0; virtual void enter( CallStack& stack ) = 0; virtual numeric_t toNumber() const = 0; virtual std::string toString() const = 0; virtual void push_back( IExpressionPtr expr ) = 0; virtual void pop_back() = 0; virtual IExpressionPtr back() = 0; virtual bool empty() const = 0; virtual bool isDelimiter() const { return false; } }; class Expression : public IExpression { public: virtual ~Expression() {} virtual void push_back( IExpressionPtr expr ) { mArgs.push_back( expr ); } virtual void pop_back() { mArgs.pop_back(); } virtual IExpressionPtr back() { return mArgs.back(); } virtual bool empty() const { return mArgs.empty(); } protected: void ftos( numeric_t src, std::string& dest ) const { char buf[ 256 ]; sprintf_s( buf, "%f", (float)src ); dest = buf; } void ntos( int src, std::string& dest ) const { char buf[ 256 ]; sprintf_s( buf, "%d", src ); dest = buf; } typedef std::deque< IExpressionPtr > ArgContainer; ArgContainer mArgs; }; /// 이항연산자 class Operator : public Expression { public: virtual ~Operator() {} virtual void enter( CallStack& stack ) { IExpressionPtr left = stack.back(); this->push_back( left ); stack.pop_back(); stack.push_back( this ); } }; class Add : public Operator { public: virtual IExpressionPtr create() { return new Add(); } virtual numeric_t toNumber() const { return add(); } virtual std::string toString() const { std::string result; ftos( add(), result ); return result; } private: numeric_t add() const { if( mArgs.size() > 1 ) return mArgs[ 0 ]->toNumber() + mArgs[ 1 ]->toNumber(); return 0.f; } }; class Sub : public Operator { public: virtual IExpressionPtr create() { return new Sub(); } virtual numeric_t toNumber() const { return sub(); } virtual std::string toString() const { std::string result; ftos( sub(), result ); return result; } private: numeric_t sub() const { if( mArgs.size() > 1 ) return mArgs[ 0 ]->toNumber() - mArgs[ 1 ]->toNumber(); return 0.f; } }; class Mul : public Operator { public: virtual IExpressionPtr create() { return new Mul(); } virtual numeric_t toNumber() const { return mul(); } virtual std::string toString() const { std::string result; ftos( mul(), result ); return result; } private: numeric_t mul() const { if( mArgs.size() > 1 ) { /// 2010.11.16 오차 때문에 0.0.000005f를 더함 - prodongi //return mArgs[ 0 ]->toNumber() * mArgs[ 1 ]->toNumber(); numeric_t ret = mArgs[ 0 ]->toNumber() * mArgs[ 1 ]->toNumber(); return (ret <= 0.0f) ? ret : (ret + 0.000005f); } return 0.f; } }; class Div : public Operator { public: virtual IExpressionPtr create() { return new Div(); } virtual numeric_t toNumber() const { return div(); } virtual std::string toString() const { std::string result; ftos( div(), result ); return result; } private: numeric_t div() const { if( mArgs.size() > 1 && mArgs[ 1 ]->toNumber() != 0.f ) return mArgs[ 0 ]->toNumber() / mArgs[ 1 ]->toNumber(); return 0.f; } }; /** @class Attach @brief 사용: 표현식1 & 표현식2 @warning 설명: 표현식1 과 표현식2를 문자열로 치환하여 합친다. */ class Attach : public Operator { public: virtual IExpressionPtr create() { return new Attach(); } virtual numeric_t toNumber() const { return (float)::atof( toString().c_str() ); } virtual std::string toString() const { std::string buffer; for( ArgContainer::const_iterator it = mArgs.begin(); it != mArgs.end(); ++it ) buffer += (*it)->toString(); return buffer; } }; class OpenGroup : public Expression { public: virtual IExpressionPtr create() { return new OpenGroup(); } virtual numeric_t toNumber() const { return 0.f; } virtual std::string toString() const { return ""; } virtual void enter( CallStack& stack ) { stack.bindStack(); } }; class CloseGroup : public Expression { public: virtual IExpressionPtr create() { return new CloseGroup(); } virtual numeric_t toNumber() const { if( mArgs.empty() ) return 0.f; return mArgs[ 0 ]->toNumber(); } virtual std::string toString() const { if( mArgs.empty() ) return ""; return mArgs[ 0 ]->toString(); } virtual void enter( CallStack& stack ) { while( !stack.empty() ) { IExpressionPtr expr = stack.back(); stack.pop_back(); if( !expr->isDelimiter() ) this->push_back( expr ); } stack.unbindStack(); if( !stack.valid() ) return; if( stack.empty() || stack.back()->isDelimiter() ) { stack.push_back( this ); } else { IExpressionPtr expr = stack.back(); expr->push_back( this ); // // 함수일 경우 앞쪽에 이항연산자가 있는지 확인 // if( dynamic_cast< Function* >( expr.get() ) ) { stack.pop_back(); if( !stack.empty() && dynamic_cast< Operator* >( stack.back().get() ) ) stack.back()->push_back( expr ); else stack.push_back( expr ); } } } }; class Delimiter : public Expression { public: virtual IExpressionPtr create() { return new Delimiter(); } virtual numeric_t toNumber() const { return 0.f; } virtual std::string toString() const { return ""; } virtual void push_back( IExpressionPtr expr ) { assert( 0 ); } virtual bool isDelimiter() const { return true; } virtual void enter( CallStack& stack ) { stack.push_back( this ); } }; // // 함수 // class Function : public Expression { public: virtual ~Function() {} virtual void enter( CallStack& stack ) { stack.push_back( this ); } }; /** @class If @brief 사용: if( 표현식1, 표현식2, 표현식3 ) @warning 설명: 표현식1 이 0 이 아닐때 표현식2 를 사용, 표현식1 이 0 이면 표현식3 을 사용한다. */ class If : public Function { public: virtual IExpressionPtr create() { return new If(); } virtual void push_back( IExpressionPtr expr ) { while( !expr->empty() ) { IExpressionPtr arg = expr->back(); expr->pop_back(); mArgs.push_back( arg ); } } virtual numeric_t toNumber() const { if( mArgs.empty() ) return 0.f; if( mArgs[ 0 ]->toNumber() ) { if( mArgs.size() > 1 ) return mArgs[ 1 ]->toNumber(); } else { if( mArgs.size() > 2 ) return mArgs[ 2 ]->toNumber(); } return 0.f; } virtual std::string toString() const { if( mArgs.empty() ) return ""; if( mArgs[ 0 ]->toNumber() ) { if( mArgs.size() > 1 ) return mArgs[ 1 ]->toString(); } else { if( mArgs.size() > 2 ) return mArgs[ 2 ]->toString(); } return ""; } }; /** @class If @brief 사용: if( 표현식1, 표현식2, 표현식3 ) @warning 설명: 표현식1 이 0보다 크면표현식2 를 사용, 표현식1 이 0 이거나 작으면 표현식3 을 사용한다. */ class UnSignedIf : public Function { public: virtual IExpressionPtr create() { return new UnSignedIf(); } virtual void push_back( IExpressionPtr expr ) { while( !expr->empty() ) { IExpressionPtr arg = expr->back(); expr->pop_back(); mArgs.push_back( arg ); } } virtual numeric_t toNumber() const { if( mArgs.empty() ) return 0.f; if( mArgs[ 0 ]->toNumber() > (numeric_t)(0) ) { if( mArgs.size() > 1 ) return mArgs[ 1 ]->toNumber(); } else { if( mArgs.size() > 2 ) return mArgs[ 2 ]->toNumber(); } return 0.f; } virtual std::string toString() const { if( mArgs.empty() ) return ""; /// 2011.03.08 양수만 가능하도록 한다 - prodongi if( mArgs[ 0 ]->toNumber() > (numeric_t)(0) ) { if( mArgs.size() > 1 ) return mArgs[ 1 ]->toString(); } else { if( mArgs.size() > 2 ) return mArgs[ 2 ]->toString(); } return ""; } }; /// 2011.03.22 - prodongi /** @class SignedIf @brief 사용: if( 표현식1, 표현식2, 표현식3 ) @warning 설명: 기존의 If()는 0일 때와 이닐때를 체크 하는데, SignedIf()는 0보다 작을 때와, 0과 같거나 클 때를 체크 함 */ class SignedIf : public Function { public: virtual IExpressionPtr create() { return new SignedIf(); } virtual void push_back( IExpressionPtr expr ) { while( !expr->empty() ) { IExpressionPtr arg = expr->back(); expr->pop_back(); mArgs.push_back( arg ); } } virtual numeric_t toNumber() const { if( mArgs.empty() ) return 0.f; if( mArgs[ 0 ]->toNumber() >= 0 ) { if( mArgs.size() > 1 ) return mArgs[ 1 ]->toNumber(); } else { if( mArgs.size() > 2 ) return mArgs[ 2 ]->toNumber(); } return 0.f; } virtual std::string toString() const { if( mArgs.empty() ) return ""; if( mArgs[ 0 ]->toNumber() >= (numeric_t)(0) ) { if( mArgs.size() > 1 ) return mArgs[ 1 ]->toString(); } else { if( mArgs.size() > 2 ) return mArgs[ 2 ]->toString(); } return ""; } }; /// 2011.04.13 - prodongi /** @class SignedIf @brief 사용: if( 표현식1, 표현식2, 표현식3 ) @warning 설명: 기존의 If()는 0일 때와 이닐때를 체크 하는데, SignedIf()는 1보다 작을 때와, 1과 같거나 클 때를 체크 함 */ class OneSignedIf : public Function { public: virtual IExpressionPtr create() { return new OneSignedIf(); } virtual void push_back( IExpressionPtr expr ) { while( !expr->empty() ) { IExpressionPtr arg = expr->back(); expr->pop_back(); mArgs.push_back( arg ); } } virtual numeric_t toNumber() const { if( mArgs.empty() ) return 0.f; if( mArgs[ 0 ]->toNumber() >= 1 ) { if( mArgs.size() > 1 ) return mArgs[ 1 ]->toNumber(); } else { if( mArgs.size() > 2 ) return mArgs[ 2 ]->toNumber(); } return 0.f; } virtual std::string toString() const { if( mArgs.empty() ) return ""; if( mArgs[ 0 ]->toNumber() >= (numeric_t)(1) ) { if( mArgs.size() > 1 ) return mArgs[ 1 ]->toString(); } else { if( mArgs.size() > 2 ) return mArgs[ 2 ]->toString(); } return ""; } }; /** @class Int @brief 사용: int( 숫자 ) @warning 설명: 숫자를 정수형으로 바꿔준다. */ class Int : public Function { public: virtual IExpressionPtr create() { return new Int(); } virtual void push_back( IExpressionPtr expr ) { while( !expr->empty() ) { IExpressionPtr arg = expr->back(); expr->pop_back(); mArgs.push_back( arg ); } } virtual numeric_t toNumber() const { if( mArgs.empty() ) return 0.f; return mArgs[ 0 ]->toNumber(); } virtual std::string toString() const { if( mArgs.empty() ) return ""; int number = (int)mArgs[ 0 ]->toNumber(); std::string dest; ntos( number, dest ); return dest; } }; /// 2011.03.17 - prodongi class SignedInt : public Function { public: virtual IExpressionPtr create() { return new SignedInt(); } virtual void push_back( IExpressionPtr expr ) { while( !expr->empty() ) { IExpressionPtr arg = expr->back(); expr->pop_back(); mArgs.push_back( arg ); } } virtual numeric_t toNumber() const { if( mArgs.empty() ) return 0.f; return mArgs[ 0 ]->toNumber(); } virtual std::string toString() const { if( mArgs.empty() ) return ""; int number = (int)mArgs[ 0 ]->toNumber(); std::string strNum; ntos( number, strNum ); std::string strSign; if (0 < number) strSign = "+"; std::string strRet = strSign + strNum; return strRet; } }; /** @class Int @brief 사용: int( 숫자 ) @warning 설명: 숫자를 0보다 큰 정수형으로 바꿔준다. */ /// 2011.04.22 - prodongi class AbsInt : public Function { public: virtual IExpressionPtr create() { return new AbsInt(); } virtual void push_back( IExpressionPtr expr ) { while( !expr->empty() ) { IExpressionPtr arg = expr->back(); expr->pop_back(); mArgs.push_back( arg ); } } virtual numeric_t toNumber() const { if( mArgs.empty() ) return 0.f; return abs((int)mArgs[ 0 ]->toNumber()); } virtual std::string toString() const { if( mArgs.empty() ) return ""; int number = abs((int)mArgs[ 0 ]->toNumber()); std::string dest; ntos( number, dest ); return dest; } }; /** @class Float @brief 사용: float( 숫자, 소수점자리수 ) @warning 설명: 소수점 자리수를 지정하지 않으면 기본적으로 4자리수까지 표현한다. */ class Float : public Function { public: virtual IExpressionPtr create() { return new Float(); } virtual void push_back( IExpressionPtr expr ) { while( !expr->empty() ) { IExpressionPtr arg = expr->back(); expr->pop_back(); mArgs.push_back( arg ); } } virtual numeric_t toNumber() const { if( mArgs.empty() ) return 0.f; return mArgs[ 0 ]->toNumber(); } virtual std::string toString() const { if( mArgs.empty() ) return ""; numeric_t number = mArgs[ 0 ]->toNumber(); int floatingPoint = 4; if( mArgs.size() > 1 ) floatingPoint = (int)mArgs[ 1 ]->toNumber(); std::string format; ntos( floatingPoint, format ); format = "%." + format; format += "f"; /// 2011.04.15 오차와 반올림 보정 - prodongi /* char buffer[ 256 ]; ::sprintf_s( buffer, format.c_str(), (float)number ); return buffer; */ return getRevisionFloat(number, floatingPoint, format); } }; /** @class Float @brief 사용: float( 숫자, 소수점자리수 ) @warning 설명: 소수점 자리수를 지정하지 않으면 기본적으로 4자리수까지 표현한다.양의 실수 표시 */ class AbsFloat : public Function { public: virtual IExpressionPtr create() { return new AbsFloat(); } virtual void push_back( IExpressionPtr expr ) { while( !expr->empty() ) { IExpressionPtr arg = expr->back(); expr->pop_back(); mArgs.push_back( arg ); } } virtual numeric_t toNumber() const { if( mArgs.empty() ) return 0.f; return fabs(mArgs[ 0 ]->toNumber()); } virtual std::string toString() const { if( mArgs.empty() ) return ""; numeric_t number = fabs(mArgs[ 0 ]->toNumber()); int floatingPoint = 4; if( mArgs.size() > 1 ) floatingPoint = (int)mArgs[ 1 ]->toNumber(); std::string format; ntos( floatingPoint, format ); format = "%." + format; format += "f"; /// 2011.04.15 오차와 반올림 보정 - prodongi /* char buffer[ 256 ]; ::sprintf_s( buffer, format.c_str(), (float)number ); return buffer; */ return getRevisionFloat(number, floatingPoint, format); } }; /** @class Float @brief 사용: float( 숫자, 소수점자리수 ) @warning 설명: 소수점 자리수를 지정하지 않으면 기본적으로 4자리수까지 표현한다., +/- 표시 */ class SignedFloat : public Function { public: virtual IExpressionPtr create() { return new SignedFloat(); } virtual void push_back( IExpressionPtr expr ) { while( !expr->empty() ) { IExpressionPtr arg = expr->back(); expr->pop_back(); mArgs.push_back( arg ); } } virtual numeric_t toNumber() const { if( mArgs.empty() ) return 0.f; return mArgs[ 0 ]->toNumber(); } virtual std::string toString() const { if( mArgs.empty() ) return ""; numeric_t number = mArgs[ 0 ]->toNumber(); int floatingPoint = 4; if( mArgs.size() > 1 ) floatingPoint = (int)mArgs[ 1 ]->toNumber(); std::string format; ntos( floatingPoint, format ); format = "%." + format; format += "f"; if (0 < number) { format = "+" + format; } /// 2011.04.15 오차와 반올림 보정 - prodongi /* char buffer[ 256 ]; ::sprintf_s( buffer, format.c_str(), (float)number ); return buffer; */ return getRevisionFloat(number, floatingPoint, format); } }; /// 값 class Value : public IExpression { public: virtual ~Value() {} virtual IExpressionPtr create() { return this; } virtual void enter( CallStack& stack ) { if( stack.empty() || stack.back()->isDelimiter() ) { stack.push_back( this ); } else { IExpressionPtr ex = stack.back(); ex->push_back( this ); } } virtual void push_back( IExpressionPtr expr ) { assert( 0 || "value can't have expression" ); } virtual void pop_back() { assert( 0 || "value can't have expression" ); } virtual IExpressionPtr back() { assert( 0 || "value can't have expression" ); return IExpressionPtr(); } virtual bool empty() const { assert( 0 || "value can't have expression" ); return true; } }; class Numeric : public Value { public: virtual ~Numeric() {} Numeric( numeric_t value ) : Value(), mValue( value ) { } virtual numeric_t toNumber() const { return mValue; } virtual std::string toString() const { char temp[ 128 ]; sprintf_s( temp, "%f", (float)mValue ); return std::string( temp ); } protected: numeric_t mValue; }; class String : public Value { public: virtual ~String() {} String( const char* value ) : Value(), mValue( value ) { } virtual numeric_t toNumber() const { return (float)::atof( mValue.c_str() ); } virtual std::string toString() const { return mValue; } protected: std::string mValue; }; /// Factory class Factory { public: virtual ~Factory() { mEqDatas.clear(); } void appendExpression( const char* key, IExpressionPtr value ) { mEqDatas.add( key, value ); } IExpressionPtr findExpression( const char* key ) { IExpressionPtr metaEq; if( mEqDatas.lookup( key, metaEq ) ) return metaEq->create(); return 0; } private: KHash< IExpressionPtr, hashPr_string > mEqDatas; }; /// Compiler class Compiler : public Parser< Compiler, std::string > { public: Compiler( Factory& factory ) : mFactory( factory ) { } virtual ~Compiler() { } IExpressionPtr result() { return mStack.valid() ? mStack.back() : 0; } void clear() { mStack.clear(); } virtual void onNormal( const std::string& expr ) { if( !mStack.valid() ) return; IExpressionPtr def = mFactory.findExpression( expr.c_str() ); if( !def ) def = new Numeric( (float)::atof( expr.c_str() ) ); def->enter( mStack ); } virtual void onEscape( const std::string& escape ) { if( !mStack.valid() ) return; IExpressionPtr value( new String( escape.c_str() ) ); value->enter( mStack ); } private: CallStack mStack; Factory& mFactory; }; }; // eq_expr< numeric_t > } // rp