/*
 * Copyright 2000 Silicon Graphics, Inc. All rights reserved.
 */
#include <lcrash.h>
#include <lc_eval.h>
#include <string.h>

/* Forward declarations
 */
static void free_node(node_t *);
static node_t *make_node(token_t *, int);
static node_t *get_node_list(token_t *, int);
static node_t *do_eval(int);
static int is_unary(int);
static int is_binary(int);
static int precedence(int);
static node_t *get_sizeof(void);
static int replace_cast(node_t *, int);
static int replace_unary(node_t *, int);
static node_t *replace(node_t *, int);
static void array_to_element(node_t*, node_t*);
static int type_to_number(node_t *);
kltype_t *number_to_type(node_t *);
static type_t *eval_type(node_t *);
static type_t *get_type(char *, int);
static int add_rchild(node_t *, node_t *);
static void free_nodelist(node_t *);

/* Global variables
 */
static int logical_flag;
static node_t *node_list = (node_t *)NULL;
uint64_t eval_error;
char *error_token;

/*
 * set_eval_error()
 */
static void
set_eval_error(uint64_t ecode)
{
	eval_error = ecode;
}

/*
 * is_typestr()
 * 
 * We check for "struct", "union", etc. separately because they
 * would not be an actual part of the type name. We also assume
 * that the string passed in 
 *
 * - does not have any leading blanks or tabs 
 * - is NULL terminated
 * - contains only one type name to check
 * - does not contain any '*' characters
 */
static int
is_typestr(char *str)
{
	int len;

	len = strlen(str);
	if ((len >= 6) && !strncmp(str, "struct", 6)) {
		return(1);
	} else if ((len >= 5) &&!strncmp(str, "union", 5)) {
		return(1);
	} else if ((len >= 5) &&!strncmp(str, "short", 5)) {
		return(1);
	} else if ((len >= 8) &&!strncmp(str, "unsigned", 8)) {
		return(1);
	} else if ((len >= 6) &&!strncmp(str, "signed", 6)) {
		return(1);
	} else if ((len >= 4) &&!strncmp(str, "long", 4)) {
		return(1);
	} 
	/* Strip off any trailing blanks 
	 */
	while(*str && ((str[strlen(str) - 1] == ' ') 
			|| (str[strlen(str) - 1] == '\t'))) {
		str[strlen(str) - 1] = 0;
	}
	if (kl_find_sym(str, (KLT_TYPE|KLT_TYPEDEF))) {
		return (1);
	}
	return(0);
}

/* 
 * free_tokens()
 */
static void
free_tokens(token_t *tp)
{
	token_t *t, *tnext;

	t = tp;
	while (t) {
		tnext = t->next;
		if (t->string) {
			kl_free_block((void *)t->string);
		}
		kl_free_block((void *)t);
		t = tnext;
	}
}

#ifdef NOTYET
/*
 * process_variable()
 */
static int
process_variable(char **str, token_t *tok)
{
	int len;
	char *s, *vname;
	variable_t *vp;
	token_t *t;

	if (s = strpbrk((cp + 1), " .\t+-*/()[]|~!$&%^<>?:&=^\"\'")) {
		len = (uaddr_t)s - (uaddr_t)cp + 1;
	} else {
		len = strlen(cp) + 1;
	}
	vname = (char *)kl_alloc_block(len, K_TEMP);
	memcpy(vname, cp, (len -1));
	vname[len - 1] = 0;
	vp = find_variable(vtab, vname, 0);
	if (!vp || (vp->v_flags & V_COMMAND)) {
		set_eval_error(E_BAD_EVAR);
		error_token = tok->ptr;
		kl_free_block((void *)vname);
		return(1);
	}
	if (vp->v_flags & V_TYPEDEF) {
		kl_free_block((void *)vname);
		free_tokens(tok);
		t = get_token_list(vp->v_typestr);
		if (!tok_head) {
			tok_head = tok_last = t;
		} else {
			tok_last->next = t;
			while (t->next) {
				t = t->next;
			}
			tok_last = t;
		}
		if (cp = s) {
			continue;
		} else {
			return(tok_head);
		}
	} else if (vp->v_flags & V_STRING) {
		if (tok_head) {
			set_eval_error(E_END_EXPECTED);
			error_token = tok->ptr;
			return(1);
		}

		/* Skip ahead to the first non-blank character
		 */
		while (s && (*s == ' ')) {
			s++;
		}
		if (s && (*s != 0)) {
			set_eval_error(E_END_EXPECTED);
			tok->ptr = s;
			error_token = tok->ptr;
			return(1);
		}

		tok->string = (char *)
			kl_alloc_block(strlen(vp->v_exp) + 1, K_TEMP);

		/* We have to copy the string so that it doesn't get 
		 * freed when the token is freed.
		 */
		strcpy(tok->string, vp->v_exp);
		tok->type = TEXT;
		return(0);
	}
	return(1);
}
#endif

/*
 * process_text()
 */
static int
process_text(char **str, token_t *tok)
{
	char *cp = *str;
	char *s;
	int len;

	/* Check and see if this token is a STRING or CHARACTER 
	 * type (beginning with a single or double quote).
	 */
	if (*cp == '\'') {
		/* make sure that only a single character is between 
		 * the single quotes (it can be an escaped character 
		 * too).
		 */
		s = strpbrk((cp + 1), "\'");
		if (!s) {
			set_eval_error(E_SINGLE_QUOTE);
			error_token = tok->ptr;
			return(1);
		}
		len = (uaddr_t)s - (uaddr_t)cp;
		if ((*(cp+1) == '\\')) {
			if (*(cp+2) == '0') {
				long int val;
				char *ep;

				val = strtol((char*)(cp+2), 
					(char **)&ep, 8);
				if ((val > 255) || (*ep != '\'')) {
					set_eval_error(E_BAD_CHAR);
					error_token = tok->ptr;
					return(1);
				}
			} else if (*(cp+3) != '\'') {
				set_eval_error(E_BAD_CHAR);
				error_token = tok->ptr;
				return(1);
			}
			tok->type = CHARACTER;
		} else if (len == 2) {
			tok->type = CHARACTER;
		} else { 

			/* Treat as a single token entry. It's possible 
			 * that what's between the single quotes is a 
			 * type name. That will be determined later on.
			 */
			tok->type = STRING;
		}
		*str = cp + len;
	} else if (*cp == '\"') {
		s = strpbrk((cp + 1), "\"");
		if (!s) {
			set_eval_error(E_BAD_STRING);
			error_token = tok->ptr;
			return(1);
		}
		len = (uaddr_t)s - (uaddr_t)cp;
		tok->type = TEXT;
		*str = cp + len;
	}
	if ((tok->type == STRING) || (tok->type == TEXT)) {

		if ((tok->type == TEXT) && (strlen(cp) > (len + 1))) {

			/* Check to see if there is a comma or semi-colon 
			 * directly following the string. If there is, 
			 * then the string is OK (the following characters 
			 * are part of the next expression). Also, it's OK 
			 * to have trailing blanks as long as that's all 
			 * threre is.
			 */
			char *c;

			c = s + 1;
			while (*c) {
				if ((*c == ',') || (*c == ';')) {
					break;
				} else if (*c != ' ') {
					set_eval_error(E_END_EXPECTED);
					tok->ptr = c;
					error_token = tok->ptr;
					return(1);
				}
				c++;
			}
			/* Truncate the trailing blanks (they are not 
			 * part of the string).
			 */
			if (c != (s + 1)) {
				*(s + 1) = 0;
			}
		}
		tok->string = (char *)kl_alloc_block(len, K_TEMP);
		bcopy((cp + 1), tok->string, len - 1);
		tok->string[len - 1] = 0;
	}
	return(0);
}

/*
 * get_token_list()
 */
