Defining Reserved Words
The framework supports a feature to allow an user to describe a custom parser to be used to parse reserved words. This is very useful, you can use it to define constant values like: True, False, Null, etc. Or you can use them for more complex concepts, for example:
calculator::calculate("my_instance = new my_class(arg1, arg2);");
The new operator has a special meaning and will cause the parsing of the rest of the expression to use different rules. For instance my_class is not a function so if the normal rules were to be applied it would throw an exception stating that the call operator () is undefined for the operands my_class and (arg1, arg2).
So although this is an advanced feature it is quite useful, and is not too hard to use.
Declaring a new Reserved Word
To declare a new reserved word you must first declare a parser function like this:
// expr starts right after the key-word, so if you print expr, // you'll see the part of the expression that was not parsed yet. void TrueParser(const char* expr, const char** rest, rpnBuilder* data) { data->handle_token(trueToken->clone()); }
After that you just need to add it to the reserved words map:
struct Startup { Startup() { parserMap_t& parser = calculator::Default().parserMap; parser.add("True", &TrueParser); } } Startup;
Declaring a new Reserved Character
A reserved character is almost the same thing as a reserved word and it is declared in much the same way, e.g.:
struct Startup { Startup() { parserMap_t& parser = calculator::Default().parserMap; // Reserved word: parser.add("//", &SlashCommentParser); // Reserved character: parser.add('/', &RegExpParser); } } Startup;
It is useful when you want a character to have a meaning regardless of the character that follows it, e.g. the = character on the expression:
Should be interpreted just like:
This would not be possible if = was a reserved word, since the interpreter would read both characters =- as a single operator.
A More Advanced Example
Lets get to a more complex example: Lets declare a function keyword to mark a function declaration. The example below was extracted from the JSpy Programming Language that uses CParse as its base engine.
Side Note: Since the function being parsed would be a nameless function, even if the user provide a name it will be ignored. That is an expected behavior.
void function_parser(const char* expr, const char** rest, rpnBuilder* data) { // Ignore white spaces: while (isspace(*expr)) ++expr; if (isalpha(*expr) || *expr == '_') { // Ignore the name if provided: while (isalnum(*expr) || *expr == '_') ++expr; // Ignore white spaces: while (isspace(*expr)) ++expr; } data->handle_token(new CompiledFunc(expr, &expr, data->scope)); // ... some code omitted ... *rest = expr; }