diff --git a/tools/qfcc/include/type.h b/tools/qfcc/include/type.h index 363f7030f..b444747e8 100644 --- a/tools/qfcc/include/type.h +++ b/tools/qfcc/include/type.h @@ -32,6 +32,8 @@ #ifndef __type_h #define __type_h +void new_typedef (const char *name, struct type_s *type); +struct type_s *get_typedef (const char *name); struct type_s *pointer_type (struct type_s *aux); void print_type (struct type_s *type); diff --git a/tools/qfcc/source/qc-lex.l b/tools/qfcc/source/qc-lex.l index db5d44bac..ceb1bc123 100644 --- a/tools/qfcc/source/qc-lex.l +++ b/tools/qfcc/source/qc-lex.l @@ -36,6 +36,7 @@ static const char rcsid[] = #include "qfcc.h" #include "scope.h" #include "struct.h" +#include "type.h" #include "qc-parse.h" #define YY_NO_UNPUT @@ -242,6 +243,7 @@ static keyword_t keywords[] = { {"NIL", NIL, 0, PROG_ID_VERSION}, {"struct", STRUCT, 0, PROG_VERSION}, {"enum", ENUM, 0, PROG_ID_VERSION}, + {"typedef", TYPEDEF, 0, PROG_ID_VERSION}, }; static const char * @@ -269,8 +271,7 @@ type_or_name (char *token) yylval.type = keyword->type; return keyword->value; } - type = find_struct (token); - if (type) { + if ((type = find_struct (token)) || (type = get_typedef (token))) { yylval.type = type; return TYPE; } diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index af0eb8369..0c577a235 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -110,7 +110,7 @@ typedef struct { %token LOCAL RETURN WHILE DO IF ELSE FOR BREAK CONTINUE ELIPSIS NIL %token IFBE IFB IFAE IFA -%token SWITCH CASE DEFAULT STRUCT ENUM +%token SWITCH CASE DEFAULT STRUCT ENUM TYPEDEF %token TYPE %type type opt_func func_parms array_decl @@ -160,13 +160,15 @@ def { current_type = build_type ($1, $4); } func_def_list | STRUCT NAME { struct_type = new_struct ($2); } '=' '{' struct_defs '}' - | ENUM '{' enum_list opt_comma '}' opt_name + | ENUM '{' enum_list opt_comma '}' { process_enum ($3); } - ; - -opt_name - : /* empty */ - | NAME {} + | TYPEDEF type NAME + { new_typedef ($3, $2); } + | TYPEDEF ENUM '{' enum_list opt_comma '}' NAME + { + process_enum ($4); + new_typedef ($7, &type_integer); + } ; struct_defs @@ -342,6 +344,8 @@ param type : opt_field TYPE { current_type = $2; } opt_func { $$ = build_type ($1, $4 ? $4 : $2); } + | opt_field TYPE { current_type = $2; } array_decl + { $$ = build_type ($1, $4); } ; opt_var_initializer diff --git a/tools/qfcc/source/type.c b/tools/qfcc/source/type.c index 3c86b75d7..156be6fbe 100644 --- a/tools/qfcc/source/type.c +++ b/tools/qfcc/source/type.c @@ -32,9 +32,54 @@ static const char rcsid[] = #include +#include "QF/hash.h" #include "qfcc.h" +typedef struct { + const char *name; + type_t *type; +} typedef_t; + +static hashtab_t *typedef_hash; + +static const char * +typedef_get_key (void *t, void *unused) +{ + return ((typedef_t *)t)->name; +} + +void +new_typedef (const char *name, type_t *type) +{ + typedef_t *td; + + if (!typedef_hash) + typedef_hash = Hash_NewTable (1023, typedef_get_key, 0, 0); + td = Hash_Find (typedef_hash, name); + if (td) { + error (0, "%s redefined", name); + return; + } + td = malloc (sizeof (typedef_t)); + td->name = name; + td->type = type; + Hash_Add (typedef_hash, td); +} + +type_t * +get_typedef (const char *name) +{ + typedef_t *td; + + if (!typedef_hash) + return 0; + td = Hash_Find (typedef_hash, name); + if (!td) + return 0; + return td->type; +} + type_t * pointer_type (type_t *aux) {