view boost-spirit/CALC/rule/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 <iostream>
#include <string>
#include <cassert>

using namespace std;
using namespace boost::spirit;

// 入力データ用のイテレータ
// 変更可能なようにtypedefしておく
typedef file_iterator<>	iterator_t;

// エラー処理用のパーサー(関数オブジェクト)
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>	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[(alpha_p | '_') >> *(alnum_p | '_')];
			// 数値
			number = uint_p;

			// 最初の(素の)要素
			prime	= identifier
					| number
					| '(' >> add_expr >> ')'
					;

			// 単項演算子
			unary	= prime
					| '-' >> prime
					;

			// 乗除算
			mul_expr = unary >> *('*' >> unary | '/' >> unary);

			// 加減算
			add_expr = mul_expr >> *('+' >> mul_expr | '-' >> mul_expr);

			// 代入文
			assign = identifier >> '=' >> add_expr >> ch_p('\n');
			// printコマンド
			print = str_p("print") >> add_expr >> ch_p('\n');
			// listコマンド
			list = str_p("list") >> ch_p('\n');

			// 文
			statement	= assign
						| print
						| list
						;

			// 入力とマッチするすべてのルール
			// 式 | 改行のみ(空文) | 文法エラー
			input = *(statement
					| ch_p('\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();

	// 解析処理を行う
	// スキップパーサーは、' ', '\t', '\r'をスキップし
	// \nは(文末に利用するため)スキップしない
	calc_grammer	gr;
	if (parse(first, last, gr, ch_p(' ') | ch_p('\t') | ch_p('\r')).full) {
		// 解析成功
		cout << "構文解析終了" << endl;
	}
	else {
		// エラー処理が入っているので、エラー処理されるとここには来ない
		// エラー処理パーサーで、エラー処理を行ったら失敗としたほうが
		// 良い。
		cout << "構文解析失敗" << endl;
	}

	return 0;
}