view boost-spirit/CALC/closure/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.hpp>
#include <boost/spirit/phoenix.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/mem_fn.hpp>
#include <iostream>
#include <map>
#include <vector>
#include <string>
#include <cassert>
#include <algorithm>
#include "node.h"

using namespace std;
using namespace boost::spirit;

typedef file_iterator<>	iterator_t;

map<string, int> values;	// 変数テーブル

// 文の実行関数定義
class caction {
  public:
	virtual ~caction()
	{
	}

	virtual void action() const = 0;
} ;

typedef	boost::shared_ptr<caction> caction_t;

// 代入文
class cassign_action: public caction {
  public:
	cassign_action(const string &value, cnode_t node)
		: value_(value), node_(node)
	{
	}

	virtual void action() const;

  protected:
	string value_;
	cnode_t node_;
} ;

// 代入文の実行関数
void cassign_action::action() const
{
	values[value_] = node_->expr(values);
}

// print文
class cprint_action: public caction {
  public:
	cprint_action(cnode_t node)
		: node_(node)
	{
	}

	virtual void action() const;

  protected:
	cnode_t node_;
} ;

// print文の実行関数
void cprint_action::action() const
{
	std::cout << node_->expr(values) << std::endl;
}

// list文
class clist_action: public caction {
  public:
	clist_action()
	{
	}

	virtual void action() const;
} ;

// list文の実行関数
struct print_value {
	void operator()(const std::pair<std::string, int> &it)
	{
		std::cout << it.first << " = " << it.second << std::endl;
	}
} ;

void clist_action::action() const
{
	for_each(values.begin(), values.end(), print_value());
}

// エラー処理パーサー定義
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 unary_node_impl {
	template <typename Ty1, typename Ty2>
	struct result { typedef cnode_t type; } ;

	template <typename Ty1, typename Ty2>
	cnode_t operator()(Ty1 op, const Ty2 &left) const
	{
		return cnode_t(new cnode(op, left));
	}
} ;

// 二項演算子ノードを生成する
struct binary_node_impl {
	template <typename Ty1, typename Ty2, typename Ty3>
	struct result { typedef cnode_t type; } ;

	template <typename Ty1, typename Ty2, typename Ty3>
	cnode_t operator()(Ty1 op, const Ty2 &left, const Ty3 &right) const
	{
		return cnode_t(new cnode(op, left, right));
	}
} ;

// phoenixが使用する「無名関数」用の関数
phoenix::function<binary_node_impl> const binary_node = binary_node_impl();
phoenix::function<unary_node_impl> const unary_node = unary_node_impl();

// 文法定義
struct calc_grammer: public grammar<calc_grammer> {
	calc_grammer(vector<caction_t> &statements)
		:statements_(statements)
	{
	}

	// 文を登録しておくvector
	vector<caction_t> &statements_;

	// 変数名のクロージャ
	struct ident_val: closure<ident_val, std::string> {
		member1 str;
	} ;
	// 数字のクロージャ
	struct number_val: closure<number_val, unsigned int> {
		member1 number;
	} ;
	// ノードのクロージャ
	struct node_val: closure<node_val, cnode_t> {
		member1 node;
	} ;
	// 代入文のクロージャ
	struct assign_val: closure<assign_val, caction_t, std::string> {
		member1 action;
		member2 value;
	} ;
	// (代入以外の)文のクロージャ
	struct state_val: closure<state_val, caction_t> {
		member1 action;
	} ;

	template <typename ScannerT>
	struct definition {
		rule<ScannerT, ident_val::context_t>	identifier;
		rule<ScannerT, number_val::context_t>	number;
		rule<ScannerT, node_val::context_t>		prime;
		rule<ScannerT, node_val::context_t>		unary;
		rule<ScannerT, node_val::context_t>		mul_expr;
		rule<ScannerT, node_val::context_t>		add_expr;
		rule<ScannerT, assign_val::context_t>	assign;
		rule<ScannerT, state_val::context_t>	print;
		rule<ScannerT, state_val::context_t>	list;
		rule<ScannerT, state_val::context_t>	statement;
		rule<ScannerT>							input;

		definition(calc_grammer const& self)
		{
			using phoenix::arg1;
			using phoenix::arg2;
			using phoenix::var;
			using phoenix::new_;
			using phoenix::construct_;

			identifier = lexeme_d[((alpha_p | '_') >> *(alnum_p | '_'))]
				[identifier.str = construct_<string>(arg1, arg2)];

			number = uint_p[number.number = arg1];

			prime	= identifier[prime.node = unary_node(OP_IDENT, arg1)]
					| number[prime.node = unary_node(OP_NUMBER, arg1)]
					| '(' >> add_expr[prime.node = arg1] >> ')'
					;

			unary	= prime[unary.node = arg1]
					| '-' >> prime[unary.node = unary_node(OP_NEG, arg1)]
					;

			mul_expr = unary[mul_expr.node = arg1]
					>> *('*' >> unary[mul_expr.node = binary_node(OP_TIMES, mul_expr.node, arg1)]
					   | '/' >> unary[mul_expr.node = binary_node(OP_DIVIDE, mul_expr.node, arg1)]);

			add_expr = mul_expr[add_expr.node = arg1]
					>> *('+' >> mul_expr[add_expr.node = binary_node(OP_PLUS, add_expr.node, arg1)]
					   | '-' >> mul_expr[add_expr.node = binary_node(OP_MINUS, add_expr.node, arg1)]);

			assign = identifier[assign.value = arg1] >> '='
					>> add_expr
					[
						assign.action = construct_<caction_t>
						(
							new_<cassign_action>(assign.value, arg1)
						)
					] >> '\n';
			print = str_p("print") >> add_expr
					[
						print.action = construct_<caction_t>
						(
							new_<cprint_action>(arg1)
						)
					] >> '\n';
			list = str_p("list")
					[
						list.action = construct_<caction_t>(new_<clist_action>())
					] >> '\n';

			statement	= assign[statement.action = arg1]
						| print[statement.action = arg1]
						| list[statement.action = arg1]
						;

			input = *(statement[push_back_a(self.statements_)] 
					| '\n'
					| syntax_error_p);
		}

		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();

	vector<caction_t> statements;
	calc_grammer	gr(statements);
	if (parse(first, last, gr, ch_p(' ') | ch_p('\t') | ch_p('\r')).full) {
		// 解析成功した文を実行
		for_each(statements.begin(), statements.end(), boost::mem_fn(&caction::action));
	}
	else {
		// エラー処理が入っているので、エラー処理されるとここには来ない
		// エラー処理パーサーで、エラー処理を行ったら失敗としたほうが
		// 良い。
		cout << "構文解析失敗" << endl;
	}

	return 0;
}