static token_t *
get_token_list(char *str)
{
	int paren_count = 0;
	char *cp;
	token_t *tok, *tok_head = (token_t*)NULL, *tok_last = (token_t*)NULL;

	cp = str;
	eval_error = 0;

	while (*cp) {

		/* Skip past any "white space" (spaces and tabs).
		 */
		switch (*cp) {
			case ' ' :
			case '\t' :
			case '`' :
				cp++;
				continue;
			default :
				break;
		}

		/* Allocate space for the next token
		 */
		tok = (token_t *)kl_alloc_block(sizeof(token_t), K_TEMP);
		tok->ptr = cp;

		switch(*cp) {

			/* Check for operators
			 */
			case '+' :
				if (*((char*)cp + 1) == '+') {

					/* We aren't doing asignment here, 
					 * so the ++ operator is not 
					 * considered valid.
					 */
					set_eval_error(E_BAD_OPERATOR);
					error_token = tok_last->ptr;
					free_tokens(tok_head);
					free_tokens(tok);
					return ((token_t*)NULL);
				} else if (!tok_last || 
					(tok_last->operator && 
					(tok_last->operator != CLOSE_PAREN))) {
					tok->operator = UNARY_PLUS;
				} else {
					tok->operator = ADD;
				}
				break;

			case '-' :
				if (*((char*)cp + 1) == '-') {

					/* We aren't doing asignment here, so 
					 * the -- operator is not considered 
					 * valid.
					 */
					set_eval_error(E_BAD_OPERATOR);
					error_token = tok_last->ptr;
					free_tokens(tok_head);
					free_tokens(tok);
					return ((token_t*)NULL);
				} else if (*((char*)cp + 1) == '>') {
					tok->operator = RIGHT_ARROW;
					cp++;
				} else if (!tok_last || (tok_last->operator && 
					(tok_last->operator != CLOSE_PAREN))) {
					tok->operator = UNARY_MINUS;
				} else {
					tok->operator = SUBTRACT;
				}
				break;

			case '.' :
				/* XXX - need to check to see if this is a 
				 * decimal point in the middle fo a floating 
				 * point value.
				 */
				tok->operator = DOT;
				break;

			case '*' :
				/* XXX - need a better way to tell if this is 
				 * an INDIRECTION. perhaps check the next 
				 * token?
				 */
				if (!tok_last || (tok_last->operator && 
					((tok_last->operator != CLOSE_PAREN) &&
					(tok_last->operator != CAST)))) {
					tok->operator = INDIRECTION;
				} else {
					tok->operator = MULTIPLY;
				}
				break;

			case '/' :
				tok->operator = DIVIDE;
				break;

			case '%' :
				tok->operator = MODULUS;
				break;

			case '(' : {
				char *s;
				int len;

				/* Make sure the previous token is an operator
				 */
				if (tok_last && !tok_last->operator) {
					set_eval_error(E_SYNTAX_ERROR);
					error_token = tok_last->ptr;
					free_tokens(tok_head);
					free_tokens(tok);
					return ((token_t*)NULL);
				}

				if (tok_last && 
					((tok_last->operator == RIGHT_ARROW) || 
						(tok_last->operator == DOT))) {
					set_eval_error(E_SYNTAX_ERROR);
					error_token = tok_last->ptr;
					free_tokens(tok_head);
					free_tokens(tok);
					return ((token_t*)NULL);
				}

				/* Check here to see if following tokens 
				 * constitute a cast.
				 */

				/* Skip past any "white space" (spaces 
				 * and tabs)
				 */
				while ((*(cp+1) == ' ') || (*(cp+1) == '\t')) {
					cp++;
				}
				if ((*(cp+1) == '(') || isdigit(*(cp+1)) ||
					(*(cp+1) == '+') || (*(cp+1) == '-') ||
					(*(cp+1) == '*') || (*(cp+1) == '&') || 
						(*(cp+1) == ')')){
					tok->operator = OPEN_PAREN;
					paren_count++;
					break;
				}
				
				if ((s = strpbrk(cp+1, "*)"))) {
					char str[128];

					len = (uaddr_t)s - (uaddr_t)(cp+1);
					strncpy(str, cp+1, len);	
					str[len] = 0;
					if (!is_typestr(str)) {
						set_eval_error(E_BAD_TYPE);
						error_token = tok->ptr;
						free_tokens(tok_head);
						free_tokens(tok);
						return ((token_t*)NULL);
					}
					if (!(s = strpbrk((cp+1), ")"))) {
						set_eval_error(E_OPEN_PAREN);
						error_token = tok->ptr;
						free_tokens(tok_head);
						free_tokens(tok);
						return ((token_t*)NULL);
					}
					len = (uaddr_t)s - (uaddr_t)(cp+1);
					tok->string = (char *) kl_alloc_block(
						len + 1, K_TEMP);
					bcopy((cp+1), tok->string, len);
					tok->string[len] = 0;
					tok->operator = CAST;
					cp = (char *)((uaddr_t)(cp+1) + len);
					break;
				}
				tok->operator = OPEN_PAREN;
				paren_count++;
				break;
			}

			case ')' :
				if (tok_last && ((tok_last->operator == 
						RIGHT_ARROW) || 
						(tok_last->operator == DOT))) {
					set_eval_error(E_SYNTAX_ERROR);
					error_token = tok_last->ptr;
					free_tokens(tok_head);
					free_tokens(tok);
					return ((token_t*)NULL);
				}
				tok->operator = CLOSE_PAREN;
				paren_count--;
				break;

			case '&' :
				if (*((char*)cp + 1) == '&') {
					tok->operator = LOGICAL_AND;
					cp++;
				} else if (!tok_last || (tok_last && 
					(tok_last->operator && 
						tok_last->operator != 
						CLOSE_PAREN))) {
					tok->operator = ADDRESS;
				} else {
					tok->operator = BITWISE_AND;
				}
				break;

			case '|' :
				if (*((char*)cp + 1) == '|') {
					tok->operator = LOGICAL_OR;
					cp++;
				} else {
					tok->operator = BITWISE_OR;
				}
				break;

			case '=' :
				if (*((char*)cp + 1) == '=') {
					tok->operator = EQUAL;
					cp++;
				} else {
					/* ASIGNMENT -- NOT IMPLEMENTED
					 */
					tok->operator = NOT_YET;
				}
				break;

			case '<' :
				if (*((char*)cp + 1) == '<') {
					tok->operator = LEFT_SHIFT;
					cp++;
				} else if (*((char*)cp + 1) == '=') {
					tok->operator = LESS_THAN_OR_EQUAL;
					cp++;
				} else {
					tok->operator = LESS_THAN;
				}
				break;

			case '>' :
				if (*((char*)(cp + 1)) == '>') {
					tok->operator = RIGHT_SHIFT;
					cp++;
				} else if (*((char*)cp + 1) == '=') {
					tok->operator = GREATER_THAN_OR_EQUAL;
					cp++;
				} else {
					tok->operator = GREATER_THAN;
				}
				break;

			case '!' :
				if (*((char*)cp + 1) == '=') {
					tok->operator = NOT_EQUAL;
					cp++;
				} else {
					tok->operator = LOGICAL_NEGATION;
				}
				break;

			case '$' :
#ifdef NOT_IMPLEMENTED
				if (process_variable(&cp, tok)) {
					free_tokens(tok_head);
					free_tokens(tok);
					return((token_t*)NULL);
				}
				break;
#else 
				set_eval_error(E_NOT_IMPLEMENTED);
				error_token = tok->ptr;
				free_tokens(tok_head);
				free_tokens(tok);
				return((token_t*)NULL);
#endif
			case '~' :
				tok->operator = ONES_COMPLEMENT;
				break;
			
			case '^' :
				tok->operator = BITWISE_EXCLUSIVE_OR;
				break;

			case '?' :
#ifdef NOT_IMPLEMENTED
				tok->operator = CONDITIONAL;
				break;
#else
				set_eval_error(E_NOT_IMPLEMENTED);
				error_token = tok->ptr;
				free_tokens(tok_head);
				free_tokens(tok);
				return((token_t*)NULL);
#endif
			case ':' :
#ifdef NOT_IMPLEMENTED
				tok->operator = CONDITIONAL_ELSE;
				break;
#else
				set_eval_error(E_NOT_IMPLEMENTED);
				error_token = tok->ptr;
				free_tokens(tok_head);
				free_tokens(tok);
				return((token_t*)NULL);
#endif
			case '[' :
				tok->operator = OPEN_SQUARE_BRACKET;;
				break;

			case ']' :
				tok->operator = CLOSE_SQUARE_BRACKET;;
				break;

			default: {

				char *s;
				int len;

				/* See if the last token is a RIGHT_ARROW
				 * or a DOT. If it is, then this token must 
				 * be the name of a struct/union member.
				 */
				if (tok_last && 
					((tok_last->operator == RIGHT_ARROW) ||
						 (tok_last->operator == DOT))) {
					tok->type = MEMBER;
				} else if (process_text(&cp, tok)) {
					free_tokens(tok_head);
					free_tokens(tok);
					return((token_t*)NULL);
				}
				if (tok->type == TEXT) {
					return(tok);
				} else if (tok->type == STRING) {
					if (is_typestr(tok->string)) {
						tok->type = TYPE_DEF;
					} else {
						tok->operator = TEXT;
						return(tok);
					}
					break;
				} else if (tok->type == CHARACTER) {
					break;
				}

				/* Check and See if the entire string is 
				 * a typename (valid only for whatis case).
				 */
				s = strpbrk(cp, 
					".\t+-*/()[]|~!$&%^<>?:&=^\"\'");
				if (!s && !tok->type && is_typestr(cp)) {
					tok->type = TYPE_DEF;
					len = strlen(cp) + 1;
					tok->string = (char *)
						kl_alloc_block(len, K_TEMP);
					bcopy(cp, tok->string, len - 1);
					tok->string[len - 1] = 0;
					cp = (char *)((uaddr_t)cp + len - 1);
					break;
				}

				/* Now check for everything else
				 */
				if ((s = strpbrk(cp, 
					" .\t+-*/()[]|~!$&%^<>?:&=^\"\'"))) {
					len = (uaddr_t)s - (uaddr_t)cp + 1;
				} else {
					len = strlen(cp) + 1;
				}

				tok->string = 
					(char *)kl_alloc_block(len, K_TEMP);
				bcopy(cp, tok->string, len - 1);
				tok->string[len - 1] = 0;

				cp = (char *)((uaddr_t)cp + len - 2);

				/* Check to see if this is the keyword 
				 * "sizeof". If not, then check to see if 
				 * the string is a member name.
				 */
				if (!strcmp(tok->string, "sizeof")) {
					tok->operator = SIZEOF;
					kl_free_block((void *)tok->string);
					tok->string = 0;
				} else if (tok_last && 
					((tok_last->operator == RIGHT_ARROW) ||
					 (tok_last->operator == DOT))) {
					tok->type = MEMBER;
				} else {
					tok->type = STRING;
				}
				break;
			}
		}
		if (!(tok->type)) {
			tok->type = OPERATOR;
		}
		if (!tok_head) {
			tok_head = tok_last = tok;
		} else {
			tok_last->next = tok;
			tok_last = tok;
		}
		cp++;
	}
	if (paren_count < 0) {
		set_eval_error(E_CLOSE_PAREN);
		error_token = tok->ptr;
		free_tokens(tok_head);
		return((token_t*)NULL);
	} else if (paren_count > 0) {
		set_eval_error(E_OPEN_PAREN);
		error_token = tok->ptr;
		free_tokens(tok_head);
		return((token_t*)NULL);
	}
	return(tok_head);
}

/*
 * valid_binary_args()
 */
int
valid_binary_args(node_t *np, node_t *left, node_t *right)
{
	int op = np->operator;

	if ((op == RIGHT_ARROW) || (op == DOT)) {
		if (!left) {
			set_eval_error(E_MISSING_STRUCTURE);
			error_token = np->tok_ptr;
			return(0);
		} else if (!(left->node_type == TYPE_DEF) &&
				!(left->node_type == MEMBER) &&
				!(left->operator == CLOSE_PAREN)) {
			set_eval_error(E_BAD_STRUCTURE);
			error_token = left->tok_ptr;
			return(0);
		}
		if (!right || (!(right->node_type == MEMBER))) {
			set_eval_error(E_BAD_MEMBER);
			error_token = right->tok_ptr;
			return(0);
		}
		return(1);
	}
	if (!left || !right) {
		set_eval_error(E_MISSING_OPERAND);
		error_token = np->tok_ptr;
		return(0);
	}
	switch (left->operator) {
		case CLOSE_PAREN:
		case CLOSE_SQUARE_BRACKET:
			break;
		default:
			switch(left->node_type) {
				case NUMBER:	
				case STRING:
				case TEXT:
				case CHARACTER:
				case EVAL_VAR:
				case MEMBER:
					break;
				default:
					set_eval_error(E_BAD_OPERAND);
					error_token = np->tok_ptr;
					return(0);
			}
	}
	switch (right->operator) {
		case OPEN_PAREN:
			break;
		default:
			switch(right->node_type) {
				case NUMBER:	
				case STRING:
				case TEXT:
				case CHARACTER:
				case EVAL_VAR:
				case MEMBER:
					break;
				default:
					set_eval_error(E_BAD_OPERAND);
					error_token = np->tok_ptr;
					return(0);
			}
	}
	return(1);
}

/*
 * get_node_list()
 */
static node_t *
get_node_list(token_t *tp, int flags)
{
	node_t *root = (node_t *)NULL; 
	node_t *np = (node_t *)NULL;
	node_t *last = (node_t *)NULL;

	/* Loop through the tokens and convert them to nodes. 
	 */
	while (tp) {
		np = make_node(tp, flags);
		if (eval_error) {
			return((node_t *)NULL);
		}
		if (root) {
			last->next = np;
			last = np;
		} else {
			root = last = np;
		}
		tp = tp->next;
	}
	last = (node_t *)NULL;
	for (np = root; np; np = np->next) {
		if (is_binary(np->operator)) {
			if (!valid_binary_args(np, last, np->next)) {
				free_nodelist(root);
				return((node_t *)NULL);
			}	
		}
		last = np;
	}
	return(root);
}

/*
 * next_node()
 */
static node_t *
next_node(void)
{
	node_t *np;
	if ((np = node_list)) {
		node_list = node_list->next;
		np->next = (node_t*)NULL;
	}
	return(np);
}

/*
 * eval_unary()
 */
static node_t *
eval_unary(node_t *curnp, int flags)
{
	node_t *n0, *n1;

	n0 = curnp;

	/* Peek ahead and make sure there is a next node.
	 * Also check to see if the next node requires
	 * a recursive call to do_eval(). If it does, we'll 
	 * let the do_eval() call take care of pulling it
	 * off the list.
	 */
	if (!node_list) {
		set_eval_error(E_SYNTAX_ERROR);
		error_token = n0->tok_ptr;
		free_nodes(n0);
		return((node_t*)NULL);
	} 
	if (n0->operator == CAST) { 
		if (node_list->operator == CLOSE_PAREN) {

			/* Free the CLOSE_PAREN and return
			 */
			free_node(next_node());
			return(n0);
		}
		if (!(node_list->node_type == NUMBER) &&
				!(node_list->node_type == VADDR) &&
				!((node_list->operator == ADDRESS) ||
				(node_list->operator == CAST) || 
				(node_list->operator == UNARY_MINUS) || 
				(node_list->operator == UNARY_PLUS) || 
				(node_list->operator == INDIRECTION) || 
				(node_list->operator == OPEN_PAREN))) {
			set_eval_error(E_SYNTAX_ERROR);
			error_token = node_list->tok_ptr;
			free_nodes(n0);
			return((node_t*)NULL);
		}
	} 
	if ((n0->operator == INDIRECTION) ||
			(n0->operator == ADDRESS) ||
			(n0->operator == OPEN_PAREN) ||
			is_unary(node_list->operator)) {
		n1 = do_eval(flags);
		if (eval_error) {
			free_nodes(n0);
			free_nodes(n1);
			return((node_t*)NULL);
		}
	} else {
		n1 = next_node();
	}

	if (n1->operator == OPEN_PAREN) {
		/* Get the value contained within the parenthesis. 
		 * If there was an error, just return.
		 */
		free_node(n1);
		n1 = do_eval(flags);
		if (eval_error) {
			free_nodes(n1);
			free_nodes(n0);
			return((node_t*)NULL);
		}
	}

	n0->right = n1;
	if (replace_unary(n0, flags) == -1) {
		if (!eval_error) {
			set_eval_error(E_SYNTAX_ERROR);
			error_token = n0->tok_ptr;
		}
		free_nodes(n0);
		return((node_t*)NULL);
	}
	return(n0);
}

/* 
 * do_eval() -- Reduces an equation to a single value. 
 * 
 *   Any parenthesis (and nested parenthesis) within the equation will
 *   be solved first via recursive calls to do_eval().
 */
