mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-21 15:12:02 +00:00
dbms: development.
This commit is contained in:
parent
2c644482db
commit
c788fd5bcc
123
dbms/include/DB/Parsers/ExpressionGrammar.h
Normal file
123
dbms/include/DB/Parsers/ExpressionGrammar.h
Normal file
@ -0,0 +1,123 @@
|
||||
#ifndef DBMS_PARSERS_EXPRESSION_H
|
||||
#define DBMS_PARSERS_EXPRESSION_H
|
||||
|
||||
#include <boost/spirit/include/qi.hpp>
|
||||
#include <boost/spirit/include/phoenix_operator.hpp>
|
||||
#include <boost/lambda/lambda.hpp>
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
#include <boost/variant/recursive_wrapper.hpp>
|
||||
#include <boost/fusion/include/adapt_struct.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <DB/Core/Types.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
/** Expression - это выражение, которое может стоять в запросе между SELECT и FROM
|
||||
* Здесь представлен парсер этого выражения (пока без операторов).
|
||||
* PS. Код довольно сложный :(
|
||||
*/
|
||||
|
||||
/** Типы данных, которые образуются автоматически в результате парсинга.
|
||||
* Они должны быть в отдельном или глобальном namespace из-за BOOST_FUSION_ADAPT_STRUCT.
|
||||
*
|
||||
* spirit может собирать типы данных - результаты парсинга (атрибуты) автоматически,
|
||||
* или можно использовать свои типы и заполнять их вручную с помощью семантических действий.
|
||||
* Здесь используется вариант - автоматически.
|
||||
* (но стоит на будущее иметь ввиду, что его очень сложно заставить скомпилироваться)
|
||||
*/
|
||||
namespace ExpressionGrammarTypes
|
||||
{
|
||||
typedef boost::variant<UInt64, Int64, Float64> 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<Function>,
|
||||
Constant,
|
||||
Name> Node; /// элемент выражения
|
||||
|
||||
typedef std::vector<Node> 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 <typename Iterator>
|
||||
struct ExpressionGrammar : qi::grammar<Iterator, ExpressionGrammarTypes::Expression(), ascii::space_type>
|
||||
{
|
||||
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<Iterator, ExpressionGrammarTypes::Expression(), ascii::space_type> expression;
|
||||
qi::rule<Iterator, ExpressionGrammarTypes::Node(), ascii::space_type> node;
|
||||
qi::rule<Iterator, ExpressionGrammarTypes::Constant(), ascii::space_type> constant;
|
||||
qi::rule<Iterator, ExpressionGrammarTypes::Name(), ascii::space_type> name;
|
||||
qi::rule<Iterator, ExpressionGrammarTypes::Function(), ascii::space_type> function;
|
||||
qi::rule<Iterator, ExpressionGrammarTypes::NumberConstant(), ascii::space_type> number;
|
||||
qi::rule<Iterator, ExpressionGrammarTypes::StringConstant(), ascii::space_type> string;
|
||||
qi::rule<Iterator, ExpressionGrammarTypes::NullConstant(), ascii::space_type> null;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
100
dbms/src/Parsers/tests/expression.cpp
Normal file
100
dbms/src/Parsers/tests/expression.cpp
Normal file
@ -0,0 +1,100 @@
|
||||
#include <iostream>
|
||||
#include <ostream>
|
||||
|
||||
#include <boost/variant/static_visitor.hpp>
|
||||
#include <boost/variant/apply_visitor.hpp>
|
||||
|
||||
#include <DB/Parsers/ExpressionGrammar.h>
|
||||
|
||||
|
||||
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<iterator_t> 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user