| /*============================================================================= |
| Copyright (c) 2001-2010 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) |
| =============================================================================*/ |
| #if !defined(BOOST_SPIRIT_CALC7) |
| #define BOOST_SPIRIT_CALC7 |
| |
| #include <boost/config/warning_disable.hpp> |
| #include <boost/spirit/include/qi.hpp> |
| #include <boost/spirit/include/phoenix_core.hpp> |
| #include <boost/spirit/include/phoenix_container.hpp> |
| #include <boost/spirit/include/phoenix_statement.hpp> |
| #include <boost/spirit/include/phoenix_operator.hpp> |
| |
| #include <iostream> |
| #include <string> |
| #include <vector> |
| |
| using boost::phoenix::function; |
| using boost::phoenix::ref; |
| using boost::phoenix::size; |
| |
| using boost::spirit::qi::unused_type; |
| |
| namespace qi = boost::spirit::qi; |
| namespace ascii = boost::spirit::ascii; |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // The Virtual Machine |
| /////////////////////////////////////////////////////////////////////////////// |
| enum byte_code |
| { |
| op_neg, // negate the top stack entry |
| op_add, // add top two stack entries |
| op_sub, // subtract top two stack entries |
| op_mul, // multiply top two stack entries |
| op_div, // divide top two stack entries |
| |
| op_not, // boolean negate the top stack entry |
| op_eq, // compare the top two stack entries for == |
| op_neq, // compare the top two stack entries for != |
| op_lt, // compare the top two stack entries for < |
| op_lte, // compare the top two stack entries for <= |
| op_gt, // compare the top two stack entries for > |
| op_gte, // compare the top two stack entries for >= |
| |
| op_and, // logical and top two stack entries |
| op_or, // logical or top two stack entries |
| |
| op_load, // load a variable |
| op_store, // store a variable |
| |
| op_int, // push constant integer into the stack |
| op_true, // push constant 0 into the stack |
| op_false, // push constant 1 into the stack |
| |
| op_jump_if, // jump to an absolute position in the code if top stack |
| // evaluates to false |
| op_jump // jump to an absolute position in the code |
| }; |
| |
| class vmachine |
| { |
| public: |
| |
| vmachine(unsigned stackSize = 4096) |
| : stack(stackSize) |
| , stack_ptr(stack.begin()) |
| { |
| } |
| |
| std::vector<int> const& get_stack() const { return stack; }; |
| void execute(std::vector<int> const& code, int nvars); |
| |
| private: |
| |
| std::vector<int> stack; |
| std::vector<int>::iterator stack_ptr; |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // A generic compiler that compiles 1 to 3 codes |
| /////////////////////////////////////////////////////////////////////////////// |
| struct compile_op |
| { |
| template <typename A, typename B = unused_type, typename C = unused_type> |
| struct result { typedef void type; }; |
| |
| compile_op(std::vector<int>& code) |
| : code(code) |
| { |
| } |
| |
| void operator()(int a) const |
| { |
| code.push_back(a); |
| } |
| |
| void operator()(int a, int b) const |
| { |
| code.push_back(a); |
| code.push_back(b); |
| } |
| |
| void operator()(int a, int b, int c) const |
| { |
| code.push_back(a); |
| code.push_back(b); |
| code.push_back(c); |
| } |
| |
| std::vector<int>& code; |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Our error handler |
| /////////////////////////////////////////////////////////////////////////////// |
| struct error_handler_ |
| { |
| template <typename, typename, typename> |
| struct result { typedef void type; }; |
| |
| template <typename Iterator> |
| void operator()( |
| qi::info const& what |
| , Iterator err_pos, Iterator last) const |
| { |
| std::cout |
| << "Error! Expecting " |
| << what // what failed? |
| << " here: \"" |
| << std::string(err_pos, last) // iterators to error-pos, end |
| << "\"" |
| << std::endl |
| ; |
| } |
| }; |
| |
| function<error_handler_> const error_handler = error_handler_(); |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Our expression grammar and compiler |
| /////////////////////////////////////////////////////////////////////////////// |
| template <typename Iterator> |
| struct expression : qi::grammar<Iterator, ascii::space_type> |
| { |
| expression(std::vector<int>& code, qi::symbols<char, int>& vars); |
| |
| qi::rule<Iterator, ascii::space_type> |
| expr, equality_expr, relational_expr |
| , logical_expr, additive_expr, multiplicative_expr |
| , unary_expr, primary_expr, variable |
| ; |
| |
| std::vector<int>& code; |
| qi::symbols<char, int>& vars; |
| function<compile_op> op; |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Our statement grammar and compiler |
| /////////////////////////////////////////////////////////////////////////////// |
| struct var_adder |
| { |
| template <typename, typename> |
| struct result { typedef void type; }; |
| |
| var_adder(qi::symbols<char, int>& vars) |
| : vars(vars) |
| { |
| } |
| |
| void operator()(std::string const& var, int& nvars) const |
| { |
| vars.add(var.begin(), var.end(), nvars++); |
| }; |
| |
| qi::symbols<char, int>& vars; |
| }; |
| |
| template <typename Iterator> |
| struct statement : qi::grammar<Iterator, ascii::space_type> |
| { |
| statement(std::vector<int>& code); |
| |
| std::vector<int>& code; |
| qi::symbols<char, int> vars; |
| int nvars; |
| |
| expression<Iterator> expr; |
| qi::rule<Iterator, ascii::space_type> |
| statement_, statement_list, var_decl, compound_statement |
| ; |
| |
| qi::rule<Iterator, qi::locals<int>, ascii::space_type> if_statement; |
| qi::rule<Iterator, qi::locals<int, int>, ascii::space_type> while_statement; |
| qi::rule<Iterator, std::string(), ascii::space_type> identifier; |
| qi::rule<Iterator, int(), ascii::space_type> var_ref; |
| qi::rule<Iterator, qi::locals<int>, ascii::space_type> assignment; |
| qi::rule<Iterator, void(int), ascii::space_type> assignment_rhs; |
| |
| function<var_adder> add_var; |
| function<compile_op> op; |
| }; |
| |
| #endif |