-
-
Save evanzillians/4379037 to your computer and use it in GitHub Desktop.
Parser using Spirit.Qi which generate additional information as token.
This file contains hidden or 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
#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 */ |
This file contains hidden or 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 <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>; |
This file contains hidden or 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
#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 */ |
This file contains hidden or 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 <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>; |
This file contains hidden or 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
#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 */ |
This file contains hidden or 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 <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>(); | |
} | |
} |
This file contains hidden or 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
#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 */ |
This file contains hidden or 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
#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 */ |
This file contains hidden or 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
#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 */ |
This file contains hidden or 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
#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 */ |
This file contains hidden or 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 <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; | |
} |
This file contains hidden or 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 <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) | |
{ | |
} | |
} |
This file contains hidden or 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
#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 */ |
This file contains hidden or 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
#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 */ |
This file contains hidden or 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 <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>; |
This file contains hidden or 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
#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 */ |
This file contains hidden or 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 <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>(); | |
} | |
} |
This file contains hidden or 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
#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 */ |
This file contains hidden or 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
#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