/*
 * Copyright (c) 2005 - 2006, Nils R. Weller
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * Parsing of, and icode generation for, sub-expressions
 */
#include "expr.h"
#include "subexpr.h"
#include <stdlib.h>
#include <string.h>
#include "token.h"
#include "error.h"

#if 0
#include "misc.h"
#endif

#include "defs.h"
#if 0
#include "decl.h"
#include "scope.h"
#endif
#include "type.h"
#if 0
#include "icode.h"
#include "cc1_main.h"
#include "debug.h"
#include "functions.h"
#include "backend.h"
#include "reg.h"
#include "builtins.h"
#endif

#include "n_libc.h"

struct context {
	struct type		curtype;
	struct decl		*var_lvalue;
	struct vreg		*curitem;
	struct vreg		*load;
	int			is_lvalue;
	int			indir;
};

static struct s_expr *
alloc_s_expr(void) {
	struct s_expr	*ret = n_xmalloc(sizeof *ret);
	static struct s_expr nullop;
	*ret = nullop;
	return ret;
}



static int
ambig_to_unary(struct token *t, int is_prefix) {
	int	op = *(int *)t->data;

	switch (op) {
	case TOK_OP_AMB_PLUS:
		if (is_prefix) op = TOK_OP_UPLUS;
		break;
	case TOK_OP_AMB_MINUS:
		if (is_prefix) op = TOK_OP_UMINUS;
		break;
	case TOK_OP_AMB_MULTI:
		if (is_prefix) op = TOK_OP_DEREF;
		break;
	case TOK_OP_AMB_BAND:
		if (is_prefix) op = TOK_OP_ADDR;
		break;
	case TOK_OP_AMB_INCR:
		if (is_prefix) op = TOK_OP_INCPRE;
		else op = TOK_OP_INCPOST;
		break;
	case TOK_OP_AMB_DECR:
		if (is_prefix) op = TOK_OP_DECPRE;
		else op = TOK_OP_DECPOST;
		break;
	default:
		/* XXX handle labels!  foo:  */
		;
		break;
	}

	if (is_prefix && !IS_UNARY(op)) {
		/*
		 * foo + bar   is ok
		 * / foo       is not
		 */
		errorfl(t, "Invalid use of operator `%s'", t->ascii);
		return -1;
	}
	return op;
}

/*
 * Function that reads what I like to refer to as ``sub-expression''.
 * A sub-expression is just an argument to the binary and ternary
 * operators, and it includes all possible unary/prefix/postfix
 * operators (bitwise/logical negation, pre/post-inc/dec-rement,
 * function call, indirection, etc.)
 * This is typically an identifier or a constant, possibly including
 * operators, but it may also be a parenthesized expression, which
 * in turn consists of one or more sub-expressions.
 *
 * In other words, a ``sub-expression'' is what the standard refers to
 * as ``unary expression''
 *
 * Examples:
 * +foo + *bar--
 * ^^^^   ^^^^^^
 * *(x + 5) - foo? bar: baz
 *   ^   ^
 * ^^^^^^^^   ^^^  ^^^  ^^^
 */
