| CARVIEW |
Navigation Menu
-
Notifications
You must be signed in to change notification settings - Fork 72
Getting Started
For a short tutorial on how to download, compile and link the CParse library to your project please read the Download and Setup page. To learn how to use the library please read the rest of this page.
The calculator class is our core parser, and everything else was built around it. You may check the Basic Containers page to understand how tokens are kept as a C++ structures, but the really important thing is to learn how to use the calculator.
There are 2 ways to use the calculator, you may use its calculate static function:
TokenMap vars;
vars["x"] = 10;
packToken my_token = calculator::calculate("y = x**2 + 3*x + 2", vars);Or you may use its constructor and create a calculator object. Each one with a pre-compiled expression that can be later re-evaluated much more efficiently:
TokenMap vars;
// This one comes with an empty expression:
calculator C1;
// So you can compile another expression explicity:
C1.compile("my_var = x**3");
// This one comes already compiled with a desired expression:
calculator C2("my_var = x / 4 + 3");After compiling some expressions you can evaluate them using different variable values, for example:
packToken result;
vars["x"] = 10;
result = C1.eval(vars); // 10**3 = 1000
vars["x"] = 2;
result = C1.eval(vars); // 2**3 = 8Its also possible to change the compiled expression inside a calculator by recompiling it. But it is not much more efficient than creating a new calculator.
One of the arguments of the calculator functions is a TokenMap. This TokenMap is used as the local namespace when the expression is evaluated. As such, you might expect it to contain the built-in functions, however, by default the TokenMap constructor will return an empty TokenMap with no access to builtin functions and/or variables.
To get access to these variables you might prefer to use the GlobalScope class, that is a sub class of TokenMap and works exactly like it, but comes with all the builtin functions and variables.
So as an example:
GlobalScope vars;
packToken y = calculator::calculate("y = x**3 + sqrt(abs(2*x)) + exp(x)**2", vars);The calculator class was designed to work together in a hierarchy of parsers, for this to work it must be able to parse a text until a defined delimiter (e.g. ;) and report back to its caller where it did stop parsing.
To do that the static calculate function, the compile function and the calculator constructor have 2 extra optional arguments, delim and rest:
packToken calculate(const char* expr, TokenMap scope,
const char* delim, const char** rest);void compile(const char* expr, TokenMap scope,
const char* delim, const char** rest);calculator(const char* expr, TokenMap scope,
const char* delim, const char** rest, ...);The
calculator constructoractually accepts 6 arguments, lets focus only on these 4.
So to parse a sequence of expressions delimited by the characters ; and \n as it is in Python, you could make a loop like this:
TokenMap vars;
const char* exp = "a = 10; b = 20\n print(a+b);";
const char* pos = exp;
std::vector<calculator> compiled_code;
while(1) {
compiled_code.push_back(calculator(pos, vars, "\n;", &pos));
if (*pos == '\0') break;
++pos;
}This example lacks some error checking so it would probably throw in a real test, but its illustrative.
As you can see the same pointer used to give the starting position of the parser (pos)
is used as return variable to keep track of the last parsed position.
That string ";\n" is how the calculator knows that it should stop parsing after finding one of those characters.
One interesting feature to know is that the calculator makes sure to only end the parsing if the parenthesis are balanced. So for instance if you want to parse an expression inside an if statement, and declare ) as the delimiting character it will work as expected even in cases like:
if (a == (true && false))Interpreting the first ) as part of the expression and the second as the delimiting character.
The easiest way to customize your calculator is by using the builtin-features.cpp file and the builtin-features directory as a template, i.e. copy them into your project and change the definitions to see what happens.
Since all built in features are defined in there, it should be easy to use them as a base to create your own or edit/remove some of the existing ones.
For it to work it is important that you remove the original builtin-features.o file from your project, as to prevent conflict between the features declared in both files, see how to compile it.
If you prefer to learn first and work later the advanced features used on the builtin-features.cpp file and builtin-features directory are explained below.
The first topic explains just how powerful is the TokenMap class, the other 4 explain how to define the behavior of the calculator class or even extend it to make your own custom type of calculators.
- TokenMaps, Scopes and Prototypes
- Writing new functions
- Writing new operations
- Defining new types
- Defining new reserved words
To get right to work you should check the examples page. There you'll have enough material to get your programming language started quickly.