]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | [#grammar] |
2 | [section grammar] | |
3 | ||
4 | [h1 Synopsis] | |
5 | ||
6 | template <class StartSymbol = BOOST_METAPARSE_STRING("S")> | |
7 | struct grammar | |
8 | { | |
9 | template <class S, class Pos> | |
10 | struct apply; | |
11 | ||
12 | template <class Name, class P> | |
13 | struct import; | |
14 | ||
15 | template <class S, class Action = /* unspecified */> | |
16 | struct rule; | |
17 | }; | |
18 | ||
19 | [h1 Description] | |
20 | ||
21 | [note | |
22 | Note that using this adds a significant overhead to your builds. When someone | |
23 | uses your parser, the compiler will have to build your grammar parser, use it | |
24 | to parse your grammar and build your parser and then it can parse the input | |
25 | the user would like to parse with your parser. You might consider using the | |
26 | parser combinators the library provides. | |
27 | ] | |
28 | ||
29 | Parser combinator for constructing parsers based on an embedded DSL similar to | |
30 | EBNF. It can be used the following way: | |
31 | ||
32 | grammar<> | |
33 | // definitions | |
34 | ||
35 | where a definition can be a rule or an import command. | |
36 | ||
37 | Rules look like on of the following: | |
38 | ||
39 | ::rule<BOOST_METAPARSE_STRING("name ::= def")> | |
40 | ::rule<BOOST_METAPARSE_STRING("name ::= def"), semantic_action> | |
41 | ||
42 | `name` consists of letters, digits and the `_` character. It is the name of | |
43 | the symbol being defined. `def` describes the rule. It can be | |
44 | ||
45 | * the name of a symbol | |
46 | * a terminal, which is a character between single quotes. `\` can be used for | |
47 | escaping. The following are accepted: `\n`, `\r`, `\t`, `\\`, `\'` | |
48 | * a sequence of definitions | |
49 | * a definition followed by the `*` character, which means repetition accepting | |
50 | 0 match | |
51 | * a definition followed by the `+` character, which means repetition expecting | |
52 | at least one match | |
53 | * a definition in brackets | |
54 | ||
55 | Rules take an optional `semantic_action` argument. It is a placeholder | |
56 | expression taking one argument. When this is given, this is used to transform | |
57 | the result of the rule. | |
58 | ||
59 | Imports can be used to turn an arbitrary parser into a symbol available for the | |
60 | rules. Import definitions look like the following: | |
61 | ||
62 | ::import<BOOST_METAPARSE_STRING("name"), parser> | |
63 | ||
64 | `name` is the name of the symbol, `parser` is the parser to bind the name to. | |
65 | ||
66 | The start symbol of the grammar is specified by the template argument of the | |
67 | `grammar` template. This is optional, the default value is `S`. | |
68 | ||
69 | Note that the current implementation "inlines" the referenced symbols while | |
70 | parsing the grammar and recursion is not supported because of this. | |
71 | ||
72 | [h1 Header] | |
73 | ||
74 | #include <boost/metaparse/grammar.hpp> | |
75 | ||
76 | [h1 Example] | |
77 | ||
78 | #define BOOST_METAPARSE_LIMIT_STRING_SIZE 64 | |
79 | ||
80 | #include <boost/metaparse/grammar.hpp> | |
81 | #include <boost/metaparse/token.hpp> | |
82 | #include <boost/metaparse/int_.hpp> | |
83 | #include <boost/metaparse/entire_input.hpp> | |
84 | #include <boost/metaparse/build_parser.hpp> | |
85 | #include <boost/metaparse/string.hpp> | |
86 | ||
87 | #include <boost/mpl/front.hpp> | |
88 | #include <boost/mpl/back.hpp> | |
89 | #include <boost/mpl/plus.hpp> | |
90 | #include <boost/mpl/fold.hpp> | |
91 | #include <boost/mpl/lambda.hpp> | |
92 | ||
93 | using boost::metaparse::token; | |
94 | using boost::metaparse::int_; | |
95 | using boost::metaparse::build_parser; | |
96 | using boost::metaparse::entire_input; | |
97 | using boost::metaparse::grammar; | |
98 | ||
99 | using boost::mpl::front; | |
100 | using boost::mpl::back; | |
101 | using boost::mpl::plus; | |
102 | using boost::mpl::fold; | |
103 | using boost::mpl::lambda; | |
104 | using boost::mpl::_1; | |
105 | using boost::mpl::_2; | |
106 | ||
107 | template <class A, class B> | |
108 | struct lazy_plus : boost::mpl::plus<typename A::type, typename B::type> {}; | |
109 | ||
110 | template <class Sequence, class State, class ForwardOp> | |
111 | struct lazy_fold : | |
112 | fold<typename Sequence::type, typename State::type, typename ForwardOp::type> | |
113 | {}; | |
114 | ||
115 | using plus_action = | |
116 | lazy_fold<back<_1>, front<_1>, lambda<lazy_plus<_1, back<_2>>>::type>; | |
117 | ||
118 | using plus_grammar = | |
119 | grammar<BOOST_METAPARSE_STRING("plus_exp")> | |
120 | ::import<BOOST_METAPARSE_STRING("int_token"), token<int_>>::type | |
121 | ||
122 | ::rule<BOOST_METAPARSE_STRING("ws ::= (' ' | '\n' | '\r' | '\t')*")>::type | |
123 | ::rule<BOOST_METAPARSE_STRING("plus_token ::= '+' ws"), front<_1>>::type | |
124 | ::rule<BOOST_METAPARSE_STRING("plus_exp ::= int_token (plus_token int_token)*"), plus_action>::type | |
125 | ; | |
126 | ||
127 | using plus_parser = build_parser<entire_input<plus_grammar>>; | |
128 | ||
129 | static_assert( | |
130 | plus_parser::apply<BOOST_METAPARSE_STRING("1 + 2 + 3 + 4")>::type::value == 10, | |
131 | "Arithmetic expression should be evaluated" | |
132 | ); | |
133 | ||
134 | [endsect] | |
135 |