Loading...
Searching...
No Matches
ExpressionParser.hpp
1#pragma once
2// This is an open source non-commercial project. Dear PVS-Studio, please check
3// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
4
5#include <State/Expression.hpp>
6
7#include <State/AddressParser.hpp>
8#include <State/ValueParser.hpp>
9/*
10Here is the grammar used. The grammar itself is split in multiple classes where
11relevant.
12
13
14# Addresses
15device := +[a-zA-Z0-9.~()_-];
16fragment := +[a-zA-Z0-9.~():_-];
17path_element := fragment;
18path := ('/', path_element)+ | '/';
19
20Address := device, ‘:’, path;
21Dataspace := 'color' || 'distance' || ...;
22UnitQualifier: Dataspace, '.', Unit, ('.', UnitAccessor)?; // e.g. color.rgb or
23color.rgb.r ; we make a static table with them precomputed.
24AddressAccessor := Address, '@', (('[', [:int:], ']')* || ('[',
25UnitQualifier,
26']'));
27
28
29
30# Values
31char := '\'', [:ascii:] - '\'', '\'';
32str := '"', ([:ascii:] - '"')*, '"';
33list := '[', -(value % ','), ']';
34bool := 'true' || 'false' ;
35int := [:int:];
36float := [:float:];
37variant := char || str || list || bool || int || float;
38
39Value := variant;
40
41
42# Relations
43RelationMember := Value || Address;
44RelationOp := '<=' || '<' || '>=' || '>' || '==' || '!=';
45
46Relation := RelationMember, RelationOp, RelationMember;
47
48Pulse := 'impulse(' , Address , ')'
49
50# Boolean operations
51
52Expr := Or;
53Or := (Xor, 'or', Or) | Xor;
54Xor := (And, 'xor', Xor) | And;
55And := (Not, 'and', And) | Not;
56Not := ('not', Simple) | Simple;
57
58Simple := ('{', Expr, '}') | Relation;
59*/
60
61BOOST_FUSION_ADAPT_STRUCT(
63 (State::RelationMember,
64 lhs)(ossia::expressions::comparator, op)(State::RelationMember, rhs))
65
66namespace
67{
69namespace qi = boost::spirit::qi;
70
71using boost::spirit::qi::rule;
72
74template <typename Iterator>
75struct RelationMember_parser : qi::grammar<Iterator, State::RelationMember()>
76{
77 RelationMember_parser()
78 : RelationMember_parser::base_type(start)
79 {
80 start %= ("%" >> addracc >> "%") | ("%" >> addr >> "%") | val;
81 }
82
83 Address_parser<Iterator> addr;
84 AddressAccessor_parser<Iterator> addracc;
85 Value_parser<Iterator> val;
86 qi::rule<Iterator, State::RelationMember()> start;
87};
88
90struct RelationOperation_map : qi::symbols<char, ossia::expressions::comparator>
91{
92 RelationOperation_map()
93 {
94 add("<=", ossia::expressions::comparator::LOWER_EQUAL)(
95 ">=", ossia::expressions::comparator::GREATER_EQUAL)(
96 "<", ossia::expressions::comparator::LOWER)(
97 ">", ossia::expressions::comparator::GREATER)(
98 "!=", ossia::expressions::comparator::DIFFERENT)(
99 "==", ossia::expressions::comparator::EQUAL)(
100 "contains", ossia::expressions::comparator::CONTAINS);
101 }
102};
103
104template <typename Iterator>
105struct Relation_parser : qi::grammar<Iterator, State::Relation()>
106{
107 Relation_parser()
108 : Relation_parser::base_type(start)
109 {
110 using boost::spirit::qi::skip;
111 start %= skip(boost::spirit::standard::space)[(rm_parser >> op_map >> rm2_parser)];
112 }
113
114 RelationMember_parser<Iterator> rm_parser;
115 RelationMember_parser<Iterator> rm2_parser;
116 RelationOperation_map op_map;
117 qi::rule<Iterator, State::Relation()> start;
118};
119
120template <typename Iterator>
121struct Pulse_parser : qi::grammar<Iterator, State::Pulse()>
122{
123 Pulse_parser()
124 : Pulse_parser::base_type(start)
125 {
126 using boost::spirit::qi::lit;
127 using boost::spirit::qi::skip;
128 using boost::spirit::standard::string;
129 start %= skip(boost::spirit::standard::space)["%" >> addr >> "%" >> "impulse"]
130 | skip(boost::spirit::standard::space)
131 [lit('{') >> lit("%") >> addr >> lit("%") >> lit("impulse") >> '}'];
132 }
133
134 Address_parser<Iterator> addr;
135 qi::rule<Iterator, State::Pulse()> start;
136};
137
138// 90% of the boolean expr. parsing was taken from the stackoverflow answer :
139// http://stackoverflow.com/a/8707598/1495627
140namespace qi = boost::spirit::qi;
141
142struct op_or
143{
144};
145struct op_and
146{
147};
148struct op_xor
149{
150};
151struct op_not
152{
153};
154
155typedef std::string var;
156template <typename tag>
157struct binop;
158template <typename tag>
159struct unop;
160
161using expr_raw = boost::variant<
162 State::Relation, State::Pulse, boost::recursive_wrapper<unop<op_not>>,
163 boost::recursive_wrapper<binop<op_and>>, boost::recursive_wrapper<binop<op_xor>>,
164 boost::recursive_wrapper<binop<op_or>>>;
165
166template <typename tag>
167struct binop
168{
169 explicit binop(expr_raw l, expr_raw r)
170 : oper1(std::move(l))
171 , oper2(std::move(r))
172 {
173 }
174 expr_raw oper1, oper2;
175};
176
177template <typename tag>
178struct unop
179{
180 explicit unop(expr_raw o)
181 : oper1(std::move(o))
182 {
183 }
184 expr_raw oper1;
185};
186
187template <typename Op>
188struct ExpressionOpConstruct
189{
190 void operator()(
191 boost::fusion::vector<expr_raw, expr_raw> x, auto& context,
192 qi::unused_type) const noexcept
193 {
194 boost::fusion::at_c<0>(context.attributes)
195 = binop<Op>(boost::fusion::at_c<0>(x), boost::fusion::at_c<1>(x));
196 }
197 void operator()(expr_raw x, auto& context, qi::unused_type) const noexcept
198 {
199 boost::fusion::at_c<0>(context.attributes) = unop<Op>(x);
200 }
201};
202
203struct ExpressionOpIdent
204{
205 void operator()(expr_raw x, auto& context, qi::unused_type) const noexcept
206 {
207 boost::fusion::at_c<0>(context.attributes) = x;
208 }
209};
210template <typename It, typename Skipper = qi::space_type>
211struct Expression_parser : qi::grammar<It, expr_raw(), Skipper>
212{
213 Expression_parser()
214 : Expression_parser::base_type(expr_)
215 {
216 using namespace qi;
217
218 expr_ = or_.alias();
219
220 namespace bsi = boost::spirit;
221 or_ = (xor_ >> "or" >> or_)[ExpressionOpConstruct<op_or>{}]
222 | xor_[ExpressionOpIdent{}];
223 xor_ = (and_ >> "xor" >> xor_)[ExpressionOpConstruct<op_xor>{}]
224 | and_[ExpressionOpIdent{}];
225 and_ = (not_ >> "and" >> and_)[ExpressionOpConstruct<op_and>{}]
226 | not_[ExpressionOpIdent{}];
227 not_ = ("not" > simple)[ExpressionOpConstruct<op_not>{}]
228 | simple[ExpressionOpIdent{}];
229
230 simple = (('{' >> expr_ >> '}') | relation_ | pulse_);
231 }
232
233private:
234 Relation_parser<It> relation_;
235 Pulse_parser<It> pulse_;
236 qi::rule<It, expr_raw(), Skipper> not_, and_, xor_, or_, simple, expr_;
237};
238
239struct Expression_builder : boost::static_visitor<void>
240{
241 Expression_builder(State::Expression* e)
242 : m_current{e}
243 {
244 }
245 State::Expression* m_current{};
246
247 void operator()(const State::Relation& rel) { m_current->emplace_back(rel, nullptr); }
248
249 void operator()(const State::Pulse& rel) { m_current->emplace_back(rel, nullptr); }
250
251 void operator()(const binop<op_and>& b)
252 {
253 rec_binop(State::BinaryOperator::AND, b.oper1, b.oper2);
254 }
255 void operator()(const binop<op_or>& b)
256 {
257 rec_binop(State::BinaryOperator::OR, b.oper1, b.oper2);
258 }
259 void operator()(const binop<op_xor>& b)
260 {
261 rec_binop(State::BinaryOperator::XOR, b.oper1, b.oper2);
262 }
263
264 void rec_binop(State::BinaryOperator binop, const expr_raw& l, const expr_raw& r)
265 {
266 m_current->emplace_back(binop, nullptr);
267
268 auto old_expr = m_current;
269 m_current = &old_expr->children().back();
270
271 boost::apply_visitor(*this, l);
272 boost::apply_visitor(*this, r);
273
274 m_current = old_expr;
275 }
276
277 void operator()(const unop<op_not>& u)
278 {
279 m_current->emplace_back(State::UnaryOperator::Not, nullptr);
280
281 auto old_expr = m_current;
282 m_current = &old_expr->children().back();
283
284 boost::apply_visitor(*this, u.oper1);
285
286 m_current = old_expr;
287 }
288};
289}
290
STL namespace.
Definition lv2_atom_helpers.hpp:99
Definition Relation.hpp:71
Definition Relation.hpp:19