1 // class template regex -*- C++ -*-
 
    3 // Copyright (C) 2013-2014 Free Software Foundation, Inc.
 
    5 // This file is part of the GNU ISO C++ Library.  This library is free
 
    6 // software; you can redistribute it and/or modify it under the
 
    7 // terms of the GNU General Public License as published by the
 
    8 // Free Software Foundation; either version 3, or (at your option)
 
   11 // This library is distributed in the hope that it will be useful,
 
   12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
 
   13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
   14 // GNU General Public License for more details.
 
   16 // Under Section 7 of GPL version 3, you are granted additional
 
   17 // permissions described in the GCC Runtime Library Exception, version
 
   18 // 3.1, as published by the Free Software Foundation.
 
   20 // You should have received a copy of the GNU General Public License and
 
   21 // a copy of the GCC Runtime Library Exception along with this program;
 
   22 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 
   23 // <http://www.gnu.org/licenses/>.
 
   26  *  @file bits/regex_automaton.tcc
 
   27  *  This is an internal header file, included by other library headers.
 
   28  *  Do not attempt to use it directly. @headername{regex}
 
   31 namespace std _GLIBCXX_VISIBILITY(default)
 
   35 _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   39   _State_base::_M_print(std::ostream& ostr) const
 
   43       case _S_opcode_alternative:
 
   44    ostr << "alt next=" << _M_next << " alt=" << _M_alt;
 
   46       case _S_opcode_subexpr_begin:
 
   47    ostr << "subexpr begin next=" << _M_next << " index=" << _M_subexpr;
 
   49       case _S_opcode_subexpr_end:
 
   50    ostr << "subexpr end next=" << _M_next << " index=" << _M_subexpr;
 
   52       case _S_opcode_backref:
 
   53    ostr << "backref next=" << _M_next << " index=" << _M_backref_index;
 
   56    ostr << "match next=" << _M_next;
 
   58       case _S_opcode_accept:
 
   59    ostr << "accept next=" << _M_next;
 
   62    ostr << "unknown next=" << _M_next;
 
   68   // Prints graphviz dot commands for state.
 
   70   _State_base::_M_dot(std::ostream& __ostr, _StateIdT __id) const
 
   74       case _S_opcode_alternative:
 
   75    __ostr << __id << " [label=\"" << __id << "\\nALT\"];\n"
 
   76           << __id << " -> " << _M_next
 
   77           << " [label=\"epsilon\", tailport=\"s\"];\n"
 
   78           << __id << " -> " << _M_alt
 
   79           << " [label=\"epsilon\", tailport=\"n\"];\n";
 
   81       case _S_opcode_backref:
 
   82    __ostr << __id << " [label=\"" << __id << "\\nBACKREF "
 
   83           << _M_subexpr << "\"];\n"
 
   84           << __id << " -> " << _M_next << " [label=\"<match>\"];\n";
 
   86       case _S_opcode_line_begin_assertion:
 
   87    __ostr << __id << " [label=\"" << __id << "\\nLINE_BEGIN \"];\n"
 
   88           << __id << " -> " << _M_next << " [label=\"epsilon\"];\n";
 
   90       case _S_opcode_line_end_assertion:
 
   91    __ostr << __id << " [label=\"" << __id << "\\nLINE_END \"];\n"
 
   92           << __id << " -> " << _M_next << " [label=\"epsilon\"];\n";
 
   94       case _S_opcode_word_boundary:
 
   95    __ostr << __id << " [label=\"" << __id << "\\nWORD_BOUNDRY "
 
   97           << __id << " -> " << _M_next << " [label=\"epsilon\"];\n";
 
   99       case _S_opcode_subexpr_lookahead:
 
  100    __ostr << __id << " [label=\"" << __id << "\\nLOOK_AHEAD\"];\n"
 
  101           << __id << " -> " << _M_next
 
  102           << " [label=\"epsilon\", tailport=\"s\"];\n"
 
  103           << __id << " -> " << _M_alt
 
  104           << " [label=\"<assert>\", tailport=\"n\"];\n";
 
  106       case _S_opcode_subexpr_begin:
 
  107    __ostr << __id << " [label=\"" << __id << "\\nSBEGIN "
 
  108           << _M_subexpr << "\"];\n"
 
  109           << __id << " -> " << _M_next << " [label=\"epsilon\"];\n";
 
  111       case _S_opcode_subexpr_end:
 
  112    __ostr << __id << " [label=\"" << __id << "\\nSEND "
 
  113           << _M_subexpr << "\"];\n"
 
  114           << __id << " -> " << _M_next << " [label=\"epsilon\"];\n";
 
  116       case _S_opcode_dummy:
 
  118       case _S_opcode_match:
 
  119    __ostr << __id << " [label=\"" << __id << "\\nMATCH\"];\n"
 
  120           << __id << " -> " << _M_next << " [label=\"<match>\"];\n";
 
  122       case _S_opcode_accept:
 
  123    __ostr << __id << " [label=\"" << __id << "\\nACC\"];\n" ;
 
  126    _GLIBCXX_DEBUG_ASSERT(false);
 
  132   template<typename _TraitsT>
 
  134     _NFA<_TraitsT>::_M_dot(std::ostream& __ostr) const
 
  136       __ostr << "digraph _Nfa {\n"
 
  138       for (size_t __i = 0; __i < this->size(); ++__i)
 
  139    (*this)[__i]._M_dot(__ostr, __i);
 
  145   template<typename _TraitsT>
 
  147     _NFA<_TraitsT>::_M_insert_backref(size_t __index)
 
  149       // To figure out whether a backref is valid, a stack is used to store
 
  150       // unfinished sub-expressions. For example, when parsing
 
  151       // "(a(b)(c\\1(d)))" at '\\1', _M_subexpr_count is 3, indicating that 3
 
  152       // sub expressions are parsed or partially parsed(in the stack), aka,
 
  153       // "(a..", "(b)" and "(c..").
 
  154       // _M_paren_stack is {1, 3}, for incomplete "(a.." and "(c..". At this
 
  155       // time, "\\2" is valid, but "\\1" and "\\3" are not.
 
  156       if (__index >= _M_subexpr_count)
 
  157    __throw_regex_error(regex_constants::error_backref);
 
  158       for (auto __it : this->_M_paren_stack)
 
  160      __throw_regex_error(regex_constants::error_backref);
 
  161       this->_M_has_backref = true;
 
  162       _StateT __tmp(_S_opcode_backref);
 
  163       __tmp._M_backref_index = __index;
 
  164       return _M_insert_state(std::move(__tmp));
 
  167   template<typename _TraitsT>
 
  169     _NFA<_TraitsT>::_M_eliminate_dummy()
 
  171       for (auto& __it : *this)
 
  173      while (__it._M_next >= 0 && (*this)[__it._M_next]._M_opcode
 
  175        __it._M_next = (*this)[__it._M_next]._M_next;
 
  176      if (__it._M_opcode == _S_opcode_alternative
 
  177          || __it._M_opcode == _S_opcode_subexpr_lookahead)
 
  178        while (__it._M_alt >= 0 && (*this)[__it._M_alt]._M_opcode
 
  180          __it._M_alt = (*this)[__it._M_alt]._M_next;
 
  184   // Just apply DFS on the sequence and re-link their links.
 
  185   template<typename _TraitsT>
 
  187     _StateSeq<_TraitsT>::_M_clone()
 
  189       std::vector<_StateIdT> __m(_M_nfa.size(), -1);
 
  190       std::stack<_StateIdT> __stack;
 
  191       __stack.push(_M_start);
 
  192       while (!__stack.empty())
 
  194      auto __u = __stack.top();
 
  196      auto __dup = _M_nfa[__u];
 
  197      // _M_insert_state() never return -1
 
  198      auto __id = _M_nfa._M_insert_state(__dup);
 
  200      if (__dup._M_opcode == _S_opcode_alternative
 
  201          || __dup._M_opcode == _S_opcode_subexpr_lookahead)
 
  202        if (__dup._M_alt != _S_invalid_state_id && __m[__dup._M_alt] == -1)
 
  203          __stack.push(__dup._M_alt);
 
  206      if (__dup._M_next != _S_invalid_state_id && __m[__dup._M_next] == -1)
 
  207        __stack.push(__dup._M_next);
 
  213      auto& __ref = _M_nfa[__v];
 
  214      if (__ref._M_next != _S_invalid_state_id)
 
  216          _GLIBCXX_DEBUG_ASSERT(__m[__ref._M_next] != -1);
 
  217          __ref._M_next = __m[__ref._M_next];
 
  219      if (__ref._M_opcode == _S_opcode_alternative
 
  220          || __ref._M_opcode == _S_opcode_subexpr_lookahead)
 
  221        if (__ref._M_alt != _S_invalid_state_id)
 
  223        _GLIBCXX_DEBUG_ASSERT(__m[__ref._M_alt] != -1);
 
  224        __ref._M_alt = __m[__ref._M_alt];
 
  227       return _StateSeq(_M_nfa, __m[_M_start], __m[_M_end]);
 
  230 _GLIBCXX_END_NAMESPACE_VERSION
 
  231 } // namespace __detail