Boost.Spirit.Qi: Prendere l'attributo di una regola e impostarlo come un campo di attributi struct di una regola di inclusione?

StackOverflow https://stackoverflow.com/questions/4620016

Domanda

Come, molte di queste altre domande, sto cercando di analizzare una grammatica semplice in un albero di struct usando Boost.Spirit.Qi.

Cercherò di distillare quello che sto cercando di fare per il più semplice possibile caso. Ho:

struct Integer {
  int value;
};
BOOST_FUSION_ADAPT_STRUCT(Integer, (int, value))

In seguito, all'interno di una struttura grammaticale, ho la seguente variabile membro:

qi::rule<Iterator, Integer> integer;

che sto definendo con

integer = qi::int_;

Quando provo ad analizzare in realtà un intero, tuttavia, utilizzando

qi::phrase_parse(iter, end, g, space, myInteger);

myInteger.value è sempre inizializzata dopo un parsing di successo. Allo stesso modo, ho provato le seguenti definizioni (ovviamente quelli che non lo fanno di compilazione sono sbagliate):

integer = qi::int_[qi::_val = qi::_1]; //compiles, uninitialized value
integer = qi::int_[qi::_r1 = qi::_1]; //doesn't compile
integer = qi::int_[phoenix::bind(&Integer::value, qi::_val) = qi::_1]; //doesn't
integer = qi::int_[phoenix::at_c<0>(qi::_val) = qi::_1]; //doesn't

Chiaramente sto equivoco qualcosa su Spirit, Phoenix, o qualcos'altro. Mi risulta che qi::_1 è il primo attributo di qi::int_, qui, e dovrebbe rappresentare il numero intero analizzata, quando la parte tra parentesi quadre viene eseguito come un oggetto funzione. Sono quindi supponendo che l'oggetto funzione avrà la racchiude integer attributo qi::_val e cercare di assegnare l'intero analizzata ad esso. La mia ipotesi è che, a causa della mia chiamata BOOST_FUSION_ADAPT_STRUCT, i due sarebbero compatibili, e che certamente sembra essere il caso dal punto di vista di analisi statica, ma i dati non viene conservato.

C'è un riferimento (e) la designazione che mi manca da qualche parte o qualcosa del genere?

È stato utile?

Soluzione

Se Integer si suppone che sia l'attributo esposto dalla regola, è necessario dichiararla come:

qi::rule<Iterator, Integer()> integer; 

(si noti la parentesi). Spirito richiede di utilizzare la sintassi di dichiarazione di funzione per descrivere la regola del 'interfaccia'. E 'utilizzato non solo nello spirito, ma da diverse altre librerie come pure (vedi boost :: funzione, per esempio).

La ragione principale di questo è che è un modo conciso bello di specificare una funzione di interfaccia. Se si pensa a ciò che una regola è, ci si rende conto rapidamente che è come una funzione: può restituire un valore (il risultato analizzata, vale a dire l'attributo sintetizzato). Inoltre si può richiedere uno o più argomenti (gli attributi ereditati).

Un secondo, ma la ragione minore è che lo Spirito ha bisogno di essere in grado di distinguere i diversi parametri del modello di una regola. I parametri del modello possono essere specificati in qualsiasi ordine (tranne che per l'iteratore), quindi ha bisogno di alcuni mezzi di capire come stanno le cose. La sintassi di dichiarazione funzione è sufficientemente diverso dal comandante o codifica (gli altri due possibili parametri template) per permettergli di essere riconosciuto in fase di compilazione.

Diamo uno sguardo alla vostra diversi tentativi:

Questo può essere fatto funzionare se si modifica la definizione della regola come descritto sopra.

integer = qi::int_[qi::_val = qi::_1]; 

Il _val si riferisce al vostro Integer, mentre il _1 si riferisce ad un int. Pertanto, è necessario definire un operatore di assegnazione da int per fare questo lavoro:

struct Integer {
    int value;
    Integer& operator=(int) {...}
};                    

Non è necessario per adattare il tipo di come una sequenza di fusione in questo caso.

Ma è possibile scrivere ancora più facile:

integer = qi::int_ >> qi::eps;

che è 100% equivalente (EPS è un trucco usato per convertire il lato destro in una sequenza parser, che consente di utilizzare l'attributo built-in propagazione mappatura degli elementi della sequenza Fusion adattato alle caratteristiche degli elementi della sequenza).

Questa:

integer = qi::int_[qi::_r1 = qi::_1]; 

non funzionerà come _r1 fa riferimento all'attributo primo ereditata di una regola. Tuttavia, la regola non ha attributi inherted.

Questo lavoro sarà:

integer = qi::int_[phoenix::bind(&Integer::value, qi::_val) = qi::_1];

, ma non richiede di adattare il tipo di come una sequenza di fusione.

E così sarà questo:

integer = qi::int_[phoenix::at_c<0>(qi::_val) = qi::_1]; 
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top