struct s_expr *
get_sub_expr(struct token **tok, int delim, int delim2, int extype) {
	struct token		*t;
	struct token		*meat = NULL;
	struct token		*left;
	struct token		*right;
	struct token		*is_sizeof = NULL;
	struct token		*continue_at = NULL;
	struct token		*endp = NULL;
	struct expr		*ex = NULL;
	struct expr		*is_expr = NULL;
	struct decl		**decv;
	int			is_func_call = 0;
	struct token		*operators[128]; /* XXX */
	struct token		*operators_f[128];
	void			*res = NULL;
	struct icode_instr	*ii;
	struct icode_list	*il;
	struct s_expr		*ret = NULL;
	int			op;
	int			i;
	int			j = 0;


	t = *tok;

#if 0
	il = alloc_icode_list();
	il->head = il->tail = NULL;
#endif

	/*
	 * Read prefix or unary operators, if any, and the
	 * identifier/constant/parenthesized expression
	 * constituting this sub-expression
	 */
	for (t = *tok, i = 0; t != NULL; t = t->next) {
		ii = NULL;
		if (expr_ends(t, delim, delim2)) {
			if (t == *tok) {
				errorfl(t, "Parse error at `%s'", t->ascii);
				return NULL;
			}	
			endp = t;
			goto out;
		} else if (t->type == TOK_PAREN_OPEN) {
			/* Must be parenthesized expression */
			t = t->next;
			ex = parse_expr(&t, TOK_PAREN_CLOSE, 0, extype);
			if (ex == NULL) {
				return NULL;
			}

			is_expr = ex;
			continue_at = t;
			break;
		} else if (t->type == TOK_OPERATOR) {
			/* Must be unary prefix operator */
			if ((op = ambig_to_unary(t, 1)) == -1) { 
				return NULL;
			}
			*(int *)t->data = op;
			operators[i++] = t;
		} else if (t->type == TOK_IDENTIFIER) {
			int	is_defined = 0;

			if (strcmp(t->data, "defined") == 0) {
				is_defined = 1;
				t->type = TOK_DEFINED;
			}

			if (t->next && t->next->type == TOK_PAREN_OPEN) {
				if (is_defined) {
					if (t->next->next == NULL
						|| t->next->next->next
							== NULL) {
						lexerror("Incomplete `defined()' "
							"expression");	
						return NULL;
					} else if (t->next->next->type
						!= TOK_IDENTIFIER) {
						lexerror("Invlaid `defined()' "
							"expression - no "
							"identifier argument");
						return NULL;
					} else if (t->next->next->next->type
						!= TOK_PAREN_CLOSE) {
						lexerror("Invalid `defined()' "
							"expression - no "
							"closing `)'");
						return NULL;
					}
					t->data = t->next->next;
					continue_at = t->next->next->next->next;
				} else {	
					/* Is function call */
					is_func_call = 1; 
				}	
			} else if (is_defined) {
				if (t->next
					&& t->next->type == TOK_IDENTIFIER) {
					t->data = t->next;
					continue_at = t->next->next;
				} else {
					lexerror("Invalid `defined' expression - "
						"not followed by identifier");
					return NULL;
				}
			}	
			meat = t;
			break;
		} else if (IS_CONSTANT(t->type)) {	
			if (IS_FLOATING(t->type)) {
				lexerror("Floating point constant in preprocessor"
					" expression");
				return NULL;
			}	
			meat = t;
			break;
		} else if (t->type == TOK_STRING_LITERAL) {
			errorfl(t, "String constants may not be used in "
				"preprocessor expressions");
			return NULL;
		} else {
			errorfl(t, "Parse error at `%s'(#1)", t->ascii);
			abort();
		}
	}

	if (is_expr) {
		right = continue_at;
		if (next_token(&right) != 0) {
			return NULL;
		}
	} else if (meat->type == TOK_DEFINED) {
		right = continue_at;
	} else if (is_func_call) {
		right = meat->next;
	} else if (!is_sizeof) {
		if (meat != *tok) {
			left = meat->prev;
		} else {
			left = NULL;
		}

		right = meat;

		if (next_token(&right) != 0) {
			return NULL;
		}
	} else {
		right = NULL;
	}

	/*
	 * Compare prefix with postfix operators and
	 * bind them accordingly
	 */
	if (i > 0) {
		left = operators[--i];
	} else {
		left = NULL;
	}

	j = 0;
	for (;;) {
		if (right != NULL) {
			endp = right;
			if (expr_ends(right, delim, delim2)) {
				right = NULL;
			}
		}

		/*
		 * Postfix operators always have higher precedence
		 * than prefix and unary operators
		 */
		res = NULL;
		if (right != NULL) {
			if (right->type == TOK_PAREN_OPEN) {
				/* Must be function-like macro ``call'' */
#if 0
				res = do_func_call(meat, &right, 1); 
				if (res == NULL) {
					return NULL;
				}
				fres = res;
				if (fres->builtin
					&& fres->builtin->type == BUILTIN_EXPECT) {
					if (is_expr) {
						errorfl(right, "Parse error at `%s'",
							right->ascii);
						return NULL;
					}
					is_expr = fres->builtin->args[0];
				} else {
					operators_f[j] = old_right;
					operators_f[j++]->data = res;
				}
#endif
			} else if (right->type == TOK_OPERATOR) {
				/* 
				 * Must be postfix operator or end of
				 * sub-expression
				 */
				op = ambig_to_unary(right, 0);
				if (IS_UNARY(op)) {
					/* XXX handle op */
					operators_f[j++] = right;
					*(int *)right->data = op;
				} else {
					right = NULL;
				}
			} else if (right->type == TOK_ARRAY_OPEN) {
				operators_f[j] = right;
				if (next_token(&right) != 0) {
					return NULL;
				}
				res = parse_expr(&right, TOK_ARRAY_CLOSE, 0, 0);
				if (res == NULL) {
					return NULL;
				}
				operators_f[j++]->data = res;
			} else {
				right = NULL;
			}
			if (right) right = right->next;
		} else if (left != NULL) {
			operators_f[j++] = left;
			if (i > 0) {
				left = operators[--i];
			} else {
				left = NULL;
			}
		} else {
			break;
		}
	}
	operators_f[j++] = NULL;

out:
	*tok = endp;
	if (meat == NULL && is_expr == NULL && is_sizeof == NULL) {
		errorfl(endp, "Parse error at `%s'", endp->ascii);
	}	

	ret = alloc_s_expr();
	memcpy(ret->operators, operators_f, j * sizeof *operators_f);
	ret->is_expr = is_expr;
	ret->meat = meat;
	ret->is_sizeof = is_sizeof;

	return ret;
}



syntax highlighted by Code2HTML, v. 0.9.1