Повысьте эффективность работы с использованием альтернативного анализатора

Я уже задал вопрос об этой проблеме. Но поскольку ответов не было, я снова спрашиваю с полным компилируемым fragmentом исходного кода.

Этот fragment кода должен быть скомпилирован без опции std = c ++ 11 из-за некоторых проблем с boost :: variant move semantic. Просто ‘g ++ -Wall -pedantic’.

В этом fragmentе кода вы найдете строку «// Комментарий здесь». Вы можете прокомментировать следующий блок до «// И здесь —–». Если этот блок раскован, выполнение этой программы очень плохое.

Таким образом, узкое место, пока я вижу, является альтернативным парсером. Мне нужны некоторые предложения по улучшению / изменению моей грамматики, чтобы улучшить производительность синтаксического анализа. Благодарю.

Код:

#include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  namespace qi = boost::spirit::qi; namespace ascii = boost::spirit::ascii; namespace phoenix = boost::phoenix; namespace client { typedef std::string::iterator input_iterator_type; struct op_and {}; struct op_or {}; struct op_eq {}; struct op_neq {}; struct is_part_of {}; struct more {}; struct more_eq {}; struct less {}; struct less_eq {}; struct mask_match {}; struct mask_not_match {}; struct in {}; namespace type { enum code_t { string = 0, boolean = 1, number = 2, none = 3, datetime = 4, unknown = 5 }; } template  struct binop; struct fn_call; struct none_type {~none_type(){}}; struct datetime { datetime(int yyyy, int mm, int dd, int hh24, int mi, int ss, int mls) : yy(yyyy), mm(mm), dd(dd), hh(hh24), mi(mi), ss(ss), ms(mls) {} datetime() : yy(0), mm(0), dd(0), hh(0), mi(0), ss(0), ms(0) {} int yy; int mm; int dd; int hh; int mi; int ss; int ms; }; typedef boost::variant< boost::recursive_wrapper<binop >, boost::recursive_wrapper<binop >, boost::recursive_wrapper<binop >, boost::recursive_wrapper<binop >, boost::recursive_wrapper<binop >, boost::recursive_wrapper<binop >, boost::recursive_wrapper<binop >, boost::recursive_wrapper<binop >, boost::recursive_wrapper<binop >, boost::recursive_wrapper<binop >, boost::recursive_wrapper<binop >, boost::recursive_wrapper<binop > > generic_binop; typedef boost::variant < std::string, double, none_type, datetime, boost::recursive_wrapper, boost::recursive_wrapper > node_value_t; struct g_node { mutable type::code_t type_id; mutable node_value_t value; }; typedef node_value_t value_type; template  struct binop { explicit binop(const g_node& l, const g_node& r) : oper1(l), oper2(r) {} g_node oper1, oper2; }; typedef std::vector node_vector; struct fn_call { explicit fn_call(){} std::string name; node_vector params; }; } BOOST_FUSION_ADAPT_STRUCT( client::g_node, (client::type::code_t, type_id) (client::node_value_t, value) ) BOOST_FUSION_ADAPT_STRUCT( client::fn_call, (std::string, name) (std::vector, params) ) namespace client { template  struct g_error_handler { template struct result { typedef void type; }; void operator()(Iterator first, Iterator last, Iterator err_pos, boost::spirit::info const& what) const { std::cout << "Syntax error. Expected: " << what << " at: " << std::distance(first, err_pos) << std::endl; } }; template<typename Iterator, typename ErrorHandler = g_error_handler > struct g_parser : qi::grammar { g_parser() : g_parser::base_type(or_, "G"), error_handler(ErrorHandler()) { using phoenix::at_c; or_ = (and_ >> "||" >> or_)[ at_c(qi::_val) = type::unknown, at_c(qi::_val) = phoenix::construct<binop >(qi::_1, qi::_2)] | and_[qi::_val = qi::_1]; and_ = (bool_op >> "&&" >> and_)[ at_c(qi::_val) = type::unknown, at_c(qi::_val) = phoenix::construct<binop >(qi::_1, qi::_2)] | bool_op[qi::_val = qi::_1]; bool_op = (prim >> "=" >> bool_op)[ at_c(qi::_val) = type::unknown, at_c(qi::_val) = phoenix::construct<binop >(qi::_1, qi::_2)] | (prim >> "" >> bool_op)[ at_c(qi::_val) = type::unknown, at_c(qi::_val) = phoenix::construct<binop >(qi::_1, qi::_2)] | // Comment here --------------------------------------------------- (prim >> ":" >> bool_op)[ at_c(qi::_val) = type::unknown, at_c(qi::_val) = phoenix::construct<binop >(qi::_1, qi::_2)] | (prim >> ">" >> bool_op)[ at_c(qi::_val) = type::unknown, at_c(qi::_val) = phoenix::construct<binop >(qi::_1, qi::_2)] | (prim >> ">=" >> bool_op)[ at_c(qi::_val) = type::unknown, at_c(qi::_val) = phoenix::construct<binop >(qi::_1, qi::_2)] | (prim >> "> bool_op)[ at_c(qi::_val) = type::unknown, at_c(qi::_val) = phoenix::construct<binop >(qi::_1, qi::_2)] | (prim >> "> bool_op)[ at_c(qi::_val) = type::unknown, at_c(qi::_val) = phoenix::construct<binop >(qi::_1, qi::_2)] | (prim >> "=~" >> bool_op)[ at_c(qi::_val) = type::unknown, at_c(qi::_val) = phoenix::construct<binop >(qi::_1, qi::_2)] | (prim >> "!~" >> bool_op)[ at_c(qi::_val) = type::unknown, at_c(qi::_val) = phoenix::construct<binop >(qi::_1, qi::_2)] | (prim >> "in" >> bool_op)[ at_c(qi::_val) = type::unknown, at_c(qi::_val) = phoenix::construct<binop >(qi::_1, qi::_2)] | // And here------------------------------------------------------------ prim[qi::_val = qi::_1]; prim = string_val [qi::_val = qi::_1] | number [qi::_val = qi::_1] | func_call [at_c(qi::_val) = type::unknown, at_c(qi::_val) = qi::_1] | '(' > or_ [qi::_val = qi::_1] > ')'; quoted_string %= "'" > qi::lexeme[*(qi::char_ - "'")] > "'"; func_call = fn_name > '(' > -(or_ % ',') > ')'; fn_name %= +(qi::alpha) > -(qi::char_('-')) > *(qi::alnum); string_val = quoted_string[ at_c(qi::_val) = type::string, at_c(qi::_val) = qi::_1]; number %= qi::attr(type::number) >> qi::double_; or_.name ("OR expression" ); and_.name ("AND expression" ); bool_op.name ("BOOL expression"); prim.name ("Atom expression"); quoted_string.name ("quoted string" ); fn_name.name ("function name" ); number.name ("number" ); qi::on_error(or_, error_handler(qi::_1, qi::_2, qi::_3, qi::_4)); } qi::rule and_, bool_op, prim, or_, string_val, number; qi::rule func_call; qi::rule quoted_string, fn_name; boost::phoenix::function error_handler; }; typedef g_parser grammar; } int main() { std::string s = "((foo(bar('','')) = foo('')) || ('a' = 'gg')) && (3  7) && (foo('','') = bar('','')) && 2=4 && 'a' ='b' && foo('')  foo('')"; client::grammar g; client::g_node ast; std::string::iterator begin = s.begin(); std::string::iterator end = s.end(); bool success = qi::phrase_parse(begin, end, g, boost::spirit::ascii::space, ast) && begin == end; std::stringstream ss; if(!success) std::cout << "Syntax error at: " << std::distance(s.begin(), begin); else std::cout << "Syntax is Ok\n"; } 

