Mercurial > hg > Members > nobuyasu > SampleSource
diff 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 diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/boost-spirit/CALC/use-map/calc.cpp Mon May 09 03:11:59 2011 +0900 @@ -0,0 +1,281 @@ +#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; +}