dbms: development.

This commit is contained in:
Alexey Milovidov 2010-03-17 20:03:06 +00:00
parent 2c644482db
commit c788fd5bcc
2 changed files with 223 additions and 0 deletions

View 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

View 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;
}