Mercurial > hg > Members > nobuyasu > SampleSource
view boost-spirit/CALC/use-map/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/core.hpp> #include <boost/spirit/utility/confix.hpp> #include <boost/spirit/tree/ast.hpp> #include <boost/spirit/utility/escape_char.hpp> #include <boost/spirit/iterator/position_iterator.hpp> #include <boost/spirit/iterator/file_iterator.hpp> #include <boost/spirit/utility/functor_parser.hpp> #include <boost/shared_ptr.hpp> #include <iostream> #include <map> #include <string> #include <cassert> #include <algorithm> using namespace std; using namespace boost::spirit; typedef file_iterator<> iterator_t; typedef tree_match<iterator_t>::tree_iterator tree_iter_t; map<string, int> values; // 変数テーブル // 関数宣言 int eval(const tree_iter_t &it); // 動作定義の構造体 struct node_action { virtual int action(const tree_iter_t &it) const = 0; } ; struct neg_action: public node_action { virtual int action(const tree_iter_t &it) const { assert(it->children.size() == 1); return -eval(it->children.begin()); } } ; struct add_action: public node_action { virtual int action(const tree_iter_t &it) const { assert(it->children.size() == 2); return eval(it->children.begin()) + eval(it->children.begin() + 1); } } ; struct sub_action: public node_action { virtual int action(const tree_iter_t &it) const { assert(it->children.size() == 2); return eval(it->children.begin()) - eval(it->children.begin() + 1); } } ; struct mul_action: public node_action { virtual int action(const tree_iter_t &it) const { assert(it->children.size() == 2); return eval(it->children.begin()) * eval(it->children.begin() + 1); } } ; struct div_action: public node_action { virtual int action(const tree_iter_t &it) const { assert(it->children.size() == 2); return eval(it->children.begin()) / eval(it->children.begin() + 1); } } ; struct subst_action: public node_action { virtual int action(const tree_iter_t &it) const { assert(it->children.size() == 2); const tree_iter_t &value = it->children.begin(); string name(value->value.begin(), value->value.end()); return values[name] = eval(it->children.begin() + 1); } } ; struct value_action: public node_action { virtual int action(const tree_iter_t &it) const { return values[string(it->value.begin(), it->value.end())]; } } ; struct number_action: public node_action { virtual int action(const tree_iter_t &it) const { return atoi(string(it->value.begin(), it->value.end()).c_str()); } } ; struct print_action: public node_action { virtual int action(const tree_iter_t &it) const { cout << eval(it->children.begin() + 1) << endl; return 0; } } ; struct list_action: public node_action { struct print_value { void operator()(const std::pair<std::string, int> &it) { cout << it.first << " = " << it.second << endl; } } ; virtual int action(const tree_iter_t &it) const { for_each(values.begin(), values.end(), print_value()); return 0; } } ; // ノードと動作の関連付け map< parser_id, boost::shared_ptr<const node_action> > action_map; // ノードの評価 int eval(const tree_iter_t &it) { const boost::shared_ptr<const node_action> &action = action_map[it->value.id()]; if (!action) { cout << "エラー" << endl; return 0; } return action->action(it); } 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 calc_grammer: public grammar<calc_grammer> { template <typename ScannerT> struct definition { rule<ScannerT> identifier; rule<ScannerT> number; rule<ScannerT> minus; rule<ScannerT> add; rule<ScannerT> sub; rule<ScannerT> mul; rule<ScannerT> div; rule<ScannerT> subst; rule<ScannerT> prime; rule<ScannerT> unary; rule<ScannerT> mul_expr; rule<ScannerT> add_expr; rule<ScannerT> assign; rule<ScannerT> print; rule<ScannerT> list; rule<ScannerT> statement; rule<ScannerT> input; definition(calc_grammer const& self) { identifier = lexeme_d[leaf_node_d[alpha_p >> *alnum_p]]; number = uint_p; minus = ch_p('-'); add = ch_p('+'); sub = ch_p('-'); mul = ch_p('*'); div = ch_p('/'); subst = ch_p('='); // prime ::= <value> | <number> | "(" <expr> ")" prime = identifier | number | inner_node_d['(' >> add_expr >> ')'] ; // unary ::= <prime> | "-" <prime> unary = prime | root_node_d[minus] >> prime ; // mul_expr ::= <unary> (("*" | "/") <unary>)* mul_expr = unary >> *(root_node_d[mul | div] >> unary); // add_expr ::= <mul_expr> (("+" | "-") <mul_expr>)* add_expr = mul_expr >> *(root_node_d[add | sub] >> mul_expr); // assign ::= <value> "=" <expr> assign = identifier >> root_node_d[subst] >> add_expr; // print ::= "print" <expr> print = str_p("print") >> add_expr; // list ::= "list" list = str_p("list"); statement = root_node_d[assign | print | list] >> discard_node_d[ch_p('\n')]; // 入力は、「文」、「空行」もしくは「エラー」 input = *(statement | discard_node_d[ch_p('\n')] | syntax_error_p); // ルールと(astツリーのノードの)動作を関連付ける // parser_id は、operator< が定義されているので、std::mapが // そのまま使える。 action_map.insert(make_pair(identifier.id(), new value_action())); action_map.insert(make_pair(number.id(), new number_action())); action_map.insert(make_pair(minus.id(), new neg_action())); action_map.insert(make_pair(add.id(), new add_action())); action_map.insert(make_pair(sub.id(), new sub_action())); action_map.insert(make_pair(mul.id(), new mul_action())); action_map.insert(make_pair(div.id(), new div_action())); action_map.insert(make_pair(subst.id(), new subst_action())); action_map.insert(make_pair(print.id(), new print_action())); action_map.insert(make_pair(list.id(), new list_action())); } 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(); // 抽象構文木作成 calc_grammer gr; tree_parse_info<iterator_t> info = ast_parse(first, last, gr, ch_p(' ') | ch_p('\t') | ch_p('\r')); if (info.full) { const tree_iter_t &root = info.trees.begin(); size_t size = root->children.size(); for(size_t i=0; i<size; i++) { eval(root->children.begin() + i); } } else { // エラー処理が入っているので、エラー処理されるとここには来ない // エラー処理パーサーで、エラー処理を行ったら失敗としたほうが // 良い。 cout << "構文解析失敗" << endl; } return 0; }