Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/theiskaa/mate

A simple and lightweight arithmetic expression interpreter
https://github.com/theiskaa/mate

interpreter math parser

Last synced: about 2 months ago
JSON representation

A simple and lightweight arithmetic expression interpreter

Awesome Lists containing this project

README

        


Package Logo



License: MIT

Mate is a library designed for parsing and calculating arithmetic expressions inputted as strings. It utilizes a Lexer structure, similar to those found in interpreted programming languages, to parse string input into a token list. The Calculator structure is then used to compute the final result from this token list. A general wrapper structure is also implemented that encapsulates both the Lexer and Calculator, simplifying the process of calculating arithmetic expression results without the need for manual parsing and calculation.

**Note**: This project serves as a demonstration and is not intended for production use. It represents my initial steps in learning to create a programming language.

# Usage

This crate is available on [crates.io](http://crates.io/crates/mate-rs) and can be added to your project's dependencies in your `Cargo.toml` file.
```toml
[dependencies]
mate-rs = "0.1.4"
```

## Example: Using `Mate`

`Mate` is a general wrapper structure for `Lexer` and `Calculator`. It provides a single method for calculating results from string input.

```rust
use mate_rs::mate::Mate;

let result = Mate::calculate("6 * 7");
match result {
Ok(v) => assert_eq!(v, 42.0),
Err(_) => {
// Handle error ...
}
};
```

## Example: Using `Lexer` and `Calculator`

`Lexer` is the primary structure that parses string input into a token list. `Calculator` is used to compute the final result from the `Lexer`'s output.

```rust
use mate_rs::{calculator::Calculator, lexer::Lexer};

let input = "[ (2 + 5) * (5 - 9 + (8 - 5)) ] + 35";
let tokens = Lexer::lex(input.clone()).unwrap(); // Error handling should also be implemented
```

View the generated token tree




// The generated tokens will resemble the following:
//
// Token(
// type: SUBEXP,
// tokens: [
// Token(
// type: SUBEXP,
// tokens: [
// Token(type: NUMBER, literal: "2")
// Token(type: PLUS, literal: "+")
// Token(type: NUMBER, literal: "5")
// ],
// ),
// Token(type: PRODUCT, literal: "*"),
// Token(
// type: SUBEXP,
// tokens: [
// Token(type: NUMBER, literal: "5")
// Token(type: MINUS, literal: "-")
// Token(type: NUMBER, literal: "9")
// Token(type: PLUS, literal: "+")
// Token(
// type: SUBEXP,
// tokens: [
// Token(type: NUMBER, literal: "8")
// Token(type: PLUS, literal: "-")
// Token(type: NUMBER, literal: "5")
// ],
// ),
// ],
// ),
// ],
// ),
// Token(type: PLUS, literal: "+")
// Token(type: NUMBER, literal: "35")

```rust
// The result is calculated from the tokens using the X/O/Y algorithm.
//
// ╭────────╮ ╭───────────╮ ╭────────╮
// │ NUMBER │ │ OPERATION │ │ NUMBER │
// ╰────────╯ ╰───────────╯ ╰────────╯
// ╰───╮ │ ╭───╯
// ▼ ▼ ▼
// X [+, -, *, /] Y
//
let result = Calculator::calculate(tokens, input.clone());
```

---

# How it Works
Mate primarily consists of two main structures: [Lexer] and [Calculator]. The [Lexer] structure is responsible for parsing and interpreting the given string expression, while the [Calculator] structure calculates the final result from the parsed tokens.

## Lexer
The Lexer iterates through the given input string, reading and converting each character into a [Token] structure. The main types of tokens include:
- `ILLEGAL` - Represents an illegal character.
- `NUMBER` - Represents a number.
- `MINUS`, `PLUS`, `PRODUCT`, `DIVIDE`, `PERCENTAGE`, `POWER` - Represents operations.
- `LPAREN`, `RPAREN` - Represents parentheses.
- `LABS`, `RABS` - Represents absolute values.
- `SUBEXP` - Represents sub-expressions, which are expressions inside parentheses, absolute values, or combinations of division and multiplication.

The Lexer's `lex` function converts each character into one of these tokens. It groups tokens related to multiplication or division operations into a single sub-expression to maintain the correct operation priority. It also nests parentheses, absolute values, and powers using a custom level-to-expression algorithm.

The level-to-expression algorithm is a mapping algorithm that maps a specific expression to its nesting level.

For example, given the token list `(2 + 5) : (5 - 9 / (8 - 5))`, the generated result will be:

mate

This approach ensures the correct operation priority is maintained.

## Calculator

The Calculator takes the parsed token list and calculates the final result. It uses a custom `X/O/Y` algorithm, also known as `X/OPERATION/Y`, where `X` and `Y` are numbers, and `O` is an operation. If `X` or `Y` cannot be obtained, they are taken as zero.
```
╭────────╮ ╭───────────╮ ╭────────╮
│ NUMBER │ │ OPERATION │ │ NUMBER │
╰────────╯ ╰───────────╯ ╰────────╯
╰───╮ │ ╭───╯
▼ ▼ ▼
X [+, -, *, /] Y
```

---

# Syntax

The syntax of `Mate` is designed to be as simple and basic as possible. It follows the plain-text mathematics syntax with a few customizations. Here are some examples:

### Addition and Subtraction
`2 + 5` and `2 - 5` are valid syntaxes. (in `x y` where x and y could be `NUMBER` or `SUBEXP`).

### Multiplication, Division, and Percentage
`4 * 2`, `4 / 2`, and `4 % 2` are valid syntaxes. (in `x y` where x and y could be `NUMBER` or `SUBEXP`). Also, `4(10 / 2)` or `4(2)` are valid syntaxes for multiplication.

### Power
`4 ^ 2` is a valid syntax. (in `x y` where x and y could be `NUMBER` or `SUBEXP`). Continuous powers are also accepted: `4 ^ 2 ^ 3`, which will be automatically converted to `4 ^ (2 ^ 3)`.

### Parentheses
`(2 * 5)` is a valid syntax. (in `x y` where x and y could be `NUMBER` or `SUBEXP`). Nested parentheses expressions are also accepted: `(2 * ((5 * 2) / (9 - 5)))`.

### Absolute Values
`[2 - 12]` is a valid syntax. (in `x y` where x and y could be `NUMBER` or `SUBEXP`). Nested absolute-value expressions are also accepted: `[7 - 14] * [5 - 9 / [5 - 3]]`.