diff --git a/math/expression_parser.cpp b/math/expression_parser.cpp new file mode 100644 index 0000000000..e150c00b5b --- /dev/null +++ b/math/expression_parser.cpp @@ -0,0 +1,462 @@ +#include "expression_parser.h" +#include +#include + +typedef enum { + EXOP_BRACKETL, EXOP_BRACKETR, EXOP_SIGNPLUS, EXOP_SIGNMINUS, + EXOP_BITNOT, EXOP_LOGNOT, EXOP_MUL, EXOP_DIV, EXOP_MOD, EXOP_ADD, EXOP_SUB, + EXOP_SHL, EXOP_SHR, EXOP_GREATEREQUAL, EXOP_GREATER, EXOP_LOWEREQUAL, EXOP_LOWER, + EXOP_EQUAL, EXOP_NOTEQUAL, EXOP_BITAND, EXOP_XOR, EXOP_BITOR, EXOP_LOGAND, + EXOP_LOGOR, EXOP_TERTIF, EXOP_TERTELSE, EXOP_NUMBER, EXOP_NONE, EXOP_COUNT +} ExpressionOpcodeType; + +typedef enum { EXCOMM_CONST, EXCOMM_REF, EXCOMM_OP } ExpressionCommand; + +static char expressionError[256]; + +typedef struct { + char Name[4]; + unsigned char Priority; + unsigned char len; + unsigned char args; + bool sign; +} ExpressionOpcode; + +const ExpressionOpcode ExpressionOpcodes[] = { + { "(", 15, 1, 0, false }, // EXOP_BRACKETL + { ")", 15, 1, 0, false }, // EXOP_BRACKETR + { "+", 12, 1, 1, true }, // EXOP_SIGNPLUS + { "-", 12, 1, 1, true }, // EXOP_SIGNMINUS + { "~", 12, 1, 1, false }, // EXOP_BITNOT + { "!", 12, 1, 1, false }, // EXOP_LOGNOT + { "*", 11, 1, 2, false }, // EXOP_MUL + { "/", 11, 1, 2, false }, // EXOP_DIV + { "%", 11, 1, 2, false }, // EXOP_MOD + { "+", 10, 1, 2, false }, // EXOP_ADD + { "-", 10, 1, 2, false }, // EXOP_SUB + { "<<", 9, 2, 2, false }, // EXOP_SHL + { ">>", 9, 2, 2, false }, // EXOP_SHR + { ">=", 8, 2, 2, false }, // EXOP_GREATEREQUAL + { ">", 8, 1, 2, false }, // EXOP_GREATER + { "<=", 8, 2, 2, false }, // EXOP_LOWEREQUAL + { "<", 8, 1, 2, false }, // EXOP_LOWER + { "==", 7, 2, 2, false }, // EXOP_EQUAL + { "!=", 7, 2, 2, false }, // EXOP_NOTEQUAL + { "&", 6, 1, 2, false }, // EXOP_BITAND + { "^", 5, 1, 2, false }, // EXOP_XOR + { "|", 4, 1, 2, false }, // EXOP_BITOR + { "&&", 3, 2, 2, false }, // EXOP_LOGAND + { "||", 2, 2, 2, false }, // EXOP_LOGOR + { "?", 0, 1, 0, false }, // EXOP_TERTIF + { ":", 1, 1, 3, false }, // EXOP_TERTELSE + { "", 0, 0, 0, false }, // EXOP_NUMBER + { "", 0, 0, 0, false } // EXOP_NONE +}; + +bool parseNumber(char* str, int defaultrad, int len, uint32& result) +{ + int val = 0; + int r = 0; + if (len == 0) len = (int) strlen(str); + + if (str[0] == '0' && tolower(str[1]) == 'x') + { + r = 16; + str+=2; + len-=2; + } else if (str[0] == '$') + { + r = 16; + str++; + len--; + } else if (str[0] == '0' && tolower(str[1]) == 'o') + { + r = 8; + str+=2; + len-=2; + } else { + if (!(str[0] >= '0' && str[0] <= '9')) return false; + + if (tolower(str[len-1]) == 'b') + { + r = 2; + len--; + } else if (tolower(str[len-1]) == 'o') + { + r = 8; + len--; + } else if (tolower(str[len-1]) == 'h') + { + r = 16; + len--; + } else { + r = defaultrad; + } + } + + switch (r) + { + case 2: // bin + while (len--) + { + if (*str != '0' && *str != '1') return false; + val = val << 1; + if (*str++ == '1') + { + val++; + } + } + break; + case 8: // oct + while (len--) + { + if (*str < '0' || *str > '7') return false; + val = val << 3; + val+=(*str++-'0'); + } + break; + case 10: // dec + while (len--) + { + if (*str < '0' || *str > '9') return false; + val = val * 10; + val += (*str++ - '0'); + } + break; + case 16: // hex + while (len--) + { + char c = tolower(*str++); + if ((c < '0' || c > '9') && (c < 'a' || c > 'f')) return false; + val = val << 4; + + if (c >= 'a') val += c-'a'+10; + else val += c-'0'; + } + break; + default: + return false; + } + + result = val; + return true; +} + +ExpressionOpcodeType getExpressionOpcode(char* str, int& ReturnLen, ExpressionOpcodeType LastOpcode) +{ + int longestlen = 0; + ExpressionOpcodeType result = EXOP_NONE; + + for (int i = 0; i < EXOP_NUMBER; i++) + { + if (ExpressionOpcodes[i].sign == true && + (LastOpcode == EXOP_NUMBER || LastOpcode == EXOP_BRACKETR)) continue; + + int len = ExpressionOpcodes[i].len; + if (len > longestlen) + { + if (strncmp(ExpressionOpcodes[i].Name,str,len) == 0) + { + result = (ExpressionOpcodeType) i; + longestlen = len; + } + } + } + + ReturnLen = longestlen; + return result; +} + +bool isAlphaNum(char c) +{ + if ((c >= '0' && c <= '9') || + (c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z') || + c == '@' || c == '_' || c == '$') + { + return true; + } else { + return false; + } +} + +bool initPostfixExpression(char* infix, IExpressionFunctions* funcs, PostfixExpression& dest) +{ + expressionError[0] = 0; + + int infixPos = 0; + int infixLen = strlen(infix); + ExpressionOpcodeType lastOpcode = EXOP_NONE; + std::vector opcodeStack; + dest.clear(); + + while (infixPos < infixLen) + { + char first = tolower(infix[infixPos]); + char subStr[256]; + int subPos = 0; + + if (first == ' ' || first == '\t') + { + infixPos++; + continue; + } + + if (first >= '0' && first <= '9') + { + while (isAlphaNum(infix[infixPos])) + { + subStr[subPos++] = infix[infixPos++]; + } + subStr[subPos] = 0; + + uint32 value; + if (parseNumber(subStr,16,subPos,value) == false) + { + sprintf(expressionError,"Invalid number \"%s\"",subStr); + return false; + } + + dest.push_back(ExpressionPair(EXCOMM_CONST,value)); + lastOpcode = EXOP_NUMBER; + } else if ((first >= 'a' && first <= 'z') || first == '@') + { + while (isAlphaNum(infix[infixPos])) + { + subStr[subPos++] = infix[infixPos++]; + } + subStr[subPos] = 0; + + uint32 value; + if (funcs->parseReference(subStr,value) == true) + { + dest.push_back(ExpressionPair(EXCOMM_REF,value)); + lastOpcode = EXOP_NUMBER; + continue; + } + + if (funcs->parseSymbol(subStr,value) == true) + { + dest.push_back(ExpressionPair(EXCOMM_CONST,value)); + lastOpcode = EXOP_NUMBER; + continue; + } + + sprintf(expressionError,"Invalid symbol \"%s\"",subStr); + return false; + } else { + int len; + ExpressionOpcodeType type = getExpressionOpcode(&infix[infixPos],len,lastOpcode); + if (type == EXOP_NONE) + { + sprintf(expressionError,"Invalid operator at \"%s\"",&infix[infixPos]); + return false; + } + + switch (type) + { + case EXOP_BRACKETL: + opcodeStack.push_back(type); + break; + case EXOP_BRACKETR: + while (true) + { + if (opcodeStack.empty()) + { + sprintf(expressionError,"Closing parenthesis without opening one"); + return false; + } + ExpressionOpcodeType t = opcodeStack[opcodeStack.size()-1]; + opcodeStack.pop_back(); + if (t == EXOP_BRACKETL) break; + dest.push_back(ExpressionPair(EXCOMM_OP,t)); + } + break; + default: + if (opcodeStack.empty() == false) + { + int CurrentPriority = ExpressionOpcodes[type].Priority; + while (!opcodeStack.empty()) + { + ExpressionOpcodeType t = opcodeStack[opcodeStack.size()-1]; + opcodeStack.pop_back(); + + if (t == EXOP_BRACKETL) + { + opcodeStack.push_back(t); + break; + } + + if (ExpressionOpcodes[t].Priority >= CurrentPriority) + { + dest.push_back(ExpressionPair(EXCOMM_OP,t)); + } else { + opcodeStack.push_back(t); + break; + } + } + } + opcodeStack.push_back(type); + break; + } + infixPos += len; + lastOpcode = type; + } + } + + while (!opcodeStack.empty()) + { + ExpressionOpcodeType t = opcodeStack[opcodeStack.size()-1]; + opcodeStack.pop_back(); + + if (t == EXOP_BRACKETL) // opening bracket without closing one + { + sprintf(expressionError,"Parenthesis not closed"); + return false; + } + dest.push_back(ExpressionPair(EXCOMM_OP,t)); + } + + return true; +} + +bool parsePostfixExpression(PostfixExpression& exp, IExpressionFunctions* funcs, uint32& dest) +{ + int num = 0; + uint32 opcode; + std::vector valueStack; + unsigned int arg[5]; + + while (num < exp.size()) + { + switch (exp[num].first) + { + case EXCOMM_CONST: // konstante zahl + valueStack.push_back(exp[num++].second); + break; + case EXCOMM_REF: + opcode = funcs->getReferenceValue(exp[num++].second); + valueStack.push_back(opcode); + break; + case EXCOMM_OP: // opcode + opcode = exp[num++].second; + if (valueStack.size() < ExpressionOpcodes[opcode].args) + { + sprintf(expressionError,"Not enough arguments"); + return false; + } + for (int l = 0; l < ExpressionOpcodes[opcode].args; l++) + { + arg[l] = valueStack[valueStack.size()-1]; + valueStack.pop_back(); + } + + switch (opcode) + { + case EXOP_SIGNPLUS: // keine aktion nötig + break; + case EXOP_SIGNMINUS: // -0 + valueStack.push_back(0-arg[0]); + break; + case EXOP_BITNOT: // ~b + valueStack.push_back(~arg[0]); + break; + case EXOP_LOGNOT: // !b + valueStack.push_back(!arg[0]); + break; + case EXOP_MUL: // a*b + valueStack.push_back(arg[1]*arg[0]); + break; + case EXOP_DIV: // a/b + if (arg[0] == 0) + { + sprintf(expressionError,"Division by zero"); + return false; + } + valueStack.push_back(arg[1]/arg[0]); + break; + case EXOP_MOD: // a%b + if (arg[0] == 0) + { + sprintf(expressionError,"Modulo by zero"); + return false; + } + valueStack.push_back(arg[1]%arg[0]); + break; + case EXOP_ADD: // a+b + valueStack.push_back(arg[1]+arg[0]); + break; + case EXOP_SUB: // a-b + valueStack.push_back(arg[1]-arg[0]); + break; + case EXOP_SHL: // a<>b + valueStack.push_back(arg[1]>>arg[0]); + break; + case EXOP_GREATEREQUAL: // a >= b + valueStack.push_back(arg[1]>=arg[0]); + break; + case EXOP_GREATER: // a > b + valueStack.push_back(arg[1]>arg[0]); + break; + case EXOP_LOWEREQUAL: // a <= b + valueStack.push_back(arg[1]<=arg[0]); + break; + case EXOP_LOWER: // a < b + valueStack.push_back(arg[1] + +typedef std::pair ExpressionPair; +typedef std::vector PostfixExpression; + +class IExpressionFunctions +{ +public: + virtual bool parseReference(char* str, uint32& referenceIndex) = 0; + virtual bool parseSymbol(char* str, uint32& symbolValue) = 0; + virtual uint32 getReferenceValue(uint32 referenceIndex) = 0; +}; + +bool initPostfixExpression(char* infix, IExpressionFunctions* funcs, PostfixExpression& dest); +bool parsePostfixExpression(PostfixExpression& exp, IExpressionFunctions* funcs, uint32& dest); +bool parseExpression(char* exp, IExpressionFunctions* funcs, uint32& dest); +const char* getExpressionError(); diff --git a/native.vcxproj b/native.vcxproj index bc4efef2cd..ea3cfa3ecb 100644 --- a/native.vcxproj +++ b/native.vcxproj @@ -231,6 +231,7 @@ + @@ -353,6 +354,7 @@ + diff --git a/native.vcxproj.filters b/native.vcxproj.filters index 99f79b14a8..eca9e19926 100644 --- a/native.vcxproj.filters +++ b/native.vcxproj.filters @@ -274,6 +274,9 @@ + + math + @@ -486,6 +489,9 @@ data + + math +