2010-05-03 55 views
6

我一直在努力尝试和(增量)从文档,但没有太大的不同,我没有得到我预期的行为修改示例代码。特别是,当if(我的意图是)它应该传递时(有一个“else”但解析器的那部分在调试期间被移除)时,“if”语句失败。赋值语句正常工作。我有一个“while”语句,它与“if”语句具有相同的问题,所以我相信如果我能找到帮助来弄清楚为什么一个人不工作,应该很容易让其他人去做。它必须有点微妙,因为这几乎是逐字的例子之一。升压精神和Lex解析器问题

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

这里是运行这个输出(读入字符串的文件是在主首先倾倒出来)

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

回答

8

问题是你添加的标记定义的词法分析器的序列。您的代码

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

先加identifier令牌,这样就可以完美匹配“如果”(以及任何其他关键字)为好。如果您将其更改为

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

万物开始工作,因为它应该。

这不是什么特定的Spirit.Lex。任何标记器都会遵守这些标记的定义顺序,以确定匹配的优先级。

+0

你的男人哈特穆特!我希望你或乔尔能够做到这一点。我没有意识到它们的添加顺序与令牌解析的优先顺序有关。顺便说一句,您是否知道使用版本2语法的任何全新解决方案?我在Spirit Applications Repository中看到的大多数示例都使用旧的语法。另外,是否有直接链接到您的“示例”文件(例如,http://www.boost.org/doc/libs/1_42_0/libs/spirit/example/lex/example#.cpp)? – bpw1621 2010-05-04 18:22:24

+1

您的意思是:http://svn.boost.org/svn/boost/trunk/libs/spirit/example/? – hkaiser 2010-05-05 00:18:25

6

也许mini_c例子就需要被修改为使用词法分析器?这将是一个更完整的例子,说明如何使用这两者。大多数Qi样本(从2.4版开始)根本不使用词法分析器。

虽然它解释了使用齐 - 我们往往会尝试和对因维护原因,生产项目专用词法分析器(我可以脱负载词法分析器子开发商为例)。