/*
 * libexparse
 * Copyright (C) 2003 Krzysztof Witkowski <tjup@gazeta.pl>
 * License: GPL
 * Last modified: working all the time :)
 * Version: 0.2.0
 */

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string.h>

#include <list>
#include <stack>

#include <stdexcept>
#include <new>


extern "C" int exp_eval(const char *,void *);

/*
#define EXPARSE_DEBUG
#define ASMSH
*/
//#define NOT_ERROR_THROW

#ifdef ASMSH

/* Tu nalezy daæ prototyp do fetch_mem */
#ifdef EXPARSE_DEBUG
int fetch_mem(int addr,int len,void *result)
{
	*(long long*)result=addr;
}
#endif
#endif

using namespace std;

enum TYPE {T_INT='I',T_DOUBLE='D',T_OPER_S='S',T_OPER_D='O',T_PARENTH='P',NONE='N'};

/* order DOES MATTER - it is used in priority table */

enum OPER {LOG_NOT=0,CAST_INT,SUBU,BIT_NOT,GET_MEM,
		POWER,
		MUL,DIV,MOD,
		ADD,SUBD,
		ROL,ROR,SHIFT_R,SHIFT_L,
		LESS,MORE,LESS_EQUAL,MORE_EQUAL,
		EQUAL,NOT_EQUAL,
		BIT_AND,
		BIT_XOR,
		BIT_OR,
		LOG_AND,
		LOG_XOR,
		LOG_OR
		};


enum NAWIASY {OPEN=0,CLOSE};
		

/*
 * Operators priority, from highest to lowest
 * '-' unary minus, ':' cast int, '!' log_not, ~ bit not
 * **
 * *,/,%
 * +,-
 * >>,>>>,<<,<<<
 * <,>,<=,>=
 * == !=
 * &
 * ^
 * |
 * &&
 * ^^
 * ||
 */

char priority[LOG_OR+1]={100,100,100,100,100,
					99,
					98,98,98,
					97,97,
					96,96,96,96,
					95,95,95,95,
					94,94,
					93,
					92,
					91,
					90,
					89,
					88};

struct token {
	int type;
	union {
		long long ll64;
		double d32;
		struct {
		char oper;
		char oper_arg;
		} oper;
	} value;
};

#define IS_DIGIT(x) ((x>='0' && x<='9') || x == '.')
#define IS_OPER(x)  ( x == '+' || x == '-' || x == '/' ||\
					  x == '*' || x == '%' || x == '~' ||\
					  x == '^' || x == '&' || x == '|' ||\
					  x == '<' || x == '>' || x == '!' ||\
					  x == '=' || x == ':' || x == '~' )


#define higher_priority(a,b) (priority[a] >= priority[b])

void list_debug(list<token> &e)
{
	list<token>::iterator li;
	
	for(li=e.begin();li != e.end();li++)
	{
		switch(li->type)
		{
			case T_INT:
			cout << li->value.ll64;
			break;

			case T_DOUBLE:
			cout << li->value.d32;
			break;

			case T_PARENTH:
			cout << '(' + li->value.oper.oper;
			break;

			case T_OPER_S:
			cout << "SINGLE_OPER";
			break;

			case T_OPER_D:
			cout << "DOUBLE OPER";
			break;
		}
		cout << endl;
	}
}

