<commit_before>#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>

#include "../util/util.h"
#include "../util/alloc.h"
#include "../util/dynarray.h"
#include "decl_init.h"
#include "funcargs.h"

#include "tokenise.h"
#include "tokconv.h"

#include "sue.h"
#include "sym.h"

#include "cc1.h"
#include "cc1_where.h"

#include "parse_type.h"
#include "parse_expr.h"
#include "parse_attr.h"
#include "parse_init.h"
#include "parse_stmt.h"

#include "expr.h"
#include "type_nav.h"
#include "type_is.h"

#include "fold.h"

/*#define PARSE_DECL_VERBOSE*/

#define PARSE_DECL_IS_FUNC(d) PARSE_type_is(type_skip_non_tdefs(d->ref), type_func)

#define PARSE_type_is_s_or_u_or_e(r) PARSE_type_is_s_or_u_or_e2(r, 1)
#define PARSE_type_is_s_or_u(r)      PARSE_type_is_s_or_u_or_e2(r, 0)

/* we don't do the type_is_* since it needs to be folded for that */
static type *PARSE_type_is(type *t, enum type_kind k)
{
	t = type_skip_non_tdefs(t);
	return t->type == k ? t : NULL;
}

static struct_union_enum_st *PARSE_type_is_s_or_u_or_e2(
		type *r, int allow_e)
{
	r = type_skip_non_tdefs(r);
	if(r->type == type_btype){
		const btype *t = r->bits.type;
		switch(t->primitive){
			case type_enum:
				if(!allow_e)
			default:
					break;
			case type_struct:
			case type_union:
				return t->sue;
		}
	}
	return NULL;
}

/* newdecl_context:
 * struct B { int b; };
 * {
 *   struct A { struct B; }; // this is not a new B
 * };
 */
static type *parse_type_sue(
		enum type_primitive prim,
		int newdecl_context,
		symtable *scope)
{
	int is_complete = 0;
	char *spel = NULL;
	sue_member **members = NULL;
	attribute *this_sue_attr = NULL;

	/* struct __attr__(()) name { ... } ... */
	parse_add_attr(&this_sue_attr, scope);

	if(curtok == token_identifier){
		spel = token_current_spel();
		EAT(token_identifier);
	}

	/* FIXME: struct A { int i; };
	 * struct A __attr__((packed)) a; - affects all struct A instances */
	/* int/struct-A __attr__ */
	parse_add_attr(&this_sue_attr, scope);

	if(accept(token_open_block)){
		if(prim == type_enum){
			for(;;){
				where w;
				expr *e;
				char *sp;
				attribute *en_attr = NULL;

				where_cc1_current(&w);
				sp = token_current_spel();
				EAT(token_identifier);

				parse_add_attr(&en_attr, scope);

				if(accept(token_assign))
					e = PARSE_EXPR_NO_COMMA(scope); /* no commas */
				else
					e = NULL;

				enum_vals_add(&members, &w, sp, e, en_attr);

				if(!accept(token_comma))
					break;

				if(curtok != token_identifier){
					if(cc1_std < STD_C99)
						warn_at(NULL, "trailing comma in enum definition");
					break;
				}
			}

		}else{
			/* always allow nameless structs (C11)
			 * we don't allow tagged ones unless
			 * -fms-extensions or -fplan9-extensions
			 */
			decl **dmembers = NULL;
			decl **i;

			parse_decls_multi_type(
					  DECL_MULTI_CAN_DEFAULT
					| DECL_MULTI_ACCEPT_FIELD_WIDTH
					| DECL_MULTI_NAMELESS
					| DECL_MULTI_ALLOW_ALIGNAS,
					/*newdecl_context:*/0,
					scope,
					NULL, &dmembers);

			if(!dmembers){
				warn_at(NULL, "empty %s", sue_str_type(prim));
			}else{
				for(i = dmembers; *i; i++)
					dynarray_add(&members,
							sue_member_from_decl(*i));

				dynarray_free(decl **, &dmembers, NULL);
			}
		}
		EAT(token_close_block);

		is_complete = 1;

	}else if(!spel){
		die_at(NULL, "expected: %s definition or name", sue_str_type(prim));
	}

	{
		/* struct [tag] <name | '{' | ';'>
		 *
		 * it's a straight declaration if we have a ';'
		 */
		struct_union_enum_st *sue = sue_decl(
				scope, spel,
				members, prim, is_complete,
				/* isdef = */newdecl_context && curtok == token_semicolon);

		parse_add_attr(&this_sue_attr, scope); /* struct A { ... } __attr__ */

		/* sue may already exist */
		attribute_append(&sue->attr, this_sue_attr);

		return type_nav_suetype(cc1_type_nav, sue);
	}
}

void parse_add_attr(attribute **append, symtable *scope)
{
	while(accept(token_attribute)){
		EAT(token_open_paren);
		EAT(token_open_paren);

		if(curtok != token_close_paren)
			attribute_append(append, parse_attr(scope));

		EAT(token_close_paren);
		EAT(token_close_paren);
	}
}

static decl *parse_at_tdef(symtable *scope)
{
	if(curtok == token_identifier){
		decl *d = symtab_search_d(scope, token_current_spel_peek(), NULL);

		if(d && d->store == store_typedef)
			return d;
	}
	return NULL;
}

int parse_at_decl(symtable *scope)
{
	/* this is similar to parse_btype() initial test logic */
	switch(curtok){
		default:
			return curtok_is_type_qual()
				|| curtok_is_decl_store()
				|| curtok_is_type_primitive();

		case token_signed:
		case token_unsigned:
		case token_inline:
		case token__Noreturn:
		case token_struct:
		case token_union:
		case token_enum:
		case token_typeof:
		case token___builtin_va_list:
		case token_attribute:
		case token__Alignas:
			return 1;

		case token_identifier:
			return !!parse_at_tdef(scope);
	}
}

