Nil is a constant, so allow it in global initializers.

This commit is contained in:
Bill Currie 2010-11-17 18:49:39 +09:00
parent b0879ba255
commit 67beaf4487
10 changed files with 38 additions and 25 deletions

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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");

View file

@ -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;

2
tools/qfcc/test/enum.r Normal file
View file

@ -0,0 +1,2 @@
typedef enum {x} X;
X y = x;

3
tools/qfcc/test/imp.r Normal file
View file

@ -0,0 +1,3 @@
void () foo = #0;
@static IMP bar = NIL;
@static IMP baz = 0;

1
tools/qfcc/test/nil.r Normal file
View file

@ -0,0 +1 @@
Class x = NIL;