/*
 * 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.
 *
 * Parsing of declarations
 */
#include "decl.h"
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include "error.h"
#include "defs.h"
#include "token.h"
#include "type.h"
#include "misc.h"
#include "scope.h"
#include "symlist.h"
#include "expr.h"
#include "icode.h" /* expr_to_icode() for evaluating typeof() argument */
#include "decl_adv.h"
#include "cc1_main.h"
#include "attribute.h"
#include "inlineasm.h"
#include "debug.h"
#include "backend.h"
#include "n_libc.h"

struct decl *
alloc_decl(void) {
	struct decl			*ret;
	static struct decl	nulldecl;
	ret = n_xmalloc(sizeof *ret);
	*ret = nulldecl;
	return ret;
}


void
append_decl(struct decl **head, struct decl **tail, struct decl *d) {
	if (*head == NULL) {
		*head = *tail = d;
	} else {
		(*tail)->next = d;
		*tail = (*tail)->next;
	}
}

static struct token *find_cast_start(struct token *pos, int mode);

/*
 * Searches for next occurance of identifier in list pointed to by pos. Returns
 * a pointer to the identifier on success, else a null pointer.
 * Used to determine identifier in declarations.
 */
static struct token *
find_ident(struct token *pos, int mode, struct type *ty) {
	struct token	*ret = NULL;
	struct token	*start;
	struct token	*prevtok = NULL;

	/* Characters that might occur in first part of declarator */
	static int		okay[] = {
		/* Pointer */
		TOK_OP_AMB_MULTI,
		TOK_PAREN_OPEN,

		/* Pointer qualifiers, as in ``char *restrict p;'' */
		TOK_KEY_CONST,
		TOK_KEY_RESTRICT, 
		TOK_KEY_VOLATILE,
		0
	};

	/* Might be needed if this is a function argument */
	start = pos;

#ifdef DEBUG2
	puts("Searching for identifier in declaration");
#endif
	for (; pos != NULL; pos = pos->next) {
		prevtok = pos;
#ifdef DEBUG2
		printf("%s ", pos->ascii);
#endif
		if (pos->type == TOK_IDENTIFIER) {
			/* Found! */
			ret = pos;
			break;
		} else if (pos->type == TOK_KEY_ATTRIBUTE) {	
			struct attrib	*attr;
			struct token	*start = pos;

			/*
			 * We have to parse and UNLINK any attributes
			 * here because of nonsense stuff like;
			 *
			 *     void *__attribute__((pure)) foo();
			 *
			 * Yes this is legal, you can put attributes
			 * anywhere, and regex of course uses this.
			 * The parser will get confused later if we
			 * don't remove this here
			 */
			attr = get_attribute(ty, &pos);
			if (pos) {
				pos = pos->prev;
			}	
			if (start->prev != NULL) {
				start->prev->next = pos;
			}
			if (pos != NULL) {
				pos->prev = start->prev;
			}
			continue;
		} else {
			/*
			 * Let's see whether the character is legal
			 * (catch syntax errors)
			 */
			int	i;
			int	type;

			if (pos->type == TOK_OPERATOR) {
				type = *(int *)pos->data;
			} else {
				type = pos->type;
			}
			for (i = 0; okay[i] != 0; ++i) {
				if (type == okay[i]) {
					/* Found */
					break;
				}
			}
			if (okay[i] == 0) {
				/*
				 * Character is illegal, but might be okay if
				 * we are parsing a function argument
				 */
				if (mode == DECL_FUNCARG) {
					/*
					 * Alright, perhaps this must be parsed
					 * cast-like, since function arguments
					 * in prototypes might be mere type 
					 * names, e.g. ``void f(int[]);''
					 * Caller must check for defintions -
					 * ``void f(int[]) { puts("hello"); }''
					 * is illegal!
					 */
					ret = find_cast_start(start,
						TOK_OP_COMMA);
					return ret;
				}

				errorfl(pos, "Syntax error at %s", pos->ascii);
				return NULL;
			}
		}
	}

	if (ret == NULL) {
		errorfl(prevtok, "Unexpected end of file");
	}

	return ret;
}


/*
 * Finds starting point to parse a cast, starting from position pos.
 * Returns a pointer to the starting point on success, else a null
 * pointer.
 * Since a cast MUST be a scalar type (that is, an integral, floating
 * point or pointer type), the token we are searching for is an
 * asterisk. This is because this routine might only be called if the
 * base type (such as ``int'' or ``unsigned long'') does NOT constitute
 * the entire cast. The effect is that we can only get a scalar out of
 * this declarator if it really is a pointer
 *
 * XXX C99 compound literals also permit stuff like array-casts!
 *
 * char *p = (char[4]){ 'a', 'b', 'c', 'd' };
 */
static struct token *
find_cast_start(struct token *pos, int mode) {
	struct token	*prevtok = NULL;
	struct token	*asterisk = NULL;

#ifdef DEBUG
	printf("Searching for start of cast ... ");
#endif

	for (; pos != NULL; pos = pos->next) {
		int	type;
		prevtok = pos;
#ifdef DEBUG2
		printf("%s ", pos->ascii); 
#endif
		if (pos->type == TOK_OPERATOR) {
			type = *(int *)pos->data;
		} else {
			type = pos->type;
		}

		if (type == TOK_PAREN_OPEN) {
			/* This is OK */
			if (mode == TOK_OP_COMMA) {
				/*
				 * Might be funtion pointer of form ``int()''
				 */
				asterisk = pos;
			}
			continue;
		} else if (type == TOK_PAREN_CLOSE) {
			if (asterisk != NULL) {
				/*
				 * The asterisk was found at the last
				 * iteration!
				 */
#ifdef DEBUG2
				printf(" - found!\n");
#endif
				return asterisk;
			} else {
				errorfl(pos, "Cast specifies non-scalar type");
				return NULL;
			}
		} else if (type == TOK_OP_AMB_MULTI) {
			/* 
			 * Might be beginning, but does not have to -
			 * Parentheses must be used to judge for
			 * pathological cases like a pointer to an
			 * array of pointers to an array, i.e.
			 *
			 * (char (*(*)[20])[40])foo;
			 *
			 * ...where in this example we are interested
			 * in the second asterisk. The strategy is to
			 * preserve a pointer to this token and check
			 * it at the next occurance of a closing
			 * parentheses
			 */
			asterisk = pos;
		} else if (type == TOK_OP_COMMA && mode == TOK_OP_COMMA) {
			/* function argument */
			return asterisk;
		} else if (type == TOK_PAREN_CLOSE && mode == TOK_OP_COMMA) {
			/* final function argument */
			return asterisk;
		} else {
			if (asterisk != NULL) {
				/* Qualifier in pointer cast */
				if (IS_QUALIFIER(type)) {
					/* Just ignore */
					continue;
				}
			}

			/*
			 * C99 permits array casts for compound literals -
			 * char *p = (char[]){ 'a', 'b', 'c', 0 };
			 * char (*p)[2] = (char[][2]) {
			 *		{ 'a', 'b' },
			 *		{ 'c', 'd' }
			 * };
			 */
			if (type == TOK_ARRAY_OPEN) {
#ifdef DEBUG2
				printf(" - found!\n");
#endif
				/*
				 * If ``*'' has been reached, we must return
				 * that
				 */
				if (asterisk) {
					return asterisk;
				} else {
					return pos;
				}
			}

			/* 
			 * This cast is definitely illegal
			 */
			errorfl(pos, "Syntax error at %s", pos->ascii);
			return NULL;
		}
	}
	errorfl(pos, "Unexpected end of file");
	return NULL;
}
					
			


/*
 * Parses the declarations base type, including storage class,
 * signedness specifiers and const/volatile/etc qualifiers. The result
 * is a pointer to a dynamically allocated ``struct type'' structure
 * on success, else a null pointer
 * On success, *curtok is also updated to point to the current token
 */

#define MAKE_TYPE(ty) \
	(ty == DECL_CAST ? "cast" : "declaration")

static struct type *
get_base_type(struct token **curtok, int type) {
	struct type		*ty;
	struct type		*tytmp;
	struct token		*tok;
	struct token		*prevtok = NULL;
#ifdef DEBUG2
	char			decascii[1024] = { 0 };
#endif
	char			*tag;
	char			*curfile;
	int			repetitions = 0;
	int			curtype;
	int			errors = 0;
	struct ty_struct	*is_struct_def = NULL;

	ty = alloc_type();
	ty->line = (*curtok)->line;
	ty->file = (*curtok)->file;

	if (!IS_KEYWORD((*curtok)->type)
		&& ((*curtok)->type != TOK_IDENTIFIER
			|| lookup_typedef(curscope, (*curtok)->data) == NULL)) {
		/* No base type specified - implicit int! ... as in main() {} */
		ty->code = TY_INT;
		ty->sign = TOK_KEY_SIGNED;
		ty->implicit = 1;
		return ty;
	}

	curfile = (*curtok)->file;
	
		

	/* Read base type and storage class/signess specifiers */
	for (tok = *curtok; tok != NULL; tok = tok->next) {
		int	was_attribute = 0;

		prevtok = tok;

		while (tok->type == TOK_KEY_ATTRIBUTE) {
			/* XXX */
			struct attrib	*a;
			struct token	*start = tok;

			was_attribute = 1;
			if ((a = get_attribute(ty, &tok)) == NULL) {
				continue;
			}

			if (is_struct_def) {
				stupid_append_attr(&is_struct_def->attrib,
					dup_attr_list(a));
			}

			/*
			 * Unlink attribute stuff so the declarator
			 * parsing can ignore it
			 * XXXXXXXXXXXXXXX WARNING ATTENTION DANGER
			 * This means we can't correctly retry this
			 * operation! Is that OK?
			 */
			if (start->prev != NULL) {
				start->prev->next = tok;
			}
			if (tok != NULL) {
				tok->prev = start->prev;
			}
		}
		if (was_attribute) {
			if (tok->prev) {
				tok = tok->prev;
			} else {
				/* XXX :-( */
				static struct token	dummy;
				dummy.next = tok;
				tok = &dummy;
			}
			continue;
		}	
		if (!IS_KEYWORD(tok->type) && tok->type != TOK_IDENTIFIER) {
			/* End of base type found */
			break;
		}

		switch (tok->type) {
		case TOK_KEY_UNSIGNED:
		case TOK_KEY_SIGNED:
			if (ty->sign) {
				/* Sign already specified */
				if (ty->sign != tok->type) {
					errorfl(tok,
				"Type cannot be both signed and unsigned");
					free(ty);
					return NULL;
				} else {
					warningfl(tok,
				"Duplicate use of signedness specifier");
				}
			}
			ty->sign = tok->type;
			break;
		case TOK_KEY_VOLATILE:
			if (ty->is_volatile) {
				warningfl(tok,
				"Duplicate use of `volatile' qualifier");
			}
			ty->is_volatile = 1;
			break;
		case TOK_KEY_INLINE:
			if (ty->is_inline) {
				warningfl(tok,
					"Duplicate use of `inline' qualifier");
			}
			ty->is_inline = 1;
			break;
		case TOK_KEY_RESTRICT:
			if (ty->is_restrict) {
				warningfl(tok,
				"Duplicate use of `restrict' qualifier");
			}
			ty->is_restrict = 1;
			break;
		case TOK_KEY_CONST:
			if (ty->is_const) {
				warningfl(tok,
					"Duplicate use of const specifier");
			}
			ty->is_const = 1;
			break;
		case TOK_KEY_TYPEDEF:
			/* 
			 * typedefs are storage class specifiers for convenient
			 * syntax 
			 */
		case TOK_KEY_STATIC:
		case TOK_KEY_EXTERN:
		case TOK_KEY_AUTO:
		case TOK_KEY_REGISTER:
			/*
			 * For now the register keyword does not have an
			 * effect 
			 */
			if (ty->storage != 0) {
				if (ty->storage != tok->type) {
					errorfl(tok,
					"Multiple storage classes specified");
					free(ty);
					return NULL;
				}
			}

			ty->storage = tok->type;
			break;
		case TOK_KEY_STRUCT:
		case TOK_KEY_UNION:
		case TOK_KEY_ENUM:
			/* Sanity checking */
			if (ty->code != 0) {
				errorfl(tok,
					"Two or more types specified in %s",
					MAKE_TYPE(type));
				free(ty);
				return NULL;
			}

			if (prevtok->type == TOK_KEY_STRUCT) {
				curtype = ty->code = TY_STRUCT;
			} else if (prevtok->type == TOK_KEY_UNION) {
				curtype = ty->code = TY_UNION;
			} else {
				curtype = ty->code = TY_ENUM;
			}

			/* Proceed to tag or { */
			if (next_token(&tok) != 0) {
				free(ty);
				return NULL;
			}

			/* Check whether structure has tag */
			if (tok->type == TOK_COMP_OPEN) {
				/*
				 * Nope, is anonymous, as in struct
				 * { int x; } bar;
				 */
				tag = NULL; /* tag = NULL indicates anon */
			} else if (tok->type != TOK_IDENTIFIER) {
				errorfl(tok, "Syntax error at %s", tok->ascii);
				free(ty);
				return NULL;
			} else {
				tag = tok->data;

				/* Is this actually a definition? */
				if (tok->next == NULL) {
					errorfl(tok, "Unexpected end of file");
					free(ty);
					return NULL;
				}
				if (tok->next->type == TOK_COMP_OPEN) {
					/*
					 * Yes, definition! Prepare for
					 * parsing 
					 */
					tok = tok->next;
				}
			}

			/* 
			 * If this is a structure definition, parse it.
			 * This used to be done by the caller of this
			 * function, but we must also pick up
			 * definitions ``along the way'' with all the
			 * other base type information so we can handle
			 * pathological cases like
			 * ``struct foo { ... } typedef bar;''
			 *              ^ can't return at this point
			 *                already!
			 */
			if (curtype == TY_STRUCT || curtype == TY_UNION) {
				if (tok->type == TOK_COMP_OPEN) {
					/* This has got to be a definition */
					struct ty_struct	*ts;
					struct ty_struct	*inc = NULL;

					if (next_token(&tok) != 0) {
						free(ty);
						return NULL;
					}

					/*
				 	 * save name of structure in list
					 * of incomplete structures, else
				 	 * struct foo { struct foo *next;} 
					 * does not work!
					 */
					if (tag != NULL) {
						inc = lookup_struct(curscope,
							tag, 1);
						if (inc != NULL) {
							if (!inc->incomplete) {
								inc = NULL;
							}	
						}		
								
						if (inc == NULL) {
							inc = alloc_ty_struct();
							inc->tag = tag;
							inc->incomplete = 0;
							inc->is_union =
								curtype == 
								TY_UNION;
							inc->attrib =
								ty->attributes;
							store_def_scope(
								curscope,
								inc, NULL, tok);
							inc->incomplete = 1;
						}	
					}

					if ((ts = parse_struct(&tok, tag,
						curtype)) == NULL) {
						free(ty);
						return NULL;
					}
					ts->is_union =
						curtype == TY_UNION;
					
					if (inc != NULL) {
						ts->parentscope = curscope;
						complete_type(inc, ts);
					} else {
						ts->attrib= ty->attributes;
						store_def_scope(curscope, ts,
							NULL, tok);
					}	

					if (type == DECL_FUNCARG
						|| type == DECL_FUNCARG_KR) {
						warningfl(tok,
"Structure type of argument has prototype or block scope");
					}
					ty->tstruc = inc? inc: ts;
					is_struct_def = ty->tstruc;
				} else if (tok->next->type != TOK_SEMICOLON) {
					/*
					 * This declaration uses either
					 * an existing structure type or
					 * introduces a new incomplete
					 * declaration
					 */
					struct ty_struct	*ts;

					if ((ty->tstruc
						= lookup_struct(curscope, tag,
						SCOPE_NESTED)) == NULL) {
						/*
						 * This is a new incomplete type
						 */
						ts = alloc_ty_struct();
						ts->tag = tag;
						ts->incomplete = 1;
						ts->attrib = 
						dup_attr_list(ty->attributes);
						store_def_scope(curscope, ts,
							NULL, tok);
						if (type == DECL_FUNCARG
							|| type == DECL_FUNCARG_KR) {
							warningfl(tok,
"Structure type of argument has prototype or block scope");
						}	
						ty->tstruc = ts;
					} else if ((ty->code == TY_UNION)
						!= ty->tstruc->is_union) {
						errorfl(tok,
							"`%s' is not %s type",
							tag,
							ty->code == TY_UNION?
							"union": "structure");
						return NULL;
					}
				} else {
					/*
					 * This is a forward-declaration as in
					 * ``struct foo;''
					 */
					struct ty_struct	*ts;
					
					if (type == DECL_STRUCT
						|| type == DECL_FUNCARG) {
						errorfl(tok,
						"Invalid forward declaration");
						free(ty);
						return NULL;
					}
					ts = alloc_ty_struct();
					ts->tag = tag;
					ts->incomplete = 1;
					ts->is_union =
						curtype == TY_UNION;
					if (ty->storage || ty->sign) {
						warningfl(tok,
				"Useless specifier in forward declaration");
					}

					ts->attrib = ty->attributes;
					store_def_scope(curscope, ts,
						NULL, tok);
					free(ty);
					return NULL;
				}
			} else {
				/* TY_ENUM */
				if (tok->type == TOK_COMP_OPEN) {
					/* This has got to be a definition */
					struct ty_enum	*te;
					if (next_token(&tok) != 0) {
						free(ty);
						return NULL;
					}

					if ((te = parse_enum(&tok)) == NULL) {
						free(ty);
						return NULL;
					}
					te->tag = tag;
					store_def_scope(curscope,
						NULL, te, tok);
					ty->tenum = te;
				} else if (tok->next->type != TOK_SEMICOLON) {
					/*
					 * This declaration uses an existing
					 * enum type
					 */
					if ((ty->tenum =
						lookup_enum(curscope, tag, 1))
						== NULL) {
						/* Handle error */
						errorfl(tok, "Undefined enum"
							" `%s'", tag);
						free(ty);
						return NULL;
					}
				} else {
					errorfl(tok, "Forward declarations of "
						"enumerations not allowed");
					free(ty);
					return NULL;
				}
			}

			break;

		case TOK_KEY_INT:
			if (ty->code == TY_LONG ||
				ty->code == TY_SHORT ||
				ty->code == TY_LLONG) {
				if (repetitions > 0
					&& (ty->code != TY_LLONG
						|| repetitions > 1)) {
					errorfl(tok, "Two or more types "
						"specified in %s",
						MAKE_TYPE(type));
					free(ty);
					return NULL;
				}
				/* ``long int'' or ``short int''- ignore*/
				++repetitions;
				continue;
			} else if (ty->code != 0) {
				errorfl(tok,
					"Two or more types specified in %s",
						MAKE_TYPE(type));
				free(ty);
				return NULL;
			}
			ty->code = TY_INT;
			break;

		case TOK_KEY_CHAR:
			if (ty->code != 0) {
				errorfl(tok,
					"Two or more types specified in %s",
						MAKE_TYPE(type));
			}
			ty->code = TY_CHAR;
			break;

		case TOK_KEY_SHORT:
			if (ty->code == TY_INT) {
				/* ``short int'' */
				ty->code = TY_SHORT;
				++repetitions;
			} else if (ty->code != 0) {
				errorfl(tok,
					"Two or more types specified in %s",
						MAKE_TYPE(type));
				free(ty);
				return NULL;
			}
			ty->code = TY_SHORT;
			break;

		case TOK_KEY_LONG:
			if (ty->code == TY_INT) {
				/* ``long int'' */
				ty->code = TY_LONG;
				++repetitions;
			} else if (ty->code == TY_LONG) {
				/* C99 ``long long'' */
				ty->code = TY_LLONG;
				--repetitions;
			} else if (ty->code == TY_LLONG) {
				errorfl(tok,
					"Two or more types specified in %s",
						MAKE_TYPE(type));
				free(ty);
				return NULL;
			} else if (ty->code == TY_DOUBLE) {
				/* ``long double'' */
				ty->code = TY_LDOUBLE;
			} else if (ty->code != 0) {
				errorfl(tok,
					"Two or more types specified in %s",
						MAKE_TYPE(type));
				free(ty);
				return NULL;
			} else {
				ty->code = TY_LONG;
				continue;
			}

			if (repetitions > 0) {
				errorfl(tok,
					"Two or more types specified in %s",
						MAKE_TYPE(type));
				free(ty);
				return NULL;
			}
			++repetitions;

			break;
		case TOK_KEY_FLOAT:
			if (ty->code != 0) {
				errorfl(tok,
					"Two or more types specified in %s",
						MAKE_TYPE(type));
				free(ty);
				return NULL;
			}
			ty->code = TY_FLOAT;
			break;
		case TOK_KEY_DOUBLE:
			if (ty->code == TY_LONG) {
				ty->code = TY_LDOUBLE;
			} else if (ty->code != 0) {
				errorfl(tok,
					"Two or more types specified in %s",
						MAKE_TYPE(type));
				free(ty);
				return NULL;
			} else {
				ty->code = TY_DOUBLE;
			}
			if (repetitions > 1) {
				errorfl(tok,
					"Two or more types specified in %s",
						MAKE_TYPE(type));
				free(ty);
				return NULL;
			}
			break;
		case TOK_KEY_BOOL:
			if (ty->code != 0) {
				errorfl(tok,
					"Two or more types specified in %s",
						MAKE_TYPE(type));
				free(ty);
				return NULL;
			}
			ty->code = TY_BOOL;
			break;
		case TOK_KEY_VOID:
			if (ty->code != 0) {
				errorfl(tok,
					"Two or more types specified in %s",
						MAKE_TYPE(type));
			}
			ty->code = TY_VOID;
			break;
		case TOK_IDENTIFIER:
			/*
			 * Typedef? Only check if no type specified yet,
			 * typedef int x; int x; should work
			 */
			if (ty->code != 0
				|| (tytmp = lookup_typedef(curscope, tok->data))
				== NULL) {
				/* Must be identifier in declaration */
				goto exit_swtch;
			} else {
				/*
				 * This does not have to be typedef,
				 * see C99 6.7.7, 8
				 */
				if (ty->sign) {
					goto exit_swtch;
				}
			}

			/* Okay, so this is an instance of a typedef'ed type */
			/*
			 * XXX Argh - adhoc copy, source of nasty bugs,
			 * why not use copy_type() ... 
			 */
			if (ty->code) {
				errorfl(tok,
					"Two or more types specified in %s",
						MAKE_TYPE(type));
				++errors;
			}
			ty->code = tytmp->code;
			ty->incomplete = tytmp->incomplete;
			ty->attributes = dup_attr_list(tytmp->attributes);
			ty->fastattr = tytmp->fastattr;
			
			/*
			 * XXX typedef int foo; unsigned foo f; should
			 * yield a diagnostic
			 */
			if (tytmp->sign && ty->sign) {
				if (tytmp->sign != ty->sign) {
					errorfl(tok, "Type cannot be both "
						"signed and unsigned");
					++errors;
				} else {
					warningfl(tok,
						"Duplicate use of signedness "
						"specifier");
				}
			} else if (ty->sign == 0) {
				if (ty->code == TY_CHAR) {
					/*
					 * Let's not trash the distinction
					 * of ``char'' vs ``signed/unsigned
					 * char'' here
					 */
					;
				} else {
					ty->sign = tytmp->sign;
				}
			}
			if (tytmp->is_const && ty->is_const) { 
				warningfl(tok,
					"Duplicate use of const specifier");
			}
			ty->is_const |= tytmp->is_const; 
			if (tytmp->is_volatile && ty->is_const) { 
				warningfl(tok,
					"Duplicate use of volatile specifier");
			}
			ty->is_volatile |= tytmp->is_volatile;
			if (tytmp->is_restrict && ty->is_volatile) {
				warningfl(tok,
					"Duplicate use of restrict specifier");
			}
			ty->is_restrict |= tytmp->is_restrict;
			if (errors) {
				free(ty);
				return NULL;
			}
			ty->tstruc = tytmp->tstruc;
			ty->tenum = tytmp->tenum;
			ty->tbit = tytmp->tbit;
			ty->tlist = tytmp->tlist;
			ty->is_def = tytmp->is_def;
			ty->is_func = tytmp->is_func;
			ty->is_vla = tytmp->is_vla;
			ty->tlist_tail = tytmp->tlist_tail;
			break;
		case TOK_KEY_TYPEOF: {	
			/*
			 * Is GNU C typeof() declaration;
			 * int *x;
			 * typeof(x) y;
			 * ... y now has type ``int *''
			 *
			 * Like with alignof and sizeof, typename and sub-expression
			 * operands are allowed, but unlike those typeof in GNU C
			 * always seems to require parentheses, so we do so too
			 */
			struct expr	*ex;
			struct vreg	*vr;
			struct decl	**dec;

			if (next_token(&tok) != 0) {
				return NULL;
			}
			if (tok->type != TOK_PAREN_OPEN) {
				errorfl(tok, "Syntax error - Opening parentheses "
					"expected, got %s", tok->ascii);
				return NULL;
			}
	
			if (next_token(&tok) != 0) {
				return NULL;
			}


			if (IS_TYPE(tok)) {
				/* typeof(typename) */
				dec = parse_decl(&tok, DECL_CAST);
				if (dec == NULL) {
					return NULL;
				}
				ty = dec[0]->dtype;
			} else {
				/* typeof(expr) */
				if ((ex = parse_expr(&tok, TOK_PAREN_CLOSE, 0, 0, 1))
					== NULL) {
					return NULL;
				}
				if ((vr = expr_to_icode(ex, NULL, NULL, 0, 0))
					== NULL) {
					return NULL;
				}	

				ty = vr->type;
			}	

#if 0
			if (next_token(&tok) != 0) {
				return NULL;
			}
#endif
			break;
		}	
		case TOK_KEY_ASM:
			/* Assembler name given for variable */
			goto exit_swtch;
			break;
		default:
			printf("BUG: get_base_type: %s\n", tok->ascii);
			exit(EXIT_FAILURE);
		}
#ifdef DEBUG2
		strncat(decascii, prevtok->ascii,
			sizeof decascii - strlen(prevtok->ascii));
#endif
	}
	
exit_swtch:		

#ifdef DEBUG2
	printf("Base type is - %s\n", decascii);
#endif
	
	/*
	 * Do some sanity checking on correctness of type, use implicit
	 * int where necessary
	 */
	if ((ty->storage || ty->sign) && ty->code == 0) {
		if (ty->sign == 0) {
			/*
			 * Don't warn for ``unsigned foo'', but for
			 * ``register bar''
			 */
			warningfl(*curtok,
				"Implicit int declarations are illegal in C99");
		}
		ty->code = TY_INT;
	}

	/* XXX MIPS/PowerPC compatibiliy kludge */
	if ((backend->arch == ARCH_MIPS
		|| backend->arch == ARCH_POWER)
		&& ty->code == TY_LDOUBLE) {
#if 0
		/* the warning seems too verbose ... */
		static int	warned;

		if (!warned) {
			warningfl(prevtok,
				"This program uses `long double', which is "
				"unsupported on MIPS. I'll pretend it used "
				"`double' instead, which may cause the program to "
				"behave badly");
			warned = 1;
		}
#endif
		ty->code = TY_DOUBLE;
	}

#if 0
	if (standard == C89) {
		if ((IS_LLONG(ty->code) || ty->code == TY_BOOL)
			&& ty->tlist == NULL) {
			warningfl(*curtok, "`%s' isn't available in C89 (don't "
				"compile with -ansi or -std=c89)",
				ty->code == TY_BOOL? "_Bool": "long long");
		}
	}
#endif

	/* Sign specified? */
	if (ty->code == TY_STRUCT ||
		ty->code == TY_ENUM ||
		ty->code == TY_UNION ||
		ty->code == TY_VOID ||
		ty->code == TY_FLOAT ||
		ty->code == TY_DOUBLE ||
		ty->code == TY_LDOUBLE) {
		if (ty->sign != 0) {
			errorfl(*curtok,
				"Invalid use of signedness specifier");
			free(ty);
			return NULL;
		}
	} else {
		/* 
		 * Integral types except ``char'' and ``_Bool'' are signed by
		 * default 
		 */
		if (ty->sign == 0) {
			if (ty->code == TY_CHAR) {
				/*
				 * XXX temporary botch to avoid passing flags
				 * to libc
				 */
				if (CHAR_MIN != SCHAR_MIN) {
					ty->sign = TOK_KEY_UNSIGNED;
				} else {
					ty->sign = TOK_KEY_SIGNED;
				}
			} else if (ty->code == TY_BOOL) {
				ty->sign = TOK_KEY_UNSIGNED;
			} else {
				ty->sign = TOK_KEY_SIGNED; 
			}
		} else if (ty->sign == TOK_KEY_UNSIGNED) {
			/* Unsigned */
			if (ty->code == TY_CHAR) {
				ty->code = TY_UCHAR;
			} else if (ty->code == TY_SHORT) {
				ty->code = TY_USHORT;
			} else if (ty->code == TY_INT) {
				ty->code = TY_UINT;
			} else if (ty->code == TY_LONG) {
				ty->code = TY_ULONG;
			} else if (ty->code == TY_LLONG) {
				ty->code = TY_ULLONG;
			}	
		} else {
			/* Explicitly signed */
			if (ty->code == TY_CHAR) {
				ty->code = TY_SCHAR;
			}
		}	
	}

	if (tok == NULL) {
		errorfl(prevtok, "Unexpected end of file");
		free(ty);
		return NULL;
	}

	/*
	 * Make sure no storage class specifiers are used in structure
	 * members
	 */
	if (type == DECL_STRUCT) {
		if (ty->storage /*&& ty->storage != TOK_KEY_TYPEDEF*/) {
			errorfl(*curtok,
				"Invalid use of storage class specifier");
			return NULL;
		}
	} else if (type == DECL_FUNCARG
		|| type == DECL_FUNCARG_KR) {
		if (ty->storage && ty->storage != TOK_KEY_REGISTER) {
			errorfl(*curtok,
				"Invalid use of storage class specifier");
			return NULL;
		}	
	}	

	*curtok = tok;
	return ty;
}


/*
 * Helper for parse_declarator() - Must be called with tok pointing to a
 * qualifier token. Returns 0 if this is a qualified pointer (and updates
 * tok to point to (*tok)->prev, else 1
 */
static int
try_qualified(struct token **tok) {
	struct token	*t;

	t = (*tok)->prev;
	if (t->type == TOK_OPERATOR) {
		if (*(int *)t->data == TOK_OP_AMB_MULTI) {
			/* Is qualified pointer indeed! */
			*tok = t;
			return 0;
		}
	}

	/* Not a pointer - syntax error */
	errorfl(*tok, "Syntax error at %s", (*tok)->ascii);
	return 1;
}


static void
merge_typedef_tlist(
	struct type *base,
	struct type_node *tlist,
	struct type_node *tlist_tail) {

	/*
	 * 08/01/07: OUCH the copy was missing!!! Thus
	 *
	 *    typedef struct __bogus {...} va_list[1];
	 *
	 *    void foo(va_list va) { .... }
	 *    void bar() { va_list va; ....}
	 *
	 * ... would make the bar() instance of va a pointer
	 * instead of an array because the typelist was trashed
	 * at foo() (since ``T[]'' becomes ``T *'' as a function
	 * parameter.)
	 */
	tlist_tail = copy_tlist(&tlist, tlist);
	if (base->tlist == NULL) {
		base->tlist = tlist;
		base->tlist_tail = tlist_tail;
	} else if (tlist != NULL) {
		base->tlist_tail->next = tlist;
		tlist->prev = base->tlist_tail;
		base->tlist_tail = tlist_tail;
	}
}	

/*
 * Does actual parsing of declarator in declaration, i.e. in
 * char (*p)[20] = foobar;
 * ... the part (*p)[20] would be parsed here.
 * Used by parse_decl(), which also grabs the optional initializer
 */
static struct type *
parse_declarator(struct token **curtok, struct type *base, int type) {
	struct token		*t;
	struct token		*start;
	struct token		*left;
	struct token		*right;
	struct token		*arstart;
	struct type		*ret; 
	struct ty_func		*tfunc = NULL;
	struct expr		*ex;
	struct type_node	*base_tlist;
	struct type_node	*base_tlist_tail;
	char			*name = NULL;
	int			parens;
	int			newrparen = 1;
	int			newlparen = 1;
	int			left_type;
	int			right_was_func;
	int			array_const;
	int			ac_for_all_dims = 1;
	int			ac_node;
	int			is_vla = 0;

	/*
	 * 07/21/07: This is a kludge to allow this construct:
	 *
	 *    void foo(char buf[restrict]);
	 *
	 * ... which has the same effect as ``char *restrict buf''.
	 * We introduce a new expression type -
	 * EXPR_CONST_FUNCARRAYPARAM - because parse_expr() can
	 * most conveniently handle this
	 */
	if (type == DECL_FUNCARG || type == DECL_FUNCARG_KR) {
		array_const = EXPR_CONST_FUNCARRAYPARAM;
		/* XXX hmmmm not really true, huh? */
		ac_for_all_dims = 0;
#if 0
	} else if (type == -3333) {	
#endif
	} else if (type == DECL_VARINIT) {
		array_const = EXPR_CONST;
		if (curscope != &global_scope) {
			/*
			 * 07/22/07: XXX (It would probably better to do this
			 * in analyze() and use DECL_CONSTINIT there if
			 * required!)
			 *
			 * Allow automatic variable arrays 
			 */
			if (base->storage != TOK_KEY_EXTERN
				&& base->storage != TOK_KEY_STATIC
				&& base->storage != TOK_KEY_REGISTER) {
				array_const = EXPR_OPTCONSTARRAYSIZE;
			}
		}
	} else {
		array_const = EXPR_CONST;
	}



	/*
	 * When using an instance of a typedef'ed type, the base type may
	 * already have a tlist;
	 * typedef char *p;
	 * p array[5];
	 * ... and that tlist stuff should be appended after the declarator's
	 * tlist such that the above reads ``array of 5 pointers to char''.
	 */
	base_tlist = base->tlist;
	base_tlist_tail = base->tlist_tail;
	
	/*
	 * Of course, *curtok is the actual start, but when parsing it is
	 * easier to exclude the previous element, because *curtok must be
	 * included in parsing
	 */
	start = (*curtok)->prev;
	if (start == NULL) {
		/*
		 * Pathological case encountered: First token in file is part
		 * of an implicit declaration, as in  ``main() {}''. We set
		 * start to *curtok for now - the later code will detect this
		 * curiosity and set the ``left'' pointer to NULL
		 */
		start = *curtok;
	}

	/* Allocate declaration structure to be returned */
	ret = alloc_type();

	*ret = *base;
	ret->tlist = NULL;
	ret->tlist_tail = NULL;
	ret->line = (*curtok)->line;

	if (type == DECL_FUNCARG || type == DECL_FUNCARG_KR) {
		/*
		 * Before we try to get the identifier, make sure this is an
		 * extended type, i.e. pointer, array, function-pointer or a
		 * combination thereof, because find_ident() would reject e.g.
		 * a plain ``int''
		 */
		int	tmp;
		
		if ((*curtok)->type == TOK_OPERATOR) {
			tmp = *(int *)(*curtok)->data;
		} else {
			tmp = (*curtok)->type;
		}
		if (tmp != TOK_OP_COMMA && tmp != TOK_PAREN_CLOSE) {
			if ((t = find_ident(*curtok, type, ret)) == NULL) {
				free(ret);
				return NULL;
			}
		} else {
			/* We are done */
			merge_typedef_tlist(ret, base_tlist, base_tlist_tail);
			return ret;
		}
	}

	if (type == DECL_CAST ||
		((type == DECL_FUNCARG || type == DECL_FUNCARG_KR)
			&& t->type != TOK_IDENTIFIER)) {
		/* Find beginning of cast or function argument */

		if (type == DECL_CAST && (*curtok)->type == TOK_PAREN_CLOSE) {
			/* 
			 * The cast ends here, so we are done parsing the cast's
			 * ``declarator'' already! 
			 */
			merge_typedef_tlist(ret, base_tlist, base_tlist_tail);
			return ret;
		}
		if (type == DECL_CAST) {
			if ((t = find_cast_start(*curtok, TOK_PAREN_CLOSE))
				== NULL) {
				free(ret);
				return NULL;
			}
		}
		left = t;

		if (left->type == TOK_OPERATOR) {
			left_type = *(int *)left->data;
		} else {
			left_type = left->type;
		}	

		/* 
		 * Since this function might only be called if this is a cast
		 * or function argument of extended type, there are only two
		 * possiblities:
		 * 1) the left side is a ``*''. In this case, the right must
		 * either be a closing parentheses/comma or array designator
		 * 2) the left side is a ``[]''. In this case, the right must
		 * be a closing parentheses/comma
		 */

		if (left_type == TOK_OP_AMB_MULTI) { 
			if (next_token(&t) != 0) {
				free(ret);
				return NULL;
			}
			if (t->type == TOK_PAREN_CLOSE) {
				right = t;
			} else if (t->type == TOK_ARRAY_OPEN) {
				right = t;
			} else if (t->type == TOK_KEY_CONST
				|| t->type == TOK_KEY_RESTRICT
				|| t->type == TOK_KEY_VOLATILE) {
				right = t; /* This is changed by code below */
			} else if (	t->type != TOK_SEMICOLON &&
					!(t->type == TOK_OPERATOR
					&& *(int *)t->data == TOK_OP_COMMA)) {
				errorfl(t, "Syntax error at %s", t->ascii);
				free(ret);
				return NULL;
			} else {
				right = t;
			}
		} else {
			/*
			 * The left side is the leftmost dimension of a possibly
			 * multidimensional array. Because of this, it makes
			 * more sense to use the right pointer in order to parse
			 * it, because it steps left-to-right, which is the
			 * natural way of reading array dimensions as well;
			 * char buf[5][6]; <-- 5 arrays of arrays
			 */
			right = left;
			if (start != *curtok) {
				left = left->prev;
			}
		}
	} else {
		/* Find identifier to start from there */
		if (type == DECL_STRUCT
			&& (*curtok)->type == TOK_OPERATOR
			&& *(int *)(*curtok)->data == TOK_OP_AMB_COND2) {
			/* Anonymous bitfield */
			t = *curtok;
			goto do_bitfield;
		}
		if (type != DECL_FUNCARG && type != DECL_FUNCARG_KR) {
			if ((t = find_ident(*curtok, type, ret)) == NULL) {
				free(ret);
				return NULL;
			}
		}
		ret->name = t->data;
		ret->line = t->line;

		if (start != *curtok) {
			/* left not first token */
			left = t->prev;
		} else {
			left = t;
		}
		if ((right = t->next) == NULL) {
			errorfl(t, "Unexpected end of file");
			free(ret);
			return NULL;
		}
		name = t->data;
	}

	/* XXX does this work? */
	if (left->type == TOK_OPERATOR
	   	&& *(int *)left->data == TOK_OP_AMB_MULTI) {
		if (IS_QUALIFIER(left->next->type)) {
			left = left->next;
			right = right->next;
		}
	}

#ifdef DEBUG2
	printf("Left = %s\n", left->ascii);
	printf("Right = %s\n", right->ascii);

	printf("Parsing %s for ``%s''\n", 
		type == DECL_CAST ? "cast" :
			type == DECL_FUNCARG || type == DECL_FUNCARG_KR
				? "function argument" :
				"declaration",
		(char *)t->ascii);
#endif

	if (t->next == NULL) {
		errorfl(t, "Unexpected end of file");
		free(ret);
		return NULL;
	}

	/*
	 * 10/03/07: This was missing a check for DECL_CAST! Otherwise
	 * things like
	 *
	 *    foo? __builtin_va_arg(bla, void *): NULL
	 *
	 * ... would break since the second part of the conditional
	 * operator was considered a potential candidate for a bitfield
	 * declarator
	 */
	if ((t->next->type == TOK_OPERATOR &&
		*(int *)t->next->data == TOK_OP_AMB_COND2)
		&& type != DECL_CAST) {
		/* This is a colon indicating a bitfield! */
		/* XXX only supports foo:bar, not (foo):bar */
do_bitfield:		
		if (type != DECL_STRUCT) {
			/* Attempt to declare bitfield outside of structure! */
			errorfl(t, "Syntax error at `%s'", t->ascii);
			free(ret);
			return NULL;
		}

		/* 
		 * ISO C only allows bitfield members of type int, unsigned
		 * int and _Bool
		 */
		if (ansiflag) {
			if (ret->code != TY_INT &&
				ret->code != TY_UINT &&
				ret->code != TY_BOOL) {
				errorfl(t, "Bitfield member must be int, "
					"unsigned int or _Bool");
				/* XXX recover :( */
				free(ret);
				return NULL;
			}
		}	

		/*
		 * Okay, this is a valid bitfield. The number of bits is a
		 * constant expression that might contain operators, so we
		 * cannot rely on it being just a number, as is usually the
		 * case
		 */
		if (name != NULL) {
			t = t->next; /* Now at ``:'' */
		}	
		if (next_token(&t) != 0) {
			free(ret);
			return NULL;
		}

		if ((ex = parse_expr(&t, TOK_OP_COMMA,
			TOK_SEMICOLON, EXPR_CONST, 1)) == NULL) {
#ifndef NO_EXPR /* parse_expr() always returns null if no_expr */
			free(ret);
			return NULL;
#endif
		}
		ret->tbit = n_xmalloc(sizeof *ret->tbit);
		ret->tbit->name = name;
		*curtok = t;
		merge_typedef_tlist(ret, base_tlist, base_tlist_tail);
		return ret;
	}

#ifdef DEBUG2
	if (ret->name) {
		printf("%s is:\n", ret->name);
	} else {
		printf("Cast is:\n");
	}
#endif

	/*
	 * Loop until end of both sides of declatator is reached. 
	 *
	 * Let us recall the rules for C's declaration syntax briefly ...
	 * 
	 * A declaration basically consists of a theoretically unlimited
	 * number of combined pointer-to, array-of and function call
	 * designators which are applied by placing them on either side of
	 * the identifier. Pointer-to is always placed on the left, array-of
	 * and function call on the right side. To read a declaration, you
	 * have to begin at the identifier (or in the case of a cast, where
	 * the identifier would be placed if it were a declaration!). You
	 * then look on the left side and on the right side. If either side
	 * is a parentheses, you pick the other side as ``significant''
	 * designator and advance this side. If it is a parentheses as well,
	 * both sides are advanced. 
	 * If you have a pointer-to on the left side and an array-of or
	 * function call on the right side, the right side wins because
	 * those have higher precedence.
	 * Example:
	 * char (*(*buf)[256])[256];
	 * ...step to buf. Left side is ``*'', right side is parentheses,
	 * thus read ``buf is a pointer to...''
	 *
	 * ...advance left side. This is a parentheses. Advance both sides
	 *
	 * ...left side is ``*'', right side is ``[256]''. [] has higher
	 * precedence, so read ``buf is a pointer to an array of 256...''
	 *
	 * ...advance right side. This is a parentheses, so pick left side 
	 * now and read ``buf is a pointer to an array of 256 pointers''
	 *
	 * ...advance left side. This is a parentheses. Advance both sides.
	 * The left side has reached the end of the declaration, the right
	 * side is ``[256]'', so read ``buf is a pointer to an array of
	 * 256 pointers to an array of 256 chars''
	 *
	 * On a final note, everything encountered after a function
	 * designator has been read is treated as the return type of that
	 * function
	 */
	if (type == DECL_CAST) {
		parens = 1;
	} else {
		parens = 0;
	}
	for (t = *curtok; t != right; t = t->next) {
		if (t->type == TOK_PAREN_OPEN) {
			++parens;
		}
	}

	if (right->type == TOK_PAREN_CLOSE) {
		if (right->next && 
			(right->next->type == TOK_SEMICOLON ||
			right->next->type == TOK_COMP_OPEN)) {
			*curtok = right;
			right = NULL;
			--parens;
		}
	}

	while (left != NULL || right != NULL) {
		int	right_paren_was_accounted_for = 0;
		
		if (left == start) {
			/* left end of declarator reached */
			left = NULL;
		}

		right_was_func = 0;

		if (right) {
			if (right->type == TOK_SEMICOLON) {
				/* right end of declarator reached */
				*curtok = right;
				right = NULL;
			} else if (right->type == TOK_OPERATOR) { 
				int	op = *(int *)right->data;

				if (op == TOK_OP_COMMA || op == TOK_OP_ASSIGN) {
					/* right end of declarator reached */
					*curtok = right;
					right = NULL;
				}
			} else if (right->type == TOK_PAREN_CLOSE) {
				/*
				 * If this is a cast, let's see whether
				 * this closing parentheses is the end
				 * of it!
				 * It is important to check that this
				 * code is not ran more than once on
				 * the same parentheses, which turned
				 * into an obscure bug ... When a
				 * parentheses is kept for more than
				 * one run because the other side is
				 * significant and evaluated first,
				 * only one parentheses might be
				 * counted
				 */
				if (newrparen) {
					--parens;
					/*
					 * 08/22/07: This variable was missing!
					 * Otherwise the code for left = ( and
					 * right ) decremented parens once more
					 * and stuff like ``int (foo)[20];''
					 * failed
		 			 */
					right_paren_was_accounted_for = 1;
					if (type == DECL_CAST) {
						if (parens == 0) {
							/* Yes! */
							*curtok = right;
							right = NULL;
						}
					} else if (type == DECL_FUNCARG) {
						if (parens == -1) {
							/*
							 * Closing parentheses
							 * reached
							 */
							*curtok = right;
							right = NULL;
						}	
					}	
					newrparen = 0;
				}
			}
		}
		

		if (left && right) {
			/* Precedence or parentheses must decide */
			if (left->type == TOK_PAREN_OPEN) {
				if (right->type == TOK_PAREN_CLOSE) {
					/* Skip parentheses */
					if (right->next == NULL) {
						*curtok = right;
					}	

					right = right->next;
					newrparen = 1;
					left = left->prev;
					newlparen = 1;
					if (!right_paren_was_accounted_for
						&& --parens  == -1) {
						if (right) *curtok = right;
						if (right
							&& right->type
							== TOK_PAREN_OPEN) {
							;
						} else {	
							right = NULL;
						}	
					}	
						
					continue;
				} else {
					/* Right is significant */
					if (right->type == TOK_ARRAY_OPEN) {
#ifdef DEBUG2
						puts("[right] array of N ...");
#endif
						arstart = right;
						if (next_token(&right) != 0) {
							free(ret);
							return NULL;
						}
						ex = parse_expr(&right,
							TOK_ARRAY_CLOSE, 0,
							
							(ac_for_all_dims
							||
							ret->tlist == NULL)?
							array_const:
							EXPR_CONST, 1);
						if (ex == NULL) {
							free(ret);
							return NULL;
						}
						if (ex->is_const) {
							ac_node = TN_ARRAY_OF; 
						} else {
							ac_node = TN_VARARRAY_OF;
							is_vla = 1;
						}
						append_typelist(ret,
							ac_node, ex, NULL,
							arstart);
					} else if (right->type
						== TOK_PAREN_OPEN) {
#ifdef DEBUG2
						puts("[right] function...");
#endif
						right_was_func = 1;
						if ((tfunc=parse_func(&right, name))
							== NULL) {
							free(ret);
							return NULL;
						}
						if ((type == DECL_FUNCARG
							|| type == DECL_FUNCARG_KR)
							&& ret->tlist == NULL) {
							append_typelist(ret,
								TN_POINTER_TO,
								0, NULL, NULL);
						}
						append_typelist(ret,
							TN_FUNCTION, 0, tfunc,
							NULL);
					} else if (right->type == TOK_OPERATOR
						&& *(int *)right->data
						== TOK_OP_AMB_MULTI) {
#ifdef DEBUG2
						puts("[right] pointer to...");
#endif
						append_typelist(ret,
							TN_POINTER_TO, 0,
							NULL, NULL);
					} else {
#ifdef DEBUG2
						printf("[right] syntax error? "
							"code = %d\n",
							right->type);
#endif
						/*
						 * XXX is this an
						 * improvement?
						 */
						*curtok = right;
						right = NULL;
					}
				}
			} else if (right->type == TOK_PAREN_CLOSE) {
				/* Left is significant */
				if (left->type == TOK_ARRAY_OPEN) {
#ifdef DEBUG2
					puts("[left] array of N...");
					puts("XXX what 2 do here");
#endif
					arstart = left;
					if (next_token(&left) != 0) {
						free(ret);
						return NULL;
					}
					ex = parse_expr(&left, TOK_ARRAY_CLOSE,
						0,
						(ac_for_all_dims || ret->tlist == NULL)?
						array_const:
						EXPR_CONST, 1);
					if (ex == NULL) {
						free(ret);
						return NULL;
					}
					if (ex->is_const) {
						ac_node = TN_ARRAY_OF;
					} else {
						ac_node = TN_VARARRAY_OF;
						is_vla = 1;
					}
					append_typelist(ret, ac_node,
						ex, NULL, arstart);
				} else if (left->type == TOK_OPERATOR &&
					*(int *)left->data
					== TOK_OP_AMB_MULTI) {
#ifdef DEBUG2
					puts("[left] pointer to...");
#endif
					append_typelist(ret, TN_POINTER_TO,
						0, NULL, NULL);
				} else {
#ifdef DEBUG2
					printf("[left] syntax error? code "
						"= %d\n", left->type);
#endif
					/* Qualified pointer? */
					if (IS_QUALIFIER(left->type)) {
						int *qualifier = &left->type;
						if (try_qualified(&left) == 1) {
							free(ret);
							return NULL;
						} else {
							append_typelist(ret,
								TN_POINTER_TO,
								qualifier,
								NULL,
								NULL);
						}
					}
				}
				if (newrparen && --parens == -1) {
					*curtok = right;
					right = NULL;
				}
			} else {
				/* 
				 * The right side always has precedence
				 * if both are not parentheses, because
				 * it must either be a function or array
				 * designator, both of which ``bind
				 * tighter'' than pointer-to
				 */
				if (right->type == TOK_ARRAY_OPEN) {
#ifdef DEBUG2
					puts("[right] array of N...");
#endif
					arstart = right;
					if (next_token(&right) != 0) {
						free(ret);
						return NULL;
					}
					ex = parse_expr(&right, TOK_ARRAY_CLOSE,
						0,
						(ac_for_all_dims ||
						 ret->tlist == NULL)? array_const:
						EXPR_CONST, 1);
					if (ex == NULL) {
						free(ret);
						return NULL;
					}
					if (ex->is_const) {
						ac_node = TN_ARRAY_OF;
					} else {
						ac_node = TN_VARARRAY_OF;
						is_vla = 1;
					}	
					append_typelist(ret, ac_node,
						ex, NULL, arstart); 
				} else if (right->type == TOK_PAREN_OPEN) {
#ifdef DEBUG2
					puts("[right] function...");
#endif
					right_was_func = 1;
					if ((tfunc = parse_func(&right, name))
						== NULL) {
						free(ret);
						return NULL;
					}
					if ((type == DECL_FUNCARG
						|| type == DECL_FUNCARG_KR)
						&& ret->tlist == NULL) {
						append_typelist(ret,
							TN_POINTER_TO,
							NULL, NULL, NULL);
					}
					append_typelist(ret, TN_FUNCTION,
						NULL, tfunc, NULL);
				} else {
#ifdef DEBUG2
					printf("[right] syntax error? "
						"code = %d\n", right->type);
#endif
					/* XXX is this an improvement? */
					*curtok = right;
					right = NULL;
				}
				if (right && right->next == NULL) {
					*curtok = right;
				}	
				if (right) right = right->next;
				newrparen = 1;
				continue;
			}
		} else if (left != NULL || right != NULL) {
			/* Either left or right is significant */
			char		*side = NULL;
			struct token	*tmp = NULL;

			if (left) {
				/* Left is sig. */
				side = "left";
				tmp = left;
			} else {
				/* Right is sig. */
				side = "right";
				tmp = right;
			}
			if (tmp->type == TOK_ARRAY_OPEN) {
#ifdef DEBUG2
				printf("%s array of N...\n", side);
#endif
				arstart = tmp;
				if (next_token(&tmp) != 0) {
					free(ret);
					return NULL;
				}

				ex = parse_expr(&tmp, TOK_ARRAY_CLOSE,
					0,
					(ac_for_all_dims || ret->tlist == NULL)?
					array_const
					: EXPR_CONST, 1);
				if (ex == NULL) {
					return NULL;
				}	
				if (ex->is_const) {
					ac_node = TN_ARRAY_OF;
				} else {
					ac_node = TN_VARARRAY_OF;
					is_vla = 1;
				}
				append_typelist(ret, ac_node, ex, NULL,
					arstart); 
			} else if (tmp->type == TOK_OPERATOR &&
				*(int *)tmp->data == TOK_OP_AMB_MULTI) {
#ifdef DEBUG2
				printf("%s pointer to...\n", side);
#endif
				append_typelist(ret, TN_POINTER_TO, NULL, NULL,
						NULL);
			} else if (tmp->type == TOK_PAREN_OPEN) {
				if (tmp == right) {
#ifdef DEBUG2
					printf("%s function...\n", side);
#endif
					right_was_func = 1;
					if ((tfunc = parse_func(&tmp, name))
							== NULL) {
						free(ret);
						return NULL;
					}
					if ((type == DECL_FUNCARG
						|| type == DECL_FUNCARG_KR)
						&& ret->tlist == NULL) {
						append_typelist(ret,
							TN_POINTER_TO,
							NULL, NULL, NULL);
					}
					append_typelist(ret, TN_FUNCTION,
						NULL, tfunc, NULL);
				} else {
					/* XXX handle error! Can't happen! */
				}
			} else if (tmp->type == TOK_PAREN_CLOSE) {
				if (tmp == right) {
					if (newrparen && --parens == -1) {
						*curtok = right;
						right = NULL;
					}
				} else {
#ifdef DEBUG2
					printf("%s syntax error? code = %d\n",
						side, tmp->type);
#endif
					/* XXX is the below an improvement? */
					if (tmp == right) *curtok = right;
					right = NULL;
					
				}
			} else {
#ifdef DEBUG2
				printf("%s syntax error? code = %d\n",
					side, tmp->type);
#endif
				/* XXX is this an improvement? */
				if (tmp == right) {
					*curtok = right;
					right = NULL;
				} else {
					if (IS_QUALIFIER(tmp->type)) {
						int	*qualifier
							= &tmp->type;

						if (try_qualified(&left) == 1) {
							free(ret);
							return NULL;
						} else {
							append_typelist(ret,
								TN_POINTER_TO,
								qualifier,
								NULL, NULL);
							tmp = left;
						}
					}
				}
			}
			if (left) {
				left = tmp;
			   	newlparen = 1;
			} else if (right) {
				right = tmp;
			   	newrparen = 1;
			}
		}

		/*
		 * We only proceed either side if it isn't a parentheses. The
		 * case where both sides are parentheses is handled above
		 */
		if (left) {
			if (left->type != TOK_PAREN_OPEN || right == NULL) {
				left = left->prev;
				if (left->type == TOK_PAREN_OPEN) {
					++parens;
					newlparen = 0;
				}
			}
		}
		if (right) {
			/*
			 * 06/30/07: right_was_func added. Lack of this
			 * check caused things like:
			 *
			 *     void foo(int (bar()), void *p);
			 *
			 * ... to break (GNU tar uses this.)
			 *
			 * The problem was that the parse_func() for the
			 * bar() declaration left a ) token, which has
			 * to be skipped here despite being a parentheses.
			 * Because otherwise it will incorrectly match
			 * with the ( before ``bar'', thus yielding
			 * parentheses mismatch
			 */
			if ((right->type != TOK_PAREN_CLOSE
				|| right_was_func)
				|| left == NULL) {
				if (right->next) *curtok = right;
				right = right->next;
				newrparen = 1;
			}
		}
	}

	while ((*curtok)->type == TOK_KEY_ATTRIBUTE) {
		(void) get_attribute(ret, curtok);
	}

	/*
	 * Finally we can check all attributes for correctness and set the
	 * fastattr flags
	 */
	merge_attr_with_type(ret);

	/*
	 * 073107: Merge typelist with the possible base typelist if this
	 * is a typedef'ed type. This was wrongly done after the ``array''
	 * parameter transformation below, such that
	 *
	 *    typedef struct blabla { } va_list[1];
	 *
	 * void foo(va_list v) {
	 *
	 * ... wrongly declared v as an array instead of a pointer
	 */
	merge_typedef_tlist(ret, base_tlist, base_tlist_tail);
	if (type != DECL_FUNCARG
		&& type != DECL_FUNCARG_KR
		&& type != DECL_CAST) {
		if ((*curtok)->type == TOK_PAREN_CLOSE) {
			*curtok = (*curtok)->next;
		}
	} else if (type == DECL_FUNCARG || type == DECL_FUNCARG_KR) {
		/* There are no array arguments; Only pointers */
		if (ret->tlist != NULL
			&& ret->tlist->type == TN_ARRAY_OF) {
			ret->tlist->type = TN_POINTER_TO;
			if (ret->tlist->next
				&& ret->tlist->next->type == TN_ARRAY_OF) {
			}	
		}
	}
	ret->is_vla += is_vla; /* typedef'ed base may already be VLA! */

	return ret;
}



