2012-04-24 19 views
5

一部の文字列が引用符で囲まれていないか、引用符で囲まれているか、引用符で囲まれている文章を解析したいとします。以下のコードはほとんど動作しますが、引用符を閉じても一致しません。私はこれがqq参照のためだと推測しています。変更はコード内でコメントされ、変更は "quoted"または "quoted"でも解析され、元の問題は終了クオートに表示されます。このコードでは、正確な文法についても説明しています。引用符付きの文字列をboost :: spiritで構文解析します。

完全にクリアするには、引用符で囲まれていない文字列を解析します。 'hello'のような引用符で囲まれた文字列は、開かれた引用文'、すべての文字helloを解析しますが、最後の引用文の解析に失敗します。'

boost tutorialsで始まるタグと終わりのタグが同じように試しましたが、成功しませんでした。ボーナス信用のため

template <typename Iterator> 
struct test_parser : qi::grammar<Iterator, dectest::Test(), ascii::space_type> 
{ 
    test_parser() 
     : 
    test_parser::base_type(test, "test") 
    { 
     using qi::fail; 
     using qi::on_error; 
     using qi::lit; 
     using qi::lexeme; 
     using ascii::char_; 
     using qi::repeat; 
     using namespace qi::labels; 
     using boost::phoenix::construct; 
     using boost::phoenix::at_c; 
     using boost::phoenix::push_back; 
     using boost::phoenix::val; 
     using boost::phoenix::ref; 
     using qi::space; 

     char qq;   

     arrow = lit("->"); 

     open_quote = (char_('\'') | char_('"')) [ref(qq) = _1]; // Remember what the opening quote was 
     close_quote = lit(val(qq)); // Close must match the open 
     // close_quote = (char_('\'') | char_('"')); // Enable this line to get code 'almost' working 

     quoted_string = 
      open_quote 
      >> +ascii::alnum   
      >> close_quote; 

     unquoted_string %= +ascii::alnum; 
     any_string %= (quoted_string | unquoted_string); 

     test = 
      unquoted_string    [at_c<0>(_val) = _1] 
      > unquoted_string   [at_c<1>(_val) = _1] 
      > repeat(1,3)[any_string] [at_c<2>(_val) = _1] 
      > arrow 
      > any_string    [at_c<3>(_val) = _1] 
      ; 

     // .. <snip>set rule names 
     on_error<fail>(/* <snip> */); 
     // debug rules 
    } 

    qi::rule<Iterator> arrow; 
    qi::rule<Iterator> open_quote; 
    qi::rule<Iterator> close_quote; 

    qi::rule<Iterator, std::string()> quoted_string; 
    qi::rule<Iterator, std::string()> unquoted_string; 
    qi::rule<Iterator, std::string()> any_string;  // A quoted or unquoted string 

    qi::rule<Iterator, dectest::Test(), ascii::space_type> test; 

}; 


// main() 
// This example should fail at the very end 
// (ie not parse "str3' because of the mismatched quote 
// However, it fails to parse the closing quote of str1 
typedef boost::tuple<string, string, vector<string>, string> DataT; 
DataT data; 
std::string str("addx001 add 'str1' \"str2\"  -> \"str3'"); 
std::string::const_iterator iter = str.begin(); 
const std::string::const_iterator end = str.end(); 
bool r = phrase_parse(iter, end, grammar, boost::spirit::ascii::space, data); 

:(上記の例ではchar qqなど)ローカル・データ・メンバーを避けるソリューションは好ましいであろうが、実用的な観点から、私は働くものを使用します!

+0

、charが '構造体test_parser'が全く同じように失敗したのメンバ変数をqq''作ります。 – Zero

+0

「同じ方法で」失敗しますか?あなたは私にこのことがどう失敗したかを教えていない(私はそれが 'qq'参照によるものであるとイメージすることができるが)。 –

+0

@NicolBolasそれはコードのコメントでした - 私はそれ以来、質問を明確にしました、指摘してくれてありがとう。私もref(qq)は疑わしいですが、boost lambda&coの欠点は、伝統的な意味で踏み込めないほどデバッグが難しいことです! – Zero

答えて

12

qqへの参照は、コンストラクタから出た後にぶら下がってしまうので、実際問題です。

qi::localsは、パーサー式内の​​ローカルな状態を維持する正規の方法です。もう1つの選択肢は、生涯をqq(それを文法クラスのメンバーにするなど)にすることです。最後に、inherited attributesにも興味があります。このメカニズムは、 'parameters'を使ってルール/文法を呼び出す方法を提供します(局所的な状態を渡します)。

NOTEクリーネオペレータ+の使用と注意事項があります。それは貪欲で、文字列が期待引用で終了されていない場合、構文解析は失敗します。

私は、関連するビットに文法を低減し、いくつかのテストケースを用意しました:

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

namespace qi = boost::spirit::qi; 

template <typename Iterator> 
struct test_parser : qi::grammar<Iterator, std::string(), qi::space_type, qi::locals<char> > 
{ 
    test_parser() : test_parser::base_type(any_string, "test") 
    { 
     using namespace qi; 

     quoted_string = 
       omit [ char_("'\"") [_a =_1] ]    
      >> no_skip [ *(char_ - char_(_a)) ] 
      >> lit(_a) 
     ; 

     any_string = quoted_string | +qi::alnum; 
    } 

    qi::rule<Iterator, std::string(), qi::space_type, qi::locals<char> > quoted_string, any_string; 
}; 

int main() 
{ 
    test_parser<std::string::const_iterator> grammar; 
    const char* strs[] = { "\"str1\"", 
          "'str2'", 
          "'str3' trailing ok", 
          "'st\"r4' embedded also ok", 
          "str5", 
          "str6'", 
          NULL }; 

    for (const char** it = strs; *it; ++it) 
    { 
     const std::string str(*it); 
     std::string::const_iterator iter = str.begin(); 
     std::string::const_iterator end = str.end(); 

     std::string data; 
     bool r = phrase_parse(iter, end, grammar, qi::space, data); 

     if (r) 
      std::cout << "Parsed: " << str << " --> " << data << "\n"; 
     if (iter!=end) 
      std::cout << "Remaining: " << std::string(iter,end) << "\n"; 
    } 
} 

出力:レコードの

Parsed: "str1" --> str1 
Parsed: 'str2' --> str2 
Parsed: 'str3' trailing ok --> str3 
Remaining: trailing ok 
Parsed: 'st"r4' embedded also ok --> st"r4 
Remaining: embedded also ok 
Parsed: str5 --> str5 
Parsed: str6' --> str6 
Remaining: ' 
+0

ありがとう、これは私が後にしたものです。 地元の人々に関するドキュメンテーション/リンクへのリンクを投稿できるかどうかは、ルールシグニチャの 'qi :: local 'に気付くまでにしばらく時間がかかりました。そうでなければこの質問を見てください。 – Zero

+0

@Zeroありがとう!そして、erm ** ['qi :: locals'](http://www.boost.org/doc/libs/1_48_0/libs/spirit/doc/html/spirit/qi/reference/parser_concepts/nonterminal.html# spirit.qi.reference.parser_concepts.nonterminal.locals)**は私の答えのハイパーリンクでした:) - _click for documentation_ – sehe

+0

@Zero良いサンプルのために、私はあなたの質問にリンクしたページを参照したいと思いますここで:[One More Take](http://www.boost.org/doc/libs/1_49_0/libs/spirit/doc/html/spirit/qi/tutorials/mini_xml___asts_.html#spirit.qi.tutorials.mini_xml___asts_)。 one_more_take) – sehe

関連する問題