Mercurial > hg > Members > nobuyasu > SampleSource
view boost-spirit/CALC/closure/EUC/calc.cpp @ 0:db40c85cad7a default tip
upload sample source
author | nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Mon, 09 May 2011 03:11:59 +0900 |
parents | |
children |
line wrap: on
line source
#include <boost/spirit.hpp> #include <boost/spirit/phoenix.hpp> #include <boost/shared_ptr.hpp> #include <boost/mem_fn.hpp> #include <iostream> #include <map> #include <vector> #include <string> #include <cassert> #include <algorithm> #include "node.h" using namespace std; using namespace boost::spirit; typedef file_iterator<> iterator_t; map<string, int> values; // 変数テーブル // 文の実行関数定義 class caction { public: virtual ~caction() { } virtual void action() const = 0; } ; typedef boost::shared_ptr<caction> caction_t; // 代入文 class cassign_action: public caction { public: cassign_action(const string &value, cnode_t node) : value_(value), node_(node) { } virtual void action() const; protected: string value_; cnode_t node_; } ; // 代入文の実行関数 void cassign_action::action() const { values[value_] = node_->expr(values); } // print文 class cprint_action: public caction { public: cprint_action(cnode_t node) : node_(node) { } virtual void action() const; protected: cnode_t node_; } ; // print文の実行関数 void cprint_action::action() const { std::cout << node_->expr(values) << std::endl; } // list文 class clist_action: public caction { public: clist_action() { } virtual void action() const; } ; // list文の実行関数 struct print_value { void operator()(const std::pair<std::string, int> &it) { std::cout << it.first << " = " << it.second << std::endl; } } ; void clist_action::action() const { for_each(values.begin(), values.end(), print_value()); } // エラー処理パーサー定義 struct error_parser { typedef nil_t result_t; // パーサーの結果型(nil_t) error_parser(char const *msg) : msg_(msg) { } template <typename ScannerT> int operator()(ScannerT const &scan, result_t &result) const { // 終わりまで来たら-1を返す if (scan.at_end()) { return -1; } cout << msg_ << endl; // 解釈した「長さ」を返すと、その分スキップするので // 改行までをスキャンし、その分をスキップ return (int)(*(anychar_p - '\n') >> ch_p('\n')).parse(scan).length(); } private: const char *msg_; } ; // エラー処理パーサー typedef functor_parser<error_parser> error_p; // 文法エラー処理パーサー error_p syntax_error_p = error_parser("文法エラー"); // 単項演算子ノードを生成する struct unary_node_impl { template <typename Ty1, typename Ty2> struct result { typedef cnode_t type; } ; template <typename Ty1, typename Ty2> cnode_t operator()(Ty1 op, const Ty2 &left) const { return cnode_t(new cnode(op, left)); } } ; // 二項演算子ノードを生成する struct binary_node_impl { template <typename Ty1, typename Ty2, typename Ty3> struct result { typedef cnode_t type; } ; template <typename Ty1, typename Ty2, typename Ty3> cnode_t operator()(Ty1 op, const Ty2 &left, const Ty3 &right) const { return cnode_t(new cnode(op, left, right)); } } ; // phoenixが使用する「無名関数」用の関数 phoenix::function<binary_node_impl> const binary_node = binary_node_impl(); phoenix::function<unary_node_impl> const unary_node = unary_node_impl(); // 文法定義 struct calc_grammer: public grammar<calc_grammer> { calc_grammer(vector<caction_t> &statements) :statements_(statements) { } // 文を登録しておくvector vector<caction_t> &statements_; // 変数名のクロージャ struct ident_val: closure<ident_val, std::string> { member1 str; } ; // 数字のクロージャ struct number_val: closure<number_val, unsigned int> { member1 number; } ; // ノードのクロージャ struct node_val: closure<node_val, cnode_t> { member1 node; } ; // 代入文のクロージャ struct assign_val: closure<assign_val, caction_t, std::string> { member1 action; member2 value; } ; // (代入以外の)文のクロージャ struct state_val: closure<state_val, caction_t> { member1 action; } ; template <typename ScannerT> struct definition { rule<ScannerT, ident_val::context_t> identifier; rule<ScannerT, number_val::context_t> number; rule<ScannerT, node_val::context_t> prime; rule<ScannerT, node_val::context_t> unary; rule<ScannerT, node_val::context_t> mul_expr; rule<ScannerT, node_val::context_t> add_expr; rule<ScannerT, assign_val::context_t> assign; rule<ScannerT, state_val::context_t> print; rule<ScannerT, state_val::context_t> list; rule<ScannerT, state_val::context_t> statement; rule<ScannerT> input; definition(calc_grammer const& self) { using phoenix::arg1; using phoenix::arg2; using phoenix::var; using phoenix::new_; using phoenix::construct_; identifier = lexeme_d[((alpha_p | '_') >> *(alnum_p | '_'))] [identifier.str = construct_<string>(arg1, arg2)]; number = uint_p[number.number = arg1]; prime = identifier[prime.node = unary_node(OP_IDENT, arg1)] | number[prime.node = unary_node(OP_NUMBER, arg1)] | '(' >> add_expr[prime.node = arg1] >> ')' ; unary = prime[unary.node = arg1] | '-' >> prime[unary.node = unary_node(OP_NEG, arg1)] ; mul_expr = unary[mul_expr.node = arg1] >> *('*' >> unary[mul_expr.node = binary_node(OP_TIMES, mul_expr.node, arg1)] | '/' >> unary[mul_expr.node = binary_node(OP_DIVIDE, mul_expr.node, arg1)]); add_expr = mul_expr[add_expr.node = arg1] >> *('+' >> mul_expr[add_expr.node = binary_node(OP_PLUS, add_expr.node, arg1)] | '-' >> mul_expr[add_expr.node = binary_node(OP_MINUS, add_expr.node, arg1)]); assign = identifier[assign.value = arg1] >> '=' >> add_expr [ assign.action = construct_<caction_t> ( new_<cassign_action>(assign.value, arg1) ) ] >> '\n'; print = str_p("print") >> add_expr [ print.action = construct_<caction_t> ( new_<cprint_action>(arg1) ) ] >> '\n'; list = str_p("list") [ list.action = construct_<caction_t>(new_<clist_action>()) ] >> '\n'; statement = assign[statement.action = arg1] | print[statement.action = arg1] | list[statement.action = arg1] ; input = *(statement[push_back_a(self.statements_)] | '\n' | syntax_error_p); } rule<ScannerT> const& start() const { return input; } }; } ; // main int main(int argc, char *argv[]) { // ファイルの読み込みに、file_iteratorを使用する file_iterator<> first("input.txt"); if (!first) { cout << "ファイルがオープンできません。" << endl; return 1; } file_iterator<> last = first.make_end(); vector<caction_t> statements; calc_grammer gr(statements); if (parse(first, last, gr, ch_p(' ') | ch_p('\t') | ch_p('\r')).full) { // 解析成功した文を実行 for_each(statements.begin(), statements.end(), boost::mem_fn(&caction::action)); } else { // エラー処理が入っているので、エラー処理されるとここには来ない // エラー処理パーサーで、エラー処理を行ったら失敗としたほうが // 良い。 cout << "構文解析失敗" << endl; } return 0; }