// Copyright (c) 2017-2018 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ #include #include #include #include #include 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; }