Mercurial > hg > Members > nobuyasu > SampleSource
view boost-spirit/CALC/AST/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; // ノードのID enum { ID_NEG = 1, ID_PLUS, ID_MINUS, ID_TIMES, ID_DIVIDE, ID_SUBST, ID_VALUE, ID_CONST, ID_PRIME, ID_UNARY, ID_MUL_EXPR, ID_ADD_EXPR, ID_STATEMENT, ID_INPUT, ID_ASSIGN, ID_PRINT, ID_LIST, } ; typedef file_iterator<> iterator_t; typedef tree_match<iterator_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 calc_grammer: public grammar<calc_grammer> { template <typename ScannerT> struct definition { rule< ScannerT, parser_context<>, parser_tag<ID_VALUE> > identifier; rule< ScannerT, parser_context<>, parser_tag<ID_CONST> > number; rule< ScannerT, parser_context<>, parser_tag<ID_NEG> > minus; rule< ScannerT, parser_context<>, parser_tag<ID_PLUS> > add; rule< ScannerT, parser_context<>, parser_tag<ID_MINUS> > sub; rule< ScannerT, parser_context<>, parser_tag<ID_TIMES> > mul; rule< ScannerT, parser_context<>, parser_tag<ID_DIVIDE> > div; rule< ScannerT, parser_context<>, parser_tag<ID_SUBST> > subst; rule< ScannerT, parser_context<>, parser_tag<ID_PRIME> > prime; rule< ScannerT, parser_context<>, parser_tag<ID_UNARY> > unary; rule< ScannerT, parser_context<>, parser_tag<ID_MUL_EXPR> > mul_expr; rule< ScannerT, parser_context<>, parser_tag<ID_ADD_EXPR> > add_expr; rule< ScannerT, parser_context<>, parser_tag<ID_ASSIGN> > assign; rule< ScannerT, parser_context<>, parser_tag<ID_PRINT> > print; rule< ScannerT, parser_context<>, parser_tag<ID_LIST> > list; rule< ScannerT, parser_context<>, parser_tag<ID_STATEMENT> > statement; rule< ScannerT, parser_context<>, parser_tag<ID_INPUT> > 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 = identifier | number | inner_node_d['(' >> add_expr >> ')'] ; unary = prime | root_node_d[minus] >> prime ; mul_expr = unary >> *(root_node_d[mul | div] >> unary); add_expr = mul_expr >> *(root_node_d[add | sub] >> mul_expr); assign = identifier >> root_node_d[subst] >> add_expr; print = str_p("print") >> add_expr; 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); } rule< ScannerT, parser_context<>, parser_tag<ID_INPUT> > 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) { if (it->value.id() == ID_NEG) { assert(it->children.size() == 1); return -eval(it->children.begin()); } else if (it->value.id() == ID_PLUS) { assert(it->children.size() == 2); return eval(it->children.begin()) + eval(it->children.begin() + 1); } else if (it->value.id() == ID_MINUS) { assert(it->children.size() == 2); return eval(it->children.begin()) - eval(it->children.begin() + 1); } else if (it->value.id() == ID_TIMES) { assert(it->children.size() == 2); return eval(it->children.begin()) * eval(it->children.begin() + 1); } else if (it->value.id() == ID_DIVIDE) { assert(it->children.size() == 2); return eval(it->children.begin()) / eval(it->children.begin() + 1); } else if (it->value.id() == ID_SUBST) { assert(it->children.size() == 2); return value_ref(it->children.begin()) = eval(it->children.begin() + 1); } else if (it->value.id() == ID_VALUE) { return values[string(it->value.begin(), it->value.end())]; } else if (it->value.id() == ID_CONST) { return atoi(string(it->value.begin(), it->value.end()).c_str()); } else if (it->value.id() == ID_PRINT) { cout << eval(it->children.begin() + 1) << endl; } else if (it->value.id() == ID_LIST) { for_each(values.begin(), values.end(), list_action()); } else { cout << "エラー" << endl; } 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> info; // 解析情報を保持する変数 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; }