pax_global_header00006660000000000000000000000064132072271520014513gustar00rootroot0000000000000052 comment=f503aa6e05707554d8812ea35a31942f652953b0 libcleri-0.9.4/000077500000000000000000000000001320722715200133125ustar00rootroot00000000000000libcleri-0.9.4/.gitignore000066400000000000000000000004311320722715200153000ustar00rootroot00000000000000# Object files *.o *.ko *.obj *.elf # Precompiled Headers *.gch *.pch # Libraries *.lib *.a *.la *.lo # Shared objects (inc. Windows DLLs) *.dll *.so *.so.* *.dylib *.d # Executables *.exe *.out *.app *.i*86 *.x86_64 *.hex # Debug files *.dSYM/ # Visual Studio Code .vscode/ libcleri-0.9.4/ChangeLog000066400000000000000000000014741320722715200150720ustar00rootroot00000000000000ibcleri (0.9.4) * Replaced pcre with pcre2. (issue #5) -- Jeroen van der Heijden 28 Nov 2017 libcleri (0.9.3) * Fixed compiler warnings. -- Jeroen van der Heijden 01 Sep 2017 libcleri (0.9.2) * Added __cplusplus macros for c++ compatibility. -- Jeroen van der Heijden 25 Aug 2017 libcleri (0.9.1) * Rename object.h to cleri.h and the cleri_object_t to cleri_t. -- Jeroen van der Heijden 23 Jun 2017 libcleri (0.9.0) * Initial version for the C program language. * fixed largets token first. * added cleri_dup(). * added header guards. * added forward reference element. (issue #2) -- Jeroen van der Heijden 22 Jun 2017 libcleri-0.9.4/LICENSE.md000066400000000000000000000020511320722715200147140ustar00rootroot00000000000000Copyright (c) 2016 Transceptor Technology Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.libcleri-0.9.4/README.md000066400000000000000000000622711320722715200146010ustar00rootroot00000000000000# C Left-Right Parser (libcleri) Language parser for the C/C++ programming language. Initially created for [SiriDB](https://github.com/transceptor-technology/siridb-server). --------------------------------------- * [Installation](#installation) * [Related projects](#related-projects) * [Quick usage](#quick-usage) * [API](#api) * [cleri_t](#cleri_t) * [cleri_grammar_t](#cleri_grammar_t) * [cleri_parse_t](#cleri_parse_t) * [cleri_node_t](#cleri_node_t) * [cleri_children_t](#cleri_children_t) * [cleri_olist_t](#cleri_olist_t) * [Elements](#elements) * [cleri_keyword_t](#cleri_keyword_t) * [cleri_regex_t](#cleri_regex_t) * [cleri_choice_t](#cleri_choice_t) * [cleri_sequence_t](#cleri_sequence_t) * [cleri_optional_t](#cleri_optional_t) * [cleri_prio_t](#cleri_prio_t) * [cleri_repeat_t](#cleri_repeat_t) * [cleri_list_t](#cleri_list_t) * [cleri_token_t](#cleri_repeat_t) * [cleri_tokens_t](#cleri_tokens_t) * [Forward reference](#forward-reference) * [cleri_dup_t](#cleri_dup_t) * [Miscellaneous functions](#miscellaneous-functions) --------------------------------------- ## Installation >Note: libcleri requires [pcre2](http://www.pcre.org/) > >On Ubuntu: > >`sudo apt install libpcre2-dev` > >On MacOs: > >`brew install pcre2` > Install debug or release version, in this example we will install the release version. ``` $ cd Release ``` Compile libcleri >Note: On MacOs you might need to set environment variables: > >`export CFLAGS="-I/usr/local/include" && export LDFLAGS="-L/usr/local/lib"` > ``` $ make all ``` Install libcleri ``` $ sudo make install ``` > Note: run `sudo make uninstall` for removal. ## Related projects - [pyleri](https://github.com/transceptor-technology/pyleri): Python parser (can export grammar to pyleri, libcleri, goleri and jsleri) - [jsleri](https://github.com/transceptor-technology/jsleri): JavaScript parser - [goleri](https://github.com/transceptor-technology/goleri): Go parser ## Quick usage >The recommended way to create a grammar is to use [pyleri](https://github.com/transceptor-technology/pyleri) for >writing the grammar and then export the grammar to libcleri or other languages. This is a simple example using libcleri: ```c #include #include void test_str(cleri_grammar_t * grammar, const char * str) { cleri_parse_t * pr = cleri_parse(grammar, str); printf("Test string '%s': %s\n", str, pr->is_valid ? "true" : "false"); cleri_parse_free(pr); } int main(void) { /* define grammar */ cleri_t * k_hi = cleri_keyword(0, "hi", 0); cleri_t * r_name = cleri_regex(0, "^(?:\"(?:[^\"]*)\")+"); cleri_t * start = cleri_sequence(0, 2, k_hi, r_name); /* compile grammar */ cleri_grammar_t * my_grammar = cleri_grammar(start, NULL); /* test some strings */ test_str(my_grammar, "hi \"Iris\""); // true test_str(my_grammar, "bye \"Iris\""); // false /* cleanup grammar */ cleri_grammar_free(my_grammar); return 0; } ``` Although libcleri is written for C, it can be used with C++ too: ```c++ #include #include void test_str(cleri_grammar_t * grammar, const char * str) { cleri_parse_t * pr = cleri_parse(grammar, str); std::cout << "Test string " << str << ": " << (pr->is_valid ? "true" : "false") << std::endl; cleri_parse_free(pr); } int main() { /* define grammar */ cleri_t * k_hi = cleri_keyword(0, "hi", 0); cleri_t * r_name = cleri_regex(0, "^(?:\"(?:[^\"]*)\")+"); cleri_t * start = cleri_sequence(0, 2, k_hi, r_name); /* compile grammar */ cleri_grammar_t * my_grammar = cleri_grammar(start, NULL); /* test some strings */ test_str(my_grammar, "hi \"Iris\""); // true test_str(my_grammar, "bye \"Iris\""); // false /* cleanup grammar */ cleri_grammar_free(my_grammar); return 0; } ``` ## API ### `cleri_t` Cleri type is the base object for each element. *Public members* - `uint32_t gid`: Global Identifier for the element. This GID is not required and as a rule it should be set to 0 if not used. You can use the GID for identifiying an element in a parse result. When exporting a Pyleri grammar, each *named* element automatically gets a unique GID assigned. (readonly) - `cleri_tp tp`: Type for the cleri object. (readonly) - `CLERI_TP_SEQUENCE` - `CLERI_TP_OPTIONAL` - `CLERI_TP_CHOICE` - `CLERI_TP_LIST` - `CLERI_TP_REPEAT` - `CLERI_TP_PRIO` - `CLERI_TP_RULE` - `CLERI_TP_THIS` - `CLERI_TP_KEYWORD` - `CLERI_TP_TOKEN` - `CLERI_TP_TOKENS` - `CLERI_TP_REGEX` - `CLERI_TP_END_OF_STATEMENT` - `cleri_via_t via`: Element. (readonly) - `cleri_sequence_t * sequence` - `cleri_optional_t * optional` - `cleri_choice_t * choice` - `cleri_list_t * list` - `cleri_repeat_t * repeat` - `cleri_prio_t * prio` - `cleri_rule_t * rule` - `cleri_keyword_t * keyword` - `cleri_regex_t * regex` - `cleri_token_t * token` - `cleri_tokens_t * tokens` - `void * dummy` (place holder, this, eof) #### `cleri_t * cleri_new(uint32_t gid, cleri_tp tp, cleri_free_object_t free_object, cleri_parse_object_t parse_object)` Create and return a new cleri object. A unique gid is not required but can help you with identifiying the element in a [parse result](#cleri_parse_t). As a rule you should assign 0 in case no specific gid is required. This function should only be used in case you want to create your own custom element. #### `void cleri_incref(cleri_t * cl_object)` Increment the reference counter for a cleri object. Should only be used in case you want to write your own custom element. #### `void cleri_decref(cleri_t * cl_object)` Decrement the reference counter for a cleri object. If no references are left the object will be destroyed. Do not use this function after the element has successfully been added to another element or grammar. Should only be used in case you want to write your own custom element. #### `int cleri_free(cleri_t * cl_object)` Decrement reference counter for a cleri object. When there are no more references left the object will be destroyed. Use this function to cleanup after errors have occurred. Do not use this function after the element has successfully been added to another element or grammar. Example strict error handling: ```c cleri_grammar_t * compile_grammar(void) { cleri_t * k_hello = cleri_keyword(0, "hello", 0); if (k_hello == NULL) { return NULL; } cleri_t * k_world = cleri_keyword(0, "world", 0); if (k_world == NULL) { cleri_free(k_hello); // must cleanup k_hello return NULL; } cleri_t * hello_world = cleri_sequence(0, 2, k_hello, k_world); if (start == NULL) { cleri_free(k_hello); cleri_free(k_world); return NULL; } cleri_t * opt = cleri_optional(0, hello_world); if (opt == NULL) { /* we now must only cleanup hello_world since this sequence will * cleanup both keywords too. */ cleri_free(hello_world); return NULL; } cleri_grammar_t * grammar = cleri_grammar(opt, NULL); if (grammar == NULL) { cleri_free(opt); } /* when your program has finished, the grammar including all elements can * be destroyed using cleri_grammar_free() */ return grammar; } ``` >Note: Usually grammar is only compiled at the startup of your program so >memory allocation errors during the grammar creation are unlikely to occur. >If NULL is parsed as an argument instead of an element, then the function >to which the argument is parsed to, will return NULL. Following this >chain the final grammar returns NULL in case an error has occurred somewhere. >In this case you should usually abort the program. ### `cleri_grammar_t` Compiled libcleri grammar. *No public members* #### `cleri_grammar_t * cleri_grammar(cleri_t * start, const char * re_keywords)` Create and return a compiled grammar. Argument `start` must be the entry element for the grammar. Argument `re_keywords` should be a regular expression starting with character `^` for matching keywords in a grammar. When a grammar is created, each defined [keyword](#cleri_keyword_t) should match this regular expression. `re_keywords` is allowed to be `NULL` in which case the defualt `CLERI_DEFAULT_RE_KEYWORDS` is used. #### `void cleri_grammar_free(cleri_grammar_t * grammar)` Cleanup grammar. This will also destroy all elements which are used by the grammar. Make sure all parse results are destroyed before destroying the grammar because a [parse result](#cleri_parse_t) depends on elements from the grammar. ### `cleri_parse_t` Parse result containing the parse tree and other information about the parse result. *Public members* - `int cleri_parse_t.is_valid`: Boolean. Value is 1 (TRUE) in case the parse string is valid or 0 (FALSE) if not. (readonly) - `size_t cleri_parse_t.pos`: Position in the string to where the string was successfully parsed. This value is (readonly) equal to the length of the string in case `cleri_parse_t.is_valid` is TRUE. (readonly) - `const char * cleri_parse_t.str`: Pointer to the provided string. (readonly) - `cleri_node_t * tree`: Parse tree. (see [cleri_node_t](#cleri_node_t) and [cleri_children_t](#cleri_children_t)) (readonly) - `const cleri_olist_t * expect`: Linked list to possible elements at position `cleri_parse_t.pos` in `cleri_parse_t.str`. (see [cleri_olist_t](#cleri_olist_t) for more information) #### `cleri_parse_t * cleri_parse(cleri_grammar_t * grammar, const char * str)` Create and return a parse result. The parse result contains pointers to the provided string (`str`) so make sure the string is available while using the parse result. #### `void cleri_parse_free(cleri_parse_t * pr)` Cleanup a parse result. #### `void cleri_parse_expect_start(cleri_parse_t * pr)` Can be used to reset the expect list to start. Usually you are not required to use this function since the expect list is already at the start position. ### `cleri_node_t` Node object. A parse result has a parse tree which consists of nodes. Each node may have children. *Public members* - `const char * cleri_node_t.str`: Pointer to the position in the parse string where this node starts. (readonly) - `size_t cleri_node_t.len`: Length of the string which is applicable for this node. (readonly) - `cleri_t * cleri_node_t.cl_obj`: Element from the grammar which matches this node. (readonly) - `cleri_children_t * cleri_node_t.children`: Optional children for this node. (readonly) #### `bool cleri_node_has_children(cleri_node_t * node)` Macro function for checking if a node has children. ### `cleri_children_t` Children from a node in a linked list. *Public members* - `cleri_node_t * cleri_children_t.node`: Child node. (readonly) - `struct cleri_children_s * cleri_children_t.next`: Next child node or `NULL` if there are no other childs. (readonly) Example looping over all children within a node: ```c /* we asume having a node (cleri_node_t*) */ if (cleri_node_has_children(node)) { cleri_children_t * child = node->children; while (child != NULL) { // do something with child->node child = child->next; } } ``` ### `cleri_olist_t` Linked list holding libcleri objects. A `cleri_olist_t` type is used for expected elements in a parse result. *Public members* - `cleri_t * cl_obj`: Object (holding an element, readonly) - `cleri_olist_t * next`: Next object. (readonly) Example looping over `cleri_parse_t.expect`: ```c /* we assume having a pr (cleri_parse_t*) * * Notes: * pr->expect is NULL if nothing is expected and it is save to * change pr->expect. If required the linked list can be reset to start * using cleri_parse_expect_start(). */ while (pr->expect != NULL) { // do something with pr->expect->cl_obj pr->expect = pr->expect->next; } ``` ## Elements Elements are objects used to define a grammar. ### `cleri_keyword_t` Keyword element. The parser needs a match with the keyword. *Type (`cleri_t.tp`)*: `CLERI_TP_KEYWORD` *Public members* - `const char * cleri_keyword_t.keyword`: Contains the keyword string. (readonly) - `int cleri_keyword_t.ign_case`: Boolean. (readonly) - `size_t cleri_keyword_t.len`: Length of the keyword string. (readonly) #### `cleri_t * cleri_keyword(uint32_t gid, const char * keyword, int ign_case)` Create and return a new [object](#cleri_t) containing a keyword element. Argument `ign_case` can be set to 1 for a case insensitive keyword match. Example: ```c /* define case insensitive keyword */ cleri_t * k_tictactoe = cleri_keyword( 0, // gid, not used in this example "tic-tac-toe", // keyword 1); // case insensitive /* create grammar with custom keyword regular expression match */ cleri_grammar_t * grammar = cleri_grammar(k_tictactoe, "^[A-Za-z-]+"); /* parse some test string */ cleri_parse_t * pr = cleri_parse(grammar, "Tic-Tac-Toe"); printf("Valid: %s\n", pr->is_valid ? "true" : "false"); // true /* cleanup */ cleri_parse_free(pr); cleri_grammar_free(grammar); ``` ### `cleri_regex_t` Regular expression element. The parser needs a match with the regular expression. *No public members* #### `cleri_t * cleri_regex(uint32_t gid, const char * pattern)` Create and return a new [object](#cleri_t) containing a regular expression element. Argument `pattern` should contain the regular expression. Each pattern must start with character `^` and the pattern should be checked before calling this function. See [Quick usage](#quick-usage) for a `cleri_regex_t` example. ### `cleri_choice_t` Choice element. The parser must choose one of the child elements. *Public members* - `int cleri_choice_t.most_greedy`: Boolean. (readonly) - `cleri_olist_t * cleri_choice_t.olist`: Children. (readonly) #### `cleri_t * cleri_choice(uint32_t gid, int most_greedy, size_t len, ...)` Create and return a new [object](#cleri_t) containing a choice element. Argument `most_greedy` can be set to 1 in which case the parser will select the most greedy match. When 0, the parser will select the first match. Example: ```c /* define grammar */ cleri_t * k_hello = cleri_keyword(0, "hello", 0); cleri_t * k_goodbye = cleri_keyword(0, "goodbye", 0); cleri_t * choice = cleri_choice( 0, // gid, not used in this example 0, // stop at first match 2, // number of elements k_hello, k_goodbye); // elements /* create grammar */ cleri_grammar_t * grammar = cleri_grammar(choice, NULL); /* parse some test string */ cleri_parse_t * pr = cleri_parse(grammar, "goodbye"); printf("Valid: %s\n", pr->is_valid ? "true" : "false"); // true /* cleanup */ cleri_parse_free(pr); cleri_grammar_free(grammar); ``` ### `cleri_sequence_t` Sequence element. The parser must match each element in the specified order. *Public members* - `cleri_olist_t * cleri_sequence_t.olist`: Elements. (readonly) #### `cleri_t * cleri_sequence(uint32_t gid, size_t len, ...)` Create and return a new [object](#cleri_t) containing a sequence element. Example: ```c cleri_t * sequence = cleri_sequence( 0, // gid, not used in the example 3, // number of elements cleri_keyword(0, "Tic", 0), // first element cleri_keyword(0, "Tac", 0), // second element cleri_keyword(0, "Toe", 0)); // third element /* create grammar */ cleri_grammar_t * grammar = cleri_grammar(sequence, NULL); /* parse some test string */ cleri_parse_t * pr = cleri_parse(grammar, "Tic Tac Toe"); printf("Valid: %s\n", pr->is_valid ? "true" : "false"); // true /* cleanup */ cleri_parse_free(pr); cleri_grammar_free(grammar); ``` ### `cleri_optional_t` Optional element. The parser looks for an optional element. *Public members* - `cleri_t * cleri_optional_t.cl_obj`: Optional element. (readonly) #### `cleri_t * cleri_optional(uint32_t gid, cleri_t * cl_obj)` Create and return a new [object](#cleri_t) containing an optional element. Example: ```c /* define grammar */ cleri_t * k_hello = cleri_keyword(0, "hello", 0); cleri_t * k_there = cleri_keyword(0, "there", 0); cleri_t * optional = cleri_optional( 0, // gid, not used in this example k_there); // optional element cleri_t * greet = cleri_sequence( 0, // gid, not used in this example 2, // number of elements k_hello, optional); // elements /* create grammar */ cleri_grammar_t * grammar = cleri_grammar(greet, NULL); /* parse some test string */ cleri_parse_t * pr = cleri_parse(grammar, "hello"); printf("Valid: %s\n", pr->is_valid ? "true" : "false"); // true /* cleanup */ cleri_parse_free(pr); cleri_grammar_free(grammar); ``` ### `cleri_prio_t` Prio element. The parser must match one element. Inside the prio element it is possible to use `CLERI_THIS` which is a reference to itself. >Note: Use a [forward reference](#forward-reference) when possible. >A prio is required when the same position in a string is potentially checked >more than once. *Public members* - `cleri_olist_t * cleri_sequence_t.olist`: Elements. (readonly) #### `cleri_t * cleri_prio(uint32_t gid, size_t len, ...)` Create and return a new [object](#cleri_t) containing a prio element. Example: ```c /* * define grammar. * * Note: The third and fourth element are using a reference to the prio * element at the same position in the string as the prio element. * This is why a forward reference cannot be used for this example. */ cleri_t * prio = cleri_prio( 0, // gid, not used in the example 4, // number of elements cleri_keyword(0, "ni", 0), // first element cleri_sequence(0, 3, // second element cleri_token(0, "("), CLERI_THIS, cleri_token(0, ")")), cleri_sequence(0, 3, // third element CLERI_THIS, cleri_keyword(0, "or", 0), CLERI_THIS), cleri_sequence(0, 3, // fourth element CLERI_THIS, cleri_keyword(0, "and", 0), CLERI_THIS)); /* create grammar */ cleri_grammar_t * grammar = cleri_grammar(prio, NULL); /* parse some test string */ cleri_parse_t * pr = cleri_parse(grammar, "(ni or ni) and (ni or ni)"); printf("Valid: %s\n", pr->is_valid ? "true" : "false"); // true /* cleanup */ cleri_parse_free(pr); cleri_grammar_free(grammar); ``` ### `cleri_repeat_t` Repeat element. The parser must math at least `cleri_repeat_t.min` elements and at most `cleri_repeat_t.max`. An unlimited amount is allowed in case `cleri_repeat_t.max` is set to 0 (zero). *Public members* - `cleri_t * cleri_repeat_t.cl_obj`: Element to repeat. (readonly) - `size_t cleri_repeat_t.min`: Minimum times an element is expected. (readonly) - `size_t cleri_repeat_t.max`: Maximum times an element is expected or 0 for unlimited. (readonly) #### `cleri_t * cleri_repeat(uint32_t gid, cleri_t * cl_obj, size_t min, size_t max)` Create and return a new [object](#cleri_t) containing a repeat element. Argument `max` should be greater or equal to `min` or 0. Example: ```c /* define grammar */ cleri_t * repeat = cleri_repeat( 0, // gid, not used in this example cleri_keyword(0, "ni", 0), // repeated element 0, // min n times 0); // max n times (0 for unlimited) /* create grammar */ cleri_grammar_t * grammar = cleri_grammar(repeat, NULL); /* parse some test string */ cleri_parse_t * pr = cleri_parse(grammar, "ni ni ni ni ni"); printf("Valid: %s\n", pr->is_valid ? "true" : "false"); // true /* cleanup */ cleri_parse_free(pr); cleri_grammar_free(grammar); ``` ### `cleri_list_t` List element. Like [repeat](#cleri_repeat_t) but with a delimiter. *Public members* - `cleri_t * cleri_list_t.cl_obj`: Element to repeat. (readonly) - `cleri_t * cleri_list_t.delimiter`: Delimiter between repeating element. (readonly) - `size_t cleri_list_t.min`: Minimum times an element is expected. (readonly) - `size_t cleri_list_t.max`: Maximum times an element is expected or 0 for unlimited. (readonly) - `int cleri_list_t.opt_closing`: Allow or disallow ending with a delimiter. #### `cleri_t * cleri_list(uint32_t gid, cleri_t * cl_obj, cleri_t * delimiter, size_t min, size_t max, int opt_closing)` Create and return a new [object](#cleri_t) containing a list element. Argument `max` should be greater or equal to `min` or 0. Argument `opt_closing` can be 1 (TRUE) to allow or 0 (FALSE) to disallow a list to end with a delimiter. Example: ```c /* define grammar */ cleri_t * list = cleri_list( 0, // gid, not used in this example cleri_keyword(0, "ni", 0), // repeated element cleri_token(0, ","), // delimiter element 0, // min n times 0, // max n times (0 for unlimited) 0); // disallow ending with a delimiter /* create grammar */ cleri_grammar_t * grammar = cleri_grammar(list, NULL); /* parse some test string */ cleri_parse_t * pr = cleri_parse(grammar, "ni, ni, ni, ni, ni"); printf("Valid: %s\n", pr->is_valid ? "true" : "false"); // true /* cleanup */ cleri_parse_free(pr); cleri_grammar_free(grammar); ``` ### `cleri_token_t` Token element. The parser must math a token exactly. A token can be one or more characters and is usually used to match operators like `+`, `-`, `*` etc. *Public members* - `const char * cleri_token_t.token`: Token string. (readonly) - `size_t cleri_token_t.len`: Length of the token string. (readonly) #### `cleri_t * cleri_token(uint32_t gid, const char * token)` Create and return a new [object](#cleri_t) containing a token element. Example: ```c /* define grammar */ cleri_t * token = cleri_token( 0, // gid, not used in this example "-"); // token string (dash) cleri_t * ni = cleri_keyword(0, "ni", 0); cleri_t * list = cleri_list(0, ni, token, 0, 0, 0); /* create grammar */ cleri_grammar_t * grammar = cleri_grammar(list, NULL); /* parse some test string */ cleri_parse_t * pr = cleri_parse(grammar, "ni-ni - ni- ni -ni"); printf("Valid: %s\n", pr->is_valid ? "true" : "false"); // true /* cleanup */ cleri_parse_free(pr); cleri_grammar_free(grammar); ``` ### `cleri_tokens_t` Tokens element. Can be used to register multiple tokens at once. #### `cleri_t * cleri_tokens(uint32_t gid, const char * tokens)` Create and return a new [object](#cleri_t) containing a tokens element. Argument `tokens` must be a string with tokens seperated by spaces. If given tokens are different in size, the parser will try to match the longest tokens first. Example: ```c /* define grammar */ cleri_t * tokens = cleri_tokens( 0, // gid, not used in this example "+ - -="); // tokens string '+', '-' and '-=' cleri_t * ni = cleri_keyword(0, "ni", 0); cleri_t * list = cleri_list(0, ni, tokens, 0, 0, 0); /* create grammar */ cleri_grammar_t * grammar = cleri_grammar(list, NULL); /* parse some test string */ cleri_parse_t * pr = cleri_parse(grammar, "ni + ni -= ni - ni"); printf("Valid: %s\n", pr->is_valid ? "true" : "false"); // true /* cleanup */ cleri_parse_free(pr); cleri_grammar_free(grammar); ``` ### `Forward reference` Forward reference to a libcleri object. There is no specific type for a reference. >Warning: A reference is not protected against testing the same position in >in a string. This could potentially lead to an infinite loop. >For example: >```c >cleri_ref_set(ref, cleri_optional(0, ref)); // DON'T DO THIS >``` >Use [prio](#cleri_prio_t) if such recursive construction is required. #### `cleri_t * cleri_ref(void)` Create and return a new [object](#cleri_t) as reference element. Once the reference is created, it can be used as element in you grammar. Do not forget to actually set the reference using `cleri_ref_set()`. #### `void cleri_ref_set(cleri_t * ref, cleri_t * cl_obj)` Set a reference. For every created forward reference, this function must be called exactly once. Argument `ref` must be created with `cleri_ref()`. Argument `cl_obj` cannot be used outside the reference. Since the reference becomes the `cl_obj`, it is the reference you should use. Example ```c /* define grammar */ cleri_t * ref = cleri_ref(); cleri_t * choice = cleri_choice( 0, 0, 2, cleri_keyword(0, "ni", 0), ref); cleri_ref_set(ref, cleri_sequence( 0, 3, cleri_token(0, "["), cleri_list(0, choice, cleri_token(0, ","), 0, 0, 0), cleri_token(0, "]"))); /* create grammar */ cleri_grammar_t * grammar = cleri_grammar(ref, NULL); /* parse some test string */ cleri_parse_t * pr = cleri_parse(grammar, "[ni, ni, [ni, [], [ni, ni]]]"); printf("Valid: %s\n", pr->is_valid ? "true" : "false"); // true /* cleanup */ cleri_parse_free(pr); cleri_grammar_free(grammar); ``` ### `cleri_dup_t` Duplicate an object. The type is an extension to `cleri_t`. #### `cleri_t * cleri_dup(uint32_t gid, cleri_t * cl_obj)` Duplicate a libcleri object with a different gid but using the same element. >Note: Only the object is duplicated. The element (`cleri_via_t via`) >is a pointer to the original object. The following [pyleri](https://github.com/transceptor-technology/pyleri) code will use `cleri_dup()` when exported to c: ```python elem = Repeat(obj, mi=1, ma=1) ``` Use the code below if you want similar behavior without duplication: ```python elem = Sequence(obj) ``` ### Miscellaneous functions #### `const char * cleri_version(void)` Returns the version of libcleri. libcleri-0.9.4/Release/000077500000000000000000000000001320722715200146725ustar00rootroot00000000000000libcleri-0.9.4/Release/makefile000066400000000000000000000022341320722715200163730ustar00rootroot00000000000000################################################################################ # Automatically-generated file. Do not edit! ################################################################################ -include ../makefile.init RM := rm -rf # All of the sources participating in the build are defined here -include sources.mk -include src/subdir.mk -include subdir.mk -include objects.mk ifneq ($(MAKECMDGOALS),clean) ifneq ($(strip $(C_DEPS)),) -include $(C_DEPS) endif endif -include ../makefile.defs OS := $(shell uname) ifeq ($(OS),Darwin) FN := libcleri.dylib INSTALL_PATH := /usr/local else FN := libcleri.so INSTALL_PATH := /usr endif # Add inputs and outputs from these tool invocations to the build variables # All Target all: libcleri # Tool invocations libcleri: $(OBJS) $(USER_OBJS) @echo 'Building target: $@' @echo 'Invoking: Cross GCC Linker' gcc -shared -Wl,-soname,$(FN).$(MAJOR) -o $(FN) $(OBJS) $(USER_OBJS) $(LIBS) $(LDFLAGS) @chmod -x $(FN) @echo 'Finished building target: $@' @echo ' ' # Other Targets clean: -$(RM) $(LIBRARIES)$(OBJS)$(C_DEPS) $(FN) -@echo ' ' .PHONY: all clean dependents .SECONDARY: -include ../makefile.targets libcleri-0.9.4/Release/objects.mk000066400000000000000000000003601320722715200166530ustar00rootroot00000000000000################################################################################ # Automatically-generated file. Do not edit! ################################################################################ USER_OBJS := LIBS := -lpcre2-8 libcleri-0.9.4/Release/sources.mk000066400000000000000000000006101320722715200167030ustar00rootroot00000000000000################################################################################ # Automatically-generated file. Do not edit! ################################################################################ OBJ_SRCS := ASM_SRCS := C_SRCS := O_SRCS := S_UPPER_SRCS := EXECUTABLES := OBJS := C_DEPS := # Every subdirectory with source files must be described here SUBDIRS := \ src \ libcleri-0.9.4/Release/src/000077500000000000000000000000001320722715200154615ustar00rootroot00000000000000libcleri-0.9.4/Release/src/subdir.mk000066400000000000000000000033231320722715200173030ustar00rootroot00000000000000################################################################################ # Automatically-generated file. Do not edit! ################################################################################ # Add inputs and outputs from these tool invocations to the build variables C_SRCS += \ ../src/children.c \ ../src/choice.c \ ../src/dup.c \ ../src/expecting.c \ ../src/grammar.c \ ../src/keyword.c \ ../src/kwcache.c \ ../src/list.c \ ../src/node.c \ ../src/cleri.c \ ../src/olist.c \ ../src/optional.c \ ../src/parse.c \ ../src/prio.c \ ../src/ref.c \ ../src/regex.c \ ../src/repeat.c \ ../src/rule.c \ ../src/sequence.c \ ../src/this.c \ ../src/token.c \ ../src/tokens.c OBJS += \ ./src/children.o \ ./src/choice.o \ ./src/dup.o \ ./src/expecting.o \ ./src/grammar.o \ ./src/keyword.o \ ./src/kwcache.o \ ./src/list.o \ ./src/node.o \ ./src/cleri.o \ ./src/olist.o \ ./src/optional.o \ ./src/parse.o \ ./src/prio.o \ ./src/ref.o \ ./src/regex.o \ ./src/repeat.o \ ./src/rule.o \ ./src/sequence.o \ ./src/this.o \ ./src/token.o \ ./src/tokens.o C_DEPS += \ ./src/children.d \ ./src/choice.d \ ./src/dup.d \ ./src/expecting.d \ ./src/grammar.d \ ./src/keyword.d \ ./src/kwcache.d \ ./src/list.d \ ./src/node.d \ ./src/cleri.d \ ./src/olist.d \ ./src/optional.d \ ./src/parse.d \ ./src/prio.d \ ./src/ref.d \ ./src/regex.d \ ./src/repeat.d \ ./src/rule.d \ ./src/sequence.d \ ./src/this.d \ ./src/token.d \ ./src/tokens.d # Each subdirectory must supply rules for building sources it contributes src/%.o: ../src/%.c @echo 'Building file: $<' @echo 'Invoking: Cross GCC Compiler' gcc -I../inc -O3 -Wall $(CFLAGS) -c -fmessage-length=0 -fPIC -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$@" "$<" @echo 'Finished building: $<' @echo ' ' libcleri-0.9.4/Release/subdir.mk000066400000000000000000000005511320722715200165140ustar00rootroot00000000000000################################################################################ # Automatically-generated file. Do not edit! ################################################################################ # Add inputs and outputs from these tool invocations to the build variables # Each subdirectory must supply rules for building sources it contributes libcleri-0.9.4/examples/000077500000000000000000000000001320722715200151305ustar00rootroot00000000000000libcleri-0.9.4/examples/choice/000077500000000000000000000000001320722715200163625ustar00rootroot00000000000000libcleri-0.9.4/examples/choice/main.c000066400000000000000000000015131320722715200174520ustar00rootroot00000000000000#include #include const char * TestChoice = "goodbye"; int main(void) { /* define grammar */ cleri_t * k_hello = cleri_keyword(0, "hello", 0); cleri_t * k_goodbye = cleri_keyword(0, "goodbye", 0); cleri_t * choice = cleri_choice( 0, // gid, not used in this example 0, // stop at first match 2, // number of elements k_hello, k_goodbye); // elements /* create grammar */ cleri_grammar_t * grammar = cleri_grammar(choice, NULL); /* parse some test string */ cleri_parse_t * pr = cleri_parse(grammar, TestChoice); printf("Test: %s, '%s'\n", pr->is_valid ? "true" : "false", TestChoice); /* cleanup */ cleri_parse_free(pr); cleri_grammar_free(grammar); return 0; }libcleri-0.9.4/examples/examples.sh000077500000000000000000000014151320722715200173060ustar00rootroot00000000000000 echo -n "json: " && cd json && gcc main.c json.c -lcleri && ./a.out echo -n "choice: " && cd ../choice && gcc main.c -lcleri && ./a.out echo -n "keyword: " && cd ../keyword && gcc main.c -lcleri && ./a.out echo -n "list: " && cd ../list && gcc main.c -lcleri && ./a.out echo -n "optional: " && cd ../optional && gcc main.c -lcleri && ./a.out echo -n "prio: " && cd ../prio && gcc main.c -lcleri && ./a.out echo -n "ref: " && cd ../ref && gcc main.c -lcleri && ./a.out echo -n "repeat: " && cd ../repeat && gcc main.c -lcleri && ./a.out echo -n "sequence: " && cd ../sequence && gcc main.c -lcleri && ./a.out echo -n "token: " && cd ../token && gcc main.c -lcleri && ./a.out echo -n "tokens: " && cd ../tokens && gcc main.c -lcleri && ./a.out libcleri-0.9.4/examples/hi_iris/000077500000000000000000000000001320722715200165565ustar00rootroot00000000000000libcleri-0.9.4/examples/hi_iris/main.c000066400000000000000000000014051320722715200176460ustar00rootroot00000000000000#include #include void test_str(cleri_grammar_t * grammar, const char * str) { cleri_parse_t * pr = cleri_parse(grammar, str); printf("Test string '%s': %s\n", str, pr->is_valid ? "true" : "false"); cleri_parse_free(pr); } int main(void) { /* define grammar */ cleri_t * k_hi = cleri_keyword(0, "hi", 0); cleri_t * r_name = cleri_regex(0, "^(?:\"(?:[^\"]*)\")+"); cleri_t * start = cleri_sequence(0, 2, k_hi, r_name); /* compile grammar */ cleri_grammar_t * my_grammar = cleri_grammar(start, NULL); /* test some strings */ test_str(my_grammar, "hi \"Iris\""); // true test_str(my_grammar, "bye \"Iris\""); // false /* cleanup grammar */ cleri_grammar_free(my_grammar); return 0; }libcleri-0.9.4/examples/json/000077500000000000000000000000001320722715200161015ustar00rootroot00000000000000libcleri-0.9.4/examples/json/json.c000066400000000000000000000036171320722715200172250ustar00rootroot00000000000000/* * json.c * * This grammar is generated using the Grammar.export_c() method and * should be used with the cleri module. * * Source class: JsonGrammar * Created at: 2017-06-20 22:05:27 */ #include "json.h" #include #define CLERI_CASE_SENSITIVE 0 #define CLERI_CASE_INSENSITIVE 1 #define CLERI_FIRST_MATCH 0 #define CLERI_MOST_GREEDY 1 cleri_grammar_t * compile_grammar(void) { cleri_t * START = cleri_ref(); cleri_t * r_string = cleri_regex(CLERI_GID_R_STRING, "^(\")(?:(?=(\\\\?))\\2.)*?\\1"); cleri_t * r_float = cleri_regex(CLERI_GID_R_FLOAT, "^-?[0-9]+\\.?[0-9]+"); cleri_t * r_integer = cleri_regex(CLERI_GID_R_INTEGER, "^-?[0-9]+"); cleri_t * k_true = cleri_keyword(CLERI_GID_K_TRUE, "true", CLERI_CASE_SENSITIVE); cleri_t * k_false = cleri_keyword(CLERI_GID_K_FALSE, "false", CLERI_CASE_SENSITIVE); cleri_t * k_null = cleri_keyword(CLERI_GID_K_NULL, "null", CLERI_CASE_SENSITIVE); cleri_t * json_map_item = cleri_sequence( CLERI_GID_JSON_MAP_ITEM, 3, r_string, cleri_token(CLERI_NONE, ":"), START ); cleri_t * json_map = cleri_sequence( CLERI_GID_JSON_MAP, 3, cleri_token(CLERI_NONE, "{"), cleri_list(CLERI_NONE, json_map_item, cleri_token(CLERI_NONE, ","), 0, 0, 0), cleri_token(CLERI_NONE, "}") ); cleri_t * json_array = cleri_sequence( CLERI_GID_JSON_ARRAY, 3, cleri_token(CLERI_NONE, "["), cleri_list(CLERI_NONE, START, cleri_token(CLERI_NONE, ","), 0, 0, 0), cleri_token(CLERI_NONE, "]") ); cleri_ref_set(START, cleri_choice( CLERI_GID_START, CLERI_MOST_GREEDY, 8, r_string, r_float, r_integer, k_true, k_false, k_null, json_map, json_array )); cleri_grammar_t * grammar = cleri_grammar(START, "^\\w+"); return grammar; } libcleri-0.9.4/examples/json/json.h000066400000000000000000000013311320722715200172210ustar00rootroot00000000000000/* * json.h * * This grammar is generated using the Grammar.export_c() method and * should be used with the cleri module. * * Source class: JsonGrammar * Created at: 2017-06-20 21:53:53 */ #ifndef CLERI_EXPORT_JSON_H_ #define CLERI_EXPORT_JSON_H_ #include cleri_grammar_t * compile_grammar(void); enum cleri_grammar_ids { CLERI_NONE, // used for objects with no name CLERI_GID_JSON_ARRAY, CLERI_GID_JSON_MAP, CLERI_GID_JSON_MAP_ITEM, CLERI_GID_K_FALSE, CLERI_GID_K_NULL, CLERI_GID_K_TRUE, CLERI_GID_R_FLOAT, CLERI_GID_R_INTEGER, CLERI_GID_R_STRING, CLERI_GID_START, CLERI_END // can be used to get the enum length }; #endif /* CLERI_EXPORT_JSON_H_ */ libcleri-0.9.4/examples/json/main.c000066400000000000000000000006631320722715200171760ustar00rootroot00000000000000#include #include #include "json.h" const char * TestJSON = "{\"Name\": \"Iris\", \"Age\": 4}"; int main(void) { cleri_grammar_t * json_grammar = compile_grammar(); cleri_parse_t * pr = cleri_parse(json_grammar, TestJSON); printf("Test: %s, '%s'\n", pr->is_valid ? "true" : "false", TestJSON); /* cleanup */ cleri_parse_free(pr); cleri_grammar_free(json_grammar); return 0; } libcleri-0.9.4/examples/keyword/000077500000000000000000000000001320722715200166145ustar00rootroot00000000000000libcleri-0.9.4/examples/keyword/main.c000066400000000000000000000013351320722715200177060ustar00rootroot00000000000000#include #include const char * TestKeyword = "Tic-Tac-Toe"; int main(void) { /* define keyword */ cleri_t * k_tictactoe = cleri_keyword( 0, // gid, not used in this example "tic-tac-toe", // keyword 1); // case insensitive /* create grammar with custom keyword regular expression match */ cleri_grammar_t * grammar = cleri_grammar(k_tictactoe, "^[A-Za-z-]+"); /* parse some test string */ cleri_parse_t * pr = cleri_parse(grammar, TestKeyword); printf("Test: %s, '%s'\n", pr->is_valid ? "true" : "false", TestKeyword); /* cleanup */ cleri_parse_free(pr); cleri_grammar_free(grammar); return 0; }libcleri-0.9.4/examples/list/000077500000000000000000000000001320722715200161035ustar00rootroot00000000000000libcleri-0.9.4/examples/list/main.c000066400000000000000000000015671320722715200172040ustar00rootroot00000000000000#include #include const char * TestList = "ni, ni, ni, ni, ni"; int main(void) { /* define grammar */ cleri_t * list = cleri_list( 0, // gid, not used in this example cleri_keyword(0, "ni", 0), // repeated element cleri_token(0, ","), // delimiter element 0, // min n times 0, // max n times (0 for unlimited) 0); // disallow ending with a delimiter /* create grammar */ cleri_grammar_t * grammar = cleri_grammar(list, NULL); /* parse some test string */ cleri_parse_t * pr = cleri_parse(grammar, TestList); printf("Test: %s, '%s'\n", pr->is_valid ? "true" : "false", TestList); /* cleanup */ cleri_parse_free(pr); cleri_grammar_free(grammar); return 0; } libcleri-0.9.4/examples/optional/000077500000000000000000000000001320722715200167555ustar00rootroot00000000000000libcleri-0.9.4/examples/optional/main.c000066400000000000000000000016401320722715200200460ustar00rootroot00000000000000#include #include const char * TestOptional = "hello"; int main(void) { /* define grammar */ cleri_t * k_hello = cleri_keyword(0, "hello", 0); cleri_t * k_there = cleri_keyword(0, "there", 0); cleri_t * optional = cleri_optional( 0, // gid, not used in this example k_there); // optional element cleri_t * greet = cleri_sequence( 0, // gid, not used in this example 2, // number of elements k_hello, optional); // elements /* create grammar */ cleri_grammar_t * grammar = cleri_grammar(greet, NULL); /* parse some test string */ cleri_parse_t * pr = cleri_parse(grammar, TestOptional); printf("Test: %s, '%s'\n", pr->is_valid ? "true" : "false", TestOptional); /* cleanup */ cleri_parse_free(pr); cleri_grammar_free(grammar); return 0; } libcleri-0.9.4/examples/prio/000077500000000000000000000000001320722715200161015ustar00rootroot00000000000000libcleri-0.9.4/examples/prio/main.c000066400000000000000000000025671320722715200172030ustar00rootroot00000000000000#include #include const char * TestPrio = "(ni or ni) and (ni or ni)"; int main(void) { /* * define grammar. * * Note: The third and fourth element are using a reference to the prio * element at the same position in the string as the prio element. * This is why a forward reference cannot be used for this example. */ cleri_t * prio = cleri_prio( 0, // gid, not used in the example 4, // number of elements cleri_keyword(0, "ni", 0), // first element cleri_sequence(0, 3, // second element cleri_token(0, "("), CLERI_THIS, cleri_token(0, ")")), cleri_sequence(0, 3, // third element CLERI_THIS, cleri_keyword(0, "or", 0), CLERI_THIS), cleri_sequence(0, 3, // fourth element CLERI_THIS, cleri_keyword(0, "and", 0), CLERI_THIS)); /* create grammar */ cleri_grammar_t * grammar = cleri_grammar(prio, NULL); /* parse some test string */ cleri_parse_t * pr = cleri_parse(grammar, TestPrio); printf("Test: %s, '%s'\n", pr->is_valid ? "true" : "false", TestPrio); /* cleanup */ cleri_parse_free(pr); cleri_grammar_free(grammar); return 0; } libcleri-0.9.4/examples/ref/000077500000000000000000000000001320722715200157045ustar00rootroot00000000000000libcleri-0.9.4/examples/ref/main.c000066400000000000000000000014241320722715200167750ustar00rootroot00000000000000#include #include const char * TestRef = "[ni, ni, [ni, [], [ni, ni]]]"; int main(void) { /* define grammar */ cleri_t * ref = cleri_ref(); cleri_t * choice = cleri_choice( 0, 0, 2, cleri_keyword(0, "ni", 0), ref); cleri_ref_set(ref, cleri_sequence( 0, 3, cleri_token(0, "["), cleri_list(0, choice, cleri_token(0, ","), 0, 0, 0), cleri_token(0, "]"))); /* create grammar */ cleri_grammar_t * grammar = cleri_grammar(ref, NULL); /* parse some test string */ cleri_parse_t * pr = cleri_parse(grammar, TestRef); printf("Test: %s, '%s'\n", pr->is_valid ? "true" : "false", TestRef); /* cleanup */ cleri_parse_free(pr); cleri_grammar_free(grammar); return 0; }libcleri-0.9.4/examples/repeat/000077500000000000000000000000001320722715200164105ustar00rootroot00000000000000libcleri-0.9.4/examples/repeat/main.c000066400000000000000000000013761320722715200175070ustar00rootroot00000000000000#include #include const char * TestRepeat = "ni ni ni ni ni"; int main(void) { /* define grammar */ cleri_t * repeat = cleri_repeat( 0, // gid, not used in this example cleri_keyword(0, "ni", 0), // repeated element 0, // min n times 0); // max n times (0 for unlimited) /* create grammar */ cleri_grammar_t * grammar = cleri_grammar(repeat, NULL); /* parse some test string */ cleri_parse_t * pr = cleri_parse(grammar, TestRepeat); printf("Test: %s, '%s'\n", pr->is_valid ? "true" : "false", TestRepeat); /* cleanup */ cleri_parse_free(pr); cleri_grammar_free(grammar); return 0; } libcleri-0.9.4/examples/sequence/000077500000000000000000000000001320722715200167405ustar00rootroot00000000000000libcleri-0.9.4/examples/sequence/main.c000066400000000000000000000015051320722715200200310ustar00rootroot00000000000000#include #include const char * TestSequence = "Tic Tac Toe"; int main(void) { /* define grammar */ cleri_t * sequence = cleri_sequence( 0, // gid, not used in the example 3, // number of elements cleri_keyword(0, "Tic", 0), // first element cleri_keyword(0, "Tac", 0), // second element cleri_keyword(0, "Toe", 0)); // third element /* create grammar */ cleri_grammar_t * grammar = cleri_grammar(sequence, NULL); /* parse some test string */ cleri_parse_t * pr = cleri_parse(grammar, TestSequence); printf("Test: %s, '%s'\n", pr->is_valid ? "true" : "false", TestSequence); /* cleanup */ cleri_parse_free(pr); cleri_grammar_free(grammar); return 0; } libcleri-0.9.4/examples/token/000077500000000000000000000000001320722715200162505ustar00rootroot00000000000000libcleri-0.9.4/examples/token/main.c000066400000000000000000000013161320722715200173410ustar00rootroot00000000000000#include #include const char * TestToken = "ni-ni - ni- ni -ni"; int main(void) { /* define grammar */ cleri_t * token = cleri_token( 0, // gid, not used in this example "-"); // token string (dash) cleri_t * ni = cleri_keyword(0, "ni", 0); cleri_t * list = cleri_list(0, ni, token, 0, 0, 0); /* create grammar */ cleri_grammar_t * grammar = cleri_grammar(list, NULL); /* parse some test string */ cleri_parse_t * pr = cleri_parse(grammar, TestToken); printf("Test: %s, '%s'\n", pr->is_valid ? "true" : "false", TestToken); /* cleanup */ cleri_parse_free(pr); cleri_grammar_free(grammar); return 0; } libcleri-0.9.4/examples/tokens/000077500000000000000000000000001320722715200164335ustar00rootroot00000000000000libcleri-0.9.4/examples/tokens/main.c000066400000000000000000000013501320722715200175220ustar00rootroot00000000000000#include #include const char * TestTokens = "ni + ni -= ni - ni"; int main(void) { /* define grammar */ cleri_t * tokens = cleri_tokens( 0, // gid, not used in this example "+ - -="); // tokens string '+', '-' and '-=' cleri_t * ni = cleri_keyword(0, "ni", 0); cleri_t * list = cleri_list(0, ni, tokens, 0, 0, 0); /* create grammar */ cleri_grammar_t * grammar = cleri_grammar(list, NULL); /* parse some test string */ cleri_parse_t * pr = cleri_parse(grammar, TestTokens); printf("Test: %s, '%s'\n", pr->is_valid ? "true" : "false", TestTokens); /* cleanup */ cleri_parse_free(pr); cleri_grammar_free(grammar); return 0; } libcleri-0.9.4/inc/000077500000000000000000000000001320722715200140635ustar00rootroot00000000000000libcleri-0.9.4/inc/cleri/000077500000000000000000000000001320722715200151615ustar00rootroot00000000000000libcleri-0.9.4/inc/cleri/children.h000066400000000000000000000014311320722715200171210ustar00rootroot00000000000000/* * children.h - linked list for keeping node results * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2016, Transceptor Technology * * changes * - initial version, 08-03-2016 * - refactoring, 17-06-2017 */ #ifndef CLERI_CHILDREN_H_ #define CLERI_CHILDREN_H_ #include /* typedefs */ typedef struct cleri_node_s cleri_node_t; typedef struct cleri_children_s cleri_children_t; /* private functions */ cleri_children_t * cleri__children_new(void); void cleri__children_free(cleri_children_t * children); int cleri__children_add(cleri_children_t * children, cleri_node_t * node); /* structs */ struct cleri_children_s { cleri_node_t * node; cleri_children_t * next; }; #endif /* CLERI_CHILDREN_H_ */libcleri-0.9.4/inc/cleri/choice.h000066400000000000000000000016051320722715200165660ustar00rootroot00000000000000/* * choice.h - this cleri element can hold other elements and the grammar * has to choose one of them. * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2017, Transceptor Technology * * changes * - initial version, 08-03-2016 * - refactoring, 17-06-2017 */ #ifndef CLERI_CHOICE_H_ #define CLERI_CHOICE_H_ #include #include #include #include /* typedefs */ typedef struct cleri_s cleri_t; typedef struct cleri_olist_s cleri_olist_t; typedef struct cleri_choice_s cleri_choice_t; /* public functions */ #ifdef __cplusplus extern "C" { #endif cleri_t * cleri_choice(uint32_t gid, int most_greedy, size_t len, ...); #ifdef __cplusplus } #endif /* structs */ struct cleri_choice_s { int most_greedy; cleri_olist_t * olist; }; #endif /* CLERI_CHOICE_H_ */libcleri-0.9.4/inc/cleri/cleri.h000066400000000000000000000067441320722715200164430ustar00rootroot00000000000000/* * cleri.h - each cleri element is a cleri object. * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2016, Transceptor Technology * * changes * - initial version, 08-03-2016 * - refactoring, 17-06-2017 */ #ifndef CLERI_OBJECT_H_ #define CLERI_OBJECT_H_ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* typedefs */ typedef struct cleri_s cleri_t; typedef struct cleri_grammar_s cleri_grammar_t; typedef struct cleri_keyword_s cleri_keyword_t; typedef struct cleri_sequence_s cleri_sequence_t; typedef struct cleri_optional_s cleri_optional_t; typedef struct cleri_choice_s cleri_choice_t; typedef struct cleri_regex_s cleri_regex_t; typedef struct cleri_list_s cleri_list_t; typedef struct cleri_repeat_s cleri_repeat_t; typedef struct cleri_token_s cleri_token_t; typedef struct cleri_tokens_s cleri_tokens_t; typedef struct cleri_prio_s cleri_prio_t; typedef struct cleri_rule_s cleri_rule_t; typedef struct cleri_rule_store_s cleri_rule_store_t; typedef struct cleri_node_s cleri_node_t; typedef struct cleri_parse_s cleri_parse_t; typedef struct cleri_ref_s cleri_ref_t; typedef struct cleri_s cleri_t; typedef struct cleri_dup_s cleri_dup_t; typedef union cleri_u cleri_via_t; typedef void (*cleri_free_object_t)(cleri_t *); typedef cleri_node_t * (*cleri_parse_object_t)( cleri_parse_t *, cleri_node_t *, cleri_t *, cleri_rule_store_t *); /* enums */ typedef enum cleri_e { CLERI_TP_SEQUENCE, CLERI_TP_OPTIONAL, CLERI_TP_CHOICE, CLERI_TP_LIST, CLERI_TP_REPEAT, CLERI_TP_PRIO, CLERI_TP_RULE, CLERI_TP_THIS, /* all items after this will not get children */ CLERI_TP_KEYWORD, CLERI_TP_TOKEN, CLERI_TP_TOKENS, CLERI_TP_REGEX, CLERI_TP_REF, CLERI_TP_END_OF_STATEMENT } cleri_tp; /* unions */ union cleri_u { cleri_keyword_t * keyword; cleri_sequence_t * sequence; cleri_optional_t * optional; cleri_choice_t * choice; cleri_regex_t * regex; cleri_list_t * list; cleri_repeat_t * repeat; cleri_token_t * token; cleri_tokens_t * tokens; cleri_prio_t * prio; cleri_rule_t * rule; cleri_dup_t * dup; void * dummy; /* place holder */ }; /* public functions */ #ifdef __cplusplus extern "C" { #endif cleri_t * cleri_new( uint32_t gid, cleri_tp tp, cleri_free_object_t free_object, cleri_parse_object_t parse_object); void cleri_incref(cleri_t * cl_object); void cleri_decref(cleri_t * cl_object); int cleri_free(cleri_t * cl_object); #ifdef __cplusplus } #endif /* fixed end of statement object */ extern cleri_t * CLERI_END_OF_STATEMENT; /* structs */ #define CLERI_OBJECT_FIELDS \ uint32_t gid; \ uint32_t ref; \ cleri_free_object_t free_object; \ cleri_parse_object_t parse_object; \ cleri_tp tp; \ cleri_via_t via; struct cleri_s { CLERI_OBJECT_FIELDS }; struct cleri_dup_s { CLERI_OBJECT_FIELDS cleri_t * dup; }; #endif /* CLERI_OBJECT_H_ */libcleri-0.9.4/inc/cleri/dup.h000066400000000000000000000012561320722715200161260ustar00rootroot00000000000000/* * dup.h - this cleri element can be used to duplicate an element. * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2017, Transceptor Technology * * changes * - initial version, 21-06-2017 * */ #ifndef CLERI_DUP_H_ #define CLERI_DUP_H_ #include #include #include /* typedefs */ typedef struct cleri_s cleri_t; typedef struct cleri_dup_s cleri_dup_t; /* public functions */ #ifdef __cplusplus extern "C" { #endif cleri_t * cleri_dup(uint32_t gid, cleri_t * cl_obj); #ifdef __cplusplus } #endif /* structs */ // cleri_dup_t is defined in cleri.h #endif /* CLERI_DUP_H_ */libcleri-0.9.4/inc/cleri/expecting.h000066400000000000000000000027251320722715200173260ustar00rootroot00000000000000/* * expecting.h - holds elements which the grammar expects at one position. * this can be used for suggestions. * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2016, Transceptor Technology * * changes * - initial version, 08-03-2016 * - refactoring, 17-06-2017 */ #ifndef CLERI_EXPECTING_H_ #define CLERI_EXPECTING_H_ #include #include #include #include #define CLERI__EXP_MODE_OPTIONAL 0 #define CLERI__EXP_MODE_REQUIRED 1 /* typedefs */ typedef struct cleri_s cleri_t; typedef struct cleri_olist_s cleri_olist_t; typedef struct cleri_exp_modes_s cleri_exp_modes_t; typedef struct cleri_expecting_s cleri_expecting_t; /* private functions */ cleri_expecting_t * cleri__expecting_new(const char * str); int cleri__expecting_update( cleri_expecting_t * expecting, cleri_t * cl_obj, const char * str); int cleri__expecting_set_mode( cleri_expecting_t * expecting, const char * str, int mode); void cleri__expecting_free(cleri_expecting_t * expecting); void cleri__expecting_combine(cleri_expecting_t * expecting); /* structs */ struct cleri_exp_modes_s { int mode; const char * str; cleri_exp_modes_t * next; }; struct cleri_expecting_s { const char * str; cleri_olist_t * required; cleri_olist_t * optional; cleri_exp_modes_t * modes; }; #endif /* CLERI_EXPECTING_H_ */libcleri-0.9.4/inc/cleri/grammar.h000066400000000000000000000016371320722715200167670ustar00rootroot00000000000000/* * grammar.h - this should contain the 'start' or your grammar. * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2016, Transceptor Technology * * changes * - initial version, 08-03-2016 * - refactoring, 17-06-2017 */ #ifndef CLERI_GRAMMAR_H_ #define CLERI_GRAMMAR_H_ #include #include #include #define CLERI_DEFAULT_RE_KEYWORDS "^\\w+" /* typedefs */ typedef struct cleri_s cleri_t; typedef struct cleri_grammar_s cleri_grammar_t; /* public functions */ #ifdef __cplusplus extern "C" { #endif cleri_grammar_t * cleri_grammar(cleri_t * start, const char * re_keywords); void cleri_grammar_free(cleri_grammar_t * grammar); #ifdef __cplusplus } #endif /* structs */ struct cleri_grammar_s { cleri_t * start; pcre2_code * re_keywords; pcre2_match_data * match_data; }; #endif /* CLERI_GRAMMAR_H_ */libcleri-0.9.4/inc/cleri/keyword.h000066400000000000000000000014071320722715200170200ustar00rootroot00000000000000/* * keyword.h - cleri keyword element * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2016, Transceptor Technology * * changes * - initial version, 08-03-2016 * - refactoring, 17-06-2017 */ #ifndef CLERI_KEYWORD_H_ #define CLERI_KEYWORD_H_ #include #include #include /* typedefs */ typedef struct cleri_s cleri_t; typedef struct cleri_keyword_s cleri_keyword_t; /* public functions */ #ifdef __cplusplus extern "C" { #endif cleri_t * cleri_keyword(uint32_t gid, const char * keyword, int ign_case); #ifdef __cplusplus } #endif /* structs */ struct cleri_keyword_s { const char * keyword; int ign_case; size_t len; }; #endif /* CLERI_KEYWORD_H_ */libcleri-0.9.4/inc/cleri/kwcache.h000066400000000000000000000015311320722715200167370ustar00rootroot00000000000000/* * kwcache.h - holds keyword regular expression result while parsing. * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2016, Transceptor Technology * * changes * - initial version, 08-03-2016 * - refactoring, 17-06-2017 */ #ifndef CLERI_KWCACHE_H_ #define CLERI_KWCACHE_H_ #include #include #include /* typedefs */ typedef struct cleri_parse_s cleri_parse_t; typedef struct cleri_kwcache_s cleri_kwcache_t; /* private functions */ cleri_kwcache_t * cleri__kwcache_new(void); ssize_t cleri__kwcache_match(cleri_parse_t * pr, const char * str); void cleri__kwcache_free(cleri_kwcache_t * kwcache); /* structs */ struct cleri_kwcache_s { size_t len; const char * str; cleri_kwcache_t * next; }; #endif /* CLERI_KWCACHE_H_ */ libcleri-0.9.4/inc/cleri/list.h000066400000000000000000000016101320722715200163030ustar00rootroot00000000000000/* * list.h - cleri list element. * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2016, Transceptor Technology * * changes * - initial version, 08-03-2016 * - refactoring, 17-06-2017 */ #ifndef CLERI_LIST_H_ #define CLERI_LIST_H_ #include #include #include #include /* typedefs */ typedef struct cleri_s cleri_t; typedef struct cleri_list_s cleri_list_t; /* public functions */ #ifdef __cplusplus extern "C" { #endif cleri_t * cleri_list( uint32_t gid, cleri_t * cl_obj, cleri_t * delimiter, size_t min, size_t max, int opt_closing); #ifdef __cplusplus } #endif /* structs */ struct cleri_list_s { cleri_t * cl_obj; cleri_t * delimiter; size_t min; size_t max; int opt_closing; }; #endif /* CLERI_LIST_H_ */libcleri-0.9.4/inc/cleri/node.h000066400000000000000000000022631320722715200162620ustar00rootroot00000000000000/* * node.h - node is created while parsing a string. a node old the result * for one element. * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2016, Transceptor Technology * * changes * - initial version, 08-03-2016 * - refactoring, 17-06-2017 */ #ifndef CLERI_NODE_H_ #define CLERI_NODE_H_ #include #include #include #include /* typedefs */ typedef struct cleri_s cleri_t; typedef struct cleri_children_s cleri_children_t; typedef struct cleri_node_s cleri_node_t; /* public macro function */ #define cleri_node_has_children(__node) \ (__node->children != NULL && __node->children->node != NULL) /* private functions */ cleri_node_t * cleri__node_new(cleri_t * cl_obj, const char * str, size_t len); void cleri__node_free(cleri_node_t * node); /* private use as empty node */ extern cleri_node_t * CLERI_EMPTY_NODE; /* structs */ struct cleri_node_s { /* public */ const char * str; size_t len; cleri_t * cl_obj; cleri_children_t * children; /* private */ uint_fast8_t ref; int64_t result; }; #endif /* CLERI_NODE_H_ */libcleri-0.9.4/inc/cleri/olist.h000066400000000000000000000016711320722715200164710ustar00rootroot00000000000000/* * olist.h - linked list for keeping cleri objects. * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2016, Transceptor Technology * * changes * - initial version, 08-03-2016 * - refactoring, 17-06-2017 */ #ifndef CLERI_OLIST_H_ #define CLERI_OLIST_H_ #include /* typedefs */ typedef struct cleri_s cleri_t; typedef struct cleri_olist_s cleri_olist_t; typedef struct cleri_olist_s cleri_olist_t; /* private functions */ cleri_olist_t * cleri__olist_new(void); int cleri__olist_append(cleri_olist_t * olist, cleri_t * cl_object); int cleri__olist_append_nref(cleri_olist_t * olist, cleri_t * cl_object); void cleri__olist_free(cleri_olist_t * olist); void cleri__olist_empty(cleri_olist_t * olist); void cleri__olist_cancel(cleri_olist_t * olist); /* structs */ struct cleri_olist_s { cleri_t * cl_obj; cleri_olist_t * next; }; #endif /* CLERI_OLIST_H_ */libcleri-0.9.4/inc/cleri/optional.h000066400000000000000000000013061320722715200171570ustar00rootroot00000000000000/* * optional.h - cleri optional element. * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2016, Transceptor Technology * * changes * - initial version, 08-03-2016 * - refactoring, 17-06-2017 */ #ifndef CLERI_OPTIONAL_H_ #define CLERI_OPTIONAL_H_ #include #include /* typedefs */ typedef struct cleri_s cleri_t; typedef struct cleri_optional_s cleri_optional_t; /* public functions */ #ifdef __cplusplus extern "C" { #endif cleri_t * cleri_optional(uint32_t gid, cleri_t * cl_obj); #ifdef __cplusplus } #endif /* structs */ struct cleri_optional_s { cleri_t * cl_obj; }; #endif /* CLERI_OPTIONAL_H_ */libcleri-0.9.4/inc/cleri/parse.h000066400000000000000000000031631320722715200164470ustar00rootroot00000000000000/* * parser.h - this contains the start for parsing a string to a grammar. * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2016, Transceptor Technology * * changes * - initial version, 08-03-2016 * - refactoring, 17-06-2017 */ #ifndef CLERI_PARSE_H_ #define CLERI_PARSE_H_ #include #include #include #include #include #include #include #include /* typedefs */ typedef struct cleri_s cleri_t; typedef struct cleri_grammar_s cleri_grammar_t; typedef struct cleri_node_s cleri_node_t; typedef struct cleri_expecting_s cleri_expecting_t; typedef struct cleri_kwcache_s cleri_kwcache_t; typedef struct cleri_rule_store_s cleri_rule_store_t; typedef struct cleri_parse_s cleri_parse_t; /* public functions */ #ifdef __cplusplus extern "C" { #endif cleri_parse_t * cleri_parse(cleri_grammar_t * grammar, const char * str); void cleri_parse_free(cleri_parse_t * pr); void cleri_parse_expect_start(cleri_parse_t * pr); #ifdef __cplusplus } #endif /* private functions */ cleri_node_t * cleri__parse_walk( cleri_parse_t * pr, cleri_node_t * parent, cleri_t * cl_obj, cleri_rule_store_t * rule, int mode); /* structs */ struct cleri_parse_s { int is_valid; size_t pos; const char * str; cleri_node_t * tree; const cleri_olist_t * expect; cleri_expecting_t * expecting; pcre2_code * re_keywords; pcre2_match_data * match_data; cleri_kwcache_t * kwcache; }; #endif /* CLERI_PARSE_H_ */libcleri-0.9.4/inc/cleri/prio.h000066400000000000000000000015471320722715200163120ustar00rootroot00000000000000/* * prio.h - cleri prio element. (this element create a cleri rule object * holding this prio element) * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2016, Transceptor Technology * * changes * - initial version, 08-03-2016 * - refactoring, 17-06-2017 */ #ifndef CLERI_PRIO_H_ #define CLERI_PRIO_H_ #include #include #include #include #include /* typedefs */ typedef struct cleri_s cleri_t; typedef struct cleri_olist_s cleri_olist_t; typedef struct cleri_prio_s cleri_prio_t; /* public functions */ #ifdef __cplusplus extern "C" { #endif cleri_t * cleri_prio(uint32_t gid, size_t len, ...); #ifdef __cplusplus } #endif /* structs */ struct cleri_prio_s { cleri_olist_t * olist; }; #endif /* CLERI_PRIO_H_ */libcleri-0.9.4/inc/cleri/ref.h000066400000000000000000000011071320722715200161050ustar00rootroot00000000000000/* * ref.h - cleri ref element * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2017, Transceptor Technology * * changes * - initial version, 20-06-2017 * */ #ifndef CLERI_REF_H_ #define CLERI_REF_H_ #include #include #include /* typedefs */ typedef struct cleri_s cleri_t; /* public functions */ #ifdef __cplusplus extern "C" { #endif cleri_t * cleri_ref(void); void cleri_ref_set(cleri_t * ref, cleri_t * cl_obj); #ifdef __cplusplus } #endif #endif /* CLERI_REF_H_ */libcleri-0.9.4/inc/cleri/regex.h000066400000000000000000000014511320722715200164450ustar00rootroot00000000000000/* * regex.h - cleri regular expression element. * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2016, Transceptor Technology * * changes * - initial version, 08-03-2016 * - refactoring, 17-06-2017 */ #ifndef CLERI_REGEX_H_ #define CLERI_REGEX_H_ #define PCRE2_CODE_UNIT_WIDTH 8 #include #include #include #include /* typedefs */ typedef struct cleri_s cleri_t; typedef struct cleri_regex_s cleri_regex_t; /* public functions */ #ifdef __cplusplus extern "C" { #endif cleri_t * cleri_regex(uint32_t gid, const char * pattern); #ifdef __cplusplus } #endif /* structs */ struct cleri_regex_s { pcre2_code * regex; pcre2_match_data * match_data; }; #endif /* CLERI_REGEX_H_ */libcleri-0.9.4/inc/cleri/repeat.h000066400000000000000000000014351320722715200166150ustar00rootroot00000000000000/* * repeat.h - cleri regular repeat element. * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2016, Transceptor Technology * * changes * - initial version, 08-03-2016 * - refactoring, 17-06-2017 */ #ifndef CLERI_REPEAT_H_ #define CLERI_REPEAT_H_ #include #include #include #include /* typedefs */ typedef struct cleri_s cleri_t; typedef struct cleri_repeat_s cleri_repeat_t; /* public functions */ #ifdef __cplusplus extern "C" { #endif cleri_t * cleri_repeat(uint32_t gid, cleri_t * cl_obj, size_t min, size_t max); #ifdef __cplusplus } #endif /* structs */ struct cleri_repeat_s { cleri_t * cl_obj; size_t min; size_t max; }; #endif /* CLERI_REPEAT_H_ */libcleri-0.9.4/inc/cleri/rule.h000066400000000000000000000026521320722715200163060ustar00rootroot00000000000000/* * rule.h - cleri regular rule element. (do not directly use this element but * create a 'prio' instead which will be wrapped by a rule element) * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2016, Transceptor Technology * * changes * - initial version, 08-03-2016 * - refactoring, 17-06-2017 */ #ifndef CLERI_RULE_H_ #define CLERI_RULE_H_ #include #include #include #include #include /* typedefs */ typedef struct cleri_s cleri_t; typedef struct cleri_node_s cleri_node_t; typedef struct cleri_rule_tested_s cleri_rule_tested_t; typedef struct cleri_rule_store_s cleri_rule_store_t; typedef struct cleri_rule_s cleri_rule_t; /* enums */ typedef enum cleri_rule_test_e { CLERI_RULE_ERROR=-1, CLERI_RULE_FALSE, CLERI_RULE_TRUE } cleri_rule_test_t; /* private functions */ cleri_t * cleri__rule(uint32_t gid, cleri_t * cl_obj); cleri_rule_test_t cleri__rule_init( cleri_rule_tested_t ** target, cleri_rule_tested_t * tested, const char * str); /* structs */ struct cleri_rule_tested_s { const char * str; cleri_node_t * node; cleri_rule_tested_t * next; } ; struct cleri_rule_store_s { cleri_rule_tested_t * tested; cleri_t * root_obj; size_t depth; }; struct cleri_rule_s { cleri_t * cl_obj; }; #endif /* CLERI_RULE_H_ */libcleri-0.9.4/inc/cleri/sequence.h000066400000000000000000000014431320722715200171440ustar00rootroot00000000000000/* * sequence.h - cleri sequence element. * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2016, Transceptor Technology * * changes * - initial version, 08-03-2016 * - refactoring, 17-06-2017 */ #ifndef CLERI_SEQUENCE_H_ #define CLERI_SEQUENCE_H_ #include #include #include #include /* typedefs */ typedef struct cleri_s cleri_t; typedef struct cleri_olist_s cleri_olist_t; typedef struct cleri_sequence_s cleri_sequence_t; /* public functions */ #ifdef __cplusplus extern "C" { #endif cleri_t * cleri_sequence(uint32_t gid, size_t len, ...); #ifdef __cplusplus } #endif /* structs */ struct cleri_sequence_s { cleri_olist_t * olist; }; #endif /* CLERI_SEQUENCE_H_ */libcleri-0.9.4/inc/cleri/this.h000066400000000000000000000013001320722715200162730ustar00rootroot00000000000000/* * this.h - cleri THIS element. there should be only one single instance * of this which can even be shared over different grammars. * Always use this element using its constant CLERI_THIS and * somewhere within a prio element. * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2016, Transceptor Technology * * changes * - initial version, 08-03-2016 * - refactoring, 17-06-2017 */ #ifndef CLERI_THIS_H_ #define CLERI_THIS_H_ #include #include /* typedefs */ typedef struct cleri_s cleri_t; /* public THIS */ extern cleri_t * CLERI_THIS; #endif /* CLERI_THIS_H_ */libcleri-0.9.4/inc/cleri/token.h000066400000000000000000000016441320722715200164570ustar00rootroot00000000000000/* * token.h - cleri token element. note that one single char will parse * slightly faster compared to tokens containing more characters. * (be careful a token should not match the keyword regular * expression) * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2016, Transceptor Technology * * changes * - initial version, 08-03-2016 * - refactoring, 17-06-2017 */ #ifndef CLERI_TOKEN_H_ #define CLERI_TOKEN_H_ #include #include #include /* typedefs */ typedef struct cleri_s cleri_t; typedef struct cleri_token_s cleri_token_t; /* public functions */ #ifdef __cplusplus extern "C" { #endif cleri_t * cleri_token(uint32_t gid, const char * token); #ifdef __cplusplus } #endif /* structs */ struct cleri_token_s { const char * token; size_t len; }; #endif /* CLERI_TOKEN_H_ */ libcleri-0.9.4/inc/cleri/tokens.h000066400000000000000000000017051320722715200166400ustar00rootroot00000000000000/* * tokens.h - cleri tokens element. (like token but can contain more tokens * in one element) * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2016, Transceptor Technology * * changes * - initial version, 08-03-2016 * - refactoring, 17-06-2017 */ #ifndef CLERI_TOKENS_H_ #define CLERI_TOKENS_H_ #include #include #include /* typedefs */ typedef struct cleri_s cleri_t; typedef struct cleri_tlist_s cleri_tlist_t; typedef struct cleri_tokens_s cleri_tokens_t; /* public functions */ #ifdef __cplusplus extern "C" { #endif cleri_t * cleri_tokens(uint32_t gid, const char * tokens); #ifdef __cplusplus } #endif /* structs */ struct cleri_tlist_s { const char * token; size_t len; cleri_tlist_t * next; }; struct cleri_tokens_s { char * tokens; char * spaced; cleri_tlist_t * tlist; }; #endif /* CLERI_TOKENS_H_ */libcleri-0.9.4/inc/cleri/version.h000066400000000000000000000015161320722715200170220ustar00rootroot00000000000000/* * version.h * * Created on: Jun 19, 2017 * Author: Jeroen van der Heijden */ #ifndef CLERI_VERSION_H_ #define CLERI_VERSION_H_ #define LIBCLERI_VERSION_MAJOR 0 #define LIBCLERI_VERSION_MINOR 9 #define LIBCLERI_VERSION_PATCH 4 #define LIBCLERI_STRINGIFY(num) #num #define LIBCLERI_VERSION_STR(major,minor,patch) \ LIBCLERI_STRINGIFY(major) "." \ LIBCLERI_STRINGIFY(minor) "." \ LIBCLERI_STRINGIFY(patch) #define LIBCLERI_VERSION LIBCLERI_VERSION_STR( \ LIBCLERI_VERSION_MAJOR, \ LIBCLERI_VERSION_MINOR, \ LIBCLERI_VERSION_PATCH) /* public funtion */ #ifdef __cplusplus extern "C" { #endif const char * cleri_version(void); #ifdef __cplusplus } #endif #endif /* CLERI_VERSION_H_ */libcleri-0.9.4/makefile.init000066400000000000000000000001061320722715200157510ustar00rootroot00000000000000MAJOR := 0 MINOR := 9 PATCH := 4 VERSION := $(MAJOR).$(MINOR).$(PATCH)libcleri-0.9.4/makefile.targets000066400000000000000000000010461320722715200164630ustar00rootroot00000000000000.PHONY: install install: @mkdir $(INSTALL_PATH)/include/cleri @cp ../inc/cleri/*.h $(INSTALL_PATH)/include/cleri/ @cp $(FN) $(INSTALL_PATH)/lib/$(FN).$(VERSION) @ln -s $(INSTALL_PATH)/lib/$(FN).$(VERSION) $(INSTALL_PATH)/lib/$(FN).$(MAJOR) @ln -s $(INSTALL_PATH)/lib/$(FN).$(VERSION) $(INSTALL_PATH)/lib/$(FN) .PHONY: uninstall uninstall: @rm -f $(INSTALL_PATH)/include/cleri/*.h @rmdir $(INSTALL_PATH)/include/cleri/ @rm -f $(INSTALL_PATH)/lib/$(FN) @rm -f $(INSTALL_PATH)/lib/$(FN).$(MAJOR) @rm -f $(INSTALL_PATH)/lib/$(FN).$(VERSION) libcleri-0.9.4/src/000077500000000000000000000000001320722715200141015ustar00rootroot00000000000000libcleri-0.9.4/src/children.c000066400000000000000000000027461320722715200160460ustar00rootroot00000000000000/* * children.c - linked list for keeping node results * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2016, Transceptor Technology * * changes * - initial version, 08-03-2016 * */ #include #include /* * Returns NULL and in case an error has occurred. */ cleri_children_t * cleri__children_new(void) { cleri_children_t * children = (cleri_children_t *) malloc(sizeof(cleri_children_t)); if (children != NULL) { children->node = NULL; children->next = NULL; } return children; } /* * Appends a node to children. * * Returns 0 when successful or -1 in case of an error. */ int cleri__children_add(cleri_children_t * children, cleri_node_t * node) { if (children->node == NULL) { children->node = node; return 0; } while (children->next != NULL) { children = children->next; } children->next = (cleri_children_t *) malloc(sizeof(cleri_children_t)); if (children->next == NULL) { return -1; } else { children->next->node = node; children->next->next = NULL; } return 0; } /* * Destroy children. */ void cleri__children_free(cleri_children_t * children) { cleri_children_t * next; while (children != NULL) { next = children->next; cleri__node_free(children->node); free(children); children = next; } } libcleri-0.9.4/src/choice.c000066400000000000000000000123421320722715200155010ustar00rootroot00000000000000/* * choice.c - this cleri element can hold other elements and the grammar * has to choose one of them. * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2016, Transceptor Technology * * changes * - initial version, 08-03-2016 * - fixed issue #53, 23-02-2017 */ #include #include #include #include #include static void CHOICE_free(cleri_t * cl_object); static cleri_node_t * CHOICE_parse( cleri_parse_t * pr, cleri_node_t * parent, cleri_t * cl_obj, cleri_rule_store_t * rule); static cleri_node_t * CHOICE_parse_most_greedy( cleri_parse_t * pr, cleri_node_t * parent, cleri_t * cl_obj, cleri_rule_store_t * rule); static cleri_node_t * CHOICE_parse_first_match( cleri_parse_t * pr, cleri_node_t * parent, cleri_t * cl_obj, cleri_rule_store_t * rule); /* * Returns NULL in case an error has occurred. */ cleri_t * cleri_choice(uint32_t gid, int most_greedy, size_t len, ...) { va_list ap; cleri_t * cl_object = cleri_new( gid, CLERI_TP_CHOICE, &CHOICE_free, &CHOICE_parse); if (cl_object == NULL) { return NULL; } cl_object->via.choice = (cleri_choice_t *) malloc(sizeof(cleri_choice_t)); if (cl_object->via.choice == NULL) { free(cl_object); return NULL; } cl_object->via.choice->most_greedy = most_greedy; cl_object->via.choice->olist = cleri__olist_new(); if (cl_object->via.choice->olist == NULL) { cleri_free(cl_object); return NULL; } va_start(ap, len); while(len--) { if (cleri__olist_append( cl_object->via.choice->olist, va_arg(ap, cleri_t *))) { cleri__olist_cancel(cl_object->via.choice->olist); cleri_free(cl_object); cl_object = NULL; break; } } va_end(ap); return cl_object; } /* * Destroy choice object. */ static void CHOICE_free(cleri_t * cl_object) { cleri__olist_free(cl_object->via.choice->olist); free(cl_object->via.choice); } /* * Returns a node or NULL. */ static cleri_node_t * CHOICE_parse( cleri_parse_t * pr, cleri_node_t * parent, cleri_t * cl_obj, cleri_rule_store_t * rule) { return (cl_obj->via.choice->most_greedy) ? CHOICE_parse_most_greedy(pr, parent, cl_obj, rule) : CHOICE_parse_first_match(pr, parent, cl_obj, rule); } /* * Returns a node or NULL. In case of an error pr->is_valid is set to -1. */ static cleri_node_t * CHOICE_parse_most_greedy( cleri_parse_t * pr, cleri_node_t * parent, cleri_t * cl_obj, cleri_rule_store_t * rule) { cleri_olist_t * olist; cleri_node_t * node; cleri_node_t * rnode; cleri_node_t * mg_node = NULL; const char * str = parent->str + parent->len; olist = cl_obj->via.choice->olist; while (olist != NULL) { if ((node = cleri__node_new(cl_obj, str, 0)) == NULL) { pr->is_valid = -1; return NULL; } rnode = cleri__parse_walk( pr, node, olist->cl_obj, rule, CLERI__EXP_MODE_REQUIRED); if (rnode != NULL && (mg_node == NULL || node->len > mg_node->len)) { cleri__node_free(mg_node); mg_node = node; } else { cleri__node_free(node); } olist = olist->next; } if (mg_node != NULL) { parent->len += mg_node->len; if (cleri__children_add(parent->children, mg_node)) { /* error occurred, reverse changes set mg_node to NULL */ pr->is_valid = -1; parent->len -= mg_node->len; cleri__node_free(mg_node); mg_node = NULL; } } return mg_node; } /* * Returns a node or NULL. In case of an error pr->is_valid is set to -1. */ static cleri_node_t * CHOICE_parse_first_match( cleri_parse_t * pr, cleri_node_t * parent, cleri_t * cl_obj, cleri_rule_store_t * rule) { cleri_olist_t * olist; cleri_node_t * node; cleri_node_t * rnode; olist = cl_obj->via.choice->olist; node = cleri__node_new(cl_obj, parent->str + parent->len, 0); if (node == NULL) { pr->is_valid = -1; return NULL; } while (olist != NULL) { rnode = cleri__parse_walk( pr, node, olist->cl_obj, rule, CLERI__EXP_MODE_REQUIRED); if (rnode != NULL) { parent->len += node->len; if (cleri__children_add(parent->children, node)) { /* error occurred, reverse changes set mg_node to NULL */ pr->is_valid = -1; parent->len -= node->len; cleri__node_free(node); node = NULL; } return node; } olist = olist->next; } cleri__node_free(node); return NULL; } libcleri-0.9.4/src/cleri.c000066400000000000000000000047211320722715200153470ustar00rootroot00000000000000/* * object.c - each cleri element is a cleri object. * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2016, Transceptor Technology * * changes * - initial version, 08-03-2016 * */ #include #include #include static cleri_t end_of_statement = { .gid=0, .ref=1, .free_object=NULL, .parse_object=NULL, .tp=CLERI_TP_END_OF_STATEMENT, .via={.dummy=NULL}}; cleri_t * CLERI_END_OF_STATEMENT = &end_of_statement; /* * Returns NULL in case an error has occurred. */ cleri_t * cleri_new( uint32_t gid, cleri_tp tp, cleri_free_object_t free_object, cleri_parse_object_t parse_object) { cleri_t * cl_object; cl_object = (cleri_t *) malloc(sizeof(cleri_t)); if (cl_object != NULL) { cl_object->gid = gid; cl_object->tp = tp; cl_object->ref = 1; cl_object->via.dummy = NULL; cl_object->free_object = free_object; cl_object->parse_object = parse_object; } return cl_object; } /* * Increment reference counter on cleri object. */ void cleri_incref(cleri_t * cl_object) { cl_object->ref++; } /* * Decrement reference counter. * If no references are left the object is destoryed. (never the element) */ void cleri_decref(cleri_t * cl_object) { if (!--cl_object->ref) { free(cl_object); } } /* * Recursive cleanup an object including the element. * If there are still references left, then only the element but not the object * is not destroyed and this function will return -1. If successful * cleaned the return value is 0. */ int cleri_free(cleri_t * cl_object) { if (cl_object->tp == CLERI_TP_THIS) { return 0; } /* Use tp to check because we need to be sure this check validates false * before calling the free function. */ if (cl_object->tp != CLERI_TP_REF) { /* Change the type so the other are treated as references */ cl_object->tp = CLERI_TP_REF; (*cl_object->free_object)(cl_object); /* We decrement once more as soon as the element has joined at least * one other element so we don't have to run the cleanup on this * specific element. */ if (cl_object->ref > 1) { cl_object->ref--; } } if (!--cl_object->ref) { free(cl_object); return 0; } return -1; } libcleri-0.9.4/src/dup.c000066400000000000000000000017511320722715200150410ustar00rootroot00000000000000/* * dup.c - this cleri element can be used to duplicate an element. * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2017, Transceptor Technology * * changes * - initial version, 21-06-2017 * */ #include static void DUP_free(cleri_t * cl_object); /* * Duplicate a libcleri object. * Note: a pointer to the original object->via (element) is used. */ cleri_t * cleri_dup(uint32_t gid, cleri_t * cl_obj) { cleri_dup_t * dup = (cleri_dup_t *) malloc(sizeof(cleri_dup_t)); if (dup != NULL) { dup->gid = gid; dup->ref = 1; dup->tp = cl_obj->tp; dup->via = cl_obj->via; dup->free_object = &DUP_free; dup->parse_object = cl_obj->parse_object; cleri_incref(cl_obj); dup->dup = cl_obj; } return (cleri_t *) dup; } static void DUP_free(cleri_t * cl_object) { cleri_dup_t * dup = (cleri_dup_t *) cl_object; cleri_free(dup->dup); } libcleri-0.9.4/src/expecting.c000066400000000000000000000125341320722715200162400ustar00rootroot00000000000000/* * expecting.c - holds elements which the grammar expects at one position. * this can be used for suggestions. * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2016, Transceptor Technology * * changes * - initial version, 08-03-2016 * */ #include #include #include static cleri_exp_modes_t * EXPECTING_modes_new(const char * str); static void EXPECTING_empty(cleri_expecting_t * expecting); static int EXPECTING_get_mode(cleri_exp_modes_t * modes, const char * str); static void EXPECTING_shift_modes( cleri_exp_modes_t ** modes, const char * str); static void EXPECTING_modes_free(cleri_exp_modes_t * modes); /* * Returns NULL in case an error has occurred. */ cleri_expecting_t * cleri__expecting_new(const char * str) { cleri_expecting_t * expecting = (cleri_expecting_t *) malloc(sizeof(cleri_expecting_t)); if (expecting != NULL) { expecting->str = str; if ((expecting->required = cleri__olist_new()) == NULL) { free(expecting); return NULL; } if ((expecting->optional = cleri__olist_new()) == NULL) { free(expecting->required); free(expecting); return NULL; } if ((expecting->modes = EXPECTING_modes_new(str)) == NULL) { free(expecting->optional); free(expecting->required); free(expecting); return NULL; } } return expecting; } /* * Returns 0 if the mode is set successful and -1 if an error has occurred. */ int cleri__expecting_update( cleri_expecting_t * expecting, cleri_t * cl_obj, const char * str) { int rc = 0; if (str > expecting->str) { EXPECTING_empty(expecting); expecting->str = str; EXPECTING_shift_modes(&(expecting->modes), str); } if (expecting->str == str) { if (EXPECTING_get_mode(expecting->modes, str)) { /* true (1) is required */ rc = cleri__olist_append_nref(expecting->required, cl_obj); } else { /* false (0) is optional */ rc = cleri__olist_append_nref(expecting->optional, cl_obj); } } return rc; } /* * Returns 0 if the mode is set successful and -1 if an error has occurred. */ int cleri__expecting_set_mode( cleri_expecting_t * expecting, const char * str, int mode) { cleri_exp_modes_t * current = expecting->modes; for (; current->next != NULL; current = current->next) { if (current->str == str) { current->mode = mode && current->mode; return 0; } } current->next = (cleri_exp_modes_t *) malloc(sizeof(cleri_exp_modes_t)); if (current->next == NULL) { return -1; } current->next->mode = mode; current->next->next = NULL; current->next->str = str; return 0; } /* * Destroy expecting object. */ void cleri__expecting_free(cleri_expecting_t * expecting) { EXPECTING_empty(expecting); free(expecting->required); free(expecting->optional); EXPECTING_modes_free(expecting->modes); free(expecting); } /* * append optional to required and sets optional to NULL */ void cleri__expecting_combine(cleri_expecting_t * expecting) { cleri_olist_t * required = expecting->required; if (expecting->optional->cl_obj == NULL) { free(expecting->optional); expecting->optional = NULL; } if (required->cl_obj == NULL) { free(expecting->required); expecting->required = expecting->optional; } else { while (required->next != NULL) { required = required->next; } required->next = expecting->optional; } expecting->optional = NULL; } /* * Returns NULL in case an error has occurred. */ static cleri_exp_modes_t * EXPECTING_modes_new(const char * str) { cleri_exp_modes_t * modes = (cleri_exp_modes_t *) malloc(sizeof(cleri_exp_modes_t)); if (modes != NULL) { modes->mode = CLERI__EXP_MODE_REQUIRED; modes->next = NULL; modes->str = str; } return modes; } /* * shift from modes */ static void EXPECTING_shift_modes( cleri_exp_modes_t ** modes, const char * str) { cleri_exp_modes_t * next; while ((*modes)->next != NULL) { if ((*modes)->str == str) { break; } next = (*modes)->next; free(*modes); *modes = next; } } /* * Destroy modes. */ static void EXPECTING_modes_free(cleri_exp_modes_t * modes) { cleri_exp_modes_t * next; while (modes != NULL) { next = modes->next; free(modes); modes = next; } } /* * Return modes for a given position in str. */ static int EXPECTING_get_mode(cleri_exp_modes_t * modes, const char * str) { for (; modes != NULL; modes = modes->next) { if (modes->str == str) { return modes->mode; } } return CLERI__EXP_MODE_REQUIRED; } /* * Empty both required and optional lists. */ static void EXPECTING_empty(cleri_expecting_t * expecting) { cleri__olist_empty(expecting->required); cleri__olist_empty(expecting->optional); } libcleri-0.9.4/src/grammar.c000066400000000000000000000043651320722715200157030ustar00rootroot00000000000000/* * grammar.c - this should contain the 'start' or your grammar. * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2016, Transceptor Technology * * changes * - initial version, 08-03-2016 * */ #define PCRE2_CODE_UNIT_WIDTH 8 #include #include #include #include #include /* * Returns a grammar object or NULL in case of an error. * * Warning: this function could write to stderr in case the re_keywords could * not be compiled. */ cleri_grammar_t * cleri_grammar(cleri_t * start, const char * re_keywords) { const char * re_kw = (re_keywords == NULL) ? CLERI_DEFAULT_RE_KEYWORDS : re_keywords; assert (re_kw[0] == '^'); if (start == NULL) { return NULL; } cleri_grammar_t * grammar = (cleri_grammar_t *) malloc(sizeof(cleri_grammar_t)); if (grammar == NULL) { return NULL; } int pcre_error_num; PCRE2_SIZE pcre_error_offset; grammar->re_keywords = pcre2_compile( (PCRE2_SPTR8) re_kw, PCRE2_ZERO_TERMINATED, 0, &pcre_error_num, &pcre_error_offset, NULL); if(grammar->re_keywords == NULL) { PCRE2_UCHAR buffer[256]; pcre2_get_error_message(pcre_error_num, buffer, sizeof(buffer)); /* this is critical and unexpected, memory is not cleaned */ fprintf(stderr, "error: cannot compile '%s' (%s)\n", re_kw, buffer); free(grammar); return NULL; } grammar->match_data = \ pcre2_match_data_create_from_pattern(grammar->re_keywords, NULL); if (grammar->match_data == NULL) { pcre2_code_free(grammar->re_keywords); fprintf(stderr, "error: cannot create matsch data\n"); free(grammar); return NULL; } /* bind root element and increment the reference counter */ grammar->start = start; cleri_incref(start); return grammar; } void cleri_grammar_free(cleri_grammar_t * grammar) { pcre2_match_data_free(grammar->match_data); pcre2_code_free(grammar->re_keywords); cleri_free(grammar->start); free(grammar); } libcleri-0.9.4/src/keyword.c000066400000000000000000000050301320722715200157270ustar00rootroot00000000000000/* * keyword.c - cleri keyword element * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2016, Transceptor Technology * * changes * - initial version, 08-03-2016 * */ #include #include #include static void KEYWORD_free(cleri_t * cl_object); static cleri_node_t * KEYWORD_parse( cleri_parse_t * pr, cleri_node_t * parent, cleri_t * cl_obj, cleri_rule_store_t * rule); /* * Returns NULL in case an error has occurred. */ cleri_t * cleri_keyword(uint32_t gid, const char * keyword, int ign_case) { cleri_t * cl_object = cleri_new( gid, CLERI_TP_KEYWORD, &KEYWORD_free, &KEYWORD_parse); if (cl_object == NULL) { return NULL; } cl_object->via.keyword = (cleri_keyword_t *) malloc(sizeof(cleri_keyword_t)); if (cl_object->via.tokens == NULL) { free(cl_object); return NULL; } cl_object->via.keyword->keyword = keyword; cl_object->via.keyword->ign_case = ign_case; cl_object->via.keyword->len = strlen(keyword); return cl_object; } /* * Destroy keyword object. */ static void KEYWORD_free(cleri_t * cl_object) { free(cl_object->via.keyword); } /* * Returns a node or NULL. In case or an error, pr->is_valid is set to -1. */ static cleri_node_t * KEYWORD_parse( cleri_parse_t * pr, cleri_node_t * parent, cleri_t * cl_obj, cleri_rule_store_t * rule __attribute__((unused))) { ssize_t match_len; cleri_node_t * node = NULL; const char * str = parent->str + parent->len; if ((match_len = cleri__kwcache_match(pr, str)) < 0) { pr->is_valid = -1; /* error occurred */ return NULL; } if (match_len == (ssize_t) cl_obj->via.keyword->len && ( strncmp(cl_obj->via.keyword->keyword, str, match_len) == 0 || ( cl_obj->via.keyword->ign_case && strncasecmp(cl_obj->via.keyword->keyword, str, match_len) == 0 ) )) { if ((node = cleri__node_new(cl_obj, str, match_len)) != NULL) { parent->len += node->len; cleri__children_add(parent->children, node); } } else { /* Update expecting */ if (cleri__expecting_update(pr->expecting, cl_obj, str) == -1) { /* error occurred, node is already NULL */ pr->is_valid = -1; } } return node; } libcleri-0.9.4/src/kwcache.c000066400000000000000000000052001320722715200156470ustar00rootroot00000000000000/* * kwcache.c - holds keyword regular expression result while parsing. * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2016, Transceptor Technology * * changes * - initial version, 08-03-2016 * */ #define PCRE2_CODE_UNIT_WIDTH 8 #include #include #include #include static void KWCACHE_kw_match( cleri_kwcache_t * kwcache, cleri_parse_t * pr, const char * str); /* * Returns NULL in case an error has occurred. */ cleri_kwcache_t * cleri__kwcache_new(void) { cleri_kwcache_t * kwcache; kwcache = (cleri_kwcache_t *) malloc(sizeof(cleri_kwcache_t)); if (kwcache != NULL) { kwcache->len = 0; kwcache->str = NULL; kwcache->next = NULL; } return kwcache; } /* * Returns 0 when no kw_match is found, -1 when an error has occurred, or the * new kwcache->len value. */ ssize_t cleri__kwcache_match( cleri_parse_t * pr, const char * str) { cleri_kwcache_t * kwcache = pr->kwcache; if (kwcache->str != NULL) { while (1) { if (str == kwcache->str) { return kwcache->len; } if (kwcache->next == NULL) { break; } kwcache = kwcache->next; } kwcache->next = (cleri_kwcache_t *) malloc(sizeof(cleri_kwcache_t)); if (kwcache->next == NULL) { return -1; } kwcache = kwcache->next; kwcache->len = 0; kwcache->next = NULL; } kwcache->str = str; KWCACHE_kw_match(kwcache, pr, str); return kwcache->len; } /* * Destroy kwcache. (parsing NULL is allowed) */ void cleri__kwcache_free(cleri_kwcache_t * kwcache) { cleri_kwcache_t * next; while (kwcache != NULL) { next = kwcache->next; free(kwcache); kwcache = next; } } /* * This function will set kwcache->len if a match is found. */ static void KWCACHE_kw_match( cleri_kwcache_t * kwcache, cleri_parse_t * pr, const char * str) { int pcre_exec_ret; PCRE2_SIZE * ovector; pcre_exec_ret = pcre2_match( pr->re_keywords, (PCRE2_SPTR8) str, strlen(str), 0, // start looking at this point 0, // OPTIONS pr->match_data, NULL); if (pcre_exec_ret < 0) { return; } ovector = pcre2_get_ovector_pointer(pr->match_data); kwcache->len = ovector[1]; } libcleri-0.9.4/src/list.c000066400000000000000000000070671320722715200152320ustar00rootroot00000000000000/* * list.c - cleri list element. * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2016, Transceptor Technology * * changes * - initial version, 08-03-2016 * */ #include #include static void LIST_free(cleri_t * cl_object); static cleri_node_t * LIST_parse( cleri_parse_t * pr, cleri_node_t * parent, cleri_t * cl_obj, cleri_rule_store_t * rule); /* * Returns NULL in case an error has occurred. * * cl_obj : object to repeat * delimiter : object (Usually a Token) as delimiter * min : should be equal to or higher then 0. * max : should be equal to or higher then 0 but when 0 it * means unlimited. * opt_closing : when set to true (1) the list can be closed with a * delimiter. when false (0) this is not allowed. */ cleri_t * cleri_list( uint32_t gid, cleri_t * cl_obj, cleri_t * delimiter, size_t min, size_t max, int opt_closing) { if (cl_obj == NULL || delimiter == NULL) { return NULL; } cleri_t * cl_object = cleri_new( gid, CLERI_TP_LIST, &LIST_free, &LIST_parse); if (cl_object == NULL) { return NULL; } cl_object->via.list = (cleri_list_t *) malloc(sizeof(cleri_list_t)); if (cl_object->via.list == NULL) { free(cl_object); return NULL; } cl_object->via.list->cl_obj = cl_obj; cl_object->via.list->delimiter = delimiter; cl_object->via.list->min = min; cl_object->via.list->max = max; cl_object->via.list->opt_closing = opt_closing; cleri_incref(cl_obj); cleri_incref(delimiter); return cl_object; } /* * Destroy list object. */ static void LIST_free(cleri_t * cl_object) { cleri_free(cl_object->via.list->cl_obj); cleri_free(cl_object->via.list->delimiter); free(cl_object->via.list); } /* * Returns a node or NULL. In case of an error pr->is_valid is set to -1. */ static cleri_node_t * LIST_parse( cleri_parse_t * pr, cleri_node_t * parent, cleri_t * cl_obj, cleri_rule_store_t * rule) { cleri_node_t * node; cleri_node_t * rnode; size_t i = 0; size_t j = 0; if ((node = cleri__node_new(cl_obj, parent->str + parent->len, 0)) == NULL) { pr->is_valid = -1; return NULL; } while (1) { rnode = cleri__parse_walk( pr, node, cl_obj->via.list->cl_obj, rule, i < cl_obj->via.list->min); // 1 = REQUIRED if (rnode == NULL) { break; } i++; rnode = cleri__parse_walk( pr, node, cl_obj->via.list->delimiter, rule, i < cl_obj->via.list->min); // 1 = REQUIRED if (rnode == NULL) { break; } j++; } if ( i < cl_obj->via.list->min || (cl_obj->via.list->max && i > cl_obj->via.list->max) || ((cl_obj->via.list->opt_closing == 0) && i && i == j)) { cleri__node_free(node); return NULL; } parent->len += node->len; if (cleri__children_add(parent->children, node)) { /* error occurred, reverse changes set mg_node to NULL */ pr->is_valid = -1; parent->len -= node->len; cleri__node_free(node); node = NULL; } return node; } libcleri-0.9.4/src/node.c000066400000000000000000000032201320722715200151670ustar00rootroot00000000000000/* * node.c - node is created while parsing a string. a node old the result * for one element. * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2016, Transceptor Technology * * changes * - initial version, 08-03-2016 * */ #include #include static cleri_node_t CLERI__EMPTY_NODE = { .children=NULL, .cl_obj=NULL, .len=0, .str=NULL }; cleri_node_t * CLERI_EMPTY_NODE = &CLERI__EMPTY_NODE; /* * Returns NULL in case an error has occurred. */ cleri_node_t * cleri__node_new(cleri_t * cl_obj, const char * str, size_t len) { cleri_node_t * node; node = (cleri_node_t *) malloc(sizeof(cleri_node_t)); if (node != NULL) { node->cl_obj = cl_obj; node->ref = 1; node->str = str; node->len = len; if (cl_obj == NULL || cl_obj->tp <= CLERI_TP_THIS) { /* NULL when initializing the root node but we do need children */ node->children = cleri__children_new(); if (node->children == NULL) { free(node); return NULL; } } else { /* we do not need children for some objects */ node->children = NULL; } } return node; } /* * Destroy node. (parsing NULL is allowed) */ void cleri__node_free(cleri_node_t * node) { /* node can be NULL or this could be an CLERI_EMPTY_NODE */ if (node == NULL || node == CLERI_EMPTY_NODE || --node->ref) { return; } cleri__children_free(node->children); free(node); } libcleri-0.9.4/src/olist.c000066400000000000000000000064231320722715200154040ustar00rootroot00000000000000/* * olist.c - linked list for keeping cleri objects. * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2016, Transceptor Technology * * changes * - initial version, 08-03-2016 * */ #include #include /* * Returns NULL in case an error has occurred. */ cleri_olist_t * cleri__olist_new(void) { cleri_olist_t * olist; olist = (cleri_olist_t *) malloc(sizeof(cleri_olist_t)); if (olist != NULL) { olist->cl_obj = NULL; olist->next = NULL; } return olist; } /* * Returns 0 if successful or -1 in case of an error. * The list remains unchanged in case of an error and the object reference * counter will be incremented when successful. */ int cleri__olist_append(cleri_olist_t * olist, cleri_t * cl_object) { if (cl_object == NULL) { return -1; } if (olist->cl_obj == NULL) { cleri_incref(cl_object); olist->cl_obj = cl_object; olist->next = NULL; return 0; } while (olist->next != NULL) { olist = olist->next; } olist->next = (cleri_olist_t *) malloc(sizeof(cleri_olist_t)); if (olist->next == NULL) { return -1; } cleri_incref(cl_object); olist->next->cl_obj = cl_object; olist->next->next = NULL; return 0; } /* * Exactly the same as cleri__olist_append, except the reference counter * will not be incremented. */ int cleri__olist_append_nref(cleri_olist_t * olist, cleri_t * cl_object) { if (cl_object == NULL) { return -1; } if (olist->cl_obj == NULL) { olist->cl_obj = cl_object; olist->next = NULL; return 0; } while (olist->next != NULL) { olist = olist->next; } olist->next = (cleri_olist_t *) malloc(sizeof(cleri_olist_t)); if (olist->next == NULL) { return -1; } olist->next->cl_obj = cl_object; olist->next->next = NULL; return 0; } /* * Destroy the olist and decrement the reference counter for each object in * the list. (NULL is allowed as olist and does nothing) */ void cleri__olist_free(cleri_olist_t * olist) { cleri_olist_t * next; while (olist != NULL) { next = olist->next; cleri_free(olist->cl_obj); free(olist); olist = next; } } /* * Empty the object list but do not free the list. This will not decrement * the reference counters for object in the list. */ void cleri__olist_empty(cleri_olist_t * olist) { cleri_olist_t * current; if (olist == NULL) { return; } /* set root object to NULL but we do not need to free root */ olist->cl_obj = NULL; /* set root next to NULL */ current = olist->next; olist->next = NULL; /* cleanup all the rest */ while (current != NULL) { olist = current->next; free(current); current = olist; } } /* * Cancel building olist. Used to recover from an error while creating * a new element. */ void cleri__olist_cancel(cleri_olist_t * olist) { cleri_olist_t * current = olist->next; /* cleanup all the rest */ while (current != NULL) { olist->cl_obj->ref--; current = current->next; } cleri__olist_empty(olist); } libcleri-0.9.4/src/optional.c000066400000000000000000000045351320722715200161010ustar00rootroot00000000000000/* * optional.c - cleri optional element. * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2016, Transceptor Technology * * changes * - initial version, 08-03-2016 * */ #include #include #include static void OPTIONAL_free(cleri_t * cl_object); static cleri_node_t * OPTIONAL_parse( cleri_parse_t * pr, cleri_node_t * parent, cleri_t * cl_obj, cleri_rule_store_t * rule); /* * Returns NULL and in case an error has occurred. */ cleri_t * cleri_optional(uint32_t gid, cleri_t * cl_obj) { if (cl_obj == NULL) { return NULL; } cleri_t * cl_object = cleri_new( gid, CLERI_TP_OPTIONAL, &OPTIONAL_free, &OPTIONAL_parse); if (cl_object == NULL) { return NULL; } cl_object->via.optional = (cleri_optional_t *) malloc(sizeof(cleri_optional_t)); if (cl_object->via.optional == NULL) { free(cl_object); return NULL; } cl_object->via.optional->cl_obj = cl_obj; cleri_incref(cl_obj); return cl_object; } /* * Destroy optional object. */ static void OPTIONAL_free(cleri_t * cl_object) { cleri_free(cl_object->via.optional->cl_obj); free(cl_object->via.optional); } /* * Returns a node or NULL. In case of an error pr->is_valid is set to -1. */ static cleri_node_t * OPTIONAL_parse( cleri_parse_t * pr, cleri_node_t * parent, cleri_t * cl_obj, cleri_rule_store_t * rule) { cleri_node_t * node; cleri_node_t * rnode; if ((node = cleri__node_new(cl_obj, parent->str + parent->len, 0)) == NULL) { pr->is_valid = -1; return NULL; } rnode = cleri__parse_walk( pr, node, cl_obj->via.optional->cl_obj, rule, CLERI__EXP_MODE_OPTIONAL); if (rnode != NULL) { parent->len += node->len; if (cleri__children_add(parent->children, node)) { /* error occurred, reverse changes set mg_node to NULL */ pr->is_valid = -1; parent->len -= node->len; cleri__node_free(node); node = NULL; } return node; } cleri__node_free(node); return CLERI_EMPTY_NODE; } libcleri-0.9.4/src/parse.c000066400000000000000000000073341320722715200153660ustar00rootroot00000000000000/* * parser.c - this contains the start for parsing a string to a grammar. * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2016, Transceptor Technology * * changes * - initial version, 08-03-2016 * */ #include #include #include #include #include #include /* * Return a parse result. In case of a memory allocation error the return value * will be NULL. */ cleri_parse_t * cleri_parse(cleri_grammar_t * grammar, const char * str) { cleri_parse_t * pr; const char * end; const char * test; bool at_end = true; /* prepare parsing */ pr = (cleri_parse_t *) malloc(sizeof(cleri_parse_t)); if (pr == NULL) { return NULL; } pr->str = str; pr->tree = NULL; pr->kwcache = NULL; pr->expecting = NULL; pr->is_valid = 0; if ( (pr->tree = cleri__node_new(NULL, str, 0)) == NULL || (pr->kwcache = cleri__kwcache_new()) == NULL || (pr->expecting = cleri__expecting_new(str)) == NULL) { cleri_parse_free(pr); return NULL; } pr->re_keywords = grammar->re_keywords; pr->match_data = grammar->match_data; /* do the actual parsing */ cleri__parse_walk( pr, pr->tree, grammar->start, NULL, CLERI__EXP_MODE_REQUIRED); /* When is_valid is -1, an allocation error has occurred. */ if (pr->is_valid == -1) { cleri_parse_free(pr); return NULL; } /* process the parse result */ end = pr->tree->str + pr->tree->len; /* check if we are at the end of the string */ for (test = end; *test; test++) { if (!isspace(*test)) { at_end = false; break; } } pr->is_valid = at_end; pr->pos = (pr->is_valid) ? pr->tree->len : (size_t) (pr->expecting->str - pr->str); if (!at_end && pr->expecting->required->cl_obj == NULL) { if (cleri__expecting_set_mode( pr->expecting, end, CLERI__EXP_MODE_REQUIRED) == -1 || cleri__expecting_update( pr->expecting, CLERI_END_OF_STATEMENT, end) == -1) { cleri_parse_free(pr); return NULL; } } cleri__expecting_combine(pr->expecting); pr->expect = pr->expecting->required; return pr; } /* * Destroy parser. (parsing NULL is allowed) */ void cleri_parse_free(cleri_parse_t * pr) { cleri__node_free(pr->tree); cleri__kwcache_free(pr->kwcache); if (pr->expecting != NULL) { cleri__expecting_free(pr->expecting); } free(pr); } /* * Reset expect to start */ void cleri_parse_expect_start(cleri_parse_t * pr) { pr->expect = pr->expecting->required; } /* * Walk a parser object. * (recursive function, called from each parse_object function) * Returns a node or NULL. (In case of error one should check pr->is_valid) */ cleri_node_t * cleri__parse_walk( cleri_parse_t * pr, cleri_node_t * parent, cleri_t * cl_obj, cleri_rule_store_t * rule, int mode) { /* set parent len to next none white space char */ while (isspace(*(parent->str + parent->len))) { parent->len++; } /* set expecting mode */ if (cleri__expecting_set_mode(pr->expecting, parent->str, mode) == -1) { pr->is_valid = -1; return NULL; } /* note that the actual node is returned or NULL but we do not * actually need the node. (boolean true/false would be enough) */ return (*cl_obj->parse_object)(pr, parent, cl_obj, rule); } libcleri-0.9.4/src/prio.c000066400000000000000000000071761320722715200152310ustar00rootroot00000000000000/* * prio.c - cleri prio element. (this element create a cleri rule object * holding this prio element) * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2016, Transceptor Technology * * changes * - initial version, 08-03-2016 * */ #include #include #include #include #include #include #define PRIO_MAX_RECURSION_DEPTH 200 static void PRIO_free(cleri_t * cl_obj); static cleri_node_t * PRIO_parse( cleri_parse_t * pr, cleri_node_t * parent, cleri_t * cl_obj, cleri_rule_store_t * rule); /* * Returns NULL in case an error has occurred. */ cleri_t * cleri_prio(uint32_t gid, size_t len, ...) { va_list ap; cleri_t * cl_object = cleri_new( 0, CLERI_TP_PRIO, &PRIO_free, &PRIO_parse); if (cl_object == NULL) { return NULL; } cl_object->via.prio = (cleri_prio_t *) malloc(sizeof(cleri_prio_t)); if (cl_object->via.prio == NULL) { free(cl_object); return NULL; } cl_object->via.prio->olist = cleri__olist_new(); if (cl_object->via.prio->olist == NULL) { cleri_free(cl_object); return NULL; } va_start(ap, len); while(len--) { if (cleri__olist_append( cl_object->via.prio->olist, va_arg(ap, cleri_t *))) { cleri__olist_cancel(cl_object->via.prio->olist); cleri_free(cl_object); cl_object = NULL; } } va_end(ap); return cleri__rule(gid, cl_object); } /* * Destroy prio object. */ static void PRIO_free(cleri_t * cl_object) { cleri__olist_free(cl_object->via.prio->olist); free(cl_object->via.prio); } /* * Returns a node or NULL. In case of an error pr->is_valid is set to -1. */ static cleri_node_t * PRIO_parse( cleri_parse_t * pr, cleri_node_t * parent, cleri_t * cl_obj, cleri_rule_store_t * rule) { cleri_olist_t * olist; cleri_node_t * node; cleri_node_t * rnode; cleri_rule_tested_t * tested; const char * str = parent->str + parent->len; /* initialize and return rule test, or return an existing test * if *str is already in tested */ if ( rule->depth++ > PRIO_MAX_RECURSION_DEPTH || cleri__rule_init(&tested, rule->tested, str) == CLERI_RULE_ERROR) { pr->is_valid = -1; return NULL; } olist = cl_obj->via.prio->olist; while (olist != NULL) { if ((node = cleri__node_new(cl_obj, str, 0)) == NULL) { pr->is_valid = -1; return NULL; } rnode = cleri__parse_walk( pr, node, olist->cl_obj, rule, CLERI__EXP_MODE_REQUIRED); if (rnode != NULL && (tested->node == NULL || node->len > tested->node->len)) { cleri__node_free(tested->node); tested->node = node; } else { cleri__node_free(node); } olist = olist->next; } if (tested->node != NULL) { parent->len += tested->node->len; if (cleri__children_add(parent->children, tested->node)) { /* error occurred, reverse changes set mg_node to NULL */ pr->is_valid = -1; parent->len -= tested->node->len; cleri__node_free(tested->node); tested->node = NULL; } return tested->node; } return NULL; } libcleri-0.9.4/src/ref.c000066400000000000000000000024301320722715200150200ustar00rootroot00000000000000/* * ref.c - cleri ref element * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2017, Transceptor Technology * * changes * - initial version, 20-06-2017 * */ #include #include #include static void REF_free(cleri_t * cl_object); /* * Returns NULL in case an error has occurred. */ cleri_t * cleri_ref(void) { cleri_t * cl_object = cleri_new( 0, CLERI_TP_REF, &REF_free, NULL); return cl_object; } /* * Both ref and cl_obj are not allowed to be NULL. */ void cleri_ref_set(cleri_t * ref, cleri_t * cl_obj) { /* cl_obj should have no other refs */ assert (ref != NULL && ref->tp == CLERI_TP_REF && cl_obj != NULL && cl_obj->ref == 1); /* assign properties, except ref counter */ ref->gid = cl_obj->gid; ref->free_object = cl_obj->free_object; ref->parse_object = cl_obj->parse_object; ref->tp = cl_obj->tp; ref->via = cl_obj->via; /* free *cl_obj and set the pointer to the ref object */ free(cl_obj); } /* * Destroy ref object. (only used when ref is not set) */ static void REF_free(cleri_t * cl_object __attribute__((unused))) { /* nothing todo */ } libcleri-0.9.4/src/regex.c000066400000000000000000000102371320722715200153620ustar00rootroot00000000000000/* * regex.c - cleri regular expression element. * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2016, Transceptor Technology * * changes * - initial version, 08-03-2016 * */ #include #include #include #include #include static void REGEX_free(cleri_t * cl_object); static cleri_node_t * REGEX_parse( cleri_parse_t * pr, cleri_node_t * parent, cleri_t * cl_obj, cleri_rule_store_t * rule); /* * Returns a regex object or NULL in case of an error. * * Argument pattern must start with character '^'. Be sure to check the pattern * for the '^' character before calling this function. * * Warning: this function could write to stderr in case the pattern could not * be compiled. */ cleri_t * cleri_regex(uint32_t gid, const char * pattern) { cleri_t * cl_object; int pcre_error_num; PCRE2_SIZE pcre_error_offset; assert (pattern[0] == '^'); cl_object = cleri_new( gid, CLERI_TP_REGEX, ®EX_free, ®EX_parse); if (cl_object == NULL) { return NULL; } cl_object->via.regex = (cleri_regex_t *) malloc(sizeof(cleri_regex_t)); if (cl_object->via.regex == NULL) { free(cl_object); return NULL; } cl_object->via.regex->regex = pcre2_compile( (PCRE2_SPTR8) pattern, PCRE2_ZERO_TERMINATED, 0, &pcre_error_num, &pcre_error_offset, NULL); if(cl_object->via.regex->regex == NULL) { PCRE2_UCHAR buffer[256]; pcre2_get_error_message(pcre_error_num, buffer, sizeof(buffer)); fprintf(stderr, "error: cannot compile '%s' (%s)\n", pattern, buffer); free(cl_object->via.regex); free(cl_object); return NULL; } cl_object->via.regex->match_data = pcre2_match_data_create_from_pattern( cl_object->via.regex->regex, NULL); if (cl_object->via.regex->match_data == NULL) { pcre2_code_free(cl_object->via.regex->regex); fprintf(stderr, "error: cannot create matsch data\n"); free(cl_object->via.regex); free(cl_object); return NULL; return NULL; } return cl_object; } /* * Destroy regex object. */ static void REGEX_free(cleri_t * cl_object) { pcre2_match_data_free(cl_object->via.regex->match_data); pcre2_code_free(cl_object->via.regex->regex); free(cl_object->via.regex); } /* * Returns a node or NULL. In case of an error, pr->is_valid is set to -1 */ static cleri_node_t * REGEX_parse( cleri_parse_t * pr, cleri_node_t * parent, cleri_t * cl_obj, cleri_rule_store_t * rule __attribute__((unused))) { int pcre_exec_ret; PCRE2_SIZE * ovector; const char * str = parent->str + parent->len; cleri_node_t * node; pcre_exec_ret = pcre2_match( cl_obj->via.regex->regex, (PCRE2_SPTR8) str, strlen(str), 0, // start looking at this point 0, // OPTIONS cl_obj->via.regex->match_data, NULL); if (pcre_exec_ret < 0) { if (cleri__expecting_update(pr->expecting, cl_obj, str) == -1) { pr->is_valid = -1; /* error occurred */ } return NULL; } ovector = pcre2_get_ovector_pointer(cl_obj->via.regex->match_data); /* since each regex pattern should start with ^ we now sub_str_vec[0] * should be 0. sub_str_vec[1] contains the end position in the sting */ if ((node = cleri__node_new(cl_obj, str, (size_t) ovector[1])) != NULL) { parent->len += node->len; if (cleri__children_add(parent->children, node)) { /* error occurred, reverse changes set node to NULL */ pr->is_valid = -1; parent->len -= node->len; cleri__node_free(node); node = NULL; } } else { pr->is_valid = -1; /* error occurred */ } return node; } libcleri-0.9.4/src/repeat.c000066400000000000000000000054771320722715200155420ustar00rootroot00000000000000/* * repeat.c - cleri regular repeat element. * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2016, Transceptor Technology * * changes * - initial version, 08-03-2016 * */ #include #include #include static void REPEAT_free(cleri_t * cl_object); static cleri_node_t * REPEAT_parse( cleri_parse_t * pr, cleri_node_t * parent, cleri_t * cl_obj, cleri_rule_store_t * rule); /* * Returns NULL in case an error has occurred. * * cl_ob : object to repeat * min : should be equal to or higher then 0. * max : should be equal to or higher then 0 but when 0 it means * unlimited. */ cleri_t * cleri_repeat(uint32_t gid, cleri_t * cl_obj, size_t min, size_t max) { if (cl_obj == NULL) { return NULL; } assert (!max || max >= min); cleri_t * cl_object = cleri_new( gid, CLERI_TP_REPEAT, &REPEAT_free, &REPEAT_parse); if (cl_object == NULL) { return NULL; } cl_object->via.repeat = (cleri_repeat_t *) malloc(sizeof(cleri_repeat_t)); if (cl_object->via.repeat == NULL) { free(cl_object); return NULL; } cl_object->via.repeat->cl_obj = cl_obj; cl_object->via.repeat->min = min; cl_object->via.repeat->max = max; cleri_incref(cl_obj); return cl_object; } /* * Destroy repeat object. */ static void REPEAT_free(cleri_t * cl_object) { cleri_free(cl_object->via.repeat->cl_obj); free(cl_object->via.repeat); } /* * Returns a node or NULL. In case of an error pr->is_valid is set to -1. */ static cleri_node_t * REPEAT_parse( cleri_parse_t * pr, cleri_node_t * parent, cleri_t * cl_obj, cleri_rule_store_t * rule) { cleri_node_t * node; cleri_node_t * rnode; size_t i; if ((node = cleri__node_new(cl_obj, parent->str + parent->len, 0)) == NULL) { pr->is_valid = -1; return NULL; } for (i = 0; cl_obj->via.repeat->max == 0 || i < cl_obj->via.repeat->max; i++) { rnode = cleri__parse_walk( pr, node, cl_obj->via.repeat->cl_obj, rule, i < cl_obj->via.repeat->min); // 1 = REQUIRED if (rnode == NULL) { break; } } if (i < cl_obj->via.repeat->min) { cleri__node_free(node); return NULL; } parent->len += node->len; if (cleri__children_add(parent->children, node)) { /* error occurred, reverse changes set mg_node to NULL */ pr->is_valid = -1; parent->len -= node->len; cleri__node_free(node); node = NULL; } return node; } libcleri-0.9.4/src/rule.c000066400000000000000000000104211320722715200152120ustar00rootroot00000000000000/* * rule.c - cleri regular rule element. (do not directly use this element but * create a 'prio' instead which will be wrapped by a rule element) * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2016, Transceptor Technology * * changes * - initial version, 08-03-2016 * */ #include #include static void RULE_free(cleri_t * cl_object); static cleri_node_t * RULE_parse( cleri_parse_t * pr, cleri_node_t * parent, cleri_t * cl_obj, cleri_rule_store_t * rule); static void RULE_tested_free(cleri_rule_tested_t * tested); /* * Returns NULL in case an error has occurred. */ cleri_t * cleri__rule(uint32_t gid, cleri_t * cl_obj) { if (cl_obj == NULL) { return NULL; } cleri_t * cl_object = cleri_new( gid, CLERI_TP_RULE, &RULE_free, &RULE_parse); if (cl_object != NULL) { cl_object->via.rule = (cleri_rule_t *) malloc(sizeof(cleri_rule_t)); if (cl_object->via.rule == NULL) { free(cl_object); cl_object = NULL; } else { cl_object->via.rule->cl_obj = cl_obj; cleri_incref(cl_obj); } } return cl_object; } /* * Initialize a rule and return the test result. * Result can be either CLERI_RULE_TRUE, CLERI_RULE_FALSE or CLERI_RULE_ERROR. * * - CLERI_RULE_TRUE: a new test is created * - CLERI_RULE_FALSE: no new test is created * - CLERI_RULE_ERROR: an error occurred */ cleri_rule_test_t cleri__rule_init( cleri_rule_tested_t ** target, cleri_rule_tested_t * tested, const char * str) { /* * return true (1) when a new test is created, false (0) when not. */ cleri_rule_tested_t * prev; (*target) = tested; if ((*target)->str == NULL) { (*target)->str = str; return CLERI_RULE_TRUE; } while ((*target) != NULL) { if ((*target)->str == str) { return CLERI_RULE_FALSE; } prev = (*target); (*target) = (*target)->next; } *target = prev->next = (cleri_rule_tested_t *) malloc(sizeof(cleri_rule_tested_t)); if (*target == NULL) { return CLERI_RULE_ERROR; } (*target)->str = str; (*target)->node = NULL; (*target)->next = NULL; return CLERI_RULE_TRUE; } static void RULE_free(cleri_t * cl_object) { cleri_free(cl_object->via.rule->cl_obj); free(cl_object->via.rule); } /* * Returns a node or NULL. In case of an error pr->is_valid is set to -1. */ static cleri_node_t * RULE_parse( cleri_parse_t * pr, cleri_node_t * parent, cleri_t * cl_obj, cleri_rule_store_t * __rule __attribute__((unused))) { cleri_node_t * node; cleri_node_t * rnode; cleri_rule_store_t nrule; if ((node = cleri__node_new(cl_obj, parent->str + parent->len, 0)) == NULL) { pr->is_valid = -1; return NULL; } nrule.depth = 0; nrule.tested = (cleri_rule_tested_t *) malloc(sizeof(cleri_rule_tested_t)); if (nrule.tested == NULL) { pr->is_valid = -1; cleri__node_free(node); return NULL; } nrule.tested->str = NULL; nrule.tested->node = NULL; nrule.tested->next = NULL; nrule.root_obj = cl_obj->via.rule->cl_obj; rnode = cleri__parse_walk( pr, node, nrule.root_obj, &nrule, CLERI__EXP_MODE_REQUIRED); if (rnode == NULL) { cleri__node_free(node); node = NULL; } else { parent->len += node->len; if (cleri__children_add(parent->children, node)) { /* error occurred, reverse changes set mg_node to NULL */ pr->is_valid = -1; parent->len -= node->len; cleri__node_free(node); node = NULL; } } /* cleanup rule */ RULE_tested_free(nrule.tested); return node; } /* * Cleanup rule tested */ static void RULE_tested_free(cleri_rule_tested_t * tested) { cleri_rule_tested_t * next; while (tested != NULL) { next = tested->next; free(tested); tested = next; } } libcleri-0.9.4/src/sequence.c000066400000000000000000000056011320722715200160570ustar00rootroot00000000000000/* * sequence.c - cleri sequence element. * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2016, Transceptor Technology * * changes * - initial version, 08-03-2016 * */ #include #include #include #include static void SEQUENCE_free(cleri_t * cl_object); static cleri_node_t * SEQUENCE_parse( cleri_parse_t * pr, cleri_node_t * parent, cleri_t * cl_obj, cleri_rule_store_t * rule); /* * Returns NULL and in case an error has occurred. */ cleri_t * cleri_sequence(uint32_t gid, size_t len, ...) { va_list ap; cleri_t * cl_object = cleri_new( gid, CLERI_TP_SEQUENCE, &SEQUENCE_free, &SEQUENCE_parse); if (cl_object == NULL) { return NULL; } cl_object->via.sequence = (cleri_sequence_t *) malloc(sizeof(cleri_sequence_t)); if (cl_object->via.sequence == NULL) { free(cl_object); return NULL; } cl_object->via.sequence->olist = cleri__olist_new(); if (cl_object->via.sequence->olist == NULL) { cleri_free(cl_object); return NULL; } va_start(ap, len); while(len--) { if (cleri__olist_append( cl_object->via.sequence->olist, va_arg(ap, cleri_t *))) { cleri__olist_cancel(cl_object->via.sequence->olist); cleri_free(cl_object); cl_object = NULL; break; } } va_end(ap); return cl_object; } /* * Destroy sequence object. */ static void SEQUENCE_free(cleri_t * cl_object) { cleri__olist_free(cl_object->via.sequence->olist); free(cl_object->via.sequence); } /* * Returns a node or NULL. In case of an error pr->is_valid is set to -1. */ static cleri_node_t * SEQUENCE_parse( cleri_parse_t * pr, cleri_node_t * parent, cleri_t * cl_obj, cleri_rule_store_t * rule) { cleri_olist_t * olist; cleri_node_t * node; cleri_node_t * rnode; olist = cl_obj->via.sequence->olist; if ((node = cleri__node_new(cl_obj, parent->str + parent->len, 0)) == NULL) { pr->is_valid = -1; return NULL; } while (olist != NULL) { rnode = cleri__parse_walk( pr, node, olist->cl_obj, rule, CLERI__EXP_MODE_REQUIRED); if (rnode == NULL) { cleri__node_free(node); return NULL; } olist = olist->next; } parent->len += node->len; if (cleri__children_add(parent->children, node)) { /* error occurred, reverse changes set mg_node to NULL */ pr->is_valid = -1; parent->len -= node->len; cleri__node_free(node); node = NULL; } return node; } libcleri-0.9.4/src/this.c000066400000000000000000000046661320722715200152300ustar00rootroot00000000000000/* * this.c - cleri THIS element. there should be only one single instance * of this which can even be shared over different grammars. * Always use this element using its constant CLERI_THIS and * somewhere within a prio element. * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2016, Transceptor Technology * * changes * - initial version, 08-03-2016 * */ #include #include #include #include static cleri_node_t * cleri_parse_this( cleri_parse_t * pr, cleri_node_t * parent, cleri_t * cl_obj, cleri_rule_store_t * rule); static int cleri_dummy = 0; static cleri_t cleri_this = { .gid=0, .ref=1, .free_object=NULL, .parse_object=&cleri_parse_this, .tp=CLERI_TP_THIS, .via={.dummy=(void *) &cleri_dummy}}; cleri_t * CLERI_THIS = &cleri_this; /* * Returns a node or NULL. In case of an error pr->is_valid is set to -1. */ static cleri_node_t * cleri_parse_this( cleri_parse_t * pr, cleri_node_t * parent, cleri_t * cl_obj, cleri_rule_store_t * rule) { cleri_node_t * node; cleri_rule_tested_t * tested; const char * str = parent->str + parent->len; switch (cleri__rule_init(&tested, rule->tested, str)) { case CLERI_RULE_TRUE: if ((node = cleri__node_new(cl_obj, str, 0)) == NULL) { pr->is_valid = -1; return NULL; } tested->node = cleri__parse_walk( pr, node, rule->root_obj, rule, CLERI__EXP_MODE_REQUIRED); if (tested->node == NULL) { cleri__node_free(node); return NULL; } break; case CLERI_RULE_FALSE: node = tested->node; if (node == NULL) { return NULL; } node->ref++; break; case CLERI_RULE_ERROR: pr->is_valid = -1; return NULL; default: assert (0); node = NULL; } parent->len += tested->node->len; if (cleri__children_add(parent->children, node)) { /* error occurred, reverse changes set mg_node to NULL */ pr->is_valid = -1; parent->len -= tested->node->len; cleri__node_free(node); node = NULL; } return node; } libcleri-0.9.4/src/token.c000066400000000000000000000050421320722715200153660ustar00rootroot00000000000000/* * token.c - cleri token element. note that one single char will parse * slightly faster compared to tokens containing more characters. * (be careful a token should not match the keyword regular * expression) * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2016, Transceptor Technology * * changes * - initial version, 08-03-2016 * */ #include #include #include static void TOKEN_free(cleri_t * cl_object); static cleri_node_t * TOKEN_parse( cleri_parse_t * pr, cleri_node_t * parent, cleri_t * cl_obj, cleri_rule_store_t * rule); /* * Returns NULL in case an error has occurred. */ cleri_t * cleri_token(uint32_t gid, const char * token) { cleri_t * cl_object = cleri_new( gid, CLERI_TP_TOKEN, &TOKEN_free, &TOKEN_parse); if (cl_object == NULL) { return NULL; } cl_object->via.token = (cleri_token_t *) malloc(sizeof(cleri_token_t)); if (cl_object->via.token == NULL) { free(cl_object); return NULL; } cl_object->via.token->token = token; cl_object->via.token->len = strlen(token); return cl_object; } /* * Destroy token object. */ static void TOKEN_free(cleri_t * cl_object) { free(cl_object->via.token); } /* * Returns a node or NULL. In case of an error pr->is_valid is set to -1. */ static cleri_node_t * TOKEN_parse( cleri_parse_t * pr, cleri_node_t * parent, cleri_t * cl_obj, cleri_rule_store_t * rule __attribute__((unused))) { cleri_node_t * node = NULL; const char * str = parent->str + parent->len; if (strncmp( cl_obj->via.token->token, str, cl_obj->via.token->len) == 0) { if ((node = cleri__node_new( cl_obj, str, cl_obj->via.token->len)) != NULL) { parent->len += node->len; if (cleri__children_add(parent->children, node)) { /* error occurred, reverse changes set mg_node to NULL */ pr->is_valid = -1; parent->len -= node->len; cleri__node_free(node); node = NULL; } } else { pr->is_valid = -1; } } else if (cleri__expecting_update(pr->expecting, cl_obj, str) == -1) { pr->is_valid = -1; } return node; } libcleri-0.9.4/src/tokens.c000066400000000000000000000130321320722715200155470ustar00rootroot00000000000000/* * tokens.c - cleri tokens element. (like token but can contain more tokens * in one element) * * author : Jeroen van der Heijden * email : jeroen@transceptor.technology * copyright : 2016, Transceptor Technology * * changes * - initial version, 08-03-2016 * */ #include #include #include #include #include #include static void TOKENS_free(cleri_t * cl_object); static cleri_node_t * TOKENS_parse( cleri_parse_t * pr, cleri_node_t * parent, cleri_t * cl_obj, cleri_rule_store_t * rule); static int TOKENS_list_add( cleri_tlist_t ** tlist, const char * token, size_t len); static void TOKENS_list_free(cleri_tlist_t * tlist); /* * Returns NULL in case an error has occurred. */ cleri_t * cleri_tokens(uint32_t gid, const char * tokens) { size_t len; char * pt; cleri_t * cl_object; cl_object = cleri_new( gid, CLERI_TP_TOKENS, &TOKENS_free, &TOKENS_parse); if (cl_object == NULL) { return NULL; } cl_object->via.tokens = (cleri_tokens_t *) malloc(sizeof(cleri_tokens_t)); if (cl_object->via.tokens == NULL) { free(cl_object); return NULL; } /* copy the sting twice, first one we set spaces to 0...*/ cl_object->via.tokens->tokens = strdup(tokens); /* ...and this one we keep for showing the original */ cl_object->via.tokens->spaced = strdup(tokens); cl_object->via.tokens->tlist = (cleri_tlist_t *) malloc(sizeof(cleri_tlist_t)); if ( cl_object->via.tokens->tokens == NULL || cl_object->via.tokens->spaced == NULL || cl_object->via.tokens->tlist == NULL) { cleri_free(cl_object); return NULL; } cl_object->via.tokens->tlist->token = NULL; cl_object->via.tokens->tlist->next = NULL; cl_object->via.tokens->tlist->len = 0; pt = cl_object->via.tokens->tokens; for (len = 0;; pt++) { if (!*pt || isspace(*pt)) { if (len) { if (TOKENS_list_add( &cl_object->via.tokens->tlist, pt - len, len)) { cleri_free(cl_object); return NULL; } len = 0; } if (*pt) *pt = 0; else { break; } } else { len++; } } #ifdef DEBUG /* check for empty token list */ assert (cl_object->via.tokens->tlist->token != NULL); #endif return cl_object; } /* * Destroy token object. */ static void TOKENS_free(cleri_t * cl_object) { TOKENS_list_free(cl_object->via.tokens->tlist); free(cl_object->via.tokens->tokens); free(cl_object->via.tokens->spaced); free(cl_object->via.tokens); } /* * Returns a node or NULL. In case of an error pr->is_valid is set to -1. */ static cleri_node_t * TOKENS_parse( cleri_parse_t * pr, cleri_node_t * parent, cleri_t * cl_obj, cleri_rule_store_t * rule __attribute__((unused))) { cleri_node_t * node = NULL; const char * str = parent->str + parent->len; cleri_tlist_t * tlist = cl_obj->via.tokens->tlist; /* we can trust that at least one token is in the list */ for (; tlist != NULL; tlist = tlist->next) { if (strncmp(tlist->token, str, tlist->len) == 0) { if ((node = cleri__node_new(cl_obj, str, tlist->len)) != NULL) { parent->len += node->len; if (cleri__children_add(parent->children, node)) { /* error occurred, reverse changes set mg_node to NULL */ pr->is_valid = -1; parent->len -= node->len; cleri__node_free(node); node = NULL; } } else { pr->is_valid = -1; } return node; } } if (cleri__expecting_update(pr->expecting, cl_obj, str) == -1) { pr->is_valid = -1; } return NULL; } /* * Returns 0 if successful and -1 in case an error occurred. * (the token list remains unchanged in case of an error) * * The token will be placed in the list based on the length. Thus the token * list remains ordered on length. (largest first) */ static int TOKENS_list_add( cleri_tlist_t ** tlist, const char * token, size_t len) { cleri_tlist_t * tmp, * prev, * current; current = prev = *tlist; if (current->token == NULL) { current->token = token; current->len = len; return 0; } tmp = (cleri_tlist_t *) malloc(sizeof(cleri_tlist_t)); if (tmp == NULL) { return -1; } tmp->len = len; tmp->token = token; while (current != NULL && len <= current->len) { prev = current; current = current->next; } if (current == *tlist) { tmp->next = *tlist; *tlist = tmp; } else { tmp->next = current; prev->next = tmp; } return 0; } /* * Destroy token list. (NULL can be parsed tlist argument) */ static void TOKENS_list_free(cleri_tlist_t * tlist) { cleri_tlist_t * next; while (tlist != NULL) { next = tlist->next; free(tlist); tlist = next; } } libcleri-0.9.4/src/version.c000066400000000000000000000003271320722715200157340ustar00rootroot00000000000000/* version.h * * Created on: Jun 14, 2017 * Author: Jeroen van der Heijden */ #include const char * cleri_version(void) { return LIBCLERI_VERSION; }