/* expression.c */
#include "codegen.h"
#include "error.h"
#include "expression.h"
#include "lex.h"
#include "parse.h"
#include "stdlib.h"
#include "vars.h"

/*	>>>>>>> start of cc5 <<<<<<<	*/

/** higher precedence operators are acted on first, **/
/** though the flow control enters at the lowest precedence, **/
/** the lower precedence is acted on upon return from **/
/** higher precedence ascent. **/

	/* - 3 element evaluation array of ints -
	** eval[0] = Symbol table address, else 0 for constant
	** eval[1] = type indirect object to fetch, else 0 for
        	     static object (const.)
	** eval[2] = type pointer or array, else 0
	*/

/** expression(Y..N) loop if comma operator is allowed in expr **/
/** comma is lowest precedence operator in C and acted on last **/
/** comma, precedence level 15 **/
/** vers_2 expression for comma'd expression **/
/** caller- expr2(NO); or expr2(YES); for comma'd expr. **/
/** identifiers with sa_ or _sa are codegen functions, i.e., **/
/** syntactic actions to output backend code, generically **/
/** patterned after stack machine operations. **/
void expression(int comma)
{
	/** precedence level 15 **/
	int eval[3];

	/** was: if (heir1(eval))  rq_val_sa(eval); **/
	do
	{
		if (heir1(eval))
			rq_val_sa(eval);
		
		if (comma == 0)
			return;
	} while (match(","));
}

/** assignments, precedence level 14 **/
/** {=} of {=,+=,-=,/=,*=,%=,<<=,>>=,&=,^=,|=} **/
int heir1(int eval[])
{
	int k, eval2[3];
	
	/** link to heir2->heir1a here **/
	k = heir1a(eval);

	if (match("="))
	{
		if (k == 0)
		{
			needlval();
			return 0;
		}
		
		/** syntatic action **/
		if (eval[1])
			sa_push();
		
		if (heir1(eval2))
			rq_val_sa(eval2);
		
		sa_store(eval);
		return 0;
	}
	else
		return k;
}

/*** install levels 13 (?:), 12 (||), 11 (&&) here ***/
/** (?:), precedence level 13 **/
/** conditional operator, ternary, takes three expressions **/
/** cond_expr ::= expr ? expr : expr **/
int heir1a(int eval[])
{
	int	k, eval2[3], T_lbl, F_lbl, X_lbl;

	k = heir1b(eval);
	deblank();

	if (streq(line + lptr, "?") == 0)
		return(k);

	if (k)
		rq_val_sa(eval);

	while (1)
	{
		if (match ("?"))
		{
			T_lbl = getlabel();
			F_lbl = getlabel();
			X_lbl = getlabel();
			sa_if_tst(T_lbl,F_lbl);

			sa_mk_lbl(T_lbl);
			/** expression evaluation, higher precedence **/
			if (heir1b (eval2))
				rq_val_sa(eval2);
	
			sa_jump(X_lbl);
	
			deblank();
	
			if (match (":") == 0)
			{
				error ("missing colon");
				return (0);
			}
			/** colon matched, do expr3 **/
			sa_mk_lbl(F_lbl);
			/** expression evaluation, higher precedence **/
			if (heir1b (eval2))
				rq_val_sa(eval2);
			
			sa_mk_lbl(X_lbl);
		}
		else
			return (0);
	}
}


/** (||), precedence level 12 - either, both, true yields true. **/
int heir1b(int eval[])
{
	int k, eval2[3], t_lbl, flab1;

	k = heir1c(eval);

	deblank();
	if (streq(line + lptr, "||") == 0)
		return(k);

	if (k)
		rq_val_sa(eval);

	while (1)
		if (match ("||"))
		{
			/** prim reg -> bool **/
			sa_mk_bool();
			sa_push();
			/** expression evaluation, higher precedence **/
			if (heir1c (eval2))
				rq_val_sa(eval2);
			
			/** prim reg -> bool **/
			sa_mk_bool();
			/* Pop into the secondary register */
			sa_pop();
			sa_or();
		}
		else
			return (0);
}

