#!/usr/bin/env python
#
# Aufgabe 1: Auswerten von Ausdrücken
# Python-Kurs SS 2003: http://www.inf.tu-dresden.de/python-kurs/
# Josef Spillner <js177634@inf.tu-dresden.de>

# Parser-Funktionen einbinden
import parser

# Fehlercodes
errstr = {
	'math' : "arithmetic error(s):\t",
	'rec' : "recursive variable(s):\t",
	'undef' : "unknown variable(s):\t"
	}

# Initialisierung
pstate = 1				# Parser aktiv
vars = {}				# Hashtabelle aller Variablen
rec = {}				# Hashtabelle für Rekursionen
reprint = 1				# Verschönerung der Ausgabe
behaviour = "compliant"	# Abbruchverhalten (fast oder compliant)
errors = {}				# Hashtabelle für Fehlermeldungen

# Evaluierung vorverarbeiteter Ausdrücke
def evaluate(s):

	# Zahl
	if type(s) == type(0.0):
		return s

	# Variable
	if type(s) == type(""):

		# Rekursion ausschließen
		if vars.has_key(s):
			if rec.has_key(s):
				if behaviour == "fast":
					return [errstr['rec'] + s]
				else:
					errors['rec'][s] = s
					return 0
			rec[s] = s;
			ret = evaluate(vars[s])
			del rec[s]
			return ret
		else:
			if behaviour == "fast":
				return [errstr['undef'] + s]
			else:
				errors['undef'][s] = s
				return 0

	# Initialisierung
	op = s[0]
	ret = evaluate(s[1])
	if type(ret) == type([]):
		return ret

	# Abarbeitung einer Operation
	for i in s[2:]:
		x = evaluate(i)
		if type(x) == type([]):
			return x
		if op == "+":
			ret = ret + x
		elif op == "-":
			ret = ret - x
		elif op == "*":
			ret = ret * x
		elif op == "/":
			if x != 0:
				ret = ret / x
			else:
				if behaviour == "fast":
					return [errstr['math'] + "division by zero"]
				else:
					errors['math']['zero'] = "division by zero"
					ret = 0

	# Rückgabe
	return ret

# Hauptprogramm
while pstate:

	# Eingabe der Daten
	l = raw_input(">")
	if reprint:
		q = "'" + l + "'"
		q = q.replace("\t", "\\t")
		print q

	# Programm beenden?
	if l == "%":
		pstate = 0
	else:
		# Eingabe normalisieren
		l = l.replace(" ", "")
		l = l.replace("\t", "")

		# Alles außer Kommentare und Leerzeilen auswerten
		if l != "" and l[0] != "#":

			# Zuweisungsoperation oder Berechnung
			if l.count("=") > 0:
				(var, value) = l.split("=")
				if not parser.is_identifier(var):
					print var +" is not an identifier"
				else:
					# Zuweisung oder Löschung
					if value:
						vars[var] = parser.parse_eq(value)
					else:
						if vars.has_key(var):
							del vars[var]
						else:
							print var + " is not set"
					if not reprint:
						print
			else:
				# Berechnen des Parse-Baumes
				list = parser.parse_eq(l)

				# Parser-Fehler erkennen
				if type(list) == type(()):
					print list[0]
				else:
					if behaviour == "compliant":
						errors['rec'] = {}
						errors['undef'] = {}
						errors['math'] = {}

					result = evaluate(list)

					# Berechnungs-Fehler erkennen
					if type(result) == type([]):
						print result[0]
					else:
						if behaviour == "compliant":
							if len(errors['math']) == 0 and len(errors['undef']) == 0 and len(errors['rec']) == 0:
								print result
							else:
								for i in errors['math'].keys():
									print errstr['math'] + errors['math'][i]
								for j in ["undef", "rec"]:
									if len(errors[j]) > 0:
										x = errstr[j]
										y = ""
										list = errors[j].keys()
										list.sort()
										for i in list:
											if len(y) > 0:
												y = y + ", "
											y = y + errors[j][i]
										print x + y
						else:
							print result
		else:
			if not reprint:
				print



syntax highlighted by Code2HTML, v. 0.9.1