/*============================================================================= 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 #include #include #include #include #include #include #include #include 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 const& get_stack() const { return stack; }; void execute(std::vector const& code, int nvars); private: std::vector stack; std::vector::iterator stack_ptr; }; /////////////////////////////////////////////////////////////////////////////// // A generic compiler that compiles 1 to 3 codes /////////////////////////////////////////////////////////////////////////////// struct compile_op { template struct result { typedef void type; }; compile_op(std::vector& 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& code; }; /////////////////////////////////////////////////////////////////////////////// // Our error handler /////////////////////////////////////////////////////////////////////////////// struct error_handler_ { template struct result { typedef void type; }; template 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 const error_handler = error_handler_(); /////////////////////////////////////////////////////////////////////////////// // Our expression grammar and compiler /////////////////////////////////////////////////////////////////////////////// template struct expression : qi::grammar { expression(std::vector& code, qi::symbols& vars); qi::rule expr, equality_expr, relational_expr , logical_expr, additive_expr, multiplicative_expr , unary_expr, primary_expr, variable ; std::vector& code; qi::symbols& vars; function op; }; /////////////////////////////////////////////////////////////////////////////// // Our statement grammar and compiler /////////////////////////////////////////////////////////////////////////////// struct var_adder { template struct result { typedef void type; }; var_adder(qi::symbols& vars) : vars(vars) { } void operator()(std::string const& var, int& nvars) const { vars.add(var.begin(), var.end(), nvars++); }; qi::symbols& vars; }; template struct statement : qi::grammar { statement(std::vector& code); std::vector& code; qi::symbols vars; int nvars; expression expr; qi::rule statement_, statement_list, var_decl, compound_statement ; qi::rule, ascii::space_type> if_statement; qi::rule, ascii::space_type> while_statement; qi::rule identifier; qi::rule var_ref; qi::rule, ascii::space_type> assignment; qi::rule assignment_rhs; function add_var; function op; }; #endif