From c788fd5bcc4a247bf07e841c4d21f4706bc721c4 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Wed, 17 Mar 2010 20:03:06 +0000 Subject: [PATCH] dbms: development. --- dbms/include/DB/Parsers/ExpressionGrammar.h | 123 ++++++++++++++++++++ dbms/src/Parsers/tests/expression.cpp | 100 ++++++++++++++++ 2 files changed, 223 insertions(+) create mode 100644 dbms/include/DB/Parsers/ExpressionGrammar.h create mode 100644 dbms/src/Parsers/tests/expression.cpp diff --git a/dbms/include/DB/Parsers/ExpressionGrammar.h b/dbms/include/DB/Parsers/ExpressionGrammar.h new file mode 100644 index 00000000000..6d67889e60f --- /dev/null +++ b/dbms/include/DB/Parsers/ExpressionGrammar.h @@ -0,0 +1,123 @@ +#ifndef DBMS_PARSERS_EXPRESSION_H +#define DBMS_PARSERS_EXPRESSION_H + +#include +#include +#include +#include +#include +#include + +#include + +#include + + +namespace DB +{ + +/** Expression - это выражение, которое может стоять в запросе между SELECT и FROM + * Здесь представлен парсер этого выражения (пока без операторов). + * PS. Код довольно сложный :( + */ + +/** Типы данных, которые образуются автоматически в результате парсинга. + * Они должны быть в отдельном или глобальном namespace из-за BOOST_FUSION_ADAPT_STRUCT. + * + * spirit может собирать типы данных - результаты парсинга (атрибуты) автоматически, + * или можно использовать свои типы и заполнять их вручную с помощью семантических действий. + * Здесь используется вариант - автоматически. + * (но стоит на будущее иметь ввиду, что его очень сложно заставить скомпилироваться) + */ +namespace ExpressionGrammarTypes +{ + typedef boost::variant NumberConstant; /// 1, -1, 0.1 + typedef String StringConstant; /// 'abc', 'ab\'c', 'abc\\' + typedef Null NullConstant; /// NULL, null, NuLl + + typedef boost::variant< + NumberConstant, + StringConstant, + NullConstant> Constant; + + typedef String Name; /// x, sum, width + + struct Function; /// forward declaration для рекурсии + typedef boost::variant< + boost::recursive_wrapper, + Constant, + Name> Node; /// элемент выражения + + typedef std::vector Expression; /// выражение - набор элементов через запятую + + struct Function /// f(x), sum(a, 10), concat('a', 'bc') + { + Name name; /// sum + Expression args; /// a, 10 + }; +} + +} + + +/** Необходимо, чтобы struct Function был совместим с boost::fusion::vector (он же boost::tuple), + * который образуется автоматически при парсинге. + * Должно быть в глобальном namespace. + */ +BOOST_FUSION_ADAPT_STRUCT( + DB::ExpressionGrammarTypes::Function, + (DB::ExpressionGrammarTypes::Name, name) + (DB::ExpressionGrammarTypes::Expression, args) +) + + +namespace DB +{ + +namespace qi = boost::spirit::qi; +namespace ascii = boost::spirit::ascii; +namespace lambda = boost::lambda; + + +/** Грамматика */ +template +struct ExpressionGrammar : qi::grammar +{ + ExpressionGrammar() : ExpressionGrammar::base_type(expression) + { + using qi::lexeme; + using qi::raw; + using qi::alpha; + using qi::alnum; + using qi::ulong_long; + using qi::long_long; + using qi::double_; + using qi::eps; + using qi::no_case; + using qi::char_; + using qi::_val; + using qi::_1; + + expression %= node % ','; + node %= function | constant | name; + name %= raw[lexeme[alpha >> -*(alnum | '_')]]; + constant %= number | string | null; + function %= name >> '(' >> expression >> ')'; + number %= ulong_long | long_long | double_; + null = eps[_val = boost::none] >> no_case["NULL"]; + string %= raw[lexeme['\'' >> *((char_ - (char_('\\') | '\'')) | (char_('\'') >> char_)) >> '\'']]; + } + + qi::rule expression; + qi::rule node; + qi::rule constant; + qi::rule name; + qi::rule function; + qi::rule number; + qi::rule string; + qi::rule null; +}; + +} + +#endif diff --git a/dbms/src/Parsers/tests/expression.cpp b/dbms/src/Parsers/tests/expression.cpp new file mode 100644 index 00000000000..d850fd4adcd --- /dev/null +++ b/dbms/src/Parsers/tests/expression.cpp @@ -0,0 +1,100 @@ +#include +#include + +#include +#include + +#include + + +namespace qi = boost::spirit::qi; +namespace ascii = boost::spirit::ascii; + +typedef DB::ExpressionGrammarTypes::Expression Expr; + +class dumpNumber : public boost::static_visitor<> +{ +public: + void operator() (const DB::UInt64 & x) const + { + std::cout << "UInt64: " << x << std::endl; + } + + void operator() (const DB::Int64 & x) const + { + std::cout << "Int64: " << x << std::endl; + } + + void operator() (const DB::Float64 & x) const + { + std::cout << "Float64: " << x << std::endl; + } +}; + +class dumpConst : public boost::static_visitor<> +{ +public: + void operator() (const DB::ExpressionGrammarTypes::NumberConstant & x) const + { + boost::apply_visitor(dumpNumber(), x); + } + + void operator() (const DB::ExpressionGrammarTypes::StringConstant & x) const + { + std::cout << "String: " << x << std::endl; + } + + void operator() (const DB::ExpressionGrammarTypes::NullConstant & x) const + { + std::cout << "Null" << std::endl; + } +}; + +class dumpNode : public boost::static_visitor<> +{ +public: + void operator() (const DB::ExpressionGrammarTypes::Constant & x) const + { + boost::apply_visitor(dumpConst(), x); + } + + void operator() (const DB::ExpressionGrammarTypes::Name & x) const + { + std::cout << "Name: " << x << std::endl; + } + + void operator() (const DB::ExpressionGrammarTypes::Function & x) const + { + std::cout << "Function, name: " << x.name << ", args: " << std::endl; + for (Expr::const_iterator it = x.args.begin(); it != x.args.end(); ++it) + boost::apply_visitor(dumpNode(), *it); + std::cout << std::endl; + } +}; + +void dumpResult(const Expr & value) +{ + + for (Expr::const_iterator it = value.begin(); it != value.end(); ++it) + boost::apply_visitor(dumpNode(), *it); +} + + +int main(int argc, char ** argv) +{ + typedef std::string::const_iterator iterator_t; + + DB::ExpressionGrammar parser; + DB::ExpressionGrammarTypes::Expression value; + + std::string s = "ab1, b, f(c), 0, g(h(i), 1), -1, NULL, null, 'abc'"; + iterator_t it = s.begin(); + iterator_t end = s.end(); + + bool res = boost::spirit::qi::phrase_parse(it, end, parser, ascii::space, value); + + std::cout << res << '\t' << s.substr(0, it - s.begin()) << std::endl; + dumpResult(value); + + return 0; +}