// FL_Calc.cpp: implementation of the CFL_Calc class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "FL_Calc.h"
#include "math.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#define VOID_SEP -1 //
#define NUMBER 0 //
#define SEP_ADD 1 // +
#define SEP_SUB 2 // -
#define SEP_MUL 3 // *
#define SEP_DIV 4 // /
#define SEP_LBR 5 // (
#define SEP_RBR 6 // )
#define SEP_DOT 7 // .
#define SEP_POW 8 // ^ [power]
#define SEP_FCT 9 // ! [factoriel]
#define PRIOR_B 10 // Brackets priority
#define PRIOR_N 11 // Number priority
#define PRIOR_H 12 // Highest priority
#define RES_OK 0 // Result is OK
#define RES_ERR_DIVZERO 1 // Divizion by zero
#define RES_ERR_CANCEL 2 // Canceled by user
#define RES_ERR_BADEXPR 3 // Expression parsed bad
#define ERRMSG_SYNTAXERROR 1
#define ERRMSG_BRACKETDISBALANCE 2
#define ERRMSG_MULTIPLEDOTS 3
#define ERRMSG_DIVZERO 4
#define ERRMSG_CANCEL 5
//-------------------------------------------------------------------------------------------------
CFL_Calc::CFL_Calc()
{
}
CFL_Calc::~CFL_Calc()
{
}
void CFL_Calc::DoAction(unsigned int nIDac, void *pCtrlObject)
{
if (!pCtrlObject)
return;
switch (nIDac)
{
case FL_ACTION_CALC_EXE:
Calculate(pCtrlObject);
return;
case FL_ACTION_CALC_CLEAR:
Clear(pCtrlObject);
return;
}
FLbase_Controller::DoAction(nIDac,pCtrlObject);//DO NOT FORGET IT
}
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
void CFL_Calc::Clear(void *pCtrlObject)
{
CEdit* pEdit=(CEdit*)pCtrlObject;
pEdit->SetWindowText(_T(""));
}
//-------------------------------------------------------------------------------------------------
void CFL_Calc::Calculate(void *pCtrlObject)
{
CEdit* pEdit=(CEdit*)pCtrlObject;
CString sExpr;
pEdit->GetWindowText(sExpr);
sExpr=CalcExpression(sExpr);
if (!sExpr.IsEmpty())
pEdit->SetWindowText(sExpr);
}
//-------------------------------------------------------------------------------------------------
CString CFL_Calc::CalcExpression(CString sExpr)
{
int i1;
BOOL bError=FALSE;
// 1. Preprocessing
// - Checking for empty string
if (sExpr.IsEmpty() || sExpr==_T("="))
return sExpr;
// - Delete '=' if it exists in the end of expression
if (sExpr.GetAt(sExpr.GetLength()-1)==_T('='))
sExpr.Delete(sExpr.GetLength()-1);
// - Removing spaces
for (i1=0;i1<sExpr.GetLength();i1++)
{
if (sExpr.GetAt(i1)==_T(' '))
{
sExpr.Delete(i1--);
}
}
if (sExpr.IsEmpty())
return "";
// - Converting ',' to '.'
for (i1=0;i1<sExpr.GetLength();i1++)
{
TCHAR cSym=sExpr.GetAt(i1);
if (cSym==_T(','))
sExpr.SetAt(i1,_T('.'));
}
// 2. Checking for errors
for (i1=0;i1<sExpr.GetLength();i1++)
{
TCHAR cSym=sExpr.GetAt(i1);
if (cSym!=_T('+') &&
cSym!=_T('-') &&
cSym!=_T('*') &&
cSym!=_T('/') &&
cSym!=_T('!') &&
cSym!=_T('^') &&
cSym!=_T('.') &&
cSym!=_T('(') &&
cSym!=_T(')') &&
cSym!=_T('0') &&
cSym!=_T('1') &&
cSym!=_T('2') &&
cSym!=_T('3') &&
cSym!=_T('4') &&
cSym!=_T('5') &&
cSym!=_T('6') &&
cSym!=_T('7') &&
cSym!=_T('8') &&
cSym!=_T('9')
)
{
bError=TRUE;
break;
}
}
if (bError)
{
TRACE(_T("#Calc Error: Syntax error! \n"));
ErrMessage(ERRMSG_SYNTAXERROR);
return "";
}
// 3. Checking brackets ballance
int cnt_bL=0,cnt_bR=0;
for (i1=0;i1<sExpr.GetLength();i1++)
{
TCHAR cSym=sExpr.GetAt(i1);
if (cSym!=_T('('))
cnt_bL++;
if (cSym!=_T(')'))
cnt_bR++;
}
if (cnt_bL!=cnt_bR)
{
TRACE(_T("#Calc Error: Brackets disbalanced! \n"));
ErrMessage(ERRMSG_BRACKETDISBALANCE);
return "";
}
// 4. Parsing
// Infunction #definitions - Don't try this at home, kids :)
#define ADD_LEX \
{\
if (!sLex.IsEmpty())\
{\
p__lex=new s_lex;\
p__lex->Type=NUMBER;\
p__lex->Priority=PRIOR_N;\
p__lex->spExp=sLex;\
arr_Lex.Add(p__lex);\
}\
}
#define ADD_SEP(sep_code,priority) \
{\
sLex.Empty();\
p__lex=new s_lex;\
p__lex->Type=sep_code;\
p__lex->Val=0;\
p__lex->Priority=priority;\
p__lex->spExp=cSym;\
arr_Lex.Add(p__lex);\
IsSep=TRUE;\
}
#define CLEAN_UP \
{\
for (i1=0;i1<arr_Lex.GetSize();i1++)\
{\
s_lex* p__lex=(s_lex*)arr_Lex.GetAt(i1);\
if (p__lex)\
delete p__lex;\
}\
arr_Lex.RemoveAll();\
}\
s_lex *p__lex=NULL;
CPtrArray arr_Lex;
CPtrArray arr_LexRev;
CString sLex;
for (i1=0;i1<sExpr.GetLength();i1++)
{
BOOL IsSep=FALSE;
TCHAR cSym=sExpr.GetAt(i1);
if (cSym==_T('+'))
{
ADD_LEX
ADD_SEP(SEP_ADD,1)
}
if (cSym==_T('-'))
{
if (i1!=0 && !IsSeparator(sExpr.GetAt(i1-1)))
{
ADD_LEX
ADD_SEP(SEP_SUB,1)
}
}
if (cSym==_T('*'))
{
ADD_LEX
ADD_SEP(SEP_MUL,2)
}
if (cSym==_T('/'))
{
ADD_LEX
ADD_SEP(SEP_DIV,2)
}
if (cSym==_T('^'))
{
ADD_LEX
ADD_SEP(SEP_POW,3)
}
if (cSym==_T('!'))
{
ADD_LEX
ADD_SEP(SEP_FCT,3)
}
if (cSym==_T('('))
{
ADD_LEX
ADD_SEP(SEP_LBR,PRIOR_B)
}
if (cSym==_T(')'))
{
ADD_LEX
ADD_SEP(SEP_RBR,PRIOR_B)
}
if (!IsSep)
{
sLex+=cSym;
}
}
ADD_LEX
// 5.Evaluating
for (i1=0;i1<arr_Lex.GetSize();i1++)
{
s_lex* p__lex=(s_lex*)arr_Lex.GetAt(i1);
if (p__lex && p__lex->Type==NUMBER)
{
// Checking for multiple decimal dots
int dot_count=0;
for (int i_dot=0;i_dot<p__lex->spExp.GetLength();i_dot++)
if (p__lex->spExp.GetAt(i_dot)==_T('.'))
{
dot_count++;
if (dot_count>1)
{
TRACE(_T("#Calc Error: Syntax error - multiple decimal dots! \n"));
ErrMessage(ERRMSG_MULTIPLEDOTS);
CLEAN_UP
return "";
}
}
p__lex->Val=atof(p__lex->spExp);
}
}
// TRACE
#ifdef _DEBUG
TRACE(_T("\nLEXEMS ->\n"));
for (i1=0;i1<arr_Lex.GetSize();i1++)
{
s_lex* p__lex=(s_lex*)arr_Lex.GetAt(i1);
if (p__lex)
TRACE(_T(" Type: %d; spExp: %s; Val %f\n"),p__lex->Type,p__lex->spExp,p__lex->Val);
}
TRACE(_T("\nLEXEMS <-\n"));
#endif
// 6.Parsing...
arr_LexRev.RemoveAll();
RevParse(&arr_Lex,&arr_LexRev,0,arr_Lex.GetSize());
// TRACE
#ifdef _DEBUG
TRACE(_T("\nLEXEMS ->\n"));
for (i1=0;i1<arr_LexRev.GetSize();i1++)
{
s_lex* p__lex=(s_lex*)arr_LexRev.GetAt(i1);
if (p__lex)
TRACE(_T(" Type: %d; spExp: %s; Val %f\n"),p__lex->Type,p__lex->spExp,p__lex->Val);
}
TRACE(_T("\nLEXEMS <-\n"));
#endif
// 7. Calculating
double dResult;
int nErrCode;
nErrCode=CalcProcess(&arr_LexRev,&dResult);
if (nErrCode==RES_OK)
{
CString sResult;
sResult.Format(_T("%f"),dResult);
// Removing trailing zeros (and decimal point if )
if (sResult.Find(_T('.')))
{
while (sResult.GetAt(sResult.GetLength()-1)==_T('0'))
sResult.Delete(sResult.GetLength()-1);
if (sResult.GetAt(sResult.GetLength()-1)==_T('.'))
sResult.Delete(sResult.GetLength()-1);
}
TRACE(_T("\nResult = %s \n"),sResult);
CLEAN_UP
return sResult;
}
else
{ // ERROR
TRACE(_T("#Calc Error: [%d] \n"),nErrCode);
switch (nErrCode)
{
case RES_ERR_DIVZERO:
ErrMessage(ERRMSG_DIVZERO);
break;
case RES_ERR_BADEXPR:
ErrMessage(ERRMSG_SYNTAXERROR);
break;
}
}
// Clean up
CLEAN_UP
return "";
}
//---------------------------------------------------------
FlexEdit_demo.zip_DEMO_Visual C++ 数学_表达式计算
版权申诉
200 浏览量
2022-09-23
23:50:54
上传
评论
收藏 23KB ZIP 举报
alvarocfc
- 粉丝: 105
- 资源: 1万+