/* expression.c */

#include "picasm.h"

static int stackpointer;
static int stack[MAXSTACK];

void clearstack()
{
	stackpointer = 0;
}

static void push(int value)
{
	stack[stackpointer] = value;
	stackpointer++;
	if (stackpointer >= MAXSTACK)
		error("Expression Stack Overflow","","","");
}

static int pop()
{
	stackpointer--;
	if (stackpointer<0)
		error("Expression Stack Underflow","","","");
	return stack[stackpointer];
}

void expr3()
{
	int unary;
	SYMBOL *temp;

	switch(current_symbol.token)
	{
		case COMP:	getanother();
				expr3();
				unary = pop();
				push(~unary);
				break;

		case NOT:	getanother();
				expr3();
				unary = pop();
				push(!unary);
				break;

		case INCSY:	getanother();
				expr3();
				unary = pop();
				++unary;
				push(unary);
				break;

		case DECSY:	getanother();
				expr3();
				unary = pop();
				--unary;
				push(unary);
				break;

		case MINUS:	getanother();		/* allow -1 */
				expr3();
				unary = pop();
				push(-unary);
				break;

		case PLUS:	getanother();		/* allow +1 */
				expr3();
				unary = pop();
				push(unary);
				break;

		case LPAREN:	getanother();
				push(expression());
				match(RPAREN);
				break;

		case NUM:	push(current_symbol.value);
				getanother();
				break;

		case ID:	if (current_symbol.type == VALUE_UNDEF)
					error("Identifier \"",current_symbol.lexptr,"\" not defined yet","");

				if (current_symbol.type == MACRO_ARG)
				{
					temp = lookup(current_symbol.lexptr);
					cpsym(&current_symbol, temp);
				}
				push(current_symbol.value);
				getanother();
				break;

		case PERIOD:	push(asm_current_address);
				getanother();
				break;

		default:	error("syntax error token out of context ","\'",lookupstr(current_symbol.token),"\'");
	}
}

void expr2()
{
	int a,b;

	expr3();
	while(1)
		switch(current_symbol.token)
		{
			case MUL:	getanother();
					expr3();
					b = pop();
					a = pop();
					push(a * b);
					break;

			case DIV:	getanother();
					expr3();
					b = pop();
					a = pop();
					push(a / b);
					break;


			case MOD:	getanother();
					expr3();
					b = pop();
					a = pop();
					push(a % b);
					break;

			case SHR:	getanother();
					expr3();
					b = pop();
					a = pop();
					push(a >> b);
					break;

			case SHL:	getanother();
					expr3();
					b = pop();
					a = pop();
					push(a << b);
					break;

			default:	return;
		}
}

void expr1()
{
	int a, b;

	expr2();
	while(1)
		switch(current_symbol.token)
		{
			case PLUS:	getanother();
					expr2();
					b = pop();
					a = pop();
					push(a + b);
					break;


			case MINUS:	getanother();
					expr2();
					b = pop();
					a = pop();
					push(a - b);
					break;

			case BAND:	getanother();
					expr2();
					b = pop();
					a = pop();
					push(a & b);
					break;

			case BOR:	getanother();
					expr2();
					b = pop();
					a = pop();
					push(a | b);
					break;

			case BXOR:	getanother();
					expr2();
					b = pop();
					a = pop();
					push(a ^ b);
					break;

			default:	return;
		}
}

int expression()
{
	int a, b;

	expr1();
	while(1)
		switch(current_symbol.token)
		{
			case SAME:	getanother();
					expr1();
					b = pop();
					a = pop();
					push(a == b);
					break;
			case GTR:	getanother();
					expr1();
					b = pop();
					a = pop();
					push(a > b);
					break;

			case GTREQ:	getanother();
					expr1();
					b = pop();
					a = pop();
					push(a >= b);
					break;

			case LESS:	getanother();
					expr1();
					b = pop();
					a = pop();
					push(a < b);
					break;

			case LESSEQ:	getanother();
					expr1();
					b = pop();
					a = pop();
					push(a <= b);
					break;

			case NOTEQ:	getanother();
					expr1();
					b = pop();
					a = pop();
					push(a != b);
					break;

			case ANDSY:	getanother();
					expr1();
					b = pop();
					a = pop();
					push(a && b);
					break;

			case ORSY:	getanother();
					expr1();
					b = pop();
					a = pop();
					push(a || b);
					break;

			default:	return pop(); /* return the answer */
		}
}

/* ... The End ... */

