www.pudn.com > MathHead > MathSys.cpp
#include "StdAfx.h"
#include "MathSys.h"
inline bool IsDigit(wchar_t c)
{
return (c >= '0' && c <= '9');
}
inline bool IsChar(wchar_t c)
{
if (c >= 'a' && c <= 'z')
return true;
return (c >= 'A' && c <= 'Z');
}
CMathNode::OpType IsOp(wchar_t c)
{
if (c == '+')
return CMathNode::Op_Add;
if (c == '-')
return CMathNode::Op_Sub;
if (c == '*')
return CMathNode::Op_Mul;
if (c == '/')
return CMathNode::Op_Div;
if (c == '^')
return CMathNode::Op_Exp;
if (c == '(')
return CMathNode::Op_ParOpen;
if (c == ')')
return CMathNode::Op_ParClose;
return (CMathNode::Op_Null);
}
std::ostream & operator<<(std::ostream & lhs, CMathNode & rhs);
// Parses a mathematical expression.
int CMathSys::ParseString(wchar_t * wszInput, CMathNode** ppTree)
{
if (!wszInput || !ppTree)
return MATHSYS__NULL_INPUT;
list * pList = NULL;
int nRet;
nRet = BuildList(wszInput, &pList);
if (nRet != MATHSYS__SUCCESS)
return nRet;
nRet = MakeTree(pList, ppTree);
delete pList;
return nRet;
}
// Builds a list of CMathNode's from a string
int CMathSys::BuildList(wchar_t * wszInput, list** ppList)
{
wchar_t wBuffer[MATHSYS__MAX_TOKEN_BUFFER];
wchar_t * pNext = wszInput - 1;
CMathNode * pNodeNext = NULL;
*ppList = new list;
CMathNode::OpType op;
while(true)
{
pNext++;
wchar_t cNext = *pNext;
if (cNext == 0)
break;
if (cNext == ' ')
continue;
else if (IsDigit(cNext) || cNext == '.')
{
int i = 0;
bool bFoundDecimal = false;// = (cNext == '.');
while(true)
{
if (!IsDigit(*pNext))
if (!(*pNext == '.'))
break;
else
if (bFoundDecimal)
return MATHSYS__BAD_INPUT; // A second decimal point was found
else
bFoundDecimal = true;
wBuffer[i++] = *(pNext++);
}
wBuffer[i] = 0; // Null char
--pNext;
pNodeNext = new CMathNode;
if (!bFoundDecimal)
pNodeNext->MakeExact(_wtoi64(wBuffer));
else
pNodeNext->MakeApprox(_wtof(wBuffer));
(*ppList)->push_back(pNodeNext);
}
else if (op = IsOp(cNext))
{
int i = 0;
while (true)
{
if (!IsChar(*pNext))
break;
wBuffer[i++] = *(pNext++);
}
wBuffer[i] = 0; // Null char
pNodeNext = new CMathNode;
pNodeNext->MakeOp(op);
(*ppList)->push_back(pNodeNext);
}
else if (IsChar(cNext))
{
int i = 0;
pNodeNext = new CMathNode;
pNodeNext->MakeVar(cNext);
(*ppList)->push_back(pNodeNext);
}
else
{
// Bad input
FreeNodeList(*ppList);
return MATHSYS__BAD_INPUT;
}
}
if ((*ppList)->size() == 0)
return MATHSYS__BAD_INPUT;
return MATHSYS__SUCCESS;
}
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
void GetNodeDescription(CMathNode* pTree, WCHAR * wBuffer);
int CMathSys::MakeTree(list* pList, CMathNode ** ppTree)
{
/*******************
Order of Operations
1. Parentheses - Sort inner elements
2. Exponent
3. Multiplication, Division
4. Addition, Subtraction
*******************/
CMathNode * pNode = NULL;
iterator iNext = pList->begin();
iterator iStart, iEnd, iArg;
int nParLevel = 0;
if (pList->size() == 0)
return MATHSYS__BAD_INPUT;
list lSub;
// 1. Parentheses
while(iNext != pList->end())
{
/*
Search for the first open paranthesis, mark it, and set
nParLevel to 1. When another is found, nParLevel++.
When a closed parenthesis is found, nParLevel--, until
nParLevel == 0. Splice on [ iStart, iEnd ) and MakeTree
on the sublist.
*/
pNode = *iNext;
if (pNode->m_Type == CMathNode::Node_Op)
{
if (pNode->m_Op == CMathNode::Op_ParOpen)
{
if (nParLevel)
nParLevel++; // Increase level
else
{
iStart = iNext;
nParLevel = 1;
}
}
else if (pNode->m_Op == CMathNode::Op_ParClose)
{
if (--nParLevel == 0)
{
iterator iRemove = iStart; // iRemove = '('
iEnd = iNext;
iNext++; // Move iNext past ')' so it is still valid after this iteration
iStart++; // Move iStart past '('
lSub.splice(lSub.begin(), *pList, iStart, iEnd);
CMathNode * pNew = NULL;
if (MakeTree(&lSub, &pNew) != MATHSYS__SUCCESS)
{
FreeNodeList(&lSub);
return MATHSYS__FAILURE;
}
delete (*iRemove);
iRemove = pList->erase(iRemove);
delete (*iRemove);
iArg = pList->erase(iRemove);
pList->insert(iArg, pNew);
nParLevel = 0;
continue;
}
}
}
iNext++;
}
// 2. Exponents
iNext = pList->begin();
while(iNext != pList->end())
{
pNode = *iNext;
if (pNode->m_Type == CMathNode::Node_Op)
{
if (pNode->m_Op == CMathNode::Op_Exp)
{
if (pNode->m_pSubArray[0].m_Type != CMathNode::Node_Null)
{
// This already has subs (it was in parentheses)
iNext++;
continue;
}
iArg = iNext;
(*(--iArg))->MoveTo(&pNode->m_pSubArray[0]); // Move previous to the first sub
delete (*iArg);
pList->erase(iArg);
iArg = iNext;
(*(++iArg))->MoveTo(&pNode->m_pSubArray[1]); // Move next to the first sub
delete (*iArg);
pList->erase(iArg);
}
}
iNext++;
}
// 3. Multiplication / Division
iNext = pList->begin();
while(iNext != pList->end())
{
pNode = *iNext;
if (pNode->m_Type == CMathNode::Node_Op)
{
if (pNode->m_Op == CMathNode::Op_Mul || pNode->m_Op == CMathNode::Op_Div)
{
if (pNode->m_pSubArray[0].m_Type != CMathNode::Node_Null)
{
// This already has subs (it was in parentheses)
iNext++;
continue;
}
iArg = iNext;
(*(--iArg))->MoveTo(&pNode->m_pSubArray[0]); // Move previous to the first sub
delete (*iArg);
pList->erase(iArg);
iArg = iNext;
(*(++iArg))->MoveTo(&pNode->m_pSubArray[1]); // Move next to the first sub
delete (*iArg);
pList->erase(iArg);
}
}
iNext++;
}
// 4. Addition / Subtraction
iNext = pList->begin();
while(iNext != pList->end())
{
pNode = *iNext;
if (pNode->m_Type == CMathNode::Node_Op)
{
if (pNode->m_Op == CMathNode::Op_Add || pNode->m_Op == CMathNode::Op_Sub)
{
if (pNode->m_pSubArray[0].m_Type != CMathNode::Node_Null)
{
// This already has subs (it was in parentheses)
iNext++;
continue;
}
iArg = iNext;
(*(--iArg))->MoveTo(&pNode->m_pSubArray[0]); // Move previous to the first sub
delete (*iArg);
pList->erase(iArg);
iArg = iNext;
(*(++iArg))->MoveTo(&pNode->m_pSubArray[1]); // Move next to the first sub
delete (*iArg);
pList->erase(iArg);
}
}
iNext++;
}
// Pointer now "owns" the tree in memory
*ppTree = pList->front();
// Don't bother freeing the tree
pList->empty();
return MATHSYS__SUCCESS;
}
void CMathSys::FreeNodeList(list* pList)
{
using std::list::iterator;
for (iterator i = pList->begin(); i != pList->end(); i++)
delete (*i); // CMathNode*
}