diff dmd/constfold.c @ 336:aaade6ded589 trunk

[svn r357] Merged DMD 1.033
author lindquist
date Sat, 12 Jul 2008 19:38:31 +0200
parents 2b72433d5c8c
children 29dc68c949b0
line wrap: on
line diff
--- a/dmd/constfold.c	Sat Jul 12 17:04:36 2008 +0200
+++ b/dmd/constfold.c	Sat Jul 12 19:38:31 2008 +0200
@@ -1,1506 +1,1512 @@
-
-// Compiler implementation of the D programming language
-// Copyright (c) 1999-2007 by Digital Mars
-// All Rights Reserved
-// written by Walter Bright
-// http://www.digitalmars.com
-// License for redistribution is by either the Artistic License
-// in artistic.txt, or the GNU General Public License in gnu.txt.
-// See the included readme.txt for details.
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <math.h>
-
-#if __DMC__
-#include <complex.h>
-#endif
-
-#include "mem.h"
-#include "root.h"
-
-#include "mtype.h"
-#include "expression.h"
-#include "aggregate.h"
-#include "declaration.h"
-
-#ifdef IN_GCC
-#include "d-gcc-real.h"
-
-/* %% fix? */
-extern "C" bool real_isnan (const real_t *);
-#endif
-
-static real_t zero;	// work around DMC bug for now
-
-#define LOG 0
-
-Expression *expType(Type *type, Expression *e)
-{
-    if (type != e->type)
-    {
-	e = e->copy();
-	e->type = type;
-    }
-    return e;
-}
-
-/* ================================== isConst() ============================== */
-
-int Expression::isConst()
-{
-    //printf("Expression::isConst(): %s\n", toChars());
-    return 0;
-}
-
-int IntegerExp::isConst()
-{
-    return 1;
-}
-
-int RealExp::isConst()
-{
-    return 1;
-}
-
-int ComplexExp::isConst()
-{
-    return 1;
-}
-
-int SymOffExp::isConst()
-{
-    return 2;
-}
-
-/* =============================== constFold() ============================== */
-
-/* The constFold() functions were redundant with the optimize() ones,
- * and so have been folded in with them.
- */
-
-/* ========================================================================== */
-
-Expression *Neg(Type *type, Expression *e1)
-{   Expression *e;
-    Loc loc = e1->loc;
-
-    if (e1->type->isreal())
-    {
-	e = new RealExp(loc, -e1->toReal(), type);
-    }
-    else if (e1->type->isimaginary())
-    {
-	e = new RealExp(loc, -e1->toImaginary(), type);
-    }
-    else if (e1->type->iscomplex())
-    {
-	e = new ComplexExp(loc, -e1->toComplex(), type);
-    }
-    else
-	e = new IntegerExp(loc, -e1->toInteger(), type);
-    return e;
-}
-
-Expression *Com(Type *type, Expression *e1)
-{   Expression *e;
-    Loc loc = e1->loc;
-
-    e = new IntegerExp(loc, ~e1->toInteger(), type);
-    return e;
-}
-
-Expression *Not(Type *type, Expression *e1)
-{   Expression *e;
-    Loc loc = e1->loc;
-
-    e = new IntegerExp(loc, e1->isBool(0), type);
-    return e;
-}
-
-Expression *Bool(Type *type, Expression *e1)
-{   Expression *e;
-    Loc loc = e1->loc;
-
-    e = new IntegerExp(loc, e1->isBool(1), type);
-    return e;
-}
-
-Expression *Add(Type *type, Expression *e1, Expression *e2)
-{   Expression *e;
-    Loc loc = e1->loc;
-
-#if LOG
-    printf("Add(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
-#endif
-    if (type->isreal())
-    {
-	e = new RealExp(loc, e1->toReal() + e2->toReal(), type);
-    }
-    else if (type->isimaginary())
-    {
-	e = new RealExp(loc, e1->toImaginary() + e2->toImaginary(), type);
-    }
-    else if (type->iscomplex())
-    {
-	// This rigamarole is necessary so that -0.0 doesn't get
-	// converted to +0.0 by doing an extraneous add with +0.0
-	complex_t c1;
-	real_t r1;
-	real_t i1;
-
-	complex_t c2;
-	real_t r2;
-	real_t i2;
-
-	complex_t v;
-	int x;
-
-	if (e1->type->isreal())
-	{   r1 = e1->toReal();
-	    x = 0;
-	}
-	else if (e1->type->isimaginary())
-	{   i1 = e1->toImaginary();
-	    x = 3;
-	}
-	else
-	{   c1 = e1->toComplex();
-	    x = 6;
-	}
-
-	if (e2->type->isreal())
-	{   r2 = e2->toReal();
-	}
-	else if (e2->type->isimaginary())
-	{   i2 = e2->toImaginary();
-	    x += 1;
-	}
-	else
-	{   c2 = e2->toComplex();
-	    x += 2;
-	}
-
-	switch (x)
-	{
-#if __DMC__
-	    case 0+0:	v = (complex_t) (r1 + r2);	break;
-	    case 0+1:	v = r1 + i2 * I;		break;
-	    case 0+2:	v = r1 + c2;			break;
-	    case 3+0:	v = i1 * I + r2;		break;
-	    case 3+1:	v = (complex_t) ((i1 + i2) * I); break;
-	    case 3+2:	v = i1 * I + c2;		break;
-	    case 6+0:	v = c1 + r2;			break;
-	    case 6+1:	v = c1 + i2 * I;		break;
-	    case 6+2:	v = c1 + c2;			break;
-#else
-	    case 0+0:	v = complex_t(r1 + r2, 0);	break;
-	    case 0+1:	v = complex_t(r1, i2);		break;
-	    case 0+2:	v = complex_t(r1 + creall(c2), cimagl(c2));	break;
-	    case 3+0:	v = complex_t(r2, i1);		break;
-	    case 3+1:	v = complex_t(0, i1 + i2);	break;
-	    case 3+2:	v = complex_t(creall(c2), i1 + cimagl(c2));	break;
-	    case 6+0:	v = complex_t(creall(c1) + r2, cimagl(c2));	break;
-	    case 6+1:	v = complex_t(creall(c1), cimagl(c1) + i2);	break;
-	    case 6+2:	v = c1 + c2;			break;
-#endif
-	    default: assert(0);
-	}
-	e = new ComplexExp(loc, v, type);
-    }
-    else if (e1->op == TOKsymoff)
-    {
-	SymOffExp *soe = (SymOffExp *)e1;
-	e = new SymOffExp(loc, soe->var, soe->offset + e2->toInteger());
-	e->type = type;
-    }
-    else if (e2->op == TOKsymoff)
-    {
-	SymOffExp *soe = (SymOffExp *)e2;
-	e = new SymOffExp(loc, soe->var, soe->offset + e1->toInteger());
-	e->type = type;
-    }
-    else
-	e = new IntegerExp(loc, e1->toInteger() + e2->toInteger(), type);
-    return e;
-}
-
-
-Expression *Min(Type *type, Expression *e1, Expression *e2)
-{   Expression *e;
-    Loc loc = e1->loc;
-
-    if (type->isreal())
-    {
-	e = new RealExp(loc, e1->toReal() - e2->toReal(), type);
-    }
-    else if (type->isimaginary())
-    {
-	e = new RealExp(loc, e1->toImaginary() - e2->toImaginary(), type);
-    }
-    else if (type->iscomplex())
-    {
-	// This rigamarole is necessary so that -0.0 doesn't get
-	// converted to +0.0 by doing an extraneous add with +0.0
-	complex_t c1;
-	real_t r1;
-	real_t i1;
-
-	complex_t c2;
-	real_t r2;
-	real_t i2;
-
-	complex_t v;
-	int x;
-
-	if (e1->type->isreal())
-	{   r1 = e1->toReal();
-	    x = 0;
-	}
-	else if (e1->type->isimaginary())
-	{   i1 = e1->toImaginary();
-	    x = 3;
-	}
-	else
-	{   c1 = e1->toComplex();
-	    x = 6;
-	}
-
-	if (e2->type->isreal())
-	{   r2 = e2->toReal();
-	}
-	else if (e2->type->isimaginary())
-	{   i2 = e2->toImaginary();
-	    x += 1;
-	}
-	else
-	{   c2 = e2->toComplex();
-	    x += 2;
-	}
-
-	switch (x)
-	{
-#if __DMC__
-	    case 0+0:	v = (complex_t) (r1 - r2);	break;
-	    case 0+1:	v = r1 - i2 * I;		break;
-	    case 0+2:	v = r1 - c2;			break;
-	    case 3+0:	v = i1 * I - r2;		break;
-	    case 3+1:	v = (complex_t) ((i1 - i2) * I); break;
-	    case 3+2:	v = i1 * I - c2;		break;
-	    case 6+0:	v = c1 - r2;			break;
-	    case 6+1:	v = c1 - i2 * I;		break;
-	    case 6+2:	v = c1 - c2;			break;
-#else
-	    case 0+0:	v = complex_t(r1 - r2, 0);	break;
-	    case 0+1:	v = complex_t(r1, -i2);		break;
-	    case 0+2:	v = complex_t(r1 - creall(c2), -cimagl(c2));	break;
-	    case 3+0:	v = complex_t(-r2, i1);		break;
-	    case 3+1:	v = complex_t(0, i1 - i2);	break;
-	    case 3+2:	v = complex_t(-creall(c2), i1 - cimagl(c2));	break;
-	    case 6+0:	v = complex_t(creall(c1) - r2, cimagl(c1));	break;
-	    case 6+1:	v = complex_t(creall(c1), cimagl(c1) - i2);	break;
-	    case 6+2:	v = c1 - c2;			break;
-#endif
-	    default: assert(0);
-	}
-	e = new ComplexExp(loc, v, type);
-    }
-    else if (e1->op == TOKsymoff)
-    {
-	SymOffExp *soe = (SymOffExp *)e1;
-	e = new SymOffExp(loc, soe->var, soe->offset - e2->toInteger());
-	e->type = type;
-    }
-    else
-    {
-	e = new IntegerExp(loc, e1->toInteger() - e2->toInteger(), type);
-    }
-    return e;
-}
-
-Expression *Mul(Type *type, Expression *e1, Expression *e2)
-{   Expression *e;
-    Loc loc = e1->loc;
-
-    if (type->isfloating())
-    {   complex_t c;
-#ifdef IN_GCC
-	real_t r;
-#else
-	d_float80 r;
-#endif
-
-	if (e1->type->isreal())
-	{
-#if __DMC__
-	    c = e1->toReal() * e2->toComplex();
-#else
-	    r = e1->toReal();
-	    c = e2->toComplex();
-	    c = complex_t(r * creall(c), r * cimagl(c));
-#endif
-	}
-	else if (e1->type->isimaginary())
-	{
-#if __DMC__
-	    c = e1->toImaginary() * I * e2->toComplex();
-#else
-	    r = e1->toImaginary();
-	    c = e2->toComplex();
-	    c = complex_t(-r * cimagl(c), r * creall(c));
-#endif
-	}
-	else if (e2->type->isreal())
-	{
-#if __DMC__
-	    c = e2->toReal() * e1->toComplex();
-#else
-	    r = e2->toReal();
-	    c = e1->toComplex();
-	    c = complex_t(r * creall(c), r * cimagl(c));
-#endif
-	}
-	else if (e2->type->isimaginary())
-	{
-#if __DMC__
-	    c = e1->toComplex() * e2->toImaginary() * I;
-#else
-	    r = e2->toImaginary();
-	    c = e1->toComplex();
-	    c = complex_t(-r * cimagl(c), r * creall(c));
-#endif
-	}
-	else
-	    c = e1->toComplex() * e2->toComplex();
-
-	if (type->isreal())
-	    e = new RealExp(loc, creall(c), type);
-	else if (type->isimaginary())
-	    e = new RealExp(loc, cimagl(c), type);
-	else if (type->iscomplex())
-	    e = new ComplexExp(loc, c, type);
-	else
-	    assert(0);
-    }
-    else
-    {
-	e = new IntegerExp(loc, e1->toInteger() * e2->toInteger(), type);
-    }
-    return e;
-}
-
-Expression *Div(Type *type, Expression *e1, Expression *e2)
-{   Expression *e;
-    Loc loc = e1->loc;
-
-    if (type->isfloating())
-    {   complex_t c;
-#ifdef IN_GCC
-	real_t r;
-#else
-	d_float80 r;
-#endif
-
-	//e1->type->print();
-	//e2->type->print();
-	if (e2->type->isreal())
-	{
-	    if (e1->type->isreal())
-	    {
-		e = new RealExp(loc, e1->toReal() / e2->toReal(), type);
-		return e;
-	    }
-#if __DMC__
-	    //r = e2->toReal();
-	    //c = e1->toComplex();
-	    //printf("(%Lg + %Lgi) / %Lg\n", creall(c), cimagl(c), r);
-
-	    c = e1->toComplex() / e2->toReal();
-#else
-	    r = e2->toReal();
-	    c = e1->toComplex();
-	    c = complex_t(creall(c) / r, cimagl(c) / r);
-#endif
-	}
-	else if (e2->type->isimaginary())
-	{
-#if __DMC__
-	    //r = e2->toImaginary();
-	    //c = e1->toComplex();
-	    //printf("(%Lg + %Lgi) / %Lgi\n", creall(c), cimagl(c), r);
-
-	    c = e1->toComplex() / (e2->toImaginary() * I);
-#else
-	    r = e2->toImaginary();
-	    c = e1->toComplex();
-	    c = complex_t(cimagl(c) / r, -creall(c) / r);
-#endif
-	}
-	else
-	{
-	    c = e1->toComplex() / e2->toComplex();
-	}
-
-	if (type->isreal())
-	    e = new RealExp(loc, creall(c), type);
-	else if (type->isimaginary())
-	    e = new RealExp(loc, cimagl(c), type);
-	else if (type->iscomplex())
-	    e = new ComplexExp(loc, c, type);
-	else
-	    assert(0);
-    }
-    else
-    {   sinteger_t n1;
-	sinteger_t n2;
-	sinteger_t n;
-
-	n1 = e1->toInteger();
-	n2 = e2->toInteger();
-	if (n2 == 0)
-	{   e2->error("divide by 0");
-	    e2 = new IntegerExp(0, 1, e2->type);
-	    n2 = 1;
-	}
-	if (e1->type->isunsigned() || e2->type->isunsigned())
-	    n = ((d_uns64) n1) / ((d_uns64) n2);
-	else
-	    n = n1 / n2;
-	e = new IntegerExp(loc, n, type);
-    }
-    return e;
-}
-
-Expression *Mod(Type *type, Expression *e1, Expression *e2)
-{   Expression *e;
-    Loc loc = e1->loc;
-
-    if (type->isfloating())
-    {
-	complex_t c;
-
-	if (e2->type->isreal())
-	{   real_t r2 = e2->toReal();
-
-#ifdef __DMC__
-	    c = fmodl(e1->toReal(), r2) + fmodl(e1->toImaginary(), r2) * I;
-#elif defined(IN_GCC)
-	    c = complex_t(e1->toReal() % r2, e1->toImaginary() % r2);
-#else
-	    c = complex_t(fmodl(e1->toReal(), r2), fmodl(e1->toImaginary(), r2));
-#endif
-	}
-	else if (e2->type->isimaginary())
-	{   real_t i2 = e2->toImaginary();
-
-#ifdef __DMC__
-	    c = fmodl(e1->toReal(), i2) + fmodl(e1->toImaginary(), i2) * I;
-#elif defined(IN_GCC)
-	    c = complex_t(e1->toReal() % i2, e1->toImaginary() % i2);
-#else
-	    c = complex_t(fmodl(e1->toReal(), i2), fmodl(e1->toImaginary(), i2));
-#endif
-	}
-	else
-	    assert(0);
-
-	if (type->isreal())
-	    e = new RealExp(loc, creall(c), type);
-	else if (type->isimaginary())
-	    e = new RealExp(loc, cimagl(c), type);
-	else if (type->iscomplex())
-	    e = new ComplexExp(loc, c, type);
-	else
-	    assert(0);
-    }
-    else
-    {   sinteger_t n1;
-	sinteger_t n2;
-	sinteger_t n;
-
-	n1 = e1->toInteger();
-	n2 = e2->toInteger();
-	if (n2 == 0)
-	{   e2->error("divide by 0");
-	    e2 = new IntegerExp(0, 1, e2->type);
-	    n2 = 1;
-	}
-	if (e1->type->isunsigned() || e2->type->isunsigned())
-	    n = ((d_uns64) n1) % ((d_uns64) n2);
-	else
-	    n = n1 % n2;
-	e = new IntegerExp(loc, n, type);
-    }
-    return e;
-}
-
-Expression *Shl(Type *type, Expression *e1, Expression *e2)
-{   Expression *e;
-    Loc loc = e1->loc;
-
-    e = new IntegerExp(loc, e1->toInteger() << e2->toInteger(), type);
-    return e;
-}
-
-Expression *Shr(Type *type, Expression *e1, Expression *e2)
-{   Expression *e;
-    Loc loc = e1->loc;
-    unsigned count;
-    integer_t value;
-
-    value = e1->toInteger();
-    count = e2->toInteger();
-    switch (e1->type->toBasetype()->ty)
-    {
-	case Tint8:
-		value = (d_int8)(value) >> count;
-		break;
-
-	case Tuns8:
-		value = (d_uns8)(value) >> count;
-		break;
-
-	case Tint16:
-		value = (d_int16)(value) >> count;
-		break;
-
-	case Tuns16:
-		value = (d_uns16)(value) >> count;
-		break;
-
-	case Tint32:
-		value = (d_int32)(value) >> count;
-		break;
-
-	case Tuns32:
-		value = (d_uns32)(value) >> count;
-		break;
-
-	case Tint64:
-		value = (d_int64)(value) >> count;
-		break;
-
-	case Tuns64:
-		value = (d_uns64)(value) >> count;
-		break;
-
-	default:
-		assert(0);
-    }
-    e = new IntegerExp(loc, value, type);
-    return e;
-}
-
-Expression *Ushr(Type *type, Expression *e1, Expression *e2)
-{   Expression *e;
-    Loc loc = e1->loc;
-    unsigned count;
-    integer_t value;
-
-    value = e1->toInteger();
-    count = e2->toInteger();
-    switch (e1->type->toBasetype()->ty)
-    {
-	case Tint8:
-	case Tuns8:
-		assert(0);		// no way to trigger this
-		value = (value & 0xFF) >> count;
-		break;
-
-	case Tint16:
-	case Tuns16:
-		assert(0);		// no way to trigger this
-		value = (value & 0xFFFF) >> count;
-		break;
-
-	case Tint32:
-	case Tuns32:
-		value = (value & 0xFFFFFFFF) >> count;
-		break;
-
-	case Tint64:
-	case Tuns64:
-		value = (d_uns64)(value) >> count;
-		break;
-
-	default:
-		assert(0);
-    }
-    e = new IntegerExp(loc, value, type);
-    return e;
-}
-
-Expression *And(Type *type, Expression *e1, Expression *e2)
-{   Expression *e;
-    Loc loc = e1->loc;
-
-    e = new IntegerExp(loc, e1->toInteger() & e2->toInteger(), type);
-    return e;
-}
-
-Expression *Or(Type *type, Expression *e1, Expression *e2)
-{   Expression *e;
-    Loc loc = e1->loc;
-
-    e = new IntegerExp(loc, e1->toInteger() | e2->toInteger(), type);
-    return e;
-}
-
-Expression *Xor(Type *type, Expression *e1, Expression *e2)
-{   Expression *e;
-    Loc loc = e1->loc;
-
-    e = new IntegerExp(loc, e1->toInteger() ^ e2->toInteger(), type);
-    return e;
-}
-
-/* Also returns EXP_CANT_INTERPRET if cannot be computed.
- */
-Expression *Equal(enum TOK op, Type *type, Expression *e1, Expression *e2)
-{   Expression *e;
-    Loc loc = e1->loc;
-    int cmp;
-    real_t r1;
-    real_t r2;
-
-    //printf("Equal(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
-
-    assert(op == TOKequal || op == TOKnotequal);
-
-    if (e1->op == TOKnull)
-    {
-	if (e2->op == TOKnull)
-	    cmp = 1;
-	else if (e2->op == TOKstring)
-	{   StringExp *es2 = (StringExp *)e2;
-	    cmp = (0 == es2->len);
-	}
-	else if (e2->op == TOKarrayliteral)
-	{   ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
-	    cmp = !es2->elements || (0 == es2->elements->dim);
-	}
-	else
-	    return EXP_CANT_INTERPRET;
-    }
-    else if (e2->op == TOKnull)
-    {
-	if (e1->op == TOKstring)
-	{   StringExp *es1 = (StringExp *)e1;
-	    cmp = (0 == es1->len);
-	}
-	else if (e1->op == TOKarrayliteral)
-	{   ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1;
-	    cmp = !es1->elements || (0 == es1->elements->dim);
-	}
-	else
-	    return EXP_CANT_INTERPRET;
-    }
-    else if (e1->op == TOKstring && e2->op == TOKstring)
-    {	StringExp *es1 = (StringExp *)e1;
-	StringExp *es2 = (StringExp *)e2;
-
-	assert(es1->sz == es2->sz);
-	if (es1->len == es2->len &&
-	    memcmp(es1->string, es2->string, es1->sz * es1->len) == 0)
-	    cmp = 1;
-	else
-	    cmp = 0;
-    }
-    else if (e1->op == TOKarrayliteral && e2->op == TOKarrayliteral)
-    {   ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1;
-	ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
-
-	if ((!es1->elements || !es1->elements->dim) &&
-	    (!es2->elements || !es2->elements->dim))
-	    cmp = 1;		// both arrays are empty
-	else if (!es1->elements || !es2->elements)
-	    cmp = 0;
-	else if (es1->elements->dim != es2->elements->dim)
-	    cmp = 0;
-	else
-	{
-	    for (size_t i = 0; i < es1->elements->dim; i++)
-	    {   Expression *ee1 = (Expression *)es1->elements->data[i];
-		Expression *ee2 = (Expression *)es2->elements->data[i];
-
-		Expression *v = Equal(TOKequal, Type::tint32, ee1, ee2);
-		if (v == EXP_CANT_INTERPRET)
-		    return EXP_CANT_INTERPRET;
-		cmp = v->toInteger();
-		if (cmp == 0)
-		    break;
-	    }
-	}
-    }
-    else if (e1->op == TOKarrayliteral && e2->op == TOKstring)
-    {	// Swap operands and use common code
-	Expression *e = e1;
-	e1 = e2;
-	e2 = e;
-	goto Lsa;
-    }
-    else if (e1->op == TOKstring && e2->op == TOKarrayliteral)
-    {
-     Lsa:
-	StringExp *es1 = (StringExp *)e1;
-	ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
-	size_t dim1 = es1->len;
-	size_t dim2 = es2->elements ? es2->elements->dim : 0;
-	if (dim1 != dim2)
-	    cmp = 0;
-	else
-	{
-	    for (size_t i = 0; i < dim1; i++)
-	    {
-		uinteger_t c = es1->charAt(i);
-		Expression *ee2 = (Expression *)es2->elements->data[i];
-		if (ee2->isConst() != 1)
-		    return EXP_CANT_INTERPRET;
-		cmp = (c == ee2->toInteger());
-		if (cmp == 0)
-		    break;
-	    }
-	}
-    }
-    else if (e1->op == TOKstructliteral && e2->op == TOKstructliteral)
-    {   StructLiteralExp *es1 = (StructLiteralExp *)e1;
-	StructLiteralExp *es2 = (StructLiteralExp *)e2;
-
-	if (es1->sd != es2->sd)
-	    cmp = 0;
-	else if ((!es1->elements || !es1->elements->dim) &&
-	    (!es2->elements || !es2->elements->dim))
-	    cmp = 1;		// both arrays are empty
-	else if (!es1->elements || !es2->elements)
-	    cmp = 0;
-	else if (es1->elements->dim != es2->elements->dim)
-	    cmp = 0;
-	else
-	{
-	    cmp = 1;
-	    for (size_t i = 0; i < es1->elements->dim; i++)
-	    {   Expression *ee1 = (Expression *)es1->elements->data[i];
-		Expression *ee2 = (Expression *)es2->elements->data[i];
-
-		if (ee1 == ee2)
-		    continue;
-		if (!ee1 || !ee2)
-		{   cmp = 0;
-		    break;
-		}
-		Expression *v = Equal(TOKequal, Type::tint32, ee1, ee2);
-		if (v == EXP_CANT_INTERPRET)
-		    return EXP_CANT_INTERPRET;
-		cmp = v->toInteger();
-		if (cmp == 0)
-		    break;
-	    }
-	}
-    }
-#if 0 // Should handle this
-    else if (e1->op == TOKarrayliteral && e2->op == TOKstring)
-    {
-    }
-#endif
-    else if (e1->isConst() != 1 || e2->isConst() != 1)
-	return EXP_CANT_INTERPRET;
-    else if (e1->type->isreal())
-    {
-	r1 = e1->toReal();
-	r2 = e2->toReal();
-	goto L1;
-    }
-    else if (e1->type->isimaginary())
-    {
-	r1 = e1->toImaginary();
-	r2 = e2->toImaginary();
-     L1:
-#if __DMC__
-	cmp = (r1 == r2);
-#else
-	if (isnan(r1) || isnan(r2))	// if unordered
-	{
-	    cmp = 0;
-	}
-	else
-	{
-	    cmp = (r1 == r2);
-	}
-#endif
-    }
-    else if (e1->type->iscomplex())
-    {
-	cmp = e1->toComplex() == e2->toComplex();
-    }
-    else if (e1->type->isintegral())
-    {
-	cmp = (e1->toInteger() == e2->toInteger());
-    }
-    else
-	return EXP_CANT_INTERPRET;
-    if (op == TOKnotequal)
-	cmp ^= 1;
-    e = new IntegerExp(loc, cmp, type);
-    return e;
-}
-
-Expression *Identity(enum TOK op, Type *type, Expression *e1, Expression *e2)
-{   Expression *e;
-    Loc loc = e1->loc;
-    int cmp;
-
-    if (e1->op == TOKnull && e2->op == TOKnull)
-    {
-	cmp = 1;
-    }
-    else if (e1->op == TOKsymoff && e2->op == TOKsymoff)
-    {
-	SymOffExp *es1 = (SymOffExp *)e1;
-	SymOffExp *es2 = (SymOffExp *)e2;
-
-	cmp = (es1->var == es2->var && es1->offset == es2->offset);
-    }
-    else if (e1->isConst() == 1 && e2->isConst() == 1)
-	return Equal((op == TOKidentity) ? TOKequal : TOKnotequal,
-		type, e1, e2);
-    else
-	assert(0);
-    if (op == TOKnotidentity)
-	cmp ^= 1;
-    return new IntegerExp(loc, cmp, type);
-}
-
-
-Expression *Cmp(enum TOK op, Type *type, Expression *e1, Expression *e2)
-{   Expression *e;
-    Loc loc = e1->loc;
-    integer_t n;
-    real_t r1;
-    real_t r2;
-
-    if (e1->type->isreal())
-    {
-	r1 = e1->toReal();
-	r2 = e2->toReal();
-	goto L1;
-    }
-    else if (e1->type->isimaginary())
-    {
-	r1 = e1->toImaginary();
-	r2 = e2->toImaginary();
-     L1:
-#if __DMC__
-	// DMC is the only compiler I know of that handles NAN arguments
-	// correctly in comparisons.
-	switch (op)
-	{
-	    case TOKlt:	   n = r1 <  r2;	break;
-	    case TOKle:	   n = r1 <= r2;	break;
-	    case TOKgt:	   n = r1 >  r2;	break;
-	    case TOKge:	   n = r1 >= r2;	break;
-
-	    case TOKleg:   n = r1 <>=  r2;	break;
-	    case TOKlg:	   n = r1 <>   r2;	break;
-	    case TOKunord: n = r1 !<>= r2;	break;
-	    case TOKue:	   n = r1 !<>  r2;	break;
-	    case TOKug:	   n = r1 !<=  r2;	break;
-	    case TOKuge:   n = r1 !<   r2;	break;
-	    case TOKul:	   n = r1 !>=  r2;	break;
-	    case TOKule:   n = r1 !>   r2;	break;
-
-	    default:
-		assert(0);
-	}
-#else
-	// Don't rely on compiler, handle NAN arguments separately
-#if IN_GCC
-	if (real_isnan(&r1) || real_isnan(&r2))	// if unordered
-#else
-	if (isnan(r1) || isnan(r2))	// if unordered
-#endif
-	{
-	    switch (op)
-	    {
-		case TOKlt:	n = 0;	break;
-		case TOKle:	n = 0;	break;
-		case TOKgt:	n = 0;	break;
-		case TOKge:	n = 0;	break;
-
-		case TOKleg:	n = 0;	break;
-		case TOKlg:	n = 0;	break;
-		case TOKunord:	n = 1;	break;
-		case TOKue:	n = 1;	break;
-		case TOKug:	n = 1;	break;
-		case TOKuge:	n = 1;	break;
-		case TOKul:	n = 1;	break;
-		case TOKule:	n = 1;	break;
-
-		default:
-		    assert(0);
-	    }
-	}
-	else
-	{
-	    switch (op)
-	    {
-		case TOKlt:	n = r1 <  r2;	break;
-		case TOKle:	n = r1 <= r2;	break;
-		case TOKgt:	n = r1 >  r2;	break;
-		case TOKge:	n = r1 >= r2;	break;
-
-		case TOKleg:	n = 1;		break;
-		case TOKlg:	n = r1 != r2;	break;
-		case TOKunord:	n = 0;		break;
-		case TOKue:	n = r1 == r2;	break;
-		case TOKug:	n = r1 >  r2;	break;
-		case TOKuge:	n = r1 >= r2;	break;
-		case TOKul:	n = r1 <  r2;	break;
-		case TOKule:	n = r1 <= r2;	break;
-
-		default:
-		    assert(0);
-	    }
-	}
-#endif
-    }
-    else if (e1->type->iscomplex())
-    {
-	assert(0);
-    }
-    else
-    {   sinteger_t n1;
-	sinteger_t n2;
-
-	n1 = e1->toInteger();
-	n2 = e2->toInteger();
-	if (e1->type->isunsigned() || e2->type->isunsigned())
-	{
-	    switch (op)
-	    {
-		case TOKlt:	n = ((d_uns64) n1) <  ((d_uns64) n2);	break;
-		case TOKle:	n = ((d_uns64) n1) <= ((d_uns64) n2);	break;
-		case TOKgt:	n = ((d_uns64) n1) >  ((d_uns64) n2);	break;
-		case TOKge:	n = ((d_uns64) n1) >= ((d_uns64) n2);	break;
-
-		case TOKleg:	n = 1;					break;
-		case TOKlg:	n = ((d_uns64) n1) != ((d_uns64) n2);	break;
-		case TOKunord:	n = 0;					break;
-		case TOKue:	n = ((d_uns64) n1) == ((d_uns64) n2);	break;
-		case TOKug:	n = ((d_uns64) n1) >  ((d_uns64) n2);	break;
-		case TOKuge:	n = ((d_uns64) n1) >= ((d_uns64) n2);	break;
-		case TOKul:	n = ((d_uns64) n1) <  ((d_uns64) n2);	break;
-		case TOKule:	n = ((d_uns64) n1) <= ((d_uns64) n2);	break;
-
-		default:
-		    assert(0);
-	    }
-	}
-	else
-	{
-	    switch (op)
-	    {
-		case TOKlt:	n = n1 <  n2;	break;
-		case TOKle:	n = n1 <= n2;	break;
-		case TOKgt:	n = n1 >  n2;	break;
-		case TOKge:	n = n1 >= n2;	break;
-
-		case TOKleg:	n = 1;		break;
-		case TOKlg:	n = n1 != n2;	break;
-		case TOKunord:	n = 0;		break;
-		case TOKue:	n = n1 == n2;	break;
-		case TOKug:	n = n1 >  n2;	break;
-		case TOKuge:	n = n1 >= n2;	break;
-		case TOKul:	n = n1 <  n2;	break;
-		case TOKule:	n = n1 <= n2;	break;
-
-		default:
-		    assert(0);
-	    }
-	}
-    }
-    e = new IntegerExp(loc, n, type);
-    return e;
-}
-
-/* Also returns EXP_CANT_INTERPRET if cannot be computed.
- *  to:	type to cast to
- *  type: type to paint the result
- */
-
-Expression *Cast(Type *type, Type *to, Expression *e1)
-{   Expression *e = EXP_CANT_INTERPRET;
-    Loc loc = e1->loc;
-
-    //printf("Cast(type = %s, to = %s, e1 = %s)\n", type->toChars(), to->toChars(), e1->toChars());
-    //printf("e1->type = %s\n", e1->type->toChars());
-    if (type->equals(e1->type) && to->equals(type))
-	return e1;
-
-    if (e1->isConst() != 1)
-	return EXP_CANT_INTERPRET;
-
-    Type *tb = to->toBasetype();
-    if (tb->ty == Tbool)
-	e = new IntegerExp(loc, e1->toInteger() != 0, type);
-    else if (type->isintegral())
-    {
-	if (e1->type->isfloating())
-	{   integer_t result;
-	    real_t r = e1->toReal();
-
-	    switch (type->toBasetype()->ty)
-	    {
-		case Tint8:	result = (d_int8)r;	break;
-		case Tchar:
-		case Tuns8:	result = (d_uns8)r;	break;
-		case Tint16:	result = (d_int16)r;	break;
-		case Twchar:
-		case Tuns16:	result = (d_uns16)r;	break;
-		case Tint32:	result = (d_int32)r;	break;
-		case Tdchar:
-		case Tuns32:	result = (d_uns32)r;	break;
-		case Tint64:	result = (d_int64)r;	break;
-		case Tuns64:	result = (d_uns64)r;	break;
-		default:
-		    assert(0);
-	    }
-
-	    e = new IntegerExp(loc, result, type);
-	}
-	else if (type->isunsigned())
-	    e = new IntegerExp(loc, e1->toUInteger(), type);
-	else
-	    e = new IntegerExp(loc, e1->toInteger(), type);
-    }
-    else if (tb->isreal())
-    {   real_t value = e1->toReal();
-
-	e = new RealExp(loc, value, type);
-    }
-    else if (tb->isimaginary())
-    {   real_t value = e1->toImaginary();
-
-	e = new RealExp(loc, value, type);
-    }
-    else if (tb->iscomplex())
-    {   complex_t value = e1->toComplex();
-
-	e = new ComplexExp(loc, value, type);
-    }
-    else if (tb->isscalar())
-	e = new IntegerExp(loc, e1->toInteger(), type);
-    else if (tb->ty == Tvoid)
-	e = EXP_CANT_INTERPRET;
-    else if (tb->ty == Tstruct && e1->op == TOKint64)
-    {	// Struct = 0;
-	StructDeclaration *sd = tb->toDsymbol(NULL)->isStructDeclaration();
-	assert(sd);
-	Expressions *elements = new Expressions;
-	for (size_t i = 0; i < sd->fields.dim; i++)
-	{   Dsymbol *s = (Dsymbol *)sd->fields.data[i];
-	    VarDeclaration *v = s->isVarDeclaration();
-	    assert(v);
-
-	    Expression *exp = new IntegerExp(0);
-	    exp = Cast(v->type, v->type, exp);
-	    if (exp == EXP_CANT_INTERPRET)
-		return exp;
-	    elements->push(exp);
-	}
-	e = new StructLiteralExp(loc, sd, elements);
-	e->type = type;
-    }
-    else
-    {
-	error(loc, "cannot cast %s to %s", e1->type->toChars(), type->toChars());
-	e = new IntegerExp(loc, 0, type);
-    }
-    return e;
-}
-
-
-Expression *ArrayLength(Type *type, Expression *e1)
-{   Expression *e;
-    Loc loc = e1->loc;
-
-    if (e1->op == TOKstring)
-    {	StringExp *es1 = (StringExp *)e1;
-
-	e = new IntegerExp(loc, es1->len, type);
-    }
-    else if (e1->op == TOKarrayliteral)
-    {	ArrayLiteralExp *ale = (ArrayLiteralExp *)e1;
-	size_t dim;
-
-	dim = ale->elements ? ale->elements->dim : 0;
-	e = new IntegerExp(loc, dim, type);
-    }
-    else if (e1->op == TOKassocarrayliteral)
-    {	AssocArrayLiteralExp *ale = (AssocArrayLiteralExp *)e1;
-	size_t dim = ale->keys->dim;
-
-	e = new IntegerExp(loc, dim, type);
-    }
-    else
-	e = EXP_CANT_INTERPRET;
-    return e;
-}
-
-/* Also return EXP_CANT_INTERPRET if this fails
- */
-Expression *Index(Type *type, Expression *e1, Expression *e2)
-{   Expression *e = EXP_CANT_INTERPRET;
-    Loc loc = e1->loc;
-
-    //printf("Index(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
-    assert(e1->type);
-    if (e1->op == TOKstring && e2->op == TOKint64)
-    {	StringExp *es1 = (StringExp *)e1;
-	uinteger_t i = e2->toInteger();
-
-	if (i >= es1->len)
-        e1->error("string index %llu is out of bounds [0 .. %"PRIuSIZE"]", i, es1->len);
-	else
-	{   unsigned value = es1->charAt(i);
-	    e = new IntegerExp(loc, value, type);
-	}
-    }
-    else if (e1->type->toBasetype()->ty == Tsarray && e2->op == TOKint64)
-    {	TypeSArray *tsa = (TypeSArray *)e1->type->toBasetype();
-	uinteger_t length = tsa->dim->toInteger();
-	uinteger_t i = e2->toInteger();
-
-	if (i >= length)
-	{
-        e2->error("array index %llu is out of bounds %s[0 .. %llu]", i, e1->toChars(), length);
-	}
-	else if (e1->op == TOKarrayliteral && !e1->checkSideEffect(2))
-	{   ArrayLiteralExp *ale = (ArrayLiteralExp *)e1;
-	    e = (Expression *)ale->elements->data[i];
-	    e->type = type;
-	}
-    }
-    else if (e1->type->toBasetype()->ty == Tarray && e2->op == TOKint64)
-    {
-	uinteger_t i = e2->toInteger();
-
-	if (e1->op == TOKarrayliteral && !e1->checkSideEffect(2))
-	{   ArrayLiteralExp *ale = (ArrayLiteralExp *)e1;
-	    if (i >= ale->elements->dim)
-	    {
-            e2->error("array index %llu is out of bounds %s[0 .. %u]", i, e1->toChars(), ale->elements->dim);
-	    }
-	    else
-	    {	e = (Expression *)ale->elements->data[i];
-		e->type = type;
-	    }
-	}
-    }
-    else if (e1->op == TOKassocarrayliteral && !e1->checkSideEffect(2))
-    {
-	AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)e1;
-	/* Search the keys backwards, in case there are duplicate keys
-	 */
-	for (size_t i = ae->keys->dim; i;)
-	{
-	    i--;
-	    Expression *ekey = (Expression *)ae->keys->data[i];
-	    Expression *ex = Equal(TOKequal, Type::tbool, ekey, e2);
-	    if (ex == EXP_CANT_INTERPRET)
-		return ex;
-	    if (ex->isBool(TRUE))
-	    {	e = (Expression *)ae->values->data[i];
-		e->type = type;
-		break;
-	    }
-	}
-    }
-    return e;
-}
-
-/* Also return EXP_CANT_INTERPRET if this fails
- */
-Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr)
-{   Expression *e = EXP_CANT_INTERPRET;
-    Loc loc = e1->loc;
-
-#if LOG
-    printf("Slice()\n");
-    if (lwr)
-    {	printf("\te1 = %s\n", e1->toChars());
-	printf("\tlwr = %s\n", lwr->toChars());
-	printf("\tupr = %s\n", upr->toChars());
-    }
-#endif
-    if (e1->op == TOKstring && lwr->op == TOKint64 && upr->op == TOKint64)
-    {	StringExp *es1 = (StringExp *)e1;
-	uinteger_t ilwr = lwr->toInteger();
-	uinteger_t iupr = upr->toInteger();
-
-	if (iupr > es1->len || ilwr > iupr)
-        e1->error("string slice [%llu .. %llu] is out of bounds", ilwr, iupr);
-	else
-	{   integer_t value;
-	    void *s;
-	    size_t len = iupr - ilwr;
-	    int sz = es1->sz;
-	    StringExp *es;
-
-	    s = mem.malloc((len + 1) * sz);
-	    memcpy((unsigned char *)s, (unsigned char *)es1->string + ilwr * sz, len * sz);
-	    memset((unsigned char *)s + len * sz, 0, sz);
-
-	    es = new StringExp(loc, s, len, es1->postfix);
-	    es->sz = sz;
-	    es->committed = 1;
-	    es->type = type;
-	    e = es;
-	}
-    }
-    else if (e1->op == TOKarrayliteral &&
-	    lwr->op == TOKint64 && upr->op == TOKint64 &&
-	    !e1->checkSideEffect(2))
-    {	ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1;
-	uinteger_t ilwr = lwr->toInteger();
-	uinteger_t iupr = upr->toInteger();
-
-	if (iupr > es1->elements->dim || ilwr > iupr)
-        e1->error("array slice [%llu .. %llu] is out of bounds", ilwr, iupr);
-	else
-	{
-	    Expressions *elements = new Expressions();
-	    elements->setDim(iupr - ilwr);
-	    memcpy(elements->data,
-		   es1->elements->data + ilwr,
-		   (iupr - ilwr) * sizeof(es1->elements->data[0]));
-	    e = new ArrayLiteralExp(e1->loc, elements);
-	    e->type = type;
-	}
-    }
-    return e;
-}
-
-/* Also return EXP_CANT_INTERPRET if this fails
- */
-Expression *Cat(Type *type, Expression *e1, Expression *e2)
-{   Expression *e = EXP_CANT_INTERPRET;
-    Loc loc = e1->loc;
-    Type *t;
-
-    //printf("Cat(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
-
-    if (e1->op == TOKnull && (e2->op == TOKint64 || e2->op == TOKstructliteral))
-    {	e = e2;
-	goto L2;
-    }
-    else if ((e1->op == TOKint64 || e1->op == TOKstructliteral) && e2->op == TOKnull)
-    {	e = e1;
-     L2:
-	Type *tn = e->type->toBasetype();
-	if (tn->ty == Tchar || tn->ty == Twchar || tn->ty == Tdchar)
-	{
-	    // Create a StringExp
-	    void *s;
-	    StringExp *es;
-	    size_t len = 1;
-	    int sz = tn->size();
-	    integer_t v = e->toInteger();
-
-	    s = mem.malloc((len + 1) * sz);
-	    memcpy((unsigned char *)s, &v, sz);
-
-	    // Add terminating 0
-	    memset((unsigned char *)s + len * sz, 0, sz);
-
-	    es = new StringExp(loc, s, len);
-	    es->sz = sz;
-	    es->committed = 1;
-	    e = es;
-	}
-	else
-	{   // Create an ArrayLiteralExp
-	    Expressions *elements = new Expressions();
-	    elements->push(e);
-	    e = new ArrayLiteralExp(e->loc, elements);
-	}
-	e->type = type;
-	return e;
-    }
-    else if (e1->op == TOKstring && e2->op == TOKstring)
-    {
-	// Concatenate the strings
-	void *s;
-	StringExp *es1 = (StringExp *)e1;
-	StringExp *es2 = (StringExp *)e2;
-	StringExp *es;
-	Type *t;
-	size_t len = es1->len + es2->len;
-	int sz = es1->sz;
-
-	assert(sz == es2->sz);
-	s = mem.malloc((len + 1) * sz);
-	memcpy(s, es1->string, es1->len * sz);
-	memcpy((unsigned char *)s + es1->len * sz, es2->string, es2->len * sz);
-
-	// Add terminating 0
-	memset((unsigned char *)s + len * sz, 0, sz);
-
-	es = new StringExp(loc, s, len);
-	es->sz = sz;
-	es->committed = es1->committed | es2->committed;
-	if (es1->committed)
-	    t = es1->type;
-	else
-	    t = es2->type;
-	es->type = type;
-	e = es;
-    }
-    else if (e1->op == TOKstring && e2->op == TOKint64)
-    {
-	// Concatenate the strings
-	void *s;
-	StringExp *es1 = (StringExp *)e1;
-	StringExp *es;
-	Type *t;
-	size_t len = es1->len + 1;
-	int sz = es1->sz;
-	integer_t v = e2->toInteger();
-
-	s = mem.malloc((len + 1) * sz);
-	memcpy(s, es1->string, es1->len * sz);
-	memcpy((unsigned char *)s + es1->len * sz, &v, sz);
-
-	// Add terminating 0
-	memset((unsigned char *)s + len * sz, 0, sz);
-
-	es = new StringExp(loc, s, len);
-	es->sz = sz;
-	es->committed = es1->committed;
-	t = es1->type;
-	es->type = type;
-	e = es;
-    }
-    else if (e1->op == TOKint64 && e2->op == TOKstring)
-    {
-	// Concatenate the strings
-	void *s;
-	StringExp *es2 = (StringExp *)e2;
-	StringExp *es;
-	Type *t;
-	size_t len = 1 + es2->len;
-	int sz = es2->sz;
-	integer_t v = e1->toInteger();
-
-	s = mem.malloc((len + 1) * sz);
-	memcpy((unsigned char *)s, &v, sz);
-	memcpy((unsigned char *)s + sz, es2->string, es2->len * sz);
-
-	// Add terminating 0
-	memset((unsigned char *)s + len * sz, 0, sz);
-
-	es = new StringExp(loc, s, len);
-	es->sz = sz;
-	es->committed = es2->committed;
-	t = es2->type;
-	es->type = type;
-	e = es;
-    }
-    else if (e1->op == TOKarrayliteral && e2->op == TOKarrayliteral &&
-	e1->type->equals(e2->type))
-    {
-	// Concatenate the arrays
-	ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1;
-	ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
-
-	es1 = new ArrayLiteralExp(es1->loc, (Expressions *)es1->elements->copy());
-	es1->elements->insert(es1->elements->dim, es2->elements);
-	e = es1;
-
-	if (type->toBasetype()->ty == Tsarray)
-	{
-	    e->type = new TypeSArray(e1->type->toBasetype()->next, new IntegerExp(0, es1->elements->dim, Type::tindex));
-	    e->type = e->type->semantic(loc, NULL);
-	}
-	else
-	    e->type = type;
-    }
-    else if (e1->op == TOKarrayliteral &&
-	e1->type->toBasetype()->nextOf()->equals(e2->type))
-    {
-	ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1;
-
-	es1 = new ArrayLiteralExp(es1->loc, (Expressions *)es1->elements->copy());
-	es1->elements->push(e2);
-	e = es1;
-
-	if (type->toBasetype()->ty == Tsarray)
-	{
-	    e->type = new TypeSArray(e2->type, new IntegerExp(0, es1->elements->dim, Type::tindex));
-	    e->type = e->type->semantic(loc, NULL);
-	}
-	else
-	    e->type = type;
-    }
-    else if (e2->op == TOKarrayliteral &&
-	e2->type->toBasetype()->nextOf()->equals(e1->type))
-    {
-	ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
-
-	es2 = new ArrayLiteralExp(es2->loc, (Expressions *)es2->elements->copy());
-	es2->elements->shift(e1);
-	e = es2;
-
-	if (type->toBasetype()->ty == Tsarray)
-	{
-	    e->type = new TypeSArray(e1->type, new IntegerExp(0, es2->elements->dim, Type::tindex));
-	    e->type = e->type->semantic(loc, NULL);
-	}
-	else
-	    e->type = type;
-    }
-    else if (e1->op == TOKnull && e2->op == TOKstring)
-    {
-	t = e1->type;
-	e = e2;
-	goto L1;
-    }
-    else if (e1->op == TOKstring && e2->op == TOKnull)
-    {	e = e1;
-	t = e2->type;
-      L1:
-	Type *tb = t->toBasetype();
-	if (tb->ty == Tarray && tb->nextOf()->equals(e->type))
-	{   Expressions *expressions = new Expressions();
-	    expressions->push(e);
-	    e = new ArrayLiteralExp(loc, expressions);
-	    e->type = t;
-	}
-	if (!e->type->equals(type))
-	{   StringExp *se = (StringExp *)e->copy();
-	    e = se->castTo(NULL, type);
-	}
-    }
-    return e;
-}
-
-Expression *Ptr(Type *type, Expression *e1)
-{
-    //printf("Ptr(e1 = %s)\n", e1->toChars());
-    if (e1->op == TOKadd)
-    {	AddExp *ae = (AddExp *)e1;
-	if (ae->e1->op == TOKaddress && ae->e2->op == TOKint64)
-	{   AddrExp *ade = (AddrExp *)ae->e1;
-	    if (ade->e1->op == TOKstructliteral)
-	    {	StructLiteralExp *se = (StructLiteralExp *)ade->e1;
-		unsigned offset = ae->e2->toInteger();
-		Expression *e = se->getField(type, offset);
-		if (!e)
-		    e = EXP_CANT_INTERPRET;
-		return e;
-	    }
-	}
-    }
-    return EXP_CANT_INTERPRET;
-}
-
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2007 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+// License for redistribution is by either the Artistic License
+// in artistic.txt, or the GNU General Public License in gnu.txt.
+// See the included readme.txt for details.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <math.h>
+
+#if __DMC__
+#include <complex.h>
+#endif
+
+#include "mem.h"
+#include "root.h"
+
+#include "mtype.h"
+#include "expression.h"
+#include "aggregate.h"
+#include "declaration.h"
+
+#ifdef IN_GCC
+#include "d-gcc-real.h"
+
+/* %% fix? */
+extern "C" bool real_isnan (const real_t *);
+#endif
+
+static real_t zero;	// work around DMC bug for now
+
+#define LOG 0
+
+Expression *expType(Type *type, Expression *e)
+{
+    if (type != e->type)
+    {
+	e = e->copy();
+	e->type = type;
+    }
+    return e;
+}
+
+/* ================================== isConst() ============================== */
+
+int Expression::isConst()
+{
+    //printf("Expression::isConst(): %s\n", toChars());
+    return 0;
+}
+
+int IntegerExp::isConst()
+{
+    return 1;
+}
+
+int RealExp::isConst()
+{
+    return 1;
+}
+
+int ComplexExp::isConst()
+{
+    return 1;
+}
+
+int SymOffExp::isConst()
+{
+    return 2;
+}
+
+/* =============================== constFold() ============================== */
+
+/* The constFold() functions were redundant with the optimize() ones,
+ * and so have been folded in with them.
+ */
+
+/* ========================================================================== */
+
+Expression *Neg(Type *type, Expression *e1)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    if (e1->type->isreal())
+    {
+	e = new RealExp(loc, -e1->toReal(), type);
+    }
+    else if (e1->type->isimaginary())
+    {
+	e = new RealExp(loc, -e1->toImaginary(), type);
+    }
+    else if (e1->type->iscomplex())
+    {
+	e = new ComplexExp(loc, -e1->toComplex(), type);
+    }
+    else
+	e = new IntegerExp(loc, -e1->toInteger(), type);
+    return e;
+}
+
+Expression *Com(Type *type, Expression *e1)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    e = new IntegerExp(loc, ~e1->toInteger(), type);
+    return e;
+}
+
+Expression *Not(Type *type, Expression *e1)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    e = new IntegerExp(loc, e1->isBool(0), type);
+    return e;
+}
+
+Expression *Bool(Type *type, Expression *e1)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    e = new IntegerExp(loc, e1->isBool(1), type);
+    return e;
+}
+
+Expression *Add(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+#if LOG
+    printf("Add(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
+#endif
+    if (type->isreal())
+    {
+	e = new RealExp(loc, e1->toReal() + e2->toReal(), type);
+    }
+    else if (type->isimaginary())
+    {
+	e = new RealExp(loc, e1->toImaginary() + e2->toImaginary(), type);
+    }
+    else if (type->iscomplex())
+    {
+	// This rigamarole is necessary so that -0.0 doesn't get
+	// converted to +0.0 by doing an extraneous add with +0.0
+	complex_t c1;
+	real_t r1;
+	real_t i1;
+
+	complex_t c2;
+	real_t r2;
+	real_t i2;
+
+	complex_t v;
+	int x;
+
+	if (e1->type->isreal())
+	{   r1 = e1->toReal();
+	    x = 0;
+	}
+	else if (e1->type->isimaginary())
+	{   i1 = e1->toImaginary();
+	    x = 3;
+	}
+	else
+	{   c1 = e1->toComplex();
+	    x = 6;
+	}
+
+	if (e2->type->isreal())
+	{   r2 = e2->toReal();
+	}
+	else if (e2->type->isimaginary())
+	{   i2 = e2->toImaginary();
+	    x += 1;
+	}
+	else
+	{   c2 = e2->toComplex();
+	    x += 2;
+	}
+
+	switch (x)
+	{
+#if __DMC__
+	    case 0+0:	v = (complex_t) (r1 + r2);	break;
+	    case 0+1:	v = r1 + i2 * I;		break;
+	    case 0+2:	v = r1 + c2;			break;
+	    case 3+0:	v = i1 * I + r2;		break;
+	    case 3+1:	v = (complex_t) ((i1 + i2) * I); break;
+	    case 3+2:	v = i1 * I + c2;		break;
+	    case 6+0:	v = c1 + r2;			break;
+	    case 6+1:	v = c1 + i2 * I;		break;
+	    case 6+2:	v = c1 + c2;			break;
+#else
+	    case 0+0:	v = complex_t(r1 + r2, 0);	break;
+	    case 0+1:	v = complex_t(r1, i2);		break;
+	    case 0+2:	v = complex_t(r1 + creall(c2), cimagl(c2));	break;
+	    case 3+0:	v = complex_t(r2, i1);		break;
+	    case 3+1:	v = complex_t(0, i1 + i2);	break;
+	    case 3+2:	v = complex_t(creall(c2), i1 + cimagl(c2));	break;
+	    case 6+0:	v = complex_t(creall(c1) + r2, cimagl(c2));	break;
+	    case 6+1:	v = complex_t(creall(c1), cimagl(c1) + i2);	break;
+	    case 6+2:	v = c1 + c2;			break;
+#endif
+	    default: assert(0);
+	}
+	e = new ComplexExp(loc, v, type);
+    }
+    else if (e1->op == TOKsymoff)
+    {
+	SymOffExp *soe = (SymOffExp *)e1;
+	e = new SymOffExp(loc, soe->var, soe->offset + e2->toInteger());
+	e->type = type;
+    }
+    else if (e2->op == TOKsymoff)
+    {
+	SymOffExp *soe = (SymOffExp *)e2;
+	e = new SymOffExp(loc, soe->var, soe->offset + e1->toInteger());
+	e->type = type;
+    }
+    else
+	e = new IntegerExp(loc, e1->toInteger() + e2->toInteger(), type);
+    return e;
+}
+
+
+Expression *Min(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    if (type->isreal())
+    {
+	e = new RealExp(loc, e1->toReal() - e2->toReal(), type);
+    }
+    else if (type->isimaginary())
+    {
+	e = new RealExp(loc, e1->toImaginary() - e2->toImaginary(), type);
+    }
+    else if (type->iscomplex())
+    {
+	// This rigamarole is necessary so that -0.0 doesn't get
+	// converted to +0.0 by doing an extraneous add with +0.0
+	complex_t c1;
+	real_t r1;
+	real_t i1;
+
+	complex_t c2;
+	real_t r2;
+	real_t i2;
+
+	complex_t v;
+	int x;
+
+	if (e1->type->isreal())
+	{   r1 = e1->toReal();
+	    x = 0;
+	}
+	else if (e1->type->isimaginary())
+	{   i1 = e1->toImaginary();
+	    x = 3;
+	}
+	else
+	{   c1 = e1->toComplex();
+	    x = 6;
+	}
+
+	if (e2->type->isreal())
+	{   r2 = e2->toReal();
+	}
+	else if (e2->type->isimaginary())
+	{   i2 = e2->toImaginary();
+	    x += 1;
+	}
+	else
+	{   c2 = e2->toComplex();
+	    x += 2;
+	}
+
+	switch (x)
+	{
+#if __DMC__
+	    case 0+0:	v = (complex_t) (r1 - r2);	break;
+	    case 0+1:	v = r1 - i2 * I;		break;
+	    case 0+2:	v = r1 - c2;			break;
+	    case 3+0:	v = i1 * I - r2;		break;
+	    case 3+1:	v = (complex_t) ((i1 - i2) * I); break;
+	    case 3+2:	v = i1 * I - c2;		break;
+	    case 6+0:	v = c1 - r2;			break;
+	    case 6+1:	v = c1 - i2 * I;		break;
+	    case 6+2:	v = c1 - c2;			break;
+#else
+	    case 0+0:	v = complex_t(r1 - r2, 0);	break;
+	    case 0+1:	v = complex_t(r1, -i2);		break;
+	    case 0+2:	v = complex_t(r1 - creall(c2), -cimagl(c2));	break;
+	    case 3+0:	v = complex_t(-r2, i1);		break;
+	    case 3+1:	v = complex_t(0, i1 - i2);	break;
+	    case 3+2:	v = complex_t(-creall(c2), i1 - cimagl(c2));	break;
+	    case 6+0:	v = complex_t(creall(c1) - r2, cimagl(c1));	break;
+	    case 6+1:	v = complex_t(creall(c1), cimagl(c1) - i2);	break;
+	    case 6+2:	v = c1 - c2;			break;
+#endif
+	    default: assert(0);
+	}
+	e = new ComplexExp(loc, v, type);
+    }
+    else if (e1->op == TOKsymoff)
+    {
+	SymOffExp *soe = (SymOffExp *)e1;
+	e = new SymOffExp(loc, soe->var, soe->offset - e2->toInteger());
+	e->type = type;
+    }
+    else
+    {
+	e = new IntegerExp(loc, e1->toInteger() - e2->toInteger(), type);
+    }
+    return e;
+}
+
+Expression *Mul(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    if (type->isfloating())
+    {   complex_t c;
+#ifdef IN_GCC
+	real_t r;
+#else
+	d_float80 r;
+#endif
+
+	if (e1->type->isreal())
+	{
+#if __DMC__
+	    c = e1->toReal() * e2->toComplex();
+#else
+	    r = e1->toReal();
+	    c = e2->toComplex();
+	    c = complex_t(r * creall(c), r * cimagl(c));
+#endif
+	}
+	else if (e1->type->isimaginary())
+	{
+#if __DMC__
+	    c = e1->toImaginary() * I * e2->toComplex();
+#else
+	    r = e1->toImaginary();
+	    c = e2->toComplex();
+	    c = complex_t(-r * cimagl(c), r * creall(c));
+#endif
+	}
+	else if (e2->type->isreal())
+	{
+#if __DMC__
+	    c = e2->toReal() * e1->toComplex();
+#else
+	    r = e2->toReal();
+	    c = e1->toComplex();
+	    c = complex_t(r * creall(c), r * cimagl(c));
+#endif
+	}
+	else if (e2->type->isimaginary())
+	{
+#if __DMC__
+	    c = e1->toComplex() * e2->toImaginary() * I;
+#else
+	    r = e2->toImaginary();
+	    c = e1->toComplex();
+	    c = complex_t(-r * cimagl(c), r * creall(c));
+#endif
+	}
+	else
+	    c = e1->toComplex() * e2->toComplex();
+
+	if (type->isreal())
+	    e = new RealExp(loc, creall(c), type);
+	else if (type->isimaginary())
+	    e = new RealExp(loc, cimagl(c), type);
+	else if (type->iscomplex())
+	    e = new ComplexExp(loc, c, type);
+	else
+	    assert(0);
+    }
+    else
+    {
+	e = new IntegerExp(loc, e1->toInteger() * e2->toInteger(), type);
+    }
+    return e;
+}
+
+Expression *Div(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    if (type->isfloating())
+    {   complex_t c;
+#ifdef IN_GCC
+	real_t r;
+#else
+	d_float80 r;
+#endif
+
+	//e1->type->print();
+	//e2->type->print();
+	if (e2->type->isreal())
+	{
+	    if (e1->type->isreal())
+	    {
+		e = new RealExp(loc, e1->toReal() / e2->toReal(), type);
+		return e;
+	    }
+#if __DMC__
+	    //r = e2->toReal();
+	    //c = e1->toComplex();
+	    //printf("(%Lg + %Lgi) / %Lg\n", creall(c), cimagl(c), r);
+
+	    c = e1->toComplex() / e2->toReal();
+#else
+	    r = e2->toReal();
+	    c = e1->toComplex();
+	    c = complex_t(creall(c) / r, cimagl(c) / r);
+#endif
+	}
+	else if (e2->type->isimaginary())
+	{
+#if __DMC__
+	    //r = e2->toImaginary();
+	    //c = e1->toComplex();
+	    //printf("(%Lg + %Lgi) / %Lgi\n", creall(c), cimagl(c), r);
+
+	    c = e1->toComplex() / (e2->toImaginary() * I);
+#else
+	    r = e2->toImaginary();
+	    c = e1->toComplex();
+	    c = complex_t(cimagl(c) / r, -creall(c) / r);
+#endif
+	}
+	else
+	{
+	    c = e1->toComplex() / e2->toComplex();
+	}
+
+	if (type->isreal())
+	    e = new RealExp(loc, creall(c), type);
+	else if (type->isimaginary())
+	    e = new RealExp(loc, cimagl(c), type);
+	else if (type->iscomplex())
+	    e = new ComplexExp(loc, c, type);
+	else
+	    assert(0);
+    }
+    else
+    {   sinteger_t n1;
+	sinteger_t n2;
+	sinteger_t n;
+
+	n1 = e1->toInteger();
+	n2 = e2->toInteger();
+	if (n2 == 0)
+	{   e2->error("divide by 0");
+	    e2 = new IntegerExp(0, 1, e2->type);
+	    n2 = 1;
+	}
+	if (e1->type->isunsigned() || e2->type->isunsigned())
+	    n = ((d_uns64) n1) / ((d_uns64) n2);
+	else
+	    n = n1 / n2;
+	e = new IntegerExp(loc, n, type);
+    }
+    return e;
+}
+
+Expression *Mod(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    if (type->isfloating())
+    {
+	complex_t c;
+
+	if (e2->type->isreal())
+	{   real_t r2 = e2->toReal();
+
+#ifdef __DMC__
+	    c = fmodl(e1->toReal(), r2) + fmodl(e1->toImaginary(), r2) * I;
+#elif defined(IN_GCC)
+	    c = complex_t(e1->toReal() % r2, e1->toImaginary() % r2);
+#else
+	    c = complex_t(fmodl(e1->toReal(), r2), fmodl(e1->toImaginary(), r2));
+#endif
+	}
+	else if (e2->type->isimaginary())
+	{   real_t i2 = e2->toImaginary();
+
+#ifdef __DMC__
+	    c = fmodl(e1->toReal(), i2) + fmodl(e1->toImaginary(), i2) * I;
+#elif defined(IN_GCC)
+	    c = complex_t(e1->toReal() % i2, e1->toImaginary() % i2);
+#else
+	    c = complex_t(fmodl(e1->toReal(), i2), fmodl(e1->toImaginary(), i2));
+#endif
+	}
+	else
+	    assert(0);
+
+	if (type->isreal())
+	    e = new RealExp(loc, creall(c), type);
+	else if (type->isimaginary())
+	    e = new RealExp(loc, cimagl(c), type);
+	else if (type->iscomplex())
+	    e = new ComplexExp(loc, c, type);
+	else
+	    assert(0);
+    }
+    else
+    {   sinteger_t n1;
+	sinteger_t n2;
+	sinteger_t n;
+
+	n1 = e1->toInteger();
+	n2 = e2->toInteger();
+	if (n2 == 0)
+	{   e2->error("divide by 0");
+	    e2 = new IntegerExp(0, 1, e2->type);
+	    n2 = 1;
+	}
+	if (e1->type->isunsigned() || e2->type->isunsigned())
+	    n = ((d_uns64) n1) % ((d_uns64) n2);
+	else
+	    n = n1 % n2;
+	e = new IntegerExp(loc, n, type);
+    }
+    return e;
+}
+
+Expression *Shl(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    e = new IntegerExp(loc, e1->toInteger() << e2->toInteger(), type);
+    return e;
+}
+
+Expression *Shr(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+    unsigned count;
+    integer_t value;
+
+    value = e1->toInteger();
+    count = e2->toInteger();
+    switch (e1->type->toBasetype()->ty)
+    {
+	case Tint8:
+		value = (d_int8)(value) >> count;
+		break;
+
+	case Tuns8:
+		value = (d_uns8)(value) >> count;
+		break;
+
+	case Tint16:
+		value = (d_int16)(value) >> count;
+		break;
+
+	case Tuns16:
+		value = (d_uns16)(value) >> count;
+		break;
+
+	case Tint32:
+		value = (d_int32)(value) >> count;
+		break;
+
+	case Tuns32:
+		value = (d_uns32)(value) >> count;
+		break;
+
+	case Tint64:
+		value = (d_int64)(value) >> count;
+		break;
+
+	case Tuns64:
+		value = (d_uns64)(value) >> count;
+		break;
+
+	default:
+		assert(0);
+    }
+    e = new IntegerExp(loc, value, type);
+    return e;
+}
+
+Expression *Ushr(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+    unsigned count;
+    integer_t value;
+
+    value = e1->toInteger();
+    count = e2->toInteger();
+    switch (e1->type->toBasetype()->ty)
+    {
+	case Tint8:
+	case Tuns8:
+		assert(0);		// no way to trigger this
+		value = (value & 0xFF) >> count;
+		break;
+
+	case Tint16:
+	case Tuns16:
+		assert(0);		// no way to trigger this
+		value = (value & 0xFFFF) >> count;
+		break;
+
+	case Tint32:
+	case Tuns32:
+		value = (value & 0xFFFFFFFF) >> count;
+		break;
+
+	case Tint64:
+	case Tuns64:
+		value = (d_uns64)(value) >> count;
+		break;
+
+	default:
+		assert(0);
+    }
+    e = new IntegerExp(loc, value, type);
+    return e;
+}
+
+Expression *And(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    e = new IntegerExp(loc, e1->toInteger() & e2->toInteger(), type);
+    return e;
+}
+
+Expression *Or(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    e = new IntegerExp(loc, e1->toInteger() | e2->toInteger(), type);
+    return e;
+}
+
+Expression *Xor(Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    e = new IntegerExp(loc, e1->toInteger() ^ e2->toInteger(), type);
+    return e;
+}
+
+/* Also returns EXP_CANT_INTERPRET if cannot be computed.
+ */
+Expression *Equal(enum TOK op, Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+    int cmp;
+    real_t r1;
+    real_t r2;
+
+    //printf("Equal(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
+
+    assert(op == TOKequal || op == TOKnotequal);
+
+    if (e1->op == TOKnull)
+    {
+	if (e2->op == TOKnull)
+	    cmp = 1;
+	else if (e2->op == TOKstring)
+	{   StringExp *es2 = (StringExp *)e2;
+	    cmp = (0 == es2->len);
+	}
+	else if (e2->op == TOKarrayliteral)
+	{   ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
+	    cmp = !es2->elements || (0 == es2->elements->dim);
+	}
+	else
+	    return EXP_CANT_INTERPRET;
+    }
+    else if (e2->op == TOKnull)
+    {
+	if (e1->op == TOKstring)
+	{   StringExp *es1 = (StringExp *)e1;
+	    cmp = (0 == es1->len);
+	}
+	else if (e1->op == TOKarrayliteral)
+	{   ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1;
+	    cmp = !es1->elements || (0 == es1->elements->dim);
+	}
+	else
+	    return EXP_CANT_INTERPRET;
+    }
+    else if (e1->op == TOKstring && e2->op == TOKstring)
+    {	StringExp *es1 = (StringExp *)e1;
+	StringExp *es2 = (StringExp *)e2;
+
+	assert(es1->sz == es2->sz);
+	if (es1->len == es2->len &&
+	    memcmp(es1->string, es2->string, es1->sz * es1->len) == 0)
+	    cmp = 1;
+	else
+	    cmp = 0;
+    }
+    else if (e1->op == TOKarrayliteral && e2->op == TOKarrayliteral)
+    {   ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1;
+	ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
+
+	if ((!es1->elements || !es1->elements->dim) &&
+	    (!es2->elements || !es2->elements->dim))
+	    cmp = 1;		// both arrays are empty
+	else if (!es1->elements || !es2->elements)
+	    cmp = 0;
+	else if (es1->elements->dim != es2->elements->dim)
+	    cmp = 0;
+	else
+	{
+	    for (size_t i = 0; i < es1->elements->dim; i++)
+	    {   Expression *ee1 = (Expression *)es1->elements->data[i];
+		Expression *ee2 = (Expression *)es2->elements->data[i];
+
+		Expression *v = Equal(TOKequal, Type::tint32, ee1, ee2);
+		if (v == EXP_CANT_INTERPRET)
+		    return EXP_CANT_INTERPRET;
+		cmp = v->toInteger();
+		if (cmp == 0)
+		    break;
+	    }
+	}
+    }
+    else if (e1->op == TOKarrayliteral && e2->op == TOKstring)
+    {	// Swap operands and use common code
+	Expression *e = e1;
+	e1 = e2;
+	e2 = e;
+	goto Lsa;
+    }
+    else if (e1->op == TOKstring && e2->op == TOKarrayliteral)
+    {
+     Lsa:
+	StringExp *es1 = (StringExp *)e1;
+	ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
+	size_t dim1 = es1->len;
+	size_t dim2 = es2->elements ? es2->elements->dim : 0;
+	if (dim1 != dim2)
+	    cmp = 0;
+	else
+	{
+	    for (size_t i = 0; i < dim1; i++)
+	    {
+		uinteger_t c = es1->charAt(i);
+		Expression *ee2 = (Expression *)es2->elements->data[i];
+		if (ee2->isConst() != 1)
+		    return EXP_CANT_INTERPRET;
+		cmp = (c == ee2->toInteger());
+		if (cmp == 0)
+		    break;
+	    }
+	}
+    }
+    else if (e1->op == TOKstructliteral && e2->op == TOKstructliteral)
+    {   StructLiteralExp *es1 = (StructLiteralExp *)e1;
+	StructLiteralExp *es2 = (StructLiteralExp *)e2;
+
+	if (es1->sd != es2->sd)
+	    cmp = 0;
+	else if ((!es1->elements || !es1->elements->dim) &&
+	    (!es2->elements || !es2->elements->dim))
+	    cmp = 1;		// both arrays are empty
+	else if (!es1->elements || !es2->elements)
+	    cmp = 0;
+	else if (es1->elements->dim != es2->elements->dim)
+	    cmp = 0;
+	else
+	{
+	    cmp = 1;
+	    for (size_t i = 0; i < es1->elements->dim; i++)
+	    {   Expression *ee1 = (Expression *)es1->elements->data[i];
+		Expression *ee2 = (Expression *)es2->elements->data[i];
+
+		if (ee1 == ee2)
+		    continue;
+		if (!ee1 || !ee2)
+		{   cmp = 0;
+		    break;
+		}
+		Expression *v = Equal(TOKequal, Type::tint32, ee1, ee2);
+		if (v == EXP_CANT_INTERPRET)
+		    return EXP_CANT_INTERPRET;
+		cmp = v->toInteger();
+		if (cmp == 0)
+		    break;
+	    }
+	}
+    }
+#if 0 // Should handle this
+    else if (e1->op == TOKarrayliteral && e2->op == TOKstring)
+    {
+    }
+#endif
+    else if (e1->isConst() != 1 || e2->isConst() != 1)
+	return EXP_CANT_INTERPRET;
+    else if (e1->type->isreal())
+    {
+	r1 = e1->toReal();
+	r2 = e2->toReal();
+	goto L1;
+    }
+    else if (e1->type->isimaginary())
+    {
+	r1 = e1->toImaginary();
+	r2 = e2->toImaginary();
+     L1:
+#if __DMC__
+	cmp = (r1 == r2);
+#else
+	if (isnan(r1) || isnan(r2))	// if unordered
+	{
+	    cmp = 0;
+	}
+	else
+	{
+	    cmp = (r1 == r2);
+	}
+#endif
+    }
+    else if (e1->type->iscomplex())
+    {
+	cmp = e1->toComplex() == e2->toComplex();
+    }
+    else if (e1->type->isintegral())
+    {
+	cmp = (e1->toInteger() == e2->toInteger());
+    }
+    else
+	return EXP_CANT_INTERPRET;
+    if (op == TOKnotequal)
+	cmp ^= 1;
+    e = new IntegerExp(loc, cmp, type);
+    return e;
+}
+
+Expression *Identity(enum TOK op, Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+    int cmp;
+
+    if (e1->op == TOKnull && e2->op == TOKnull)
+    {
+	cmp = 1;
+    }
+    else if (e1->op == TOKsymoff && e2->op == TOKsymoff)
+    {
+	SymOffExp *es1 = (SymOffExp *)e1;
+	SymOffExp *es2 = (SymOffExp *)e2;
+
+	cmp = (es1->var == es2->var && es1->offset == es2->offset);
+    }
+    else if (e1->isConst() == 1 && e2->isConst() == 1)
+	return Equal((op == TOKidentity) ? TOKequal : TOKnotequal,
+		type, e1, e2);
+    else
+	assert(0);
+    if (op == TOKnotidentity)
+	cmp ^= 1;
+    return new IntegerExp(loc, cmp, type);
+}
+
+
+Expression *Cmp(enum TOK op, Type *type, Expression *e1, Expression *e2)
+{   Expression *e;
+    Loc loc = e1->loc;
+    integer_t n;
+    real_t r1;
+    real_t r2;
+
+    if (e1->type->isreal())
+    {
+	r1 = e1->toReal();
+	r2 = e2->toReal();
+	goto L1;
+    }
+    else if (e1->type->isimaginary())
+    {
+	r1 = e1->toImaginary();
+	r2 = e2->toImaginary();
+     L1:
+#if __DMC__
+	// DMC is the only compiler I know of that handles NAN arguments
+	// correctly in comparisons.
+	switch (op)
+	{
+	    case TOKlt:	   n = r1 <  r2;	break;
+	    case TOKle:	   n = r1 <= r2;	break;
+	    case TOKgt:	   n = r1 >  r2;	break;
+	    case TOKge:	   n = r1 >= r2;	break;
+
+	    case TOKleg:   n = r1 <>=  r2;	break;
+	    case TOKlg:	   n = r1 <>   r2;	break;
+	    case TOKunord: n = r1 !<>= r2;	break;
+	    case TOKue:	   n = r1 !<>  r2;	break;
+	    case TOKug:	   n = r1 !<=  r2;	break;
+	    case TOKuge:   n = r1 !<   r2;	break;
+	    case TOKul:	   n = r1 !>=  r2;	break;
+	    case TOKule:   n = r1 !>   r2;	break;
+
+	    default:
+		assert(0);
+	}
+#else
+	// Don't rely on compiler, handle NAN arguments separately
+#if IN_GCC
+	if (real_isnan(&r1) || real_isnan(&r2))	// if unordered
+#else
+	if (isnan(r1) || isnan(r2))	// if unordered
+#endif
+	{
+	    switch (op)
+	    {
+		case TOKlt:	n = 0;	break;
+		case TOKle:	n = 0;	break;
+		case TOKgt:	n = 0;	break;
+		case TOKge:	n = 0;	break;
+
+		case TOKleg:	n = 0;	break;
+		case TOKlg:	n = 0;	break;
+		case TOKunord:	n = 1;	break;
+		case TOKue:	n = 1;	break;
+		case TOKug:	n = 1;	break;
+		case TOKuge:	n = 1;	break;
+		case TOKul:	n = 1;	break;
+		case TOKule:	n = 1;	break;
+
+		default:
+		    assert(0);
+	    }
+	}
+	else
+	{
+	    switch (op)
+	    {
+		case TOKlt:	n = r1 <  r2;	break;
+		case TOKle:	n = r1 <= r2;	break;
+		case TOKgt:	n = r1 >  r2;	break;
+		case TOKge:	n = r1 >= r2;	break;
+
+		case TOKleg:	n = 1;		break;
+		case TOKlg:	n = r1 != r2;	break;
+		case TOKunord:	n = 0;		break;
+		case TOKue:	n = r1 == r2;	break;
+		case TOKug:	n = r1 >  r2;	break;
+		case TOKuge:	n = r1 >= r2;	break;
+		case TOKul:	n = r1 <  r2;	break;
+		case TOKule:	n = r1 <= r2;	break;
+
+		default:
+		    assert(0);
+	    }
+	}
+#endif
+    }
+    else if (e1->type->iscomplex())
+    {
+	assert(0);
+    }
+    else
+    {   sinteger_t n1;
+	sinteger_t n2;
+
+	n1 = e1->toInteger();
+	n2 = e2->toInteger();
+	if (e1->type->isunsigned() || e2->type->isunsigned())
+	{
+	    switch (op)
+	    {
+		case TOKlt:	n = ((d_uns64) n1) <  ((d_uns64) n2);	break;
+		case TOKle:	n = ((d_uns64) n1) <= ((d_uns64) n2);	break;
+		case TOKgt:	n = ((d_uns64) n1) >  ((d_uns64) n2);	break;
+		case TOKge:	n = ((d_uns64) n1) >= ((d_uns64) n2);	break;
+
+		case TOKleg:	n = 1;					break;
+		case TOKlg:	n = ((d_uns64) n1) != ((d_uns64) n2);	break;
+		case TOKunord:	n = 0;					break;
+		case TOKue:	n = ((d_uns64) n1) == ((d_uns64) n2);	break;
+		case TOKug:	n = ((d_uns64) n1) >  ((d_uns64) n2);	break;
+		case TOKuge:	n = ((d_uns64) n1) >= ((d_uns64) n2);	break;
+		case TOKul:	n = ((d_uns64) n1) <  ((d_uns64) n2);	break;
+		case TOKule:	n = ((d_uns64) n1) <= ((d_uns64) n2);	break;
+
+		default:
+		    assert(0);
+	    }
+	}
+	else
+	{
+	    switch (op)
+	    {
+		case TOKlt:	n = n1 <  n2;	break;
+		case TOKle:	n = n1 <= n2;	break;
+		case TOKgt:	n = n1 >  n2;	break;
+		case TOKge:	n = n1 >= n2;	break;
+
+		case TOKleg:	n = 1;		break;
+		case TOKlg:	n = n1 != n2;	break;
+		case TOKunord:	n = 0;		break;
+		case TOKue:	n = n1 == n2;	break;
+		case TOKug:	n = n1 >  n2;	break;
+		case TOKuge:	n = n1 >= n2;	break;
+		case TOKul:	n = n1 <  n2;	break;
+		case TOKule:	n = n1 <= n2;	break;
+
+		default:
+		    assert(0);
+	    }
+	}
+    }
+    e = new IntegerExp(loc, n, type);
+    return e;
+}
+
+/* Also returns EXP_CANT_INTERPRET if cannot be computed.
+ *  to:	type to cast to
+ *  type: type to paint the result
+ */
+
+Expression *Cast(Type *type, Type *to, Expression *e1)
+{   Expression *e = EXP_CANT_INTERPRET;
+    Loc loc = e1->loc;
+
+    //printf("Cast(type = %s, to = %s, e1 = %s)\n", type->toChars(), to->toChars(), e1->toChars());
+    //printf("e1->type = %s\n", e1->type->toChars());
+    if (type->equals(e1->type) && to->equals(type))
+	return e1;
+
+    if (e1->isConst() != 1)
+	return EXP_CANT_INTERPRET;
+
+    Type *tb = to->toBasetype();
+    if (tb->ty == Tbool)
+	e = new IntegerExp(loc, e1->toInteger() != 0, type);
+    else if (type->isintegral())
+    {
+	if (e1->type->isfloating())
+	{   integer_t result;
+	    real_t r = e1->toReal();
+
+	    switch (type->toBasetype()->ty)
+	    {
+		case Tint8:	result = (d_int8)r;	break;
+		case Tchar:
+		case Tuns8:	result = (d_uns8)r;	break;
+		case Tint16:	result = (d_int16)r;	break;
+		case Twchar:
+		case Tuns16:	result = (d_uns16)r;	break;
+		case Tint32:	result = (d_int32)r;	break;
+		case Tdchar:
+		case Tuns32:	result = (d_uns32)r;	break;
+		case Tint64:	result = (d_int64)r;	break;
+		case Tuns64:	result = (d_uns64)r;	break;
+		default:
+		    assert(0);
+	    }
+
+	    e = new IntegerExp(loc, result, type);
+	}
+	else if (type->isunsigned())
+	    e = new IntegerExp(loc, e1->toUInteger(), type);
+	else
+	    e = new IntegerExp(loc, e1->toInteger(), type);
+    }
+    else if (tb->isreal())
+    {   real_t value = e1->toReal();
+
+	e = new RealExp(loc, value, type);
+    }
+    else if (tb->isimaginary())
+    {   real_t value = e1->toImaginary();
+
+	e = new RealExp(loc, value, type);
+    }
+    else if (tb->iscomplex())
+    {   complex_t value = e1->toComplex();
+
+	e = new ComplexExp(loc, value, type);
+    }
+    else if (tb->isscalar())
+	e = new IntegerExp(loc, e1->toInteger(), type);
+    else if (tb->ty == Tvoid)
+	e = EXP_CANT_INTERPRET;
+    else if (tb->ty == Tstruct && e1->op == TOKint64)
+    {	// Struct = 0;
+	StructDeclaration *sd = tb->toDsymbol(NULL)->isStructDeclaration();
+	assert(sd);
+	Expressions *elements = new Expressions;
+	for (size_t i = 0; i < sd->fields.dim; i++)
+	{   Dsymbol *s = (Dsymbol *)sd->fields.data[i];
+	    VarDeclaration *v = s->isVarDeclaration();
+	    assert(v);
+
+	    Expression *exp = new IntegerExp(0);
+	    exp = Cast(v->type, v->type, exp);
+	    if (exp == EXP_CANT_INTERPRET)
+		return exp;
+	    elements->push(exp);
+	}
+	e = new StructLiteralExp(loc, sd, elements);
+	e->type = type;
+    }
+    else
+    {
+	error(loc, "cannot cast %s to %s", e1->type->toChars(), type->toChars());
+	e = new IntegerExp(loc, 0, type);
+    }
+    return e;
+}
+
+
+Expression *ArrayLength(Type *type, Expression *e1)
+{   Expression *e;
+    Loc loc = e1->loc;
+
+    if (e1->op == TOKstring)
+    {	StringExp *es1 = (StringExp *)e1;
+
+	e = new IntegerExp(loc, es1->len, type);
+    }
+    else if (e1->op == TOKarrayliteral)
+    {	ArrayLiteralExp *ale = (ArrayLiteralExp *)e1;
+	size_t dim;
+
+	dim = ale->elements ? ale->elements->dim : 0;
+	e = new IntegerExp(loc, dim, type);
+    }
+    else if (e1->op == TOKassocarrayliteral)
+    {	AssocArrayLiteralExp *ale = (AssocArrayLiteralExp *)e1;
+	size_t dim = ale->keys->dim;
+
+	e = new IntegerExp(loc, dim, type);
+    }
+    else
+	e = EXP_CANT_INTERPRET;
+    return e;
+}
+
+/* Also return EXP_CANT_INTERPRET if this fails
+ */
+Expression *Index(Type *type, Expression *e1, Expression *e2)
+{   Expression *e = EXP_CANT_INTERPRET;
+    Loc loc = e1->loc;
+
+    //printf("Index(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
+    assert(e1->type);
+    if (e1->op == TOKstring && e2->op == TOKint64)
+    {	StringExp *es1 = (StringExp *)e1;
+	uinteger_t i = e2->toInteger();
+
+	if (i >= es1->len)
+        e1->error("string index %llu is out of bounds [0 .. %"PRIuSIZE"]", i, es1->len);
+	else
+	{   unsigned value = es1->charAt(i);
+	    e = new IntegerExp(loc, value, type);
+	}
+    }
+    else if (e1->type->toBasetype()->ty == Tsarray && e2->op == TOKint64)
+    {	TypeSArray *tsa = (TypeSArray *)e1->type->toBasetype();
+	uinteger_t length = tsa->dim->toInteger();
+	uinteger_t i = e2->toInteger();
+
+	if (i >= length)
+	{
+        e2->error("array index %llu is out of bounds %s[0 .. %llu]", i, e1->toChars(), length);
+	}
+	else if (e1->op == TOKarrayliteral && !e1->checkSideEffect(2))
+	{   ArrayLiteralExp *ale = (ArrayLiteralExp *)e1;
+	    e = (Expression *)ale->elements->data[i];
+	    e->type = type;
+	}
+    }
+    else if (e1->type->toBasetype()->ty == Tarray && e2->op == TOKint64)
+    {
+	uinteger_t i = e2->toInteger();
+
+	if (e1->op == TOKarrayliteral && !e1->checkSideEffect(2))
+	{   ArrayLiteralExp *ale = (ArrayLiteralExp *)e1;
+	    if (i >= ale->elements->dim)
+	    {
+            e2->error("array index %llu is out of bounds %s[0 .. %u]", i, e1->toChars(), ale->elements->dim);
+	    }
+	    else
+	    {	e = (Expression *)ale->elements->data[i];
+		e->type = type;
+	    }
+	}
+    }
+    else if (e1->op == TOKassocarrayliteral && !e1->checkSideEffect(2))
+    {
+	AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)e1;
+	/* Search the keys backwards, in case there are duplicate keys
+	 */
+	for (size_t i = ae->keys->dim; i;)
+	{
+	    i--;
+	    Expression *ekey = (Expression *)ae->keys->data[i];
+	    Expression *ex = Equal(TOKequal, Type::tbool, ekey, e2);
+	    if (ex == EXP_CANT_INTERPRET)
+		return ex;
+	    if (ex->isBool(TRUE))
+	    {	e = (Expression *)ae->values->data[i];
+		e->type = type;
+		break;
+	    }
+	}
+    }
+    return e;
+}
+
+/* Also return EXP_CANT_INTERPRET if this fails
+ */
+Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr)
+{   Expression *e = EXP_CANT_INTERPRET;
+    Loc loc = e1->loc;
+
+#if LOG
+    printf("Slice()\n");
+    if (lwr)
+    {	printf("\te1 = %s\n", e1->toChars());
+	printf("\tlwr = %s\n", lwr->toChars());
+	printf("\tupr = %s\n", upr->toChars());
+    }
+#endif
+    if (e1->op == TOKstring && lwr->op == TOKint64 && upr->op == TOKint64)
+    {	StringExp *es1 = (StringExp *)e1;
+	uinteger_t ilwr = lwr->toInteger();
+	uinteger_t iupr = upr->toInteger();
+
+	if (iupr > es1->len || ilwr > iupr)
+        e1->error("string slice [%llu .. %llu] is out of bounds", ilwr, iupr);
+	else
+	{   integer_t value;
+	    void *s;
+	    size_t len = iupr - ilwr;
+	    int sz = es1->sz;
+	    StringExp *es;
+
+	    s = mem.malloc((len + 1) * sz);
+	    memcpy((unsigned char *)s, (unsigned char *)es1->string + ilwr * sz, len * sz);
+	    memset((unsigned char *)s + len * sz, 0, sz);
+
+	    es = new StringExp(loc, s, len, es1->postfix);
+	    es->sz = sz;
+	    es->committed = 1;
+	    es->type = type;
+	    e = es;
+	}
+    }
+    else if (e1->op == TOKarrayliteral &&
+	    lwr->op == TOKint64 && upr->op == TOKint64 &&
+	    !e1->checkSideEffect(2))
+    {	ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1;
+	uinteger_t ilwr = lwr->toInteger();
+	uinteger_t iupr = upr->toInteger();
+
+	if (iupr > es1->elements->dim || ilwr > iupr)
+        e1->error("array slice [%llu .. %llu] is out of bounds", ilwr, iupr);
+	else
+	{
+	    Expressions *elements = new Expressions();
+	    elements->setDim(iupr - ilwr);
+	    memcpy(elements->data,
+		   es1->elements->data + ilwr,
+		   (iupr - ilwr) * sizeof(es1->elements->data[0]));
+	    e = new ArrayLiteralExp(e1->loc, elements);
+	    e->type = type;
+	}
+    }
+    return e;
+}
+
+/* Also return EXP_CANT_INTERPRET if this fails
+ */
+Expression *Cat(Type *type, Expression *e1, Expression *e2)
+{   Expression *e = EXP_CANT_INTERPRET;
+    Loc loc = e1->loc;
+    Type *t;
+
+    //printf("Cat(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
+
+    if (e1->op == TOKnull && (e2->op == TOKint64 || e2->op == TOKstructliteral))
+    {	e = e2;
+	goto L2;
+    }
+    else if ((e1->op == TOKint64 || e1->op == TOKstructliteral) && e2->op == TOKnull)
+    {	e = e1;
+     L2:
+	Type *tn = e->type->toBasetype();
+	if (tn->ty == Tchar || tn->ty == Twchar || tn->ty == Tdchar)
+	{
+	    // Create a StringExp
+	    void *s;
+	    StringExp *es;
+	    size_t len = 1;
+	    int sz = tn->size();
+	    integer_t v = e->toInteger();
+
+	    s = mem.malloc((len + 1) * sz);
+	    memcpy((unsigned char *)s, &v, sz);
+
+	    // Add terminating 0
+	    memset((unsigned char *)s + len * sz, 0, sz);
+
+	    es = new StringExp(loc, s, len);
+	    es->sz = sz;
+	    es->committed = 1;
+	    e = es;
+	}
+	else
+	{   // Create an ArrayLiteralExp
+	    Expressions *elements = new Expressions();
+	    elements->push(e);
+	    e = new ArrayLiteralExp(e->loc, elements);
+	}
+	e->type = type;
+	return e;
+    }
+    else if (e1->op == TOKstring && e2->op == TOKstring)
+    {
+	// Concatenate the strings
+	void *s;
+	StringExp *es1 = (StringExp *)e1;
+	StringExp *es2 = (StringExp *)e2;
+	StringExp *es;
+	Type *t;
+	size_t len = es1->len + es2->len;
+	int sz = es1->sz;
+
+	assert(sz == es2->sz);
+	s = mem.malloc((len + 1) * sz);
+	memcpy(s, es1->string, es1->len * sz);
+	memcpy((unsigned char *)s + es1->len * sz, es2->string, es2->len * sz);
+
+	// Add terminating 0
+	memset((unsigned char *)s + len * sz, 0, sz);
+
+	es = new StringExp(loc, s, len);
+	es->sz = sz;
+	es->committed = es1->committed | es2->committed;
+	if (es1->committed)
+	    t = es1->type;
+	else
+	    t = es2->type;
+	es->type = type;
+	e = es;
+    }
+    else if (e1->op == TOKstring && e2->op == TOKint64)
+    {
+	// Concatenate the strings
+	void *s;
+	StringExp *es1 = (StringExp *)e1;
+	StringExp *es;
+	Type *t;
+	size_t len = es1->len + 1;
+	int sz = es1->sz;
+	integer_t v = e2->toInteger();
+
+	s = mem.malloc((len + 1) * sz);
+	memcpy(s, es1->string, es1->len * sz);
+	memcpy((unsigned char *)s + es1->len * sz, &v, sz);
+
+	// Add terminating 0
+	memset((unsigned char *)s + len * sz, 0, sz);
+
+	es = new StringExp(loc, s, len);
+	es->sz = sz;
+	es->committed = es1->committed;
+	t = es1->type;
+	es->type = type;
+	e = es;
+    }
+    else if (e1->op == TOKint64 && e2->op == TOKstring)
+    {
+	// Concatenate the strings
+	void *s;
+	StringExp *es2 = (StringExp *)e2;
+	StringExp *es;
+	Type *t;
+	size_t len = 1 + es2->len;
+	int sz = es2->sz;
+	integer_t v = e1->toInteger();
+
+	s = mem.malloc((len + 1) * sz);
+	memcpy((unsigned char *)s, &v, sz);
+	memcpy((unsigned char *)s + sz, es2->string, es2->len * sz);
+
+	// Add terminating 0
+	memset((unsigned char *)s + len * sz, 0, sz);
+
+	es = new StringExp(loc, s, len);
+	es->sz = sz;
+	es->committed = es2->committed;
+	t = es2->type;
+	es->type = type;
+	e = es;
+    }
+    else if (e1->op == TOKarrayliteral && e2->op == TOKarrayliteral &&
+	e1->type->equals(e2->type))
+    {
+	// Concatenate the arrays
+	ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1;
+	ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
+
+	es1 = new ArrayLiteralExp(es1->loc, (Expressions *)es1->elements->copy());
+	es1->elements->insert(es1->elements->dim, es2->elements);
+	e = es1;
+
+	if (type->toBasetype()->ty == Tsarray)
+	{
+	    e->type = new TypeSArray(e1->type->toBasetype()->next, new IntegerExp(0, es1->elements->dim, Type::tindex));
+	    e->type = e->type->semantic(loc, NULL);
+	}
+	else
+	    e->type = type;
+    }
+    else if ((e1->op == TOKarrayliteral || e1->op == TOKnull) &&
+	e1->type->toBasetype()->nextOf()->equals(e2->type))
+    {
+	ArrayLiteralExp *es1;
+	if (e1->op == TOKarrayliteral)
+	{   es1 = (ArrayLiteralExp *)e1;
+	    es1 = new ArrayLiteralExp(es1->loc, (Expressions *)es1->elements->copy());
+	    es1->elements->push(e2);
+	}
+	else
+	{
+	    es1 = new ArrayLiteralExp(e1->loc, e2);
+	}
+	e = es1;
+
+	if (type->toBasetype()->ty == Tsarray)
+	{
+	    e->type = new TypeSArray(e2->type, new IntegerExp(0, es1->elements->dim, Type::tindex));
+	    e->type = e->type->semantic(loc, NULL);
+	}
+	else
+	    e->type = type;
+    }
+    else if (e2->op == TOKarrayliteral &&
+	e2->type->toBasetype()->nextOf()->equals(e1->type))
+    {
+	ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
+
+	es2 = new ArrayLiteralExp(es2->loc, (Expressions *)es2->elements->copy());
+	es2->elements->shift(e1);
+	e = es2;
+
+	if (type->toBasetype()->ty == Tsarray)
+	{
+	    e->type = new TypeSArray(e1->type, new IntegerExp(0, es2->elements->dim, Type::tindex));
+	    e->type = e->type->semantic(loc, NULL);
+	}
+	else
+	    e->type = type;
+    }
+    else if (e1->op == TOKnull && e2->op == TOKstring)
+    {
+	t = e1->type;
+	e = e2;
+	goto L1;
+    }
+    else if (e1->op == TOKstring && e2->op == TOKnull)
+    {	e = e1;
+	t = e2->type;
+      L1:
+	Type *tb = t->toBasetype();
+	if (tb->ty == Tarray && tb->nextOf()->equals(e->type))
+	{   Expressions *expressions = new Expressions();
+	    expressions->push(e);
+	    e = new ArrayLiteralExp(loc, expressions);
+	    e->type = t;
+	}
+	if (!e->type->equals(type))
+	{   StringExp *se = (StringExp *)e->copy();
+	    e = se->castTo(NULL, type);
+	}
+    }
+    return e;
+}
+
+Expression *Ptr(Type *type, Expression *e1)
+{
+    //printf("Ptr(e1 = %s)\n", e1->toChars());
+    if (e1->op == TOKadd)
+    {	AddExp *ae = (AddExp *)e1;
+	if (ae->e1->op == TOKaddress && ae->e2->op == TOKint64)
+	{   AddrExp *ade = (AddrExp *)ae->e1;
+	    if (ade->e1->op == TOKstructliteral)
+	    {	StructLiteralExp *se = (StructLiteralExp *)ade->e1;
+		unsigned offset = ae->e2->toInteger();
+		Expression *e = se->getField(type, offset);
+		if (!e)
+		    e = EXP_CANT_INTERPRET;
+		return e;
+	    }
+	}
+    }
+    return EXP_CANT_INTERPRET;
+}
+