# encoding=shiftjis

import MeCab
import sys
import re
import math


# 引数エラークラス
class ParamError(Exception):
	def __init__(self, value):
		self.value = value
	def __str__(self):
		return repr(self.value)

# 意味不明エラークラス
class Incoherent(Exception):
	def __init__(self, value):
		self.value = value
	def __str__(self):
		return repr(self.value)


# 引数チェック
def checkparam(param,num):
	if len(param) < num:
		raise ParamError,"引数の数が足りません:"+str(len(param))

	if len(param) > num:
		raise ParamError,"引数の数が多すぎます:"+str(len(param))

	for n in range(num):
		if ( param[n] == None ):
			raise ParamError,"値がありません"

# コマンド関数
def func_add(param):
	checkparam(param,2)
	p2 = int(param[0].v)
	p1 = int(param[1].v)
	return p1+p2

def func_radd(param):
	checkparam(param,2)
	p2 = int(param[1].v)
	p1 = int(param[0].v)
	return p1+p2

def func_sub(param):
	checkparam(param,2)
	p2 = int(param[0].v)
	p1 = int(param[1].v)
	return p1-p2

def func_rsub(param):
	checkparam(param,2)
	p2 = int(param[1].v)
	p1 = int(param[0].v)
	return p1-p2

def func_mul(param):
	checkparam(param,2)
	p2 = int(param[0].v)
	p1 = int(param[1].v)
	return p1*p2

def func_rmul(param):
	checkparam(param,2)
	p2 = int(param[1].v)
	p1 = int(param[0].v)
	return p1*p2

def func_div(param):
	checkparam(param,2)
	p2 = int(param[0].v)
	p1 = int(param[1].v)
	if p2 == 0:
		raise ParamError,"０では割れません"
	return p1/p2

def func_rdiv(param):
	checkparam(param,2)
	p2 = int(param[1].v)
	p1 = int(param[0].v)
	if p2 == 0:
		raise ParamError,"０では割れません"
	return p1/p2

def func_value(param):
	checkparam(param,1)
	p1 = int(param[0].v)
	return p1

def func_pi(param):
	checkparam(param,0)
	return math.pi


# コマンド定義
commands = (
	(func_pi, "パイ"),
	(func_add, "ニ,ヲ,タス"),
	(func_radd, "ヲ,ニ,タス"),
	(func_add, "ト,ヲ,タス"),
	(func_radd, "ヲ,ト,タス"),
	(func_sub,"カラ,ヲ,ヒク"),
	(func_rsub,"ヲ,カラ,ヒク"),
	(func_mul,"ニ,ヲ,カケル"),
	(func_rmul,"ヲ,ニ,カケル"),
	(func_mul,"ト,ヲ,カケル"),
	(func_div,"ヲ,デ,ワル"),
	(func_rdiv,"デ,ヲ,ワル"),
	(func_div,"ヲ,デ,ワレル"),	# 辞書補正
	(func_rdiv,"デ,ヲ,ワル"),
	(func_value,"ノ,アタイ"),
)

# コマンドクラス
class Command:
	def __init__(self,func,string):
		self.f = func
		temp   = string.split(',')
		self.s = temp[::-1]
		self.k = "func"

# 大域変数
nodes =[]	# 文章
primitives = []	# 基本述語リスト

# ノードクラス
class Node:
	def __init__(self,value,kind):
		self.v = value
		self.k = kind
		self.n = 0


# 命令の候補を探す（この段階では助詞は考慮しない）
def searchCommand(word):
#	print "word:",word
	if word == None:
#		print "none"
		return []
	res = []
	for p in primitives:
#		print "primitive:",p.s[0]
		if p.s[0] == word:
			res.append(p)

	return res



# 命令を生成する
def makeCommand(nodes,coms):
	if coms == []:
		try:
			temp = int(nodes[0].v)
			res = []
			res.append( func_value )
			res.append(nodes[0])
			return res
		except:
			raise Incoherent,"定義されていない述語です"


	# 関数照合
	verbonly = 0
	for p in coms:
		res = []
		nc  = 0

		s = p.s
		v = s[0]
		s = s[1:]


		# 命令の確認
		if v <> nodes[nc].v:
			raise Incoherent,"述語が違います:"+v+","+nodes[nc].v

		# 命令の格納
		res.append(p.f)
		verbonly = 1

		# 助詞をもとに引数を探す
		flag = 1
		nc   = nc + 1
		for n in s:
			# 助詞との照合
#			print len(nodes),nc,nodes[nc]
			if len(nodes) <= nc:
				flag = 0
				break
			if nodes[nc].v <> n:
				flag = 0
				break
			nc = nc + 1
			if len(nodes) <= nc:
				flag = 0
				break

			# 引数の格納
			res.append(nodes[nc])
			nc = nc + 1

		if flag == 0:
			continue

		return res

	if verbonly:
		raise Incoherent,"述語'"+ v +"'と助詞が対応しません"

	raise Incoherent,"述語'"+ v +"'を知りません"


# 文字列中の数値を日本語に変換する


# 文字列中の全角数値を半角数値に変換する
def convertZenkakuNum(str):

	# 全角数字辞書
	znumChar = {
		u"０":u"0",
		u"１":u"1",
		u"２":u"2",
		u"３":u"3",
		u"４":u"4",
		u"５":u"5",
		u"６":u"6",
		u"７":u"7",
		u"８":u"8",
		u"９":u"9",
		u"，":u",",
		u"．":u".",
	}

	number    = re.compile( u'([0-9０-９]+[,，]?[0-9,，０-９]*)([.．][0-9０-９]*)?' )
	zenNumber = re.compile( u'[０-９，．]' )

	str = unicode( str, 'Shift_JIS' )
#	print str

	endpos = 0
	temp = ""

	# 数値文字列を検索
	it = number.finditer( str )
	for val in it:
#		print val.group(0),

		# 数値文字列
		num = val.group(0)
		v = zenNumber.match(num)
		if v == None:
			continue

		s = []
		for c in num:
			s.append( znumChar.get(c,c) )

		# 配列を連結する
		s = u''.join(s)

		# 置換文字列追加
		if val.start(0) > endpos:
			temp = temp + str[endpos:val.start(0)]
		temp = temp + s

		if len(str) > val.end(0):
			endpos = val.end(0)
		else:
			endpos = len(str)

	if len(str) > endpos-1:
		str = temp + str[endpos:]
#	print str

	return str.encode('Shift_JIS')


# コマンド呼び出し
def doCommand(param):
	if param == []:
		raise Incoherent,"述語がありません"

	verb = param.pop(0)
	return verb(param)

try:
	# コマンド登録
	for t in commands:
		x = Command( t[0], t[1] )
		primitives.append(x)

	# オープニング
	print "日本語計算機インタプリタ"

	# コマンド一覧
#	print "述語一覧"
#	for i in primitives:
#		print i.f,
#		for j in i.s:
#			print j,
#		print

	# 文章解析
	m = MeCab.Tagger ("")

	while 1:
		string = raw_input('> ')

		if string == None or string == "":
			continue

		if string == "終了":
			print "終了します。"
			break

#		print string

		string = convertZenkakuNum( string )
#		print "全角数字変換後:",string


		s = m.parseToNode(string)
		s = s.next
		nodes = []

		try:
			temp = []
			while s:
				t = s.feature
				t = t.split(",")

				if t[0] == '助詞':
					if temp <> []:
						n = Node( "".join(temp), "word" )
						nodes.append(n)
						temp = []
					n = Node( t[7], "par" )
					nodes.append(n)
				elif t[1] == '句点':
					if temp <> []:
						n = Node( "".join(temp), "word" )
						nodes.append(n)
						temp = []
					n = Node( "。", "punct" )
					nodes.append(n)
					n = 'punct'
				elif t[1] == '読点':
					if temp <> []:
						n = Node( "".join(temp), "word" )
						nodes.append(n)
						temp = []
					n = 'punct'
					n = Node( "、", "punct" )
					nodes.append(n)
				elif t[0] == "BOS/EOS":
					if temp <> []:
						n = Node( "".join(temp), "word" )
						nodes.append(n)
						temp = []
					break
				else:
					try:
						temp.append( t[7] )
					except IndexError:
						temp.append( s.surface )
				s = s.next

			nodes = nodes[::-1]

#			for i in nodes:
#				print i.k,i.v

			# 命令の候補を探す
			node = nodes[0]
	#		print "node:",node.k,node.v
			val = []
			if node.k == 'word':
				val = searchCommand(node.v)
	#			print "val:",val
	#			for v in val:
	#				print v.f

			# 助詞の合致する命令を探し、引数を確定する
			com = makeCommand(nodes,val)

			# 呼び出し
			ret = doCommand( com )
			print "答:",ret

		# 命令と助詞の組み合わせが存在しないとき
		except Incoherent,e:
			print "構文エラー:",e.value

		# 引数にエラーがあるとき
		except ParamError,e:
			print "引数エラー：",e.value

		except ValueError:
			print "構文エラー:整数ではありません"

except ValueError:
	print "エラー:終了しました"
