2

I am interested in Boost Spirit nowadays and trying to build something. Can we implement something like a const in C++ using Spirit? For instance, user will define an item like;

constant var PROG_LANG="Java"; 

"constant var" seems weird, I accept but you got the idea. I searched the internet but can't found anything about it.

Barış Akkurt
  • 2,255
  • 3
  • 22
  • 37
  • You **do know** there's a `const` keyword in C++, right? –  Oct 28 '12 at 23:32
  • of course i know and how is this related to this question? How can i implement the constants in my small language? – Barış Akkurt Oct 28 '12 at 23:35
  • 1
    @userXXX Ah so you are asking about your own language! In this cass, just implement a check in the compiler which prohibits assignments to `const` values. –  Oct 29 '12 at 05:52

2 Answers2

3

What the BigBoss said :)

Only I'd do without the semantic actions - making it far less... verbose (See also Boost Spirit: "Semantic actions are evil"?):

vdef = 
    ("constant" >> attr(true) | attr(false)) >>
    "var" >> identifier >> '=' >> identifier_value >> ';' ;

That's all. This uses qi::attr to account for the default (missing constant keyword).

Here's a full demo with output:

http://liveworkspace.org/code/c9e4bef100d2249eb4d4b88205f85c4b

Output:

parse success: 'var myvariable = "has some value";'
data: false;myvariable;has some value;
parse success: 'constant var myvariable = "has some value";'
data: true;myvariable;has some value;

Code:

#include <boost/fusion/adapted.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>

namespace qi    = boost::spirit::qi;
namespace karma = boost::spirit::karma;
namespace phx   = boost::phoenix;

struct var_definition {
    bool is_constant;
    std::string name;
    std::string value;

    var_definition() : is_constant( false ) {}
};

BOOST_FUSION_ADAPT_STRUCT(var_definition, (bool, is_constant)(std::string, name)(std::string, value))


void doParse(const std::string& input)
{
    typedef std::string::const_iterator It;

    qi::rule<It, std::string()> identifier, identifier_value;
    qi::rule<It, var_definition(), qi::space_type> vdef;

    {
        using namespace qi;

        identifier_value = '"' >> lexeme [ +~char_('"') ] > '"';
        identifier       = lexeme [ +graph ];
        vdef             = 
            ("constant" >> attr(true) | attr(false)) >>
            "var" >> identifier >> '=' >> identifier_value >> ';' ;
    }

    var_definition data;

    It f(std::begin(input)), l(std::end(input));
    bool ok = qi::phrase_parse(f,l,vdef,qi::space,data);
    if (ok)   
    {
        std::cout << "parse success: '" << input << "'\n";
        std::cout << "data: " << karma::format_delimited(karma::auto_, ';', data) << "\n";
    }
}

int main()
{
    doParse("var myvariable = \"has some value\";");
    doParse("constant var myvariable = \"has some value\";");
}
Community
  • 1
  • 1
sehe
  • 374,641
  • 47
  • 450
  • 633
  • thanks for your reply, sehe. i will apply this after i arrive home and then accept your answer. you are answering my 2nd question in spirit. (i can't look at spirit because of assignments everyday) i wish i could vote 5 times up. thanks again. – Barış Akkurt Nov 01 '12 at 08:59
  • and how did you becoma a spirit expert? i read all the qi documentation and i am looking at examples but i am having hard times understanding examples? do you have any suggestions? – Barış Akkurt Nov 01 '12 at 09:01
  • @user1662800 I learned, basically, by reading the documentation _when I needed it_. And then I did a lot of exercises (basically, using Spirit for my every parsing need, even if it wasn't the best fit). I should admit I never paid any attention to the examples, so I don't know how 'hard' they are. – sehe Nov 01 '12 at 10:41
  • @sehe, a couple of questions if I may... 1) will the parser for identifier_value eat whitespace after the opening (and before the closing) quote? If that's undesirable then we just widen the lexeme[]? 2) What does that tilde '~' character do? I can't find documentation for it in the Spirit docs. – PeteUK Feb 13 '13 at 15:45
  • 1
    @PeteUK the whitespace will be properly included. If anything, the `lexeme` is redundant here, because the rules (`identifier`, `identifier_value`) are declared _without a skipper_. Good catch, in that respect. The documentation for `~` is here [Expression Semantics](http://www.boost.org/doc/libs/1_53_0/libs/spirit/doc/html/spirit/qi/reference/char/char.html#spirit.qi.reference.char.char.expression_semantics) – sehe Feb 13 '13 at 16:14
  • @sehe of course - the lack of skipper! Thank you for the expression semantics link. I understand the ~ now. – PeteUK Feb 13 '13 at 18:22
1

I don't get your question correctly, spirit is a parser and it has nothing to do with the meaning of constant it can only parse it, but if you mean parse an optional variable like constant then it can be something line:

namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;

typedef std::string::const_iterator it;
struct var_definition {
    bool is_constant;
    std::string name;
    std::string value;
    var_definition() : is_constant( false ) {}
};
qi::rule<it, std::string()> identifier;
qi::rule<it, std::string()> identifier_value;
qi::rule<it, var_definition(), boost::spirit::ascii::space_type> vdef;

void mark_var_as_constant(var_definition& vd) {vd.is_constant=true;}
void set_var_name(var_definition& vd, std::string const& val) {vd.name=val;}
void set_var_value(var_definition& vd, std::string const& val) {vd.value=val;}

vdef %=
    -qi::lit("constant")[phx::bind(mark_var_as_constant, qi::_val)] >>
    qi::lit("var") >>
    identifier[phx::bind(set_var_name, qi::_val, qi::_1)] >>
    qi::char_('=') >>
    identifier_value[phx::bind(set_var_value, qi::_val, qi::_1)] >>
    qi::char_(';');

Of course there are other ways, for example:

(qi::lit("constant")[phx::bind(mark_var_as_constant, qi::_val)] | qi::eps)

And the easiest is:

qi::hold[ qi::lit("constant")[phx::bind(mark_var_as_constant, qi::_val)] ]
BigBoss
  • 6,904
  • 2
  • 23
  • 38
  • Your `vdef` rule has a problem: both the `char_` expressions should be literals, and/or the normal rule assignment (`operator=` instead of _auto-rule_ `operator%=`) should be used. (See my answer for a more succinct way to write this without all the manual binding with phoenix). – sehe Oct 29 '12 at 08:57