mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-02-20 18:52:28 +00:00
Rewrite binary_expr().
It is now in its own file and uses table lookups to check for valid type and operator combinations, and also the resulting type of the expression. This probably breaks multiple function calls in the one expression.
This commit is contained in:
parent
ec98954dfc
commit
4bc40b3917
3 changed files with 789 additions and 202 deletions
|
@ -41,7 +41,8 @@ bin_SCRIPTS= qfpreqcc
|
|||
common_src=\
|
||||
class.c codespace.c constfold.c cpp.c dags.c debug.c def.c defspace.c \
|
||||
diagnostic.c dot.c dot_dag.c dot_expr.c dot_flow.c dot_sblock.c emit.c \
|
||||
expr.c flow.c function.c grab.c idstuff.c linker.c method.c obj_file.c \
|
||||
expr.c expr_binary.c flow.c function.c grab.c idstuff.c linker.c method.c \
|
||||
obj_file.c \
|
||||
obj_type.c opcodes.c options.c pragma.c qfcc.c reloc.c shared.c \
|
||||
statements.c strpool.c struct.c switch.c symtab.c type.c value.c
|
||||
|
||||
|
|
|
@ -1488,91 +1488,6 @@ is_logic (int op)
|
|||
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;
|
||||
}
|
||||
|
||||
static int
|
||||
has_function_call (expr_t *e)
|
||||
{
|
||||
|
@ -1599,122 +1514,6 @@ has_function_call (expr_t *e)
|
|||
}
|
||||
}
|
||||
|
||||
expr_t *
|
||||
binary_expr (int op, expr_t *e1, expr_t *e2)
|
||||
{
|
||||
type_t *t1, *t2;
|
||||
type_t *type = 0;
|
||||
expr_t *e;
|
||||
|
||||
if (e1->type == ex_error)
|
||||
return e1;
|
||||
if (e2->type == ex_error)
|
||||
return e2;
|
||||
|
||||
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 (op == '.')
|
||||
return field_expr (e1, e2);
|
||||
|
||||
convert_name (e2);
|
||||
if (op == OR || op == AND) {
|
||||
e1 = test_expr (e1);
|
||||
e2 = test_expr (e2);
|
||||
}
|
||||
if (is_compare (op)) {
|
||||
e1 = fold_constants (e1);
|
||||
e2 = fold_constants (e2);
|
||||
}
|
||||
|
||||
if (e1->type == ex_error)
|
||||
return e1;
|
||||
if (e2->type == ex_error)
|
||||
return e2;
|
||||
t1 = get_type (e1);
|
||||
t2 = get_type (e2);
|
||||
if (!t1 || !t2)
|
||||
internal_error (e1, 0);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
if (e1->type == ex_bool)
|
||||
e1 = convert_from_bool (e1, t2);
|
||||
|
||||
if (e2->type == ex_bool)
|
||||
e2 = convert_from_bool (e2, t1);
|
||||
|
||||
if ((e = check_precedence (op, e1, e2)))
|
||||
return e;
|
||||
|
||||
type = t1;
|
||||
|
||||
if (is_compare (op)) {
|
||||
if (!type_assignable (t1, t2))
|
||||
return error (e1, "type mismatch for %s", get_op_string (op));
|
||||
}
|
||||
if (is_compare (op) || is_logic (op)) {
|
||||
if (options.code.progsversion > PROG_ID_VERSION)
|
||||
type = &type_integer;
|
||||
else
|
||||
type = &type_float;
|
||||
} else if (op == '*' && t1 == &type_vector && t2 == &type_vector) {
|
||||
type = &type_float;
|
||||
}
|
||||
if (!type)
|
||||
internal_error (e1, 0);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
e = new_binary_expr (op, e1, e2);
|
||||
e->e.expr.type = type;
|
||||
return e;
|
||||
}
|
||||
|
||||
expr_t *
|
||||
asx_expr (int op, expr_t *e1, expr_t *e2)
|
||||
{
|
||||
|
|
787
tools/qfcc/source/expr_binary.c
Normal file
787
tools/qfcc/source/expr_binary.c
Normal file
|
@ -0,0 +1,787 @@
|
|||
/*
|
||||
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_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;
|
||||
}
|
Loading…
Reference in a new issue