https://github.com/mrange/cppparsercombinator
CppParserCombinator
https://github.com/mrange/cppparsercombinator
Last synced: 12 months ago
JSON representation
CppParserCombinator
- Host: GitHub
- URL: https://github.com/mrange/cppparsercombinator
- Owner: mrange
- License: apache-2.0
- Created: 2015-06-26T21:05:26.000Z (almost 11 years ago)
- Default Branch: master
- Last Pushed: 2015-07-04T18:29:00.000Z (almost 11 years ago)
- Last Synced: 2025-06-21T00:44:04.812Z (about 1 year ago)
- Language: C++
- Size: 305 KB
- Stars: 2
- Watchers: 2
- Forks: 2
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# CppParserCombinator
CppParserCombinator is a parser combinator library for C++14.
1. CppParserCombinator is inspired by [FParsec](http://www.quanttec.com/fparsec/)
1. Which in turn is inspired by [Parsec](https://wiki.haskell.org/Parsec)
1. Which in turn was inspired by the classic paper [Monadic Parser Combinators](http://www.cs.nott.ac.uk/~gmh/monparsing.pdf)
Parser combinators simplifies writing parsers for simple to semi-complex grammars.
Parser Combinators have similarities to RegEx but have the following benefits over RegEx:
1. More readable (once you understand them)
1. Produces values of the desired type (ie an int parser returns an integer)
1. Supports more complex grammars, for instance sub-expressions and operator precedence is simple to implement
1. Produces human-readable error messages "for free"
Example, a calculator grammar support able to parse expressions like: (x+y)*3 + z
```c++
// AST left out
auto pcalculator_expr = [] ()
{
auto satisfy_identifier = [] (std::size_t pos, char ch)
{
return
(ch >= 'A' && ch <= 'Z' )
|| (ch >= 'a' && ch <= 'z' )
|| ((pos > 0) && ch >= '0' && ch <= '9' )
;
};
auto pidentifier_expr = pmap (psatisfy ("identifier", 1, SIZE_MAX, satisfy_identifier), identifier_expr::create);
auto pint_expr = pmap (pint, int_expr::create);
auto pexpr_trampoline = create_trampoline ();
auto pexpr = ptrampoline (pexpr_trampoline);
auto psub_expr = pbetween (pskip_char ('(') > pskip_ws, pexpr, pskip_char (')'));
auto pvalue_expr = pchoice (pint_expr, pidentifier_expr, psub_expr) > pskip_ws;
auto p0_op =
pany_of ("*/%")
> pskip_ws
;
auto pop0_expr = psep (pvalue_expr , p0_op , binary_expr::create);
auto p1_op =
pany_of ("+-")
> pskip_ws
;
auto pop1_expr = psep (pop0_expr , p1_op , binary_expr::create);
pexpr_trampoline->trampoline = pop1_expr.parser_function;
return pskip_ws < pexpr > peos;
} ();
```
A slightly more interesting example is a JSON parser:
```c++
// JSON specification: http://json.org/
auto parray_trampoline = create_trampoline ();
auto parray = ptrampoline (parray_trampoline);
auto pobject_trampoline = create_trampoline ();
auto pobject = ptrampoline (pobject_trampoline);
auto pnchar = psatisfy_char ("char", satisfy_char);
auto pescaped = pskip_char ('\\') < pmap (pany_of ("\"\\/bfnrt"), map_escaped);
// TODO: Handle unicode escaping (\u)
auto pchar = pchoice (pnchar, pescaped);
auto pchars = pbetween (pskip_char ('"'), pmany_char (pchar), pskip_char ('"'));
auto pstring = pmap (pchars, json_string::create);
auto pfrac = popt (pskip_char ('.') < praw_uint64);
auto psign = popt (pany_of ("+-"));
auto pexp = popt (pany_of ("eE") < ptuple (psign, pint));
// TODO: Handle that 0123 is not allowed
auto pnumber = pmap (ptuple (popt (pskip_char ('-')), puint64, pfrac, pexp), map_number);
auto ptrue = pskip_string ("true") < preturn (json_true_value);
auto pfalse = pskip_string ("false") < preturn (json_false_value);
auto pnull = pskip_string ("null") < preturn (json_null_value);
auto pvalue = pchoice (pstring, pnumber, ptrue, pfalse, pnull, parray, pobject) > pskip_ws;
auto pvalues = pmany_sepby (pvalue, pskip_char (',') > pskip_ws);
auto parray_ = pmap (pbetween (pskip_char ('[') > pskip_ws, pvalues, pskip_char (']') > pskip_ws), json_array::create);
auto pmember = ptuple (pchars > pskip_ws > pskip_char (':') > pskip_ws, pvalue);
auto pmembers = pmany_sepby (pmember, pskip_char (',') > pskip_ws);
auto pobject_ = pmap (pbetween (pskip_char ('{') > pskip_ws, pmembers, pskip_char ('}') > pskip_ws), json_object::create);
auto pjson = [] ()
{
parray_trampoline->trampoline = parray_.parser_function;
pobject_trampoline->trampoline = pobject_.parser_function;
return pskip_ws < pchoice (parray, pobject) > pskip_ws > peos;
} ();
```