CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/Common/Math/expression_parser.cpp
Views: 1401
#include "Common/StringUtils.h"1#include "expression_parser.h"2#include <ctype.h>3#include <cstring>4#include <cstdio>5#include <cstdlib>67typedef enum {8EXOP_BRACKETL, EXOP_BRACKETR, EXOP_MEML, EXOP_MEMR, EXOP_MEMSIZE, EXOP_SIGNPLUS, EXOP_SIGNMINUS,9EXOP_BITNOT, EXOP_LOGNOT, EXOP_MUL, EXOP_DIV, EXOP_MOD, EXOP_ADD, EXOP_SUB,10EXOP_SHL, EXOP_SHR, EXOP_GREATEREQUAL, EXOP_GREATER, EXOP_LOWEREQUAL, EXOP_LOWER,11EXOP_EQUAL, EXOP_NOTEQUAL, EXOP_BITAND, EXOP_XOR, EXOP_BITOR, EXOP_LOGAND,12EXOP_LOGOR, EXOP_TERTIF, EXOP_TERTELSE, EXOP_NUMBER, EXOP_MEM, EXOP_NONE, EXOP_COUNT13} ExpressionOpcodeType;1415typedef enum { EXCOMM_CONST, EXCOMM_CONST_FLOAT, EXCOMM_REF, EXCOMM_OP } ExpressionCommand;1617static std::string expressionError;1819typedef struct {20char Name[4];21unsigned char Priority;22unsigned char len;23unsigned char args;24bool sign;25} ExpressionOpcode;2627const ExpressionOpcode ExpressionOpcodes[] = {28{ "(", 25, 1, 0, false }, // EXOP_BRACKETL29{ ")", 25, 1, 0, false }, // EXOP_BRACKETR30{ "[", 4, 1, 0, false }, // EXOP_MEML31{ "]", 4, 1, 0, false }, // EXOP_MEMR32{ ",", 5, 1, 2, false }, // EXOP_MEMSIZE33{ "+", 22, 1, 1, true }, // EXOP_SIGNPLUS34{ "-", 22, 1, 1, true }, // EXOP_SIGNMINUS35{ "~", 22, 1, 1, false }, // EXOP_BITNOT36{ "!", 22, 1, 1, false }, // EXOP_LOGNOT37{ "*", 21, 1, 2, false }, // EXOP_MUL38{ "/", 21, 1, 2, false }, // EXOP_DIV39{ "%", 21, 1, 2, false }, // EXOP_MOD40{ "+", 20, 1, 2, false }, // EXOP_ADD41{ "-", 20, 1, 2, false }, // EXOP_SUB42{ "<<", 19, 2, 2, false }, // EXOP_SHL43{ ">>", 19, 2, 2, false }, // EXOP_SHR44{ ">=", 18, 2, 2, false }, // EXOP_GREATEREQUAL45{ ">", 18, 1, 2, false }, // EXOP_GREATER46{ "<=", 18, 2, 2, false }, // EXOP_LOWEREQUAL47{ "<", 18, 1, 2, false }, // EXOP_LOWER48{ "==", 17, 2, 2, false }, // EXOP_EQUAL49{ "!=", 17, 2, 2, false }, // EXOP_NOTEQUAL50{ "&", 16, 1, 2, false }, // EXOP_BITAND51{ "^", 15, 1, 2, false }, // EXOP_XOR52{ "|", 14, 1, 2, false }, // EXOP_BITOR53{ "&&", 13, 2, 2, false }, // EXOP_LOGAND54{ "||", 12, 2, 2, false }, // EXOP_LOGOR55{ "?", 10, 1, 0, false }, // EXOP_TERTIF56{ ":", 11, 1, 3, false }, // EXOP_TERTELSE57{ "", 0, 0, 0, false }, // EXOP_NUMBER58{ "[]", 0, 0, 1, false }, // EXOP_MEM59{ "", 0, 0, 0, false } // EXOP_NONE60};6162static int radixFromZeroPrefix(char c) {63switch (tolower(c)) {64case 'b': return 2;65case 'o': return 8;66case 'x': return 16;67// Inventing a prefix since we default to hex.68case 'd': return 10;69}7071return -1;72}7374static int radixFromSuffix(char c, int defaultrad) {75switch (tolower(c)) {76case 'o': return 8;77case 'h': return 16;78case 'i': return 10;79case 'u': return 10;80case 'b': return defaultrad == 16 ? -1 : 2;81}8283return -1;84}8586bool parseNumber(char *str, int defaultrad, int len, uint32_t &result) {87int val = 0;88int r = 0;89if (len == 0)90len = (int)strlen(str);9192if (str[0] == '0' && radixFromZeroPrefix(str[1]) != -1) {93r = radixFromZeroPrefix(str[1]);94str += 2;95len -= 2;96} else if (str[0] == '$') {97r = 16;98str++;99len--;100} else if (str[0] >= '0' && str[0] <= '9') {101int suffix = radixFromSuffix(str[len - 1], defaultrad);102if (suffix != -1) {103r = suffix;104len--;105} else {106r = defaultrad;107}108} else {109return false;110}111112switch (r)113{114case 2: // bin115while (len--)116{117if (*str != '0' && *str != '1') return false;118val = val << 1;119if (*str++ == '1')120{121val++;122}123}124break;125case 8: // oct126while (len--)127{128if (*str < '0' || *str > '7') return false;129val = val << 3;130val+=(*str++-'0');131}132break;133case 10: // dec134while (len--)135{136if (*str < '0' || *str > '9') return false;137val = val * 10;138val += (*str++ - '0');139}140break;141case 16: // hex142while (len--)143{144char c = tolower(*str++);145if ((c < '0' || c > '9') && (c < 'a' || c > 'f')) return false;146val = val << 4;147148if (c >= 'a') val += c-'a'+10;149else val += c-'0';150}151break;152default:153return false;154}155156result = val;157return true;158}159160// Parse only a float, and return as float bits.161static bool parseFloat(const char *str, int len, uint32_t &result)162{163bool foundDecimal = false;164for (int i = 0; i < len; ++i)165{166if (str[i] == '.')167{168if (foundDecimal)169return false;170foundDecimal = true;171continue;172}173if (str[i] < '0' || str[i] > '9')174return false;175}176177float f = (float)atof(str);178memcpy(&result, &f, sizeof(result));179return foundDecimal;180}181182ExpressionOpcodeType getExpressionOpcode(const char* str, int& ReturnLen, ExpressionOpcodeType LastOpcode)183{184int longestlen = 0;185ExpressionOpcodeType result = EXOP_NONE;186187for (int i = 0; i < EXOP_NUMBER; i++)188{189if (ExpressionOpcodes[i].sign == true &&190(LastOpcode == EXOP_NUMBER || LastOpcode == EXOP_BRACKETR)) continue;191192int len = ExpressionOpcodes[i].len;193if (len > longestlen)194{195if (strncmp(ExpressionOpcodes[i].Name,str,len) == 0)196{197result = (ExpressionOpcodeType) i;198longestlen = len;199}200}201}202203ReturnLen = longestlen;204return result;205}206207bool isAlphaNum(char c)208{209if ((c >= '0' && c <= '9') ||210(c >= 'A' && c <= 'Z') ||211(c >= 'a' && c <= 'z') ||212c == '@' || c == '_' || c == '$' || c == '.')213{214return true;215} else {216return false;217}218}219220bool initPostfixExpression(const char* infix, IExpressionFunctions* funcs, PostfixExpression& dest)221{222expressionError.clear();223224int infixPos = 0;225int infixLen = (int)strlen(infix);226ExpressionOpcodeType lastOpcode = EXOP_NONE;227std::vector<ExpressionOpcodeType> opcodeStack;228dest.clear();229230while (infixPos < infixLen)231{232char first = tolower(infix[infixPos]);233char subStr[256];234int subPos = 0;235236if (first == ' ' || first == '\t')237{238infixPos++;239continue;240}241242if (first >= '0' && first <= '9')243{244while (isAlphaNum(infix[infixPos]))245{246subStr[subPos++] = infix[infixPos++];247}248subStr[subPos] = 0;249250uint32_t value;251bool isFloat = false;252if (parseFloat(subStr,subPos,value) == true)253isFloat = true;254else if (parseNumber(subStr,16,subPos,value) == false)255{256expressionError = StringFromFormat("Invalid number \"%s\"", subStr);257return false;258}259260dest.emplace_back(isFloat?EXCOMM_CONST_FLOAT:EXCOMM_CONST,value);261lastOpcode = EXOP_NUMBER;262} else if ((first >= 'a' && first <= 'z') || first == '@')263{264while (isAlphaNum(infix[infixPos]))265{266subStr[subPos++] = infix[infixPos++];267}268subStr[subPos] = 0;269270uint32_t value;271if (funcs->parseReference(subStr,value) == true)272{273dest.emplace_back(EXCOMM_REF,value);274lastOpcode = EXOP_NUMBER;275continue;276}277278if (funcs->parseSymbol(subStr,value) == true)279{280dest.emplace_back(EXCOMM_CONST,value);281lastOpcode = EXOP_NUMBER;282continue;283}284285expressionError = StringFromFormat("Invalid symbol \"%s\"", subStr);286return false;287} else {288int len;289ExpressionOpcodeType type = getExpressionOpcode(&infix[infixPos],len,lastOpcode);290if (type == EXOP_NONE)291{292expressionError = StringFromFormat("Invalid operator at \"%s\"", &infix[infixPos]);293return false;294}295296switch (type)297{298case EXOP_BRACKETL:299case EXOP_MEML:300opcodeStack.push_back(type);301break;302case EXOP_BRACKETR:303while (true)304{305if (opcodeStack.empty())306{307expressionError = "Closing parenthesis without opening one";308return false;309}310ExpressionOpcodeType t = opcodeStack[opcodeStack.size()-1];311opcodeStack.pop_back();312if (t == EXOP_BRACKETL) break;313dest.emplace_back(EXCOMM_OP,t);314}315break;316case EXOP_MEMR:317while (true)318{319if (opcodeStack.empty())320{321expressionError = "Closing bracket without opening one";322return false;323}324ExpressionOpcodeType t = opcodeStack[opcodeStack.size()-1];325opcodeStack.pop_back();326if (t == EXOP_MEML)327{328dest.emplace_back(EXCOMM_OP,EXOP_MEM);329break;330}331dest.emplace_back(EXCOMM_OP,t);332}333type = EXOP_NUMBER;334break;335default:336if (opcodeStack.empty() == false)337{338int CurrentPriority = ExpressionOpcodes[type].Priority;339while (!opcodeStack.empty())340{341ExpressionOpcodeType t = opcodeStack[opcodeStack.size()-1];342opcodeStack.pop_back();343344if (t == EXOP_BRACKETL || t == EXOP_MEML)345{346opcodeStack.push_back(t);347break;348}349350if (ExpressionOpcodes[t].Priority >= CurrentPriority)351{352dest.emplace_back(EXCOMM_OP,t);353} else {354opcodeStack.push_back(t);355break;356}357}358}359opcodeStack.push_back(type);360break;361}362infixPos += len;363lastOpcode = type;364}365}366367while (!opcodeStack.empty())368{369ExpressionOpcodeType t = opcodeStack[opcodeStack.size()-1];370opcodeStack.pop_back();371372if (t == EXOP_BRACKETL) // opening bracket without closing one373{374expressionError = "Parenthesis not closed";375return false;376}377dest.emplace_back(EXCOMM_OP,t);378}379380#if 0 // only for testing381char test[1024];382int testPos = 0;383for (int i = 0; i < dest.size(); i++)384{385switch (dest[i].first)386{387case EXCOMM_CONST:388case EXCOMM_CONST_FLOAT:389testPos += snprintf(&test[testPos], sizeof(test) - testPos, "0x%04X ", dest[i].second);390break;391case EXCOMM_REF:392testPos += snprintf(&test[testPos], sizeof(test) - testPos, "r%d ", dest[i].second);393break;394case EXCOMM_OP:395testPos += snprintf(&test[testPos], sizeof(test) - testPos, "%s ", ExpressionOpcodes[dest[i].second].Name);396break;397};398}399#endif400401return true;402}403404bool parsePostfixExpression(PostfixExpression& exp, IExpressionFunctions* funcs, uint32_t& dest)405{406size_t num = 0;407uint32_t opcode;408std::vector<uint32_t> valueStack;409unsigned int arg[5]{};410float fArg[5]{};411bool useFloat = false;412413while (num < exp.size())414{415switch (exp[num].first)416{417case EXCOMM_CONST: // konstante zahl418valueStack.push_back(exp[num++].second);419break;420case EXCOMM_CONST_FLOAT:421useFloat = true;422valueStack.push_back(exp[num++].second);423break;424case EXCOMM_REF:425useFloat = useFloat || funcs->getReferenceType(exp[num].second) == EXPR_TYPE_FLOAT;426opcode = funcs->getReferenceValue(exp[num++].second);427valueStack.push_back(opcode);428break;429case EXCOMM_OP: // opcode430opcode = exp[num++].second;431if (valueStack.size() < ExpressionOpcodes[opcode].args)432{433expressionError = "Not enough arguments";434return false;435}436for (int l = 0; l < ExpressionOpcodes[opcode].args; l++)437{438arg[l] = valueStack[valueStack.size()-1];439valueStack.pop_back();440}441// In case of float representation.442memcpy(fArg, arg, sizeof(fArg));443444switch (opcode)445{446case EXOP_MEMSIZE: // must be followed by EXOP_MEM447if (exp[num++].second != EXOP_MEM)448{449expressionError = "Invalid memsize operator";450return false;451}452453uint32_t val;454if (funcs->getMemoryValue(arg[1], arg[0], val, &expressionError) == false)455{456return false;457}458valueStack.push_back(val);459break;460case EXOP_MEM:461{462uint32_t val;463if (funcs->getMemoryValue(arg[0], 4, val, &expressionError) == false)464{465return false;466}467valueStack.push_back(val);468}469break;470case EXOP_SIGNPLUS: // keine aktion nötig471break;472case EXOP_SIGNMINUS: // -0473if (useFloat)474valueStack.push_back((uint32_t)(0.0f - fArg[0]));475else476valueStack.push_back(0-arg[0]);477break;478case EXOP_BITNOT: // ~b479valueStack.push_back(~arg[0]);480break;481case EXOP_LOGNOT: // !b482valueStack.push_back(!(arg[0] != 0));483break;484case EXOP_MUL: // a*b485if (useFloat)486valueStack.push_back((uint32_t)(fArg[1] * fArg[0]));487else488valueStack.push_back(arg[1]*arg[0]);489break;490case EXOP_DIV: // a/b491if (arg[0] == 0)492{493expressionError = "Division by zero";494return false;495}496if (useFloat)497valueStack.push_back((uint32_t)(fArg[1] / fArg[0]));498else499valueStack.push_back(arg[1]/arg[0]);500break;501case EXOP_MOD: // a%b502if (arg[0] == 0)503{504expressionError = "Modulo by zero";505return false;506}507valueStack.push_back(arg[1]%arg[0]);508break;509case EXOP_ADD: // a+b510if (useFloat)511valueStack.push_back((uint32_t)(fArg[1] + fArg[0]));512else513valueStack.push_back(arg[1]+arg[0]);514break;515case EXOP_SUB: // a-b516if (useFloat)517valueStack.push_back((uint32_t)(fArg[1] - fArg[0]));518else519valueStack.push_back(arg[1]-arg[0]);520break;521case EXOP_SHL: // a<<b522valueStack.push_back(arg[1]<<arg[0]);523break;524case EXOP_SHR: // a>>b525valueStack.push_back(arg[1]>>arg[0]);526break;527case EXOP_GREATEREQUAL: // a >= b528if (useFloat)529valueStack.push_back(fArg[1]>=fArg[0]);530else531valueStack.push_back(arg[1]>=arg[0]);532break;533case EXOP_GREATER: // a > b534if (useFloat)535valueStack.push_back(fArg[1]>fArg[0]);536else537valueStack.push_back(arg[1]>arg[0]);538break;539case EXOP_LOWEREQUAL: // a <= b540if (useFloat)541valueStack.push_back(fArg[1]<=fArg[0]);542else543valueStack.push_back(arg[1]<=arg[0]);544break;545case EXOP_LOWER: // a < b546if (useFloat)547valueStack.push_back(fArg[1]<fArg[0]);548else549valueStack.push_back(arg[1]<arg[0]);550break;551case EXOP_EQUAL: // a == b552valueStack.push_back(arg[1]==arg[0]);553break;554case EXOP_NOTEQUAL: // a != b555valueStack.push_back(arg[1]!=arg[0]);556break;557case EXOP_BITAND: // a&b558valueStack.push_back(arg[1]&arg[0]);559break;560case EXOP_XOR: // a^b561valueStack.push_back(arg[1]^arg[0]);562break;563case EXOP_BITOR: // a|b564valueStack.push_back(arg[1]|arg[0]);565break;566case EXOP_LOGAND: // a && b567valueStack.push_back(arg[1]&&arg[0]);568break;569case EXOP_LOGOR: // a || b570valueStack.push_back(arg[1]||arg[0]);571break;572case EXOP_TERTIF: // darf so nicht vorkommen573return false;574case EXOP_TERTELSE: // exp ? exp : exp, else muss zuerst kommen!575if (exp[num++].second != EXOP_TERTIF)576{577expressionError = "Invalid tertiary operator";578return false;579}580valueStack.push_back(arg[2]?arg[1]:arg[0]);581break;582}583break;584}585}586587if (valueStack.size() != 1) return false;588dest = valueStack[0];589return true;590}591592bool parseExpression(const char *exp, IExpressionFunctions *funcs, uint32_t &dest) {593PostfixExpression postfix;594if (initPostfixExpression(exp,funcs,postfix) == false) return false;595return parsePostfixExpression(postfix,funcs,dest);596}597598const char *getExpressionError()599{600if (expressionError.empty())601expressionError = "Invalid expression";602return expressionError.c_str();603}604605606