diff --git a/tools/qfcc/include/struct.h b/tools/qfcc/include/struct.h index 55f4f1108..4f475c94d 100644 --- a/tools/qfcc/include/struct.h +++ b/tools/qfcc/include/struct.h @@ -51,6 +51,7 @@ struct_field_t *new_struct_field (struct type_s *strct, struct type_s *type, struct_field_t *struct_find_field (struct type_s *strct, const char *name); int struct_compare_fields (struct type_s *s1, struct type_s *s2); struct type_s *new_struct (const char *name); +struct type_s *new_union (const char *name); struct type_s *find_struct (const char *name); void copy_struct_fields (struct type_s *dst, struct type_s *src); diff --git a/tools/qfcc/source/qc-lex.l b/tools/qfcc/source/qc-lex.l index 816c3c7c9..649c0f5aa 100644 --- a/tools/qfcc/source/qc-lex.l +++ b/tools/qfcc/source/qc-lex.l @@ -278,6 +278,7 @@ static keyword_t keywords[] = { {"default", DEFAULT, 0, 0, PROG_ID_VERSION}, {"NIL", NIL, 0, 0, PROG_ID_VERSION}, {"struct", STRUCT, 0, 0, PROG_VERSION}, + {"union", UNION, 0, 0, PROG_VERSION}, {"enum", ENUM, 0, 0, PROG_ID_VERSION}, {"typedef", TYPEDEF, 0, 0, PROG_ID_VERSION}, {"super", SUPER, 0, 0, PROG_VERSION}, diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 3da67651c..e26baaf3b 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -126,7 +126,7 @@ void free_local_inits (hashtab_t *def_list); %token LOCAL RETURN WHILE DO IF ELSE FOR BREAK CONTINUE ELLIPSIS NIL %token IFBE IFB IFAE IFA -%token SWITCH CASE DEFAULT STRUCT ENUM TYPEDEF SUPER SELF THIS +%token SWITCH CASE DEFAULT STRUCT UNION ENUM TYPEDEF SUPER SELF THIS %token ARGC ARGV %token ELE_START %token TYPE @@ -197,6 +197,8 @@ def : type { current_type = $1; } def_list | STRUCT NAME { struct_type = new_struct ($2); } '=' '{' struct_defs '}' + | UNION NAME + { struct_type = new_union ($2); } '=' '{' struct_defs '}' | ENUM '{' enum_list opt_comma '}' { process_enum ($3); } | TYPEDEF type NAME @@ -1216,6 +1218,7 @@ reserved_word | DEFAULT { $$ = strdup (yytext); } | NIL { $$ = strdup (yytext); } | STRUCT { $$ = strdup (yytext); } + | UNION { $$ = strdup (yytext); } | ENUM { $$ = strdup (yytext); } | TYPEDEF { $$ = strdup (yytext); } | SUPER { $$ = strdup (yytext); } diff --git a/tools/qfcc/source/struct.c b/tools/qfcc/source/struct.c index dd2a88caa..acc781154 100644 --- a/tools/qfcc/source/struct.c +++ b/tools/qfcc/source/struct.c @@ -57,6 +57,7 @@ static const char rcsid[] = typedef struct { const char *name; type_t *type; + int is_union; } struct_t; typedef struct { @@ -97,8 +98,14 @@ new_struct_field (type_t *strct, type_t *type, const char *name, field->visibility = visibility; field->name = name; field->type = type; - field->offset = strct->num_parms; - strct->num_parms += type_size (type); + if (((struct_t *) strct->class)->is_union) { + int size = type_size (type); + field->offset = 0; + strct->num_parms = strct->num_parms > size ? strct->num_parms : size; + } else { + field->offset = strct->num_parms; + strct->num_parms += type_size (type); + } field->next = 0; *strct->struct_tail = field; strct->struct_tail = &field->next; @@ -136,6 +143,8 @@ new_struct (const char *name) strct->type->type = ev_struct; strct->type->struct_tail = &strct->type->struct_head; strct->type->struct_fields = Hash_NewTable (61, struct_field_get_key, 0, 0); + strct->type->class = (struct class_s *)strct; + strct->is_union = 0; if (name) { strct->type->name = strdup (name); Hash_Add (structs, strct); @@ -143,6 +152,16 @@ new_struct (const char *name) return strct->type; } +type_t * +new_union (const char *name) +{ + type_t *un = new_struct (name); + + if (un) + ((struct_t *) un->class)->is_union = 1; + return un; +} + type_t * find_struct (const char *name) {