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;
+}