TokenType ScannerContextBase::lookupToken(int start, int end, TokenMap map){ TokenType rangeTokenType = TokenType::None; string possibleToken = _scanner->range(start, end); TokenMap::const_iterator it = map.find(possibleToken); if(it != map.end()){ // found matching token rangeTokenType = it->second; } return rangeTokenType; };
TokenQueue_t calculator::toRPN(const char* expr, TokenMap vars, const char* delim, const char** rest, OppMap_t opPrecedence, rWordMap_t rWordMap) { rpnBuilder data(vars, opPrecedence); char* nextChar; static char c = '\0'; if (!delim) delim = &c; while (*expr && isspace(*expr) && !strchr(delim, *expr)) ++expr; if (*expr == '\0' || strchr(delim, *expr)) { throw std::invalid_argument("Cannot build a calculator from an empty expression!"); } // In one pass, ignore whitespace and parse the expression into RPN // using Dijkstra's Shunting-yard algorithm. while (*expr && (data.bracketLevel || !strchr(delim, *expr))) { if (isdigit(*expr)) { // If the token is a number, add it to the output queue. int64_t _int = strtol(expr, &nextChar, 10); // If the number was not a float: if (!strchr(".eE", *nextChar)) { data.handle_token(new Token<int64_t>(_int, INT)); } else { double digit = strtod(expr, &nextChar); data.handle_token(new Token<double>(digit, REAL)); } expr = nextChar; } else if (isvariablechar(*expr)) { rWordMap_t::iterator it; // If the token is a variable, resolve it and // add the parsed number to the output queue. std::stringstream ss; ss << *expr; ++expr; while (isvariablechar(*expr) || isdigit(*expr)) { ss << *expr; ++expr; } std::string key = ss.str(); if (data.lastTokenWasOp == '.') { data.handle_token(new Token<std::string>(key, STR)); } else if ((it=rWordMap.find(key)) != rWordMap.end()) { // Parse reserved words: try { it->second(expr, &expr, &data); } catch (...) { rpnBuilder::cleanRPN(&data.rpn); throw; } } else { packToken* value = vars.find(key); if (value) { // Save a reference token: TokenBase* copy = (*value)->clone(); data.handle_token(new RefToken(key, copy)); } else { // Save the variable name: data.handle_token(new Token<std::string>(key, VAR)); } } } else if (*expr == '\'' || *expr == '"') { // If it is a string literal, parse it and // add to the output queue. char quote = *expr; ++expr; std::stringstream ss; while (*expr && *expr != quote && *expr != '\n') { if (*expr == '\\') { switch (expr[1]) { case 'n': expr+=2; ss << '\n'; break; case 't': expr+=2; ss << '\t'; break; default: if (strchr("\"'\n", expr[1])) ++expr; ss << *expr; ++expr; } } else { ss << *expr; ++expr; } } if (*expr != quote) { std::string squote = (quote == '"' ? "\"": "'"); rpnBuilder::cleanRPN(&data.rpn); throw syntax_error("Expected quote (" + squote + ") at end of string declaration: " + squote + ss.str() + "."); } ++expr; data.handle_token(new Token<std::string>(ss.str(), STR)); } else { // Otherwise, the variable is an operator or paranthesis. // Check for syntax errors (excess of operators i.e. 10 + + -1): if (data.lastTokenWasUnary) { std::string op; op.push_back(*expr); rpnBuilder::cleanRPN(&data.rpn); throw syntax_error("Expected operand after unary operator `" + data.opStack.top() + "` but found: `" + op + "` instead."); } switch (*expr) { case '(': // If it is a function call: if (data.lastTokenWasOp == false) { // This counts as a bracket and as an operator: data.handle_op("()"); // Add it as a bracket to the op stack: } data.open_bracket("("); ++expr; break; case '[': if (data.lastTokenWasOp == false) { // If it is an operator: data.handle_op("[]"); } else { // If it is the list constructor: // Add the list constructor to the rpn: data.handle_token(new CppFunction(&TokenList::default_constructor, "list")); // We make the program see it as a normal function call: data.handle_op("()"); } // Add it as a bracket to the op stack: data.open_bracket("["); ++expr; break; case '{': // Add a map constructor call to the rpn: data.handle_token(new CppFunction(&TokenMap::default_constructor, "map")); // We make the program see it as a normal function call: data.handle_op("()"); data.open_bracket("{"); ++expr; break; case ')': data.close_bracket("("); ++expr; break; case ']': data.close_bracket("["); ++expr; break; case '}': data.close_bracket("{"); ++expr; break; default: { // Then the token is an operator std::stringstream ss; ss << *expr; ++expr; while (*expr && ispunct(*expr) && !strchr("+-'\"()_", *expr)) { ss << *expr; ++expr; } std::string op = ss.str(); rWordMap_t::iterator it; if ((it=rWordMap.find(op)) != rWordMap.end()) { // Parse reserved operators: try { it->second(expr, &expr, &data); } catch (...) { rpnBuilder::cleanRPN(&data.rpn); throw; } } else { data.handle_op(op); } } } } // Ignore spaces but stop on delimiter if not inside brackets. while (*expr && isspace(*expr) && (data.bracketLevel || !strchr(delim, *expr))) ++expr; } // Check for syntax errors (excess of operators i.e. 10 + + -1): if (data.lastTokenWasUnary) { rpnBuilder::cleanRPN(&data.rpn); throw syntax_error("Expected operand after unary operator `" + data.opStack.top() + "`"); } while (!data.opStack.empty()) { data.rpn.push(new Token<std::string>(data.opStack.top(), OP)); data.opStack.pop(); } // In case one of the custom parsers left an empty expression: if (data.rpn.size() == 0) data.rpn.push(new TokenNone()); if (rest) *rest = expr; return data.rpn; }