c++ boost boost-spirit template-meta-programming

c++ - más locura espiritual-parser-types(rules vs int_parser<>) y técnicas de meta-programación



boost boost-spirit (1)

No estoy tan seguro de entender todo el alcance de la pregunta, pero aquí hay algunos consejos

  • La línea comentada con // THIS is what I need to do. compila bien conmigo (¿problema resuelto? Supongo que en realidad querías asignar un analizador sintáctico, no una regla)

  • La inicialización de la función static local se ha definido para que sea segura para subprocesos en el último estándar (C ++ 11). Compruebe su compatibilidad con el compilador para el encriptado C ++ 0x. (Si el inicializador arroja, un pase de la declaración de inicialización intentará inicializarse de nuevo, por cierto).

  • reglas alias()

    Como se describe en http://boost-spirit.com/home/articles/doc-addendum/faq/#aliases

    Puede crear ''copias lógicas'' de reglas sin tener que realmente copiar el valor de la expresión proto. Como dice la pregunta frecuente, esto es principalmente para permitir el enlace perezoso

  • El truco de Nabialek puede ser precisamente lo que necesitas, básicamente selecciona perezosamente un analizador para su posterior análisis

    one = id; two = id >> '','' >> id; keyword.add ("one", &one) ("two", &two) ; start = *(keyword[_a = _1] >> lazy(*_a));

    En su contexto, pude ver la keyword definida como

    qi::symbols<char, qi::rule<Iterator>*> keyword;

    haciendo todo el trabajo con atributos de acciones semánticas. Alternativamente,

    qi::symbols<char, qi::rule<Iterator, std::variant<std::string,int>() >*> keyword;

  • Trae las reglas bajo el mismo tipo (como se muestra en la línea anterior, básicamente)

    Esta es la parte en la que me confundo: dices que quieres unificar tu sistema de tipos. Es posible que no haya necesidad de analizadores sintácticos (firmas de atributos distintivos).

    typedef boost::variant<std::string,int> unified_type; typedef qi::rule<std::string::iterator, unified_type() > unified_rule; unified_rule rstring = +(qi::char_ - ''.''); unified_rule rint = qi::int_; unified_rule combine = rstring | rint;

La pregunta está en negrita en la parte inferior, el problema también se resume por el fragmento de código de destilación hacia el final.

Estoy tratando de unificar mi sistema de tipos (el tipo de sistema hace ay de tipo a cadena) en un solo componente (como lo define Lakos). Estoy usando boost::array , boost::variant y boost::mpl para lograr esto. Quiero tener las reglas de generador y analizador para mis tipos unificados en una variante. hay un tipo indefinido, un tipo int4 (ver a continuación) y un tipo int8. La variante se lee como variant<undefined, int4,int8> .

rasgos int4:

struct rbl_int4_parser_rule_definition { typedef boost::spirit::qi::rule<std::string::iterator, rbl_int4()> rule_type; boost::spirit::qi::int_parser<rbl_int4> parser_int32_t; rule_type rule; rbl_int4_parser_rule_definition() { rule.name("rbl int4 rule"); rule = parser_int32_t; } }; template<> struct rbl_type_parser_rule<rbl_int4> { typedef rbl_int4_parser_rule_definition string_parser; };

la variante anterior comienza como indefinida, y luego inicializo las reglas. Tuve un problema, que causó 50 páginas de errores, y finalmente pude rastrearlo, Variant usa operator= durante la asignación y un boost::spirit::qi::int_parser<> no se puede asignar a otro (operator = )

Para contrastar, no tengo ningún problema con mi tipo indefinido:

struct rbl_undefined_parser_rule_definition { typedef boost::spirit::qi::rule<std::string::iterator, void()> rule_type; rule_type rule; rbl_undefined_parser_rule_definition() { rule.name("undefined parse rule"); rule = boost::spirit::qi::eps; } }; template<> struct rbl_type_parser_rule<rbl_undefined> { typedef rbl_undefined_parser_rule_definition string_parser; };

Destilación del problema:

#include <string> #include <boost/spirit/include/qi.hpp> #include <boost/variant.hpp> #include <boost/cstdint.hpp> typedef boost::spirit::qi::rule<std::string::iterator,void()> r1; typedef boost::spirit::qi::rule<std::string::iterator,int()> r2; typedef boost::variant<r1,r2> v; int main() { /* problematic boost::spirit::qi::int_parser<int32_t> t2; boost::spirit::qi::int_parser<int32_t> t1; t1 = t2; */ //unproblematic r1 r1_; r2 r2_; r1_ = r2_; v v_; // THIS is what I need to do. v_ = r2(); }

Existe una brecha semántica entre los analizadores sintácticos concretos y las reglas. Mi cerebro está fumando en este momento, así que no voy a pensar en pramatismo. Mi pregunta es, ¿cómo puedo resolver este problema? Puedo pensar en tres enfoques para resolver el problema.

uno: miembros de la función estática:

struct rbl_int4_parser_rule_definition { typedef boost::spirit::qi::rule<std::string::iterator, rbl_int4()> rule_type; //boost::spirit::qi::int_parser<rbl_int4> parser_int32_t; rule_type rule; rbl_int4_parser_rule_definition() { static boost::spirit::qi::int_parser<rbl_int4> parser_int32_t; rule.name("rbl int4 rule"); rule = parser_int32_t; } };

Supongo que el enfoque uno evita el código seguro de subprocesos? ?

dos: el analizador integral está envuelto en un shared_ptr. Hay dos razones por las que estoy molestando con TMP para el sistema de tipeo: 1 eficiencia, 2 preocupaciones de centralización en los componentes. el uso de punteros derrota la primera razón.

tres: operator = se define como no-op. La variante garantiza que lhs se construye por defecto antes de la asignación.

Editar: Estoy pensando que la opción 3 tiene más sentido (operador = no funciona). Una vez que se crea el contenedor de reglas, no cambiará, y solo estoy asignando para forzar un rasgo de regla de un tipo en su desplazamiento.