Skip to content

razkar-studio/quickeval-cpp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

quickeval-cpp

quickeval-cpp is a C++ header and cpp tool, using the eval() function that takes a string to mimic python's eval() function.

QuickEval (as Calculator)

A mathematical expression evaluator built from scratch in C++, featuring custom lexer, parser, and interpreter.

Overview

This calculator processes mathematical expressions through three distinct phases:

  • Lexing: Tokenizes the input string into meaningful components
  • Parsing: Handles operator precedence and parentheses evaluation
  • Interpreting: Computes the final result

No external libraries. No shortcuts. Just pure C++ implementation.

Documentation

API Reference

double eval(string input)

The main entry point. Evaluates a mathematical expression and returns the result.

double result = eval("2 + 3 * 4");  // Returns 14.0

vector<string> lex(string input)

Tokenizes the input string into individual components (numbers, operators, parentheses).

vector<string> tokens = lex("2 + 3");  // Returns ["2", "+", "3"]

vector<string> parse(vector<string> tokens)

Processes tokens to handle operator precedence and evaluates parentheses recursively.

vector<string> parsed = parse({"2", "+", "3", "*", "4"});  // Returns ["2", "+", "12"]

double interpret(vector<string> tokens)

Evaluates the parsed tokens from left to right, computing the final result.

double result = interpret({"2", "+", "12"});  // Returns 14.0

double evaluate(string a, string op, string b)

Helper function that performs basic arithmetic on two operands.

double result = evaluate("5", "*", "3");  // Returns 15.0

Supported Operations

Operator Description Example Result
+ Addition 5 + 3 8
- Subtraction 5 - 3 2
* Multiplication 5 * 3 15
/ Division 6 / 3 2
() Parentheses (2 + 3) * 4 20

Usage

As a standalone program:

g++ main.cpp calculator.cpp -o calculator
./calculator

As a library:

#include "calculator.h"

int main() {
    double result = eval("(1 + 2) * 3");
    cout << result << endl;  // Outputs: 9
    return 0;
}

Understanding How It Works

This section breaks down the journey from text to result, perfect for learning how interpreters work.

The Big Picture

When you type 2 + 3 * 4, here's what happens:

Input String:  "2 + 3 * 4"
      ↓
   LEXER (lex)
      ↓
Tokens:  ["2", "+", "3", "*", "4"]
      ↓
   PARSER (parse)
      ↓
Parsed:  ["2", "+", "12"]
      ↓
   INTERPRETER (interpret)
      ↓
Result:  14.0

Phase 1: Lexing (Tokenization)

What it does: Breaks the input string into meaningful pieces called "tokens".

Why we need it: Computers can't understand "2+3" as math - they just see characters. We need to identify what's a number, what's an operator, and what's a parenthesis.

Example:

Input:  "2 + 3 * 4"
Output: ["2", "+", "3", "*", "4"]

Input:  "(10 + 5) / 3"
Output: ["(", "10", "+", "5", ")", "/", "3"]

How it works:

The lexer reads the input character by character:

  • If it sees a digit or decimal point → part of a number
  • If it sees a space → separator (ignore it)
  • If it sees +, -, *, / → operator token
  • If it sees ( or ) → parenthesis token
// Simplified logic:
for (char c : input) {
    if (isdigit(c) || c == '.') {
        // Build up a number
        current += c;
    }
    else if (c == '+' || c == '-' || c == '*' || c == '/') {
        // Save the number, then save the operator
        tokens.push_back(current);
        tokens.push_back(string(1, c));
    }
}

Phase 2: Parsing (Understanding Structure)

What it does: Figures out the order of operations and handles parentheses.

Why we need it: Math has rules! 2 + 3 * 4 should be 2 + 12 = 14, not 5 * 4 = 20. Multiplication comes before addition.

Example:

Input:  ["2", "+", "3", "*", "4"]
Step 1: Handle * first → "3 * 4" = "12"
Output: ["2", "+", "12"]

Input:  ["(", "2", "+", "3", ")", "*", "4"]
Step 1: Evaluate parentheses → "(2 + 3)" = "5"
Step 2: Now we have ["5", "*", "4"]
Output: ["20"]

How it works:

Step 1: Handle Parentheses When we find (, we locate its matching ), extract everything inside, and recursively parse and evaluate it. Replace the entire parenthetical expression with its result.

// Find: ["(", "2", "+", "3", ")", "*", "4"]
// Extract: ["2", "+", "3"]
// Evaluate recursively: 5
// Replace: ["5", "*", "4"]

