mirror of
https://github.com/chibicitiberiu/rainmeter-studio.git
synced 2024-02-24 04:33:31 +00:00
Removed ccalc and replaced with MathParser
This commit is contained in:
parent
f373ea0b1e
commit
caf0a60a5b
@ -18,6 +18,7 @@
|
||||
|
||||
#include "StdAfx.h"
|
||||
#include "ConfigParser.h"
|
||||
#include "MathParser.h"
|
||||
#include "Litestep.h"
|
||||
#include "Rainmeter.h"
|
||||
#include "System.h"
|
||||
@ -37,7 +38,6 @@ std::unordered_map<std::wstring, std::wstring> CConfigParser::c_MonitorVariables
|
||||
**
|
||||
*/
|
||||
CConfigParser::CConfigParser() :
|
||||
m_Parser(MathParser_Create(NULL)),
|
||||
m_LastReplaced(false),
|
||||
m_LastDefaultUsed(false),
|
||||
m_LastValueDefined(false),
|
||||
@ -53,7 +53,6 @@ CConfigParser::CConfigParser() :
|
||||
*/
|
||||
CConfigParser::~CConfigParser()
|
||||
{
|
||||
MathParser_Destroy(m_Parser);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -757,7 +756,7 @@ double CConfigParser::ReadFormula(LPCTSTR section, LPCTSTR key, double defValue)
|
||||
if (!result.empty() && result[0] == L'(' && result[result.size() - 1] == L')')
|
||||
{
|
||||
double resultValue = defValue;
|
||||
char* errMsg = MathParser_Parse(m_Parser, ConvertToAscii(result.c_str()).c_str(), &resultValue);
|
||||
char* errMsg = MathParser::CheckParse(ConvertToAscii(result.c_str()).c_str(), &resultValue);
|
||||
if (errMsg != NULL)
|
||||
{
|
||||
std::wstring error = L"ReadFormula: ";
|
||||
@ -783,7 +782,7 @@ bool CConfigParser::ParseFormula(const std::wstring& result, double* resultValue
|
||||
// Formulas must be surrounded by parenthesis
|
||||
if (!result.empty() && result[0] == L'(' && result[result.size() - 1] == L')')
|
||||
{
|
||||
char* errMsg = MathParser_Parse(m_Parser, ConvertToAscii(result.c_str()).c_str(), resultValue);
|
||||
char* errMsg = MathParser::CheckParse(ConvertToAscii(result.c_str()).c_str(), resultValue);
|
||||
if (errMsg != NULL)
|
||||
{
|
||||
std::wstring error = L"ParseFormula: ";
|
||||
|
@ -28,7 +28,6 @@
|
||||
#include <unordered_map>
|
||||
#include <algorithm>
|
||||
#include <gdiplus.h>
|
||||
#include "ccalc-0.5.1/mparser.h"
|
||||
|
||||
class CRainmeter;
|
||||
class CMeterWindow;
|
||||
@ -122,7 +121,6 @@ private:
|
||||
|
||||
std::wstring m_Filename;
|
||||
|
||||
hqMathParser* m_Parser;
|
||||
std::unordered_map<std::wstring, CMeasure*> m_Measures;
|
||||
|
||||
std::vector<std::wstring> m_StyleTemplate;
|
||||
|
@ -333,6 +333,17 @@
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Use</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MathParser.cpp">
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
|
||||
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Use</PrecompiledHeader>
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
|
||||
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">EnableFastChecks</BasicRuntimeChecks>
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Use</PrecompiledHeader>
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Use</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Measure.cpp">
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
|
||||
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
|
||||
@ -721,30 +732,6 @@
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Use</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ccalc-0.5.1\lexer.c">
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
|
||||
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
|
||||
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">EnableFastChecks</BasicRuntimeChecks>
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ccalc-0.5.1\mparser.c">
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
|
||||
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
|
||||
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">EnableFastChecks</BasicRuntimeChecks>
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ccalc-0.5.1\strmap.c">
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
|
||||
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
|
||||
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">EnableFastChecks</BasicRuntimeChecks>
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>
|
||||
</ClCompile>
|
||||
<ClCompile Include="lua\LuaManager.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../StdAfx.h</PrecompiledHeaderFile>
|
||||
@ -855,6 +842,7 @@
|
||||
<ClInclude Include="Group.h" />
|
||||
<ClInclude Include="Litestep.h" />
|
||||
<ClInclude Include="DialogManage.h" />
|
||||
<ClInclude Include="MathParser.h" />
|
||||
<ClInclude Include="Measure.h" />
|
||||
<ClInclude Include="MeasureCalc.h" />
|
||||
<ClInclude Include="MeasureCPU.h" />
|
||||
@ -896,10 +884,6 @@
|
||||
<ClInclude Include="TintedImage.h" />
|
||||
<ClInclude Include="TrayWindow.h" />
|
||||
<ClInclude Include="UpdateCheck.h" />
|
||||
<ClInclude Include="ccalc-0.5.1\lexer.h" />
|
||||
<ClInclude Include="ccalc-0.5.1\mparser.h" />
|
||||
<ClInclude Include="ccalc-0.5.1\pack.h" />
|
||||
<ClInclude Include="ccalc-0.5.1\strmap.h" />
|
||||
<ClInclude Include="lua\LuaManager.h" />
|
||||
<ClInclude Include="lua\LuaScript.h" />
|
||||
<ClInclude Include="lua\include\lua.hpp" />
|
||||
|
@ -13,9 +13,6 @@
|
||||
<UniqueIdentifier>{2d6bf39d-48e1-4de3-8924-46c5666cb141}</UniqueIdentifier>
|
||||
<Extensions>ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="CCalc">
|
||||
<UniqueIdentifier>{1d914071-7b9c-400c-b7ab-76ac461a16f3}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Lua">
|
||||
<UniqueIdentifier>{6570e2b7-2e40-4fba-a051-01de85760fea}</UniqueIdentifier>
|
||||
</Filter>
|
||||
@ -144,15 +141,6 @@
|
||||
<ClCompile Include="UpdateCheck.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ccalc-0.5.1\lexer.c">
|
||||
<Filter>CCalc</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ccalc-0.5.1\mparser.c">
|
||||
<Filter>CCalc</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ccalc-0.5.1\strmap.c">
|
||||
<Filter>CCalc</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="lua\LuaManager.cpp">
|
||||
<Filter>Lua</Filter>
|
||||
</ClCompile>
|
||||
@ -354,6 +342,9 @@
|
||||
<ClCompile Include="Export.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MathParser.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="ConfigParser.h">
|
||||
@ -476,18 +467,6 @@
|
||||
<ClInclude Include="UpdateCheck.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ccalc-0.5.1\lexer.h">
|
||||
<Filter>CCalc</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ccalc-0.5.1\mparser.h">
|
||||
<Filter>CCalc</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ccalc-0.5.1\pack.h">
|
||||
<Filter>CCalc</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ccalc-0.5.1\strmap.h">
|
||||
<Filter>CCalc</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="lua\LuaManager.h">
|
||||
<Filter>Lua</Filter>
|
||||
</ClInclude>
|
||||
@ -596,6 +575,12 @@
|
||||
<ClInclude Include="Export.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="RawString.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MathParser.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="Library.rc">
|
||||
|
877
Library/MathParser.cpp
Normal file
877
Library/MathParser.cpp
Normal file
@ -0,0 +1,877 @@
|
||||
/*
|
||||
Copyright (C) 2011 Birunthan Mohanathas
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNEstring FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
// Heavily based on ccalc 0.5.1 by Walery Studennikov <hqsoftware@mail.ru>
|
||||
|
||||
#include "StdAfx.h"
|
||||
#include "MathParser.h"
|
||||
|
||||
static const int MAX_STACK_SIZE = 32;
|
||||
static const double M_E = 2.7182818284590452354;
|
||||
static const double M_PI = 3.14159265358979323846;
|
||||
|
||||
typedef double (*OneArgProc)(double arg);
|
||||
typedef char* (*MultiArgProc)(int paramcnt, double* args, double* result);
|
||||
typedef double (*FunctionProc)(double);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
OP_SHL,
|
||||
OP_SHR,
|
||||
OP_POW,
|
||||
OP_LOGIC_NEQ,
|
||||
OP_LOGIC_GEQ,
|
||||
OP_LOGIC_LEQ,
|
||||
OP_LOGIC_AND,
|
||||
OP_LOGIC_OR,
|
||||
OP_OBR,
|
||||
OP_ADD,
|
||||
OP_SUB,
|
||||
OP_MUL,
|
||||
OP_DIV,
|
||||
OP_MOD,
|
||||
OP_UNK,
|
||||
OP_XOR,
|
||||
OP_NOT,
|
||||
OP_AND,
|
||||
OP_OR,
|
||||
OP_EQU,
|
||||
OP_GREATER,
|
||||
OP_SMALLER,
|
||||
OP_LOGIC,
|
||||
OP_LOGIC_SEP,
|
||||
OP_CBR,
|
||||
OP_COMMA,
|
||||
OP_FUNC_ONEARG, // Special
|
||||
OP_FUNC_MULTIARG // Special
|
||||
} OperationType;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void* Func;
|
||||
char prevvalTop;
|
||||
OperationType type;
|
||||
} Operation;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CH_LETTER = 0x01,
|
||||
CH_DIGIT = 0x02,
|
||||
CH_SEPARAT = 0x04,
|
||||
CH_SYMBOL = 0x08,
|
||||
CH_UNKNOWN = 0x7E,
|
||||
CH_FINAL = 0x7F
|
||||
} CharType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TOK_ERROR,
|
||||
TOK_NONE,
|
||||
TOK_FINAL,
|
||||
TOK_FLOAT,
|
||||
TOK_SYMBOL,
|
||||
TOK_NAME
|
||||
} MathTokenType;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char* name;
|
||||
FunctionProc proc;
|
||||
unsigned char length;
|
||||
} Function;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char* string;
|
||||
const char* name;
|
||||
size_t nameLen;
|
||||
double extValue;
|
||||
int intValue;
|
||||
MathTokenType PrevTokenType;
|
||||
CharType CharType;
|
||||
} Lexer;
|
||||
|
||||
char eBrackets [] = "Unmatched brackets";
|
||||
char eSyntax [] = "Syntax error";
|
||||
char eInternal [] = "Internal error";
|
||||
char eExtraOp [] = "Extra operation";
|
||||
char eInfinity [] = "Infinity somewhere";
|
||||
char eInvArg [] = "Invalid argument";
|
||||
char eUnknFunc [] = "\"%s\" is unknown";
|
||||
char eLogicErr [] = "Logical expression error";
|
||||
char eCalcErr [] = "Calculation error";
|
||||
char eValSizErr[] = "Value too big for operation";
|
||||
char eInvPrmCnt[] = "Invalid function parameter count";
|
||||
char g_ErrorBuffer[128];
|
||||
|
||||
static char* CalcToObr();
|
||||
static char* Calc();
|
||||
static int GetFunction(const char* str, size_t len, void** data);
|
||||
int FindSymbol(const char* str);
|
||||
|
||||
static int Lexer_SetParseString(const char* str);
|
||||
static MathTokenType Lexer_GetNextToken();
|
||||
|
||||
static double neg(double x);
|
||||
static double frac(double x);
|
||||
static double trunc(double x);
|
||||
static double sgn(double x);
|
||||
static char* round(int paramcnt, double* args, double* result);
|
||||
|
||||
static Function g_Functions[] =
|
||||
{
|
||||
{ "atan", &atan, 4 },
|
||||
{ "cos", &cos, 3 },
|
||||
{ "sin", &sin, 3 },
|
||||
{ "tan", &tan, 3 },
|
||||
{ "abs", &fabs, 3 },
|
||||
{ "exp", &exp, 3 },
|
||||
{ "ln", &log, 2 },
|
||||
{ "log", &log10, 3 },
|
||||
{ "sqrt", &sqrt, 4 },
|
||||
{ "frac", &frac, 4 },
|
||||
{ "trunc", &trunc, 5 },
|
||||
{ "floor", &floor, 5 },
|
||||
{ "ceil", &ceil, 4 },
|
||||
{ "round", (FunctionProc)&round, 5 },
|
||||
{ "asin", &asin, 4 },
|
||||
{ "acos", &acos, 4 },
|
||||
{ "sgn", &sgn, 4 },
|
||||
{ "neg", &neg, 4 },
|
||||
{ "e", NULL, 1 },
|
||||
{ "pi", NULL, 2}
|
||||
};
|
||||
|
||||
static const int MAX_FUNC_LEN = 5;
|
||||
|
||||
#define FUNC_ROUND 13
|
||||
#define FUNC_E 18
|
||||
#define FUNC_PI 19
|
||||
|
||||
static const Operation g_BrOp = { NULL, '0', OP_OBR };
|
||||
static const Operation g_NegOp = { (void*)&neg, '0', OP_FUNC_ONEARG };
|
||||
|
||||
static const char g_OpPriorities[OP_FUNC_MULTIARG + 1] =
|
||||
{
|
||||
5, // OP_SHL
|
||||
5, // OP_SHR
|
||||
5, // OP_POW
|
||||
2, // OP_LOGIC_NEQ
|
||||
2, // OP_LOGIC_GEQ
|
||||
2, // OP_LOGIC_LEQ
|
||||
2, // OP_LOGIC_AND
|
||||
2, // OP_LOGIC_OR
|
||||
0, // OP_OBR
|
||||
3, // OP_ADD
|
||||
3, // OP_SUB
|
||||
4, // OP_MUL
|
||||
4, // OP_DIV
|
||||
4, // OP_MOD
|
||||
4, // OP_UNK
|
||||
5, // OP_XOR
|
||||
5, // OP_NOT
|
||||
5, // OP_AND
|
||||
5, // OP_OR
|
||||
2, // OP_EQU
|
||||
2, // OP_GREATER
|
||||
2, // OP_SMALLER
|
||||
1, // OP_LOGIC
|
||||
2, // OP_LOGIC_SEP
|
||||
0, // OP_CBR
|
||||
2, // OP_COMMA
|
||||
6, // OP_FUNC_ONEARG
|
||||
6 // OP_FUNC_MULTIARG
|
||||
};
|
||||
|
||||
static Operation g_OpStack[MAX_STACK_SIZE];
|
||||
static double g_ValStack[MAX_STACK_SIZE];
|
||||
static int g_OpTop = 0;
|
||||
static int g_ValTop = -1;
|
||||
static int g_ObrDist = 0;
|
||||
static CharType g_CharTypes[256] = {(CharType)0};
|
||||
static Lexer g_Lexer = {0};
|
||||
|
||||
void MathParser::Initialize()
|
||||
{
|
||||
g_CharTypes['\0'] = CH_FINAL;
|
||||
|
||||
g_CharTypes[' '] = g_CharTypes['\t'] = g_CharTypes['\n'] = CH_SEPARAT;
|
||||
|
||||
g_CharTypes['_'] = CH_LETTER;
|
||||
for (int ch = 'A'; ch <= 'Z'; ++ch) g_CharTypes[ch] = CH_LETTER;
|
||||
for (int ch = 'a'; ch <= 'z'; ++ch) g_CharTypes[ch] = CH_LETTER;
|
||||
for (int ch = '0'; ch <= '9'; ++ch) g_CharTypes[ch] = CH_DIGIT;
|
||||
|
||||
g_CharTypes['+'] = g_CharTypes['-'] = g_CharTypes['/'] = g_CharTypes['*'] =
|
||||
g_CharTypes['~'] = g_CharTypes['('] = g_CharTypes[')'] = g_CharTypes['<'] =
|
||||
g_CharTypes['>'] = g_CharTypes['%'] = g_CharTypes['$'] = g_CharTypes[','] =
|
||||
g_CharTypes['?'] = g_CharTypes[':'] = g_CharTypes['='] = g_CharTypes['&'] =
|
||||
g_CharTypes['|'] = CH_SYMBOL;
|
||||
}
|
||||
|
||||
char* MathParser::Check(const char* formula)
|
||||
{
|
||||
int BrCnt = 0;
|
||||
|
||||
// Brackets Matching
|
||||
while (*formula)
|
||||
{
|
||||
if (*formula == '(')
|
||||
{
|
||||
++BrCnt;
|
||||
}
|
||||
else if (*formula == ')' && (--BrCnt < 0))
|
||||
{
|
||||
return eBrackets;
|
||||
}
|
||||
++formula;
|
||||
}
|
||||
|
||||
if (BrCnt != 0)
|
||||
{
|
||||
return eBrackets;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char* MathParser::CheckParse(const char* formula, double* result)
|
||||
{
|
||||
char* ret = Check(formula);
|
||||
if (ret) return ret;
|
||||
|
||||
ret = Parse(formula, NULL, result);
|
||||
if (ret) return ret;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char* MathParser::Parse(const char* formula, ParameterSearchProc searchProc, double* result)
|
||||
{
|
||||
if (!formula || !*formula)
|
||||
{
|
||||
*result = 0.0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Lexer_SetParseString(formula);
|
||||
|
||||
g_OpTop = 0;
|
||||
g_ValTop = -1;
|
||||
g_OpStack[0].type = OP_OBR;
|
||||
g_ObrDist = 2;
|
||||
|
||||
char* error;
|
||||
MathTokenType token = Lexer_GetNextToken();
|
||||
for (;;)
|
||||
{
|
||||
--g_ObrDist;
|
||||
switch (token)
|
||||
{
|
||||
case TOK_ERROR:
|
||||
return eSyntax;
|
||||
|
||||
case TOK_FINAL:
|
||||
if ((error = CalcToObr()) != NULL)
|
||||
return error;
|
||||
goto setResult;
|
||||
|
||||
case TOK_FLOAT:
|
||||
g_ValStack[++g_ValTop] = g_Lexer.extValue;
|
||||
break;
|
||||
|
||||
case TOK_SYMBOL:
|
||||
switch (g_Lexer.intValue)
|
||||
{
|
||||
case OP_OBR: // (
|
||||
{
|
||||
g_OpStack[++g_OpTop] = g_BrOp;
|
||||
g_ObrDist = 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_CBR: //)
|
||||
{
|
||||
if ((error = CalcToObr()) != NULL) return error;
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_COMMA: // ,
|
||||
{
|
||||
Operation* pOp;
|
||||
if ((error = CalcToObr()) != NULL) return error;
|
||||
|
||||
if ((pOp = &g_OpStack[g_OpTop])->type == OP_FUNC_MULTIARG)
|
||||
{
|
||||
g_OpStack[++g_OpTop] = g_BrOp;
|
||||
g_ObrDist = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
return eSyntax;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
Operation op;
|
||||
op.type = (OperationType) g_Lexer.intValue;
|
||||
switch (op.type)
|
||||
{
|
||||
case OP_ADD:
|
||||
if (g_ObrDist >= 1) goto nextToken;
|
||||
break;
|
||||
|
||||
case OP_SUB:
|
||||
if (g_ObrDist >= 1)
|
||||
{
|
||||
g_OpStack[++g_OpTop] = g_NegOp;
|
||||
goto nextToken;
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_LOGIC:
|
||||
case OP_LOGIC_SEP:
|
||||
g_ObrDist = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
while (g_OpPriorities[op.type] <= g_OpPriorities[g_OpStack[g_OpTop].type])
|
||||
{
|
||||
if ((error = Calc()) != NULL) return error;
|
||||
}
|
||||
g_OpStack[++g_OpTop] = op;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case TOK_NAME:
|
||||
{
|
||||
Operation op;
|
||||
double dblval;
|
||||
void* *func = NULL;
|
||||
int funcnum, namelen = g_Lexer.nameLen;
|
||||
|
||||
if (g_Lexer.nameLen <= MAX_FUNC_LEN &&
|
||||
((funcnum = GetFunction(g_Lexer.name, g_Lexer.nameLen, (void**)&op.Func)) >= 0))
|
||||
{
|
||||
switch (funcnum)
|
||||
{
|
||||
case FUNC_E:
|
||||
g_ValStack[++g_ValTop] = M_E;
|
||||
break;
|
||||
|
||||
case FUNC_PI:
|
||||
g_ValStack[++g_ValTop] = M_PI;
|
||||
break;
|
||||
|
||||
case FUNC_ROUND:
|
||||
op.type = OP_FUNC_MULTIARG;
|
||||
op.prevvalTop = g_ValTop;
|
||||
g_OpStack[++g_OpTop] = op;
|
||||
break;
|
||||
|
||||
default: // Internal function
|
||||
op.type = OP_FUNC_ONEARG;
|
||||
g_OpStack[++g_OpTop] = op;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (searchProc && (*searchProc)(g_Lexer.name, g_Lexer.nameLen, &dblval))
|
||||
{
|
||||
g_ValStack[++g_ValTop] = dblval;
|
||||
break;
|
||||
}
|
||||
|
||||
char buffer[128 - _countof(eUnknFunc)];
|
||||
strncpy_s(buffer, g_Lexer.name, g_Lexer.nameLen);
|
||||
buffer[g_Lexer.nameLen] = '\0';
|
||||
_snprintf_s(g_ErrorBuffer, _TRUNCATE, eUnknFunc, buffer);
|
||||
return g_ErrorBuffer;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return eSyntax;
|
||||
}
|
||||
|
||||
nextToken:
|
||||
token = Lexer_GetNextToken();
|
||||
}
|
||||
|
||||
setResult:
|
||||
if (g_OpTop != -1 || g_ValTop != 0) return eInternal;
|
||||
|
||||
*result = g_ValStack[0];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char* Calc()
|
||||
{
|
||||
double res;
|
||||
Operation op = g_OpStack[g_OpTop--];
|
||||
|
||||
// Multi-argument function
|
||||
if (op.type == OP_FUNC_MULTIARG)
|
||||
{
|
||||
int paramcnt = g_ValTop - op.prevvalTop;
|
||||
|
||||
g_ValTop = op.prevvalTop;
|
||||
char* error = (*(MultiArgProc)op.Func)(paramcnt, &g_ValStack[g_ValTop + 1], &res);
|
||||
if (error) return error;
|
||||
|
||||
g_ValStack[++g_ValTop] = res;
|
||||
return NULL;
|
||||
}
|
||||
else if (op.type == OP_LOGIC)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else if (g_ValTop < 0)
|
||||
{
|
||||
return eExtraOp;
|
||||
}
|
||||
|
||||
// Right arg
|
||||
double right = g_ValStack[g_ValTop--];
|
||||
|
||||
// One arg operations
|
||||
if (op.type == OP_NOT)
|
||||
{
|
||||
if (right >= INT_MIN && right <= INT_MAX)
|
||||
{
|
||||
res = ~((int)right);
|
||||
}
|
||||
else
|
||||
{
|
||||
return eValSizErr;
|
||||
}
|
||||
}
|
||||
else if (op.type == OP_FUNC_ONEARG)
|
||||
{
|
||||
res = (*(OneArgProc)op.Func)(right);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (g_ValTop < 0)
|
||||
{
|
||||
return eExtraOp;
|
||||
}
|
||||
|
||||
// Left arg
|
||||
double left = g_ValStack[g_ValTop--];
|
||||
switch (op.type)
|
||||
{
|
||||
case OP_SHL:
|
||||
if (left >= INT_MIN && left <= INT_MAX && right >= INT_MIN && right <= INT_MAX)
|
||||
{
|
||||
res = (int)left << (int)right;
|
||||
}
|
||||
else
|
||||
{
|
||||
return eValSizErr;
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_SHR:
|
||||
if (left >= INT_MIN && left <= INT_MAX && right >= INT_MIN && right <= INT_MAX)
|
||||
{
|
||||
res = (int)left >> (int)right;
|
||||
}
|
||||
else
|
||||
{
|
||||
return eValSizErr;
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_POW:
|
||||
res = pow(left, right);
|
||||
break;
|
||||
|
||||
case OP_LOGIC_NEQ:
|
||||
res = left != right;
|
||||
break;
|
||||
|
||||
case OP_LOGIC_GEQ:
|
||||
res = left >= right;
|
||||
break;
|
||||
|
||||
case OP_LOGIC_LEQ:
|
||||
res = left <= right;
|
||||
break;
|
||||
|
||||
case OP_LOGIC_AND:
|
||||
res = left && right;
|
||||
break;
|
||||
|
||||
case OP_LOGIC_OR:
|
||||
res = left || right;
|
||||
break;
|
||||
|
||||
case OP_ADD:
|
||||
res = left + right;
|
||||
break;
|
||||
|
||||
case OP_SUB:
|
||||
res = left - right;
|
||||
break;
|
||||
|
||||
case OP_MUL:
|
||||
res = left* right;
|
||||
break;
|
||||
|
||||
case OP_DIV:
|
||||
if (right == 0.0)
|
||||
{
|
||||
return eInfinity;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = left / right;
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_MOD:
|
||||
res = fmod(left, right);
|
||||
break;
|
||||
|
||||
case OP_UNK:
|
||||
if (left <= 0)
|
||||
{
|
||||
res = 0.0;
|
||||
}
|
||||
else if (right == 0.0)
|
||||
{
|
||||
return eInfinity;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = ceil(left / right);
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_XOR:
|
||||
if (left >= INT_MIN && left <= INT_MAX && right >= INT_MIN && right <= INT_MAX)
|
||||
{
|
||||
res = (int)left ^ (int)right;
|
||||
}
|
||||
else
|
||||
{
|
||||
return eValSizErr;
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_AND:
|
||||
if (left >= INT_MIN && left <= INT_MAX && right >= INT_MIN && right <= INT_MAX)
|
||||
{
|
||||
res = (int)left & (int)right;
|
||||
}
|
||||
else
|
||||
{
|
||||
return eValSizErr;
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_OR:
|
||||
if (left >= INT_MIN && left <= INT_MAX && right >= INT_MIN && right <= INT_MAX)
|
||||
{
|
||||
res = (int)left | (int)right;
|
||||
}
|
||||
else
|
||||
{
|
||||
return eValSizErr;
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_EQU:
|
||||
res = left == right;
|
||||
break;
|
||||
|
||||
case OP_GREATER:
|
||||
res = left > right;
|
||||
break;
|
||||
|
||||
case OP_SMALLER:
|
||||
res = left < right;
|
||||
break;
|
||||
|
||||
case OP_LOGIC_SEP:
|
||||
{
|
||||
// needs three arguments
|
||||
double ValLL;
|
||||
if (g_OpTop < 0 || g_OpStack[g_OpTop--].type != OP_LOGIC)
|
||||
{
|
||||
return eLogicErr;
|
||||
}
|
||||
ValLL = g_ValStack[g_ValTop--];
|
||||
res = ValLL ? left : right;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return eInternal;
|
||||
}
|
||||
}
|
||||
|
||||
g_ValStack[++g_ValTop] = res;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char* CalcToObr()
|
||||
{
|
||||
while (g_OpStack[g_OpTop].type != OP_OBR)
|
||||
{
|
||||
char* error = Calc();
|
||||
if (error) return error;
|
||||
}
|
||||
--g_OpTop;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int GetFunction(const char* str, size_t len, void** data)
|
||||
{
|
||||
const int funcCount = sizeof(g_Functions) / sizeof(Function);
|
||||
for (int i = 0; i < funcCount; ++i)
|
||||
{
|
||||
if (g_Functions[i].length == len &&
|
||||
_strnicmp(str, g_Functions[i].name, len) == 0)
|
||||
{
|
||||
*data = g_Functions[i].proc;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int FindSymbol(const char* str)
|
||||
{
|
||||
switch (str[0])
|
||||
{
|
||||
case '(': return (int)OP_OBR;
|
||||
case '+': return OP_ADD;
|
||||
case '-': return OP_SUB;
|
||||
case '*': return (str[1] == '*') ? OP_POW : OP_MUL;
|
||||
case '/': return OP_DIV;
|
||||
case '%': return OP_MOD;
|
||||
case '$': return OP_UNK;
|
||||
case '^': return OP_XOR;
|
||||
case '~': return OP_NOT;
|
||||
case '&': return (str[1] == '&') ? OP_LOGIC_AND : OP_AND;
|
||||
case '|': return (str[1] == '|') ? OP_LOGIC_OR : OP_OR;
|
||||
case '=': return OP_EQU;
|
||||
case '>': return (str[1] == '>') ? OP_SHR : (str[1] == '=') ? OP_LOGIC_GEQ : OP_GREATER;
|
||||
case '<': return (str[1] == '>') ? OP_LOGIC_NEQ : (str[1] == '<') ? OP_SHL : (str[1] == '=') ? OP_LOGIC_LEQ : OP_SMALLER;
|
||||
case '?': return OP_LOGIC;
|
||||
case ':': return OP_LOGIC_SEP;
|
||||
case ')': return OP_CBR;
|
||||
case ',': return OP_COMMA;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
// Lexer
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
|
||||
inline CharType CHARTYPEPP() { return g_CharTypes[(unsigned char)*++(g_Lexer.string)]; }
|
||||
inline CharType CHARTYPE() { return g_CharTypes[(unsigned char)*g_Lexer.string]; }
|
||||
|
||||
int Lexer_SetParseString(const char* str)
|
||||
{
|
||||
g_Lexer.PrevTokenType = TOK_NONE;
|
||||
if (!str || !*str) return 0;
|
||||
|
||||
g_Lexer.string = str;
|
||||
g_Lexer.CharType = CHARTYPE();
|
||||
return 1;
|
||||
}
|
||||
|
||||
MathTokenType Lexer_GetNextToken()
|
||||
{
|
||||
MathTokenType result = TOK_ERROR;
|
||||
|
||||
while (g_Lexer.CharType == CH_SEPARAT)
|
||||
{
|
||||
g_Lexer.CharType = CHARTYPEPP();
|
||||
}
|
||||
|
||||
switch (g_Lexer.CharType)
|
||||
{
|
||||
case CH_FINAL:
|
||||
{
|
||||
result = TOK_FINAL;
|
||||
}
|
||||
break;
|
||||
|
||||
case CH_LETTER:
|
||||
{
|
||||
g_Lexer.name = g_Lexer.string;
|
||||
do
|
||||
{
|
||||
g_Lexer.CharType = CHARTYPEPP();
|
||||
}
|
||||
while (g_Lexer.CharType <= CH_DIGIT);
|
||||
|
||||
g_Lexer.nameLen = g_Lexer.string - g_Lexer.name;
|
||||
result = TOK_NAME;
|
||||
}
|
||||
break;
|
||||
|
||||
case CH_DIGIT:
|
||||
{
|
||||
char* newString;
|
||||
if (g_Lexer.string[0] == '0')
|
||||
{
|
||||
bool valid = true;
|
||||
switch (g_Lexer.string[1])
|
||||
{
|
||||
case 'x': // Hexadecimal
|
||||
g_Lexer.intValue = strtol(g_Lexer.string, &newString, 16);
|
||||
break;
|
||||
|
||||
case 'o': // Octal
|
||||
g_Lexer.intValue = strtol(g_Lexer.string + 2, &newString, 8);
|
||||
break;
|
||||
|
||||
case 'b': // Binary
|
||||
g_Lexer.intValue = strtol(g_Lexer.string + 2, &newString, 2);
|
||||
break;
|
||||
|
||||
default:
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (valid)
|
||||
{
|
||||
if (g_Lexer.string != newString)
|
||||
{
|
||||
g_Lexer.string = newString;
|
||||
g_Lexer.CharType = CHARTYPE();
|
||||
g_Lexer.extValue = g_Lexer.intValue;
|
||||
result = TOK_FLOAT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Decimal
|
||||
g_Lexer.extValue = strtod(g_Lexer.string, &newString);
|
||||
if (g_Lexer.string != newString)
|
||||
{
|
||||
g_Lexer.string = newString;
|
||||
g_Lexer.CharType = CHARTYPE();
|
||||
result = TOK_FLOAT;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CH_SYMBOL:
|
||||
{
|
||||
int sym = FindSymbol(g_Lexer.string);
|
||||
if (sym >= 0)
|
||||
{
|
||||
g_Lexer.string += (sym == OP_POW ||
|
||||
sym == OP_LOGIC_AND || sym == OP_LOGIC_OR ||
|
||||
sym == OP_SHR || sym == OP_LOGIC_GEQ ||
|
||||
sym == OP_LOGIC_NEQ || sym == OP_SHL || sym == OP_LOGIC_LEQ) ? 2 : 1;
|
||||
|
||||
g_Lexer.CharType = CHARTYPE();
|
||||
g_Lexer.intValue = sym;
|
||||
result = TOK_SYMBOL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return g_Lexer.PrevTokenType = result;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
// Misc
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
|
||||
static double frac(double x)
|
||||
{
|
||||
double y;
|
||||
return modf(x, &y);
|
||||
}
|
||||
|
||||
static double trunc(double x)
|
||||
{
|
||||
return (x >= 0.0) ? floor(x) : ceil(x);
|
||||
}
|
||||
|
||||
static double sgn(double x)
|
||||
{
|
||||
return (x > 0) ? 1 : (x < 0) ? -1 : 0;
|
||||
}
|
||||
|
||||
static double neg(double x)
|
||||
{
|
||||
return -x;
|
||||
}
|
||||
|
||||
// "Advanced" round function; second argument - sharpness
|
||||
static char* round(int paramcnt, double* args, double* result)
|
||||
{
|
||||
int sharpness;
|
||||
if (paramcnt == 1)
|
||||
{
|
||||
sharpness = 0;
|
||||
}
|
||||
else if (paramcnt == 2)
|
||||
{
|
||||
sharpness = (int)args[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
return eInvPrmCnt;
|
||||
}
|
||||
|
||||
double x = args[0];
|
||||
double coef;
|
||||
if (sharpness < 0)
|
||||
{
|
||||
coef = 0.1;
|
||||
sharpness = -sharpness;
|
||||
}
|
||||
else
|
||||
{
|
||||
coef = 10;
|
||||
}
|
||||
|
||||
for (int i = 0; i < sharpness; i++) x *= coef;
|
||||
|
||||
x = (x + ((x >= 0) ? 0.5 : -0.5));
|
||||
x = (x >= 0.0) ? floor(x) : ceil(x);
|
||||
|
||||
for (int i = 0; i < sharpness; i++) x /= coef;
|
||||
|
||||
*result = x;
|
||||
return NULL;
|
||||
}
|
35
Library/MathParser.h
Normal file
35
Library/MathParser.h
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
Copyright (C) 2011 Birunthan Mohanathas
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
// Heavily based on ccalc 0.5.1 by Walery Studennikov <hqsoftware@mail.ru>
|
||||
|
||||
#ifndef __MATHPARSER_H__
|
||||
#define __MATHPARSER_H__
|
||||
|
||||
namespace MathParser
|
||||
{
|
||||
typedef int (*ParameterSearchProc)(const char* str, int len, double* value);
|
||||
|
||||
void Initialize();
|
||||
|
||||
char* Check(const char* formula);
|
||||
char* CheckParse(const char* formula, double* result);
|
||||
char* Parse(const char* formula, ParameterSearchProc searchProc, double* result);
|
||||
};
|
||||
|
||||
#endif
|
@ -19,8 +19,9 @@
|
||||
#include "StdAfx.h"
|
||||
#include "MeasureCalc.h"
|
||||
#include "Rainmeter.h"
|
||||
#include "MathParser.h"
|
||||
|
||||
hqStrMap* CMeasureCalc::c_VarMap = NULL;
|
||||
CMeterWindow* CMeasureCalc::c_MeterWindow = NULL;
|
||||
bool CMeasureCalc::c_RandSeeded = false;
|
||||
|
||||
/*
|
||||
@ -30,7 +31,6 @@ bool CMeasureCalc::c_RandSeeded = false;
|
||||
**
|
||||
*/
|
||||
CMeasureCalc::CMeasureCalc(CMeterWindow* meterWindow, const WCHAR* name) : CMeasure(meterWindow, name),
|
||||
m_Parser(MathParser_Create(NULL)),
|
||||
m_LowBound(),
|
||||
m_HighBound(100),
|
||||
m_UpdateRandom(false)
|
||||
@ -52,13 +52,6 @@ CMeasureCalc::CMeasureCalc(CMeterWindow* meterWindow, const WCHAR* name) : CMeas
|
||||
*/
|
||||
CMeasureCalc::~CMeasureCalc()
|
||||
{
|
||||
MathParser_Destroy(m_Parser);
|
||||
|
||||
if (c_VarMap)
|
||||
{
|
||||
StrMap_Destroy(c_VarMap);
|
||||
c_VarMap = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -71,13 +64,12 @@ bool CMeasureCalc::Update()
|
||||
{
|
||||
if (!CMeasure::PreUpdate()) return false;
|
||||
|
||||
m_Parser->Parameters = c_VarMap;
|
||||
if (m_UpdateRandom)
|
||||
{
|
||||
FormulaReplace();
|
||||
}
|
||||
|
||||
char* errMsg = MathParser_Parse(m_Parser, ConvertToAscii(m_Formula.c_str()).c_str(), &m_Value);
|
||||
char* errMsg = MathParser::Parse(ConvertToAscii(m_Formula.c_str()).c_str(), MatchMeasure, &m_Value);
|
||||
if (errMsg != NULL)
|
||||
{
|
||||
std::wstring error = L"Calc: ";
|
||||
@ -91,32 +83,27 @@ bool CMeasureCalc::Update()
|
||||
return PostUpdate();
|
||||
}
|
||||
|
||||
void CMeasureCalc::UpdateVariableMap(CMeterWindow& meterWindow)
|
||||
int CMeasureCalc::MatchMeasure(const char* str, int len, double* value)
|
||||
{
|
||||
// Delete the old map
|
||||
if (c_VarMap)
|
||||
{
|
||||
StrMap_Destroy(c_VarMap);
|
||||
c_VarMap = NULL;
|
||||
}
|
||||
|
||||
// Create the variable map
|
||||
c_VarMap = Strmap_Create(sizeof(double), 0);
|
||||
|
||||
const std::list<CMeasure*>& measures = meterWindow.GetMeasures();
|
||||
const std::list<CMeasure*>& measures = c_MeterWindow->GetMeasures();
|
||||
|
||||
std::list<CMeasure*>::const_iterator iter = measures.begin();
|
||||
for ( ; iter != measures.end(); ++iter)
|
||||
{
|
||||
const char* name = (*iter)->GetAsciiName();
|
||||
double val = (*iter)->GetValue();
|
||||
|
||||
StrMap_AddString(c_VarMap, name, &val);
|
||||
if (_strnicmp(str, (*iter)->GetAsciiName(), len) == 0)
|
||||
{
|
||||
*value = (*iter)->GetValue();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the counter
|
||||
double counter = meterWindow.GetUpdateCounter();
|
||||
StrMap_AddString(c_VarMap, "Counter", &counter);
|
||||
if (_strnicmp(str, "counter", len) == 0)
|
||||
{
|
||||
*value = c_MeterWindow->GetUpdateCounter();
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -153,6 +140,17 @@ void CMeasureCalc::ReadConfig(CConfigParser& parser, const WCHAR* section)
|
||||
{
|
||||
FormulaReplace();
|
||||
}
|
||||
|
||||
char* errMsg = MathParser::Check(ConvertToAscii(m_Formula.c_str()).c_str());
|
||||
if (errMsg != NULL)
|
||||
{
|
||||
std::wstring error = L"Calc: ";
|
||||
error += ConvertToWide(errMsg);
|
||||
error += L" in [";
|
||||
error += m_Name;
|
||||
error += L']';
|
||||
throw CError(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -164,8 +162,8 @@ void CMeasureCalc::ReadConfig(CConfigParser& parser, const WCHAR* section)
|
||||
*/
|
||||
void CMeasureCalc::FormulaReplace()
|
||||
{
|
||||
//To implement random numbers the word "Random" in the string
|
||||
//formula is being replaced by the random number value
|
||||
// To implement random numbers the word "Random" in the string
|
||||
// formula is being replaced by the random number value
|
||||
m_Formula = m_FormulaHolder;
|
||||
size_t start = 0, pos;
|
||||
|
||||
|
@ -20,7 +20,6 @@
|
||||
#define __MEASURECALC_H__
|
||||
|
||||
#include "Measure.h"
|
||||
#include "ccalc-0.5.1/mparser.h"
|
||||
|
||||
class CMeasureCalc : public CMeasure
|
||||
{
|
||||
@ -30,7 +29,7 @@ public:
|
||||
|
||||
virtual bool Update();
|
||||
|
||||
static void UpdateVariableMap(CMeterWindow& meterWindow);
|
||||
static void SetCurrentMeterWindow(CMeterWindow* meterWindow) { c_MeterWindow = meterWindow; }
|
||||
|
||||
protected:
|
||||
virtual void ReadConfig(CConfigParser& parser, const WCHAR* section);
|
||||
@ -39,15 +38,16 @@ private:
|
||||
void FormulaReplace();
|
||||
bool IsDelimiter(WCHAR ch);
|
||||
|
||||
static int MatchMeasure(const char* str, int len, double* value);
|
||||
|
||||
std::wstring m_Formula;
|
||||
std::wstring m_FormulaHolder;
|
||||
hqMathParser* m_Parser;
|
||||
|
||||
int m_LowBound;
|
||||
int m_HighBound;
|
||||
bool m_UpdateRandom;
|
||||
|
||||
static hqStrMap* c_VarMap;
|
||||
static CMeterWindow* c_MeterWindow;
|
||||
static bool c_RandSeeded;
|
||||
};
|
||||
|
||||
|
@ -1417,7 +1417,7 @@ void CMeterWindow::UpdateMeasure(const WCHAR* name, bool group)
|
||||
// Pre-updates
|
||||
if (!m_Measures.empty())
|
||||
{
|
||||
CMeasureCalc::UpdateVariableMap(*this);
|
||||
CMeasureCalc::SetCurrentMeterWindow(this);
|
||||
}
|
||||
|
||||
bool bNetStats = m_HasNetMeasures;
|
||||
@ -2944,7 +2944,7 @@ void CMeterWindow::Update(bool nodraw)
|
||||
CMeasureNet::UpdateIFTable();
|
||||
CMeasureNet::UpdateStats();
|
||||
}
|
||||
CMeasureCalc::UpdateVariableMap(*this);
|
||||
CMeasureCalc::SetCurrentMeterWindow(this);
|
||||
|
||||
// Update all measures
|
||||
std::list<CMeasure*>::const_iterator i = m_Measures.begin();
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "Error.h"
|
||||
#include "DialogAbout.h"
|
||||
#include "DialogManage.h"
|
||||
#include "MathParser.h"
|
||||
#include "MeasureNet.h"
|
||||
#include "MeterString.h"
|
||||
#include "resource.h"
|
||||
@ -1067,6 +1068,7 @@ int CRainmeter::Initialize(HWND hParent, HINSTANCE hInstance, LPCWSTR szPath)
|
||||
// Test that the Rainmeter.ini file is writable
|
||||
TestSettingsFile(bDefaultIniLocation);
|
||||
|
||||
MathParser::Initialize();
|
||||
CSystem::Initialize(hInstance);
|
||||
CMeasureNet::InitializeNewApi();
|
||||
|
||||
|
@ -1,290 +0,0 @@
|
||||
/*
|
||||
Universal lexical analiser implementation
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include "lexer.h"
|
||||
|
||||
//#define MY_DEBUG 1
|
||||
|
||||
#ifdef MY_DEBUG
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
/* Uppercase translation table for the Win1251 charset */
|
||||
const char Win1251UpcaseTbl[] =
|
||||
"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017"
|
||||
"\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
|
||||
" !\042#$%&'()*+,-./0123456789:;<=>?"
|
||||
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
|
||||
"`ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~\177"
|
||||
"\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
|
||||
"\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237"
|
||||
"\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257"
|
||||
"\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277"
|
||||
"\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317"
|
||||
"\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337"
|
||||
"\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317"
|
||||
"\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337";
|
||||
|
||||
char Win1251RusLetters[] =
|
||||
"\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317"
|
||||
"\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337"
|
||||
"\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357"
|
||||
"\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377";
|
||||
|
||||
|
||||
hqCharType Win1251NameTbl[256];
|
||||
int win1251nametbl_initialized = 0;
|
||||
|
||||
int FindSymbol( SymbolRec **SymTable, const char *str, int *nchars );
|
||||
|
||||
// initializations
|
||||
|
||||
void InitCharTypeTable( hqCharType *CharTypeTable, int CharTypes )
|
||||
{
|
||||
int ch;
|
||||
#ifdef MY_DEBUG
|
||||
printf( "CharTypeTable = 0x%X; CharTypes = %d\n", (unsigned)CharTypeTable,
|
||||
CharTypes );
|
||||
#endif
|
||||
memset( CharTypeTable, CH_UNKNOWN, 256 * sizeof(hqCharType) );
|
||||
|
||||
CharTypeTable[0] = CH_FINAL;
|
||||
|
||||
if (CharTypes & CH_SEPARAT) {
|
||||
CharTypeTable[' '] = CH_SEPARAT;
|
||||
CharTypeTable[9] = CH_SEPARAT;
|
||||
CharTypeTable[13] = CH_SEPARAT;
|
||||
CharTypeTable[10] = CH_SEPARAT;
|
||||
}
|
||||
|
||||
if (CharTypes & CH_QUOTE) {
|
||||
CharTypeTable['\''] = CH_QUOTE;
|
||||
}
|
||||
|
||||
if (CharTypes & CH_LETTER) {
|
||||
for (ch='A'; ch<='Z'; ch++)
|
||||
CharTypeTable[ch] = CH_LETTER;
|
||||
for (ch='a'; ch<='z'; ch++)
|
||||
CharTypeTable[ch] = CH_LETTER;
|
||||
CharTypeTable['_'] = CH_LETTER;
|
||||
}
|
||||
|
||||
if (CharTypes & CH_DIGIT) {
|
||||
for (ch='0'; ch<='9'; ch++)
|
||||
CharTypeTable[ch] = CH_DIGIT;
|
||||
}
|
||||
}
|
||||
|
||||
void TypeTableAddChars( hqCharType *CharTypeTable, char *Symbols,
|
||||
hqCharType CharType )
|
||||
{
|
||||
while (*Symbols)
|
||||
CharTypeTable[ (uchar) *Symbols++] = CharType;
|
||||
}
|
||||
|
||||
void UpcaseWin1251Str( char *Str )
|
||||
{
|
||||
while (( *Str = Win1251UpcaseTbl[ (uchar) *Str ] ))
|
||||
++Str;
|
||||
}
|
||||
|
||||
|
||||
// hqLexer implementation
|
||||
|
||||
#define CHARTYPEPP lexer->CharTypeTable[ (uchar) *++(lexer->SS) ]
|
||||
#define CHARTYPE lexer->CharTypeTable[ (uchar) *lexer->SS ]
|
||||
|
||||
int Lexer_SetParseString( hqLexer *lexer, const char *str )
|
||||
{
|
||||
lexer->PrevTokenType = TOK_NONE;
|
||||
if ( !str || !*str )
|
||||
return 0;
|
||||
|
||||
lexer->SS = str;
|
||||
lexer->CharType = CHARTYPE;
|
||||
return 1;
|
||||
}
|
||||
|
||||
hqTokenType Lexer_GetNextToken( hqLexer *lexer )
|
||||
{
|
||||
hqTokenType result = TOK_ERROR;
|
||||
|
||||
next_token:
|
||||
|
||||
while ( lexer->CharType == CH_SEPARAT )
|
||||
lexer->CharType = CHARTYPEPP;
|
||||
|
||||
switch ( lexer->CharType ) {
|
||||
case CH_FINAL:
|
||||
result = TOK_FINAL;
|
||||
break;
|
||||
case CH_LETTER:
|
||||
lexer->Name = lexer->SS;
|
||||
do {
|
||||
lexer->CharType = CHARTYPEPP;
|
||||
} while (lexer->CharType <= CH_DIGIT);
|
||||
lexer->NameLen = lexer->SS - lexer->Name;
|
||||
result = TOK_NAME;
|
||||
break;
|
||||
case CH_DIGIT: {
|
||||
char *NewSS, ch = *lexer->SS, nch = *(lexer->SS+1);
|
||||
int intreaded = 0;
|
||||
// Readind hex number
|
||||
if ( ch == '0' && nch == 'x' ) {
|
||||
lexer->IntValue = strtol( lexer->SS, &NewSS, 16 );
|
||||
intreaded = 1;
|
||||
}
|
||||
// Readind oct number
|
||||
if ( ch == '0' && nch == 'o') { // original version: if ( ch == '0' && nch >= '0' && nch <='9')
|
||||
lexer->IntValue = strtol( lexer->SS+2, &NewSS, 8 );
|
||||
intreaded = 1;
|
||||
}
|
||||
|
||||
// Readind bin number
|
||||
if ( ch == '0' && nch == 'b') { // original version: if ( ch == '0' && nch >= '0' && nch <='9')
|
||||
lexer->IntValue = strtol( lexer->SS+2, &NewSS, 2 );
|
||||
intreaded = 1;
|
||||
}
|
||||
|
||||
if (intreaded == 1) {
|
||||
if ( lexer->SS != NewSS ) {
|
||||
lexer->SS = NewSS;
|
||||
if (lexer->NoIntegers) {
|
||||
lexer->ExtValue = lexer->IntValue;
|
||||
result = TOK_FLOAT;
|
||||
} else
|
||||
result = TOK_INT;
|
||||
lexer->CharType = CHARTYPE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Readind dec number
|
||||
lexer->ExtValue = strtod( lexer->SS, &NewSS );
|
||||
if ( lexer->SS != NewSS ) {;
|
||||
lexer->SS = NewSS;
|
||||
if ( !lexer->NoIntegers
|
||||
&& lexer->ExtValue<=INT_MAX
|
||||
&& lexer->ExtValue>=INT_MAX
|
||||
&& (double)( lexer->IntValue = (uchar) lexer->ExtValue )
|
||||
== lexer->ExtValue ) {
|
||||
result = TOK_INT;
|
||||
} else
|
||||
result = TOK_FLOAT;
|
||||
lexer->CharType = CHARTYPE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CH_SYMBOL: {
|
||||
int nchars;
|
||||
int i = FindSymbol( lexer->SymTable, lexer->SS, &nchars );
|
||||
if (i >= 0) {
|
||||
lexer->SS += nchars;
|
||||
if (i == lexer->cssn) {
|
||||
char comend = *lexer->ComEnd;
|
||||
char comendpp = *(lexer->ComEnd+1);
|
||||
while ( *lexer->SS ) {
|
||||
if ( *lexer->SS == comend
|
||||
&&
|
||||
( comendpp == '\0' || *(lexer->SS+1) == comendpp )
|
||||
) {
|
||||
++lexer->SS;
|
||||
if (comendpp != '\0')
|
||||
++lexer->SS;
|
||||
lexer->CharType = CHARTYPE;
|
||||
goto next_token;
|
||||
}
|
||||
++lexer->SS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
lexer->CharType = CHARTYPE;
|
||||
lexer->IntValue = i;
|
||||
result = TOK_SYMBOL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CH_QUOTE:
|
||||
lexer->Name = ++(lexer->SS);
|
||||
while ( lexer->CharTypeTable[ (uchar)*lexer->SS ] != CH_QUOTE
|
||||
&& *(lexer->SS) != '\0' )
|
||||
++lexer->SS;
|
||||
if ( CHARTYPE == CH_QUOTE ) {
|
||||
lexer->NameLen = lexer->SS - lexer->Name;
|
||||
++lexer->SS;
|
||||
lexer->CharType = CHARTYPE;
|
||||
result = TOK_STRING;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return lexer->PrevTokenType = result;
|
||||
}
|
||||
|
||||
const char* Lexer_GetCurrentPos( hqLexer *lexer )
|
||||
{
|
||||
return lexer->SS;
|
||||
}
|
||||
|
||||
// misc functions
|
||||
|
||||
void PrepareSymTable( SymbolRec **SymTable, char *symbols )
|
||||
{
|
||||
int i = 0, nchars = 1;
|
||||
memset( SymTable, 0, 256 * sizeof(void*) );
|
||||
while (*symbols) {
|
||||
if (*symbols=='\033') {
|
||||
nchars = *++symbols;
|
||||
++symbols;
|
||||
} else {
|
||||
SymbolRec **RecList = SymTable + *symbols;
|
||||
SymbolRec *Rec = *RecList;
|
||||
int count = 0;
|
||||
while ( Rec ) {
|
||||
++count;
|
||||
if ( Rec->More )
|
||||
++Rec;
|
||||
else
|
||||
break;
|
||||
}
|
||||
if ( Rec ) {
|
||||
*RecList = (SymbolRec*)
|
||||
realloc( *RecList, (count+1)*sizeof(SymbolRec) );
|
||||
Rec = *RecList + count;
|
||||
(Rec-1)->More = 1;
|
||||
} else {
|
||||
*RecList = (SymbolRec*) malloc( sizeof(SymbolRec) );
|
||||
Rec = *RecList;
|
||||
}
|
||||
strncpy( Rec->Sym, symbols, 4 );
|
||||
Rec->Len = (char) nchars;
|
||||
Rec->Index = (char) i;
|
||||
Rec->More = 0;
|
||||
symbols += nchars;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int FindSymbol( SymbolRec **SymTable, const char *str, int *nchars )
|
||||
{
|
||||
SymbolRec *Rec = SymTable[ (int)*str ];
|
||||
while ( Rec ) {
|
||||
if ( (Rec->Len == 1 && Rec->Sym[0] == str[0])
|
||||
||
|
||||
(Rec->Len == 2 && Rec->Sym[0] == str[0] && Rec->Sym[1] == str[1])
|
||||
||
|
||||
(Rec->Len == 3 && Rec->Sym[0] == str[0] && Rec->Sym[1] == str[1]
|
||||
&& Rec->Sym[2] == str[2])
|
||||
) {
|
||||
*nchars = Rec->Len;
|
||||
return Rec->Index;
|
||||
}
|
||||
Rec = ( Rec->More ) ? Rec + 1 : NULL;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
@ -1,81 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
Universal lexical analiser by hq_software
|
||||
*/
|
||||
|
||||
#ifndef __LEXER_HPP__
|
||||
#define __LEXER_HPP__
|
||||
|
||||
#include "pack.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef unsigned char uchar;
|
||||
|
||||
typedef enum {
|
||||
CH_LETTER = 0x01, CH_DIGIT = 0x02, CH_SEPARAT = 0x04,
|
||||
CH_SYMBOL = 0x08, CH_QUOTE = 0x10,
|
||||
CH_UNKNOWN= 0x7E, CH_FINAL = 0x7F
|
||||
} hqCharType;
|
||||
|
||||
typedef enum {
|
||||
TOK_ERROR, TOK_NONE, TOK_FINAL, TOK_INT, TOK_FLOAT, TOK_SYMBOL,
|
||||
TOK_NAME, TOK_STRING
|
||||
} hqTokenType;
|
||||
|
||||
#pragma pack(push,1)
|
||||
|
||||
typedef struct {
|
||||
char Sym[4];
|
||||
char Len;
|
||||
char Index;
|
||||
char More;
|
||||
} SymbolRec;
|
||||
|
||||
typedef struct {
|
||||
// input params
|
||||
const char *SS;
|
||||
hqCharType *CharTypeTable;
|
||||
SymbolRec **SymTable;
|
||||
int NoIntegers;
|
||||
int cssn; // Comment Start Symbol Number. -1 if none
|
||||
char *ComEnd; // End of comment
|
||||
// output params
|
||||
const char *Name;
|
||||
size_t NameLen;
|
||||
double ExtValue;
|
||||
int IntValue;
|
||||
hqTokenType PrevTokenType;
|
||||
hqCharType CharType;
|
||||
} hqLexer;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
/* Main "API" */
|
||||
|
||||
int Lexer_SetParseString( hqLexer *lexer, const char *str );
|
||||
hqTokenType Lexer_GetNextToken( hqLexer *lexer );
|
||||
const char* Lexer_GetCurrentPos( hqLexer *lexer );
|
||||
|
||||
/* Misc */
|
||||
|
||||
void UpcaseWin1251Str( char *Str );
|
||||
void InitCharTypeTable( hqCharType *CharTypeTable, int CharTypes );
|
||||
|
||||
void TypeTableAddChars( hqCharType *CharTypeTable, char *Symbols,
|
||||
hqCharType CharType );
|
||||
|
||||
void PrepareSymTable( SymbolRec **SymTable, char *symbols );
|
||||
|
||||
//int IsEngWin1251RusName( char *Str );
|
||||
|
||||
extern char const Win1251UpcaseTbl[];
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __LEXER_HPP__ */
|
@ -1,657 +0,0 @@
|
||||
#include <math.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "mparser.h"
|
||||
|
||||
//#define MY_DEBUG 1
|
||||
|
||||
#ifndef M_E
|
||||
# define M_E 2.7182818284590452354
|
||||
#endif
|
||||
#ifndef M_PI
|
||||
# define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
const double DblErR = -1.68736462823243E308;
|
||||
const double DblNiN = -1.68376462823243E308;
|
||||
|
||||
char eBrackets [] = "#Brackets not match!";
|
||||
char eSyntax [] = "#Syntax error!";
|
||||
char eInternal [] = "#Internal error!";
|
||||
char eExtraOp [] = "#Extra operation!";
|
||||
char eInfinity [] = "#Infinity somewhere!";
|
||||
char eInvArg [] = "#Invalid argument!";
|
||||
char eUnknFunc [] = "# %s - Unknown function/variable!";
|
||||
char eExtrnFunc[] = "#External function error!";
|
||||
char eLogicErr [] = "#Logical expression error!";
|
||||
char eCalcErr [] = "#Calculation error!";
|
||||
char eUnexpEnd [] = "#Unexpected end of script!";
|
||||
char eExpVarRet[] = "#Variable name or return expected!";
|
||||
char eExpAssign[] = "#Assignment expected!";
|
||||
char eValSizErr[] = "#Value too big for operation!";
|
||||
char eInvPrmCnt[] = "#Invalid parameters count for function call!";
|
||||
|
||||
static double _neg_(double);
|
||||
static double _frac_(double);
|
||||
static double _trunc_(double);
|
||||
static double _sgn_(double);
|
||||
static double _neg_(double);
|
||||
static double _floor_(double);
|
||||
static double _ceil_(double);
|
||||
static char* _round_( int paramcnt, double *args, hqStrMap *strparams, double *result );
|
||||
|
||||
const Operation BrOp = { OP_OBR };
|
||||
const Operation NegOp = { OP_FUNC_ONEARG, (void*)&_neg_, 0, NULL };
|
||||
|
||||
const char OpPriorities[OP_FUNC_MULTIARG+1] = {
|
||||
5, 5, 5, 2, 2, 2, 2, 2, -1, -1, 0,
|
||||
3, 3, 4, 4, 4, 4,
|
||||
5, 5, 5, 5, 2, 2, 2, 1, 2, 0, 2,
|
||||
-1, 6, 6 };
|
||||
|
||||
char MathSymbols[] =
|
||||
"\033\002" "<<" ">>" "**" "<>" ">=" "<=" "&&" "||" "/*" ":="
|
||||
"\033\001" "(+-*/%$^~&|=><?:),;";
|
||||
|
||||
char StdSymbols[] = "+-/*^~()<>%$,?:=&|;";
|
||||
|
||||
hqCharType MathCharTypeTable[256];
|
||||
int initializations_performed = 0;
|
||||
|
||||
char func_names[] =
|
||||
"ATAN\000COS\000SIN\000TAN\000ABS\000"
|
||||
"EXP\000LN\000LOG\000SQRT\000FRAC\000"
|
||||
"TRUNC\000FLOOR\000CEIL\000ROUND\000ASIN\000"
|
||||
"ACOS\000SGN\000NEG\000E\000PI\000";
|
||||
|
||||
/* Indexes of some functions in func_names[] array */
|
||||
#define FUNC_ROUND 13
|
||||
#define FUNC_E 18
|
||||
#define FUNC_PI 19
|
||||
|
||||
static char* CalcToObr( hqMathParser *parser );
|
||||
static char* Calc( hqMathParser *parser );
|
||||
static char* MathParser_ParseScript( hqMathParser* parser, double *result );
|
||||
static char* MathParser_ParseFormula( hqMathParser* parser, double *result );
|
||||
|
||||
double (*func_addresses[]) () = {
|
||||
&atan, &cos, &sin, &tan, &fabs,
|
||||
&exp, &log, &log10, &sqrt, &_frac_,
|
||||
&_trunc_, &_floor_, _ceil_, (double(*)(double)) &_round_, &asin,
|
||||
&acos, &_sgn_, &_neg_, NULL, NULL };
|
||||
|
||||
hqStrMap *IntFunctions;
|
||||
|
||||
SymbolRec *MathSymTable[256];
|
||||
|
||||
char errbuf[256];
|
||||
|
||||
// hqMathParser implementation
|
||||
|
||||
hqMathParser* MathParser_Create( char *MoreLetters )
|
||||
{
|
||||
hqMathParser *parser = calloc( 1, sizeof(hqMathParser) );
|
||||
if (!initializations_performed) {
|
||||
// init character tables
|
||||
InitCharTypeTable( MathCharTypeTable,
|
||||
CH_LETTER | CH_DIGIT | CH_SEPARAT | CH_QUOTE );
|
||||
TypeTableAddChars( MathCharTypeTable, StdSymbols, CH_SYMBOL );
|
||||
if (MoreLetters)
|
||||
TypeTableAddChars( MathCharTypeTable, MoreLetters, CH_LETTER );
|
||||
// init function maps
|
||||
PrepareSymTable( MathSymTable, MathSymbols );
|
||||
IntFunctions = Strmap_CreateFromChain( sizeof(void*),
|
||||
(char*)func_names,
|
||||
func_addresses );
|
||||
initializations_performed = 1;
|
||||
}
|
||||
parser->Lexer.NoIntegers = 1;
|
||||
parser->Lexer.SymTable = MathSymTable;
|
||||
parser->Lexer.CharTypeTable = MathCharTypeTable;
|
||||
parser->Lexer.cssn = 8;
|
||||
parser->Lexer.ComEnd = "*/";
|
||||
return parser;
|
||||
}
|
||||
|
||||
void MathParser_Destroy( hqMathParser* parser )
|
||||
{
|
||||
free( parser );
|
||||
}
|
||||
|
||||
static char* PrepareFormula( hqMathParser* parser )
|
||||
{
|
||||
int BrCnt = 0;
|
||||
const char *SS = parser->Lexer.SS;
|
||||
|
||||
// Brackets Matching
|
||||
while ( (!parser->script && *SS) || (parser->script && *SS != ';') ) {
|
||||
if (*SS=='(')
|
||||
++BrCnt;
|
||||
else if (*SS==')' && --BrCnt<0)
|
||||
goto brkerr;
|
||||
++SS;
|
||||
}
|
||||
if (BrCnt != 0)
|
||||
brkerr: return eBrackets;
|
||||
|
||||
parser->OpTop = 0;
|
||||
parser->ValTop = -1;
|
||||
parser->OpStack[0].OperType = OP_OBR;
|
||||
parser->ObrDist = 2;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char* MathParser_Parse( hqMathParser* parser, const char *Formula, double *result )
|
||||
{
|
||||
if (!Formula || !*Formula) {
|
||||
*result = 0.0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
parser->script = *Formula == '#' && *(Formula+1) == '!'
|
||||
&& MathCharTypeTable[ (uchar)*(Formula+2) ] == CH_SEPARAT;
|
||||
|
||||
if ( parser->script )
|
||||
Formula += 3;
|
||||
|
||||
Lexer_SetParseString( &parser->Lexer, Formula );
|
||||
|
||||
return ( parser->script )
|
||||
?
|
||||
MathParser_ParseScript( parser, result )
|
||||
:
|
||||
MathParser_ParseFormula( parser, result );
|
||||
}
|
||||
|
||||
static char* MathParser_ParseFormula( hqMathParser* parser, double *result )
|
||||
{
|
||||
char *ErrorMsg;
|
||||
hqTokenType ToTi;
|
||||
|
||||
if ( (ErrorMsg = PrepareFormula( parser )) != NULL )
|
||||
return ErrorMsg;
|
||||
|
||||
ToTi = Lexer_GetNextToken( &parser->Lexer );
|
||||
for (;;) {
|
||||
--parser->ObrDist;
|
||||
switch (ToTi) {
|
||||
case TOK_ERROR:
|
||||
return eSyntax;
|
||||
case TOK_FINAL:
|
||||
formulaend: if ( (ErrorMsg = CalcToObr( parser )) != NULL )
|
||||
return ErrorMsg;
|
||||
goto getout;
|
||||
case TOK_FLOAT:
|
||||
parser->ValStack[++parser->ValTop] = parser->Lexer.ExtValue;
|
||||
break;
|
||||
case TOK_SYMBOL:
|
||||
switch ( parser->Lexer.IntValue ) {
|
||||
case OP_OBR: // (
|
||||
parser->OpStack[++parser->OpTop] = BrOp;
|
||||
parser->ObrDist = 2;
|
||||
break;
|
||||
case OP_CBR: // )
|
||||
if ( (ErrorMsg = CalcToObr( parser )) != NULL )
|
||||
return ErrorMsg;
|
||||
break;
|
||||
case OP_COMMA: { // ,
|
||||
Operation *pOp;
|
||||
if ( (ErrorMsg = CalcToObr( parser )) != NULL )
|
||||
return ErrorMsg;
|
||||
if ( (pOp = &parser->OpStack[parser->OpTop])->OperType
|
||||
== OP_FUNC_MULTIARG ) {
|
||||
parser->OpStack[++parser->OpTop] = BrOp;
|
||||
parser->ObrDist = 2;
|
||||
} else
|
||||
return eSyntax;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
Operation Op;
|
||||
Op.OperType = (OperType_t) parser->Lexer.IntValue;
|
||||
switch (Op.OperType) {
|
||||
case OP_FORMULAEND:
|
||||
if (parser->script)
|
||||
goto formulaend;
|
||||
else
|
||||
return eSyntax;
|
||||
case OP_ADD:
|
||||
if (parser->ObrDist >= 1)
|
||||
goto next_tok;
|
||||
break;
|
||||
case OP_SUB:
|
||||
if (parser->ObrDist >= 1) {
|
||||
parser->OpStack[++parser->OpTop] = NegOp;
|
||||
goto next_tok;
|
||||
}
|
||||
break;
|
||||
case OP_LOGIC:
|
||||
case OP_LOGIC_SEP:
|
||||
parser->ObrDist = 2;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
while ( OpPriorities[ Op.OperType ]
|
||||
<=
|
||||
OpPriorities[ parser->OpStack[parser->OpTop].OperType ] ) {
|
||||
if ( (ErrorMsg = Calc( parser )) != NULL )
|
||||
return ErrorMsg;
|
||||
}
|
||||
parser->OpStack[++parser->OpTop] = Op;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TOK_NAME: {
|
||||
Operation Op;
|
||||
double *value, dblval;
|
||||
void **func;
|
||||
int funcnum, /*i,*/ namelen = parser->Lexer.NameLen;
|
||||
|
||||
// const char *SS = parser->Lexer.Name;
|
||||
// for (i = namelen; i>0; --i)
|
||||
// *SS++ = Win1251UpcaseTbl[ (int) (uchar) *SS ];
|
||||
|
||||
funcnum = StrMap_LenIndexOf( IntFunctions,
|
||||
parser->Lexer.Name,
|
||||
parser->Lexer.NameLen,
|
||||
(void**) &func );
|
||||
if ( funcnum >= 0 ) {
|
||||
Op.Func = *func;
|
||||
switch ( funcnum ) {
|
||||
case FUNC_E:
|
||||
parser->ValStack[++parser->ValTop] = M_E;
|
||||
break;
|
||||
case FUNC_PI:
|
||||
parser->ValStack[++parser->ValTop] = M_PI;
|
||||
break;
|
||||
case FUNC_ROUND:
|
||||
Op.OperType = OP_FUNC_MULTIARG;
|
||||
Op.PrevValTop = parser->ValTop;
|
||||
Op.StrParams = NULL;
|
||||
parser->OpStack[++parser->OpTop] = Op;
|
||||
break;
|
||||
default:// Internal function
|
||||
Op.OperType = OP_FUNC_ONEARG;
|
||||
parser->OpStack[++parser->OpTop] = Op;
|
||||
}
|
||||
} else if (parser->Parameters
|
||||
&&
|
||||
StrMap_LenIndexOf( parser->Parameters,
|
||||
parser->Lexer.Name,
|
||||
parser->Lexer.NameLen,
|
||||
(void**) &value ) >= 0
|
||||
) {
|
||||
if (*value==DblErR) {
|
||||
return eInternal;
|
||||
} else
|
||||
parser->ValStack[++parser->ValTop] = *value;
|
||||
} else if (parser->ExtFunctions
|
||||
&&
|
||||
StrMap_LenIndexOf( parser->ExtFunctions,
|
||||
parser->Lexer.Name,
|
||||
parser->Lexer.NameLen,
|
||||
(void**) &func ) >= 0
|
||||
) {
|
||||
Op.Func = *func;
|
||||
Op.OperType = OP_FUNC_MULTIARG;
|
||||
Op.PrevValTop = parser->ValTop;
|
||||
Op.StrParams = NULL;
|
||||
parser->OpStack[++parser->OpTop] = Op;
|
||||
} else if (parser->VarParams
|
||||
&&
|
||||
StrMap_LenIndexOf( parser->VarParams,
|
||||
parser->Lexer.Name,
|
||||
parser->Lexer.NameLen,
|
||||
(void**) &value ) >= 0
|
||||
) {
|
||||
if (*value==DblErR) {
|
||||
return eInternal;
|
||||
} else
|
||||
parser->ValStack[++parser->ValTop] = *value;
|
||||
} else if (parser->MoreParams
|
||||
&&
|
||||
(*parser->MoreParams)( parser->Lexer.Name,
|
||||
parser->Lexer.NameLen,
|
||||
&dblval,
|
||||
parser->ParamFuncParam )
|
||||
) {
|
||||
parser->ValStack[++parser->ValTop] = dblval;
|
||||
} else {
|
||||
char buf[256];
|
||||
strncpy( buf, parser->Lexer.Name, parser->Lexer.NameLen );
|
||||
buf[ parser->Lexer.NameLen ] = '\0';
|
||||
sprintf( errbuf, eUnknFunc, buf );
|
||||
return errbuf;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TOK_STRING: {
|
||||
Operation *pOp;
|
||||
if (parser->OpTop < 1)
|
||||
return eSyntax;
|
||||
if ( (pOp = &parser->OpStack[parser->OpTop-1])->OperType
|
||||
== OP_FUNC_MULTIARG ) {
|
||||
if (!pOp->StrParams)
|
||||
pOp->StrParams = Strmap_Create( 0, 0 );
|
||||
StrMap_AddStrLen( pOp->StrParams,
|
||||
parser->Lexer.Name,
|
||||
parser->Lexer.NameLen, NULL );
|
||||
parser->ValStack[++parser->ValTop] = DblNiN;
|
||||
} else
|
||||
return eSyntax;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return eSyntax;
|
||||
}
|
||||
next_tok:
|
||||
ToTi = Lexer_GetNextToken( &parser->Lexer );
|
||||
} // forever
|
||||
|
||||
getout:
|
||||
if (parser->OpTop != -1 || parser->ValTop != 0)
|
||||
return eInternal;
|
||||
|
||||
*result = parser->ValStack[0];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char* MathParser_ParseScript( hqMathParser* parser, double *result )
|
||||
{
|
||||
char *ErrorMsg = NULL;
|
||||
hqTokenType ToTi;
|
||||
int expectvar = 1, was_return = 0;
|
||||
const char *varname = NULL;
|
||||
int varnamelen = 0;
|
||||
|
||||
parser->VarParams = Strmap_Create( sizeof(double), 0 );
|
||||
|
||||
ToTi = Lexer_GetNextToken( &parser->Lexer );
|
||||
for (;;) {
|
||||
switch (ToTi) {
|
||||
case TOK_FINAL:
|
||||
ErrorMsg = eUnexpEnd;
|
||||
goto getout;
|
||||
case TOK_NAME: {
|
||||
if (!expectvar) {
|
||||
ErrorMsg = eExpVarRet;
|
||||
goto getout;
|
||||
} else {
|
||||
// int i;
|
||||
// const char *SS = parser->Lexer.Name;
|
||||
|
||||
varnamelen = parser->Lexer.NameLen;
|
||||
|
||||
// for (i = varnamelen; i>0; --i)
|
||||
// *SS++ = Win1251UpcaseTbl[ (int) (uchar) *SS ];
|
||||
}
|
||||
varname = parser->Lexer.Name;
|
||||
|
||||
was_return = strncmp( varname, "RETURN", varnamelen ) == 0;
|
||||
if ( was_return ) {
|
||||
ErrorMsg = MathParser_ParseFormula( parser, result );
|
||||
goto getout;
|
||||
}
|
||||
expectvar = 0;
|
||||
break;
|
||||
}
|
||||
case TOK_SYMBOL: {
|
||||
double *value;
|
||||
|
||||
if ( parser->Lexer.IntValue != OP_ASSIGN || expectvar ) {
|
||||
ErrorMsg = eExpAssign;
|
||||
goto getout;
|
||||
}
|
||||
ErrorMsg = MathParser_ParseFormula( parser, result );
|
||||
if (ErrorMsg)
|
||||
goto getout;
|
||||
|
||||
if ( StrMap_LenIndexOf( parser->VarParams,
|
||||
varname, varnamelen,
|
||||
(void**) &value ) >= 0 )
|
||||
*value = *result;
|
||||
else
|
||||
StrMap_AddStrLen( parser->VarParams, varname, varnamelen,
|
||||
result );
|
||||
expectvar = 1;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ErrorMsg = eSyntax;
|
||||
goto getout;
|
||||
}
|
||||
ToTi = Lexer_GetNextToken( &parser->Lexer );
|
||||
} // forever
|
||||
|
||||
getout:
|
||||
StrMap_Destroy( parser->VarParams );
|
||||
parser->VarParams = NULL;
|
||||
return ErrorMsg;
|
||||
}
|
||||
|
||||
static char* Calc( hqMathParser *parser )
|
||||
{
|
||||
double Res, ValR;
|
||||
Operation Op = parser->OpStack[parser->OpTop--];
|
||||
|
||||
// multi-argument external or internal fucntion
|
||||
if ( Op.OperType == OP_FUNC_MULTIARG ) {
|
||||
int paramcnt = parser->ValTop - Op.PrevValTop;
|
||||
char *ErrorMsg;
|
||||
#ifdef MY_DEBUG
|
||||
printf( "ValTop = %d, OpTop = %d, PrevValTop = %d\n",
|
||||
parser->ValTop, parser->OpTop, Op.PrevValTop );
|
||||
#endif
|
||||
parser->ValTop = Op.PrevValTop;
|
||||
ErrorMsg = (*(MultiArgFunc)Op.Func)( paramcnt,
|
||||
&parser->ValStack[parser->ValTop+1],
|
||||
Op.StrParams, &Res );
|
||||
if (ErrorMsg)
|
||||
return ErrorMsg;
|
||||
if (Op.StrParams)
|
||||
StrMap_Destroy( Op.StrParams );
|
||||
parser->ValStack[++parser->ValTop] = Res;
|
||||
#ifdef MY_DEBUG
|
||||
printf("ValTop = %d, OpTop = %d\n", parser->ValTop, parser->OpTop );
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (Op.OperType==OP_LOGIC)
|
||||
return NULL;
|
||||
|
||||
// get right arg
|
||||
if (parser->ValTop<0)
|
||||
return eExtraOp;
|
||||
ValR = parser->ValStack[parser->ValTop--];
|
||||
|
||||
// one arg operations
|
||||
if (Op.OperType==OP_NOT) {
|
||||
if (ValR >= INT_MIN && ValR <= INT_MAX)
|
||||
Res = ~((int) ValR);
|
||||
else
|
||||
return eValSizErr;
|
||||
} else if (Op.OperType==OP_FUNC_ONEARG) {
|
||||
Res = (*(OneArgFunc)Op.Func)( ValR );
|
||||
} else {
|
||||
// get left arg
|
||||
double ValL;
|
||||
if (parser->ValTop<0)
|
||||
return eExtraOp;
|
||||
ValL = parser->ValStack[parser->ValTop--];
|
||||
switch (Op.OperType) {
|
||||
// Binary
|
||||
case OP_SHL:
|
||||
if (ValL >= INT_MIN && ValL <= INT_MAX && ValR >= INT_MIN && ValR <= INT_MAX)
|
||||
Res = (int) ValL << (int) ValR;
|
||||
else
|
||||
return eValSizErr;
|
||||
break;
|
||||
case OP_SHR:
|
||||
if (ValL >= INT_MIN && ValL <= INT_MAX && ValR >= INT_MIN && ValR <= INT_MAX)
|
||||
Res = (int) ValL >> (int) ValR;
|
||||
else
|
||||
return eValSizErr;
|
||||
break;
|
||||
case OP_POW:
|
||||
Res = pow( ValL, ValR ); break;
|
||||
// Logical
|
||||
case OP_LOGIC_NEQ:
|
||||
Res = ValL != ValR; break;
|
||||
case OP_LOGIC_GEQ:
|
||||
Res = ValL >= ValR; break;
|
||||
case OP_LOGIC_LEQ:
|
||||
Res = ValL <= ValR; break;
|
||||
case OP_LOGIC_AND:
|
||||
Res = ValL && ValR; break;
|
||||
case OP_LOGIC_OR:
|
||||
Res = ValL || ValR; break;
|
||||
// Arithmetic
|
||||
case OP_ADD:
|
||||
Res = ValL + ValR; break;
|
||||
case OP_SUB:
|
||||
Res = ValL - ValR; break;
|
||||
case OP_MUL:
|
||||
Res = ValL * ValR; break;
|
||||
case OP_DIV:
|
||||
if (ValR == 0.0)
|
||||
return eInfinity;
|
||||
Res = ValL / ValR;
|
||||
break;
|
||||
case OP_MOD:
|
||||
Res = fmod(ValL, ValR); break;
|
||||
case OP_UNK:
|
||||
if (ValL<=0)
|
||||
Res = 0.0;
|
||||
else if (ValR==0.0)
|
||||
return eInfinity;
|
||||
else
|
||||
Res = ceil(ValL / ValR);
|
||||
break;
|
||||
// Bitwise
|
||||
case OP_XOR:
|
||||
if (ValL >= INT_MIN && ValL <= INT_MAX && ValR >= INT_MIN && ValR <= INT_MAX)
|
||||
Res = (int) ValL ^ (int) ValR;
|
||||
else
|
||||
return eValSizErr;
|
||||
break;
|
||||
case OP_AND:
|
||||
if (ValL >= INT_MIN && ValL <= INT_MAX && ValR >= INT_MIN && ValR <= INT_MAX)
|
||||
Res = (int) ValL & (int) ValR;
|
||||
else
|
||||
return eValSizErr;
|
||||
break;
|
||||
case OP_OR:
|
||||
if (ValL >= INT_MIN && ValL <= INT_MAX && ValR >= INT_MIN && ValR <= INT_MAX)
|
||||
Res = (int) ValL | (int) ValR;
|
||||
else
|
||||
return eValSizErr;
|
||||
break;
|
||||
// Logical
|
||||
case OP_EQU:
|
||||
Res = ValL == ValR; break;
|
||||
case OP_GREATER:
|
||||
Res = ValL > ValR; break;
|
||||
case OP_LESS:
|
||||
Res = ValL < ValR; break;
|
||||
case OP_LOGIC_SEP: {
|
||||
// needs three arguments
|
||||
double ValLL;
|
||||
if (parser->OpTop < 0
|
||||
|| parser->OpStack[parser->OpTop--].OperType != OP_LOGIC)
|
||||
return eLogicErr;
|
||||
ValLL = parser->ValStack[ parser->ValTop-- ];
|
||||
Res = ValLL ? ValL : ValR;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return eInternal;
|
||||
}
|
||||
}
|
||||
parser->ValStack[++parser->ValTop] = Res;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char* CalcToObr( hqMathParser *parser )
|
||||
{
|
||||
while ( parser->OpStack[parser->OpTop].OperType != OP_OBR ) {
|
||||
char *ErrorMsg;
|
||||
if ( (ErrorMsg = Calc( parser )) != NULL )
|
||||
return ErrorMsg;
|
||||
}
|
||||
--parser->OpTop;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* misc functions */
|
||||
|
||||
static double _frac_( double x )
|
||||
{
|
||||
double y;
|
||||
return modf(x, &y);
|
||||
}
|
||||
|
||||
static double _trunc_( double x )
|
||||
{
|
||||
return (x >= 0.0) ? floor(x) : ceil(x);
|
||||
}
|
||||
|
||||
static double _sgn_( double x )
|
||||
{
|
||||
return (x > 0) ? 1 : (x < 0) ? -1 : 0;
|
||||
}
|
||||
|
||||
static double _neg_( double x )
|
||||
{
|
||||
return -x;
|
||||
}
|
||||
|
||||
static double _floor_( double x )
|
||||
{
|
||||
return floor(x);
|
||||
}
|
||||
|
||||
static double _ceil_( double x )
|
||||
{
|
||||
return ceil(x);
|
||||
}
|
||||
|
||||
/* "Advanced" round function; second argument - sharpness */
|
||||
static char* _round_( int paramcnt, double *args, hqStrMap *strparams, double *result )
|
||||
{
|
||||
int i, sharpness;
|
||||
double x, coef;
|
||||
|
||||
if (paramcnt == 1)
|
||||
sharpness = 0;
|
||||
else if (paramcnt == 2)
|
||||
sharpness = (int) args[1];
|
||||
else
|
||||
return eInvPrmCnt;
|
||||
|
||||
x = args[0];
|
||||
if (sharpness < 0) {
|
||||
coef = 0.1;
|
||||
sharpness = -sharpness;
|
||||
} else
|
||||
coef = 10;
|
||||
|
||||
for (i = 0; i < sharpness; i++)
|
||||
x *= coef;
|
||||
|
||||
x = (x + ( (x >= 0) ? 0.5 : -0.5 ) );
|
||||
if (x >= 0.0)
|
||||
x = floor(x);
|
||||
else
|
||||
x = ceil(x);
|
||||
|
||||
for (i = 0; i < sharpness; i++)
|
||||
x /= coef;
|
||||
|
||||
*result = x;
|
||||
|
||||
return NULL;
|
||||
}
|
@ -1,82 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
Math parser for CCalc library.
|
||||
*/
|
||||
#include "strmap.h"
|
||||
#include "lexer.h"
|
||||
#include "pack.h"
|
||||
|
||||
//#define RUSSIAN 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MAX_STACK_SIZE 32
|
||||
|
||||
extern const double DblErR;
|
||||
extern const double DblNiN;
|
||||
|
||||
typedef enum {
|
||||
// Binary
|
||||
OP_SHL, OP_SHR, OP_POW,
|
||||
OP_LOGIC_NEQ, OP_LOGIC_GEQ, OP_LOGIC_LEQ,
|
||||
OP_LOGIC_AND, OP_LOGIC_OR, // Logical
|
||||
OP_COMSTART, OP_ASSIGN, // For internal needs
|
||||
OP_OBR, // Special
|
||||
OP_ADD, OP_SUB, OP_MUL, OP_DIV, OP_MOD, OP_UNK, // Arithmetic
|
||||
OP_XOR, OP_NOT, OP_AND, OP_OR, // Bitwise
|
||||
OP_EQU, OP_GREATER, OP_LESS,
|
||||
OP_LOGIC, OP_LOGIC_SEP, OP_CBR, OP_COMMA, // Logical
|
||||
OP_FORMULAEND, // For script
|
||||
OP_FUNC_ONEARG, OP_FUNC_MULTIARG // Special
|
||||
} OperType_t;
|
||||
|
||||
typedef struct {
|
||||
char *str;
|
||||
double value;
|
||||
} Parameter;
|
||||
|
||||
typedef double (*OneArgFunc) ( double arg );
|
||||
typedef char* (*MultiArgFunc) ( int paramcnt, double *args,
|
||||
hqStrMap *strparams, double *result );
|
||||
typedef int (*PrmSrchFunc) ( const char *str, int len, double *value,
|
||||
void *param );
|
||||
|
||||
#pragma pack(push,1)
|
||||
|
||||
typedef struct {
|
||||
OperType_t OperType;
|
||||
void *Func;
|
||||
char PrevValTop;
|
||||
hqStrMap *StrParams;
|
||||
} Operation;
|
||||
|
||||
typedef struct {
|
||||
/* public */
|
||||
hqStrMap *Parameters; // List of numeric veriables
|
||||
hqStrMap *ExtFunctions; // List of multi-argument external functions
|
||||
PrmSrchFunc MoreParams; // Function for calculating unhandled parameters
|
||||
void *ParamFuncParam; // Parameter given to this function
|
||||
/* private */
|
||||
Operation OpStack[MAX_STACK_SIZE];
|
||||
double ValStack[MAX_STACK_SIZE];
|
||||
int OpTop, ValTop;
|
||||
int ObrDist;
|
||||
hqLexer Lexer;
|
||||
int script;
|
||||
hqStrMap *VarParams;
|
||||
} hqMathParser;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
/* API */
|
||||
|
||||
hqMathParser* MathParser_Create( char *MoreLetters );
|
||||
void MathParser_Destroy( hqMathParser* parser );
|
||||
char* MathParser_Parse( hqMathParser* parser, const char *Formula, double *result );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -1,23 +0,0 @@
|
||||
/* Definitions for packing structures */
|
||||
#ifndef __PACK_H__
|
||||
#define __PACK_H__
|
||||
|
||||
#if defined(__BORLANDC__) && (__BORLANDC <= 0x520)
|
||||
# define PACK_START #pragma option -a1
|
||||
#elif (defined(__GNUC__) && (__GNUC__ <= 2) && (__GNUC_MINOR__ < 95)) \
|
||||
|| (defined(__WATCOMC__) && (__WATCOMC__ < 1100))
|
||||
# define PACK_START #pragma pack(1)
|
||||
#else
|
||||
# define PACK_START #pragma pack(push,1)
|
||||
#endif
|
||||
|
||||
#if defined(__BORLANDC__) && (__BORLANDC <= 0x520)
|
||||
# define PACK_STOP #pragma option -a.
|
||||
#elif (defined(__GNUC__) && (__GNUC__ <= 2) && (__GNUC_MINOR__ < 95)) \
|
||||
|| (defined(__WATCOMC__) && (__WATCOMC__ < 1100))
|
||||
# define PACK_STOP #pragma pack()
|
||||
#else
|
||||
# define PACK_STOP #pragma pack(pop)
|
||||
#endif
|
||||
|
||||
#endif /* __PACK_H__ */
|
@ -1,129 +0,0 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "strmap.h"
|
||||
|
||||
hqStrMap* create_instance( int extrabytes, int dup )
|
||||
{
|
||||
hqStrMap* strmap = calloc( 1, sizeof(hqStrMap) );
|
||||
strmap->FDoDuplicate = dup;
|
||||
strmap->FExtraLen = extrabytes;
|
||||
strmap->FRecordLen = sizeof(char*) + sizeof(int) + extrabytes;
|
||||
strmap->FList = NULL;
|
||||
return strmap;
|
||||
}
|
||||
|
||||
hqStrMap* Strmap_Create( int extrabytes, int dup )
|
||||
{
|
||||
return create_instance( extrabytes, dup );
|
||||
}
|
||||
|
||||
void Strmap_FillFromChain( hqStrMap* strmap, char *strchain, void *data )
|
||||
{
|
||||
while ( *strchain ) {
|
||||
size_t len = strlen( strchain );
|
||||
StrMap_AddStrLen( strmap, strchain, len, data );
|
||||
strchain += len+1;
|
||||
data = (char*)data + strmap->FExtraLen;
|
||||
}
|
||||
}
|
||||
|
||||
hqStrMap* Strmap_CreateFromChain( int extrabytes, char *strchain, void *data )
|
||||
{
|
||||
hqStrMap* strmap = create_instance( extrabytes, 0 );
|
||||
Strmap_FillFromChain( strmap, strchain, data );
|
||||
StrMap_ShrinkMem( strmap );
|
||||
return strmap;
|
||||
}
|
||||
|
||||
void StrMap_Destroy( hqStrMap* strmap )
|
||||
{
|
||||
if ( strmap->FDoDuplicate )
|
||||
StrMap_TrimClear( strmap, 0 );
|
||||
if ( strmap->FList )
|
||||
free( strmap->FList );
|
||||
|
||||
free(strmap);
|
||||
}
|
||||
|
||||
void StrMap_AddString( hqStrMap* strmap, const char *str, void *data )
|
||||
{
|
||||
StrMap_AddStrLen( strmap, str, strlen(str), data );
|
||||
}
|
||||
|
||||
void StrMap_AddStrLen( hqStrMap* strmap, const char *str, size_t len, void *data )
|
||||
{
|
||||
const char *Rec;
|
||||
if ( strmap->FCount >= strmap->FCapacity ) {
|
||||
int delta = (strmap->FCapacity > 64) ? strmap->FCapacity / 4 : 16;
|
||||
StrMap_SetCapacity( strmap, strmap->FCapacity + delta );
|
||||
}
|
||||
Rec = strmap->FList + strmap->FCount * strmap->FRecordLen;
|
||||
*(const char**)Rec = str;
|
||||
*(int*)(Rec + sizeof(char*)) = len;
|
||||
if (data) {
|
||||
void *recdata = (void*)(Rec + sizeof(char*) + sizeof(int));
|
||||
memcpy( recdata, data, strmap->FExtraLen );
|
||||
}
|
||||
++ strmap->FCount;
|
||||
}
|
||||
|
||||
void StrMap_ShrinkMem( hqStrMap* strmap )
|
||||
{
|
||||
StrMap_SetCapacity( strmap, strmap->FCount );
|
||||
}
|
||||
|
||||
void StrMap_Trim( hqStrMap* strmap, int NewCount )
|
||||
{
|
||||
strmap->FCount = NewCount;
|
||||
}
|
||||
|
||||
void StrMap_TrimClear( hqStrMap* strmap, int NewCount )
|
||||
{
|
||||
int i;
|
||||
char *Rec = strmap->FList + NewCount * strmap->FRecordLen;
|
||||
for (i=NewCount; i < strmap->FCount; i++) {
|
||||
free( *(char**)Rec );
|
||||
Rec += strmap->FRecordLen;
|
||||
}
|
||||
strmap->FCount = NewCount;
|
||||
}
|
||||
|
||||
void StrMap_SetCapacity( hqStrMap* strmap, int NewCapacity )
|
||||
{
|
||||
strmap->FCapacity = NewCapacity;
|
||||
if ( strmap->FCount > strmap->FCapacity )
|
||||
strmap->FCount = strmap->FCapacity;
|
||||
strmap->FList = (char*) realloc( strmap->FList,
|
||||
strmap->FCapacity * strmap->FRecordLen );
|
||||
}
|
||||
|
||||
int StrMap_IndexOf( hqStrMap* strmap, const char *str, void **data )
|
||||
{
|
||||
return StrMap_LenIndexOf( strmap, str, strlen(str), data );
|
||||
}
|
||||
|
||||
int StrMap_LenIndexOf( hqStrMap* strmap, const char *str, size_t len, void **data )
|
||||
{
|
||||
int i;
|
||||
char *Rec = strmap->FList;
|
||||
for (i=0; i<strmap->FCount; i++) {
|
||||
int recLen = *(int*)(Rec + sizeof(char*));
|
||||
if (recLen==len && strnicmp( str, *(char**)Rec, recLen )==0 ) {
|
||||
*data = (Rec + sizeof(char*) + sizeof(int));
|
||||
return i;
|
||||
}
|
||||
Rec += strmap->FRecordLen;
|
||||
}
|
||||
*data = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
char* StrMap_GetString( hqStrMap* strmap, int index, int *len, void **data )
|
||||
{
|
||||
char *Rec = strmap->FList + index * strmap->FRecordLen;
|
||||
*len = *(int*)(Rec + sizeof(char*));
|
||||
if (data!=NULL && strmap->FExtraLen>0)
|
||||
*data = (Rec + sizeof(char*) + sizeof(int));
|
||||
return *(char**)Rec;
|
||||
}
|
||||
|
@ -1,39 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "pack.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#pragma pack(push,1)
|
||||
|
||||
typedef struct {
|
||||
int FCount, FCapacity;
|
||||
int FExtraLen, FRecordLen;
|
||||
int FDoDuplicate;
|
||||
char *FList;
|
||||
} hqStrMap;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
/* API */
|
||||
|
||||
hqStrMap* Strmap_Create( int extrabytes, int dup );
|
||||
hqStrMap* Strmap_CreateFromChain( int extrabytes, char *strchain, void *data );
|
||||
void StrMap_Destroy( hqStrMap* strmap );
|
||||
|
||||
void StrMap_AddString( hqStrMap* strmap, const char *str, void *data );
|
||||
void StrMap_AddStrLen( hqStrMap* strmap, const char *str, size_t len, void *data );
|
||||
void StrMap_ShrinkMem( hqStrMap* strmap );
|
||||
void StrMap_Trim( hqStrMap* strmap, int NewCount );
|
||||
void StrMap_TrimClear( hqStrMap* strmap, int NewCount );
|
||||
void StrMap_SetCapacity( hqStrMap* strmap, int NewCapacity );
|
||||
int StrMap_IndexOf( hqStrMap* strmap, const char *str, void **data );
|
||||
int StrMap_LenIndexOf( hqStrMap* strmap, const char *str, size_t len, void **data );
|
||||
char* StrMap_GetString( hqStrMap* strmap, int index, int *len, void **data );
|
||||
void Strmap_FillFromChain( hqStrMap* strmap, char *strchain, void *data );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -1,6 +0,0 @@
|
||||
#include <windows.h>
|
||||
|
||||
extern int WINAPI dll_entry (HANDLE h, DWORD reason, void *ptr)
|
||||
{
|
||||
return 1;
|
||||
}
|
Loading…
Reference in New Issue
Block a user