#include <iostream>

#include <string>

#include <stdlib.h>
using namespace std;

typedef float Lisp_t;
#define convFunc atof


const size_t MAX_ARGS = 10;
const size_t MAX_FUNCS = 50;

size_t NUM_FUNCS = 0;

size_t NUM_ARGS = 0;
Lisp_t* ARG_SET = 0;
string* ARG_NAME = 0;

Lisp_t eval (string str);
Lisp_t eval_iter (string& str);
char pop (string& str);
void removeInitialWhiteSpace (string& str);
bool isWhiteSpace (char c);
bool moreArgs (string& str);
string popWord (string& str);
string popSExp (string& str);
Lisp_t popValue (string& str);
Lisp_t add (string& str);
Lisp_t subt (string& str);
Lisp_t mult (string& str);
Lisp_t div (string& str);
void removeRightParen (string& str);

class Function
{
public:
	Function (string& inName, string inLambdaList, string& inBody);

	size_t getNumArgs ();
	string getName ();
	string* getArgNames ();
	string getBody ();

	~Function ();
private:

	string name, body;
	string* arg;
	size_t numArgs;
};

Function* FUNC[MAX_FUNCS];

Function::Function (string& inName, string inLambdaList, string& inBody)
:name(inName), body(inBody)
{
	if (pop(inLambdaList) != '(')
	{
		cerr << "Could not construct function " << name << endl;
		exit(1);
	}

	arg = new string[MAX_ARGS];
	size_t i = 0;

	while (moreArgs(inLambdaList))
	{
		if (i == MAX_ARGS)
		{
			cerr << "Too many args in definition for function " << name << endl;
		}

		arg[i] = popWord(inLambdaList);
		i++;
	};

	numArgs = i;
}

Function::~Function ()
{
	delete [] arg;
}

size_t Function::getNumArgs ()
{
	return numArgs;
}

string Function::getName ()
{
	return name;
}

string* Function::getArgNames ()
{
	return arg;
}

string Function::getBody ()
{
	return body;
}

void main ()
{
	string input;

	while (1)
	{
		cout << "Gimme: ";
		getline(cin, input, '\n');
		cout << "Input is " << input << endl;
		cout << eval(input) << endl;

	};
}

// Make a copy so we can evaluate the string
// Destructively
Lisp_t eval (string str)
{
	return eval_iter(str);
}

Lisp_t eval_iter (string& str)
{
	removeInitialWhiteSpace(str);
	string word;

	if (str[0] == '(')
	{
		pop(str);
		removeInitialWhiteSpace(str);

		word = popWord(str);
		
		if (word == "+")
		{
			Lisp_t temp = add(str);
			removeRightParen(str);
			return temp;
		}

		= "*")
	

		if (word == "-")


 "/")
		{
	

		if (word == "defun")
		{
			if (NUM_FUNCS == MAX_FUNCS)
			
			int i;

			if (NUM_FUNCS)
			{
				for (i = 0; i < NUM_FUNCS; i++)
			
			}

			if (newFunc)
				i = NUM_FUNCS++;

	
		}

// need to handle function redefinitions

		if (NUM_FUNCS)
		{
			int fc;
			for (fc = 0; fc < NUM_FUNCS; fc++)
			{
				if (word == FUNC[fc]->getName ())
				{
					Lisp_t* arg = new Lisp_t[FUNC

					for (i = 0; i < FUNC[fc]->getNumArgs (); i++)
					{
						if (!moreArgs(str))
			

				

				
						cerr << "Too many arguments provided to function " << FUNC[fc]->getName () << endl;
					

				old_arg_set = ARG_SET;
				
		
					ARG_NAME = FUNC[fc]->getArgNames ();
					N;

					Lisp_t temp = eval(;

				

		}

		if (word == "exit")
			exit(0);


		cerr << "Unknown function" << endl;
		exit(1);
	}
	else
	{
		word = popWord(str);


	cerr << "I am very confused" << endl;
	exit(1);
	return(1);
}

void removeInitialWhiteSpace (string& str)
{
	if (isWhiteSpace(str[0]))
	{
		pop(str);
		removeInitialWhiteSpace(str);
	}
}

char pop (string& str)
{
	char temp = str[0];
	str.erase(unsigned(0), unsigned(1));
	return temp;
}

bool isWhiteSpace (char c)
{
	return c == ' ' || c == '\t' || c == '\n';
}

string popWord (string& str)
{
	string word;

	removeInitialWhiteSpace (str);

	while (!isWhiteSpace(str[0]) && str[0] != ')')
	{
		word += pop(str);
	};

	return word;
}

string popSExp (string& str)
{
	removeInitialWhiteSpace (str);

	if (str[0] != '(')
	{
		return popWord(str);
	}
	else
	{
		string sExp;
		int danglingParens = 0;

		do
		{
			char c = pop(str);
			switch (c)
			{
			case '(':
				danglingParens++;
				break;

			case ')':
				danglingParens--;
				break;
			}

			sExp += c;
		} while (danglingParens > 0);

		return sExp;
	}
}

Lisp_t popValue (string& str)
{
	return convFunc ( (popWord(str)).c_str() );
}

bool moreArgs (string& str)
{
	removeInitialWhiteSpace(str);

	return str[0] != ')';
}

Lisp_t add (string& str)
{
	Lisp_t total = 0;

	while (moreArgs(str))
	{
		total += eval_iter(str);
	};

	return total;
}

Lisp_t mult (string& str)
{
	Lisp_t prod = 1;

	while (moreArgs(str))
	{
		prod *= eval_iter(str);
	};

	return prod;
}

Lisp_t subt (string& str)
{
	if (!moreArgs(str))
	{
		cerr << "Insufficient arguments" << endl;
		exit(1);
	}

	Lisp_t total = eval_iter(str);

	while (moreArgs(str))
	{
		total -= eval_iter(str);
	};

	return total;
}

Lisp_t div (string& str)
{
	if (!moreArgs(str))
	{
		cerr << "Insufficient arguments" << endl;
		exit(1);
	}

	Lisp_t quotient = eval_iter(str);

	while (moreArgs(str))
	{
		Lisp_t temp = eval_iter (str);

		if (temp == 0)
		{
			cerr << "Division by zero" << endl;
			exit(1);
		}


		quotient /= temp;
	};

	return quotient;
}

void removeRightParen (string& str)
{
	removeInitialWhiteSpace (str);
	if (pop(str) != ')')
	{
		cerr << "Badly formatted command" << endl;
		exit(1);
	}
}
