I have several commands in a script language, so I need to parse them. During parsing, I would like to check that syntax is correct and the type of commands and its arguments (there is a variable number of arguments per script command type, so I use a std::vector<std::string>
to store them).
I have had problems because when parsing, Only the first string is included into the vector, whatever the real numbers of strings exists.
Also, I have had to use a qi::as_string
rule in all the arguments in order compiler works.
A minimal working example of my project is shown next:
//#define BOOST_SPIRIT_DEBUG
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/spirit/include/qi.hpp>
#include <iomanip>
#include <iostream>
#include <sstream>
namespace qi = boost::spirit::qi;
enum class TYPE {
NONE,
CMD1,
CMD2,
FAIL
};
struct Command {
TYPE type = TYPE::NONE;
std::vector<std::string> args;
};
using Commands = std::vector<Command>;
BOOST_FUSION_ADAPT_STRUCT(Command, type, args)
template <typename It>
class Parser : public qi::grammar<It, Commands()>
{
private:
qi::rule<It, Command(), qi::blank_type> none, cmd1, cmd2, fail;
qi::rule<It, Commands()> start;
public:
Parser() : Parser::base_type(start)
{
using namespace qi;
none = omit[*blank] >> &(eol | eoi)
>> attr(TYPE::NONE)
>> attr(std::vector<std::string>{});
cmd1 = lit("CMD1") >> '('
>> attr(TYPE::CMD1)
>> as_string[lexeme[+~char_(")\r\n")]] >> ')';
cmd2 = lit("CMD2") >> '('
>> attr(TYPE::CMD2)
>> as_string[lexeme[+~char_(",)\r\n")]] >> ','
>> as_string[raw[double_]] >> ')';
fail = omit[*~char_("\r\n")] //
>> attr(TYPE::FAIL);
start = skip(blank)[(none | cmd1 | cmd2 | fail) % eol] > eoi;
}
};
Commands parse(std::string text)
{
std::istringstream in(std::move(text));
using It = boost::spirit::istream_iterator;
static const Parser<It> parser;
Commands commands;
It first(in >> std::noskipws), last;//No white space skipping
if (!qi::parse(first, last, parser, commands))
// throw std::runtime_error("command parse error")
;
return commands;
}
int main()
{
std::string test{
R"(CMD1(some ad hoc text)
CMD2(identity, 25.5))"};
try {
auto commands = parse(test);
std::cout << "elements: " << commands.size() << std::endl;
std::cout << "CMD1 args: " << commands[0].args.size() << std::endl;
std::cout << "CMD2 args: " << commands[1].args.size() << std::endl;// Error! Should be 2!!!!!
} catch (std::exception const& e) {
std::cout << e.what() << "\n";
}
}
Also, here is a link to compiler explorer: https://godbolt.org/z/qM6KTcTTK
Any help fixing this? Thanks in advance