pax_global_header00006660000000000000000000000064145164656100014522gustar00rootroot0000000000000052 comment=2964b6ce6ee57dac5d6dfd13f5a3a351c568fb2f cesbit-libcleri-2964b6c/000077500000000000000000000000001451646561000151175ustar00rootroot00000000000000cesbit-libcleri-2964b6c/.github/000077500000000000000000000000001451646561000164575ustar00rootroot00000000000000cesbit-libcleri-2964b6c/.github/workflows/000077500000000000000000000000001451646561000205145ustar00rootroot00000000000000cesbit-libcleri-2964b6c/.github/workflows/ci.yml000066400000000000000000000007521451646561000216360ustar00rootroot00000000000000name: CI on: push: branches: - master pull_request: branches: - master jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Install dependencies run: | sudo apt-get install -y libpcre2-dev valgrind - name: Run tests run: | cd ./Release/ make test - name: Compile code run: | cd ./Release/ CFLAGS="-Werror -Winline -std=gnu89" make cesbit-libcleri-2964b6c/.gitignore000066400000000000000000000010651451646561000171110ustar00rootroot00000000000000# 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/ # Folder for build artifacts [Bb]uild/ # Debian debian/.debhelper/ debian/debhelper-build-stamp debian/files debian/libcleri-dev.debhelper.log debian/libcleri-dev.substvars debian/libcleri-dev/ debian/libcleri0.debhelper.log debian/libcleri0.substvars debian/libcleri0/ debian/tmp/ cesbit-libcleri-2964b6c/CONTRIBUTING.md000066400000000000000000000015741451646561000173570ustar00rootroot00000000000000# Install dependencies ``` sudo apt-get install libpcre2-8-0 ``` # Running tests ``` make --directory ./Release test ``` # Build ``` make --directory ./Release clean make --directory ./Release ``` # Install ``` # You might want to uninstall first... sudo make --directory ./Release uninstall sudo make --directory ./Release install ``` # Building deb package Make sure the required tools are installed ``` sudo apt-get install devscripts lintian ``` When symbols are changed: ``` dpkg-gensymbols -eRelease/libcleri.so -plibcleri0 ``` In case of a new package, update the changelog. Skip this step if you just want to rebuild the current deb version. ``` debchange ``` In case of any changes, commit ``` git commit -am 'some work that has been done' ``` Create archive from code ``` git archive -o ../libcleri_1.0.0.orig.tar.gz master ``` Build deb package ``` debuild -us -uc ``` cesbit-libcleri-2964b6c/LICENSE.md000066400000000000000000000020311451646561000165170ustar00rootroot00000000000000Copyright (c) 2021 Cesbit 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.cesbit-libcleri-2964b6c/README.md000066400000000000000000000660601451646561000164060ustar00rootroot00000000000000[![CI](https://github.com/cesbit/libcleri/workflows/CI/badge.svg)](https://github.com/cesbit/libcleri/actions) [![Release Version](https://img.shields.io/github/release/cesbit/libcleri)](https://github.com/cesbit/libcleri/releases) # C Left-Right Parser (libcleri) Language parser for the C/C++ programming language. --------------------------------------- * [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_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 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/cesbit/pyleri): Python parser (can export grammar to pyleri, libcleri, goleri, jsleri and jleri) - [jsleri](https://github.com/cesbit/jsleri): JavaScript parser - [goleri](https://github.com/cesbit/goleri): Go parser - [jleri](https://github.com/cesbit/jleri): Java parser ## Quick usage >The recommended way to create a grammar is to use [pyleri](https://github.com/cesbit/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 default `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. Even when `is_valid` is `False` the parse tree is returned but will only contain results as far as parsing has succeeded. The tree is the root node which can include several `children` nodes. The structure will be further clarified in the example that explains a way of visualizing the parse tree. This example can be found in the "examples/tree_and_expect/tree" folder. Run this code and it will output a parse tree in JSON format. (see also [cleri_node_t](#cleri_node_t)) (readonly) - `const cleri_olist_t * expect`: Linked list to possible elements at position `cleri_parse_t.pos` in `cleri_parse_t.str`. Even if `is_valid` is true there might be elements in this set, for example when an `Optional()` element could be added to the string. Expecting is useful if you want to implement things like auto-completion, syntax error handling, auto-syntax-correction etc. (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. #### `void cleri_parse_strn(char * s, size_t n, cleri_parse_t * pr, cleri_translate_t * translate)` Can be used to generate a textual parse result. The first argument `s` should be able to hold the complete message and will be restricted by `n`. The return value is the number of characters which are (or would be) written to `s`, excluding the terminator char. This behavior is similar to functions like `snprintf`. One could for example use `NULL` for `s` with `n` equals to `0` to get the size which is required. Then you could `malloc` the size plus one for the terminator and run the functions again. A negative value indicates an error. Argument `pr` should be a parse result or `NULL` and `translate` a translation function or `NULL`. Example: ```c // In case a translation function returns an empty string, no text is used const char * translate(cleri_t * o) { return ""; // a possible result might be: `error at line 1, position x` } // Text may be returned based on gid const char * translate(cleri_t * o) { switch (o->gid) { case 1: return "A"; // error at line 1, position x, expecting: A case 2: return ""; // gid 2 will be ignored } return NULL; // normal parsing for everything else } ``` ### `cleri_node_t` Node object. A parse result has a parse tree which consists of nodes. Each node may have children. *Members* - `const char * cleri_node_t.str`: Pointer to the position in the parse string where this node starts. (readonly) - `uint32_t cleri_node_t.len`: Length of the string which is applicable for this node. (readonly) - `uint32_t cleri_node_t.ref`: Reference counter for this node. (for internal use, readonly) - `cleri_t * cleri_node_t.cl_obj`: Element from the grammar which matches this node. Note that the `cl_obj` is `NULL` for the root node and the first can be found in its children. (readonly) - `cleri_node_t * cleri_node_t.children`: Optional children for this node. (readonly) - `cleri_node_t * cleri_node_t.next`: Optional next sibling. (readonly) - `void * cleri_node_t.data`: Free to use. Example looping over all children of a node: ```c /* we asume having a node (cleri_node_t*) */ cleri_node_t * child = node->children; while (child != NULL) { // do something with *child* and go to the next sibling child = child->next; } ``` #### `bool cleri_node_has_children(cleri_node_t * node)` Macro function for checking if a node has children. ### `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/cesbit/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. cesbit-libcleri-2964b6c/Release/000077500000000000000000000000001451646561000164775ustar00rootroot00000000000000cesbit-libcleri-2964b6c/Release/makefile000066400000000000000000000016331451646561000202020ustar00rootroot00000000000000-include ../makefile.init RM := rm -rf CC ?= gcc -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 SO_NAME := install_name else FN := libcleri.so INSTALL_PATH := /usr SO_NAME := soname endif # All Target all: libcleri # Tool invocations libcleri: $(OBJS) $(USER_OBJS) @echo 'Building target: $@' @echo "Invoking: Cross $(CC) Linker" $(CC) -shared -Wl,-$(SO_NAME),$(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 test: @cd ../test && ./test.sh cesbit-libcleri-2964b6c/Release/objects.mk000066400000000000000000000000401451646561000204530ustar00rootroot00000000000000USER_OBJS := LIBS := -lpcre2-8 cesbit-libcleri-2964b6c/Release/sources.mk000066400000000000000000000001621451646561000205120ustar00rootroot00000000000000OBJ_SRCS := ASM_SRCS := C_SRCS := O_SRCS := S_UPPER_SRCS := EXECUTABLES := OBJS := C_DEPS := SUBDIRS := \ src \ cesbit-libcleri-2964b6c/Release/src/000077500000000000000000000000001451646561000172665ustar00rootroot00000000000000cesbit-libcleri-2964b6c/Release/src/subdir.mk000066400000000000000000000026131451646561000211110ustar00rootroot00000000000000C_SRCS += \ ../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 \ ../src/version.c OBJS += \ ./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 \ ./src/version.o C_DEPS += \ ./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 \ ./src/version.d src/%.o: ../src/%.c @echo 'Building file: $<' @echo "Invoking: Cross $(CC) Compiler" $(CC) -DNDEBUG -I../inc -O3 -Winline -Wall $(CPPFLAGS) $(CFLAGS) -c -fmessage-length=0 -fPIC -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$@" "$<" @echo 'Finished building: $<' @echo ' ' cesbit-libcleri-2964b6c/debian/000077500000000000000000000000001451646561000163415ustar00rootroot00000000000000cesbit-libcleri-2964b6c/debian/changelog000066400000000000000000000066221451646561000202210ustar00rootroot00000000000000libcleri (1.0.2-0~tt1) unstable; urgency=medium * Fixed makefile to correct version. * Do not hard-code GCC as compiler #24, @giordano -- Jeroen van der Heijden Thu, 26 Oct 2023 15:03:14 +0200 libcleri (1.0.1-0~tt1.1) UNRELEASED; urgency=medium * Non-maintainer upload. * Fix FTCBFS: (Closes: #-1) + Let dh_auto_build pass cross tools to make. + cross.patch: Make gcc substitutable. -- Helmut Grohne Sun, 17 May 2020 12:14:38 +0200 libcleri (1.0.1-0~tt1) unstable; urgency=medium * Changed company name to Cesbit. * Removed regular expression assertion. -- Jeroen van der Heijden Mon, 17 Oct 2022 09:24 +0100 libcleri (1.0.0-0~tt1) unstable; urgency=medium * Remove cleri_children_t to reduce mallocs, issue #18 * Fixed bug with `CLERI_FLAG_EXPECTING_DISABLED` flag * Ordered expecting chages for minor speed improvement -- Jeroen van der Heijden Mon, 03 Jan 2022 16:20:49 +0100 libcleri (0.12.2-0~tt1) unstable; urgency=medium * Fixed bug in Prio element -- Jeroen van der Heijden Tue, 10 Aug 2021 11:08:22 +0200 libcleri (0.11.1-0~tt1) unstable; urgency=medium * Changed start of line numbering from 0 to 1 -- Jeroen van der Heijden Tue, 12 Nov 2019 08:44:10 +0100 libcleri (0.11.0-0~tt1) unstable; urgency=medium * Added cleri_parse2() which accepts an additional `flags` argument * Improved syntax error handling * Set correct position when nested error in syntax is found -- Jeroen van der Heijden Tue, 22 Oct 2019 10:59:14 +0200 libcleri (0.10.1-0~alpha1-tt1) unstable; urgency=medium * Added option to disable generating expecting info -- Jeroen van der Heijden Mon, 12 Nov 2018 14:34:16 +0100 libcleri (0.10.1-0~alpha0-tt1) unstable; urgency=medium * Added `void *data` to node type for public usage * Children will only be added to a node when necessary (Be carefull that accessing the first child therefore must be checked for NULL whereas in previous versions, one could immediately check the `children->node` pointer) -- Jeroen van der Heijden Wed, 31 Oct 2018 22:22:05 +0100 libcleri (0.10.0-0~tt1) unstable; urgency=medium * Update deb test * Update Vsc fields * New upstream release - Fixed expecting when parsing a list (Issue: #11) - Fixed `is_valid` property when parsing empty strings (Issue #12) - Added `cleri_parse_strn()` function for generating a textual parse result -- Jeroen van der Heijden Fri, 12 Oct 2018 15:28:28 +0200 libcleri (0.9.4-2) unstable; urgency=medium * Update and add Vcs-* fields for move to salsa (Closes: #890701) * Add autopkgtest by compiling the examples * Install examples -- Paul Gevers Fri, 27 Jul 2018 21:04:02 +0200 libcleri (0.9.4-1) unstable; urgency=medium * New upstream release - Migrated to pcre2 after being informed by us about the state of pcre3 * Drop obsolete patch * Make packages as Multi-Arch:same * Bump standards to 4.1.2 (no changes) -- Paul Gevers Sun, 03 Dec 2017 19:24:17 +0100 libcleri (0.9.3-1) unstable; urgency=medium * Initial release. (Closes: #882677) -- Paul Gevers Sun, 26 Nov 2017 08:11:22 +0100 cesbit-libcleri-2964b6c/debian/compat000066400000000000000000000000031451646561000175400ustar00rootroot0000000000000010 cesbit-libcleri-2964b6c/debian/control000066400000000000000000000027501451646561000177500ustar00rootroot00000000000000Source: libcleri Section: libs Priority: optional Maintainer: SiriDB Maintainers Uploaders: Jeroen van der Heijden , Paul Gevers , Rules-Requires-Root: no Build-Depends: debhelper (>= 10~), dh-exec, libpcre2-dev, Homepage: https://siridb.net/ Vcs-Browser: https://salsa.debian.org/siridb-team/libcleri Vcs-Git: https://salsa.debian.org/siridb-team/libcleri.git Standards-Version: 4.1.2 Package: libcleri0 Architecture: any Multi-Arch: same Depends: ${misc:Depends}, ${shlibs:Depends}, Description: language parser library Libcleri is a powerful tool to build languages. From a built language, libcleri can automatically create parse trees, which are data structures representing how a grammar matches input. It also provides feedback in case the input does not match the language. This can be useful for auto-completion, suggestions or error handling. Package: libcleri-dev Section: libdevel Architecture: any Multi-Arch: same Depends: libcleri0 (= ${binary:Version}), ${misc:Depends}, Description: language parser library - development files Libcleri is a powerful tool to build languages. From a built language, libcleri can automatically create parse trees, which are data structures representing how a grammar matches input. It also provides feedback in case the input does not match the language. This can be useful for auto-completion, suggestions or error handling. . This package contains the development files. cesbit-libcleri-2964b6c/debian/copyright000066400000000000000000000024331451646561000202760ustar00rootroot00000000000000Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Files: * Copyright: 2021, Cesbit License: Expat Files: debian/* Copyright: 2017 Paul Gevers License: Expat License: Expat The MIT License . 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. cesbit-libcleri-2964b6c/debian/libcleri-dev.docs000066400000000000000000000000121451646561000215450ustar00rootroot00000000000000README.md cesbit-libcleri-2964b6c/debian/libcleri-dev.examples000066400000000000000000000000131451646561000224340ustar00rootroot00000000000000examples/* cesbit-libcleri-2964b6c/debian/libcleri-dev.install000066400000000000000000000000401451646561000222640ustar00rootroot00000000000000inc/cleri/*.h usr/include/cleri cesbit-libcleri-2964b6c/debian/libcleri-dev.links000077500000000000000000000001621451646561000217460ustar00rootroot00000000000000#! /usr/bin/dh-exec usr/lib/${DEB_HOST_MULTIARCH}/libcleri.so.${SONAME} usr/lib/${DEB_HOST_MULTIARCH}/libcleri.so cesbit-libcleri-2964b6c/debian/libcleri0.examples000066400000000000000000000000131451646561000217400ustar00rootroot00000000000000examples/* cesbit-libcleri-2964b6c/debian/libcleri0.install000077500000000000000000000001561451646561000216030ustar00rootroot00000000000000#! /usr/bin/dh-exec Release/libcleri.so => /usr/lib/${DEB_HOST_MULTIARCH}/libcleri.so.${DEB_VERSION_UPSTREAM} cesbit-libcleri-2964b6c/debian/libcleri0.links000077500000000000000000000002121451646561000212460ustar00rootroot00000000000000#! /usr/bin/dh-exec usr/lib/${DEB_HOST_MULTIARCH}/libcleri.so.${DEB_VERSION_UPSTREAM} usr/lib/${DEB_HOST_MULTIARCH}/libcleri.so.${SONAME} cesbit-libcleri-2964b6c/debian/libcleri0.symbols000066400000000000000000000026041451646561000216220ustar00rootroot00000000000000libcleri.so.0 libcleri0 #MINVER# CLERI_EMPTY_NODE@Base 0.9.3 CLERI_END_OF_STATEMENT@Base 0.9.3 CLERI_THIS@Base 0.9.3 cleri__expecting_combine@Base 0.9.3 cleri__expecting_free@Base 0.9.3 cleri__expecting_new@Base 0.9.3 cleri__expecting_set_mode@Base 0.9.3 cleri__expecting_update@Base 0.9.3 cleri__kwcache_free@Base 0.9.3 cleri__kwcache_match@Base 0.9.3 cleri__kwcache_new@Base 0.9.3 cleri__node_dup@Base 1.0.0~ cleri__node_free@Base 0.9.3 cleri__node_new@Base 0.9.3 cleri__olist_append@Base 0.9.3 cleri__olist_append_nref@Base 0.9.3 cleri__olist_cancel@Base 0.9.3 cleri__olist_empty@Base 0.9.3 cleri__olist_free@Base 0.9.3 cleri__olist_new@Base 0.9.3 cleri__olist_unique@Base 0.11.0~ cleri__parse_walk@Base 0.9.3 cleri__rule@Base 0.9.3 cleri__rule_init@Base 0.9.3 cleri_choice@Base 0.9.3 cleri_decref@Base 0.9.3 cleri_dup@Base 0.9.3 cleri_free@Base 0.9.3 cleri_grammar@Base 0.9.3 cleri_grammar_free@Base 0.9.3 cleri_incref@Base 0.9.3 cleri_keyword@Base 0.9.3 cleri_list@Base 0.9.3 cleri_new@Base 0.9.3 cleri_optional@Base 0.9.3 cleri_parse2@Base 0.10.1~ cleri_parse_expect_start@Base 0.9.3 cleri_parse_free@Base 0.9.3 cleri_parse_strn@Base 0.10.0~ cleri_prio@Base 0.9.3 cleri_ref@Base 0.9.3 cleri_ref_set@Base 0.9.3 cleri_regex@Base 0.9.3 cleri_repeat@Base 0.9.3 cleri_sequence@Base 0.9.3 cleri_token@Base 0.9.3 cleri_tokens@Base 0.9.3 cleri_version@Base 0.10.1~ cesbit-libcleri-2964b6c/debian/rules000077500000000000000000000007541451646561000174270ustar00rootroot00000000000000#!/usr/bin/make -f export DEB_BUILD_MAINT_OPTIONS=hardening=+all include /usr/share/dpkg/pkg-info.mk # Use both these variable to create the right libcleri.so* files/links export DEB_VERSION_UPSTREAM # Should be dynamic or unnecessary in the future, for now, just hard-code export SONAME=0 %: dh $@ override_dh_auto_build-arch: dh_auto_build --sourcedirectory=Release -- all override_dh_auto_clean: $(MAKE) --directory=Release clean dh_auto_clean override_dh_fixperms: dh_fixperms cesbit-libcleri-2964b6c/debian/source/000077500000000000000000000000001451646561000176415ustar00rootroot00000000000000cesbit-libcleri-2964b6c/debian/source/format000066400000000000000000000000141451646561000210470ustar00rootroot000000000000003.0 (quilt) cesbit-libcleri-2964b6c/debian/tests/000077500000000000000000000000001451646561000175035ustar00rootroot00000000000000cesbit-libcleri-2964b6c/debian/tests/control000066400000000000000000000001651451646561000211100ustar00rootroot00000000000000Test-Command: USELIB=1 make --directory=Release test Features: test-name=libcleri-unit-tests Depends: @, @builddeps@ cesbit-libcleri-2964b6c/debian/watch000066400000000000000000000002461451646561000173740ustar00rootroot00000000000000version=4 opts="filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%libcleri-$1.tar.gz%" \ https://github.com/cesbit/libcleri/releases \ (?:.*?/)?v?(\d[\d.]*)\.tar\.gz cesbit-libcleri-2964b6c/examples/000077500000000000000000000000001451646561000167355ustar00rootroot00000000000000cesbit-libcleri-2964b6c/examples/choice/000077500000000000000000000000001451646561000201675ustar00rootroot00000000000000cesbit-libcleri-2964b6c/examples/choice/main.c000066400000000000000000000015131451646561000212570ustar00rootroot00000000000000#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; }cesbit-libcleri-2964b6c/examples/hi_iris/000077500000000000000000000000001451646561000203635ustar00rootroot00000000000000cesbit-libcleri-2964b6c/examples/hi_iris/main.c000066400000000000000000000014051451646561000214530ustar00rootroot00000000000000#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; }cesbit-libcleri-2964b6c/examples/json/000077500000000000000000000000001451646561000177065ustar00rootroot00000000000000cesbit-libcleri-2964b6c/examples/json/json.c000066400000000000000000000036171451646561000210320ustar00rootroot00000000000000/* * 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; } cesbit-libcleri-2964b6c/examples/json/json.h000066400000000000000000000013311451646561000210260ustar00rootroot00000000000000/* * 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_ */ cesbit-libcleri-2964b6c/examples/json/main.c000066400000000000000000000006631451646561000210030ustar00rootroot00000000000000#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; } cesbit-libcleri-2964b6c/examples/keyword/000077500000000000000000000000001451646561000204215ustar00rootroot00000000000000cesbit-libcleri-2964b6c/examples/keyword/main.c000066400000000000000000000013351451646561000215130ustar00rootroot00000000000000#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; }cesbit-libcleri-2964b6c/examples/list/000077500000000000000000000000001451646561000177105ustar00rootroot00000000000000cesbit-libcleri-2964b6c/examples/list/main.c000066400000000000000000000015671451646561000210110ustar00rootroot00000000000000#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; } cesbit-libcleri-2964b6c/examples/optional/000077500000000000000000000000001451646561000205625ustar00rootroot00000000000000cesbit-libcleri-2964b6c/examples/optional/main.c000066400000000000000000000016401451646561000216530ustar00rootroot00000000000000#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; } cesbit-libcleri-2964b6c/examples/prio/000077500000000000000000000000001451646561000177065ustar00rootroot00000000000000cesbit-libcleri-2964b6c/examples/prio/main.c000066400000000000000000000025671451646561000210100ustar00rootroot00000000000000#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; } cesbit-libcleri-2964b6c/examples/ref/000077500000000000000000000000001451646561000175115ustar00rootroot00000000000000cesbit-libcleri-2964b6c/examples/ref/main.c000066400000000000000000000014241451646561000206020ustar00rootroot00000000000000#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; }cesbit-libcleri-2964b6c/examples/repeat/000077500000000000000000000000001451646561000202155ustar00rootroot00000000000000cesbit-libcleri-2964b6c/examples/repeat/main.c000066400000000000000000000013761451646561000213140ustar00rootroot00000000000000#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; } cesbit-libcleri-2964b6c/examples/sequence/000077500000000000000000000000001451646561000205455ustar00rootroot00000000000000cesbit-libcleri-2964b6c/examples/sequence/main.c000066400000000000000000000015051451646561000216360ustar00rootroot00000000000000#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; } cesbit-libcleri-2964b6c/examples/token/000077500000000000000000000000001451646561000200555ustar00rootroot00000000000000cesbit-libcleri-2964b6c/examples/token/main.c000066400000000000000000000013161451646561000211460ustar00rootroot00000000000000#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; } cesbit-libcleri-2964b6c/examples/tokens/000077500000000000000000000000001451646561000202405ustar00rootroot00000000000000cesbit-libcleri-2964b6c/examples/tokens/main.c000066400000000000000000000013501451646561000213270ustar00rootroot00000000000000#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; } cesbit-libcleri-2964b6c/inc/000077500000000000000000000000001451646561000156705ustar00rootroot00000000000000cesbit-libcleri-2964b6c/inc/cleri/000077500000000000000000000000001451646561000167665ustar00rootroot00000000000000cesbit-libcleri-2964b6c/inc/cleri/choice.h000066400000000000000000000012541451646561000203730ustar00rootroot00000000000000/* * choice.h - this cleri element can hold other elements and the grammar * has to choose one of them. */ #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_ */cesbit-libcleri-2964b6c/inc/cleri/cleri.h000066400000000000000000000071201451646561000202350ustar00rootroot00000000000000/* * cleri.h - each cleri element is a cleri object. */ #ifndef CLERI_OBJECT_H_ #define CLERI_OBJECT_H_ #ifdef __cplusplus #define cleri__malloc(__t) ((__t*)malloc(sizeof(__t))) #else #define cleri__malloc(__t) (malloc(sizeof(__t))) #endif #ifdef __cplusplus #define cleri__mallocn(__n, __t) ((__t*)malloc(__n * sizeof(__t))) #else #define cleri__mallocn(__n, __t) (malloc(__n * sizeof(__t))) #endif #include #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_ */cesbit-libcleri-2964b6c/inc/cleri/dup.h000066400000000000000000000007601451646561000177320ustar00rootroot00000000000000/* * dup.h - this cleri element can be used to duplicate an element. */ #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_ */cesbit-libcleri-2964b6c/inc/cleri/expecting.h000066400000000000000000000024071451646561000211300ustar00rootroot00000000000000/* * expecting.h - holds elements which the grammar expects at one position. * this can be used for suggestions. */ #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 flags); 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_ */cesbit-libcleri-2964b6c/inc/cleri/grammar.h000066400000000000000000000013471451646561000205720ustar00rootroot00000000000000/* * grammar.h - this should contain the 'start' or your grammar. */ #ifndef CLERI_GRAMMAR_H_ #define CLERI_GRAMMAR_H_ #define PCRE2_CODE_UNIT_WIDTH 8 #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_ */cesbit-libcleri-2964b6c/inc/cleri/keyword.h000066400000000000000000000010571451646561000206260ustar00rootroot00000000000000/* * keyword.h - cleri keyword element. */ #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_ */cesbit-libcleri-2964b6c/inc/cleri/kwcache.h000066400000000000000000000007371451646561000205530ustar00rootroot00000000000000/* * kwcache.h - holds keyword regular expression result while parsing. */ #ifndef CLERI_KWCACHE_H_ #define CLERI_KWCACHE_H_ #include #include #include /* typedefs */ typedef struct cleri_parse_s cleri_parse_t; /* private functions */ uint8_t * cleri__kwcache_new(const char * str); uint8_t cleri__kwcache_match(cleri_parse_t * pr, const char * str); void cleri__kwcache_free(uint8_t * kwcache); #endif /* CLERI_KWCACHE_H_ */ cesbit-libcleri-2964b6c/inc/cleri/list.h000066400000000000000000000012571451646561000201170ustar00rootroot00000000000000/* * list.h - cleri list element. */ #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_ */cesbit-libcleri-2964b6c/inc/cleri/node.h000066400000000000000000000021751451646561000200710ustar00rootroot00000000000000/* * node.h - node is created while parsing a string. a node old the result * for one element. */ #ifndef CLERI_NODE_H_ #define CLERI_NODE_H_ #include #include #include #include /* typedefs */ typedef struct cleri_s cleri_t; typedef struct cleri_node_s cleri_node_t; /* public macro function */ #define cleri_node_has_children(__node) ((__node)->children != NULL) /* private functions */ cleri_node_t * cleri__node_new(cleri_t * cl_obj, const char * str, size_t len); cleri_node_t * cleri__node_dup(cleri_node_t * node); 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 { uint32_t ref; uint32_t len; const char * str; cleri_t * cl_obj; cleri_node_t * children; cleri_node_t * next; void * data; /* free to use by the user */ }; static inline void cleri__node_add(cleri_node_t * parent, cleri_node_t * node) { cleri_node_t ** nodeaddr = parent->data; *nodeaddr = node; parent->data = &node->next; } #endif /* CLERI_NODE_H_ */cesbit-libcleri-2964b6c/inc/cleri/olist.h000066400000000000000000000014211451646561000202670ustar00rootroot00000000000000/* * olist.h - linked list for keeping cleri objects. */ #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); void cleri__olist_unique(cleri_olist_t * olist); /* structs */ struct cleri_olist_s { cleri_t * cl_obj; cleri_olist_t * next; }; #endif /* CLERI_OLIST_H_ */cesbit-libcleri-2964b6c/inc/cleri/optional.h000066400000000000000000000007551451646561000207730ustar00rootroot00000000000000/* * optional.h - cleri optional element. */ #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_ */cesbit-libcleri-2964b6c/inc/cleri/parse.h000066400000000000000000000040311451646561000202470ustar00rootroot00000000000000/* * parse.h - this contains everything for parsing a string to a grammar. */ #ifndef CLERI_PARSE_H_ #define CLERI_PARSE_H_ #include #include #include #include #include #include #include #include #ifndef MAX_RECURSION_DEPTH #define MAX_RECURSION_DEPTH 500 #endif enum { CLERI_FLAG_EXPECTING_DISABLED =1<<0, CLERI_FLAG_EXCLUDE_OPTIONAL =1<<1, CLERI_FLAG_EXCLUDE_FM_CHOICE =1<<2, CLERI_FLAG_EXCLUDE_RULE_THIS =1<<3, }; /* 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_rule_store_s cleri_rule_store_t; typedef struct cleri_parse_s cleri_parse_t; typedef const char * (cleri_translate_t)(cleri_t *); /* public functions */ #ifdef __cplusplus extern "C" { #endif static inline cleri_parse_t * cleri_parse( cleri_grammar_t * grammar, const char * str); cleri_parse_t * cleri_parse2( cleri_grammar_t * grammar, const char * str, int flags); void cleri_parse_free(cleri_parse_t * pr); void cleri_parse_expect_start(cleri_parse_t * pr); int cleri_parse_strn( char * s, size_t n, cleri_parse_t * pr, cleri_translate_t * translate); #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; int flags; 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; uint8_t * kwcache; }; static inline cleri_parse_t * cleri_parse( cleri_grammar_t * grammar, const char * str) { return cleri_parse2(grammar, str, 0); } #endif /* CLERI_PARSE_H_ */ cesbit-libcleri-2964b6c/inc/cleri/prio.h000066400000000000000000000012161451646561000201100ustar00rootroot00000000000000/* * prio.h - cleri prio element. (this element create a cleri rule object * holding this prio element) */ #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_ */cesbit-libcleri-2964b6c/inc/cleri/ref.h000066400000000000000000000006111451646561000177110ustar00rootroot00000000000000/* * ref.h - cleri ref element */ #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_ */cesbit-libcleri-2964b6c/inc/cleri/regex.h000066400000000000000000000011201451646561000202430ustar00rootroot00000000000000/* * regex.h - cleri regular expression element. */ #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_ */cesbit-libcleri-2964b6c/inc/cleri/repeat.h000066400000000000000000000011041451646561000204130ustar00rootroot00000000000000/* * repeat.h - cleri regular repeat element. */ #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_ */cesbit-libcleri-2964b6c/inc/cleri/rule.h000066400000000000000000000023161451646561000201100ustar00rootroot00000000000000/* * 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) */ #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_ */cesbit-libcleri-2964b6c/inc/cleri/sequence.h000066400000000000000000000011121451646561000207420ustar00rootroot00000000000000/* * sequence.h - cleri sequence element. */ #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_ */cesbit-libcleri-2964b6c/inc/cleri/this.h000066400000000000000000000007471451646561000201160ustar00rootroot00000000000000/* * 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. */ #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_ */cesbit-libcleri-2964b6c/inc/cleri/token.h000066400000000000000000000013131451646561000202550ustar00rootroot00000000000000/* * 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) */ #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_ */ cesbit-libcleri-2964b6c/inc/cleri/tokens.h000066400000000000000000000013541451646561000204450ustar00rootroot00000000000000/* * tokens.h - cleri tokens element. (like token but can contain more tokens * in one element) */ #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_ */cesbit-libcleri-2964b6c/inc/cleri/version.h000066400000000000000000000013331451646561000206240ustar00rootroot00000000000000/* * version.h - cleri version information. */ #ifndef CLERI_VERSION_H_ #define CLERI_VERSION_H_ #define CLERI_VERSION_MAJOR 1 #define CLERI_VERSION_MINOR 0 #define CLERI_VERSION_PATCH 2 #define VERSION__STRINGIFY(num) #num #define VERSION___STR(major,minor,patch) \ VERSION__STRINGIFY(major) "." \ VERSION__STRINGIFY(minor) "." \ VERSION__STRINGIFY(patch) /* end helpers */ /* start auto generated from above */ #define LIBCLERI_VERSION VERSION___STR( \ CLERI_VERSION_MAJOR, \ CLERI_VERSION_MINOR, \ CLERI_VERSION_PATCH) /* public funtion */ #ifdef __cplusplus extern "C" { #endif const char * cleri_version(void); #ifdef __cplusplus } #endif #endif /* CLERI_VERSION_H_ */ cesbit-libcleri-2964b6c/makefile.init000066400000000000000000000001071451646561000175570ustar00rootroot00000000000000MAJOR := 1 MINOR := 0 PATCH := 2 VERSION := $(MAJOR).$(MINOR).$(PATCH) cesbit-libcleri-2964b6c/makefile.targets000066400000000000000000000010511451646561000202640ustar00rootroot00000000000000.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 @rm -r -f $(INSTALL_PATH)/include/cleri/ @rm -f $(INSTALL_PATH)/lib/$(FN) @rm -f $(INSTALL_PATH)/lib/$(FN).$(MAJOR) @rm -f $(INSTALL_PATH)/lib/$(FN).$(VERSION) cesbit-libcleri-2964b6c/src/000077500000000000000000000000001451646561000157065ustar00rootroot00000000000000cesbit-libcleri-2964b6c/src/choice.c000066400000000000000000000117041451646561000173070ustar00rootroot00000000000000/* * choice.c - this cleri element can hold other elements and the grammar * has to choose one of them. */ #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__malloc(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; cleri__node_add(parent, mg_node); } 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; if ((pr->flags & CLERI_FLAG_EXCLUDE_FM_CHOICE) && !cl_obj->gid) { while (olist != NULL) { node = cleri__parse_walk( pr, parent, olist->cl_obj, rule, CLERI__EXP_MODE_REQUIRED); if (node != NULL) { return node; } olist = olist->next; } return NULL; } 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; cleri__node_add(parent, node); return node; } olist = olist->next; } cleri__node_free(node); return NULL; } cesbit-libcleri-2964b6c/src/cleri.c000066400000000000000000000043411451646561000171520ustar00rootroot00000000000000/* * cleri.c - each cleri element is a cleri object. */ #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 = cleri__malloc(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; } cesbit-libcleri-2964b6c/src/dup.c000066400000000000000000000014351451646561000166450ustar00rootroot00000000000000/* * dup.c - this cleri element can be used to duplicate an element. */ #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__malloc(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); } cesbit-libcleri-2964b6c/src/expecting.c000066400000000000000000000116011451646561000200370ustar00rootroot00000000000000/* * expecting.c - holds elements which the grammar expects at one position. * this can be used for suggestions. */ #include #include 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, int flags) { cleri_expecting_t * expecting = cleri__malloc(cleri_expecting_t); if (expecting != NULL) { expecting->str = str; expecting->modes = NULL; if (flags & CLERI_FLAG_EXPECTING_DISABLED) { expecting->required = NULL; expecting->optional = NULL; return expecting; } 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; } } 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 (expecting->required == NULL) { if (str > expecting->str) { expecting->str = str; } return 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 ** modes = &expecting->modes; if (expecting->required == NULL) { return 0; } for (; *modes != NULL; modes = &(*modes)->next) { if ((*modes)->str == str) { (*modes)->mode = mode && (*modes)->mode; return 0; } } *modes = cleri__malloc(cleri_exp_modes_t); if (*modes == NULL) { return -1; } (*modes)->mode = mode; (*modes)->next = NULL; (*modes)->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; } /* * 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; } (*modes)->str = str; } /* * 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); } cesbit-libcleri-2964b6c/src/grammar.c000066400000000000000000000041021451646561000174750ustar00rootroot00000000000000/* * grammar.c - this should contain the 'start' or your grammar. */ #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; /* re_keywords should start with a ^ */ assert (re_kw[0] == '^'); if (start == NULL) { return NULL; } cleri_grammar_t * grammar = cleri__malloc(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); } cesbit-libcleri-2964b6c/src/keyword.c000066400000000000000000000046631451646561000175470ustar00rootroot00000000000000/* * keyword.c - cleri keyword element. */ #include #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); /* * Keywords must match the `keyword` regular expression defined by the grammar, * and should have more than 0 and less than 255 characters. * * Returns NULL in case an error has occurred. */ cleri_t * cleri_keyword(uint32_t gid, const char * keyword, int ign_case) { size_t n = strlen(keyword); assert (n > 0 && n < UINT8_MAX); 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__malloc(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 = n; 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))) { size_t kw_len = cl_obj->via.keyword->len; cleri_node_t * node = NULL; const char * str = parent->str + parent->len; if ((strncmp(cl_obj->via.keyword->keyword, str, kw_len) == 0 || ( cl_obj->via.keyword->ign_case && strncasecmp(cl_obj->via.keyword->keyword, str, kw_len) == 0)) && cleri__kwcache_match(pr, str) == kw_len) { if ((node = cleri__node_new(cl_obj, str, kw_len)) != NULL) { parent->len += node->len; cleri__node_add(parent, node); } else { pr->is_valid = -1; /* error occurred */ } } 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; } cesbit-libcleri-2964b6c/src/kwcache.c000066400000000000000000000027371451646561000174700ustar00rootroot00000000000000/* * kwcache.c - holds keyword regular expression result while parsing. */ #define PCRE2_CODE_UNIT_WIDTH 8 #include #include #include #include #include #define NOT_FOUND UINT8_MAX /* * Returns NULL in case an error has occurred. */ uint8_t * cleri__kwcache_new(const char * str) { size_t n = strlen(str); uint8_t * kwcache = cleri__mallocn(n, uint8_t); if (kwcache != NULL) { memset(kwcache, NOT_FOUND, n * sizeof(uint8_t)); } return kwcache; } /* * Returns 0 when no kw_match is found, -1 when an error has occurred, or the * new kwcache->len value. */ uint8_t cleri__kwcache_match(cleri_parse_t * pr, const char * str) { uint8_t * len; if (*str == '\0') { return 0; } len = &pr->kwcache[str - pr->str]; if (*len == NOT_FOUND) { int pcre_exec_ret; pcre_exec_ret = pcre2_match( pr->re_keywords, (PCRE2_SPTR8) str, PCRE2_ZERO_TERMINATED, 0, // start looking at this point 0, // OPTIONS pr->match_data, NULL); *len = pcre_exec_ret < 0 ? 0 : pcre2_get_ovector_pointer(pr->match_data)[1]; } return *len; } /* * Destroy kwcache. (parsing NULL is allowed) */ void cleri__kwcache_free(uint8_t * kwcache) { free(kwcache); }cesbit-libcleri-2964b6c/src/list.c000066400000000000000000000061151451646561000170300ustar00rootroot00000000000000/* * list.c - cleri list element. */ #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__malloc(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_list_t * list = cl_obj->via.list; 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, list->cl_obj, rule, i < list->min); // 1 = REQUIRED if (rnode == NULL || (++i == list->max && list->opt_closing == false)) { break; } rnode = cleri__parse_walk( pr, node, list->delimiter, rule, i < list->min); // 1 = REQUIRED if (rnode == NULL || ++j == list->max) { break; } } if (i < list->min || (list->opt_closing == false && i && i == j)) { cleri__node_free(node); return NULL; } parent->len += node->len; cleri__node_add(parent, node); return node; } cesbit-libcleri-2964b6c/src/node.c000066400000000000000000000032321451646561000167770ustar00rootroot00000000000000/* * node.c - node is created while parsing a string. a node old the result * for one element. */ #include #include static cleri_node_t CLERI__EMPTY_NODE = { .children=NULL, .next=NULL, .cl_obj=NULL, .len=0, .str=NULL, .ref=1, }; 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 = cleri__malloc(cleri_node_t); if (node != NULL) { node->cl_obj = cl_obj; node->ref = 1; node->str = str; node->len = len; node->children = NULL; node->next = NULL; node->data = &node->children; } return node; } cleri_node_t * cleri__node_dup(cleri_node_t * node) { cleri_node_t * dup = cleri__malloc(cleri_node_t); if (dup != NULL) { dup->cl_obj = node->cl_obj; dup->ref = 1; dup->str = node->str; dup->len = node->len; node = node->children; dup->children = node; while(node) { node->ref++; node = node->next; } dup->next = NULL; } return dup; } void cleri__node_free(cleri_node_t * node) { cleri_node_t * next; /* node can be NULL or this could be an CLERI_EMPTY_NODE */ if (node == NULL || --node->ref) { return; } next = node->children; while (next != NULL) { cleri_node_t * tmp = next->next; next->next = NULL; cleri__node_free(next); next = tmp; } free(node); } cesbit-libcleri-2964b6c/src/olist.c000066400000000000000000000070021451646561000172030ustar00rootroot00000000000000/* * olist.c - linked list for keeping cleri objects. */ #include #include /* * Returns NULL in case an error has occurred. */ cleri_olist_t * cleri__olist_new(void) { cleri_olist_t * olist = cleri__malloc(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__malloc(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__malloc(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); } void cleri__olist_unique(cleri_olist_t * olist) { while (olist != NULL && olist->next != NULL) { cleri_olist_t * test = olist; while (test->next != NULL) { if (olist->cl_obj == test->next->cl_obj) { cleri_olist_t * tmp = test->next->next; free(test->next); test->next = tmp; continue; } test = test->next; } olist = olist->next; } }cesbit-libcleri-2964b6c/src/optional.c000066400000000000000000000042761451646561000177100ustar00rootroot00000000000000/* * optional.c - cleri optional element. */ #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__malloc(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 ((pr->flags & CLERI_FLAG_EXCLUDE_OPTIONAL) && !cl_obj->gid) { node = cleri__parse_walk( pr, parent, cl_obj->via.optional->cl_obj, rule, CLERI__EXP_MODE_OPTIONAL); return node ? node : CLERI_EMPTY_NODE; } 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; cleri__node_add(parent, node); return node; } cleri__node_free(node); return CLERI_EMPTY_NODE; } cesbit-libcleri-2964b6c/src/parse.c000066400000000000000000000201651451646561000171700ustar00rootroot00000000000000/* * parse.c - this contains everything for parsing a string to a grammar. */ #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_parse2( cleri_grammar_t * grammar, const char * str, int flags) { cleri_node_t * nd; cleri_parse_t * pr; const char * end; const char * test; /* prepare parsing */ pr = cleri__malloc(cleri_parse_t); if (pr == NULL) { return NULL; } pr->flags = flags; 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(str)) == NULL || (pr->expecting = cleri__expecting_new(str, flags)) == NULL) { cleri_parse_free(pr); return NULL; } pr->re_keywords = grammar->re_keywords; pr->match_data = grammar->match_data; /* do the actual parsing */ nd = 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; } pr->is_valid = nd != NULL; /* process the parse result */ end = pr->tree->str + pr->tree->len; /* check if we are at the end of the string */ if (pr->is_valid) for (test = end; *test; test++) { if (!isspace(*test)) { pr->is_valid = false; if (pr->expecting->required) { 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); } else if (cleri__expecting_update( pr->expecting, CLERI_END_OF_STATEMENT, end)) { cleri_parse_free(pr); return NULL; } break; } } pr->pos = pr->is_valid ? pr->tree->len : (size_t) (pr->expecting->str - pr->str); cleri__olist_unique(pr->expecting->required); 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); 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; } static void parse__line_pos(cleri_parse_t * pr, size_t * line, size_t * pos) { size_t n = pr->pos; const char * pt = pr->str; *pos = 0; *line = 1; while (n--) { if (*pt == '\n') { if (!n) break; ++pt; if (*pt == '\r') { if (!--n) break; ++pt; } ++(*line); *pos = 0; continue; } if (*pt == '\r') { if (!n) break; ++pt; if (*(++pt) == '\n' ) { if (!--n) break; ++pt; ++(*line); *pos = 0; } ++(*line); *pos = 0; continue; } ++(*pos); ++pt; } } /* * Print parse result to a string. The return value is equal to the snprintf * function. Argument `translate_cb` maybe NULL or a function which may return * a string based on the `cleri_t`. This allows for returning nice strings for * regular expressions. The function may return NULL if it has no translation * for the given regular expression. */ int cleri_parse_strn( char * s, size_t n, cleri_parse_t * pr, cleri_translate_t * translate) { int rc, count = 0; size_t i, m, line, pos; cleri_t * o; const char * expect; const char * template; if (pr == NULL) { return snprintf(s, n, "no parse result, a possible reason might be that the maximum " "recursion depth of %d has been reached", MAX_RECURSION_DEPTH); } if (pr->is_valid) { return snprintf(s, n, "parsed successfully"); } /* make sure expecting is at start */ cleri_parse_expect_start(pr); parse__line_pos(pr, &line, &pos); rc = snprintf(s, n, "error at line %zu, position %zu", line, pos); if (rc < 0) { return rc; } i = rc; expect = pr->str + pr->pos; if (isgraph(*expect)) { size_t nc = cleri__kwcache_match(pr, expect); const char * pt = expect; const unsigned int max_chars = 20; if (nc < 1) { while (isdigit(*pt)) ++pt; nc = pt - expect; } m = (i < n) ? n-i : 0; if (nc > 1) { rc = nc > max_chars ? snprintf(s+i, m, ", unexpected `%.*s...`", max_chars, expect) : snprintf(s+i, m, ", unexpected `%.*s`", (int) nc, expect); } else { rc = snprintf(s+i, m, ", unexpected character `%c`", *expect); } if (rc < 0) { return rc; } i += rc; } while (pr->expect) { o = pr->expect->cl_obj; if (!translate || !(expect = (*translate)(o))) switch(o->tp) { case CLERI_TP_END_OF_STATEMENT: expect = "end_of_statement"; break; case CLERI_TP_KEYWORD: expect = o->via.keyword->keyword; break; case CLERI_TP_TOKENS: expect = o->via.tokens->spaced; break; case CLERI_TP_TOKEN: expect = o->via.token->token; break; default: expect = ""; /* continue */ } if (*expect == '\0') { /* ignore empty strings */ pr->expect = pr->expect->next; continue; } /* make sure len is not greater than the maximum size */ m = (i < n) ? n-i : 0; /* we use count = 0 to print the first one, then for the others * a comma prefix and the last with -or- * * TODO: could be improved since the last `or` might never be added */ template = !count++ ? ", expecting: %s" : pr->expect->next ? ", %s" : " or %s"; rc = snprintf(s+i, m, template, expect); if (rc < 0) { return rc; } i += rc; pr->expect = pr->expect->next; } return (int) i; } /* * 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) { const char * str = parent->str + parent->len; /* set parent len to next none white space char */ for (; isspace(*str); ++str, ++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); } cesbit-libcleri-2964b6c/src/prio.c000066400000000000000000000071441451646561000170310ustar00rootroot00000000000000/* * prio.c - cleri prio element. (this element create a cleri rule object * holding this prio element) */ #include #include #include #include #include #include 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__malloc(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++ > 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)) { if (tested->node != NULL) { /* * It is required to decrement an extra reference here, one * belongs to the parse result, and one for the tested rule. * The node->ref increment below is required for when a str * position is visited a second time by another parent. */ --tested->node->ref; cleri__node_free(tested->node); } tested->node = node; node->ref++; } else { cleri__node_free(node); } olist = olist->next; } rule->depth--; if (tested->node != NULL) { parent->len += tested->node->len; cleri__node_add(parent, tested->node); return tested->node; } return NULL; } cesbit-libcleri-2964b6c/src/ref.c000066400000000000000000000021361451646561000166300ustar00rootroot00000000000000/* * ref.c - cleri ref element. */ #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 */ } cesbit-libcleri-2964b6c/src/regex.c000066400000000000000000000075011451646561000171670ustar00rootroot00000000000000/* * regex.c - cleri regular expression element. */ #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; /* * starting with ^ is not required as flags may go first * 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__malloc(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 match 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, PCRE2_ZERO_TERMINATED, 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; cleri__node_add(parent, node); } else { pr->is_valid = -1; /* error occurred */ } return node; } cesbit-libcleri-2964b6c/src/repeat.c000066400000000000000000000046241451646561000173400ustar00rootroot00000000000000/* * repeat.c - cleri regular repeat element. */ #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 min, or 0 which 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__malloc(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; cleri__node_add(parent, node); return node; } cesbit-libcleri-2964b6c/src/rule.c000066400000000000000000000105021451646561000170170ustar00rootroot00000000000000/* * 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) */ #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__malloc(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. */ (*target) = tested; if ((*target)->str == NULL) { (*target)->str = str; return CLERI_RULE_TRUE; } if ((*target)->str == str) { return CLERI_RULE_FALSE; } while (((*target) = (*target)->next) != NULL && str <= (*target)->str) { if ((*target)->str == str) { return CLERI_RULE_FALSE; } tested = (*target); } *target = cleri__malloc(cleri_rule_tested_t); if (*target == NULL) { return CLERI_RULE_ERROR; } (*target)->str = str; (*target)->node = NULL; (*target)->next = tested->next; tested->next = *target; 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_rule_store_t nrule; cleri_node_t * node; cleri_node_t * rnode; if (pr->flags & CLERI_FLAG_EXCLUDE_RULE_THIS) { nrule.depth = 0; nrule.tested.str = NULL; nrule.tested.node = NULL; nrule.tested.next = NULL; nrule.root_obj = cl_obj->via.rule->cl_obj; node = cleri__parse_walk( pr, parent, nrule.root_obj, &nrule, CLERI__EXP_MODE_REQUIRED); if (node != NULL) { node = parent; } /* cleanup rule */ rule__tested_free(&nrule.tested); return node; } if ((node = cleri__node_new(cl_obj, parent->str + parent->len, 0)) == NULL) { pr->is_valid = -1; return NULL; } nrule.depth = 0; 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; cleri__node_add(parent, node); } /* 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 = tested->next; cleri__node_free(tested->node); while (next != NULL) { tested = next->next; cleri__node_free(next->node); free(next); next = tested; } } cesbit-libcleri-2964b6c/src/sequence.c000066400000000000000000000047251451646561000176720ustar00rootroot00000000000000/* * sequence.c - cleri sequence element. */ #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__malloc(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; cleri__node_add(parent, node); return node; } cesbit-libcleri-2964b6c/src/this.c000066400000000000000000000056711451646561000170320ustar00rootroot00000000000000/* * 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. */ #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 (pr->flags & CLERI_FLAG_EXCLUDE_RULE_THIS) { tested->node = cleri__parse_walk( pr, parent, rule->root_obj, rule, CLERI__EXP_MODE_REQUIRED); return tested->node == NULL ? NULL : parent; } if ((node = cleri__node_new(cl_obj, str, 0)) == NULL) { pr->is_valid = -1; return NULL; } assert(tested->node == 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; } if (node->next) { /* It is only required to duplicate when a sibling is set. * If no sibling is set, then either this node will win over the * previous parent but then the sibling will be kept, or the parent * will win, but then we should end up with no sibling */ node = cleri__node_dup(node); if (node == NULL) { pr->is_valid = -1; return NULL; } } else { node->ref++; } break; case CLERI_RULE_ERROR: pr->is_valid = -1; return NULL; default: assert (0); return NULL; } parent->len += node->len; cleri__node_add(parent, node); return node; } cesbit-libcleri-2964b6c/src/token.c000066400000000000000000000041001451646561000171650ustar00rootroot00000000000000/* * 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) */ #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__malloc(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; cleri__node_add(parent, node); } else { pr->is_valid = -1; } } else if (cleri__expecting_update(pr->expecting, cl_obj, str) == -1) { pr->is_valid = -1; } return node; } cesbit-libcleri-2964b6c/src/tokens.c000066400000000000000000000132051451646561000173560ustar00rootroot00000000000000/* * tokens.c - cleri tokens element. (like token but can contain more tokens * in one element) */ #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_str(cleri_tlist_t * tlist, char * s); 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__malloc(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 a spaced version */ cl_object->via.tokens->spaced = (char *) malloc(strlen(tokens) + 1); cl_object->via.tokens->tlist = cleri__malloc(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++; } } /* tlist->token is never empty */ assert (cl_object->via.tokens->tlist->token != NULL); tokens__list_str( cl_object->via.tokens->tlist, cl_object->via.tokens->spaced); 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; cleri__node_add(parent, node); } 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__malloc(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; } /* * Copies tokens to spaced. This is the input tokes orders by their length. * No errors can occur since in any case enough space is allocated for *s. */ static void tokens__list_str(cleri_tlist_t * tlist, char * s) { assert (tlist->token != NULL); memcpy(s, tlist->token, tlist->len); s += tlist->len; while ((tlist = tlist->next) != NULL) { *s = ' '; s++; memcpy(s, tlist->token, tlist->len); s += tlist->len; } *s = '\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; } } cesbit-libcleri-2964b6c/src/version.c000066400000000000000000000002201451646561000175310ustar00rootroot00000000000000/* * version.c - cleri version information. */ #include const char * cleri_version(void) { return LIBCLERI_VERSION; }cesbit-libcleri-2964b6c/test/000077500000000000000000000000001451646561000160765ustar00rootroot00000000000000cesbit-libcleri-2964b6c/test/helpers.h000066400000000000000000000036741451646561000177230ustar00rootroot00000000000000#include #include static char * parse_str( cleri_parse_t * pr, cleri_translate_t * translate) __attribute__((unused)); static char * parse_str(cleri_parse_t * pr, cleri_translate_t * translate) { size_t sz; int i = cleri_parse_strn(NULL, 0, pr, translate); if (i < 0) { return NULL; } sz = i + 1; char * s = (char *) malloc(sz); if (s) { i = cleri_parse_strn(s, sz, pr, translate); if (i < 0 || i >= (int) sz) { free(s); return NULL; } } return s; } #define _assert_is_valid(__grammar, __str) \ { \ cleri_parse_t * __pr = cleri_parse2(__grammar, __str, 0); \ _assert (__pr); \ _assert (__pr->is_valid); \ cleri_parse_free(__pr); \ } #define _assert_is_not_valid(__grammar, __str) \ { \ cleri_parse_t * __pr = cleri_parse(__grammar, __str); \ _assert (__pr); \ _assert (!__pr->is_valid); \ cleri_parse_free(__pr); \ } #define _assert_is_valid_flags(__grammar, __str, __flags) \ { \ cleri_parse_t * __pr = cleri_parse2(__grammar, __str, __flags); \ _assert (__pr); \ _assert (__pr->is_valid); \ cleri_parse_free(__pr); \ } #define _assert_parse_str(__grammar, __str, __expect, __translate) \ { \ cleri_parse_t * __pr = cleri_parse2(__grammar, __str, 0); \ char * __s = parse_str(__pr, __translate); \ _assert (__s); \ if (strcmp(__s, __expect) != 0) printf("\n\ngot: `%s`\n", __s); \ _assert (strcmp(__s, __expect) == 0); \ free(__s); \ if (__pr) cleri_parse_free(__pr); \ } #define _assert_parse_str2(__grammar, __str, __expect, __translate) \ { \ cleri_parse_t * __pr = cleri_parse2(__grammar, __str, 1); \ char * __s = parse_str(__pr, __translate); \ _assert (__s); \ if (strcmp(__s, __expect) != 0) printf("\n\ngot: `%s`\n", __s); \ _assert (strcmp(__s, __expect) == 0); \ free(__s); \ if (__pr) cleri_parse_free(__pr); \ } cesbit-libcleri-2964b6c/test/test.h000066400000000000000000000022071451646561000172270ustar00rootroot00000000000000#ifndef CLERI_TEST_H_ #define CLERI_TEST_H_ #include #include #include #include #define TEST_OK 0 #define TEST_FAILED 1 #define TEST_MSG_OK "....\x1B[32mOK\x1B[0m" #define TEST_MSG_FAILED "\x1B[31mFAILED\x1B[0m" static struct timeval start; static struct timeval end; static int status = TEST_OK; static int count = 0; const char * padding = ".............................." ".............................."; static void test_start(char * test_name) { count = 0; int padlen = 60 - strlen(test_name); printf("Testing %s%*.*s", test_name, padlen, padlen, padding); gettimeofday(&start, 0); } static int test_end(void) { gettimeofday(&end, 0); float t = (end.tv_sec - start.tv_sec) * 1000.0f + (end.tv_usec - start.tv_usec) / 1000.0f; printf("%s (%.3f ms)\n", (status == TEST_OK) ? TEST_MSG_OK : TEST_MSG_FAILED, t); return status; } #define _assert(e) (void)((e)?count++:(status = TEST_FAILED) && printf("\n\x1B[33mAssertion failed (%s:%d):\x1B[0m %s\n\n", __FILE__, __LINE__, #e)) #endif /* CLERI_TEST_H_ */cesbit-libcleri-2964b6c/test/test.sh000077500000000000000000000020611451646561000174130ustar00rootroot00000000000000#!/bin/bash RET=0 echo -n "Test using valgrind for memory errors and leaks: " if [[ "$NOMEMTEST" -ne "1" ]] && hash valgrind 2>/dev/null; then NOMEMTEST=0; echo -e "\x1B[32menabled\x1B[0m"; else NOMEMTEST=1; echo -e "\x1B[33mdisabled\x1B[0m"; fi run () { if [ ! -f $1/sources ]; then return; fi if [[ "$USELIB" -eq "1" ]]; then LSOURCE=-lcleri else LSOURCE=$(cat $1/sources) fi SOURCE=$1/$1.c OUT=$1.out rm "$OUT" 2> /dev/null gcc -I"../inc" -O0 -g3 -Wall -Wextra -Winline -std=gnu89 $SOURCE $LSOURCE -lm -lpcre2-8 -o "$OUT" if [[ "$NOMEMTEST" -ne "1" ]]; then valgrind --tool=memcheck --error-exitcode=1 --leak-check=full -q ./$OUT else ./$OUT fi rc=$?; if [[ $rc != 0 ]]; then RET=$((RET+1)); fi rm "$OUT" 2> /dev/null rm -r "$OUT.dSYM" 2> /dev/null } if [ $# -eq 0 ]; then for d in test_*/ ; do run "${d%?}" done else name=`echo $1 | sed 's/\(test_\)\?\(.*\?\)$/\2/g' | sed 's/\(.*\)\/$/\1/g'` run "test_$name" fi exit $RETcesbit-libcleri-2964b6c/test/test_choice/000077500000000000000000000000001451646561000203675ustar00rootroot00000000000000cesbit-libcleri-2964b6c/test/test_choice/sources000066400000000000000000000002431451646561000217740ustar00rootroot00000000000000../src/cleri.c ../src/expecting.c ../src/grammar.c ../src/kwcache.c ../src/node.c ../src/olist.c ../src/parse.c ../src/keyword.c ../src/sequence.c ../src/choice.c cesbit-libcleri-2964b6c/test/test_choice/test_choice.c000066400000000000000000000044631451646561000230330ustar00rootroot00000000000000#include "../test.h" #include "../helpers.h" static int test_choice_most_greedy(void) { test_start("choice (most_greedy)"); cleri_grammar_t * grammar; cleri_t * k_hi, * k_iris, * seq, * choice; k_hi = cleri_keyword(0, "hi", false); k_iris = cleri_keyword(0, "iris", false); seq = cleri_sequence(0, 2, k_hi, k_iris); choice = cleri_choice(0, true, 2, k_hi, seq); grammar = cleri_grammar(choice, NULL); _assert (choice->via.choice->most_greedy == true); _assert_is_valid (grammar, "hi"); _assert_is_valid (grammar, "hi iris"); _assert_is_not_valid (grammar, "hi sasha"); cleri_grammar_free(grammar); return test_end(); } static int test_choice_first_match(void) { test_start("choice (first_match)"); cleri_grammar_t * grammar; cleri_t * k_hi, * k_iris, * seq, * choice; k_hi = cleri_keyword(0, "hi", false); k_iris = cleri_keyword(0, "iris", false); seq = cleri_sequence(0, 2, k_hi, k_iris); choice = cleri_choice(0, false, 2, k_hi, seq); grammar = cleri_grammar(choice, NULL); _assert (choice->via.choice->most_greedy == false); _assert_is_valid (grammar, "hi"); _assert_is_not_valid (grammar, "hi iris"); _assert_is_not_valid (grammar, "hi sasha"); cleri_grammar_free(grammar); return test_end(); } static int test_choice_expecting(void) { test_start("choice (expecting)"); cleri_grammar_t * grammar; cleri_t * k_hi, * k_iris, * k_sasha, * seq, * choice; k_hi = cleri_keyword(0, "hi", false); k_iris = cleri_keyword(0, "iris", false); k_sasha = cleri_keyword(0, "sasha", false); choice = cleri_choice(0, false, 2, k_iris, k_sasha); seq = cleri_sequence(0, 2, k_hi, choice); grammar = cleri_grammar(seq, NULL); _assert (choice->via.choice->most_greedy == false); _assert_is_valid (grammar, "hi iris"); _assert_is_valid (grammar, "hi sasha"); _assert_is_not_valid (grammar, "hi cleri"); _assert_parse_str ( grammar, "hi cleri", "error at line 1, position 3, " "unexpected `cleri`, expecting: iris or sasha", NULL); cleri_grammar_free(grammar); return test_end(); } int main() { return ( test_choice_most_greedy() || test_choice_first_match() || test_choice_expecting() || 0 ); } cesbit-libcleri-2964b6c/test/test_dup/000077500000000000000000000000001451646561000177255ustar00rootroot00000000000000cesbit-libcleri-2964b6c/test/test_dup/sources000066400000000000000000000002401451646561000213270ustar00rootroot00000000000000../src/cleri.c ../src/expecting.c ../src/grammar.c ../src/kwcache.c ../src/node.c ../src/olist.c ../src/parse.c ../src/keyword.c ../src/sequence.c ../src/dup.c cesbit-libcleri-2964b6c/test/test_dup/test_dup.c000066400000000000000000000023331451646561000217210ustar00rootroot00000000000000#include "../test.h" #include "../helpers.h" #define ORIG 0 #define DUPL 1 static const char * translate(cleri_t * o) { switch (o->gid) { case DUPL: return "hi(dup)"; } return NULL; }; static int test_dup(void) { test_start("dup"); cleri_grammar_t * grammar; cleri_t * k_hi, * dup; k_hi = cleri_keyword(ORIG, "hi", false); dup = cleri_dup(DUPL, k_hi); grammar = cleri_grammar(cleri_sequence(0, 2, k_hi, dup), NULL); _assert (k_hi->gid == ORIG); _assert (dup->gid == DUPL); _assert_is_valid (grammar, "hi hi"); _assert_is_not_valid (grammar, "hi"); _assert_parse_str ( grammar, "", "error at line 1, position 0, expecting: hi", &translate); _assert_parse_str ( grammar, "hi", "error at line 1, position 2, expecting: hi(dup)", &translate); _assert_parse_str2 ( grammar, "", "error at line 1, position 0", &translate); _assert_parse_str2 ( grammar, "hi", "error at line 1, position 2", &translate); cleri_grammar_free(grammar); return test_end(); } int main() { return ( test_dup() || 0 ); } cesbit-libcleri-2964b6c/test/test_json_lang/000077500000000000000000000000001451646561000211075ustar00rootroot00000000000000cesbit-libcleri-2964b6c/test/test_json_lang/sources000066400000000000000000000003341451646561000225150ustar00rootroot00000000000000../src/cleri.c ../src/expecting.c ../src/grammar.c ../src/kwcache.c ../src/node.c ../src/olist.c ../src/parse.c ../src/choice.c ../src/keyword.c ../src/list.c ../src/ref.c ../src/regex.c ../src/sequence.c ../src/token.c cesbit-libcleri-2964b6c/test/test_json_lang/test_json_lang.c000066400000000000000000000050221451646561000242630ustar00rootroot00000000000000#include "../test.h" #include "../helpers.h" 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 }; #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; } static int test_json_lang(void) { test_start("json (language)"); cleri_grammar_t * grammar = compile_grammar(); _assert (grammar); _assert_is_valid (grammar, "{\"json\": [1, 2, 3]}"); _assert_is_valid (grammar, "{\"json\": {\"isOk\": true}}"); _assert_is_not_valid (grammar, "{\"json\": [1, 2, 3]"); cleri_grammar_free(grammar); return test_end(); } int main() { return ( test_json_lang() || 0 ); }cesbit-libcleri-2964b6c/test/test_keyword/000077500000000000000000000000001451646561000206215ustar00rootroot00000000000000cesbit-libcleri-2964b6c/test/test_keyword/sources000066400000000000000000000002401451646561000222230ustar00rootroot00000000000000../src/cleri.c ../src/expecting.c ../src/grammar.c ../src/kwcache.c ../src/node.c ../src/olist.c ../src/parse.c ../src/keyword.c ../src/token.c ../src/choice.c cesbit-libcleri-2964b6c/test/test_keyword/test_keyword.c000066400000000000000000000054711451646561000235170ustar00rootroot00000000000000#include "../test.h" #include "../helpers.h" static int test_keyword(void) { test_start("keyword"); cleri_grammar_t * grammar; cleri_t * k_hi; k_hi = cleri_keyword(0, "hi", false); _assert (k_hi); grammar = cleri_grammar(k_hi, NULL); _assert (grammar); _assert (k_hi->gid == 0); _assert (k_hi->via.keyword->ign_case == false); _assert_is_valid (grammar, "hi"); _assert_is_valid (grammar, " hi "); _assert_is_not_valid (grammar, "Hi"); _assert_is_not_valid (grammar, "hello"); _assert_parse_str ( grammar, "hello", "error at line 1, position 0, unexpected `hello`, expecting: hi", NULL); _assert_parse_str ( grammar, "hi", "parsed successfully", NULL); _assert_parse_str2 ( grammar, "hello", "error at line 1, position 0, unexpected `hello`", NULL); _assert_parse_str2 ( grammar, "hi", "parsed successfully", NULL); cleri_grammar_free(grammar); return test_end(); } static int test_keyword_ign_case(void) { test_start("keyword (ign_case)"); cleri_grammar_t * grammar; cleri_t * k_hi; k_hi = cleri_keyword(1, "hi", true); _assert (k_hi); grammar = cleri_grammar(k_hi, NULL); _assert (grammar); _assert (k_hi->gid == 1); _assert (k_hi->via.keyword->ign_case == true); _assert_is_valid (grammar, "hi"); _assert_is_valid (grammar, "Hi"); _assert_is_not_valid (grammar, "hello"); _assert_is_not_valid (grammar, "hihihihihihihihihihihihihihihihi" "hihihihihihihihihihihihihihihihi" "hihihihihihihihihihihihihihihihi" "hihihihihihihihihihihihihihihihi" "hihihihihihihihihihihihihihihihi" "hihihihihihihihihihihihihihihihi" "hihihihihihihihihihihihihihihihi" "hihihihihihihihihihihihihihihihi"); _assert_parse_str ( grammar, "Hi Iris", "error at line 1, position 2, expecting: end_of_statement", NULL); _assert_parse_str2 ( grammar, "Hi Iris", "error at line 1, position 2", NULL); cleri_grammar_free(grammar); return test_end(); } static int test_keyword_alt_regkw(void) { test_start("keyword (alt_regkw)"); cleri_grammar_t * grammar; cleri_t * k_hi, * t_hi; k_hi = cleri_keyword(0, "hi", false); t_hi = cleri_token(0, "HI"); grammar = cleri_grammar(cleri_choice(0, 1, 2, k_hi, t_hi), "^[a-z]+"); _assert (grammar); _assert_is_valid (grammar, "hi"); _assert_is_valid (grammar, "HI"); _assert_is_not_valid (grammar, "Hi"); cleri_grammar_free(grammar); return test_end(); } int main() { return ( test_keyword() || test_keyword_ign_case() || test_keyword_alt_regkw() || 0 ); } cesbit-libcleri-2964b6c/test/test_list/000077500000000000000000000000001451646561000201105ustar00rootroot00000000000000cesbit-libcleri-2964b6c/test/test_list/sources000066400000000000000000000002551451646561000215200ustar00rootroot00000000000000../src/cleri.c ../src/expecting.c ../src/grammar.c ../src/kwcache.c ../src/node.c ../src/olist.c ../src/parse.c ../src/keyword.c ../src/token.c ../src/list.c ../src/choice.ccesbit-libcleri-2964b6c/test/test_list/test_list.c000066400000000000000000000103311451646561000222640ustar00rootroot00000000000000#include "../test.h" #include "../helpers.h" static int test_list(void) { test_start("list"); cleri_grammar_t * grammar; cleri_t * k_hi, * delimiter, * list; k_hi = cleri_keyword(0, "hi", false); delimiter = cleri_token(0, ","); list = cleri_list(0, k_hi, delimiter, 0, 0, false); grammar = cleri_grammar(list, NULL); // assert statements _assert (list->via.list->min == 0); _assert (list->via.list->max == 0); _assert (list->via.list->opt_closing == false); _assert_is_valid (grammar, "hi, hi, hi"); _assert_is_valid (grammar, "hi"); _assert_is_valid (grammar, ""); _assert_is_not_valid (grammar, "hi,"); _assert_parse_str ( grammar, "hi.", "error at line 1, position 2, " "unexpected character `.`, expecting: , or end_of_statement", NULL); _assert_parse_str2 ( grammar, "hi.", "error at line 1, position 2, unexpected character `.`", NULL); /* check if list children is really NULL */ { cleri_parse_t * pr = cleri_parse(grammar, ""); _assert (pr); _assert (pr->is_valid); _assert (pr->tree->children->cl_obj->tp == CLERI_TP_LIST); _assert (pr->tree->children->children == NULL); cleri_parse_free(pr); } cleri_grammar_free(grammar); return test_end(); } static int test_list_all_options(void) { test_start("list (all_options)"); cleri_grammar_t * grammar; cleri_t * k_hi, * delimiter, * list; k_hi = cleri_keyword(0, "hi", false); delimiter = cleri_token(0, "-"); list = cleri_list(0, k_hi, delimiter, 1, 3, true); grammar = cleri_grammar(list, NULL); // assert statements _assert (list->via.list->min == 1); _assert (list->via.list->max == 3); _assert (list->via.list->opt_closing == true); _assert_is_valid (grammar, "hi - hi - hi"); _assert_is_valid (grammar, "hi-hi-hi-"); _assert_is_valid (grammar, "hi-"); _assert_is_valid (grammar, "hi"); _assert_is_not_valid (grammar, ""); _assert_is_not_valid (grammar, "-"); _assert_is_not_valid (grammar, "hi-hi-hi-hi"); _assert_parse_str ( grammar, "hi-hi-hi-hi-hi", "error at line 1, position 9, " "unexpected `hi`, expecting: end_of_statement", NULL); _assert_parse_str ( grammar, "hi.", "error at line 1, position 2" ", unexpected character `.`, expecting: - or end_of_statement", NULL); _assert_parse_str ( grammar, "", "error at line 1, position 0, expecting: hi", NULL); _assert_parse_str2 ( grammar, "hi-hi-hi-hi-hi", "error at line 1, position 9, unexpected `hi`", NULL); _assert_parse_str2 ( grammar, "hi.", "error at line 1, position 2, unexpected character `.`", NULL); _assert_parse_str2 ( grammar, "", "error at line 1, position 0", NULL); cleri_grammar_free(grammar); return test_end(); } static int test_list_vs_single(void) { test_start("list (vs_single)"); cleri_grammar_t * grammar; cleri_t * k_hi, * delimiter, * list, * choice; k_hi = cleri_keyword(0, "hi", false); delimiter = cleri_token(0, ","); list = cleri_list(0, k_hi, delimiter, 1, 0, false); choice = cleri_choice(0, true, 2, k_hi, list); grammar = cleri_grammar(choice, NULL); // assert statements _assert_is_valid (grammar, "hi, hi, hi"); _assert_parse_str ( grammar, "hi, hello", "error at line 1, position 4, unexpected `hello`, expecting: hi", NULL); _assert_parse_str ( grammar, "hello", "error at line 1, position 0, unexpected `hello`, expecting: hi", NULL); _assert_parse_str2 ( grammar, "hi, hello", "error at line 1, position 4, unexpected `hello`", NULL); _assert_parse_str2 ( grammar, "hello", "error at line 1, position 0, unexpected `hello`", NULL); cleri_grammar_free(grammar); return test_end(); } int main() { return ( test_list() || test_list_all_options() || test_list_vs_single() || 0 ); } cesbit-libcleri-2964b6c/test/test_optional/000077500000000000000000000000001451646561000207625ustar00rootroot00000000000000cesbit-libcleri-2964b6c/test/test_optional/sources000066400000000000000000000002231451646561000223650ustar00rootroot00000000000000../src/cleri.c ../src/expecting.c ../src/grammar.c ../src/kwcache.c ../src/node.c ../src/olist.c ../src/parse.c ../src/keyword.c ../src/optional.c cesbit-libcleri-2964b6c/test/test_optional/test_optional.c000066400000000000000000000021701451646561000240120ustar00rootroot00000000000000#include "../test.h" #include "../helpers.h" static int test_optional(void) { test_start("optional"); cleri_grammar_t * grammar; cleri_t * k_hi, * optional; k_hi = cleri_keyword(0, "hi", false); optional = cleri_optional(0, k_hi); grammar = cleri_grammar(optional, NULL); // assert statements _assert_is_valid (grammar, "hi"); _assert_is_valid (grammar, ""); _assert_is_not_valid(grammar, "hello"); _assert_parse_str ( grammar, "hello", "error at line 1, position 0, " "unexpected `hello`, expecting: hi or end_of_statement", NULL); _assert_parse_str ( grammar, "hi hi", "error at line 1, position 2, expecting: end_of_statement", NULL); _assert_parse_str2 ( grammar, "hello", "error at line 1, position 0, unexpected `hello`", NULL); _assert_parse_str2 ( grammar, "hi hi", "error at line 1, position 2", NULL); cleri_grammar_free(grammar); return test_end(); } int main() { return ( test_optional() || 0 ); } cesbit-libcleri-2964b6c/test/test_prio/000077500000000000000000000000001451646561000201065ustar00rootroot00000000000000cesbit-libcleri-2964b6c/test/test_prio/sources000066400000000000000000000003141451646561000215120ustar00rootroot00000000000000../src/cleri.c ../src/expecting.c ../src/grammar.c ../src/kwcache.c ../src/node.c ../src/olist.c ../src/parse.c ../src/keyword.c ../src/token.c ../src/sequence.c ../src/this.c ../src/rule.c ../src/prio.c cesbit-libcleri-2964b6c/test/test_prio/test_prio.c000066400000000000000000000155771451646561000223010ustar00rootroot00000000000000#include "../test.h" #include "../helpers.h" static int test_prio(void) { test_start("prio"); cleri_grammar_t * grammar; cleri_t * k_hi, * k_bye, * k_and, * k_or, * t_open, * t_close, * prio, * t_comma, * k_if; k_hi = cleri_keyword(0, "hi", false); k_bye = cleri_keyword(0, "bye", false); k_and = cleri_keyword(0, "and", false); k_or = cleri_keyword(0, "or", false); t_open = cleri_token(0, "("); t_close = cleri_token(0, ")"); t_comma = cleri_token(0, ","); k_if = cleri_keyword(0, "if", false); prio = cleri_prio( 0, 7, k_hi, k_bye, cleri_sequence(0, 5, k_if, t_open, CLERI_THIS, t_close, CLERI_THIS), cleri_sequence(0, 7, k_if, t_open, CLERI_THIS, t_comma, k_bye, t_close, CLERI_THIS), cleri_sequence(0, 3, t_open, CLERI_THIS, t_close), cleri_sequence(0, 3, CLERI_THIS, k_and, CLERI_THIS), cleri_sequence(0, 3, CLERI_THIS, k_or, CLERI_THIS)); grammar = cleri_grammar(prio, NULL); // assert statements _assert_is_valid(grammar, "hi"); _assert_is_valid(grammar, "(bye)"); _assert_is_valid(grammar, "(hi and bye)"); _assert_is_valid(grammar, "(hi or hi) and (hi or hi)"); _assert_is_valid(grammar, "(hi or (hi and bye))"); _assert_is_not_valid(grammar, ""); _assert_is_not_valid(grammar, "(hi"); _assert_is_not_valid(grammar, "()"); _assert_is_not_valid(grammar, "(hi or hi) and"); { cleri_parse_t * pr = cleri_parse( grammar, "(((((((((((((((((((((((((((((((((((((((((((((((((((" "(((((((((((((((((((((((((((((((((((((((((((((((((((" "(((((((((((((((((((((((((((((((((((((((((((((((((((" "(((((((((((((((((((((((((((((((((((((((((((((((((((" "(((((((((((((((((((((((((((((((((((((((((((((((((((" "(((((((((((((((((((((((((((((((((((((((((((((((((((" "(((((((((((((((((((((((((((((((((((((((((((((((((((" "(((((((((((((((((((((((((((((((((((((((((((((((((((" "(((((((((((((((((((((((((((((((((((((((((((((((((((" "(((((((((((((((((((((((((((((((((((((((((((((((((((hi" ")))))))))))))))))))))))))))))))))))))))))))))))))))" ")))))))))))))))))))))))))))))))))))))))))))))))))))" ")))))))))))))))))))))))))))))))))))))))))))))))))))" ")))))))))))))))))))))))))))))))))))))))))))))))))))" ")))))))))))))))))))))))))))))))))))))))))))))))))))" ")))))))))))))))))))))))))))))))))))))))))))))))))))" ")))))))))))))))))))))))))))))))))))))))))))))))))))" ")))))))))))))))))))))))))))))))))))))))))))))))))))" ")))))))))))))))))))))))))))))))))))))))))))))))))))" ")))))))))))))))))))))))))))))))))))))))))))))))))))" ); _assert (pr == NULL); /* max recursion depth */ } _assert_parse_str ( grammar, "(((((((((((((((((((((((((((((((((((((((((((((((((((" "(((((((((((((((((((((((((((((((((((((((((((((((((((" "(((((((((((((((((((((((((((((((((((((((((((((((((((" "(((((((((((((((((((((((((((((((((((((((((((((((((((" "(((((((((((((((((((((((((((((((((((((((((((((((((((" "(((((((((((((((((((((((((((((((((((((((((((((((((((" "(((((((((((((((((((((((((((((((((((((((((((((((((((" "(((((((((((((((((((((((((((((((((((((((((((((((((((" "(((((((((((((((((((((((((((((((((((((((((((((((((((" "(((((((((((((((((((((((((((((((((((((((((((((((((((hi" ")))))))))))))))))))))))))))))))))))))))))))))))))))" ")))))))))))))))))))))))))))))))))))))))))))))))))))" ")))))))))))))))))))))))))))))))))))))))))))))))))))" ")))))))))))))))))))))))))))))))))))))))))))))))))))" ")))))))))))))))))))))))))))))))))))))))))))))))))))" ")))))))))))))))))))))))))))))))))))))))))))))))))))" ")))))))))))))))))))))))))))))))))))))))))))))))))))" ")))))))))))))))))))))))))))))))))))))))))))))))))))" ")))))))))))))))))))))))))))))))))))))))))))))))))))" ")))))))))))))))))))))))))))))))))))))))))))))))))))", "no parse result, a possible reason might be that the maximum " "recursion depth of 500 has been reached", NULL); _assert_parse_str2 ( grammar, "(((((((((((((((((((((((((((((((((((((((((((((((((((" "(((((((((((((((((((((((((((((((((((((((((((((((((((" "(((((((((((((((((((((((((((((((((((((((((((((((((((" "(((((((((((((((((((((((((((((((((((((((((((((((((((" "(((((((((((((((((((((((((((((((((((((((((((((((((((" "(((((((((((((((((((((((((((((((((((((((((((((((((((" "(((((((((((((((((((((((((((((((((((((((((((((((((((" "(((((((((((((((((((((((((((((((((((((((((((((((((((" "(((((((((((((((((((((((((((((((((((((((((((((((((((" "(((((((((((((((((((((((((((((((((((((((((((((((((((hi" ")))))))))))))))))))))))))))))))))))))))))))))))))))" ")))))))))))))))))))))))))))))))))))))))))))))))))))" ")))))))))))))))))))))))))))))))))))))))))))))))))))" ")))))))))))))))))))))))))))))))))))))))))))))))))))" ")))))))))))))))))))))))))))))))))))))))))))))))))))" ")))))))))))))))))))))))))))))))))))))))))))))))))))" ")))))))))))))))))))))))))))))))))))))))))))))))))))" ")))))))))))))))))))))))))))))))))))))))))))))))))))" ")))))))))))))))))))))))))))))))))))))))))))))))))))" ")))))))))))))))))))))))))))))))))))))))))))))))))))", "no parse result, a possible reason might be that the maximum " "recursion depth of 500 has been reached", NULL); { cleri_parse_t * pr; cleri_node_t * node; pr = cleri_parse2( grammar, "if(hi) bye", CLERI_FLAG_EXPECTING_DISABLED| CLERI_FLAG_EXCLUDE_OPTIONAL| CLERI_FLAG_EXCLUDE_FM_CHOICE| CLERI_FLAG_EXCLUDE_RULE_THIS ); _assert (pr->is_valid); _assert (pr->tree->children->children->children->next->next->next); node = pr->tree->children->children->children->next->next->next; _assert (*node->str == ')'); _assert (node->len == 1); cleri_parse_free(pr); pr = cleri_parse2( grammar, "if(hi, bye) bye", CLERI_FLAG_EXPECTING_DISABLED| CLERI_FLAG_EXCLUDE_OPTIONAL| CLERI_FLAG_EXCLUDE_FM_CHOICE| CLERI_FLAG_EXCLUDE_RULE_THIS ); _assert (pr->is_valid); _assert (pr->tree->children->children->children->next->next->next); node = pr->tree->children->children->children->next->next->next; _assert (*node->str == ','); _assert (node->len == 1); cleri_parse_free(pr); } cleri_grammar_free(grammar); return test_end(); } int main() { return ( test_prio() || 0 ); } cesbit-libcleri-2964b6c/test/test_ref/000077500000000000000000000000001451646561000177115ustar00rootroot00000000000000cesbit-libcleri-2964b6c/test/test_ref/sources000066400000000000000000000002161451646561000213160ustar00rootroot00000000000000../src/cleri.c ../src/expecting.c ../src/grammar.c ../src/kwcache.c ../src/node.c ../src/olist.c ../src/parse.c ../src/keyword.c ../src/ref.c cesbit-libcleri-2964b6c/test/test_ref/test_ref.c000066400000000000000000000014401451646561000216670ustar00rootroot00000000000000#include "../test.h" #include "../helpers.h" static int test_ref(void) { test_start("ref"); cleri_grammar_t * grammar; cleri_t * k_hi, * ref; k_hi = cleri_keyword(0, "hi", false); ref = cleri_ref(); grammar = cleri_grammar(ref, NULL); /* now set the reference */ cleri_ref_set(ref, k_hi); _assert_is_valid (grammar, "hi"); _assert_is_not_valid (grammar, ""); _assert_parse_str ( grammar, "ha", "error at line 1, position 0, unexpected `ha`, expecting: hi", NULL); _assert_parse_str2 ( grammar, "ha", "error at line 1, position 0, unexpected `ha`", NULL); cleri_grammar_free(grammar); return test_end(); } int main() { return ( test_ref() || 0 ); } cesbit-libcleri-2964b6c/test/test_regex/000077500000000000000000000000001451646561000202475ustar00rootroot00000000000000cesbit-libcleri-2964b6c/test/test_regex/sources000066400000000000000000000001771451646561000216620ustar00rootroot00000000000000../src/cleri.c ../src/expecting.c ../src/grammar.c ../src/kwcache.c ../src/node.c ../src/olist.c ../src/parse.c ../src/regex.c cesbit-libcleri-2964b6c/test/test_regex/test_regex.c000066400000000000000000000023011451646561000225600ustar00rootroot00000000000000#include "../test.h" #include "../helpers.h" #define id 5 static const char * translate(cleri_t * o) { switch (o->gid) { case id: return "single_quoted_string"; } return NULL; } static int test_regex(void) { test_start("regex"); cleri_grammar_t * grammar; cleri_t * regex; regex = cleri_regex(id, "^(?:\'(?:[^\']*)\')+"); _assert (regex); grammar = cleri_grammar(regex, NULL); _assert (grammar); _assert (regex->gid == id); _assert_is_valid (grammar, "'hi'"); _assert_is_valid (grammar, "'this is ''SiriDB'''"); _assert_is_not_valid (grammar, "'Hi !"); _assert_is_not_valid (grammar, "'hello''"); _assert_is_not_valid (grammar, ""); _assert_parse_str ( grammar, "\"double quoted\"", "error at line 1, position 0, " "unexpected character `\"`, expecting: single_quoted_string", translate); _assert_parse_str2 ( grammar, "\"double quoted\"", "error at line 1, position 0, " "unexpected character `\"`", translate); cleri_grammar_free(grammar); return test_end(); } int main() { return ( test_regex() || 0 ); } cesbit-libcleri-2964b6c/test/test_repeat/000077500000000000000000000000001451646561000204155ustar00rootroot00000000000000cesbit-libcleri-2964b6c/test/test_repeat/sources000066400000000000000000000002211451646561000220160ustar00rootroot00000000000000../src/cleri.c ../src/expecting.c ../src/grammar.c ../src/kwcache.c ../src/node.c ../src/olist.c ../src/parse.c ../src/keyword.c ../src/repeat.c cesbit-libcleri-2964b6c/test/test_repeat/test_repeat.c000066400000000000000000000056701451646561000231100ustar00rootroot00000000000000#include "../test.h" #include "../helpers.h" static const char * translate(cleri_t * o __attribute__((unused))) { /* this should ignore expecting: ... */ return ""; } static int test_repeat(void) { test_start("repeat"); cleri_grammar_t * grammar; cleri_t * k_hi, * repeat; k_hi = cleri_keyword(0, "hi", false); repeat = cleri_repeat(0, k_hi, 0, 0); grammar = cleri_grammar(repeat, NULL); // assert statements _assert (repeat->via.repeat->min == 0); _assert (repeat->via.repeat->max == 0); _assert_is_valid (grammar, "hi hi hi"); _assert_is_valid (grammar, "hi"); _assert_is_valid (grammar, ""); _assert_is_not_valid (grammar, "hihi"); _assert_is_not_valid (grammar, "ha"); _assert_parse_str ( grammar, "hi.", "error at line 1, position 2, " "unexpected character `.`, expecting: hi or end_of_statement", NULL); _assert_parse_str ( grammar, "hi.", "error at line 1, position 2, " "unexpected character `.`", &translate); _assert_parse_str2 ( grammar, "hi.", "error at line 1, position 2, " "unexpected character `.`", NULL); _assert_parse_str2 ( grammar, "hi.", "error at line 1, position 2, " "unexpected character `.`", &translate); cleri_grammar_free(grammar); return test_end(); } static int test_repeat_all_options(void) { test_start("repeat (all_options)"); cleri_grammar_t * grammar; cleri_t * k_hi, * repeat; k_hi = cleri_keyword(0, "hi", false); repeat = cleri_repeat(0, k_hi, 1, 3); grammar = cleri_grammar(repeat, NULL); // assert statements _assert (repeat->via.repeat->min == 1); _assert (repeat->via.repeat->max == 3); _assert_is_valid (grammar, "hi hi hi"); _assert_is_valid (grammar, "hi"); _assert_is_not_valid (grammar, ""); _assert_is_not_valid (grammar, "hi hi hi hi"); _assert_parse_str ( grammar, "hi hi hi hi hi", "error at line 1, position 8, expecting: end_of_statement", NULL); _assert_parse_str ( grammar, "hi.", "error at line 1, position 2, " "unexpected character `.`, expecting: hi or end_of_statement", NULL); _assert_parse_str ( grammar, "", "error at line 1, position 0, expecting: hi", NULL); _assert_parse_str2 ( grammar, "hi hi hi hi hi", "error at line 1, position 8", NULL); _assert_parse_str2 ( grammar, "hi.", "error at line 1, position 2, " "unexpected character `.`", NULL); _assert_parse_str2 ( grammar, "", "error at line 1, position 0", NULL); cleri_grammar_free(grammar); return test_end(); } int main() { return ( test_repeat() || test_repeat_all_options() || 0 ); } cesbit-libcleri-2964b6c/test/test_sequence/000077500000000000000000000000001451646561000207455ustar00rootroot00000000000000cesbit-libcleri-2964b6c/test/test_sequence/sources000066400000000000000000000002231451646561000223500ustar00rootroot00000000000000../src/cleri.c ../src/expecting.c ../src/grammar.c ../src/kwcache.c ../src/node.c ../src/olist.c ../src/parse.c ../src/keyword.c ../src/sequence.c cesbit-libcleri-2964b6c/test/test_sequence/test_sequence.c000066400000000000000000000015661451646561000237700ustar00rootroot00000000000000#include "../test.h" #include "../helpers.h" static int test_sequence(void) { test_start("sequence"); cleri_grammar_t * grammar; cleri_t * k_hi, * k_iris, * seq; k_hi = cleri_keyword(0, "hi", false); k_iris = cleri_keyword(0, "iris", false); seq = cleri_sequence(0, 2, k_hi, k_iris); grammar = cleri_grammar(seq, NULL); _assert_is_valid (grammar, "hi iris"); _assert_is_not_valid (grammar, "hi sasha"); _assert_parse_str ( grammar, "hi sasha", "error at line 1, position 3, " "unexpected `sasha`, expecting: iris", NULL); _assert_parse_str2 ( grammar, "hi sasha", "error at line 1, position 3, " "unexpected `sasha`", NULL); cleri_grammar_free(grammar); return test_end(); } int main() { return ( test_sequence() || 0 ); } cesbit-libcleri-2964b6c/test/test_thingsdb_lang/000077500000000000000000000000001451646561000217405ustar00rootroot00000000000000cesbit-libcleri-2964b6c/test/test_thingsdb_lang/sources000066400000000000000000000005051451646561000233460ustar00rootroot00000000000000../src/choice.c ../src/cleri.c ../src/dup.c ../src/expecting.c ../src/grammar.c ../src/keyword.c ../src/kwcache.c ../src/list.c ../src/node.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 cesbit-libcleri-2964b6c/test/test_thingsdb_lang/test_thingsdb_lang.c000066400000000000000000000324151451646561000257530ustar00rootroot00000000000000#include "../test.h" #include "../helpers.h" enum cleri_grammar_ids { CLERI_NONE, // used for objects with no name CLERI_GID_ARRAY, CLERI_GID_ASSIGN, CLERI_GID_BLOCK, CLERI_GID_CHAIN, CLERI_GID_CLOSURE, CLERI_GID_COMMENTS, CLERI_GID_END_STATEMENT, CLERI_GID_ENUM_, CLERI_GID_EXPRESSION, CLERI_GID_FOR_STATEMENT, CLERI_GID_FUNCTION, CLERI_GID_IF_STATEMENT, CLERI_GID_INDEX, CLERI_GID_INSTANCE, CLERI_GID_K_BREAK, CLERI_GID_K_CONTINUE, CLERI_GID_K_ELSE, CLERI_GID_K_FOR, CLERI_GID_K_IF, CLERI_GID_K_IN, CLERI_GID_K_RETURN, CLERI_GID_NAME, CLERI_GID_NAME_OPT_MORE, CLERI_GID_OPERATIONS, CLERI_GID_OPR0_MUL_DIV_MOD, CLERI_GID_OPR1_ADD_SUB, CLERI_GID_OPR2_BITWISE_AND, CLERI_GID_OPR3_BITWISE_XOR, CLERI_GID_OPR4_BITWISE_OR, CLERI_GID_OPR5_COMPARE, CLERI_GID_OPR6_CMP_AND, CLERI_GID_OPR7_CMP_OR, CLERI_GID_OPR8_TERNARY, CLERI_GID_PARENTHESIS, CLERI_GID_RETURN_STATEMENT, CLERI_GID_SLICE, CLERI_GID_START, CLERI_GID_STATEMENT, CLERI_GID_STATEMENTS, CLERI_GID_TEMPLATE, CLERI_GID_THING, CLERI_GID_T_FALSE, CLERI_GID_T_FLOAT, CLERI_GID_T_INT, CLERI_GID_T_NIL, CLERI_GID_T_REGEX, CLERI_GID_T_STRING, CLERI_GID_T_TRUE, CLERI_GID_VAR, CLERI_GID_VAR_OPT_MORE, CLERI_GID_X_ARRAY, CLERI_GID_X_ASSIGN, CLERI_GID_X_BLOCK, CLERI_GID_X_CHAIN, CLERI_GID_X_CLOSURE, CLERI_GID_X_FUNCTION, CLERI_GID_X_INDEX, CLERI_GID_X_PARENTHESIS, CLERI_GID_X_PREOPR, CLERI_GID_X_TERNARY, CLERI_GID_X_THING, CLERI_END // can be used to get the enum length }; #define CLERI_CASE_SENSITIVE 0 #define CLERI_CASE_INSENSITIVE 1 #define CLERI_FIRST_MATCH 0 #define CLERI_MOST_GREEDY 1 cleri_grammar_t * compile_langdef(void) { cleri_t * x_array = cleri_token(CLERI_GID_X_ARRAY, "["); cleri_t * x_assign = cleri_tokens(CLERI_GID_X_ASSIGN, "+= -= *= /= %= &= ^= |= ="); cleri_t * x_block = cleri_token(CLERI_GID_X_BLOCK, "{"); cleri_t * x_chain = cleri_token(CLERI_GID_X_CHAIN, "."); cleri_t * x_closure = cleri_token(CLERI_GID_X_CLOSURE, "|"); cleri_t * x_function = cleri_token(CLERI_GID_X_FUNCTION, "("); cleri_t * x_index = cleri_token(CLERI_GID_X_INDEX, "["); cleri_t * x_parenthesis = cleri_token(CLERI_GID_X_PARENTHESIS, "("); cleri_t * x_preopr = cleri_regex(CLERI_GID_X_PREOPR, "^(\\s*!|\\s*[\\-+](?=[^0-9]))*"); cleri_t * x_ternary = cleri_token(CLERI_GID_X_TERNARY, "?"); cleri_t * x_thing = cleri_token(CLERI_GID_X_THING, "{"); cleri_t * template = cleri_sequence( CLERI_GID_TEMPLATE, 3, cleri_token(CLERI_NONE, "`"), cleri_repeat(CLERI_NONE, cleri_choice( CLERI_NONE, CLERI_FIRST_MATCH, 2, cleri_regex(CLERI_NONE, "^([^`{}]|``|{{|}})+"), cleri_sequence( CLERI_NONE, 3, cleri_token(CLERI_NONE, "{"), CLERI_THIS, cleri_token(CLERI_NONE, "}") ) ), 0, 0), cleri_token(CLERI_NONE, "`") ); cleri_t * t_false = cleri_keyword(CLERI_GID_T_FALSE, "false", CLERI_CASE_SENSITIVE); cleri_t * t_float = cleri_regex(CLERI_GID_T_FLOAT, "^[-+]?(inf|nan|[0-9]*\\.[0-9]+(e[+-][0-9]+)?)(?![0-9A-Za-z_])"); cleri_t * t_int = cleri_regex(CLERI_GID_T_INT, "^[-+]?((0b[01]+)|(0o[0-8]+)|(0x[0-9a-fA-F]+)|([0-9]+))(?![0-9A-Za-z_])"); cleri_t * t_nil = cleri_keyword(CLERI_GID_T_NIL, "nil", CLERI_CASE_SENSITIVE); cleri_t * t_regex = cleri_regex(CLERI_GID_T_REGEX, "^/((?:.(?!(?= < >"); cleri_t * opr6_cmp_and = cleri_token(CLERI_GID_OPR6_CMP_AND, "&&"); cleri_t * opr7_cmp_or = cleri_token(CLERI_GID_OPR7_CMP_OR, "||"); cleri_t * opr8_ternary = cleri_sequence( CLERI_GID_OPR8_TERNARY, 3, x_ternary, CLERI_THIS, cleri_token(CLERI_NONE, ":") ); cleri_t * operations = cleri_sequence( CLERI_GID_OPERATIONS, 3, CLERI_THIS, cleri_choice( CLERI_NONE, CLERI_FIRST_MATCH, 9, opr8_ternary, opr7_cmp_or, opr6_cmp_and, opr5_compare, opr4_bitwise_or, opr3_bitwise_xor, opr2_bitwise_and, opr1_add_sub, opr0_mul_div_mod ), CLERI_THIS ); cleri_t * assign = cleri_sequence( CLERI_GID_ASSIGN, 2, x_assign, CLERI_THIS ); cleri_t * name_opt_more = cleri_sequence( CLERI_GID_NAME_OPT_MORE, 2, name, cleri_optional(CLERI_NONE, cleri_choice( CLERI_NONE, CLERI_FIRST_MATCH, 2, function, assign )) ); cleri_t * var_opt_more = cleri_sequence( CLERI_GID_VAR_OPT_MORE, 2, var, cleri_optional(CLERI_NONE, cleri_choice( CLERI_NONE, CLERI_FIRST_MATCH, 4, function, assign, instance, enum_ )) ); cleri_t * slice = cleri_list(CLERI_GID_SLICE, cleri_optional(CLERI_NONE, CLERI_THIS), cleri_token(CLERI_NONE, ":"), 0, 3, 0); cleri_t * index = cleri_repeat(CLERI_GID_INDEX, cleri_sequence( CLERI_NONE, 4, x_index, slice, cleri_token(CLERI_NONE, "]"), cleri_optional(CLERI_NONE, cleri_sequence( CLERI_NONE, 2, x_assign, CLERI_THIS )) ), 0, 0); cleri_t * end_statement = cleri_regex(CLERI_GID_END_STATEMENT, "^((;|((?s)\\/\\/.*?(\\r?\\n|$))|((?s)\\/\\*.*?\\*\\/))\\s*)*"); cleri_t * block = cleri_sequence( CLERI_GID_BLOCK, 4, x_block, comments, cleri_list(CLERI_NONE, CLERI_THIS, end_statement, 1, 0, 1), cleri_token(CLERI_NONE, "}") ); cleri_t * parenthesis = cleri_sequence( CLERI_GID_PARENTHESIS, 3, x_parenthesis, CLERI_THIS, cleri_token(CLERI_NONE, ")") ); cleri_t * k_if = cleri_keyword(CLERI_GID_K_IF, "if", CLERI_CASE_SENSITIVE); cleri_t * k_else = cleri_keyword(CLERI_GID_K_ELSE, "else", CLERI_CASE_SENSITIVE); cleri_t * k_return = cleri_keyword(CLERI_GID_K_RETURN, "return", CLERI_CASE_SENSITIVE); cleri_t * k_for = cleri_keyword(CLERI_GID_K_FOR, "for", CLERI_CASE_SENSITIVE); cleri_t * k_in = cleri_keyword(CLERI_GID_K_IN, "in", CLERI_CASE_SENSITIVE); cleri_t * k_continue = cleri_keyword(CLERI_GID_K_CONTINUE, "continue", CLERI_CASE_SENSITIVE); cleri_t * k_break = cleri_keyword(CLERI_GID_K_BREAK, "break", CLERI_CASE_SENSITIVE); cleri_t * if_statement = cleri_sequence( CLERI_GID_IF_STATEMENT, 6, k_if, cleri_token(CLERI_NONE, "("), CLERI_THIS, cleri_token(CLERI_NONE, ")"), CLERI_THIS, cleri_optional(CLERI_NONE, cleri_sequence( CLERI_NONE, 2, k_else, CLERI_THIS )) ); cleri_t * return_statement = cleri_sequence( CLERI_GID_RETURN_STATEMENT, 3, k_return, CLERI_THIS, cleri_optional(CLERI_NONE, cleri_sequence( CLERI_NONE, 2, cleri_token(CLERI_NONE, ","), CLERI_THIS )) ); cleri_t * for_statement = cleri_sequence( CLERI_GID_FOR_STATEMENT, 7, k_for, cleri_token(CLERI_NONE, "("), cleri_list(CLERI_NONE, var, cleri_token(CLERI_NONE, ","), 1, 0, 0), k_in, CLERI_THIS, cleri_token(CLERI_NONE, ")"), CLERI_THIS ); cleri_t * expression = cleri_sequence( CLERI_GID_EXPRESSION, 4, x_preopr, cleri_choice( CLERI_NONE, CLERI_FIRST_MATCH, 13, chain, t_false, t_nil, t_true, t_float, t_int, t_string, t_regex, template, var_opt_more, thing, array, parenthesis ), index, cleri_optional(CLERI_NONE, chain) ); cleri_t * statement = cleri_prio( CLERI_GID_STATEMENT, 4, k_continue, k_break, cleri_choice( CLERI_NONE, CLERI_FIRST_MATCH, 6, if_statement, return_statement, for_statement, closure, expression, block ), operations ); cleri_t * statements = cleri_list(CLERI_GID_STATEMENTS, statement, end_statement, 0, 0, 1); cleri_t * START = cleri_sequence( CLERI_GID_START, 2, comments, statements ); cleri_ref_set(chain, cleri_sequence( CLERI_GID_CHAIN, 4, x_chain, name_opt_more, index, cleri_optional(CLERI_NONE, chain) )); cleri_grammar_t * grammar = cleri_grammar(START, "^[A-Za-z_][0-9A-Za-z_]{0,254}(?![0-9A-Za-z_])"); return grammar; } static char * query = \ "for (x in range(100)) { \n" " user = .users.find(|user| user.name.upper() == 'test');\n" " \n" " if (user) { \n" " return 'user found!'; \n" " } else { \n" " wse({ \n" " user = User{name: 'test'}; \n" " .users.push(user); \n" " }); \n" " .room.emit('new-user', user); \n" " } \n" " \n" " .channel = Channel(id); \n" " .channel.user = user; \n" " .users.reduce(|arr, user| { \n" " user = user.filter(|prop| prop == 'name'); \n" " arr.push(user); \n" " arr; \n" " }, []); \n" "} \n"; static int test_thingsdb_lang(void) { test_start("thingsdb (language)"); cleri_grammar_t * grammar = compile_langdef(); _assert (grammar); int i, flags; char buf[262144]; char * str = buf; size_t query_len = strlen(query); for (i = 0; i < 20; i++) // max 200 { memcpy(str, query, query_len); str += query_len; } *str = '\0'; _assert_is_valid (grammar, "x = 1"); _assert_is_valid (grammar, "||1?2:3"); _assert_is_valid (grammar, "||nil"); _assert_is_valid (grammar, "4 + 5;"); _assert_is_not_valid (grammar, "||1?2"); flags = ( CLERI_FLAG_EXPECTING_DISABLED| CLERI_FLAG_EXCLUDE_OPTIONAL| CLERI_FLAG_EXCLUDE_FM_CHOICE| CLERI_FLAG_EXCLUDE_RULE_THIS ); _assert_is_valid_flags (grammar, buf, flags); cleri_grammar_free(grammar); return test_end(); } int main() { return ( test_thingsdb_lang() || 0 ); }cesbit-libcleri-2964b6c/test/test_token/000077500000000000000000000000001451646561000202555ustar00rootroot00000000000000cesbit-libcleri-2964b6c/test/test_token/sources000066400000000000000000000001771451646561000216700ustar00rootroot00000000000000../src/cleri.c ../src/expecting.c ../src/grammar.c ../src/kwcache.c ../src/node.c ../src/olist.c ../src/parse.c ../src/token.c cesbit-libcleri-2964b6c/test/test_token/test_token.c000066400000000000000000000025661451646561000226110ustar00rootroot00000000000000#include "../test.h" #include "../helpers.h" static int test_token(void) { test_start("token"); cleri_grammar_t * grammar; cleri_t * dot; dot = cleri_token(0, "."); grammar = cleri_grammar(dot, NULL); // assert statements _assert_is_valid(grammar, "."); _assert_is_not_valid(grammar, ".."); _assert_is_not_valid(grammar, ""); _assert_parse_str ( grammar, "", "error at line 1, position 0, expecting: .", NULL); _assert_parse_str2 ( grammar, "", "error at line 1, position 0", NULL); cleri_grammar_free(grammar); return test_end(); } static int test_token_multi_char(void) { test_start("token (multi_char)"); cleri_grammar_t * grammar; cleri_t * not; not = cleri_token(0, "!="); grammar = cleri_grammar(not, NULL); // assert statements _assert_is_valid(grammar, " != "); _assert_is_not_valid(grammar, "!"); _assert_is_not_valid(grammar, ""); _assert_parse_str ( grammar, "", "error at line 1, position 0, expecting: !=", NULL); _assert_parse_str2 ( grammar, "", "error at line 1, position 0", NULL); cleri_grammar_free(grammar); return test_end(); } int main() { return ( test_token() || test_token_multi_char() || 0 ); } cesbit-libcleri-2964b6c/test/test_tokens/000077500000000000000000000000001451646561000204405ustar00rootroot00000000000000cesbit-libcleri-2964b6c/test/test_tokens/sources000066400000000000000000000002001451646561000220360ustar00rootroot00000000000000../src/cleri.c ../src/expecting.c ../src/grammar.c ../src/kwcache.c ../src/node.c ../src/olist.c ../src/parse.c ../src/tokens.c cesbit-libcleri-2964b6c/test/test_tokens/test_tokens.c000066400000000000000000000017461451646561000231560ustar00rootroot00000000000000#include "../test.h" #include "../helpers.h" static int test_tokens(void) { test_start("tokens"); cleri_grammar_t * grammar; cleri_t * tokens; /* tokes will be ordered on length */ const char * spaced = "== != >= <= > <"; tokens = cleri_tokens(0, "== > != < >= <= "); grammar = cleri_grammar(tokens, NULL); // assert statements _assert (strcmp(tokens->via.tokens->spaced, spaced) == 0); _assert_is_valid (grammar, "=="); _assert_is_valid (grammar, "<="); _assert_is_valid (grammar, ">"); _assert_is_not_valid (grammar, ""); _assert_is_not_valid (grammar, "="); _assert_parse_str ( grammar, "", "error at line 1, position 0, expecting: == != >= <= > <", NULL); _assert_parse_str2 ( grammar, "", "error at line 1, position 0", NULL); cleri_grammar_free(grammar); return test_end(); } int main() { return ( test_tokens() || 0 ); } cesbit-libcleri-2964b6c/test/test_version/000077500000000000000000000000001451646561000206225ustar00rootroot00000000000000cesbit-libcleri-2964b6c/test/test_version/sources000066400000000000000000000000201451646561000222200ustar00rootroot00000000000000../src/version.ccesbit-libcleri-2964b6c/test/test_version/test_version.c000066400000000000000000000004061451646561000235120ustar00rootroot00000000000000#include "../test.h" #include static int test_version(void) { test_start("version"); _assert ( strcmp(cleri_version(), "1.0.2") == 0 ); return test_end(); } int main() { return ( test_version() || 0 ); }