2014-10-24 1 views
3

을 사용하여 구분 된 토큰 목록을 구문 분석 boost :: spirit :: qi를 사용하여 구분 된 토큰의 가변 개수가 뒤에 오는 레이블로 구성된 행을 구문 분석하려고합니다. 문법을 phrase_parse으로 호출하고 제공된 레이블 파서를 건너 뛰기 파서로 사용하여 각 줄의 첫 번째 항목이 레이블인지 확인해야합니다.Boost Spirit Qi

간단한 기본 케이스 :

label token, token, token 

은 문법과 구문 분석 할 수 있습니다

line = label >> (token % ',') >> eol; 

내가 직면하고 문제는 문법 0 개 이상의 토큰을 받아 들여야한다는 및 토큰이 될 수 있다는 것이다 빈. 문법은 다음 줄을 받아 들여야합니다 :

label 
label , 
label , token 
label token, , token, 

나는 위의 모든 예제를 허용하는 문법을 만들지 못했습니다. 해결 방법에 대한 제안 사항이 있으십니까?

편집 :

덕분에 위에서 언급 한 문제에 대한 모든 입력 sehe합니다. 재미있는 부분을 포함 시켜서 깜박입니다 ... 문법은 빈 줄과 줄을 받아 들여야합니다. (레이블이없는 토큰) 레이블을 선택적으로 만들려고 할 때 빈 문자열과 일치하는 무한 루프가 발생합니다.

label 

label token 
token 
+0

내가 대신 ANTLR을 사용하는 것이 좋습니다. 나는 이것이 당신이 원했던 대답이 아니라는 것을 알고 있습니다. 그래서 저는 그것을 코멘트로 올리고 있습니다. ANTLR은 장기간 사용하기가 훨씬 쉬우 며 도구 지원이 뛰어나고 배울 수있는 참조가 많습니다. –

+2

@JohnZwinck 우리는 당신이 지금 Spirit을 좋아하지 않는다는 것을 알게됩니다. 그것에 대해 (그리고 일반적으로 C++에 대해)별로 마음에 들지 않습니다. 괜찮아. 그러나 여기에 ANTLR을 사용하라는 제안은 질문 밖에서 어떤 문맥도없이 약간 우스꽝 스럽다. 파리를 날치기 위해 캐논을 가져 오는 것 같아요. – sehe

+1

러시아어 문법에 대한 질문을하는 사람에게 영어로 바꿔야한다고 말하는 것과 같습니다. – Spacemoose

답변

3

당신은 당신의 주장이 너무 EOL을 생략하는 경우 (그래서 qi::space를 사용하지 않는 eol가 작동하지 않습니다

line = label >> -(token % ',') >> eol; 

참고로 빈리스트를 받아 들일 수 있어야하지만, 예를 들어 qi::blank이 목적을 위해)

또한, token의 정의에 따라 당신은 어쩌면

뿐만 아니라 "빈"토큰을 받아 변경해야 주석에 대한 응답으로 691,363,210


: 완전 작업 샘플 Live On Coliru

#include <boost/spirit/include/qi.hpp> 

namespace qi = boost::spirit::qi; 

int main() 
{ 
    using namespace qi; 

    using It  = std::string::const_iterator; 
    using Token = std::string; 
    using Tokens = std::vector<Token>; 

    rule<It, blank_type> label 
     = lexeme[+~char_(":")] >> ':' 
     ; 

    rule<It, Token(), blank_type> token 
     = lexeme[*~char_(",\n")]; 
     ; 

    rule<It, Tokens(), blank_type> line 
     = label >> -(token % ',') >> eol 
     ; 

    for (std::string const input : { 
     "my first label: 123, 234, 345 with spaces\n", 
     "1:\n", 
     "2: \n", 
     "3: ,,,\n", 
     "4: , \t ,,\n", 
     "5: , \t , something something,\n", 
    }) 
    { 
     std::cout << std::string(40, '=') << "\nparsing: '" << input << "'\n"; 

     Tokens parsed; 
     auto f = input.begin(), l = input.end(); 
     bool ok = phrase_parse(f, l, line, blank, parsed); 

     if (ok) 
     { 
      std::cout << "Tokens parsed successfully, number parsed: " << parsed.size() << "\n"; 
      for (auto token : parsed) 
       std::cout << "token value '" << token << "'\n"; 
     } 
     else 
      std::cout << "Parse failed\n"; 

     if (f != l) 
      std::cout << "Remaining input: '" << std::string(f, l) << "'\n"; 
    } 
} 

출력 :

======================================== 
parsing: 'my first label: 123, 234, 345 with spaces 
' 
Tokens parsed successfully, number parsed: 3 
token value '123' 
token value '234' 
token value '345 with spaces' 
======================================== 
parsing: '1: 
' 
Tokens parsed successfully, number parsed: 1 
token value '' 
======================================== 
parsing: '2: 
' 
Tokens parsed successfully, number parsed: 1 
token value '' 
======================================== 
parsing: '3: ,,, 
' 
Tokens parsed successfully, number parsed: 4 
token value '' 
token value '' 
token value '' 
token value '' 
======================================== 
parsing: '4: ,  ,, 
' 
Tokens parsed successfully, number parsed: 4 
token value '' 
token value '' 
token value '' 
token value '' 
======================================== 
parsing: '5: ,  , something something, 
' 
Tokens parsed successfully, number parsed: 4 
token value '' 
token value '' 
token value 'something something' 
token value '' 
+0

"빈"토큰에 대한 규칙을 추가하려고 할 때 문제가 발생합니다. 'token = -lit ("token")'과 같은 아주 간단한 규칙조차도 실패합니다. 예제를 제공해 줄 수 있습니까? – Fredrik

+0

@Fredrik 샘플을 추가했습니다 (토큰에 대해'* (char_ - ','-eol)'이 조금 더 정확할 것임을 알았지 만 :) = – sehe

+0

사이드 노트에 : spirit :: qi 문법을 디버깅하려면 어떻게해야합니까? #defines를 사용하여 debug blurbs를 활성화하는 방법에 대한 몇 가지 의견을 보았습니다. 그러나 그 작업은 결코 없었습니다 ... – Fredrik