static int parse_at_decl_spec(void)
{
	switch(curtok){
		case token_identifier:
		case token_multiply:
		case token_xor:
		case token_open_paren:
			return 1;
		default:
			return 0;
	}
}

static void btype_set_store(
		enum decl_storage *store, int *pstore_set, enum decl_storage st)
{
	if(!store)
		die_at(NULL, "storage unwanted (%s)", decl_store_to_str(st));

	if(*pstore_set)
		die_at(NULL, "second store %s", decl_store_to_str(st));

	*store = st;
	*pstore_set = 1;
}

static type *parse_btype(
		enum decl_storage *store, struct decl_align **palign,
		int newdecl_context, symtable *scope)
{
	/* *store and *palign should be initialised */
	expr *tdef_typeof = NULL;
	attribute *attr = NULL;
	enum type_qualifier qual = qual_none;
	enum type_primitive primitive = type_int;
	int is_signed = 1, is_inline = 0, had_attr = 0, is_noreturn = 0, is_va_list = 0;
	int store_set = 0, signed_set = 0;
	decl *tdef_decl = NULL;
	enum
	{
		NONE,
		PRIMITIVE_MAYBE_MORE,
		PRIMITIVE_NO_MORE,
		TYPEDEF,
		TYPEOF
	} primitive_mode = NONE;

	for(;;){
		decl *tdef_decl_test;

		if(curtok_is_type_qual()){
			qual |= curtok_to_type_qualifier();
			EAT(curtok);

		}else if(curtok_is_decl_store()){

			btype_set_store(store, &store_set, curtok_to_decl_storage());
			EAT(curtok);

		}else if(curtok_is_type_primitive()){
			const enum type_primitive got = curtok_to_type_primitive();

			switch(primitive_mode){
				case PRIMITIVE_MAYBE_MORE:
					/* allow "long int" and "short int" */
#define INT(x)   x == type_int
#define SHORT(x) x == type_short
#define LONG(x)  x == type_long
#define LLONG(x) x == type_llong
#define DBL(x)   x == type_double

					if(      INT(got) && (SHORT(primitive) || LONG(primitive))){
						/* fine, ignore the int */
					}else if(INT(primitive) && (SHORT(got) || LONG(got))){
						primitive = got;
					}else{
						int die = 1;

						if(primitive_mode == PRIMITIVE_MAYBE_MORE){
							/* special case for long long and long double */
							if(LONG(primitive) && LONG(got))
								primitive = type_llong, die = 0; /* allow "int" after this */
							else if(LLONG(primitive) && INT(got))
								primitive_mode = PRIMITIVE_NO_MORE, die = 0;
							else if((LONG(primitive) && DBL(got)) || (DBL(primitive) && LONG(got)))
								primitive = type_ldouble, die = 0, primitive_mode = PRIMITIVE_NO_MORE;
						}

						if(die)
				case PRIMITIVE_NO_MORE:
							die_at(NULL, "second type primitive %s", type_primitive_to_str(got));
					}
					if(primitive_mode == PRIMITIVE_MAYBE_MORE){
						switch(primitive){
							case type_int:
							case type_long:
							case type_llong:
								/* allow short int, long int and long long and long long int */
								break;
							default:
								primitive_mode = PRIMITIVE_NO_MORE;
						}
					}
					break;

				case NONE:
					primitive = got;
					primitive_mode = PRIMITIVE_MAYBE_MORE;
					break;
				case TYPEDEF:
				case TYPEOF:
					die_at(NULL, "type primitive (%s) with %s",
							type_primitive_to_str(primitive),
							primitive_mode == TYPEDEF ? "typedef-instance" : "typeof");
			}

			EAT(curtok);

		}else if(curtok == token_signed || curtok == token_unsigned){
			is_signed = curtok == token_signed;

			if(signed_set)
				die_at(NULL, "unwanted second \"%ssigned\"", is_signed ? "" : "un");

			signed_set = 1;
			EAT(curtok);

		}else if(curtok == token_inline){
			if(store)
				*store |= store_inline;
			else
				die_at(NULL, "inline not wanted");

			is_inline = 1;
			EAT(curtok);

		}else if(curtok == token__Noreturn){
			is_noreturn = 1;
			EAT(curtok);

		}else if(curtok == token_struct
				|| curtok == token_union
				|| curtok == token_enum)
		{
			const enum token tok = curtok;
			const char *str;
			type *tref;
			int is_qual;

			EAT(curtok);

			switch(tok){
#define CASE(a)                              \
				case token_ ## a:                    \
					tref = parse_type_sue(type_ ## a,  \
							newdecl_context, scope);       \
					str = #a;                          \
					break

				CASE(enum);
				CASE(struct);
				CASE(union);

				default:
					ICE("wat");
			}

			if(signed_set || primitive_mode != NONE)
				die_at(NULL, "primitive/signed/unsigned with %s", str);

			/* fine... although a _Noreturn function returning a sue
			 * is pretty daft... */
			if(is_noreturn)
				tref = type_attributed(tref, attribute_new(attr_noreturn));

			/*
			 * struct A { ... } const x;
			 * accept qualifiers and storage for the type, not decl
			 */
			while((is_qual = curtok_is_type_qual()) || curtok_is_decl_store()){
				if(is_qual)
					qual |= curtok_to_type_qualifier();
				else
					btype_set_store(store, &store_set, curtok_to_decl_storage());
				EAT(curtok);
			}

			/* *store is assigned elsewhere */
			return type_qualify(tref, qual);

		}else if(accept(token_typeof)){
			if(primitive_mode != NONE)
				die_at(NULL, "typeof specifier after primitive");

			tdef_typeof = parse_expr_sizeof_typeof_alignof(what_typeof, scope);
			primitive_mode = TYPEOF;

		}else if(accept(token___builtin_va_list)){
			if(primitive_mode != NONE)
				die_at(NULL, "can't combine previous primitive with va_list");

			primitive_mode = PRIMITIVE_NO_MORE;
			is_va_list = 1;
			primitive = type_struct;

		}else if(!signed_set /* can't sign a typedef */
		&& (tdef_decl_test = parse_at_tdef(scope)))
		{
			/* typedef name or decl:
			 * if we find a decl named this in our scope,
			 * we're a reference to that, not a type, e.g.
			 * typedef int td;
			 * {
			 *   int td;
			 *   td = 2; // "td" found as typedef + decl
			 * }
			 */

			if(primitive_mode != NONE)
				break; /* already got a primitive
								* e.g. typedef int td
								*      { short td; }
								*/

			assert(tdef_decl_test->store == store_typedef);

			tdef_decl = tdef_decl_test;
			tdef_typeof = expr_new_sizeof_type(tdef_decl->ref, what_typeof);

			primitive_mode = TYPEDEF;

			EAT(token_identifier);

		}else if(curtok == token_attribute){
			parse_add_attr(&attr, scope); /* __attr__ int ... */
			had_attr = 1;
			/*
			 * can't depend on !!attr, since it is null when:
			 * __attribute__(());
			 */

		}else if(curtok == token__Alignas){
			struct decl_align *da, **psave;
			type *as_ty;

			if(!palign)
				die_at(NULL, "%s unexpected", token_to_str(curtok));

			for(psave = palign; *psave; psave = &(*psave)->next);

			da = *psave = umalloc(sizeof **palign);

			EAT(token__Alignas);
			EAT(token_open_paren);

			if((as_ty = parse_type(newdecl_context, scope))){
				da->as_int = 0;
				da->bits.align_ty = as_ty;
			}else{
				da->as_int = 1;
				da->bits.align_intk = parse_expr_exp(scope);
			}

			EAT(token_close_paren);

		}else{
			break;
		}
	}

	if(qual != qual_none
	|| store_set
	|| primitive_mode != NONE
	|| signed_set
	|| tdef_typeof
	|| is_inline
	|| had_attr
	|| is_noreturn
	|| (palign && *palign))
	{
		where w;
		type *r;

		where_cc1_current(&w);

		if(signed_set){
			switch(primitive){
				case type__Bool:
				case type_void:
				case type_float:
				case type_double:
				case type_ldouble:
					die_at(NULL, "%ssigned with %s",
							is_signed ? "" : "un",
							type_primitive_to_str(primitive));
					break;

				case type_struct:
				case type_union:
				case type_enum:
				case type_unknown:
					ucc_unreach(NULL);

				case type_schar:
				case type_uchar:
					ucc_unreach(NULL);
				case type_nchar:
					primitive = is_signed ? type_schar : type_uchar;
					break;

				case type_uint:
				case type_ushort:
				case type_ulong:
				case type_ullong:
					ICE("parsed unsigned type?");
				case type_int:
				case type_short:
				case type_long:
				case type_llong:
					if(!is_signed)
						primitive = TYPE_PRIMITIVE_TO_UNSIGNED(primitive);
					break;
			}
		}

		if(is_va_list){
			r = type_nav_va_list(cc1_type_nav);

		}else switch(primitive_mode){
			case TYPEDEF:
			case TYPEOF:
				UCC_ASSERT(tdef_typeof, "no tdef_typeof for typedef/typeof");
				/* signed size_t x; */
				if(signed_set){
					die_at(NULL, "signed/unsigned not allowed with typedef instance (%s)",
							tdef_typeof->bits.ident.spel);
				}

				r = type_tdef_of(tdef_typeof, tdef_decl);
				break;

			case PRIMITIVE_NO_MORE:
			case PRIMITIVE_MAYBE_MORE:
			case NONE:
				if(primitive_mode != NONE && primitive == type_llong)
					C99_LONGLONG();

				if(primitive_mode == NONE && !signed_set)
					primitive = type_int;

				r = type_nav_btype(cc1_type_nav, primitive);
				break;
		}

		if(store
		&& (*store & STORE_MASK_STORE) == store_typedef
		&& palign && *palign)
		{
			die_at(NULL, "typedefs can't be aligned");
		}

		r = type_qualify(r, qual);

		if(is_noreturn)
			attribute_append(&attr, attribute_new(attr_noreturn));

		parse_add_attr(&attr, scope); /* int/struct-A __attr__ */
		r = type_attributed(r, attr);

		return type_at_where(r, &w);
	}else{
		return NULL;
	}
}