/** (&&), precedence level 11 - both true yields true **/
int heir1c(int eval[])
{
	int k, eval2[3], t_lbl, flab1;

	k = heir2(eval);

	deblank();
	if (streq(line + lptr, "&&") == 0)
		return(k);
	
	if (k)
		rq_val_sa(eval);
	
	while (1)
		if (match ("&&"))
		{
			/** prim reg -> bool **/
			sa_mk_bool();
			sa_push();
			/** expression evaluation, higher precedence **/
			if (heir2 (eval2))
				rq_val_sa(eval2);
			
			/** prim reg -> bool **/
			sa_mk_bool();
			/* Pop into the secondary register */
			sa_pop();
			sa_and();
		}
		else
			return (0);
}

/** bitwise inclusive OR, precedence level 10 **/
int heir2(int eval[])
{
	int k, eval2[3];

	k = heir3(eval);

	deblank();
	if (inspect_chr() != '|')
		return k;
	
	/** added '||' ck for heir1b **/
	if (streq(line + lptr, "||") != 0)
		return(k);
	
	if (k)
		rq_val_sa(eval);
	
	while (1)
	{
		if (match("|"))
		{
			/** syntatic action **/
			sa_push();
			
			if (heir3(eval2))
				rq_val_sa(eval2);
			
			/** syntatic action **/
			sa_pop();
			
			/** syntatic action **/
			sa_or();
		}
		else
			return 0;
	}
}

/** bitwise exclusive OR, precedence level 9 **/
int heir3(int eval[])
{
	int k, eval2[3];

	k = heir4(eval);

	deblank();
	
	if (inspect_chr() != '^')
		return k;

	if (k)
		rq_val_sa(eval);
	
	while (1)
	{
		if (match("^"))
		{
			/** syntatic action **/
			sa_push();
			
			if (heir4(eval2))
				rq_val_sa(eval2);
			
			/** syntatic action **/
			sa_pop();
			
			/** syntatic action **/
			sa_xor();
		}
		else
			return 0;
	}
}

/** bitwise AND, precedence level 8 **/

int heir4(int eval[])
{
	int k, eval2[3];

	k = heir5(eval);

	deblank();
	if (inspect_chr() != '&')
		return k;

	/** added '&&' ck for heir1c **/
	if (streq(line + lptr, "&&") != 0)
		return(k);

	if (k)
		rq_val_sa(eval);
	
	while (1)
	{
		if (match("&"))
		{
			sa_push();
			
			if (heir5(eval2))
				rq_val_sa(eval2);
			
			sa_pop();
			sa_and();
		}
		else
			return 0;
	}
}

/** equality operator; (T..F) equivalence, precedence level 7.1 **/
/** equality operator; not_equal, precedence level 7.2 **/
int heir5(int eval[])
{
	int k, eval2[3];

	k = heir6(eval);

	deblank();
	if ((streq(line + lptr, "==") == 0) & (streq(line + lptr, "!=") == 0))
		return k;

	if (k)
		rq_val_sa(eval);
	
	while (1)
	{
		if (match("=="))
		{
			sa_push();
	
			if (heir6(eval2))
				rq_val_sa(eval2);
	
			sa_pop();
			sa_eq();
		}
		else if (match("!="))
		{
			sa_push();

			if (heir6(eval2))
				rq_val_sa(eval2);

			sa_pop();
			sa_not_equal();
		}
		else
			return 0;
	}
}

/** relational operator; less than, <, precedence level 6.1 **/
/** relational operator; less than or eq, <=, precedence level 6.2 **/
/** relational operator; greater than or eq, >=, precedence level 6.3 **/
/** relational operator; greater than, >, precedence level 6.4 **/
int heir6(int eval[])
{
	int k, eval2[3];

	k = heir7(eval);

	deblank();
	
	if ((streq(line + lptr, "<") == 0) & (streq(line + lptr, ">") == 0) &
		(streq(line + lptr, "<=") == 0) & (streq(line + lptr, ">=") == 0))
	{
		return k;
	}
	
	if (streq(line + lptr, ">>"))
		return k;
	if (streq(line + lptr, "<<"))
		return k;

	if (k)
		rq_val_sa(eval);

	while (1)
	{
		if (match("<="))
		{
			sa_push();
			if (heir7(eval2))
				rq_val_sa(eval2);
			sa_pop();
			if (eval[2] | eval2[2])
			{
				sa_uless_oreq();
				continue;
			}
			sa_sless_or_eq();
		}
		else if (match(">="))
		{
			sa_push();
			if (heir7(eval2))
				rq_val_sa(eval2);
			sa_pop();
			if (eval[2] | eval2[2])
			{
				sa_uge();
				continue;
			}
			sa_sge();
		}
		else if ((streq(line+lptr,"<")) & (streq(line+lptr,"<<") == 0))
		{
			scan_nxt();
			sa_push();
			if (heir7(eval2))
				rq_val_sa(eval2);
			sa_pop();
			if (eval[2] | eval2[2])
			{
				sa_uless_than();
				continue;
			}
			sa_sless_than();
		}
		else if ((streq(line+lptr,">")) & (streq(line+lptr,">>") == 0))
		{
			scan_nxt();
			sa_push();
			if (heir7(eval2))
				rq_val_sa(eval2);
			sa_pop();
			if (eval[2] | eval2[2])
			{
				sa_ugt();
				continue;
			}
			sa_sgreater_than();
		}
		else
			return 0;
	}
}