int exp_anal(const char *e,list<token> &exp)
{
	/* Change data structure from char[] to list<token> 
	 * Boring :) 
	 * if throw is not supported it returns 1 on failure and 0 
	 * on success
	 */

	int i=0;
	struct token curr;
	int l; 
	char *liczba;
	
	l = strlen(e);
	liczba = new char[l+1];
	memset(liczba,0,l+1);

#ifndef NOT_ERROR_THROW
	try {
#endif
	while(i<l)	//czy to dobre?
	{
		curr.type = NONE;
		curr.value.ll64=0;

		if(IS_DIGIT(e[i]))
		{
#define	MAX_DIGIT	100
			int il=0,dot=0,hex=0;
			char *ch_wsk;

			liczba[il]=e[i];
			il++;
			
			if(e[i] == '.')
				dot++;

			i++;
			
			if(e[i] == 'x')
			{
				/* na drugiej pozycji x */
				liczba[i]='x';
				hex++;
				i++;
				il++;
			}


			while(IS_DIGIT(e[i]) || e[i] == '.')
			{
				liczba[il++]=e[i];
				
				if(e[i++] == '.')
					dot++;
			}

			liczba[il]=0;

			if(dot>1)
#ifndef NOT_ERROR_THROW
				throw runtime_error("Too many dotes in float number");
#else
			{
				delete [] liczba;
				fprintf(stderr,"Too many dotes in float number\n");
				return 1;
			}
#endif

			if(dot && hex)
#ifndef NOT_ERROR_THROW
				throw runtime_error("Numbers in hex can't contain dots");
#else
			{
				delete [] liczba;
				fprintf(stderr,"Numbers in hex can't contain dots\n");
				return 1;
			}
#endif

			if(dot == 1)
			{
				curr.value.d32 = strtod(liczba,&ch_wsk);
				curr.type = T_DOUBLE;
			}
			else
			{
				curr.value.ll64 = strtoll(liczba,&ch_wsk,0);
				curr.type = T_INT;
			}
			// format powinien byæ ok 
			if(liczba+il != ch_wsk)
#ifndef	NOT_ERROR_THROW
				runtime_error("Unknown numeric format");
#else
			{
				delete [] liczba;
				fprintf(stderr,"Unknown numeric format\n");
				return 1;
			}
#endif
		}
#ifdef ASMSH
		else if(e[i] == '@')
		{
			int len;
			i++;
			if(e[i] < '1' || e[i] > '8')
#ifndef NOT_ERROR_THROW
				throw runtime_error("@ operator must be followed by 1-8");
#else
			{
				delete [] liczba;
				fprintf(stderr,"@ operator must be followed by 1-8\n");
				return 1;
			}
#endif
			len = e[i] - '0';
			i++;
			if(e[i] != ':')
#ifndef NOT_ERROR_THROW
				throw runtime_error("@ must be followed by :");
#else
			{
				delete [] liczba;
				fprintf(stderr,"@ must be followed by :\n");
				return 1;
			}
#endif

			i++;
			curr.type = T_OPER_S;
			curr.value.oper.oper = GET_MEM;
			curr.value.oper.oper_arg = len;
		}
#endif
		else if(IS_OPER(e[i]))
		{
			curr.type = T_OPER_D;
			
			if(e[i] == '!')
			{
				i++;
				curr.value.oper.oper = LOG_NOT;
				curr.type = T_OPER_S;
				if(e[i] == '=')
				{
					i++;
					curr.value.oper.oper = NOT_EQUAL;
					curr.type = T_OPER_D;
				}
			}
			else if(e[i] == '>')
			{
				if(e[i+1] == '>')
				{
					if(e[i+2] == '>')
					{
						i += 3;
						curr.value.oper.oper = ROR;
					}
					else
					{
						i+=2;
						curr.value.oper.oper = SHIFT_R;
					}
				}
				else if(e[i+1] == '=')
				{
					i+=2;
					curr.value.oper.oper = MORE_EQUAL;
				}
				else
				{
					i++;
					curr.value.oper.oper = MORE;
				}
			}
			else if(e[i] == '<')
			{
				if(e[i+1] == '<')
				{
					if(e[i+2] == '<')
					{
						i += 3;
						curr.value.oper.oper = ROL;
					}
					else
					{
						i+=2;
						curr.value.oper.oper = SHIFT_L;
					}
				}
				else if(e[i+1] == '=')
				{
					i+=2;
					curr.value.oper.oper = LESS_EQUAL;
				}
				else
				{
					i++;
					curr.value.oper.oper = LESS;
				}
			}
			else if(e[i] == '*')
			{
				if(e[i+1] == '*')
				{
					curr.value.oper.oper = POWER;
					i+=2;
				}
				else
				{
					i++;
					curr.value.oper.oper = MUL;
				}
			}
			else if(e[i] == '&')
			{
				if(e[i+1] == '&')
				{
					i+=2;
					curr.value.oper.oper = LOG_AND;
				}
				else
				{
					curr.value.oper.oper = BIT_AND;
					i++;
				}
			}
			else if(e[i] == '|')
			{
				if(e[i+1] == '|')
				{
					i+=2;
					curr.value.oper.oper = LOG_OR;
				}
				else
				{
					i++;
					curr.value.oper.oper = BIT_OR;
				}
			}
			else if(e[i] == '^')
			{
				if(e[i+1] == '^')
				{
					i+=2;
					curr.value.oper.oper = LOG_XOR;
				}
				else
				{
					i++;
					curr.value.oper.oper = BIT_XOR;
				}
			}
			else if(e[i] == '=')
			{
				if(e[i+1] == '=')
					i++;
				i++;
				curr.value.oper.oper = EQUAL;
			}
			else if(e[i] == ':')
			{
				i++;
				curr.value.oper.oper = CAST_INT;
				curr.type = T_OPER_S;
			}
			else if(e[i] == '+')
			{
				i++;
				curr.value.oper.oper = ADD;
			}
			else if(e[i] == '-')
			{
				i++;
				curr.value.oper.oper = SUBU;
				curr.type = T_OPER_S;
			}
			else if(e[i] == '/')
			{
				i++;
				curr.value.oper.oper = DIV;
			}
			else if(e[i] == '%')
			{
				i++;
				curr.value.oper.oper = MOD;
			}
			else if(e[i] == '~')
			{
				i++;
				curr.value.oper.oper = BIT_NOT;
				curr.type = T_OPER_S;
			}
			else
#ifndef NOT_ERROR_THROW
				throw runtime_error("Operator not implemented: internal error");
#else
			{
				delete [] liczba;
				fprintf(stderr,"Operator not implemented: internal error\n");
				return 1;
			}
#endif
		}
		else if(e[i] == ')')
		{
			i++;
			curr.value.oper.oper = CLOSE;
			curr.type = T_PARENTH;
		}
		else if(e[i] == '(')
		{
			i++;
			curr.value.oper.oper = OPEN;
			curr.type = T_PARENTH;
		}
		else if(isspace(e[i]))
		{
			i++;
		}
		else
#ifndef NOT_ERROR_THROW
				throw runtime_error("Wron expression format");
#else
			{
				delete [] liczba;
				fprintf(stderr,"Wrong expreesion format\n");
				return 1;
			}
#endif
		
		if(curr.type != NONE)
			exp.push_back(curr);
	}	//while
#ifndef NOT_ERROR_THROW
	}	//try 
#endif

#ifndef NOT_ERROR_THROW
	catch ( runtime_error err )
	{
		delete [] liczba;
		throw;
	}
#endif
	
	delete [] liczba;
	return 0;
}