static int parse_curtok_is_type(symtable *scope)
{
	if(curtok_is_type_qual()
	|| curtok_is_decl_store()
	|| curtok_is_type_primitive())
		return 1;

	switch(curtok){
		case token_signed:
		case token_unsigned:
		case token_struct:
		case token_union:
		case token_enum:
		case token_typeof:
		case token_attribute:
		case token___builtin_va_list:
			return 1;

		case token_identifier:
			return typedef_visible(scope, token_current_spel_peek());

		default:
			break;
	}

	return 0;
}

static decl *parse_arg_decl(symtable *scope)
{
	/* argument decls can default to int */
	const enum decl_mode flags = DECL_CAN_DEFAULT | DECL_ALLOW_STORE;
	decl *argdecl = parse_decl_single(flags, 0, scope);

	if(!argdecl)
		die_at(NULL, "type expected (got %s)", token_to_str(curtok));

	switch(argdecl->store & STORE_MASK_STORE){
		default:
			parse_had_error = 1;
			warn_at_print_error(NULL, "%s storage on parameter",
					decl_store_to_str(argdecl->store));
			break;

		case store_default:/* aka: no store */
		case store_register:
			break;
	}

	return argdecl;
}

funcargs *parse_func_arglist(symtable *scope)
{
	funcargs *args = funcargs_new();

	if(curtok == token_close_paren)
		goto empty_func;

	/* we allow default-to-int here, but need to make
	 * sure we also handle old functions.
	 *
	 * if we have an ident that isn't a typedef, it's an old-func
	 *
	 * f( <here>  (int)) = f(int (int)) = f(int (*)(int))
	 * f( <here> ident) -> old function
	 */
	if(curtok != token_identifier || parse_at_tdef(scope)){
		decl *argdecl = parse_arg_decl(scope);
		type *ty_v = PARSE_type_is(argdecl->ref, type_btype);

		/* check for x(void) (or an equivalent typedef) */
		/* can't use type_is, since that requires folding */
		if(ty_v
		&& ty_v->bits.type->primitive == type_void
		&& !argdecl->spel)
		{
			/* x(void); */
			funcargs_empty(args);
			args->args_void = 1; /* (void) vs () */
			goto fin;
		}

		for(;;){
			dynarray_add(&args->arglist, argdecl);

			if(curtok == token_close_paren)
				break;

			EAT_OR_DIE(token_comma);

			if(accept(token_elipsis)){
				args->variadic = 1;
				break;
			}

			/* continue loop */
			argdecl = parse_arg_decl(scope);
		}

fin:;

	}else{
		/* old func - list of idents */
		do{
			decl *d = decl_new();

			if(curtok != token_identifier)
				EAT(token_identifier); /* error */

			d->ref = type_nav_btype(cc1_type_nav, type_int);

			d->spel = token_current_spel();
			dynarray_add(&args->arglist, d);

			EAT(token_identifier);

			if(curtok == token_close_paren)
				break;

			EAT_OR_DIE(token_comma);
		}while(1);

		cc1_warn_at(NULL, 0, WARN_OMITTED_PARAM_TYPES,
				"old-style function declaration");
		args->args_old_proto = 1;
	}

empty_func:
	return args;
}

