quakeforge/tools/qfcc/source/emit.c
Bill Currie 638f4445cc More return code cleanup.
Don't use the true void return in traditional mode.
Prefer the true void return over "done" at the end of functions.
Don't emit the above if the last emitted statement is a return and there is
no label at the end of the function.
2011-01-13 00:46:46 +09:00

917 lines
22 KiB
C

/*
emit.c
statement emittion
Copyright (C) 2001 Bill Currie <bill@taniwha.org>
Author: Bill Currie <bill@taniwha.org>
Date: 2001/07/26
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
static __attribute__ ((used)) const char rcsid[] =
"$Id$";
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#include <stdlib.h>
#include <QF/mathlib.h>
#include <QF/va.h>
#include "codespace.h"
#include "def.h"
#include "debug.h"
#include "emit.h"
#include "expr.h"
#include "function.h"
#include "immediate.h"
#include "opcodes.h"
#include "options.h"
#include "qfcc.h"
#include "reloc.h"
#include "type.h"
#include "qc-parse.h"
static expr_t zero;
static void
add_statement_ref (def_t *def, dstatement_t *st, int field)
{
if (def) {
int st_ofs = st - pr.code->code;
def->users--;
def->used = 1;
if (def->parent)
def->parent->used = 1;
if (def->alias) {
def = def->alias;
def->users--;
def->used = 1;
if (def->parent)
def->parent->used = 1;
reloc_op_def_ofs (def, st_ofs, field);
} else
reloc_op_def (def, st_ofs, field);
}
}
def_t *
emit_statement (expr_t *e, opcode_t *op, def_t *var_a, def_t *var_b,
def_t *var_c)
{
dstatement_t *statement;
def_t *ret;
if (!op) {
error (e, "ice ice baby");
abort ();
}
if (options.code.debug && current_func->aux) {
pr_uint_t line = (e ? e->line : pr.source_line) - lineno_base;
if (line != pr.linenos[pr.num_linenos - 1].line) {
pr_lineno_t *lineno = new_lineno ();
lineno->line = line;
lineno->fa.addr = pr.code->size;
}
}
statement = codespace_newstatement (pr.code);
statement->op = op->opcode;
statement->a = var_a ? var_a->ofs : 0;
statement->b = var_b ? var_b->ofs : 0;
statement->c = 0;
if (op->type_c == ev_invalid || op->right_associative
|| op->opcode == OP_DONE/*stupid opcode*/) {
// ifs, gotos, and assignments don't need vars allocated
if (var_c)
statement->c = var_c->ofs;
ret = var_a;
} else { // allocate result space
if (!var_c) {
var_c = get_tempdef (ev_types[op->type_c], current_scope);
var_c->users += 2;
}
statement->c = var_c->ofs;
ret = var_c;
}
#if 0
printf ("%s %s(%d:%d) %s(%d:%d) %s(%d:%d)\n", op->opname,
var_a ? var_a->name : "", var_a ? var_a->users : 99, statement->a,
var_b ? var_b->name : "", var_b ? var_b->users : 99, statement->b,
var_c ? var_c->name : "", var_c ? var_c->users : 99, statement->c);
#endif
add_statement_ref (var_a, statement, 0);
add_statement_ref (var_b, statement, 1);
add_statement_ref (var_c, statement, 2);
if (op->right_associative)
return var_a;
return var_c;
}
static void
emit_branch (expr_t *_e, opcode_t *op, expr_t *e, expr_t *l)
{
dstatement_t *st;
reloc_t *ref;
def_t *def = 0;
int ofs;
if (e)
def = emit_sub_expr (e, 0);
ofs = pr.code->size;
emit_statement (_e, op, def, 0, 0);
st = &pr.code->code[ofs];
if (l->e.label.ofs) {
if (op == op_goto)
st->a = l->e.label.ofs - ofs;
else
st->b = l->e.label.ofs - ofs;
} else {
ref = new_reloc (ofs, op == op_goto ? rel_op_a_op : rel_op_b_op);
ref->next = l->e.label.refs;
l->e.label.refs = ref;
}
}
static def_t *
vector_call (expr_t *earg, expr_t *parm, int ind)
{
expr_t *a, *v, *n;
int i;
static const char *names[] = {"x", "y", "z"};
for (i = 0; i < 3; i++) {
n = new_name_expr (names[i]);
v = new_float_expr (earg->e.vector_val[i]);
a = assign_expr (binary_expr ('.', parm, n), v);
parm = new_param_expr (get_type (earg), ind);
a->line = earg->line;
a->file = earg->file;
emit_expr (a);
}
return emit_sub_expr (parm, 0);
}
static def_t *
emit_function_call (expr_t *e, def_t *dest)
{
def_t *func = emit_sub_expr (e->e.expr.e1, 0);
def_t *ret;
def_t *arg;
def_t *p;
def_t *a[2] = {0, 0};
expr_t *earg;
expr_t *parm;
opcode_t *op;
type_t *t1 = &type_invalid;
type_t *t2 = &type_invalid;
int count = 0, ind;
const char *pref = "";
for (earg = e->e.expr.e2; earg; earg = earg->next)
count++;
ind = count;
for (earg = e->e.expr.e2; earg; earg = earg->next) {
ind--;
parm = new_param_expr (get_type (earg), ind);
if (options.code.progsversion != PROG_ID_VERSION && ind < 2) {
pref = "R";
if (ind == 1)
t2 = &type_void;
if (ind == 0)
t1 = &type_void;
if (options.code.vector_calls && earg->type == ex_vector) {
a[ind] = vector_call (earg, parm, ind);
} else {
a[ind] = emit_sub_expr (earg, emit_sub_expr (parm, 0));
}
continue;
}
if (is_struct (get_type (parm))) {
expr_t *a = assign_expr (parm, earg);
a->line = e->line;
a->file = e->file;
emit_expr (a);
} else {
if (options.code.vector_calls && earg->type == ex_vector) {
vector_call (earg, parm, ind);
} else {
p = emit_sub_expr (parm, 0);
arg = emit_sub_expr (earg, p);
if (arg != p) {
op = opcode_find ("=", arg->type, arg->type, &type_invalid);
emit_statement (e, op, arg, p, 0);
}
}
}
}
op = opcode_find (va ("<%sCALL%d>", pref, count), &type_function, t1, t2);
emit_statement (e, op, func, a[0], a[1]);
ret = emit_sub_expr (new_ret_expr (func->type->t.func.type), 0);
if (dest) {
op = opcode_find ("=", dest->type, ret->type, &type_invalid);
emit_statement (e, op, ret, dest, 0);
return dest;
} else {
return ret;
}
}
static def_t *
emit_assign_expr (int oper, expr_t *e)
{
def_t *def_a, *def_b, *def_c, *a, *b;
opcode_t *op;
expr_t *e1 = e->e.expr.e1;
expr_t *e2 = e->e.expr.e2;
const char *operator = get_op_string (oper);
if (e1->type == ex_temp && e1->e.temp.users < 2) {
e1->e.temp.users--;
return 0;
}
if (oper == '=') {
def_a = emit_sub_expr (e1, 0);
if (def_a->constant) {
if (options.code.cow) {
int size = type_size (def_a->type);
int ofs = new_location (def_a->type, pr.near_data);
memcpy (G_POINTER (void, ofs), G_POINTER (void, def_a->ofs),
size);
def_a->ofs = ofs;
def_a->constant = 0;
def_a->nosave = 1;
if (options.warnings.cow)
warning (e1, "assignment to constant %s (Moooooooo!)",
def_a->name);
} else {
if (options.traditional) {
if (options.warnings.cow)
warning (e1, "assignment to constant %s (Moooooooo!)",
def_a->name);
} else
error (e1, "assignment to constant %s", def_a->name);
}
}
def_b = emit_sub_expr (e2, def_a);
a = def_a;
if (a->alias)
a = a->alias;
b = def_b;
if (b->alias)
b = b->alias;
if (b != a) {
op = opcode_find (operator, def_b->type, def_a->type,
&type_invalid);
emit_statement (e, op, def_b, def_a, 0);
}
return def_a;
} else {
def_b = emit_sub_expr (e2, 0);
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_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);
} else {
def_a = emit_sub_expr (e1, 0);
def_c = 0;
op = opcode_find (operator, def_b->type, def_a->type, &type_invalid);
}
emit_statement (e, op, def_b, def_a, def_c);
return def_b;
}
}
static def_t *
emit_bind_expr (expr_t *e1, expr_t *e2)
{
type_t *t1 = get_type (e1);
type_t *t2 = get_type (e2);
def_t *def;
if (!e2 || e2->type != ex_temp) {
error (e1, "internal error");
abort ();
}
def = emit_sub_expr (e1, e2->e.temp.def);
if (t1 != t2) {
def_t *tmp = new_def (t2, 0, def->scope);
tmp->ofs = 0;
tmp->alias = def;
tmp->users = e2->e.temp.users;
tmp->freed = 1; // don't free this offset when freeing def
def = tmp;
}
e2->e.temp.def = def;
return e2->e.temp.def;
}
static def_t *
emit_move_expr (expr_t *e)
{
expr_t *e1 = e->e.expr.e1;
expr_t *e2 = e->e.expr.e2;
expr_t *size_expr;
def_t *size, *src, *dst;
type_t *src_type, *dst_type;
opcode_t *op;
dst_type = get_type (e1);
src_type = get_type (e2);
src = emit_sub_expr (e2, 0);
dst = emit_sub_expr (e1, 0);
if (is_struct (dst_type) && is_struct (src_type)) {
size_expr = new_short_expr (type_size (dst->type));
dst_type = src_type = &type_void;
} else if (is_struct (dst_type)) {
if (dst->alias)
dst = dst->alias;
dst = emit_sub_expr (address_expr (new_def_expr (dst), 0, 0), 0);
dst_type = dst->type;
size_expr = new_integer_expr (type_size (dst_type));
} else if (is_struct (src_type)) {
if (src->alias)
src = src->alias;
src = emit_sub_expr (address_expr (new_def_expr (src), 0, 0), 0);
src_type = src->type;
size_expr = new_integer_expr (type_size (dst_type->t.fldptr.type));
} else {
size_expr = new_integer_expr (type_size (dst_type->t.fldptr.type));
}
size = emit_sub_expr (size_expr, 0);
op = opcode_find ("<MOVE>", src_type, size->type, dst_type);
return emit_statement (e, op, src, size, dst);
}
static def_t *
emit_address_expr (expr_t *e)
{
def_t *def_a, *def_b, *d;
opcode_t *op;
def_a = emit_sub_expr (e->e.expr.e1, 0);
def_b = emit_sub_expr (e->e.expr.e2, 0);
op = opcode_find ("&", def_a->type, def_b->type, 0);
d = emit_statement (e, op, def_a, def_b, 0);
return d;
}
static def_t *
emit_deref_expr (expr_t *e, def_t *dest)
{
def_t *d;
type_t *type = e->e.expr.type;
def_t *z;
opcode_t *op;
e = e->e.expr.e1;
if (e->type == ex_pointer) {
if (e->e.pointer.def) {
d = new_def (e->e.pointer.type, 0, e->e.pointer.def->scope);
d->local = e->e.pointer.def->local;
d->ofs = e->e.pointer.val;
d->alias = e->e.pointer.def;
} else if (e->e.pointer.val >= 0 && e->e.pointer.val < 65536) {
d = new_def (e->e.pointer.type, 0, current_scope);
d->ofs = e->e.pointer.val;
} else {
d = ReuseConstant (e, 0);
zero.type = ex_short;
z = emit_sub_expr (&zero, 0);
op = opcode_find (".", d->type, z->type, dest->type);
d = emit_statement (e, op, d, z, dest);
}
return d;
}
if (e->type == ex_uexpr && e->e.expr.op == '&'
&& e->e.expr.e1->type == ex_def) {
d = new_def (e->e.expr.type->t.fldptr.type, 0, current_scope);
d->alias = e->e.expr.e1->e.def;
d->local = d->alias->local;
d->ofs = d->alias->ofs;
return d;
}
if (!dest) {
dest = get_tempdef (type, current_scope);
dest->line = e->line;
dest->file = e->file;
dest->users += 2;
}
if (is_struct (dest->type)) {
expr_t *d = new_def_expr (dest);
expr_t *m = new_move_expr (d, e, dest->type);
d->line = dest->line;
d->file = dest->file;
m->line = e->line;
m->file = e->file;
emit_sub_expr (m, 0);
return dest;
}
if (e->type == ex_expr
&& e->e.expr.op == '&'
&& 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);
else
d = emit_sub_expr (e, dest);
if (dest && d != dest) {
zero.type = ex_short;
z = emit_sub_expr (&zero, 0);
op = opcode_find (".", d->type, z->type, dest->type);
d = emit_statement (e, op, d, z, dest);
} else {
if (!d->name)
d->type = type;
}
return d;
}
static void
build_bool_block (expr_t *block, expr_t *e)
{
switch (e->type) {
case ex_bool:
build_bool_block (block, e->e.bool.e);
free_tempdefs ();
return;
case ex_label:
e->next = 0;
append_expr (block, e);
free_tempdefs ();
return;
case ex_expr:
if (e->e.expr.op == OR || e->e.expr.op == AND) {
build_bool_block (block, e->e.expr.e1);
build_bool_block (block, e->e.expr.e2);
} else if (e->e.expr.op == 'i') {
e->next = 0;
append_expr (block, e);
} else if (e->e.expr.op == 'n') {
e->next = 0;
append_expr (block, e);
}
free_tempdefs ();
return;
case ex_uexpr:
if (e->e.expr.op == 'g') {
e->next = 0;
append_expr (block, e);
free_tempdefs ();
return;
}
break;
case ex_block:
if (!e->e.block.result) {
expr_t *t;
for (e = e->e.block.head; e; e = t) {
t = e->next;
build_bool_block (block, e);
}
free_tempdefs ();
return;
}
break;
default:
;
}
error (e, "internal error");
abort ();
}
static int
is_goto (expr_t *e)
{
return e && e->type == ex_uexpr && e->e.expr.op == 'g';
}
static int
is_if (expr_t *e)
{
return e && e->type == ex_expr && e->e.expr.op == 'i';
}
static int
is_ifnot (expr_t *e)
{
return e && e->type == ex_expr && e->e.expr.op == 'n';
}
static void
emit_bool_expr (expr_t *e)
{
expr_t *block = new_block_expr ();
expr_t **s;
expr_t *l;
build_bool_block (block, e);
s = &block->e.block.head;
while (*s) {
if (is_if (*s) && is_goto ((*s)->next)) {
l = (*s)->e.expr.e2;
for (e = (*s)->next->next; e && e->type == ex_label; e = e->next) {
if (e == l) {
e = *s;
e->e.expr.op = 'n';
e->e.expr.e2 = e->next->e.expr.e1;
e->next = e->next->next;
break;
}
}
s = &(*s)->next;
} else if (is_ifnot (*s) && is_goto ((*s)->next)) {
l = (*s)->e.expr.e2;
for (e = (*s)->next->next; e && e->type == ex_label; e = e->next) {
if (e == l) {
e = *s;
e->e.expr.op = 'i';
e->e.expr.e2 = e->next->e.expr.e1;
e->next = e->next->next;
break;
}
}
s = &(*s)->next;
} else if (is_goto (*s)) {
l = (*s)->e.expr.e1;
for (e = (*s)->next; e && e->type == ex_label; e = e->next) {
if (e == l) {
*s = (*s)->next;
l = 0;
break;
}
}
if (l)
s = &(*s)->next;
} else {
s = &(*s)->next;
}
}
emit_expr (block);
}
def_t *
emit_sub_expr (expr_t *e, def_t *dest)
{
opcode_t *op;
const char *operator;
def_t *def_a, *def_b, *d = 0;
def_t *tmp = 0;
switch (e->type) {
case ex_block:
if (e->e.block.result) {
expr_t *res = e->e.block.result;
for (e = e->e.block.head; e; e = e->next)
emit_expr (e);
d = emit_sub_expr (res, dest);
}
break;
case ex_state:
case ex_bool:
case ex_name:
case ex_nil:
case ex_label:
case ex_error:
error (e, "internal error");
abort ();
case ex_expr:
if (e->e.expr.op == 'M') {
d = emit_move_expr (e);
break;
}
if (e->e.expr.op == 'b') {
d = emit_bind_expr (e->e.expr.e1, e->e.expr.e2);
break;
}
if (e->e.expr.op == 'c') {
d = emit_function_call (e, dest);
break;
}
if (e->e.expr.op == '=' || e->e.expr.op == PAS) {
d = emit_assign_expr (e->e.expr.op, e);
if (!d->managed)
d->users++;
break;
}
if (e->e.expr.op == '&' && e->e.expr.type->type == ev_pointer) {
d = emit_address_expr (e);
break;
}
if (e->e.expr.e1->type == ex_block
&& e->e.expr.e1->e.block.is_call) {
def_b = emit_sub_expr (e->e.expr.e2, 0);
def_a = emit_sub_expr (e->e.expr.e1, 0);
} else {
def_a = emit_sub_expr (e->e.expr.e1, 0);
def_b = emit_sub_expr (e->e.expr.e2, 0);
}
operator = get_op_string (e->e.expr.op);
if (!dest) {
dest = get_tempdef (e->e.expr.type, current_scope);
dest->file = e->file;
dest->line = e->line;
dest->users += 2;
}
op = opcode_find (operator, def_a->type, def_b->type,
dest->type);
d = emit_statement (e, op, def_a, def_b, dest);
break;
case ex_uexpr:
switch (e->e.expr.op) {
case '!':
operator = "!";
def_a = emit_sub_expr (e->e.expr.e1, 0);
def_b = &def_invalid;
break;
case '~':
operator = "~";
def_a = emit_sub_expr (e->e.expr.e1, 0);
def_b = &def_invalid;
break;
case '-':
zero.type = expr_types[extract_type (e->e.expr.e1)];
operator = "-";
def_a = ReuseConstant (&zero, 0);
def_b = emit_sub_expr (e->e.expr.e1, 0);
if (!dest) {
dest = get_tempdef (e->e.expr.type, current_scope);
dest->file = e->file;
dest->line = e->line;
dest->users += 2;
}
break;
case '&':
zero.type = ex_short;
operator = "&";
if (e->e.expr.e1->type == ex_expr
&& e->e.expr.e1->e.expr.op == '.') {
tmp = get_tempdef (e->e.expr.type, current_scope);
tmp->file = e->file;
tmp->line = e->line;
tmp->users += 2;
def_b = emit_sub_expr (&zero, 0);
} else {
def_b = &def_void;
}
def_a = emit_sub_expr (e->e.expr.e1, tmp);
if (!dest) {
dest = get_tempdef (e->e.expr.type, current_scope);
dest->file = e->file;
dest->line = e->line;
dest->users += 2;
}
break;
case '.':
return emit_deref_expr (e, dest);
case 'C':
def_a = emit_sub_expr (e->e.expr.e1, 0);
if ((def_a->type->type == ev_pointer
&& e->e.expr.type->type == ev_pointer)
|| (def_a->type->type == ev_func
&& e->e.expr.type->type == ev_func)) {
return def_a;
}
if ((def_a->type->type == ev_pointer
&& e->e.expr.type->type == ev_integer)
|| (def_a->type->type == ev_integer
&& e->e.expr.type->type == ev_pointer)) {
def_t *tmp;
tmp = new_def (e->e.expr.type, 0, def_a->scope);
tmp->ofs = 0;
tmp->alias = def_a;
tmp->users = def_a->users;
tmp->freed = 1;
return tmp;
}
def_b = &def_invalid;
if (!dest) {
dest = get_tempdef (e->e.expr.type, current_scope);
dest->file = e->file;
dest->line = e->line;
dest->users = 2;
}
operator = "=";
break;
default:
abort ();
}
op = opcode_find (operator, def_a->type, def_b->type,
dest ? dest->type : 0);
d = emit_statement (e, op, def_a, def_b, dest);
break;
case ex_def:
d = e->e.def;
break;
case ex_temp:
if (!e->e.temp.def) {
if (dest)
e->e.temp.def = dest;
else {
e->e.temp.def = get_tempdef (e->e.temp.type, current_scope);
e->e.temp.def->line = e->line;
e->e.temp.def->file = e->file;
}
e->e.temp.def->users = e->e.temp.users;
e->e.temp.def->expr = e;
e->e.temp.def->managed = 1;
}
d = e->e.temp.def;
break;
case ex_pointer:
case ex_string:
case ex_float:
case ex_vector:
case ex_entity:
case ex_field:
case ex_func:
case ex_quaternion:
case ex_integer:
case ex_uinteger:
d = ReuseConstant (e, 0);
break;
case ex_short:
d = new_def (&type_short, 0, 0);
d->ofs = e->e.short_val;
d->absolute = 1;
d->users = 1;
break;
}
free_tempdefs ();
return d;
}
void
emit_expr (expr_t *e)
{
def_t *def;
def_t *def_a;
def_t *def_b;
def_t *def_c;
ex_label_t *label;
opcode_t *op;
//printf ("%d ", e->line);
//print_expr (e);
//puts ("");
switch (e->type) {
case ex_error:
break;
case ex_state:
def_a = emit_sub_expr (e->e.state.frame, 0);
def_b = emit_sub_expr (e->e.state.think, 0);
if (e->e.state.step) {
def_c = emit_sub_expr (e->e.state.step, 0);
op = op_state_f;
} else {
def_c = 0;
op = op_state;
}
emit_statement (e, op, def_a, def_b, def_c);
break;
case ex_bool:
emit_bool_expr (e);
break;
case ex_label:
label = &e->e.label;
label->ofs = pr.code->size;
relocate_refs (label->refs, label->ofs);
break;
case ex_block:
for (e = e->e.block.head; e; e = e->next)
emit_expr (e);
break;
case ex_expr:
switch (e->e.expr.op) {
case 'M':
emit_move_expr (e);
break;
case PAS:
case '=':
emit_assign_expr (e->e.expr.op, e);
break;
case 'n':
emit_branch (e, op_ifnot, e->e.expr.e1, e->e.expr.e2);
break;
case 'i':
emit_branch (e, op_if, e->e.expr.e1, e->e.expr.e2);
break;
case IFBE:
emit_branch (e, op_ifbe, e->e.expr.e1, e->e.expr.e2);
break;
case IFB:
emit_branch (e, op_ifb, e->e.expr.e1, e->e.expr.e2);
break;
case IFAE:
emit_branch (e, op_ifae, e->e.expr.e1, e->e.expr.e2);
break;
case IFA:
emit_branch (e, op_ifa, e->e.expr.e1, e->e.expr.e2);
break;
case 'c':
emit_function_call (e, 0);
break;
case 'b':
emit_bind_expr (e->e.expr.e1, e->e.expr.e2);
break;
case 'g':
def_a = emit_sub_expr (e->e.expr.e1, 0);
def_b = emit_sub_expr (e->e.expr.e2, 0);
emit_statement (e, op_jumpb, def_a, def_b, 0);
break;
default:
if (options.warnings.executable)
warning (e, "Non-executable statement; "
"executing programmer instead.");
break;
}
break;
case ex_uexpr:
switch (e->e.expr.op) {
case 'r':
def = 0;
if (e->e.expr.e1)
def = emit_sub_expr (e->e.expr.e1, 0);
if (!def && !options.traditional && op_return_v)
emit_statement (e, op_return_v, 0, 0, 0);
else
emit_statement (e, op_return, def, 0, 0);
break;
case 'g':
emit_branch (e, op_goto, 0, e->e.expr.e1);
break;
default:
if (options.warnings.executable)
warning (e, "Non-executable statement; "
"executing programmer instead.");
emit_expr (e->e.expr.e1);
break;
}
break;
case ex_def:
case ex_temp:
case ex_string:
case ex_float:
case ex_vector:
case ex_entity:
case ex_field:
case ex_func:
case ex_pointer:
case ex_quaternion:
case ex_integer:
case ex_uinteger:
case ex_short:
case ex_name:
case ex_nil:
if (options.warnings.executable)
warning (e, "Non-executable statement; "
"executing programmer instead.");
break;
}
free_tempdefs ();
}