Boost logo

Boost Users :

Subject: [Boost-users] [Spirit.Qi] How do I get Rule Name/Id through Semantic Action / Phoenix variable
From: HT4N - (ht4n_at_[hidden])
Date: 2009-11-22 06:54:08


 
I want to create a generic Parse Tree from a simple expression grammar (see below code snippet). Using the Mini_XML as the reference, I was able to create a Parse Tree close to what I want.
 
If I run my simple program and parse an expressions "[foo=1 bar=2]", for example, it will printout the following Parse Tree:
 
[foo=1 bar=2]
-------------------------
Parsing succeeded
<nonterminal>
{
    <nonterminal>
    {
        <value_str>foo</value_str>
        <value_int>1</value_int>
    }
    <nonterminal>
    {
        <value_str>bar</value_str>
        <value_int>2</value_int>
    }
}
 
The next thing I want to achieve is to have the Parse Tree looks very similar to the one produced in Spirit.Classic. In Spirit.Classic for each node it has RuleId for which we associate it with a RuleName so that when we are iterating the node of the Parse Tree we can printout the RuleName. In other words, instead I want the above Parse Tree to look like the following :
 
<Option>
    <Expression>
        <ParameterName>foo</ParameterName>
        <ParameterValue>1</ParameterValue>
    </Expression>
    <Expression>
        <ParameterName>bar</ParameterName>
        <ParameterValue>2</ParameterValue>
    </Expression>
</Option>
 
In other words, what I need to know is how I can get the Rule Name/Id through semantic actions/phoenix variable. Any pointer is appreciated.
 
Thanks again.
 
HT
 
 
Code Snippet:
namespace client
{
    struct ptnode;
    typedef boost::variant<
        nil,
        unsigned int,
        string,
        boost::recursive_wrapper<ptnode>
> ptnode_var;
    ///////////////////////////////////////////////////////////////////////////
    // Our AST
    ///////////////////////////////////////////////////////////////////////////
    struct ptnode
    {
        ptnode()
            : data(nil())
        {
        }
        template<typename T>
        ptnode(const T& data)
            : data(data)
        {
        }
        ptnode_var data;
        vector<ptnode_var> children;
    };
}
// We need to tell fusion about our mini_xml struct
// to make it a first-class fusion citizen
//[tutorial_xml1_adapt_structures
BOOST_FUSION_ADAPT_STRUCT(
                          client::ptnode,
                          (client::ptnode_var, data)
                          (std::vector<client::ptnode_var>, children)
                          )
                          //]
namespace client
{
    template <typename Iterator>
    struct ExpressionGrammar : qi::grammar<Iterator, ptnode(), ascii::space_type>
    {
        ExpressionGrammar() : ExpressionGrammar::base_type(Option)
        {
            using qi::_val;
            using qi::_1;
            using qi::char_;
            using qi::alnum;
            using qi::alpha;
            using qi::lexeme;
            using qi::raw;
            using qi::uint_;
            using phoenix::at_c;
            using phoenix::push_back;
            Option = char_('[')
>> *Expression [push_back(at_c<1>(_val), _1)]
>> char_(']');
            Expression = ParameterName [push_back(at_c<1>(_val), _1)]
>> (char_('=')>> ParameterValue [push_back(at_c<1>(_val), _1)]);
            ParameterName = lexeme[+(alnum) [_val += _1]];
            ParameterValue = uint_ [_val = _1];
            Option.name("Option");
            Expression.name("Expression");
            ParameterName.name("ParameterName");
            ParameterValue.name("ParameterValue");
        }
        qi::rule<Iterator, ptnode(), ascii::space_type> Option;
        qi::rule<Iterator, ptnode(), ascii::space_type> Expression;
        qi::rule<Iterator, string(), ascii::space_type> ParameterName;
        qi::rule<Iterator, int(), ascii::space_type> ParameterValue;
    };
 
    ///////////////////////////////////////////////////////////////////////////
    // Print out the mini xml tree
    ///////////////////////////////////////////////////////////////////////////
    int const tabsize = 4;
    void tab(int indent)
    {
        for (int i = 0; i < indent; ++i)
        {
            printf_s(" ");
        }
    }
 
    struct ptnode_printer
    {
        ptnode_printer(int indent = 0)
            : indent(indent)
        {
        }
        void operator()(ptnode const& node) const;
        int indent;
    };
 
    struct ptnode_var_printer : boost::static_visitor<>
    {
        ptnode_var_printer(int indent = 0)
            : indent(indent)
        {
        }
 
        void operator()(const ptnode& var) const
        {
            ptnode_printer(indent+tabsize)(var);
        }
 
        void operator()(const nil&) const
        {
            // Print node type ...
            tab(indent);
            printf_s("<nonterminal>\n");
        }
 
        void operator()(const string& val) const
        {
            tab(indent+tabsize);
            printf_s("<value_str>%s</value_str>\n", val.c_str());
        }
 
        void operator()(const int& val) const
        {
            tab(indent+tabsize);
            printf_s("<value_int>%d</value_int>\n", val);
        }
 
        int indent;
    };
 
    void ptnode_printer::operator()(const ptnode& node) const
    {
        boost::apply_visitor(ptnode_var_printer(indent), node.data);
        tab(indent);
        printf_s("{\n");
        BOOST_FOREACH(const ptnode_var& child, node.children)
        {
            boost::apply_visitor(ptnode_var_printer(indent), child);
        }
        tab(indent);
        printf_s("}\n");
    }
}
                                                
_________________________________________________________________
Windows 7: I wanted simpler, now it's simpler. I'm a rock star.
http://www.microsoft.com/Windows/windows-7/default.aspx?h=myidea?ocid=PID24727::T:WLMTAGL:ON:WL:en-US:WWL_WIN_myidea:112009


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net