
///////////////////////////////////////////////////////////////////////////////
//                                                                           //
//                                  Parser                                   //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

#include "..\include.h"

/* Operator precedence (priority):
 a..z, A..Z (variable)
 ! (factorial, '!' immediately after operand)
 () (expression)
 function (parentheses not needed)
 + - ~ (unary plus and minus, unary bitwise NOT)
 ^ (power)
 * / : % (multiplication, division, integer division, remainder = modulo)
 + - (addition and subtraction)
 < > (bitwise left/right shift)
 & (bitwise AND)
 @ (bitwise XOR)
 | (bitwise OR)
 = (set variable)
 ? (request to display result)
 # (comment until end of row)
*/

///////////////////////////////////////////////////////////////////////////////
// get character (0=none)

char ParseCh()
{
	if (RowPos >= Row.Length()) return 0;
	return Row[RowPos++];
}

///////////////////////////////////////////////////////////////////////////////
// test next character (0=none)

char ParseTest()
{
	if (RowPos >= Row.Length()) return 0;
	return Row[RowPos];
}

///////////////////////////////////////////////////////////////////////////////
// return character

void ParseRet(char ch)
{
	if (ch != 0) RowPos--;
}

///////////////////////////////////////////////////////////////////////////////
// skip spaces

void ParseSpc()
{
	char ch;
	for (;;)
	{
		ch = ParseCh();
		if ((ch <= 0) || (ch > ' '))
		{
			ParseRet(ch);
			break;
		}
	}
}

///////////////////////////////////////////////////////////////////////////////
// get word

CText ParseWord()
{
	ParseSpc();
	CText txt;
	char ch;

	for (;;)
	{
		ch = ParseCh();
		if ((ch < 'a') || (ch > 'z'))
		{
			ParseRet(ch);
			break;
		}
		txt += ch;
	}

	return txt;
}

///////////////////////////////////////////////////////////////////////////////
// parse one operand

void ParseOper()
{
	Stack[StackNum].Set0();

	ParseSpc();
	CText wrd;

	char ch;
	for (;;)
	{
		// check word
		wrd = ParseWord();
		if (wrd.Length() > 1)
		{
			// random
			if (wrd == "randraw")
			{
				Stack[StackNum].RandRaw(IntRand, DecRand, IntRandMin, DecRandMin);
				break;
			}
		}
		RowPos -= wrd.Length();

		// get character
		ch = ParseCh();
		if (ch == 0) return;
		if (ch == '+') continue;

		// negate
		if (ch == '-')
		{
			ParseOper();
			Stack[StackNum].Neg();
			break;
		}

		// inverse
		if (ch == '~')
		{
			ParseOper();
			Stack[StackNum].Not();
			break;
		}

		// number
		if (((ch >= '0') && (ch <= '9')) || (ch == '.'))
		{
			ParseRet(ch);
			RowPos = Stack[StackNum].FromText(Row, RowPos);
			break;
		}

		// variable
		if ((ch >= 'a') && (ch <= 'z'))
		{
			Stack[StackNum].Copy(Var[ch - 'a']);
			break;
		}
		if ((ch >= 'A') && (ch <= 'Z'))
		{
			Stack[StackNum].Copy(Var[ch - 'A' + 26]);
			break;
		}

		// parentheses
		if (ch == '(')
		{
			ParseExp();
			ParseSpc();
			if (ParseTest() == ')') ParseCh();
			break;
		}

		// invalid character
		break;
	}

	// factorial
	ParseSpc();
	if (ParseTest() == '!')
	{
		ParseCh();
		Stack[StackNum].Fact();
	}
}

///////////////////////////////////////////////////////////////////////////////
// parse one level, power ^

void ParsePower()
{
	// parse first operand
	ParseOper();

	char ch;
	for (;;)
	{
		// check operator
		ParseSpc();
		ch = ParseTest();
		if (ch != '^') break;
		ParseCh();

		// parse next operand
		StackNum++;
		ParseOper();
		StackNum--;

		// do operation
		//Stack[StackNum].Pow(Stack[StackNum+1]);
	}
}

