{"id":27057839,"url":"https://github.com/mrange/cppparsercombinator","last_synced_at":"2025-06-28T02:02:44.653Z","repository":{"id":34250141,"uuid":"38133711","full_name":"mrange/CppParserCombinator","owner":"mrange","description":"CppParserCombinator","archived":false,"fork":false,"pushed_at":"2015-07-04T18:29:00.000Z","size":312,"stargazers_count":2,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-06-21T00:44:04.812Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mrange.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-06-26T21:05:26.000Z","updated_at":"2025-03-03T08:13:19.000Z","dependencies_parsed_at":"2022-08-03T20:00:26.968Z","dependency_job_id":null,"html_url":"https://github.com/mrange/CppParserCombinator","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/mrange/CppParserCombinator","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrange%2FCppParserCombinator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrange%2FCppParserCombinator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrange%2FCppParserCombinator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrange%2FCppParserCombinator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mrange","download_url":"https://codeload.github.com/mrange/CppParserCombinator/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrange%2FCppParserCombinator/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262362041,"owners_count":23299118,"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":[],"created_at":"2025-04-05T11:33:39.936Z","updated_at":"2025-06-28T02:02:44.626Z","avatar_url":"https://github.com/mrange.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# CppParserCombinator\n\nCppParserCombinator is a parser combinator library for C++14.\n\n1. CppParserCombinator is inspired by [FParsec](http://www.quanttec.com/fparsec/)\n1. Which in turn is inspired by [Parsec](https://wiki.haskell.org/Parsec)\n1. Which in turn was inspired by the classic paper [Monadic Parser Combinators](http://www.cs.nott.ac.uk/~gmh/monparsing.pdf)\n\nParser combinators simplifies writing parsers for simple to semi-complex grammars.\nParser Combinators have similarities to RegEx but have the following benefits over RegEx:\n\n1. More readable (once you understand them)\n1. Produces values of the desired type (ie an int parser returns an integer)\n1. Supports more complex grammars, for instance sub-expressions and operator precedence is simple to implement\n1. Produces human-readable error messages \"for free\"\n\nExample, a calculator grammar support able to parse expressions like: (x+y)*3 + z\n\n```c++\n// AST left out\nauto pcalculator_expr = [] ()\n{\n  auto satisfy_identifier = [] (std::size_t pos, char ch)\n    {\n      return\n            (ch \u003e= 'A' \u0026\u0026 ch \u003c= 'Z'               )\n        ||  (ch \u003e= 'a' \u0026\u0026 ch \u003c= 'z'               )\n        ||  ((pos \u003e 0) \u0026\u0026 ch \u003e= '0' \u0026\u0026 ch \u003c= '9'  )\n        ;\n    };\n\n  auto pidentifier_expr = pmap (psatisfy (\"identifier\", 1, SIZE_MAX, satisfy_identifier), identifier_expr::create);\n\n  auto pint_expr        = pmap (pint, int_expr::create);\n\n  auto pexpr_trampoline = create_trampoline\u003cexpr::ptr\u003e ();\n  auto pexpr            = ptrampoline\u003cexpr::ptr\u003e (pexpr_trampoline);\n  auto psub_expr        = pbetween (pskip_char ('(') \u003e pskip_ws, pexpr, pskip_char (')'));\n\n  auto pvalue_expr      = pchoice (pint_expr, pidentifier_expr, psub_expr) \u003e pskip_ws;\n\n  auto p0_op =\n        pany_of (\"*/%\")\n    \u003e   pskip_ws\n    ;\n  auto pop0_expr        = psep (pvalue_expr , p0_op , binary_expr::create);\n\n  auto p1_op =\n        pany_of (\"+-\")\n    \u003e   pskip_ws\n    ;\n  auto pop1_expr        = psep (pop0_expr   , p1_op , binary_expr::create);\n\n  pexpr_trampoline-\u003etrampoline = pop1_expr.parser_function;\n  return pskip_ws \u003c pexpr \u003e peos;\n} ();\n```\n\nA slightly more interesting example is a JSON parser:\n\n```c++\n// JSON specification: http://json.org/\nauto parray_trampoline  = create_trampoline\u003cjson_ast::ptr\u003e ();\nauto parray             = ptrampoline\u003cjson_ast::ptr\u003e (parray_trampoline);\n\nauto pobject_trampoline = create_trampoline\u003cjson_ast::ptr\u003e ();\nauto pobject            = ptrampoline\u003cjson_ast::ptr\u003e (pobject_trampoline);\n\nauto pnchar   = psatisfy_char (\"char\", satisfy_char);\nauto pescaped = pskip_char ('\\\\') \u003c pmap (pany_of (\"\\\"\\\\/bfnrt\"), map_escaped);\n// TODO: Handle unicode escaping (\\u)\nauto pchar    = pchoice (pnchar, pescaped);\nauto pchars   = pbetween (pskip_char ('\"'), pmany_char (pchar), pskip_char ('\"'));\nauto pstring  = pmap (pchars, json_string::create);\n\nauto pfrac    = popt (pskip_char ('.') \u003c praw_uint64);\nauto psign    = popt (pany_of (\"+-\"));\nauto pexp     = popt (pany_of (\"eE\") \u003c ptuple (psign, pint));\n// TODO: Handle that 0123 is not allowed\nauto pnumber  = pmap (ptuple (popt (pskip_char ('-')), puint64, pfrac, pexp), map_number);\n\nauto ptrue    = pskip_string (\"true\")   \u003c preturn (json_true_value);\n\nauto pfalse   = pskip_string (\"false\")  \u003c preturn (json_false_value);\n\nauto pnull    = pskip_string (\"null\")   \u003c preturn (json_null_value);\n\nauto pvalue   = pchoice (pstring, pnumber, ptrue, pfalse, pnull, parray, pobject) \u003e pskip_ws;\n\nauto pvalues  = pmany_sepby (pvalue, pskip_char (',') \u003e pskip_ws);\nauto parray_  = pmap (pbetween (pskip_char ('[') \u003e pskip_ws, pvalues, pskip_char (']') \u003e pskip_ws), json_array::create);\n\nauto pmember  = ptuple (pchars \u003e pskip_ws \u003e pskip_char (':') \u003e pskip_ws, pvalue);\nauto pmembers = pmany_sepby (pmember, pskip_char (',') \u003e pskip_ws);\nauto pobject_ = pmap (pbetween (pskip_char ('{') \u003e pskip_ws, pmembers, pskip_char ('}') \u003e pskip_ws), json_object::create);\n\nauto pjson = [] ()\n{\n  parray_trampoline-\u003etrampoline   = parray_.parser_function;\n  pobject_trampoline-\u003etrampoline  = pobject_.parser_function;\n  return pskip_ws \u003c pchoice (parray, pobject) \u003e pskip_ws \u003e peos;\n} ();\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmrange%2Fcppparsercombinator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmrange%2Fcppparsercombinator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmrange%2Fcppparsercombinator/lists"}