2010-05-03 8 views
6

Ich habe gekämpft, um zu versuchen und (inkrementell) Beispielcode aus der Dokumentation zu ändern, aber mit nicht viel anders, ich bekomme nicht das Verhalten, das ich erwarte. Insbesondere schlägt die "if" -Anweisung fehl, wenn (meine Absicht ist dies) es sollte übergeben werden (es gab ein "else", aber dieser Teil des Parsers wurde während des Debuggens entfernt). Die Zuweisungsanweisung funktioniert einwandfrei. Ich hatte auch eine "while" -Anweisung, die das gleiche Problem hatte wie die "if" -Anweisung, also bin ich sicher, wenn ich Hilfe bekommen kann, um herauszufinden, warum man nicht arbeitet, sollte es einfach sein, den anderen zum Laufen zu bringen. Es muss irgendwie subtil sein, weil das fast wörtlich ist, was in einem der Beispiele ist.Boost Spirit und Lex Parser Problem

#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); 
} 

Hier ist die Ausgabe dieses laufen

******************** 
{ 
    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 

Antwort

8

Das Problem (die Datei in die Zeichenfolge gelesen wird zunächst in Haupt abgeladen out) ist die Reihenfolge Sie die Token-Definitionen in der Lexer hinzugefügt. Ihr Code

this->self += identifier | number | if_ | else_; 

zuerst fügt die identifier Token, die perfekt die ‚if‘ (und anderes Schlüsselwort) und passen auf. Wenn Sie das zu

this->self += if_ | else_ | identifier | number; 

ändern, beginnt Everythings zu arbeiten, wie es sollte.

Dies ist nichts spezifisch für Spirit.Lex. Jeder Tokenizer respektiert die Reihenfolge, in der die Token definiert sind, um die Übereinstimmung zu priorisieren.

+0

Ihr der Mann Hartmut! Ich hatte gehofft, entweder du oder Joel würden dazu kommen. Ich wusste nicht, dass die Reihenfolge, in der sie hinzugefügt wurden, etwas mit dem Vorrang der Tokenanalyse zu tun hatte. Abgesehen davon, kennen Sie neue vollständig ausgearbeitete Beispiele mit der Version 2-Syntax? Die meisten Beispiele, die ich im Spirit Applications Repository gesehen habe, verwenden die alte Syntax. Gibt es außerdem einen direkten Link zu Ihren Beispieldateien (z. B. http://www.boost.org/doc/libs/1_42_0/libs/spirit/example/lex/example#.cpp)? – bpw1621

+1

Meinst du das: http://svn.boost.org/svn/boost/trunk/libs/spirit/example/? – hkaiser

6

Vielleicht muss das mini_c-Beispiel geändert werden, um den Lexer zu verwenden? Es wird ein vollständigeres Beispiel für die Verwendung der beiden sein. Die meisten Qi-Samples (ab Version 2.4) verwenden überhaupt keinen Lexer.

Obwohl es zur Veranschaulichung der Qi-Verwendung dient - wir versuchen aus Gründen der Wartbarkeit einen dedizierten Lexer für Produktionsprojekte zu verwenden (ich kann Lexer beispielsweise an einen Unterentwickler laden).

Verwandte Themen