Skip to content

Instantly share code, notes, and snippets.

@cviebig
Created October 9, 2015 14:35
Show Gist options
  • Save cviebig/32510a8e57edd0b545c8 to your computer and use it in GitHub Desktop.
Save cviebig/32510a8e57edd0b545c8 to your computer and use it in GitHub Desktop.
Encapsulating alternatives (2) separate AST nodes
/*=============================================================================
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 select_stmt : boost::spirit::x3::position_tagged
{
char a;
};
struct explain_clause : boost::spirit::x3::position_tagged {
bool explain;
bool query_plan;
};
struct sql_stmt : boost::spirit::x3::position_tagged
{
explain_clause explain;
select_stmt stmt;
};
}}
BOOST_FUSION_ADAPT_STRUCT(sql::ast::select_stmt,
a
)
BOOST_FUSION_ADAPT_STRUCT(sql::ast::explain_clause,
(bool, explain)
(bool, query_plan)
)
BOOST_FUSION_ADAPT_STRUCT(sql::ast::sql_stmt,
(sql::ast::explain_clause, explain)
(sql::ast::select_stmt, stmt)
)
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 ";
}
}
}
void operator()(ast::sql_stmt const& ast) const
{
sql_printer{out}(ast.explain);
sql_printer{out}(ast.stmt);
}
void operator()(ast::select_stmt const& ast) const
{
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 select_stmt_class;
struct explain_clause_class;
struct sql_stmt_class;
x3::rule<select_stmt_class, ast::select_stmt> const
select_stmt = "select_stmt";
x3::rule<explain_clause_class, ast::explain_clause> const
explain_clause = "explain_clause";
x3::rule<sql_stmt_class, ast::sql_stmt> const
sql_stmt = "sql_stmt";
auto const select_stmt_def = char_;
auto const explain_clause_def = (omit[lit("EXPLAIN")] >> attr(true) >> matches[lit("QUERY") >> lit("PLAN")])
| (attr(false) >> attr(false));
auto const sql_stmt_def = explain_clause_def >> select_stmt_def;
BOOST_SPIRIT_DEFINE(select_stmt, explain_clause, sql_stmt);
}}
///////////////////////////////////////////////////////////////////////////////
// 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::sql_stmt; // Our grammar
sql::ast::sql_stmt ast; // Our tree
using boost::spirit::x3::ascii::space;
auto iter(str.begin());
auto const end(str.end());
if (phrase_parse(iter, end, sql_stmt, 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