Created
October 9, 2015 14:35
-
-
Save cviebig/c1887c89b23b2958d179 to your computer and use it in GitHub Desktop.
Encapsulating alternatives (3) Shared AST node
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*============================================================================= | |
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 sql_stmt : boost::spirit::x3::position_tagged | |
{ | |
bool explain; | |
bool query_plan; | |
select_stmt stmt; | |
}; | |
}} | |
BOOST_FUSION_ADAPT_STRUCT(sql::ast::select_stmt, | |
a | |
) | |
BOOST_FUSION_ADAPT_STRUCT(sql::ast::sql_stmt, | |
(bool, explain) | |
(bool, query_plan) | |
(sql::ast::select_stmt, stmt) | |
) | |
namespace sql { namespace ast | |
{ | |
struct sql_printer | |
{ | |
sql_printer(std::ostream& out) | |
: out(out) {} | |
void operator()(ast::sql_stmt const& ast) const | |
{ | |
if(ast.explain) { | |
out << "EXPLAIN "; | |
if(ast.query_plan) { | |
out << "QUERY PLAN "; | |
} | |
} | |
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 sql_stmt_class; | |
x3::rule<select_stmt_class, ast::select_stmt> const | |
select_stmt = "select_stmt"; | |
x3::rule<sql_stmt_class, ast::sql_stmt> const | |
sql_stmt = "sql_stmt"; | |
auto const select_stmt_def = char_; | |
// This fails the same way as minast2 does: | |
// auto const explain_clause = (omit[lit("EXPLAIN")] >> attr(true) >> matches[lit("QUERY") >> lit("PLAN")]) | |
// | (attr(false) >> attr(false)); | |
// auto const sql_stmt_def = explain_clause >> select_stmt_def; | |
// Again it works, if we duplicate the select_stmt_def and put it into both branches of the alternative: | |
auto const explain_clause = ((omit[lit("EXPLAIN")] >> attr(true) >> matches[lit("QUERY") >> lit("PLAN")]) >> select_stmt_def) | |
| ((attr(false) >> attr(false)) >> select_stmt_def); | |
auto const sql_stmt_def = explain_clause; | |
BOOST_SPIRIT_DEFINE(select_stmt, 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