📄 fprase.cpp
字号:
data->Variables.clear();
parseErrorType = FP_NO_ERROR;
return -1;
}
namespace
{
// Is given char an operator?
inline bool IsOperator(int c)
{
return strchr("+-*/%^=<>&|",c)!=NULL;
}
// skip whitespace
inline void sws(const char* F, int& Ind)
{
while(F[Ind] && isspace(F[Ind])) ++Ind;
}
};
// Returns an iterator to the variable with the same name as 'F', or to
// Variables.end() if no such variable exists:
inline FunctionParser::Data::VarMap_t::const_iterator
FunctionParser::FindVariable(const char* F, const Data::VarMap_t& vars) const
{
if(vars.size())
{
unsigned ind = 0;
while(isalnum(F[ind]) || F[ind] == '_') ++ind;
if(ind)
{
string name(F, ind);
return vars.find(name);
}
}
return vars.end();
}
inline FunctionParser::Data::ConstMap_t::const_iterator
FunctionParser::FindConstant(const char* F) const
{
if(data->Constants.size())
{
unsigned ind = 0;
while(isalnum(F[ind]) || F[ind] == '_') ++ind;
if(ind)
{
string name(F, ind);
return data->Constants.find(name);
}
}
return data->Constants.end();
}
//---------------------------------------------------------------------------
// Check function string syntax
// ----------------------------
int FunctionParser::CheckSyntax(const char* Function)
{
const Data::VarMap_t& Variables = data->Variables;
const Data::ConstMap_t& Constants = data->Constants;
const Data::VarMap_t& FuncPtrNames = data->FuncPtrNames;
const Data::VarMap_t& FuncParserNames = data->FuncParserNames;
vector<int> functionParenthDepth;
int Ind=0, ParenthCnt=0, c;
char* Ptr;
while(true)
{
sws(Function, Ind);
c=Function[Ind];
// Check for valid operand (must appear)
// Check for leading -
if(c=='-') { sws(Function, ++Ind); c=Function[Ind]; }
if(c==0) { parseErrorType=PREMATURE_EOS; return Ind; }
// Check for math function
bool foundFunc = false;
const FuncDefinition* fptr = FindFunction(&Function[Ind]);
if(fptr)
{
Ind += fptr->nameLength;
foundFunc = true;
}
else
{
// Check for user-defined function
Data::VarMap_t::const_iterator fIter =
FindVariable(&Function[Ind], FuncPtrNames);
if(fIter != FuncPtrNames.end())
{
Ind += fIter->first.size();
foundFunc = true;
}
else
{
Data::VarMap_t::const_iterator pIter =
FindVariable(&Function[Ind], FuncParserNames);
if(pIter != FuncParserNames.end())
{
Ind += pIter->first.size();
foundFunc = true;
}
}
}
if(foundFunc)
{
sws(Function, Ind);
c = Function[Ind];
if(c!='(') { parseErrorType=EXPECT_PARENTH_FUNC; return Ind; }
functionParenthDepth.push_back(ParenthCnt+1);
}
// Check for opening parenthesis
if(c=='(')
{
++ParenthCnt;
sws(Function, ++Ind);
if(Function[Ind]==')') { parseErrorType=EMPTY_PARENTH; return Ind;}
continue;
}
// Check for number
if(isdigit(c) || (c=='.' && isdigit(Function[Ind+1])))
{
strtod(&Function[Ind], &Ptr);
Ind += int(Ptr-&Function[Ind]);
sws(Function, Ind);
c = Function[Ind];
}
else
{ // Check for variable
Data::VarMap_t::const_iterator vIter =
FindVariable(&Function[Ind], Variables);
if(vIter != Variables.end())
Ind += vIter->first.size();
else
{
// Check for constant
Data::ConstMap_t::const_iterator cIter =
FindConstant(&Function[Ind]);
if(cIter != Constants.end())
Ind += cIter->first.size();
else
{ parseErrorType=SYNTAX_ERROR; return Ind; }
}
sws(Function, Ind);
c = Function[Ind];
}
// Check for closing parenthesis
while(c==')')
{
if(functionParenthDepth.size() &&
functionParenthDepth.back() == ParenthCnt)
functionParenthDepth.pop_back();
if((--ParenthCnt)<0) { parseErrorType=MISM_PARENTH; return Ind; }
sws(Function, ++Ind);
c=Function[Ind];
}
// If we get here, we have a legal operand and now a legal operator or
// end of string must follow
// Check for EOS
if(c==0) break; // The only way to end the checking loop without error
// Check for operator
if(!IsOperator(c) &&
(c != ',' || functionParenthDepth.empty() ||
functionParenthDepth.back() != ParenthCnt))
{ parseErrorType=EXPECT_OPERATOR; return Ind; }
// If we get here, we have an operand and an operator; the next loop will
// check for another operand (must appear)
++Ind;
} // while
// Check that all opened parentheses are also closed
if(ParenthCnt>0) { parseErrorType=MISSING_PARENTH; return Ind; }
// The string is ok
parseErrorType=FP_NO_ERROR;
return -1;
}
// Compile function string to bytecode
// -----------------------------------
bool FunctionParser::Compile(const char* Function)
{
if(data->ByteCode) { delete[] data->ByteCode; data->ByteCode=0; }
if(data->Immed) { delete[] data->Immed; data->Immed=0; }
if(data->Stack) { delete[] data->Stack; data->Stack=0; }
vector<unsigned> byteCode; byteCode.reserve(1024);
tempByteCode = &byteCode;
vector<double> immed; immed.reserve(1024);
tempImmed = &immed;
data->StackSize = StackPtr = 0;
CompileExpression(Function, 0);
if(parseErrorType != FP_NO_ERROR) return false;
data->ByteCodeSize = byteCode.size();
data->ImmedSize = immed.size();
if(data->ByteCodeSize)
{
data->ByteCode = new unsigned[data->ByteCodeSize];
memcpy(data->ByteCode, &byteCode[0],
sizeof(unsigned)*data->ByteCodeSize);
}
if(data->ImmedSize)
{
data->Immed = new double[data->ImmedSize];
memcpy(data->Immed, &immed[0],
sizeof(double)*data->ImmedSize);
}
if(data->StackSize)
data->Stack = new double[data->StackSize];
return true;
}
inline void FunctionParser::AddCompiledByte(unsigned c)
{
tempByteCode->push_back(c);
}
inline void FunctionParser::AddImmediate(double i)
{
tempImmed->push_back(i);
}
inline void FunctionParser::AddFunctionOpcode(unsigned opcode)
{
if(data->useDegreeConversion)
switch(opcode)
{
case cCos:
case cCosh:
case cCot:
case cCsc:
case cSec:
case cSin:
case cSinh:
case cTan:
case cTanh:
AddCompiledByte(cRad);
}
AddCompiledByte(opcode);
if(data->useDegreeConversion)
switch(opcode)
{
case cAcos:
#ifndef NO_ASINH
case cAcosh:
case cAsinh:
case cAtanh:
#endif
case cAsin:
case cAtan:
case cAtan2:
AddCompiledByte(cDeg);
}
}
inline void FunctionParser::incStackPtr()
{
if(++StackPtr > data->StackSize) ++(data->StackSize);
}
// Compile if()
int FunctionParser::CompileIf(const char* F, int ind)
{
int ind2 = CompileExpression(F, ind, true); // condition
sws(F, ind2);
if(F[ind2] != ',') { parseErrorType=ILL_PARAMS_AMOUNT; return ind2; }
AddCompiledByte(cIf);
unsigned curByteCodeSize = tempByteCode->size();
AddCompiledByte(0); // Jump index; to be set later
AddCompiledByte(0); // Immed jump index; to be set later
--StackPtr;
ind2 = CompileExpression(F, ind2+1, true); // then
sws(F, ind2);
if(F[ind2] != ',') { parseErrorType=ILL_PARAMS_AMOUNT; return ind2; }
AddCompiledByte(cJump);
unsigned curByteCodeSize2 = tempByteCode->size();
unsigned curImmedSize2 = tempImmed->size();
AddCompiledByte(0); // Jump index; to be set later
AddCompiledByte(0); // Immed jump index; to be set later
--StackPtr;
ind2 = CompileExpression(F, ind2+1, true); // else
sws(F, ind2);
if(F[ind2] != ')') { parseErrorType=ILL_PARAMS_AMOUNT; return ind2; }
// Set jump indices
(*tempByteCode)[curByteCodeSize] = curByteCodeSize2+1;
(*tempByteCode)[curByteCodeSize+1] = curImmedSize2;
(*tempByteCode)[curByteCodeSize2] = tempByteCode->size()-1;
(*tempByteCode)[curByteCodeSize2+1] = tempImmed->size();
return ind2+1;
}
int FunctionParser::CompileFunctionParams(const char* F, int ind,
unsigned requiredParams)
{
unsigned curStackPtr = StackPtr;
int ind2 = CompileExpression(F, ind);
if(StackPtr != curStackPtr+requiredParams)
{ parseErrorType=ILL_PARAMS_AMOUNT; return ind; }
StackPtr -= requiredParams - 1;
sws(F, ind2);
return ind2+1; // F[ind2] is ')'
}
// Compiles element
int FunctionParser::CompileElement(const char* F, int ind)
{
sws(F, ind);
char c = F[ind];
if(c == '(')
{
ind = CompileExpression(F, ind+1);
sws(F, ind);
return ind+1; // F[ind] is ')'
}
if(isdigit(c) || c=='.' /*|| c=='-'*/) // Number
{
const char* startPtr = &F[ind];
char* endPtr;
double val = strtod(startPtr, &endPtr);
AddImmediate(val);
AddCompiledByte(cImmed);
incStackPtr();
return ind+(endPtr-startPtr);
}
if(isalpha(c) || c == '_') // Function, variable or constant
{
const FuncDefinition* func = FindFunction(F+ind);
if(func) // is function
{
int ind2 = ind + func->nameLength;
sws(F, ind2); // F[ind2] is '('
if(strcmp(func->name, "if") == 0) // "if" is a special case
{
return CompileIf(F, ind2+1);
}
#ifndef DISABLE_EVAL
unsigned requiredParams =
strcmp(func->name, "eval") == 0 ?
data->Variables.size() : func->params;
#else
unsigned requiredParams = func->params;
#endif
ind2 = CompileFunctionParams(F, ind2+1, requiredParams);
AddFunctionOpcode(func->opcode);
return ind2; // F[ind2-1] is ')'
}
Data::VarMap_t::const_iterator vIter =
FindVariable(F+ind, data->Variables);
if(vIter != data->Variables.end()) // is variable
{
AddCompiledByte(vIter->second);
incStackPtr();
return ind + vIter->first.size();
}
Data::ConstMap_t::const_iterator cIter = FindConstant(F+ind);
if(cIter != data->Constants.end()) // is constant
{
AddImmediate(cIter->second);
AddCompiledByte(cImmed);
incStackPtr();
return ind + cIter->first.size();
}
Data::VarMap_t::const_iterator fIter =
FindVariable(F+ind, data->FuncPtrNames);
if(fIter != data->FuncPtrNames.end()) // is user-defined func pointer
{
unsigned index = fIter->second;
int ind2 = ind + fIter->first.length();
sws(F, ind2); // F[ind2] is '('
ind2 = CompileFunctionParams(F, ind2+1,
data->FuncPtrs[index].params);
AddCompiledByte(cFCall);
AddCompiledByte(index);
return ind2;
}
Data::VarMap_t::const_iterator pIter =
FindVariable(F+ind, data->FuncParserNames);
if(pIter != data->FuncParserNames.end()) // is user-defined func parser
{
unsigned index = pIter->second;
int ind2 = ind + pIter->first.length();
sws(F, ind2); // F[ind2] is '('
ind2 = CompileFunctionParams
(F, ind2+1, data->FuncParsers[index]->data->varAmount);
AddCompiledByte(cPCall);
AddCompiledByte(index);
return ind2;
}
}
parseErrorType = UNEXPECTED_ERROR;
return ind;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -