quakeforge/tools/qfcc/source/expr_binary.c
2013-09-27 23:15:57 +09:00

792 lines
18 KiB
C

/*
exprtype.c
Expression type manipulation
Copyright (C) 2013 Bill Currie <bill@taniwha.org>
Author: Bill Currie <bill@taniwha.org>
Date: 2013/06/27
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
#include "diagnostic.h"
#include "expr.h"
#include "options.h"
#include "type.h"
#include "qc-parse.h"
typedef struct {
int op;
type_t *type;
type_t *a_cast;
type_t *b_cast;
} expr_type_t;
static expr_type_t string_string[] = {
{'+', &type_string},
{EQ, &type_integer},
{NE, &type_integer},
{LE, &type_integer},
{GE, &type_integer},
{LT, &type_integer},
{GT, &type_integer},
{0, 0}
};
static expr_type_t float_float[] = {
{'+', &type_float},
{'-', &type_float},
{'*', &type_float},
{'/', &type_float},
{'&', &type_float},
{'|', &type_float},
{'^', &type_float},
{'%', &type_float},
{SHL, &type_float},
{SHR, &type_float},
{EQ, &type_integer},
{NE, &type_integer},
{LE, &type_integer},
{GE, &type_integer},
{LT, &type_integer},
{GT, &type_integer},
{0, 0}
};
static expr_type_t float_vector[] = {
{'*', &type_vector},
{0, 0}
};
static expr_type_t float_quat[] = {
{'*', &type_quaternion},
{'/', &type_quaternion},
{0, 0}
};
static expr_type_t float_integer[] = {
{'+', &type_float, 0, &type_float},
{'-', &type_float, 0, &type_float},
{'*', &type_float, 0, &type_float},
{'/', &type_float, 0, &type_float},
{'&', &type_float, 0, &type_float},
{'|', &type_float, 0, &type_float},
{'^', &type_float, 0, &type_float},
{'%', &type_float, 0, &type_float},
{SHL, &type_float, 0, &type_float},
{SHR, &type_float, 0, &type_float},
{EQ, &type_integer, 0, &type_float},
{NE, &type_integer, 0, &type_float},
{LE, &type_integer, 0, &type_float},
{GE, &type_integer, 0, &type_float},
{LT, &type_integer, 0, &type_float},
{GT, &type_integer, 0, &type_float},
{0, 0}
};
#define float_uinteger float_integer
#define float_short float_integer
static expr_type_t vector_float[] = {
{'*', &type_vector},
{'/', &type_vector},
{0, 0}
};
static expr_type_t vector_vector[] = {
{'+', &type_vector},
{'-', &type_vector},
{'*', &type_float},
{EQ, &type_integer},
{NE, &type_integer},
{0, 0}
};
#define vector_integer vector_float
#define vector_uinteger vector_float
#define vector_short vector_float
static expr_type_t entity_entity[] = {
{EQ, &type_integer},
{NE, &type_integer},
{0, 0}
};
static expr_type_t field_field[] = {
{EQ, &type_integer},
{NE, &type_integer},
{0, 0}
};
static expr_type_t func_func[] = {
{EQ, &type_integer},
{NE, &type_integer},
{0, 0}
};
static expr_type_t pointer_pointer[] = {
{'-', &type_integer, &type_integer, &type_integer},
{EQ, &type_integer},
{NE, &type_integer},
{LE, &type_integer},
{GE, &type_integer},
{LT, &type_integer},
{GT, &type_integer},
{0, 0}
};
static expr_type_t pointer_integer[] = {
{'+', &type_pointer},
{'-', &type_pointer},
{0, 0}
};
#define pointer_uinteger pointer_integer
#define pointer_short pointer_integer
static expr_type_t quat_float[] = {
{'*', &type_quaternion},
{'/', &type_quaternion},
{0, 0}
};
static expr_type_t quat_vector[] = {
{'*', &type_vector},
{0, 0}
};
static expr_type_t quat_quat[] = {
{'+', &type_quaternion},
{'-', &type_quaternion},
{'*', &type_quaternion},
{EQ, &type_integer},
{NE, &type_integer},
{0, 0}
};
static expr_type_t quat_integer[] = {
{'*', &type_quaternion, 0, &type_float},
{'/', &type_quaternion, 0, &type_float},
{0, 0}
};
#define quat_uinteger quat_integer
#define quat_short quat_integer
static expr_type_t integer_float[] = {
{'+', &type_float, &type_float, 0},
{'-', &type_float, &type_float, 0},
{'*', &type_float, &type_float, 0},
{'/', &type_float, &type_float, 0},
{'&', &type_float, &type_float, 0},
{'|', &type_float, &type_float, 0},
{'^', &type_float, &type_float, 0},
{'%', &type_float, &type_float, 0},
{SHL, &type_integer, 0, &type_integer}, //FIXME?
{SHR, &type_integer, 0, &type_integer}, //FIXME?
{EQ, &type_integer, &type_float, 0},
{NE, &type_integer, &type_float, 0},
{LE, &type_integer, &type_float, 0},
{GE, &type_integer, &type_float, 0},
{LT, &type_integer, &type_float, 0},
{GT, &type_integer, &type_float, 0},
{0, 0}
};
static expr_type_t integer_vector[] = {
{'*', &type_vector, &type_float, 0},
{0, 0}
};
static expr_type_t integer_pointer[] = {
{'+', &type_pointer},
{0, 0}
};
static expr_type_t integer_quat[] = {
{'*', &type_quaternion, &type_float, 0},
{'/', &type_quaternion, &type_float, 0},
{0, 0}
};
static expr_type_t integer_integer[] = {
{'+', &type_integer},
{'-', &type_integer},
{'*', &type_integer},
{'/', &type_integer},
{'&', &type_integer},
{'|', &type_integer},
{'^', &type_integer},
{'%', &type_integer},
{SHL, &type_integer},
{SHR, &type_integer},
{EQ, &type_integer},
{NE, &type_integer},
{LE, &type_integer},
{GE, &type_integer},
{LT, &type_integer},
{GT, &type_integer},
{0, 0}
};
static expr_type_t integer_uinteger[] = {
{'+', &type_integer},
{'-', &type_integer},
{'*', &type_integer},
{'/', &type_integer},
{'&', &type_integer},
{'|', &type_integer},
{'^', &type_integer},
{'%', &type_integer},
{SHL, &type_integer},
{SHR, &type_integer},
{EQ, &type_integer},
{NE, &type_integer},
{LE, &type_integer},
{GE, &type_integer},
{LT, &type_integer},
{GT, &type_integer},
{0, 0}
};
static expr_type_t integer_short[] = {
{'+', &type_integer},
{'-', &type_integer},
{'*', &type_integer},
{'/', &type_integer},
{'&', &type_integer},
{'|', &type_integer},
{'^', &type_integer},
{'%', &type_integer},
{SHL, &type_integer},
{SHR, &type_integer},
{EQ, &type_integer},
{NE, &type_integer},
{LE, &type_integer},
{GE, &type_integer},
{LT, &type_integer},
{GT, &type_integer},
{0, 0}
};
#define uinteger_float integer_float
#define uinteger_vector integer_vector
#define uinteger_pointer integer_pointer
#define uinteger_quat integer_quat
static expr_type_t uinteger_integer[] = {
{'+', &type_integer},
{'-', &type_integer},
{'*', &type_integer},
{'/', &type_integer},
{'&', &type_integer},
{'|', &type_integer},
{'^', &type_integer},
{'%', &type_integer},
{SHL, &type_uinteger},
{SHR, &type_uinteger},
{EQ, &type_integer},
{NE, &type_integer},
{LE, &type_integer},
{GE, &type_integer},
{LT, &type_integer},
{GT, &type_integer},
{0, 0}
};
static expr_type_t uinteger_uinteger[] = {
{'+', &type_uinteger},
{'-', &type_uinteger},
{'*', &type_uinteger},
{'/', &type_uinteger},
{'&', &type_uinteger},
{'|', &type_uinteger},
{'^', &type_uinteger},
{'%', &type_uinteger},
{SHL, &type_uinteger},
{SHR, &type_uinteger},
{EQ, &type_integer},
{NE, &type_integer},
{LE, &type_integer},
{GE, &type_integer},
{LT, &type_integer},
{GT, &type_integer},
{0, 0}
};
#define uinteger_short uinteger_integer
#define short_float integer_float
#define short_vector integer_vector
#define short_pointer integer_pointer
#define short_quat integer_quat
static expr_type_t short_integer[] = {
{'+', &type_integer},
{'-', &type_integer},
{'*', &type_integer},
{'/', &type_integer},
{'&', &type_integer},
{'|', &type_integer},
{'^', &type_integer},
{'%', &type_integer},
{SHL, &type_short},
{SHR, &type_short},
{EQ, &type_integer},
{NE, &type_integer},
{LE, &type_integer},
{GE, &type_integer},
{LT, &type_integer},
{GT, &type_integer},
{0, 0}
};
static expr_type_t short_uinteger[] = {
{'+', &type_uinteger},
{'-', &type_uinteger},
{'*', &type_uinteger},
{'/', &type_uinteger},
{'&', &type_uinteger},
{'|', &type_uinteger},
{'^', &type_uinteger},
{'%', &type_uinteger},
{SHL, &type_short},
{SHR, &type_short},
{EQ, &type_integer},
{NE, &type_integer},
{LE, &type_integer},
{GE, &type_integer},
{LT, &type_integer},
{GT, &type_integer},
{0, 0}
};
static expr_type_t short_short[] = {
{'+', &type_short},
{'-', &type_short},
{'*', &type_short},
{'/', &type_short},
{'&', &type_short},
{'|', &type_short},
{'^', &type_short},
{'%', &type_short},
{SHL, &type_short},
{SHR, &type_short},
{EQ, &type_integer},
{NE, &type_integer},
{LE, &type_integer},
{GE, &type_integer},
{LT, &type_integer},
{GT, &type_integer},
{0, 0}
};
static expr_type_t *string_x[] = {
0, // ev_void
string_string,
0, // ev_float
0, // ev_vector
0, // ev_entity
0, // ev_field
0, // ev_func
0, // ev_pointer
0, // ev_quat
0, // ev_integer
0, // ev_uinteger
0, // ev_short
};
static expr_type_t *float_x[] = {
0, // ev_void
0, // ev_string
float_float,
float_vector,
0, // ev_entity
0, // ev_field
0, // ev_func
0, // ev_pointer
float_quat,
float_integer,
float_uinteger,
float_short,
};
static expr_type_t *vector_x[] = {
0, // ev_void
0, // ev_string
vector_float,
vector_vector,
0, // ev_entity
0, // ev_field
0, // ev_func
0, // ev_pointer
0, // ev_quaternion
vector_integer,
vector_uinteger,
vector_short,
};
static expr_type_t *entity_x[] = {
0, // ev_void
0, // ev_string
0, // ev_float
0, // ev_vector
entity_entity, // ev_entity
0, // ev_field
0, // ev_func
0, // ev_pointer
0, // ev_quaternion
0, // ev_integer
0, // ev_uinteger
0, // ev_short
};
static expr_type_t *field_x[] = {
0, // ev_void
0, // ev_string
0, // ev_float
0, // ev_vector
0, // ev_entity
field_field, // ev_field
0, // ev_func
0, // ev_pointer
0, // ev_quaternion
0, // ev_integer
0, // ev_uinteger
0, // ev_short
};
static expr_type_t *funcx[] = {
0, // ev_void
0, // ev_string
0, // ev_float
0, // ev_vector
0, // ev_entity
0, // ev_field
func_func, // ev_func
0, // ev_pointer
0, // ev_quaternion
0, // ev_integer
0, // ev_uinteger
0, // ev_short
};
static expr_type_t *pointer_x[] = {
0, // ev_void
0, // ev_string
0, // ev_float
0, // ev_vector
0, // ev_entity
0, // ev_field
0, // ev_func
pointer_pointer,
0, // ev_quat
pointer_integer,
pointer_uinteger,
pointer_short,
};
static expr_type_t *quat_x[] = {
0, // ev_void
0, // ev_string
quat_float,
quat_vector,
0, // ev_entity
0, // ev_field
0, // ev_func
0, // ev_pointer
quat_quat,
quat_integer,
quat_uinteger,
quat_short,
};
static expr_type_t *integer_x[] = {
0, // ev_void
0, // ev_string
integer_float,
integer_vector,
0, // ev_entity
0, // ev_field
0, // ev_func
integer_pointer,
integer_quat,
integer_integer,
integer_uinteger,
integer_short,
};
static expr_type_t *uinteger_x[] = {
0, // ev_void
0, // ev_string
uinteger_float,
uinteger_vector,
0, // ev_entity
0, // ev_field
0, // ev_func
uinteger_pointer,
uinteger_quat,
uinteger_integer,
uinteger_uinteger,
uinteger_short,
};
static expr_type_t *short_x[] = {
0, // ev_void
0, // ev_string
short_float,
short_vector,
0, // ev_entity
0, // ev_field
0, // ev_func
short_pointer,
short_quat,
short_integer,
short_uinteger,
short_short,
};
static expr_type_t **binary_expr_types[] = {
0, // ev_void
string_x,
float_x,
vector_x,
entity_x,
field_x,
funcx,
pointer_x,
quat_x,
integer_x,
uinteger_x,
short_x,
};
static expr_t *
invalid_binary_expr (int op, expr_t *e1, expr_t *e2)
{
etype_t t1, t2;
t1 = extract_type (e1);
t2 = extract_type (e2);
return error (e1, "invalid binary expression: %s %s %s",
pr_type_name[t1], get_op_string (op), pr_type_name[t2]);
}
static expr_t *
reimplement_binary_expr (int op, expr_t *e1, expr_t *e2)
{
expr_t *e;
if (options.code.progsversion == PROG_ID_VERSION) {
switch (op) {
case '%':
{
expr_t *tmp1, *tmp2, *tmp3, *tmp4, *t1, *t2;
e = new_block_expr ();
t1 = new_temp_def_expr (&type_float);
t2 = new_temp_def_expr (&type_float);
tmp1 = new_temp_def_expr (&type_float);
tmp2 = new_temp_def_expr (&type_float);
tmp3 = new_temp_def_expr (&type_float);
tmp4 = new_temp_def_expr (&type_float);
append_expr (e, assign_expr (t1, e1));
e1 = binary_expr ('&', t1, t1);
append_expr (e, assign_expr (tmp1, e1));
append_expr (e, assign_expr (t2, e2));
e2 = binary_expr ('&', t2, t2);
append_expr (e, assign_expr (tmp2, e2));
e1 = binary_expr ('/', tmp1, tmp2);
append_expr (e, assign_expr (tmp3, e1));
e2 = binary_expr ('&', tmp3, tmp3);
append_expr (e, assign_expr (tmp4, e2));
e1 = binary_expr ('*', tmp2, tmp4);
e2 = binary_expr ('-', tmp1, e1);
e->e.block.result = e2;
return e;
}
break;
}
}
return 0;
}
static expr_t *
check_precedence (int op, expr_t *e1, expr_t *e2)
{
if (e1->type == ex_uexpr && e1->e.expr.op == '!' && !e1->paren) {
if (options.traditional) {
if (op != AND && op != OR && op != '=') {
notice (e1, "precedence of `!' and `%s' inverted for "
"traditional code", get_op_string (op));
e1->e.expr.e1->paren = 1;
return unary_expr ('!', binary_expr (op, e1->e.expr.e1, e2));
}
} else if (op == '&' || op == '|') {
if (options.warnings.precedence)
warning (e1, "ambiguous logic. Suggest explicit parentheses "
"with expressions involving ! and %s",
get_op_string (op));
}
}
if (options.traditional) {
if (e2->type == ex_expr && !e2->paren) {
if (((op == '&' || op == '|')
&& (is_math_op (e2->e.expr.op) || is_compare (e2->e.expr.op)))
|| (op == '='
&& (e2->e.expr.op == OR || e2->e.expr.op == AND))) {
notice (e1, "precedence of `%s' and `%s' inverted for "
"traditional code", get_op_string (op),
get_op_string (e2->e.expr.op));
e1 = binary_expr (op, e1, e2->e.expr.e1);
e1->paren = 1;
return binary_expr (e2->e.expr.op, e1, e2->e.expr.e2);
}
if (((op == EQ || op == NE) && is_compare (e2->e.expr.op))
|| (op == OR && e2->e.expr.op == AND)
|| (op == '|' && e2->e.expr.op == '&')) {
notice (e1, "precedence of `%s' raised to `%s' for "
"traditional code", get_op_string (op),
get_op_string (e2->e.expr.op));
e1 = binary_expr (op, e1, e2->e.expr.e1);
e1->paren = 1;
return binary_expr (e2->e.expr.op, e1, e2->e.expr.e2);
}
} else if (e1->type == ex_expr && !e1->paren) {
if (((op == '&' || op == '|')
&& (is_math_op (e1->e.expr.op) || is_compare (e1->e.expr.op)))
|| (op == '='
&& (e1->e.expr.op == OR || e1->e.expr.op == AND))) {
notice (e1, "precedence of `%s' and `%s' inverted for "
"traditional code", get_op_string (op),
get_op_string (e1->e.expr.op));
e2 = binary_expr (op, e1->e.expr.e2, e2);
e2->paren = 1;
return binary_expr (e1->e.expr.op, e1->e.expr.e1, e2);
}
}
} else {
if (e2->type == ex_expr && !e2->paren) {
if ((op == '&' || op == '|' || op == '^')
&& (is_math_op (e2->e.expr.op)
|| is_compare (e2->e.expr.op))) {
if (options.warnings.precedence)
warning (e2, "suggest parentheses around %s in "
"operand of %c",
is_compare (e2->e.expr.op)
? "comparison"
: get_op_string (e2->e.expr.op),
op);
}
}
if (e1->type == ex_expr && !e1->paren) {
if ((op == '&' || op == '|' || op == '^')
&& (is_math_op (e1->e.expr.op)
|| is_compare (e1->e.expr.op))) {
if (options.warnings.precedence)
warning (e1, "suggest parentheses around %s in "
"operand of %c",
is_compare (e1->e.expr.op)
? "comparison"
: get_op_string (e1->e.expr.op),
op);
}
}
}
return 0;
}
expr_t *
binary_expr (int op, expr_t *e1, expr_t *e2)
{
type_t *t1, *t2;
etype_t et1, et2;
expr_t *e;
expr_type_t *expr_type;
convert_name (e1);
if (e1->type == ex_block && e1->e.block.is_call
&& has_function_call (e2) && e1->e.block.result) {
e = new_temp_def_expr (get_type (e1->e.block.result));
e1 = assign_expr (e, e1);
}
if (e1->type == ex_error)
return e1;
convert_name (e2);
if (e2->type == ex_error)
return e2;
if (e1->type == ex_bool)
e1 = convert_from_bool (e1, get_type (e2));
if (e2->type == ex_bool)
e2 = convert_from_bool (e2, get_type (e1));
if ((e = check_precedence (op, e1, e2)))
return e;
t1 = get_type (e1);
t2 = get_type (e2);
if (!t1 || !t2)
internal_error (e1, "expr with no type");
if (op == EQ || op == NE) {
if (e1->type == ex_nil) {
t1 = t2;
convert_nil (e1, t1);
} else if (e2->type == ex_nil) {
t2 = t1;
convert_nil (e2, t2);
}
}
et1 = low_level_type (t1);
et2 = low_level_type (t2);
if (et1 > ev_short || !binary_expr_types[et1])
return invalid_binary_expr(op, e1, e2);
if (et2 > ev_short || !binary_expr_types[et1][et2])
return invalid_binary_expr(op, e1, e2);
expr_type = binary_expr_types[et1][et2];
while (expr_type->op && expr_type->op != op)
expr_type++;
if (!expr_type->op)
return invalid_binary_expr(op, e1, e2);
if (expr_type->a_cast)
e1 = cast_expr (expr_type->a_cast, e1);
if (expr_type->b_cast)
e2 = cast_expr (expr_type->b_cast, e2);
if ((e = reimplement_binary_expr (op, e1, e2)))
return e;
e = new_binary_expr (op, e1, e2);
e->e.expr.type = expr_type->type;
if (is_compare (op) || is_logic (op)) {
if (options.code.progsversion == PROG_ID_VERSION)
e->e.expr.type = &type_float;
}
return e;
}