correl.phoenixinquis.netProjects and coding adventures

Project: Scripted IRC Client


Friday 29 of May, 2009 04:23 AM
Scripted IRC Client :: Parsing mIRC script with Boost::Spirit
This is a project to create a mIRC script language interpreter using Boost::Spirit. The following code describes the grammar in Spirit's inline EBNF format. Currently the project supports loading and executing scripts including aliases. Grammar is in place to allow events, but they are not yet stored or acted upon. struct mirc_script : public grammar<mirc_script> { mirc_script_engine *actions; mirc_script( mirc_script_engine *_actions ) { actions = _actions; } template <typename ScannerT> struct definition { rule<ScannerT> script, space, nospace, identifier, string, value, expression, expression_group, parameters, variable, assignment, alias_action, alias_function, alias_definition, event_option, event_definition, code_line, code_block, comment; definition(mirc_script const &self) { typedef function< void(const char*, const char*) > s_action; s_action a_def ( bind( &mirc_script_engine::handle_alias_definition, self.actions, _1, _2 ) ); s_action l_def ( bind( &mirc_script_engine::handle_alias_definition_local, self.actions, _1, _2 ) ); s_action e_def ( bind( &mirc_script_engine::handle_event_definition, self.actions, _1, _2 ) ); s_action a_close ( bind( &mirc_script_engine::close_alias, self.actions, _1, _2 ) ); s_action a_set ( bind( &mirc_script_engine::set_alias, self.actions, _1, _2 ) ); s_action a_call ( bind( &mirc_script_engine::call_alias, self.actions, _1, _2 ) ); s_action a_return ( bind( &mirc_script_engine::return_alias, self.actions, _1, _2 ) ); s_action v_def ( bind( &mirc_script_engine::declare_variable, self.actions, _1, _2 ) ); s_action v_assign ( bind( &mirc_script_engine::assign_variable, self.actions, _1, _2 ) ); s_action v_fetch ( bind( &mirc_script_engine::fetch_variable, self.actions, _1, _2 ) ); s_action v_append ( bind( &mirc_script_engine::append_value, self.actions, _1, _2 ) ); s_action e_append ( bind( &mirc_script_engine::append_expression, self.actions, _1, _2 ) ); s_action s_code ( bind( &mirc_script_engine::store_code, self.actions, _1, _2 ) ); s_action c_line (bind( &mirc_script_engine::code_line, self.actions, _1, _2 ) ); s_action c_stack ( bind( &mirc_script_engine::clear_stack, self.actions, _1, _2 ) ); script = *( alias_definition[a_close] | event_definition | code_block ) >> end_p ; space = ( blank_p | str_p("$&") >> *blank_p >> eol_p[c_line] ) ; nospace = +space >> str_p("$+") >> +space ; identifier = alpha_p >> *alnum_p ; string = (+(graph_p - ch_p(',') - ch_p('(') - ch_p(')'))) ; value = ( variable[v_append][v_fetch] | alias_function[v_append][a_return] | string[v_append] ) ; expression = (*nospace >> value)[e_append] >> *(+space >> (+(*nospace >> value))[e_append]) ; expression_group = (*nospace >> *(*(ch_p(',') | ch_p('(') | ch_p(')'))[v_append] >> value))[e_append] >> *(+space >> (+(*nospace >> *(*(ch_p(',') | ch_p('(') | ch_p(')'))[v_append] >> value))[e_append])[e_append]) ; parameters = expression >> *(*space >> ch_p(',') >> *space >> expression) ; variable = ch_p('%') >> identifier ; assignment = !(str_p("var") >> *space) >> variable[v_def] >> *space >> ch_p('=') >> *space >> expression[v_assign] ; alias_action = !ch_p('/') >> !ch_p('/') >> (identifier[a_set] >> *(*space >> parameters))[a_call] ; alias_function = ch_p('$') >> identifier[a_set] >> !( ch_p('(') >> *space >> parameters >> *space >> ch_p(')') ) ; alias_definition = str_p("alias") >> *space >> if_p(str_p("-l") >> *space)[identifier[l_def]].else_p[identifier[a_def]] >> *space >> !eol_p[c_line] >> code_block ; event_option = (+(graph_p - ch_p(':'))) ; event_definition = str_p("on") >> *space >> ( //event_option >> ch_p(':') >> event_option /* level:EVENT */ //>> *(ch_p(':') >> event_option) >> ch_p(':') /* options */ +(event_option[v_append][e_append] >> ch_p(':')) )[e_def] >> code_block ; code_line = *space >> ( comment[c_line] | ( assignment /* Must come first to avoid "var" being caught as an action */ | alias_action | eol_p[c_line] )[s_code] )[c_stack] >> !eol_p[c_line] ; code_block = ( *space >> ch_p('{') >> *space >> !eol_p[c_line] >> (*code_line) >> ch_p('}') >> *space >> !eol_p[c_line] ) | code_line ; comment = comment_p(";"); BOOST_SPIRIT_DEBUG_NODE(script); BOOST_SPIRIT_DEBUG_NODE(space); BOOST_SPIRIT_DEBUG_NODE(identifier); BOOST_SPIRIT_DEBUG_NODE(string); BOOST_SPIRIT_DEBUG_NODE(expression); BOOST_SPIRIT_DEBUG_NODE(variable); BOOST_SPIRIT_DEBUG_NODE(assignment); BOOST_SPIRIT_DEBUG_NODE(alias_action); BOOST_SPIRIT_DEBUG_NODE(alias_function); BOOST_SPIRIT_DEBUG_NODE(alias_definition); BOOST_SPIRIT_DEBUG_NODE(code_line); BOOST_SPIRIT_DEBUG_NODE(code_block); BOOST_SPIRIT_DEBUG_NODE(comment); BOOST_SPIRIT_DEBUG_NODE(*this); } rule<ScannerT> const& start() const { return script; } }; };
0 Comment(s)
Post a comment
Name (optional)
Website (optional)
Comment
HTML is allowed with the following tags: p,b,a[href],i
Captcha