int infix2postfix(list<token> &exp_i,list<token> &exp_p)
{
	/* Transform infix expression into postfix */
	
	struct token tmp;
	stack<token> s;
	list<token>::iterator li;
	int last=1;
	
	tmp.type = T_PARENTH;
	tmp.value.oper.oper = CLOSE;
	exp_i.push_back(tmp);
	
	tmp.value.oper.oper = OPEN;
	s.push(tmp);

	li = exp_i.begin();

	while(!s.empty() && li != exp_i.end())
	{
		if(li->type == T_INT || li->type == T_DOUBLE) {
			exp_p.push_back(*li);

			tmp = s.top();

			if(tmp.type == T_OPER_S) {
				s.pop();
				exp_p.push_back(tmp);
			}
		}
		else if(li->type == T_PARENTH)
			if(li->value.oper.oper == OPEN)
				s.push(*li);
			else
			{
				int err=1;
				while(!s.empty())
				{
					tmp = s.top();
					s.pop();
					if(tmp.type == T_PARENTH && tmp.value.oper.oper == OPEN)
					{
						err=0;
						break;
					}
					if(err)
						exp_p.push_back(tmp);
				}

				if(err)
#ifndef NOT_ERROR_THROW
					throw runtime_error("too many closing brackets");
#else
				{
					fprintf(stderr,"Too many closing brackets\n");
					return 1;
				}
#endif
			}
		else if(li->type == T_OPER_D || li->type == T_OPER_S)
		{
			/* minus is unary only if it is after parenthethis */
			if(li->value.oper.oper == SUBU && !last)
			{
				li->type = T_OPER_D;
				li->value.oper.oper = SUBD;
			}

			 /* if(!s.empty()) nigdy nie jest prawdziwe, bo na stosie
			  * otwierajacy nawias*/
			tmp = s.top();

			if(tmp.type == T_OPER_D && 
			  higher_priority((int)tmp.value.oper.oper,(int)li->value.oper.oper))
			{
				s.pop();
				exp_p.push_back(tmp);
			}
			s.push(*li);
		}
		else
#ifndef NOT_ERROR_THROW
			throw runtime_error("None? Why?");
#else
		{
			fprintf(stderr,"Nony? Why?\n");
			return 1;
		}
#endif

		last=1;
		if(li->type == T_INT || li->type == T_DOUBLE)
			last=0;
		li++;
	}

	if(li != exp_i.end())
#ifndef NOT_ERROR_THROW
		throw runtime_error("parse error");
#else
	{
		fprintf(stderr,"parse error\n");
		return 1;
	}
#endif
	return 0;
}

