Arithmetic Expression EvaluatorLoading saved progress…

Arithmetic Expression Evaluator

An arithmetic expression evaluator turns a math string like "2 + 3 * 4" into the number it represents — 14, not 20 — by honoring operator precedence and parentheses the way a pocket calculator does. You will write arithmeticExpressionEvaluator(expression), which tokenizes the string, parses it, and returns the result as a number. No eval and no new Function: the whole point is to build the parser yourself.

Signature

arithmeticExpressionEvaluator(expression: string): number

Examples

arithmeticExpressionEvaluator('2 + 3 * 4');   // 14  — '*' binds tighter than '+'
arithmeticExpressionEvaluator('(2 + 3) * 4'); // 20  — parentheses override that
arithmeticExpressionEvaluator('10 - 3 - 2');  // 5   — left to right, not 9
arithmeticExpressionEvaluator('10 / 4');      // 2.5 — real division
arithmeticExpressionEvaluator('3 * -2');   // -6  — unary minus
arithmeticExpressionEvaluator('-(2 + 3)'); // -5  — unary minus on a group
arithmeticExpressionEvaluator('1 +');      // throws — dangling operator
arithmeticExpressionEvaluator('(1 + 2');   // throws — unbalanced parenthesis

Notes

  • Numbers — support integers and decimals (3, 3.5). A result can be non-integer: 10 / 4 is 2.5, not 2.
  • Precedence and associativity* and / bind tighter than + and -, and equal-precedence operators are left-associative, so 8 - 3 - 2 is 3, not 7.
  • Parentheses — group sub-expressions and can nest to any depth. (2 + 3) * 4 is 20.
  • Unary minus — a leading - may negate a value or a whole group: -5, 3 * -2, -(2 + 3), and 2 - -3 all work.
  • Whitespace — any amount between tokens is ignored; 2+3 and 2 + 3 mean the same thing.
  • Malformed input — throw an Error for unbalanced parentheses, a leading or trailing operator with no operand, an empty string, or an unexpected character, so abc and 2 ** 3 both throw. Division by zero is not malformed: it follows JavaScript and yields Infinity.
  • Do not worry about — exponentiation (**), modulo (%), variables, named functions like sqrt, or scientific notation. The four basic operators plus parentheses are the whole surface.

FAQ

How do you make multiplication and division bind tighter than addition and subtraction?
Use one parse function per precedence level: parseExpression joins terms with + and -, and each term joins factors with * and /. Because parseExpression calls parseTerm calls parseFactor, a multiplication is always folded into a single value before an addition can use it, so 2 + 3 * 4 is 14, not 20.
Why is unary minus handled at the factor level?
Unary minus must bind tighter than binary + and -, or -2 + 3 would parse as -(2 + 3) and give -5 instead of 1. Placing it in parseFactor, the innermost rule, makes the minus negate only the immediate factor, and it still nests so 3 * -2 and -(2 + 3) both work.
What does the evaluator do on division by zero?
It mirrors JavaScript: 1 / 0 returns Infinity and 0 / 0 returns NaN, because a well-formed expression that divides by zero has a defined IEEE-754 result. Only malformed input — unbalanced parentheses, a dangling operator, an empty string, or an unexpected character — throws an Error.
Loading editor…