// Copyright (c) 2017-2018 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
#include <iostream>
#include <string>
#include <type_traits>
#include <tao/pegtl.hpp>
#include <tao/pegtl/contrib/parse_tree.hpp>
using namespace tao::TAO_PEGTL_NAMESPACE; // NOLINT
namespace example
{
// the grammar
// clang-format off
struct integer : plus< digit > {};
struct variable : identifier {};
struct plus : pad< one< '+' >, space > {};
struct minus : pad< one< '-' >, space > {};
struct multiply : pad< one< '*' >, space > {};
struct divide : pad< one< '/' >, space > {};
struct open_bracket : seq< one< '(' >, star< space > > {};
struct close_bracket : seq< star< space >, one< ')' > > {};
struct expression;
struct bracketed : if_must< open_bracket, expression, close_bracket > {};
struct value : sor< integer, variable, bracketed >{};
struct product : list_must< value, sor< multiply, divide > > {};
struct expression : list_must< product, sor< plus, minus > > {};
struct grammar : seq< expression, eof > {};
// clang-format on
// select which rules in the grammar will produce parse tree nodes:
// clang-format off
// by default, nodes are not generated/stored
template< typename > struct store : std::false_type {};
// select which rules in the grammar will produce parse tree nodes:
template<> struct store< integer > : std::true_type {};
template<> struct store< variable > : std::true_type {};
template<> struct store< plus > : parse_tree::remove_content {};
template<> struct store< minus > : parse_tree::remove_content {};
template<> struct store< multiply > : parse_tree::remove_content {};
template<> struct store< divide > : parse_tree::remove_content {};
// clang-format on
// after a node is stored successfully, you can add an optional transformer like this:
struct rearrange : std::true_type
{
// recursively rearrange nodes. the basic principle is:
//
// from: PROD/EXPR
// / | \ (LHS... may be one or more children, followed by OP,)
// LHS... OP RHS (which is one operator, and RHS, which is a single child)
//
// to: OP
// / \ (OP now has two children, the original PROD/EXPR and RHS)
// PROD/EXPR RHS (Note that PROD/EXPR has two fewer children now)
// |
// LHS...
//
// if only one child is left for LHS..., replace the PROD/EXPR with the child directly.
// otherwise, perform the above transformation, then apply it recursively until LHS...
// becomes a single child, which then replaces the parent node and the recursion ends.
static void transform( std::unique_ptr< parse_tree::node >& n )
{
if( n->children.size() == 1 ) {
n = std::move( n->children.back() );
}
else {
auto& c = n->children;
auto r = std::move( c.back() );
c.pop_back();
auto o = std::move( c.back() );
c.pop_back();
o->children.emplace_back( std::move( n ) );
o->children.emplace_back( std::move( r ) );
n = std::move( o );
transform( n->children.front() );
}
}
};
// clang-format off
template<> struct store< product > : rearrange {};
template<> struct store< expression > : rearrange {};
// clang-format on
// debugging/show result:
void print_node( const parse_tree::node& n, const std::string& s = "" )
{
// detect the root node:
if( n.is_root() ) {
std::cout << "ROOT" << std::endl;
}
else {
if( n.has_content() ) {
std::cout << s << n.name() << " \"" << n.content() << "\" at " << n.begin() << " to " << n.end() << std::endl;
}
else {
std::cout << s << n.name() << " at " << n.begin() << std::endl;
}
}
// print all child nodes
if( !n.children.empty() ) {
const auto s2 = s + " ";
for( auto& up : n.children ) {
print_node( *up, s2 );
}
}
}
} // namespace example
int main( int argc, char** argv )
{
for( int i = 1; i < argc; ++i ) {
try {
argv_input<> in( argv, i );
if( const auto root = parse_tree::parse< example::grammar, example::store >( in ) ) {
example::print_node( *root );
}
else {
std::cout << "PARSE FAILED" << std::endl;
}
}
catch( const std::exception& e ) {
std::cout << "PARSE FAILED WITH EXCEPTION: " << e.what() << std::endl;
}
}
return 0;
}