/*
 * Copyright (c) 2004 - 2007, 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.
 *
 * Expression parser
 */
#include "expr.h"
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include "token.h"
#include "error.h"
#include "misc.h"
#include "defs.h"
#include "decl.h"
#include "scope.h"
#include "type.h"
#include "icode.h"
#include "debug.h"
#include "cc1_main.h"
#include "subexpr.h"
#include "functions.h"
#include "analyze.h"
#include "typemap.h"
#include "symlist.h"
#include "backend.h"
#include "libnwcc.h"
#include "reg.h"
#include "n_libc.h"

void
append_expr(struct expr **head, struct expr **tail, struct expr *e) {
	if (*head == NULL) {
		*head = *tail = e;
	} else {
		(*tail)->next = e;
		e->prev = *tail;
		*tail = (*tail)->next;
	}
}

struct expr *
alloc_expr(void) {
	struct expr	*ret = n_xmalloc(sizeof *ret);
	static struct expr	nullexpr;
	*ret = nullexpr;
	return ret;
}


void	recover(struct token **tok, int delim, int delim2);

static int
ambig_to_binary(struct token *t) {
	int	op = *(int *)t->data;
	switch (op) {
	case TOK_OP_AMB_PLUS:
		op = TOK_OP_PLUS;
		break;
	case TOK_OP_AMB_MINUS:
		op = TOK_OP_MINUS;
		break;
	case TOK_OP_AMB_MULTI:
		op = TOK_OP_MULTI;
		break;
	case TOK_OP_AMB_BAND:
		op = TOK_OP_BAND;
		break;
	case TOK_OP_AMB_COND2:
		op = TOK_OP_COND2;
		break;
	}

	if (!IS_BINARY(op) && op != TOK_OP_COND2) {
		errorfl(t, "Invalid operator ``%s'' - "
			"binary or ternary operator expected", t->ascii);
		return -1;
	}
	*(int *)t->data = op; /* XXXXXXXXXXXXXXXXXXXXXXXXXXXX ok? */
	return op;
}


int
expr_ends(struct token *t, int delim, int delim2) {
	int	type;

	if (t->type == TOK_OPERATOR) {
		type = *(int *)t->data;
	} else {
		type = t->type;
	}
	if (type == delim || type == delim2) {
		return 1;
	}
	return 0; 
}


/*
 * Get lowest precedence operator in an expression. Note that the
 * conditional operator requires special handling; In
 * foo? bar: baz;
 * ... ? and : act like parentheses, i.e. lower precedence operators
 * such as the comma operator may occur between them.
 */
static struct operator *
get_lowest_prec(struct expr *ex, struct expr **endp, int want_condop) {
	int		lowest = 100;
	int		cond_expr = 0;
	struct expr	*lptr = NULL;

	*endp = NULL;
	for (; ex != NULL; ex = ex->next) {
		struct operator	*tmp;

		if (ex->op == 0 || ex->used) {
			continue;
		}
		tmp = &operators[LOOKUP_OP2(ex->op)];
		/*
		 * 08/22/07: This flag had to be added because otherwise
		 * the search loop for the second part of the conditional
		 * operator didn't work right in
		 *
		 *   1? 0:  1? 1,1   : 2;
		 */
		if (want_condop
			&& ex->op != TOK_OP_COND
			&& ex->op != TOK_OP_COND2) {
			continue;
		}	
		if (!cond_expr) {
			if (tmp->prec < lowest) {
				lowest = tmp->prec;
				lptr = ex;
			} else if (tmp->prec == lowest) {
				if (tmp->assoc != OP_ASSOC_RIGHT) {
					lptr = ex;
				}
			}
		}	
		if (ex->op == TOK_OP_COND) {
			++cond_expr;
		} else if (ex->op == TOK_OP_COND2) {
			if (cond_expr == 0) {
				if (want_condop) {
					/*
					 * Added... Otherwise stuff breaks
					 * because ? is selected rather than
					 * :
					 */
					lptr = ex;
					break;
				}
			}
			--cond_expr;
		}
	}
	*endp = lptr;
	return lptr? (void *)&operators[LOOKUP_OP2(lptr->op)]: (void *)NULL;
}

static struct expr *
bind_operators(struct expr *ex) {
	struct operator	*op;
	struct expr	*endp;
	struct expr	*start = ex;

	if (ex == NULL) return NULL;
	if ((op = get_lowest_prec(ex, &endp, 0)) == NULL) {
		/* No more operators left */
		if (!ex->used) {
			endp = ex;
			endp->used = 1;
		}
		else endp = NULL;
		return endp;
	} else if (op->value == TOK_OP_COND) {
		struct expr	*endp2;
		struct expr	*ex2 = endp->next;

		/*
		 * Need to get second part of conditional operator. This
		 * requires skipping intermediate conditional operators.
		 *
		 * 08/22/07: This loop is nonsense since we added the
		 * want_condop flag to get_lowest_prec()
		 */
/*		for (;;) {*/
			if (ex2 == NULL 
				|| (op = get_lowest_prec(ex2, &endp2, 1))
				== NULL) {
				errorfl(ex2? ex2->tok: endp->tok,
					"Parse error - missing second part"
					" of conditional operator");
				return NULL;
			}
#if 0
			} else if (op->value == TOK_OP_COND) {
				++cond1;
			} else if (op->value == TOK_OP_COND2) {
				if (cond1 == 0) {
					/* done! */
					break;
				} else {
					--cond1;
				}	
			}	
#endif
	/*		ex2 = endp2->next;*/
/*		} */

		/*
		 * At this point, endp points to ``?'' and endp2 to ``:''. We
		 * bind them such that:
		 * Given x = ``?''
		 * ... x->left = cond-expr
		 * ... x->right = :
		 * ... x->right->left = expr-nonzero
		 * ... x->right->right = expr-zero
		 */
		endp->used = endp2->used = 1;
		ex = endp->next;
		endp->next = NULL;
		endp->left = bind_operators(start);
		endp->right = endp2; 
		ex2 = endp2->next;
		endp2->next = NULL;
		endp->right->left = bind_operators(ex);
		endp->right->right = bind_operators(ex2);
		return endp;
	}	

	endp->used = 1;

	ex = endp->next;
	endp->next = NULL;

	endp->left = bind_operators(start);
	endp->right = bind_operators(ex);
	return endp;
}

static void
append_init_list(
	struct initializer **init, 
	struct initializer **init_tail,
	struct initializer *i) {

	if (i->type == 0) abort();
	if (*init == NULL) {
		*init = *init_tail = i;
	} else {
		(*init_tail)->next = i;
		i->prev = *init_tail;
		*init_tail = (*init_tail)->next;
	}	
}	

struct initializer *
alloc_initializer(void) {
	static struct initializer	nullinit;
	struct initializer	*ret;
	ret = n_xmalloc(sizeof *ret);
	*ret = nullinit;
if (ret == (void *)0x80c46c0) abort();	
	return ret;
}	

static void
conv_init(struct tyval *tv, struct type *toty, struct token *t) {
	struct type		*fromty = tv->type;
	struct type_node	*ltn;
	struct type_node	*rtn;

	if (toty->tlist == NULL) {
		/* Simple basic type conversion */
		if (tv->address != NULL) {
			/* Must be pointer to int cast... Dangerous!!! */
			return;
		}	
		if (toty->code != fromty->code) {
			cross_do_conv(tv, toty->code);
		}
		return;
	}

	if (fromty->tlist == NULL || 
		(toty->code != fromty->code
		&& (toty->code != TY_VOID && fromty->code != TY_VOID))) { 
	/* this bullshit doesn't work */		
		return;

#if 0
#if 0
/* XXX */	 && (!IS_CHAR(toty->code) || !IS_CHAR(fromty->code)))) {
#endif
		if (!tv->is_nullptr_const) {
			errorfl(t, "Initializer of incompatible type");
			return;
		} else {
			/* Explains various mysteries - Don't check tlists */
			return;
		}	
#endif
	}


	/* 
	 * Must be assignment to pointer since this function is only
	 * called for scalar types
	 */

	if (tv->is_nullptr_const) {
		return;
	}
	if (toty->code == TY_VOID
		&& toty->tlist->type == TN_POINTER_TO
		&& toty->tlist->next == NULL) {
		/* Assignment to void pointer */
		return;
	}	
		

	ltn = toty->tlist;
	rtn = fromty->tlist;

	if (rtn && rtn->type == TN_FUNCTION) {
		if (ltn->type == TN_POINTER_TO) {
			/* Probably pointer to function */
			ltn = ltn->next;
		}
	}	

	for (; ltn != NULL && rtn != NULL;
		ltn = ltn->next, rtn = rtn->next) {
		if (ltn->type != rtn->type) {
			if (rtn->type == TN_ARRAY_OF
				&& rtn == fromty->tlist) {
				/* OK - assign array address to ptr */
				;
			} else {
				errorfl(t,
					"Initializer of incompatible type");
				return;
			}	
		}	
	}

	if (ltn != rtn) {
		/* One type list is longer */
		errorfl(t, "Initializer of incompatible type");
		return;
	}
}

struct desig_init_data {
	struct initializer	**init_head;
	struct initializer	**init_tail;
	struct initializer	*cur_init_ptr;
	struct sym_entry	*highest_encountered_member;
	int			highest_encountered_index;
};

static void
replace_cur_init(struct desig_init_data *data, struct initializer *init) {	
	if (data->cur_init_ptr->prev) {
		data->cur_init_ptr->prev->next = init;
	} else {
		*data->init_head = init;
	}
	if (data->cur_init_ptr->next) {
		data->cur_init_ptr->next->prev = init;
	} else {
		*data->init_tail = init;
	}
	init->next = data->cur_init_ptr->next;
	init->prev = data->cur_init_ptr->prev;
	free/*initializer*/(data->cur_init_ptr);
	data->cur_init_ptr = init->next;
}

/*
 * Put an initializer into the designated initializer list. As soon as the
 * first designated initializer is encountered, this function also has to
 * be called for all subsequent initializers, since it may have trashed the
 * initializer order.
 *
 * There are four cases to handle here:
 *
 *    - The initializer is itself designated, and it jumps forward. If that
 * happens we create a null initializer for every skipped member (this element
 * may have to be replaced later if another designated initializer jumps back
 * in the order)
 *
 *    - The initializer is itself designated, and it jumps backward. In that
 * case we have to jump back and OVERWRITE an existing explicit data or null
 * initializer. Also, the current ``initializer pointer'' must be moved to
 * that location
 *
 *    - The initializer is not designated, but overwrites an existing
 * initializer because the current initializer pointer points to one
 *
 *    - The initializer is not designated and just appended at the end of
 * the list
 */
static void 
put_desig_init_struct(struct desig_init_data *data,
	struct sym_entry *desig_se,
	struct sym_entry *prev_se,
	struct sym_entry *whole_struct,
	struct initializer *init,
	struct token *tok,
	int *items_read) {

	int	skipped = 0;

	if (desig_se != NULL
		&& prev_se != NULL
		&& desig_se->dec->offset == prev_se->dec->offset) {
		/*
		 * Designating the initializer which would we done now
		 * anyway - ignore designation.
		 */
		desig_se = NULL;
	}


	if (desig_se == NULL) {
		/* Not designated, thank heaven */
		if (data->cur_init_ptr == NULL) {
			/* At end too! */
			append_init_list(data->init_head,
				data->init_tail, init);
		} else {
			/*
			 * We have to trash an existing initializer
			 */
			if (data->cur_init_ptr->type != INIT_NULL) {
				warningfl(tok, "Member `%s' already has an "
					"initializer",
					prev_se->dec->dtype->name);	
			}
			replace_cur_init(data, init);
		}
	} else {
		/*
		 * Designated! But is it forward or backward?
		 */
		if (prev_se == NULL) {
			/*
			 * Brute-force search for the target
			 */
			struct initializer	*tmpinit;

			tmpinit = *data->init_head;
			for (prev_se = whole_struct;
				prev_se != NULL;
				prev_se = prev_se->next) {
				if (prev_se->dec->offset == desig_se->dec->offset) {
					break;
				}
				if (tmpinit->next == NULL) {
					/*
					 * Fill holes with null initializers
					 */
					struct initializer	*nullb;

					nullb = backend->make_null_block(NULL,
						prev_se->next->dec->dtype,
						NULL, 1);
					nullb->prev = tmpinit;
					tmpinit->next = nullb;
				}
				tmpinit = tmpinit->next;
				++skipped;
			}
			if (tmpinit->prev) {
				tmpinit->prev->next = init;
			} else {
				*data->init_head = init;
			}
			if (tmpinit->next) {
				tmpinit->next->prev = init;
			} else {
				*data->init_tail = init;
			}
			init->prev = tmpinit->prev;
			init->next = tmpinit->next;
			data->cur_init_ptr = tmpinit->next;
			free/*_initializer XXX */(tmpinit);
			*items_read = skipped;
			if (skipped == 0) {
				*data->init_head = init;
			} else if (skipped > *items_read) {
				*data->init_tail = init;
			}
		} else if (desig_se->dec->offset > prev_se->dec->offset) {
			int	highest_offset =
				data->highest_encountered_member?
				(int)data->highest_encountered_member->dec->offset:
				-1;
				
			/*
			 * Forward - create a null initializer for every
			 * skipped member if necessary
			 */
			while (prev_se->dec->offset < desig_se->dec->offset) {
				if ((signed long)prev_se->dec->offset
					> highest_offset) {
					struct initializer	*nullb;

					nullb = backend->make_null_block(NULL,
						prev_se->dec->dtype, NULL, 1);	
					append_init_list(data->init_head,
						data->init_tail, nullb);
				}
				if (data->cur_init_ptr) {
					data->cur_init_ptr =
						data->cur_init_ptr->next;
				}

				++skipped;
				prev_se = prev_se->next;
			}
			if (data->cur_init_ptr) {
				if (data->cur_init_ptr->type != INIT_NULL) {
					warningfl(tok, "Member `%s' already "
					"has an initializer",
					desig_se->dec->dtype->name);	
				}
			
			
				replace_cur_init(data, init);
			} else {	
				append_init_list(data->init_head,
					data->init_tail,
					init);
			}
			*items_read += skipped;
		} else {
			/*
			 * Backward. First search the target initializer.
			 * We can exploit the fact that every member behind
			 * us has one initializer already (null if skipped.)
			 */
			struct initializer	*tmp;

			tmp = *data->init_tail;
			prev_se = prev_se->prev;
			while (prev_se->dec->offset > desig_se->dec->offset) {
				prev_se = prev_se->prev;
				tmp = tmp->prev;
				++skipped;
			}
			*items_read -= skipped;

			if (tmp->prev) {
				tmp->prev->next = init;
			} else {
				*data->init_head = init;
			}	

			if (tmp->next) {
				tmp->next->prev = init;
			} else {
				*data->init_tail = init;
			}
			init->next = tmp->next;
			init->prev = tmp->prev;
			if (desig_se == whole_struct) {
				/* Start */
				*data->init_head = init;
			}

			free/*_initializer XXX */(tmp);
			data->cur_init_ptr = init->next;
		}
	}

	if (desig_se != NULL) {
		if (data->highest_encountered_member == NULL
			|| data->highest_encountered_member->dec->offset
				< desig_se->dec->offset) {
			data->highest_encountered_member = desig_se;
		}
	} else {
		if (data->cur_init_ptr == NULL) {
			/* Appending at end */
			data->highest_encountered_member = prev_se;
		}
	}	
}



static void
put_desig_init_array(struct desig_init_data *data,
	int desig_elem,
	int *items_read,
	struct initializer *init,
	struct type *elem_type,
	struct token *tok) {
	int	skipped = 0;

	if (desig_elem == *items_read) {
		/*
		 * Designating the initializer which would we done now
		 * anyway - ignore designation.
		 */
		desig_elem = -1;
	}

	if (desig_elem == -1) {
		/* Not designated, thank heaven */
		if (data->cur_init_ptr == NULL) {
			/* At end too! */
			append_init_list(data->init_head,
				data->init_tail, init);	
		} else {
			/*
			 * We have to trash an existing initializer
			 */
			if (data->cur_init_ptr->type != INIT_NULL) {
				warningfl(tok, "Element %d already has an "
					"initializer",
					items_read);	
			}

			replace_cur_init(data, init);
		}
	} else {
		/*
		 * Designated! But is it forward or backward?
		 */
		if (desig_elem > *items_read) {
			/*
			 * Forward - create a null initializer for every
			 * skipped member
			 */
			while (*items_read + skipped < desig_elem) {
				if (*items_read + skipped >
					data->highest_encountered_index) {	
					struct initializer	*nullb;

					nullb = backend->make_null_block(NULL,
						elem_type, NULL, 1);	
					append_init_list(data->init_head,
						data->init_tail, nullb);
				}
				if (data->cur_init_ptr) {
					data->cur_init_ptr =
						data->cur_init_ptr->next;
				}

				++skipped;
			}
			if (data->cur_init_ptr) {
				warningfl(tok, "Element %d already has an "
					"initializer", desig_elem);	
				replace_cur_init(data, init);
			} else {	
				append_init_list(data->init_head,
					data->init_tail, init);
			}
			*items_read += skipped;
			data->cur_init_ptr = NULL;
		} else {
			/*
			 * Backward. First search the target initializer.
			 * We can exploit the fact that every member behind
			 * us has one initializer already (null if skipped.)
			 */
			struct initializer	*tmp;

			tmp = *data->init_tail;

			++skipped;
			while (*items_read - skipped > desig_elem) {
				tmp = tmp->prev;
				++skipped;
			}
			*items_read -= skipped;

			if (tmp->prev) {
				tmp->prev->next = init;
			} else {
				*data->init_head = init;
			}	

			if (tmp->next) {
				tmp->next->prev = init;
			} else {
				*data->init_tail = init;
			}
			init->next = tmp->next;
			init->prev = tmp->prev;

			free/*_initializer XXX */(tmp);
			data->cur_init_ptr = init->next;
		}
	}

	if (desig_elem != -1) {
		if (desig_elem > data->highest_encountered_index) {
			data->highest_encountered_index = desig_elem;
		}
	} else {
		if (data->cur_init_ptr == NULL) {
			/* Appending at end */
			data->highest_encountered_index = *items_read;
		}
	}
}

struct initializer *
get_init_expr(struct token **tok, int type, struct type *lvalue, int initial,
	int complit) {

	struct token		*t = *tok;
	struct expr		*ex;
	struct initializer	*ret = NULL;
	struct initializer	*rettail = NULL;
	struct initializer	*init;
	struct sym_entry	*se = NULL;
	struct type		*curtype = NULL;
	struct type		arrtype;
	struct desig_init_data 	init_data;
	struct sym_entry	*prevse = NULL;
	int			items_read = 0;
	int			items_ok = 0;
	int			is_aggregate = 0;
	int			is_array = 0;
	int			is_char_array = 0;
	int			is_braced_string = 0;
	int			warned = 0;
	int			needbrace = 0;
	int			have_desig = 0;

	init_data.init_head = &ret;
	init_data.init_tail = &rettail;
	init_data.cur_init_ptr = NULL;
	init_data.highest_encountered_member = NULL;
	init_data.highest_encountered_index = -1;

	if (lvalue->tlist != NULL
		&& lvalue->tlist->type == TN_ARRAY_OF) {
		is_aggregate = 1;
		is_array = 1;
		items_ok = lvalue->tlist->arrarg_const;
		if (!initial && items_ok == 0) {
			errorfl(t, "Array size for nested array dimension "
					"unspecified");
			return NULL;
		}	
		arrtype = *lvalue;
		curtype = &arrtype;
		arrtype.tlist = arrtype.tlist->next;
		if (IS_CHAR(lvalue->code) && lvalue->tlist->next == NULL) {
			is_char_array = 1;
		}
	} else if (lvalue->code == TY_STRUCT
		&& lvalue->tlist == NULL) {
		is_aggregate = 1;
		se = lvalue->tstruc->scope->slist;
		curtype = se->dec->dtype;
		/* XXX should set items_ok ?!?!? */
		if (initial && t->type != TOK_COMP_OPEN) {
			/*
			 * 09/07/07: This always used EXPR_INIT instead of
			 * type!! (breaks for constant initializers like
			 * compound literals)
			 */
			if (type == EXPR_OPTCONSTINIT) {
				type = EXPR_INIT;
			}	
			ex = parse_expr(&t, TOK_OP_COMMA, TOK_SEMICOLON,
				type, 1);
			if (ex == NULL) {
				return NULL;
			}
			if (ex->const_value && ex->const_value->static_init) {
				init = ex->const_value->static_init;
			} else {	
				init = alloc_initializer();
				init->type = INIT_STRUCTEXPR;
				init->left_type = dup_type(curtype);
				init->data = ex;
			}
			*tok = t;
			return init;
		}	
	} else if (lvalue->code == TY_UNION
		&& lvalue->tlist == NULL) {
		se = lvalue->tstruc->scope->slist;
		curtype = se->dec->dtype;
		items_ok = 1;
		if (initial && t->type != TOK_COMP_OPEN) {
			/* XXX duplicates stuff for TY_STRUCT above */
			if (type == EXPR_OPTCONSTINIT) {
				type = EXPR_INIT;
			}	
			ex = parse_expr(&t, TOK_OP_COMMA, TOK_SEMICOLON,
				type, 1);
			if (ex == NULL) {
				return NULL;
			}
			if (ex->const_value && ex->const_value->static_init) {
				init = ex->const_value->static_init;
			} else {	
				init = alloc_initializer();
				init->left_type = dup_type(curtype);
				init->type = INIT_STRUCTEXPR;
				init->data = ex;
			}
			*tok = t;
			return init;
		}
	} else {
		struct initializer	*was_nullblock = NULL;
		int			was_varinit = 0;

		/* The following are for variable struct/array inits */
		struct token		*starttok;
		int			delim1;
		int			delim2;

		/* Only one item */
		if (t->type == TOK_COMP_OPEN) {
			/*
			 * Compound initializers are also allowed for
			 * non-aggregate types;
			 * int x = { 0 };
			 */
			t = t->next;
			starttok = t;
			ex = parse_expr(&t, TOK_COMP_CLOSE, TOK_OP_COMMA,type,1);
			delim1 = TOK_COMP_CLOSE;
			delim2 = TOK_OP_COMMA;
			if (t->type == TOK_OP_COMMA
				&& t->next != NULL	
				&& t->next->type == TOK_COMP_CLOSE) {
				/* Trailing comma permitted in compound init */
				t = t->next->next;
			} else if (t->type != TOK_COMP_CLOSE) {		
				/*
				 * There may be a trailing comma here. BitchX
				 * uses that
				 */
				if (t->type == TOK_OPERATOR
					&& *(int *)t->data == TOK_OP_COMMA
					&& t->next
					&& t->next->type == TOK_COMP_CLOSE) {
					t = t->next->next;
				} else {	
					errorfl(t, "Invalid initializer");
					return NULL;
				}	
			} else {
				t = t->next;
			}	
		} else {
			starttok = t;
			delim1 = TOK_OP_COMMA;
			delim2 = initial? TOK_SEMICOLON: TOK_COMP_CLOSE;
			ex = parse_expr(&t, TOK_OP_COMMA,
				initial? TOK_SEMICOLON: TOK_COMP_CLOSE, type,1);
		}	
		if (ex == NULL) {
			*tok = t;
			return NULL;
		}

		if (type == EXPR_CONSTINIT || type == EXPR_OPTCONSTINIT) {
			if (ex->const_value != NULL) {
				if (ex->const_value->static_init != NULL) {
					/*
					 * Initialized with value of other static
					 * variable
					 */
					struct initializer	*tmp;
	
					tmp = ex->const_value->static_init;
					if (tmp->type == INIT_EXPR) {
						struct expr	*tmpex = tmp->data;
	
						ex->const_value = tmpex->const_value;
					} else {	
						/* INIT_NULL */
						was_nullblock = tmp->data;
					}
				}	
				/*
				 * Convert constant initializer to destination
				 * type
				 */
				if (!was_nullblock) {
					conv_init(ex->const_value, lvalue, t->prev);
					/*
					 * 08/03/07: To make
					 *  static long nonsense = (long)&addr;
					 * work
					 */
					if (ex->const_value->address != NULL
						&& is_integral_type(lvalue)) {
						;
					} else {	
					ex->const_value->type = ex->type
						= n_xmemdup(lvalue, sizeof *lvalue);
					}
				} else {
					/* XXX */
					unimpl();
				}	
			} else {
				if (type == EXPR_OPTCONSTINIT
					&& !ex->is_const) {
					/*
					 * This is a non-constant expression
					 * used as initializer for a struct
					 * or an array. We have to save the
					 * expression and evaluate it when
					 * the initializer assignment takes
					 * place
					 */
					was_varinit = 1;
					ex = parse_expr(&starttok, delim1,
						delim2, 0,1);
					t = starttok;
					if (ex == NULL) {
						*tok = t;
						return NULL;
					}

					/*
					 * Initialize value to 0 for now
					 */
					was_nullblock = backend->
						make_null_block(NULL, lvalue,
							NULL, 1);	
					was_nullblock->varinit = ex;
				} else {
					return NULL;
				}	
			}
		}

		if (was_nullblock) {
			ret = init = was_nullblock;
		} else {
			ret = init = alloc_initializer();
			init->type = INIT_EXPR;
			init->data = ex;
		}
		init->left_type = dup_type(lvalue);

		*tok = t;
		return init;
	}

	if (t->type == TOK_COMP_OPEN && is_char_array) {
		if (t->next && t->next->type == TOK_STRING_LITERAL) {
			/*
			 * This must be a braces-enclosed string constant;
			 *    char buf[] = { "hello" };
			 * The GNU people love using unnecessary braces
			 * (and parentheses) like this
			 */
			t = t->next;
			is_braced_string = 1;
		}
	}

	/*
	 * 08/22/07: Null initializers for strings were completely ignored!
	 * E.g. in
	 *
	 *     static char buf[10] = "hehe";
	 *
	 * ... only 5 bytes would be allocated for the buffer, since there
	 * were only 5 bytes of initialized data! Same thing with string
	 * initializers for nested array initializers. So now we resize the
	 * string and add any necessary null bytes
	 */
	if (t->type == TOK_STRING_LITERAL) {
		struct ty_string	*ts = t->data;
		size_t			newlen;

		if (lvalue->tlist != NULL
			&& lvalue->tlist->type == TN_ARRAY_OF
			&& (newlen = lvalue->tlist->arrarg_const) > ts->size) {
			ts->str = n_xrealloc(ts->str, newlen);
			memset(ts->str + ts->size - 1, 0, newlen - ts->size);
			ts->size = newlen;
			ts->ty->tlist->arrarg_const = newlen;
		}	
	}

	if (t->type != TOK_COMP_OPEN) {
		if (t->type == TOK_STRING_LITERAL
			&& is_array) {
			struct token	*tmp = t;

			if (lvalue->tlist->next != NULL
				|| !IS_CHAR(lvalue->code)) {
				errorfl(t, "Invalid initializer");
				return NULL;
			} else if (lvalue->sign == TOK_KEY_UNSIGNED) {
#if 0
				warningfl(t,
		"Assigning string constant to array of `unsigned char'");
#endif
			}

			/*
			 * 09/01/07: The extra } check was needed because
			 * othrwise
			 *
			 *    char foo[1][2] = { "hello" };
			 * breaks, since "hello" is an un-braced array
			 * initializer (the braces belong to the outer
			 * array), and we ended up looking for a , or ;
			 *
			 * XXX MAybe this still isn't fully correct
			 */
			if (is_braced_string
				|| (t->next && t->next->type == TOK_COMP_CLOSE)) {
				/*
				 * Read up to closing brace
				 */
				ex = parse_expr(&t, TOK_COMP_CLOSE, 0, type, 1);
			} else {	
				/*
				 * Read up to comma or semicolon
				 */
				ex = parse_expr(&t, TOK_OP_COMMA, TOK_SEMICOLON, type,
					1);
			}
			if (ex == NULL) {
				return NULL;
			}	
			if (t != tmp->next) {
				tmp = tmp->next? tmp->next: t;
				errorfl(tmp, "Parse error at `%s'",
					tmp->ascii);
				return NULL;
			}
			if (is_braced_string && t != NULL) {
				/* Skip brace */
				t = t->next;
			}	
			init = alloc_initializer();
			init->left_type = dup_type(lvalue);
			init->data = ex;
			init->type = INIT_EXPR;
			*tok = t;

			if (lvalue->tlist->arrarg->const_value != NULL) {
				(void) backend->get_sizeof_type(lvalue, NULL);
			}	
			if (lvalue->tlist->arrarg_const == 0) {
				lvalue->tlist->arrarg_const =
					strlen(t->prev->ascii) + 1;
			}	
			return init;
		} else if (initial) {
			/* Initial array initializer requires braces */
			errorfl(t, "Parse error at `%s'", t->ascii);
			return NULL;
		} else if (is_aggregate) {
			warningfl(t,
		"Nested aggregate initializer not surrounded by braces");
			needbrace = 0;
		}
	} else {
		needbrace = 1;
		if (next_token(&t) != 0) {
			return NULL;
		}
	}


	do {
		struct token		*starttok = t;
		struct sym_entry	*desig_se = NULL;
		struct sym_entry	*prev_se = se;
		int			desig_elem = -1;
		
		if ((t->type == TOK_OPERATOR
			&& *(int *)t->data == TOK_OP_STRUMEMB)
			|| (t->type == TOK_IDENTIFIER
				&& t->next
				&& t->next->type == TOK_OPERATOR
				&& *(int *)t->next->data == TOK_OP_AMB_COND2)) {
			int	is_c99_style = 0;

			/*
			 * Designated initializer -
			 *
			 *   .membername = expr 
			 *
			 * ... as per C99 or
			 * 
			 *   membername: expr
			 *
			 * ... as per GNU C (deprecated)
			 */
			have_desig = 1;
			if (is_array) {
				/*
				 * Only allowed for structs! (Note that we
				 * can't check ``se'' because it may be
				 * NULL here;
				 *
				 *   struct foo { int x, y; }
				 *     f = { .y = 0, .x = 0 };
				 *                   ^ NULL here
				 */
				errorfl(t, "Invalid designated initializer");
				return NULL;
			}
			if (t->type != TOK_IDENTIFIER) {
				is_c99_style = 1;
				/* Skip . */
				if (next_token(&t) != 0) {
					return NULL;
				}
				if (t->type != TOK_IDENTIFIER) {
					errorfl(t, "Syntax error - "
						"identifier expected");
					return NULL;
				}
			} else {
				warningfl(t, "GNU C designated initializiers "
					"are deprecated, use the C99 way "
					"instead (`.member = expr' instead "
					"of `member: expr')");
			}	
			desig_se = lookup_symbol_se(
					lvalue->tstruc->scope, t->data, 0);
			if (desig_se == NULL) {
				errorfl(t, "Unknown member `%s'", t->data);
				return NULL;
			}
			if (next_token(&t) != 0) {
				return NULL;
			}
			if (is_c99_style) {
				if (t->type != TOK_OPERATOR
					|| *(int *)t->data != TOK_OP_ASSIGN) {
					errorfl(t, "Syntax error at `%s' - "
						"`=' expected", t->next->ascii);
					return NULL;
				}
			}

			/* Skip : (GNU C) or = (C99) */
			if (next_token(&t) != 0) {
				return NULL;
			}	
			se = desig_se;
			curtype = se->dec->dtype;
		} else if (t->type == TOK_ARRAY_OPEN) {
			struct expr	*ex;
			size_t		elem;

			have_desig = 1;
			if (next_token(&t) != 0) {
				return NULL;
			}
			ex = parse_expr(&t, TOK_ARRAY_CLOSE, 0, EXPR_CONST, 1);
			if (ex == NULL) {
				return NULL;
			}
			elem = cross_to_host_size_t(ex->const_value);
			if ((ssize_t)elem < 0) {
				errorfl(t, "Negative and very large designated "
					"array elements are not allowed");	
				return NULL;
			} else if (elem > items_ok && items_ok != 0) {
				errorfl(t, "Array index %lu out of bounds",
					(unsigned long)elem);
				return NULL;
			} else if (elem > INT_MAX) {
				errorfl(t, "Array index %lu too large",
					(unsigned long)elem);
				return NULL;
			}
			if (next_token(&t) != 0
				|| t->type != TOK_OPERATOR
				|| *(int *)t->data != TOK_OP_ASSIGN) {
				if (t != NULL) {
					errorfl(t, "Syntax error at `%s' - ",
						"`=' expected",
						t->ascii);
				}
				return NULL;
			}
			if (next_token(&t) != 0) {
				return NULL;
			}	
			desig_elem = (int)elem;
		}

		init = get_init_expr(&t, type, curtype, 0, 0);

		if (init == NULL) {
			return NULL;
		}	

		if (is_basic_agg_type(curtype)) {
			struct initializer	*init2;

			init2 = alloc_initializer();
			init2->left_type = dup_type(curtype);
			init2->type = INIT_NESTED;
			init2->data = init;
			init = init2;
			/*append_init_list(&ret, &rettail, init2);*/
		} else {	
			/*append_init_list(&ret, &rettail, init);*/
		}

		if (is_array) {
/*			append_init_list(&ret, &rettail, init);*/
			put_desig_init_array(&init_data, desig_elem,
					&items_read,
					init,
					curtype,
					NULL);
		} else {	
			put_desig_init_struct(&init_data, desig_se,
					prev_se,
					lvalue->tstruc->scope->slist,
					init,
					NULL, &items_read);	
		}

		++items_read;
		if (items_ok != 0) {
			if (items_read > items_ok && !warned) {
				if (!is_aggregate) {
					errorfl(starttok,
		"Invalid aggregate initializer");
				} else {
					errorfl(starttok,
		"Initializer for aggregate type too big");
				}
				warned = 1;
			} else if (!needbrace && items_read == items_ok) {
				/* We're done */
				t = t->prev;
				break;
			}
		}
		if (se != NULL) {
			prevse = se;
			se = se->next;
			if (se != NULL) {
				/* XXX error msg if se = NULL maybe? */
				curtype = se->dec->dtype;
			}	
		}	

		/*
		 * 08/05/07: The code below was previously BEFORE the se 
		 * update above! Thus if there was a trailing comma, the
		 * make_null_block() call at the bottom would wrongly
		 * create a null initializer for this structure member
		 * even though it already has an initializer
		 *
		 * This broke some vim option structs
		 */
		if (t->type == TOK_OPERATOR
			&& *(int *)t->data == TOK_OP_COMMA	
			&& t->next != NULL	
			&& t->next->type == TOK_COMP_CLOSE) {
			/* Trailing comma permitted in compound init. */
			t = t->next;
			break;
		}	
		if (t->type == TOK_SEMICOLON) break; /* XXXXXXXX */
	} while (!expr_ends(t, TOK_COMP_CLOSE, 0) && (t = t->next) != NULL);

	if (t->type != TOK_SEMICOLON) /* XXXXXXXXXXX */
	t = t->next;
	*tok = t;

	if (is_array && items_ok == 0) {
		lvalue->tlist->arrarg_const = items_ok = items_read;
	}
	
	if (initial
		&& t->type != TOK_SEMICOLON
		&& (t->type != TOK_OPERATOR
		|| *(int *)t->data != TOK_OP_COMMA)) {
		if (!complit) {
			errorfl(t, "Parse error at `%s'- expected semicolon or comma",
				t->ascii);	
			return NULL;
		}
	}

	/*
   	 * Remaining fields are initialized to 0. This is very straightforward
	 * for normal initializers - just initialize the rest of the struct
	 * or array - and requires brute-force for designated initializers
	 */
	if (have_desig) {
		init = NULL;
		if (is_array) {
			if (items_ok != 0) {
				int	remaining =
					items_ok -
					(init_data.highest_encountered_index+1);

				if (remaining < 0) {
					puts("BUG: ??????");
					abort();
				} else if (remaining > 0) {
					init = backend->
						make_null_block(NULL, curtype,
							NULL, remaining);
				}
			}
		} else {
			struct initializer	*tmp;

			se = lvalue->tstruc->scope->slist;
			tmp = ret;
			for (; se != NULL; se = se->next) {
				if (tmp->next == NULL) {
					break;
				}
				tmp = tmp->next;
			}
			se = se->next;
			if (se != NULL) {
				init = backend->make_null_block(se, NULL, lvalue, 0);
			}	
		}
		if (init != NULL) {
			append_init_list(&ret, &rettail, init);
		}	
	} else {	
		if (items_read < items_ok || se != NULL) {	
			/* Remaining fields are initialized to 0 */
			if (se != NULL) {
				/* Structure */
				init = backend->
					make_null_block(se, NULL, lvalue, 0);
			} else {
				/* Array */
				int remaining = items_ok - items_read;
				init = backend->
					make_null_block(NULL, curtype,
							NULL, remaining);
			}	
			if (init != NULL) {
				append_init_list(&ret, &rettail, init);
			}	
		}	
	}
	return ret;
}

/*
 * Parses an expression and returns a pointer to the parse tree.
 *
 * 09/07/07: Finally the ``nesting'' variable is gone! Instead the caller
 * passes an ``initial'' flag, which states whether this is the initial
 * call to get a particular expression.
 *
 * Only if ``initial'' is set, will constant expression results be
 * evaluated before returning
 */
struct expr *
parse_expr(struct token **tok, int delim, int delim2, int type, int initial) {
	struct token	*t;
	struct token	*tokstart = *tok;
	struct expr	*ret = NULL;
	struct expr	*rettail = NULL;
	struct expr	*ex = NULL;
	struct s_expr	*s_ex;
	struct s_expr	*last_s_ex = NULL;

#ifdef NO_EXPR
	/* Don't use expression parser */
	recover(tok, delim, delim2);
	if (*tok == NULL) {
		lexerror("Unterminated expression");
		exit(1);
	}
	return NULL;
#endif

	t = *tok;

	if (t->type == TOK_SEMICOLON) {
		/* Empty expression */
		if ((delim != TOK_SEMICOLON && delim2 != TOK_SEMICOLON)
			|| type == EXPR_INIT
			|| type == EXPR_CONSTINIT
			|| type == EXPR_OPTCONSTINIT
			|| type == EXPR_OPTCONSTARRAYSIZE) {
			errorfl(t, "Parse error at `%s'", t->ascii);
			return NULL;
		}
		ret = alloc_expr();
		ret->is_const = 1;
		return ret;
	} else if (t->type == TOK_ARRAY_CLOSE
			&& (delim == TOK_ARRAY_CLOSE
				|| delim2 == TOK_ARRAY_CLOSE)) {
		ret = alloc_expr();
		ret->is_const = 1;
		return ret;
	} else if (delim == TOK_ARRAY_CLOSE
		&& type == EXPR_CONST_FUNCARRAYPARAM) {
		if ((t->type == TOK_KEY_RESTRICT
			|| t->type == TOK_KEY_CONST /* XXX honor this */
			|| t->type == TOK_KEY_VOLATILE)
			&& t->next != NULL
			&& t->next->type == TOK_ARRAY_CLOSE) {
			/*
			 * This is a construct of the form
			 *
			 *   char buf[restrict]
			 *
			 * which is equivalent to
			 *
			 *   char *restrict buf
			 */
			*tok = t->next;
			ret = alloc_expr();
			ret->is_const = 1;
			return ret;
		}
		type = EXPR_CONST;
	} else if (t->type == TOK_COMP_OPEN) {
		struct scope	*scope;

		/* GNU C statement-as-expression */

		if (ansiflag) {
			warningfl(t,
				"Statement-as-expression (`({ ... })') isn't "
				"available in ISO C (don't use -ansi!)");
		}

		scope = new_scope(SCOPE_CODE);

		if (analyze(&t) != 0) {
			close_scope();
			return NULL;
		}
		close_scope();
		scope->code->type = ST_EXPRSTMT; 

		*tok = t->next;
		ret = alloc_expr();
		ret->stmt_as_expr = /*curscope->next*/scope;
		return ret;
	}



	/*
	 * Strategy: An expression is a number of sub-expressions
	 * connected through binary and ternary operators, so we
	 * just always need to read a sub-expression, a connecting
	 * operator - if any - and then the next sub-expression.
	 */
	while ((s_ex = get_sub_expr(&t, delim, delim2, type)) != NULL) {
		int	op;

		last_s_ex = s_ex;

		ex = alloc_expr();
		ex->op = 0;
		ex->data = s_ex;

		append_expr(&ret, &rettail, ex);

		if (expr_ends(t, delim, delim2)) {
			if ((ex->tok = s_ex->meat) == NULL) {
				if ((ex->tok = s_ex->is_sizeof) == NULL) {
					/* Must be parenthesized expr */
					ex->tok = s_ex->is_expr->tok;
				}
			}	
			break;
		} else if (t->type != TOK_OPERATOR) {
			errorfl(t, "Parse error at `%s'(#2)", t->ascii);
			ex = NULL;
			break;
		}
		/* Must be binary or ternary operator */
		ex = alloc_expr();
		ex->data = NULL;
		op = *(int *)t->data;
		ex->tok = t;
		if (op != TOK_OP_COND) {
			op = ambig_to_binary(t);
		}
		if (type == EXPR_CONST || type == EXPR_CONSTINIT) {
			int		err = 0;
			char	*is_what =
				type == EXPR_CONST? "expression": "initializer";

			if (op == TOK_OP_COMMA) {
				errorfl(t,
					"The comma operator is not allowed "
					"in constant %ss", is_what);
				err = 1;
			} else if (IS_ASSIGN_OP(op)) {
				errorfl(t,
					"Assignment operators are not allowed "
					"in constant %ss", is_what);
				err = 1;
			}
			if (err) {
				free(ex);
				ex = NULL;
				break;
			}
		}
		ex->op = op;

		append_expr(&ret, &rettail, ex);

		if (next_token(&t) != 0) {
			return NULL;
		}
		if (expr_ends(t, delim, delim2)) {
			errorfl(ex->tok, "Syntax error at `%s'",
				ex->tok->ascii);
			break;
		}
		if (op == TOK_OP_COND) { 
			/*
			 * 08/18/07: Allow GNU C's empty first conditional
			 * operator operand
			 */
			if (t->type == TOK_OPERATOR
				&& *(int *)t->data == TOK_OP_AMB_COND2) {
				warningfl(t, "Conditionals with omitted "
					"operands are not ISO C (GNU C only)");
				if (next_token(&t) != 0) {
					return NULL;
				}
				if (expr_ends(t, delim, delim2)) {
					errorfl(t, "Syntax error at `%s'",
						t->ascii);
					break;
				}
				ex = alloc_expr();
				ex->tok = t;
				ex->op = TOK_OP_COND2;
				append_expr(&ret, &rettail, ex);
			}
		}
	}

	*tok = t;

	if (ex == NULL || !expr_ends(t, delim, delim2)) {
		/* Try to recover from parse errors */
		if (initial) {
			recover(&tokstart, delim, delim2);
			*tok = tokstart;
		}
		return NULL;
	}

	debug_print_expr(ret);
	fflush(stdout);

	if ((ret = bind_operators(ret)) == NULL) {
		puts("panic: cannot bind operators");
		exit(1); /* XXX */
	}
	debug_print_tree(ret);
	ret->extype = type;

	if (initial
		&& (type == EXPR_CONST
		|| type == EXPR_CONSTINIT
		|| type == EXPR_OPTCONSTINIT
		|| type == EXPR_OPTCONSTARRAYSIZE)) {
		int	not_constant;

		if (eval_const_expr(ret, type, &not_constant) != 0) {
			if ((type == EXPR_OPTCONSTINIT 
				|| type == EXPR_OPTCONSTARRAYSIZE)
				&& not_constant) {
				ret->is_const = 0;
			} else {
				return NULL;
			}
		} else {
			ret->is_const = 1;
		}
	}

	return ret;
}




void
recover(struct token **tok, int delim, int delim2) {
	struct token	*t;
	int		parens = 0;
	int		brackets = 0;
	int		braces = 0;

	if (*tok == NULL) return; 

	if (delim == TOK_PAREN_CLOSE || delim2 == TOK_PAREN_CLOSE) {
		++parens;
	}
	if (delim == TOK_ARRAY_CLOSE || delim2 == TOK_ARRAY_CLOSE) {
		++brackets;
	}
	if (delim == TOK_COMP_CLOSE || delim2 == TOK_COMP_CLOSE) {
		++braces;
	}

	for (t = *tok; t != NULL; t = t->next) {
		int	ty = -1; /* 0 compared even with unused delim :( */

#ifdef DEBUG2
printf(" lol %s\n", t->ascii);
#endif
		if (t->type == TOK_OPERATOR) {
			ty = *(int *)t->data;
		} else if (t->type == TOK_PAREN_OPEN) {
			++parens;
			continue;
		} else if (t->type == TOK_PAREN_CLOSE) {
			/*
			 * The below was --parens < 0, but <=
			 * seems more permissive for parse 
			 * errors - so use that!
			 */
			if (--parens <= 0
				&& (delim == TOK_PAREN_CLOSE
					|| delim2 == TOK_PAREN_CLOSE)) {
				*tok = t;
				return;
			}
			continue;
		} else if (t->type == TOK_ARRAY_OPEN) {
			++brackets;
			continue;
		} else if (t->type == TOK_ARRAY_CLOSE) {
			if (--brackets <= 0
				&& (delim == TOK_ARRAY_CLOSE
					|| delim2 == TOK_ARRAY_CLOSE)) {
				*tok = t;
				return;
			}
			continue;
		} else if (t->type == TOK_COMP_OPEN) {
			++braces;
			continue;
		} else if (t->type == TOK_COMP_CLOSE) {
			if (--braces <= 0
				&& (delim == TOK_COMP_CLOSE
					|| delim2 == TOK_COMP_CLOSE)) {
				*tok = t;
				return;
			}
			continue;
		} else {
			ty = t->type;
		}
		if (ty == delim || ty == delim2) {
			if (ty == TOK_OP_COMMA) {
				/*
				 * We must take into account that someone
				 * could write
				 * int foo = bar(x, y, z);
				 * ... in which case we do not want to exit
				 * after x!
				 */
				if (parens != 0) {
					continue;
				}
			}
			*tok = t;
			return; 
		}
	}
	*tok = NULL;
}



syntax highlighted by Code2HTML, v. 0.9.1