Mercurial > hg > Members > nobuyasu > SampleSource
view boost-spirit/CALC/AST-value/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/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 <iostream> #include <map> #include <string> #include <cassert> #include <algorithm> using namespace std; using namespace boost::spirit; typedef file_iterator<> iterator_t; typedef node_val_data_factory<int> factory_t; typedef tree_match<iterator_t, factory_t> tree_match_t; typedef tree_match_t::tree_iterator tree_iter_t; map<string, int> values; // 変数テーブル 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 set_value { set_value(int id): id_(id){} void operator()(tree_node< node_val_data<iterator_t, int> >& node, iterator_t b, iterator_t e) const { node.value.value(id_); } int id_; } ; // 文法定義 struct calc_grammer: public grammar<calc_grammer> { enum { OP_NOP, OP_IDENTIFIER, OP_NUMBER, OP_NEG, OP_MUL, OP_DIV, OP_ADD, OP_SUB, OP_ASSIGN, OP_PRINT, OP_LIST, } ; template <typename ScannerT> struct definition { rule<ScannerT> identifier; rule<ScannerT> number; 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 = access_node_d[leaf_node_d[lexeme_d[alpha_p >> *alnum_p]]][set_value(OP_IDENTIFIER)]; number = access_node_d[uint_p][set_value(OP_NUMBER)]; prime = identifier | number | inner_node_d['(' >> add_expr >> ')'] ; unary = prime | access_node_d[root_node_d[ch_p('-')]][set_value(OP_NEG)] >> prime ; mul_expr = unary % root_node_d[access_node_d[ch_p('*')][set_value(OP_MUL)] | access_node_d[ch_p('/')][set_value(OP_DIV)]]; add_expr = mul_expr % root_node_d[access_node_d[ch_p('+')][set_value(OP_ADD)] | access_node_d[ch_p('-')][set_value(OP_SUB)]]; assign = identifier >> access_node_d[root_node_d[ch_p('=')]][set_value(OP_ASSIGN)] >> add_expr; print = access_node_d[root_node_d[str_p("print")]][set_value(OP_PRINT)] >> add_expr; list = access_node_d[root_node_d[str_p("list")]][set_value(OP_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); } rule<ScannerT> const& start() const { return input; } } ; } ; // ツリーのイテレータから、変数を取り出す int &value_ref(const tree_iter_t &it) { return values[string(it->value.begin(), it->value.end())]; } // リストコマンドの関数オブジェクト struct list_action { void operator()(const std::pair<std::string, int> &it) { cout << it.first << " = " << it.second << endl; } } ; int eval(const tree_iter_t &it) { switch (it->value.value()) { case calc_grammer::OP_NEG: assert(it->children.size() == 1); return -eval(it->children.begin()); case calc_grammer::OP_ADD: assert(it->children.size() == 2); return eval(it->children.begin()) + eval(it->children.begin() + 1); case calc_grammer::OP_SUB: assert(it->children.size() == 2); return eval(it->children.begin()) - eval(it->children.begin() + 1); case calc_grammer::OP_MUL: assert(it->children.size() == 2); return eval(it->children.begin()) * eval(it->children.begin() + 1); case calc_grammer::OP_DIV: assert(it->children.size() == 2); return eval(it->children.begin()) / eval(it->children.begin() + 1); case calc_grammer::OP_ASSIGN: assert(it->children.size() == 2); return value_ref(it->children.begin()) = eval(it->children.begin() + 1); case calc_grammer::OP_IDENTIFIER: return values[string(it->value.begin(), it->value.end())]; case calc_grammer::OP_NUMBER: return atoi(string(it->value.begin(), it->value.end()).c_str()); case calc_grammer::OP_PRINT: cout << eval(it->children.begin()) << endl; break; case calc_grammer::OP_LIST: for_each(values.begin(), values.end(), list_action()); break; } return 0; } // 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, factory_t> info; // 解析情報を保持する変数 info = ast_parse(first, last, gr, ch_p(' ') | ch_p('\t') | ch_p('\r'), factory_t()); 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; }