Skip to content

Instantly share code, notes, and snippets.

@cviebig
Created October 9, 2015 14:06
Show Gist options
  • Save cviebig/4daf7fb690ed7e4c5f1f to your computer and use it in GitHub Desktop.
Save cviebig/4daf7fb690ed7e4c5f1f to your computer and use it in GitHub Desktop.
/*=============================================================================
Copyright (c) 2001-2015 Joel de Guzman
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
=============================================================================*/
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/position_tagged.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/std_pair.hpp>
#include <boost/fusion/include/io.hpp>
#include <iostream>
#include <fstream>
#include <string>
#include <map>
namespace sql { namespace ast
{
struct explain_clause : boost::spirit::x3::position_tagged {
bool explain;
bool query_plan;
char a;
};
}}
BOOST_FUSION_ADAPT_STRUCT(sql::ast::explain_clause,
(bool, explain)
(bool, query_plan)
(char, a)
)
namespace sql { namespace ast
{
struct sql_printer
{
sql_printer(std::ostream& out)
: out(out) {}
void operator()(ast::explain_clause const& ast) const
{
if(ast.explain) {
out << "EXPLAIN ";
if(ast.query_plan) {
out << "QUERY PLAN ";
}
}
out << ast.a;
}
std::ostream& out;
};
}}
namespace sql { namespace parser
{
namespace x3 = boost::spirit::x3;
namespace ascii = boost::spirit::x3::ascii;
using x3::attr;
using x3::lit;
using x3::matches;
using x3::omit;
using x3::char_;
struct explain_clause_class;
x3::rule<explain_clause_class, ast::explain_clause> const
explain_clause = "explain_clause";
// proof that the ast is configured correctly:
// auto const explain_clause_def = (attr(true) >> attr(false)) >> char_;
// auto const explain_clause_def = attr(true) >> attr(false) >> char_;
// this one is the problem:
// auto const explain_clause_def = ((omit[lit("EXPLAIN")] >> attr(true) >> matches[lit("QUERY") >> lit("PLAN")])
// | (attr(false) >> attr(false))) >> char_;
// I would expect that it is able to parse char, EXPLAIN char or EXPLAIN QUERY char. but it fails to compile
// in turn __duplicating__ the char_ parser makes it work:
auto const explain_clause_def = ((omit[lit("EXPLAIN")] >> attr(true) >> matches[lit("QUERY") >> lit("PLAN")]) >> char_)
| ((attr(false) >> attr(false)) >> char_);
// but shouldn't the first case be valid too, because of the encapsulation in braces?
BOOST_SPIRIT_DEFINE(explain_clause);
}}
///////////////////////////////////////////////////////////////////////////////
// Main program
///////////////////////////////////////////////////////////////////////////////
int main(int argc, char **argv)
{
std::cout << "Give input to parse or type [q or Q] to quit\n\n";
std::string str;
while (getline(std::cin, str))
{
if (str.empty() || str[0] == 'q' || str[0] == 'Q')
break;
using sql::parser::explain_clause; // Our grammar
sql::ast::explain_clause ast; // Our tree
using boost::spirit::x3::ascii::space;
auto iter(str.begin());
auto const end(str.end());
if (phrase_parse(iter, end, explain_clause, space, ast)) {
if(iter == end) {
std::cout << "Parsing succeeded and the whole string was consumed\n";
} else {
std::cout << "Parsing succeeded but only a part of the string was consumed\n";
}
sql::ast::sql_printer printer(std::cout);
printer(ast);
std::cout << "\n";
} else {
std::cout << "Parsing failed\n";
}
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment