/*
 * 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 ``advanced declarations''.
 * This module exports parse_func/struct/enum() used by the parse_decl()
 * subsystem
 */

#include "decl_adv.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "type.h"
#include "backend.h"
#include "token.h"
#include "misc.h"
#include "decl.h"
#include "symlist.h"
#include "error.h"
#include "scope.h"
#include "reg.h"
#include "typemap.h"
#include "expr.h"
#include "attribute.h"
#include "inlineasm.h"
#include "debug.h"
#include "n_libc.h"

/* Parsing framework for structure and function definitions/declarations */

#define STORE_FUNC (1)
#define STORE_STRUCT (2)

/*
 * Stores src argument as structure member(s) of deststr argument
 * The integer pointed to by the ``alloc'' argument must be set to
 * zero every time a new structure is parsed, but not be touched after-
 * wards
 */
static void 
store_member_struct(struct ty_struct *deststr,
                    struct decl      **src) {
	int		nsrc;

	/* Determine number of declarations */
	for (nsrc = 0; src[nsrc] != NULL; ++nsrc)
		;
	deststr->nmemb += nsrc; 
	store_decl_scope(deststr->scope, src);
}


/* Same as store_member_struct(), but for function arguments */
static void
store_member_func(struct ty_func *destfun,
                  struct decl    **src) {
	int		nsrc;

	/* Determine number of declarations */
	for (nsrc = 0; src[nsrc] != NULL; ++nsrc)
		;

	destfun->lastarg = src[nsrc - 1];
	destfun->nargs += nsrc;
	store_decl_scope(curscope, src);
}


static int 
store_member_enum(struct ty_enum *dest,
                  char *name,
		  struct token *value,
		  struct type *type,
                  int *alloc) {
	int		i;
	struct scope	*scope;
	struct vreg	*vr;
	struct decl	*dec[2];


	/* Resize space if necessary */
	
	if (dest->nmemb >= *alloc) {
		*alloc += 8;
		dest->members = 
			n_xrealloc(dest->members,
				*alloc * sizeof *dest->members);
	}

	vr = vreg_alloc(NULL, value, NULL, NULL);

	if (type == NULL) {
		vr->type =
			n_xmemdup(make_basic_type(TY_INT), sizeof *vr->type);
	} else {
		vr->type = type;
	}	
	vr->size = backend->get_sizeof_type(vr->type, NULL);

	dec[0] = alloc_decl();
	dec[0]->dtype = vr->type;
	dec[0]->dtype->name = name;
	dec[0]->dtype->tenum = dest;
	dec[0]->vreg = vr;
	dec[1] = NULL;

	/* Store */
	dest->members[ dest->nmemb ].name = name;
	dest->members[ dest->nmemb ].dec = dec[0];
	for (i = 0; i < dest->nmemb; ++i) {
		if (strcmp(dest->members[i].name, name) == 0) {
			return -1;
		}
	}
	++dest->nmemb;

	/* 
	 * An enumeration constant need only appear in the symbol list,
	 * as it doesn't have to be allocated anywhere
	 */
	for (scope = curscope;
		scope->type == SCOPE_STRUCT;
		scope = scope->parent)
		;
	append_symlist(scope, &scope->slist,
		&scope->slist_tail, dec[0]);
	return 0;
}


/*
 * Function for glueing the member declarations of structures and unions
 * together. This must be called by the declaration parsing code as soon
 * as a structure *definition* (struct foo { ... }) is encountered, where
 * the curtok argument must point to the node after { 
 * Returns a pointer to the newly allocated definition on success, else 
 * a null pointer
 */

#define PS_RET_ERR(ret) do { \
	if (ret && ret->scope) { \
		/*free(ret->scope);*/ \
	} \
	free(ret); \
	close_scope(); \
	return NULL; \
} while (0)


/*
 * XXX struct alignment is done in x86_emit_nasm.c, print_init_list() and
 * x86_emit_nasm.c,  do_print_struct() ... there is some duplication of
 * efforts, should probably all be done here
 */
struct ty_struct *
parse_struct(struct token **curtok, char *tag, int type) {
	struct token		*t;
	struct token		*prevtok = NULL;
	struct decl		**dec = NULL;
	struct ty_struct	*ret;
	struct sym_entry	*se;
	unsigned long		offset = 0;
	size_t			maxalign = 0;
	size_t			align;


	ret = alloc_ty_struct();
	ret->tag = tag;

#ifdef DEBUG2
	printf("Parsing structure definition...\n");
#endif

	ret->scope = new_scope(SCOPE_STRUCT);

	for (t = *curtok; t != NULL; t = t->next) {
		prevtok = t;
		if (t->type == TOK_COMP_CLOSE) {
			/* } reached - definition complete */
			break;
		} else if (!IS_KEYWORD(t->type) && t->type != TOK_IDENTIFIER) {
			errorfl(t, "Syntax error at ``%s'' - "
				"Expected start of structure member definition",
				t->ascii);
			PS_RET_ERR(ret);
		}
		if ((dec = parse_decl(&t, DECL_STRUCT)) == NULL) {
			PS_RET_ERR(ret);
		}

		store_member_struct(ret, dec);

		/*
		 * If any of the structure members is incomplete, the entire
		 * structure is incomplete 
		 * XXX implement incomplete check in decl.c!
		 */
#if 0 /* dtype is not yet filled! */
		if (dec->dtype->incomplete) {
			ret->incomplete = 1;
		}
#endif
	}

	if (ret->scope->slist == NULL) {
		errorfl(t, "Empty structure declaration");
		PS_RET_ERR(ret);
	}

	ret->size = 0;
	for (se = ret->scope->slist; se != NULL; se = se->next) {
		size_t		size;
		struct type	*ty = se->dec->dtype;
		
		if (ty->tlist != NULL) {
			if (ty->tlist->type == TN_ARRAY_OF
				&& ty->tlist->arrarg->const_value == NULL) {
				/* C99 flexible array member */

				/*
				 * 09/15/07: Wow this was missing alignment
				 * and member offset assignment... because
				 * we used to ``break'' here
				 */
				if (se->next != NULL) {
					errorfl(NULL /* XXX */,
						"Flexible array not "
						"last member of "
						"structure");
					continue;
				} else {
					ret->flexible = se->dec;
				/*	break;*/
				}
			/*	continue;*/
			}
		}	


		if (ret->flexible != se->dec) {
			size = backend->get_sizeof_decl(se->dec, NULL);

			if (size == 0) {
				errorfl(NULL, "Incomplete type `%s'", ty->name);
				continue;
			}	
		}

		if (type == TY_STRUCT) {
			/* struct */
			align = backend->get_align_type(ty);
			if (/*align*/1) {
				/* Align all types > char */ 
				while (offset % align/*size*/) ++offset;
			}
			se->dec->offset = offset;
			offset += size;
		} else {
			/* union */
			size_t	align;

			align = backend->get_align_type(ty);
			if (align > maxalign) {
				maxalign = align;
			}	
			if (size > ret->size) {
				ret->size = size;
			}
		}	
	}

	if (type == TY_UNION) {
		/* XXX this seems completely bogus ... */
		if (/*align*/1) {
			while (ret->size % maxalign) ++ret->size;
		}
	} else {
		/* XXX ?!? */
		ret->size = offset;
		se = ret->scope->slist;
#if 0
		align = backend->get_align_type(se->dec->dtype);
#endif
		{
			static struct type	ty;
			ty.code = TY_STRUCT;
			ty.tstruc =  ret;
			align = backend->get_align_type(&ty);
		}
		while (ret->size % align) {
			++ret->size;
		} 
	}	

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

#ifdef DEBUG2
	printf("Structure def with %d members parsed successfully!\n",
		ret->nmemb);
#endif
	if (ret->nmemb == 0) {
		if (ret->tag != NULL) {
			errorfl(*curtok,
				"Empty structure declaration `%s'", ret->tag);
		} else {
			errorfl(*curtok, "Empty structure declaration");
		}
	}	
/* XXX ? */ *curtok = t;
	close_scope();
	return ret;
}


