22#include <boost/bind.hpp>
23#include <boost/fusion/adapted/struct/adapt_struct.hpp>
24#include <boost/phoenix/bind.hpp>
25#include <boost/phoenix/fusion/at.hpp>
26#include <fmt/format.h>
27#include <fmt/ostream.h>
32BOOST_FUSION_ADAPT_STRUCT(
34BOOST_FUSION_ADAPT_STRUCT(
38 std::vector<func_sketch::parser::ParsedExpression>, arguments))
45namespace func_sketch::parser {
49 using boost::phoenix::at_c;
50 using boost::phoenix::bind;
51 using boost::phoenix::push_back;
52 using boost::spirit::qi::alpha;
53 using boost::spirit::qi::char_;
54 using boost::spirit::qi::digit;
55 using boost::spirit::qi::double_;
56 using boost::spirit::qi::fail;
57 using boost::spirit::qi::int_;
58 using boost::spirit::qi::lexeme;
59 using boost::spirit::qi::on_error;
60 using boost::spirit::qi::real_parser;
61 using boost::spirit::qi::strict_real_policies;
62 using boost::spirit::qi::labels::_1;
63 using boost::spirit::qi::labels::_2;
64 using boost::spirit::qi::labels::_3;
65 using boost::spirit::qi::labels::_4;
66 using boost::spirit::qi::labels::_a;
67 using boost::spirit::qi::labels::_val;
71#pragma clang diagnostic push
72#pragma clang diagnostic ignored "-Woverloaded-shift-op-parentheses"
79 const auto handle_imaginary_number = [](
Complex& result,
83 imaginary_number_rule_ =
84 lexeme[double_[bind(handle_imaginary_number, _val, _1)] >>
'i'];
86 const real_parser<double, strict_real_policies<double>> strict_double;
87 literal_rule_ = imaginary_number_rule_[at_c<0>(_val) = _1] |
88 strict_double[at_c<0>(_val) = _1] | int_[at_c<0>(_val) = _1];
90 identifier_rule_ = lexeme[(alpha | char_(
'_'))[at_c<0>(_val) += _1] >
91 *(alpha | char_(
'_') | digit)[at_c<0>(_val) += _1]];
93 function_call_expr_rule_ = identifier_rule_[at_c<0>(_val) = _1] >>
'(' >
94 -(sum_expr_rule_[push_back(at_c<1>(_val), _1)] >
95 *(
',' > sum_expr_rule_[push_back(at_c<1>(_val), _1)])) >
')';
97 atomic_value_expr_rule_ =
98 function_call_expr_rule_ | literal_rule_ | identifier_rule_;
100 value_expr_rule_ = atomic_value_expr_rule_ |
'(' > sum_expr_rule_ >
')';
104 left = ParsedBinaryExpression{
105 .operator_str =
"**", .left_operand = left, .right_operand = right};
107 factor_expr_rule_ = value_expr_rule_[_val = _1] >
108 -(
"**" > factor_expr_rule_[bind(handle_power, _val, _1)]);
112 result = ParsedUnaryExpression{.operator_str =
"-", .operand = operand};
115 (
'-' > factor_expr_rule_[bind(handle_unary_minus, _val, _1)]) |
116 factor_expr_rule_[_val = _1];
120 left = ParsedBinaryExpression{
121 .operator_str =
"*", .left_operand = left, .right_operand = right};
125 left = ParsedBinaryExpression{
126 .operator_str =
"/", .left_operand = left, .right_operand = right};
128 term_expr_rule_ = unary_expr_rule_[_val = _1] >
129 *(
'*' > unary_expr_rule_[bind(handle_multiplication, _val, _1)] |
130 '/' > unary_expr_rule_[bind(handle_division, _val, _1)]);
134 left = ParsedBinaryExpression{
135 .operator_str =
"+", .left_operand = left, .right_operand = right};
139 left = ParsedBinaryExpression{
140 .operator_str =
"-", .left_operand = left, .right_operand = right};
142 sum_expr_rule_ = term_expr_rule_[_val = _1] >
143 *(
'+' > term_expr_rule_[bind(handle_addition, _val, _1)] |
144 '-' > term_expr_rule_[bind(handle_subtraction, _val, _1)]);
146 expr_rule_ = sum_expr_rule_[_val = _1];
149#pragma clang diagnostic pop
154 imaginary_number_rule_.name(
"imaginary number");
155 literal_rule_.name(
"literal");
156 identifier_rule_.name(
"identifier");
160 function_call_expr_rule_.name(
"expression");
161 atomic_value_expr_rule_.name(
"expression");
162 value_expr_rule_.name(
"expression");
163 factor_expr_rule_.name(
"expression");
164 unary_expr_rule_.name(
"expression");
165 term_expr_rule_.name(
"expression");
166 sum_expr_rule_.name(
"expression");
167 expr_rule_.name(
"expression");
169 const auto handle_error = [
this](
const auto& first,
const auto& ,
170 const auto& error_pos,
const auto& what) {
171 error_message_ = fmt::format(
"Expected {} at position {}.",
172 fmt::streamed(what), std::distance(first, error_pos));
174 on_error<fail>(expr_rule_, bind(handle_error, _1, _2, _3, _4));
177const std::string& ExpressionGrammar::error_message() const noexcept {
178 return error_message_;
181void ExpressionGrammar::clear_error_message() noexcept {
182 error_message_.clear();
187 auto iter = str.begin();
188 clear_error_message();
189 bool is_parsed = boost::spirit::qi::phrase_parse(
190 iter, str.end(), *
this, boost::spirit::ascii::space, parsed_expression);
191 if (!is_parsed || iter != str.end()) {
192 const auto& error_message = this->error_message();
193 if (!error_message.empty()) {
194 throw InvalidExpressionException(error_message);
196 if (iter != str.end()) {
197 throw InvalidExpressionException(
198 fmt::format(
"Unexpected token at position {}.",
200 std::distance(str.begin(), iter) + 1));
202 throw InvalidExpressionException(
"Failed to parse expression.");
204 return parsed_expression;
Class of grammar for parsing expressions.
ExpressionGrammar()
Constructor.
double Real
Type of real numbers in this project.
std::variant< Integer, Real, Complex > Number
Type of numbers.
std::complex< Real > Complex
Type of complex numbers in this project.
Definition of exception classes.
Definition of ExpressionGrammar class.
Definition of ParsedExpression structure.
boost::variant< ParsedLiteral, ParsedIdentifier, boost::recursive_wrapper< ParsedFunctionCallExpression >, boost::recursive_wrapper< ParsedUnaryExpression >, boost::recursive_wrapper< ParsedBinaryExpression > > ParsedExpression
Variant of parsed expressions.
Struct of parsed binary expressions.
Struct of parsed function call expressions.
Struct of parsed identifiers.
Struct of parsed literals.
Struct of parsed unary expressions.