Step 2: Handle Multiplication and Division After parentheses are gone, scan through and immediately evaluate any * or / operations.

// Find: ["2", "+", "3", "*", "4"]
// See *: evaluate "3 * 4" = 12
// Replace: ["2", "+", "12"]

Now only addition and subtraction remain (left to right).

Phase 3: Interpreting (Computing the Answer)

What it does: Takes the simplified tokens and calculates the final result.

Why we need it: After parsing, we're left with simple left-to-right operations. Time to actually do the math!

Example:

Input:  ["2", "+", "12"]
Step 1: Start with 2
Step 2: See "+", add 12 → 2 + 12 = 14
Output: 14.0

How it works:

Start with the first number, then repeatedly:

  1. Read an operator (+, -, *, /)
  2. Read the next number
  3. Perform that operation
  4. Continue with the result
result = 2        // Start
result = 2 + 12   // Apply "+" with 12
result = 14       // Done!

Putting It All Together

Let's trace through a complex example: (1 + (2 * 3)) * ((4 + 5) / 3) - 2

Step 1: Lexing

"(1 + (2 * 3)) * ((4 + 5) / 3) - 2"
↓
["(", "1", "+", "(", "2", "*", "3", ")", ")", "*", "(", "(", "4", "+", "5", ")", "/", "3", ")", "-", "2"]

Step 2: Parsing (innermost parentheses first)

Round 1: Evaluate (2 * 3)

["(", "1", "+", "(", "2", "*", "3", ")", ")", ...]
                  └─────────┘
                      ↓
                     "6"
["(", "1", "+", "6", ")", ...]

Round 2: Evaluate (1 + 6)

["(", "1", "+", "6", ")", ...]
 └──────────────────┘
          ↓
         "7"
["7", "*", "(", "(", "4", "+", "5", ")", "/", "3", ")", "-", "2"]

Round 3: Evaluate (4 + 5)

["7", "*", "(", "(", "4", "+", "5", ")", "/", "3", ")", "-", "2"]
                    └─────────┘
                         ↓
                        "9"
["7", "*", "(", "9", "/", "3", ")", "-", "2"]

Round 4: Evaluate (9 / 3)

["7", "*", "(", "9", "/", "3", ")", "-", "2"]
            └──────────────┘
                   ↓
                  "3"
["7", "*", "3", "-", "2"]

Round 5: Handle multiplication

["7", "*", "3", "-", "2"]
 └─────────┘
      ↓
    "21"
["21", "-", "2"]

Step 3: Interpreting

["21", "-", "2"]
↓
21 - 2 = 19

Final Result: 19

Key Concepts for Beginners

1. Recursion in Parsing

When we encounter parentheses, we don't try to solve them directly. Instead, we extract what's inside and say "figure this out first" (by calling parse again). This is recursion - a function calling itself.

2. Operator Precedence

Not all operators are equal:

  • Parentheses: highest priority (do these first)
  • Multiplication/Division: medium priority
  • Addition/Subtraction: lowest priority (do these last)

We handle this by processing in order: parentheses → then * and / → then + and -.

3. Left-to-Right Evaluation

Once we've handled precedence, operations of equal priority go left to right:

10 - 5 - 2  →  (10 - 5) - 2  →  5 - 2  →  3
NOT: 10 - (5 - 2)  →  10 - 3  →  7  ✗

4. State Machines

The lexer is a simple state machine - it's either:

  • Building a number
  • Just saw an operator
  • Just saw a parenthesis

This pattern (state machines) is everywhere in computer science.

Example

========CALCULATOR=======
This calculator is made in C++ and uses manual processing with lexing, parsing, and interpreting.
Made by Razka Rizaldi, tyydev1.
Evaluate: (1 + (2 * 3)) * ((4 + 5) / 3) - 2
Result: 19

Project Structure

calculator/
├── calculator.h      # Public API declarations
├── calculator.cpp    # Implementation of lexer, parser, interpreter
└── main.cpp          # CLI interface

Future Plans

  • Unary operators (-5, +3)
  • Exponentiation (2^3)
  • More mathematical functions (sin, cos, sqrt)
  • Variables and assignments (x = 5)

Author

Razka Rizaldi (tyydev1)

Built as a learning project to understand how interpreters work under the hood - no tutorials, just problem-solving and debugging.

License

Free to use for learning purposes. If you learn something from this, that's the best license there is.

About

quickeval-cpp is a C++ header and cpp tool, using the `eval()` function that takes a string to mimic python's `eval()` function.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages