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