/*

declarator:
		|  '*' declarator
		|  '*' type_qualifier_list declarator
		|  C_NAME
		|  '(' attr_spec_list declarator ')'
		|  '(' declarator ')'
		|  declarator '[' e ']'
		|  declarator '[' ']'
		|  declarator '(' parameter_type_list ')'
		|  declarator '(' identifier_list ')'
		|  declarator '(' ')'
		;
*/

typedef struct type_parsed type_parsed;
struct type_parsed
{
	where where;

	enum type_parsed_kind
	{
		PARSED_PTR,
		PARSED_FUNC,
		PARSED_ARRAY
	} type;

	attribute *attr;

	union
	{
		struct
		{
			type *(*maker)(type *);
			attribute *attr;
			enum type_qualifier qual;
		} ptr;
		struct
		{
			funcargs *arglist;
			symtable *scope;
		} func;
		struct
		{
			expr *size;
			enum type_qualifier qual;
			int is_static;
		} array;
	} bits;

	type_parsed *prev;
};

static type_parsed *parsed_type_ptr(
		enum decl_mode mode, decl *dfor,
		type_parsed *base, symtable *);
#define parsed_type_declarator parsed_type_ptr

static type_parsed *type_parsed_new(
		enum type_parsed_kind kind, type_parsed *prev)
{
	type_parsed *tp = umalloc(sizeof *tp);
	tp->type = kind;
	tp->prev = prev;
	where_cc1_current(&tp->where);
	return tp;
}

static type_parsed *parsed_type_nest(
		enum decl_mode mode, decl *dfor, type_parsed *base, symtable *scope)
{
	if(accept(token_open_paren)){
		type_parsed *ret;

		/*
		 * we could be here:
		 * int (int a) - from either "^int(int...)" or "void f(int (int));"
		 *                                ^                        ^
		 * in which case, we've read the first "int", stop early, and unget the open paren
		 *
		 * we don't look for open parens - they're used for nexting, e.g.
		 * int ((*p)(void));
		 */
		if(parse_curtok_is_type(scope) || curtok == token_close_paren){
			/* int() or char(short) - func decl */
			uneat(token_open_paren);
			/* parse_...func will grab this as funcargs instead */
			return base;
		}

		ret = parsed_type_declarator(mode, dfor, base, scope);
		EAT(token_close_paren);
		return ret;

	}else if(curtok == token_identifier){
		if(!dfor)
			die_at(NULL, "identifier unexpected");

		/* set spel + location info */
		where_cc1_current(&dfor->where);
		dfor->spel = token_current_spel();
		where_cc1_adj_identifier(&dfor->where, dfor->spel);

		EAT(token_identifier);

	}else if(mode & DECL_SPEL_NEED){
		die_at(NULL, "need identifier for decl");
	}

	return base;
}

static type_parsed *parsed_type_array(
		enum decl_mode mode, decl *dfor, type_parsed *base, symtable *scope)
{
	type_parsed *r = parsed_type_nest(mode, dfor, base, scope);

	while(accept(token_open_square)){
		expr *size;
		enum type_qualifier q = qual_none;
		int is_static = 0;

		/* parse int x[restrict|static ...] */
		for(;;){
			if(curtok_is_type_qual())
				q |= curtok_to_type_qualifier();
			else if(curtok == token_static)
				is_static++;
			else
				break;

			EAT(curtok);
		}

		if(accept(token_close_square)){
			/* take size as zero */
			size = NULL;
		}else{
			/* fold.c checks for const-ness */
			/* grammar says it's a conditional here, hence no-comma */
			size = PARSE_EXPR_NO_COMMA(scope);
			EAT(token_close_square);<commit_msg>We can now fold expressions during parse - fixes array types<commit_after>#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>

#include "../util/util.h"
#include "../util/alloc.h"
#include "../util/dynarray.h"
#include "decl_init.h"
#include "funcargs.h"

#include "tokenise.h"
#include "tokconv.h"

#include "sue.h"
#include "sym.h"

#include "cc1.h"
#include "cc1_where.h"

#include "parse_type.h"
#include "parse_expr.h"
#include "parse_attr.h"
#include "parse_init.h"
#include "parse_stmt.h"

#include "expr.h"
#include "type_nav.h"
#include "type_is.h"

#include "fold.h"

/*#define PARSE_DECL_VERBOSE*/

#define PARSE_DECL_IS_FUNC(d) PARSE_type_is(type_skip_non_tdefs(d->ref), type_func)

#define PARSE_type_is_s_or_u_or_e(r) PARSE_type_is_s_or_u_or_e2(r, 1)
#define PARSE_type_is_s_or_u(r)      PARSE_type_is_s_or_u_or_e2(r, 0)

/* we don't do the type_is_* since it needs to be folded for that */
static type *PARSE_type_is(type *t, enum type_kind k)
{
	t = type_skip_non_tdefs(t);
	return t->type == k ? t : NULL;
}

static struct_union_enum_st *PARSE_type_is_s_or_u_or_e2(
		type *r, int allow_e)
{
	r = type_skip_non_tdefs(r);
	if(r->type == type_btype){
		const btype *t = r->bits.type;
		switch(t->primitive){
			case type_enum:
				if(!allow_e)
			default:
					break;
			case type_struct:
			case type_union:
				return t->sue;
		}
	}
	return NULL;
}

/* newdecl_context:
 * struct B { int b; };
 * {
 *   struct A { struct B; }; // this is not a new B
 * };
 */
static type *parse_type_sue(
		enum type_primitive prim,
		int newdecl_context,
		symtable *scope)
{
	int is_complete = 0;
	char *spel = NULL;
	sue_member **members = NULL;
	attribute *this_sue_attr = NULL;

	/* struct __attr__(()) name { ... } ... */
	parse_add_attr(&this_sue_attr, scope);

	if(curtok == token_identifier){
		spel = token_current_spel();
		EAT(token_identifier);
	}

	/* FIXME: struct A { int i; };
	 * struct A __attr__((packed)) a; - affects all struct A instances */
	/* int/struct-A __attr__ */
	parse_add_attr(&this_sue_attr, scope);

	if(accept(token_open_block)){
		if(prim == type_enum){
			for(;;){
				where w;
				expr *e;
				char *sp;
				attribute *en_attr = NULL;

				where_cc1_current(&w);
				sp = token_current_spel();
				EAT(token_identifier);

				parse_add_attr(&en_attr, scope);

				if(accept(token_assign))
					e = PARSE_EXPR_NO_COMMA(scope); /* no commas */
				else
					e = NULL;

				enum_vals_add(&members, &w, sp, e, en_attr);

				if(!accept(token_comma))
					break;

				if(curtok != token_identifier){
					if(cc1_std < STD_C99)
						warn_at(NULL, "trailing comma in enum definition");
					break;
				}
			}

		}else{
			/* always allow nameless structs (C11)
			 * we don't allow tagged ones unless
			 * -fms-extensions or -fplan9-extensions
			 */
			decl **dmembers = NULL;
			decl **i;

			parse_decls_multi_type(
					  DECL_MULTI_CAN_DEFAULT
					| DECL_MULTI_ACCEPT_FIELD_WIDTH
					| DECL_MULTI_NAMELESS
					| DECL_MULTI_ALLOW_ALIGNAS,
					/*newdecl_context:*/0,
					scope,
					NULL, &dmembers);

			if(!dmembers){
				warn_at(NULL, "empty %s", sue_str_type(prim));
			}else{
				for(i = dmembers; *i; i++)
					dynarray_add(&members,
							sue_member_from_decl(*i));

				dynarray_free(decl **, &dmembers, NULL);
			}
		}
		EAT(token_close_block);

		is_complete = 1;

	}else if(!spel){
		die_at(NULL, "expected: %s definition or name", sue_str_type(prim));
	}

	{
		/* struct [tag] <name | '{' | ';'>
		 *
		 * it's a straight declaration if we have a ';'
		 */
		struct_union_enum_st *sue = sue_decl(
				scope, spel,
				members, prim, is_complete,
				/* isdef = */newdecl_context && curtok == token_semicolon);

		parse_add_attr(&this_sue_attr, scope); /* struct A { ... } __attr__ */

		/* sue may already exist */
		attribute_append(&sue->attr, this_sue_attr);

		return type_nav_suetype(cc1_type_nav, sue);
	}
}

void parse_add_attr(attribute **append, symtable *scope)
{
	while(accept(token_attribute)){
		EAT(token_open_paren);
		EAT(token_open_paren);

		if(curtok != token_close_paren)
			attribute_append(append, parse_attr(scope));

		EAT(token_close_paren);
		EAT(token_close_paren);
	}
}

static decl *parse_at_tdef(symtable *scope)
{
	if(curtok == token_identifier){
		decl *d = symtab_search_d(scope, token_current_spel_peek(), NULL);

		if(d && d->store == store_typedef)
			return d;
	}
	return NULL;
}

int parse_at_decl(symtable *scope)
{
	/* this is similar to parse_btype() initial test logic */
	switch(curtok){
		default:
			return curtok_is_type_qual()
				|| curtok_is_decl_store()
				|| curtok_is_type_primitive();

		case token_signed:
		case token_unsigned:
		case token_inline:
		case token__Noreturn:
		case token_struct:
		case token_union:
		case token_enum:
		case token_typeof:
		case token___builtin_va_list:
		case token_attribute:
		case token__Alignas:
			return 1;

		case token_identifier:
			return !!parse_at_tdef(scope);
	}
}

static int parse_at_decl_spec(void)
{
	switch(curtok){
		case token_identifier:
		case token_multiply:
		case token_xor:
		case token_open_paren:
			return 1;
		default:
			return 0;
	}
}

static void btype_set_store(
		enum decl_storage *store, int *pstore_set, enum decl_storage st)
{
	if(!store)
		die_at(NULL, "storage unwanted (%s)", decl_store_to_str(st));

	if(*pstore_set)
		die_at(NULL, "second store %s", decl_store_to_str(st));

	*store = st;
	*pstore_set = 1;
}

static type *parse_btype(
		enum decl_storage *store, struct decl_align **palign,
		int newdecl_context, symtable *scope)
{
	/* *store and *palign should be initialised */
	expr *tdef_typeof = NULL;
	attribute *attr = NULL;
	enum type_qualifier qual = qual_none;
	enum type_primitive primitive = type_int;
	int is_signed = 1, is_inline = 0, had_attr = 0, is_noreturn = 0, is_va_list = 0;
	int store_set = 0, signed_set = 0;
	decl *tdef_decl = NULL;
	enum
	{
		NONE,
		PRIMITIVE_MAYBE_MORE,
		PRIMITIVE_NO_MORE,
		TYPEDEF,
		TYPEOF
	} primitive_mode = NONE;

	for(;;){
		decl *tdef_decl_test;

		if(curtok_is_type_qual()){
			qual |= curtok_to_type_qualifier();
			EAT(curtok);

		}else if(curtok_is_decl_store()){

			btype_set_store(store, &store_set, curtok_to_decl_storage());
			EAT(curtok);

		}else if(curtok_is_type_primitive()){
			const enum type_primitive got = curtok_to_type_primitive();

			switch(primitive_mode){
				case PRIMITIVE_MAYBE_MORE:
					/* allow "long int" and "short int" */
#define INT(x)   x == type_int
#define SHORT(x) x == type_short
#define LONG(x)  x == type_long
#define LLONG(x) x == type_llong
#define DBL(x)   x == type_double

					if(      INT(got) && (SHORT(primitive) || LONG(primitive))){
						/* fine, ignore the int */
					}else if(INT(primitive) && (SHORT(got) || LONG(got))){
						primitive = got;
					}else{
						int die = 1;

						if(primitive_mode == PRIMITIVE_MAYBE_MORE){
							/* special case for long long and long double */
							if(LONG(primitive) && LONG(got))
								primitive = type_llong, die = 0; /* allow "int" after this */
							else if(LLONG(primitive) && INT(got))
								primitive_mode = PRIMITIVE_NO_MORE, die = 0;
							else if((LONG(primitive) && DBL(got)) || (DBL(primitive) && LONG(got)))
								primitive = type_ldouble, die = 0, primitive_mode = PRIMITIVE_NO_MORE;
						}

						if(die)
				case PRIMITIVE_NO_MORE:
							die_at(NULL, "second type primitive %s", type_primitive_to_str(got));
					}
					if(primitive_mode == PRIMITIVE_MAYBE_MORE){
						switch(primitive){
							case type_int:
							case type_long:
							case type_llong:
								/* allow short int, long int and long long and long long int */
								break;
							default:
								primitive_mode = PRIMITIVE_NO_MORE;
						}
					}
					break;

				case NONE:
					primitive = got;
					primitive_mode = PRIMITIVE_MAYBE_MORE;
					break;
				case TYPEDEF:
				case TYPEOF:
					die_at(NULL, "type primitive (%s) with %s",
							type_primitive_to_str(primitive),
							primitive_mode == TYPEDEF ? "typedef-instance" : "typeof");
			}

			EAT(curtok);

		}else if(curtok == token_signed || curtok == token_unsigned){
			is_signed = curtok == token_signed;

			if(signed_set)
				die_at(NULL, "unwanted second \"%ssigned\"", is_signed ? "" : "un");

			signed_set = 1;
			EAT(curtok);

		}else if(curtok == token_inline){
			if(store)
				*store |= store_inline;
			else
				die_at(NULL, "inline not wanted");

			is_inline = 1;
			EAT(curtok);

		}else if(curtok == token__Noreturn){
			is_noreturn = 1;
			EAT(curtok);

		}else if(curtok == token_struct
				|| curtok == token_union
				|| curtok == token_enum)
		{
			const enum token tok = curtok;
			const char *str;
			type *tref;
			int is_qual;

			EAT(curtok);

			switch(tok){
#define CASE(a)                              \
				case token_ ## a:                    \
					tref = parse_type_sue(type_ ## a,  \
							newdecl_context, scope);       \
					str = #a;                          \
					break

				CASE(enum);
				CASE(struct);
				CASE(union);

				default:
					ICE("wat");
			}

			if(signed_set || primitive_mode != NONE)
				die_at(NULL, "primitive/signed/unsigned with %s", str);

			/* fine... although a _Noreturn function returning a sue
			 * is pretty daft... */
			if(is_noreturn)
				tref = type_attributed(tref, attribute_new(attr_noreturn));

			/*
			 * struct A { ... } const x;
			 * accept qualifiers and storage for the type, not decl
			 */
			while((is_qual = curtok_is_type_qual()) || curtok_is_decl_store()){
				if(is_qual)
					qual |= curtok_to_type_qualifier();
				else
					btype_set_store(store, &store_set, curtok_to_decl_storage());
				EAT(curtok);
			}

			/* *store is assigned elsewhere */
			return type_qualify(tref, qual);

		}else if(accept(token_typeof)){
			if(primitive_mode != NONE)
				die_at(NULL, "typeof specifier after primitive");

			tdef_typeof = parse_expr_sizeof_typeof_alignof(what_typeof, scope);
			primitive_mode = TYPEOF;

		}else if(accept(token___builtin_va_list)){
			if(primitive_mode != NONE)
				die_at(NULL, "can't combine previous primitive with va_list");

			primitive_mode = PRIMITIVE_NO_MORE;
			is_va_list = 1;
			primitive = type_struct;

		}else if(!signed_set /* can't sign a typedef */
		&& (tdef_decl_test = parse_at_tdef(scope)))
		{
			/* typedef name or decl:
			 * if we find a decl named this in our scope,
			 * we're a reference to that, not a type, e.g.
			 * typedef int td;
			 * {
			 *   int td;
			 *   td = 2; // "td" found as typedef + decl
			 * }
			 */

			if(primitive_mode != NONE)
				break; /* already got a primitive
								* e.g. typedef int td
								*      { short td; }
								*/

			assert(tdef_decl_test->store == store_typedef);

			tdef_decl = tdef_decl_test;
			tdef_typeof = expr_new_sizeof_type(tdef_decl->ref, what_typeof);

			primitive_mode = TYPEDEF;

			EAT(token_identifier);

		}else if(curtok == token_attribute){
			parse_add_attr(&attr, scope); /* __attr__ int ... */
			had_attr = 1;
			/*
			 * can't depend on !!attr, since it is null when:
			 * __attribute__(());
			 */

		}else if(curtok == token__Alignas){
			struct decl_align *da, **psave;
			type *as_ty;

			if(!palign)
				die_at(NULL, "%s unexpected", token_to_str(curtok));

			for(psave = palign; *psave; psave = &(*psave)->next);

			da = *psave = umalloc(sizeof **palign);

			EAT(token__Alignas);
			EAT(token_open_paren);

			if((as_ty = parse_type(newdecl_context, scope))){
				da->as_int = 0;
				da->bits.align_ty = as_ty;
			}else{
				da->as_int = 1;
				da->bits.align_intk = parse_expr_exp(scope);
			}

			EAT(token_close_paren);

		}else{
			break;
		}
	}

	if(qual != qual_none
	|| store_set
	|| primitive_mode != NONE
	|| signed_set
	|| tdef_typeof
	|| is_inline
	|| had_attr
	|| is_noreturn
	|| (palign && *palign))
	{
		where w;
		type *r;

		where_cc1_current(&w);

		if(signed_set){
			switch(primitive){
				case type__Bool:
				case type_void:
				case type_float:
				case type_double:
				case type_ldouble:
					die_at(NULL, "%ssigned with %s",
							is_signed ? "" : "un",
							type_primitive_to_str(primitive));
					break;

				case type_struct:
				case type_union:
				case type_enum:
				case type_unknown:
					ucc_unreach(NULL);

				case type_schar:
				case type_uchar:
					ucc_unreach(NULL);
				case type_nchar:
					primitive = is_signed ? type_schar : type_uchar;
					break;

				case type_uint:
				case type_ushort:
				case type_ulong:
				case type_ullong:
					ICE("parsed unsigned type?");
				case type_int:
				case type_short:
				case type_long:
				case type_llong:
					if(!is_signed)
						primitive = TYPE_PRIMITIVE_TO_UNSIGNED(primitive);
					break;
			}
		}

		if(is_va_list){
			r = type_nav_va_list(cc1_type_nav);

		}else switch(primitive_mode){
			case TYPEDEF:
			case TYPEOF:
				UCC_ASSERT(tdef_typeof, "no tdef_typeof for typedef/typeof");
				/* signed size_t x; */
				if(signed_set){
					die_at(NULL, "signed/unsigned not allowed with typedef instance (%s)",
							tdef_typeof->bits.ident.spel);
				}

				r = type_tdef_of(tdef_typeof, tdef_decl);
				break;

			case PRIMITIVE_NO_MORE:
			case PRIMITIVE_MAYBE_MORE:
			case NONE:
				if(primitive_mode != NONE && primitive == type_llong)
					C99_LONGLONG();

				if(primitive_mode == NONE && !signed_set)
					primitive = type_int;

				r = type_nav_btype(cc1_type_nav, primitive);
				break;
		}

		if(store
		&& (*store & STORE_MASK_STORE) == store_typedef
		&& palign && *palign)
		{
			die_at(NULL, "typedefs can't be aligned");
		}

		r = type_qualify(r, qual);

		if(is_noreturn)
			attribute_append(&attr, attribute_new(attr_noreturn));

		parse_add_attr(&attr, scope); /* int/struct-A __attr__ */
		r = type_attributed(r, attr);

		return type_at_where(r, &w);
	}else{
		return NULL;
	}
}

static int parse_curtok_is_type(symtable *scope)
{
	if(curtok_is_type_qual()
	|| curtok_is_decl_store()
	|| curtok_is_type_primitive())
		return 1;

	switch(curtok){
		case token_signed:
		case token_unsigned:
		case token_struct:
		case token_union:
		case token_enum:
		case token_typeof:
		case token_attribute:
		case token___builtin_va_list:
			return 1;

		case token_identifier:
			return typedef_visible(scope, token_current_spel_peek());

		default:
			break;
	}

	return 0;
}

static decl *parse_arg_decl(symtable *scope)
{
	/* argument decls can default to int */
	const enum decl_mode flags = DECL_CAN_DEFAULT | DECL_ALLOW_STORE;
	decl *argdecl = parse_decl_single(flags, 0, scope);

	if(!argdecl)
		die_at(NULL, "type expected (got %s)", token_to_str(curtok));

	switch(argdecl->store & STORE_MASK_STORE){
		default:
			parse_had_error = 1;
			warn_at_print_error(NULL, "%s storage on parameter",
					decl_store_to_str(argdecl->store));
			break;

		case store_default:/* aka: no store */
		case store_register:
			break;
	}

	return argdecl;
}

funcargs *parse_func_arglist(symtable *scope)
{
	funcargs *args = funcargs_new();

	if(curtok == token_close_paren)
		goto empty_func;

	/* we allow default-to-int here, but need to make
	 * sure we also handle old functions.
	 *
	 * if we have an ident that isn't a typedef, it's an old-func
	 *
	 * f( <here>  (int)) = f(int (int)) = f(int (*)(int))
	 * f( <here> ident) -> old function
	 */
	if(curtok != token_identifier || parse_at_tdef(scope)){
		decl *argdecl = parse_arg_decl(scope);
		type *ty_v = PARSE_type_is(argdecl->ref, type_btype);

		/* check for x(void) (or an equivalent typedef) */
		/* can't use type_is, since that requires folding */
		if(ty_v
		&& ty_v->bits.type->primitive == type_void
		&& !argdecl->spel)
		{
			/* x(void); */
			funcargs_empty(args);
			args->args_void = 1; /* (void) vs () */
			goto fin;
		}

		for(;;){
			dynarray_add(&args->arglist, argdecl);

			if(curtok == token_close_paren)
				break;

			EAT_OR_DIE(token_comma);

			if(accept(token_elipsis)){
				args->variadic = 1;
				break;
			}

			/* continue loop */
			argdecl = parse_arg_decl(scope);
		}

fin:;

	}else{
		/* old func - list of idents */
		do{
			decl *d = decl_new();

			if(curtok != token_identifier)
				EAT(token_identifier); /* error */

			d->ref = type_nav_btype(cc1_type_nav, type_int);

			d->spel = token_current_spel();
			dynarray_add(&args->arglist, d);

			EAT(token_identifier);

			if(curtok == token_close_paren)
				break;

			EAT_OR_DIE(token_comma);
		}while(1);

		cc1_warn_at(NULL, 0, WARN_OMITTED_PARAM_TYPES,
				"old-style function declaration");
		args->args_old_proto = 1;
	}

empty_func:
	return args;
}

/*

declarator:
		|  '*' declarator
		|  '*' type_qualifier_list declarator
		|  C_NAME
		|  '(' attr_spec_list declarator ')'
		|  '(' declarator ')'
		|  declarator '[' e ']'
		|  declarator '[' ']'
		|  declarator '(' parameter_type_list ')'
		|  declarator '(' identifier_list ')'
		|  declarator '(' ')'
		;
*/

typedef struct type_parsed type_parsed;
struct type_parsed
{
	where where;

	enum type_parsed_kind
	{
		PARSED_PTR,
		PARSED_FUNC,
		PARSED_ARRAY
	} type;

	attribute *attr;

	union
	{
		struct
		{
			type *(*maker)(type *);
			attribute *attr;
			enum type_qualifier qual;
		} ptr;
		struct
		{
			funcargs *arglist;
			symtable *scope;
		} func;
		struct
		{
			expr *size;
			enum type_qualifier qual;
			int is_static;
		} array;
	} bits;

	type_parsed *prev;
};

static type_parsed *parsed_type_ptr(
		enum decl_mode mode, decl *dfor,
		type_parsed *base, symtable *);
#define parsed_type_declarator parsed_type_ptr

static type_parsed *type_parsed_new(
		enum type_parsed_kind kind, type_parsed *prev)
{
	type_parsed *tp = umalloc(sizeof *tp);
	tp->type = kind;
	tp->prev = prev;
	where_cc1_current(&tp->where);
	return tp;
}

static type_parsed *parsed_type_nest(
		enum decl_mode mode, decl *dfor, type_parsed *base, symtable *scope)
{
	if(accept(token_open_paren)){
		type_parsed *ret;

		/*
		 * we could be here:
		 * int (int a) - from either "^int(int...)" or "void f(int (int));"
		 *                                ^                        ^
		 * in which case, we've read the first "int", stop early, and unget the open paren
		 *
		 * we don't look for open parens - they're used for nexting, e.g.
		 * int ((*p)(void));
		 */
		if(parse_curtok_is_type(scope) || curtok == token_close_paren){
			/* int() or char(short) - func decl */
			uneat(token_open_paren);
			/* parse_...func will grab this as funcargs instead */
			return base;
		}

		ret = parsed_type_declarator(mode, dfor, base, scope);
		EAT(token_close_paren);
		return ret;

	}else if(curtok == token_identifier){
		if(!dfor)
			die_at(NULL, "identifier unexpected");

		/* set spel + location info */
		where_cc1_current(&dfor->where);
		dfor->spel = token_current_spel();
		where_cc1_adj_identifier(&dfor->where, dfor->spel);

		EAT(token_identifier);

	}else if(mode & DECL_SPEL_NEED){
		die_at(NULL, "need identifier for decl");
	}

	return base;
}

static type_parsed *parsed_type_array(
		enum decl_mode mode, decl *dfor, type_parsed *base, symtable *scope)
{
	type_parsed *r = parsed_type_nest(mode, dfor, base, scope);

	while(accept(token_open_square)){
		expr *size;
		enum type_qualifier q = qual_none;
		int is_static = 0;

		/* parse int x[restrict|static ...] */
		for(;;){
			if(curtok_is_type_qual())
				q |= curtok_to_type_qualifier();
			else if(curtok == token_static)
				is_static++;
			else
				break;

			EAT(curtok);
		}

		if(accept(token_close_square)){
			/* take size as zero */
			size = NULL;
		}else{
			/* fold.c checks for const-ness */
			/* grammar says it's a conditional here, hence no-comma */
			size = PARSE_EXPR_NO_COMMA(scope);
			EAT(token_close_square);

			FOLD_EXPR(size, scope);
{'fraction_non_alphanumeric': 0.13128840612968204, 'fraction_numerical': 0.0031617328335755627, 'mean_word_length': 3.3108375467135636, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 95, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '312669', 'n_tokens_mistral': 17523, 'n_tokens_neox': 14784, 'n_words': 3232}