/*	>>>>>> start of cc6 <<<<<<	*/
/** shift operator; left shift, <<, precedence level 5.1 **/
/** shift operator; right shift, >>, precedence level 5.2 **/
/* Arithmetic left shift the secondary register by the */
/*  count in the primary. (results in primary) */
int heir7(int eval[])
{
	int k, eval2[3];

	k = heir8(eval);

	deblank();
	
	if ((streq(line + lptr, ">>") == 0) & (streq(line + lptr, "<<") == 0))
		return k;

	if (k)
		rq_val_sa(eval);
	
	while (1)
	{
		if (match(">>"))
		{
			sa_push();
			if (heir8(eval2))
				rq_val_sa(eval2);
			sa_pop();
			sa_asr();
		}
		else if (match("<<"))
		{
			sa_push();
			if (heir8(eval2))
				rq_val_sa(eval2);
			sa_pop();
			sa_asl();
		}
		else
			return 0;
	}
}

/** binary arithmetic operator; add, +, precedence level 4.1 **/
/** binary arithmetic operator; subtract, -, precedence level 4.2 **/
int heir8(int eval[])
{
	int k, eval2[3];

	k = heir9(eval);

	deblank();
	
	if ((inspect_chr() != '+') & (inspect_chr() != '-'))
		return k;

	if (k)
		rq_val_sa(eval);
	
	while (1)
	{
		if (match("+"))
		{
			sa_push();
			
			if (heir9(eval2))
				rq_val_sa(eval2);
			
			if (dbltest(eval,eval2))
				sa_doublereg();
			
			sa_pop();
			
			if (dbltest(eval2,eval))
			{
				sa_swap();
				sa_doublereg();
				sa_swap();
			}
			
			sa_add();
			result(eval,eval2);
		}
		else if (match("-"))
		{
			sa_push();
			
			if (heir9(eval2))
				rq_val_sa(eval2);
			
			if (dbltest(eval,eval2))
				sa_doublereg();
			
			sa_pop();

			if (dbltest(eval2,eval))
			{
				sa_swap();
				sa_doublereg();
				sa_swap();
			}
			
			sa_sub();
			
			if ((eval[2] == CINT) & (eval2[2] == CINT))
			{
				sa_swap();
				sa_immed();
				ol("1");
				sa_asr();									/** div by 2 **/
			}
			result(eval,eval2);
		}
		else
			return 0;
	}
}

/** binary arithmetic operator; multiply, *, precedence level 3.1 **/
/** binary arithmetic operator; divide, /, precedence level 3.2 **/
/** binary arithmetic operator; modulo, %, precedence level 3.3 **/
int heir9(int eval[])
{
	int k, eval2[3];

	k = heir10(eval);

	deblank();
	if ((inspect_chr() != '*') & (inspect_chr() != '/') & (inspect_chr() != '%'))
		return k;

	if (k)
		rq_val_sa(eval);
	
	while (1)
	{
		if (match("*"))
		{
			sa_push();
											/** Push Primary Reg. **/
			if (heir9(eval2))
				rq_val_sa(eval2);
			
			sa_pop();								/** Pop into Secondary Reg. **/
			sa_mult();
		}
		else if (match("/"))
		{
			sa_push();
			
			if (heir10(eval2))
				rq_val_sa(eval2);
			
			sa_pop();
			sa_div();
		}
		else if (match("%"))
		{
			sa_push();
			
			if (heir10(eval2))
				rq_val_sa(eval2);
			
			sa_pop();
			sa_modulo();
		}
		else
			return 0;
	}
}

