mirror of
https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
synced 2025-04-18 21:44:02 +03:00
657 lines
15 KiB
C++
657 lines
15 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 */
|
|
|
|
#pragma once
|
|
|
|
#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);
|
|
}
|
|
}
|
|
} // namespace detail
|
|
|
|
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
|
|
{
|
|
return std::copy(first, last, start());
|
|
}
|
|
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
|
|
} // namespace expression
|