Files
Leviathan/Client/Game/game/Utility/EqExpr.h
T
2026-06-01 12:46:52 +02:00

1227 lines
23 KiB
Objective-C

#pragma once
// #2.1.2.12
//#include <string>
#include <map>
#include <deque>
#include <toolkit/khash.h>
#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