#include <sys/types.h>
#include <stdarg.h>
#include <stdio.h>
#include "ansi.h"
#include "host.h"
#include "files.h"
#include "hash.h"
#include "il.h"
#include "allocate.h"
#include "config.h"
#undef NULL
#define NULL 0
extern file_pos_t yypos;
static node_t *free_list;
typedef enum {
_Binary,
_Unary,
_Pointer,
_Other
} node_class_t;
#define is_const_int(x) ((x)->node_kind == _Int_Number)
#define is_const_fp(x) ((x)->node_kind == _FP_Number)
#define is_constant(x) (is_const_int(x) || is_const_fp(x))
void
free_node(n)
node_t *n;
{
assert(n->node_kind != _Ident);
n->node_kind = 0;
n->node.unary = free_list;
free_list = n;
}
static node_t*
alloc_node(kind)
node_kind_t kind;
{
node_t *n;
int i;
n = free_list;
if (n == NULL) {
n = (node_t*) allocate(sizeof(node_t)*64);
for (i = 1; i<63; i++) {
n[i].node.unary = &n[i+1];
}
free_list = &n[1];
}
else {
free_list = n->node.unary;
memset(n, 0, sizeof(node_t));
}
n->node_def = yypos;
n->node_kind = kind;
return n;
}
node_class_t
node_classof(kind)
node_kind_t kind;
{
if (kind >= _List && kind <= _Shr) {
return _Binary;
}
if (kind >= _Sizeof && kind <= _Indirect) {
return _Unary;
}
switch (kind) {
case _Ident:
return _Pointer;
default:
break;
}
return _Other;
}
node_t*
new_node(node_kind_t kind, ...)
{
va_list ap;
node_t *n;
va_start(ap, kind);
n = alloc_node(kind);
switch (node_classof(kind)) {
case _Binary:
n->node.binary.l = va_arg(ap, node_t*);
n->node.binary.r = va_arg(ap, node_t*);
break;
case _Unary:
n->node.unary = va_arg(ap, node_t*);
break;
case _Pointer:
n->node.id.name = va_arg(ap, char*);
break;
case _Other:
switch (kind) {
case _Elipsis:
break;
case _String:
n->node.str.form = va_arg(ap, char*);
n->node.str.len = va_arg(ap, int);
break;
case _Sym:
n->node.sym = va_arg(ap, symbol_t*);
break;
case _Type:
n->node.typ = va_arg(ap, typeinfo_t*);
break;
case _Cond:
n->node.cond.bool = va_arg(ap, node_t*);
n->node.cond.tru = va_arg(ap, node_t*);
n->node.cond.fals = va_arg(ap, node_t*);
break;
case _FP_Number:
n->node.fval = va_arg(ap, host_float_t);
break;
case _Int_Number:
n->node.ival = va_arg(ap, host_int_t);
break;
default:
fatal(__FILE__,__LINE__,"Unandled noded - (%d)", kind);
break;
}
break;
default:
assert(0);
break;
}
va_end(ap);
return n;
}
static void
promote(n)
node_t *n;
{
node_t *l, *r;
host_float_t fv;
assert(n != NULL);
l = n->node.binary.l;
r = n->node.binary.r;
assert(l != NULL);
assert(r != NULL);
if (is_const_int(l) && is_const_fp(r)) {
fv = (host_float_t) l->node.ival;
l->node_kind = _FP_Number;
l->node.fval = fv;
}
else if (is_const_fp(l) && is_const_int(r)) {
fv = (host_float_t) r->node.ival;
r->node_kind = _FP_Number;
r->node.fval = fv;
}
}
static void reduce_binary();
/* Force constants to RHS */
static void
distributive(n)
node_t *n;
{
node_t *l, *r, *dr;
assert(n != NULL);
l = n->node.binary.l; assert(l != NULL);
r = n->node.binary.r; assert(r != NULL);
if (is_constant(l) && !is_constant(r)) {
n->node.binary.l = r;
n->node.binary.r = l;
}
if (is_constant(r) && l->node_kind == n->node_kind) {
dr = l->node.binary.r;
if (is_constant(dr)) {
/* Transformation
*
* (n) (n)
* / \ / \
* (l) (C) (?) (l)
* / \ / \
* (?) (C) (C) (C)
*/
n->node.binary.l = l->node.binary.l;
n->node.binary.r = l;
l->node.binary.l = dr;
l->node.binary.r = r;
reduce_binary(l);
}
}
}
static void
reduce_binary(n)
node_t *n;
{
node_t *l, *r;
if (n == NULL) return;
switch (n->node_kind) {
case _Add:
distributive(n);
promote(n);
l = n->node.binary.l; assert(l != NULL);
r = n->node.binary.r; assert(r != NULL);
if (is_constant(l)) {
assert(is_constant(r)); /* because distributive() */
if (is_const_int(l)) {
n->node_kind = _Int_Number;
n->node.ival = l->node.ival + r->node.ival;
}
else {
n->node_kind = _FP_Number;
n->node.fval = l->node.fval + r->node.fval;
}
free_node(l); free_node(r);
}
break;
case _Sub:
promote(n);
l = n->node.binary.l; assert(l != NULL);
r = n->node.binary.r; assert(r != NULL);
if (is_constant(l) && is_constant(r)) {
if (is_const_int(l)) {
n->node_kind = _Int_Number;
n->node.ival = l->node.ival - r->node.ival;
}
else {
n->node_kind = _FP_Number;
n->node.fval = l->node.fval - r->node.fval;
}
free_node(l); free_node(r);
}
break;
case _Mul:
distributive(n);
promote(n);
l = n->node.binary.l; assert(l != NULL);
r = n->node.binary.r; assert(r != NULL);
if (is_constant(l)) {
assert(is_constant(r)); /* because distributive() */
if (is_const_int(l)) {
n->node_kind = _Int_Number;
n->node.ival = l->node.ival * r->node.ival;
}
else {
n->node_kind = _FP_Number;
n->node.fval = l->node.fval * r->node.fval;
}
free_node(l); free_node(r);
}
break;
case _Div:
promote(n);
l = n->node.binary.l; assert(l != NULL);
r = n->node.binary.r; assert(r != NULL);
if (is_constant(l) && is_constant(r)) {
if (is_const_int(l)) {
if (r->node.ival != 0) {
n->node_kind = _Int_Number;
n->node.ival = l->node.ival / r->node.ival;
free_node(l); free_node(r);
}
}
else {
if (r->node.fval != 0.0) {
n->node_kind = _FP_Number;
n->node.fval = l->node.fval / r->node.fval;
free_node(l); free_node(r);
}
}
}
break;
case _Rem:
l = n->node.binary.l; assert(l != NULL);
r = n->node.binary.r; assert(r != NULL);
if (is_const_int(l) && is_const_int(r)) {
if (r->node.ival != 0) {
n->node_kind = _Int_Number;
n->node.ival = l->node.ival % r->node.ival;
free_node(l); free_node(r);
}
}
break;
case _Shl:
l = n->node.binary.l; assert(l != NULL);
r = n->node.binary.r; assert(r != NULL);
if (is_const_int(l) && is_const_int(r)) {
n->node_kind = _Int_Number;
n->node.ival = l->node.ival << r->node.ival;
free_node(l);
free_node(r);
}
break;
case _Shr:
l = n->node.binary.l; assert(l != NULL);
r = n->node.binary.r; assert(r != NULL);
if (is_const_int(l) && is_const_int(r)) {
n->node_kind = _Int_Number;
n->node.ival = l->node.ival >> r->node.ival;
free_node(l);
free_node(r);
}
break;
case _Bor:
distributive(n);
l = n->node.binary.l; assert(l != NULL);
r = n->node.binary.r; assert(r != NULL);
if (is_const_int(l) && is_const_int(r)) {
n->node_kind = _Int_Number;
n->node.ival = l->node.ival | r->node.ival;
free_node(l);
free_node(r);
}
break;
case _Band:
distributive(n);
l = n->node.binary.l; assert(l != NULL);
r = n->node.binary.r; assert(r != NULL);
if (is_const_int(l) && is_const_int(r)) {
n->node_kind = _Int_Number;
n->node.ival = l->node.ival & r->node.ival;
free_node(l);
free_node(r);
}
break;
case _Xor:
distributive(n);
l = n->node.binary.l; assert(l != NULL);
r = n->node.binary.r; assert(r != NULL);
if (is_const_int(l) && is_const_int(r)) {
n->node_kind = _Int_Number;
n->node.ival = l->node.ival ^ r->node.ival;
free_node(l);
free_node(r);
}
break;
}
}
static void
reduce_unary(n)
node_t *n;
{
node_t *l;
typeinfo_t *typ;
symbol_t *sym;
host_int_t iv;
assert(n != NULL);
l = n->node.unary;
if (l == NULL) return;
switch (n->node_kind) {
case _Sizeof:
switch (l->node_kind) {
case _Type:
typ = l->node.typ;
break;
case _Sym:
sym = l->node.sym;
if (sym == NULL) return;
typ = sym->sym_type;
break;
default:
return;
}
if (typ == NULL) return;
iv = type_sizeof(typ);
free_node(l);
n->node_kind = _Int_Number;
n->node.ival = iv;
break;
case _Unary_Plus:
switch (l->node_kind) {
case _Int_Number:
n->node_kind = _Int_Number;
n->node.ival = l->node.ival;
free_node(l);
break;
case _FP_Number:
n->node_kind = _FP_Number;
n->node.fval = l->node.fval;
free_node(l);
break;
}
break;
case _Unary_Minus:
switch (l->node_kind) {
case _Int_Number:
n->node_kind = _Int_Number;
n->node.ival = -l->node.ival;
free_node(l);
break;
case _FP_Number:
n->node_kind = _FP_Number;
n->node.fval = -l->node.fval;
free_node(l);
break;
}
break;
case _Ones_Complement:
if (l->node_kind == _Int_Number) {
n->node_kind = _Int_Number;
n->node.ival = ~l->node.ival;
free_node(l);
}
break;
case _Not:
if (l->node_kind == _Int_Number) {
n->node_kind = _Int_Number;
n->node.ival = !l->node.ival;
free_node(l);
}
break;
case _Pre_Inc:
case _Pre_Dec:
case _Post_Inc:
case _Post_Dec:
case _Addrof:
case _Aggregate:
case _Indirect:
break;
}
}
void
reduce_node(n)
node_t *n;
{
if (n == NULL) return;
switch (node_classof(n->node_kind)) {
case _Binary:
reduce_node(n->node.binary.l);
reduce_node(n->node.binary.r);
reduce_binary(n);
break;
case _Unary:
reduce_node(n->node.unary);
reduce_unary(n);
break;
default:
return;
}
}
node_t*
access_to(ptr, decl)
node_t *ptr, *decl;
{
node_t *n;
assert(ptr != NULL);
assert(decl != NULL);
assert(ptr->node_kind == _Indirect);
for (n = ptr; n; ) {
switch (n->node_kind) {
case _Indirect:
if (n->node.unary == NULL) {
n->node.unary = decl;
return ptr;
}
n = n->node.unary;
break;
default:
fatal(__FILE__,__LINE__,"Unhandled node (%d)", n->node_kind);
break;
}
}
assert(0);
return ptr;
}
node_t*
id_from_typedef(typ)
typeinfo_t *typ;
{
symbol_t *basetype;
assert(typ != NULL);
basetype = typ->type_base;
assert(basetype != NULL);
assert(basetype->sym_ident != NULL);
assert(basetype->sym_ident->node_kind == _Ident);
assert(basetype->sym_ident->node.id.name != NULL);
return new_node(_Ident, basetype->sym_ident->node.id.name);
}
syntax highlighted by Code2HTML, v. 0.9.1