#include <nidl.h>
#include <nametbl.h>
#include <errors.h>
#include <astp.h>
#include <nidlmsg.h>
#include <nidl_y.h>
static void ASTP_free_exp(
AST_exp_n_t * exp
);
AST_exp_n_t * AST_exp_new
(
unsigned long exp_type
)
{
AST_exp_n_t * exp = NEW(AST_exp_n_t);
exp->exp_type = exp_type;
return exp;
}
AST_exp_n_t * AST_exp_integer_constant
(
parser_location_p location ATTRIBUTE_UNUSED,
long value,
int int_signed
)
{
AST_exp_n_t * exp = AST_exp_new(AST_EXP_CONSTANT);
exp->exp.constant.type = AST_int_const_k;
exp->exp.constant.val.integer = value;
exp->exp.constant.int_signed = int_signed;
return exp;
}
AST_exp_n_t * AST_exp_char_constant
(
parser_location_p location,
char value
)
{
AST_exp_n_t * exp = AST_exp_new(AST_EXP_CONSTANT);
exp->exp.constant.type = AST_nil_const_k;
exp->exp.constant.val.other = AST_char_constant(location, value);
return exp;
}
AST_exp_n_t * AST_exp_identifier
(
parser_location_p location ATTRIBUTE_UNUSED,
NAMETABLE_id_t name
)
{
AST_exp_n_t * exp = AST_exp_new(AST_EXP_CONSTANT);
exp->exp.constant.type = AST_nil_const_k;
exp->exp.constant.val.other = NULL;
exp->exp.constant.name = name;
return exp;
}
AST_exp_n_t * AST_exp_string_constant
(
parser_location_p location,
STRTAB_str_t string
)
{
AST_exp_n_t * exp = AST_exp_new(AST_EXP_CONSTANT);
exp->exp.constant.type = AST_nil_const_k;
exp->exp.constant.val.other = AST_string_constant(location, string);
return exp;
}
AST_exp_n_t * AST_exp_null_constant
(
parser_location_p location
)
{
AST_exp_n_t * exp = AST_exp_new(AST_EXP_CONSTANT);
exp->exp.constant.type = AST_nil_const_k;
exp->exp.constant.val.other = AST_null_constant(location);
return exp;
}
AST_exp_n_t * AST_exp_boolean_constant
(
parser_location_p location,
boolean value
)
{
AST_exp_n_t * exp = AST_exp_new(AST_EXP_CONSTANT);
exp->exp.constant.type = AST_nil_const_k;
exp->exp.constant.val.other = AST_boolean_constant(location, value);
return exp;
}
AST_exp_n_t * AST_expression
(
parser_location_p location ATTRIBUTE_UNUSED,
unsigned long exp_type,
AST_exp_n_t * oper1,
AST_exp_n_t * oper2,
AST_exp_n_t * oper3
)
{
AST_exp_n_t * exp = AST_exp_new(exp_type);
exp->exp.expression.oper1 = oper1;
exp->exp.expression.oper2 = oper2;
exp->exp.expression.oper3 = oper3;
return exp;
}
AST_constant_n_t * AST_constant_from_exp
(
parser_location_p location,
AST_exp_n_t * exp
)
{
AST_constant_n_t * const_return;
ASTP_evaluate_expr(location, exp, true);
if (exp->exp_type == AST_EXP_CONSTANT) {
if (exp->exp.constant.type == AST_int_const_k) {
const_return = AST_integer_constant(location, exp->exp.constant.val.integer);
const_return->int_signed = exp->exp.constant.int_signed;
}
else {
const_return = exp->exp.constant.val.other;
}
}
else
const_return = NULL;
return const_return;
}
boolean ASTP_expr_is_simple
(
parser_location_p location,
AST_exp_n_t * exp
)
{
if (ASTP_evaluate_expr(location, exp, true)) {
return true;
}
switch(exp->exp_type) {
case AST_EXP_CONSTANT:
return true;
break;
case AST_EXP_BINARY_SLASH:
case AST_EXP_BINARY_STAR:
if (exp->exp.expression.oper1->exp_type == AST_EXP_CONSTANT &&
((ASTP_expr_integer_value(location, exp->exp.expression.oper2) == 2) ||
(ASTP_expr_integer_value(location, exp->exp.expression.oper2) == 4) ||
(ASTP_expr_integer_value(location, exp->exp.expression.oper2) == 8)))
{
return true;
}
break;
case AST_EXP_BINARY_PLUS:
case AST_EXP_BINARY_MINUS:
if (exp->exp.expression.oper1->exp_type == AST_EXP_CONSTANT &&
ASTP_expr_integer_value(location, exp->exp.expression.oper2) == 1)
{
return true;
}
break;
case AST_EXP_UNARY_STAR:
while(exp->exp_type == AST_EXP_UNARY_STAR)
exp = exp->exp.expression.oper1;
if (exp->exp_type == AST_EXP_CONSTANT) {
return true;
}
break;
case AST_EXP_BINARY_AND:
if (exp->exp.expression.oper1->exp_type == AST_EXP_BINARY_PLUS
&&
exp->exp.expression.oper2->exp_type == AST_EXP_UNARY_TILDE)
{
AST_exp_n_t * op1 = exp->exp.expression.oper1;
AST_exp_n_t * op2 = exp->exp.expression.oper2;
AST_exp_n_t * ident_exp = op1->exp.expression.oper1;
long nval = ASTP_expr_integer_value(location, op1->exp.expression.oper2);
if ((ident_exp->exp_type == AST_EXP_CONSTANT || (
ident_exp->exp_type == AST_EXP_UNARY_STAR &&
ident_exp->exp.expression.oper1->exp_type == AST_EXP_CONSTANT))
&& (nval == 1 || nval == 3 || nval == 7) &&
ASTP_expr_integer_value(location, op2->exp.expression.oper1)
== nval)
return true;
}
break;
}
return false;
}
long ASTP_expr_integer_value
(
parser_location_p location,
AST_exp_n_t * exp
)
{
long value;
ASTP_evaluate_expr(location, exp, true);
if (exp->exp.constant.type == AST_int_const_k)
value = exp->exp.constant.val.integer;
else {
switch(exp->exp.constant.val.other->kind) {
case AST_int_const_k:
value = exp->exp.constant.val.other->value.int_val;
break;
case AST_char_const_k:
value = exp->exp.constant.val.other->value.char_val;
break;
case AST_boolean_const_k:
value = exp->exp.constant.val.other->value.boolean_val;
break;
default:
value = 0;
}
}
return value;
}
void ASTP_free_exp(AST_exp_n_t * exp) {
if (exp == NULL)
return;
if (exp->exp_type != AST_EXP_CONSTANT) {
ASTP_free_exp(exp->exp.expression.oper1);
ASTP_free_exp(exp->exp.expression.oper2);
ASTP_free_exp(exp->exp.expression.oper3);
}
FREE(exp);
}
boolean ASTP_evaluate_expr
(
parser_location_p location,
AST_exp_n_t * exp,
boolean constant_only
)
{
boolean result;
long val, val1, val2;
AST_exp_n_t * op1=NULL, *op2=NULL, *op3=NULL;
if (exp == NULL) {
log_warning(location->lineno, NIDL_EXP_IS_NULL, NULL);
return true;
}
if (exp->exp_type == AST_EXP_CONSTANT) {
if (exp->exp.constant.type == AST_nil_const_k &&
exp->exp.constant.val.other == NULL) {
exp->exp.constant.val.other =
(AST_constant_n_t*)ASTP_lookup_binding(
location,
exp->exp.constant.name,
fe_constant_n_k, FALSE);
if (exp->exp.constant.val.other == NULL)
return false;
}
return true;
} else if (exp->exp_type == AST_EXP_TUPLE) {
op1 = exp->exp.expression.oper1;
if (op1->exp.constant.type == AST_nil_const_k &&
op1->exp.constant.val.other == NULL) {
op1->exp.constant.val.other =
(AST_constant_n_t *)ASTP_lookup_binding(
location,
op1->exp.constant.name,
fe_constant_n_k, FALSE);
if (op1->exp.constant.val.other == NULL)
return false;
}
op2 = exp->exp.expression.oper2;
if (op2->exp.constant.type == AST_nil_const_k &&
op2->exp.constant.val.other == NULL) {
op2->exp.constant.val.other =
(AST_constant_n_t *)ASTP_lookup_binding(
location,
op2->exp.constant.name,
fe_constant_n_k, FALSE);
if (op2->exp.constant.val.other == NULL)
return false;
}
return true;
}
result = ASTP_evaluate_expr(location, exp->exp.expression.oper1, constant_only);
if (result == false)
return false;
op1 = exp->exp.expression.oper1;
if ((exp->exp_type & AST_EXP_2_OP_MASK) != 0) {
result = ASTP_evaluate_expr(location, exp->exp.expression.oper2, constant_only);
if (result == false)
return false;
op2 = exp->exp.expression.oper2;
}
if ((exp->exp_type & AST_EXP_3_OP_MASK) != 0) {
result = ASTP_evaluate_expr(location, exp->exp.expression.oper3, constant_only);
if (result == false)
return false;
op3 = exp->exp.expression.oper3;
}
switch(exp->exp_type) {
case AST_EXP_UNARY_NOT:
exp->exp.constant.val.integer =
!ASTP_expr_integer_value(location, op1);
break;
case AST_EXP_UNARY_TILDE:
exp->exp.constant.val.integer =
~ASTP_expr_integer_value(location, op1);
break;
case AST_EXP_UNARY_PLUS:
exp->exp.constant.val.integer =
+ASTP_expr_integer_value(location, op1);
break;
case AST_EXP_UNARY_MINUS:
exp->exp.constant.val.integer =
-ASTP_expr_integer_value(location, op1);
break;
case AST_EXP_UNARY_STAR:
return false;
case AST_EXP_BINARY_PERCENT:
val = ASTP_expr_integer_value(location, op2);
if (val == 0)
log_error(location->lineno, NIDL_INTDIVBY0, NULL);
else
val = ASTP_expr_integer_value(location, op1) % val;
exp->exp.constant.val.integer = val;
break;
case AST_EXP_BINARY_SLASH:
val = ASTP_expr_integer_value(location, op2);
if (val == 0)
log_error(location->lineno, NIDL_INTDIVBY0, NULL);
else
val = ASTP_expr_integer_value(location, op1) / val;
exp->exp.constant.val.integer = val;
break;
case AST_EXP_BINARY_STAR:
val1 = ASTP_expr_integer_value(location, op1);
val2 = ASTP_expr_integer_value(location, op2);
val = val1 * val2;
if (val < val1 && val > val2)
log_error(location->lineno, NIDL_INTOVERFLOW, KEYWORDS_lookup_text(LONG_KW), NULL);
exp->exp.constant.val.integer = val;
break;
case AST_EXP_BINARY_MINUS:
exp->exp.constant.val.integer =
ASTP_expr_integer_value(location, op1) -
ASTP_expr_integer_value(location, op2);
break;
case AST_EXP_BINARY_PLUS:
exp->exp.constant.val.integer =
ASTP_expr_integer_value(location, op1) +
ASTP_expr_integer_value(location, op2);
break;
case AST_EXP_BINARY_RSHIFT:
exp->exp.constant.val.integer =
ASTP_expr_integer_value(location, op1) >>
ASTP_expr_integer_value(location, op2);
break;
case AST_EXP_BINARY_LSHIFT:
exp->exp.constant.val.integer =
ASTP_expr_integer_value(location, op1) <<
ASTP_expr_integer_value(location, op2);
break;
case AST_EXP_BINARY_GE:
exp->exp.constant.val.integer =
ASTP_expr_integer_value(location, op1) >=
ASTP_expr_integer_value(location, op2);
break;
case AST_EXP_BINARY_LE:
exp->exp.constant.val.integer =
ASTP_expr_integer_value(location, op1) <=
ASTP_expr_integer_value(location, op2);
break;
case AST_EXP_BINARY_GT:
exp->exp.constant.val.integer =
ASTP_expr_integer_value(location, op1) >
ASTP_expr_integer_value(location, op2);
break;
case AST_EXP_BINARY_LT:
exp->exp.constant.val.integer =
ASTP_expr_integer_value(location, op1) <
ASTP_expr_integer_value(location, op2);
break;
case AST_EXP_BINARY_NE:
exp->exp.constant.val.integer =
ASTP_expr_integer_value(location, op1) !=
ASTP_expr_integer_value(location, op2);
break;
case AST_EXP_BINARY_EQUAL:
exp->exp.constant.val.integer =
ASTP_expr_integer_value(location, op1) ==
ASTP_expr_integer_value(location, op2);
break;
case AST_EXP_BINARY_AND:
exp->exp.constant.val.integer =
ASTP_expr_integer_value(location, op1) &
ASTP_expr_integer_value(location, op2);
break;
case AST_EXP_BINARY_OR:
exp->exp.constant.val.integer =
ASTP_expr_integer_value(location, op1) |
ASTP_expr_integer_value(location, op2);
break;
case AST_EXP_BINARY_XOR:
exp->exp.constant.val.integer =
ASTP_expr_integer_value(location, op1) ^
ASTP_expr_integer_value(location, op2);
break;
case AST_EXP_BINARY_LOG_AND:
exp->exp.constant.val.integer =
ASTP_expr_integer_value(location, op1) &&
ASTP_expr_integer_value(location, op2);
break;
case AST_EXP_BINARY_LOG_OR:
exp->exp.constant.val.integer =
ASTP_expr_integer_value(location, op1) ||
ASTP_expr_integer_value(location, op2);
break;
case AST_EXP_TERNARY_OP:
if (ASTP_expr_integer_value(location, op1)) {
assert(op2 != NULL);
*exp = *op2;
}
else {
assert(op3 != NULL);
*exp = *op3;
}
return true;
default:
break;
}
ASTP_free_exp(op1);
ASTP_free_exp(op2);
ASTP_free_exp(op3);
exp->exp_type = AST_EXP_CONSTANT;
exp->exp.constant.type = AST_int_const_k;
return true;
}