rule_parser.hpp

来自「Boost provides free peer-reviewed portab」· HPP 代码 · 共 1,143 行 · 第 1/4 页

HPP
1,143
字号
/*==============================================================================    Copyright (c) 2006 Tobias Schwinger    http://spirit.sourceforge.net/  Distributed under 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)==============================================================================*/// The comment below contains a unnamed 'namespace {', which is flagged by the// Boost inspect tool as a violation of common C++ programming rules. Since it's// in a comment, well, we switch it off :-P// boostinspect:nounnamed//// About:// =====//// Using a typeof operator or Boost.Typeof to automatically set the type of// variables (as done in the Spirit example demonstrating typeof) is by far not// all we can do to tighten up our grammars as there are some significant // drawbacks of this approach:// - the types complexity scales with the complexity of the grammar (sooner or//   later hitting the limits of the compiler),// - recursive grammars are not possible, and// - all parser objects are embedded by value.//// The Spirit documentation therefore recommends creating custom parser classes// (derived from the a sub_grammar template):////   http://www.boost.org/libs/spirit/doc/techniques.html#no_rules//   http://www.boost.org/libs/spirit/doc/techniques.html#typeof//// In practice manually applying this technique leads to rather lengthy code and// overthis requires the user to have a solid understanding of Spirit details.//// Here is a generalized, macro-based approach to easily create typeof-based // grammars that can be recursive and arbitrarily complex.////// Quick manual:// ============// // 1. Setup// // Before the rule parser macro (the protagonist of the facility) can be used // the the user must define the macro BOOST_SPIRIT__NAMESPACE (note the double// underscore characeter) and setup a registration group for Boost.Typeof.// // Examples:// //   // should come after regular #includeS//   #include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()// //   // [...]// //   #define BOOST_SPIRIT__NAMESPACE (2,(my_project, my_module))//   //                             | |     +- outer     +- inner//   //                  ! space ! -+ |         namespace    namespace//   //                               |//   //                               +--- number of nested namespaces// //   namespace my_project { namespace my_module {// //   // [...]// //  ---// //   // should come after regular #includeS//   #include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()// //   // [...]// //   #define BOOST_SPIRIT__NAMESPACE (2,(my_project, (anonymous) ))// //   namespace my_project { namespace {// //   // [...]// //  ---// //   // should come after regular #includeS//   #include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()// //   // [...]// //   //   #define BOOST_SPIRIT__NAMESPACE -//   // we're working at root namespace// // // Why do I have to do this?// //   Boost.Typeof needs to assign a unique ID for each registration. This ID is//   created composed of the line number and the registration group. The //   facility performs Typeof registration and thus requires the source file to//   have its own registration group. Further Boost.Typeof requires registration//   to happen at root namespace so we have to close and reopen the namespace//   we're in.//// // 2. The rule parser macro// // A simple rule parser definition looks like that:// //   // we're at namespace scope here// //   // Skip parser for C/C++ comments and whitespace//   BOOST_SPIRIT_RULE_PARSER(skipper, //     -,-,-, // //     +(   confix_p("//",*anychar_p,eol_p) //        | confix_p("/*",*anychar_p,"*/")//        | space_p //     )//   )// // Now we can use 'skipper' in other Spirit expressions.// // The code above creates a parser (template) class 'skpper_t' and (in this // case, because there are no parameters) a static const instance 'skipper' of // that class. The class is automatically registered with Boost.Typeof. The type// name our parser is skipper_t here.// // // 2.1. Parametrized rule parsers// // Rule parser definitions can have parameters.// // Parameters are passed to the BOOST_SPIRIT_RULE_PARSER macro as its second// argument (just pass '-' if there are no parameters) with the following // format:// //   (N,( param1,param2, / ... / paramN ))//    +-- number of parameters// // Example of a whole rule parser:// //   BOOST_SPIRIT_RULE_PARSER(new_name,//     (1,( symbol_table )),-,-,// //     lexeme_d[ (alpha_p >> *alnum_p)[ symbol_table.add ] ]//   )// // The expression 'new_name(my_symbols)' parses a string literal and adds it to// the symbol table 'my_symbols'.// // The rule parser macro creates a function template as called 'new_name' that// takes one parameter of deduced reference type and returns a specialization of// 'new_name_t' in this case.// // Since parsers that require to be fast and lightweight often also require to // be reentrant, it's quite common to pass in some semantic controller (the // symbol table in the example above).// However, parameters are templated so they can be anything (including parsers // of course) so refactoring tasks can be abstracted with rule parsers as well.// //   BOOST_SPIRIT_RULE_PARSER(enumeration_parser,//     (2,( element_parser, delimiter_parser )),-,-,// //     element_parser >> *(delimiter_parser >> element_parser)//   ) // // The expression 'enumeration_parser(int_p[ some_action ], ',')' creates a // parser for a comma-separated list of integers.// // // 2.2. Rule parsrs and semantic actions// // While semantic actions can be globally attached to a rule parser or passed// to a parametrized rule parser as (part of) an argument, even more control is // possible by using action placeholders. E.g:// //   BOOST_SPIRIT_ACTION_PLACEHOLDER(int_action)// //   BOOST_SPIRIT_RULE_PARSER(int_list,//     -,(1,( int_action )),-,// //     int_p[ int_action ] >> *(',' >> int_p[ int_action ])//   )// // The expression 'int_list[ my_action ]' parses a comma separated list of // integers and calls 'my_action' for every integer parsed therein.// // Of course multiple actions can be attached to one placeholder as usual (in // this case 'int_list[ my_action1 ][ my_action2 ] would call two actions).// // Further there can be multiple action placeholders for a single rule parser:// //   BOOST_SPIRIT_ACTION_PLACEHOLDER(feed_int)//   BOOST_SPIRIT_ACTION_PLACEHOLDER(next_int)// //   BOOST_SPIRIT_RULE_PARSER(int_list,//     -,(2,( feed_int, next_int )),-,// //     int_p[ feed_int ] >> *(',' >> int_p[ next_int ][ feed_int ])//   )// // The expression 'int_list[ (feed_int = my_action1), (next_int = my_action2) ]'// creates a parser for a comma separated list of integers with the actions // attached appropriately.// //   int_list[ feed_int = my_action1,my_action2, next_int = my_action3 ]// // works too (in this case the action placeholder 'feed_int' has two actions // attached to it).// // You can both override and append actions associated with an action // placeholder:// //   var = int_list[ feed_int = my_action1, next_int = my_action2 ]// //   // [...]// //   ... var[ feed_int = another_action ] //   // 'another_action' overrides the actions previously attached to 'feed_int'// //   ... var[ next_int += another_action ]//   // 'another_action' is appended to the list of actions attached to //   // 'next_int'// // Action placeholders are not entirely for free -- they add to the size and the// initialization time of the rule parser. However, the impact on an already // initialized rule parser instance should be quite small.// // // 2.3. Member variables// // You can add member variables to the rule parser class using the third // parameter of the rule parser macro:// //   BOOST_SPIRIT_RULE_PARSER( calc,//     -,//     -,//     (3,( ((subrule<0>),expression,()),//          ((subrule<1>),term,()),//          ((subrule<2>),factor,() )) ),// //     // [...]// // adds three subrules to the rule parser.// Each parameter must have the following type to allow commas to be handled// safely from within the preprocessing code:// //   ((type)),name,(constructor argument(s)))// //// 2.4. The opaque rule parser//// Rule parsers usually are templates. Building large grammars pushes the // compiler really hard (and eventually to its limits) because of the // metafunction complexity involved.// If a rule parser without parameters and action placeholders is defined, a // non-template class is created. Non-templated rule parsers can also be created// explicitly by using BOOST_SPIRIT_OPAQUE_RULE_PARSER. // Opaque rule parsers can have parameters and member variables (note: no action// placeholders are possible). The parameters of an opaque rule parsers are // strictly typed, e.g:////   BOOST_SPIRIT_OPAQUE_RULE_PARSER(new_identifier,//     (1,( ((my_symbol_table_t &),symbol_table) ))//     ,-,//     (alpha_p >> *alnum_p) [ symbol_table.add ]//   ) //// Note it's also possible to have opaque rule parsers accept parameters of // non-const reference types which is not possible with regular rule parsers.////// 3. Utilities for by-reference embedding// // When using parsers mutiple times or recursively it can be helpful to embed // them by-reference into the final parser expression.// For this purpose the library provides a wrapper template 'parser_reference'.// There is also a function template to create a wrapped parser which can deduce// the parser's type from its argument.//// --- --- - - --- - - --- - - - - --- - - - - - - - - - - - - - - - - - - - - -#if !defined(BOOST_SPIRIT_UTILITY_RULE_PARSER_HPP_INCLUDED)#   define BOOST_SPIRIT_UTILITY_RULE_PARSER_HPP_INCLUDED//==============================================================================// Dependencies//==============================================================================#   include <boost/config.hpp>#   include <boost/detail/workaround.hpp>#   include <boost/call_traits.hpp>#   include <boost/typeof/typeof.hpp>#   include <boost/spirit/home/classic/namespace.hpp>

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?