Added regex matching operators to the conditional G-code processor
in a form similar to Perl: Following expression returns true, if the variable matches the regex: variable =~ /regex/ Following expression returns true, if the variable does not match the regex: variable !~ /regex/
This commit is contained in:
parent
88e9ba510b
commit
bbfb9a4190
1 changed files with 39 additions and 2 deletions
|
@ -22,6 +22,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
|
#include <boost/regex.hpp>
|
||||||
// Unicode iterator to iterate over utf8.
|
// Unicode iterator to iterate over utf8.
|
||||||
#include <boost/regex/pending/unicode_iterator.hpp>
|
#include <boost/regex/pending/unicode_iterator.hpp>
|
||||||
|
|
||||||
|
@ -382,9 +383,37 @@ namespace client
|
||||||
lhs.type = TYPE_BOOL;
|
lhs.type = TYPE_BOOL;
|
||||||
lhs.data.b = (op == '=') ? value : !value;
|
lhs.data.b = (op == '=') ? value : !value;
|
||||||
}
|
}
|
||||||
static void equal(expr &lhs, expr &rhs) { compare_op(lhs, rhs, '='); }
|
static void equal (expr &lhs, expr &rhs) { compare_op(lhs, rhs, '='); }
|
||||||
static void not_equal(expr &lhs, expr &rhs) { compare_op(lhs, rhs, '!'); }
|
static void not_equal(expr &lhs, expr &rhs) { compare_op(lhs, rhs, '!'); }
|
||||||
|
|
||||||
|
static void regex_op(expr &lhs, boost::iterator_range<Iterator> &rhs, char op)
|
||||||
|
{
|
||||||
|
const std::string *subject = nullptr;
|
||||||
|
const std::string *mask = nullptr;
|
||||||
|
if (lhs.type == TYPE_STRING) {
|
||||||
|
// One type is string, the other could be converted to string.
|
||||||
|
subject = &lhs.s();
|
||||||
|
} else {
|
||||||
|
lhs.throw_exception("Left hand side of a regex match must be a string.");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
std::string pattern(++ rhs.begin(), -- rhs.end());
|
||||||
|
bool result = boost::regex_match(*subject, boost::regex(pattern));
|
||||||
|
if (op == '!')
|
||||||
|
result = ! result;
|
||||||
|
lhs.reset();
|
||||||
|
lhs.type = TYPE_BOOL;
|
||||||
|
lhs.data.b = result;
|
||||||
|
} catch (boost::regex_error &ex) {
|
||||||
|
// Syntax error in the regular expression
|
||||||
|
boost::throw_exception(qi::expectation_failure<Iterator>(
|
||||||
|
rhs.begin(), rhs.end(), spirit::info(std::string("*Regular expression compilation failed: ") + ex.what())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void regex_matches (expr &lhs, boost::iterator_range<Iterator> &rhs) { return regex_op(lhs, rhs, '='); }
|
||||||
|
static void regex_doesnt_match(expr &lhs, boost::iterator_range<Iterator> &rhs) { return regex_op(lhs, rhs, '!'); }
|
||||||
|
|
||||||
static void set_if(bool &cond, bool ¬_yet_consumed, std::string &str_in, std::string &str_out)
|
static void set_if(bool &cond, bool ¬_yet_consumed, std::string &str_in, std::string &str_out)
|
||||||
{
|
{
|
||||||
if (cond && not_yet_consumed) {
|
if (cond && not_yet_consumed) {
|
||||||
|
@ -810,6 +839,8 @@ namespace client
|
||||||
>> *( ("==" > additive_expression(_r1) ) [px::bind(&expr<Iterator>::equal, _val, _1)]
|
>> *( ("==" > additive_expression(_r1) ) [px::bind(&expr<Iterator>::equal, _val, _1)]
|
||||||
| ("!=" > additive_expression(_r1) ) [px::bind(&expr<Iterator>::not_equal, _val, _1)]
|
| ("!=" > additive_expression(_r1) ) [px::bind(&expr<Iterator>::not_equal, _val, _1)]
|
||||||
| ("<>" > additive_expression(_r1) ) [px::bind(&expr<Iterator>::not_equal, _val, _1)]
|
| ("<>" > additive_expression(_r1) ) [px::bind(&expr<Iterator>::not_equal, _val, _1)]
|
||||||
|
| ("=~" > regular_expression ) [px::bind(&expr<Iterator>::regex_matches, _val, _1)]
|
||||||
|
| ("!~" > regular_expression ) [px::bind(&expr<Iterator>::regex_doesnt_match, _val, _1)]
|
||||||
);
|
);
|
||||||
bool_expr.name("bool expression");
|
bool_expr.name("bool expression");
|
||||||
|
|
||||||
|
@ -877,6 +908,9 @@ namespace client
|
||||||
[ px::bind(&MyContext::resolve_variable<Iterator>, _r1, _1, _val) ];
|
[ px::bind(&MyContext::resolve_variable<Iterator>, _r1, _1, _val) ];
|
||||||
variable_reference.name("variable reference");
|
variable_reference.name("variable reference");
|
||||||
|
|
||||||
|
regular_expression = raw[lexeme['/' > *((utf8char - char_('\\') - char_('/')) | ('\\' > char_)) > '/']];
|
||||||
|
regular_expression.name("regular_expression");
|
||||||
|
|
||||||
keywords.add
|
keywords.add
|
||||||
("and")
|
("and")
|
||||||
("if")
|
("if")
|
||||||
|
@ -905,6 +939,7 @@ namespace client
|
||||||
debug(factor);
|
debug(factor);
|
||||||
debug(scalar_variable_reference);
|
debug(scalar_variable_reference);
|
||||||
debug(variable_reference);
|
debug(variable_reference);
|
||||||
|
debug(regular_expression);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -922,6 +957,8 @@ namespace client
|
||||||
qi::rule<Iterator, boost::iterator_range<Iterator>(), spirit::ascii::space_type> identifier;
|
qi::rule<Iterator, boost::iterator_range<Iterator>(), spirit::ascii::space_type> identifier;
|
||||||
// Math expression consisting of +- operators over terms.
|
// Math expression consisting of +- operators over terms.
|
||||||
qi::rule<Iterator, expr<Iterator>(const MyContext*), spirit::ascii::space_type> additive_expression;
|
qi::rule<Iterator, expr<Iterator>(const MyContext*), spirit::ascii::space_type> additive_expression;
|
||||||
|
// Rule to capture a regular expression enclosed in //.
|
||||||
|
qi::rule<Iterator, boost::iterator_range<Iterator>(), spirit::ascii::space_type> regular_expression;
|
||||||
// Boolean expressions over expressions.
|
// Boolean expressions over expressions.
|
||||||
qi::rule<Iterator, expr<Iterator>(const MyContext*), spirit::ascii::space_type> bool_expr;
|
qi::rule<Iterator, expr<Iterator>(const MyContext*), spirit::ascii::space_type> bool_expr;
|
||||||
// Evaluate boolean expression into bool.
|
// Evaluate boolean expression into bool.
|
||||||
|
|
Loading…
Reference in a new issue