static node_t *
do_eval(int flags)
{
	node_t *root = (node_t*)NULL, *curnp, *n0, *n1;

	/* Loop through the list of nodes until we run out of nodes
	 * or we hit a CLOSE_PAREN. If we hit an OPEN_PAREN, make a 
	 * recursive call to do_eval().
	 */
	curnp = next_node();
	while (curnp) {
		n0 = n1 = (node_t *)NULL;

		if (curnp->operator == OPEN_PAREN) {
			/* Get the value contained within the parenthesis. 
			 * If there was an error, just return.
			 */
			free_node(curnp);
			n0 = do_eval(flags);
			if (eval_error) {
				free_nodes(n0);
				free_nodes(root);
				return((node_t *)NULL);
			}

		} else if (curnp->operator == SIZEOF) {
			/* Free the SIZEOF node and then make a call 
			 * to the get_sizeof() function (which will 
			 * get the next node off the list).
			 */
			n0 = get_sizeof();
			if (eval_error) {
				if (!error_token) {
					error_token = curnp->tok_ptr;
				}
				free_node(curnp);
				free_nodes(root);
				return((node_t *)NULL);
			}
			free_node(curnp);
			curnp = (node_t *)NULL;
		} else if (is_unary(curnp->operator)) {
			n0 = eval_unary(curnp, flags);
		} else {
			n0 = curnp;
			curnp = (node_t *)NULL;
		}
		if (eval_error) {
			free_nodes(n0);
			free_nodes(root);
			return((node_t *)NULL);
		}

		/* n0 should now contain a non-operator node. Check to see if 
		 * there is a next token. If there isn't, just add the last 
		 * rchild and return.
		 */
		if (!node_list) {
			if (root) {
				add_rchild(root, n0);
			} else {
				root = n0;
			}
			replace(root, flags);
			if (eval_error) {
				free_nodes(root);
				return((node_t *)NULL);
			}
			return(root);
		}

		/* Make sure the next token is an operator.
		 */
		if (!node_list->operator) {
			free_nodes(root);
			free_node(n0);
			set_eval_error(E_SYNTAX_ERROR);
			error_token = node_list->tok_ptr;
			return((node_t *)NULL);
		} else if ((node_list->operator == CLOSE_PAREN) ||
			(node_list->operator == CLOSE_SQUARE_BRACKET)) {

			if (root) {
				add_rchild(root, n0);
			} else {
				root = n0;
			}

			/* Reduce the resulting tree to a single value
			 */
			replace(root, flags);
			if (eval_error) {
				free_nodes(root);
				return((node_t *)NULL);
			}
			
			/* Step over the CLOSE_PAREN or CLOSE_SQUARE_BRACKET
			 * and then return.
			 */
			free_node(next_node());
			return(root);
		} else if (node_list->operator == OPEN_SQUARE_BRACKET) {

			/* skip over the OPEN_SQUARE_BRACKET token
			 */
			free_node(next_node());

			/* Get the value contained within the brackets. This 
			 * value must represent an array index (value or
			 * equation).
			 */
			n1 = do_eval(0);
			if (eval_error) {
				free_nodes(root);
				free_node(n0);
				free_node(n1);
				return((node_t *)NULL);
			}

			/* Convert the array (or pointer type) to an 
			 * element type using the index value obtained 
			 * above. Make sure that n0 contains some sort 
			 * of type definition first, however.
			 */
			if (n0->node_type != TYPE_DEF) {
				set_eval_error(E_BAD_TYPE);
				error_token = n0->tok_ptr;
				free_nodes(n0);
				free_nodes(n1);
				free_nodes(root);
				return((node_t *)NULL);
			}
			array_to_element(n0, n1);
			free_node(n1);
			if (eval_error) {
				free_nodes(root);
				free_nodes(n0);
				return((node_t *)NULL);
			}

			/* If there aren't any more nodes, just
			 * return.
			 */
			if (!node_list) {
				return(n0);
			}
		} else if (!is_binary(node_list->operator)) {
			set_eval_error(E_BAD_OPERATOR);
			error_token = node_list->tok_ptr;
			free_nodes(root);
			free_nodes(n0);
			return((node_t *)NULL);
		}

		/* Now get the operator node
		 */
		if (!(n1 = next_node())) {
			set_eval_error(E_SYNTAX_ERROR);
			error_token = n0->tok_ptr;
			free_nodes(n0);
			free_nodes(root);
			return((node_t *)NULL);
		}

		/* Check to see if this binary operator is RIGHT_ARROW or DOT.
		 * If it is, we need to reduce it to a single value node now.
		 */
		while ((n1->operator == RIGHT_ARROW) || (n1->operator == DOT)) {

			/* The next node must contain the name of the 
			 * struct|union member.
			 */
			if (!node_list || (node_list->node_type != MEMBER)) {
				set_eval_error(E_BAD_MEMBER);
				error_token = n1->tok_ptr;
				free_nodes(n0);
				free_nodes(n1);
				free_nodes(root);
				return((node_t *)NULL);
			}
			n1->left = n0;

			/* Now get the next node and link it as the 
			 * right child.
			 */
			if (!(n0 = next_node())) {
				set_eval_error(E_SYNTAX_ERROR);
				error_token = n1->tok_ptr;
				free_nodes(n1);
				free_nodes(root);
				return((node_t *)NULL);
			}
			n1->right = n0;
			if (!(n0 = replace(n1, flags))) {
				if (!(eval_error)) {
					set_eval_error(E_SYNTAX_ERROR);
					error_token = n1->tok_ptr;
				}
				free_nodes(n1);
				free_nodes(root);
				return((node_t *)NULL);
			}
			n1 = (node_t *)NULL;

			/* Check to see if there is a next node. If there 
			 * is, check to see if it is the operator CLOSE_PAREN. 
			 * If it is, then return (skipping over the 
			 * CLOSE_PAREN first).
			 */
			if (node_list && ((node_list->operator == CLOSE_PAREN) 
						|| (node_list->operator == 
						CLOSE_SQUARE_BRACKET))) {
				if (root) {
					add_rchild(root, n0);
				} else {
					root = n0;
				}

				/* Reduce the resulting tree to a single 
				 * value
				 */
				replace(root, flags);
				if (eval_error) {
					free_nodes(root);
					return((node_t *)NULL);
				}
				
				/* Advance the token pointer past the 
				 * CLOSE_PAREN and then return.
				 */
				free_node(next_node());
				return(root);
			}

			/* Check to see if the next node is an 
			 * OPEN_SQUARE_BRACKET. If it is, then we have to 
			 * reduce the contents of the square brackets to 
			 * an index array.
			 */
			if (node_list && (node_list->operator 
						== OPEN_SQUARE_BRACKET)) {

				/* Advance the token pointer and call 
				 * do_eval() again.
				 */
				free_node(next_node());
				n1 = do_eval(0);
				if (eval_error) {
					free_node(n0);
					free_node(n1);
					free_nodes(root);
					return((node_t *)NULL);
				}

				/* Convert the array (or pointer type) to 
				 * an element type using the index value 
				 * obtained above. Make sure that n0 
				 * contains some sort of type definition 
				 * first, however.
				 */
				if (n0->node_type != TYPE_DEF) {
					set_eval_error(E_BAD_TYPE);
					error_token = n0->tok_ptr;
					free_node(n0);
					free_node(n1);
					free_node(root);
					return((node_t *)NULL);
				}
				array_to_element(n0, n1);
				free_node(n1);
				if (eval_error) {
					free_node(n0);
					free_node(root);
					return((node_t *)NULL);
				}
			}

			/* Now get the next operator node (if there is one).
			 */
			if (!node_list) {
				if (root) {
					add_rchild(root, n0);
				} else {
					root = n0;
				}
				return(root);
			}
			n1 = next_node();
		}

		if (n1 && ((n1->operator == CLOSE_PAREN) ||
				(n1->operator == CLOSE_SQUARE_BRACKET))) {
			free_node(n1);
			if (root) {
				add_rchild(root, n0);
			} else {
				root = n0;
			}
			replace(root, flags);
			if (eval_error) {
				free_nodes(root);
				return((node_t *)NULL);
			}
			return(root);
		}

		if (!root) {
			root = n1;
			n1->left = n0;
		} else if (precedence(root->operator) 
				>= precedence(n1->operator)) {
			add_rchild(root, n0);
			n1->left = root;
			root = n1;
		} else {
			if (!root->right) {
				n1->left = n0;
				root->right = n1;
			} else {
				add_rchild(root, n0);
				n1->left = root->right;
				root->right = n1;
			}
		}
		curnp = next_node();
	} /* while(curnp) */
	return(root);
}

/*
 * is_unary()
 */
static int
is_unary(int op)
{
	switch (op) {
		case LOGICAL_NEGATION :
		case ADDRESS :
		case INDIRECTION :
		case UNARY_MINUS :
		case UNARY_PLUS :
		case ONES_COMPLEMENT :
		case CAST :
			return(1);

		default :
			return(0);
	}
}


/*
 * is_binary()
 */
static int
is_binary(int op)
{
	switch (op) {

		case BITWISE_OR :
		case BITWISE_EXCLUSIVE_OR :
		case BITWISE_AND :
		case RIGHT_SHIFT :
		case LEFT_SHIFT :
		case ADD :
		case SUBTRACT :
		case MULTIPLY :
		case DIVIDE :
		case MODULUS :
		case LOGICAL_OR :
		case LOGICAL_AND :
		case EQUAL :
		case NOT_EQUAL :
		case LESS_THAN :
		case GREATER_THAN :
		case LESS_THAN_OR_EQUAL :
		case GREATER_THAN_OR_EQUAL :
		case RIGHT_ARROW :
		case DOT :
			return(1);

		default :
			return(0);
	}
}

/*
 * precedence()
 */
static int
precedence(int a) 
{
	if ((a >= CONDITIONAL) && (a <= CONDITIONAL_ELSE)) {
		return(1);
	} else if (a == LOGICAL_OR) {
		return(2);
	} else if (a == LOGICAL_AND) {
		return(3);
	} else if (a == BITWISE_OR) {
		return(4);
	} else if (a == BITWISE_EXCLUSIVE_OR) {
		return(5);
	} else if (a == BITWISE_AND) {
		return(6);
	} else if ((a >= EQUAL) && (a <= NOT_EQUAL)) {
		return(7);
	} else if ((a >= LESS_THAN) && (a <= GREATER_THAN_OR_EQUAL)) {
		return(8);
	} else if ((a >= RIGHT_SHIFT) && (a <= LEFT_SHIFT)) {
		return(9);
	} else if ((a >= ADD) && (a <= SUBTRACT)) {
		return(10);
	} else if ((a >= MULTIPLY) && (a <= MODULUS)) {
		return(11);
	} else if ((a >= LOGICAL_NEGATION) && (a <= SIZEOF)) {
		return(12);
	} else if ((a >= RIGHT_ARROW) && (a <= DOT)) {
		return(13);
	} else {
		return(0);
	}
}

/* 
 * esc_char()
 */
char
esc_char(char *str)
{
	long int val;
	char ch;

	if (strlen(str) > 1) {
		val = strtol(str, (char **)NULL, 8);
		ch = (char)val; 
	} else {
		ch = str[0];
	}
	switch (ch) {
		case 'a' :
			return((char)7);
		case 'b' :
			return((char)8);
		case 't' :
			return((char)9);
		case 'n' :
			return((char)10);
		case 'f' :
			return((char)12);
		case 'r' :
			return((char)13);
		case 'e' :
			return((char)27);
		default:
			return(ch);
	}
}

/*
 * make_node()
 */
