From 67beaf44875f87562f352d104480637695624303 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 17 Nov 2010 18:49:39 +0900 Subject: [PATCH] Nil is a constant, so allow it in global initializers. --- tools/qfcc/include/expr.h | 3 ++- tools/qfcc/source/emit.c | 4 ++-- tools/qfcc/source/expr.c | 23 +++++++++++++---------- tools/qfcc/source/immediate.c | 2 ++ tools/qfcc/source/qc-lex.l | 8 +++++--- tools/qfcc/source/qc-parse.y | 15 +++++++-------- tools/qfcc/source/switch.c | 2 +- tools/qfcc/test/enum.r | 2 ++ tools/qfcc/test/imp.r | 3 +++ tools/qfcc/test/nil.r | 1 + 10 files changed, 38 insertions(+), 25 deletions(-) create mode 100644 tools/qfcc/test/enum.r create mode 100644 tools/qfcc/test/imp.r create mode 100644 tools/qfcc/test/nil.r diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index 845e7d032..6b06a45d9 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -44,9 +44,9 @@ typedef enum { ex_uexpr, // unary expression ex_def, ex_temp, // temporary variable - ex_nil, // umm, nil, null. nuff said ex_name, + ex_nil, // umm, nil, null. nuff said ex_string, ex_float, ex_vector, @@ -206,6 +206,7 @@ void convert_uint_int (expr_t *e); void convert_int_uint (expr_t *e); void convert_short_int (expr_t *e); void convert_short_uint (expr_t *e); +void convert_nil (expr_t *e, struct type_s *t); expr_t *test_expr (expr_t *e, int test); void backpatch (ex_list_t *list, expr_t *label); diff --git a/tools/qfcc/source/emit.c b/tools/qfcc/source/emit.c index 5e2daba2d..94223e7e7 100644 --- a/tools/qfcc/source/emit.c +++ b/tools/qfcc/source/emit.c @@ -328,7 +328,7 @@ emit_assign_expr (int oper, expr_t *e) if (e->rvalue && def_b->managed) def_b->users++; if (e1->type == ex_expr && extract_type (e1->e.expr.e1) == ev_pointer - && e1->e.expr.e1->type < ex_string) { + && e1->e.expr.e1->type < ex_nil) { def_a = emit_sub_expr (e1->e.expr.e1, 0); def_c = emit_sub_expr (e1->e.expr.e2, 0); op = opcode_find (operator, def_b->type, def_a->type, def_c->type); @@ -470,7 +470,7 @@ emit_deref_expr (expr_t *e, def_t *dest) if (e->type == ex_expr && e->e.expr.op == '&' - && e->e.expr.e1->type < ex_string) + && e->e.expr.e1->type < ex_nil) e->e.expr.op = '.'; if (e->type == ex_uexpr && e->e.expr.op == '.') d = emit_sub_expr (e, 0); diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 72969d1c3..7f9f18fa4 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -76,9 +76,9 @@ etype_t qc_types[] = { ev_void, // ex_uexpr ev_void, // ex_def ev_void, // ex_temp - ev_void, // ex_nil ev_void, // ex_name + ev_void, // ex_nil ev_string, // ex_string ev_float, // ex_float ev_vector, // ex_vector @@ -141,6 +141,10 @@ convert_name (expr_t *e) expr_t *new; class_t *class; + new = get_enum (name); + if (new) + goto convert; + class = get_class (name, 0); if (class) { e->type = ex_def; @@ -159,9 +163,6 @@ convert_name (expr_t *e) return; } new = class_ivar_expr (current_class, name); - if (new) - goto convert; - new = get_enum (name); if (new) goto convert; error (e, "Undeclared variable \"%s\".", name); @@ -604,7 +605,7 @@ new_short_expr (short short_val) int is_constant (expr_t *e) { - if (e->type >= ex_string + if (e->type >= ex_nil || (e->type == ex_def && e->e.def->constant)) return 1; return 0; @@ -615,6 +616,8 @@ constant_expr (expr_t *var) { def_t *def; + convert_name (var); + if (var->type != ex_def || !var->e.def->constant) return var; @@ -818,7 +821,7 @@ print_expr (expr_t *e) e->e.temp.users); break; case ex_nil: - printf ("NULL"); + printf ("NIL"); break; case ex_string: case ex_name: @@ -1365,7 +1368,7 @@ convert_short_uint (expr_t *e) e->e.uinteger_val = e->e.short_val; } -static void +void convert_nil (expr_t *e, type_t *t) { e->type = expr_types[t->type]; @@ -1696,7 +1699,7 @@ binary_expr (int op, expr_t *e1, expr_t *e2) { expr_t *tmp1, *tmp2; e = new_block_expr (); - if (e2->type < ex_string) + if (e2->type < ex_nil) tmp1 = new_temp_def_expr (&type_float); else tmp1 = e2; @@ -2519,7 +2522,7 @@ assign_expr (expr_t *e1, expr_t *e2) && POINTER_VAL (e->e.pointer) < 65536)) { if (e->type == ex_expr && e->e.expr.op == '&' && e->e.expr.type->type == ev_pointer - && e->e.expr.e1->type < ex_string) { + && e->e.expr.e1->type < ex_nil) { e2 = e; e2->e.expr.op = '.'; e2->e.expr.type = t2; @@ -2640,7 +2643,7 @@ init_elements (def_t *def, expr_t *eles) } init_elements (&elements[i], c); continue; - } else if (c->type >= ex_string) { + } else if (c->type >= ex_nil) { if (c->type == ex_integer && elements[i].type->type == ev_float) convert_int (c); diff --git a/tools/qfcc/source/immediate.c b/tools/qfcc/source/immediate.c index 93c8db928..7b5890c8b 100644 --- a/tools/qfcc/source/immediate.c +++ b/tools/qfcc/source/immediate.c @@ -167,6 +167,8 @@ ReuseConstant (expr_t *expr, def_t *def) clear_immediates (); } cn = 0; + if (e.type == ex_nil) + convert_nil (&e, def->type); switch (e.type) { case ex_entity: tab = entity_imm_defs; diff --git a/tools/qfcc/source/qc-lex.l b/tools/qfcc/source/qc-lex.l index 8d5511778..aaaefd331 100644 --- a/tools/qfcc/source/qc-lex.l +++ b/tools/qfcc/source/qc-lex.l @@ -358,9 +358,11 @@ type_or_name (char *token) yylval.typename = typename; return TYPE_NAME; } - if ((class = get_class (token, 0))) { - yylval.string_val = save_string (token); - return CLASS_NAME; + if (!get_enum (token)) { + if ((class = get_class (token, 0))) { + yylval.string_val = save_string (token); + return CLASS_NAME; + } } yylval.string_val = save_string (token); return NAME; diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 852ccb655..f92d57f3d 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -373,7 +373,7 @@ enum { $$ = 0; $3 = constant_expr ($3); - if ($3->type < ex_string) { + if ($3->type < ex_nil) { error ($3, "non-constant initializer"); } else if ($3->type != ex_integer) { error ($3, "invalid initializer type"); @@ -600,15 +600,14 @@ var_initializer def_initialized ($$); } else { $2 = constant_expr ($2); - if ($2->type >= ex_string) { - if ($$->constant) { + if ($2->type >= ex_nil) { + if ($2->type != ex_nil + && !type_assignable ($$->type, get_type ($2))) { + error ($2, "incompatible types in initialization"); + } else if ($$->constant) { error ($2, "%s re-initialized", $$->name); } else { - if ($$->type->type == ev_func) { - PARSE_ERROR; - } else { - ReuseConstant ($2, $$); - } + ReuseConstant ($2, $$); } } else { error ($2, "non-constant expression used for initializer"); diff --git a/tools/qfcc/source/switch.c b/tools/qfcc/source/switch.c index 6b6e33484..187e80633 100644 --- a/tools/qfcc/source/switch.c +++ b/tools/qfcc/source/switch.c @@ -106,7 +106,7 @@ case_label_expr (switch_block_t *switch_block, expr_t *value) convert_name (value); value = constant_expr (value); } - if (value && value->type < ex_string) { + if (value && value->type < ex_nil) { error (value, "non-constant case value"); free (cl); return 0; diff --git a/tools/qfcc/test/enum.r b/tools/qfcc/test/enum.r new file mode 100644 index 000000000..e2c31e9d8 --- /dev/null +++ b/tools/qfcc/test/enum.r @@ -0,0 +1,2 @@ +typedef enum {x} X; +X y = x; diff --git a/tools/qfcc/test/imp.r b/tools/qfcc/test/imp.r new file mode 100644 index 000000000..030a21ddd --- /dev/null +++ b/tools/qfcc/test/imp.r @@ -0,0 +1,3 @@ +void () foo = #0; +@static IMP bar = NIL; +@static IMP baz = 0; diff --git a/tools/qfcc/test/nil.r b/tools/qfcc/test/nil.r new file mode 100644 index 000000000..2b6a193ce --- /dev/null +++ b/tools/qfcc/test/nil.r @@ -0,0 +1 @@ +Class x = NIL;