{"id":19271007,"url":"https://github.com/mgood7123/qparse","last_synced_at":"2026-05-08T16:50:10.871Z","repository":{"id":119196285,"uuid":"555818044","full_name":"mgood7123/QParse","owner":"mgood7123","description":"A powerful Parser Combinator library with error reporting and input rewriting capabilities, build WITH or WITHOUT QT6 support","archived":false,"fork":false,"pushed_at":"2023-10-25T10:57:22.000Z","size":134,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-01-05T13:21:30.078Z","etag":null,"topics":["cpp","parser","parser-combinators","qt6","std"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mgood7123.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-10-22T12:01:14.000Z","updated_at":"2023-02-18T09:07:35.000Z","dependencies_parsed_at":null,"dependency_job_id":"13803c3f-0ba2-4243-8b80-8c1dec35c26d","html_url":"https://github.com/mgood7123/QParse","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mgood7123%2FQParse","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mgood7123%2FQParse/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mgood7123%2FQParse/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mgood7123%2FQParse/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mgood7123","download_url":"https://codeload.github.com/mgood7123/QParse/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240373207,"owners_count":19791158,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cpp","parser","parser-combinators","qt6","std"],"created_at":"2024-11-09T20:28:42.869Z","updated_at":"2026-05-08T16:50:05.819Z","avatar_url":"https://github.com/mgood7123.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# QParse\nA powerful Parser Combinator library with error reporting and input rewriting capabilities\n\n## Building\n\ndefine `QParse_RULES_USE_QT_FRAMEWORK` when building with QT6 for QT6 specialization support, uses `QString` and friends\n\notherwise leave `QParse_RULES_USE_QT_FRAMEWORK` undefined to build with `std` (non-QT) support, uses `std::string` and friends\n\nto add support for another framework, see `framework_defines.h`\n\n\n## Usage\n\n### Basic Usage\n\n```cpp\n#include \u003cQParse/Rules_Extra.h\u003e\n```\n\nwe first start with an `Iterator`\n\n```cpp\nusing namespace QParse;\n\nIterator iter = \"some string\";\n```\n\nwe then create a `Grammar`\n\n# Custom Rules\n\nfirst, lets get the obvious out of the way\n\nQParse supports the creation of user defined `Rule` objects\n\na custom `Rule` object can be defined by extending from `QParse::Rules::Rule` (for a single rule), `QParse::Rules::RuleHolder` (for a collection of rules),  or any of their subclasses\n\nit is recommended to extend from `Rule` and store `Rule` input arguments in one or more `RuleHolder` variables, where the number of rules is known, or in a vector of `RuleHolder` if the number of rules is unknown\n\nit is recommended to extend from `RuleHolder` directly if the input is a single rule\n\nfor a single input rule, either `Rule` or `RuleHolder` will do, but `RuleHolder` is recommended if possible\n\nhere is the rule for the custom `If` rule, implemented via `Rule`\n\n```cpp\n#include \"Rules.h\"\n\nnamespace QParse {\n    namespace Rules {\n\n    using Condition = std::function\u003cbool()\u003e;\n\n    class If : public Rule {\n        Condition condition;\n        RuleHolder rule_if_true;\n        RuleHolder rule_if_false;\n    public:\n\n        If(Condition cond, Rule * rule_if_true) : condition(cond), rule_if_true(rule_if_true), rule_if_false(nullptr) {}\n\n        If(Condition cond, Rule * rule_if_true, Rule* rule_if_false) : condition(cond), rule_if_true(rule_if_true), rule_if_false(rule_if_false) {}\n\n        using Rule::match;\n\n        virtual std::optional\u003cIteratorMatcher::MatchData\u003e match(Iterator \u0026iterator, UndoRedo *undo, bool doAction, bool logErrors = true) override {\n            IteratorMatcher::MatchData match;\n            match.begin = iterator.current();\n            match.end = iterator.current();\n            match.matched = false;\n\n            if (condition()) {\n                    auto tmp_ = rule_if_true.match(iterator, undo, doAction, logErrors);\n                    if (!tmp_.has_value()) return std::nullopt;\n                    auto tmp = *tmp_;\n                    match.matched = tmp.matched;\n                    match.end = tmp.end;\n                    match.matches += tmp.matches;\n            } else {\n                auto tmp_ = rule_if_false.match(iterator, undo, doAction, logErrors);\n                if (!tmp_.has_value()) return std::nullopt;\n                auto tmp = *tmp_;\n                match.matched = tmp.matched;\n                match.end = tmp.end;\n                match.matches += tmp.matches;\n            }\n\n            return match;\n        }\n    };\n    }\n}\n```\n\nhere is the rule for `Optional`, implemented via `RuleHolder`\n\n```cpp\n        struct Optional : RuleHolder {\n            Optional(Rule * rule, Action action = NO_ACTION);\n\n            using Rule::match;\n\n            virtual std::optional\u003cIteratorMatcher::MatchData\u003e match(Iterator \u0026iterator, UndoRedo *undo, bool doAction = true, bool logErrors = true) override;\n        };\n```\n```cpp\nQParse::Rules::Optional::Optional(Rule *rule, Action action) : RuleHolder(rule, action) {}\n\nstd::optional\u003cQParse::IteratorMatcher::MatchData\u003e QParse::Rules::Optional::match(Iterator \u0026iterator, UndoRedo *undo, bool doAction, bool logErrors) {\n    IteratorMatcher::MatchData match;\n    match.begin = iterator.current();\n    match.end = iterator.current();\n    auto tmp_ = rule-\u003ematch(iterator, undo, doAction, logErrors);\n    if (!tmp_.has_value()) return std::nullopt;\n    auto tmp = *tmp_;\n    if (tmp) {\n        match.end = tmp.end;\n        match.matches = tmp.matches;\n    }\n    match.matched = true;\n    iterator.pushInfo();\n    match.matches++;\n    if (doAction) action(Input(iterator, match, undo, match.matches));\n    return match;\n}\n```\n\nand here is the rule for `Or`, implemented via `Rule`\n\n```cpp\n        struct Or : Rule {\n            QParse_RULES____VECTOR\u003cRuleHolder\u003e rules;\n\n            Or(std::initializer_list\u003cRule*\u003e rules, Action action = NO_ACTION);\n\n            using Rule::match;\n\n            virtual std::optional\u003cIteratorMatcher::MatchData\u003e match(Iterator \u0026iterator, UndoRedo *undo, bool doAction = true, bool logErrors = true) override;\n        };\n```\n```cpp\nQParse::Rules::Or::Or(std::initializer_list\u003cRule *\u003e rules, Action action) : Rule(action) {\n\n    for (Rule * rule : rules) {\n        this-\u003erules.push_back(rule);\n    }\n}\n\nstd::optional\u003cQParse::IteratorMatcher::MatchData\u003e QParse::Rules::Or::match(Iterator \u0026iterator, UndoRedo *undo, bool doAction, bool logErrors) {\n    IteratorMatcher::MatchData match;\n    match.begin = iterator.current();\n    match.end = iterator.current();\n    match.matched = false;\n    if (rules.size() == 0) {\n        match.matched = true;\n        iterator.pushInfo();\n        match.matches++;\n        if (doAction) action(Input(iterator, match, undo, match.matches));\n        return match;\n    }\n    for (Rule \u0026 rule : rules) {\n        auto match_ = rule.match(iterator, undo, doAction, logErrors);\n        if (!match_.has_value()) {\n            iterator.popInfo(match.matches);\n            return std::nullopt;\n        }\n        match = *match_;\n        if (match) {\n            if (doAction) action(Input(iterator, match, undo, match.matches));\n            return match;\n        } else {\n            iterator.popInfo(match.matches);\n            match.matches = 0;\n        }\n    }\n    return match;\n}\n```\n# Rule\n\na `Grammar` is a set of `Rule` objects that define the `Grammar Definition`\n\nall rule objects accept an `ACTION` in the form of the following lambda: `[\u0026] (QParse::Rules::Input input) { code_here(); }`, or `std::function\u003cvoid, QParse::Rules::Input\u003e`\n\nrule objects are sometimes called `expressions` as they `express` how you want to parse something\n\nfor example, lets parse `\"some string\"`\n\n```cpp\nusing namespace QParse;\n\nIterator iter = \"some string\";\n\nRules::String(\"some string\").match(iter);\n```\n\nhere, we match \"some string\" exactly, character for character\n\nthis is too easy, lets match it via an expression\n\nwe know it consists of alphabetical characters and a white space\n\nfor this we will use `Rules::Sequence` and `Rules::Range`\n\n```cpp\n\nauto text = new Rules::OneOrMore(\n  new Rules::Range('a', 'z')\n);\n\nauto space = new Rules::Char(' ');\n\nRules::Sequence({ text, space, text }).match(iter);\n```\n\nhere, we match against `one or more` range of `a to z`, followed by a space, followed by `one or more` range of `a to z`\n\nyou may notice we do not delete `text` or `space`, this is because each `Rules::` takes a `Rule*` object, and manages its lifetime automatically\n\n```cpp\n{\n    Rules::At(\n        new Rules::Char('a') // managed by At\n    );\n}\n// At is destructed\n// Char gets deleted by the destructor\n\n```\n\nthis is done via a hidden `RuleHolder*` \n\n# RuleHolder\na `RuleHolder` object extends `Rule`, and manages the lifetime of a `Rule` object via `reference counting`\n\nthis makes it possible to use a `Rule` in multiple places without worrying about `dangling references` or `use-after-free`\n\n\nall `Rules::` that accept `Rule*` objects must store each `Rule*` object in a `RuleHolder*` object\n\nthis is done by simply extending `RuleHolder` or by extending `Rule` and then storing each `Rule*` inside a `RuleHolder`\n\na `RuleHolder` can only contain one `Rule` at a time\n\nwe will cover some advance topics such as `conditional expressions`, `stack expressions`, `error reporting`, and `input modification` later\n\n## capabilities\n\n#### Rule\nsee above\n\n#### RuleHolder\nsee above\n\nunless explicitly stated, all rules fail if they encounter EOF\n\n#### Error\nfails the entire rule, except if inside an `Or`, `Optional`, or `At` rules\n\nany further execution is haulted, and the input stack (see `Input Modification`) is unwound\n\nthe name will be displayed for identifying iterators\n\nthe name can be changed via the `iterator.name` variable\n\nthe default name is `unknown`\n\n#### ErrorIf*Match\nsame as `Error` but conditionally, actions are invoked conditionally, respectively\n\n#### EndOfFile\nexplicitly matches against `EOF` (succeeds if and ONLY if `EOF` is encountered)\n\n#### Newline\nmatches if either `\\n` or `\\r\\n` are encountered\n\n#### NewlineOrEOF\nmatches if either `Newline` or `EOF` are encountered \n\n#### Success\nself explanatory, the rule itself always succeeds, even at EOF\n\n#### Fail\nself explanatory, the rule itself always fails\n\n#### Char\naccepts a single character `'c'`, use this for matching individual characters or hexadecimal\n\n#### Range\nmatches `characters` in a range\n\nsyntax is as follows\n\none or more pairs of [`start`, `end`]\n\nmay end with an `extra character`, as if `or [ [ range ... ], [ 'extra character' ] ]`\n\n#### String\naccepts a string of characters `\"string\"`, use this for matching individual strings or character/hexadecimal sequences\n\n#### Any\nmatches and consumes any input\n\n#### AdvanceInputBy\nadvances the input by `N` characters, this is faster than `Any` as it can skip multiple characters in a single go\n\n#### TemporaryAction\ntemporarily overrides the action of the specified rule, prevents all other actions from executing within the rule\n\n```\nTemporaryAction B1\n  TemporaryAction B2\n    TemporaryAction B3\n```\n\nonly `B1` will run, any `Error` rules will be logged but their actions will not be executed\n\n#### At\nexecutes the given `rule` but does not consume any input and does not execute any actions, no errors are logged\n\n#### NotAt\nexecutes the given `rule` but does not consume any input and does not execute any actions, no errors are logged\n\nfails if the given rule succeeds, succeeds if the given rule fails\n\n#### Optional\nalways matches regardless of if the given `Rule` matches or not, any `Error` rules will execute as normal\n\n#### Log*\nvarious rules for logging information about the current given rule\n\n#### LogCurrentCharacter\nprints the current character, does not consume input\n\n#### LogTrace\ncombines all Log* into a single rule\n\n#### ZeroOrMore\nkeeps matching until the given rule fails to match, always succeeds\n\nequivalent to `Optional(OneOrMore(rule))`\n\n#### OneOrMore\nmatches if the given rule matches at least once, and keeps matching until the given rule fails to match\n\n#### MatchBUntilA\nmatches rule B until rule A is matched\n\n```\n1. A is matched, if A succeeds, the rule succeeds\n2. if A fails, B is matched\n3. if B succeeds, go to 1\n4. if B fails to match, the rule fails\n```\n\n#### Or\nmatches if any of the given rules match, any `Error` rules will execute as normal\n\n#### Sequence\nmatches only if all of the given rules match\n\n#### Until\nadvances the input by 1 until the given rule matches\n\n\n\n## advanced capabilities\n\n#### if\nan `if statement` in the form of a `Rule`\n\nsyntax: `if([\u0026] { return CONDITION; }, RTrue, RFalse)`\n\nuse this to conditionally execute rules based on conditional input that may be determined by executed actions or outside factors such as threads or input variables\n\n#### Stack\na `Rule` stack, use `setBase` to set the base rule, and an optional action\n\nuse `push` to push to the top of the stack\n\nuse `pop/popAll` to pop from top of the stack\n\nthe top most rule is executed\n\nit is an error to have a `nullptr` base\n\n### Input Modification and Rescan\n\na powerful feature of `QParse` is its `input modification` and `rescan` capabilities\n\n`input modification` and `rescan` are done via `actions`, specifically the `Input` object that is passed to every `ACTION` argument\n\nthis works based on `captured` input, if a rule succeeds, it will capture any input it sees, otherwise it will capture nothing\n\nnote that a capture of nothing is itself a valid capture\n\nthe input stream can be modified in the following ways:\n\n#### rescan\nrescans the input stream starting at the beginning of the capture\n\nif you capture `a`, and the input is `ab`, then it will rescan `a` on the next rule, and then `b` on the next rule, depending on the rule\n\n#### erase and rescan\nremoves the captured input from the input stream and then rescans\n\n#### replace\nreplaces the captured input with a `character` or a `string`, then continues from the start of the next character at the end of the replacement\n\nthe replacement can be `smaller` or `larger` than the `capture`\n\nif you capture `ab` and replace it with `f`, and the input is `abcd`, then it will transform the input into `fcd` and then continue at `c` on the next rule, and then `d` on the next rule, depending on the rule\n\n#### replace and rescan\nsame as doing `replace` and then `rescan`, with above, it will continue at `f` on the next rule, and then `c` on the next rule, depending on the rule\n\n#### insert\ninserts a `character` or a `string` ahead of the captured input, then continues from the start of the inserted text\n\nif you capture `ab` and insert `f`, and the input is `abcd`, then it will transform the input into `abfcd` and then continue at `f` on the next rule, and then `c` on the next rule, depending on the rule\n\n#### insert and rescan\nsame as doing `insert` and then `rescan`, with above, it will continue at `a` on the next rule, and then `b` on the next rule, and then `f` on the next rule, depending on the rule\n\n\n\n\n\n\n### Example\n\n#### simple:\n\n```c\n    // y, ye, yes, n, no\n    // case insensitive\n    auto y_ = new Rules::Or({new Rules::Char('y'), new Rules::Char('Y')});\n    auto e_ = new Rules::Or({new Rules::Char('e'), new Rules::Char('E')});\n    auto s_ = new Rules::Or({new Rules::Char('s'), new Rules::Char('S')});\n    auto n_ = new Rules::Or({new Rules::Char('n'), new Rules::Char('N')});\n    auto o_ = new Rules::Or({new Rules::Char('o'), new Rules::Char('O')});\n\n    bool a;\n\n    auto yes = new Rules::Or({\n        y_,\n        new Rules::Sequence({y_, e_}),\n        new Rules::Sequence({y_, e_, s_}),\n    }, [\u0026](Rules::Input i) {\n        a = true;\n    });\n    auto no = new Rules::Or({\n        n_,\n        new Rules::Sequence({n_, o_}),\n    }, [\u0026](Rules::Input i) {\n        a = false;\n    });\n    Rules::Or({yes, no}).match(answer);\n    return a;\n```\n\n#### moderate:\n\n```c\n    Iterator it = content;\n\n    auto single_comment = new Rules::Sequence({\n        new Rules::String(\"//\"),\n        new Rules::Optional(new Rules::Char(' ')),\n        new Rules::Until(new Rules::At(new Rules::NewlineOrEOF), [](QParse::Rules::Input i) {\n            std::cout \u003c\u003c \"comment: \" \u003c\u003c i.quotedString() \u003c\u003c std::endl;\n        }),\n        new Rules::Optional(new Rules::Newline)\n    });\n\n    auto block_comment = new Rules::Sequence({\n        new Rules::String(\"#COMMENT_BEGIN\"),\n        new Rules::Until(new Rules::Sequence({\n            new Rules::Newline(),\n            new Rules::String(\"#COMMENT_END\")}\n        ))\n    }, [](QParse::Rules::Input i) {\n        //std::cout \u003c\u003c \"block comment: \" \u003c\u003c i.quotedString() \u003c\u003c std::endl;\n    });\n\n    auto line = new Rules::Sequence({\n        new Rules::Until(new Rules::At(new Rules::NewlineOrEOF), [](QParse::Rules::Input i) {\n            std::cout \u003c\u003c \"line: \" \u003c\u003c i.quotedString() \u003c\u003c std::endl;\n        }),\n        new Rules::Optional(new Rules::Newline)\n    });\n\n    auto empty_line = new Rules::Sequence({\n        new Rules::MatchBUntilA(new Rules::At(new Rules::Newline), new Rules::Or({new Rules::Char(' '), new Rules::Char('\\t')})),\n        new Rules::Newline\n    });\n\n    if (!Rules::MatchBUntilA(new Rules::EndOfFile,\n            new Rules::Or({\n                single_comment,\n                block_comment,\n                empty_line,\n                line,\n                new Rules::Error(\"unexpected token\")\n            }\n    )).match(it)) {\n        return -1;\n    }\n```\n\n#### complex\n\n```c\n    std::string a = \"../../wl_syscalls.decl\";\n    auto content = readFile(a);\n\n    typedef struct Info {\n        bool is_typedef;\n        std::vector\u003cstd::string\u003e comment;\n        std::string current_typedef, current_syscall, current_arguments, current_argument_count, current_arguments_usages;\n    } Info;\n\n    Info info;\n    info.is_typedef = false;\n\n    std::vector\u003cInfo\u003e syscalls;\n\n    using namespace QParse;\n\n    Iterator it = content;\n\n    auto space = new Rules::Or({new Rules::Char(' '), new Rules::Char('\\t')});\n\n    auto spaces = new Rules::ZeroOrMore(space);\n\n    auto single_comment = new Rules::Sequence({\n        new Rules::String(\"//\"),\n        spaces,\n        new Rules::Sequence({\n            new Rules::Until(new Rules::At(new Rules::NewlineOrEOF), [\u0026](QParse::Rules::Input i) {\n                info.comment.push_back(i.string());\n            }),\n            new Rules::Optional(new Rules::Newline)\n        })\n    });\n\n    auto block_comment = new Rules::Sequence({\n        new Rules::String(\"#COMMENT_BEGIN\"), new Rules::Newline(),\n        new Rules::MatchBUntilA(\n            new Rules::Sequence({\n                new Rules::String(\"#COMMENT_END\"), new Rules::Newline()\n            }),\n            new Rules::Sequence({\n                new Rules::Until(new Rules::At(new Rules::NewlineOrEOF), [\u0026](QParse::Rules::Input i) {\n                    info.comment.push_back(i.string());\n                }),\n                new Rules::Optional(new Rules::Newline)\n            })\n        )\n    });\n    \n    auto c_ident = Rules_NS_LogTrace1(new Rules::Sequence({\n        new Rules::Range({'a', 'z', 'A', 'Z', '_'}),\n        new Rules::Optional(new Rules::OneOrMore(new Rules::Range({'a', 'z', 'A', 'Z', '0', '9', '_'})))\n    }), \"c_ident\");\n\n    auto number = Rules_NS_LogTrace1(new Rules::OneOrMore(new Rules::Range({'0', '9'})), \"number\");\n\n    auto c_value = Rules_NS_LogTrace1(new Rules::Or({c_ident, number}), \"c_value\");\n\n    auto syscall = new Rules::TemporaryAction(c_ident, [\u0026](QParse::Rules::Input i) {\n        std::string sl = i.string();\n        std::transform(sl.begin(), sl.end(), sl.begin(), std::tolower);\n        if (!info.is_typedef) {\n            info.current_syscall = sl;\n        } else {\n            info.current_typedef = sl;\n            info.is_typedef = false;\n        }\n    });\n\n    auto arguments = new Rules::Sequence({\n        new Rules::Char('\u003c'),\n        spaces,\n        new Rules::Or({\n            Rules_NS_LogTrace1(new Rules::Sequence({\n                Rules_NS_LogTrace(new Rules::NotAt(\n                    new Rules::Or({\n                        new Rules::Sequence({\n                            new Rules::Char('\u003e'),\n                            spaces,\n                            new Rules::Or({\n                                single_comment,\n                                new Rules::Newline()\n                            })\n                        }),\n                        new Rules::String(\"...\")\n                    })\n                )),\n                new Rules::ErrorIfNotMatch(new Rules::TemporaryAction(number, [\u0026](Rules::Input i) { info.current_argument_count = i.string(); }), \"expected an integer\"),\n                new Rules::ErrorIfNotMatch(new Rules::Char(','), \"expected comma after number of arguments\"),\n                spaces,\n                Rules_NS_LogTrace1(new Rules::ErrorIfNotMatch(new Rules::Sequence({\n                    c_ident,\n                    new Rules::Until(new Rules::At(new Rules::Sequence({spaces, new Rules::Char('\u003e')})))\n                }, [\u0026](QParse::Rules::Input i) {\n                    info.current_arguments = i.string();\n                }), \"expected argument declarations, followed by closing '\u003e'\"), \"argument declaration\"),\n                spaces,\n                new Rules::ErrorIfNotMatch(new Rules::Char('\u003e'), \"expected closing '\u003e'\"),\n                spaces,\n                new Rules::ErrorIfNotMatch(new Rules::Char('\u003c'), \"expected opening '\u003c'\"),\n                spaces,\n                new Rules::ErrorIfNotMatch(new Rules::Sequence({\n                    new Rules::Optional(new Rules::Char('\u0026')),\n                    c_value,\n                    // we cannot use an Until rule here since we need to skip '-\u003e' if it occurs\n                    Rules_NS_LogTrace1(new Rules::MatchBUntilA(\n                        Rules_NS_LogTrace1(new Rules::At(new Rules::Char('\u003e')), \"at \u003e\"),\n                        new Rules::Or({\n                            new Rules::Sequence({\n                                new Rules::At(new Rules::String(\"-\u003e\")),\n                                Rules_NS_LogTrace1(new Rules::String(\"-\u003e\"), \"ignore -\u003e\")\n                            }),\n                            new Rules::Any\n                        })\n                    ), \"argument usages\"),\n                }, [\u0026](QParse::Rules::Input i) { info.current_arguments_usages = i.string(); }), \"expected argument usages, followed by closing '\u003e'\"),\n            }), \"numbered arguments\"),\n            Rules_NS_LogTrace1(new Rules::If(\n                [\u0026]() { return info.current_typedef.length() != 0; },\n                new Rules::ErrorIfMatch(\n                    new Rules::At(new Rules::String(\"...\"))\n                    , \"typedef declaration does not support varadic arguments (...)\"\n                ),\n                new Rules::Optional(\n                    new Rules::String(\"...\", [\u0026](QParse::Rules::Input i) { info.current_arguments = i.string(); })\n                )\n            ), \"any number of arguments\")\n        }),\n        spaces,\n        new Rules::ErrorIfNotMatch(new Rules::Char('\u003e'), \"expected closing '\u003e'\")\n    });\n\n    auto syscall_line_end = new Rules::Or({\n        single_comment,\n        new Rules::Newline,\n        new Rules::At(new Rules::EndOfFile)\n    });\n\n    auto syscall_line = new Rules::Sequence({\n        syscall,\n        spaces,\n        new Rules::Optional(Rules_NS_LogTrace(arguments)),\n        spaces,\n        syscall_line_end,\n    });\n\n    auto syscall_line__or__typedef_syscall_line = new Rules::Or({\n        new Rules::Sequence({\n            new Rules::At(new Rules::Sequence({\n                Rules_NS_LogTrace1(syscall, \"at syscall\"), spaces,\n                new Rules::Or({\n                    Rules_NS_LogTrace1(new Rules::Char('\u003c'), \"at \u003c\"),\n                    Rules_NS_LogTrace1(syscall_line_end, \"at syscall line end\")\n                })\n            })),\n            syscall_line\n        }),\n        new Rules::Sequence({\n            new Rules::At(new Rules::Sequence({\n                Rules_NS_LogTrace1(new Rules::String(\"typedef\"), \"at typedef\"),\n                spaces,\n                Rules_NS_LogTrace1(syscall, \"at syscall\"), spaces,\n                Rules_NS_LogTrace1(syscall, \"at syscall\"), spaces,\n                new Rules::Or({\n                    Rules_NS_LogTrace1(new Rules::Char('\u003c'), \"at \u003c\"),\n                    Rules_NS_LogTrace1(syscall_line_end, \"at syscall line end\")\n                })\n            })),\n            new Rules::String(\"typedef\", [\u0026](QParse::Rules::Input i) { info.is_typedef = true; }),\n            spaces,\n            new Rules::ErrorIfNotMatch(syscall, \"expected syscall\"),\n            spaces,\n            syscall_line\n        }),\n    }, [\u0026](Rules::Input i) {\n        syscalls.push_back(info);\n        info.is_typedef = false;\n        info.current_typedef.clear();\n        info.comment.clear();\n        info.comment.shrink_to_fit();\n        info.current_syscall.clear();\n        info.current_argument_count.clear();\n        info.current_arguments.clear();\n        info.current_arguments_usages.clear();\n    });\n\n    auto empty_line = new Rules::Sequence({\n        new Rules::MatchBUntilA(new Rules::At(new Rules::NewlineOrEOF), space),\n        new Rules::Optional(new Rules::Newline)\n    }, [\u0026](QParse::Rules::Input i) {\n        info.comment.clear();\n        info.comment.shrink_to_fit();\n    });\n\n    if (!Rules::MatchBUntilA(\n        new Rules::EndOfFile,\n        new Rules::ErrorIfNotMatch(\n            new Rules::Or({\n                single_comment,\n                block_comment,\n                empty_line,\n                Rules_NS_LogTrace(syscall_line__or__typedef_syscall_line),\n            }),\n            \"expected a comment, empty line, typedef syscall, or a syscall declaration\"\n        )\n    ).match(it)) {\n        printf(\"failed to parse syscalls.decl\\n\");\n        return -1;\n    }\n\n    if (syscalls.empty()) {\n        printf(\"no syscalls specified in syscalls.decl\\n\");\n        return 0;\n    }\n```\nparses the following\n```\n// syscall.decl\n//\n//     file format:\n//         // comment, this can \u003c contain anything % at @ all !\n//\n//         #COMMENT_BEGIN\n//         this is a block comment\n//             this can \u003c contain anything % at @ all !\n//         #COMMENT_END\n//\n//         // syscall documentation goes directly above syscall\n//         // this can be\n//         // multiple comments\n//         #COMMENT_BEGIN\n//               or multiple\n//         #COMMENT_END\n//         #COMMENT_BEGIN\n//               block comments\n//         #COMMENT_END\n//         // or both\n//         syscall                                                              // you can even put documentation here!  zero arguments example: foo  \n//         syscall \u003c\u003e                                                           // zero arguments                                       example: foo  \u003c\u003e\n//         syscall \u003cargc, arg declaration\u003e \u003cargument usage\u003e                     // argc arguments,                                      example: foo  \u003c2, int foo, float bar\u003e \u003cfoo, bar\u003e\n//         syscall \u003c...\u003e                                                        // up to 125 arguments of any type                      example: foo  \u003c...\u003e\n//\n//         // syscalls can also be typedef'd\n//         //\n//         // a typedef is like a mapping that maps the input of syscall_to to the input of syscall_from\n//\n//         // can map to any syscall that can accept specified argument types\n//         //   eg, struct IO arg -\u003e int, int*\n//         //   eg, struct IO arg -\u003e arg.input, \u0026arg.outputInt   // passing arg.input would produce a compile error since it expects int* but we passed int\n//         \n//         //   eg, struct IO arg -\u003e int, float*\n//         //   eg, struct IO arg -\u003e arg.input, \u0026arg.outputFloat // passing arg.outputInt or arg.input would produce a compile error since it expects float* but we passed int or int*\n//         //\n//         typedef syscall_from syscall_to \u003cargc, arg declaration\u003e \u003cargument usage\u003e   // typedef argc arguments,                              example: typedef foo foo1  \u003c2, foobar f\u003e \u003cf.foo, f.bar\u003e\n//         typedef syscall_from syscall_to \u003c...\u003e                                      // NOT SUPPORTED !!!    IT IS IMPOSSIBLE TO RELIABLE TYPEDEF A VARADIC ARGUMENT !\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmgood7123%2Fqparse","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmgood7123%2Fqparse","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmgood7123%2Fqparse/lists"}