[Spirit-devel] id node preserving ast2_parse

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

[Spirit-devel] id node preserving ast2_parse

Dan Nuffer-2
I'm not sure if this is the direction you want to go, but this should be
an improvement over the current state of my neglected ast code :-/

Here is a patch to ast.hpp which adds a set of functions ast2_parse()
which have the same effect as the #define
BOOST_SPIRIT_NO_TREE_NODE_COLLAPSING.
I also added an example to test it out with.

A patch for the html docs shouldn't take too long...

--- ast.hpp.orig 2005-09-27 21:16:27.131212815 -0600
+++ ast.hpp 2005-09-27 21:34:47.264785741 -0600
@@ -15,7 +15,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 namespace boost { namespace spirit {
 
-template <typename MatchPolicyT, typename NodeFactoryT>
+template <typename MatchPolicyT, typename NodeFactoryT, bool CollapseIDNodes = true>
 struct ast_tree_policy;
 
 //////////////////////////////////
@@ -33,13 +33,34 @@
         ast_tree_policy<
             ast_match_policy<IteratorT, NodeFactoryT>,
             NodeFactoryT
+#if defined(BOOST_SPIRIT_NO_TREE_NODE_COLLAPSING)
+ , false
+#endif
+        >
+    >
+{
+};
+
+template <
+    typename IteratorT,
+    typename NodeFactoryT = node_val_data_factory<nil_t>
+>
+struct ast2_match_policy :
+    public common_tree_match_policy<
+        ast_match_policy<IteratorT, NodeFactoryT>,
+        IteratorT,
+        NodeFactoryT,
+        ast_tree_policy<
+            ast_match_policy<IteratorT, NodeFactoryT>,
+            NodeFactoryT,
+            false
         >
     >
 {
 };
 
 //////////////////////////////////
-template <typename MatchPolicyT, typename NodeFactoryT>
+template <typename MatchPolicyT, typename NodeFactoryT, bool CollapseIDNodes>
 struct ast_tree_policy :
     public common_tree_tree_policy<MatchPolicyT, NodeFactoryT>
 {
@@ -116,10 +137,8 @@
         typedef typename container_t::iterator cont_iterator_t;
         typedef typename NodeFactoryT::template factory<iterator_t> factory_t;
 
-        if (m.trees.size() == 1
-#ifdef BOOST_SPIRIT_NO_TREE_NODE_COLLAPSING
-            && !(id.to_long() && m.trees.begin()->value.id().to_long())
-#endif
+        if ((CollapseIDNodes && m.trees.size() == 1)
+            || (!CollapseIDNodes && m.trees.size() == 1 && !(id.to_long() && m.trees.begin()->value.id().to_long()))
             )
         {
             // set rule_id's.  There may have been multiple nodes created.
@@ -346,6 +365,97 @@
     return ast_parse(str, last, parser);
 }
 
+//////////////////////////////////
+template <
+    typename AstFactoryT, typename IteratorT, typename ParserT,
+    typename SkipT
+>
+inline tree_parse_info<IteratorT, AstFactoryT>
+ast2_parse(
+    IteratorT const&        first_,
+    IteratorT const&        last_,
+    parser<ParserT> const&  parser,
+    SkipT const&            skip_,
+    AstFactoryT const &   /*dummy_*/ = AstFactoryT())
+{
+    typedef skip_parser_iteration_policy<SkipT> iter_policy_t;
+    typedef ast2_match_policy<IteratorT, AstFactoryT> ast_match_policy_t;
+    typedef
+        scanner_policies<iter_policy_t, ast_match_policy_t>
+        scanner_policies_t;
+    typedef scanner<IteratorT, scanner_policies_t> scanner_t;
+
+    iter_policy_t iter_policy(skip_);
+    scanner_policies_t policies(iter_policy);
+    IteratorT first = first_;
+    scanner_t scan(first, last_, policies);
+    tree_match<IteratorT, AstFactoryT> hit = parser.derived().parse(scan);
+    scan.skip(scan);
+    return tree_parse_info<IteratorT, AstFactoryT>(
+        first, hit, hit && (first == last_), hit.length(), hit.trees);
+}
+
+//////////////////////////////////
+template <typename IteratorT, typename ParserT, typename SkipT>
+inline tree_parse_info<IteratorT>
+ast2_parse(
+    IteratorT const&        first_,
+    IteratorT const&        last_,
+    parser<ParserT> const&  parser,
+    SkipT const&            skip_)
+{
+    typedef node_val_data_factory<nil_t> default_factory_t;
+    return ast2_parse(first_, last_, parser, skip_, default_factory_t());
+}
+  
+//////////////////////////////////
+template <typename IteratorT, typename ParserT>
+inline tree_parse_info<IteratorT>
+ast2_parse(
+    IteratorT const&        first_,
+    IteratorT const&        last,
+    parser<ParserT> const&  parser)
+{
+    typedef ast2_match_policy<IteratorT> ast_match_policy_t;
+    IteratorT first = first_;
+    scanner<
+        IteratorT,
+        scanner_policies<iteration_policy, ast_match_policy_t>
+    > scan(first, last);
+    tree_match<IteratorT> hit = parser.derived().parse(scan);
+    return tree_parse_info<IteratorT>(
+        first, hit, hit && (first == last), hit.length(), hit.trees);
+}
+
+//////////////////////////////////
+template <typename CharT, typename ParserT, typename SkipT>
+inline tree_parse_info<CharT const*>
+ast2_parse(
+    CharT const*            str,
+    parser<ParserT> const&  parser,
+    SkipT const&            skip)
+{
+    CharT const* last = str;
+    while (*last)
+        last++;
+    return ast2_parse(str, last, parser, skip);
+}
+
+//////////////////////////////////
+template <typename CharT, typename ParserT>
+inline tree_parse_info<CharT const*>
+ast2_parse(
+    CharT const*            str,
+    parser<ParserT> const&  parser)
+{
+    CharT const* last = str;
+    while (*last)
+    {
+        last++;
+    }
+    return ast2_parse(str, last, parser);
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 }} // namespace boost::spirit
 

/*=============================================================================
    Copyright (c) 2001-2003 Daniel Nuffer
    http://spirit.sourceforge.net/

    Use, modification and distribution is subject to the Boost Software
    License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
    http://www.boost.org/LICENSE_1_0.txt)
=============================================================================*/
///////////////////////////////////////////////////////////////////////////////
//
//  Demonstrates the ASTs. This is discussed in the
//  "Trees" chapter in the Spirit User's Guide.
//
///////////////////////////////////////////////////////////////////////////////
#define BOOST_SPIRIT_DUMP_PARSETREE_AS_XML

#include <boost/spirit/core.hpp>
#include <boost/spirit/tree/ast.hpp>
#include <boost/spirit/tree/tree_to_xml.hpp>
#include "tree_calc_grammar.hpp"

#include <iostream>
#include <stack>
#include <functional>
#include <string>
#include <cassert>

#if defined(BOOST_SPIRIT_DUMP_PARSETREE_AS_XML)
#include <map>
#endif

// This example shows how to use an AST.
////////////////////////////////////////////////////////////////////////////
using namespace std;
using namespace boost::spirit;

typedef char const*         iterator_t;
typedef tree_match<iterator_t> parse_tree_match_t;
typedef parse_tree_match_t::tree_iterator iter_t;

////////////////////////////////////////////////////////////////////////////
long evaluate(parse_tree_match_t hit);
long eval_expression(iter_t const& i);

////////////////////////////////////////////////////////////////////////////
int
main()
{
    // look in tree_calc_grammar for the definition of calculator
    calculator calc;

    cout << "/////////////////////////////////////////////////////////\n\n";
    cout << "\t\tThe simplest working calculator...\n\n";
    cout << "/////////////////////////////////////////////////////////\n\n";
    cout << "Type an expression...or [q or Q] to quit\n\n";

    string str;
    while (getline(cin, str))
    {
        if (str.empty() || str[0] == 'q' || str[0] == 'Q')
            break;

        tree_parse_info<> info = ast2_parse(str.c_str(), calc);

        if (info.full)
        {
#if defined(BOOST_SPIRIT_DUMP_PARSETREE_AS_XML)
            // dump parse tree as XML
            std::map<parser_id, std::string> rule_names;
            rule_names[calculator::integerID] = "integer";
            rule_names[calculator::factorID] = "factor";
            rule_names[calculator::termID] = "term";
            rule_names[calculator::expressionID] = "expression";
            tree_to_xml(cout, info.trees, str.c_str(), rule_names);
#endif

            // print the result
            cout << "parsing succeeded\n";
        }
        else
        {
            cout << "parsing failed\n";
        }
    }

    cout << "Bye... :-) \n\n";
    return 0;
}