I am trying to write a simple tokenizer for a basic arithmetic calculator. Here's the code:
// Example program
#include <iostream>
#include <regex>
#include <string>
#include <vector>
#include <map>
#include <utility>
std::string operandRegex = "^(-?)(0|([1-9][0-9]*))(\\.[0-9]+)?";
enum Operator { ADD = 0, SUBTRACT = 1, MULTIPLY = 2, DIVIDE = 3 };
static const std::map<std::string, enum Operator> operatorRegexMap = {
std::make_pair("^\\+", Operator::ADD),
std::make_pair("^\\-", Operator::SUBTRACT),
std::make_pair("^\\*", Operator::MULTIPLY),
std::make_pair("^/", Operator::DIVIDE),
};
std::vector<std::string> tokenize(const std::string &expression) {
std::vector<std::string> result;
std::string::const_iterator searchStart(expression.cbegin());
while (searchStart != expression.cend()) {
std::regex re = std::regex{operandRegex};
std::smatch match;
// Operand
if (regex_search(searchStart, expression.cend(), match, re)) {
searchStart = match.suffix().first;
result.push_back(match.str(0));
} else {
// Operator
bool noMatch = true;
for (const auto &re_op : operatorRegexMap) {
std::regex re = std::regex{re_op.first};
if (regex_search(searchStart, expression.cend(), match, re)) {
searchStart = match.suffix().first;
result.push_back(match.str(0));
noMatch = false;
break;
}
}
if (noMatch) {
break;
}
}
}
return result;
}
void print(const std::vector<std::string> &tokens) {
for (const auto &token : tokens) {
std::cout << token << std::endl;
}
}
int main() {
std::string expression;
std::cout << "Input Expression: ";
std::getline(std::cin, expression);
std::vector<std::string> tokens = tokenize(expression);
std::cout << "Parsed: " << std::endl;
print(tokens);
return 0;
}
I am getting issue with associativity of operator vs operand:
Input Expression: 2-3+5
Parsed:
2
-3
+
5
These are unary operators, and I could fix it. But what if I wanted to experiment with more complex operators, say, pow()
function or integral(function, low, high)
.
How do I change the code to make it into a better design, with emphasis on SOLID principles?