#ifdef ASMSH
void get_mem(int oper,int len,token &t)
{
	if(t.type != T_INT)
#ifndef NOT_ERROR_THROW
		throw runtime_error("Address in @n:address must be integer");
#else
	{
		fprintf(stderr,"Address in @n:address must be integer\n");
		return 1;
	}
#endif
	if(fetch_mem(t.value.ll64,len,(void*)(&t.value.ll64)) == 1)
#ifndef NOT_ERROR_THROW
		throw runtime_error("fetch_mem failed");
#else
	{
		fprintf(stderr,"fetch_mem failed\n");
		return 1;
	}
#endif
	
}
#endif

int single_oper(int oper,token &t)
{
	/* Computes single unary statement */
	switch(oper)
	{
		case BIT_NOT:
		if(t.type != T_INT)
#ifndef NOT_ERROR_THROW
			throw runtime_error("Operator ~ needs integer as operand");
#else
		{
			fprintf(stderr,"Operator ~ needs integer as operand\n");
			return 1;
		}
#endif
		else
			t.value.ll64 = (~t.value.ll64);
		break;

		case LOG_NOT:
		if(t.type != T_INT)
#ifndef	NOT_ERROR_THROW
			throw runtime_error("Operator ! need integer as operand");
#else
		{
			fprintf(stderr,"Operator ! need integer as operand\n");
			return 1;
		}
#endif
		else
			t.value.ll64 = (!t.value.ll64);
		break;

		case CAST_INT:
		if(t.type == T_DOUBLE)
			t.value.ll64 = (long long)t.value.d32;
		t.type = T_INT;
		break;

		case SUBU:
		if(t.type == T_INT)
			t.value.ll64 = -t.value.ll64;
		else
			t.value.d32 = -t.value.d32;
		break;

		default:
#ifndef NOT_ERROR_THROW
		throw runtime_error("shit. this shouldn't happen!");
#else
		{
			fprintf(stderr,"shit, this shouldn't happen!\n");
			return 1;
		}
#endif
	}
	return 0;
}

template< class T>
void power(T &p,long long w)
{
	T m=p;
	p=1;
	for(int i=1;i<=w;i++)
			p*=m;
}

void ror(long long &l,int x)
{
	/* shifts leave number zeroed, I hope :)
	 * x = <0,63>							*/
	long long tmp = 0;

	tmp = (l >> x) | (l << (64 - x));

	l = tmp;
}

void rol(long long &l,int x)
{
	long long tmp = 0;

	tmp = (l << x) | (l >> (64 -x));

	l=tmp;
}

