Expression Evaluator with Recursive Descent Parser
Build a calculator in C++ that understands full expressions like 2 + 3 * (4 - 1) / x, with the right order of operations, parentheses and variables (x = 5). Instead of evaluating text directly, it works like a real compiler in miniature: a tokenizer splits the input into numbers, operators and names, a recursive descent parser builds a tree of the expression (an abstract syntax tree, or AST), and an evaluator walks the tree to compute the answer. Errors point to the exact position of the problem. It's a classic, rewarding project: you'll learn how parsers work, grammars and operator precedence, recursion, trees with smart pointers, and error handling with exceptions.
- Estimate
- ~9.5h
- Steps
- 6
- Completed by
- 0
- Proposed by
- codeseed.app
Standard Library (STL)
Project roadmap
- 01
Write the tokenizer
~1.5hDefine a Token struct with a type (number, name, plus, minus, star, slash, caret, left and right parenthesis, equals, end) and its position in the input. Write a tokenizer that skips spaces, reads numbers (including decimals such as 3.14) and names, and throws an error with the position for unknown characters. Done when: unit tests show 2*(x+3.5) becomes the right list of tokens.
- 02
Define the tree nodes
~1hDefine AST node types: Number, Variable, Unary (negation), Binary (an operator with left and right children) and Assign, with an abstract Node class and std::unique_ptr for children, so memory is freed automatically. Add a to_string method that prints a node fully parenthesized, useful for checking the tree. Done when: you can build a small tree by hand and print it.
- 03
Write the recursive descent parser
~2.5hWrite down the grammar first: expression = term { (+|-) term }, term = power { (*|/) power }, power = unary [ ^ power ] (right-associative), unary = - unary | primary, primary = number | name | ( expression ). Write one function per rule that builds nodes, plus assignment (name = expression) at the top. Report errors such as a missing ) with the position. Done when: 2+3*4 parses as 2+(3*4), and 2^3^2 as 2^(3^2).
- 04
Evaluate the tree
~1.5hWrite an evaluate function (a virtual method or a visitor) that computes each node's value recursively. Throw clear errors for division by zero and unknown variables. Done when: evaluating test expressions gives the correct results, and 1/0 gives a clear error.
- 05
Add variables and a prompt
~1.5hKeep variables in a std::unordered_map (a symbol table). Assignments store a value and print it; later expressions can use it. Build a prompt loop that reads lines, prints results or errors (with a ^ marker under the error position), and supports commands such as vars and quit. Done when: x = 5 followed by 2 * x prints 10, and errors show where the problem is.
- 06
Test it
~1.5hWrite tests (with a small framework such as doctest, or plain assert) for tokenizing, precedence and associativity, parentheses, unary minus (such as -2^2), variables, and errors (unbalanced parentheses, a trailing operator, unknown variables, and division by zero). Done when: all tests pass.
Ready to build this?
Get a GitHub repo and start building. Your AI reviewer checks each step as you go.
Tech stack