eedb/share/include/tao/json/external/pegtl/analysis/analyze_cycles.hh
2017-02-26 09:32:45 +01:00

130 lines
4.0 KiB
C++

// Copyright (c) 2014-2016 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/ColinH/PEGTL/
#ifndef TAO_CPP_PEGTL_ANALYSIS_ANALYZE_CYCLES_HH
#define TAO_CPP_PEGTL_ANALYSIS_ANALYZE_CYCLES_HH
#include <cassert>
#include <map>
#include <set>
#include <utility>
#include <iostream>
#include "grammar_info.hh"
#include "insert_guard.hh"
namespace tao_json_pegtl
{
namespace analysis
{
class analyze_cycles_impl
{
protected:
explicit
analyze_cycles_impl( const bool verbose )
: m_verbose( verbose ),
m_problems( 0 )
{ }
const bool m_verbose;
unsigned m_problems;
grammar_info m_info;
std::set< std::string > m_stack;
std::map< std::string, bool > m_cache;
std::map< std::string, bool > m_results;
const std::map< std::string, rule_info >::const_iterator find( const std::string & name ) const
{
const auto iter = m_info.map.find( name );
assert( iter != m_info.map.end() );
return iter;
}
bool work( const std::map< std::string, rule_info >::const_iterator & start, const bool accum )
{
const auto j = m_cache.find( start->first );
if ( j != m_cache.end() ) {
return j->second;
}
if ( const auto g = make_insert_guard( m_stack, start->first ) ) {
switch ( start->second.type ) {
case rule_type::ANY: {
bool a = false;
for ( const auto & r : start->second.rules ) {
a = a || work( find( r ), accum || a );
}
return m_cache[ start->first ] = true;
}
case rule_type::OPT: {
bool a = false;
for ( const auto & r : start->second.rules ) {
a = a || work( find( r ), accum || a );
}
return m_cache[ start->first ] = false;
}
case rule_type::SEQ: {
bool a = false;
for ( const auto & r : start->second.rules ) {
a = a || work( find( r ), accum || a );
}
return m_cache[ start->first ] = a;
}
case rule_type::SOR: {
bool a = true;
for ( const auto & r : start->second.rules ) {
a = a && work( find( r ), accum );
}
return m_cache[ start->first ] = a;
}
}
throw std::runtime_error( "code should be unreachable" ); // LCOV_EXCL_LINE
}
if ( ! accum ) {
++m_problems;
if ( m_verbose ) {
std::cout << "problem: cycle without progress detected at rule class " << start->first << std::endl;
}
}
return m_cache[ start->first ] = accum;
}
};
template< typename Grammar >
class analyze_cycles
: private analyze_cycles_impl
{
public:
explicit
analyze_cycles( const bool verbose )
: analyze_cycles_impl( verbose )
{
Grammar::analyze_t::template insert< Grammar >( m_info );
}
std::size_t problems()
{
for ( auto i = m_info.map.begin(); i != m_info.map.end(); ++i ) {
m_results[ i->first ] = work( i, false );
m_cache.clear();
}
return m_problems;
}
template< typename Rule >
bool consumes() const
{
const auto i = m_results.find( internal::demangle< Rule >() );
assert( i != m_results.end() );
return i->second;
}
};
} // namespace analysis
} // namespace tao_json_pegtl
#endif