int double_oper(int oper,token &t1,token &t2)
{
	/* Computes single expression of two arguments */
	
	if(t1.type == T_DOUBLE || t2.type == T_DOUBLE)
		switch(oper)
		{
			case MOD:
			case BIT_AND:
			case BIT_OR:
			case BIT_XOR:
			case LOG_OR:
			case LOG_AND:
			case LOG_XOR:
			case ROR:
			case SHIFT_R:
			case ROL:
			case SHIFT_L:
#ifndef NOT_ERROR_THROW
				throw runtime_error("Double found where integer expected");
#else
				fprintf(stderr,"Double found where integer expected\n");
				return 1;
#endif
			break;
			
			case POWER:
			if(t2.type == T_DOUBLE)
#ifndef NOT_ERROR_THROW
				throw runtime_error("Exponent must be integer");
#else
			{
				fprintf(stderr,"Exponent must be integer\n");
				return 1;
			}
#endif
			break;
		}

	switch(oper)
	{
		case MOD:
		if(t2.value.ll64 != 0)
			t1.value.ll64 %= t2.value.ll64;
		else
#ifndef NOT_ERROR_THROW
			throw runtime_error("Division by zero");
#else
		{
			fprintf(stderr,"Division by zero\n");
			return 1;
		}
#endif
		break;

		case BIT_AND:
			t1.value.ll64 &= t2.value.ll64;
		break;

		case BIT_OR:
			t1.value.ll64 |= t2.value.ll64;
		break;

		case BIT_XOR:
			t1.value.ll64 ^= t2.value.ll64;
		
		case LOG_AND:
			t1.value.ll64 = t1.value.ll64 && t2.value.ll64;
		break;

		case LOG_OR:
			t1.value.ll64 = t1.value.ll64 || t2.value.ll64;
		break;

		case LOG_XOR:
		if((t1.value.ll64 && !t2.value.ll64) ||
			(t2.value.ll64 && !t1.value.ll64))
			t1.value.ll64 = 1;
		else
			t1.value.ll64 = 0;
		break;

		case SHIFT_R:
		if(t2.value.ll64 >= 64)
			t1.value.ll64=0;
		else
			t1.value.ll64 >>= t2.value.ll64;
		break;

		case SHIFT_L:
		if(t2.value.ll64 >= 64)
			t1.value.ll64=0;
		else
			t1.value.ll64 <<= t2.value.ll64;
		break;

		case ROR:
		ror(t1.value.ll64,(t2.value.ll64 % 64));
		break;
		case ROL:
		rol(t1.value.ll64,(t2.value.ll64 % 64));
		break;

		case POWER:
		if(t1.type == T_DOUBLE)
			power(t1.value.d32,t2.value.ll64);
		else
			power(t1.value.ll64,t2.value.ll64);
		break;

		case ADD:
		if(t1.type == T_DOUBLE)
			if(t2.type == T_DOUBLE)
				t1.value.d32 += t2.value.d32;
			else
				t1.value.d32 += (double)t2.value.ll64;
		else
			if(t2.type == T_INT)
				t1.value.ll64 += t2.value.ll64;
			else
			{
				t1.type = T_DOUBLE;
				t1.value.d32 = t2.value.d32 + (double)t1.value.ll64;
			}
		break;
		
		case SUBD:
		if(t1.type == T_DOUBLE)
			if(t2.type == T_DOUBLE)
				t1.value.d32 -= t2.value.d32;
			else
				t1.value.d32 -= (double)t2.value.ll64;
		else
			if(t2.type == T_INT)
				t1.value.ll64 -= t2.value.ll64;
			else
			{
				t1.type = T_DOUBLE;
				t1.value.d32 = t1.value.ll64 - t2.value.d32;
			}
		break;
		
		case DIV:
		if(t2.type == T_DOUBLE)
		{
			if(t2.value.d32 == 0)
#ifndef NOT_ERROR_THROW
				throw runtime_error("Division by zero");
#else
			{
				fprintf(stderr,"Division by zero\n");
				return 1;
			}
#endif
			
			if(t1.type == T_DOUBLE)
				t1.value.d32 /= t2.value.d32;
			else
			{
				t1.type = T_DOUBLE;
				t1.value.d32 = t1.value.ll64 / t2.value.d32;
			}
		}
		else
		{
			if(t2.value.ll64 == 0)
#ifndef NOT_ERROR_THROW
				throw runtime_error("Division by zero");
#else
			{
				fprintf(stderr,"Division by zero\n");
				return 1;
			}
#endif
			
			if(t1.type == T_INT)
				t1.value.ll64 /= t2.value.ll64;
			else
			{
				t1.value.d32 /= t2.value.ll64;
			}
		}
		break;
		
		case MUL:
		if(t1.type == T_DOUBLE)
			if(t2.type == T_DOUBLE)
				t1.value.d32 *= t2.value.d32;
			else
				t1.value.d32 *= (double)t2.value.ll64;
		else
			if(t2.type == T_INT)
				t1.value.ll64 *= t2.value.ll64;
			else
			{
				t1.type = T_DOUBLE;
				t1.value.d32 = t2.value.d32 * (double)t1.value.ll64;
			}
		break;

		case EQUAL:
		if(t1.type == T_DOUBLE)
			if(t2.type == T_DOUBLE)
				t1.value.ll64 = (t1.value.d32 == t2.value.d32);
			else
				t1.value.ll64 = (t1.value.d32 == t2.value.ll64);
		else
			if(t2.type == T_INT)
				t1.value.ll64 = (t1.value.ll64 == t2.value.ll64);
			else
			{
				t1.value.ll64 = (t1.value.ll64 == t2.value.d32);
			}
		break;
	
		case NOT_EQUAL:
		if(t1.type == T_DOUBLE)
			if(t2.type == T_DOUBLE)
				t1.value.ll64 = (t1.value.d32 != t2.value.d32);
			else
				t1.value.ll64 = (t1.value.d32 != t2.value.ll64);
		else
			if(t2.type == T_INT)
				t1.value.ll64 = (t1.value.ll64 != t2.value.ll64);
			else
			{
				t1.value.ll64 = (t1.value.ll64 != t2.value.d32);
			}
		break;
		
		case MORE:
		if(t1.type == T_DOUBLE)
			if(t2.type == T_DOUBLE)
				t1.value.ll64 = (t1.value.d32 > t2.value.d32);
			else
				t1.value.ll64 = (t1.value.d32 > t2.value.ll64);
		else
			if(t2.type == T_INT)
				t1.value.ll64 = (t1.value.ll64 > t2.value.ll64);
			else
			{
				t1.value.ll64 = (t1.value.ll64 > t2.value.d32);
			}
		break;

		case MORE_EQUAL:
		if(t1.type == T_DOUBLE)
			if(t2.type == T_DOUBLE)
				t1.value.ll64 = (t1.value.d32 >= t2.value.d32);
			else
				t1.value.ll64 = (t1.value.d32 >= t2.value.ll64);
		else
			if(t2.type == T_INT)
				t1.value.ll64 = (t1.value.ll64 >= t2.value.ll64);
			else
			{
				t1.value.ll64 = (t1.value.ll64 >= t2.value.d32);
			}
		break;

		case LESS:
		if(t1.type == T_DOUBLE)
			if(t2.type == T_DOUBLE)
				t1.value.ll64 = (t1.value.d32 < t2.value.d32);
			else
				t1.value.ll64 = (t1.value.d32 < t2.value.ll64);
		else
			if(t2.type == T_INT)
				t1.value.ll64 = (t1.value.ll64 < t2.value.ll64);
			else
			{
				t1.value.ll64 = (t1.value.ll64 < t2.value.d32);
			}
		break;

		case LESS_EQUAL:
		if(t1.type == T_DOUBLE)
			if(t2.type == T_DOUBLE)
				t1.value.ll64 = (t1.value.d32 <= t2.value.d32);
			else
				t1.value.ll64 = (t1.value.d32 <= t2.value.ll64);
		else
			if(t2.type == T_INT)
				t1.value.ll64 = (t1.value.ll64 <= t2.value.ll64);
			else
			{
				t1.value.ll64 = (t1.value.ll64 <= t2.value.d32);
			}
		break;

		default:
#ifndef NOT_ERROR_THROW
		throw runtime_error("buggy software 1.0");
#else
		{
			fprintf(stderr,"buggy software 1.0\n");
			return 1;
		}
#endif
		break;
	}
	return 0;
}