/** unary operator; increment, ++, precedence level 2.7 **/
/** unary operator; decrement, --, precedence level 2.8 **/
/** unary operator; minus, -, precedence level 2.3 **/
/** unary operator; indirection, *, precedence level 2.5 **/
/** unary operator; address of, &, precedence level 2.6 **/
/** unary operator; logical not, !, precedence level 2.1 **/
/** unary operator; bitwise one's complement, ~, precedence level 2.2 **/
/** TBI, ~, sizeof, cast (typename)expr **/
int heir10(int eval[])
{
	int k;
	char *ptr;

	if (match("++"))
	{
		if ((k = heir10(eval)) == 0)
		{
			needlval();
			return 0;
		}

		if (eval[1])
			sa_push();
		
		rq_val_sa(eval);
		sa_inc();
		
		if (eval[2] == CINT)
			sa_inc();
		
		sa_store(eval);
		return 0;
	}
	else if (match("--"))
	{
		if ((k = heir10(eval)) == 0)
		{
			needlval();
			return 0;
		}

		if (eval[1])
			sa_push();
		
		rq_val_sa(eval);
		sa_dec();
		
		if (eval[2] == CINT)
			sa_dec();
		
		sa_store(eval);
		return 0;
	}
	else if (match("-"))
	{
		k = heir10(eval);

		if (k)
			rq_val_sa(eval);
		
		/** two's complement **/
		sa_neg();
		return 0;
	}
	/** bitwise complement, one's complement, bit flip **/
	else if (match("~"))
	{
		k = heir10(eval);

		if (k)
			rq_val_sa(eval);
		
		sa_not();
		return 0;
	}
	/** boolean logical negate, 0->1, >0->0 **/
	else if (match("!"))
	{
		k = heir10(eval);

		if (k)
			rq_val_sa(eval);
		
		/** prim reg -> not (bool) **/
		sa_mk_nbool();
		return 0;
	}
	else if (match("*"))
	{
		k = heir10(eval);

		if (k)
			rq_val_sa(eval);
		
		if (ptr = (char*)eval[0])
			eval[1] = ptr[TYPE];
		else
			eval[1] = CINT;
		
		/*flag as not ptr or array*/
		eval[2] = 0;
		return 1;
	}
	else if (match("&"))
	{
		k = heir10(eval);

		if (k == 0)
		{
			error("illegal address");
			return 0;
		}
		
		ptr = (char*)eval[0];
		eval[2] = ptr[TYPE];
		if (eval[1])
			return 0;

		/* global & non-array & function */
		sa_immedo();
		outstr(ptr);
		nl();
		eval[1] = ptr[TYPE];
		return 0;
	}
	else 
	{
		/** for recursive non-match of above unary ops **/
		k = heir11(eval);

		if (match("++"))
		{
			if (k == 0)
			{
				needlval();
				return 0;
			}
			
			if (eval[1])
				sa_push();
			
			rq_val_sa(eval);
			sa_inc();
			
			if (eval[2] == CINT)
				sa_inc();
			
			sa_store(eval);
			sa_dec();
			
			if (eval[2] == CINT)
				sa_dec();
			
			return 0;
		}
		else if (match("--"))
		{
			if (k == 0)
			{
				needlval();
				return 0;
			}
			
			if (eval[1])
				sa_push();
			
			rq_val_sa(eval);
			sa_dec();
			
			if (eval[2] == CINT)
				sa_dec();
			
			sa_store(eval);
			sa_inc();
			
			if (eval[2] == CINT)
				sa_inc();
			
			return 0;
		}
		else
			return k;
	}
}

/** EO C86N-6.C **/
/*	>>>>>> start of cc7 <<<<<<	*/

