1
0
mirror of https://github.com/mariadb-corporation/mariadb-columnstore-engine.git synced 2025-07-05 15:41:14 +03:00
Files
mariadb-columnstore-engine/dbcon/execplan/exp_templates.h
2017-10-26 17:18:17 +01:00

677 lines
18 KiB
C++

/* Copyright (C) 2014 InfiniDB, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; version 2 of
the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA. */
/***********************************************************************
* $Id: exp_templates.h 9210 2013-01-21 14:10:42Z rdempsey $
*
*
***********************************************************************/
/** @file */
#ifndef EXP_TEMPLATES
#define EXP_TEMPLATES
#include <iostream>
#include <fstream>
#include <stack>
#include <stdexcept>
#include <cassert>
#include <string>
#include <iterator>
//#include <parsetree.h>
namespace expression
{
enum precedence { none, lower, equal, higher };
struct not_an_acceptor_tag {};
struct acceptor_tag {};
struct accumulating_acceptor_tag {};
template<typename Acceptor>
struct acceptor_traits
{
typedef typename Acceptor::acceptor_category acceptor_category;
typedef typename Acceptor::input_symbol_type input_symbol_type;
typedef typename Acceptor::result_type result_type;
};
// Constants indicating possible operator placements. An incoming operator
// may be ambiguous so its position will be the bitwise or of several of
// these positions.
const int prefix = 0x01;
const int postfix = 0x02;
const int infix = 0x04;
const int open = 0x08;
const int close = 0x10;
const int function_open = 0x20;
const int function_close = close;
enum associativity { non_associative, left_associative, right_associative };
struct default_expression_parser_error_policy
{
template<typename Operand>
void invalid_operand_position(Operand)
{
std::cerr << "Invalid operand position\n";
}
template<typename Operator>
void invalid_operator_position(Operator)
{
std::cerr << "Invalid operator position\n";
}
template<typename Operator>
void requires_precedence_relation(Operator, Operator)
{
std::cerr << "Requires precedence relation\n";
}
template<typename Operator>
void requires_associativity_relation(Operator, Operator)
{
std::cerr << "Requires associativity relation\n";
}
template<typename Operator>
void ambiguity(Operator, Operator)
{
std::cerr << "Unresolvable ambiguity\n";
}
template<typename Operator>
void unbalanced_confix(Operator)
{
std::cerr << "Unbalanced confix operator\n";
}
template<typename Operator>
void missing_operand(Operator)
{
std::cerr << "Missing operand\n";
}
};
#define EXP_TEMPLATE \
template<typename Token , typename Operand, typename Operator, \
typename Policy, typename OperandStack, typename OperatorStack>
#define EXP_ACCEPTOR \
expression_acceptor<Token, Operand, Operator, Policy, OperandStack, \
OperatorStack>
namespace detail
{
enum action {shift, reduce, prec, prec_assoc, invalid};
// Current larser state
enum state { accepting, rejected, pre_operand, post_operand, lookahead };
// The operator placements that are allowed for each state
const int pre_positions = prefix | open;
const int post_positions = postfix | close | infix | function_open;
const action parse_action[6][6] =
{
/* prefix postfix infix open close func open */
/* prefix */ { shift, prec, prec, shift, reduce, prec },
/* postfix */ { invalid, reduce, reduce, reduce, reduce, reduce },
/* infix */ { shift, prec, prec_assoc, shift, reduce, prec },
/* open */ { shift, shift, shift, shift, shift, shift },
/* close */ { reduce, reduce, reduce, reduce, reduce, reduce },
/* func open */ { shift, shift, shift, shift, shift, shift }
};
template <
typename Token,
typename Operand,
typename Operator,
typename Policy,
typename OperandStack = std::stack<Operand>,
typename OperatorStack = std::stack<Operator>
>
class expression_acceptor
{
private:
class assignment_proxy
{
public:
explicit assignment_proxy(expression_acceptor* acceptor) :
m_expression_acceptor(acceptor) {}
assignment_proxy& operator=(const Token& t)
{
m_expression_acceptor->disambiguate_and_parse(t);
return *this;
}
private:
expression_acceptor* m_expression_acceptor;
};
friend class assignment_proxy;
public:
typedef accumulating_acceptor_tag acceptor_category;
typedef Token input_symbol_type;
typedef Operand result_type;
typedef std::output_iterator_tag iterator_category;
typedef Token value_type;
typedef Token& reference;
typedef Token* pointer;
typedef int difference_type;
explicit expression_acceptor(const Policy& policy,
OperandStack& operandStack,
OperatorStack& operatorStack) :
m_policy(policy),
m_operand_stack (operandStack),
m_operator_stack (operatorStack),
m_state(detail::pre_operand)
{
}
assignment_proxy operator*()
{
return assignment_proxy(this);
}
expression_acceptor& operator++()
{
return *this;
}
expression_acceptor& operator++(int)
{
return *this;
}
bool accepted();
bool trapped()
{
return m_state == rejected;
}
operator Operand()
{
return this->accepted() ? m_operand_stack.top() : Operand();
}
private:
void disambiguate_and_parse(const Token&);
int operator_type_index(int);
void parse_operator(const Operator&);
void do_reduce();
private:
Policy m_policy;
OperandStack& m_operand_stack; // changed to reference by Zhixuan Zhu
OperatorStack& m_operator_stack; // changed to reference by Zhixuan Zhu
state m_state;
Token m_ambiguous_operator;
};
EXP_TEMPLATE
bool EXP_ACCEPTOR::accepted()
{
if (m_state == accepting)
{
return true;
}
else if (m_state == rejected)
{
return false;
}
else if (m_state == lookahead)
{
m_state = post_operand;
int position = m_policy.positions(m_ambiguous_operator);
parse_operator(m_policy.as_operator(m_ambiguous_operator,
position & (postfix | close)));
}
while (!m_operator_stack.empty() && m_state != rejected)
{
do_reduce();
}
if (m_state == rejected)
{
return false;
}
else if (m_operand_stack.size() > 1 || !m_operator_stack.empty())
{
m_state = rejected;
return false;
}
else
{
m_state = accepting;
return true;
}
}
EXP_TEMPLATE
void EXP_ACCEPTOR::disambiguate_and_parse(const Token& t)
{
assert(m_state != accepting);
if (m_state == rejected)
return;
if (m_policy.is_operator(t))
{
int operator_positions = m_policy.positions(t);
if (m_state == lookahead)
{
bool could_be_pre = ((operator_positions & pre_positions) != 0);
bool could_be_post = ((operator_positions & post_positions) != 0);
int ambiguous_position = m_policy.positions(m_ambiguous_operator);
if ( (could_be_pre && could_be_post) ||
(!could_be_pre && !could_be_post) )
{
m_policy.ambiguity(m_ambiguous_operator, t);
m_state = rejected;
return;
}
else if (could_be_pre)
{
ambiguous_position &= (infix | function_open);
parse_operator(m_policy.as_operator(m_ambiguous_operator,
ambiguous_position));
m_state = pre_operand;
}
else
{
ambiguous_position &= (postfix | close);
parse_operator(m_policy.as_operator(m_ambiguous_operator,
ambiguous_position));
m_state = post_operand;
}
}
int valid_positions =
(m_state == pre_operand) ? pre_positions : post_positions;
int positions = operator_positions & valid_positions;
switch (positions)
{
case infix:
case function_open:
m_state = pre_operand;
// Fall through
case prefix:
case postfix:
case open:
case close:
parse_operator(m_policy.as_operator(t, positions));
break;
case postfix | infix:
case close | infix:
case postfix | function_open:
case function_open | function_close:
m_state = lookahead;
m_ambiguous_operator = t;
break;
default:
m_policy.invalid_operator_position(t);
m_state = rejected;
return;
}
}
else
{
if (m_state == lookahead)
{
int positions = m_policy.positions(m_ambiguous_operator);
positions &= (infix | function_open);
parse_operator(m_policy.as_operator(m_ambiguous_operator,
positions));
m_state = post_operand;
}
else if (m_state == post_operand)
{
m_policy.invalid_operand_position(m_policy.as_operand(t));
m_state = rejected;
return;
}
else
{
m_state = post_operand;
}
m_operand_stack.push(m_policy.as_operand(t));
}
}
EXP_TEMPLATE
inline int EXP_ACCEPTOR::operator_type_index(int position)
{
switch (position)
{
case prefix:
return 0;
case postfix:
return 1;
case infix:
return 2;
case open:
return 3;
case close:
return 4;
case function_open:
return 5;
}
assert(0);
return 0;
}
EXP_TEMPLATE
void EXP_ACCEPTOR::parse_operator(const Operator& cur_operator)
{
if (m_operator_stack.empty())
{
m_operator_stack.push(cur_operator);
}
else
{
int cur_index = operator_type_index(m_policy.position(cur_operator));
Operator& prev_operator = m_operator_stack.top();
int prev_index = operator_type_index(m_policy.position(prev_operator));
switch (parse_action[prev_index][cur_index])
{
case shift:
m_operator_stack.push(cur_operator);
break;
case reduce:
do_reduce();
parse_operator(cur_operator);
break;
case prec:
switch (m_policy.precedence(prev_operator, cur_operator))
{
case lower:
m_operator_stack.push(cur_operator);
break;
case higher:
do_reduce();
parse_operator(cur_operator);
break;
default:
m_policy.requires_precedence_relation(prev_operator, cur_operator);
m_state = rejected;
return;
}
break;
case prec_assoc:
switch (m_policy.precedence(prev_operator, cur_operator))
{
case lower:
m_operator_stack.push(cur_operator);
break;
case higher:
do_reduce();
parse_operator(cur_operator);
break;
case equal:
switch (m_policy.associativity(prev_operator, cur_operator))
{
case left_associative:
do_reduce();
parse_operator(cur_operator);
break;
case right_associative:
m_operator_stack.push(cur_operator);
break;
default:
m_policy.requires_associativity_relation(prev_operator,
cur_operator);
m_state = rejected;
return;
}
break;
default:
m_policy.requires_precedence_relation(prev_operator, cur_operator);
m_state = rejected;
return;
}
break;
case invalid:
m_policy.invalid_operator_position(cur_operator);
m_state = rejected;
return;
}
}
}
EXP_TEMPLATE
void EXP_ACCEPTOR::do_reduce()
{
Operator op = m_operator_stack.top();
m_operator_stack.pop();
switch (m_policy.position(op))
{
case prefix:
case postfix:
{
if (m_operand_stack.empty())
{
m_policy.missing_operand(op);
m_state = rejected;
return;
}
Operand operand = m_operand_stack.top();
m_operand_stack.pop();
m_operand_stack.push(m_policy.reduce(op, operand));
}
break;
case infix:
{
if (m_operand_stack.size() < 2)
{
m_policy.missing_operand(op);
m_state = rejected;
return;
}
Operand rhs = m_operand_stack.top();
m_operand_stack.pop();
Operand lhs = m_operand_stack.top();
m_operand_stack.pop();
m_operand_stack.push(m_policy.reduce(op, lhs, rhs));
}
break;
case open:
m_policy.unbalanced_confix(op);
m_state = rejected;
return;
case close:
if (m_operator_stack.empty())
{
m_policy.unbalanced_confix(op);
m_state = rejected;
return;
}
if (m_operand_stack.empty())
{
m_policy.missing_operand(op);
m_state = rejected;
return;
}
{
Operator open = m_operator_stack.top();
m_operator_stack.pop();
Operand operand = m_operand_stack.top();
m_operand_stack.pop();
if (m_policy.position(open) == function_open)
{
if (m_operand_stack.empty())
{
m_policy.missing_operand(open);
m_state = rejected;
return;
}
Operand function = m_operand_stack.top();
m_operand_stack.pop();
m_operand_stack.push(
m_policy.reduce(function, open, operand, op)
);
}
else
{
m_operand_stack.push(m_policy.reduce(open, op, operand));
}
}
return;
default:
assert(0);
}
}
}
EXP_TEMPLATE
inline bool accepted(const detail::EXP_ACCEPTOR& acceptor)
{
return acceptor.accepted();
}
EXP_TEMPLATE
inline bool trapped(const detail::EXP_ACCEPTOR& acceptor)
{
return acceptor.trapped();
}
template <
typename Token,
typename Operand,
typename Operator,
typename Policy,
typename OperandStack = std::stack<Operand>,
typename OperatorStack = std::stack<Operator>
>
class expression_parser
{
public:
typedef detail::EXP_ACCEPTOR acceptor;
typedef Token token_type;
typedef Operand operand_type;
typedef Operator operator_type;
typedef Policy policy_type;
typedef Token input_symbol_type;
typedef Operand result_type;
expression_parser() : m_policy() {}
explicit expression_parser(const Policy& policy) : m_policy(policy) {}
template<typename InputIterator>
Operand parse(InputIterator first, InputIterator last)
{
try
{
#if _MSC_VER > 1600
return std::_Copy_impl(first, last, start());
}
#else
return std::copy(first, last, start());
}
#endif
catch (const std::runtime_error&)
{
m_policy.cleanup(operandStack, operatorStack);
throw;
}
}
acceptor start()
{
// pass in operator and operand stacks to acceptor constructor.
// this is to chean up the pointers in the stack when exception
// is thrown. the exception is then passed to the upper level.
// changed by Zhixuan Zhu 07/03/06
try
{
return acceptor(m_policy, operandStack, operatorStack);
}
catch (const std::runtime_error&)
{
m_policy.cleanup(operandStack, operatorStack);
throw;
}
}
private:
Policy m_policy;
// added operand and operator stacks by Zhixuan Zhu
OperandStack operandStack;
OperatorStack operatorStack;
};
#undef EXP_ACCEPTOR
#undef EXP_TEMPLATE
}
#endif