The String Calculator is a robust C++ program designed to evaluate mathematical expressions entered as a string by the user. It handles a wide variety of arithmetic operations, trigonometric functions, and parentheses with operator precedence. This program demonstrates advanced programming concepts such as tokenization, operator precedence parsing, stack-based evaluation, and function handling.
- Basic Arithmetic Operations: Supports addition (
+), subtraction (-), multiplication (*), division (/), and exponentiation (^). - Trigonometric Functions: Includes support for functions such as
sin,cos, andtan. - Additional Mathematical Functions:
sqrt: Square rootlog: Natural logarithmabs: Absolute value
- Constants:
PI(3.14159...)E(2.71828...)
- Parentheses: Supports nested parentheses to enforce specific evaluation orders.
- Operator Precedence: Correctly evaluates operations according to standard precedence rules (e.g., multiplication and division before addition and subtraction).
- Error Handling: Comprehensive error handling for invalid tokens, mismatched parentheses, division by zero, and domain errors.
-
Tokenization:
- The input string is first broken into tokens (numbers, operators, parentheses, and functions).
- Example: The input
2+2*2is tokenized as:Token 1: Number (2) Token 2: Operator (+) Token 3: Number (2) Token 4: Operator (*) Token 5: Number (2)
-
Shunting-Yard Algorithm:
- Operators and functions are pushed onto a stack, respecting precedence and associativity rules.
- Parentheses are handled to allow nested expressions.
-
Evaluation:
- The program uses two stacks:
- A values stack to store numbers.
- An operators stack to store operators and functions.
- Operators are applied to operands as they are popped from the stacks, and the result is pushed back onto the values stack.
- The program uses two stacks:
-
Output:
- After all tokens are processed, the result is printed to the console.
To compile the program, ensure you have a C++20-compliant compiler such as g++. Use the following command:
g++ -std=c++20 StringCalculator.cpp -o StringCalculatorRun the compiled program:
./StringCalculatorThe program will prompt you to enter a mathematical expression. For example:
Enter a mathematical expression:
2+2*2
Result: 6.0000000
- Numbers: Enter numbers using standard decimal notation (e.g.,
2,3.14). - Operators: Use the following symbols:
+for addition-for subtraction*for multiplication/for division^for exponentiation
- Functions: Enter supported functions with parentheses. Examples:
sin(PI/2)sqrt(16)log(E)
- Parentheses: Use
(and)to group expressions.
| Expression | Expected Output |
|---|---|
2+2*2 |
6.0000000 |
(2+2)*2 |
8.0000000 |
2^3+5 |
13.0000000 |
| Expression | Expected Output |
|---|---|
sin(PI/2) |
1.0000000 |
cos(0) |
1.0000000 |
tan(PI/4) |
1.0000000 |
| Expression | Expected Output |
|---|---|
(2+3)*(5-1) |
20.0000000 |
sqrt(16)+log(E) |
5.0000000 |
| Input | Error Message |
|---|---|
2++2 |
Error: Unknown token: + |
(2+2 |
Error: Mismatched parentheses. |
log(-1) |
Error: Logarithm domain error. |
1/0 |
Error: Division by zero. |
The tokenize function splits the input string into valid tokens such as numbers, operators, and parentheses.
std::vector<Token> tokenize(const std::string& expression) {
std::vector<Token> tokens;
std::string current;
for (size_t i = 0; i < expression.size(); ++i) {
char c = expression[i];
if (std::isspace(c)) continue;
if (std::isdigit(c) || c == '.') {
current += c;
if (i == expression.size() - 1 || !std::isdigit(expression[i + 1]) && expression[i + 1] != '.') {
tokens.push_back({TokenType::Number, current});
current.clear();
}
} else if (std::isalpha(c)) {
current += c;
if (i == expression.size() - 1 || !std::isalpha(expression[i + 1])) {
tokens.push_back({TokenType::Function, current});
current.clear();
}
} else if (c == '(' || c == ')') {
tokens.push_back({TokenType::Parenthesis, std::string(1, c)});
} else if (precedence_.count(std::string(1, c))) {
tokens.push_back({TokenType::Operator, std::string(1, c)});
} else {
throw std::runtime_error(std::string("Invalid character: ") + c);
}
}
return tokens;
}The program respects operator precedence using the precedence_ map:
std::unordered_map<std::string, int> precedence_ = {
{"+", 1}, {"-", 1},
{"*", 2}, {"/", 2},
{"^", 3}
};The program provides comprehensive error handling for:
- Invalid tokens
- Division by zero
- Mismatched parentheses
- Invalid function arguments (e.g.,
sqrt(-1))
- Extended Functionality:
- Add support for hyperbolic functions (e.g.,
sinh,cosh). - Include additional constants like
πandefor easy reference.
- Add support for hyperbolic functions (e.g.,
- Variable Assignment:
- Enable users to define variables (e.g.,
x = 5) for reuse in expressions.
- Enable users to define variables (e.g.,
- Graphical Interface:
- Provide a GUI for entering and visualizing expressions.
Contributions are welcome! Feel free to fork this repository and submit pull requests.
This project is open-source and licensed under the MIT License. See the LICENSE file for details.
Developed by Vladislav Cernega.