/** primary operator; function parenthesis, (), precedence level 1.1 **/
/** primary op; subscripting square brakets, [], precedence level 1.2 **/
/** primary operator; member access, ->, precedence level 1.3 **/
/** primary operator; member access, ., precedence level 1.4 **/
int heir11(int eval[])
{
	int k;
	char *ptr;

	k = primary(eval);
	
	/** address of symbol in symb_tbl **/
	ptr = (char*)eval[0];
	
	deblank();
	
	if ((inspect_chr() == '[') | (inspect_chr() == '('))
		while (1)
		{
			if (match("["))
			{
				if (ptr == 0)
				{
					error("can't subscript");
					junk();
					needbrack("]");
					return 0;
				}
				else if (ptr[IDENT] == POINTER)
					rq_val_sa(eval);
				else if (ptr[IDENT] != ARRAY)
				{
					error("can't subscript");
					k = 0;
				}
				
				sa_push();
				expression(YES);
				needbrack("]");
				
				if (ptr[TYPE] == CINT)
					sa_doublereg();
				
				sa_pop();
				sa_add();
				eval[0] = eval[2] = 0;
				eval[1] = ptr[TYPE];
				k = 1;
			}
			else if (match("("))
			{
				if (ptr == 0)
				{
					callfunction(0);
				}
				else if (ptr[IDENT] != FUNCTION)
				{
					rq_val_sa(eval);
					callfunction(0);
				}
				else
					callfunction(ptr);
				
				k = eval[0] = 0;
			}
			else
				return k;
		}
	
	if (ptr == 0)
		return k;
	
	if (ptr[IDENT] == FUNCTION)
	{
		/* global & non-array & function */
		sa_immedo();
		asm_symb(ptr);
		nl();
		return 0;
	}
	
	return k;
}

/** primary is called when an expression is expected, it is **/
/** the highest precedence level, it is acted on first. **/
int primary(int eval[])
{
	char *ptr, sname[NAMESIZE]; 						/** auto symb array **/
	int num[1], k;
	
	/* Clear ptr/array type. */
	eval[2] = 0;
	
	/** parenthesized expression **/
	if (match("("))
	{
		/** recursive call to check for rvalue **/
		k = heir1(eval);
		needbrack(")");
		return k;
	}

	/** is_identifier() gets & validates identifier **/
	if (is_identifier(sname))
	{
		/** srch auto tbl 1st **/
		if (ptr = findauto(sname))
		{
			/** code gen fn, syntatic action **/
			sa_deref(ptr);
			/** get stk relative addr of auto var **/
			/** set eval[] according to auto identifier **/
			eval[0] = ptr;
			eval[1] = ptr[TYPE];
			
			if (ptr[IDENT] == POINTER)
			{
				eval[1] = CINT;
				eval[2] = ptr[TYPE];
			}
			if (ptr[IDENT] == ARRAY)
			{
				eval[2] = ptr[TYPE];
				return 0;
			}
			/** auto VARIABLE, or auto POINTER **/
			else
				return 1;
			
			/** ! auto ARRAY or FUNCTION **/
			/** fn()'s are external static by definition. **/
			/** so the IDENT is a auto; VARIABLE or POINTER **/
		}
		
		/** search static tbl 2nd **/
		if (ptr = findstatic(sname))
			if (ptr[IDENT] != FUNCTION)
			{
				/** set eval[] according to static identifier **/
				/** ptr to symb in tbl **/
				eval[0] = ptr;
				eval[1] = 0;
				if (ptr[IDENT] != ARRAY)
				{
					if (ptr[IDENT] == POINTER)
						eval[2] = ptr[TYPE];
					return 1;
				}
				/** .else. array & !function */
				sa_immedo();
				asm_symb(ptr); nl();
				eval[1] = eval[2] = ptr[TYPE];
				return 0;
			}

		/** not found in auto tbl, not in static tbl, **/
		/** so add the unknown identifier as a static function, **/
		/** variables are declared symbols, already (elsewhere) **/
		/** parsed & entered into the auto or static symbol tables. **/
		/** The defaults for undeclared functions are setup now. **/

		ptr = addstatic(sname, FUNCTION, CINT, 0);
		eval[0] = ptr;					/** address of its entry in symb tbl **/
		eval[1] = 0;    				/** functions are static objects **/
		return 0;       				/** FALSE, not an expression **/
	}	/** eo if (is_identifier(sname)) **/
	
	if (kind_const(num))
		return (eval[0] = eval[1] = 0);
	else
	{
		error("invalid expression");
		sa_immed();
		outdec(0);
		nl();
		junk();
		return 0;
	}
}
/** eo primary **/