static void
store_decl(struct decl ***d, struct decl *dec, int *nalloc, int *index) {
	if (*index >= (*nalloc - 2)) {
		*nalloc += 8;
		*d = n_xrealloc(*d, *nalloc * sizeof **d);
	}
	(*d)[*index] = dec;
	(*d)[++*index] = NULL;
}

/*
 * Parses declaration beginning from token list beginning at *curtok
 * and, if the mode permits it, the optional initializer. The end of a
 * declaration is indicated by either a semicolon or a comma (,). If the
 * latter is encountered, the function just uses the same base type to
 * parse the next declarator.
 * On success, a pointer to a newly allocated declaration structure is
 * returned, else NULL. *curtok is updated to point to the next token
 * after this declaration.
 */ 
struct decl **
parse_decl(struct token **curtok, int mode) {
	struct decl		**ret = NULL;
	struct decl		*tmp;
	struct type		*ty;
	struct initializer	*init;
	int			alloc = 0;
	int			index = 0;

#ifdef DEBUG2
	printf("Reading decl -- %s\n", (*curtok)->ascii);
#endif
	if ((ty = get_base_type(curtok, mode)) == NULL) {
#if 0
			/* XXX */
			recover(curtok, TOK_OP_COMMA, TOK_SEMICOLON);
#endif
		return NULL;
	}

	if ((*curtok)->type == TOK_SEMICOLON) {
		if (ty->tstruc == NULL
			&& ty->code != TY_ENUM) {
			errorfl(*curtok, "Syntax error at `;'");
			return NULL;
		} else {
			static struct decl	*dummy[2];
			static struct decl	dummy2;

			/*
			 * 08/18/07: Wow, this always ended up using
			 * the same declaration for every anonymous
			 * union! So now the declaration is copied.
			 * Was probably wrong for lots eof other
			 * things too, how come it seemed to work?!?
			 */
			dummy[0] = n_xmemdup(&dummy2, sizeof dummy2);
			/* XXX misleading for struct foo; */
			dummy[0]->dtype = ty;
			dummy[0]->dtype->is_def = 1;
			dummy[0]->dtype = ty;
			dummy[1] =  NULL;
			merge_attr_with_type(ty);
			return dummy;
		}	
	}

	/* 
	 * Now that we have the base type, the declarator list can be
	 * read - separated by commas in case there are more than one
	 */
	for (;;) {
		struct type		*decty;
		struct token	*declstart = *curtok;

		decty = parse_declarator(curtok, ty, mode);

		if (decty != NULL) {
			char	*asmname = NULL;

			/* Store declaration */

			debug_print_type(decty, mode, 0);

			if ((*curtok)->type == TOK_KEY_ASM) {
				if (curscope != &global_scope
					&& decty->storage != TOK_KEY_EXTERN
					&& decty->storage != TOK_KEY_STATIC) {
					errorfl(*curtok,
						"Cannot give asm name to "
						"nonstatic variable");
					return ret;
				}	
				asmname = parse_asm_varname(curtok);
				if (asmname == NULL) {
					return NULL;
				}	
			}

			if (decty->code == TY_VOID
				&& decty->tlist == NULL
				&& mode != DECL_CAST
				&& decty->storage != TOK_KEY_TYPEDEF) {
				errorfl(declstart,
					"Cannot create object of type `void'");
				return ret;
			} else if ((decty->code == TY_STRUCT
					|| decty->code == TY_UNION)	
				&& decty->storage != TOK_KEY_TYPEDEF	
				&& decty->storage != TOK_KEY_EXTERN
				&& decty->tstruc->incomplete
				&& !decty->is_def
				&& (decty->tlist == NULL
					|| (decty->tlist->type != TN_FUNCTION
					&& !is_arr_of_ptr(decty)))) {
				errorfl(declstart,
				"Cannot instantiate object of incomplete type");
				return ret;
			}
			if (decty->implicit
				&& decty->name != NULL) {
				if (decty->is_func
					&& (*curtok)->type == TOK_COMP_OPEN) {
					warningfl(*curtok,
						"Return type of `%s' defaults "
						"to `int'", decty->name);
				} else {
					errorfl(*curtok,
				"No type or storage class specified for `%s'",
					decty->name);
					return ret;
				}
			}

			if (decty->storage == 0) {
#if 0
				if (curscope == &global_scope) {
					decty->storage = TOK_KEY_EXTERN;
				}
#endif
			} else if (decty->storage == TOK_KEY_EXTERN) {
				if (curscope != &global_scope) {
					/*
					 * ``extern'' declarations with block
					 * scope may not have an initializer!
					 */
#if 0
					errorfl(*curtok,
	"Invalid initializer for ``extern'' declaration at block scope"); 
#endif
				}
			}

			tmp = alloc_decl();
			tmp->tok = declstart; 
			tmp->dtype = decty;
			if (decty->is_func
				&& decty->tlist->type == TN_FUNCTION) {
				tmp->asmname = decty->tlist->tfunc->asmname; 
			} else {
				tmp->asmname = asmname;
			}
			if (mode == DECL_VARINIT) {
				struct decl	*dummy[2];
				dummy[0] = tmp;
				dummy[1] = NULL;
				if ((*curtok)->type == TOK_COMP_OPEN
					&& tmp->dtype->is_func) {
					tmp->dtype->is_def = 1;
					store_decl_scope(curscope->parent,
						dummy);
				} else  if (!tmp->dtype->is_def
					|| (tmp->dtype->code != TY_ENUM
					&& tmp->dtype->code != TY_STRUCT
					&& tmp->dtype->code != TY_UNION)) {
					if ((*curtok)->type == TOK_OPERATOR
						&& *(int *)(*curtok)->data
						== TOK_OP_ASSIGN) {
						/*
						 * store_decl_scope() will look
						 * at the initializer, which
						 * has not been read yet ...
						 * So use dummy initializer to
						 * fool it
						 */
						static struct initializer in;

						tmp->init = &in;
					}	
					store_decl_scope(curscope, dummy);
				}	
			}	
			store_decl(&ret, tmp, &alloc, &index);

			/*
			 * If this is an array declaration, check whether the
			 * size was specified (if necessary!). important: Need
			 * to take initializer into account;
			 * int foo[] = { ... }; is OK
			 */
			if (decty->storage != TOK_KEY_EXTERN
				&& decty->storage != TOK_KEY_TYPEDEF
				&& decty->tlist != NULL
				&& decty->tlist->type == TN_ARRAY_OF
				&& decty->tlist->arrarg->const_value == NULL
				&& mode != DECL_FUNCARG
				&& mode != DECL_FUNCARG_KR
				&& mode != DECL_STRUCT
				&& mode != DECL_CAST
				&& ((*curtok)->type != TOK_OPERATOR
					|| *(int *)(*curtok)->data !=
					TOK_OP_ASSIGN)) {
				errorfl(declstart,
					"Array declaration misses size");
				return ret;
			}

			if (mode == 0) {
				/* Is init */
				return ret;
			}
		} else {
			return ret;
		}
		if (*curtok == NULL) return ret;
		if ((*curtok)->type == TOK_SEMICOLON) {
			break; /* done */
		} else if ((*curtok)->type == TOK_PAREN_CLOSE &&
			(mode == DECL_CAST
				|| mode == DECL_FUNCARG
				|| mode == DECL_FUNCARG_KR)) {
			return ret;
		} else if ((*curtok)->type == TOK_OPERATOR &&
			*(int *)(*curtok)->data == TOK_OP_COMMA) {
			/* 
			 * If this is an ISO function argument, the base
			 * type cannot be reused, so we must start
			 * from scratch again - return. However, in K&R
			 * definitions, it can be reused!
			 */
			if (mode == DECL_FUNCARG) {
				return ret;
			}	
			if (next_token(curtok) != 0) {
				return ret;
			}
			continue;
		} else if ((*curtok)->type == TOK_OPERATOR &&
			*(int *)(*curtok)->data == TOK_OP_ASSIGN) {
			if (decty->is_vla) {
				errorfl(*curtok, "Variable-length arrays "
					"may not have initializers");
				return ret;
			} else if (mode == DECL_STRUCT) {
				errorfl(*curtok, "Invalid initializer for "
					"structure member");
				return ret;
			} else if (mode == DECL_FUNCARG
				|| mode == DECL_FUNCARG_KR) {
				errorfl(*curtok, "Initializer given for "
					"function argument");
				return ret;
			} else {
				/* Read initializer */

				if (tmp->dtype->storage == TOK_KEY_TYPEDEF) {
					errorfl(*curtok, "Initializer "
						"specified for typedef");
					;
				}

				if (next_token(curtok) != 0) {
					return ret;
				}

				if (((tmp->dtype->tlist
					&& tmp->dtype->tlist->type
						== TN_ARRAY_OF)
					|| ((tmp->dtype->code == TY_STRUCT
					|| tmp->dtype->code == TY_UNION)
					&& tmp->dtype->tlist == NULL))
					&& tmp->dtype->storage != TOK_KEY_STATIC
					&& tmp->dtype->storage != TOK_KEY_EXTERN) {
					/*
					 * Automatic struct or array. These are
					 * now allowed to have variable
					 * initializers (as per GNU C/C99), but
					 * constants are preferred - thus use
					 * EXPR_OPTCONST
					 */
					init = get_init_expr(curtok,
							EXPR_OPTCONSTINIT,
							tmp->dtype, 1, 0);
				} else if (tmp->dtype->storage == TOK_KEY_STATIC
					|| tmp->dtype->storage
						== TOK_KEY_EXTERN) {
					init = get_init_expr(curtok,
							EXPR_CONSTINIT,
							tmp->dtype, 1, 0);
				} else {
					init = get_init_expr(
						curtok, EXPR_INIT,
						tmp->dtype, 1, 0); 
				}
				if (init == NULL) {
					return ret;
				}
				tmp->init = init;
				if (tmp->dtype->tlist != NULL
					&& tmp->dtype->tlist->type
						== TN_ARRAY_OF	
					&&tmp->dtype->tlist->arrarg->const_value
						== NULL) {
					/* 
					 * Array size determined by
					 * initializer
					 * XXX this is completely bogus and
					 * only works for 1d arrays ... need
					 * to do this in get_init_expr()?!
					 */
					init_to_array_size(tmp->dtype, init);
				}
					
#ifdef DEBUG2
				if (*curtok) {
					printf("returned at %s\n",
						(*curtok)->ascii);
				}
#endif
				if ((*curtok)->type == TOK_SEMICOLON) {
					break;
				} else if ((*curtok)->type == TOK_OPERATOR
					&& *(int *)(*curtok)->data
						== TOK_OP_COMMA) {
					if (next_token(curtok) != 0) {
						return ret;
					}
				}	
			}
		} else if ((*curtok)->type == TOK_COMP_OPEN) {
			return ret;
		} else {
			errorfl(*curtok, 
				"Syntax error at `%s'", (*curtok)->ascii);
			return ret;
		}
	}
	/**curtok = tok;*/
	return ret;
}



syntax highlighted by Code2HTML, v. 0.9.1