This project provides a C++ library to parse a character sequence as an expression using Dijkstra's Shunting-yard algorithm, which modifies Jesse Brown's original code.
This project was developed by Brandon Amos and Vinícius Garcia.
If you want to use this library in your project please take a look at our Wiki
- Unary operators.
+,- - Binary operators.
+,-,/,*,%,<<,>>,^,&,|,** - Boolean operators.
<,>,<=,>=,==,!=,&&,|| - Functions.
sin,cos,tan,abs,print - Support for an hierarchy of scopes with local scope, global scope etc.
- Easy to add new operators, operations, functions and even new types
- Easy to implement object-to-object inheritance (with the prototype concept)
- Built-in garbage collector (does not handle cyclic references yet)
cd 'my/project/dir' git clone https://github.com/cparse/cparse.git make release -C cparse
g++ -I cparse -std=c++11 cparse/builtin-features.o cparse/core-shunting-yard.o main.cpp -o main
If you want to make sure everything is working in your environment:
make test -C cparseTo customize your calculator:
- Copy the
builtin-features.cppfile andbuiltin-features/directory to your project. - Edit the
builtin-features/*.incfiles as you like. - Then build the project:
- Compile the library:
make release -C cparse/ - Compile your modified features:
g++ -I cparse -std=c++11 -c builtin-features.cpp -o my-features.o - Link your project:
g++ -I cparse -std=c++11 my-features.o cparse/core-shunting-yard.o main.cpp -o main
- Compile the library:
For a more detailed guide read our Wiki advanced concepts' section:
#include <iostream> #include "shunting-yard.h" int main() { cparse::TokenMap vars; vars["pi"] = 3.14; std::cout << cparse::calculator::calculate("-pi+1", &vars) << std::endl; // Or if you want to evaluate an expression // several times efficiently: cparse::calculator c1("pi-b"); vars["b"] = 0.14; std::cout << c1.eval(vars) << std::endl; // 3 vars["b"] = 2.14; std::cout << c1.eval(vars) << std::endl; // 1 return 0; }
Here we implement an interpreter for multiple expressions, the delimiter used
will be ; or \n just like Javascript or Python and the code must start and end on curly brackets.
A similar architecture can be used for interpreting other common programming language statements like for loops and if statements. If you're interested take a look on the jSpy programming language that uses this project as the core parsing system.
#include <iostream> #include "shunting-yard.h" #include "shunting-yard-exceptions.h" struct codeBlock { static void interpret(const char* start, const char** end, TokenMap vars) { // Remove white spaces: while (isspace(*start)) ++start; if (*start != '{') { throw syntax_error("Expected '{'"); } else { ++start; } while (*start != '}') { cparse::calculator::calculate(start, vars, ";\n}", &start); // Alternatively you could write above: // - calculator(start, ";\n}", &start).eval(vars); // Find the beginning of the next expression: while(isspace(*start) || *start == ';') ++start; } if (*start == '}') { *end = start+1; } else { throw syntax_error("Expected '}'"); } } }; int main() { cparse::GlobalScope vars; const char* code = "{" " a = 10;" " b = 20\n" " c = a + b }"; codeBlock::interpret(code, &code, vars); std::cout << vars["c"] << std::endl; // 30 return 0; }
Please note that a calculator can compile an expression so that it can efficiently be executed several times at a later moment.
- For more examples and a comprehensible guide please read our Wiki
- I would like to keep this library minimal so new features should be very useful to be accepted.
- If proposed change is not a common use case, I will probably not accept it.