Dav*_* O. 2 c++ parsing boost boost-spirit qi
我正在尝试使用Boost :: Spirit解析字符串,但是我无法使其正常工作。从今天开始,我没有使用Boost :: Spirit的经验。
该字符串由用“;”分隔的命令组成。这些命令是
“ INC someInteger”
“ BOMB第一整数第二整数”
“移动第一整数第二整数第三第三整数”
“ MSG someString”
“等待”
我设法做到了这一点:
#include <boost/spirit/include/qi.hpp>
#include <boost/phoenix/phoenix.hpp>
using namespace boost::spirit;
int main() {
std::string testInput = "MOVE 1 2 43;BOMB 0 3;INC 6;MOVE 2 3 99;MOVE 1 2 6";
typedef std::string::iterator iter;
using boost::phoenix::ref;
iter start = testInput.begin();
std::vector<int> IncCommands;
std::vector<std::pair<int, int>> BombCommands;
std::vector<std::tuple<int, int, int>> MoveCommands;
qi::rule<iter, std::vector<int>(), ascii::space_type> nextIncrease = ("INC " >> qi::int_);
//qi::rule<iter, std::vector<std::pair<int, int>>(), ascii::space_type> nextBomb = ("BOMB " >> qi::int_ >> qi::int_);
//qi::rule<iter, std::vector<int>(), ascii::space_type> nextMove = ("MOVE " >> qi::int_ >> qi::int_ >> qi::int_);
//qi::rule<iter, std::string, ascii::space_type> nextAction = (nextMove | nextBomb | nextIncrease) % ';';
bool match = qi::phrase_parse(
start,
testInput.end(),
nextIncrease,
ascii::space,
IncCommands
);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我现在遇到的问题:
我不知道我怎么能提取多个整数
我不知道如何将所有内容合并为适当的语法,以便将所有内容解析为多个向量。
我还没有考虑过味精和等待。
我建议像往常一样从所需的AST开始。
Spirit可与静态多态性很好地配合使用,因此我将使用一个变体来表示命令:
namespace AST {
namespace Cmd {
struct Move { int x,y,z; };
struct Bomb { int x,y; };
struct Inc { int amount; };
struct Msg { std::string text; };
struct Wait {};
}
using Command = boost::variant<Cmd::Move, Cmd::Bomb, Cmd::Inc, Cmd::Msg, Cmd::Wait>;
using Commands = std::vector<Command>;
}
Run Code Online (Sandbox Code Playgroud)
现在,编写最简单的语法来匹配它:
template <typename It>
struct ScriptGrammar : qi::grammar<It, AST::Commands()>
{
ScriptGrammar() : ScriptGrammar::base_type(start) {
using namespace qi;
start = skip(space) [ script ];
script = command % ";";
command = move|bomb|inc|msg|wait;
move = "MOVE" >> int_ >> int_ >> int_;
bomb = "BOMB" >> int_ >> int_;
inc = "INC" >> int_;
msg = "MSG" >> text;
wait = "WAIT" >> qi::attr(AST::Cmd::Wait{});
text = +~char_(";");
BOOST_SPIRIT_DEBUG_NODES((start)(script)(command)(move)(bomb)(inc)(msg)(wait)(text))
}
private:
using Skipper = qi::space_type;
qi::rule<It, AST::Commands(), Skipper> script;
qi::rule<It, AST::Command(), Skipper> command;
qi::rule<It, AST::Cmd::Move(), Skipper> move;
qi::rule<It, AST::Cmd::Bomb(), Skipper> bomb;
qi::rule<It, AST::Cmd::Inc(), Skipper> inc;
qi::rule<It, AST::Cmd::Msg(), Skipper> msg;
qi::rule<It, AST::Cmd::Wait(), Skipper> wait;
// lexeme
qi::rule<It, AST::Commands()> start;
qi::rule<It, std::string()> text;
};
Run Code Online (Sandbox Code Playgroud)
添加一些用于调试(融合适应和输出流传输)的胶水,我们有一个有效的示例:
#define BOOST_SPIRIT_DEBUG
#include <iostream>
#include <vector>
#include <string>
#include <iterator>
#include <iomanip>
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/phoenix/phoenix.hpp>
namespace AST {
namespace Cmd {
struct Move { int x,y,z; };
struct Bomb { int x,y; };
struct Inc { int amount; };
struct Msg { std::string text; };
struct Wait {};
}
using Command = boost::variant<Cmd::Move, Cmd::Bomb, Cmd::Inc, Cmd::Msg, Cmd::Wait>;
using Commands = std::vector<Command>;
}
BOOST_FUSION_ADAPT_STRUCT(AST::Cmd::Move, x,y,z)
BOOST_FUSION_ADAPT_STRUCT(AST::Cmd::Bomb, x,y)
BOOST_FUSION_ADAPT_STRUCT(AST::Cmd::Inc, amount)
BOOST_FUSION_ADAPT_STRUCT(AST::Cmd::Msg, text)
BOOST_FUSION_ADAPT_STRUCT(AST::Cmd::Wait)
namespace AST { namespace Cmd { // For demo/debug
std::ostream& operator<<(std::ostream& os, Move const& cmd) { return os << "MOVE " << boost::fusion::as_vector(cmd); }
std::ostream& operator<<(std::ostream& os, Bomb const& cmd) { return os << "BOMB " << boost::fusion::as_vector(cmd); }
std::ostream& operator<<(std::ostream& os, Inc const& cmd) { return os << "INC " << boost::fusion::as_vector(cmd); }
std::ostream& operator<<(std::ostream& os, Msg const& cmd) { return os << "MSG " << boost::fusion::as_vector(cmd); }
std::ostream& operator<<(std::ostream& os, Wait const& cmd) { return os << "WAIT " << boost::fusion::as_vector(cmd); }
} }
namespace qi = boost::spirit::qi;
template <typename It>
struct ScriptGrammar : qi::grammar<It, AST::Commands()>
{
ScriptGrammar() : ScriptGrammar::base_type(start) {
using namespace qi;
start = skip(space) [ script ];
script = command % ";";
command = move|bomb|inc|msg|wait;
move = "MOVE" >> int_ >> int_ >> int_;
bomb = "BOMB" >> int_ >> int_;
inc = "INC" >> int_;
msg = "MSG" >> text;
wait = "WAIT" >> qi::attr(AST::Cmd::Wait{});
text = +~char_(";");
BOOST_SPIRIT_DEBUG_NODES((start)(script)(command)(move)(bomb)(inc)(msg)(wait)(text))
}
private:
using Skipper = qi::space_type;
qi::rule<It, AST::Commands(), Skipper> script;
qi::rule<It, AST::Command(), Skipper> command;
qi::rule<It, AST::Cmd::Move(), Skipper> move;
qi::rule<It, AST::Cmd::Bomb(), Skipper> bomb;
qi::rule<It, AST::Cmd::Inc(), Skipper> inc;
qi::rule<It, AST::Cmd::Msg(), Skipper> msg;
qi::rule<It, AST::Cmd::Wait(), Skipper> wait;
// lexeme
qi::rule<It, AST::Commands()> start;
qi::rule<It, std::string()> text;
};
int main() {
std::string const testInput = "MOVE 1 2 43;BOMB 0 3;INC 6;MOVE 2 3 99;MSG MOVE ZIG;WAIT;MSG FOR GREAT JUSTICE!;MOVE 1 2 6";
typedef std::string::const_iterator iter;
iter start = testInput.begin(), end = testInput.end();
AST::Commands script;
bool match = qi::parse(start, testInput.end(), ScriptGrammar<iter>(), script);
if (match) {
std::cout << "Parsed " << script.size() << " commands\n";
std::copy(script.begin(), script.end(), std::ostream_iterator<AST::Command>(std::cout, ";"));
} else {
std::cout << "Parse failed\n";
}
if (start != end)
std::cout << "Remaining unparsed input: '" << std::string(start, end) << "'\n";
}
Run Code Online (Sandbox Code Playgroud)
哪些打印:
Parsed 8 commands
MOVE (1 2 43);BOMB (0 3);INC (6);MOVE (2 3 99);MSG (MOVE ZIG);WAIT ();MSG (FOR GREAT JUSTICE!);MOVE (1 2 6);
Run Code Online (Sandbox Code Playgroud)
以及可选的BOOST_SPIRIT_DEBUG输出:
namespace AST {
namespace Cmd {
struct Move { int x,y,z; };
struct Bomb { int x,y; };
struct Inc { int amount; };
struct Msg { std::string text; };
struct Wait {};
}
using Command = boost::variant<Cmd::Move, Cmd::Bomb, Cmd::Inc, Cmd::Msg, Cmd::Wait>;
using Commands = std::vector<Command>;
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
407 次 |
最近记录: |