可以支持简单的函数计算:如(+、-、*、/、^、sin, cos)等等。
用正则表达式写的,核心就如下了:
// compute.h
//
#ifndef HEADFILE_COMPUTE_H_H
#define HEADFILE_COMPUTE_H_H
#pragma once
class CCompute
{
public:
CCompute(FILE* fp);
~CCompute();
void Compute();
private:
void match(char expectedToken);
void error();
void delSpace();
const double term();
const double exp();
const double factor();
const double power();
const double KeyWordOperator();
const double KeyExp();
const CString GetOperatorName();
bool IsAccepted(char);
bool IsLegal(char) const;
public:
bool m_bError;
CString m_cResult;
CString m_strExpress;
private:
FILE* m_fp;
char m_cToken;
};
#endif
// compute.h
//
#include "StdAfx.h"
#include "Compute.h"
/** 表达式
* <exp> -> <term> {<addop> <term>}
* <addop> -> + | -
* <term> -> <factor> {<mulop> <factor>}
* <mulop> -> * | /
* <factor> -> <power> {<powop> <power>}
* <powop> -> ^
* <power> -> <KeyExp> | number
* <KeyExp> -> (exp) | KeyWordOper(exp)
**/
CCompute::CCompute(FILE* fp)
{
m_fp = fp;
m_cToken = ' ';
m_cResult = "";
m_bError = false;
m_strExpress = "";
}
CCompute::~CCompute()
{
m_fp = NULL;
}
void CCompute::error()
{
m_bError = true;
}
void CCompute::match(char expectedToken)
{
if(m_cToken == expectedToken)
{
m_cToken = getc(m_fp);
m_strExpress += expectedToken;
}
else
error();
}
const double CCompute::exp()
{
double temp;
delSpace();
temp = term();
delSpace();
while((m_cToken == '+') || (m_cToken == '-'))
{
switch(m_cToken)
{
case '+' :
match('+');
delSpace();
temp += term();
delSpace();
break;
case '-':
match('-');
delSpace();
temp -= term();
delSpace();
break;
default:
break;
}
}
return temp;
}
const double CCompute::term()
{
double t;
delSpace();
double temp = factor();
delSpace();
while((m_cToken == '*') || (m_cToken == '/'))
{
switch(m_cToken)
{
case '*':
match('*');
delSpace();
temp *= factor();
delSpace();
break;
case '/':
match('/');
delSpace();
t = factor();
if(t != 0.0)
temp /= t;
else
error();
delSpace();
break;
default:
delSpace();
break;
}
}
return temp;
}
const double CCompute::factor()
{
delSpace();
double temp = power();
delSpace();
while(m_cToken == '^')
{
match('^');
delSpace();
temp = pow(temp, power());
delSpace();
}
return temp;
}
void CCompute::delSpace()
{
if(' ' == m_cToken)
{
m_cToken = getc(m_fp);
delSpace();
}
}
const double CCompute::power()
{
double temp = 0.0;
delSpace();
if(isdigit(m_cToken) || (m_cToken == '.')
|| (m_cToken == '-') || (m_cToken == '+'))
{
CString strTemp;
if('-' == m_cToken)
{
fscanf(m_fp, "%lf", &temp);
strTemp.Format("%0.10lf", temp);
temp *= -1;
m_strExpress += m_cToken + CutTail(strTemp);
m_cToken = getc(m_fp);
if(IsAccepted(m_cToken))
delSpace();
else
error();
}
else if('+' == m_cToken)
{
fscanf(m_fp, "%lf", &temp);
strTemp.Format("%0.10lf", temp);
m_strExpress += m_cToken + CutTail(strTemp);
m_cToken = getc(m_fp);
if(IsAccepted(m_cToken))
delSpace();
else
error();
}
else
{
ungetc(m_cToken, m_fp);
fscanf(m_fp, "%lf", &temp);
strTemp.Format("%0.10lf", temp);
m_strExpress += CutTail(strTemp);
m_cToken = getc(m_fp);
if(IsAccepted(m_cToken))
delSpace();
else
error();
}
}
else
temp = KeyExp();
return temp;
}
void CCompute::Compute()
{
m_cToken = getc(m_fp);
double result = exp();
if(false == m_bError)
{
if(m_cToken == '\n' || m_cToken == EOF)
m_cResult.Format("%0.10lf", result);
}
else
m_cResult = "Error";
m_cResult = (m_cResult == "" ? "Error" : m_cResult);
}
const CString CCompute::GetOperatorName()
{
CString _strName;
while(IsLegal(m_cToken))
{
_strName += m_cToken;
m_cToken = getc(m_fp);
}
_strName.MakeLower();
m_strExpress += _strName;
return _strName;
}
bool CCompute::IsLegal(char c) const
{
if ((c > 0X60 && c < 0X7B)
|| (c > 0X40 && c < 0X5B)
|| (c > 0X2F && c < 0X3A)
|| (c == 0X25))
return true;
else
return false;
}
const double CCompute::KeyWordOperator()
{
delSpace();
CString _strOpName = GetOperatorName();
delSpace();
match('(');
delSpace();
//
double temp = 0.0;
double _nExp = exp();
if(_strOpName)
{
if(_strOpName == "sqrt")
temp = sqrt(_nExp);
else if((_strOpName == "abs")
|| (_strOpName == "fabs"))
temp = fabs(_nExp);
else if(_strOpName == "sin")
temp = sin(_nExp);
else if(_strOpName == "cos")
temp = cos(_nExp);
else if((_strOpName == "tan")
|| (_strOpName == "tg"))
temp = tan(_nExp);
else if((_strOpName == "asin")
|| (_strOpName == "arsin")
|| (_strOpName == "arcsin"))
temp = asin(_nExp);
else if((_strOpName == "acos")
|| (_strOpName == "arcos")
|| (_strOpName == "arccos"))
temp = acos(_nExp);
else if((_strOpName == "atan")
|| (_strOpName == "artan")
|| (_strOpName == "arctan"))
temp = atan(_nExp);
else if((_strOpName == "lg")
|| (_strOpName == "lge"))
temp = log(_nExp);
else if((_strOpName == "log")
|| (_strOpName == "log10"))
temp = log10(_nExp);
else if((_strOpName == "ctan")
|| (_strOpName == "ctg"))
temp = 1.0 / tan(_nExp);
else
error();
}
//
match(')');
delSpace();
return temp;
}
const double CCompute::KeyExp()
{
double temp = 0.0;
delSpace();
if(m_cToken == '(')
{
match('(');
delSpace();
temp = exp();
delSpace();
match(')');
}
else if(IsLegal(m_cToken))
temp = KeyWordOperator();
else
error();
return temp;
}
bool CCompute::IsAccepted(char c)
{
return
(
(' ' == c) || ('+' == c) ||
('-' == c) || ('*' == c) ||
('/' == c) || ('^' == c) ||
('(' == c) || (')' == c) ||
(EOF == c) || ('\n' == c)
);
}