static node_t *
make_node(token_t *t, int flags)
{
	node_t *np;

	np = (node_t*)kl_alloc_block(sizeof(*np), flags);

	if (t->type == OPERATOR) {

		/* Check to see if this token represents a typecast
		 */
		if (t->operator == CAST) {
			type_t *tp;

			if (!(np->type = get_type(t->string, flags))) {
				set_eval_error(E_BAD_CAST);
				error_token = t->ptr;
				free_nodes(np);
				return((node_t*)NULL);
			}

			/* Determin if this is a pointer to a type
			 */
			tp = np->type;
			if (tp->flag == POINTER_FLAG) {
				np->flags = POINTER_FLAG;
				tp = tp->t_next;
				while (tp->flag == POINTER_FLAG) {
					tp = tp->t_next;
				}
			}
			switch(tp->flag) {
				case KLTYPE_FLAG:
					np->flags |= KLTYPE_FLAG;
					break;

				default:
					free_nodes(np);
					set_eval_error(E_BAD_CAST); 
					error_token = t->ptr;
					return((node_t*)NULL);
			}
			if (!t->next) {
				if (flags & C_WHATIS) {
					np->node_type = TYPE_DEF;
				} else {
					set_eval_error(E_BAD_CAST);
					error_token = t->ptr;
					return((node_t*)NULL);
				}
			} else {
				np->node_type = OPERATOR;
				np->operator = CAST;
			}
		} else {
			np->node_type = OPERATOR;
			np->operator = t->operator;
		}
	} else if (t->type == MEMBER) {
		np->name = (char *)kl_dup_block((void *)t->string, K_TEMP);
		np->node_type = MEMBER;
	} else if ((t->type == STRING) || (t->type == TYPE_DEF)) {
		syment_t *sp;

		if ((sp = kl_lkup_symname(t->string)) && !(flags & C_NOVARS)) {

			/* The string is a symbol name. We'll treat it as 
			 * a global kernel variable and, at least, gather in
			 * the address of the symbol and the value it points 
			 * to.
			 */
			np->address = sp->s_addr;
			np->flags |= ADDRESS_FLAG;
			np->name = t->string;
			t->string = (char*)NULL;

			/* Need to see if there is type information available
			 * for this variable. Since this mapping is not 
			 * available yet, we will just attach a type struct 
			 * for either uint32_t or uint64_t (depending on the
			 * size of a kernel pointer).  That will at least let 
			 * us do something and will prevent the scenario where 
			 * we have a type node with out a pointer to a type 
			 * struct! 
			 *
			 * XXX - We should get the actual type information
			 * for the variable.
			 */
			np->node_type = TYPE_DEF;
			np->flags |= KLTYPE_FLAG;
			GET_BLOCK(np->address, KL_NBPW, &np->value);
			if (PTRSZ64) {
				np->type = get_type("uint64_t", flags);
			} else {
				np->type = get_type("uint32_t", flags);
				np->value = *((uint32_t*) &np->value);
			}
		} else if (flags & (C_WHATIS|C_SIZEOF)) {

			kltype_t *kltp;

			if ((kltp = kl_find_sym(t->string, 
						(KLT_TYPE|KLT_TYPEDEF)))) {

				np->node_type = TYPE_DEF;
				np->flags = KLTYPE_FLAG;
				np->type = (type_t*)
					kl_alloc_block(sizeof(type_t), K_TEMP);
				np->type->flag = KLTYPE_FLAG;
				np->type->t_kltp = kltp;
			} else {
				if (GET_VALUE(t->string, &np->value)) {
					set_eval_error(E_BAD_VALUE);
					error_token = t->ptr;
					free_nodes(np);
					return((node_t*)NULL);
				}
				if (!strncmp(t->string, "0x", 2) ||
						!strncmp(t->string, "0X", 2)) {
					np->flags |= UNSIGNED_FLAG;
				}
				np->node_type = NUMBER;
			}
			np->tok_ptr = t->ptr;
			return(np);
		} else {
			if (GET_VALUE(t->string, &np->value)) {
				set_eval_error(E_BAD_VALUE);
				error_token = t->ptr;
				free_nodes(np);
				return((node_t*)NULL);
			}
			if (np->value > 0xffffffff) {
				np->byte_size = 8;
			} else {
				np->byte_size = 4;
			}
			if (!strncmp(t->string, "0x", 2) ||
					!strncmp(t->string, "0X", 2)) {
				np->flags |= UNSIGNED_FLAG;
			}
			np->node_type = NUMBER;
		}
	} else if (t->type == CHARACTER) {
		char *cp;

		/* Step over the single quote
		 */
		cp = (t->ptr + 1);
		if (*cp == '\\') {
			int i = 0;
			char str[16];

			/* Step over the back slash
		 	 */
			cp++;
			while (*cp != '\'') {
				str[i++] = *cp++;
			}
			str[i] = 0;
			np->value = esc_char(str);
		} else {
			np->value = *cp;
		}
		np->type = get_type("char", flags);
		np->node_type = TYPE_DEF;
		np->flags |= KLTYPE_FLAG;
	} else if (t->type == TEXT) {
		np->node_type = TEXT;
		np->name = t->string;
		/* So the block doesn't get freed twice */
		t->string = (char*)NULL; 
	} else {
		set_eval_error(E_SYNTAX_ERROR);
		error_token = t->ptr;
		return((node_t*)NULL);
	}
	np->tok_ptr = t->ptr;
	return(np);
}

/*
 * add_node()
 */
static int
add_node(node_t *root, node_t *new_node)
{
	node_t *n = root;

	/* Find the most lower-right node
	 */
	while (n->right) {
		n = n->right;
	}

	/* If the node we found is a leaf node, return an error (we will 
	 * have to insert the node instead).
	 */
	if (n->node_type == NUMBER) {
		return(-1);
	} else {
		n->right = new_node;
	}
	return(0);
}

/*
 * add_rchild()
 */
static int
add_rchild(node_t *root, node_t *new_node)
{
	if (add_node(root, new_node) == -1) {
		return(-1);
	}
	return(0);
}

#ifdef NOT
/*
 * add_lchild()
 */
static int
add_lchild(node_t *root, node_t *new_node)
{
	node_t *n = root;

	/* Find the most lower-left node and make sure it is not a leaf 
	 * (child) node.
	 */
	while (n->left) {
		n = n->left;
	}

	/* If the node we found is a leaf node, return an error.
	 */
	if (n->node_type == NUMBER) {
		return(-1);
	} else {
		n->left = new_node;
	}
	return(0);

}
#endif

/*
 * free_type()
 */
static void
free_type(type_t *head) 
{
	type_t *t0, *t1;

	t0 = head;
	while(t0) {
		if (t0->flag == POINTER_FLAG) {
			t1 = t0->t_next;
			kl_free_block((void *)t0);
			t0 = t1;
		} else {
			if (is_temp_block(t0->t_kltp)) {
				if (t0->flag != KLTYPE_FLAG) {
					kl_free_block((void *)t0->t_kltp);
				}
			}
			kl_free_block((void *)t0);
			t0 = (type_t *)NULL;
		}
	}
}

/*
 * get_type() -- Convert a typecast string into a type. 
 * 
 *   Returns a pointer to a struct containing type information.
 *   The type of struct returned is indicated by the contents 
 *   of type. If the typecast contains an asterisk, set ptr_type 
 *   equal to one, otherwise set it equal to zero.
 */
static type_t *
get_type(char *s, int flags)
{
	int len, type = 0;
	char *cp, typename[128];
	type_t *t, *head, *last;
	kltype_t *kltp;

	head = last = (type_t *)NULL;

	/* Get the type string
	 */
        if (!strncmp(s, "struct", 6)) {
                if ((cp = strpbrk(s + 7, " \t*"))) {
                        len = cp - (s + 7);
                } else {
                        len = strlen(s + 7);
                }
                bcopy (s + 7, typename, len);
        } else if (!strncmp(s, "union", 5)) {
                if ((cp = strpbrk(s + 6, " \t*"))) {
                        len = cp - (s + 6);
                } else {
                        len = strlen(s + 6);
                }
                bcopy (s + 6, typename, len);
        } else {
		if ((cp = strpbrk(s, "*)"))) {
			len = cp - s;
		} else {
			len = strlen(s);
		}
		bcopy (s, typename, len);
	}

	/* Strip off any trailing spaces 
	 */
	while (len && ((typename[len - 1] == ' ') || 
			(typename[len - 1] == '\t'))) {
		len--;
	}
	typename[len] = 0;

	if (!(kltp = kl_find_sym(typename, (KLT_TYPE|KLT_TYPEDEF)))) {
		return ((type_t *)NULL);
	}
	type = KLTYPE_FLAG;

	/* check to see if this cast is a pointer to a type, a pointer
	 * to a pointer to a type, etc.
	 */
	cp = s;
	while ((cp = strpbrk(cp, "*"))) {
		t = (type_t *)kl_alloc_block(sizeof(type_t), flags);
		t->flag = POINTER_FLAG;
		if (last) {
			last->t_next = t;
			last = t;
		} else {
			head = last = t;
		}
		cp++;
	}

	/* Allocate a type block that will point to the type specific
	 * record.
	 */
	t = (type_t *)kl_alloc_block(sizeof(type_t), flags);
	t->flag = type;

	switch (t->flag) {

		case KLTYPE_FLAG:
			t->t_kltp = kltp;
			break;

		default:
			free_type(head);
			return((type_t*)NULL);
	}
	if (last) {
		last->t_next = t;
	} else {
		head = t;
	}
	return(head);
}

/*
 * free_node()
 */
static void
free_node(node_t *np)
{
	/* If there is nothing to free, just return.
	 */
	if (!np) {
		return;
	}
	if (np->name) {
		kl_free_block((void *)np->name);
	}
	free_type(np->type);
	kl_free_block((void *)np);
}

/*
 * free_nodes()
 */
void
free_nodes(node_t *np)
{
	node_t *q;

	/* If there is nothing to free, just return.
	 */
	if (!np) {
		return;
	}
	if ((q = np->left)) {
		free_nodes(q);
	}
	if ((q = np->right)) {
		free_nodes(q);
	}
	if (np->name) {
		kl_free_block((void *)np->name);
	}
	free_type(np->type);
	kl_free_block((void *)np);
}

/*
 * free_nodelist()
 */
static void
free_nodelist(node_t *np)
{
	node_t *nnp;

	while(np) {
		nnp = np->next;
		free_node(np);
		np = nnp;
	}
}

extern int alloc_debug;

/*
 * free_eval_memory()
 */
void
free_eval_memory(void)
{
	free_nodelist(node_list);
	node_list = (node_t*)NULL;
}

/*
 * get_sizeof()
 */
static node_t *
get_sizeof()
{
	node_t *curnp, *n0;

	if (!(curnp = next_node())) {
		set_eval_error(E_SYNTAX_ERROR);
		return((node_t*)NULL);
	}

	/* The next token should be a CAST or an open paren. 
 	 * If it's something else, then return an error.
	 */
	if (curnp->operator == OPEN_PAREN) {
		free_nodes(curnp);
		n0 = do_eval(C_SIZEOF);
		if (eval_error) {
			error_token = n0->tok_ptr;
			free_nodes(n0);
			return((node_t*)NULL);
		}
	} else if (curnp->operator == CAST) {
		n0 = curnp;
	} else {
		set_eval_error(E_BAD_TYPE);
		error_token = n0->tok_ptr;
		free_nodes(n0);
		return((node_t*)NULL);
	}

	if (!n0->type) {
		set_eval_error(E_NOTYPE);
		error_token = n0->tok_ptr;
		free_nodes(n0);
		return((node_t*)NULL);
	}

	if (n0->type->flag & POINTER_FLAG) {
		n0->value = KL_NBPW;
	} else if (n0->type->flag & KLTYPE_FLAG) {
		kltype_t *kltp;
		
		kltp = kl_realtype(n0->type->t_kltp, 0);

		if (kltp->kl_bit_size) {
			n0->value = kltp->kl_bit_size / 8;
			if (kltp->kl_bit_size % 8) {
				n0->value += 1;
			}
		} else {
			n0->value = kltp->kl_size;
		}
	} else {
		set_eval_error(E_BAD_TYPE);
		error_token = n0->tok_ptr;
		free_nodes(n0);
		return((node_t*)NULL);
	}
	n0->node_type = NUMBER;
	n0->flags = 0;
	n0->operator = 0;
	n0->byte_size = 0;
	n0->address = 0;
	if (n0->type) {
		free_type(n0->type);
		n0->type = 0;
	}
	return(n0);
}

/*
 * apply_unary()
 */
static int
apply_unary(node_t *n, uint64_t *value)
{
	if (!n || !n->right) {
		return(-1);
	}

	switch (n->operator) {

		case UNARY_MINUS :
			*value = (0 - n->right->value);
			break;

		case UNARY_PLUS :
			*value = (n->right->value);
			break;

		case ONES_COMPLEMENT :
			*value = ~(n->right->value);
			break;

		case LOGICAL_NEGATION :
			if (n->right->value) {
				*value = 0;
			} else {
				*value = 1;
			}
			logical_flag++;
			break;

		default :
			break;
	}
	return(0);
}

/*
 * pointer_math()
 */
static int
pointer_math(node_t *np, uint64_t *value, int type, int flags)
{
	int size;
	uint64_t lvalue, rvalue;
	type_t *tp, *tp1;

	if (type < 0) {
		if (np->left->flags & POINTER_FLAG) {

			/* Since we only allow pointer math, 
			 * anything other than a pointer causes 
			 * failure.
			 */
			tp = (type_t*)np->left->type;
			if (tp->flag != POINTER_FLAG) {
				set_eval_error(E_SYNTAX_ERROR);
				error_token = np->left->tok_ptr;
				return(-1);
			}

			tp = tp->t_next;

			switch (tp->flag) {

				case POINTER_FLAG :
					size = KL_NBPW;
					break;

				case KLTYPE_FLAG : {
					/* Get the size of the real type,
					 * not just the size of a pointer 
					 * If there isn't any type info,
					 * then just set size equal to the
					 * size of a pointer.
					 */
					kltype_t *kltp, *rkltp;

					kltp = tp->t_kltp;
					rkltp = kl_realtype(kltp, 0);
					if (!(size = rkltp->kl_size)) {
						if (kltp != rkltp) {
							size = kltp->kl_size;
						} else {
							size = KL_NBPW;
						}
					}
					break;
				}

				default :
					set_eval_error(E_SYNTAX_ERROR);
					error_token = np->left->tok_ptr;
					return(-1);
			}
			lvalue = np->left->value;
		} else {
			size = KL_NBPW;
			lvalue = np->left->address;
		} 
		switch (np->operator) {
			case ADD :
				*value = lvalue + (np->right->value * size);
				break;

			case SUBTRACT :
				*value = lvalue - (np->right->value * size);
				break;

			default :
				set_eval_error(E_BAD_OPERATOR);
				error_token = np->tok_ptr;
				return(-1);
		}
	} else if (type > 0) {
		if (np->right->flags & POINTER_FLAG) {

			/* Since we only allow pointer math, 
			 * anything other than a pointer causes 
			 * failure.
			 */
			tp = (type_t*)np->right->type;
			if (tp->flag != POINTER_FLAG) {
				set_eval_error(E_SYNTAX_ERROR);
				error_token = np->right->tok_ptr;
				return(-1);
			}

			tp = tp->t_next;

			switch (tp->flag) {

				case POINTER_FLAG :
					size = KL_NBPW;
					break;

				case KLTYPE_FLAG :
					size = tp->t_kltp->kl_size;
					break;

				default :
					set_eval_error(E_SYNTAX_ERROR);
					error_token = np->right->tok_ptr;
					return(-1);
			}
			rvalue = np->right->value;
		} else {
			size = KL_NBPW;
			rvalue = np->right->address;
		} 
		switch (np->operator) {
			case ADD :
				*value = rvalue + (np->left->value * size);
				break;

			case SUBTRACT :
				*value = rvalue - (np->left->value * size);
				break;

			default :
				set_eval_error(E_BAD_OPERATOR);
				error_token = np->tok_ptr;
				return(-1);
		}
	} else {
		return(-1);
	}
	tp1 = (type_t *)kl_alloc_block(sizeof(type_t), flags);
	tp1->flag = POINTER_FLAG;
	np->type = tp1;
	while (tp->flag == POINTER_FLAG) {
		tp1->t_next = (type_t *)kl_alloc_block(sizeof(type_t), flags);
		tp1->flag = POINTER_FLAG;
		tp1 = tp1->t_next;	
		tp = tp->t_next;	
	}
	if (tp) {
		tp1->t_next = (type_t *)kl_alloc_block(sizeof(type_t), flags);
		tp1 = tp1->t_next;
		tp1->flag = KLTYPE_FLAG;
		tp1->t_kltp = tp->t_kltp;
		if (type < 0) {
			if (np->left->flags & POINTER_FLAG) {
				np->flags |= POINTER_FLAG;
			} else {
				np->flags |= VADDR;
			}
		} else {
			if (np->right->flags & POINTER_FLAG) {
				np->flags |= POINTER_FLAG;
			} else {
				np->flags |= VADDR;
			}
		}
	}
	return(0);
}

/*
 * check_unsigned()
 */
int
check_unsigned(node_t *np)
{
	kltype_t *kltp, *rkltp;

	if (np->flags & UNSIGNED_FLAG) {
		return(1);
	} 
	if (!np->type) {
		return(0);
	}
	if (np->type->flag == POINTER_FLAG) {
		return(0);
	}
	kltp = np->type->t_kltp;
	if ((rkltp = kl_realtype(kltp, 0))) {
		if (rkltp->kl_encoding == ENC_UNSIGNED) {
			np->flags |= UNSIGNED_FLAG;
			return(1);
		}
	}
	return(0);
}

/*
 * apply()
 */
static int
apply(node_t *np, uint64_t *value, int flags)
{
	int ltype, rtype, do_signed = 0;

	/* There must be two operands
	 */
	if (!np->right || !np->left) {
		set_eval_error(E_MISSING_OPERAND);
		error_token = np->tok_ptr;
		return(-1);
	}

	if (np->right->node_type == OPERATOR) {
		replace(np->right, flags);
		if (eval_error) {
			return(-1);
		}
	}

	ltype = np->left->node_type;
	rtype = np->right->node_type;
	if ((ltype == TYPE_DEF) || (ltype == VADDR)) {
		if ((rtype == TYPE_DEF) || (rtype == VADDR)) {
			set_eval_error(E_NO_VALUE);
			error_token = np->tok_ptr;
			return(-1);
		}
		if (check_unsigned(np->left)) {
			np->flags |= UNSIGNED_FLAG;
		} else {
			do_signed++;
		}
		if (!type_to_number(np->left)) {
			return(pointer_math(np, value, -1, flags));
		}
		np->byte_size = np->left->byte_size;
	} else if ((rtype == TYPE_DEF) || (rtype == VADDR)) {
		if ((ltype == TYPE_DEF) || (ltype == VADDR)) {
			error_token = np->tok_ptr;
			set_eval_error(E_NO_VALUE);
			return(-1);
		}
		if (check_unsigned(np->right)) {
			np->flags |= UNSIGNED_FLAG;
		} else {
			do_signed++;
		}
		if (!type_to_number(np->right)) {
			return(pointer_math(np, value, 1, flags));
		}
		np->byte_size = np->right->byte_size;
	} else if ((np->left->flags & UNSIGNED_FLAG) || 
			(np->right->flags & UNSIGNED_FLAG)) {
		np->flags |= UNSIGNED_FLAG;
	} else {
		do_signed++;
	}

	if (do_signed) {
		switch (np->operator) {
			case ADD :
				*value = (int64_t)np->left->value + 
					(int64_t)np->right->value;
				break;

			case SUBTRACT :
				*value = (int64_t)np->left->value - 
					(int64_t)np->right->value;
				break;

			case MULTIPLY :
				*value = (int64_t)np->left->value * 
					(int64_t)np->right->value;
				break;

			case DIVIDE :
				if ((int64_t)np->right->value == 0) {
					set_eval_error(E_DIVIDE_BY_ZERO);
					error_token = np->right->tok_ptr;
					return(-1);
				}
				*value = (int64_t)np->left->value / 
					(int64_t)np->right->value;
				break;

			case BITWISE_OR :
				*value = (int64_t)np->left->value | 
					(int64_t)np->right->value;
				break;

			case BITWISE_AND :
				*value = (int64_t)np->left->value & 
					(int64_t)np->right->value;
				break;

			case MODULUS :
				if ((int64_t)np->right->value == 0) {
					set_eval_error(E_DIVIDE_BY_ZERO);
					error_token = np->right->tok_ptr;
					return(-1);
				}
				*value = (int64_t)np->left->value % 
					(int64_t)np->right->value;
				break;

			case RIGHT_SHIFT :
				*value = 
					(int64_t)np->left->value >> 
						(int64_t)np->right->value;
				break;

			case LEFT_SHIFT :
				*value = 
					(int64_t)np->left->value << 
						(int64_t)np->right->value;
				break;

			case LOGICAL_OR :
				if ((int64_t)np->left->value || 	
						(int64_t)np->right->value) {
					*value = 1;
				} else {
					*value = 0;
				}
				logical_flag++;
				break;

			case LOGICAL_AND :
				if ((int64_t)np->left->value && 
						(int64_t)np->right->value) {
					*value = 1;
				} else {
					*value = 0;
				}
				logical_flag++;
				break;

			case EQUAL :
				if ((int64_t)np->left->value == 
						(int64_t)np->right->value) {
					*value = 1;
				} else {
					*value = 0;
				}
				logical_flag++;
				break;

			case NOT_EQUAL :
				if ((int64_t)np->left->value != 
						(int64_t)np->right->value) {
					*value = 1;
				} else {
					*value = 0;
				}
				logical_flag++;
				break;

			case LESS_THAN :
				if ((int64_t)np->left->value < 
						(int64_t)np->right->value) {
					*value = 1;
				} else {
					*value = 0;
				}
				logical_flag++;
				break;

			case GREATER_THAN :
				if ((int64_t)np->left->value > 
						(int64_t)np->right->value) {
					*value = 1;
				} else {
					*value = 0;
				}
				logical_flag++;
				break;

			case LESS_THAN_OR_EQUAL :
				if ((int64_t)np->left->value <= 
						(int64_t)np->right->value) {
					*value = 1;
				} else {
					*value = 0;
				}
				logical_flag++;
				break;

			case GREATER_THAN_OR_EQUAL :
				if ((int64_t)np->left->value >= 
						(int64_t)np->right->value) {
					*value = 1;
				} else {
					*value = 0;
				}
				logical_flag++;
				break;

			default :
				break;
		}
	} else {
		switch (np->operator) {
			case ADD :
				*value = np->left->value + np->right->value;
				break;

			case SUBTRACT :
				*value = np->left->value - np->right->value;
				break;

			case MULTIPLY :
				*value = np->left->value * np->right->value;
				break;

			case DIVIDE :
				*value = np->left->value / np->right->value;
				break;

			case BITWISE_OR :
				*value = np->left->value | np->right->value;
				break;

			case BITWISE_AND :
				*value = np->left->value & np->right->value;
				break;

			case MODULUS :
				*value = np->left->value % np->right->value;
				break;

			case RIGHT_SHIFT :
				*value = np->left->value >> np->right->value;
				break;

			case LEFT_SHIFT :
				*value = np->left->value << np->right->value;
				break;

			case LOGICAL_OR :
				if (np->left->value || np->right->value) {
					*value = 1;
				} else {
					*value = 0;
				}
				logical_flag++;
				break;

			case LOGICAL_AND :
				if (np->left->value && np->right->value) {
					*value = 1;
				} else {
					*value = 0;
				}
				logical_flag++;
				break;

			case EQUAL :
				if (np->left->value == np->right->value) {
					*value = 1;
				} else {
					*value = 0;
				}
				logical_flag++;
				break;

			case NOT_EQUAL :
				if (np->left->value != np->right->value) {
					*value = 1;
				} else {
					*value = 0;
				}
				logical_flag++;
				break;

			case LESS_THAN :
				if (np->left->value < np->right->value) {
					*value = 1;
				} else {
					*value = 0;
				}
				logical_flag++;
				break;

			case GREATER_THAN :
				if (np->left->value > np->right->value) {
					*value = 1;
				} else {
					*value = 0;
				}
				logical_flag++;
				break;

			case LESS_THAN_OR_EQUAL :
				if (np->left->value <= np->right->value) {
					*value = 1;
				} else {
					*value = 0;
				}
				logical_flag++;
				break;

			case GREATER_THAN_OR_EQUAL :
				if (np->left->value >= np->right->value) {
					*value = 1;
				} else {
					*value = 0;
				}
				logical_flag++;
				break;

			default :
				break;
		}
	}
	return(0);
}

/*
 * member_to_type()
 */