struct ty_enum *
parse_enum(struct token **curtok) {
	struct ty_enum	*ret;
	struct token	*t;
	struct token	*prevtok = NULL;
	struct token	*valtok;
	struct expr	*ex;
	char		*name;
	int		op;
	int		val = 0;
	int		alloc;
	int		curval = 0;

	ret = alloc_ty_enum();

	alloc = 0;
#ifdef DEBUG2
	puts("------------------------------------");
#endif
	for (t = *curtok; t != NULL; t = t->next) {
		prevtok = t;
		if (t->type == TOK_COMP_CLOSE) {
			/* End of definition reached */
			break;
		} else if (t->type != TOK_IDENTIFIER) {
			errorfl(t, "Syntax error at `%s' - Expected enum "
				"member name", t->ascii);
			free(ret);
			return NULL;
		}

		/*
		 * Ok, is identifier. Either read constant expression, if
		 * specified, or add one to previous member value
		 */
		name = t->data;

		if (next_token(&t) != 0) {
			free(ret);
			return NULL;
		}

		if (t->type == TOK_COMP_CLOSE) {
			/* } - Definition ends here */
			val = curval;
			valtok = const_from_value(&val, NULL); 
			if (store_member_enum(ret, name, valtok,
					NULL, &alloc) != 0) {
				errorfl(t, "Multiple definitions of `%s'",
					name);
			}
			break;
		} else if (t->type == TOK_OPERATOR) {
			/* Must be ``,'' or ``='' */
			op = *(int *)t->data;
			if (op == TOK_OP_ASSIGN) {
				if (next_token(&t) != 0) {
					return NULL;
				}
				ex = parse_expr(&t, TOK_OP_COMMA,
					TOK_COMP_CLOSE, EXPR_CONST, 1);
				if (ex == NULL) {
#ifndef NO_EXPR
					return NULL;
#endif
				}

				if (t->type == TOK_COMP_CLOSE) {
					t = t->prev;
				}	
				/* XXX evaluate ex ... */
				valtok = const_from_value(
						ex->const_value->value,
						ex->const_value->type);
				if (store_member_enum(ret, name, valtok,
					NULL, &alloc) != 0) {
					errorfl(t, "Multiple definitions of "
						"`%s'", name);
				}

				/* Now update current value counter */
				curval = (int)cross_to_host_size_t(
					ex->const_value);
				++curval;
			} else if (op == TOK_OP_COMMA) {
				/*
				 * No initializer given, so this gets the value
				 * of the previous member + 1. Note that C99
				 * permits a ``dangling'' comma at the end of
				 * an enum def., as in ``enum foo { FOO, BAR,
				 * };'', so we must also check whether the
				 * definition ends here
				 */
				val = curval++;
				valtok = const_from_value(&val, NULL);
				if (store_member_enum(ret, name, valtok,
					NULL, &alloc) != 0) {
					errorfl(t, "Multiple definitions of "
						"`%s'", name);
				}
				if (t->next
					&& t->next->type == TOK_COMP_CLOSE) {
					/* Definition ends */
					t = t->next;
					break;
				}
			}
		} else {
			errorfl(t,
				"Syntax error at `%s' - "
				"Expected enum initializer, comma or }",
				t->ascii);
			free(ret);
			return NULL;
		}
	}
#ifdef DEBUG2
	puts("------------------------------------");
#endif

	if (t == NULL) {
		errorfl(prevtok, "Unexpected end of file");
		free(ret);
		return NULL;
	}
	*curtok = t;
	return ret;
}


struct ntab {
	struct nentry {
		char		*name;
		int		refcount;
		int		line;
		struct decl	*dec;
	}	*nametab;
	int	alloc;
	int	index;
};

/*
 * Delete structure members or function arguments of dest, if existent, then
 * delete dest. Intended to use for early escape from syntax errors in struct
 * and func parsing
 */

static void
drop_stuff(struct ty_func *dest, struct ntab *n) {
#if 0
	if (dest->args != NULL) {
		/* Is function */
		free(dest->args);
		dest->args = NULL;
	}
#endif
	if (dest->scope != NULL) {
		/* free(dest->scope); */
	}
	free(dest);
	if (n != NULL && n->nametab != NULL) {
		free(n->nametab);
		n->nametab = NULL;
	}
}


	
/*
 * Stores pointer ``p'' in the name entry table pointed to by ``dest''.
 * The table must be created with all members set to zero, e.g. by
 * writing: struct ntab n = { 0, 0, 0 };
 * Returns 1 if a string equivalent to the one to by ``p'' already
 * resides in the table (p is not stored if this happens), else 0 
 * n.nametab[n.index].name will always be a null pointer
 */
static int 
store_ident(struct ntab *dest, char *name, int line) {
	int	i;

	if (dest->index >= (dest->alloc - 1)) {
		dest->alloc += 8;
		dest->nametab =
			n_xrealloc(dest->nametab,
				dest->alloc * sizeof *dest->nametab);
	}

	/* Make sure we have no multiple definitions */
	for (i = 0; i < dest->index; ++i) {
		if (strcmp(dest->nametab[i].name, name) == 0) {
			/* Already exists - no need to save */
			return 1;
		}
	}
	dest->nametab[ dest->index ].name = name;
	dest->nametab[ dest->index ].line = line;
	dest->nametab[ dest->index ].refcount = 0;
	dest->nametab[ ++dest->index ].name = NULL;
	return 0;
}

/*
 * Looks up string pointed to by ``name'' in name table pointed to by
 * ``n''. Returns a pointer to that on success, else NULL.
 */
static struct nentry *
lookup_ident(struct ntab *n, char *name) {
	int	i;

	for (i = 0; n->nametab[i].name != NULL; ++i) {
		if (strcmp(n->nametab[i].name, name) == 0) {
			++n->nametab[i].refcount;
			return &n->nametab[i];
		}
	}
	return NULL;
}


/*
 * Helper macro for parse_func() - Close scope only if it is a function
 * prototype scope, i.e. not a definition. If we are dealing with a
 * definition (prototype followed by a ``{''), this is block scope and
 * should not be closed
 */
#if 0
#define CLOSE_SCOPE(tok) do { \
	if (tok) { \
		struct token	*_t2; \
		if ((_t2 = ignore_attr(tok)) != NULL) { \
			if (_t2->type != TOK_COMP_OPEN) { \
				/* Is declaration */ \
				close_scope(); \
			} \
		} \
	} \
} while (0)
#endif

void CLOSE_SCOPE(struct token *tok) { do { \
	if (tok) { \
		struct token	*_t2; \
		if ((_t2 = ignore_attr(tok)) != NULL) { \
			if (_t2->type != TOK_COMP_OPEN) { \
				/* Is declaration */ \
				close_scope(); \
			} \
		} \
	} \
} while (0)
; }

static void 
check_matches(struct token *t, struct ntab *n, struct decl **dec) {
	int		i;
	struct nentry	*np;

	for (i = 0; dec[i] != NULL; ++i) {
		if ((np = lookup_ident(n, dec[i]->dtype->name)) == NULL) {
			errorfl(t,
				"Declaration for non-existent parameter `%s'",
				dec[i]->dtype->name);
		} else if (np->refcount > 1) {
			errorfl(t,
				"Multiple declarations for parameter `%s'",
				dec[i]->dtype->name);
		} else {
			np->dec = dec[i];
		}
	}
}

static int
do_parse_kr_func(struct token **tok, struct ty_func *ret) {
	struct token	*t;
	struct decl	**dec;
	int		errors = 0;
	int		i;
	char		**names = NULL;
	struct nentry	*np;
	struct ntab	n = { 0, 0, 0 };

	ret->type = FDTYPE_KR;
	(void) names;

	for (t = *tok; t != NULL; t = t->next) {
		if (t->type == TOK_PAREN_CLOSE) {
			/*
			 * End of parenthesized part of declaration reached -
			 * read parameter declarations now!
			 */
			if (next_token(&t) != 0) {
				return -1;
			}

			for (; t != NULL; t = t->next) {
				if (t->type == TOK_COMP_OPEN) {
					/*
					 * Opening compound statement -
					 * end reached
					 */
					t = t->prev;
					break;
				} else if (IS_TYPE(t)) {
					dec = parse_decl(&t, DECL_FUNCARG_KR);
					if (dec == NULL) {
						return -1;
					}
					if (t && t->type != TOK_SEMICOLON) {
						errorfl(t,
						"Syntax error at `%s' - "
						"Expected semicolon", t->ascii);
						return -1;
					} else if (t == NULL) {
						break;
					}

					check_matches(t, &n, dec);
#if 0
					store_member_func(ret, dec);
#endif
				} else {
					if (t->type == TOK_OPERATOR) {
						int	i;
						for (i = 0; i < 3; ++i) {
							if (*(int *)t->data
							!= TOK_OP_STRUMEMB) {
								break;
							}
							if (t->next == NULL) {
								break;
							}
							t = t->next;
						}
						if (i == 3) continue;
					}
					/* Garbage */
					errorfl(t, "Syntax error at `%s' - "
						"Expected parameter "
						"declaration", t->ascii);
					return -1;
				}
			}

			/*
			 * If this point is reached, either the declaration
			 * list was valid, or the end-of-file has been
			 * encountered prematurely. Both cases are handled by
			 * the code below...
			 * We must check whether all parameters enclosed by
			 * parentheses have been resolved by declarations!
			 */
			if ((np = n.nametab) != NULL) {
				for (i = 0; n.nametab[i].name != NULL; ++i) {
					struct decl	*dummy[2];

					if (n.nametab[i].refcount < 1) {
						/* Undeclared - assume int */
						n.nametab[i].dec = alloc_decl();
						n.nametab[i].dec->dtype =
							n_xmemdup(
							make_basic_type(TY_INT),
							sizeof(struct type));
						n.nametab[i].dec->dtype->name =
							n.nametab[i].name;
							
					}
					dummy[0] = n.nametab[i].dec;
					dummy[1] = NULL;
					store_member_func(ret, dummy);
				}
			}
			break;
		} else {
			/*
			 * This must be an identifier. Everything else is
			 * illegal!
			 */
			if (t->type != TOK_IDENTIFIER) {
				errorfl(t, "Syntax error at `%s' - " 
					"Expected identifier", t->ascii);
				break;
			}

			if (store_ident(&n, t->data, t->line) == 1) {
				errorfl(t,
					"Multiple definitions of `%s'",
					t->ascii);
				++errors;
			}

			if (next_token(&t) != 0) {
				return -1;
			}

			if (t->type == TOK_OPERATOR) {
				if (*(int *)t->data != TOK_OP_COMMA) {
	   				errorfl(t, "Syntax error at `%s' - "
						"expected comma or closing "
						"parentheses", t->ascii);
				} else {
					continue;
				}
			} else if (t->type != TOK_PAREN_CLOSE) {
		   		errorfl(t, "Syntax error at `%s' - "
					"expected comma or closing parentheses",
					t->ascii);
			} else {
				t = t->prev;
				continue;
			}
			return -1;
		}
	}
	if (errors) {
		return -1;
	}

	*tok = t;
	return 0;
}

static int
do_parse_iso_func(struct token **tok, struct ty_func *ret) {
	struct token	*t;
	struct token	*prevtok;
	struct decl	**dec;

	ret->type = FDTYPE_ISO;
	t = *tok;
	for (t = *tok; t != NULL; t = t->next) {
		prevtok = t;
		if (t->type == TOK_PAREN_CLOSE) {

			if (t->next == NULL) {
				break;
			}

			if (t->next->type != TOK_COMP_OPEN) {
				if (ret->nargs == 0) {
					/*
					 * This is a declaration and no
					 * arguments are given; -1 indicates
					 * an unknown amount of arguments
					 */
					ret->nargs = -1;
				}
				if (t->next->type == TOK_KEY_ASM) {
					t = t->next;
					ret->asmname
						= parse_asm_varname(&t);
					if (ret->asmname == NULL) {
						return -1;
					}
					t = t->prev;
				}	
			}

#if 0
			/* End of declaration reached */
			if (ret->nargs == 0) {
				/*
				 * This might either be a declaration like
				 * void f();
				 * or a definition like
				 * void f() {
				 * In case of a declaration, -1 indicates
				 * unknown number of arguments.
				 */
				if (t->next != NULL
					&& t->next->type != TOK_COMP_OPEN) {
					ret->nargs = -1;
				}
			}
#endif
			break;
		} else if (IS_TYPE(t)) {
			struct	token	*tmp;

			/* int, unsigned, static, etc or typedef */
			if (ret->variadic) {
				errorfl(t, "`...' must be last argument");
			}
			tmp = t;
			if ((dec = parse_decl(&t, DECL_FUNCARG)) == NULL) {
				return -1;
			}
#ifdef DEBUG2
			printf("parsed declaration:\n");
			puts("--------------");
			while (tmp != t) {
				printf("%s\n", tmp->ascii);
				tmp = tmp->next;
			}
			puts("--------------");
#endif

			if (t && 
				(t->type != TOK_OPERATOR || 
				*(int *)t->data != TOK_OP_COMMA)) {
				if (t->type != TOK_PAREN_CLOSE) { 
					errorfl(t,
						"Syntax error at `%s' - "
						"expected comma", t->ascii);
					return -1;
				} else {
					t = t->prev;
				}
			}
			store_member_func(ret, dec);
		} else {
			/* Garbage or variadic function */
			if (t->type == TOK_OPERATOR) {
				int	i = 0;

				do {
					if (*(int *)t->data
						!= TOK_OP_STRUMEMB) {
						break;
					}
				} while (++i < 3
					&& (t = t->next)
					&& t->type == TOK_OPERATOR); 

				if (i == 3) {
					if (ret->variadic) {
						errorfl(t, "Duplicate use of "
							"`...'");
					}
					ret->variadic = 1;
					if (ret->nargs == 0) {
						errorfl(t, "At least one "
							"argument before `...'"
							"required");
					}
					t = t->next;
					if (t && 
						(t->type != TOK_OPERATOR || 
						*(int *)t->data
							!= TOK_OP_COMMA)) {
						if (t->type
							!= TOK_PAREN_CLOSE) {
							errorfl(t, "Syntax "
								"error at `%s'"
								"- expected "
								"comma",
								t->ascii);
							return -1;
						} else {
							t = t->prev;
						}
					}
					continue;
				}
			}
			errorfl(t,
"Syntax error at `%s' - Expected closing " 
"parentheses or start of parameter declaration",
			t->ascii);
			return -1;
		}
	}

	*tok = t;
	return 0;
}


static void
put_func_name(const char *name) {
	size_t			size = strlen(name) + 1;
	struct decl		*d = alloc_decl();
	struct initializer	*init = alloc_initializer();
	struct ty_string	*ts;
	struct expr		*ex = alloc_expr();
	struct decl		*decls[4];

	ts = make_ty_string(name, size);
	ts->ty->tlist->arrarg = ex;
	ex->const_value = n_xmalloc(sizeof *ex->const_value);
	memset(ex->const_value, 0, sizeof *ex->const_value);
	ex->const_value->str = ts;
	ex->const_value->type = ts->ty;
	init->type = INIT_EXPR;
	init->data = ex;
	ts->ty->storage = TOK_KEY_STATIC;
	d->dtype = ts->ty;
	ts->ty->name = "__func__";
	d->init = init;
	decls[0] = d;
	decls[1] = n_xmemdup(d, sizeof *d);
	decls[1]->dtype = n_xmemdup(decls[1]->dtype, sizeof *decls[1]->dtype);
	decls[1]->dtype->name = "__PRETTY_FUNCTION__";

	/* 09/30/07: BitchX uses __FUNCTION__ */
	decls[2] = n_xmemdup(d, sizeof *d);
	decls[2]->dtype = n_xmemdup(decls[1]->dtype, sizeof *decls[1]->dtype);
	decls[2]->dtype->name = "__FUNCTION__";

	decls[3] = NULL;
	store_decl_scope(curscope, decls);
	decls[1]->dtype->name = decls[0]->dtype->name;
	decls[2]->dtype->name = decls[0]->dtype->name;
#if 0
	decls[1]->is_alias = 1;
#endif
	/*
	 * 070501: Setting a boolean alias flag is not correct. Instead we
	 * must have a pointer to the base declaration, so that access_
	 * symbol() can reference it. And then only define that declaration
	 * in the backend (currently only PowerPC seems to make use of
	 * is_alias at all
	 */
	decls[1]->is_alias = decls[0];
	decls[2]->is_alias = decls[0];
}

