2013-03-06 47 views
2

我試圖解析爲具有這種類型的語法的循環:如何使用boost :: sprit來解析嵌套for循環?

for(loop = 1:10) { 


} 

在我的語法我有規則:

genericString %= lexeme[+(char_("a-zA-Z"))]; 
intRule %= int_; 
commandString %= lexeme[+(char_ - '}')]; 
forLoop %= string("for") 
     >> '(' 
     >> genericString // variable e.g. c 
     >> '=' 
     >> (intRule | genericString) // variable e.g. i 
     >> ':' 
     >> (intRule | genericString) // variable e.g. j 
     >> ')' >> '{' 
     >> (forLoop | commandString) 
     >> '}'; 

儘管這適用於上面的簡單的例子,它無法解析下面的嵌套示例:

for(loop = 1:10) { 
    for(inner = 1:10) { 

    } 
} 

我猜這是由於解析器'與大括號放置混淆'。我想我需要做一些類似於http://boost-spirit.com/distrib/spirit_1_7_0/libs/spirit/example/fundamental/lazy_parser.cpp(唉,我發現很難遵循)。

乾杯,

本。

編輯1:

現在我想這將是更好地處理來自CommandString中(下文稱爲nestedBlock)遞歸而非for循環中,即是這樣的:

forLoop %= string("for") 
     >> '(' 
     >> genericString // variable e.g. c 
     >> '=' 
     >> (intRule | genericString) // variable e.g. i 
     >> ':' 
     >> (intRule | genericString) // variable e.g. j 
     >> ')' 
     >> nestedBlock; 

nestedBlock %= lexeme['{' >> -(char_ - '}' - '{') 
          >> -nestedBlock 
          >> -(char_ - '}' - '{') 
          >> '}']; 

這與大規模boost :: spriti錯誤失敗。該規則被定義爲:

qi::rule<Iterator, std::string(), ascii::space_type> nestedBlock; 
    qi::rule<Iterator, Function(), ascii::space_type> forLoop; 

功能是增強的結構變異::

編輯2:

因此,這是我現在有(其中設計有或沒有嵌套工作結構):

commandCollection %= *start; 

forLoop %= string("for") 
     >> '(' 
     >> genericString // variable e.g. c 
     >> '=' 
     >> (intRule | genericString) // variable e.g. i 
     >> ':' 
     >> (intRule | genericString) // variable e.g. j 
     >> ')' 
     >> '{' 
     >>  commandCollection 
     >> '}'; 

start %= loadParams | restoreGenomeData | openGenomeData | initNeat | initEvo | 
       initAllPositions | initAllAgents | initCoreSimulationPointers | 
       resetSimulationKernel | writeStats | restoreSimState | 
       run | simulate | removeObjects | setGeneration | 
       setParam | getParam | pause | create | reset | 
       loadAgents | getAgent | setAgent | listParams | loadScript | forLoop 
       | wait | commentFunc | var | add | sub | mult | div | query; 

我宣佈commandCollection規則如下:

qi::rule<Iterator, boost::fusion::vector<Function>, ascii::space_type> commandCollection; 

我認爲這會做我想的。 commandCollection被定義爲0或更多的命令,它們應該存儲在boost :: fusion :: vector中。但是,當我從Function()結構中提取向量時(考慮到啓動規則使用Function()迭代器),由於某種原因,該類型未被識別爲boost :: fusion :: vector,因此不能提取。我不知道爲什麼...

但是,如果我只是有

commandCollection %= start; 

和decalre治國

qi::rule<Iterator, Function(), ascii::space_type> commandCollection; 

,然後嘗試提取數據爲單函數()結構,它工作正常。但我希望它在某種容器中存儲多個命令(即* start)。我也嘗試過一個std :: vector,但是這也失敗了。

+0

,什麼是問題? – 2013-03-06 12:51:49

+0

對我來說問題很清楚。 – sehe 2013-03-06 13:44:17

+0

@sehe - 我只是在Arne的評論之後澄清了標題中的問題:-) – 2013-03-06 13:55:47

回答

3

你的命令字符串不喜歡內部循環的空體。

修復它通過改變+*這裏:

commandString %= lexeme[*(char_ - '}')]; 

或者,如果你喜歡匹配,而不是潛在空塊的可選塊,考慮@llonesmiz提及該修補程序。

測試用例:

#define BOOST_SPIRIT_DEBUG 
#include <boost/fusion/adapted.hpp> 
#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/karma.hpp> 
// #include <boost/spirit/include/phoenix.hpp> 

namespace qi = boost::spirit::qi; 
namespace karma = boost::spirit::karma; 
namespace phx = boost::phoenix; 

typedef boost::variant<int, std::string> Value; 
typedef std::pair<Value, Value> Range; 
typedef std::pair<std::string, Range> Iteration; 

typedef Iteration attr_t; 

template <typename It, typename Skipper = qi::space_type> 
    struct parser : qi::grammar<It, attr_t(), Skipper> 
{ 
    parser() : parser::base_type(start) 
    { 
     using namespace qi; 

     genericString %= lexeme[+(char_("a-zA-Z"))];// variable e.g. c 
     intRule %= int_; 
     commandString %= lexeme[*(char_ - '}')]; 
     value = intRule | genericString; 
     range = value >> ':' >> value; 
     forLoop %= lit("for") 
       >> '(' >> genericString >> '=' >> range >> ')' 
       >> '{' 
       >>  (forLoop | commandString) 
       >> '}'; 

     start = forLoop; 

     BOOST_SPIRIT_DEBUG_NODES(
       (start)(intRule)(genericString)(commandString)(forLoop)(value)(range) 
       ); 
    } 

    private: 
    qi::rule<It, std::string(), Skipper> genericString, commandString; 
    qi::rule<It, int(), Skipper> intRule; 
    qi::rule<It, Value(), Skipper> value; 
    qi::rule<It, Range(), Skipper> range; 
    qi::rule<It, attr_t(), Skipper> forLoop, start; 
}; 

bool doParse(const std::string& input) 
{ 
    typedef std::string::const_iterator It; 
    auto f(begin(input)), l(end(input)); 

    parser<It, qi::space_type> p; 
    attr_t data; 

    try 
    { 
     bool ok = qi::phrase_parse(f,l,p,qi::space,data); 
     if (ok) 
     { 
      std::cout << "parse success\n"; 
     } 
     else  std::cerr << "parse failed: '" << std::string(f,l) << "'\n"; 

     if (f!=l) std::cerr << "trailing unparsed: '" << std::string(f,l) << "'\n"; 
     return ok; 
    } catch(const qi::expectation_failure<It>& e) 
    { 
     std::string frag(e.first, e.last); 
     std::cerr << e.what() << "'" << frag << "'\n"; 
    } 

    return false; 
} 

int main() 
{ 
    bool ok = doParse(
      "for(loop = 1:10) {\n" 
      " for(inner = 1:10) {\n" 
      " }\n" 
      "}" 
      ); 
    return ok? 0 : 255; 
} 

我衷心建議看DEBUG輸出顯示解析如何失敗:

<forLoop> 
    <try>\n }\n}</try> 
    <fail/> 
</forLoop> 
<commandString> 
    <try>\n }\n}</try> 
    <fail/> 
</commandString> 
<fail/> 
+0

再次感謝您的幫助..我現在試圖將這些想法應用於我的代碼。乾杯:-) – 2013-03-06 15:05:27

+0

另一個編輯(編輯2)對原始文章。道歉我已經擴大了,也許偏離了我原來的問題的細節。 – 2013-03-06 17:05:13