Ho avuto difficoltà a provare e (incrementalmente) modificare il codice di esempio dalla documentazione ma con non molto diverso non sto ottenendo il comportamento che mi aspetto. Nello specifico, l'istruzione "if" fallisce quando (il mio intento è quello) dovrebbe passare (c'era un "else" ma quella parte del parser è stata rimossa durante il debug). La dichiarazione di assegnazione funziona bene. Ho avuto anche una dichiarazione "while" che aveva lo stesso problema dell'istruzione "if", quindi sono sicuro che se riuscirò a ottenere aiuto per capire perché non funziona, dovrebbe essere facile far funzionare l'altro. Deve essere un po 'sottile perché questo è quasi testualmente quello che c'è in uno degli esempi.Problema di parser Spirit e Lex parser
#include <iostream>
#include <fstream>
#include <string>
#define BOOST_SPIRIT_DEBUG
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_statement.hpp>
#include <boost/spirit/include/phoenix_container.hpp>
namespace qi = boost::spirit::qi;
namespace lex = boost::spirit::lex;
inline std::string read_from_file(const char* infile)
{
std::ifstream instream(infile);
if(!instream.is_open())
{
std::cerr << "Could not open file: \"" << infile << "\"" << std::endl;
exit(-1);
}
instream.unsetf(std::ios::skipws);
return(std::string(
std::istreambuf_iterator<char>(instream.rdbuf()),
std::istreambuf_iterator<char>()
));
}
template< typename Lexer >
struct LangLexer : lex::lexer<Lexer>
{
LangLexer()
{
identifier = "[a-zA-Z][a-zA-Z0-9_]*";
number = "[-+]?(\\d*\\.)?\\d+([eE][-+]?\\d+)?";
if_ = "if";
else_ = "else";
this->self = lex::token_def<> ('(') | ')' | '{' | '}' | '=' | ';';
this->self += identifier | number | if_ | else_;
this->self("WS") = lex::token_def<>("[ \\t\\n]+");
}
lex::token_def<> if_, else_;
lex::token_def<std::string> identifier;
lex::token_def<double> number;
};
template< typename Iterator, typename Lexer >
struct LangGrammar : qi::grammar< Iterator, qi::in_state_skipper<Lexer> >
{
template< typename TokenDef >
LangGrammar(const TokenDef& tok) : LangGrammar::base_type(program)
{
using boost::phoenix::val;
using boost::phoenix::ref;
using boost::phoenix::size;
program = +block;
block = '{' >> *statement >> '}';
statement = assignment | if_stmt;
assignment = (tok.identifier >> '=' >> expression >> ';');
if_stmt = (tok.if_ >> '(' >> expression >> ')' >> block);
expression = (tok.identifier[ qi::_val = qi::_1 ] | tok.number[ qi::_val = qi::_1 ]);
BOOST_SPIRIT_DEBUG_NODE(program);
BOOST_SPIRIT_DEBUG_NODE(block);
BOOST_SPIRIT_DEBUG_NODE(statement);
BOOST_SPIRIT_DEBUG_NODE(assignment);
BOOST_SPIRIT_DEBUG_NODE(if_stmt);
BOOST_SPIRIT_DEBUG_NODE(expression);
}
qi::rule< Iterator, qi::in_state_skipper<Lexer> > program, block, statement;
qi::rule< Iterator, qi::in_state_skipper<Lexer> > assignment, if_stmt;
typedef boost::variant< double, std::string > expression_type;
qi::rule< Iterator, expression_type(), qi::in_state_skipper<Lexer> > expression;
};
int main(int argc, char** argv)
{
typedef std::string::iterator base_iterator_type;
typedef lex::lexertl::token< base_iterator_type, boost::mpl::vector< double, std::string > > token_type;
typedef lex::lexertl::lexer<token_type> lexer_type;
typedef LangLexer<lexer_type> LangLexer;
typedef LangLexer::iterator_type iterator_type;
typedef LangGrammar< iterator_type, LangLexer::lexer_def > LangGrammar;
LangLexer lexer;
LangGrammar grammar(lexer);
std::string str(read_from_file(1 == argc ? "boostLexTest.dat" : argv[1]));
base_iterator_type strBegin = str.begin();
iterator_type tokenItor = lexer.begin(strBegin, str.end());
iterator_type tokenItorEnd = lexer.end();
std::cout << std::setfill('*') << std::setw(20) << '*' << std::endl <<
str
<< std::endl << std::setfill('*') << std::setw(20) << '*' << std::endl;
bool result = qi::phrase_parse(tokenItor, tokenItorEnd, grammar, qi::in_state("WS")[ lexer.self ]);
if(result)
{
std::cout << "Parsing successful" << std::endl;
}
else
{
std::cout << "Parsing error" << std::endl;
}
return(0);
}
Ecco l'output di esecuzione di questo (il file letto nella stringa viene scaricata prima in principale)
********************
{
a = 5;
if(a){ b = 2; }
}
********************
<program>
<try>{</try>
<block>
<try>{</try>
<statement>
<try></try>
<assignment>
<try></try>
<expression>
<try></try>
<success>;</success>
<attributes>(5)</attributes>
</expression>
<success></success>
<attributes>()</attributes>
</assignment>
<success></success>
<attributes>()</attributes>
</statement>
<statement>
<try></try>
<assignment>
<try></try>
<fail/>
</assignment>
<if_stmt>
<try>
if(</try>
<fail/>
</if_stmt>
<fail/>
</statement>
<fail/>
</block>
<fail/>
</program>
Parsing error
Il tuo uomo Hartmut! Speravo che tu o Joel aveste ottenuto questo. Non mi rendevo conto che l'ordine in cui erano stati aggiunti aveva qualcosa a che fare con la precedenza dell'analisi del token. Per inciso, sei a conoscenza di nuovi esempi completamente elaborati che utilizzano la sintassi della versione 2? La maggior parte degli esempi che ho visto su Spirit Applications Repository usano la vecchia sintassi. Inoltre, esiste un collegamento diretto ai file di "esempio" (ad es. Http://www.boost.org/doc/libs/1_42_0/libs/spirit/example/lex/example#.cpp)? – bpw1621
Intendi questo: http://svn.boost.org/svn/boost/trunk/libs/spirit/example/? – hkaiser