Вы можете реорганизовать грамматику, чтобы вызвать меньше обратного отслеживания. Я сделал пример такого рефакторинга раньше на SO.

Ссылка: не найдена

Однако вот суть. Следующее должно быть эквивалентным, за исключением значительно уменьшенной потребности в обратном направлении:

Посмотреть Live On Coliru

 using boost::phoenix::construct; using qi::_val; using qi::_1; bool_op = prim [ _val = _1 ] >> -(( ("=" >> bool_op [ at_c<1>(_val) = construct > (_val, _1) ]) | ("<>" >> bool_op [ at_c<1>(_val) = construct > (_val, _1) ]) | (":" >> bool_op [ at_c<1>(_val) = construct > (_val, _1) ]) | (">" >> bool_op [ at_c<1>(_val) = construct > (_val, _1) ]) | (">=" >> bool_op [ at_c<1>(_val) = construct > (_val, _1) ]) | ("<" >> bool_op [ at_c<1>(_val) = construct > (_val, _1) ]) | ("<=" >> bool_op [ at_c<1>(_val) = construct > (_val, _1) ]) | ("=~" >> bool_op [ at_c<1>(_val) = construct > (_val, _1) ]) | ("!~" >> bool_op [ at_c<1>(_val) = construct > (_val, _1) ]) | ("in" >> bool_op [ at_c<1>(_val) = construct > (_val, _1) ]) ) >> qi::eps [ at_c<0>(_val) = type::unknown ]) ; 

Также обратите внимание на мою тенденцию избегать повторного кода и представить код . Даже если у вас есть стандарт кодирования, который налагает максимальную длину строки, он, несомненно, более parsingчив, более удобен в обслуживании и гораздо меньше подвержен ошибкам для компоновки кода в выравниваемых столбцах, как и я. Фактически, вы можете просто утверждать, что этот fragment кода является «метаданные», таблица, если хотите, и вы можете сделать обоснованное исключение.

Я думаю, что вижу ряд других «кодовых запахов» – или, что более положительно, «возможностей для упрощения».

Фактически я реорганизовал много грамматик, как и в прошлом, на SO и обычно уменьшал код до <50% от исходного кода, часто добавляя функции одновременно. У меня, к сожалению, нет времени, чтобы найти их прямо сейчас, но, может быть, вы можете посмотреть сами.