/*============================================================================= 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_MINI_C) #define BOOST_SPIRIT_MINI_C #include #include #include #include #include #include #include #include #include #include #include using boost::phoenix::function; using boost::phoenix::ref; using boost::phoenix::size; using namespace boost::spirit; using namespace boost::spirit::qi; /////////////////////////////////////////////////////////////////////////////// // 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 op_stk_adj, // adjust the stack (for args and locals) op_call, // function call op_return // return from function }; class vmachine { public: vmachine(unsigned stackSize = 4096) : stack(stackSize) { } int execute( std::vector const& code // the program code , std::vector::const_iterator pc // program counter , std::vector::iterator frame_ptr // start of arguments and locals ); std::vector stack; }; /////////////////////////////////////////////////////////////////////////////// // A generic compiler that compiles 1 to 3 codes /////////////////////////////////////////////////////////////////////////////// struct function_info { int arity; int address; }; 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); } // special overload for function calls void operator()(function_info const& info, int got_nargs, bool& parse_result) const { if (got_nargs == info.arity) { code.push_back(op_call); code.push_back(info.arity); code.push_back(info.address); } else { parse_result = false; // fail the parse std::cerr << "wrong number of args" << std::endl; } } std::vector& code; }; /////////////////////////////////////////////////////////////////////////////// // Our error handler /////////////////////////////////////////////////////////////////////////////// struct error_handler_ { template struct result { typedef void type; }; template void operator()( 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_(); /////////////////////////////////////////////////////////////////////////////// // A functor that adds variables to our (variables) symbol-table /////////////////////////////////////////////////////////////////////////////// struct var_adder { template struct result { typedef void type; }; var_adder(symbols& vars, int& nvars) : vars(vars), nvars(nvars) { } void operator()(std::string const& var) const { vars.add(var.begin(), var.end(), nvars++); }; symbols& vars; int& nvars; }; /////////////////////////////////////////////////////////////////////////////// // A functor that adds functions to our (function) symbol-table /////////////////////////////////////////////////////////////////////////////// struct function_adder { template struct result { typedef void type; }; function_adder(symbols& functions) : functions(functions) { } void operator()(std::string const& function_id, int arity, int address) const { function_info info = {arity, address}; functions.add(function_id.begin(), function_id.end(), info); }; symbols& functions; }; /////////////////////////////////////////////////////////////////////////////// // A functor that resets the function-related state variables /////////////////////////////////////////////////////////////////////////////// struct function_state_reset { template struct result { typedef void type; }; function_state_reset( std::vector& code , symbols& vars , int& nvars) : code(code) , vars(vars) , nvars(nvars) { } void operator()(int address) const { code[address+1] = nvars; nvars = 0; // reset vars.clear(); // reset }; std::vector& code; symbols& vars; int& nvars; }; /////////////////////////////////////////////////////////////////////////////// // White-space and comments grammar definition /////////////////////////////////////////////////////////////////////////////// template struct white_space : grammar { white_space() : white_space::base_type(start) { using boost::spirit::ascii::char_; start = space // tab/space/cr/lf | "/*" >> *(char_ - "*/") >> "*/" // C-style comments ; } rule start; }; /////////////////////////////////////////////////////////////////////////////// // Our expression grammar and compiler /////////////////////////////////////////////////////////////////////////////// template struct expression : grammar > { expression( std::vector& code , symbols& vars , symbols& functions); typedef white_space white_space_; rule expr, equality_expr, relational_expr , logical_expr, additive_expr, multiplicative_expr , unary_expr, primary_expr, variable ; rule, white_space_> function_call; std::vector& code; symbols& vars; symbols& functions; function op; }; /////////////////////////////////////////////////////////////////////////////// // Our statement grammar and compiler /////////////////////////////////////////////////////////////////////////////// template struct statement : grammar > { statement(std::vector& code, symbols& functions); typedef white_space white_space_; std::vector& code; symbols vars; symbols& functions; int nvars; bool has_return; expression expr; rule statement_, statement_list, var_decl, compound_statement , return_statement; rule, white_space_> if_statement; rule, white_space_> while_statement; rule identifier; rule var_ref; rule, white_space_> assignment; rule assignment_rhs; function add_var; function op; }; /////////////////////////////////////////////////////////////////////////////// // Our program grammar and compiler /////////////////////////////////////////////////////////////////////////////// template struct program : grammar > { program(std::vector& code); typedef white_space white_space_; std::vector& code; rule identifier; rule start; typedef locals< std::string // function name , int // address > function_locals; symbols functions; statement statement_; rule function; boost::phoenix::function add_function; boost::phoenix::function state_reset; boost::phoenix::function op; }; #endif