//Originically created on October 10, 2004
|
//Modified on January 11, 2011
|
#include <windows.h>
|
#include <stdio.h>
|
#include <tchar.h>
|
|
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
|
|
struct TOKEN;
|
typedef double EVALTYPE;
|
|
class CEvaluator
|
{
|
protected:
|
TOKEN *m_pRoot;
|
void CopyObject(const CEvaluator& obj); //recursive
|
|
public:
|
enum ErrorCode
|
{
|
noError=0, tooComplex=-1, invalidMatch=-2, invalidChar=-3, invalidCode=-4, divisionZero=-5, invalidAssign=-6, noToken=-7
|
};
|
|
CEvaluator(): m_pRoot(NULL) { }
|
CEvaluator(EVALTYPE x); //constructs a constant expression
|
CEvaluator(const CEvaluator& obj): m_pRoot(NULL) { CopyObject(obj); }
|
const CEvaluator& operator =(const CEvaluator& obj) { CopyObject(obj); return *this; }
|
~CEvaluator()
|
{
|
Clear();
|
}
|
|
//µ¥ÀÌÅÍ Ã³¸®
|
void Clear();
|
BOOL IsEmpty() const { return !m_pRoot; }
|
|
//¼ö½Ä ó¸®, Æò°¡ °ü·Ã
|
int Interpret(PCTSTR pszExp);
|
int Evaluate(EVALTYPE& res, EVALTYPE *pVar=NULL, UINT *pvcg=NULL) const;
|
void Simplify();
|
BOOL Restore(PTSTR pszStr, BOOL bHex=FALSE) const; //recursive
|
static EVALTYPE QuickEvaluate(PCTSTR pszExp, EVALTYPE *pVar=NULL, int *pErr=NULL);
|
};
|
|
struct TOKEN
|
{
|
TOKEN(int cod, EVALTYPE pp);
|
TOKEN(int cod, TOKEN *p1, TOKEN *p2, TOKEN *p3=NULL);
|
int nOpCode;
|
union
|
{
|
EVALTYPE nValue;
|
int nVar;
|
TOKEN *pOper[3];
|
};
|
};
|
|
class CCalc
|
{
|
public:
|
class CIterator
|
{ //for recursive calculation
|
public:
|
PTSTR m_pszTo;
|
BOOL m_bHex; //string restoration
|
void Infix(const TOKEN& rt, BOOL bParen=FALSE);
|
};
|
|
struct SIMPLESTACK
|
{ //for non-recursive calculation
|
int pos;
|
TOKEN *pt;
|
};
|
|
enum { SIZE=32 };
|
|
//operator descriptor
|
static PCTSTR m_szOpc[];
|
static inline BOOL IsOperator(int cod) { return cod>=0; }
|
static int GetPrecedence(int cod);
|
static int IsRightToLeft(int cod);
|
static int GetDegree(int cod);
|
|
//operation helper
|
static void FreeNode(TOKEN *rt);
|
static TOKEN *GetClone(TOKEN *rt); //recursive
|
static int PopStack(TOKEN **tok_stk, int& tok_pos, int *opc_stk, int& opc_pos, int baseop=999);
|
};
|
|
enum ETokenType
|
{ //»ó¼ö, º¯¼ö, ¿©´Â°ýÈ£¿Í ´Ý´Â°ýÈ£
|
CONSTANT=-3, VARIABLE=-2, OPENINGBR=100, CLOSINGBR
|
};
|
|
enum EOperatorCode
|
{ //operator code
|
//unary: ~ ! - + (0~3)
|
ONECOMPL, LOGICALNOT, UNARYMINUS, UNARYPLUS,
|
//binary * / % + - << >> < > (4~12)
|
TIMES, DIVIDE, MODULOUS, PLUS, MINUS, LEFTSHIFT, RIGHTSHIFT, LESSTHAN, GREATERTHAN,
|
//<= >= == != & ^ | && || (13~21)
|
LESSTHANEQ, GREATERTHANEQ, EQUALTO, INEQUAL, BITAND, BITXOR, BITOR, AND, OR,
|
//? : = , (22~25)
|
CONDITIONAL, CONDITIONAL2, ASSIGN, COMMA, __endopc
|
};
|
|
//baseopº¸´Ù ¿ì¼±¼øÀ§°¡ ³ô°Å³ª °°Àº °Í(Áï, Äڵ尪ÀÌ ´õ ÀÛÀº °Í)À» ¸ðµÎ »©³½´Ù.
|
//´Ü, baseop°¡ right-to-leftÀÌ¸é ¾È »©³¿.
|
int CCalc::PopStack(TOKEN **tok_stk, int& tok_pos, int *opc_stk, int& opc_pos, int baseop)
|
{
|
int x,y,z=GetPrecedence(baseop);
|
|
TOKEN *ps;
|
|
for(;opc_pos>0;opc_pos--)
|
{
|
x=opc_stk[opc_pos-1];
|
y=GetPrecedence(x);
|
//½ºÅÃÀÇ ¿¬»êÀÚ, Áï ½Ä¿¡¼ ¿ÞÂÊ¿¡ ÀÖ´Â ¿¬»êÀÚ°¡ ¿ì¸® ±âÁØ ¿¬»êÀÚº¸´Ù ¿ì¼±¼øÀ§°¡ ³·°Å³ª,
|
//¿ì¼±¼øÀ§°¡ °°¾Æµµ ¹æÇâÀÌ ¹Ý´ë¸é, ³ªÁß¿¡ 󸮵ǵµ·Ï ¿¬»êÀÚ¸¦ ´õ »©³»Áö ¾Ê´Â´Ù.
|
if(x==CONDITIONAL2 && (z>y || baseop==CONDITIONAL2))
|
{
|
//?:¸¦ »©³¾ Á¶°ÇÀº? baseop ÀÚü°¡ :À̰ųª, baseop°¡ ?:º¸´Ùµµ ¿ì¼± ¼øÀ§°¡ ³·À» ¶§¸¸
|
//x ¾Õ¿¡´Â CONDITIONALÀÌ ÀÖ¾î¾ß ÇÑ´Ù. ÀÌ°É »©³»µµ·Ï.
|
if(opc_pos<2)
|
{
|
return CEvaluator::invalidMatch;
|
}
|
else
|
{
|
if(opc_stk[opc_pos-2]!=CONDITIONAL)
|
{
|
return CEvaluator::invalidMatch;
|
}
|
//try again with ? operator
|
opc_pos--;
|
x=opc_stk[opc_pos-1];
|
y=GetPrecedence(x);
|
}
|
}
|
else if(y>z || (y==z && IsRightToLeft(x) && IsRightToLeft(baseop)) )
|
{
|
break;
|
}
|
|
//´Ý´Â °ýÈ£°¡ µåµð¾î ¿¸° °ýÈ£¸¦ ¸¸³µÀ¸¹Ç·Î ÀÓ¹« ¿Ï¼ö
|
if(x==OPENINGBR && baseop==CLOSINGBR)
|
{
|
opc_pos--;
|
return CEvaluator::noError;
|
}
|
|
y=GetDegree(x);
|
|
if(tok_pos-y<0)
|
{
|
return CEvaluator::invalidMatch; //stack underflow.. ÇÇ¿¬»êÀÚ°¡ ºÎÁ·ÇÏ´Ù
|
}
|
|
TOKEN *p1 = tok_stk[tok_pos-y];
|
TOKEN *p2 = (y>=2) ? tok_stk[tok_pos-y+1]: NULL;
|
TOKEN *p3 = (y==3) ? tok_stk[tok_pos-y+2]: NULL;
|
|
ps = new TOKEN(x, p1, p2, p3);
|
|
tok_stk[tok_pos-y] = ps;
|
|
if(y>=2)
|
{
|
//clear the buffer that has become a child
|
tok_stk[tok_pos-y+1]=NULL;
|
|
if(y==3)
|
{
|
tok_stk[tok_pos-y+2]=NULL;
|
}
|
}
|
tok_pos-=y-1;
|
|
//¹®¹ýÀûÀ¸·Î ¸í¹éÇÑ ¿¬»ê ¿À·ù¸¦ ÄÄÆÄÀÏ Å¸ÀÓ¿¡ ¹Ì¸® °¡·Á³½´Ù
|
if(ps->nOpCode==ASSIGN && ps->pOper[0]->nOpCode!=VARIABLE)
|
{
|
return CEvaluator::invalidAssign;
|
}
|
|
if((ps->nOpCode==DIVIDE || ps->nOpCode==MODULOUS) && (ps->pOper[1]->nOpCode==CONSTANT && ps->pOper[1]->nValue==0) )
|
{
|
return CEvaluator::divisionZero;
|
}
|
}
|
|
//¿©´Â °ýÈ£°¡ ºÎÁ·ÇÏ´Ù
|
return baseop==CLOSINGBR ? CEvaluator::invalidMatch: CEvaluator::noError;
|
}
|
|
int CEvaluator::Interpret(PCTSTR st)
|
{
|
Clear();
|
|
int retc=noError, lastopr=0;
|
|
TOKEN *tok_stk[CCalc::SIZE]={NULL,};
|
int opc_stk[CCalc::SIZE]; //ÇÇ¿¬»êÀÚ¿Í ¿¬»êÀÚÀÇ ½ºÅÃ
|
int tok_pos=0, opc_pos=0;
|
|
while(*st)
|
{
|
//skip whitespaces
|
while(*st==' ' || *st=='\t')
|
{
|
st++;
|
}
|
|
if(!*st)
|
{
|
break;
|
}
|
|
int arr_size = ARRAY_SIZE(tok_stk);
|
|
if(tok_pos==arr_size)
|
{
|
retc=tooComplex;
|
break;
|
}
|
|
//ÇÇ¿¬»êÀÚ¸¦ ã´Â´Ù
|
if((*st>='0' && *st<='9') || (*st=='.')) // »ó¼ö
|
{
|
//ÇÇ¿¬»êÀÚ
|
if(lastopr==CONSTANT)
|
{
|
retc=invalidMatch;
|
break;
|
}
|
|
EVALTYPE x = 0;
|
bool bFindDot = false;
|
double dDotValue = 10.0;
|
for(x=0; (*st>='0' && *st<='9') || (*st=='.'); st++)
|
{
|
if (*st=='.')
|
{
|
bFindDot = true;
|
continue;
|
}
|
|
if (bFindDot)
|
{
|
x = x + double(*st-'0')/(dDotValue);
|
dDotValue *= 10.0;
|
}
|
else
|
{
|
x = (x*10) + (*st-'0');
|
}
|
}
|
|
tok_stk[tok_pos] = new TOKEN(CONSTANT, x);
|
tok_pos++;
|
lastopr=CONSTANT;
|
}
|
else if((*st|32)>='a' && (*st|32)<='z') // º¯¼ö
|
{
|
if(lastopr==CONSTANT)
|
{
|
retc=invalidMatch;
|
break;
|
} //¿¬´Þ¾Æ »ó¼ö??
|
|
tok_stk[tok_pos] = new TOKEN(VARIABLE, (*st|32)-'a');
|
tok_pos++;
|
|
while((*st|32)>='a' && (*st|32)<='z')
|
{
|
st++;
|
}
|
|
lastopr=CONSTANT;
|
}
|
else // ¿¬»êÀÚ È¤Àº °ýÈ£
|
{
|
int x,y;
|
for(y=2;y>=1;y--)
|
{
|
for(x=0;CCalc::m_szOpc[x];x++)
|
{
|
if((int)_tcslen(CCalc::m_szOpc[x])==y && _tcsncmp(CCalc::m_szOpc[x], st, y)==0)
|
{
|
goto Exf;
|
}
|
}
|
}
|
|
Exf:
|
if(*st=='(')
|
{
|
x=OPENINGBR, y=1;
|
}
|
else if(*st==')')
|
{
|
x=CLOSINGBR, y=1;
|
}
|
else if(!CCalc::m_szOpc[x])
|
{
|
retc=invalidChar;
|
break;
|
} //unrecognized code
|
else if(CCalc::IsOperator(lastopr))
|
{ //+, -°¡ ´ÜÇ×ÀÎÁö ÀÌÇ×ÀÎÁö ÆÇ´Ü
|
if(x==PLUS)
|
{
|
x=UNARYPLUS;
|
}
|
else if(x==MINUS)
|
{
|
x=UNARYMINUS;
|
}
|
}
|
else
|
{
|
if(x==UNARYPLUS)
|
{
|
x=PLUS;
|
}
|
else if(x==UNARYMINUS)
|
{
|
x=MINUS;
|
}
|
}
|
|
//¾Õ¿¡ ÀÖ´Â ¿¬»êÀÚ Áß, ¿ì¸® ¿¬»êÀÚº¸´Ù ¿ì¼±¼øÀ§°¡ ³ôÀº °ÍÀ» »©³½´Ù (¿©´Â °ýÈ£´Â ¿¹¿Ü)
|
if(x!=OPENINGBR)
|
{
|
retc = CCalc::PopStack(tok_stk, tok_pos, opc_stk, opc_pos, x);
|
|
if(retc)
|
{
|
break;
|
}
|
}
|
|
//¿ì¸® ¿¬»êÀÚ¸¦ ½ºÅÿ¡´Ù ³Ö´Â´Ù. (´Ý´Â °ýÈ£´Â ¿¹¿Ü)
|
if(x!=CLOSINGBR)
|
{
|
if(opc_pos==ARRAY_SIZE(opc_stk))
|
{
|
retc=tooComplex;
|
break;
|
}
|
opc_stk[opc_pos++]=x; lastopr=x;
|
}
|
else
|
{
|
lastopr=CONSTANT; //´Ý´Â °ýÈ£ÀÇ µî±ÞÀº »ó¼öÀÌ´Ù!!
|
}
|
st+=y;
|
}
|
}
|
|
if(!retc)
|
{ //°ýÈ£°í ¹¹°í ÇÒ °Í ¾øÀÌ ½ºÅÿ¡ ³²¾Æ ÀÖ´Â ÇÇ¿¬»êÀÚ¿Í ¿¬»êÀÚµéÀ» ÃÖÁ¾ Á¤¸®ÇÑ´Ù
|
retc=CCalc::PopStack(tok_stk, tok_pos, opc_stk, opc_pos);
|
//ÇÇ¿¬»êÀÚ ½ºÅÿ£ ¿ø¼Ò°¡ µü Çϳª¸¸ ÀÖ¾î¾ß ÇÑ´Ù
|
if(tok_pos!=1 && !opc_pos)
|
{
|
retc= tok_pos ? invalidMatch: noToken;
|
}
|
}
|
|
if(retc)
|
{
|
for(int x=0;x<ARRAY_SIZE(tok_stk); x++) //free all other remaining nodes
|
{
|
CCalc::FreeNode(tok_stk[x]);
|
}
|
}
|
else
|
{
|
m_pRoot = tok_stk[0]; //¼ö½Ä ÇØ¼®¿¡ ½ÇÆÐÇß´Ù¸é ·çÆ® ³ëµåµµ Áö¿ö ¹ö¸°´Ù
|
}
|
|
return retc;
|
}
|
|
TOKEN *CCalc::GetClone(TOKEN *rt)
|
{
|
if(rt)
|
{
|
switch(rt->nOpCode)
|
{
|
case CONSTANT:
|
return new TOKEN(rt->nOpCode, rt->nValue);
|
|
case VARIABLE:
|
return new TOKEN(rt->nOpCode, rt->nVar);
|
|
default:
|
return new TOKEN(rt->nOpCode, GetClone(rt->pOper[0]), GetClone(rt->pOper[1]), GetClone(rt->pOper[2]));
|
}
|
}
|
else
|
{
|
return NULL;
|
}
|
}
|
|
void CCalc::FreeNode(TOKEN *rt)
|
{
|
CCalc::SIMPLESTACK stk[CCalc::SIZE], *cs=stk, *st_top=stk+ARRAY_SIZE(stk)-1;
|
|
stk[0].pos=0;
|
stk[0].pt=rt;
|
|
while(cs>=stk)
|
{
|
if(cs==st_top) return;
|
|
if(cs->pt && CCalc::IsOperator(cs->pt->nOpCode))
|
{
|
if(cs->pos<3)
|
{
|
cs[1].pt=cs->pt->pOper[cs->pos];
|
cs->pos++;
|
cs++;
|
cs->pos=0;
|
} //push
|
else
|
{
|
delete cs->pt;
|
cs--;
|
}
|
}
|
else
|
{
|
delete cs->pt;
|
cs--;
|
} //delete leaf node
|
}
|
}
|
|
void CCalc::CIterator::Infix(const TOKEN& rt, BOOL bParen)
|
{
|
int x;
|
|
switch(rt.nOpCode)
|
{
|
case CONSTANT:
|
if(m_bHex)
|
{
|
_stprintf_s(m_pszTo, sizeof(m_pszTo)/sizeof(PTSTR), _T("0x%I64x"), rt.nValue);
|
}
|
else
|
{
|
_stprintf_s(m_pszTo, sizeof(m_pszTo)/sizeof(PTSTR), _T("%I64d"), rt.nValue);
|
}
|
|
while(*m_pszTo)
|
{
|
m_pszTo++;
|
}
|
break;
|
|
case VARIABLE:
|
_stprintf_s(m_pszTo, sizeof(m_pszTo)/sizeof(PTSTR), _T("%c"), rt.nVar+'a');
|
while(*m_pszTo)
|
{
|
m_pszTo++;
|
}
|
break;
|
|
default://1==a ? b==c+2 ? a+5:f: 3==2+3
|
x=GetPrecedence(rt.nOpCode);
|
if(bParen)
|
{
|
_tcscpy_s(m_pszTo, sizeof(m_pszTo)/sizeof(PTSTR), _T("(")), m_pszTo++;
|
}
|
|
switch(rt.nOpCode)
|
{
|
case CONDITIONAL:
|
Infix(*rt.pOper[0], GetPrecedence(rt.pOper[0]->nOpCode)>=x);
|
_tcscpy_s(m_pszTo,sizeof(m_pszTo)/sizeof(PTSTR), _T(" ? "));
|
m_pszTo+=3;
|
Infix(*rt.pOper[1], GetPrecedence(rt.pOper[1]->nOpCode)>x);
|
_tcscpy_s(m_pszTo, sizeof(m_pszTo)/sizeof(PTSTR), _T(" : "));
|
m_pszTo+=3;
|
Infix(*rt.pOper[2], GetPrecedence(rt.pOper[2]->nOpCode)>x);
|
break;
|
|
case UNARYMINUS:
|
case UNARYPLUS:
|
case ONECOMPL:
|
case LOGICALNOT: //prefix ´ÜÇ×
|
_tcscpy_s(m_pszTo, sizeof(m_pszTo)/sizeof(PTSTR), m_szOpc[rt.nOpCode]);
|
while(*m_pszTo)
|
{
|
m_pszTo++;
|
}
|
Infix(*rt.pOper[0], GetPrecedence(rt.pOper[0]->nOpCode)>x);
|
break;
|
|
case ASSIGN: //¿À¸¥ÂÊ¿¡¼ ¿ÞÂÊÀ¸·Î °áÇÕÇÏ´Â ÀÌÇ× ¿¬»êÀÚ
|
Infix(*rt.pOper[0], GetPrecedence(rt.pOper[0]->nOpCode)>=x);
|
_tcscpy_s(m_pszTo, sizeof(m_pszTo)/sizeof(PTSTR), m_szOpc[rt.nOpCode]);
|
while(*m_pszTo)
|
{
|
m_pszTo++;
|
}
|
Infix(*rt.pOper[1], GetPrecedence(rt.pOper[1]->nOpCode)>x);
|
break;
|
|
default: //¿ÞÂÊ¿¡¼ ¿À¸¥ÂÊÀ¸·Î °áÇÕÇÏ´Â ÀÌÇ× ¿¬»êÀÚ
|
Infix(*rt.pOper[0], GetPrecedence(rt.pOper[0]->nOpCode)>x);
|
_tcscpy_s(m_pszTo, sizeof(m_pszTo)/sizeof(PTSTR), m_szOpc[rt.nOpCode]);
|
while(*m_pszTo)
|
{
|
m_pszTo++;
|
}
|
Infix(*rt.pOper[1], GetPrecedence(rt.pOper[1]->nOpCode)>=x);
|
}
|
|
if(bParen)
|
{
|
_tcscpy_s(m_pszTo, sizeof(m_pszTo)/sizeof(PTSTR), _T(")")), m_pszTo++;
|
}
|
break;
|
}
|
}
|
|
CEvaluator::CEvaluator(EVALTYPE x): m_pRoot(new TOKEN(CONSTANT, x))
|
{
|
|
}
|
|
void CEvaluator::Clear()
|
{
|
CCalc::FreeNode(m_pRoot);
|
m_pRoot = NULL;
|
}
|
|
//a? b: c? d: e´Â a? b: (c ? d: e)¿Í °°´Ù. µû¶ó¼ ¿À¸¥ÂÊ¿¡¼ ¿ÞÂÊÀ¸·Î °áÇÕ
|
//¿ì¼±¼øÀ§°¡ °°Àº ¿¬»êÀÚµéÀº °áÇÕ ¼ø¼µµ °°´Ù.
|
int CCalc::GetPrecedence(int cod)
|
{
|
#define SAMEORDER(a,b) if(cod>=a && cod<=b) return a
|
SAMEORDER(ONECOMPL, UNARYPLUS);
|
else SAMEORDER(TIMES, MODULOUS);
|
else SAMEORDER(PLUS, MINUS);
|
else SAMEORDER(LEFTSHIFT, RIGHTSHIFT);
|
else SAMEORDER(LESSTHAN, GREATERTHANEQ);
|
else SAMEORDER(EQUALTO, INEQUAL);
|
else SAMEORDER(CONDITIONAL, CONDITIONAL2);
|
else return cod;
|
#undef SAMEORDER
|
}
|
|
int CCalc::IsRightToLeft(int cod)
|
{
|
//´ÜÇ× ¿¬»êÀÚ, ´ëÀÔ ¿¬»êÀÚ, ? : ¿¬»êÀÚ.
|
//1? 0?2:3 :4 ÀÌ·± ¹®ÀåÀ» º¸¸é ? ¿¬»êÀÚ´Â ¿À¸¥ÂÊ¿¡¼ ¿ÞÂÊÀ¸·Î Æò°¡µÈ´Ù
|
return cod==ASSIGN || (cod>=ONECOMPL && cod<=UNARYPLUS) || cod==CONDITIONAL || cod==CONDITIONAL2;
|
}
|
|
int CCalc::GetDegree(int cod)
|
{
|
if(cod>=ONECOMPL && cod<=UNARYPLUS)
|
{
|
return 1; //´ÜÇ× ¿¬»êÀÚ
|
}
|
else if(cod==CONDITIONAL || cod==CONDITIONAL2)
|
{
|
return 3; //»ïÇ× ¿¬»êÀÚ
|
}
|
else
|
{
|
return 2; //³ª¸ÓÁö´Â ÀÌÇ× ¿¬»êÀÚ
|
}
|
}
|
|
PCTSTR CCalc::m_szOpc[]={
|
_T("~"), _T("!"), _T("-"), _T("+"), _T("*"), _T("/"), _T("%"), _T("+"), _T("-"), _T("<<"),
|
_T(">>"), _T("<"), _T(">"), _T("<="), _T(">="), _T("=="), _T("!="), _T("&"), _T("^"),
|
_T("|"), _T("&&"), _T("||"), _T("?"), _T(":"), _T("="), _T(","), NULL
|
};
|
|
int CEvaluator::Evaluate(EVALTYPE& res, EVALTYPE *pVar, UINT *pvcg) const
|
{
|
if(!m_pRoot)
|
{
|
return noToken;
|
}
|
|
struct
|
{
|
EVALTYPE calval[3];
|
TOKEN *pt;
|
int pos, loc; //NOTE: loc is very likely to be elmiated
|
} stk[CCalc::SIZE], *cs=stk, *st_top=stk+ARRAY_SIZE(stk)-1;
|
|
stk[0].pos=stk[0].loc=0;
|
stk[0].pt=m_pRoot;
|
|
int op;
|
while(cs>=stk)
|
{
|
if(cs==st_top)
|
{
|
return tooComplex;
|
}
|
|
op=cs->pt->nOpCode;
|
|
switch(op)
|
{
|
case CONSTANT: //for non-operators
|
cs->calval[cs->loc]=cs->pt->nValue;
|
break;
|
|
case VARIABLE:
|
cs->calval[cs->loc]=pVar ? pVar[cs->pt->nVar]: 0;
|
break;
|
|
default:
|
{
|
EVALTYPE &ea=cs[1].calval[0], &eb=cs[1].calval[1], &ev=cs->calval[cs->loc];
|
|
switch(cs->pos)
|
{
|
//if sufficient number of operands are provided
|
case 1:
|
switch(op)
|
{
|
// case ONECOMPL:
|
// ev=~ea;
|
// goto Q;
|
|
case LOGICALNOT:
|
ev=!ea;
|
goto Q;
|
|
case UNARYMINUS:
|
ev=-ea;
|
goto Q;
|
|
case UNARYPLUS:
|
ev=ea;
|
goto Q;
|
|
default:
|
if(op>=__endopc || op<0)
|
{
|
return invalidCode;
|
}
|
}
|
break;
|
|
case 2:
|
switch(op)
|
{
|
//arithemetic
|
case TIMES:
|
ev=ea*eb;
|
goto Q;
|
|
case DIVIDE:
|
if(eb)
|
{
|
ev=ea/eb;
|
goto Q;
|
}
|
else
|
{
|
return divisionZero;
|
}
|
|
// case MODULOUS:
|
// if(eb)
|
// {
|
// ev=ea%eb;
|
// goto Q;
|
// }
|
// else
|
// {
|
// return divisionZero;
|
// }
|
|
case PLUS:
|
ev=ea+eb;
|
goto Q;
|
|
case MINUS:
|
ev=ea-eb;
|
goto Q;
|
|
// case LEFTSHIFT:
|
// ev=ea<<eb;
|
// goto Q;
|
|
// case RIGHTSHIFT:
|
// ev=ea>>eb;
|
// goto Q;
|
|
//logical
|
case LESSTHAN:
|
ev=ea<eb;
|
goto Q;
|
|
case GREATERTHAN:
|
ev=ea>eb;
|
goto Q;
|
|
case LESSTHANEQ:
|
ev=ea<=eb;
|
goto Q;
|
|
case GREATERTHANEQ:
|
ev=ea>=eb;
|
goto Q;
|
|
case EQUALTO:
|
ev=ea==eb;
|
goto Q;
|
|
case INEQUAL:
|
ev=ea!=eb;
|
goto Q;
|
|
//bit
|
// case BITAND:
|
// ev=ea&eb;
|
// goto Q;
|
|
// case BITXOR:
|
// ev=ea^eb;
|
// goto Q;
|
|
// case BITOR:
|
// ev=ea|eb;
|
// goto Q;
|
|
//logic
|
case AND:
|
case OR:
|
ev=!!eb;
|
goto Q; //lazy evaluation
|
|
//et cetra
|
case CONDITIONAL:
|
ev=eb;
|
goto Q; //it's already handled in a special way
|
|
case ASSIGN:
|
if(cs->pt->pOper[0]->nOpCode!=VARIABLE)
|
{
|
return invalidAssign;
|
}
|
ev=eb;
|
if(pVar)
|
{
|
pVar[cs->pt->pOper[0]->nVar]=eb;
|
}
|
goto Q;
|
|
case COMMA:
|
ev=eb;
|
goto Q;
|
|
default:
|
if(op>=__endopc || op<0)
|
{
|
return invalidCode;
|
}
|
}
|
break;
|
}
|
|
//preprae to push stack
|
if(cs->pos==1)
|
{ //first operand is determined
|
EVALTYPE &ea=cs[1].calval[0], &ev=cs->calval[cs->loc];
|
|
switch(op)
|
{
|
case AND:
|
if(!ea)
|
{
|
ev=0;
|
goto Q;
|
}
|
break; //unconditionally false
|
|
case OR:
|
if(ea)
|
{
|
ev=1;
|
goto Q;
|
}
|
break; //unconditionally true
|
|
case CONDITIONAL: //decide which token to evaluate
|
cs[1].pt=cs->pt->pOper[ea ? 1:2], cs[1].loc=cs->pos; goto P;
|
}
|
}
|
|
cs[1].pt=cs->pt->pOper[cs->pos], cs[1].loc=cs->pos;
|
|
P:
|
cs->pos++, cs++, cs->pos=0;
|
continue;
|
} // default
|
} // end main switch
|
|
Q:
|
cs--; //pop
|
} // end while
|
|
res=stk[0].calval[0];
|
|
return noError;
|
}
|
|
TOKEN::TOKEN(int cod, EVALTYPE pp): nOpCode(cod)
|
{
|
if(cod==CONSTANT)
|
{
|
nValue=pp;
|
}
|
else
|
{
|
nVar=(int)pp;
|
}
|
}
|
|
TOKEN::TOKEN(int cod, TOKEN *p1, TOKEN *p2, TOKEN *p3): nOpCode(cod)
|
{
|
pOper[0]=p1;
|
pOper[1]=p2;
|
pOper[2]=p3;
|
}
|
|
EVALTYPE CEvaluator::QuickEvaluate(PCTSTR pszExp, EVALTYPE *pVar, int *pErr)
|
{
|
CEvaluator ev;
|
EVALTYPE vp;
|
int ec=ev.Interpret(pszExp);
|
|
if(ec)
|
{
|
if(pErr)
|
{
|
*pErr=ec;
|
return 0;
|
}
|
}
|
|
ec=ev.Evaluate(vp, pVar);
|
|
if(pErr)
|
{
|
*pErr=ec;
|
}
|
|
return ec ? 0: vp;
|
}
|
|
BOOL CEvaluator::Restore(PTSTR pszStr, BOOL bHex) const
|
{
|
if(m_pRoot)
|
{
|
CCalc::CIterator is;
|
is.m_pszTo=pszStr;
|
is.m_bHex=bHex;
|
is.Infix(*m_pRoot);
|
return TRUE;
|
}
|
else
|
{
|
*pszStr=0;
|
return FALSE;
|
}
|
}
|
|
void CEvaluator::CopyObject(const CEvaluator& obj)
|
{
|
if(&obj!=this)
|
{
|
m_pRoot=CCalc::GetClone(obj.m_pRoot);
|
}
|
}
|