static type_t *
member_to_type(kltype_t *kltp, int flags)
{
	kltype_t *rkltp;
	type_t *tp, *head = (type_t *)NULL, *last = (type_t *)NULL;

	/* Make sure this is a member
	 */
	if (kltp->kl_type != KLT_MEMBER) {
		return((type_t *)NULL);
	}

	rkltp = kltp->kl_realtype;
	while (rkltp && rkltp->kl_type == KLT_POINTER) {
		tp = (type_t *)kl_alloc_block(sizeof(type_t), flags);
		tp->flag = POINTER_FLAG;
		if (last) {
			last->t_next = tp;
			last = tp;
		} else {
			head = last = tp;
		}
		rkltp = rkltp->kl_realtype;
	}

	/* If We step past all the pointer records and don't point 
	 * at anything, this must be a void pointer. Setup a VOID 
	 * type struct so that we can maintain a pointer to some 
	 * type info.
	 */
	if (!rkltp) {
		tp = (type_t *)kl_alloc_block(sizeof(type_t), flags);
		tp->flag = VOID_FLAG;
		tp->t_kltp = kltp;
		if (last) {
			last->t_next = tp;
			last = tp;
		} else {
			head = last = tp;
		}
		return(head);
	}

	tp = (type_t *)kl_alloc_block(sizeof(type_t), flags);
	tp->flag = KLTYPE_FLAG;
	tp->t_kltp = kltp;
	if (last) {
		last->t_next = tp;
	} else {
		head = tp;
	}
	return(head);
}

/*
 * replace() -- 
 *
 * Replace the tree with a node containing the numerical result of
 * the equation. If pointer math is performed, the result will have
 * the same type as the pointer.
 */
static node_t *
replace(node_t *np, int flags)
{
	uint64_t value;
	node_t *q;
				
	if (!np) {
		return((node_t *)NULL);
	}

	if (np->node_type == OPERATOR) {
		if (!(q = np->left)) {
			return((node_t *)NULL);
		}
		while (q) {
			if (!replace(q, flags)) {
				return((node_t *)NULL);
			}
			q = q->right;
		}

		if ((np->operator == RIGHT_ARROW) || (np->operator == DOT)) {
			kaddr_t addr = 0;
			type_t *tp;

			/* The left node must point to a TYPE_DEF
			 */
			if (np->left->node_type != TYPE_DEF) {
				if (np->left->flags & NOTYPE_FLAG) {
					set_eval_error(E_NOTYPE);
					error_token = np->left->tok_ptr;
				} else {
					set_eval_error(E_BAD_TYPE);
					error_token = np->left->tok_ptr;
				}
				return((node_t *)NULL);
			}

			/* Get the type information.  Check to see if we 
			 * have a pointer to a type. If we do, we need 
			 * to strip off the pointer and get the type info. 
			 */
			if (np->left->type->flag == POINTER_FLAG) {
				tp = np->left->type->t_next;
				kl_free_block((void *)np->left->type);
			} else {
				tp = np->left->type;
			}

			/* We need to zero out the left child's type pointer 
			 * to prevent the type structs from being prematurely 
			 * freed (upon success). We have to remember, however, 
			 * to the free the type information before we return.
			 */
			np->left->type = (type_t*)NULL;

			/* tp should now point at a type_t struct that
			 * references a kltype_t struct. If it points 
			 * to anything else, return failure.
			 *
			 */
			if (tp->flag != KLTYPE_FLAG) {
				set_eval_error(E_BAD_TYPE);
				error_token = np->left->tok_ptr;
				free_type(tp);
				return((node_t *)NULL);
			}

			switch (tp->flag) {
				case KLTYPE_FLAG: {
					/* Make sure that the type referenced
					 * is a struct, union, or pointer to
					 * a struct or union. If it isn't one
					 * of these, then return failure.
					 */
					kltype_t *kltp, *kltmp; 
					
					kltp = kl_realtype(tp->t_kltp, 0);
					if ((kltp->kl_type != KLT_STRUCT) &&
						(kltp->kl_type != KLT_UNION)) {
						error_token = 
							np->left->tok_ptr;
						set_eval_error(E_BAD_TYPE);
						free_type(tp);
						return((node_t *)NULL);
					}

					/* Get type information for member. 
					 * If member is a pointer to a type, 
					 * get the pointer address and load 
					 * it into value. In any event, load 
					 * the struct/union address plus the
					 * offset of the member.
					 */
					kltmp = kl_get_member(kltp,
							np->right->name);
					if (!kltmp) {
						set_eval_error(E_BAD_MEMBER);
						error_token = 
							np->right->tok_ptr;
						free_type(tp);
						return((node_t *)NULL);
					}
					np->type = member_to_type(kltmp, flags);
					if (!np->type) {
						set_eval_error(E_BAD_MEMBER);
						error_token = 
							np->right->tok_ptr;
						free_type(tp);
						return((node_t *)NULL);
					}

					/* Now free the struct type information
					 */
					free_type(tp);
					np->node_type = TYPE_DEF;
					np->flags |= KLTYPE_FLAG;
					np->operator = 0;
					addr = 0;
					if (np->left->flags & POINTER_FLAG) {
						addr =  np->left->value +
							kltmp->kl_offset;
					} else if (np->left->flags & 
							ADDRESS_FLAG) {
						addr =  np->left->address +
							kltmp->kl_offset;
					}
					if (addr) {
						np->address = addr;
						np->flags |= ADDRESS_FLAG;
					}

					if (np->type->flag == POINTER_FLAG) {
						np->flags |= POINTER_FLAG;
						GET_BLOCK(addr, KL_NBPW, 
							&np->value);
						if (!PTRSZ64) {
							np->value = *((uint32_t*)
								&np->value);
						}
					} else {
						np->value = addr;
					}
					break;
				}
			}
			free_nodes(np->left);
			free_nodes(np->right);
			np->left = np->right = (node_t*)NULL;
			return(np);
		} else {
			if (!np->left || !np->right) {
				set_eval_error(E_MISSING_OPERAND);
				error_token = np->tok_ptr;
				return((node_t *)NULL);
			}
			if (np->left->byte_size && np->right->byte_size) {
				if (np->left->byte_size > 
						np->right->byte_size) {

					/* Left byte_size is greater than right
					 */
					np->byte_size = np->left->byte_size;
					np->type = np->left->type;
					np->flags = np->left->flags;
					free_type(np->right->type);
				} else if (np->left->byte_size < 
						np->right->byte_size) {

					/* Right byte_size is greater than left
					 */
					np->byte_size = np->right->byte_size;
					np->type = np->right->type;
					np->flags = np->right->flags;
					free_type(np->left->type);
				} else {

					/* Left and right byte_size is equal
					 */
					if (np->left->flags & UNSIGNED_FLAG) {
						np->byte_size = 
							np->left->byte_size;
						np->type = np->left->type;
						np->flags = np->left->flags;
						free_type(np->right->type);
					} else if (np->right->flags & 
							UNSIGNED_FLAG) {
						np->byte_size = 
							np->right->byte_size;
						np->type = np->right->type;
						np->flags = np->right->flags;
						free_type(np->left->type);
					} else {
						np->byte_size = 
							np->left->byte_size;
						np->type = np->left->type;
						np->flags = np->left->flags;
						free_type(np->right->type);
					}
				}
			} else if (np->left->byte_size) {
				np->byte_size = np->left->byte_size;
				np->type = np->left->type;
				np->flags = np->left->flags;
				free_type(np->right->type);
			} else if (np->right->byte_size) {
				np->byte_size = np->right->byte_size;
				np->type = np->right->type;
				np->flags = np->right->flags;
			} else {
				/* XXX - No byte sizes
				 */
			}

			if (apply(np, &value, flags)) {
				return((node_t *)NULL);
			}
		}
		np->right->type = np->left->type = (type_t*)NULL;

		/* Flesh out the rest of the node struct. 
		 */
		if (np->type) {
			np->node_type = TYPE_DEF;
			np->flags |= KLTYPE_FLAG;
		} else {
			np->node_type = NUMBER;
			np->flags &= ~(KLTYPE_FLAG);
		}
		np->operator = 0;
		np->value = value;
		kl_free_block((void *)np->left);
		kl_free_block((void *)np->right);
		np->left = np->right = (node_t*)NULL;
	}
	return(np);
}

/*
 * replace_cast()
 */
static int
replace_cast(node_t *n, int flags)
{
	type_t *t;

	if (!n) {
		set_eval_error(E_SYNTAX_ERROR);
		return(-1);
	} else if (!n->right) {
		set_eval_error(E_SYNTAX_ERROR);
		error_token = n->tok_ptr;
		return(-1);
	}
	if (n->flags & POINTER_FLAG) {
		if (n->right->node_type == VADDR) {
			if (n->right->flags & ADDRESS_FLAG) {
				n->value = n->right->address;
			} else {
				set_eval_error(E_SYNTAX_ERROR);
				error_token = n->right->tok_ptr;
				return(-1);
			}

		} else {
			n->value = n->right->value;
			n->address = 0;
		}
	} else if (n->right->flags & ADDRESS_FLAG) {
		n->flags |= ADDRESS_FLAG;
		n->address = n->right->address;
		n->value = n->right->value;
	} else {
		kltype_t *kltp;

		if (!(t = eval_type(n))) {
			set_eval_error(E_BAD_TYPE);
			error_token = n->tok_ptr;
			return(-1);
		}
		if (t->t_kltp->kl_type != KLT_BASE) {

			kltp = kl_realtype(t->t_kltp, 0);
			if (kltp->kl_type != KLT_BASE) {
				set_eval_error(E_BAD_CAST);
				error_token = n->tok_ptr;
				return(-1);
			}
		}
		n->value = n->right->value;
		n->type = t;
	}
	n->node_type = TYPE_DEF;
	n->operator = 0;
	free_node(n->right);
	n->right = (node_t *)NULL;
	return(0);
}

/*
 * replace_indirection()
 */
static int
replace_indirection(node_t *n, int flags)
{
	kaddr_t addr;
	type_t *t, *tp;

	/* Make sure there is a right child and that it is a TYPE_DEF. 
	 */
	if (!n->right) {
		set_eval_error(E_BAD_TYPE);
		error_token = n->tok_ptr;
		return(-1);
	} else if (n->right->node_type != TYPE_DEF) {
		set_eval_error(E_BAD_TYPE);
		error_token = n->right->tok_ptr;
		return(-1);
	}

	if ((flags & C_WHATIS) && (!(POINTER_FLAG|ADDRESS_FLAG))) {
		set_eval_error(E_BAD_WHATIS);
		error_token = n->tok_ptr;
		return(-1);
	}

	/* Make sure the right node contains a pointer value
	 */
	if (!(n->right->flags & POINTER_FLAG)) {
		set_eval_error(E_BAD_POINTER);
		error_token = n->right->tok_ptr;
		return(-1);
	}
	
	/* Get the pointer to the first type struct and make sure 
	 * it's a pointer.
	 */
	if (!(tp = n->right->type) || (tp->flag != POINTER_FLAG)) {
		set_eval_error(E_BAD_TYPE);
		error_token = n->right->tok_ptr;
		return(-1);
	}

	/* Make sure we have a pointer to a type structure.
	 */
	if (!(n->right->flags & KLTYPE_FLAG)) {
		set_eval_error(E_BAD_TYPE);
		error_token = n->right->tok_ptr;
		return(-1);
	}

	n->node_type = TYPE_DEF;
	n->flags = KLTYPE_FLAG;
	n->operator = 0;

	if (!(t = eval_type(n->right))) {
		set_eval_error(E_BAD_TYPE);
		error_token = n->right->tok_ptr;
		return(-1);
	}

	/* Zero out the type field in the right child so 
	 * it wont accidently be freed when the right child 
	 * is freed (upon success).
	 */
	n->right->type = (type_t*)NULL;

	if (!strcmp(t->t_kltp->kl_name, "char")) {
		n->flags |= STRING_FLAG;
	}
	n->type = tp->t_next;

	/* Free the pointer struct
	 */
	kl_free_block((void *)tp);

	/* Get the pointer address 
	 */
	addr = n->address = n->right->value;
	n->flags |= ADDRESS_FLAG;

	/* If this is a pointer to a pointer, get the next
	 * pointer value.
	 */
	if (n->type->flag == POINTER_FLAG) {

		GET_BLOCK(addr, KL_NBPW, &n->value);
		if (!PTRSZ64) {
			n->value = *((uint32_t*) &n->value);
		}

		/* Set the appropriate node flag values 
		 */
		n->flags |= POINTER_FLAG;
		free_node(n->right);
		n->left = n->right = (node_t *)NULL;
		return(0);
	} 

	/* Zero out the type field in the right child so it doesn't 
	 * accidently get freed up when the right child is freed 
	 * (upon success).
	 */
	n->right->type = (type_t*)NULL;
	free_node(n->right);
	n->left = n->right = (node_t *)NULL;
	return(0);
}

