From 9b81bc5ea6ede37251df47bd571b57e2d2170fc7 Mon Sep 17 00:00:00 2001
From: Bill Currie <bill@taniwha.org>
Date: Sat, 13 Nov 2004 04:02:00 +0000
Subject: [PATCH] allow access to the parameter type via @param and variable
 initializers for local arrays/structs.

This is an imperfect revision of history.
---
 tools/qfcc/source/expr.c   | 25 ++++++++++++++++++++-----
 tools/qfcc/source/qc-lex.l |  1 +
 tools/qfcc/source/type.c   | 14 +++++++-------
 3 files changed, 28 insertions(+), 12 deletions(-)

diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c
index 3099a3a64..304a3a7e5 100644
--- a/tools/qfcc/source/expr.c
+++ b/tools/qfcc/source/expr.c
@@ -2495,15 +2495,18 @@ void
 init_elements (def_t *def, expr_t *eles)
 {
 	expr_t     *e, *c;
-	int         count, i, num_params;
+	int         count, i, num_params, ofs;
 	pr_type_t  *g;
 	def_t      *elements;
 
+	ofs = def->ofs;
+	if (def->local && local_expr)
+		ofs = 0;
 	if (def->type->type == ev_array) {
 		elements = calloc (def->type->num_parms, sizeof (def_t));
 		for (i = 0; i < def->type->num_parms; i++) {
 			elements[i].type = def->type->aux_type;
-			elements[i].ofs = def->ofs + i * type_size (def->type->aux_type);
+			elements[i].ofs = ofs + i * type_size (def->type->aux_type);
 		}
 		num_params = i;
 	} else if (def->type->type == ev_struct) {
@@ -2516,7 +2519,7 @@ init_elements (def_t *def, expr_t *eles)
 		for (i = 0, field = def->type->s.strct->struct_head; field;
 			 i++, field = field->next) {
 			elements[i].type = field->type;
-			elements[i].ofs = def->ofs + field->offset;
+			elements[i].ofs = ofs + field->offset;
 		}
 		num_params = i;
 	} else {
@@ -2543,6 +2546,7 @@ init_elements (def_t *def, expr_t *eles)
 				continue;
 			}
 			init_elements (&elements[i], c);
+			continue;
 		} else if (c->type >= ex_string) {
 			if (c->type == ex_integer
 				&& elements[i].type->type == ev_float)
@@ -2560,13 +2564,24 @@ init_elements (def_t *def, expr_t *eles)
 				error (e, "type mismatch in initializer");
 				continue;
 			}
+		} else {
+			if (!def->local || !local_expr) {
+				error (e, "non-constant initializer");
+				continue;
+			}
+		}
+		if (def->local && local_expr) {
+			int         ofs = elements[i].ofs;
+			type_t     *type = elements[i].type;
+			expr_t     *ptr = new_pointer_expr (ofs, type, def);
+
+			append_expr (local_expr, assign_expr (unary_expr ('.', ptr), c));
+		} else {
 			if (c->type == ex_string) {
 				EMIT_STRING (g->string_var, c->e.string_val);
 			} else {
 				memcpy (g, &c->e, type_size (get_type (c)) * 4);
 			}
-		} else {
-			error (e, "non-constant initializer");
 		}
 	}
 	free (elements);
diff --git a/tools/qfcc/source/qc-lex.l b/tools/qfcc/source/qc-lex.l
index 23233230b..80f326172 100644
--- a/tools/qfcc/source/qc-lex.l
+++ b/tools/qfcc/source/qc-lex.l
@@ -339,6 +339,7 @@ static keyword_t keywords[] = {
 	{"@argc",		ARGC,	0,					0, PROG_VERSION},
 	{"@argv",		ARGV,	0,					0, PROG_VERSION},
 	{"@va_list",	TYPE,	&type_va_list,		0, PROG_VERSION},
+	{"@param",		TYPE,	&type_param,		0, PROG_VERSION},
 	{"@extern",		EXTERN,	0,					1, PROG_ID_VERSION},
 	{"@static",		STATIC,	0,					1, PROG_ID_VERSION},
 	{"@system",		SYSTEM,	0,					1, PROG_ID_VERSION},
diff --git a/tools/qfcc/source/type.c b/tools/qfcc/source/type.c
index b04e67c06..48c41fd18 100644
--- a/tools/qfcc/source/type.c
+++ b/tools/qfcc/source/type.c
@@ -89,8 +89,8 @@ type_t      type_method_description = { ev_struct, "obj_method_description" };
 type_t     *type_category;
 type_t     *type_ivar;
 type_t     *type_module;
-type_t      type_va_list;
-type_t      type_param;
+type_t      type_va_list = { ev_struct, "@va_list" };
+type_t      type_param = { ev_struct, "@param" };
 type_t      type_zero;
 
 struct_t   *vector_struct;
@@ -751,11 +751,6 @@ init_types (void)
 	new_struct_field (strct, &type_integer, "ivar_offset", vis_public);
 	type_ivar = strct->type;
 
-	strct = calloc (sizeof (struct_t), 1);
-	init_struct (strct, &type_va_list, str_union, 0);
-	new_struct_field (strct, &type_integer, "count", vis_public);
-	new_struct_field (strct, pointer_type (&type_param), "list", vis_public);
-
 	strct = get_struct ("Super", 1);
 	init_struct (strct, new_type (), str_struct, 0);
 	new_struct_field (strct, &type_id, "self", vis_public);
@@ -811,6 +806,11 @@ chain_initial_types (void)
 	type_supermsg.parm_types[0] = &type_Super;
 	chain_type (&type_supermsg);
 
+	strct = calloc (sizeof (struct_t), 1);
+	init_struct (strct, &type_va_list, str_struct, 0);
+	new_struct_field (strct, &type_integer, "count", vis_public);
+	new_struct_field (strct, pointer_type (&type_param), "list", vis_public);
+
 	strct = get_struct ("obj_module_s", 1);
 	init_struct (strct, new_type (), str_struct, 0);
 	new_struct_field (strct, &type_integer, "version", vis_public);