📄 fprase.cpp
字号:
// Compiles '^'
int FunctionParser::CompilePow(const char* F, int ind)
{
int ind2 = CompileElement(F, ind);
sws(F, ind2);
while(F[ind2] == '^')
{
ind2 = CompileUnaryMinus(F, ind2+1);
sws(F, ind2);
AddCompiledByte(cPow);
--StackPtr;
}
return ind2;
}
// Compiles unary '-'
int FunctionParser::CompileUnaryMinus(const char* F, int ind)
{
sws(F, ind);
if(F[ind] == '-')
{
int ind2 = ind+1;
sws(F, ind2);
ind2 = CompilePow(F, ind2);
sws(F, ind2);
// if we are negating a constant, negate the constant itself:
if(tempByteCode->back() == cImmed)
tempImmed->back() = -tempImmed->back();
// if we are negating a negation, we can remove both:
else if(tempByteCode->back() == cNeg)
tempByteCode->pop_back();
else
AddCompiledByte(cNeg);
return ind2;
}
int ind2 = CompilePow(F, ind);
sws(F, ind2);
return ind2;
}
// Compiles '*', '/' and '%'
int FunctionParser::CompileMult(const char* F, int ind)
{
int ind2 = CompileUnaryMinus(F, ind);
sws(F, ind2);
char op;
while((op = F[ind2]) == '*' || op == '/' || op == '%')
{
ind2 = CompileUnaryMinus(F, ind2+1);
sws(F, ind2);
switch(op)
{
case '*': AddCompiledByte(cMul); break;
case '/': AddCompiledByte(cDiv); break;
case '%': AddCompiledByte(cMod); break;
}
--StackPtr;
}
return ind2;
}
// Compiles '+' and '-'
int FunctionParser::CompileAddition(const char* F, int ind)
{
int ind2 = CompileMult(F, ind);
sws(F, ind2);
char op;
while((op = F[ind2]) == '+' || op == '-')
{
ind2 = CompileMult(F, ind2+1);
sws(F, ind2);
AddCompiledByte(op=='+' ? cAdd : cSub);
--StackPtr;
}
return ind2;
}
// Compiles '=', '<' and '>'
int FunctionParser::CompileComparison(const char* F, int ind)
{
int ind2 = CompileAddition(F, ind);
sws(F, ind2);
char op;
while((op = F[ind2]) == '=' || op == '<' || op == '>')
{
ind2 = CompileAddition(F, ind2+1);
sws(F, ind2);
switch(op)
{
case '=': AddCompiledByte(cEqual); break;
case '<': AddCompiledByte(cLess); break;
case '>': AddCompiledByte(cGreater); break;
}
--StackPtr;
}
return ind2;
}
// Compiles '&'
int FunctionParser::CompileAnd(const char* F, int ind)
{
int ind2 = CompileComparison(F, ind);
sws(F, ind2);
while(F[ind2] == '&')
{
ind2 = CompileComparison(F, ind2+1);
sws(F, ind2);
AddCompiledByte(cAnd);
--StackPtr;
}
return ind2;
}
// Compiles '|'
int FunctionParser::CompileOr(const char* F, int ind)
{
int ind2 = CompileAnd(F, ind);
sws(F, ind2);
while(F[ind2] == '|')
{
ind2 = CompileAnd(F, ind2+1);
sws(F, ind2);
AddCompiledByte(cOr);
--StackPtr;
}
return ind2;
}
// Compiles ','
int FunctionParser::CompileExpression(const char* F, int ind, bool stopAtComma)
{
int ind2 = CompileOr(F, ind);
sws(F, ind2);
if(stopAtComma) return ind2;
while(F[ind2] == ',')
{
ind2 = CompileOr(F, ind2+1);
sws(F, ind2);
}
return ind2;
}
// Return parse error message
// --------------------------
const char* FunctionParser::ErrorMsg() const
{
if(parseErrorType != FP_NO_ERROR) return ParseErrorMessage[parseErrorType];
return 0;
}
//---------------------------------------------------------------------------
// Function evaluation
//---------------------------------------------------------------------------
//===========================================================================
namespace
{
inline int doubleToInt(double d)
{
return d<0 ? -int((-d)+.5) : int(d+.5);
}
inline double Min(double d1, double d2)
{
return d1<d2 ? d1 : d2;
}
inline double Max(double d1, double d2)
{
return d1>d2 ? d1 : d2;
}
inline double DegreesToRadians(double degrees)
{
return degrees*(M_PI/180.0);
}
inline double RadiansToDegrees(double radians)
{
return radians*(180.0/M_PI);
}
}
double FunctionParser::Eval(const double* Vars)
{
const unsigned* const ByteCode = data->ByteCode;
const double* const Immed = data->Immed;
double* const Stack = data->Stack;
const unsigned ByteCodeSize = data->ByteCodeSize;
unsigned IP, DP=0;
int SP=-1;
for(IP=0; IP<ByteCodeSize; ++IP)
{
switch(ByteCode[IP])
{
// Functions:
case cAbs: Stack[SP] = fabs(Stack[SP]); break;
case cAcos: if(Stack[SP] < -1 || Stack[SP] > 1)
{ evalErrorType=4; return 0; }
Stack[SP] = acos(Stack[SP]); break;
#ifndef NO_ASINH
case cAcosh: Stack[SP] = acosh(Stack[SP]); break;
#endif
case cAsin: if(Stack[SP] < -1 || Stack[SP] > 1)
{ evalErrorType=4; return 0; }
Stack[SP] = asin(Stack[SP]); break;
#ifndef NO_ASINH
case cAsinh: Stack[SP] = asinh(Stack[SP]); break;
#endif
case cAtan: Stack[SP] = atan(Stack[SP]); break;
case cAtan2: Stack[SP-1] = atan2(Stack[SP-1], Stack[SP]);
--SP; break;
#ifndef NO_ASINH
case cAtanh: Stack[SP] = atanh(Stack[SP]); break;
#endif
case cCeil: Stack[SP] = ceil(Stack[SP]); break;
case cCos: Stack[SP] = cos(Stack[SP]); break;
case cCosh: Stack[SP] = cosh(Stack[SP]); break;
case cCot:
{
double t = tan(Stack[SP]);
if(t == 0) { evalErrorType=1; return 0; }
Stack[SP] = 1/t; break;
}
case cCsc:
{
double s = sin(Stack[SP]);
if(s == 0) { evalErrorType=1; return 0; }
Stack[SP] = 1/s; break;
}
#ifndef DISABLE_EVAL
case cEval:
{
data->Stack = new double[data->StackSize];
double retVal = Eval(&Stack[SP-data->varAmount+1]);
delete[] data->Stack;
data->Stack = Stack;
SP -= data->varAmount-1;
Stack[SP] = retVal;
break;
}
#endif
case cExp: Stack[SP] = exp(Stack[SP]); break;
case cFloor: Stack[SP] = floor(Stack[SP]); break;
case cIf:
{
unsigned jumpAddr = ByteCode[++IP];
unsigned immedAddr = ByteCode[++IP];
if(doubleToInt(Stack[SP]) == 0)
{
IP = jumpAddr;
DP = immedAddr;
}
--SP; break;
}
case cInt: Stack[SP] = floor(Stack[SP]+.5); break;
case cLog: if(Stack[SP] <= 0) { evalErrorType=3; return 0; }
Stack[SP] = log(Stack[SP]); break;
case cLog10: if(Stack[SP] <= 0) { evalErrorType=3; return 0; }
Stack[SP] = log10(Stack[SP]); break;
case cMax: Stack[SP-1] = Max(Stack[SP-1], Stack[SP]);
--SP; break;
case cMin: Stack[SP-1] = Min(Stack[SP-1], Stack[SP]);
--SP; break;
case cSec:
{
double c = cos(Stack[SP]);
if(c == 0) { evalErrorType=1; return 0; }
Stack[SP] = 1/c; break;
}
case cSin: Stack[SP] = sin(Stack[SP]); break;
case cSinh: Stack[SP] = sinh(Stack[SP]); break;
case cSqrt: if(Stack[SP] < 0) { evalErrorType=2; return 0; }
Stack[SP] = sqrt(Stack[SP]); break;
case cTan: Stack[SP] = tan(Stack[SP]); break;
case cTanh: Stack[SP] = tanh(Stack[SP]); break;
// Misc:
case cImmed: Stack[++SP] = Immed[DP++]; break;
case cJump: DP = ByteCode[IP+2];
IP = ByteCode[IP+1];
break;
// Operators:
case cNeg: Stack[SP] = -Stack[SP]; break;
case cAdd: Stack[SP-1] += Stack[SP]; --SP; break;
case cSub: Stack[SP-1] -= Stack[SP]; --SP; break;
case cMul: Stack[SP-1] *= Stack[SP]; --SP; break;
case cDiv: if(Stack[SP] == 0) { evalErrorType=1; return 0; }
Stack[SP-1] /= Stack[SP]; --SP; break;
case cMod: if(Stack[SP] == 0) { evalErrorType=1; return 0; }
Stack[SP-1] = fmod(Stack[SP-1], Stack[SP]);
--SP; break;
case cPow: Stack[SP-1] = pow(Stack[SP-1], Stack[SP]);
--SP; break;
case cEqual: Stack[SP-1] = (Stack[SP-1] == Stack[SP]);
--SP; break;
case cLess: Stack[SP-1] = (Stack[SP-1] < Stack[SP]);
--SP; break;
case cGreater: Stack[SP-1] = (Stack[SP-1] > Stack[SP]);
--SP; break;
case cAnd: Stack[SP-1] =
(doubleToInt(Stack[SP-1]) &&
doubleToInt(Stack[SP]));
--SP; break;
case cOr: Stack[SP-1] =
(doubleToInt(Stack[SP-1]) ||
doubleToInt(Stack[SP]));
--SP; break;
// Degrees-radians conversion:
case cDeg: Stack[SP] = RadiansToDegrees(Stack[SP]); break;
case cRad: Stack[SP] = DegreesToRadians(Stack[SP]); break;
// User-defined function calls:
case cFCall:
{
unsigned index = ByteCode[++IP];
unsigned params = data->FuncPtrs[index].params;
double retVal =
data->FuncPtrs[index].ptr(&Stack[SP-params+1]);
SP -= params-1;
Stack[SP] = retVal;
break;
}
case cPCall:
{
unsigned index = ByteCode[++IP];
unsigned params = data->FuncParsers[index]->data->varAmount;
double retVal =
data->FuncParsers[index]->Eval(&Stack[SP-params+1]);
SP -= params-1;
Stack[SP] = retVal;
break;
}
#ifdef SUPPORT_OPTIMIZER
case cVar: break; // Paranoia. These should never exist
case cDup: Stack[SP+1] = Stack[SP]; ++SP; break;
case cInv:
if(Stack[SP] == 0.0) { evalErrorType=1; return 0; }
Stack[SP] = 1.0/Stack[SP];
break;
#endif
// Variables:
default:
Stack[++SP] = Vars[ByteCode[IP]-VarBegin];
}
}
evalErrorType=0;
return Stack[SP];
}
#ifdef FUNCTIONPARSER_SUPPORT_DEBUG_OUTPUT
namespace
{
inline void printHex(std::ostream& dest, unsigned n)
{
dest.width(8); dest.fill('0'); hex(dest); //uppercase(dest);
dest << n;
}
}
void FunctionParser::PrintByteCode(std::ostream& dest) const
{
const unsigned* const ByteCode = data->ByteCode;
const double* const Immed = data->Immed;
for(unsigned IP=0, DP=0; IP<data->ByteCodeSize; ++IP)
{
printHex(dest, IP);
dest << ": ";
unsigned opcode = ByteCode[IP];
switch(opcode)
{
case cIf:
dest << "jz\t";
printHex(dest, ByteCode[IP+1]+1);
dest << endl;
IP += 2;
break;
case cJump:
dest << "jump\t";
printHex(dest, ByteCode[IP+1]+1);
dest << endl;
IP += 2;
break;
case cImmed:
dest.precision(10);
dest << "push\t" << Immed[DP++] << endl;
break;
case cFCall:
{
unsigned index = ByteCode[++IP];
Data::VarMap_t::const_iterator iter =
data->FuncPtrNames.begin();
while(iter->second != index) ++iter;
dest << "call\t" << iter->first << endl;
break;
}
case cPCall:
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -