Last active
October 12, 2015 02:05
-
-
Save sehe/878c623638750cf32404 to your computer and use it in GitHub Desktop.
Rudimentary stone parser in Boost Spirit
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
all:test | |
CPPFLAGS+=-std=c++1y -Wall -pedantic | |
CPPFLAGS+=-g -O3 | |
#BOOST_DIR=/mnt/LARGE/MODULAR_BOOST/modular-boost | |
BOOST_DIR=/home/sehe/custom/boost | |
CPPFLAGS+=-isystem /home/sehe/custom/nonius/include | |
CPPFLAGS+=-isystem $(BOOST_DIR) | |
# CPPFLAGS+=-fopenmp | |
CPPFLAGS+=-pthread | |
CPPFLAGS+=-march=native | |
LDFLAGS+=-L $(BOOST_DIR)/stage/lib/ -Wl,-rpath,$(BOOST_DIR)/stage/lib | |
LDFLAGS+=-lboost_system -lboost_regex -lboost_thread -lboost_iostreams -lboost_serialization | |
LDFLAGS+=-lboost_date_time | |
# CXX=g++-5 | |
# CXX=/usr/lib/gcc-snapshot/bin/g++ | |
# CC=/usr/lib/gcc-snapshot/bin/gcc | |
CXX=clang++-3.6 -stdlib=libc++ | |
# CC=clang | |
%.S:%.cpp | |
$(CXX) $(CPPFLAGS) $^ -S -masm=intel -o - | egrep -v '\s*\.' | c++filt > $@ | |
%.o:%.cpp | |
$(CXX) $(CPPFLAGS) $^ -c -o $@ | |
%:%.o | |
$(CXX) $(CPPFLAGS) $^ -o $@ $(LDFLAGS) |
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
#include <iostream> | |
#include <vector> | |
// a little hack to get X3 DEBUG to "be nice" | |
#define BOOST_SPIRIT_X3_DEBUG | |
namespace stone { namespace ast { template<typename... Ts> static std::ostream& operator<<(std::ostream& os, std::vector<Ts...> const&) { | |
return os << "(astvector)"; // TODO FIXME | |
} } } | |
namespace std { using ::stone::ast::operator<<; } | |
#include <boost/fusion/adapted/struct.hpp> | |
#include <boost/optional/optional_io.hpp> | |
#include <boost/spirit/home/x3.hpp> | |
#include <boost/spirit/include/support_istream_iterator.hpp> | |
#include <boost/phoenix.hpp> | |
namespace x3 = boost::spirit::x3; | |
namespace stone { namespace ast { | |
using boost::variant; | |
namespace { | |
template <typename Tag> struct Literal; | |
namespace Tags { | |
struct NumberLiteral; | |
struct StringLiteral; | |
} | |
template <> struct Literal<Tags::NumberLiteral> { double value; }; | |
template <> struct Literal<Tags::StringLiteral> { std::string value; }; | |
} | |
namespace { | |
using Identifier = std::string; | |
using Number = Literal<Tags::NumberLiteral>; | |
using String = Literal<Tags::StringLiteral>; | |
struct UnaryExpr; | |
struct BinaryExpr; | |
using Expression = boost::make_recursive_variant< | |
Number, | |
Identifier, | |
String, | |
boost::recursive_variant_, // refers to Expression itself | |
boost::recursive_wrapper<UnaryExpr>, | |
boost::recursive_wrapper<BinaryExpr> | |
>::type; | |
struct UnaryExpr { | |
char op; // - | |
Expression expr; | |
}; | |
struct BinaryExpr { | |
char op; // +-/* | |
Expression lhs, rhs; | |
}; | |
using Simple = Expression; | |
} | |
namespace { | |
struct IfStatement; | |
struct WhileLoop; | |
using Statement = boost::make_recursive_variant< | |
boost::recursive_wrapper<IfStatement>, | |
boost::recursive_wrapper<WhileLoop>, | |
Simple | |
>::type; | |
using Block = std::vector<Statement>; | |
struct IfStatement { | |
Expression condition; | |
Block true_branch; | |
boost::optional<Block> false_branch; | |
}; | |
struct WhileLoop { | |
Expression condition; | |
Block body; | |
}; | |
} | |
using Program = Block; | |
} } | |
#include <boost/type_index.hpp> | |
namespace stone { namespace operations { | |
struct dump_ast { | |
using result_type = void; | |
std::ostream& os_; | |
template <typename... Ts> void operator()(boost::variant<Ts...> const& v) { | |
boost::apply_visitor(*this, v); | |
} | |
void operator()(ast::Program const& v) { | |
os_ << "{ "; | |
for (auto& s : v) { | |
(*this)(s); | |
os_ << "; "; | |
} | |
os_ << "} "; | |
} | |
void operator()(ast::Number const& v) { os_ << v.value; } | |
void operator()(ast::String const& v) { os_ << '"' << v.value << '"'; } | |
void operator()(ast::Identifier const& v) { os_ << '[' << v << ']'; } | |
void operator()(ast::WhileLoop const& stmt) { | |
os_ << "while "; | |
(*this)(stmt.condition); | |
(*this)(stmt.body); | |
} | |
void operator()(ast::IfStatement const& stmt) { | |
os_ << "if "; | |
(*this)(stmt.condition); | |
(*this)(stmt.true_branch); | |
if (stmt.false_branch) { | |
os_ << " else "; | |
(*this)(*stmt.false_branch); | |
} | |
} | |
void operator()(ast::UnaryExpr const& e) { | |
os_ << "(" << e.op << " "; | |
(*this)(e.expr); | |
os_ << ")"; | |
} | |
void operator()(ast::BinaryExpr const& e) { | |
os_ << "("; | |
(*this)(e.lhs); | |
os_ << e.op << " "; | |
(*this)(e.rhs); | |
os_ << ")"; | |
} | |
}; | |
} } | |
BOOST_FUSION_ADAPT_TPL_STRUCT( (Tag), (stone::ast::Literal) (Tag), value) | |
BOOST_FUSION_ADAPT_STRUCT(stone::ast::IfStatement, condition, true_branch, false_branch) | |
BOOST_FUSION_ADAPT_STRUCT(stone::ast::WhileLoop, condition, body) | |
BOOST_FUSION_ADAPT_STRUCT(stone::ast::BinaryExpr, lhs, op, rhs) | |
BOOST_FUSION_ADAPT_STRUCT(stone::ast::UnaryExpr, op, expr) | |
namespace stone { namespace grammar { | |
using boost::fusion::at_c; | |
x3::rule<class Start, ast::Program> start = "start"; | |
x3::rule<class Program, ast::Program> program = "program"; | |
x3::rule<class Block, ast::Block> block = "block"; | |
x3::rule<class Statement, ast::Statement> statement = "statement"; | |
x3::rule<class IfStatement, ast::IfStatement> ifstatement = "ifstatement"; | |
x3::rule<class WhileLoop, ast::WhileLoop> whileloop = "whileloop"; | |
x3::rule<class Simple, ast::Simple> simple = "simple"; | |
x3::rule<class Expression, ast::Expression> expression = "expression"; | |
x3::rule<class UnaryExpr, ast::UnaryExpr> unaryexpr = "unaryexpr"; | |
x3::rule<class Identifier, ast::Identifier> identifier = "identifier"; | |
x3::rule<class Number, ast::Number> number = "number"; | |
x3::rule<class String, ast::String> string = "string"; | |
// precedence helpers | |
x3::rule<class E_Top, ast::Expression> e_top = "e_top"; | |
x3::rule<class E_Factor, ast::Expression> e_factor = "e_factor"; | |
x3::rule<class E_Term, ast::Expression> e_term = "e_term"; | |
x3::rule<class E_Simple, ast::Expression> e_simple = "e_simple"; | |
const auto start_def = x3::skip(x3::blank) [program]; | |
const auto program_def = -statement % (x3::eol|';'); | |
const auto statement_def = ifstatement | whileloop | simple; | |
const auto simple_def = !x3::eoi >> expression; | |
const auto ifstatement_def = "if" >> expression >> block >> -("else" >> block); | |
const auto whileloop_def = "while" >> expression >> block; | |
const auto block_def = '{' >> program >> '}'; | |
const auto expression_def = e_top; | |
const auto e_simple_def = '(' >> expression >> ')' | number | string | identifier; | |
auto const make_binop = [](auto& ctx) { | |
auto& lhs = at_c<0>(_attr(ctx)); | |
auto& op = at_c<1>(_attr(ctx)); | |
auto& rhs = at_c<2>(_attr(ctx)); | |
_val(ctx) = ast::BinaryExpr { op, lhs, rhs }; | |
}; | |
auto const propagate = [](auto& ctx) { _val(ctx) = _attr(ctx); }; // _val = _1 | |
const auto e_top_def = (e_factor >> x3::char_("*/") >> e_top) [make_binop] | e_factor [ propagate ]; | |
const auto e_factor_def = (e_term >> x3::char_("-+") >> e_factor) [make_binop] | e_term [ propagate ]; | |
const auto e_term_def = unaryexpr | e_simple; | |
const auto unaryexpr_def = x3::char_('-') >> e_simple; | |
const auto number_def = x3::real_parser<double, x3::ureal_policies<double> >(); | |
const auto string_def = x3::lexeme [ '"' >> *~x3::char_('"') >> '"' ]; | |
const auto identifier_def = x3::lexeme [ x3::alpha >> *(x3::alnum | x3::char_('_')) ]; | |
BOOST_SPIRIT_DEFINE(start, program, statement, simple, | |
ifstatement, whileloop, block, expression, e_simple, | |
e_top, e_factor, e_term, unaryexpr, | |
number, string, identifier) | |
} } | |
#include <fstream> | |
int main(int argc, char **argv) { | |
using It = boost::spirit::istream_iterator; | |
stone::operations::dump_ast dumper{std::cout}; | |
for (auto const fname : boost::make_iterator_range(argv+1, argv+argc)) { | |
std::ifstream ifs(fname, std::ios::binary); | |
It first(ifs >> std::noskipws), last; | |
stone::ast::Program parsed_ast; | |
bool ok = x3::parse(first, last, stone::grammar::start, parsed_ast); | |
if (ok) | |
{ | |
std::cout << "File " << fname << " was parsed succesfully: "; | |
dumper(parsed_ast); | |
std::cout << "\n"; | |
} | |
else | |
std::cout << "File " << fname << " failed to parse\n"; | |
if (first!=last) | |
std::cout << "Warning: trailing unparsed input '" << std::string(first, last) << "'\n"; | |
} | |
} |
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
1; if IsValid { | |
make | |
noise; | |
while 2 * (8+1)/"something else that is unimportant" { | |
shoot; cannon | |
} | |
} else { cry_in_7_corners_; } | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment