Skip to content

Instantly share code, notes, and snippets.

@evanzillians
Forked from anonymous/main.cpp
Last active December 10, 2015 04:08
Show Gist options
  • Save evanzillians/4379037 to your computer and use it in GitHub Desktop.
Save evanzillians/4379037 to your computer and use it in GitHub Desktop.
Parser using Spirit.Qi which generate additional information as token.
#ifndef ITERATOR_HPP
#define ITERATOR_HPP
#include <boost/spirit/include/classic_position_iterator.hpp>
typedef boost::spirit::classic::position_iterator<std::wstring::const_iterator> iterator_type;
#endif /* ITERATOR_HPP */
#include <memory>
#include <boost/spirit/include/qi_action.hpp>
#include <boost/spirit/include/qi_core.hpp>
#include <boost/spirit/include/qi_eps.hpp>
#include "iterator.hpp"
#include "nodes.hpp"
#include "lex_and_qi_grammar.hpp"
#include "lex_and_qi_lexer.hpp"
#include "lex_and_qi_phoenix_helper.hpp"
#include "lex_and_qi_token_value.hpp"
#include "lex_and_qi_token_value_converter.hpp"
namespace qi = boost::spirit::qi;
namespace lex_and_qi {
template<typename iterator>
inline grammar<iterator>::grammar(const lexer<iterator> &lexer)
: grammar::base_type(start)
{
using qi::_1;
using qi::_2;
using qi::_3;
using qi::_4;
using qi::_val;
using qi::eps;
start = function.alias();
function =
(
lexer.kw_function
>> lexer.identifier
>> lexer.delim_lparen
>> lexer.delim_rparen
>> lexer.delim_colon
>> type
>> block
)
[_val = make_shared_with_pos<tree::function>(_1, _2, _3, _4)]
;
block =
(
lexer.delim_lbrace
>> *((expression >> lexer.delim_semi))
>> lexer.delim_rbrace
)
[_val = make_shared_with_pos<tree::block>(_1, _2)]
;
expression =
lexer.lit_int[_val = _1]
>> (
(lexer.op_add >> expression)[_val = make_shared_with_pos<tree::binary_expr>(_1, tree::binary_expr::ADD, _val, _2)]
| (lexer.op_sub >> expression)[_val = make_shared_with_pos<tree::binary_expr>(_1, tree::binary_expr::SUB, _val, _2)]
| eps
)
;
type =
lexer.kw_void[_val = make_shared_with_pos<tree::type>(_1, tree::type::VOID)]
| lexer.kw_bool[_val = make_shared_with_pos<tree::type>(_1, tree::type::BOOL)]
| lexer.kw_int [_val = make_shared_with_pos<tree::type>(_1, tree::type::INT )]
;
}
}
template struct lex_and_qi::grammar<iterator_type>;
#ifndef LEX_AND_QI_GRAMMAR_HPP
#define LEX_AND_QI_GRAMMAR_HPP
#include <memory>
#include <boost/spirit/include/qi_grammar.hpp>
#include <boost/spirit/include/qi_rule.hpp>
#include "nodes.hpp"
#include "lex_and_qi_lexer.hpp"
namespace lex_and_qi {
template<typename iterator>
struct grammar : boost::spirit::qi::grammar<typename lexer<iterator>::iterator_type, std::shared_ptr<tree::function>()> {
template<typename value_type>
using rule = boost::spirit::qi::rule<typename grammar::iterator_type, value_type()>;
explicit grammar(const lexer<iterator> &lexer);
rule<std::shared_ptr<tree::function >> start;
rule<std::shared_ptr<tree::function >> function;
rule<std::shared_ptr<tree::block >> block;
rule<std::shared_ptr<tree::expression >> expression;
rule<std::shared_ptr<tree::type >> type;
};
}
#endif /* LEX_AND_QI_GRAMMAR_HPP */
#include <boost/spirit/include/lex.hpp>
#include "iterator.hpp"
#include "lex_and_qi_lexer.hpp"
namespace lex_and_qi {
template<typename iterator>
inline lexer<iterator>::lexer()
{
namespace lex = boost::spirit::lex;
op_add = L'+';
op_sub = L'-';
delim_lparen = L'(';
delim_rparen = L')';
delim_lbrace = L'{';
delim_rbrace = L'}';
delim_colon = L':';
delim_semi = L';';
kw_void = L"void" ;
kw_bool = L"bool" ;
kw_int = L"int" ;
kw_return = L"return" ;
kw_function = L"function";
lit_int = L"0|[1-9][0-9]*";
identifier = L"[a-zA-Z_][a-zA-Z_0-9]*";
this->self +=
op_add
| op_sub
| delim_lparen
| delim_rparen
| delim_lbrace
| delim_rbrace
| delim_colon
| delim_semi
| kw_void
| kw_bool
| kw_int
| kw_return
| kw_function
| lit_int
| identifier
| lex::string(L"\\/\\*[^*]*\\*+([^/*][^*]*\\*+)*\\/")[lex::_pass = lex::pass_flags::pass_ignore]
| lex::string(L"[ \t\n\r]+" )[lex::_pass = lex::pass_flags::pass_ignore]
;
}
}
template struct lex_and_qi::lexer<iterator_type>;
#ifndef LEX_AND_QI_LEXER_HPP
#define LEX_AND_QI_LEXER_HPP
#include <memory>
#include <boost/mpl/vector.hpp>
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/lex_lexertl_position_token.hpp>
#include "lex_and_qi_token_value.hpp"
#include "nodes.hpp"
namespace lex_and_qi {
namespace detail {
template<typename iterator>
struct lexer_def {
typedef boost::mpl::vector<
position,
std::shared_ptr<tree::integer_literal>,
std::shared_ptr<tree::identifier>
> value_types;
typedef boost::spirit::lex::lexertl::position_token<
iterator,
value_types,
boost::mpl::false_
> token_type;
typedef boost::spirit::lex::lexertl::actor_lexer<token_type> lexer_type;
};
}
template<typename iterator>
struct lexer : boost::spirit::lex::lexer<typename detail::lexer_def<iterator>::lexer_type> {
template<typename value_type>
using token_def = boost::spirit::lex::token_def<value_type, typename iterator::value_type>;
using omit = boost::spirit::lex::omit;
lexer();
token_def<position> kw_void;
token_def<position> kw_bool;
token_def<position> kw_int;
token_def<position> kw_return;
token_def<position> kw_function;
token_def<position> op_add;
token_def<position> op_sub;
token_def<omit > delim_lparen;
token_def<omit > delim_rparen;
token_def<position> delim_lbrace;
token_def<omit > delim_rbrace;
token_def<omit > delim_colon;
token_def<omit > delim_semi;
token_def<std::shared_ptr<tree::integer_literal>> lit_int;
token_def<std::shared_ptr<tree::identifier>> identifier;
};
}
#endif /* LEX_AND_QI_LEXER_HPP */
#include <memory>
#include <boost/spirit/include/lex_lexer.hpp>
#include <boost/spirit/include/qi_core.hpp>
#include "iterator.hpp"
#include "nodes.hpp"
#include "lex_and_qi_grammar.hpp"
#include "lex_and_qi_lexer.hpp"
#include "lex_and_qi_parse.hpp"
namespace lex_and_qi {
namespace lex = boost::spirit::lex;
namespace qi = boost::spirit::qi;
struct accepter {
template<typename token_type>
bool operator()(const token_type &token) const
{
return true;
}
};
std::shared_ptr<tree::function> tokenize(const std::wstring &source) {
typedef lexer<iterator_type> lexer_type;
typedef grammar<iterator_type> grammar_type;
iterator_type begin(source.begin(), source.end());
iterator_type end;
lexer_type lexer;
grammar_type grammar(lexer);
auto token_begin = lexer.begin(begin, end);
auto token_end = lexer.end();
std::shared_ptr<tree::function> func;
const bool is_succeeded = qi::parse(token_begin, token_end, grammar, func);
if (is_succeeded && token_begin == token_end)
return func;
else
return std::shared_ptr<tree::function>();
}
}
#ifndef LEX_AND_QI_PARSE_HPP
#define LEX_AND_QI_PARSE_HPP
#include <memory>
#include "nodes.hpp"
namespace lex_and_qi {
std::shared_ptr<tree::function> tokenize(const std::wstring &source);
}
#endif /* LEX_AND_QI_PARSE_HPP */
#ifndef LEX_AND_QI_PHOENIX_HELPER_HPP
#define LEX_AND_QI_PHOENIX_HELPER_HPP
#include <memory>
#include <boost/spirit/include/phoenix_core.hpp>
namespace lex_and_qi {
template<typename target_type>
struct make_shared_with_pos_eval {
template<typename evn_type, typename referred_type, typename... arg_types>
struct result {
typedef std::shared_ptr<target_type> type;
};
template<typename result_type, typename env_type, typename referred_type, typename... arg_types>
static result_type eval(const env_type &env, const referred_type &referred_expr, const arg_types &...arg_exprs)
{
auto &&referred = referred_expr.eval(env);
std::shared_ptr<target_type> created_target = std::make_shared<target_type>(arg_exprs.eval(env)...);
created_target->line = referred.line ;
created_target->column = referred.column;
return std::move(created_target);
}
};
template<typename target_type, typename referred_type, typename... arg_types>
boost::phoenix::actor<
typename boost::phoenix::as_composite<
make_shared_with_pos_eval<target_type>,
referred_type,
arg_types...
>::type
> make_shared_with_pos(const referred_type &referred, const arg_types &...args) {
return boost::phoenix::compose<make_shared_with_pos_eval<target_type>>(referred, args...);
}
}
#endif /* LEX_AND_QI_PHOENIX_HELPER_HPP */
#ifndef LEX_AND_QI_TOKEN_VALUE_HPP
#define LEX_AND_QI_TOKEN_VALUE_HPP
namespace lex_and_qi {
struct position {
unsigned line ;
unsigned column;
};
}
#endif /* LEX_AND_QI_TOKEN_VALUE_HPP */
#ifndef LEX_AND_QI_TOKEN_VALUE_CONVERTER_HPP
#define LEX_AND_QI_TOKEN_VALUE_CONVERTER_HPP
#include <memory>
#include <utility>
#include "nodes.hpp"
#include "lex_and_qi_phoenix_helper.hpp"
#include "lex_and_qi_token_value.hpp"
namespace boost { namespace spirit { namespace traits {
template<typename iterator>
struct assign_to_attribute_from_iterators<lex_and_qi::position, iterator> {
static void call(const iterator &first, const iterator &last, lex_and_qi::position &position) {
const auto &temp_position = first.get_position();
position.line = temp_position.line;
position.column = temp_position.column;
}
};
template<typename iterator>
struct assign_to_attribute_from_iterators<std::shared_ptr<tree::integer_literal>, iterator> {
static void call(const iterator &first, const iterator &last, std::shared_ptr<tree::integer_literal> &literal) {
int value = 0;
lex_and_qi::position position;
traits::assign_to(first, last, value );
traits::assign_to(first, last, position);
literal = lex_and_qi::make_shared_with_pos<tree::integer_literal>(position, std::move(value))();
}
};
template<typename iterator>
struct assign_to_attribute_from_iterators<std::shared_ptr<tree::identifier>, iterator> {
static void call(const iterator &first, const iterator &last, std::shared_ptr<tree::identifier> &identifier) {
std::wstring name;
lex_and_qi::position position;
traits::assign_to(first, last, name );
traits::assign_to(first, last, position);
identifier = lex_and_qi::make_shared_with_pos<tree::identifier>(position, std::move(name))();
}
};
} } }
#endif /* LEX_AND_QI_TOKEN_VALUE_CONVERTER_HPP */
#include <iostream>
#include <memory>
#include <string>
#include "nodes.hpp"
#include "lex_and_qi_parse.hpp"
#include "pure_qi_parse.hpp"
void dump_info_impl(const wchar_t *const name, const tree::node &node)
{
std::wcout << L"node<" << name << L">: " << node.line << L", " << node.column << std::endl;
}
void dump_info(const tree::identifier &node)
{
dump_info_impl(L"identifier", node);
std::wcout << L" name: " << node.name << std::endl;
}
void dump_info(const tree::type &node)
{
dump_info_impl(L"type", node);
std::wcout << L" kind: " << node.kind << std::endl;
}
void dump_info(const tree::expression &node)
{
dump_info_impl(L"expression", node);
}
void dump_info(const tree::block &node)
{
dump_info_impl(L"block", node);
for (const std::shared_ptr<tree::expression> &expr: node.exprs)
{
dump_info(*expr);
}
}
void dump_info(const tree::function &node)
{
dump_info_impl(L"function", node);
dump_info(*node.name);
dump_info(*node.result_type);
dump_info(*node.body);
}
int main() {
std::wstring source =
LR"testsource(function functionfff( ):
int
{ 1 + 3; })testsource"
;
std::shared_ptr<tree::function> xxxx = lex_and_qi::tokenize(source);
std::wcout << std::boolalpha << (xxxx != nullptr) << std::endl;
if (xxxx != nullptr)
{
dump_info(*xxxx);
}
std::shared_ptr<tree::function> func = pure_qi::parse(source);
std::wcout << std::boolalpha << (func != nullptr) << std::endl;
if (func != nullptr)
{
dump_info(*func);
}
return 0;
}
#include <memory>
#include <string>
#include <utility>
#include "nodes.hpp"
namespace tree {
node::~node() = default;
identifier::identifier(std::wstring name)
: name(std::move(name))
{
}
type::type(primitive kind)
: kind(kind)
{
}
integer_literal::integer_literal(int value)
: value(value)
{
}
binary_expr::binary_expr(op_type op, const std::shared_ptr<expression> &lhs, const std::shared_ptr<expression> &rhs)
: op(op)
, lhs(lhs)
, rhs(rhs)
{
}
block::block(const std::vector<std::shared_ptr<expression>> &exprs)
: exprs(exprs)
{
}
function::function(const std::shared_ptr<identifier> &name, const std::shared_ptr<type> &result_type, const std::shared_ptr<block> &body)
: name(name)
, result_type(result_type)
, body(body)
{
}
}
#ifndef NODES_HPP
#define NODES_HPP
#include <memory>
#include <string>
#include <vector>
namespace tree {
struct node {
virtual ~node() = 0;
unsigned line = 0;
unsigned column = 0;
};
struct type : node {
enum primitive {
VOID,
BOOL,
INT ,
};
explicit type(primitive kind);
primitive kind;
};
struct identifier : node {
explicit identifier(std::wstring name);
std::wstring name;
};
//struct parameter : node {
// identifier* name = nullptr;
// type* t = nullptr;
//};
struct expression : node {
};
struct integer_literal : expression {
explicit integer_literal(int value);
int value;
};
struct binary_expr : expression {
enum op_type {
ADD,
SUB,
};
binary_expr(op_type op, const std::shared_ptr<expression> &lhs, const std::shared_ptr<expression> &rhs);
op_type op;
std::shared_ptr<expression> lhs;
std::shared_ptr<expression> rhs;
};
struct block : node {
explicit block(const std::vector<std::shared_ptr<expression>> &exprs);
std::vector<std::shared_ptr<expression>> exprs;
};
struct function : node {
function(const std::shared_ptr<identifier> &name, const std::shared_ptr<type> &result_type, const std::shared_ptr<block> &body);
// std::vector<parameter*> parameters;
std::shared_ptr<identifier> name;
std::shared_ptr<type> result_type;
std::shared_ptr<block> body;
};
}
#endif /* NODES_HPP */
#ifndef PURE_QI_CUSTOMIZATION_HPP
#define PURE_QI_CUSTOMIZATION_HPP
#include <boost/spirit/home/support/terminal.hpp>
namespace pure_qi { namespace custom_parser {
BOOST_SPIRIT_TERMINAL(iter_pos);
} }
namespace boost { namespace spirit
{
// We want custom_parser::iter_pos to be usable as a terminal only,
// and only for parser expressions (qi::domain).
template <>
struct use_terminal<qi::domain, pure_qi::custom_parser::tag::iter_pos>
: mpl::true_
{};
} }
namespace pure_qi { namespace custom_parser {
struct iter_pos_parser
: boost::spirit::qi::primitive_parser<iter_pos_parser>
{
// Define the attribute type exposed by this parser component
template <typename Context, typename Iterator>
struct attribute
{
typedef Iterator type;
};
// This function is called during the actual parsing process
template <typename Iterator, typename Context
, typename Skipper, typename Attribute>
bool parse(Iterator& first, Iterator const& last
, Context&, Skipper const& skipper, Attribute& attr) const
{
boost::spirit::qi::skip_over(first, last, skipper);
boost::spirit::traits::assign_to(first, attr);
return true;
}
// This function is called during error handling to create
// a human readable string for the error context.
template <typename Context>
boost::spirit::info what(Context&) const
{
return boost::spirit::info("iter_pos");
}
};
} }
namespace boost { namespace spirit { namespace qi {
// This is the factory function object invoked in order to create
// an instance of our iter_pos_parser.
template <typename Modifiers>
struct make_primitive<pure_qi::custom_parser::tag::iter_pos, Modifiers>
{
typedef pure_qi::custom_parser::iter_pos_parser result_type;
result_type operator()(unused_type, unused_type) const
{
return result_type();
}
};
} } }
#endif /* PURE_QI_CUSTOMIZATION_HPP */
#include <memory>
#include <type_traits>
#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/spirit/include/phoenix_bind.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_function.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/qi_action.hpp>
#include <boost/spirit/include/qi_char.hpp>
#include <boost/spirit/include/qi_char_class.hpp>
#include <boost/spirit/include/qi_as_string.hpp>
#include <boost/spirit/include/qi_eps.hpp>
#include <boost/spirit/include/qi_int.hpp>
#include <boost/spirit/include/qi_lexeme.hpp>
#include <boost/spirit/include/qi_lit.hpp>
#include <boost/spirit/include/qi_nonterminal.hpp>
#include <boost/spirit/include/qi_operator.hpp>
#include "iterator.hpp"
#include "pure_qi_grammar.hpp"
#include "pure_qi_customization.hpp"
#include "pure_qi_tokens.hpp"
namespace pure_qi {
namespace phx = boost::phoenix;
namespace qi = boost::spirit::qi;
namespace {
template<typename target_type>
struct make_shared_with_pos_eval {
template<typename evn_type, typename referred_type, typename... arg_types>
struct result {
typedef std::shared_ptr<target_type> type;
};
template<typename result_type, typename env_type, typename referred_type, typename... arg_types>
static result_type eval(const env_type &env, const referred_type &referred_expr, const arg_types &...arg_exprs)
{
std::shared_ptr<target_type> created_target = std::make_shared<target_type>(arg_exprs.eval(env)...);
set_position(*created_target, referred_expr.eval(env));
return std::move(created_target);
}
template<
typename referred_type,
typename std::enable_if<
std::is_base_of<token_base, referred_type>::value ||
std::is_base_of<tree::node, referred_type>::value
>::type * = nullptr
>
static void set_position(target_type &target, const referred_type &referred)
{
target.line = referred.line;
target.column = referred.column;
}
template<
typename iterator,
typename std::enable_if<
!std::is_base_of<token_base, iterator>::value &&
!std::is_base_of<tree::node, iterator>::value
>::type * = nullptr
>
static void set_position(target_type &target, const iterator &i)
{
const auto &position = i.get_position();
target.line = position.line;
target.column = position.column;
}
};
template<typename target_type, typename referred_type, typename... arg_types>
phx::actor<
typename phx::as_composite<
make_shared_with_pos_eval<target_type>,
referred_type,
arg_types...
>::type
> make_shared_with_pos(const referred_type &referred, const arg_types &...args) {
return phx::compose<make_shared_with_pos_eval<target_type>>(referred, args...);
}
struct store_source_position_impl {
template<typename token_type, typename iterator>
struct result {
typedef void type;
};
template<typename token_type, typename iterator>
typename result<token_type, iterator>::type operator()(token_type &token, const iterator &i) const
{
const auto &position = i.get_position();
token.line = position.line;
token.column = position.column;
}
};
const phx::function<store_source_position_impl> store_source_position;
}
template<typename iterator>
function_grammar<iterator>::function_grammar()
: function_grammar::base_type(start)
{
#define DEF_RULE_KEYWORD(r, data, elem) \
BOOST_PP_CAT(kw_, elem) = \
( \
custom_parser::iter_pos \
>> lit(BOOST_PP_STRINGIZE(elem)) \
) \
[store_source_position(_val, _1)] \
;
#define DEF_RULE_OPERATOR(r, data, elem) \
BOOST_PP_CAT(op_, BOOST_PP_SEQ_ELEM(1, elem)) = \
( \
custom_parser::iter_pos \
>> lit(BOOST_PP_SEQ_ELEM(0, elem)) \
) \
[store_source_position(_val, _1)] \
;
using qi::alpha;
using qi::_1;
using qi::_2;
using qi::_3;
using qi::_4;
using qi::_val;
using qi::as_wstring;
using qi::eps;
using qi::int_;
using qi::lexeme;
using qi::lit;
BOOST_PP_SEQ_FOR_EACH(DEF_RULE_KEYWORD , _, SEQ_KEYWORD );
BOOST_PP_SEQ_FOR_EACH(DEF_RULE_OPERATOR, _, SEQ_OPERATOR);
start = function.alias();
function =
(
kw_function
>> name
>> L'('
>> L')'
>> L':'
>> type
>> block
)
[_val = make_shared_with_pos<tree::function>(_1, _2, _3, _4)]
;
name =
(
custom_parser::iter_pos
>> as_wstring[lexeme[+alpha]]
)
[_val = make_shared_with_pos<tree::identifier>(_1, _2)]
;
type =
kw_void[_val = make_shared_with_pos<tree::type>(_1, tree::type::VOID)]
| kw_bool[_val = make_shared_with_pos<tree::type>(_1, tree::type::BOOL)]
| kw_int [_val = make_shared_with_pos<tree::type>(_1, tree::type::INT )]
;
block =
(
op_left_brace
>> *((expression >> L';'))
>> L'}'
)
[_val = make_shared_with_pos<tree::block>(_1, _2)]
;
expression =
literal[_val = _1]
>> (
(op_add >> expression)[_val = make_shared_with_pos<tree::binary_expr>(_1, tree::binary_expr::ADD, _val, _2)]
| (op_sub >> expression)[_val = make_shared_with_pos<tree::binary_expr>(_1, tree::binary_expr::SUB, _val, _2)]
| eps
)
;
literal =
integer_literal
;
integer_literal =
(
custom_parser::iter_pos
>> int_
)
[_val = make_shared_with_pos<tree::integer_literal>(_1, _2)]
;
}
}
template struct pure_qi::function_grammar<iterator_type>;
#ifndef PURE_QI_GRAMMAR_HPP
#define PURE_QI_GRAMMAR_HPP
#include <memory>
#include <boost/spirit/include/qi_char_class.hpp>
#include <boost/spirit/include/qi_grammar.hpp>
#include <boost/spirit/include/qi_rule.hpp>
#include "nodes.hpp"
#include "pure_qi_tokens.hpp"
namespace pure_qi {
template<typename iterator>
struct function_grammar : boost::spirit::qi::grammar<iterator, std::shared_ptr<tree::function>(), boost::spirit::qi::ascii::space_type>
{
function_grammar();
boost::spirit::qi::rule<iterator, std::shared_ptr<tree::function >(), boost::spirit::qi::ascii::space_type> start;
boost::spirit::qi::rule<iterator, std::shared_ptr<tree::function >(), boost::spirit::qi::ascii::space_type> function;
boost::spirit::qi::rule<iterator, std::shared_ptr<tree::identifier >(), boost::spirit::qi::ascii::space_type> name;
boost::spirit::qi::rule<iterator, std::shared_ptr<tree::type >(), boost::spirit::qi::ascii::space_type> type;
boost::spirit::qi::rule<iterator, std::shared_ptr<tree::block >(), boost::spirit::qi::ascii::space_type> block;
boost::spirit::qi::rule<iterator, std::shared_ptr<tree::expression >(), boost::spirit::qi::ascii::space_type> expression;
boost::spirit::qi::rule<iterator, std::shared_ptr<tree::expression >(), boost::spirit::qi::ascii::space_type> literal;
boost::spirit::qi::rule<iterator, std::shared_ptr<tree::integer_literal>(), boost::spirit::qi::ascii::space_type> integer_literal;
#define DECL_RULE_KEYWORD(r, data, elem) \
boost::spirit::qi::rule< \
iterator, \
BOOST_PP_CAT(token_, elem) (), \
boost::spirit::qi::ascii::space_type \
> BOOST_PP_CAT(kw_, elem);
#define DECL_RULE_OPERATOR(r, data, elem) \
boost::spirit::qi::rule< \
iterator, \
BOOST_PP_CAT(token_, BOOST_PP_SEQ_ELEM(1, elem)) (), \
boost::spirit::qi::ascii::space_type \
> BOOST_PP_CAT(op_, BOOST_PP_SEQ_ELEM(1, elem));
BOOST_PP_SEQ_FOR_EACH(DECL_RULE_KEYWORD , _, SEQ_KEYWORD );
BOOST_PP_SEQ_FOR_EACH(DECL_RULE_OPERATOR, _, SEQ_OPERATOR);
#undef DECL_RULE_OPERATOR
#undef DECL_RULE_KEYWORD
};
}
#endif /* PURE_QI_GRAMMAR_HPP */
#include <memory>
#include <string>
#include <boost/spirit/include/qi_parse.hpp>
#include "iterator.hpp"
#include "pure_qi_grammar.hpp"
#include "pure_qi_parse.hpp"
namespace pure_qi {
std::shared_ptr<tree::function> parse(const std::wstring &source)
{
namespace qi = boost::spirit::qi;
iterator_type current_pos(source.begin(), source.end());
iterator_type current_end;
std::shared_ptr<tree::function> func;
function_grammar<iterator_type> grammar;
const bool is_success = qi::phrase_parse(current_pos, current_end, grammar, qi::ascii::space, func);
return is_success && current_pos == current_end ? func : std::shared_ptr<tree::function>();
}
}
#ifndef PURE_QI_PARSE_HPP
#define PURE_QI_PARSE_HPP
#include <memory>
#include <string>
#include "nodes.hpp"
namespace pure_qi {
std::shared_ptr<tree::function> parse(const std::wstring &source);
}
#endif /* PURE_QI_PARSE_HPP */
#ifndef PURE_QI_TOKENS_HPP
#define PURE_QI_TOKENS_HPP
#include <boost/preprocessor/seq/for_each.hpp>
namespace pure_qi {
struct token_base {
unsigned line ;
unsigned column;
};
#define SEQ_KEYWORD \
(void ) \
(bool ) \
(int ) \
(return ) \
(function)
#define SEQ_OPERATOR \
(("(")( left_paren)) \
((")")(right_paren)) \
(("{")( left_brace)) \
(("}")(right_brace)) \
((":")( colon)) \
((",")( comma)) \
(("+")( add )) \
(("-")( sub )) \
(("*")( mul )) \
(("/")( div ))
#define DEF_TOKEN_KEYWORD(r, data, elem) \
struct BOOST_PP_CAT(token_, elem) \
: token_base \
{};
#define DEF_TOKEN_OPERATOR(r, data, elem) \
struct BOOST_PP_CAT(token_, BOOST_PP_SEQ_ELEM(1, elem)) \
: token_base \
{};
BOOST_PP_SEQ_FOR_EACH(DEF_TOKEN_KEYWORD , _, SEQ_KEYWORD );
BOOST_PP_SEQ_FOR_EACH(DEF_TOKEN_OPERATOR, _, SEQ_OPERATOR);
#undef DEF_TOKEN_OPERATOR
#undef DEF_TOKEN_KEYWORD
}
#endif /* PURE_QI_TOKENS_HPP */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment