MathParser: Converted to use WCHAR.

This commit is contained in:
Birunthan Mohanathas 2012-01-23 09:30:51 +00:00
parent 01b22e2d5e
commit 33d447a907
6 changed files with 366 additions and 318 deletions

View File

@ -756,11 +756,11 @@ double CConfigParser::ReadFormula(LPCTSTR section, LPCTSTR key, double defValue)
if (!result.empty() && result[0] == L'(' && result[result.size() - 1] == L')') if (!result.empty() && result[0] == L'(' && result[result.size() - 1] == L')')
{ {
double resultValue = defValue; double resultValue = defValue;
char* errMsg = MathParser::CheckParse(ConvertToAscii(result.c_str()).c_str(), &resultValue); WCHAR* errMsg = MathParser::CheckParse(result.c_str(), &resultValue);
if (errMsg != NULL) if (errMsg != NULL)
{ {
std::wstring error = L"ReadFormula: "; std::wstring error = L"ReadFormula: ";
error += ConvertToWide(errMsg); error += errMsg;
error += L" in key \""; error += L" in key \"";
error += key; error += key;
error += L"\" in ["; error += L"\" in [";
@ -782,11 +782,11 @@ bool CConfigParser::ParseFormula(const std::wstring& result, double* resultValue
// Formulas must be surrounded by parenthesis // Formulas must be surrounded by parenthesis
if (!result.empty() && result[0] == L'(' && result[result.size() - 1] == L')') if (!result.empty() && result[0] == L'(' && result[result.size() - 1] == L')')
{ {
char* errMsg = MathParser::CheckParse(ConvertToAscii(result.c_str()).c_str(), resultValue); WCHAR* errMsg = MathParser::CheckParse(result.c_str(), resultValue);
if (errMsg != NULL) if (errMsg != NULL)
{ {
std::wstring error = L"ParseFormula: "; std::wstring error = L"ParseFormula: ";
error += ConvertToWide(errMsg); error += errMsg;
error += L": "; error += L": ";
error += result; error += result;
Log(LOG_ERROR, error.c_str()); Log(LOG_ERROR, error.c_str());

View File

@ -27,10 +27,10 @@ static const double M_E = 2.7182818284590452354;
static const double M_PI = 3.14159265358979323846; static const double M_PI = 3.14159265358979323846;
typedef double (*OneArgProc)(double arg); typedef double (*OneArgProc)(double arg);
typedef char* (*MultiArgProc)(int paramcnt, double* args, double* result); typedef WCHAR* (*MultiArgProc)(int paramcnt, double* args, double* result);
typedef double (*FunctionProc)(double); typedef double (*FunctionProc)(double);
typedef enum enum OperationType
{ {
OP_SHL, OP_SHL,
OP_SHR, OP_SHR,
@ -60,26 +60,19 @@ typedef enum
OP_COMMA, OP_COMMA,
OP_FUNC_ONEARG, // Special OP_FUNC_ONEARG, // Special
OP_FUNC_MULTIARG // Special OP_FUNC_MULTIARG // Special
} OperationType; };
typedef struct enum CharType
{
void* Func;
char prevvalTop;
OperationType type;
} Operation;
typedef enum
{ {
CH_UNKNOWN = 0x00,
CH_LETTER = 0x01, CH_LETTER = 0x01,
CH_DIGIT = 0x02, CH_DIGIT = 0x02,
CH_SEPARAT = 0x04, CH_SEPARAT = 0x04,
CH_SYMBOL = 0x08, CH_SYMBOL = 0x08,
CH_UNKNOWN = 0x7E,
CH_FINAL = 0x7F CH_FINAL = 0x7F
} CharType; };
typedef enum enum MathTokenType
{ {
TOK_ERROR, TOK_ERROR,
TOK_NONE, TOK_NONE,
@ -87,87 +80,61 @@ typedef enum
TOK_FLOAT, TOK_FLOAT,
TOK_SYMBOL, TOK_SYMBOL,
TOK_NAME TOK_NAME
} MathTokenType; };
typedef struct struct Operation
{ {
char* name; void* proc;
BYTE prevTop;
OperationType type;
};
struct Function
{
WCHAR* name;
FunctionProc proc; FunctionProc proc;
unsigned char length; BYTE 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 neg(double x);
static double frac(double x); static double frac(double x);
static double trunc(double x); static double trunc(double x);
static double sgn(double x); static double sgn(double x);
static char* round(int paramcnt, double* args, double* result); static WCHAR* round(int paramcnt, double* args, double* result);
static Function g_Functions[] = static Function g_Functions[] =
{ {
{ "atan", &atan, 4 }, { L"atan", &atan, 4 },
{ "cos", &cos, 3 }, { L"cos", &cos, 3 },
{ "sin", &sin, 3 }, { L"sin", &sin, 3 },
{ "tan", &tan, 3 }, { L"tan", &tan, 3 },
{ "abs", &fabs, 3 }, { L"abs", &fabs, 3 },
{ "exp", &exp, 3 }, { L"exp", &exp, 3 },
{ "ln", &log, 2 }, { L"ln", &log, 2 },
{ "log", &log10, 3 }, { L"log", &log10, 3 },
{ "sqrt", &sqrt, 4 }, { L"sqrt", &sqrt, 4 },
{ "frac", &frac, 4 }, { L"frac", &frac, 4 },
{ "trunc", &trunc, 5 }, { L"trunc", &trunc, 5 },
{ "floor", &floor, 5 }, { L"floor", &floor, 5 },
{ "ceil", &ceil, 4 }, { L"ceil", &ceil, 4 },
{ "round", (FunctionProc)&round, 5 }, { L"round", (FunctionProc)&round, 5 },
{ "asin", &asin, 4 }, { L"asin", &asin, 4 },
{ "acos", &acos, 4 }, { L"acos", &acos, 4 },
{ "sgn", &sgn, 4 }, { L"sgn", &sgn, 4 },
{ "neg", &neg, 4 }, { L"neg", &neg, 4 },
{ "e", NULL, 1 }, { L"e", NULL, 1 },
{ "pi", NULL, 2} { L"pi", NULL, 2}
}; };
static const int MAX_FUNC_LEN = 5; static const int FUNC_MAX_LEN = 5;
static const int FUNC_ROUND = 13;
static const int FUNC_E = 18;
static const int FUNC_PI = 19;
#define FUNC_ROUND 13 static const Operation g_BrOp = { NULL, 0, OP_OBR };
#define FUNC_E 18 static const Operation g_NegOp = { (void*)&neg, 0, OP_FUNC_ONEARG };
#define FUNC_PI 19
static const Operation g_BrOp = { NULL, '0', OP_OBR }; static const BYTE g_OpPriorities[OP_FUNC_MULTIARG + 1] =
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_SHL
5, // OP_SHR 5, // OP_SHR
@ -199,46 +166,66 @@ static const char g_OpPriorities[OP_FUNC_MULTIARG + 1] =
6 // OP_FUNC_MULTIARG 6 // OP_FUNC_MULTIARG
}; };
static Operation g_OpStack[MAX_STACK_SIZE]; static CharType GetCharType(WCHAR ch);
static double g_ValStack[MAX_STACK_SIZE]; static int GetFunction(const WCHAR* str, size_t len, void** data);
static int g_OpTop = 0; static int FindSymbol(const WCHAR* str);
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() struct Parser
{ {
g_CharTypes['\0'] = CH_FINAL; Operation opStack[MAX_STACK_SIZE];
double valStack[MAX_STACK_SIZE];
int opTop;
int valTop;
int obrDist;
g_CharTypes[' '] = g_CharTypes['\t'] = g_CharTypes['\n'] = CH_SEPARAT; Parser() : opTop(0), valTop(-1), obrDist(2) { opStack[0].type = OP_OBR; }
};
g_CharTypes['_'] = CH_LETTER; static WCHAR* CalcToObr(Parser& parser);
for (int ch = 'A'; ch <= 'Z'; ++ch) g_CharTypes[ch] = CH_LETTER; static WCHAR* Calc(Parser& parser);
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['*'] = struct Lexer
g_CharTypes['~'] = g_CharTypes['('] = g_CharTypes[')'] = g_CharTypes['<'] = {
g_CharTypes['>'] = g_CharTypes['%'] = g_CharTypes['$'] = g_CharTypes[','] = const WCHAR* string;
g_CharTypes['?'] = g_CharTypes[':'] = g_CharTypes['='] = g_CharTypes['&'] = const WCHAR* name;
g_CharTypes['|'] = CH_SYMBOL; size_t nameLen;
} double extValue;
int intValue;
MathTokenType prevToken;
CharType charType;
char* MathParser::Check(const char* formula) Lexer(const WCHAR* str) : string(str), name(), nameLen(), extValue(), intValue(), prevToken(TOK_NONE), charType(GetCharType(*str)) {}
};
static MathTokenType GetNextToken(Lexer& lexer);
WCHAR eBrackets [] = L"Unmatched brackets";
WCHAR eSyntax [] = L"Syntax error";
WCHAR eInternal [] = L"Internal error";
WCHAR eExtraOp [] = L"Extra operation";
WCHAR eInfinity [] = L"Infinity somewhere";
WCHAR eInvArg [] = L"Invalid argument";
WCHAR eUnknFunc [] = L"\"%s\" is unknown";
WCHAR eLogicErr [] = L"Logical expression error";
WCHAR eCalcErr [] = L"Calculation error";
WCHAR eValSizErr[] = L"Value too big for operation";
WCHAR eInvPrmCnt[] = L"Invalid function parameter count";
WCHAR g_ErrorBuffer[128];
WCHAR* MathParser::Check(const WCHAR* formula)
{ {
int BrCnt = 0; int BrCnt = 0;
// Brackets Matching // Brackets Matching
while (*formula) while (*formula)
{ {
if (*formula == '(') if (*formula == L'(')
{ {
++BrCnt; ++BrCnt;
} }
else if (*formula == ')' && (--BrCnt < 0)) else if (*formula == L')')
{ {
return eBrackets; --BrCnt;
} }
++formula; ++formula;
} }
@ -251,76 +238,82 @@ char* MathParser::Check(const char* formula)
return NULL; return NULL;
} }
char* MathParser::CheckParse(const char* formula, double* result) WCHAR* MathParser::CheckParse(const WCHAR* formula, double* result)
{ {
char* ret = Check(formula); WCHAR* error = Check(formula);
if (ret) return ret; if (!error)
{
ret = Parse(formula, NULL, result); error = Parse(formula, NULL, result);
if (ret) return ret; }
return error;
return NULL;
} }
char* MathParser::Parse(const char* formula, CMeasureCalc* calc, double* result) WCHAR* MathParser::Parse(const WCHAR* formula, CMeasureCalc* calc, double* result)
{ {
if (!formula || !*formula) if (!*formula)
{ {
*result = 0.0; *result = 0.0;
return NULL; return NULL;
} }
Lexer_SetParseString(formula); Parser parser;
Lexer lexer(formula);
g_OpTop = 0; WCHAR* error;
g_ValTop = -1;
g_OpStack[0].type = OP_OBR;
g_ObrDist = 2;
char* error;
MathTokenType token = Lexer_GetNextToken();
for (;;) for (;;)
{ {
--g_ObrDist; MathTokenType token = GetNextToken(lexer);
--parser.obrDist;
switch (token) switch (token)
{ {
case TOK_ERROR: case TOK_ERROR:
return eSyntax; return eSyntax;
case TOK_FINAL: case TOK_FINAL:
if ((error = CalcToObr()) != NULL) if ((error = CalcToObr(parser)) != NULL)
{
return error; return error;
goto setResult; }
else if (parser.opTop != -1 || parser.valTop != 0)
{
return eInternal;
}
else
{
// Done!
*result = parser.valStack[0];
return NULL;
}
break;
case TOK_FLOAT: case TOK_FLOAT:
g_ValStack[++g_ValTop] = g_Lexer.extValue; parser.valStack[++parser.valTop] = lexer.extValue;
break; break;
case TOK_SYMBOL: case TOK_SYMBOL:
switch (g_Lexer.intValue) switch (lexer.intValue)
{ {
case OP_OBR: // ( case OP_OBR:
{ {
g_OpStack[++g_OpTop] = g_BrOp; parser.opStack[++parser.opTop] = g_BrOp;
g_ObrDist = 2; parser.obrDist = 2;
} }
break; break;
case OP_CBR: //) case OP_CBR:
{ {
if ((error = CalcToObr()) != NULL) return error; if ((error = CalcToObr(parser)) != NULL) return error;
} }
break; break;
case OP_COMMA: // , case OP_COMMA:
{ {
Operation* pOp; if ((error = CalcToObr(parser)) != NULL) return error;
if ((error = CalcToObr()) != NULL) return error;
if ((pOp = &g_OpStack[g_OpTop])->type == OP_FUNC_MULTIARG) if (parser.opStack[parser.opTop].type == OP_FUNC_MULTIARG)
{ {
g_OpStack[++g_OpTop] = g_BrOp; parser.opStack[++parser.opTop] = g_BrOp;
g_ObrDist = 2; parser.obrDist = 2;
} }
else else
{ {
@ -332,81 +325,86 @@ char* MathParser::Parse(const char* formula, CMeasureCalc* calc, double* result)
default: default:
{ {
Operation op; Operation op;
op.type = (OperationType) g_Lexer.intValue; op.type = (OperationType)lexer.intValue;
switch (op.type) switch (op.type)
{ {
case OP_ADD: case OP_ADD:
if (g_ObrDist >= 1) goto nextToken; if (parser.obrDist >= 1)
{
// Goto next token
continue;
}
break; break;
case OP_SUB: case OP_SUB:
if (g_ObrDist >= 1) if (parser.obrDist >= 1)
{ {
g_OpStack[++g_OpTop] = g_NegOp; parser.opStack[++parser.opTop] = g_NegOp;
goto nextToken;
// Goto next token
continue;
} }
break; break;
case OP_LOGIC: case OP_LOGIC:
case OP_LOGIC_SEP: case OP_LOGIC_SEP:
g_ObrDist = 2; parser.obrDist = 2;
break; break;
} }
while (g_OpPriorities[op.type] <= g_OpPriorities[g_OpStack[g_OpTop].type]) while (g_OpPriorities[op.type] <= g_OpPriorities[parser.opStack[parser.opTop].type])
{ {
if ((error = Calc()) != NULL) return error; if ((error = Calc(parser)) != NULL) return error;
} }
g_OpStack[++g_OpTop] = op; parser.opStack[++parser.opTop] = op;
} }
break; break;
} }
break; break;
case TOK_NAME: case TOK_NAME:
{ {
Operation op; Operation op;
double dblval; int funcnum, namelen = lexer.nameLen;
void* *func = NULL;
int funcnum, namelen = g_Lexer.nameLen;
if (g_Lexer.nameLen <= MAX_FUNC_LEN && if (lexer.nameLen <= FUNC_MAX_LEN &&
((funcnum = GetFunction(g_Lexer.name, g_Lexer.nameLen, (void**)&op.Func)) >= 0)) ((funcnum = GetFunction(lexer.name, lexer.nameLen, (void**)&op.proc)) >= 0))
{ {
switch (funcnum) switch (funcnum)
{ {
case FUNC_E: case FUNC_E:
g_ValStack[++g_ValTop] = M_E; parser.valStack[++parser.valTop] = M_E;
break; break;
case FUNC_PI: case FUNC_PI:
g_ValStack[++g_ValTop] = M_PI; parser.valStack[++parser.valTop] = M_PI;
break; break;
case FUNC_ROUND: case FUNC_ROUND:
op.type = OP_FUNC_MULTIARG; op.type = OP_FUNC_MULTIARG;
op.prevvalTop = g_ValTop; op.prevTop = parser.valTop;
g_OpStack[++g_OpTop] = op; parser.opStack[++parser.opTop] = op;
break; break;
default: // Internal function default: // Internal function
op.type = OP_FUNC_ONEARG; op.type = OP_FUNC_ONEARG;
g_OpStack[++g_OpTop] = op; parser.opStack[++parser.opTop] = op;
break; break;
} }
} }
else else
{ {
if (calc && calc->GetMeasureValue(g_Lexer.name, g_Lexer.nameLen, &dblval)) double dblval;
if (calc && calc->GetMeasureValue(lexer.name, lexer.nameLen, &dblval))
{ {
g_ValStack[++g_ValTop] = dblval; parser.valStack[++parser.valTop] = dblval;
break; break;
} }
char buffer[128 - _countof(eUnknFunc)]; WCHAR buffer[128 - _countof(eUnknFunc)];
strncpy_s(buffer, g_Lexer.name, g_Lexer.nameLen); wcsncpy_s(buffer, lexer.name, lexer.nameLen);
buffer[g_Lexer.nameLen] = '\0'; buffer[lexer.nameLen] = L'\0';
_snprintf_s(g_ErrorBuffer, _TRUNCATE, eUnknFunc, buffer); _snwprintf_s(g_ErrorBuffer, _TRUNCATE, eUnknFunc, buffer);
return g_ErrorBuffer; return g_ErrorBuffer;
} }
break; break;
@ -415,46 +413,37 @@ char* MathParser::Parse(const char* formula, CMeasureCalc* calc, double* result)
default: default:
return eSyntax; 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() static WCHAR* Calc(Parser& parser)
{ {
double res; double res;
Operation op = g_OpStack[g_OpTop--]; Operation op = parser.opStack[parser.opTop--];
// Multi-argument function // Multi-argument function
if (op.type == OP_FUNC_MULTIARG) if (op.type == OP_FUNC_MULTIARG)
{ {
int paramcnt = g_ValTop - op.prevvalTop; int paramcnt = parser.valTop - op.prevTop;
g_ValTop = op.prevvalTop; parser.valTop = op.prevTop;
char* error = (*(MultiArgProc)op.Func)(paramcnt, &g_ValStack[g_ValTop + 1], &res); WCHAR* error = (*(MultiArgProc)op.proc)(paramcnt, &parser.valStack[parser.valTop + 1], &res);
if (error) return error; if (error) return error;
g_ValStack[++g_ValTop] = res; parser.valStack[++parser.valTop] = res;
return NULL; return NULL;
} }
else if (op.type == OP_LOGIC) else if (op.type == OP_LOGIC)
{ {
return NULL; return NULL;
} }
else if (g_ValTop < 0) else if (parser.valTop < 0)
{ {
return eExtraOp; return eExtraOp;
} }
// Right arg // Right arg
double right = g_ValStack[g_ValTop--]; double right = parser.valStack[parser.valTop--];
// One arg operations // One arg operations
if (op.type == OP_NOT) if (op.type == OP_NOT)
@ -470,17 +459,17 @@ static char* Calc()
} }
else if (op.type == OP_FUNC_ONEARG) else if (op.type == OP_FUNC_ONEARG)
{ {
res = (*(OneArgProc)op.Func)(right); res = (*(OneArgProc)op.proc)(right);
} }
else else
{ {
if (g_ValTop < 0) if (parser.valTop < 0)
{ {
return eExtraOp; return eExtraOp;
} }
// Left arg // Left arg
double left = g_ValStack[g_ValTop--]; double left = parser.valStack[parser.valTop--];
switch (op.type) switch (op.type)
{ {
case OP_SHL: case OP_SHL:
@ -620,11 +609,11 @@ static char* Calc()
{ {
// needs three arguments // needs three arguments
double ValLL; double ValLL;
if (g_OpTop < 0 || g_OpStack[g_OpTop--].type != OP_LOGIC) if (parser.opTop < 0 || parser.opStack[parser.opTop--].type != OP_LOGIC)
{ {
return eLogicErr; return eLogicErr;
} }
ValLL = g_ValStack[g_ValTop--]; ValLL = parser.valStack[parser.valTop--];
res = ValLL ? left : right; res = ValLL ? left : right;
} }
break; break;
@ -634,91 +623,31 @@ static char* Calc()
} }
} }
g_ValStack[++g_ValTop] = res; parser.valStack[++parser.valTop] = res;
return NULL; return NULL;
} }
static char* CalcToObr() static WCHAR* CalcToObr(Parser& parser)
{ {
while (g_OpStack[g_OpTop].type != OP_OBR) while (parser.opStack[parser.opTop].type != OP_OBR)
{ {
char* error = Calc(); WCHAR* error = Calc(parser);
if (error) return error; if (error) return error;
} }
--g_OpTop; --parser.opTop;
return NULL; return NULL;
} }
int GetFunction(const char* str, size_t len, void** data) MathTokenType GetNextToken(Lexer& lexer)
{
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; MathTokenType result = TOK_ERROR;
while (g_Lexer.CharType == CH_SEPARAT) while (lexer.charType == CH_SEPARAT)
{ {
g_Lexer.CharType = CHARTYPEPP(); lexer.charType = GetCharType(*++lexer.string);
} }
switch (g_Lexer.CharType) switch (lexer.charType)
{ {
case CH_FINAL: case CH_FINAL:
{ {
@ -728,36 +657,36 @@ MathTokenType Lexer_GetNextToken()
case CH_LETTER: case CH_LETTER:
{ {
g_Lexer.name = g_Lexer.string; lexer.name = lexer.string;
do do
{ {
g_Lexer.CharType = CHARTYPEPP(); lexer.charType = GetCharType(*++lexer.string);
} }
while (g_Lexer.CharType <= CH_DIGIT); while (lexer.charType <= CH_DIGIT);
g_Lexer.nameLen = g_Lexer.string - g_Lexer.name; lexer.nameLen = lexer.string - lexer.name;
result = TOK_NAME; result = TOK_NAME;
} }
break; break;
case CH_DIGIT: case CH_DIGIT:
{ {
char* newString; WCHAR* newString;
if (g_Lexer.string[0] == '0') if (lexer.string[0] == L'0')
{ {
bool valid = true; bool valid = true;
switch (g_Lexer.string[1]) switch (lexer.string[1])
{ {
case 'x': // Hexadecimal case L'x': // Hexadecimal
g_Lexer.intValue = strtol(g_Lexer.string, &newString, 16); lexer.intValue = wcstol(lexer.string, &newString, 16);
break; break;
case 'o': // Octal case L'o': // Octal
g_Lexer.intValue = strtol(g_Lexer.string + 2, &newString, 8); lexer.intValue = wcstol(lexer.string + 2, &newString, 8);
break; break;
case 'b': // Binary case L'b': // Binary
g_Lexer.intValue = strtol(g_Lexer.string + 2, &newString, 2); lexer.intValue = wcstol(lexer.string + 2, &newString, 2);
break; break;
default: default:
@ -767,11 +696,11 @@ MathTokenType Lexer_GetNextToken()
if (valid) if (valid)
{ {
if (g_Lexer.string != newString) if (lexer.string != newString)
{ {
g_Lexer.string = newString; lexer.string = newString;
g_Lexer.CharType = CHARTYPE(); lexer.charType = GetCharType(*lexer.string);
g_Lexer.extValue = g_Lexer.intValue; lexer.extValue = lexer.intValue;
result = TOK_FLOAT; result = TOK_FLOAT;
} }
break; break;
@ -779,11 +708,11 @@ MathTokenType Lexer_GetNextToken()
} }
// Decimal // Decimal
g_Lexer.extValue = strtod(g_Lexer.string, &newString); lexer.extValue = wcstod(lexer.string, &newString);
if (g_Lexer.string != newString) if (lexer.string != newString)
{ {
g_Lexer.string = newString; lexer.string = newString;
g_Lexer.CharType = CHARTYPE(); lexer.charType = GetCharType(*lexer.string);
result = TOK_FLOAT; result = TOK_FLOAT;
} }
} }
@ -791,16 +720,13 @@ MathTokenType Lexer_GetNextToken()
case CH_SYMBOL: case CH_SYMBOL:
{ {
int sym = FindSymbol(g_Lexer.string); int sym = FindSymbol(lexer.string);
if (sym >= 0) if (sym >= 0)
{ {
g_Lexer.string += (sym == OP_POW || lexer.string += (sym <= OP_LOGIC_OR) ? 2 : 1;
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(); lexer.charType = GetCharType(*lexer.string);
g_Lexer.intValue = sym; lexer.intValue = sym;
result = TOK_SYMBOL; result = TOK_SYMBOL;
} }
} }
@ -809,7 +735,97 @@ MathTokenType Lexer_GetNextToken()
default: default:
break; break;
} }
return g_Lexer.PrevTokenType = result; return lexer.prevToken = result;
}
CharType GetCharType(WCHAR ch)
{
switch (ch)
{
case L'\0':
return CH_FINAL;
case L' ':
case L'\t':
case L'\n':
return CH_SEPARAT;
case L'_':
return CH_LETTER;
case L'+':
case L'-':
case L'/':
case L'*':
case L'~':
case L'(':
case L')':
case L'<':
case L'>':
case L'%':
case L'$':
case L',':
case L'?':
case L':':
case L'=':
case L'&':
case L'|':
return CH_SYMBOL;
}
if (iswalpha(ch)) return CH_LETTER;
if (iswdigit(ch)) return CH_DIGIT;
return CH_UNKNOWN;
}
bool MathParser::IsDelimiter(WCHAR ch)
{
CharType type = GetCharType(ch);
return type == CH_SYMBOL || type == CH_SEPARAT;
}
int GetFunction(const WCHAR* 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 &&
_wcsnicmp(str, g_Functions[i].name, len) == 0)
{
*data = g_Functions[i].proc;
return i;
}
}
return -1;
}
int FindSymbol(const WCHAR* str)
{
switch (str[0])
{
case L'(': return (int)OP_OBR;
case L'+': return OP_ADD;
case L'-': return OP_SUB;
case L'*': return (str[1] == L'*') ? OP_POW : OP_MUL;
case L'/': return OP_DIV;
case L'%': return OP_MOD;
case L'$': return OP_UNK;
case L'^': return OP_XOR;
case L'~': return OP_NOT;
case L'&': return (str[1] == L'&') ? OP_LOGIC_AND : OP_AND;
case L'|': return (str[1] == L'|') ? OP_LOGIC_OR : OP_OR;
case L'=': return OP_EQU;
case L'>': return (str[1] == L'>') ? OP_SHR : (str[1] == L'=') ? OP_LOGIC_GEQ : OP_GREATER;
case L'<': return (str[1] == L'>') ? OP_LOGIC_NEQ : (str[1] == L'<') ? OP_SHL : (str[1] == L'=') ? OP_LOGIC_LEQ : OP_SMALLER;
case L'?': return OP_LOGIC;
case L':': return OP_LOGIC_SEP;
case L')': return OP_CBR;
case L',': return OP_COMMA;
}
return -1;
} }
// ----------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------
@ -838,7 +854,7 @@ static double neg(double x)
} }
// "Advanced" round function; second argument - sharpness // "Advanced" round function; second argument - sharpness
static char* round(int paramcnt, double* args, double* result) static WCHAR* round(int paramcnt, double* args, double* result)
{ {
int sharpness; int sharpness;
if (paramcnt == 1) if (paramcnt == 1)

View File

@ -25,11 +25,11 @@ class CMeasureCalc;
namespace MathParser namespace MathParser
{ {
void Initialize(); WCHAR* Check(const WCHAR* formula);
WCHAR* CheckParse(const WCHAR* formula, double* result);
WCHAR* Parse(const WCHAR* formula, CMeasureCalc* calc, double* result);
char* Check(const char* formula); bool IsDelimiter(WCHAR ch);
char* CheckParse(const char* formula, double* result);
char* Parse(const char* formula, CMeasureCalc* calc, double* result);
}; };
#endif #endif

View File

@ -30,7 +30,6 @@ bool CMeasureCalc::c_RandSeeded = false;
** **
*/ */
CMeasureCalc::CMeasureCalc(CMeterWindow* meterWindow, const WCHAR* name) : CMeasure(meterWindow, name), CMeasureCalc::CMeasureCalc(CMeterWindow* meterWindow, const WCHAR* name) : CMeasure(meterWindow, name),
m_Random(),
m_LowBound(), m_LowBound(),
m_HighBound(100), m_HighBound(100),
m_UpdateRandom(false) m_UpdateRandom(false)
@ -64,13 +63,11 @@ bool CMeasureCalc::Update()
{ {
if (!CMeasure::PreUpdate()) return false; if (!CMeasure::PreUpdate()) return false;
if (m_UpdateRandom) UpdateRandom(); WCHAR* errMsg = MathParser::Parse(m_Formula.c_str(), this, &m_Value);
char* errMsg = MathParser::Parse(ConvertToAscii(m_Formula.c_str()).c_str(), this, &m_Value);
if (errMsg != NULL) if (errMsg != NULL)
{ {
std::wstring error = L"Calc: "; std::wstring error = L"Calc: ";
error += ConvertToWide(errMsg); error += errMsg;
error += L" in ["; error += L" in [";
error += m_Name; error += m_Name;
error += L']'; error += L']';
@ -108,13 +105,16 @@ void CMeasureCalc::ReadConfig(CConfigParser& parser, const WCHAR* section)
oldHighBound != m_HighBound || oldHighBound != m_HighBound ||
oldUpdateRandom != m_UpdateRandom) oldUpdateRandom != m_UpdateRandom)
{ {
if (!m_UpdateRandom) UpdateRandom(); if (!m_UpdateRandom)
{
FormulaReplace();
}
char* errMsg = MathParser::Check(ConvertToAscii(m_Formula.c_str()).c_str()); WCHAR* errMsg = MathParser::Check(m_Formula.c_str());
if (errMsg != NULL) if (errMsg != NULL)
{ {
std::wstring error = L"Calc: "; std::wstring error = L"Calc: ";
error += ConvertToWide(errMsg); error += errMsg;
error += L" in ["; error += L" in [";
error += m_Name; error += m_Name;
error += L']'; error += L']';
@ -122,38 +122,72 @@ void CMeasureCalc::ReadConfig(CConfigParser& parser, const WCHAR* section)
} }
} }
} }
/*
** FormulaReplace
**
** This replaces the word Random in the formula with a random number
**
*/
void CMeasureCalc::FormulaReplace()
{
size_t start = 0, pos;
do
{
pos = m_Formula.find_first_of(L"Rr", start);
if (pos != std::wstring::npos)
{
if (_wcsnicmp(L"random", m_Formula.c_str() + pos, 6) == 0 &&
(pos == 0 || MathParser::IsDelimiter((*(m_Formula.c_str() + pos - 1))) &&
(pos == (m_Formula.length() - 6) || MathParser::IsDelimiter((*(m_Formula.c_str() + pos + 6))))))
{
int randNumber = GetRandom();
bool CMeasureCalc::GetMeasureValue(const char* str, int len, double* value) WCHAR buffer[32];
_itow_s(randNumber, buffer, 10);
size_t len = wcslen(buffer);
m_Formula.replace(pos, 6, buffer, len);
start = pos + len;
}
else
{
start = pos + 1;
}
}
}
while (pos != std::wstring::npos);
}
bool CMeasureCalc::GetMeasureValue(const WCHAR* str, int len, double* value)
{ {
const std::list<CMeasure*>& measures = m_MeterWindow->GetMeasures(); const std::list<CMeasure*>& measures = m_MeterWindow->GetMeasures();
std::list<CMeasure*>::const_iterator iter = measures.begin(); std::list<CMeasure*>::const_iterator iter = measures.begin();
for ( ; iter != measures.end(); ++iter) for ( ; iter != measures.end(); ++iter)
{ {
if (_strnicmp(str, (*iter)->GetAsciiName(), len) == 0) if (_wcsnicmp(str, (*iter)->GetName(), len) == 0)
{ {
*value = (*iter)->GetValue(); *value = (*iter)->GetValue();
return 1; return true;
} }
} }
if (_strnicmp(str, "counter", len) == 0) if (_wcsnicmp(str, L"counter", len) == 0)
{ {
*value = m_MeterWindow->GetUpdateCounter(); *value = m_MeterWindow->GetUpdateCounter();
return 1; return true;
} }
else if (_strnicmp(str, "random", len) == 0) else if (_wcsnicmp(str, L"random", len) == 0)
{ {
*value = (double)m_Random; *value = GetRandom();
return 1; return true;
} }
return 0; return false;
} }
void CMeasureCalc::UpdateRandom() int CMeasureCalc::GetRandom()
{ {
int range = (m_HighBound - m_LowBound) + 1; int range = (m_HighBound - m_LowBound) + 1;
srand((unsigned)rand()); srand((unsigned)rand());
m_Random = m_LowBound + (int)(range * rand() / (RAND_MAX + 1.0)); return m_LowBound + (int)(range * rand() / (RAND_MAX + 1.0));
} }

View File

@ -29,20 +29,20 @@ public:
virtual bool Update(); virtual bool Update();
bool GetMeasureValue(const char* str, int len, double* value); bool GetMeasureValue(const WCHAR* str, int len, double* value);
protected: protected:
virtual void ReadConfig(CConfigParser& parser, const WCHAR* section); virtual void ReadConfig(CConfigParser& parser, const WCHAR* section);
private: private:
void UpdateRandom(); void FormulaReplace();
int GetRandom();
std::wstring m_Formula; std::wstring m_Formula;
int m_Random;
int m_LowBound; int m_LowBound;
int m_HighBound; int m_HighBound;
bool m_UpdateRandom; bool m_UpdateRandom;
static bool c_RandSeeded; static bool c_RandSeeded;

View File

@ -23,7 +23,6 @@
#include "Error.h" #include "Error.h"
#include "DialogAbout.h" #include "DialogAbout.h"
#include "DialogManage.h" #include "DialogManage.h"
#include "MathParser.h"
#include "MeasureNet.h" #include "MeasureNet.h"
#include "MeterString.h" #include "MeterString.h"
#include "resource.h" #include "resource.h"
@ -1068,7 +1067,6 @@ int CRainmeter::Initialize(HWND hParent, HINSTANCE hInstance, LPCWSTR szPath)
// Test that the Rainmeter.ini file is writable // Test that the Rainmeter.ini file is writable
TestSettingsFile(bDefaultIniLocation); TestSettingsFile(bDefaultIniLocation);
MathParser::Initialize();
CSystem::Initialize(hInstance); CSystem::Initialize(hInstance);
CMeasureNet::InitializeNewApi(); CMeasureNet::InitializeNewApi();