diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index d11b5d05c..b8ec8f9f5 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -128,6 +128,7 @@ expr_t *new_binary_expr (int op, expr_t *e1, expr_t *e2); expr_t *new_unary_expr (int op, expr_t *e1); expr_t *new_temp_def_expr (type_t *type); expr_t *new_bind_expr (expr_t *e1, expr_t *e2); +expr_t *new_name_expr (const char *name); void inc_users (expr_t *e); diff --git a/tools/qfcc/include/struct.h b/tools/qfcc/include/struct.h index bfab99fe8..69c169d05 100644 --- a/tools/qfcc/include/struct.h +++ b/tools/qfcc/include/struct.h @@ -45,4 +45,7 @@ struct_field_t *struct_find_field (struct type_s *strct, const char *name); struct type_s *new_struct (const char *name); struct type_s *find_struct (const char *name); +void process_enum (struct expr_s *enm); +expr_t *get_enum (const char *name); + #endif//__struct_h diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 8a15dc79e..ccf823169 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -103,14 +103,22 @@ void convert_name (expr_t *e) { if (e->type == ex_name) { - const char * name = e->e.string_val; + const char *name = e->e.string_val; + def_t *d = PR_GetDef (NULL, name, pr_scope, 0); + expr_t *enm; - e->type = ex_def; - e->e.def = PR_GetDef (NULL, name, pr_scope, false); - if (!e->e.def) { - error (e, "Undeclared variable \"%s\".", name); - e->e.def = &def_float; + if (d) { + e->type = ex_def; + e->e.def = d; + return; } + enm = get_enum (name); + if (enm) { + e->type = ex_integer; + e->e.integer_val = enm->e.integer_val; + return; + } + error (e, "Undeclared variable \"%s\".", name); } } @@ -418,6 +426,15 @@ new_bind_expr (expr_t *e1, expr_t *e2) return e; } +expr_t * +new_name_expr (const char *name) +{ + expr_t *e = new_expr (); + e->type = ex_name; + e->e.string_val = name; + return e; +} + expr_t * append_expr (expr_t *block, expr_t *e) { diff --git a/tools/qfcc/source/pr_def.c b/tools/qfcc/source/pr_def.c index 2669814a0..f8e385510 100644 --- a/tools/qfcc/source/pr_def.c +++ b/tools/qfcc/source/pr_def.c @@ -26,6 +26,7 @@ static const char rcsid[] = #include #include "qfcc.h" +#include "struct.h" typedef struct locref_s { struct locref_s *next; @@ -60,6 +61,10 @@ check_for_name (type_t *type, const char *name, def_t *scope, int *allocate) if (!defs_by_name) { defs_by_name = Hash_NewTable (16381, defs_get_key, 0, &defs_by_name); } + if (!scope && (find_struct (name) || get_enum (name))) { + error (0, "%s redeclared", name); + return 0; + } // see if the name is already in use def = (def_t *) Hash_Find (defs_by_name, name); if (def) { diff --git a/tools/qfcc/source/qc-lex.l b/tools/qfcc/source/qc-lex.l index ef5eee7cc..db5d44bac 100644 --- a/tools/qfcc/source/qc-lex.l +++ b/tools/qfcc/source/qc-lex.l @@ -241,6 +241,7 @@ static keyword_t keywords[] = { {"default", DEFAULT, 0, PROG_ID_VERSION}, {"NIL", NIL, 0, PROG_ID_VERSION}, {"struct", STRUCT, 0, PROG_VERSION}, + {"enum", ENUM, 0, PROG_ID_VERSION}, }; static const char * diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index d1f326461..4a0af9791 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 +%token SWITCH CASE DEFAULT STRUCT ENUM %token TYPE %type type opt_func func_parms array_decl @@ -120,7 +120,7 @@ typedef struct { %type func_def_item func_def_list %type const opt_expr expr arg_list element_list element_list1 element %type statement statements statement_block -%type break_label continue_label +%type break_label continue_label enum_list enum %type begin_function %type save_inits %type switch_block @@ -160,6 +160,8 @@ def { current_type = build_type ($1, $4); } func_def_list | STRUCT NAME { struct_type = new_struct ($2); } '=' '{' struct_defs '}' + | ENUM '{' enum_list opt_comma '}' + { process_enum ($3); } ; struct_defs @@ -176,6 +178,34 @@ struct_def { current_type = build_type ($1, $4); } struct_def_list ; +enum_list + : enum + | enum_list ',' enum + { + if ($3) { + $3->next = $1; + $$ = $3; + } else { + $$ = $1; + } + } + ; + +enum + : NAME { $$ = new_name_expr ($1); } + | NAME '=' expr + { + $$ = 0; + if ($3->type < ex_string) { + error ($3, "non-constant initializer"); + } else if ($3->type != ex_integer) { + error ($3, "invalid initializer type"); + } else { + $$ = new_binary_expr ('=', new_name_expr ($1), $3); + } + } + ; + opt_field : /* empty */ { $$ = 0; } | '.' { $$ = 1; } @@ -251,7 +281,7 @@ var_def_item : def_name opt_var_initializer { $$ = $1; - if (!$$->scope && $$->type->type != ev_func) + if ($$ && !$$->scope && $$->type->type != ev_func) PR_DefInitialized ($$); } ; @@ -758,12 +788,7 @@ expr | '&' expr %prec UNARY { $$ = address_expr ($2, 0, 0); } | INCOP expr { $$ = incop_expr ($1, $2, 0); } | expr INCOP { $$ = incop_expr ($2, $1, 1); } - | NAME - { - $$ = new_expr (); - $$->type = ex_name; - $$->e.string_val = $1; - } + | NAME { $$ = new_name_expr ($1); } | const { $$ = $1; } | '(' expr ')' { $$ = $2; $$->paren = 1; } ; diff --git a/tools/qfcc/source/struct.c b/tools/qfcc/source/struct.c index 5beee24f0..fbb4c7b50 100644 --- a/tools/qfcc/source/struct.c +++ b/tools/qfcc/source/struct.c @@ -31,6 +31,7 @@ static const char rcsid[] = "$Id$"; #include +#include #include "qfcc.h" #include "struct.h" @@ -40,7 +41,13 @@ typedef struct { type_t *type; } struct_t; +typedef struct { + const char *name; + expr_t value; +} enum_t; + static hashtab_t *structs; +static hashtab_t *enums; static const char * structs_get_key (void *s, void *unused) @@ -54,6 +61,12 @@ struct_field_get_key (void *f, void *unused) return ((struct_field_t *) f)->name; } +static const char * +enums_get_key (void *e, void *unused) +{ + return ((enum_t *) e)->name; +} + struct_field_t * new_struct_field (type_t *strct, type_t *type, const char *name) { @@ -116,3 +129,60 @@ find_struct (const char *name) return strct->type; return 0; } + +void +process_enum (expr_t *enm) +{ + expr_t *e = enm; + expr_t *c_enum = 0; + int enum_val = 0; + + if (!enums) { + enums = Hash_NewTable (16381, enums_get_key, 0, 0); + } + while (e) { + expr_t *t = e->next; + e->next = c_enum; + c_enum = e; + e = t; + } + for (e = c_enum; e; e = e->next) { + expr_t *name = e; + expr_t *val = 0; + enum_t *new_enum; + + if (name->type == ex_expr) { + val = name->e.expr.e2; + name = name->e.expr.e1; + } + if ((structs && find_struct (name->e.string_val)) + || get_enum (name->e.string_val) + || PR_GetDef (NULL, name->e.string_val, 0, 0)) { + error (name, "%s redeclared", name->e.string_val); + continue; + } + if (val) + enum_val = val->e.integer_val; + new_enum = malloc (sizeof (enum_t)); + if (!new_enum) + Sys_Error ("out of memory"); + new_enum->name = name->e.string_val; + new_enum->value.type = ex_integer; + new_enum->value.e.integer_val = enum_val++; + Hash_Add (enums, new_enum); + //printf ("%s = %d\n", new_enum->name, new_enum->value.e.integer_val); + } +} + +expr_t * +get_enum (const char *name) +{ + enum_t *e; + + if (!enums) + return 0; + e = (enum_t *) Hash_Find (enums, name); + if (!e) + return 0; + return &e->value; +}