///////////////////////////////////////////////////////////////////////////////
// parse multiply level

void ParseMul()
{
	// parse first operand
	ParsePower();

	char ch;
	for (;;)
	{
		// check operator
		ParseSpc();
		ch = ParseTest();
		if ((ch != '*') && (ch != '/') && (ch != ':') && (ch != '%')) break;
		ParseCh();

		// parse next operand
		StackNum++;
		ParsePower();
		StackNum--;

		// do operation
		//Stack[StackNum].Exchange(Stack[StackNum+2]);
		if (ch == '*')
			Stack[StackNum].Mul(Stack[StackNum+1]);
		else if (ch == '/')
			Stack[StackNum].DivU(Stack[StackNum+1].UIntVal()); // Stack[StackNum+1], Stack[StackNum+1]);
		else if (ch == ':')
			Stack[StackNum].DivUInt(Stack[StackNum+1].UIntVal());
		//else
		//	Stack[StackNum].Mod(Stack[StackNum+2], Stack[StackNum+1]);
	}
}

///////////////////////////////////////////////////////////////////////////////
// parse plus level

void ParsePlus()
{
	// parse first operand
	ParseMul();

	char ch;
	for (;;)
	{
		// check operator
		ParseSpc();
		ch = ParseTest();
		if ((ch != '+') && (ch != '-')) break;
		ParseCh();

		// parse next operand
		StackNum++;
		ParseMul();
		StackNum--;

		// do operation
		if (ch == '+')
			Stack[StackNum].Add(Stack[StackNum+1]);
		else
			Stack[StackNum].Sub(Stack[StackNum+1]);
	}
}

///////////////////////////////////////////////////////////////////////////////
// parse Shift level

void ParseShift()
{
	// parse first operand
	ParsePlus();

	char ch;
	for (;;)
	{
		// check operator
		ParseSpc();
		ch = ParseTest();
		if ((ch != '<') && (ch != '>')) break;
		ParseCh();

		// parse next operand
		StackNum++;
		ParsePlus();
		StackNum--;

		// do operation
		if (ch == '<')
			Stack[StackNum].LShift(Stack[StackNum+1]);
		else
			Stack[StackNum].RShift(Stack[StackNum+1]);
	}
}

///////////////////////////////////////////////////////////////////////////////
// parse AND level

void ParseAND()
{
	// parse first operand
	ParseShift();

	char ch;
	for (;;)
	{
		// check operator
		ParseSpc();
		ch = ParseTest();
		if (ch != '&') break;
		ParseCh();

		// parse next operand
		StackNum++;
		ParseShift();
		StackNum--;

		// do operation
		Stack[StackNum].And(Stack[StackNum+1]);
	}
}

///////////////////////////////////////////////////////////////////////////////
// parse XOR level

void ParseXOR()
{
	// parse first operand
	ParseAND();

	char ch;
	for (;;)
	{
		// check operator
		ParseSpc();
		ch = ParseTest();
		if (ch != '@') break;
		ParseCh();

		// parse next operand
		StackNum++;
		ParseAND();
		StackNum--;

		// do operation
		Stack[StackNum].Xor(Stack[StackNum+1]);
	}
}

///////////////////////////////////////////////////////////////////////////////
// parse OR level

void ParseOR()
{
	// parse first operand
	ParseXOR();

	char ch;
	for (;;)
	{
		// check operator
		ParseSpc();
		ch = ParseTest();
		if (ch != '|') break;
		ParseCh();

		// parse next operand
		StackNum++;
		ParseXOR();
		StackNum--;

		// do operation
		Stack[StackNum].Or(Stack[StackNum+1]);
	}
}

///////////////////////////////////////////////////////////////////////////////
// parse expression

void ParseExp()
{
	ParseOR();
}

///////////////////////////////////////////////////////////////////////////////
// parse calculator row

void Parse()
{
	RowPos = 0;
	StackNum = 0;
	Stack[0].Set0();

	// parse expression
	ParseExp();

	Res.Copy(Stack[0]);
}
