2

このタイプの構文を持つ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:

私は今、forLoop内ではなく、commandString(以下ではnestedBlockと呼ばれます)からの再帰を処理する方がよいと考えています。

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;

関数はboost::variantsの構造体です

編集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は、boost ::fusion::vectorに格納する必要がある0個以上のコマンドとして定義されています。ただし、Function()構造体からベクトルを抽出する場合(開始ルールがFunction()イテレーターを使用することを念頭に置いて)、何らかの理由で型がboost ::fusion :: vectorとして識別されないため、抽出されました。理由はわかりません...

しかし、もし私が

commandCollection %= start;

ルールを次のようにデカールします

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

次に、データを単一のFunction()構造体として抽出しようとすると、正常に機能します。ただし、複数のコマンド(* start)をある種のコンテナーに格納したいと思います。std :: vectorも試してみましたが、これも失敗しました。

4

1 に答える 1

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/>
于 2013-03-06T14:00:47.437 に答える