Expression Evaluator in JavaScript
This challenge asks you to implement a function that evaluates mathematical expressions provided as strings. Expression evaluators are fundamental components in many applications, from scripting languages to calculators, and understanding their implementation provides valuable insight into parsing and computation. Your goal is to create a robust and accurate evaluator capable of handling basic arithmetic operations.
Problem Description
You need to implement a JavaScript function called evaluateExpression that takes a string representing a mathematical expression as input and returns the numerical result of evaluating that expression. The expression will consist of integers, the operators +, -, *, and /, and parentheses. The function should adhere to standard operator precedence (PEMDAS/BODMAS) and handle parentheses correctly.
Key Requirements:
- Operator Precedence: Multiplication and division should be performed before addition and subtraction.
- Parentheses: Parenthesized sub-expressions should be evaluated first.
- Integer Arithmetic: The expressions will only contain integers.
- Division by Zero: The function should handle division by zero gracefully, returning
NaN(Not a Number) in such cases. - Whitespace: Ignore any whitespace in the input string.
Expected Behavior:
The function should parse the expression string, perform the necessary calculations according to operator precedence and parentheses, and return the final numerical result.
Edge Cases to Consider:
- Empty input string.
- Invalid characters in the input string (other than integers, operators, parentheses, and whitespace).
- Nested parentheses.
- Multiple consecutive operators (e.g.,
2++3). While not strictly required to handle these gracefully (e.g., throwing an error), your solution should not crash or produce incorrect results due to them. - Expressions starting or ending with operators or parentheses.
Examples
Example 1:
Input: "2 + 3 * 4"
Output: 14
Explanation: Multiplication is performed before addition: (3 * 4) + 2 = 14
Example 2:
Input: "(2 + 3) * 4"
Output: 20
Explanation: The parentheses are evaluated first: (2 + 3) * 4 = 5 * 4 = 20
Example 3:
Input: "10 / 2 - 3"
Output: 2
Explanation: Division is performed before subtraction: (10 / 2) - 3 = 5 - 3 = 2
Example 4:
Input: "10 / (2 - 3)"
Output: -10
Explanation: Parentheses are evaluated first: 10 / (2 - 3) = 10 / -1 = -10
Example 5:
Input: "5 + 5 / (2 * (3 - 1))"
Output: 7
Explanation: Nested parentheses and operator precedence: 5 + 5 / (2 * 2) = 5 + 5 / 4 = 5 + 1.25 = 6.25 (Note: the prompt specifies integer arithmetic, so the result should be 6, as the division is truncated)
Example 6:
Input: "10 / 0"
Output: NaN
Explanation: Division by zero results in NaN.
Constraints
- The input string will have a length between 1 and 100 characters.
- The input string will only contain integers (0-9), the operators
+,-,*,/, parentheses(,), and whitespace. - The expression will be syntactically valid (though not necessarily well-formed in terms of consecutive operators).
- The function should return a number.
- Performance: The function should evaluate expressions in a reasonable time (within a few hundred milliseconds for typical expressions).
Notes
Consider using a stack-based approach to handle operator precedence and parentheses. You might want to break down the problem into smaller, manageable functions, such as a function to tokenize the expression string and a function to perform the actual evaluation. Remember to handle potential errors gracefully, especially division by zero. Integer division should truncate towards zero.