int num_eval(list<token> &exp,token &result)
{
	/* Input: postfix expression
	 * Computes numeric result of expression
	 */
	
	stack<token> s;
	list<token>::iterator li;
	token t1,t2;

	li = exp.begin();

	while(li != exp.end())
	{
		if(li->type == T_INT || li->type == T_DOUBLE)
			s.push(*li);
		else if(li->type == T_OPER_S)
		{
			if(s.empty())
#ifndef NOT_ERROR_THROW
				throw runtime_error("parse error 2");
#else
			{
				fprintf(stderr,"parse error 2\n");
				return 1;
			}
#endif
			
			t1 = s.top();
			s.pop();

#ifdef ASMSH
			if(li->value.oper.oper != GET_MEM)
				if(single_oper(li->value.oper.oper,t1)) {
					return 1;
				}
			else {
				if(get_mem(li->value.oper.oper,li->value.oper.oper_arg,t1)) {
					return 1;
				}
			}
#else
			if(single_oper(li->value.oper.oper,t1)) {
				return 1;
			}
#endif

			s.push(t1);
		}
		else // T_OPER_D
		{
			if(s.size() < 2)
#ifndef NOT_ERROR_THROW
				throw runtime_error("parse error 3");
#else
			{
				fprintf(stderr,"parse error 3\n");
				return 1;
			}
#endif

			t2 = s.top();
			s.pop();
			t1 = s.top();
			s.pop();

			if(double_oper(li->value.oper.oper,t1,t2)) {
				return 1;
			}

			s.push(t1);
		}
		li++;
	}

	if(s.size() != 1)
#ifndef NOT_ERROR_THROW
		throw runtime_error("parse error 4");
#else
	{
		fprintf(stderr,"parse error 4\n");
		return 1;
	}
#endif

	result = s.top();
	s.pop();

	return 0;
}
	