/*
 * replace_unary() 
 * 
 * Convert a unary operator node that contains a pointer to a value
 * with a node containing the numerical result. Free the node that
 * originally contained the value.
 */
static int
replace_unary(node_t *n, int flags)
{
	uint64_t value;

	if (!n->right) {
		set_eval_error(E_MISSING_OPERAND);
		error_token = n->tok_ptr;
		return(-1);
	}
	if (is_unary(n->right->operator)) {
		if (replace_unary(n->right, flags) == -1) {
			return(-1);
		}
	}
	if (n->operator == CAST) {
		return(replace_cast(n, flags));
	} else if (n->operator == INDIRECTION) {
		return(replace_indirection(n, flags));
	} else if (n->operator == ADDRESS) {
		type_t *t;

		if (n->right->node_type == TYPE_DEF) {
			if (!(n->right->flags & ADDRESS_FLAG)) {
				set_eval_error(E_NO_ADDRESS);
				error_token = n->right->tok_ptr;
				return(-1);
			}
			t = n->right->type;
		} else {
			set_eval_error(E_BAD_TYPE);
			error_token = n->right->tok_ptr;
			return(-1);
		}
		n->type = (type_t*)kl_alloc_block(sizeof(type_t), flags);
		n->type->flag = POINTER_FLAG;
		n->type->t_next = t;
		n->node_type = TYPE_DEF;
		n->operator = 0;
		n->value = n->right->address;
		n->flags = POINTER_FLAG;
		if (!(t = eval_type(n))) {
			set_eval_error(E_BAD_TYPE);
			error_token = n->tok_ptr;
			return(-1);
		}
		n->flags |= t->flag;
		n->right->type = 0;
		free_nodes(n->right);
		n->left = n->right = (node_t *)NULL;
		return(0);
	} else if (apply_unary(n, &value) == -1) {
		return(-1);
	}
	free_nodes(n->right);
	n->node_type = NUMBER;
	n->operator = 0;
	n->left = n->right = (node_t *)NULL;
	bcopy(&value, &n->value, sizeof(uint64_t));
	return(0);
}

/*
 * pointer_to_element()
 */
static void
pointer_to_element(node_t *n0, node_t *n1)
{
	int size;
	kltype_t *kltp, *rkltp;
	type_t *tp;

	if (!(tp = n0->type)) {
		set_eval_error(E_BAD_INDEX);
		error_token = n0->tok_ptr;
		return;
	} 
	if (tp->t_next->flag == POINTER_FLAG) {
		size = KL_NBPW;
	} else {
		kltp = tp->t_next->t_kltp;
		if (!(rkltp = kl_realtype(kltp, 0))) {
			set_eval_error(E_BAD_INDEX);
			error_token = n0->tok_ptr;
			return;
		}
		size = rkltp->kl_size;
	}

	/* Get the details on the array element
	 */
	n0->flags |= ADDRESS_FLAG;
	n0->address = n0->value + (n1->value * size);
	n0->type = tp->t_next;
	kl_free_block(tp);
	if (tp->flag == POINTER_FLAG) {
		n0->flags |= POINTER_FLAG;
		GET_BLOCK(n0->address, KL_NBPW, &n0->value);
		if (!PTRSZ64) { 
			n0->value = *((uint32_t*) &n0->value);
		}
	} else {
		n0->flags &= (~POINTER_FLAG);
		n0->value = 0;
	}
}

/*
 * array_to_element()
 */
static void
array_to_element(node_t *n0, node_t *n1)
{
	kltype_t *kltp, *rkltp, *ip, *ep;
	type_t *tp, *troot = (type_t *)NULL;

	if (!(tp = n0->type)) {
		set_eval_error(E_BAD_INDEX);
		error_token = n0->tok_ptr;
		return;
	}

	/* If we are indexing a pointer, then make a call to the
	 * pointer_to_element() and return.
	 */
	if (tp->flag == POINTER_FLAG) {
		return(pointer_to_element(n0, n1));
	}

	if (!(kltp = n0->type->t_kltp)) {
		set_eval_error(E_BAD_INDEX);
		error_token = n0->tok_ptr;
		return;
	}
	if (!(rkltp = kl_realtype(kltp, KLT_ARRAY))) {
		set_eval_error(E_BAD_INDEX);
		error_token = n0->tok_ptr;
		return;
	}
	ip = rkltp->kl_indextype; 
	ep = rkltp->kl_elementtype;
	if (!ip || !ep) {
		set_eval_error(E_BAD_INDEX);
		error_token = n0->tok_ptr;
		return;
	}
	/* Get the details on the array element
	 */
	n0->address = n0->address + (n1->value * ep->kl_size);
	if (ep->kl_flags & POINTER_FLAG) { 
		n0->flags |= POINTER_FLAG;
		GET_BLOCK(n0->address, KL_NBPW, &n0->value);
		if (!PTRSZ64) { 
			n0->value = *((uint32_t*) &n0->value);
		}
	}
	n0->value = 0;
	n0->flags |= ADDRESS_FLAG;
	kltp = ep;
	while (kltp->kl_type == KLT_POINTER) {
		if (troot) {
			tp->t_next = (type_t*)kl_alloc_block(sizeof(type_t), 
					K_TEMP);
			tp = tp->t_next;
		} else {
			tp = (type_t*)kl_alloc_block(sizeof(type_t), K_TEMP);
			troot = tp;
		}
		tp->flag = POINTER_FLAG;
		kltp = kltp->kl_realtype;
	}
	if (troot) {
		tp->t_next = (type_t*)kl_alloc_block(sizeof(type_t), K_TEMP);
		tp = tp->t_next;
		n0->type = troot;
	} else {
		tp = (type_t*)kl_alloc_block(sizeof(type_t), K_TEMP);
		n0->type = tp;
	}
	tp->flag = KLTYPE_FLAG; 
	tp->t_kltp = ep;
}

/*
 * number_to_size()
 */
int
number_to_size(node_t *np)
{
	int unsigned_flag = 0;

	if (np->node_type != NUMBER) {
		set_eval_error(E_BAD_TYPE);
		error_token = np->tok_ptr;
		return(0);
	}
	if (np->flags & UNSIGNED_FLAG) {
		unsigned_flag = 1;
	} 
	if ((np->value >= 0) && (np->value <= 0xffffffff)) {
		return(4);
	} else if (((np->value >> 32) & 0xffffffff) == 0xffffffff) {
		if (unsigned_flag) {
			return(8);
		} else if (KL_NBPW == 4) {
			return(4);
		} else {
			return(8);
		}
	} 
	return(8);
}

/*
 * number_to_type()
 */
kltype_t *
number_to_type(node_t *np)
{
	int unsigned_flag = 0;
	kltype_t *kltp, *rkltp = (kltype_t *)NULL;

	if (np->node_type != NUMBER) {
		set_eval_error(E_BAD_TYPE);
		error_token = np->tok_ptr;
		return((kltype_t *)NULL);
	}
	if (np->flags & UNSIGNED_FLAG) {
		unsigned_flag = 1;
	} 
	if ((np->value >= 0) && (np->value <= 0xffffffff)) {
		if (unsigned_flag) {
			kltp = kl_find_sym("uint32_t", KLT_TYPEDEF);
		} else {
			kltp = kl_find_sym("int32_t", KLT_TYPEDEF);
		}
	} else if (((np->value >> 32) & 0xffffffff) == 0xffffffff) {
		if (unsigned_flag) {
			kltp = kl_find_sym("uint64_t", KLT_TYPEDEF);
		} else if (KL_NBPW == 4) {
			kltp = kl_find_sym("int32_t", KLT_TYPEDEF);
		} else {
			kltp = kl_find_sym("int64_t", KLT_TYPEDEF);
		}
	} else {
		if (unsigned_flag) {
			kltp = kl_find_sym("uint64_t", KLT_TYPEDEF);
		} else {
			kltp = kl_find_sym("int64_t", KLT_TYPEDEF);
		}
	}
	if (kltp) {
		if (!(rkltp = kl_realtype(kltp, 0))) {
			rkltp = kltp;
		}
	} else {
		set_eval_error(E_BAD_TYPE);
		error_token = np->tok_ptr;
	}
	return(rkltp);
}

/*
 * type_to_number() 
 *
 * Convert a base type to a numeric value. Return 1 on successful 
 * conversion, 0 if nothing was done.
 */
static int
type_to_number(node_t *np) 
{
	int byte_size, bit_offset, bit_size, encoding;
	uint64_t value, value1;
	kltype_t *kltp, *rkltp;

	/* Sanity check...
	 */
	if (np->node_type != TYPE_DEF) {
		set_eval_error(E_NOTYPE);
		error_token = np->tok_ptr;
		return(0);
	}
	if (!np->type) {
		set_eval_error(E_NOTYPE);
		error_token = np->tok_ptr;
		return(0);
	}
	if (np->type->flag == POINTER_FLAG) {
		return(0);
	}

	/* Get the real type record and make sure that it is
	 * for a base type.
	 */
	kltp = np->type->t_kltp;
	rkltp = kl_realtype(kltp, 0);
	if (rkltp->kl_type != KLT_BASE) {
		set_eval_error(E_NOTYPE);
		error_token = np->tok_ptr;
		return(0);
	}

	byte_size = rkltp->kl_size;
	bit_offset = rkltp->kl_bit_offset;
	if (!(bit_size = rkltp->kl_bit_size)) {
		bit_size = byte_size * 8;
	}
	encoding = rkltp->kl_encoding;
	if (np->flags & ADDRESS_FLAG) {
		GET_BLOCK(np->address, byte_size, &value1);
	} else {
		value1 = np->value;
	}
	value = kl_get_bit_value(&value1, byte_size, bit_size, bit_offset);
	switch (byte_size) {

		case 1 :
			if (encoding == ENC_UNSIGNED) {
				np->value = (unsigned char)value;
				np->flags |= UNSIGNED_FLAG;
			} else if (encoding == ENC_SIGNED) {
				np->value = (signed char)value;
			} else {
				np->value = (char)value;
			}
			break;

		case 2 :
			if (encoding == ENC_UNSIGNED) {
				np->value = (uint16_t)value;
				np->flags |= UNSIGNED_FLAG;
			} else {
				np->value = (int16_t)value;
			}
			break;

		case 4 :
			if (encoding == ENC_UNSIGNED) {
				np->value = (uint32_t)value;
				np->flags |= UNSIGNED_FLAG;
			} else {
				np->value = (int32_t)value;
			}
			break;

		case 8 :
			if (encoding == ENC_UNSIGNED) {
				np->value = (uint64_t)value;
				np->flags |= UNSIGNED_FLAG;
			} else {
				np->value = (int64_t)value;
			}
			break;

		default :
			set_eval_error(E_BAD_TYPE);
			error_token = np->tok_ptr;
			return(0);
	}
	np->byte_size = byte_size;
	np->node_type = NUMBER;
	return(1);
}

/*
 * eval_type()
 */
static type_t *
eval_type(node_t *n) 
{
	type_t *t;

	t = n->type;
	while (t->flag == POINTER_FLAG) {
		t = t->t_next;

		/* If for some reason, there is no type pointer (this shouldn't 
		 * happen but...), we have to make sure that we don't try to
		 * reference a NULL pointer and get a SEGV. Return an error if 
		 * 't' is NULL.
		 */
		 if (!t) {
			return((type_t*)NULL);
		 }
	}
	if (t->flag == KLTYPE_FLAG) {
		return (t);
	}
	return((type_t*)NULL);
}

/* 
 * expand_variables()
 */
