Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/miromannino/mexpr
C++ library which parses human-like arithmetic expressions
https://github.com/miromannino/mexpr
compiler cpp interpreter mathematical-expressions parser parsing parsing-library
Last synced: 14 days ago
JSON representation
C++ library which parses human-like arithmetic expressions
- Host: GitHub
- URL: https://github.com/miromannino/mexpr
- Owner: miromannino
- License: mit
- Created: 2012-06-15T09:18:06.000Z (over 12 years ago)
- Default Branch: master
- Last Pushed: 2015-05-25T20:43:54.000Z (over 9 years ago)
- Last Synced: 2024-10-27T22:36:34.496Z (2 months ago)
- Topics: compiler, cpp, interpreter, mathematical-expressions, parser, parsing, parsing-library
- Language: C++
- Homepage:
- Size: 221 KB
- Stars: 4
- Watchers: 2
- Forks: 2
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# MExpr
C++ library which parses human-like arithmetic expressions like the following:
-3xy^2 - 3(xy + 3)(-5x + y)
To understand better, let's make some examples comparing them to the more traditional computer-like notation:
MExpr notationTraditional computer-like notation
3xy3 * x * y
-3(x + y)-3 * (x + y)
(x + y)(x + 4)(x + y) * (x + 4)## Features
### Implicit multiplications
The parser interprets the text to detect implicit multiplication. For example the expression `xy` is interpreted as `x * y`, and the expression `-3(x + y)(x + 4)` as `-3 * (x + y) * (x + 4)`.
### One character variables
Like the arithmetic expression which we are used to write in a sheet of paper, the variables are single-character words like: `x`, `y`, etc.
That has opened the possibility to recognize implicit multiplications in a expression like: `xy^2`.
That is also an assumption which we have in our minds, and that allow us to interprets `xy` as a multiplication between the variables `x` and `y`, rather than the single variable `xy`.
### Bytecode compilation
The library parses the input string and then it builds an abstract syntax tree. For example, with the expression
-3xy^2
, the parser builds the following abstract syntax tree:[ * ]─[ -1 ]
└───[ * ]─[ 3 ]
└───[ * ]─[ x ]
└───[ ^ ]─[ y ]
└───[ 2 ]
At this point, the library can directly evaluate the expression using the tree (browsing it recursively).
In some cases, for example when you want to draw a plot, you need to evaluate the same expression changing only the value of a variable. For this reason, the library can "compile" the AST to have a more efficient representation of the expression. The generated code is a simple bytecode, that uses a stack to compute operations (similarly to the Java bytecode).
This is the representation of the bytecode generated using the previous expression:
VAL: -1
VAL: 3
VAR: x
VAR: y
VAL: 2
POW
MUL
MUL
MUL
### Functions
MExpr has the possibility to use functions inside the expression.
The library comes with all the functions of _math.h_. Furthermore, one can also
insert new custom functions that can do almost anything!All the function names starts with the underscore character, for example `_f(x)`. This notation is important
because it allows to disambiguate expressions like `f(x)`. In fact, that could be interprets as a multiplication
between the variables `f` and `x`, or as the call of the function `f` passing `x` as argument. On the contrary
`_f(x)` has only one interpretation.#### Function overloading
The functions can be overloaded. For example, one can define the function `_sum(a,b)` that adds two numbers.
Furthermore, one can also define `_sum(a,b,c)`. The parser can manage overloaded functions distinguishing
the functions by the number of parameters.### Dynamic environment
The parser has a dynamic environment, that maintains all the value associated to a variable symbol. Moreover, for each function symbol, it maintains a pointer to the associated function.
This approach allows one to define a variable or a function even after the expression parsing (as well as the expression compilation). For the same reason one can redefine a previously defined function, or change the value of a variable (useful if one is drawing a plot).
## How to use it
The following examples introduces how to use MExpr in your own project. Those examples are also available in the `test` folder and compiled in the `build/test/` folder.
### Example 1
This example shows how to create an expression, assign some values to its variables and print its value.
Expression* e = new Expression("-3(4xy^2x-2x)(8x^-(3x)+2y^-2)");
e->setVariable('x', 4);
e->setVariable('y', -5);cout << e->evaluate() << endl;
### Example 2
This example shows how MExpr could be used to repeatedly evaluate the same expression, only changing the value of a variable.
The expression is previously compiled, to allow a faster evaluation.Expression* e = new Expression("x^2");
e->compile(); //To allow a faster evaluations (e.g. to draw a plot)for (int i = 0; i < 10; i++) {
e->setVariable('x', i);
cout << e->evaluate() << ' ';
}
cout << endl;
### Example 3
This example shows how to print in the console the tree representation and the bytecode representation of the expression.
Expression* e = new Expression("-3xy^2");
cout << "Expression AST: " << endl;
string* s = e->getExprTreeString();
cout << *s;
delete s;e->compile();
cout << endl << "Compiled expression: " << endl;
s = e->getExprCodeString();
cout << *s;
delete s;
### Example 4
This example shows how to create and use a custom function inside the expression.
// myDiv(a, b) = a / b
void myDiv(MExpr::StackType* s) {
MExpr::ValueType arg1, arg2;
arg1 = s->stack[s->stp - 2];
arg2 = s->stack[s->stp - 1];
s->stack[s->stp - 2] = arg1 / arg2;
s->stp--;
}int main(void) {
Expression* e = new Expression("_div(16,4)");
e->setFunction("_div", &myDiv, 2);cout << e->evaluate() << endl;
return 0;
}
### Compile your code that uses MExpr
The Makefile is configured to create a shared library, you can use it with your C++ programs dynamically linking this library.
g++ -o myExample -lmexpr myExample.cpp
## How to compile MExpr
- Ensure that you satisfy the requirements.
- Open the Makefile and set your OS changing the `OperatingSystem` variable.Run the command you need
- `make all` to compile the library
- `make run-tests` to run the tests
- `make clean-gtest` to remove the GoogleTest library folder
- `make install` to install the library in `/usr/local/lib`
### Common issues
- Mac OS X, by default, doesn't have the `/usr/local/lib` and `/usr/local/include` folders, check that you have these folders.
- You can have some problems compiling your examples if you don't install it before. If you don't want to install it, ensure that the `DYLD_LIBRARY_PATH` (or the `LD_LIBRARY_PATH`) was proudly configured.
- Ensure that you have installed `wget`, that is used to download the GoogleTest library## Requirements
Tested operating systems: OSX, Linux
To compile the library you need: bison, flex and g++.
GoogleTests library: but is automatically downloaded in the `gtest` folder during the building process (i.e. `make all`).
## License
This project is licensed under the MIT license