int exp_eval(const char *e,void *result)
{
	/* Main library function: catch errors,
	 * call other functions and prepare results
	 */
	list<token> *exp_i,*exp_p;
	token r;

	exp_i = NULL;
	exp_p = NULL;

#ifndef NOT_ERROR_THROW
	try {
#endif

		exp_i = new list<token>;
		exp_p = new list<token>;
		
		if(!e || !result)
#ifndef NOT_ERROR_THROW
			throw runtime_error("Null pointer supplied");
#else
		{
			fprintf(stderr,"Null pointer supplied\n");
			delete exp_i;
			delete exp_p;
			return 2;
		}
#endif

#ifndef NOT_ERROR_THROW
		exp_anal(e,*exp_i);
#else
		if(exp_anal(e,*exp_i)) {
			delete exp_i;
			delete exp_p;
			return 2;
		}
#endif

#ifdef NOT_ERROR_THROW
		if(infix2postfix(*exp_i,*exp_p)) {
			delete exp_i;
			delete exp_p;
			return 2;
		}
#else
		infix2postfix(*exp_i,*exp_p);
#endif

		delete exp_i;
		exp_i = NULL;

#ifdef EXPARSE_DEBUG
		list_debug(*exp_p);
#endif

#ifdef NOT_ERROR_THROW
		if(num_eval(*exp_p,r)) {
			delete exp_p;
			return 2;
		}
#else
		num_eval(*exp_p,r);
#endif

#ifdef EXPARSE_DEBUG
		if(r.type == T_DOUBLE)
			cout << "Lib Wynik: " << r.value.d32;
		else
			cout << "Lib Wynik: " << r.value.ll64;
		cout << endl;
#endif

		delete exp_p;
		exp_p = NULL;

		if(r.type == T_INT)
		{
			*(long long *)result=r.value.ll64;
			return 0;
		}
		*(double*)result=r.value.d32;
		return 1;

#ifndef NOT_ERROR_THROW	
	}
	catch ( bad_alloc err )
	{
		if(exp_p != NULL)
			delete exp_p;
		if(exp_i != NULL)
			delete exp_i;
		cerr << "libexparse: " << err.what() << endl;
		return 2;
	}
	
	catch ( runtime_error err )
	{
		if(exp_p != NULL)
			delete exp_p;
		if(exp_i != NULL)
			delete exp_i;

		cerr << "libexparse: " << err.what() << endl;
		return 2;
	}

#endif

}