static char *
expand_variables(char *exp, int flags)
{
#ifdef NOTYET
	int len, vcount = 0;
	char vname[64], *s, *e, *v, *newexp;
	variable_t *vp;

	eval_error = 0;

	newexp = (char *)kl_alloc_block(256, flags);
	e = exp;
	v = strchr(e, '$');
	while (v) {
		vcount++;
		vname[0] = 0;
		strncat(newexp, e, (v - e));
		if (s = strpbrk((v + 1), " .\t+-*/()[]|~!$&%^<>?:&=^\"\'")) {
			len = (uaddr_t)s - (uaddr_t)v + 1;
		} else {
			len = strlen(v) + 1;
		}
		strncpy(vname, v, len);
		vname[len -1] = 0;
		vp = find_variable(vtab, vname, V_TYPEDEF|V_STRING);
		if (!vp) {
			return((char *)NULL);
		}

		/* If this is a typedef, then make sure the typestr is between
		 * an open and close parenthesis. Otherwise, just include the 
		 * string.
		 */
		if (vp->v_flags & V_TYPEDEF) {
			strcat(newexp, "(");
			strcat(newexp, vp->v_typestr);
			strcat(newexp, ")");
		} else {
			strcat(newexp, vp->v_exp);
		}

		if (e = s) {
			v = strchr(e, '$');;
		} else {
			v = (char *)NULL;
		}
	}
	if (vcount) {
		if (e) {
			strcat(newexp, e);
		}
	}
	return(newexp);
#endif
	return((char *)NULL);
}

/*
 * eval()
 */
node_t *
eval(char **exp, int flags)
{
	token_t *tok;
	node_t *n, *root;
	char *e, *s;

	eval_error = 0;
	logical_flag = 0;

	/* Make sure there is an expression to evaluate
	 */
	if (!(*exp)) {
		return ((node_t*)NULL);
	}

	/* Expand any variables that are in the expression string. If
	 * a new string is allocated by the expand_variables() function,
	 * we need to make sure the original expression string gets 
	 * freed. In any event, point s at the current expression string 
	 * so that it gets freed up when we are done.
	 */
	if ((e = expand_variables(*exp, 0))) {
		kl_free_block((void *)*exp);
		*exp = e;
	} else if (eval_error) {
		eval_error |= E_BAD_EVAR;
		error_token = *exp;
	} 
	s = *exp;
	tok = get_token_list(s);
	if (eval_error) { 
		return((node_t*)NULL);
	} 
	
	/* Get the node_list and evaluate the expression.
	 */
	node_list = get_node_list(tok, flags);
	if (eval_error) {
		free_nodelist(node_list);
		node_list = (node_t*)NULL;
		free_tokens(tok);
		return((node_t*)NULL);
	}
	if (!(n = do_eval(flags))) {
		if (!eval_error) {
			set_eval_error(E_SYNTAX_ERROR);
			error_token = s + strlen(s) - 1;
		}
		free_nodes(n);
		free_tokens(tok);
		return((node_t*)NULL);
	}

	if (!(root = replace(n, flags))) {
		if (eval_error) {
			free_nodes(n);
			free_tokens(tok);
			return((node_t*)NULL);
		}
		root = n;
	}

	/* Check to see if the the result should 
	 * be interpreted as 'true' or 'false'
	 */
	if (logical_flag && ((root->value == 0) || (root->value == 1))) {
		root->flags |= BOOLIAN_FLAG;
	}
	free_tokens(tok);
	return(root);
}

/*
 * print_number()
 */
void
print_number(node_t *np, FILE *ofp, int flags)
{
	int size;
	uint64_t value;

	if ((size = number_to_size(np)) && (size != sizeof(uint64_t))) {
		value = np->value & (((uint64_t)1 << (uint64_t)(size*8))-1);
	} else {
		value = np->value;
	}
	if (flags & K_HEX) {
		fprintf(ofp, "0x%"FMT64"x", value);
	} else if (flags & K_OCTAL) {
		fprintf(ofp, "0%"FMT64"o", value);
	} else if (flags & K_BINARY) {
		fprintf(ofp, "0b");
		kl_binary_print(value, ofp);
	} else {
		if (np->flags & UNSIGNED_FLAG) {
			fprintf(ofp, "%"FMT64"u", value);
		} else {
			fprintf(ofp, "%"FMT64"d", np->value);
		}
	}
}

/*
 * print_string()
 */
void
print_string(kaddr_t addr, int size, FILE *ofp)
{
	int i;
	char *str;

	if (!size) {
		size = 255;
	}
	str = (char*)kl_alloc_block(size, K_TEMP);
	GET_BLOCK(addr, size, str);
	fprintf(ofp, "\"%s", str);
	for (i = 0; i < size; i++) {
		if (!str[i]) {
			break;
		}
	}
	if (KL_ERROR || (i == size)) {
		fprintf(ofp, "...");
	}
	fprintf(ofp, "\"");
	kl_free_block(str);
}

/*
 * print_eval_results()
 */
int
print_eval_results(node_t *np, FILE *ofp, int flags)
{
	int size;
	kaddr_t addr;

	/* Print the results
	 */
	switch (np->node_type) {

		kltype_t *kltp, *rkltp;

		case NUMBER:
			print_number(np, ofp, flags);
			break;

		case TYPE_DEF: {

			if (np->flags & POINTER_FLAG) {
				fprintf(ofp, "0x%"FMT64"x", np->value);
				if (np->type->t_next->flag == POINTER_FLAG) {
					break;
				}
				kltp = np->type->t_next->t_kltp;
				if (kltp->kl_encoding == ENC_CHAR) {
					fprintf(ofp, " ");
					print_string(np->value, 0, ofp);
				}
				break;
			}
			if (np->flags & KLTYPE_FLAG) {
				void * ptr;

				/* Get the type information. It's possible
				 * that the type is a member. In which case,
				 * the size may only be from this record
				 * (which would be the casse if this is an 
				 * array). We must check the original type
				 * record first, and try the realtype record
				 * if the value is zero.
				 */
				kltp = np->type->t_kltp;

				/* Check to see if this is a typedef. If
				 * it is, then it might be a typedef for
				 * a pointer type. Don't walk to the last
				 * type record.
				 */
				if ((rkltp = kl_realtype(kltp, KLT_TYPEDEF))) {
					while (rkltp->kl_realtype) {
						rkltp = rkltp->kl_realtype;
						if (rkltp->kl_type ==
						    KLT_POINTER) {
							break;
						}
						if((rkltp->kl_name != 0) && !(strcmp(rkltp->kl_name,
							    "void"))) {
							/* we are about to
							 * dereference a void*
							 */
							fprintf(KL_ERRORFP,
			       "Can't dereference a generic pointer.\n");
							return(1);
						}
					}
					if (rkltp->kl_type == KLT_POINTER) {
						fprintf(ofp, "0x%"FMT64"x", 
							np->value);
						break;
					}
				}
				rkltp = kl_realtype(kltp, 0);
				size = rkltp->kl_size;
				if (!size || (size < 0)) {
					size = kltp->kl_size;
				}
				if(size){
					ptr = kl_alloc_block(size, K_TEMP);
				} else {
					ptr = NULL;
				}
				if ((rkltp->kl_type == KLT_BASE) && 
						!(np->flags & ADDRESS_FLAG)) {
					switch (size) {
						case 1:
							*(unsigned char *)ptr =
								np->value;
							break;

						case 2:
							*(unsigned short *)ptr =
								np->value;
							break;

						case 4:
							*(unsigned int *)ptr = 
								np->value;
							break;

						case 8:
							*(unsigned long long *)
								ptr = np->value;
							break;
					}
					kl_print_type(ptr, rkltp, 0, 
						flags|SUPPRESS_NAME, ofp);
					kl_free_block(ptr);
					return(1);
				}

				if(size){
					addr = np->address;
					GET_BLOCK(addr, size, ptr);
					if (KL_ERROR) {
						kl_print_error();
						kl_free_block(ptr);
						return(1);
					}
				}	
				/* Print out the actual type
				 */
				switch (rkltp->kl_type) {
					case KLT_STRUCT:
					case KLT_UNION:
						kl_print_type(ptr, rkltp, 0, 
							flags, ofp);
						break;

					case KLT_ARRAY:
						kl_print_type(ptr, rkltp, 0, 
							flags|
							SUPPRESS_NAME, ofp);
						break;

					default:
						kl_print_type(ptr, rkltp, 0, 
							(flags|
							SUPPRESS_NAME|
							SUPPRESS_NL), ofp);
						break;
				}
				if(ptr)
					kl_free_block(ptr);
			}
			break;
		}

		case VADDR:
			/* If we get here, there was no type info available.
			 * The ADDRESS_FLAG should be set (otherwise we 
			 * would have returned an error). So, print out 
			 * the address.
			 */ 
			fprintf(ofp, "0x%"FMT64"x", np->address);
			break;

		default:
			if (np->node_type == TEXT) {
				kl_print_string(np->name, ofp);
				if (KL_ERROR) {
					kl_print_error();
					return(1);
				}
			} else if (np->node_type == CHARACTER) {
				fprintf(ofp, "\'%c\'", (char)np->value);
			}
			break;
	}
	return(0);
}

/*
 * print_eval_error()
 */
void
print_eval_error(
	char *cmdname, 
	char *s, 
	char *bad_ptr, 
	uint64_t error, 
	int flags)
{
	int i, cmd_len;

	fprintf(KL_ERRORFP, "%s %s\n", cmdname, s);
	cmd_len = strlen(cmdname);

	if (!bad_ptr) {
		for (i = 0; i < (strlen(s) + cmd_len); i++) {
			fprintf(KL_ERRORFP, " ");
		}
	} else {
		for (i = 0; i < (bad_ptr - s + 1 + cmd_len); i++) {
			fprintf(KL_ERRORFP, " ");
		}
	}
	fprintf(KL_ERRORFP, "^ ");
	switch (error) {
		case E_OPEN_PAREN :
			fprintf(KL_ERRORFP, "Too many open parenthesis\n");
			break;

		case E_CLOSE_PAREN :
			fprintf(KL_ERRORFP, "Too many close parenthesis\n");
			break;

		case E_BAD_STRUCTURE :
			fprintf(KL_ERRORFP, "Invalid structure\n");
			break;

		case E_MISSING_STRUCTURE :
			fprintf(KL_ERRORFP, "Missing structure\n");
			break;

		case E_BAD_MEMBER :
			fprintf(KL_ERRORFP, "No such member\n");
			break;

		case E_BAD_OPERATOR :
			fprintf(KL_ERRORFP, "Invalid operator\n");
			break;

		case E_MISSING_OPERAND :
			fprintf(KL_ERRORFP, "Missing operand\n");
			break;

		case E_BAD_OPERAND :
			fprintf(KL_ERRORFP, "Invalid operand\n");
			break;

		case E_BAD_TYPE :
			fprintf(KL_ERRORFP, "Invalid type\n");
			break;

		case E_NOTYPE :
			fprintf(KL_ERRORFP, 
				"Could not find type information\n");
			break;

		case E_BAD_POINTER :
			fprintf(KL_ERRORFP, "Invalid pointer\n");
			break;

		case E_BAD_INDEX :
			fprintf(KL_ERRORFP, "Invalid array index\n");
			break;

		case E_BAD_CHAR :
			fprintf(KL_ERRORFP, "Invalid character value\n");
			break;

		case E_BAD_STRING :
			fprintf(KL_ERRORFP, "Non-termining string\n");
			break;

		case E_END_EXPECTED :
			fprintf(KL_ERRORFP, 
				"Expected end of print statement\n");
			break;

		case E_BAD_EVAR :
			fprintf(KL_ERRORFP, "Invalid eval variable\n");
			break;

		case E_BAD_VALUE :
			fprintf(KL_ERRORFP, "Invalid value\n");
			break;

		case E_NO_VALUE :
			fprintf(KL_ERRORFP, "No value supplied\n");
			break;

		case E_DIVIDE_BY_ZERO :
			fprintf(KL_ERRORFP, "Divide by zero\n");
			break;

		case E_BAD_CAST :
			fprintf(KL_ERRORFP, "Invalid cast\n");
			break;

		case E_NO_ADDRESS :
			fprintf(KL_ERRORFP, "Not an address\n");
			break;

		case E_SINGLE_QUOTE :
			fprintf(KL_ERRORFP, "Missing single quote\n");
			break;

		case E_BAD_WHATIS :
			fprintf(KL_ERRORFP, "Invalid whatis Operation\n");
			break;

		case E_NOT_IMPLEMENTED :
			fprintf(KL_ERRORFP, "Not implemented\n");
			break;

		default :
			fprintf(KL_ERRORFP, "Syntax error\n");
			break;
	}
}