/*
 * Must be called with a curtok pointing to the beginning of the function
 * argument list
 * void f(foo)
 *       ^
 * 09/30/07: Now we pass the declaration type to avoid breakage when a
 * cast is read;
 * 
 *    (void(*)())expr;
 *
 * ... here the (kludged) search for the identifier breaks. Maybe we
 * should pass the name instead of searching it here
 */
struct ty_func *
parse_func(struct token **curtok, const char *name) {
	struct token	*t = NULL;
	struct token	*prevtok = NULL;
	struct type	*td = NULL;
	struct ty_func	*ret;
	struct ntab	n = { 0, 0, 0 };
/*	char		*name;*/
  
	ret = alloc_ty_func();

#if 0
	/* XXX kludge */
	for (t = (*curtok)->prev; t->type != TOK_IDENTIFIER; t = t->prev) {
		;
	}
	name = t->ascii;
#endif

	if (next_token(curtok) != 0) {
		free(ret);
		return NULL;
	}
	t = *curtok;
	ret->scope = new_scope(SCOPE_CODE);

	if (t->type == TOK_KEY_VOID) {
		if (t->next != NULL) {
			if (t->next->type == TOK_PAREN_CLOSE) {
#ifdef DEBUG2
				printf("Function takes no arguments\n");
#endif
				*curtok = t->next;
				if (t->next->next
					&& t->next->next->type
						 == TOK_COMP_OPEN) {	
					put_func_name(name);
					CLOSE_SCOPE(t->next->next);
					return ret;
				}
				t = t->next;
#if 0
				CLOSE_SCOPE(t->next->next);
				return ret;
#endif
			}
		} else {
			errorfl(t, "Premature end of file");
			free(ret);
			return NULL;
		}
	}

	/* 
	 * There are two possible definition types:
	 * ISO style or K&R style, i.e.
	 * void f(char *foo, char bar, int x) {
	 * or
	 * void f(foo, bar, x)
	 *     char *foo, bar;
	 *     int   x; {
	 * K&R C has no prototypes, so every paramter declaration
	 * indicates a function definition. Thus, it can be assumed
	 * that the parameter declarations end when the ``{'' token
	 * is encountered.
	 *
	 * If the first node of the token list at this point is an
	 * identifier, we simply assume a K&R declaration, else ISO 
	 */
	if (t->type == TOK_IDENTIFIER
		&& (td = lookup_typedef(curscope, t->data)) == NULL) {
		/* Is K&R declaration */
		if (do_parse_kr_func(&t, ret) != 0) {
			drop_stuff(ret, &n);
			recover(curtok, TOK_PAREN_CLOSE, 0);
			ret = NULL;
		}
	} else {
		/* Is ISO declaration */
		if (do_parse_iso_func(&t, ret) != 0) {
			drop_stuff(ret, &n);
			recover(curtok, TOK_PAREN_CLOSE, 0);
			ret = NULL;
		}
	}

	if (t == NULL) {
		errorfl(prevtok, "Unexpected end of file");
		drop_stuff(ret, ret->type == FDTYPE_KR?
				(void *)&n : (void *)NULL);
		return NULL;
	}

	if (t->next && t->next->type == TOK_COMP_OPEN) {
		put_func_name(name);
	}

	*curtok = t;
	CLOSE_SCOPE(t->next);
	return ret;
}



syntax highlighted by Code2HTML, v. 0.9.1