1
0
mirror of https://github.com/mariadb-corporation/mariadb-columnstore-engine.git synced 2025-04-18 21:44:02 +03:00
2023-03-02 15:59:42 +00:00

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