// Copyright (c) 2017-2018 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
// This is a small experiment with a grammar that can recover from errors.
//
// Triggered by https://github.com/taocpp/PEGTL/issues/55
//
// The grammar will recognise simple expressions terminated by semicolons.
// When an expression fails to parse, it skips to the next expression
// by looking for the terminator.
//
// Try: build/src/example/pegtl/recover '1+2*3;1+2*(3-)-4;-5;6/;7*(8+9)'
#include <iostream>
#include <string>
#include <tao/pegtl.hpp>
using namespace tao::TAO_PEGTL_NAMESPACE; // NOLINT
// clang-format off
template< typename T >
struct skipping : until< T > {};
template< typename R, typename T >
struct recoverable : sor< try_catch< must< R >, T >, skipping< T > > {};
struct expr_sum;
struct expr_identifier : identifier {};
struct expr_number : plus< digit > {};
struct expr_braced : if_must< one< '(' >, pad< expr_sum, space >, one< ')' > > {};
struct expr_value : sor< expr_identifier, expr_number, expr_braced > {};
struct expr_power : list< must< expr_value >, one< '^' >, space > {};
struct expr_prod : list_must< expr_power, one< '*', '/', '%' >, space > {};
struct expr_sum : list_must< expr_prod, one< '+', '-' >, space > {};
struct term : sor< one< ';' >, eof > {};
struct expr : pad< expr_sum, space > {};
struct recoverable_expr : recoverable< expr, term > {};
struct my_grammar : star< not_at< eof >, recoverable_expr > {};
// clang-format on
template< typename Rule >
struct my_action
: nothing< Rule >
{
};
template< typename T >
struct my_action< skipping< T > >
{
template< typename Input >
static void apply( const Input& in, bool& error )
{
if( !error ) {
std::cout << in.position() << ": Invalid expression \"" << in.string() << "\"" << std::endl;
}
error = true;
}
};
template< typename R >
struct found
{
template< typename Input >
static void apply( const Input& in, bool& error )
{
if( !error ) {
std::cout << in.position() << ": Found " << internal::demangle< R >() << ": \"" << in.string() << "\"" << std::endl;
}
}
};
// clang-format off
// template<> struct my_action< expr_identifier > : found< expr_identifier > {};
// template<> struct my_action< expr_number > : found< expr_number > {};
// template<> struct my_action< expr_braced > : found< expr_braced > {};
// template<> struct my_action< expr_value > : found< expr_value > {};
// template<> struct my_action< expr_power > : found< expr_power > {};
// template<> struct my_action< expr_prod > : found< expr_prod > {};
// template<> struct my_action< expr_sum > : found< expr_sum > {};
template<> struct my_action< expr > : found< expr > {};
// clang-format on
template<>
struct my_action< recoverable_expr >
{
template< typename Input >
static void apply( const Input& /*unused*/, bool& error )
{
error = false;
std::cout << std::string( 79, '-' ) << std::endl;
}
};
template< typename Rule >
struct my_control
: normal< Rule >
{
template< typename Input, typename... States >
static void raise( const Input& in, States&&... /*unused*/ )
{
std::cout << in.position() << ": Parse error matching " << internal::demangle< Rule >() << std::endl;
throw parse_error( "parse error matching " + internal::demangle< Rule >(), in );
}
};
int main( int argc, char** argv )
{
for( int i = 1; i < argc; ++i ) {
argv_input<> in( argv, i );
bool error = false;
parse< my_grammar, my_action, my_control >( in, error );
}
return 0;
}