mirror of https://git.wuffs.org/MWCC
4972 lines
160 KiB
C
4972 lines
160 KiB
C
#include "compiler/CExpr.h"
|
|
#include "compiler/CABI.h"
|
|
#include "compiler/CClass.h"
|
|
#include "compiler/CDecl.h"
|
|
#include "compiler/CError.h"
|
|
#include "compiler/CException.h"
|
|
#include "compiler/CInit.h"
|
|
#include "compiler/CInline.h"
|
|
#include "compiler/CIRTransform.h"
|
|
#include "compiler/CMachine.h"
|
|
#include "compiler/CMangler.h"
|
|
#include "compiler/CInt64.h"
|
|
#include "compiler/CObjC.h"
|
|
#include "compiler/CObjCModern.h"
|
|
#include "compiler/CParser.h"
|
|
#include "compiler/CPrep.h"
|
|
#include "compiler/CPrepTokenizer.h"
|
|
#include "compiler/CRTTI.h"
|
|
#include "compiler/CSOM.h"
|
|
#include "compiler/CTemplateNew.h"
|
|
#include "compiler/CTemplateTools.h"
|
|
#include "compiler/CodeGen.h"
|
|
#include "compiler/CompilerTools.h"
|
|
#include "compiler/PPCError.h"
|
|
#include "compiler/objects.h"
|
|
#include "compiler/scopes.h"
|
|
#include "compiler/templates.h"
|
|
|
|
Boolean (*name_obj_check)(HashNameNode *, Object *);
|
|
Boolean disallowgreaterthan;
|
|
|
|
// forward declarations
|
|
static ENode *makeaddnode(ENode *left, ENode *right);
|
|
static ENode *makesubnode(ENode *left, ENode *right);
|
|
|
|
ENode *CExpr_RewriteConst(ENode *expr) {
|
|
Object *obj;
|
|
|
|
restart:
|
|
if (ENODE_IS(expr, EINDIRECT) && ENODE_IS(expr->data.monadic, EOBJREF)) {
|
|
obj = expr->data.monadic->data.objref;
|
|
if (obj->datatype == DALIAS) {
|
|
CExpr_AliasTransform(expr->data.monadic);
|
|
goto restart;
|
|
}
|
|
|
|
if ((obj->qual & Q_10000) && expr->rtype == obj->type) {
|
|
switch (expr->rtype->type) {
|
|
case TYPEINT:
|
|
case TYPEENUM:
|
|
expr->type = EINTCONST;
|
|
expr->data.intval = obj->u.data.u.intconst;
|
|
break;
|
|
case TYPEPOINTER:
|
|
expr->type = EINTCONST;
|
|
expr->data.intval = obj->u.data.u.intconst;
|
|
expr->rtype = TYPE(&stunsignedlong);
|
|
expr = makemonadicnode(expr, ETYPCON);
|
|
expr->rtype = obj->type;
|
|
break;
|
|
case TYPEFLOAT:
|
|
expr->type = EFLOATCONST;
|
|
if (obj->u.data.u.floatconst)
|
|
expr->data.floatval = *obj->u.data.u.floatconst;
|
|
else
|
|
expr->data.floatval = CMach_CalcFloatConvertFromInt(TYPE(&stsignedlong), cint64_zero);
|
|
break;
|
|
default:
|
|
CError_FATAL(105);
|
|
}
|
|
}
|
|
}
|
|
|
|
return expr;
|
|
}
|
|
|
|
void optimizecomm(ENode *expr) {
|
|
ENode *right;
|
|
ENode *left;
|
|
|
|
if (ENODE_IS((right = expr->data.diadic.right), EINTCONST))
|
|
return;
|
|
if (ENODE_IS((left = expr->data.diadic.left), EINTCONST)) {
|
|
swap:
|
|
expr->data.diadic.right = left;
|
|
expr->data.diadic.left = right;
|
|
return;
|
|
}
|
|
|
|
if (ENODE_IS(left, EFLOATCONST))
|
|
return;
|
|
if (ENODE_IS(right, EFLOATCONST))
|
|
goto swap;
|
|
|
|
if (expr->rtype->type > TYPEFLOAT)
|
|
return;
|
|
|
|
if (left->cost > right->cost)
|
|
goto swap;
|
|
}
|
|
|
|
static void checkadditive(ENode *expr) {
|
|
switch (expr->rtype->type) {
|
|
case TYPEINT:
|
|
if (expr->rtype == TYPE(&stbool))
|
|
break;
|
|
case TYPEFLOAT:
|
|
return;
|
|
case TYPEENUM:
|
|
if (copts.cplusplus)
|
|
break;
|
|
return;
|
|
case TYPEPOINTER:
|
|
if (TPTR_TARGET(expr->rtype)->size == 0)
|
|
CDecl_CompleteType(TPTR_TARGET(expr->rtype));
|
|
if (TPTR_TARGET(expr->rtype)->size == 0)
|
|
break;
|
|
return;
|
|
case TYPEARRAY:
|
|
if (ENODE_IS(expr, EOBJREF))
|
|
return;
|
|
}
|
|
|
|
CError_Error(CErrorStr376, expr->rtype, ENODE_QUALS(expr));
|
|
}
|
|
|
|
static void CExpr_CompareConvert(ENode **leftp, char *opname, ENode **rightp, Boolean flag) {
|
|
ENode *left;
|
|
ENode *right;
|
|
CInt64 val;
|
|
|
|
left = *leftp;
|
|
right = *rightp;
|
|
|
|
switch (left->rtype->type) {
|
|
case TYPEINT:
|
|
break;
|
|
case TYPEFLOAT:
|
|
if (left->rtype != right->rtype)
|
|
CExpr_ArithmeticConversion(leftp, rightp);
|
|
return;
|
|
case TYPEENUM:
|
|
left->rtype = TYPE_ENUM(left->rtype)->enumtype;
|
|
break;
|
|
default:
|
|
CError_Error(CErrorStr377,
|
|
left->rtype, ENODE_QUALS(left),
|
|
opname,
|
|
right->rtype, ENODE_QUALS(right));
|
|
left = nullnode();
|
|
}
|
|
|
|
switch (right->rtype->type) {
|
|
case TYPEINT:
|
|
break;
|
|
case TYPEFLOAT:
|
|
CExpr_ArithmeticConversion(leftp, rightp);
|
|
return;
|
|
case TYPEENUM:
|
|
right->rtype = TYPE_ENUM(right->rtype)->enumtype;
|
|
break;
|
|
default:
|
|
CError_Error(CErrorStr377,
|
|
left->rtype, ENODE_QUALS(left),
|
|
opname,
|
|
right->rtype, ENODE_QUALS(right));
|
|
right = nullnode();
|
|
}
|
|
|
|
if (left->rtype == right->rtype) {
|
|
*leftp = left;
|
|
*rightp = right;
|
|
return;
|
|
}
|
|
|
|
if (left->rtype->size == right->rtype->size) {
|
|
if (is_unsigned(left->rtype) == is_unsigned(right->rtype)) {
|
|
left->rtype = right->rtype;
|
|
*leftp = left;
|
|
*rightp = right;
|
|
return;
|
|
}
|
|
} else {
|
|
if (ENODE_IS(right, EINTCONST) && left->rtype->size <= right->rtype->size && (is_unsigned(left->rtype) == is_unsigned(right->rtype) || is_unsigned(left->rtype))) {
|
|
val = CMach_CalcIntDiadic(left->rtype, right->data.intval, '+', cint64_zero);
|
|
val = CMach_CalcIntDiadic(right->rtype, val, '+', cint64_zero);
|
|
if (CInt64_Equal(val, right->data.intval)) {
|
|
right->rtype = left->rtype;
|
|
*leftp = left;
|
|
*rightp = right;
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (ENODE_IS(left, EINTCONST) && left->rtype->size >= right->rtype->size && (is_unsigned(left->rtype) == is_unsigned(right->rtype) || is_unsigned(right->rtype))) {
|
|
val = CMach_CalcIntDiadic(right->rtype, left->data.intval, '+', cint64_zero);
|
|
val = CMach_CalcIntDiadic(left->rtype, val, '+', cint64_zero);
|
|
if (CInt64_Equal(val, left->data.intval)) {
|
|
left->rtype = right->rtype;
|
|
*leftp = left;
|
|
*rightp = right;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
*leftp = left;
|
|
*rightp = right;
|
|
CExpr_ArithmeticConversion(leftp, rightp);
|
|
}
|
|
|
|
static ENode *CExpr_ConstResult(ENode *expr, SInt32 value) {
|
|
ENode *constnode;
|
|
|
|
if (IS_TYPE_FLOAT(expr->rtype)) {
|
|
constnode = intconstnode(TYPE(&stsignedint), value);
|
|
constnode->type = EFLOATCONST;
|
|
constnode->data.floatval = CMach_CalcFloatConvertFromInt(TYPE(&stsignedint), constnode->data.intval);
|
|
constnode->rtype = expr->rtype;
|
|
} else {
|
|
constnode = intconstnode(expr->rtype, value);
|
|
}
|
|
|
|
if (CInline_ExpressionHasSideEffect(expr))
|
|
return makediadicnode(expr, constnode, ECOMMA);
|
|
else
|
|
return constnode;
|
|
}
|
|
|
|
static ENode *makemultnode(ENode *left, ENode *right) {
|
|
CExpr_ArithmeticConversion(&left, &right);
|
|
if (iszero(left))
|
|
return CExpr_ConstResult(right, 0);
|
|
if (iszero(right))
|
|
return CExpr_ConstResult(left, 0);
|
|
|
|
if (CExpr_IsOne(right))
|
|
return left;
|
|
if (CExpr_IsOne(left))
|
|
return right;
|
|
|
|
if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) {
|
|
left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, '*', right->data.intval);
|
|
return left;
|
|
}
|
|
if (ENODE_IS(left, EFLOATCONST) && ENODE_IS(right, EFLOATCONST)) {
|
|
left->data.floatval = CMach_CalcFloatDiadic(left->rtype, left->data.floatval, '*', right->data.floatval);
|
|
return left;
|
|
}
|
|
|
|
left = makediadicnode(left, right, EMUL);
|
|
optimizecomm(left);
|
|
if (IS_TYPE_INT(left->rtype) && left->rtype->size > 2) {
|
|
left->cost++;
|
|
if (left->cost > 200)
|
|
left->cost = 200;
|
|
}
|
|
|
|
if (IS_TYPE_FLOAT(left->rtype))
|
|
left = CExpr_BinaryFloatExpression(left);
|
|
|
|
return left;
|
|
}
|
|
|
|
static ENode *makedivnode(ENode *left, ENode *right, Boolean no_warning) {
|
|
CExpr_ArithmeticConversion(&left, &right);
|
|
if (iszero(right) && IS_TYPE_INT(right->rtype)) {
|
|
if (!no_warning)
|
|
CError_Warning(CErrorStr139);
|
|
return right;
|
|
}
|
|
|
|
if (CExpr_IsOne(right))
|
|
return left;
|
|
|
|
if (iszero(left) && IS_TYPE_INT(left->rtype))
|
|
return CExpr_ConstResult(right, 0);
|
|
|
|
if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) {
|
|
left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, '/', right->data.intval);
|
|
return left;
|
|
}
|
|
if (ENODE_IS(left, EFLOATCONST) && ENODE_IS(right, EFLOATCONST)) {
|
|
left->data.floatval = CMach_CalcFloatDiadic(left->rtype, left->data.floatval, '/', right->data.floatval);
|
|
return left;
|
|
}
|
|
|
|
left = makediadicnode(left, right, EDIV);
|
|
if (IS_TYPE_FLOAT(left->rtype))
|
|
left = CExpr_BinaryFloatExpression(left);
|
|
|
|
return left;
|
|
}
|
|
|
|
static short canadd2(ENode *expr, CInt64 value) {
|
|
Float tmp;
|
|
|
|
if (CInt64_IsZero(&value))
|
|
return 1;
|
|
|
|
switch (expr->type) {
|
|
case EINTCONST:
|
|
expr->data.intval = CMach_CalcIntDiadic(expr->rtype, expr->data.intval, '+', value);
|
|
return 1;
|
|
case EFLOATCONST:
|
|
tmp = CMach_CalcFloatConvertFromInt(TYPE(&stsignedlong), value);
|
|
expr->data.floatval = CMach_CalcFloatDiadic(expr->rtype, expr->data.floatval, '+', tmp);
|
|
return 1;
|
|
case EADD:
|
|
if (canadd2(expr->data.diadic.left, value))
|
|
return 1;
|
|
if (canadd2(expr->data.diadic.right, value))
|
|
return 1;
|
|
return 0;
|
|
case ESUB:
|
|
if (canadd2(expr->data.diadic.left, value))
|
|
return 1;
|
|
if (canadd2(expr->data.diadic.right, CInt64_Neg(value)))
|
|
return 1;
|
|
return 0;
|
|
case ETYPCON:
|
|
if (IS_TYPE_POINTER_ONLY(expr->rtype) && ENODE_IS(expr->data.monadic, EINTCONST)) {
|
|
expr->data.monadic->data.intval = CMach_CalcIntDiadic(TYPE(&stunsignedlong), expr->data.monadic->data.intval, '+', value);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
short canadd(ENode *expr, SInt32 value) {
|
|
CInt64 value64;
|
|
CInt64_SetLong(&value64, value);
|
|
return canadd2(expr, value64);
|
|
}
|
|
|
|
static ENode *addconst(ENode *expr, SInt32 value) {
|
|
ENode *right;
|
|
|
|
if (canadd(expr, value))
|
|
return expr;
|
|
|
|
if (stsignedint.size < 4 && (value > 0x7FFF || value < -0x8000))
|
|
right = intconstnode(TYPE(&stsignedlong), value);
|
|
else
|
|
right = intconstnode(TYPE(&stsignedint), value);
|
|
|
|
CExpr_ArithmeticConversion(&expr, &right);
|
|
expr = makediadicnode(expr, right, EADD);
|
|
return expr;
|
|
}
|
|
|
|
static ENode *integralpointerpromote(ENode *expr) {
|
|
Boolean uns;
|
|
Type *type;
|
|
|
|
if (!IS_TYPE_INT(expr->rtype))
|
|
expr = forceintegral(expr);
|
|
|
|
if (expr->rtype->size != 4) {
|
|
type = TYPE(&stunsignedlong);
|
|
if (is_unsigned(type) != (uns = is_unsigned(expr->rtype))) {
|
|
if (uns) {
|
|
if (stunsignedlong.size == 4) {
|
|
type = TYPE(&stunsignedlong);
|
|
} else if (stunsignedint.size == 4) {
|
|
type = TYPE(&stunsignedint);
|
|
} else {
|
|
CError_FATAL(480);
|
|
}
|
|
} else {
|
|
if (stsignedlong.size == 4) {
|
|
type = TYPE(&stsignedlong);
|
|
} else if (stsignedint.size == 4) {
|
|
type = TYPE(&stsignedint);
|
|
} else {
|
|
CError_FATAL(486);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ENODE_IS(expr, EINTCONST))
|
|
expr->data.intval = CExpr_IntConstConvert(type, expr->rtype, expr->data.intval);
|
|
else
|
|
expr = makemonadicnode(expr, ETYPCON);
|
|
|
|
expr->rtype = type;
|
|
}
|
|
|
|
return expr;
|
|
}
|
|
|
|
static ENode *padd(ENode *left, ENode *right) {
|
|
Type *innertype;
|
|
SInt32 innersize;
|
|
ENode *expr;
|
|
|
|
right = integralpointerpromote(right);
|
|
innertype = TPTR_TARGET(left->rtype);
|
|
innersize = innertype->size;
|
|
if (innersize == 0) {
|
|
CDecl_CompleteType(innertype);
|
|
innersize = innertype->size;
|
|
if (innersize == 0) {
|
|
CError_Error(CErrorStr146);
|
|
return left;
|
|
}
|
|
}
|
|
|
|
expr = makemultnode(
|
|
right,
|
|
intconstnode((innersize > 0x7FFF) ? TYPE(&stsignedlong) : TYPE(&stsignedint), innersize));
|
|
|
|
if (ENODE_IS(expr, EINTCONST) && canadd2(left, expr->data.intval))
|
|
return left;
|
|
|
|
if (ENODE_IS(left, EADD) && ENODE_IS(left->data.diadic.right, EINTCONST)) {
|
|
left->data.diadic.left = makediadicnode(left->data.diadic.left, expr, EADD);
|
|
return left;
|
|
}
|
|
|
|
expr = makediadicnode(left, expr, EADD);
|
|
expr->rtype = left->rtype;
|
|
expr->flags = left->flags;
|
|
return expr;
|
|
}
|
|
|
|
static ENode *psub(ENode *left, ENode *right) {
|
|
Type *innertype;
|
|
SInt32 innersize;
|
|
ENode *expr;
|
|
|
|
if (IS_TYPE_POINTER(right->rtype)) {
|
|
innersize = TPTR_TARGET(left->rtype)->size;
|
|
if (innersize == 0) {
|
|
CDecl_CompleteType(TPTR_TARGET(left->rtype));
|
|
innersize = TPTR_TARGET(left->rtype)->size;
|
|
if (innersize == 0) {
|
|
CError_Error(CErrorStr146);
|
|
return left;
|
|
}
|
|
}
|
|
|
|
if (!is_typeequal(left->rtype, right->rtype)) {
|
|
CError_Error(CErrorStr245, left->rtype, ENODE_QUALS(left), right->rtype, ENODE_QUALS(right));
|
|
return left;
|
|
}
|
|
|
|
if (ENODE_IS(left, ETYPCON) && ENODE_IS(left->data.monadic, EINTCONST) && ENODE_IS(right, ETYPCON) && ENODE_IS(right->data.monadic, EINTCONST)) {
|
|
left->data.monadic->rtype = right->data.monadic->rtype = CABI_GetPtrDiffTType();
|
|
expr = makesubnode(left->data.monadic, right->data.monadic);
|
|
if (innersize > 1)
|
|
expr = makedivnode(expr, intconstnode(CABI_GetPtrDiffTType(), innersize), 11);
|
|
return expr;
|
|
}
|
|
|
|
expr = makediadicnode(left, right, ESUB);
|
|
expr->rtype = CABI_GetPtrDiffTType();
|
|
if (innersize > 1)
|
|
expr = makediadicnode(expr, intconstnode(CABI_GetPtrDiffTType(), innersize), EDIV);
|
|
return expr;
|
|
}
|
|
|
|
right = integralpointerpromote(right);
|
|
innertype = TPTR_TARGET(left->rtype);
|
|
innersize = innertype->size;
|
|
if (innersize == 0) {
|
|
CDecl_CompleteType(innertype);
|
|
innersize = innertype->size;
|
|
if (innersize == 0) {
|
|
CError_Error(CErrorStr146);
|
|
return left;
|
|
}
|
|
}
|
|
|
|
expr = makemultnode(right, intconstnode(CABI_GetPtrDiffTType(), innersize));
|
|
if (ENODE_IS(expr, EINTCONST) && canadd2(left, CInt64_Neg(expr->data.intval)))
|
|
return left;
|
|
|
|
expr = makediadicnode(left, expr, ESUB);
|
|
expr->rtype = left->rtype;
|
|
expr->flags = left->flags;
|
|
return expr;
|
|
}
|
|
|
|
static ENode *makeaddnode(ENode *left, ENode *right) {
|
|
if (IS_TYPE_POINTER(left->rtype))
|
|
return padd(left, right);
|
|
if (IS_TYPE_POINTER(right->rtype))
|
|
return padd(right, left);
|
|
|
|
CExpr_ArithmeticConversion(&left, &right);
|
|
if (iszero(right))
|
|
return left;
|
|
if (iszero(left))
|
|
return right;
|
|
|
|
if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) {
|
|
left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, '+', right->data.intval);
|
|
return left;
|
|
}
|
|
if (ENODE_IS(left, EFLOATCONST) && ENODE_IS(right, EFLOATCONST)) {
|
|
left->data.floatval = CMach_CalcFloatDiadic(left->rtype, left->data.floatval, '+', right->data.floatval);
|
|
return left;
|
|
}
|
|
|
|
if (ENODE_IS(left, EINTCONST) && canadd2(right, left->data.intval))
|
|
return right;
|
|
if (ENODE_IS(right, EINTCONST) && canadd2(left, right->data.intval))
|
|
return left;
|
|
|
|
left = makediadicnode(left, right, EADD);
|
|
optimizecomm(left);
|
|
if (IS_TYPE_FLOAT(left->rtype))
|
|
left = CExpr_BinaryFloatExpression(left);
|
|
return left;
|
|
}
|
|
|
|
static ENode *makesubnode(ENode *left, ENode *right) {
|
|
if (ENODE_IS(right, EINTCONST) && !is_unsigned(right->rtype) && !IS_TYPE_FLOAT(left->rtype)) {
|
|
right->data.intval = CInt64_Neg(right->data.intval);
|
|
return makeaddnode(left, right);
|
|
}
|
|
|
|
if (IS_TYPE_POINTER(left->rtype))
|
|
return psub(left, right);
|
|
|
|
CExpr_ArithmeticConversion(&left, &right);
|
|
if (iszero(right))
|
|
return left;
|
|
if (iszero(left)) {
|
|
if (ENODE_IS(right, EINTCONST)) {
|
|
right->data.intval = CInt64_Neg(right->data.intval);
|
|
return right;
|
|
}
|
|
if (ENODE_IS(right, EFLOATCONST)) {
|
|
right->data.floatval = CMach_CalcFloatMonadic(right->rtype, '-', right->data.floatval);
|
|
return right;
|
|
}
|
|
return CExpr_UnaryFloatExpression(makemonadicnode(right, EMONMIN));
|
|
}
|
|
|
|
if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) {
|
|
left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, '-', right->data.intval);
|
|
return left;
|
|
}
|
|
if (ENODE_IS(left, EFLOATCONST) && ENODE_IS(right, EFLOATCONST)) {
|
|
left->data.floatval = CMach_CalcFloatDiadic(left->rtype, left->data.floatval, '-', right->data.floatval);
|
|
return left;
|
|
}
|
|
|
|
if (ENODE_IS(right, EINTCONST) && canadd2(left, CInt64_Neg(right->data.intval)))
|
|
return left;
|
|
|
|
left = makediadicnode(left, right, ESUB);
|
|
if (IS_TYPE_FLOAT(left->rtype))
|
|
left = CExpr_BinaryFloatExpression(left);
|
|
return left;
|
|
}
|
|
|
|
ENode *checkreference(ENode *expr) {
|
|
if (!IS_TYPE_REFERENCE(expr->rtype))
|
|
return expr;
|
|
|
|
expr = makemonadicnode(expr, EINDIRECT);
|
|
expr->rtype = TPTR_TARGET(expr->rtype);
|
|
return expr;
|
|
}
|
|
|
|
static ENode *pointer_generation2(ENode *expr) {
|
|
switch (expr->type) {
|
|
case EINDIRECT:
|
|
switch (expr->rtype->type) {
|
|
case TYPEARRAY:
|
|
switch (expr->data.monadic->type) {
|
|
case EPOSTINC:
|
|
case EPOSTDEC:
|
|
case EPREINC:
|
|
case EPREDEC:
|
|
expr->type = ETYPCON;
|
|
expr->rtype = CDecl_NewPointerType(TPTR_TARGET(expr->rtype));
|
|
return expr;
|
|
default:
|
|
expr->data.monadic->rtype = CDecl_NewPointerType(TPTR_TARGET(expr->rtype));
|
|
expr->data.monadic->flags = expr->flags;
|
|
return expr->data.monadic;
|
|
}
|
|
case TYPEFUNC:
|
|
expr = expr->data.monadic;
|
|
if (ENODE_IS(expr, EOBJREF) && expr->data.objref->datatype == DINLINEFUNC)
|
|
CError_Error(CErrorStr175);
|
|
return expr;
|
|
}
|
|
}
|
|
return expr;
|
|
}
|
|
|
|
ENode *pointer_generation(ENode *expr) {
|
|
return CExpr_RewriteConst(pointer_generation2(expr));
|
|
}
|
|
|
|
ENode *CExpr_PointerGeneration(ENode *expr) {
|
|
switch (expr->type) {
|
|
case EINDIRECT:
|
|
switch (expr->rtype->type) {
|
|
case TYPEARRAY:
|
|
expr->data.monadic->rtype = CDecl_NewPointerType(TPTR_TARGET(expr->rtype));
|
|
return expr->data.monadic;
|
|
case TYPEFUNC:
|
|
return expr->data.monadic;
|
|
}
|
|
}
|
|
return expr;
|
|
}
|
|
|
|
static void CExpr_ConstPointerCheck(ENode *expr, Type *type, short qual) {
|
|
Type *exprtype;
|
|
Type *b;
|
|
Type *a;
|
|
short exprqual;
|
|
|
|
exprtype = expr->rtype;
|
|
if (IS_TYPE_POINTER_ONLY(type) && IS_TYPE_POINTER_ONLY(exprtype)) {
|
|
exprqual = expr->flags;
|
|
|
|
if (TPTR_TARGET(type) == &stvoid) {
|
|
exprqual = CParser_GetCVTypeQualifiers(TPTR_TARGET(exprtype), exprqual);
|
|
} else {
|
|
a = TPTR_TARGET(type);
|
|
b = TPTR_TARGET(exprtype);
|
|
while (IS_TYPE_POINTER_ONLY(a) && IS_TYPE_POINTER_ONLY(b)) {
|
|
if (CParser_IsMoreCVQualified(TPTR_QUAL(b), TPTR_QUAL(a))) {
|
|
CError_Warning(CErrorStr220, expr->rtype, ENODE_QUALS(expr), type, qual);
|
|
return;
|
|
}
|
|
a = TPTR_TARGET(a);
|
|
b = TPTR_TARGET(b);
|
|
}
|
|
}
|
|
|
|
if (CParser_IsMoreCVQualified(exprqual, qual)) {
|
|
CError_Warning(CErrorStr220, expr->rtype, ENODE_QUALS(expr), type, (UInt32) qual);
|
|
}
|
|
}
|
|
}
|
|
|
|
ENode *oldassignmentpromotion(ENode *expr, Type *type, short qual, Boolean flag) {
|
|
Boolean is_ref;
|
|
UInt32 ref_qual;
|
|
short orig_qual;
|
|
|
|
is_ref = 0;
|
|
if (!IS_TYPE_MEMBERPOINTER(type)) {
|
|
if (IS_TYPE_REFERENCE(type)) {
|
|
if (ENODE_IS(expr, ECOND))
|
|
expr = CExpr_LValue(expr, 0, 0);
|
|
expr = pointer_generation2(expr);
|
|
ref_qual = CParser_GetCVTypeQualifiers(expr->rtype, expr->flags);
|
|
is_ref = 1;
|
|
} else {
|
|
expr = pointer_generation(expr);
|
|
}
|
|
}
|
|
|
|
if (ENODE_IS(expr, EMEMBER))
|
|
expr = getpointertomemberfunc(expr, type, 1);
|
|
|
|
if (!is_ref)
|
|
CExpr_ConstPointerCheck(expr, type, qual);
|
|
else
|
|
CExpr_ConstPointerCheck(expr, TPTR_TARGET(type), qual);
|
|
|
|
if (!(assign_check(expr, type, orig_qual = qual, 1, 0, flag)))
|
|
return expr;
|
|
|
|
if (is_ref) {
|
|
if (temp_reference_init) {
|
|
switch (TPTR_TARGET(type)->type) {
|
|
case TYPEPOINTER:
|
|
qual = TPTR_QUAL(TPTR_TARGET(type));
|
|
}
|
|
if (!(qual & Q_CONST))
|
|
CError_Warning(CErrorStr228);
|
|
} else {
|
|
if (ref_qual && ref_qual > CParser_GetCVTypeQualifiers(TPTR_TARGET(type), orig_qual))
|
|
CError_Warning(CErrorStr259);
|
|
}
|
|
}
|
|
|
|
return assign_node;
|
|
}
|
|
|
|
ENode *argumentpromotion(ENode *expr, Type *type, short qual, Boolean flag) {
|
|
ENode *tmp;
|
|
ENodeList *list;
|
|
|
|
if (IS_TYPE_CLASS(type) && CClass_ReferenceArgument(TYPE_CLASS(type))) {
|
|
if ((tmp = CExpr_IsTempConstruction(expr, type, NULL)))
|
|
return tmp;
|
|
|
|
list = lalloc(sizeof(ENodeList));
|
|
list->next = NULL;
|
|
list->node = expr;
|
|
tmp = CExpr_ConstructObject(
|
|
TYPE_CLASS(type),
|
|
create_temp_node(type),
|
|
list, 1, 1, 1, 1, 0);
|
|
return getnodeaddress(tmp, 0);
|
|
}
|
|
|
|
return CExpr_AssignmentPromotion(expr, type, qual, flag);
|
|
}
|
|
|
|
ENode *classargument(ENode *expr) {
|
|
ENodeList *list;
|
|
|
|
if (CClass_CopyConstructor(TYPE_CLASS(expr->rtype))) {
|
|
list = lalloc(sizeof(ENodeList));
|
|
list->next = NULL;
|
|
list->node = expr;
|
|
return CExpr_ConstructObject(
|
|
TYPE_CLASS(expr->rtype),
|
|
create_temp_node(expr->rtype),
|
|
list, 1, 1, 1, 1, 0);
|
|
}
|
|
|
|
return expr;
|
|
}
|
|
|
|
ENodeList *CExpr_ScanExpressionList(Boolean is_parens) {
|
|
ENodeList *list;
|
|
ENodeList *current;
|
|
|
|
if (is_parens && tk == ')')
|
|
return NULL;
|
|
|
|
list = current = lalloc(sizeof(ENodeList));
|
|
|
|
while (1) {
|
|
current->next = NULL;
|
|
current->node = assignment_expression();
|
|
if (copts.old_argmatch && !ENODE_IS(current->node, EMEMBER))
|
|
current->node = pointer_generation(current->node);
|
|
|
|
if (is_parens) {
|
|
if (tk == ')')
|
|
break;
|
|
} else {
|
|
if (tk == ']')
|
|
break;
|
|
}
|
|
|
|
if (tk != ',') {
|
|
CError_ErrorSkip(CErrorStr116);
|
|
break;
|
|
}
|
|
|
|
tk = lex();
|
|
current->next = lalloc(sizeof(ENodeList));
|
|
current = current->next;
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
static ENode *skipcommaexpr(ENode *expr) {
|
|
while (ENODE_IS(expr, ECOMMA))
|
|
expr = expr->data.diadic.right;
|
|
return expr;
|
|
}
|
|
|
|
ENode *CExpr_DoExplicitConversion(Type *type, UInt32 qual, ENodeList *list) {
|
|
Object *obj;
|
|
ENode *tmp;
|
|
|
|
if (!IS_TYPE_CLASS(type)) {
|
|
if (!list)
|
|
return do_typecast(nullnode(), type, qual);
|
|
if (list->next)
|
|
CError_Error(CErrorStr356);
|
|
return do_typecast(pointer_generation(list->node), type, qual);
|
|
}
|
|
|
|
CDecl_CompleteType(type);
|
|
if (!(TYPE_CLASS(type)->flags & CLASS_FLAGS_2))
|
|
CError_Error(CErrorStr136, type, 0);
|
|
|
|
CanCreateObject(type);
|
|
if (!list && CClass_IsPODClass(TYPE_CLASS(type))) {
|
|
obj = CParser_NewGlobalDataObject(NULL);
|
|
obj->name = CParser_GetUniqueName();
|
|
obj->nspace = cscope_root;
|
|
obj->type = type;
|
|
obj->qual = qual;
|
|
obj->sclass = TK_STATIC;
|
|
CInit_DeclareData(obj, NULL, NULL, type->size);
|
|
|
|
tmp = makemonadicnode(create_temp_node(type), EINDIRECT);
|
|
tmp->rtype = type;
|
|
tmp->flags = qual & ENODE_FLAG_QUALS;
|
|
return makediadicnode(tmp, create_objectnode(obj), EASS);
|
|
}
|
|
|
|
return CExpr_ConstructObject(TYPE_CLASS(type), create_temp_node(type), list, 1, 1, 1, 1, 1);
|
|
}
|
|
|
|
static ENode *CExpr_TemplArgDepCast(Type *type, UInt32 qual, ENodeList *args) {
|
|
ENode *expr = CExpr_NewTemplDepENode(TDE_CAST);
|
|
expr->data.templdep.u.cast.args = args;
|
|
expr->data.templdep.u.cast.type = type;
|
|
expr->data.templdep.u.cast.qual = qual;
|
|
return expr;
|
|
}
|
|
|
|
static ENode *CExpr_ParseExplicitConversion(Type *type, UInt32 qual) {
|
|
ENodeList *args;
|
|
ENodeList *scan;
|
|
|
|
if (IS_TEMPL_CLASS(type) && !CParser_CheckTemplateClassUsage(TEMPL_CLASS(type), 1))
|
|
type = TYPE(&stsignedint);
|
|
|
|
if (tk == '(')
|
|
tk = lex();
|
|
else
|
|
CError_Error(CErrorStr114);
|
|
|
|
args = CExpr_ScanExpressionList(1);
|
|
if (tk != ')') {
|
|
CError_Error(CErrorStr115);
|
|
return nullnode();
|
|
}
|
|
|
|
tk = lex();
|
|
if (CTemplTool_IsTemplateArgumentDependentType(type))
|
|
return CExpr_TemplArgDepCast(type, qual, args);
|
|
|
|
for (scan = args; scan; scan = scan->next) {
|
|
if (CTemplTool_IsTemplateArgumentDependentExpression(scan->node))
|
|
return CExpr_TemplArgDepCast(type, qual, args);
|
|
}
|
|
|
|
return CExpr_DoExplicitConversion(type, qual, args);
|
|
}
|
|
|
|
static ENode *CExpr_MemberVarAccess(BClassList *path, ObjMemberVar *var, ENode *expr) {
|
|
ENode *accessnode;
|
|
BClassList *varpath;
|
|
|
|
CError_ASSERT(1152, path);
|
|
|
|
if (TYPE_CLASS(path->type)->sominfo)
|
|
return CSOM_MemberVarAccess(path, var, expr);
|
|
|
|
varpath = NULL;
|
|
if (var->has_path)
|
|
varpath = OBJ_MEMBER_VAR_PATH(var)->path;
|
|
accessnode = CExpr_GetClassAccessNode(path, varpath, expr, NULL, var->access, 1);
|
|
if (!accessnode)
|
|
return nullnode();
|
|
|
|
return CClass_AccessMember(accessnode, var->type, var->qual, var->offset);
|
|
}
|
|
|
|
static Boolean CExpr_IsTemplateFunc(Object *obj) {
|
|
return IS_TEMPL_FUNC(obj->type);
|
|
}
|
|
|
|
static ENode *CExpr_ExplicitTemplateArgCheck(CScopeParseResult *pr) {
|
|
NameSpaceObjectList *list;
|
|
NameSpaceObjectList *newhead;
|
|
NameSpaceObjectList *newlist;
|
|
ENode *expr;
|
|
|
|
if (pr->obj_10) {
|
|
if (pr->obj_10->otype != OT_OBJECT || !CExpr_IsTemplateFunc(OBJECT(pr->obj_10)))
|
|
return NULL;
|
|
|
|
list = lalloc(sizeof(NameSpaceObjectList));
|
|
memclrw(list, sizeof(NameSpaceObjectList));
|
|
list->object = pr->obj_10;
|
|
} else if (pr->nsol_14) {
|
|
for (list = pr->nsol_14; list; list = list->next) {
|
|
if (list->object->otype == OT_OBJECT && CExpr_IsTemplateFunc(OBJECT(list->object))) {
|
|
newhead = newlist = galloc(sizeof(NameSpaceObjectList));
|
|
*newlist = *list;
|
|
newlist->next = NULL;
|
|
while ((list = list->next)) {
|
|
if (list->object->otype == OT_OBJECT && CExpr_IsTemplateFunc(OBJECT(list->object))) {
|
|
newlist->next = galloc(sizeof(NameSpaceObjectList));
|
|
newlist = newlist->next;
|
|
*newlist = *list;
|
|
newlist->next = NULL;
|
|
}
|
|
}
|
|
list = newhead;
|
|
break;
|
|
}
|
|
}
|
|
if (!list)
|
|
return NULL;
|
|
} else {
|
|
return NULL;
|
|
}
|
|
|
|
expr = CExpr_NewENode(EOBJLIST);
|
|
expr->rtype = OBJECT(list->object)->type;
|
|
expr->data.objlist.list = list;
|
|
expr->data.objlist.templargs = CTempl_ParseUncheckTemplArgs(NULL, 0);
|
|
|
|
tk = lex();
|
|
return expr;
|
|
}
|
|
|
|
ENode *CExpr_MakeNameLookupResultExpr(CScopeParseResult *pr) {
|
|
ENode *expr;
|
|
|
|
if (pr->obj_10) {
|
|
switch (pr->obj_10->otype) {
|
|
case OT_OBJECT:
|
|
CClass_CheckObjectAccess(pr->bcl_18, OBJECT(pr->obj_10));
|
|
return create_objectnode(OBJECT(pr->obj_10));
|
|
case OT_ENUMCONST:
|
|
CClass_CheckEnumAccess(pr->bcl_18, OBJ_ENUM_CONST(pr->obj_10));
|
|
expr = lalloc(sizeof(ENode));
|
|
expr->type = EINTCONST;
|
|
expr->cost = 0;
|
|
expr->flags = 0;
|
|
expr->rtype = OBJ_ENUM_CONST(pr->obj_10)->type;
|
|
expr->data.intval = OBJ_ENUM_CONST(pr->obj_10)->val;
|
|
return expr;
|
|
case OT_MEMBERVAR:
|
|
CError_Error(CErrorStr221);
|
|
return nullnode();
|
|
default:
|
|
CError_FATAL(1268);
|
|
}
|
|
}
|
|
|
|
if (pr->nsol_14) {
|
|
expr = CExpr_NewENode(EOBJLIST);
|
|
expr->rtype = OBJECT(pr->nsol_14->object)->type;
|
|
expr->data.objlist.list = pr->nsol_14;
|
|
return expr;
|
|
}
|
|
|
|
CError_FATAL(1278);
|
|
return NULL;
|
|
}
|
|
|
|
static Type *CExpr_NewPTMType(EMemberInfo *member, Object *obj) {
|
|
TypeMemberPointer *ptm;
|
|
TypeMemberFunc *tmethod;
|
|
BClassList *path;
|
|
|
|
ptm = galloc(sizeof(TypeMemberPointer));
|
|
memclrw(ptm, sizeof(TypeMemberPointer));
|
|
ptm->type = TYPEMEMBERPOINTER;
|
|
|
|
if (member->list->object->otype == OT_MEMBERVAR) {
|
|
path = member->path;
|
|
while (path->next)
|
|
path = path->next;
|
|
ptm->size = 4;
|
|
ptm->ty2 = path->type;
|
|
ptm->ty1 = OBJ_MEMBER_VAR(member->list->object)->type;
|
|
} else {
|
|
if (!obj) {
|
|
CError_ASSERT(1306, member->list->object->otype == OT_OBJECT);
|
|
obj = OBJECT(member->list->object);
|
|
CError_ASSERT(1308, IS_TYPE_FUNC(obj->type));
|
|
}
|
|
|
|
tmethod = galloc(sizeof(TypeMemberFunc));
|
|
memclrw(tmethod, sizeof(TypeMemberFunc));
|
|
*tmethod = *TYPE_METHOD(obj->type);
|
|
|
|
CError_ASSERT(1312, tmethod->args);
|
|
|
|
tmethod->args = tmethod->args->next;
|
|
CDecl_MakePTMFuncType(TYPE_FUNC(tmethod));
|
|
tmethod->flags &= ~FUNC_FLAGS_2;
|
|
|
|
ptm->size = 12;
|
|
ptm->ty2 = TYPE(tmethod->theclass);
|
|
ptm->ty1 = TYPE(tmethod);
|
|
}
|
|
|
|
return TYPE(ptm);
|
|
}
|
|
|
|
static ENode *CExpr_ParseNameResultExpr(CScopeParseResult *pr, ENode *expr, Boolean flag1, Boolean flag2) {
|
|
ENode *result;
|
|
ENode *ta_expr;
|
|
ObjEnumConst *oec;
|
|
TemplateAction *act;
|
|
EMemberInfo *member;
|
|
NameSpaceObjectList *list;
|
|
Object *obj;
|
|
TypeFunc *tfunc;
|
|
SInt32 val;
|
|
|
|
if (pr->x8) {
|
|
if (copts.cplusplus) {
|
|
if (IS_TYPE_TEMPLATE(pr->x8)) {
|
|
if (TYPE_TEMPLATE(pr->x8)->dtype == TEMPLDEP_ARGUMENT && TYPE_TEMPLATE(pr->x8)->u.pid.type == TPT_NONTYPE) {
|
|
result = CExpr_NewTemplDepENode(TDE_PARAM);
|
|
result->data.templdep.u.pid = TYPE_TEMPLATE(pr->x8)->u.pid;
|
|
tk = lex();
|
|
return result;
|
|
}
|
|
if (TYPE_TEMPLATE(pr->x8)->dtype == TEMPLDEP_QUALNAME && !pr->x20) {
|
|
result = CExpr_NewTemplDepENode(TDE_QUALNAME);
|
|
result->data.templdep.u.qual.type = TYPE_TEMPLATE(pr->x8)->u.qual.type;
|
|
result->data.templdep.u.qual.name = TYPE_TEMPLATE(pr->x8)->u.qual.name;
|
|
tk = lex();
|
|
return result;
|
|
}
|
|
}
|
|
tk = lex();
|
|
return CExpr_ParseExplicitConversion(pr->x8, pr->xC);
|
|
}
|
|
CError_ErrorSkip(CErrorStr141);
|
|
tk = lex();
|
|
return nullnode();
|
|
}
|
|
|
|
if (pr->obj_10) {
|
|
switch (pr->obj_10->otype) {
|
|
case OT_OBJECT:
|
|
if (OBJECT(pr->obj_10)->nspace && OBJECT(pr->obj_10)->nspace->theclass && (OBJECT(pr->obj_10)->nspace->theclass->flags & CLASS_FLAGS_100)) {
|
|
result = CExpr_NewTemplDepENode(TDE_OBJ);
|
|
result->data.templdep.u.obj = OBJECT(pr->obj_10);
|
|
tk = lex();
|
|
return result;
|
|
}
|
|
if (!expr || !IS_TEMPL_FUNC(OBJECT(pr->obj_10)->type)) {
|
|
if (!IS_TYPE_NONSTATIC_METHOD(OBJECT(pr->obj_10)->type)) {
|
|
tk = lex();
|
|
if (tk == '<' && (ta_expr = CExpr_ExplicitTemplateArgCheck(pr)))
|
|
return ta_expr;
|
|
if (OBJECT(pr->obj_10)->datatype == DLOCAL && OBJECT(pr->obj_10)->u.var.info->func != cscope_currentfunc) {
|
|
CError_Error(CErrorStr330);
|
|
return nullnode();
|
|
}
|
|
if (OBJECT(pr->obj_10)->datatype == DEXPR) {
|
|
result = CInline_CopyExpression(OBJECT(pr->obj_10)->u.expr, CopyMode0);
|
|
if (IS_TYPE_POINTER_ONLY(result->rtype) && ENODE_IS(result, EINTCONST)) {
|
|
result = makemonadicnode(result, ETYPCON);
|
|
result->data.monadic->rtype = TYPE(&stunsignedlong);
|
|
}
|
|
return result;
|
|
}
|
|
CClass_CheckObjectAccess(pr->bcl_18, OBJECT(pr->obj_10));
|
|
if (tk == '(' && flag2 && OBJECT(pr->obj_10)->datatype == DFUNC && copts.cplusplus && !pr->x1D && !IS_TYPEFUNC_METHOD(TYPE_FUNC(OBJECT(pr->obj_10)->type))) {
|
|
result = CExpr_NewENode(EOBJLIST);
|
|
result->rtype = OBJECT(pr->obj_10)->type;
|
|
result->data.objlist.list = galloc(sizeof(NameSpaceObjectList));
|
|
result->data.objlist.list->next = pr->nsol_14;
|
|
result->data.objlist.list->object = pr->obj_10;
|
|
result->data.objlist.name = OBJECT(pr->obj_10)->name;
|
|
return result;
|
|
}
|
|
|
|
result = create_objectnode(OBJECT(pr->obj_10));
|
|
if (expr) {
|
|
while (ENODE_IS(expr, EINDIRECT))
|
|
expr = expr->data.monadic;
|
|
switch (expr->type) {
|
|
case EINTCONST:
|
|
case EOBJREF:
|
|
case EOBJLIST:
|
|
break;
|
|
default:
|
|
result = makecommaexpression(expr, result);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
if (CClass_IsDestructor(OBJECT(pr->obj_10))) {
|
|
if ((tk = lex()) != '(') {
|
|
CError_Error(CErrorStr114);
|
|
return nullnode();
|
|
}
|
|
if ((tk = lex()) != ')') {
|
|
CError_Error(CErrorStr115);
|
|
return nullnode();
|
|
}
|
|
if (!expr && (!cscope_currentfunc || !cscope_currentclass || !cscope_is_member_func)) {
|
|
CError_Error(CErrorStr221);
|
|
return nullnode();
|
|
}
|
|
if (pr->isambig)
|
|
CError_Error(CErrorStr188);
|
|
|
|
if ((expr = CExpr_GetClassAccessNode(pr->bcl_18, NULL, expr, OBJECT(pr->obj_10), pr->obj_10->access, 1))) {
|
|
tk = lex();
|
|
return CABI_DestroyObject(OBJECT(pr->obj_10), expr->data.monadic, 1, pr->x1D, 0);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case OT_ENUMCONST:
|
|
CClass_CheckEnumAccess(pr->bcl_18, OBJ_ENUM_CONST(pr->obj_10));
|
|
oec = OBJ_ENUM_CONST(pr->obj_10);
|
|
if (CInt64_IsZero(&oec->val) && IS_TYPE_ENUM(oec->type) && TYPE_ENUM(oec->type)->nspace && TYPE_ENUM(oec->type)->nspace->theclass && (TYPE_ENUM(oec->type)->nspace->theclass->flags & CLASS_FLAGS_100)) {
|
|
val = 0;
|
|
expr = NULL;
|
|
for (act = TEMPL_CLASS(TYPE_ENUM(oec->type)->nspace->theclass)->actions; act; act = act->next) {
|
|
if (act->type == TAT_ENUMERATOR) {
|
|
if (act->u.enumerator.initexpr) {
|
|
expr = act->u.enumerator.initexpr;
|
|
val = 0;
|
|
} else {
|
|
val++;
|
|
}
|
|
if (act->u.enumerator.objenumconst == oec) {
|
|
CError_ASSERT(1521, expr);
|
|
expr = CInline_CopyExpression(expr, CopyMode0);
|
|
if (val)
|
|
expr = makediadicnode(expr, intconstnode(TYPE(&stsignedlong), val), EADD);
|
|
tk = lex();
|
|
return expr;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
result = lalloc(sizeof(ENode));
|
|
result->type = EINTCONST;
|
|
result->cost = 0;
|
|
result->flags = 0;
|
|
result->rtype = OBJ_ENUM_CONST(pr->obj_10)->type;
|
|
result->data.intval = OBJ_ENUM_CONST(pr->obj_10)->val;
|
|
tk = lex();
|
|
return result;
|
|
case OT_MEMBERVAR:
|
|
if (!flag1 || expr || !pr->x1D) {
|
|
if (pr->isambig)
|
|
CError_Error(CErrorStr188);
|
|
result = checkreference(CExpr_MemberVarAccess(pr->bcl_18, OBJ_MEMBER_VAR(pr->obj_10), expr));
|
|
tk = lex();
|
|
return result;
|
|
}
|
|
break;
|
|
default:
|
|
CError_FATAL(1552);
|
|
}
|
|
|
|
member = lalloc(sizeof(EMemberInfo));
|
|
memclrw(member, sizeof(EMemberInfo));
|
|
member->path = pr->bcl_18;
|
|
member->expr = expr;
|
|
member->pr_1D = pr->x1D;
|
|
member->isambig = pr->isambig;
|
|
if ((tk = lex()) == '<' && (ta_expr = CExpr_ExplicitTemplateArgCheck(pr))) {
|
|
CError_ASSERT(1564, ENODE_IS(ta_expr, EOBJLIST));
|
|
member->list = ta_expr->data.objlist.list;
|
|
member->templargs = ta_expr->data.objlist.templargs;
|
|
} else {
|
|
member->list = galloc(sizeof(NameSpaceObjectList));
|
|
member->list->next = NULL;
|
|
member->list->object = pr->obj_10;
|
|
}
|
|
|
|
result = CExpr_NewENode(EMEMBER);
|
|
result->data.emember = member;
|
|
result->rtype = &stvoid;
|
|
return result;
|
|
}
|
|
|
|
if (pr->nsol_14) {
|
|
if ((tk = lex()) == '<' && (ta_expr = CExpr_ExplicitTemplateArgCheck(pr))) {
|
|
CError_ASSERT(1591, ENODE_IS(ta_expr, EOBJLIST));
|
|
for (list = ta_expr->data.objlist.list; list; list = list->next) {
|
|
if (list->object->otype == OT_OBJECT && IS_TYPE_NONSTATIC_METHOD(OBJECT(list->object)->type)) {
|
|
member = lalloc(sizeof(EMemberInfo));
|
|
memclrw(member, sizeof(EMemberInfo));
|
|
|
|
member->path = pr->bcl_18;
|
|
member->expr = expr;
|
|
member->list = ta_expr->data.objlist.list;
|
|
member->templargs = ta_expr->data.objlist.templargs;
|
|
member->pr_1D = pr->x1D;
|
|
member->isambig = pr->isambig;
|
|
|
|
result = CExpr_NewENode(EMEMBER);
|
|
result->data.emember = member;
|
|
result->rtype = &stvoid;
|
|
return result;
|
|
}
|
|
}
|
|
return ta_expr;
|
|
}
|
|
|
|
for (list = pr->nsol_14; list; list = list->next) {
|
|
if (list->object->otype == OT_OBJECT && IS_TYPE_NONSTATIC_METHOD(OBJECT(list->object)->type)) {
|
|
member = lalloc(sizeof(EMemberInfo));
|
|
memclrw(member, sizeof(EMemberInfo));
|
|
|
|
member->path = pr->bcl_18;
|
|
member->expr = expr;
|
|
member->list = pr->nsol_14;
|
|
member->pr_1D = pr->x1D;
|
|
member->isambig = pr->isambig;
|
|
|
|
result = CExpr_NewENode(EMEMBER);
|
|
result->data.emember = member;
|
|
result->rtype = &stvoid;
|
|
return result;
|
|
}
|
|
}
|
|
|
|
if (tk == '<' && (ta_expr = CExpr_ExplicitTemplateArgCheck(pr)))
|
|
return ta_expr;
|
|
|
|
result = CExpr_NewENode(EOBJLIST);
|
|
result->rtype = OBJECT(pr->nsol_14->object)->type;
|
|
result->data.objlist.list = pr->nsol_14;
|
|
if (tk == '(' && copts.cplusplus && flag2 && !pr->x1D && pr->nsol_14->object->otype == OT_OBJECT)
|
|
result->data.objlist.name = OBJECT(pr->nsol_14->object)->name;
|
|
return result;
|
|
}
|
|
|
|
if (pr->name_4) {
|
|
if (copts.cplusplus && flag2) {
|
|
if (lookahead() == '(') {
|
|
result = CExpr_NewENode(EOBJLIST);
|
|
result->rtype = &stvoid;
|
|
result->data.objlist.name = pr->name_4;
|
|
tk = lex();
|
|
return result;
|
|
}
|
|
CError_Error(CErrorStr140, pr->name_4->name);
|
|
tk = lex();
|
|
return nullnode();
|
|
}
|
|
|
|
if (lookahead() != '(') {
|
|
CError_Error(CErrorStr140, pr->name_4->name);
|
|
tk = lex();
|
|
return nullnode();
|
|
}
|
|
|
|
if (copts.checkprotos)
|
|
CError_Error(CErrorStr178);
|
|
|
|
tfunc = galloc(sizeof(TypeFunc));
|
|
memclrw(tfunc, sizeof(TypeFunc));
|
|
tfunc->type = TYPEFUNC;
|
|
tfunc->functype = TYPE(&stsignedint);
|
|
tfunc->args = &oldstyle;
|
|
CDecl_SetFuncFlags(tfunc, 0);
|
|
|
|
obj = CParser_NewFunctionObject(NULL);
|
|
obj->name = pr->name_4;
|
|
obj->sclass = TK_EXTERN;
|
|
obj->nspace = cscope_root;
|
|
obj->type = TYPE(tfunc);
|
|
|
|
CScope_AddGlobalObject(obj);
|
|
tk = lex();
|
|
return create_objectrefnode(obj);
|
|
}
|
|
|
|
CError_FATAL(1711);
|
|
return NULL;
|
|
}
|
|
|
|
static ENode *CExpr_ParseRotate(Boolean is_right) {
|
|
ENode *expr1;
|
|
ENode *expr2;
|
|
|
|
if (lex() != '(') {
|
|
CError_Error(CErrorStr114);
|
|
return nullnode();
|
|
}
|
|
|
|
tk = lex();
|
|
expr1 = assignment_expression();
|
|
|
|
if (tk != ',') {
|
|
CError_Error(CErrorStr116);
|
|
return nullnode();
|
|
}
|
|
|
|
tk = lex();
|
|
expr2 = assignment_expression();
|
|
|
|
if (tk != ')') {
|
|
CError_Error(CErrorStr115);
|
|
return nullnode();
|
|
}
|
|
|
|
if (!IS_TYPE_INT(expr1->rtype))
|
|
expr1 = forceintegral(expr1);
|
|
expr2 = integralpromote(expr2);
|
|
|
|
tk = lex();
|
|
if (iszero(expr1) || iszero(expr2))
|
|
return expr1;
|
|
|
|
return makediadicnode(expr1, expr2, is_right ? EROTR : EROTL);
|
|
}
|
|
|
|
static ENode *CExpr_ParseNextArg(void) {
|
|
NameSpaceObjectList *list;
|
|
CScopeParseResult pr;
|
|
ENode *expr;
|
|
SInt32 rounded_size;
|
|
|
|
if ((tk = lex()) != '(') {
|
|
CError_Error(CErrorStr114);
|
|
return nullnode();
|
|
}
|
|
if ((tk = lex()) != TK_IDENTIFIER) {
|
|
CError_Error(CErrorStr107);
|
|
return nullnode();
|
|
}
|
|
|
|
list = CScope_FindObjectList(&pr, tkidentifier);
|
|
if (!list) {
|
|
CError_Error(CErrorStr140, tkidentifier->name);
|
|
return nullnode();
|
|
}
|
|
|
|
if (list->object->otype != OT_OBJECT || OBJECT(list->object)->datatype != DLOCAL) {
|
|
CError_Error(CErrorStr140, tkidentifier->name);
|
|
return nullnode();
|
|
}
|
|
|
|
rounded_size = CMach_RoundedSizeOf(OBJECT(list->object));
|
|
expr = CExpr_MakeObjRefNode(OBJECT(list->object), 1);
|
|
expr = makediadicnode(expr, intconstnode(CABI_GetPtrDiffTType(), rounded_size), EADD);
|
|
expr->rtype = TYPE(&void_ptr);
|
|
|
|
if ((tk = lex()) != ')') {
|
|
CError_Error(CErrorStr115);
|
|
return expr;
|
|
} else {
|
|
tk = lex();
|
|
return expr;
|
|
}
|
|
}
|
|
|
|
static ENode *CExpr_ParseVecStep(void) {
|
|
ENode *expr;
|
|
Type *type;
|
|
SInt32 value;
|
|
DeclInfo di;
|
|
|
|
expr = intconstnode(TYPE(&stsignedint), 0);
|
|
if ((tk = lex()) == '(') {
|
|
if (tk == '(' && islookaheaddeclaration()) {
|
|
tk = lex();
|
|
memclrw(&di, sizeof(DeclInfo));
|
|
CParser_GetDeclSpecs(&di, 0);
|
|
scandeclarator(&di);
|
|
if (di.name)
|
|
CError_Error(CErrorStr121);
|
|
|
|
if (tk != ')')
|
|
CError_ErrorSkip(CErrorStr115);
|
|
else
|
|
tk = lex();
|
|
|
|
type = di.thetype;
|
|
if (IS_TYPE_REFERENCE(type))
|
|
type = TPTR_TARGET(type);
|
|
} else {
|
|
expr = unary_expression();
|
|
if (ENODE_IS(expr, EINDIRECT) && ENODE_IS(expr->data.monadic, EBITFIELD))
|
|
CError_Error(CErrorStr144);
|
|
type = expr->rtype;
|
|
}
|
|
|
|
CDecl_CompleteType(type);
|
|
if (IS_TYPE_VECTOR(type)) {
|
|
switch (TYPE_STRUCT(type)->stype) {
|
|
case STRUCT_VECTOR_UCHAR:
|
|
case STRUCT_VECTOR_SCHAR:
|
|
case STRUCT_VECTOR_BCHAR:
|
|
value = 16;
|
|
break;
|
|
case STRUCT_VECTOR_USHORT:
|
|
case STRUCT_VECTOR_SSHORT:
|
|
case STRUCT_VECTOR_BSHORT:
|
|
case STRUCT_VECTOR_PIXEL:
|
|
value = 8;
|
|
break;
|
|
default:
|
|
value = 4;
|
|
}
|
|
expr = intconstnode(TYPE(&stsignedint), value);
|
|
} else {
|
|
PPCError_Error(104, "vec_step", "vec_step", type, 0);
|
|
}
|
|
} else {
|
|
CError_Error(CErrorStr114);
|
|
}
|
|
|
|
return expr;
|
|
}
|
|
|
|
static SInt32 CExpr_BuiltInComputeAlign(Type *type) {
|
|
return CMach_GetTypeAlign(type);
|
|
}
|
|
|
|
static SInt32 CExpr_AtomTypeID(IntegralType what) {
|
|
switch (what) {
|
|
case IT_BOOL: return 1;
|
|
case IT_CHAR: return 2;
|
|
case IT_SCHAR: return 3;
|
|
case IT_UCHAR: return 4;
|
|
case IT_WCHAR_T: return 5;
|
|
case IT_SHORT: return 6;
|
|
case IT_USHORT: return 7;
|
|
case IT_INT: return 8;
|
|
case IT_UINT: return 9;
|
|
case IT_LONG: return 10;
|
|
case IT_ULONG: return 10;
|
|
case IT_LONGLONG: return 12;
|
|
case IT_ULONGLONG: return 13;
|
|
case IT_FLOAT: return 14;
|
|
case IT_SHORTDOUBLE: return 15;
|
|
case IT_DOUBLE: return 16;
|
|
case IT_LONGDOUBLE: return 17;
|
|
case IT_17: return 32;
|
|
case IT_18: return 33;
|
|
case IT_19: return 34;
|
|
case IT_20: return 35;
|
|
case IT_21: return 36;
|
|
case IT_22: return 37;
|
|
case IT_23: return 38;
|
|
case IT_24: return 39;
|
|
default:
|
|
CError_FATAL(1976);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static SInt32 CExpr_BuiltInComputeType(Type *type) {
|
|
switch (type->type) {
|
|
case TYPEINT:
|
|
return 0x100 | CExpr_AtomTypeID(TYPE_INTEGRAL(type)->integral);
|
|
case TYPEFLOAT:
|
|
return 0x200 | CExpr_AtomTypeID(TYPE_INTEGRAL(type)->integral);
|
|
case TYPEENUM:
|
|
return 0x400 | (CExpr_BuiltInComputeType(TYPE_ENUM(type)->enumtype) & 0xFF);
|
|
case TYPEPOINTER:
|
|
return 0x800;
|
|
case TYPEARRAY:
|
|
return 0x1000;
|
|
case TYPESTRUCT:
|
|
return 0x2000;
|
|
case TYPECLASS:
|
|
return 0x2000;
|
|
case TYPEMEMBERPOINTER:
|
|
return 0x4000;
|
|
case TYPEFUNC:
|
|
return 0x8000;
|
|
default:
|
|
CError_Error(CErrorStr146);
|
|
case TYPEVOID:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static SInt32 CExpr_BuiltInClassifyType(Type *type) {
|
|
switch (type->type) {
|
|
case TYPEVOID: return 0;
|
|
case TYPEFUNC: return 10;
|
|
case TYPEENUM: return 3;
|
|
case TYPEINT: return 1;
|
|
case TYPEFLOAT: return 8;
|
|
case TYPEPOINTER: case TYPEMEMBERPOINTER: return 5;
|
|
case TYPEARRAY: return 14;
|
|
case TYPESTRUCT: return 12;
|
|
case TYPECLASS: return 12;
|
|
case TYPEBITFIELD: return -1;
|
|
case TYPETEMPLATE: return -1;
|
|
default: return -1;
|
|
}
|
|
}
|
|
|
|
static SInt32 CExpr_BuiltInComputeVArgType(Type *type) {
|
|
switch (type->type) {
|
|
case TYPEINT:
|
|
case TYPEENUM:
|
|
return 0;
|
|
case TYPEFLOAT:
|
|
return 1;
|
|
default:
|
|
return 2;
|
|
}
|
|
}
|
|
|
|
static Type *CExpr_ParseTypeExpression(Boolean *outflag) {
|
|
ENode *expr;
|
|
Type *type;
|
|
DeclInfo di;
|
|
|
|
tk = lex();
|
|
if (tk == '(' && islookaheaddeclaration()) {
|
|
tk = lex();
|
|
memclrw(&di, sizeof(DeclInfo));
|
|
CParser_GetDeclSpecs(&di, 0);
|
|
scandeclarator(&di);
|
|
if (di.name)
|
|
CError_Error(CErrorStr121);
|
|
|
|
if (tk != ')')
|
|
CError_ErrorSkip(CErrorStr115);
|
|
else
|
|
tk = lex();
|
|
|
|
type = di.thetype;
|
|
if (IS_TYPE_REFERENCE(type))
|
|
type = TPTR_TARGET(type);
|
|
} else {
|
|
expr = unary_expression();
|
|
if (ENODE_IS(expr, EINDIRECT) && ENODE_IS(expr->data.monadic, EBITFIELD))
|
|
CError_Error(CErrorStr144);
|
|
|
|
if (outflag)
|
|
*outflag = ENODE_IS(expr, EINTCONST) && CInt64_IsZero(&expr->data.intval);
|
|
|
|
type = expr->rtype;
|
|
}
|
|
|
|
CDecl_CompleteType(type);
|
|
return type;
|
|
}
|
|
|
|
static ENode *CExpr_ParseBuiltin(SInt32 (*parser)(Type *)) {
|
|
ENode *expr;
|
|
expr = intconstnode(TYPE(&stsignedint), 0);
|
|
CInt64_SetLong(&expr->data.intval, parser(CExpr_ParseTypeExpression(NULL)));
|
|
return expr;
|
|
}
|
|
|
|
static ENode *CExpr_ParseBuiltin_isintconst(void) {
|
|
ENode *expr;
|
|
expr = intconstnode(TYPE(&stsignedint), 0);
|
|
|
|
tk = lex();
|
|
if (tk != '(')
|
|
CError_ErrorSkip(CErrorStr121);
|
|
else
|
|
tk = lex();
|
|
|
|
if (ENODE_IS(expression(), EINTCONST))
|
|
CInt64_SetLong(&expr->data.intval, 1);
|
|
|
|
if (tk != ')')
|
|
CError_ErrorSkip(CErrorStr115);
|
|
else
|
|
tk = lex();
|
|
|
|
return expr;
|
|
}
|
|
|
|
static ENode *primary_expression(Boolean flag) {
|
|
CScopeParseResult pr;
|
|
ENode *expr;
|
|
|
|
switch (tk) {
|
|
case TK_TRUE:
|
|
expr = lalloc(sizeof(ENode));
|
|
expr->type = EINTCONST;
|
|
expr->cost = 0;
|
|
expr->flags = 0;
|
|
expr->rtype = TYPE(&stbool);
|
|
CInt64_SetULong(&expr->data.intval, 1);
|
|
tk = lex();
|
|
return expr;
|
|
case TK_FALSE:
|
|
expr = lalloc(sizeof(ENode));
|
|
expr->type = EINTCONST;
|
|
expr->cost = 0;
|
|
expr->flags = 0;
|
|
expr->rtype = TYPE(&stbool);
|
|
CInt64_SetULong(&expr->data.intval, 0);
|
|
tk = lex();
|
|
return expr;
|
|
case TK_INTCONST:
|
|
expr = lalloc(sizeof(ENode));
|
|
expr->type = EINTCONST;
|
|
expr->cost = 0;
|
|
expr->flags = 0;
|
|
expr->rtype = atomtype();
|
|
expr->data.intval = tkintconst;
|
|
tk = lex();
|
|
return expr;
|
|
case TK_FLOATCONST:
|
|
expr = lalloc(sizeof(ENode));
|
|
expr->type = EFLOATCONST;
|
|
expr->cost = 0;
|
|
expr->flags = 0;
|
|
expr->rtype = atomtype();
|
|
expr->data.floatval = tkfloatconst;
|
|
tk = lex();
|
|
return expr;
|
|
case TK_STRING:
|
|
expr = CExpr_NewENode(ESTRINGCONST);
|
|
expr->rtype = CDecl_NewArrayType(ispascalstring ? TYPE(&stunsignedchar) : TYPE(&stchar), tksize);
|
|
expr->data.string.size = tksize;
|
|
expr->data.string.data = tkstring;
|
|
expr->data.string.ispascal = ispascalstring;
|
|
if (copts.const_strings)
|
|
expr->flags = ENODE_FLAG_CONST;
|
|
expr = makemonadicnode(expr, EINDIRECT);
|
|
expr->data.monadic->rtype = CDecl_NewPointerType(expr->rtype);
|
|
tk = lex();
|
|
return expr;
|
|
case TK_STRING_WIDE:
|
|
expr = CExpr_NewENode(ESTRINGCONST);
|
|
expr->rtype = CDecl_NewArrayType(CParser_GetWCharType(), tksize);
|
|
expr->data.string.size = tksize;
|
|
expr->data.string.data = tkstring;
|
|
expr->data.string.ispascal = ispascalstring;
|
|
if (copts.const_strings)
|
|
expr->flags = ENODE_FLAG_CONST;
|
|
expr = makemonadicnode(expr, EINDIRECT);
|
|
expr->data.monadic->rtype = CDecl_NewPointerType(expr->rtype);
|
|
tk = lex();
|
|
return expr;
|
|
case TK_THIS:
|
|
case TK_SELF:
|
|
expr = CClass_CreateThisSelfExpr();
|
|
if (!expr)
|
|
expr = nullnode();
|
|
tk = lex();
|
|
return expr;
|
|
case TK_AT_SELECTOR:
|
|
return CObjC_ParseSelectorExpression();
|
|
case TK_AT_ENCODE:
|
|
return CObjC_ParseEncodeExpression();
|
|
case TK_AT_PROTOCOL:
|
|
return CObjC_ParseProtocolExpression();
|
|
case '@':
|
|
if (copts.objective_c)
|
|
return CObjC_ParseAtExpression();
|
|
break;
|
|
case '(':
|
|
tk = lex();
|
|
expr = s_expression();
|
|
if (tk != ')')
|
|
CError_ErrorSkip(CErrorStr115);
|
|
else
|
|
tk = lex();
|
|
if (ENODE_IS(expr, EASS))
|
|
expr->flags |= ENODE_FLAG_80;
|
|
return expr;
|
|
case '[':
|
|
if (copts.objective_c)
|
|
return CObjC_ParseMessageExpression();
|
|
break;
|
|
case TK_IDENTIFIER:
|
|
if (tkidentifier->name[0] == '_' && tkidentifier->name[1] == '_') {
|
|
if (!strcmp(tkidentifier->name, "__builtin_align"))
|
|
return CExpr_ParseBuiltin(CExpr_BuiltInComputeAlign);
|
|
if (!strcmp(tkidentifier->name, "__builtin_ntype"))
|
|
return CExpr_ParseBuiltin(CExpr_BuiltInComputeType);
|
|
if (!strcmp(tkidentifier->name, "__builtin_type") || !strcmp(tkidentifier->name, "__builtin_vargtype"))
|
|
return CExpr_ParseBuiltin(CExpr_BuiltInComputeVArgType);
|
|
if (!strcmp(tkidentifier->name, "__builtin_classify_type"))
|
|
return CExpr_ParseBuiltin(CExpr_BuiltInClassifyType);
|
|
if (!strcmp(tkidentifier->name, "__builtin_next_arg"))
|
|
return CExpr_ParseNextArg();
|
|
}
|
|
if (copts.altivec_model && !strcmp("vec_step", tkidentifier->name))
|
|
return CExpr_ParseVecStep();
|
|
case '~':
|
|
case TK_OPERATOR:
|
|
case TK_INHERITED:
|
|
case TK_COLON_COLON:
|
|
if (CScope_ParseExprName(&pr))
|
|
return CExpr_ParseNameResultExpr(&pr, NULL, flag, 1);
|
|
tk = lex();
|
|
return nullnode();
|
|
}
|
|
|
|
CError_ErrorSkip(CErrorStr141);
|
|
return nullnode();
|
|
}
|
|
|
|
static ENode *CExpr_SimpleExplicitConversion(void) {
|
|
DeclInfo di;
|
|
|
|
memclrw(&di, sizeof(DeclInfo));
|
|
|
|
if (!copts.cpp_extensions && tk != TK_UU_TYPEOF_UU && tk != TK_TYPENAME && lookahead() != '(')
|
|
CError_Error(CErrorStr114);
|
|
|
|
CParser_GetDeclSpecs(&di, 0);
|
|
return CExpr_ParseExplicitConversion(di.thetype, di.qual);
|
|
}
|
|
|
|
static ENode *CExpr_NewPTMFCall(void) {
|
|
tk = lex();
|
|
CExpr_ScanExpressionList(1);
|
|
|
|
if (tk != ')') {
|
|
CError_Error(CErrorStr115);
|
|
return nullnode();
|
|
} else {
|
|
CError_FATAL(2465);
|
|
return nullnode();
|
|
}
|
|
}
|
|
|
|
static ENode *call_ptmf(ENode *expr) {
|
|
Type *rettype;
|
|
ENodeList *args;
|
|
ENodeList *list1;
|
|
ENodeList *list2;
|
|
Object *callobj;
|
|
|
|
rettype = TYPE_FUNC(TPTR_TARGET(expr->data.mfpointer.mfpointer->rtype))->functype;
|
|
tk = lex();
|
|
args = CExpr_ScanExpressionList(1);
|
|
|
|
if (tk != ')') {
|
|
CError_Error(CErrorStr115);
|
|
return nullnode();
|
|
}
|
|
|
|
if (IS_TYPE_STRUCT(rettype) || IS_TYPE_CLASS(rettype) || IS_TYPE_12BYTES_MEMBERPOINTER(rettype))
|
|
callobj = rt_ptmf_scall4;
|
|
else
|
|
callobj = rt_ptmf_scall;
|
|
|
|
list1 = lalloc(sizeof(ENodeList));
|
|
list1->next = args;
|
|
list1->node = expr->data.mfpointer.accessnode->data.monadic;
|
|
|
|
list2 = lalloc(sizeof(ENodeList));
|
|
list2->next = list1;
|
|
list2->node = expr->data.mfpointer.mfpointer->data.monadic;
|
|
|
|
if (!copts.old_argmatch) {
|
|
CError_ASSERT(2568, IS_TYPE_POINTER_ONLY(list2->node->rtype));
|
|
list2->node->rtype = TYPE(&void_ptr);
|
|
}
|
|
|
|
expr = CExpr_GenericPtmfCall(
|
|
callobj,
|
|
TYPE_FUNC(TPTR_TARGET(expr->data.mfpointer.mfpointer->rtype)),
|
|
list2);
|
|
tk = lex();
|
|
return expr;
|
|
}
|
|
|
|
static ENode *CExpr_DummyDestr(ENode *expr) {
|
|
SInt32 state;
|
|
CScopeParseResult pr;
|
|
DeclInfo di;
|
|
NameSpace *nspace;
|
|
|
|
CPrep_TokenStreamGetState(&state);
|
|
nspace = cscope_current;
|
|
if ((tk = lex()) == TK_COLON_COLON) {
|
|
nspace = cscope_root;
|
|
tk = lex();
|
|
} else if (tk != '~' && tk != TK_IDENTIFIER && !(tk >= TK_AUTO && tk <= TK_BYREF)) {
|
|
CPrep_TokenStreamSetCurState(&state);
|
|
return NULL;
|
|
}
|
|
|
|
loop:
|
|
if (tk == '~')
|
|
goto is_tilde;
|
|
if (tk == TK_IDENTIFIER) {
|
|
if (CScope_FindTypeName(nspace, tkidentifier, &pr)) {
|
|
tk = lex();
|
|
if (pr.nspace_0) {
|
|
if (tk == TK_COLON_COLON) {
|
|
tk = lex();
|
|
nspace = pr.nspace_0;
|
|
goto loop;
|
|
}
|
|
} else if (IS_TYPE_CLASS(pr.x8) && tk == TK_COLON_COLON) {
|
|
tk = lex();
|
|
nspace = TYPE_CLASS(pr.x8)->nspace;
|
|
goto loop;
|
|
} else {
|
|
if (!is_typesame(pr.x8, expr->rtype))
|
|
CError_Error(CErrorStr146);
|
|
if (tk == TK_COLON_COLON && ((tk = lex()) == '~') && ((tk = lex()) == TK_IDENTIFIER)) {
|
|
parse_dtor:
|
|
if (CScope_FindTypeName(nspace, tkidentifier, &pr) && !pr.nspace_0) {
|
|
if (!is_typesame(pr.x8, expr->rtype))
|
|
CError_Error(CErrorStr146);
|
|
tk = lex();
|
|
goto parsed;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else if (tk >= TK_AUTO && tk <= TK_BYREF) {
|
|
memclrw(&di, sizeof(DeclInfo));
|
|
CParser_GetDeclSpecs(&di, 0);
|
|
if (di.storageclass || di.qual || !is_typesame(di.thetype, expr->rtype))
|
|
CError_Error(CErrorStr146);
|
|
if (tk == TK_COLON_COLON && ((tk = lex()) == '~')) {
|
|
is_tilde:
|
|
if ((tk = lex()) == TK_IDENTIFIER)
|
|
goto parse_dtor;
|
|
memclrw(&di, sizeof(DeclInfo));
|
|
CParser_GetDeclSpecs(&di, 0);
|
|
if (di.storageclass || !is_typesame(di.thetype, expr->rtype))
|
|
CError_Error(CErrorStr146);
|
|
goto parsed;
|
|
}
|
|
}
|
|
|
|
CError_Error(CErrorStr141);
|
|
return NULL;
|
|
|
|
parsed:
|
|
if (tk == '(') {
|
|
if ((tk = lex()) != ')')
|
|
CError_Error(CErrorStr115);
|
|
else
|
|
tk = lex();
|
|
} else {
|
|
CError_Error(CErrorStr114);
|
|
}
|
|
|
|
expr = makemonadicnode(expr, ETYPCON);
|
|
expr->rtype = &stvoid;
|
|
return expr;
|
|
}
|
|
|
|
static ENode *postfix_expression(Boolean flag) {
|
|
CScopeParseResult pr;
|
|
Conversion conv;
|
|
ENode *expr;
|
|
ENode *subexpr;
|
|
ENode *funcexpr;
|
|
ENodeList *args;
|
|
ENode *copy;
|
|
ENode *tmp;
|
|
StructMember *member;
|
|
|
|
if (copts.cplusplus) {
|
|
switch (tk) {
|
|
case TK_VOID:
|
|
case TK_CHAR:
|
|
case TK_SHORT:
|
|
case TK_INT:
|
|
case TK_LONG:
|
|
case TK_FLOAT:
|
|
case TK_DOUBLE:
|
|
case TK_SIGNED:
|
|
case TK_UNSIGNED:
|
|
case TK_UNK_113:
|
|
case TK_UNK_114:
|
|
case TK_UNK_115:
|
|
case TK_UNK_116:
|
|
case TK_UNK_117:
|
|
case TK_UNK_118:
|
|
case TK_UNK_119:
|
|
case TK_UNK_11A:
|
|
case TK_UU_TYPEOF_UU:
|
|
case TK_BOOL:
|
|
case TK_WCHAR_T:
|
|
case TK_TYPENAME:
|
|
expr = CExpr_SimpleExplicitConversion();
|
|
break;
|
|
default:
|
|
expr = primary_expression(flag);
|
|
break;
|
|
case TK_CONST_CAST:
|
|
expr = CRTTI_Parse_const_cast();
|
|
break;
|
|
case TK_DYNAMIC_CAST:
|
|
expr = CRTTI_Parse_dynamic_cast();
|
|
break;
|
|
case TK_REINTERPRET_CAST:
|
|
expr = CRTTI_Parse_reinterpret_cast();
|
|
break;
|
|
case TK_STATIC_CAST:
|
|
expr = CRTTI_Parse_static_cast();
|
|
break;
|
|
case TK_TYPEID:
|
|
expr = CRTTI_ParseTypeID();
|
|
break;
|
|
}
|
|
} else {
|
|
expr = primary_expression(flag);
|
|
}
|
|
|
|
loop:
|
|
switch (tk) {
|
|
case '[':
|
|
expr = pointer_generation(expr);
|
|
tk = lex();
|
|
subexpr = expression();
|
|
if (copts.cplusplus && CExpr_CheckOperator('[', expr, subexpr, &conv)) {
|
|
if ((expr = conv.x0)) {
|
|
if (tk != ']')
|
|
CError_ErrorSkip(CErrorStr125);
|
|
else
|
|
tk = lex();
|
|
goto loop;
|
|
}
|
|
|
|
CError_ASSERT(2753, expr = conv.left);
|
|
CError_ASSERT(2754, subexpr = conv.right);
|
|
}
|
|
|
|
if (IS_TYPE_POINTER(expr->rtype)) {
|
|
expr = padd(expr, subexpr);
|
|
} else if (IS_TYPE_POINTER(subexpr->rtype)) {
|
|
expr = padd(subexpr, expr);
|
|
} else {
|
|
CError_Error(CErrorStr148);
|
|
goto dont_do_indirect;
|
|
}
|
|
expr = makemonadicnode(expr, EINDIRECT);
|
|
expr->rtype = TPTR_TARGET(expr->rtype);
|
|
dont_do_indirect:
|
|
if (tk != ']')
|
|
CError_ErrorSkip(CErrorStr125);
|
|
else
|
|
tk = lex();
|
|
goto loop;
|
|
|
|
case '(':
|
|
funcexpr = CExpr_PointerGeneration(expr);
|
|
if (copts.cplusplus) {
|
|
if (CExpr_CheckOperator('(', funcexpr, NULL, &conv)) {
|
|
CError_ASSERT(2775, expr = conv.x0);
|
|
goto loop;
|
|
}
|
|
if (ENODE_IS(funcexpr, EMFPOINTER)) {
|
|
expr = checkreference(call_ptmf(funcexpr));
|
|
goto loop;
|
|
}
|
|
}
|
|
|
|
tk = lex();
|
|
args = CExpr_ScanExpressionList(1);
|
|
if (tk != ')')
|
|
CError_Error(CErrorStr115);
|
|
|
|
if (ENODE_IS(funcexpr, ETEMPLDEP)) {
|
|
expr = CExpr_NewENode(EFUNCCALL);
|
|
expr->rtype = &sttemplexpr;
|
|
expr->data.funccall.funcref = funcexpr;
|
|
expr->data.funccall.args = args;
|
|
expr->data.funccall.functype = &rt_func;
|
|
tk = lex();
|
|
} else {
|
|
expr = checkreference(CExpr_MakeFunctionCall(funcexpr, args));
|
|
tk = lex();
|
|
}
|
|
goto loop;
|
|
|
|
case TK_ARROW:
|
|
expr = pointer_generation(expr);
|
|
if (copts.cplusplus) {
|
|
while (IS_TYPE_CLASS(expr->rtype) && CExpr_CheckOperator(TK_ARROW, expr, NULL, &conv)) {
|
|
CError_ASSERT(2810, subexpr = conv.x0);
|
|
expr = pointer_generation(subexpr);
|
|
}
|
|
}
|
|
|
|
if (!IS_TYPE_POINTER(expr->rtype)) {
|
|
CError_ErrorSkip(CErrorStr148);
|
|
return expr;
|
|
}
|
|
|
|
if (copts.cplusplus && copts.objective_c && CObjC_IsType_id(expr->rtype)) {
|
|
expr = makemonadicnode(expr, EINDIRECT);
|
|
expr->rtype = TPTR_TARGET(expr->rtype);
|
|
if ((subexpr = CObjC_CheckModernSendMessage(NULL, expr)))
|
|
return subexpr;
|
|
} else {
|
|
expr = makemonadicnode(expr, EINDIRECT);
|
|
expr->rtype = TPTR_TARGET(expr->rtype);
|
|
}
|
|
case '.':
|
|
expr = pointer_generation(expr);
|
|
if (IS_TYPE_CLASS(expr->rtype)) {
|
|
CDecl_CompleteType(expr->rtype);
|
|
if (TYPE_CLASS(expr->rtype)->objcinfo && copts.cplusplus && (subexpr = CObjC_CheckModernSendMessage(TYPE_CLASS(expr->rtype), expr)))
|
|
return subexpr;
|
|
|
|
if (!(TYPE_CLASS(expr->rtype)->flags & CLASS_FLAGS_2))
|
|
CError_Error(CErrorStr136, expr->rtype, 0);
|
|
|
|
if ((tk = lex()) == TK_TEMPLATE && (tk = lex()) != TK_IDENTIFIER)
|
|
CError_Error(CErrorStr107);
|
|
|
|
if (CScope_ParseMemberName(TYPE_CLASS(expr->rtype), &pr, 0)) {
|
|
if (pr.x1C) {
|
|
if ((tk = lex()) == '(') {
|
|
if ((tk = lex()) != ')')
|
|
CError_Error(CErrorStr115);
|
|
else
|
|
tk = lex();
|
|
} else {
|
|
CError_Error(CErrorStr114);
|
|
}
|
|
|
|
expr = makemonadicnode(expr, ETYPCON);
|
|
expr->rtype = &stvoid;
|
|
} else {
|
|
expr = checkreference(CExpr_ParseNameResultExpr(&pr, expr, 0, 0));
|
|
}
|
|
}
|
|
goto loop;
|
|
}
|
|
if (!IS_TYPE_STRUCT(expr->rtype) || TYPE_STRUCT(expr->rtype)->stype > STRUCT_TYPE_MAX) {
|
|
if (copts.cplusplus && (subexpr = CExpr_DummyDestr(expr)))
|
|
return subexpr;
|
|
CError_ErrorSkip(CErrorStr149);
|
|
return expr;
|
|
}
|
|
if (!ENODE_IS(expr, EINDIRECT)) {
|
|
subexpr = CExpr_NewETEMPNode(expr->rtype, 1);
|
|
copy = lalloc(sizeof(ENode));
|
|
*copy = *subexpr;
|
|
|
|
tmp = makemonadicnode(subexpr, EINDIRECT);
|
|
tmp->rtype = expr->rtype;
|
|
|
|
tmp = makediadicnode(tmp, expr, EASS);
|
|
tmp = makediadicnode(tmp, copy, ECOMMA);
|
|
tmp->rtype = copy->rtype;
|
|
|
|
tmp = makemonadicnode(tmp, EINDIRECT);
|
|
tmp->rtype = expr->rtype;
|
|
expr = tmp;
|
|
}
|
|
if ((tk = lex()) != TK_IDENTIFIER) {
|
|
CError_Error(CErrorStr107);
|
|
return expr;
|
|
}
|
|
|
|
member = ismember(TYPE_STRUCT(expr->rtype), tkidentifier);
|
|
if (!member) {
|
|
if (!expr->rtype->size)
|
|
CError_Error(CErrorStr136, expr->rtype, 0);
|
|
else
|
|
CError_Error(CErrorStr150, tkidentifier->name);
|
|
return expr;
|
|
}
|
|
|
|
if (!IS_TYPE_POINTER(expr->data.monadic->rtype)) {
|
|
CError_ErrorSkip(CErrorStr149);
|
|
return expr;
|
|
}
|
|
|
|
expr = checkreference(CClass_AccessMember(expr, member->type, member->qual, member->offset));
|
|
tk = lex();
|
|
goto loop;
|
|
|
|
case TK_INCREMENT:
|
|
tmp = pointer_generation(expr);
|
|
if (copts.cplusplus && CExpr_CheckOperator(TK_INCREMENT, tmp, nullnode(), &conv)) {
|
|
if ((expr = conv.x0)) {
|
|
tk = lex();
|
|
goto loop;
|
|
}
|
|
CError_ASSERT(2952, tmp = conv.left);
|
|
}
|
|
tmp = CExpr_LValue(tmp, 1, 1);
|
|
if (tmp->rtype == TYPE(&stbool)) {
|
|
expr = CExpr_TempModifyExpr(tmp);
|
|
tk = lex();
|
|
} else {
|
|
checkadditive(tmp);
|
|
expr = makemonadicnode(tmp, EPOSTINC);
|
|
tk = lex();
|
|
}
|
|
goto loop;
|
|
|
|
case TK_DECREMENT:
|
|
tmp = pointer_generation(expr);
|
|
if (copts.cplusplus && CExpr_CheckOperator(TK_DECREMENT, tmp, nullnode(), &conv)) {
|
|
if ((expr = conv.x0)) {
|
|
tk = lex();
|
|
goto loop;
|
|
}
|
|
CError_ASSERT(2976, tmp = conv.left);
|
|
}
|
|
tmp = CExpr_LValue(tmp, 1, 1);
|
|
checkadditive(tmp);
|
|
expr = makemonadicnode(tmp, EPOSTDEC);
|
|
tk = lex();
|
|
goto loop;
|
|
}
|
|
|
|
return expr;
|
|
}
|
|
|
|
static ENode *CExpr_ParseSizeof(void) {
|
|
Type *type;
|
|
ENode *expr;
|
|
|
|
type = CExpr_ParseTypeExpression(NULL);
|
|
if (IS_TYPE_CLASS(type) && TYPE_CLASS(type)->sominfo)
|
|
CError_Error(CErrorStr286);
|
|
|
|
if (CTemplTool_IsTemplateArgumentDependentType(type)) {
|
|
expr = CExpr_NewTemplDepENode(TDE_SIZEOF);
|
|
expr->data.templdep.u.typeexpr.type = type;
|
|
return expr;
|
|
}
|
|
|
|
if (type->size == 0) {
|
|
if (copts.gcc_extensions && (IS_TYPE_FUNC(type) || IS_TYPE_VOID(type)))
|
|
return intconstnode(CABI_GetSizeTType(), 1);
|
|
|
|
if (IS_TYPE_CLASS(type) || IS_TYPE_STRUCT(type))
|
|
CError_Error(CErrorStr136, type, 0);
|
|
else
|
|
CError_Error(CErrorStr146);
|
|
}
|
|
|
|
return intconstnode(CABI_GetSizeTType(), type->size);
|
|
}
|
|
|
|
SInt32 scansizeof(void) {
|
|
ENode *expr;
|
|
|
|
expr = CExpr_ParseSizeof();
|
|
if (!ENODE_IS(expr, EINTCONST)) {
|
|
CError_Error(CErrorStr190);
|
|
return 0;
|
|
}
|
|
|
|
return CInt64_GetULong(&expr->data.intval);
|
|
}
|
|
|
|
static ENode *CExpr_ParseAlignof(void) {
|
|
Type *type;
|
|
ENode *expr;
|
|
SInt16 align;
|
|
|
|
type = CExpr_ParseTypeExpression(NULL);
|
|
if (IS_TYPE_CLASS(type) && TYPE_CLASS(type)->sominfo)
|
|
CError_Error(CErrorStr364);
|
|
|
|
if (CTemplTool_IsTemplateArgumentDependentType(type)) {
|
|
expr = CExpr_NewTemplDepENode(TDE_ALIGNOF);
|
|
expr->data.templdep.u.typeexpr.type = type;
|
|
return expr;
|
|
}
|
|
|
|
if (type->size == 0) {
|
|
if (IS_TYPE_CLASS(type) || IS_TYPE_STRUCT(type))
|
|
CError_Error(CErrorStr136, type, 0);
|
|
else
|
|
CError_Error(CErrorStr146);
|
|
}
|
|
|
|
align = CMach_GetTypeAlign(type);
|
|
if (align == 0)
|
|
align = 1;
|
|
|
|
return intconstnode(CABI_GetSizeTType(), align);
|
|
}
|
|
|
|
SInt32 scanalignof(void) {
|
|
ENode *expr;
|
|
|
|
expr = CExpr_ParseAlignof();
|
|
if (!ENODE_IS(expr, EINTCONST)) {
|
|
CError_Error(CErrorStr190);
|
|
return 0;
|
|
}
|
|
|
|
return CInt64_GetULong(&expr->data.intval);
|
|
}
|
|
|
|
static ENode *logicalexpression(ENode *expr) {
|
|
if (copts.cplusplus && copts.booltruefalse)
|
|
expr->rtype = TYPE(&stbool);
|
|
else
|
|
expr->rtype = TYPE(&stsignedint);
|
|
return expr;
|
|
}
|
|
|
|
ENode *getnodeaddress(ENode *expr, Boolean flag) {
|
|
ENode *result;
|
|
Object *obj;
|
|
|
|
if (!ENODE_IS(expr, EINDIRECT)) {
|
|
expr = CExpr_LValue(expr, flag, flag);
|
|
if (!ENODE_IS(expr, EINDIRECT)) {
|
|
if (!flag)
|
|
CError_Error(CErrorStr142);
|
|
return nullnode();
|
|
}
|
|
} else {
|
|
if (flag &&
|
|
ENODE_IS(expr->data.monadic, EOBJREF) &&
|
|
expr->data.monadic->data.objref->name == this_name_node &&
|
|
cscope_currentfunc &&
|
|
cscope_currentclass &&
|
|
expr->data.monadic->data.objref == CClass_ThisSelfObject())
|
|
CError_Error(CErrorStr189);
|
|
}
|
|
|
|
result = lalloc(sizeof(ENode));
|
|
*result = *expr;
|
|
restart:
|
|
switch (result->data.monadic->type) {
|
|
case EPOSTINC:
|
|
case EPOSTDEC:
|
|
case EPREINC:
|
|
case EPREDEC:
|
|
result->type = ETYPCON;
|
|
if (IS_TYPE_POINTER_ONLY(result->rtype))
|
|
result->flags = TPTR_QUAL(result->rtype) & ENODE_FLAG_QUALS;
|
|
result->rtype = CDecl_NewPointerType(result->rtype);
|
|
return result;
|
|
case EOBJREF:
|
|
obj = result->data.monadic->data.objref;
|
|
if (obj->datatype == DALIAS) {
|
|
CExpr_AliasTransform(result->data.monadic);
|
|
goto restart;
|
|
}
|
|
if (obj->datatype == DINLINEFUNC)
|
|
CError_Error(CErrorStr175);
|
|
obj->flags |= OBJECT_FLAGS_2;
|
|
if (flag && !copts.cplusplus && obj->sclass == TK_REGISTER)
|
|
CError_Error(CErrorStr163);
|
|
break;
|
|
case EFUNCCALL:
|
|
if (flag && !IS_TYPE_POINTER_ONLY(result->data.monadic->data.funccall.functype->functype))
|
|
CError_Warning(CErrorStr142);
|
|
break;
|
|
case EBITFIELD:
|
|
CError_Error(CErrorStr144);
|
|
return nullnode();
|
|
}
|
|
|
|
switch (result->rtype->type) {
|
|
case TYPEPOINTER:
|
|
result->data.monadic->rtype = CDecl_NewPointerType(result->rtype);
|
|
result->data.monadic->flags = result->flags;
|
|
break;
|
|
default:
|
|
result->data.monadic->rtype = CDecl_NewPointerType(result->rtype);
|
|
result->data.monadic->flags = result->flags;
|
|
}
|
|
|
|
return result->data.monadic;
|
|
}
|
|
|
|
static ENode *CExpr_MakeStaticMemberList(NameSpaceObjectList *list) {
|
|
NameSpaceObjectList *newlist;
|
|
NameSpaceObjectList *n;
|
|
ENode *result;
|
|
|
|
newlist = NULL;
|
|
while (list) {
|
|
if (list->object->otype == OT_OBJECT && IS_TYPE_STATIC_METHOD(OBJECT(list->object)->type)) {
|
|
n = galloc(sizeof(NameSpaceObjectList));
|
|
*n = *list;
|
|
n->next = newlist;
|
|
newlist = n;
|
|
}
|
|
list = list->next;
|
|
}
|
|
|
|
if (!newlist) {
|
|
CError_Warning(CErrorStr331);
|
|
return nullnode();
|
|
}
|
|
|
|
result = CExpr_NewENode(EOBJLIST);
|
|
result->rtype = OBJECT(newlist->object)->type;
|
|
result->data.objlist.list = newlist;
|
|
return result;
|
|
}
|
|
|
|
static ENode *CExpr_MakePTDM(ENode *expr) {
|
|
ENode *result;
|
|
|
|
CError_ASSERT(3414, ENODE_IS(expr, EMEMBER) && expr->data.emember->list->object->otype == OT_MEMBERVAR);
|
|
|
|
result = nullnode();
|
|
result->rtype = CExpr_NewPTMType(expr->data.emember, NULL);
|
|
CInt64_SetLong(&result->data.intval, OBJ_MEMBER_VAR(expr->data.emember->list->object)->offset + 1);
|
|
return result;
|
|
}
|
|
|
|
ENode *getpointertomemberfunc(ENode *expr, Type *type, Boolean flag) {
|
|
NameSpaceObjectList *list;
|
|
Object *obj;
|
|
Object *dataobj;
|
|
Type *ptmtype;
|
|
TypeMemberFunc *tmethod;
|
|
OLinkList *olist;
|
|
SInt32 data[3];
|
|
|
|
CError_ASSERT(3442, ENODE_IS(expr, EMEMBER));
|
|
|
|
if (expr->data.emember->expr && !copts.cpp_extensions)
|
|
CError_Error(CErrorStr141);
|
|
|
|
if (!copts.cpp_extensions) {
|
|
if (!(expr->data.emember->x11 && expr->data.emember->pr_1D)) {
|
|
if (type && IS_TYPE_MEMBERPOINTER(type))
|
|
CError_Warning(CErrorStr331);
|
|
}
|
|
}
|
|
|
|
if (expr->data.emember->list->next) {
|
|
if (type) {
|
|
if (IS_TYPE_MEMBERPOINTER(type)) {
|
|
type = TYPE_MEMBER_POINTER(type)->ty1;
|
|
for (list = expr->data.emember->list; list; list = list->next) {
|
|
if (list->object->otype == OT_OBJECT && is_memberpointerequal(OBJECT(list->object)->type, type)) {
|
|
obj = OBJECT(list->object);
|
|
break;
|
|
}
|
|
}
|
|
if (!list) {
|
|
CError_Error(CErrorStr146);
|
|
return nullnode();
|
|
}
|
|
} else {
|
|
return CExpr_MakeStaticMemberList(expr->data.emember->list);
|
|
}
|
|
} else {
|
|
obj = OBJECT(expr->data.emember->list->object);
|
|
}
|
|
} else {
|
|
obj = OBJECT(expr->data.emember->list->object);
|
|
}
|
|
|
|
while (obj->datatype == DALIAS)
|
|
obj = obj->u.alias.object;
|
|
|
|
CError_ASSERT(3503, obj->otype == OT_OBJECT && IS_TYPE_NONSTATIC_METHOD(obj->type));
|
|
|
|
if (TYPE_FUNC(obj->type)->flags & FUNC_FLAGS_100000)
|
|
CError_Error(CErrorStr190);
|
|
|
|
ptmtype = CExpr_NewPTMType(expr->data.emember, obj);
|
|
tmethod = TYPE_METHOD(obj->type);
|
|
dataobj = CParser_NewGlobalDataObject(NULL);
|
|
dataobj->name = CParser_GetUniqueName();
|
|
dataobj->nspace = cscope_root;
|
|
dataobj->type = ptmtype;
|
|
dataobj->sclass = TK_STATIC;
|
|
|
|
if (flag) {
|
|
data[0] = 0;
|
|
if (obj->datatype == DVFUNC) {
|
|
olist = NULL;
|
|
data[1] = tmethod->x1E;
|
|
data[2] = tmethod->theclass->vtable->offset;
|
|
} else {
|
|
data[1] = -1;
|
|
data[2] = 0;
|
|
olist = galloc(sizeof(OLinkList));
|
|
olist->next = NULL;
|
|
olist->obj = obj;
|
|
olist->somevalue = 0;
|
|
olist->offset = 8;
|
|
}
|
|
CInit_DeclareData(dataobj, data, olist, dataobj->type->size);
|
|
}
|
|
|
|
return create_objectnode(dataobj);
|
|
}
|
|
|
|
static ENode *getpointertomember(ENode *expr) {
|
|
CError_ASSERT(3554, ENODE_IS(expr, EMEMBER));
|
|
|
|
if (expr->data.emember->expr)
|
|
CError_Error(CErrorStr141);
|
|
|
|
expr->data.emember->x11 = 1;
|
|
if (!expr->data.emember->list->next) {
|
|
if (expr->data.emember->list->object->otype == OT_MEMBERVAR)
|
|
return CExpr_MakePTDM(expr);
|
|
else
|
|
return getpointertomemberfunc(expr, NULL, 1);
|
|
}
|
|
|
|
return expr;
|
|
}
|
|
|
|
ENode *CExpr_New_ELOGNOT_Node(ENode *input) {
|
|
ENode *expr;
|
|
Conversion conv;
|
|
|
|
if (IS_TYPE_TEMPLDEPEXPR(input->rtype))
|
|
return CTempl_MakeTemplDepExpr(NULL, ELOGNOT, input);
|
|
|
|
expr = pointer_generation(input);
|
|
if (copts.cplusplus && CExpr_CheckOperator('!', expr, NULL, &conv)) {
|
|
if ((input = conv.x0))
|
|
return input;
|
|
CError_ASSERT(3593, expr = conv.left);
|
|
}
|
|
|
|
switch (expr->rtype->type) {
|
|
case TYPEINT:
|
|
case TYPEFLOAT:
|
|
case TYPEPOINTER:
|
|
case TYPEARRAY:
|
|
break;
|
|
case TYPEENUM:
|
|
expr = forceintegral(expr);
|
|
break;
|
|
case TYPEMEMBERPOINTER:
|
|
expr = CExpr_ConvertToCondition(expr);
|
|
break;
|
|
default:
|
|
CError_Error(CErrorStr144);
|
|
return expr;
|
|
}
|
|
|
|
switch (expr->type) {
|
|
case EINTCONST:
|
|
expr->data.intval = CInt64_Not(expr->data.intval);
|
|
break;
|
|
case EFLOATCONST:
|
|
expr->type = EINTCONST;
|
|
CInt64_SetLong(&expr->data.intval, CMach_FloatIsZero(expr->data.floatval));
|
|
break;
|
|
default:
|
|
expr = makemonadicnode(expr, ELOGNOT);
|
|
}
|
|
|
|
return logicalexpression(expr);
|
|
}
|
|
|
|
ENode *CExpr_New_EMONMIN_Node(ENode *input) {
|
|
ENode *expr;
|
|
Conversion conv;
|
|
|
|
if (IS_TYPE_TEMPLDEPEXPR(input->rtype))
|
|
return CTempl_MakeTemplDepExpr(NULL, EMONMIN, input);
|
|
|
|
expr = pointer_generation(input);
|
|
if (copts.cplusplus && CExpr_CheckOperator('-', expr, NULL, &conv)) {
|
|
if ((input = conv.x0))
|
|
return input;
|
|
CError_ASSERT(3652, expr = conv.left);
|
|
}
|
|
|
|
switch (expr->rtype->type) {
|
|
case TYPEINT:
|
|
case TYPEENUM:
|
|
expr = integralpromote(expr);
|
|
if (ENODE_IS(expr, EINTCONST)) {
|
|
expr->data.intval = CMach_CalcIntMonadic(expr->rtype, '-', expr->data.intval);
|
|
return expr;
|
|
}
|
|
return makemonadicnode(expr, EMONMIN);
|
|
case TYPEFLOAT:
|
|
if (ENODE_IS(expr, EFLOATCONST)) {
|
|
expr->data.floatval = CMach_CalcFloatMonadic(expr->rtype, '-', expr->data.floatval);
|
|
return expr;
|
|
}
|
|
return CExpr_UnaryFloatExpression(makemonadicnode(expr, EMONMIN));
|
|
default:
|
|
CError_Error(CErrorStr144);
|
|
return expr;
|
|
}
|
|
}
|
|
|
|
ENode *CExpr_New_EBINNOT_Node(ENode *input) {
|
|
ENode *expr;
|
|
Conversion conv;
|
|
|
|
if (IS_TYPE_TEMPLDEPEXPR(input->rtype))
|
|
return CTempl_MakeTemplDepExpr(NULL, EBINNOT, input);
|
|
|
|
expr = pointer_generation(input);
|
|
if (copts.cplusplus && CExpr_CheckOperator('~', expr, NULL, &conv)) {
|
|
if ((input = conv.x0))
|
|
return input;
|
|
CError_ASSERT(3702, expr = conv.left);
|
|
}
|
|
|
|
expr = integralpromote(expr);
|
|
|
|
if (ENODE_IS(expr, EINTCONST)) {
|
|
expr->data.intval = CMach_CalcIntMonadic(expr->rtype, '~', expr->data.intval);
|
|
return expr;
|
|
}
|
|
return makemonadicnode(expr, EBINNOT);
|
|
}
|
|
|
|
ENode *unary_expression(void) {
|
|
ENode *expr;
|
|
ENode *tmp;
|
|
Conversion conv;
|
|
|
|
switch (tk) {
|
|
case TK_COLON_COLON:
|
|
switch (lookahead()) {
|
|
case TK_NEW:
|
|
tk = lex();
|
|
return scannew(1);
|
|
case TK_DELETE:
|
|
tk = lex();
|
|
return scandelete(1);
|
|
}
|
|
return postfix_expression(0);
|
|
|
|
case TK_NEW:
|
|
return scannew(0);
|
|
case TK_DELETE:
|
|
return scandelete(0);
|
|
case TK_INCREMENT:
|
|
tk = lex();
|
|
if (copts.cplusplus) {
|
|
expr = pointer_generation(cast_expression());
|
|
if (CExpr_CheckOperator(TK_INCREMENT, expr, NULL, &conv)) {
|
|
if (conv.x0)
|
|
return conv.x0;
|
|
CError_ASSERT(3748, expr = conv.left);
|
|
}
|
|
} else {
|
|
expr = pointer_generation(unary_expression());
|
|
}
|
|
expr = CExpr_LValue(expr, 1, 1);
|
|
if (expr->rtype == TYPE(&stbool)) {
|
|
tmp = nullnode();
|
|
tmp->rtype = TYPE(&stbool);
|
|
CInt64_SetLong(&tmp->data.intval, 1);
|
|
return makediadicnode(expr, tmp, EASS);
|
|
} else {
|
|
checkadditive(expr);
|
|
return makemonadicnode(expr, EPREINC);
|
|
}
|
|
case TK_DECREMENT:
|
|
tk = lex();
|
|
if (copts.cplusplus) {
|
|
expr = pointer_generation(cast_expression());
|
|
if (CExpr_CheckOperator(TK_DECREMENT, expr, NULL, &conv)) {
|
|
if (conv.x0)
|
|
return conv.x0;
|
|
CError_ASSERT(3776, expr = conv.left);
|
|
}
|
|
} else {
|
|
expr = pointer_generation(unary_expression());
|
|
}
|
|
expr = CExpr_LValue(expr, 1, 1);
|
|
checkadditive(expr);
|
|
return makemonadicnode(expr, EPREDEC);
|
|
|
|
case '&':
|
|
if (copts.cplusplus) {
|
|
switch ((tk = lex())) {
|
|
case TK_IDENTIFIER:
|
|
case TK_INHERITED:
|
|
case TK_COLON_COLON:
|
|
expr = postfix_expression(1);
|
|
if (ENODE_IS(expr, EMEMBER))
|
|
return getpointertomember(expr);
|
|
break;
|
|
default:
|
|
expr = cast_expression();
|
|
}
|
|
|
|
if (CExpr_CheckOperator('&', expr, NULL, &conv)) {
|
|
CError_ASSERT(3809, conv.x0);
|
|
return conv.x0;
|
|
}
|
|
} else {
|
|
tk = lex();
|
|
expr = cast_expression();
|
|
}
|
|
|
|
if (copts.mpwc_relax && !copts.cplusplus && IS_TYPE_ARRAY(expr->rtype) && ENODE_IS(expr, EINDIRECT))
|
|
return pointer_generation(expr);
|
|
if (ENODE_IS(expr, EOBJLIST))
|
|
return expr;
|
|
|
|
if (IS_TYPE_TEMPLDEPEXPR(expr->rtype)) {
|
|
tmp = CExpr_NewTemplDepENode(TDE_ADDRESS_OF);
|
|
tmp->data.templdep.u.monadic = expr;
|
|
return tmp;
|
|
}
|
|
|
|
return getnodeaddress(expr, 1);
|
|
|
|
case '*':
|
|
tk = lex();
|
|
expr = pointer_generation(cast_expression());
|
|
if (copts.cplusplus && CExpr_CheckOperator('*', expr, NULL, &conv)) {
|
|
if (conv.x0)
|
|
return conv.x0;
|
|
CError_ASSERT(3840, expr = conv.left);
|
|
}
|
|
|
|
if (!IS_TYPE_POINTER(expr->rtype)) {
|
|
CError_Error(CErrorStr148);
|
|
return expr;
|
|
}
|
|
|
|
tmp = makemonadicnode(expr, EINDIRECT);
|
|
CDecl_CompleteType(tmp->rtype = TPTR_TARGET(tmp->rtype));
|
|
return tmp;
|
|
|
|
case '+':
|
|
tk = lex();
|
|
expr = pointer_generation(cast_expression());
|
|
if (copts.cplusplus && CExpr_CheckOperator('+', expr, NULL, &conv)) {
|
|
if (conv.x0)
|
|
return conv.x0;
|
|
CError_ASSERT(3852, expr = conv.left);
|
|
}
|
|
|
|
switch (expr->rtype->type) {
|
|
case TYPEINT:
|
|
case TYPEENUM:
|
|
return integralpromote(expr);
|
|
case TYPEFLOAT:
|
|
case TYPEPOINTER:
|
|
case TYPEARRAY:
|
|
return expr;
|
|
default:
|
|
CError_Error(CErrorStr144);
|
|
return expr;
|
|
}
|
|
|
|
case '-':
|
|
tk = lex();
|
|
return CExpr_New_EMONMIN_Node(cast_expression());
|
|
case '~':
|
|
tk = lex();
|
|
return CExpr_New_EBINNOT_Node(cast_expression());
|
|
case '!':
|
|
tk = lex();
|
|
return CExpr_New_ELOGNOT_Node(cast_expression());
|
|
|
|
case TK_SIZEOF:
|
|
return CExpr_ParseSizeof();
|
|
case TK_UU_ALIGNOF_UU:
|
|
return CExpr_ParseAlignof();
|
|
|
|
case TK_LOGICAL_AND:
|
|
if (copts.ANSIstrict)
|
|
break;
|
|
|
|
if ((tk = lex()) != TK_IDENTIFIER) {
|
|
CError_Error(CErrorStr107);
|
|
return nullnode();
|
|
}
|
|
|
|
expr = lalloc(sizeof(ENode));
|
|
expr->type = ELABEL;
|
|
expr->cost = 0;
|
|
expr->flags = 0;
|
|
expr->rtype = TYPE(&void_ptr);
|
|
expr->data.label = findlabel();
|
|
if (!expr->data.label) {
|
|
expr->data.label = newlabel();
|
|
expr->data.label->name = tkidentifier;
|
|
expr->data.label->next = Labels;
|
|
Labels = expr->data.label;
|
|
}
|
|
tk = lex();
|
|
return expr;
|
|
}
|
|
|
|
return postfix_expression(0);
|
|
}
|
|
|
|
ENode *do_castnullcheck(ENode *condexpr, ENode *nullcheckexpr) {
|
|
ENode *result;
|
|
|
|
if (isnotzero(nullcheckexpr))
|
|
return condexpr;
|
|
|
|
result = lalloc(sizeof(ENode));
|
|
*result = *condexpr;
|
|
result->type = ENULLCHECK;
|
|
result->data.nullcheck.nullcheckexpr = lalloc(sizeof(ENode));
|
|
*result->data.nullcheck.nullcheckexpr = *nullcheckexpr;
|
|
result->data.nullcheck.condexpr = condexpr;
|
|
result->data.nullcheck.precompid = CParser_GetUniqueID();
|
|
|
|
nullcheckexpr->type = EPRECOMP;
|
|
nullcheckexpr->data.precompid = result->data.nullcheck.precompid;
|
|
|
|
return result;
|
|
}
|
|
|
|
ENode *CExpr_SafeClassPointerCast(ENode *expr, TypeClass *a, TypeClass *b, Boolean typconflag, Boolean pathcheckflag) {
|
|
ENode *result;
|
|
|
|
result = CClass_ClassPointerCast(expr, a, b, typconflag, 1, pathcheckflag);
|
|
if (result != expr) {
|
|
if (!(ENODE_IS(result, ETYPCON) && result->data.monadic == expr))
|
|
result = do_castnullcheck(result, expr);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
ENode *PointerToMemberCast(ENode *expr, TypeMemberPointer *tm1, TypeMemberPointer *tm2, Boolean flag) {
|
|
BClassList *path;
|
|
Boolean negate;
|
|
short depth;
|
|
Boolean isambig;
|
|
SInt32 pathoffset;
|
|
CInt64 pathoffset64;
|
|
ENode *tmp;
|
|
|
|
CError_ASSERT(3984, IS_TYPE_CLASS(tm1->ty2));
|
|
CError_ASSERT(3985, IS_TYPE_CLASS(tm2->ty2));
|
|
|
|
if (tm1->ty2 == tm2->ty2) {
|
|
expr->rtype = TYPE(tm2);
|
|
return expr;
|
|
}
|
|
|
|
negate = 0;
|
|
path = CClass_GetBasePath(TYPE_CLASS(tm2->ty2), TYPE_CLASS(tm1->ty2), &depth, &isambig);
|
|
if (!path) {
|
|
path = CClass_GetBasePath(TYPE_CLASS(tm1->ty2), TYPE_CLASS(tm2->ty2), &depth, &isambig);
|
|
if (!path)
|
|
goto failed;
|
|
negate = 1;
|
|
}
|
|
|
|
if (isambig)
|
|
CError_Error(CErrorStr188);
|
|
|
|
if ((pathoffset = CClass_GetPathOffset(path)) < 0)
|
|
goto failed;
|
|
if (negate)
|
|
pathoffset = -pathoffset;
|
|
|
|
if (flag)
|
|
CClass_CheckPathAccess(path, NULL, ACCESSPUBLIC);
|
|
|
|
if (tm1->size != tm2->size) {
|
|
failed:
|
|
CError_Error(CErrorStr247, tm1, 0, tm2, 0);
|
|
return nullnode();
|
|
}
|
|
|
|
if (!pathoffset) {
|
|
expr->rtype = TYPE(tm2);
|
|
return expr;
|
|
}
|
|
|
|
if (tm1->size == 4u) {
|
|
if (ENODE_IS(expr, EINTCONST)) {
|
|
if (!CInt64_IsZero(&expr->data.intval)) {
|
|
CInt64_SetLong(&pathoffset64, pathoffset);
|
|
expr->data.intval = CInt64_Add(expr->data.intval, pathoffset64);
|
|
}
|
|
expr->rtype = TYPE(tm2);
|
|
return expr;
|
|
} else {
|
|
expr->rtype = TYPE(&stunsignedlong);
|
|
tmp = intconstnode(TYPE(&stunsignedlong), pathoffset);
|
|
tmp = makediadicnode(expr, tmp, EADD);
|
|
tmp = makemonadicnode(tmp, ETYPCON);
|
|
tmp->rtype = TYPE(tm2);
|
|
return do_castnullcheck(tmp, expr);
|
|
}
|
|
} else {
|
|
tmp = create_temp_node(TYPE(&ptmstruct));
|
|
expr = getnodeaddress(expr, 0);
|
|
tmp = funccallexpr(rt_ptmf_cast, intconstnode(TYPE(&stsignedlong), pathoffset), expr, tmp, NULL);
|
|
tmp = makemonadicnode(tmp, EINDIRECT);
|
|
tmp->rtype = TYPE(tm2);
|
|
return tmp;
|
|
}
|
|
}
|
|
|
|
ENode *CExpr_MemberPointerConversion(ENode *expr, TypeMemberPointer *type, Boolean flag1) {
|
|
if (ENODE_IS(expr, EINTCONST) && CInt64_IsZero(&expr->data.intval)) {
|
|
if (IS_TYPE_FUNC(type->ty1))
|
|
expr = create_objectnode(rt_ptmf_null);
|
|
expr->rtype = TYPE(type);
|
|
} else if (ENODE_IS(expr, EMEMBER)) {
|
|
expr = getpointertomemberfunc(expr, TYPE(type), flag1);
|
|
}
|
|
|
|
return expr;
|
|
}
|
|
|
|
static ENode *CExpr_MemberPointerCast(ENode *expr, TypeMemberPointer *type, UInt32 qual) {
|
|
if (!IS_TYPE_MEMBERPOINTER(expr->rtype))
|
|
expr = CExpr_MemberPointerConversion(expr, type, 1);
|
|
|
|
if (!IS_TYPE_MEMBERPOINTER(expr->rtype)) {
|
|
CError_Error(CErrorStr164);
|
|
return nullnode();
|
|
}
|
|
|
|
expr = PointerToMemberCast(expr, TYPE_MEMBER_POINTER(expr->rtype), type, 0);
|
|
expr->flags = qual & ENODE_FLAG_QUALS;
|
|
return expr;
|
|
}
|
|
|
|
ENode *do_typecast(ENode *expr, Type *type, UInt32 qual) {
|
|
TypePointer *tptr;
|
|
ENode *tmp;
|
|
UInt32 flags;
|
|
|
|
if (!copts.old_argmatch)
|
|
return CExpr_Convert(expr, type, qual, 1, 0);
|
|
|
|
if (copts.cpp_extensions && is_typesame(expr->rtype, type) && !ENODE_IS(expr, EOBJLIST)) {
|
|
expr->rtype = type;
|
|
expr->flags &= ~ENODE_FLAG_QUALS;
|
|
expr->flags |= qual & ENODE_FLAG_QUALS;
|
|
return expr;
|
|
}
|
|
|
|
switch (type->type) {
|
|
case TYPEARRAY:
|
|
CError_Error(CErrorStr247, expr->rtype, ENODE_QUALS(expr), type, qual);
|
|
return expr;
|
|
case TYPEMEMBERPOINTER:
|
|
if (!IS_TYPE_CLASS(expr->rtype))
|
|
return CExpr_MemberPointerCast(expr, TYPE_MEMBER_POINTER(type), qual);
|
|
}
|
|
|
|
flags = qual & ENODE_FLAG_QUALS;
|
|
|
|
if (ENODE_IS(expr, EOBJLIST))
|
|
return CExpr_AssignmentPromotion(expr, type, flags, 1);
|
|
|
|
if (ENODE_IS(expr, EOBJREF) && IS_TYPE_NONSTATIC_METHOD(expr->data.objref->type)) {
|
|
CError_Error(CErrorStr221);
|
|
return nullnode();
|
|
}
|
|
|
|
if (type == &stvoid) {
|
|
expr = makemonadicnode(expr, ETYPCON);
|
|
expr->rtype = type;
|
|
expr->flags = flags;
|
|
return expr;
|
|
}
|
|
|
|
if (IS_TYPE_REFERENCE(type)) {
|
|
tmp = getnodeaddress(expr, 0);
|
|
tptr = galloc(sizeof(TypePointer));
|
|
*tptr = *TYPE_POINTER(type);
|
|
tptr->qual &= ~Q_REFERENCE;
|
|
|
|
tmp = do_typecast(tmp, TYPE(tptr), qual);
|
|
tmp = makemonadicnode(tmp, EINDIRECT);
|
|
tmp->rtype = TPTR_TARGET(type);
|
|
tmp->flags = flags;
|
|
return tmp;
|
|
}
|
|
|
|
if (IS_TYPE_CLASS(expr->rtype) || IS_TYPE_CLASS(type)) {
|
|
if (expr->rtype->size == 0)
|
|
CDecl_CompleteType(expr->rtype);
|
|
|
|
if (expr->rtype == type && !CClass_CopyConstructor(TYPE_CLASS(type)))
|
|
return expr;
|
|
|
|
if (user_assign_check(expr, type, qual, 1, 1, 1)) {
|
|
assign_node->flags = flags;
|
|
return assign_node;
|
|
}
|
|
|
|
CError_Error(CErrorStr247, expr->rtype, ENODE_QUALS(expr), type, qual);
|
|
return nullnode();
|
|
}
|
|
|
|
if (IS_TYPE_STRUCT(type) && copts.cplusplus && is_typesame(expr->rtype, type)) {
|
|
expr->rtype = type;
|
|
expr->flags = flags;
|
|
return expr;
|
|
}
|
|
|
|
if (type == TYPE(&stbool)) {
|
|
expr = CExpr_ConvertToBool(expr, 1);
|
|
expr->flags = flags;
|
|
return expr;
|
|
}
|
|
|
|
if (IS_TYPE_ENUM(type)) {
|
|
tmp = do_typecast(expr, TYPE_ENUM(type)->enumtype, qual);
|
|
if (!ENODE_IS(tmp, EINTCONST))
|
|
tmp = makemonadicnode(tmp, ETYPCON);
|
|
tmp->rtype = type;
|
|
tmp->flags = flags;
|
|
return tmp;
|
|
}
|
|
|
|
if (IS_TYPE_INT_OR_FLOAT(type)) {
|
|
if (ENODE_IS(expr, ETYPCON) && expr->rtype->type == type->type && expr->rtype->size == type->size) {
|
|
if (is_unsigned(expr->rtype) == is_unsigned(type) && ENODE_QUALS(expr) == qual) {
|
|
expr->rtype = type;
|
|
expr->flags |= ENODE_FLAG_80;
|
|
return expr;
|
|
}
|
|
}
|
|
|
|
if (IS_TYPE_ENUM(expr->rtype))
|
|
expr = forceintegral(expr);
|
|
|
|
if (IS_TYPE_INT_OR_FLOAT(expr->rtype)) {
|
|
expr = promote(expr, type);
|
|
expr->flags = flags;
|
|
return expr;
|
|
}
|
|
|
|
if (!(IS_TYPE_POINTER_ONLY(expr->rtype) && !IS_TYPE_FLOAT(type)))
|
|
CError_Error(CErrorStr247, expr->rtype, ENODE_QUALS(expr), type, qual);
|
|
|
|
if (ENODE_IS(expr, ETYPCON) && ENODE_IS(tmp = expr->data.monadic, EINTCONST)) {
|
|
tmp->rtype = type;
|
|
tmp->flags = flags;
|
|
tmp->data.intval = CExpr_IntConstConvert(type, TYPE(&stunsignedlong), tmp->data.intval);
|
|
return tmp;
|
|
}
|
|
|
|
if (type->size != 4) {
|
|
expr = makemonadicnode(expr, ETYPCON);
|
|
expr->rtype = TYPE(&stunsignedlong);
|
|
}
|
|
|
|
expr = makemonadicnode(expr, ETYPCON);
|
|
expr->rtype = type;
|
|
expr->flags = flags;
|
|
return expr;
|
|
}
|
|
|
|
if (IS_TYPE_POINTER(type)) {
|
|
if (IS_TYPE_POINTER(expr->rtype)) {
|
|
if (IS_TYPE_CLASS(TPTR_TARGET(expr->rtype)) && IS_TYPE_CLASS(TPTR_TARGET(type)))
|
|
expr = CExpr_SafeClassPointerCast(expr, TYPE_CLASS(TPTR_TARGET(expr->rtype)), TYPE_CLASS(TPTR_TARGET(type)), 1, 0);
|
|
|
|
if (!ENODE_IS(expr, ETYPCON))
|
|
expr = makemonadicnode(expr, ETYPCON);
|
|
|
|
expr->rtype = type;
|
|
expr->flags = flags;
|
|
return expr;
|
|
}
|
|
|
|
if (!IS_TYPE_INT(expr->rtype)) {
|
|
if (!IS_TYPE_ENUM(expr->rtype)) {
|
|
CError_Error(CErrorStr247, expr->rtype, ENODE_QUALS(expr), type, qual);
|
|
return expr;
|
|
}
|
|
expr = forceintegral(expr);
|
|
}
|
|
|
|
if (expr->rtype->size != 4) {
|
|
if (!ENODE_IS(expr, EINTCONST))
|
|
expr = makemonadicnode(expr, ETYPCON);
|
|
expr->rtype = TYPE(&stunsignedlong);
|
|
}
|
|
|
|
expr = makemonadicnode(expr, ETYPCON);
|
|
expr->rtype = type;
|
|
expr->flags = flags;
|
|
return expr;
|
|
}
|
|
|
|
if ((tmp = CodeGen_HandleTypeCast(expr, type, qual)))
|
|
return tmp;
|
|
|
|
CError_Error(CErrorStr247, expr->rtype, ENODE_QUALS(expr), type, qual);
|
|
return nullnode();
|
|
}
|
|
|
|
static Boolean isvectorconst(ENode *node) {
|
|
if (ENODE_IS3(node, ECOMMA, EINTCONST, EFLOATCONST))
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
ENode *cast_expression(void) {
|
|
ENode *expr;
|
|
ENode *tmp;
|
|
ENodeList *args;
|
|
MWVector128 vec;
|
|
DeclInfo di;
|
|
|
|
if (!(tk == '(' && islookaheaddeclaration()))
|
|
return unary_expression();
|
|
tk = lex();
|
|
|
|
memclrw(&di, sizeof(DeclInfo));
|
|
CParser_GetDeclSpecs(&di, 0);
|
|
scandeclarator(&di);
|
|
|
|
if (tk != ')')
|
|
CError_ErrorSkip(CErrorStr115);
|
|
else
|
|
tk = lex();
|
|
|
|
if (di.name)
|
|
CError_Error(CErrorStr164);
|
|
|
|
if (copts.altivec_model && tk == '(' && IS_TYPE_VECTOR(di.thetype)) {
|
|
tk = lex();
|
|
expr = s_expression();
|
|
if (tk != ')')
|
|
CError_ErrorSkip(CErrorStr115);
|
|
else
|
|
tk = lex();
|
|
|
|
if (CodeGen_CollapseVectorExpression(expr, &vec, di.thetype)) {
|
|
tmp = lalloc(sizeof(ENode));
|
|
tmp->type = EVECTOR128CONST;
|
|
if ((tmp->cost = expr->cost) == 0)
|
|
tmp->cost = 1;
|
|
tmp->flags = ENODE_QUALS(expr);
|
|
tmp->rtype = di.thetype;
|
|
tmp->data.vector128val = vec;
|
|
} else {
|
|
tmp = makemonadicnode(expr, ETYPCON);
|
|
}
|
|
tmp->rtype = di.thetype;
|
|
tmp->flags = expr->flags;
|
|
return tmp;
|
|
}
|
|
|
|
if (tk == '{' && (!copts.ANSIstrict || copts.c9x) && !IS_TYPE_VECTOR(di.thetype))
|
|
return CInit_AutoObject(NULL, di.thetype, di.qual);
|
|
|
|
expr = cast_expression();
|
|
if (copts.cplusplus && (CTemplTool_IsTemplateArgumentDependentType(di.thetype) ||
|
|
CTemplTool_IsTemplateArgumentDependentExpression(expr))) {
|
|
args = lalloc(sizeof(ENodeList));
|
|
args->next = NULL;
|
|
args->node = expr;
|
|
return CExpr_TemplArgDepCast(di.thetype, di.qual, args);
|
|
}
|
|
|
|
if (!IS_TYPE_REFERENCE(di.thetype))
|
|
expr = pointer_generation(expr);
|
|
return do_typecast(expr, di.thetype, di.qual);
|
|
}
|
|
|
|
static ENode *pm_expression(void) {
|
|
ENode *left;
|
|
ENode *right;
|
|
ENode *tmp;
|
|
Type *type;
|
|
UInt32 qual;
|
|
short flags;
|
|
Conversion conv;
|
|
|
|
left = cast_expression();
|
|
restart:
|
|
switch (tk) {
|
|
case TK_ARROW_STAR:
|
|
left = pointer_generation(left);
|
|
tk = lex();
|
|
right = pointer_generation(cast_expression());
|
|
|
|
if (CExpr_CheckOperator(TK_ARROW_STAR, left, right, &conv)) {
|
|
CError_ASSERT(4457, left = conv.x0);
|
|
goto restart;
|
|
}
|
|
|
|
if (!IS_TYPE_POINTER(left->rtype)) {
|
|
CError_Error(CErrorStr148);
|
|
return left;
|
|
}
|
|
|
|
left = makemonadicnode(left, EINDIRECT);
|
|
left->rtype = TPTR_TARGET(left->rtype);
|
|
goto common_part;
|
|
case TK_DOT_STAR:
|
|
left = pointer_generation(left);
|
|
tk = lex();
|
|
right = pointer_generation(cast_expression());
|
|
if (!ENODE_IS(left, EINDIRECT)) {
|
|
CError_Error(CErrorStr142);
|
|
return left;
|
|
}
|
|
common_part:
|
|
if (!IS_TYPE_CLASS(left->rtype)) {
|
|
CError_Error(CErrorStr149);
|
|
return left;
|
|
}
|
|
if (!IS_TYPE_MEMBERPOINTER(right->rtype)) {
|
|
CError_Error(CErrorStr144);
|
|
return left;
|
|
}
|
|
if (left->rtype != TYPE_MEMBER_POINTER(right->rtype)->ty2) {
|
|
if (CClass_IsBaseClass(TYPE_CLASS(left->rtype), TYPE_CLASS(TYPE_MEMBER_POINTER(right->rtype)->ty2), NULL, 1, 1)) {
|
|
left->data.monadic = CClass_ClassPointerCast(
|
|
left->data.monadic,
|
|
TYPE_CLASS(left->rtype),
|
|
TYPE_CLASS(TYPE_MEMBER_POINTER(right->rtype)->ty2),
|
|
0, 1, 1);
|
|
left->rtype = TYPE_MEMBER_POINTER(right->rtype)->ty2;
|
|
} else {
|
|
CError_Error(CErrorStr146);
|
|
return left;
|
|
}
|
|
}
|
|
type = CClass_CombineClassAccessQualifiers(
|
|
TYPE_MEMBER_POINTER(right->rtype)->ty1,
|
|
ENODE_QUALS(right),
|
|
left->flags,
|
|
&qual);
|
|
flags = qual;
|
|
if (!IS_TYPE_FUNC(type)) {
|
|
if (!ENODE_IS(right, EINTCONST)) {
|
|
if (!canadd(left->data.monadic, -1)) {
|
|
left->data.monadic = makediadicnode(left->data.monadic, nullnode(), EADD);
|
|
CInt64_SetLong(&left->data.monadic->data.diadic.right->data.intval, -1);
|
|
optimizecomm(left->data.monadic);
|
|
}
|
|
right->rtype = TYPE(&stunsignedlong);
|
|
left->data.monadic = makediadicnode(left->data.monadic, right, EADD);
|
|
optimizecomm(left->data.monadic);
|
|
} else {
|
|
right->data.intval = CInt64_Sub(right->data.intval, cint64_one);
|
|
if (!canadd2(left->data.monadic, right->data.intval)) {
|
|
right->rtype = TYPE(&stunsignedlong);
|
|
left->data.monadic = makediadicnode(left->data.monadic, right, EADD);
|
|
optimizecomm(left->data.monadic);
|
|
}
|
|
}
|
|
|
|
if (IS_TYPE_BITFIELD(type)) {
|
|
left->data.monadic = makemonadicnode(left->data.monadic, EBITFIELD);
|
|
left->data.monadic->rtype = type;
|
|
left->rtype = TYPE_BITFIELD(type)->bitfieldtype;
|
|
} else {
|
|
left->rtype = type;
|
|
}
|
|
left->flags = flags;
|
|
left = checkreference(left);
|
|
goto restart;
|
|
} else {
|
|
CError_ASSERT(4535, ENODE_IS(right, EINDIRECT));
|
|
tmp = lalloc(sizeof(ENode));
|
|
tmp->type = EMFPOINTER;
|
|
tmp->cost = 4;
|
|
tmp->flags = 0;
|
|
tmp->rtype = &stvoid;
|
|
tmp->data.mfpointer.accessnode = left;
|
|
tmp->data.mfpointer.mfpointer = right;
|
|
return tmp;
|
|
}
|
|
default:
|
|
return left;
|
|
}
|
|
}
|
|
|
|
ENode *CExpr_New_EMUL_Node(ENode *left, ENode *right) {
|
|
Conversion conv;
|
|
|
|
if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype))
|
|
return CTempl_MakeTemplDepExpr(left, EMUL, right);
|
|
|
|
left = pointer_generation(left);
|
|
right = pointer_generation(right);
|
|
if (copts.cplusplus && CExpr_CheckOperator('*', left, right, &conv)) {
|
|
if (conv.x0)
|
|
return conv.x0;
|
|
CError_ASSERT(4566, left = conv.left);
|
|
CError_ASSERT(4567, right = conv.right);
|
|
}
|
|
|
|
return makemultnode(left, right);
|
|
}
|
|
|
|
ENode *CExpr_New_EDIV_Node(ENode *left, ENode *right, Boolean no_warning) {
|
|
Conversion conv;
|
|
|
|
if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype))
|
|
return CTempl_MakeTemplDepExpr(left, EDIV, right);
|
|
|
|
left = pointer_generation(left);
|
|
right = pointer_generation(right);
|
|
if (copts.cplusplus && CExpr_CheckOperator('/', left, right, &conv)) {
|
|
if (conv.x0)
|
|
return conv.x0;
|
|
CError_ASSERT(4592, left = conv.left);
|
|
CError_ASSERT(4593, right = conv.right);
|
|
}
|
|
|
|
return makedivnode(left, right, no_warning);
|
|
}
|
|
|
|
ENode *CExpr_New_EMODULO_Node(ENode *left, ENode *right, Boolean no_warning) {
|
|
Conversion conv;
|
|
|
|
if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype))
|
|
return CTempl_MakeTemplDepExpr(left, EMODULO, right);
|
|
|
|
left = pointer_generation(left);
|
|
right = pointer_generation(right);
|
|
if (copts.cplusplus && CExpr_CheckOperator('%', left, right, &conv)) {
|
|
if (conv.x0)
|
|
return conv.x0;
|
|
CError_ASSERT(4618, left = conv.left);
|
|
CError_ASSERT(4619, right = conv.right);
|
|
}
|
|
|
|
left = integralpromote(left);
|
|
right = integralpromote(right);
|
|
CExpr_ArithmeticConversion(&left, &right);
|
|
|
|
if (iszero(right)) {
|
|
if (!no_warning)
|
|
CError_Warning(CErrorStr139);
|
|
return left;
|
|
}
|
|
|
|
if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) {
|
|
left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, '%', right->data.intval);
|
|
return left;
|
|
}
|
|
|
|
if (iszero(left))
|
|
return makediadicnode(right, left, ECOMMA);
|
|
|
|
if (CExpr_IsOne(right)) {
|
|
right = nullnode();
|
|
right->rtype = left->rtype;
|
|
return makediadicnode(left, right, ECOMMA);
|
|
}
|
|
|
|
return makediadicnode(left, right, EMODULO);
|
|
}
|
|
|
|
ENode *CExpr_New_EADD_Node(ENode *left, ENode *right) {
|
|
Conversion conv;
|
|
|
|
if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype))
|
|
return CTempl_MakeTemplDepExpr(left, EADD, right);
|
|
|
|
left = pointer_generation(left);
|
|
right = pointer_generation(right);
|
|
if (copts.cplusplus && CExpr_CheckOperator('+', left, right, &conv)) {
|
|
if (conv.x0)
|
|
return conv.x0;
|
|
CError_ASSERT(4665, left = conv.left);
|
|
CError_ASSERT(4666, right = conv.right);
|
|
}
|
|
|
|
return makeaddnode(left, right);
|
|
}
|
|
|
|
ENode *CExpr_New_ESUB_Node(ENode *left, ENode *right) {
|
|
Conversion conv;
|
|
|
|
if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype))
|
|
return CTempl_MakeTemplDepExpr(left, ESUB, right);
|
|
|
|
left = pointer_generation(left);
|
|
right = pointer_generation(right);
|
|
if (copts.cplusplus && CExpr_CheckOperator('-', left, right, &conv)) {
|
|
if (conv.x0)
|
|
return conv.x0;
|
|
CError_ASSERT(4690, left = conv.left);
|
|
CError_ASSERT(4691, right = conv.right);
|
|
}
|
|
|
|
return makesubnode(left, right);
|
|
}
|
|
|
|
ENode *CExpr_New_ESHL_Node(ENode *left, ENode *right) {
|
|
Conversion conv;
|
|
|
|
if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype))
|
|
return CTempl_MakeTemplDepExpr(left, ESHL, right);
|
|
|
|
left = pointer_generation(left);
|
|
right = pointer_generation(right);
|
|
if (copts.cplusplus && CExpr_CheckOperator(TK_SHL, left, right, &conv)) {
|
|
if (conv.x0)
|
|
return conv.x0;
|
|
CError_ASSERT(4715, left = conv.left);
|
|
CError_ASSERT(4716, right = conv.right);
|
|
}
|
|
|
|
left = integralpromote(left);
|
|
right = integralpromote(right);
|
|
|
|
if (iszero(left) || iszero(right)) {
|
|
return left;
|
|
}
|
|
|
|
if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) {
|
|
left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, TK_SHL, right->data.intval);
|
|
return left;
|
|
}
|
|
|
|
return makediadicnode(left, right, ESHL);
|
|
}
|
|
|
|
ENode *CExpr_New_ESHR_Node(ENode *left, ENode *right) {
|
|
Conversion conv;
|
|
|
|
if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype))
|
|
return CTempl_MakeTemplDepExpr(left, ESHR, right);
|
|
|
|
left = pointer_generation(left);
|
|
right = pointer_generation(right);
|
|
if (copts.cplusplus && CExpr_CheckOperator(TK_SHR, left, right, &conv)) {
|
|
if (conv.x0)
|
|
return conv.x0;
|
|
CError_ASSERT(4752, left = conv.left);
|
|
CError_ASSERT(4753, right = conv.right);
|
|
}
|
|
|
|
left = integralpromote(left);
|
|
right = integralpromote(right);
|
|
|
|
if (iszero(left) || iszero(right)) {
|
|
return left;
|
|
}
|
|
|
|
if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) {
|
|
left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, TK_SHR, right->data.intval);
|
|
return left;
|
|
}
|
|
|
|
return makediadicnode(left, right, ESHR);
|
|
}
|
|
|
|
static ENode *pointercompare(ENodeType nt, ENode *left, ENode *right) {
|
|
Type *ltype;
|
|
Type *rtype;
|
|
|
|
ltype = left->rtype;
|
|
rtype = right->rtype;
|
|
if (IS_TYPE_POINTER_ONLY(ltype) && IS_TYPE_POINTER_ONLY(rtype)) {
|
|
ltype = TPTR_TARGET(left->rtype);
|
|
rtype = TPTR_TARGET(right->rtype);
|
|
if (IS_TYPE_CLASS(ltype) && IS_TYPE_CLASS(rtype)) {
|
|
if (ltype != rtype) {
|
|
if (ltype == TPTR_TARGET(left->rtype)) {
|
|
if (CClass_IsBaseClass(TYPE_CLASS(ltype), TYPE_CLASS(rtype), NULL, 0, 1)) {
|
|
left = CExpr_SafeClassPointerCast(left, TYPE_CLASS(ltype), TYPE_CLASS(rtype), 0, 1);
|
|
} else if (CClass_IsBaseClass(TYPE_CLASS(rtype), TYPE_CLASS(ltype), NULL, 0, 1)) {
|
|
right = CExpr_SafeClassPointerCast(right, TYPE_CLASS(rtype), TYPE_CLASS(ltype), 0, 1);
|
|
} else {
|
|
CError_Error(CErrorStr245, left->rtype, ENODE_QUALS(left), right->rtype, ENODE_QUALS(right));
|
|
}
|
|
} else {
|
|
CError_Error(CErrorStr245, left->rtype, ENODE_QUALS(left), right->rtype, ENODE_QUALS(right));
|
|
}
|
|
}
|
|
} else if (!is_typeequal(left->rtype, right->rtype)) {
|
|
if (!copts.objective_c || !CObjC_IsCompatibleType(left->rtype, right->rtype)) {
|
|
CError_Error(CErrorStr245, left->rtype, ENODE_QUALS(left), right->rtype, ENODE_QUALS(right));
|
|
}
|
|
}
|
|
} else if (nt == EEQU || nt == ENOTEQU) {
|
|
if (IS_TYPE_INT(ltype)) {
|
|
if (!(ENODE_IS(left, EINTCONST) && CInt64_IsZero(&left->data.intval)))
|
|
CError_Error(CErrorStr144);
|
|
CError_ASSERT(4847, IS_TYPE_POINTER_ONLY(rtype));
|
|
left->rtype = TYPE(&stunsignedlong);
|
|
} else if (IS_TYPE_INT(rtype)) {
|
|
if (!(ENODE_IS(right, EINTCONST) && CInt64_IsZero(&right->data.intval)))
|
|
CError_Error(CErrorStr144);
|
|
CError_ASSERT(4855, IS_TYPE_POINTER_ONLY(ltype));
|
|
right->rtype = TYPE(&stunsignedlong);
|
|
} else if (!is_typeequal(ltype, rtype)) {
|
|
CError_Error(CErrorStr245, left->rtype, ENODE_QUALS(left), right->rtype, ENODE_QUALS(right));
|
|
}
|
|
} else {
|
|
if (!is_typeequal(ltype, rtype))
|
|
CError_Error(CErrorStr245, left->rtype, ENODE_QUALS(left), right->rtype, ENODE_QUALS(right));
|
|
}
|
|
|
|
return logicalexpression(makediadicnode(left, right, nt));
|
|
}
|
|
|
|
static ENode *unsigncheck(ENode *expr, Boolean flag1, Boolean flag2) {
|
|
if (is_unsigned(expr->data.diadic.left->rtype)) {
|
|
if (ENODE_IS(expr->data.diadic.left, EINTCONST) && CInt64_IsZero(&expr->data.diadic.left->data.intval)) {
|
|
flag1 = !flag1;
|
|
} else if (!(ENODE_IS(expr->data.diadic.right, EINTCONST) && CInt64_IsZero(&expr->data.diadic.right->data.intval))) {
|
|
return logicalexpression(expr);
|
|
}
|
|
|
|
if (flag1 && flag2) {
|
|
expr->type = EEQU;
|
|
return logicalexpression(expr);
|
|
}
|
|
if (!flag1 && !flag2) {
|
|
expr->type = ENOTEQU;
|
|
return logicalexpression(expr);
|
|
}
|
|
return CExpr_ConstResult(logicalexpression(expr), !flag1);
|
|
}
|
|
return logicalexpression(expr);
|
|
}
|
|
|
|
ENode *CExpr_New_ELESS_Node(ENode *left, ENode *right) {
|
|
Conversion conv;
|
|
|
|
if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype))
|
|
return CTempl_MakeTemplDepExpr(left, ELESS, right);
|
|
|
|
left = pointer_generation(left);
|
|
right = pointer_generation(right);
|
|
if (copts.cplusplus && CExpr_CheckOperator('<', left, right, &conv)) {
|
|
if (conv.x0)
|
|
return conv.x0;
|
|
CError_ASSERT(4929, left = conv.left);
|
|
CError_ASSERT(4930, right = conv.right);
|
|
}
|
|
|
|
if (IS_TYPE_POINTER(left->rtype) || IS_TYPE_POINTER(right->rtype))
|
|
return pointercompare(ELESS, left, right);
|
|
|
|
CExpr_CompareConvert(&left, "<", &right, 0);
|
|
if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) {
|
|
left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, '<', right->data.intval);
|
|
left->rtype = CParser_GetBoolType();
|
|
} else if (ENODE_IS(left, EFLOATCONST) && ENODE_IS(right, EFLOATCONST)) {
|
|
CInt64_SetLong(&left->data.intval, CMach_CalcFloatDiadicBool(left->rtype, left->data.floatval, '<', right->data.floatval));
|
|
left->type = EINTCONST;
|
|
left->rtype = CParser_GetBoolType();
|
|
} else {
|
|
left = unsigncheck(makediadicnode(left, right, ELESS), 1, 0);
|
|
}
|
|
|
|
return left;
|
|
}
|
|
|
|
ENode *CExpr_New_ELESSEQU_Node(ENode *left, ENode *right) {
|
|
Conversion conv;
|
|
|
|
if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype))
|
|
return CTempl_MakeTemplDepExpr(left, ELESSEQU, right);
|
|
|
|
left = pointer_generation(left);
|
|
right = pointer_generation(right);
|
|
if (copts.cplusplus && CExpr_CheckOperator(TK_LESS_EQUAL, left, right, &conv)) {
|
|
if (conv.x0)
|
|
return conv.x0;
|
|
CError_ASSERT(4976, left = conv.left);
|
|
CError_ASSERT(4977, right = conv.right);
|
|
}
|
|
|
|
if (IS_TYPE_POINTER(left->rtype) || IS_TYPE_POINTER(right->rtype))
|
|
return pointercompare(ELESSEQU, left, right);
|
|
|
|
CExpr_CompareConvert(&left, "<=", &right, 0);
|
|
if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) {
|
|
left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, TK_LESS_EQUAL, right->data.intval);
|
|
left->rtype = CParser_GetBoolType();
|
|
} else if (ENODE_IS(left, EFLOATCONST) && ENODE_IS(right, EFLOATCONST)) {
|
|
CInt64_SetLong(&left->data.intval, CMach_CalcFloatDiadicBool(left->rtype, left->data.floatval, TK_LESS_EQUAL, right->data.floatval));
|
|
left->type = EINTCONST;
|
|
left->rtype = CParser_GetBoolType();
|
|
} else {
|
|
left = unsigncheck(makediadicnode(left, right, ELESSEQU), 1, 1);
|
|
}
|
|
|
|
return left;
|
|
}
|
|
|
|
ENode *CExpr_New_EGREATER_Node(ENode *left, ENode *right) {
|
|
Conversion conv;
|
|
|
|
if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype))
|
|
return CTempl_MakeTemplDepExpr(left, EGREATER, right);
|
|
|
|
left = pointer_generation(left);
|
|
right = pointer_generation(right);
|
|
if (copts.cplusplus && CExpr_CheckOperator('>', left, right, &conv)) {
|
|
if (conv.x0)
|
|
return conv.x0;
|
|
CError_ASSERT(5023, left = conv.left);
|
|
CError_ASSERT(5024, right = conv.right);
|
|
}
|
|
|
|
if (IS_TYPE_POINTER(left->rtype) || IS_TYPE_POINTER(right->rtype))
|
|
return pointercompare(EGREATER, left, right);
|
|
|
|
CExpr_CompareConvert(&left, ">", &right, 0);
|
|
if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) {
|
|
left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, '>', right->data.intval);
|
|
left->rtype = CParser_GetBoolType();
|
|
} else if (ENODE_IS(left, EFLOATCONST) && ENODE_IS(right, EFLOATCONST)) {
|
|
CInt64_SetLong(&left->data.intval, CMach_CalcFloatDiadicBool(left->rtype, left->data.floatval, '>', right->data.floatval));
|
|
left->type = EINTCONST;
|
|
left->rtype = CParser_GetBoolType();
|
|
} else {
|
|
left = unsigncheck(makediadicnode(left, right, EGREATER), 0, 0);
|
|
}
|
|
|
|
return left;
|
|
}
|
|
|
|
ENode *CExpr_New_EGREATEREQU_Node(ENode *left, ENode *right) {
|
|
Conversion conv;
|
|
|
|
if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype))
|
|
return CTempl_MakeTemplDepExpr(left, EGREATEREQU, right);
|
|
|
|
left = pointer_generation(left);
|
|
right = pointer_generation(right);
|
|
if (copts.cplusplus && CExpr_CheckOperator(TK_GREATER_EQUAL, left, right, &conv)) {
|
|
if (conv.x0)
|
|
return conv.x0;
|
|
CError_ASSERT(5070, left = conv.left);
|
|
CError_ASSERT(5071, right = conv.right);
|
|
}
|
|
|
|
if (IS_TYPE_POINTER(left->rtype) || IS_TYPE_POINTER(right->rtype))
|
|
return pointercompare(EGREATEREQU, left, right);
|
|
|
|
CExpr_CompareConvert(&left, ">=", &right, 0);
|
|
if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) {
|
|
left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, TK_GREATER_EQUAL, right->data.intval);
|
|
left->rtype = CParser_GetBoolType();
|
|
} else if (ENODE_IS(left, EFLOATCONST) && ENODE_IS(right, EFLOATCONST)) {
|
|
CInt64_SetLong(&left->data.intval, CMach_CalcFloatDiadicBool(left->rtype, left->data.floatval, TK_GREATER_EQUAL, right->data.floatval));
|
|
left->type = EINTCONST;
|
|
left->rtype = CParser_GetBoolType();
|
|
} else {
|
|
left = unsigncheck(makediadicnode(left, right, EGREATEREQU), 0, 1);
|
|
}
|
|
|
|
return left;
|
|
}
|
|
|
|
ENode *memberpointercompare(ENodeType nt, ENode *left, ENode *right) {
|
|
Object *func;
|
|
ENodeList *arg;
|
|
|
|
if (!IS_TYPE_MEMBERPOINTER(left->rtype)) {
|
|
if (!(IS_TYPE_INT(left->rtype) && ENODE_IS(left, EINTCONST) && CInt64_IsZero(&left->data.intval))) {
|
|
CError_Error(CErrorStr144);
|
|
return nullnode();
|
|
}
|
|
} else if (!IS_TYPE_MEMBERPOINTER(right->rtype)) {
|
|
if (!(IS_TYPE_INT(right->rtype) && ENODE_IS(right, EINTCONST) && CInt64_IsZero(&right->data.intval))) {
|
|
CError_Error(CErrorStr144);
|
|
return nullnode();
|
|
}
|
|
} else if (!is_typeequal(left->rtype, right->rtype)) {
|
|
left = PointerToMemberCast(left, TYPE_MEMBER_POINTER(left->rtype), TYPE_MEMBER_POINTER(right->rtype), 1);
|
|
}
|
|
|
|
if ((ENODE_IS(left, EINTCONST) || !IS_TYPE_FUNC(TYPE_MEMBER_POINTER(left->rtype)->ty1)) && (ENODE_IS(right, EINTCONST) || !IS_TYPE_FUNC(TYPE_MEMBER_POINTER(right->rtype)->ty1))) {
|
|
left->rtype = TYPE(&stunsignedlong);
|
|
right->rtype = TYPE(&stunsignedlong);
|
|
return logicalexpression(makediadicnode(left, right, nt));
|
|
}
|
|
|
|
arg = lalloc(sizeof(ENodeList));
|
|
if (ENODE_IS(left, EINTCONST) || ENODE_IS(right, EINTCONST)) {
|
|
func = rt_ptmf_test;
|
|
if (ENODE_IS(left, EINTCONST))
|
|
arg->node = getnodeaddress(right, 0);
|
|
else
|
|
arg->node = getnodeaddress(left, 0);
|
|
arg->next = NULL;
|
|
} else {
|
|
func = rt_ptmf_cmpr;
|
|
arg->next = lalloc(sizeof(ENodeList));
|
|
arg->node = getnodeaddress(left, 0);
|
|
arg->next->node = getnodeaddress(right, 0);
|
|
arg->next->next = NULL;
|
|
}
|
|
|
|
left = lalloc(sizeof(ENode));
|
|
left->type = EFUNCCALL;
|
|
left->rtype = TYPE(&stsignedlong);
|
|
left->cost = 4;
|
|
left->data.funccall.funcref = create_objectrefnode(func);
|
|
left->data.funccall.args = arg;
|
|
left->data.funccall.functype = TYPE_FUNC(func->type);
|
|
left->flags = TYPE_FUNC(func->type)->qual & ENODE_FLAG_QUALS;
|
|
|
|
if (nt == EEQU)
|
|
left = makemonadicnode(left, ELOGNOT);
|
|
|
|
return left;
|
|
}
|
|
|
|
ENode *CExpr_New_EEQU_Node(ENode *left, ENode *right) {
|
|
Conversion conv;
|
|
|
|
if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype))
|
|
return CTempl_MakeTemplDepExpr(left, EEQU, right);
|
|
|
|
left = pointer_generation(left);
|
|
right = pointer_generation(right);
|
|
if (copts.cplusplus && CExpr_CheckOperator(TK_LOGICAL_EQ, left, right, &conv)) {
|
|
if (conv.x0)
|
|
return conv.x0;
|
|
CError_ASSERT(5201, left = conv.left);
|
|
CError_ASSERT(5202, right = conv.right);
|
|
}
|
|
|
|
if (IS_TYPE_POINTER(left->rtype) || IS_TYPE_POINTER(right->rtype))
|
|
return pointercompare(EEQU, left, right);
|
|
if (IS_TYPE_MEMBERPOINTER(left->rtype) || IS_TYPE_MEMBERPOINTER(right->rtype))
|
|
return memberpointercompare(EEQU, left, right);
|
|
|
|
CExpr_CompareConvert(&left, "==", &right, 1);
|
|
if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) {
|
|
left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, TK_LOGICAL_EQ, right->data.intval);
|
|
left->rtype = CParser_GetBoolType();
|
|
} else if (ENODE_IS(left, EFLOATCONST) && ENODE_IS(right, EFLOATCONST)) {
|
|
left->type = EINTCONST;
|
|
CInt64_SetLong(&left->data.intval, CMach_CalcFloatDiadicBool(left->rtype, left->data.floatval, TK_LOGICAL_EQ, right->data.floatval));
|
|
left->type = EINTCONST;
|
|
left->rtype = CParser_GetBoolType();
|
|
} else {
|
|
left = makediadicnode(left, right, EEQU);
|
|
optimizecomm(left);
|
|
}
|
|
|
|
return logicalexpression(left);
|
|
}
|
|
|
|
ENode *CExpr_New_ENOTEQU_Node(ENode *left, ENode *right) {
|
|
Conversion conv;
|
|
|
|
if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype))
|
|
return CTempl_MakeTemplDepExpr(left, ENOTEQU, right);
|
|
|
|
left = pointer_generation(left);
|
|
right = pointer_generation(right);
|
|
if (copts.cplusplus && CExpr_CheckOperator(TK_LOGICAL_NE, left, right, &conv)) {
|
|
if (conv.x0)
|
|
return conv.x0;
|
|
CError_ASSERT(5261, left = conv.left);
|
|
CError_ASSERT(5262, right = conv.right);
|
|
}
|
|
|
|
if (IS_TYPE_POINTER(left->rtype) || IS_TYPE_POINTER(right->rtype))
|
|
return pointercompare(ENOTEQU, left, right);
|
|
if (IS_TYPE_MEMBERPOINTER(left->rtype) || IS_TYPE_MEMBERPOINTER(right->rtype))
|
|
return memberpointercompare(ENOTEQU, left, right);
|
|
|
|
CExpr_CompareConvert(&left, "!=", &right, 1);
|
|
if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) {
|
|
left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, TK_LOGICAL_NE, right->data.intval);
|
|
left->rtype = CParser_GetBoolType();
|
|
} else if (ENODE_IS(left, EFLOATCONST) && ENODE_IS(right, EFLOATCONST)) {
|
|
CInt64_SetLong(&left->data.intval, CMach_CalcFloatDiadicBool(left->rtype, left->data.floatval, TK_LOGICAL_NE, right->data.floatval));
|
|
left->type = EINTCONST;
|
|
left->rtype = CParser_GetBoolType();
|
|
} else {
|
|
left = makediadicnode(left, right, ENOTEQU);
|
|
optimizecomm(left);
|
|
}
|
|
|
|
return logicalexpression(left);
|
|
}
|
|
|
|
ENode *CExpr_New_EAND_Node(ENode *left, ENode *right) {
|
|
Conversion conv;
|
|
|
|
if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype))
|
|
return CTempl_MakeTemplDepExpr(left, EAND, right);
|
|
|
|
left = pointer_generation(left);
|
|
right = pointer_generation(right);
|
|
if (copts.cplusplus && CExpr_CheckOperator('&', left, right, &conv)) {
|
|
if (conv.x0)
|
|
return conv.x0;
|
|
CError_ASSERT(5321, left = conv.left);
|
|
CError_ASSERT(5322, right = conv.right);
|
|
}
|
|
|
|
left = integralpromote(left);
|
|
right = integralpromote(right);
|
|
CExpr_ArithmeticConversion(&left, &right);
|
|
|
|
if (iszero(left) || CExpr_AllBitsSet(right))
|
|
return left;
|
|
if (iszero(right) || CExpr_AllBitsSet(left))
|
|
return right;
|
|
|
|
if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) {
|
|
left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, '&', right->data.intval);
|
|
return left;
|
|
}
|
|
|
|
left = makediadicnode(left, right, EAND);
|
|
optimizecomm(left);
|
|
return left;
|
|
}
|
|
|
|
ENode *CExpr_New_EXOR_Node(ENode *left, ENode *right) {
|
|
Conversion conv;
|
|
|
|
if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype))
|
|
return CTempl_MakeTemplDepExpr(left, EXOR, right);
|
|
|
|
left = pointer_generation(left);
|
|
right = pointer_generation(right);
|
|
if (copts.cplusplus && CExpr_CheckOperator('^', left, right, &conv)) {
|
|
if (conv.x0)
|
|
return conv.x0;
|
|
CError_ASSERT(5360, left = conv.left);
|
|
CError_ASSERT(5361, right = conv.right);
|
|
}
|
|
|
|
left = integralpromote(left);
|
|
right = integralpromote(right);
|
|
CExpr_ArithmeticConversion(&left, &right);
|
|
|
|
if (iszero(right))
|
|
return left;
|
|
if (iszero(left))
|
|
return right;
|
|
|
|
if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) {
|
|
left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, '^', right->data.intval);
|
|
return left;
|
|
}
|
|
|
|
left = makediadicnode(left, right, EXOR);
|
|
optimizecomm(left);
|
|
return left;
|
|
}
|
|
|
|
ENode *CExpr_New_EOR_Node(ENode *left, ENode *right) {
|
|
Conversion conv;
|
|
|
|
if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype))
|
|
return CTempl_MakeTemplDepExpr(left, EOR, right);
|
|
|
|
left = pointer_generation(left);
|
|
right = pointer_generation(right);
|
|
if (copts.cplusplus && CExpr_CheckOperator('|', left, right, &conv)) {
|
|
if (conv.x0)
|
|
return conv.x0;
|
|
CError_ASSERT(5399, left = conv.left);
|
|
CError_ASSERT(5400, right = conv.right);
|
|
}
|
|
|
|
left = integralpromote(left);
|
|
right = integralpromote(right);
|
|
CExpr_ArithmeticConversion(&left, &right);
|
|
|
|
if (iszero(right) || CExpr_AllBitsSet(left))
|
|
return left;
|
|
if (iszero(left) || CExpr_AllBitsSet(right))
|
|
return right;
|
|
|
|
if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) {
|
|
left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, '|', right->data.intval);
|
|
return left;
|
|
}
|
|
|
|
left = makediadicnode(left, right, EOR);
|
|
optimizecomm(left);
|
|
return left;
|
|
}
|
|
|
|
ENode *CExpr_New_ELAND_Node(ENode *left, ENode *right) {
|
|
Conversion conv;
|
|
|
|
if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype))
|
|
return CTempl_MakeTemplDepExpr(left, ELAND, right);
|
|
|
|
left = pointer_generation(left);
|
|
right = pointer_generation(right);
|
|
if (copts.cplusplus && CExpr_CheckOperator(TK_LOGICAL_AND, left, right, &conv)) {
|
|
if (conv.x0)
|
|
return conv.x0;
|
|
CError_ASSERT(5438, left = conv.left);
|
|
CError_ASSERT(5439, right = conv.right);
|
|
}
|
|
|
|
switch (left->rtype->type) {
|
|
case TYPEINT:
|
|
case TYPEFLOAT:
|
|
case TYPEPOINTER:
|
|
case TYPEARRAY:
|
|
break;
|
|
case TYPEENUM:
|
|
case TYPEMEMBERPOINTER:
|
|
left = CExpr_ConvertToCondition(left);
|
|
break;
|
|
default:
|
|
CError_Error(CErrorStr144);
|
|
left = nullnode();
|
|
}
|
|
switch (right->rtype->type) {
|
|
case TYPEINT:
|
|
case TYPEFLOAT:
|
|
case TYPEPOINTER:
|
|
case TYPEARRAY:
|
|
break;
|
|
case TYPEENUM:
|
|
case TYPEMEMBERPOINTER:
|
|
right = CExpr_ConvertToCondition(right);
|
|
break;
|
|
default:
|
|
CError_Error(CErrorStr144);
|
|
right = nullnode();
|
|
}
|
|
|
|
if (iszero(left)) {
|
|
left->type = EINTCONST;
|
|
left->rtype = CParser_GetBoolType();
|
|
CInt64_SetLong(&left->data.intval, 0);
|
|
return left;
|
|
}
|
|
|
|
if (isnotzero(left)) {
|
|
if (iszero(right)) {
|
|
left->type = EINTCONST;
|
|
left->rtype = CParser_GetBoolType();
|
|
CInt64_SetLong(&left->data.intval, 0);
|
|
return left;
|
|
} else if (isnotzero(right)) {
|
|
left->type = EINTCONST;
|
|
left->rtype = CParser_GetBoolType();
|
|
CInt64_SetLong(&left->data.intval, 1);
|
|
return left;
|
|
} else {
|
|
left = makemonadicnode(right, ELOGNOT);
|
|
left->rtype = CParser_GetBoolType();
|
|
return makemonadicnode(left, ELOGNOT);
|
|
}
|
|
} else {
|
|
if (isnotzero(right)) {
|
|
left = makemonadicnode(left, ELOGNOT);
|
|
left->rtype = CParser_GetBoolType();
|
|
return makemonadicnode(left, ELOGNOT);
|
|
} else if (iszero(right)) {
|
|
right->type = EINTCONST;
|
|
right->rtype = CParser_GetBoolType();
|
|
CInt64_SetLong(&right->data.intval, 0);
|
|
return makecommaexpression(left, right);
|
|
} else {
|
|
left = makediadicnode(left, right, ELAND);
|
|
left->rtype = CParser_GetBoolType();
|
|
return left;
|
|
}
|
|
}
|
|
}
|
|
|
|
ENode *CExpr_New_ELOR_Node(ENode *left, ENode *right) {
|
|
Conversion conv;
|
|
|
|
if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype))
|
|
return CTempl_MakeTemplDepExpr(left, ELOR, right);
|
|
|
|
left = pointer_generation(left);
|
|
right = pointer_generation(right);
|
|
if (copts.cplusplus && CExpr_CheckOperator(TK_LOGICAL_OR, left, right, &conv)) {
|
|
if (conv.x0)
|
|
return conv.x0;
|
|
CError_ASSERT(5543, left = conv.left);
|
|
CError_ASSERT(5544, right = conv.right);
|
|
}
|
|
|
|
switch (left->rtype->type) {
|
|
case TYPEINT:
|
|
case TYPEFLOAT:
|
|
case TYPEPOINTER:
|
|
case TYPEARRAY:
|
|
break;
|
|
case TYPEENUM:
|
|
case TYPEMEMBERPOINTER:
|
|
left = CExpr_ConvertToCondition(left);
|
|
break;
|
|
default:
|
|
CError_Error(CErrorStr144);
|
|
left = nullnode();
|
|
}
|
|
switch (right->rtype->type) {
|
|
case TYPEINT:
|
|
case TYPEFLOAT:
|
|
case TYPEPOINTER:
|
|
case TYPEARRAY:
|
|
break;
|
|
case TYPEENUM:
|
|
case TYPEMEMBERPOINTER:
|
|
right = CExpr_ConvertToCondition(right);
|
|
break;
|
|
default:
|
|
CError_Error(CErrorStr144);
|
|
right = nullnode();
|
|
}
|
|
|
|
if (isnotzero(left)) {
|
|
left->type = EINTCONST;
|
|
left->rtype = CParser_GetBoolType();
|
|
CInt64_SetLong(&left->data.intval, 1);
|
|
return left;
|
|
}
|
|
|
|
if (iszero(left)) {
|
|
if (iszero(right)) {
|
|
left->type = EINTCONST;
|
|
left->rtype = CParser_GetBoolType();
|
|
CInt64_SetLong(&left->data.intval, 0);
|
|
return left;
|
|
} else if (isnotzero(right)) {
|
|
left->type = EINTCONST;
|
|
left->rtype = CParser_GetBoolType();
|
|
CInt64_SetLong(&left->data.intval, 1);
|
|
return left;
|
|
} else {
|
|
left = makemonadicnode(right, ELOGNOT);
|
|
left->rtype = CParser_GetBoolType();
|
|
return makemonadicnode(left, ELOGNOT);
|
|
}
|
|
} else {
|
|
if (isnotzero(right)) {
|
|
right->type = EINTCONST;
|
|
right->rtype = CParser_GetBoolType();
|
|
CInt64_SetLong(&right->data.intval, 1);
|
|
} else if (iszero(right)) {
|
|
left = makemonadicnode(left, ELOGNOT);
|
|
left->rtype = CParser_GetBoolType();
|
|
return makemonadicnode(left, ELOGNOT);
|
|
}
|
|
left = makediadicnode(left, right, ELOR);
|
|
left->rtype = CParser_GetBoolType();
|
|
return left;
|
|
}
|
|
}
|
|
|
|
ENode *CExpr_NewDyadicNode(ENode *left, ENodeType nt, ENode *right) {
|
|
switch (nt) {
|
|
default:
|
|
CError_FATAL(5642);
|
|
case EADD: return CExpr_New_EADD_Node(left, right);
|
|
case ESUB: return CExpr_New_ESUB_Node(left, right);
|
|
case EMUL: return CExpr_New_EMUL_Node(left, right);
|
|
case EDIV: return CExpr_New_EDIV_Node(left, right, 1);
|
|
case EMODULO: return CExpr_New_EMODULO_Node(left, right, 1);
|
|
case EAND: return CExpr_New_EAND_Node(left, right);
|
|
case EXOR: return CExpr_New_EXOR_Node(left, right);
|
|
case EOR: return CExpr_New_EOR_Node(left, right);
|
|
case ESHL: return CExpr_New_ESHL_Node(left, right);
|
|
case ESHR: return CExpr_New_ESHR_Node(left, right);
|
|
case ELESS: return CExpr_New_ELESS_Node(left, right);
|
|
case EGREATER: return CExpr_New_EGREATER_Node(left, right);
|
|
case ELESSEQU: return CExpr_New_ELESSEQU_Node(left, right);
|
|
case EGREATEREQU: return CExpr_New_EGREATEREQU_Node(left, right);
|
|
case EEQU: return CExpr_New_EEQU_Node(left, right);
|
|
case ENOTEQU: return CExpr_New_ENOTEQU_Node(left, right);
|
|
case ELAND: return CExpr_New_ELAND_Node(left, right);
|
|
case ELOR: return CExpr_New_ELOR_Node(left, right);
|
|
}
|
|
}
|
|
|
|
typedef struct DyadicInfo {
|
|
ENodeType t;
|
|
UInt8 prec;
|
|
} DyadicInfo;
|
|
|
|
static Boolean CExpr_GetDyadicInfo(short token, DyadicInfo *info) {
|
|
switch (token) {
|
|
case '*':
|
|
info->t = EMUL;
|
|
info->prec = 20;
|
|
return 1;
|
|
case '/':
|
|
info->t = EDIV;
|
|
info->prec = 20;
|
|
return 1;
|
|
case '%':
|
|
info->t = EMODULO;
|
|
info->prec = 20;
|
|
return 1;
|
|
case '+':
|
|
info->t = EADD;
|
|
info->prec = 19;
|
|
return 1;
|
|
case '-':
|
|
info->t = ESUB;
|
|
info->prec = 19;
|
|
return 1;
|
|
case TK_SHL:
|
|
info->t = ESHL;
|
|
info->prec = 18;
|
|
return 1;
|
|
case TK_SHR:
|
|
info->t = ESHR;
|
|
info->prec = 18;
|
|
return 1;
|
|
case '<':
|
|
info->t = ELESS;
|
|
info->prec = 17;
|
|
return 1;
|
|
case TK_LESS_EQUAL:
|
|
info->t = ELESSEQU;
|
|
info->prec = 17;
|
|
return 1;
|
|
case '>':
|
|
if (disallowgreaterthan)
|
|
return 0;
|
|
info->t = EGREATER;
|
|
info->prec = 17;
|
|
return 1;
|
|
case TK_GREATER_EQUAL:
|
|
info->t = EGREATEREQU;
|
|
info->prec = 17;
|
|
return 1;
|
|
case TK_LOGICAL_EQ:
|
|
info->t = EEQU;
|
|
info->prec = 16;
|
|
return 1;
|
|
case TK_LOGICAL_NE:
|
|
info->t = ENOTEQU;
|
|
info->prec = 16;
|
|
return 1;
|
|
case '&':
|
|
info->t = EAND;
|
|
info->prec = 15;
|
|
return 1;
|
|
case '^':
|
|
info->t = EXOR;
|
|
info->prec = 14;
|
|
return 1;
|
|
case '|':
|
|
info->t = EOR;
|
|
info->prec = 13;
|
|
return 1;
|
|
case TK_LOGICAL_AND:
|
|
info->t = ELAND;
|
|
info->prec = 12;
|
|
return 1;
|
|
case TK_LOGICAL_OR:
|
|
info->t = ELOR;
|
|
info->prec = 11;
|
|
return 1;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static ENode *CExpr_ParseDyadicExpression(ENode *left, UInt8 prec, Boolean no_warning) {
|
|
ENode *right;
|
|
Boolean is_eland_or_elor;
|
|
Boolean save_dgt;
|
|
Boolean cont;
|
|
DyadicInfo left_info;
|
|
DyadicInfo right_info;
|
|
|
|
save_dgt = disallowgreaterthan;
|
|
if (!left) {
|
|
disallowgreaterthan = 0;
|
|
left = pm_expression();
|
|
disallowgreaterthan = save_dgt;
|
|
}
|
|
|
|
do {
|
|
if (!CExpr_GetDyadicInfo(tk, &left_info))
|
|
return left;
|
|
|
|
switch (left_info.t) {
|
|
case ELAND:
|
|
CExpr_CheckUnwantedAssignment(left);
|
|
if (iszero(left))
|
|
no_warning = 1;
|
|
is_eland_or_elor = 1;
|
|
break;
|
|
case ELOR:
|
|
CExpr_CheckUnwantedAssignment(left);
|
|
if (isnotzero(left))
|
|
no_warning = 1;
|
|
is_eland_or_elor = 1;
|
|
break;
|
|
default:
|
|
is_eland_or_elor = 0;
|
|
}
|
|
|
|
tk = lex();
|
|
disallowgreaterthan = 0;
|
|
right = pm_expression();
|
|
disallowgreaterthan = save_dgt;
|
|
inner_loop:
|
|
if (CExpr_GetDyadicInfo(tk, &right_info)) {
|
|
if (left_info.prec >= right_info.prec) {
|
|
cont = (prec >= right_info.prec);
|
|
} else {
|
|
right = CExpr_ParseDyadicExpression(right, left_info.prec, no_warning);
|
|
goto inner_loop;
|
|
}
|
|
} else {
|
|
cont = 1;
|
|
}
|
|
|
|
if (is_eland_or_elor)
|
|
CExpr_CheckUnwantedAssignment(right);
|
|
|
|
switch (left_info.t) {
|
|
case EDIV:
|
|
left = CExpr_New_EDIV_Node(left, right, no_warning);
|
|
break;
|
|
case EMODULO:
|
|
left = CExpr_New_EMODULO_Node(left, right, no_warning);
|
|
break;
|
|
default:
|
|
left = CExpr_NewDyadicNode(left, left_info.t, right);
|
|
}
|
|
} while (!cont);
|
|
|
|
return left;
|
|
}
|
|
|
|
static Boolean CExpr_IsBlockMoveType(Type *type) {
|
|
switch (type->type) {
|
|
case TYPESTRUCT:
|
|
case TYPECLASS:
|
|
return 1;
|
|
case TYPEMEMBERPOINTER:
|
|
return type->size != 4;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
ENode *CExpr_New_ECOND_Node(ENode *cond, ENode *expr1, ENode *expr2) {
|
|
ENode *result;
|
|
ENodeList *args;
|
|
short cost;
|
|
Conversion conv;
|
|
|
|
cond = CExpr_ConvertToCondition(pointer_generation(cond));
|
|
expr1 = pointer_generation(expr1);
|
|
expr2 = pointer_generation(expr2);
|
|
|
|
if (!IS_TYPE_INT_OR_FLOAT(cond->rtype) && !IS_TYPE_POINTER_ONLY(cond->rtype)) {
|
|
CError_Error(CErrorStr144);
|
|
return nullnode();
|
|
}
|
|
|
|
cost = cond->cost + 1;
|
|
if (expr1->cost > expr2->cost)
|
|
cost += expr1->cost;
|
|
else
|
|
cost += expr2->cost;
|
|
if (expr2->cost > cost)
|
|
cost = expr2->cost;
|
|
if (cost > 200)
|
|
cost = 200;
|
|
|
|
result = CExpr_NewENode(ECOND);
|
|
result->cost = cost;
|
|
result->rtype = expr1->rtype;
|
|
result->flags = expr1->flags | expr2->flags;
|
|
result->data.cond.cond = cond;
|
|
if (ENODE_IS(expr1, EFUNCCALL) && expr1->rtype == &stvoid && (expr1->flags & ENODE_FLAG_VOLATILE)) {
|
|
result->rtype = expr2->rtype;
|
|
result->flags = expr2->flags;
|
|
result->data.cond.expr1 = expr1;
|
|
result->data.cond.expr2 = expr2;
|
|
return result;
|
|
}
|
|
if (ENODE_IS(expr2, EFUNCCALL) && expr2->rtype == &stvoid && (expr2->flags & ENODE_FLAG_VOLATILE)) {
|
|
result->rtype = expr1->rtype;
|
|
result->flags = expr1->flags;
|
|
result->data.cond.expr1 = expr1;
|
|
result->data.cond.expr2 = expr2;
|
|
return result;
|
|
}
|
|
|
|
if (
|
|
ENODE_IS(expr1, EINDIRECT) &&
|
|
ENODE_IS(expr2, EINDIRECT) &&
|
|
is_typesame(expr1->rtype, expr2->rtype) &&
|
|
ENODE_QUALS(expr1) == ENODE_QUALS(expr2) &&
|
|
CExpr_IsBlockMoveType(expr1->rtype) &&
|
|
!ENODE_IS(expr1->data.monadic, EBITFIELD) &&
|
|
!ENODE_IS(expr2->data.monadic, EBITFIELD)
|
|
) {
|
|
if (isnotzero(cond))
|
|
return expr1;
|
|
if (iszero(cond))
|
|
return expr2;
|
|
result->data.cond.expr1 = getnodeaddress(expr1, 0);
|
|
result->data.cond.expr2 = getnodeaddress(expr2, 0);
|
|
result->rtype = result->data.cond.expr1->rtype;
|
|
result = makemonadicnode(result, EINDIRECT);
|
|
result->rtype = TPTR_TARGET(result->rtype);
|
|
return result;
|
|
}
|
|
|
|
if ((IS_TYPE_CLASS(expr1->rtype) || IS_TYPE_CLASS(expr2->rtype)) && !is_typesame(expr1->rtype, expr2->rtype)) {
|
|
if (!copts.old_argmatch) {
|
|
if (CExpr_CondOperatorMatch(expr1, expr2, &conv)) {
|
|
CError_ASSERT(6246, !conv.x0);
|
|
expr1 = conv.left;
|
|
expr2 = conv.right;
|
|
} else if (CExpr_CanImplicitlyConvert(expr1, expr2->rtype, ENODE_QUALS(expr2))) {
|
|
if (CExpr_CanImplicitlyConvert(expr2, expr1->rtype, ENODE_QUALS(expr1)))
|
|
CError_Error(CErrorStr188);
|
|
expr1 = CExpr_Convert(expr1, expr2->rtype, ENODE_QUALS(expr2), 0, 1);
|
|
} else if (CExpr_CanImplicitlyConvert(expr2, expr1->rtype, ENODE_QUALS(expr1))) {
|
|
expr2 = CExpr_Convert(expr2, expr1->rtype, ENODE_QUALS(expr1), 0, 1);
|
|
} else {
|
|
goto failed;
|
|
}
|
|
|
|
result->rtype = expr1->rtype;
|
|
} else {
|
|
args = lalloc(sizeof(ENodeList));
|
|
args->node = expr1;
|
|
args->next = lalloc(sizeof(ENodeList));
|
|
args->next->node = expr2;
|
|
args->next->next = NULL;
|
|
|
|
if (CExpr_CheckOperatorConversion(':', expr1, expr2, args, &conv)) {
|
|
CError_ASSERT(6274, !conv.x0);
|
|
expr1 = conv.left;
|
|
expr2 = conv.right;
|
|
}
|
|
|
|
result->rtype = expr1->rtype;
|
|
}
|
|
}
|
|
|
|
switch (expr1->rtype->type) {
|
|
case TYPEENUM:
|
|
if (expr1->rtype == expr2->rtype)
|
|
break;
|
|
expr1 = forceintegral(expr1);
|
|
case TYPEINT:
|
|
if (IS_TYPE_POINTER_ONLY(expr2->rtype) || IS_TYPE_MEMBERPOINTER(expr2->rtype)) {
|
|
expr1 = CExpr_Convert(expr1, expr2->rtype, ENODE_QUALS(expr2), 0, 1);
|
|
result->rtype = expr2->rtype;
|
|
break;
|
|
}
|
|
case TYPEFLOAT:
|
|
if (expr1->rtype != expr2->rtype) {
|
|
CExpr_ArithmeticConversion(&expr1, &expr2);
|
|
result->rtype = expr1->rtype;
|
|
}
|
|
break;
|
|
case TYPEPOINTER:
|
|
if (ENODE_IS(expr2, EINTCONST) && CInt64_IsZero(&expr2->data.intval)) {
|
|
expr2->rtype = TYPE(&stunsignedlong);
|
|
break;
|
|
}
|
|
if (IS_TYPE_POINTER_ONLY(expr2->rtype)) {
|
|
if (IS_TYPE_CLASS(TPTR_TARGET(expr1->rtype)) && IS_TYPE_CLASS(TPTR_TARGET(expr2->rtype))) {
|
|
if (TPTR_TARGET(expr1->rtype) != TPTR_TARGET(expr2->rtype)) {
|
|
if (CClass_IsBaseClass(TYPE_CLASS(TPTR_TARGET(expr1->rtype)), TYPE_CLASS(TPTR_TARGET(expr2->rtype)), NULL, 0, 1)) {
|
|
expr1 = CExpr_SafeClassPointerCast(
|
|
expr1,
|
|
TYPE_CLASS(TPTR_TARGET(expr1->rtype)),
|
|
TYPE_CLASS(TPTR_TARGET(expr2->rtype)),
|
|
0, 1);
|
|
expr1->rtype = expr2->rtype;
|
|
} else if (CClass_IsBaseClass(TYPE_CLASS(TPTR_TARGET(expr2->rtype)), TYPE_CLASS(TPTR_TARGET(expr1->rtype)), NULL, 0, 1)) {
|
|
expr2 = CExpr_SafeClassPointerCast(
|
|
expr2,
|
|
TYPE_CLASS(TPTR_TARGET(expr2->rtype)),
|
|
TYPE_CLASS(TPTR_TARGET(expr1->rtype)),
|
|
0, 1);
|
|
expr2->rtype = expr1->rtype;
|
|
} else {
|
|
goto failed;
|
|
}
|
|
}
|
|
result->rtype = expr1->rtype;
|
|
break;
|
|
}
|
|
if (TPTR_TARGET(expr2->rtype) == &stvoid)
|
|
result->rtype = expr2->rtype;
|
|
}
|
|
if (!is_typeequal(expr1->rtype, expr2->rtype)) {
|
|
if (!copts.objective_c)
|
|
goto failed;
|
|
if (!CObjC_IsCompatibleType(expr1->rtype, expr2->rtype))
|
|
goto failed;
|
|
expr1->rtype = expr2->rtype = CObjC_GetObjCType_id(1);
|
|
}
|
|
break;
|
|
case TYPEVOID:
|
|
if (!is_typeequal(expr1->rtype, expr2->rtype))
|
|
goto failed;
|
|
break;
|
|
case TYPESTRUCT:
|
|
case TYPECLASS:
|
|
if (!is_typeequal(expr1->rtype, expr2->rtype))
|
|
goto failed;
|
|
result->rtype = expr1->rtype;
|
|
break;
|
|
case TYPEMEMBERPOINTER:
|
|
if (IS_TYPE_MEMBERPOINTER(expr2->rtype) && TYPE_MEMBER_POINTER(expr1->rtype)->ty2 == TYPE_MEMBER_POINTER(expr2->rtype)->ty2) {
|
|
expr2 = CExpr_Convert(expr2, expr1->rtype, ENODE_QUALS(expr1), 0, 1);
|
|
} else if (CExpr_CanImplicitlyConvert(expr1, expr2->rtype, ENODE_QUALS(expr2))) {
|
|
if (CExpr_CanImplicitlyConvert(expr2, expr1->rtype, ENODE_QUALS(expr1)))
|
|
CError_Error(CErrorStr188);
|
|
expr1 = CExpr_Convert(expr1, expr2->rtype, ENODE_QUALS(expr2), 0, 1);
|
|
} else if (CExpr_CanImplicitlyConvert(expr2, expr1->rtype, ENODE_QUALS(expr1))) {
|
|
expr2 = CExpr_Convert(expr2, expr1->rtype, ENODE_QUALS(expr1), 0, 1);
|
|
} else {
|
|
goto failed;
|
|
}
|
|
result->rtype = expr1->rtype;
|
|
break;
|
|
default:
|
|
failed:
|
|
CError_Error(CErrorStr245, expr1->rtype, ENODE_QUALS(expr1), expr2->rtype, ENODE_QUALS(expr2));
|
|
return nullnode();
|
|
}
|
|
|
|
result->data.cond.expr1 = expr1;
|
|
result->data.cond.expr2 = expr2;
|
|
if (isnotzero(cond))
|
|
result = expr1;
|
|
else if (iszero(cond))
|
|
result = expr2;
|
|
return result;
|
|
}
|
|
|
|
static ENode *conditional_expression(void) {
|
|
ENode *cond;
|
|
ENode *expr1;
|
|
ENode *expr2;
|
|
ENode *result;
|
|
Boolean is_templdep_cond;
|
|
|
|
is_templdep_cond = 0;
|
|
cond = CExpr_ParseDyadicExpression(NULL, 0, 0);
|
|
if (tk != '?')
|
|
return cond;
|
|
|
|
cond = pointer_generation(cond);
|
|
if (!IS_TYPE_TEMPLDEPEXPR(cond->rtype)) {
|
|
cond = CExpr_ConvertToCondition(cond);
|
|
if (!IS_TYPE_INT_OR_FLOAT(cond->rtype) && !IS_TYPE_POINTER_ONLY(cond->rtype)) {
|
|
CError_Error(CErrorStr144);
|
|
return nullnode();
|
|
}
|
|
} else {
|
|
is_templdep_cond = 1;
|
|
}
|
|
|
|
tk = lex();
|
|
expr1 = expression();
|
|
if (tk != ':')
|
|
CError_ErrorSkip(CErrorStr141);
|
|
else
|
|
tk = lex();
|
|
|
|
expr2 = (copts.cplusplus && !copts.ARMconform) ? assignment_expression() : conditional_expression();
|
|
|
|
if (is_templdep_cond || IS_TYPE_TEMPLDEPEXPR(expr1->rtype) || IS_TYPE_TEMPLDEPEXPR(expr2->rtype)) {
|
|
result = CExpr_NewENode(ECOND);
|
|
result->rtype = &sttemplexpr;
|
|
result->data.cond.cond = cond;
|
|
result->data.cond.expr1 = expr1;
|
|
result->data.cond.expr2 = expr2;
|
|
return result;
|
|
}
|
|
|
|
return CExpr_New_ECOND_Node(cond, expr1, expr2);
|
|
}
|
|
|
|
static ENode *CExpr_MakeOpAssNode(ENode *left, ENode *right, ENodeType nt) {
|
|
if (left->rtype != right->rtype) {
|
|
switch (right->rtype->type) {
|
|
case TYPEINT:
|
|
case TYPEFLOAT:
|
|
break;
|
|
case TYPEENUM:
|
|
right->rtype = TYPE_ENUM(right->rtype)->enumtype;
|
|
break;
|
|
default:
|
|
right = CExpr_AssignmentPromotion(right, left->rtype, 0, 1);
|
|
}
|
|
if (IS_TYPE_FLOAT(left->rtype)) {
|
|
if (IS_TYPE_INT(right->rtype) || (IS_TYPE_FLOAT(right->rtype) && left->rtype->size >= right->rtype->size))
|
|
right = CExpr_AssignmentPromotion(right, left->rtype, 0, 1);
|
|
} else if (IS_TYPE_INT(left->rtype)) {
|
|
if (IS_TYPE_INT(right->rtype) && (left->rtype->size > right->rtype->size || (left->rtype->size == right->rtype->size && is_unsigned(left->rtype) == is_unsigned(right->rtype))))
|
|
right = CExpr_AssignmentPromotion(right, left->rtype, 0, 1);
|
|
}
|
|
}
|
|
|
|
return makediadicnode(left, right, nt);
|
|
}
|
|
|
|
static ENode *makeassignmentnode(ENode *left, ENodeType nt, short token) {
|
|
ENode *right;
|
|
ENode *tmp;
|
|
ENode *funcexpr;
|
|
ENodeList *args;
|
|
Conversion conv;
|
|
|
|
tk = lex();
|
|
right = assignment_expression();
|
|
if (copts.cplusplus) {
|
|
if (copts.old_argmatch && !ENODE_IS(right, EMEMBER))
|
|
right = pointer_generation(right);
|
|
if (CExpr_CheckOperator(token, left, right, &conv)) {
|
|
if (!conv.x0) {
|
|
if (nt == EASS)
|
|
goto continue_anyway;
|
|
CError_FATAL(6531);
|
|
}
|
|
return conv.x0;
|
|
}
|
|
if (IS_TYPE_CLASS(left->rtype) && CClass_AssignmentOperator(TYPE_CLASS(left->rtype)))
|
|
CError_Error(CErrorStr144);
|
|
}
|
|
continue_anyway:
|
|
if (IS_TYPE_ARRAY(left->rtype)) {
|
|
if (copts.gcc_extensions && nt == EASS && is_typesame(left->rtype, right->rtype)) {
|
|
tmp = makediadicnode(left, right, nt);
|
|
tmp->flags = left->flags;
|
|
return tmp;
|
|
}
|
|
CError_Error(CErrorStr144);
|
|
return nullnode();
|
|
}
|
|
|
|
left = CExpr_LValue(pointer_generation(left), 1, 1);
|
|
if (nt != EASS) {
|
|
if (!IS_TYPE_INT(right->rtype)) {
|
|
if (!IS_TYPE_ENUM(right->rtype)) {
|
|
CError_Error(CErrorStr144);
|
|
return left;
|
|
}
|
|
right = forceintegral(right);
|
|
}
|
|
if (!IS_TYPE_INT(left->rtype)) {
|
|
if (copts.cplusplus) {
|
|
CError_Error(CErrorStr144);
|
|
return left;
|
|
}
|
|
left = forceintegral(left);
|
|
if (!IS_TYPE_INT(left->rtype)) {
|
|
CError_Error(CErrorStr144);
|
|
return left;
|
|
}
|
|
}
|
|
return CExpr_MakeOpAssNode(left, right, nt);
|
|
}
|
|
|
|
if (IS_TYPE_CLASS(left->rtype) && TYPE_CLASS(left->rtype)->sominfo) {
|
|
CError_Error(CErrorStr285);
|
|
return left;
|
|
}
|
|
|
|
if (copts.warn_implicitconv && ENODE_IS(left, EINDIRECT) && ENODE_IS(left->data.monadic, EBITFIELD) && !ENODE_IS(right, EINTCONST)) {
|
|
copts.warn_implicitconv = 0;
|
|
right = CExpr_AssignmentPromotion(right, left->rtype, left->flags, 1);
|
|
copts.warn_implicitconv = 1;
|
|
} else {
|
|
right = CExpr_AssignmentPromotion(right, left->rtype, left->flags, 1);
|
|
}
|
|
|
|
tmp = right;
|
|
if (IS_TYPE_FLOAT(right->rtype) && ENODE_IS(right, ETYPCON) && right->rtype->size == right->data.monadic->rtype->size)
|
|
tmp = right->data.monadic;
|
|
|
|
if (
|
|
ENODE_IS(left, EINDIRECT) &&
|
|
ENODE_IS(left->data.monadic, EOBJREF) &&
|
|
ENODE_IS(tmp, EINDIRECT) &&
|
|
(ENODE_IS(funcexpr = right->data.monadic, EFUNCCALL) || ENODE_IS(funcexpr, EFUNCCALLP)) &&
|
|
left->rtype == funcexpr->data.funccall.functype->functype &&
|
|
CMach_GetFunctionResultClass(funcexpr->data.funccall.functype) == 1 &&
|
|
(args = funcexpr->data.funccall.args)
|
|
) {
|
|
switch (CABI_GetStructResultArgumentIndex(funcexpr->data.funccall.functype)) {
|
|
case 0:
|
|
break;
|
|
case 1:
|
|
if ((args = args->next))
|
|
break;
|
|
CError_FATAL(6625);
|
|
default:
|
|
CError_FATAL(6626);
|
|
}
|
|
if (ENODE_IS(args->node, ETEMP)) {
|
|
if (!(IS_TYPE_CLASS(left->rtype) && CClass_Destructor(TYPE_CLASS(left->rtype)))) {
|
|
args->node = getnodeaddress(left, 0);
|
|
return right;
|
|
}
|
|
}
|
|
}
|
|
|
|
right = makediadicnode(left, right, nt);
|
|
right->flags = left->flags;
|
|
return right;
|
|
}
|
|
|
|
static ENode *makepassignmentnode(ENode *left, ENodeType nt, short token) {
|
|
ENode *right;
|
|
Boolean is_array;
|
|
Conversion conv;
|
|
|
|
is_array = IS_TYPE_ARRAY(left->rtype);
|
|
left = pointer_generation(left);
|
|
if (copts.cplusplus) {
|
|
tk = lex();
|
|
right = pointer_generation(assignment_expression());
|
|
if (CExpr_CheckOperator(token, left, right, &conv)) {
|
|
CError_ASSERT(6669, conv.x0);
|
|
return conv.x0;
|
|
}
|
|
left = CExpr_LValue(left, 1, 1);
|
|
} else {
|
|
left = CExpr_LValue(left, 1, 1);
|
|
tk = lex();
|
|
right = pointer_generation(assignment_expression());
|
|
}
|
|
|
|
if (is_array)
|
|
CError_Error(CErrorStr144);
|
|
|
|
switch (left->rtype->type) {
|
|
case TYPEINT:
|
|
case TYPEFLOAT:
|
|
case TYPEPOINTER:
|
|
break;
|
|
case TYPEENUM:
|
|
if (copts.cplusplus) {
|
|
CError_Error(CErrorStr144);
|
|
return left;
|
|
}
|
|
left = forceintegral(left);
|
|
break;
|
|
default:
|
|
CError_Error(CErrorStr144);
|
|
return left;
|
|
}
|
|
|
|
if (IS_TYPE_ENUM(right->rtype))
|
|
right = forceintegral(right);
|
|
|
|
if (iszero(right))
|
|
return left;
|
|
|
|
if (IS_TYPE_POINTER_ONLY(left->rtype)) {
|
|
if (IS_TYPE_INT(right->rtype)) {
|
|
if (nt == ESUBASS) {
|
|
left = psub(left, right);
|
|
if (ENODE_IS(left, ESUB))
|
|
left->type = ESUBASS;
|
|
return left;
|
|
} else {
|
|
left = padd(left, right);
|
|
if (ENODE_IS(left, EADD))
|
|
left->type = EADDASS;
|
|
return left;
|
|
}
|
|
}
|
|
CError_Error(CErrorStr144);
|
|
return left;
|
|
} else {
|
|
return CExpr_MakeOpAssNode(left, right, nt);
|
|
}
|
|
}
|
|
|
|
static ENode *makemulassignmentnode(ENode *left, ENodeType nt, short token) {
|
|
ENode *right;
|
|
Boolean is_array;
|
|
Conversion conv;
|
|
|
|
is_array = IS_TYPE_ARRAY(left->rtype);
|
|
left = pointer_generation(left);
|
|
if (copts.cplusplus) {
|
|
tk = lex();
|
|
right = pointer_generation(assignment_expression());
|
|
if (CExpr_CheckOperator(token, left, right, &conv)) {
|
|
CError_ASSERT(6753, conv.x0);
|
|
return conv.x0;
|
|
}
|
|
if (!IS_TYPE_INT(left->rtype) && !(IS_TYPE_FLOAT(left->rtype) && nt != EMODASS)) {
|
|
CError_Error(CErrorStr144);
|
|
return nullnode();
|
|
}
|
|
left = CExpr_LValue(left, 1, 1);
|
|
} else {
|
|
if (IS_TYPE_ENUM(left->rtype))
|
|
left = forceintegral(left);
|
|
if (!IS_TYPE_INT(left->rtype) && !(IS_TYPE_FLOAT(left->rtype) && nt != EMODASS)) {
|
|
CError_Error(CErrorStr144);
|
|
return nullnode();
|
|
}
|
|
|
|
left = CExpr_LValue(left, 1, 1);
|
|
tk = lex();
|
|
right = pointer_generation(assignment_expression());
|
|
}
|
|
|
|
if (is_array)
|
|
CError_Error(CErrorStr144);
|
|
|
|
if (IS_TYPE_ENUM(right->rtype))
|
|
right = forceintegral(right);
|
|
|
|
if (IS_TYPE_INT(left->rtype) && IS_TYPE_FLOAT(right->rtype) && nt == EMODASS) {
|
|
CError_Error(CErrorStr144);
|
|
return nullnode();
|
|
}
|
|
|
|
return CExpr_MakeOpAssNode(left, right, nt);
|
|
}
|
|
|
|
static ENode *CExpr_TransformOpAssign(ENode *expr) {
|
|
switch (expr->type) {
|
|
case EMULASS:
|
|
case EDIVASS:
|
|
case EMODASS:
|
|
case EADDASS:
|
|
case ESUBASS:
|
|
case ESHLASS:
|
|
case ESHRASS:
|
|
case EANDASS:
|
|
case EXORASS:
|
|
case EORASS:
|
|
if (expr->rtype == TYPE(&stbool)) {
|
|
expr = CIRTrans_TransformOpAss(expr);
|
|
if (ENODE_IS(expr, EASS)) {
|
|
expr->data.diadic.right = makemonadicnode(expr->data.diadic.right, ELOGNOT);
|
|
expr->data.diadic.right->rtype = TYPE(&stbool);
|
|
expr->data.diadic.right = makemonadicnode(expr->data.diadic.right, ELOGNOT);
|
|
}
|
|
}
|
|
}
|
|
|
|
return expr;
|
|
}
|
|
|
|
ENode *assignment_expression(void) {
|
|
ENode *expr;
|
|
|
|
if (tk == TK_THROW)
|
|
return CExcept_ScanThrowExpression();
|
|
|
|
expr = conditional_expression();
|
|
switch (tk) {
|
|
case '=':
|
|
return makeassignmentnode(expr, EASS, tk);
|
|
case TK_ADD_ASSIGN:
|
|
return CExpr_TransformOpAssign(makepassignmentnode(expr, EADDASS, tk));
|
|
case TK_SUB_ASSIGN:
|
|
return CExpr_TransformOpAssign(makepassignmentnode(expr, ESUBASS, tk));
|
|
case TK_MULT_ASSIGN:
|
|
expr = makemulassignmentnode(expr, EMULASS, tk);
|
|
if (ENODE_IS(expr, EMULASS) && CExpr_IsOne(expr->data.diadic.right))
|
|
return expr->data.diadic.left;
|
|
return CExpr_TransformOpAssign(expr);
|
|
case TK_DIV_ASSIGN:
|
|
expr = makemulassignmentnode(expr, EDIVASS, tk);
|
|
if (ENODE_IS(expr, EDIVASS)) {
|
|
if (iszero(expr->data.diadic.right) && !IS_TYPE_FLOAT(expr->rtype)) {
|
|
CError_Warning(CErrorStr139);
|
|
return expr->data.diadic.left;
|
|
}
|
|
if (CExpr_IsOne(expr->data.diadic.right))
|
|
return expr->data.diadic.left;
|
|
}
|
|
return CExpr_TransformOpAssign(expr);
|
|
case TK_MOD_ASSIGN:
|
|
expr = makemulassignmentnode(expr, EMODASS, tk);
|
|
if (ENODE_IS(expr, EMODASS)) {
|
|
if (iszero(expr->data.diadic.right)) {
|
|
CError_Warning(CErrorStr139);
|
|
return expr->data.diadic.left;
|
|
}
|
|
}
|
|
return CExpr_TransformOpAssign(expr);
|
|
case TK_SHL_ASSIGN:
|
|
expr = makeassignmentnode(expr, ESHLASS, tk);
|
|
if (ENODE_IS(expr, ESHLASS) && iszero(expr->data.diadic.right))
|
|
return expr->data.diadic.left;
|
|
return CExpr_TransformOpAssign(expr);
|
|
case TK_SHR_ASSIGN:
|
|
expr = makeassignmentnode(expr, ESHRASS, tk);
|
|
if (ENODE_IS(expr, ESHRASS) && iszero(expr->data.diadic.right))
|
|
return expr->data.diadic.left;
|
|
return CExpr_TransformOpAssign(expr);
|
|
case TK_AND_ASSIGN:
|
|
expr = makeassignmentnode(expr, EANDASS, tk);
|
|
if (ENODE_IS(expr, EANDASS) && CExpr_AllBitsSet(expr->data.diadic.right))
|
|
return expr->data.diadic.left;
|
|
return expr;
|
|
case TK_XOR_ASSIGN:
|
|
expr = makeassignmentnode(expr, EXORASS, tk);
|
|
if (ENODE_IS(expr, EXORASS) && iszero(expr->data.diadic.right))
|
|
return expr->data.diadic.left;
|
|
return CExpr_TransformOpAssign(expr);
|
|
case TK_OR_ASSIGN:
|
|
expr = makeassignmentnode(expr, EORASS, tk);
|
|
if (ENODE_IS(expr, EORASS) && iszero(expr->data.diadic.right))
|
|
return expr->data.diadic.left;
|
|
return CExpr_TransformOpAssign(expr);
|
|
default:
|
|
return expr;
|
|
}
|
|
}
|
|
|
|
ENode *conv_assignment_expression(void) {
|
|
return pointer_generation(assignment_expression());
|
|
}
|
|
|
|
static Boolean CExpr_HasSideEffect(ENode *expr) {
|
|
switch (expr->type) {
|
|
case EMONMIN:
|
|
case EBINNOT:
|
|
case ELOGNOT:
|
|
case EMUL:
|
|
case EDIV:
|
|
case EMODULO:
|
|
case EADD:
|
|
case ESUB:
|
|
case ESHL:
|
|
case ESHR:
|
|
case ELESS:
|
|
case EGREATER:
|
|
case ELESSEQU:
|
|
case EGREATEREQU:
|
|
case EEQU:
|
|
case ENOTEQU:
|
|
case EAND:
|
|
case EXOR:
|
|
case EOR:
|
|
case ELAND:
|
|
case ELOR:
|
|
case EROTL:
|
|
case EROTR:
|
|
case EBITFIELD:
|
|
case EINTCONST:
|
|
case EFLOATCONST:
|
|
case ESTRINGCONST:
|
|
case EOBJREF:
|
|
case ETEMP:
|
|
case EARGOBJ:
|
|
case ELOCOBJ:
|
|
case EOBJLIST:
|
|
case EMEMBER:
|
|
case EVECTOR128CONST:
|
|
return 0;
|
|
case ETYPCON:
|
|
return IS_TYPE_VOID(expr->rtype);
|
|
case EINDIRECT:
|
|
switch (expr->data.monadic->type) {
|
|
case EFUNCCALL:
|
|
case EFUNCCALLP:
|
|
return 1;
|
|
default:
|
|
return 0;
|
|
}
|
|
case ECOMMA:
|
|
return CInline_ExpressionHasSideEffect(expr->data.diadic.right);
|
|
case ECOND:
|
|
return CInline_ExpressionHasSideEffect(expr->data.cond.expr1) || CInline_ExpressionHasSideEffect(expr->data.cond.expr2);
|
|
case EPOSTINC:
|
|
case EPOSTDEC:
|
|
case EPREINC:
|
|
case EPREDEC:
|
|
case EFORCELOAD:
|
|
case EASS:
|
|
case EMULASS:
|
|
case EDIVASS:
|
|
case EMODASS:
|
|
case EADDASS:
|
|
case ESUBASS:
|
|
case ESHLASS:
|
|
case ESHRASS:
|
|
case EANDASS:
|
|
case EXORASS:
|
|
case EORASS:
|
|
case EFUNCCALL:
|
|
case EFUNCCALLP:
|
|
case EMFPOINTER:
|
|
case ENULLCHECK:
|
|
case EPRECOMP:
|
|
case ELABEL:
|
|
case ENEWEXCEPTION:
|
|
case ENEWEXCEPTIONARRAY:
|
|
case EINITTRYCATCH:
|
|
case EINSTRUCTION:
|
|
return 1;
|
|
default:
|
|
CError_FATAL(7056);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
void CExpr_CheckUnusedExpression(ENode *expr) {
|
|
ENode *scan;
|
|
ENodeList *arg;
|
|
|
|
if (copts.warn_possunwant) {
|
|
scan = expr;
|
|
while (ENODE_IS(scan, ETYPCON))
|
|
scan = scan->data.monadic;
|
|
if (ENODE_IS(scan, EEQU)) {
|
|
CError_Warning(CErrorStr208);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (copts.warn_no_side_effect) {
|
|
if (!CExpr_HasSideEffect(expr)) {
|
|
CError_Warning(CErrorStr369);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (copts.warn_resultnotused) {
|
|
scan = expr;
|
|
if (IS_TYPE_VOID(expr->rtype))
|
|
return;
|
|
if (ENODE_IS(expr, EINDIRECT))
|
|
scan = expr->data.monadic;
|
|
|
|
switch (scan->type) {
|
|
case EFUNCCALL:
|
|
case EFUNCCALLP:
|
|
if (ENODE_IS(scan->data.funccall.funcref, EOBJREF) && scan->data.funccall.funcref->data.objref->name == asop_name_node)
|
|
return;
|
|
if (CMach_GetFunctionResultClass(scan->data.funccall.functype) == 1 && (arg = scan->data.funccall.args)) {
|
|
switch (CABI_GetStructResultArgumentIndex(scan->data.funccall.functype)) {
|
|
case 0:
|
|
break;
|
|
case 1:
|
|
if ((arg = arg->next))
|
|
break;
|
|
CError_FATAL(7110);
|
|
default:
|
|
CError_FATAL(7111);
|
|
}
|
|
|
|
if (!ENODE_IS(arg->node, ETEMP))
|
|
return;
|
|
}
|
|
CError_Warning(CErrorStr370);
|
|
}
|
|
}
|
|
}
|
|
|
|
ENode *s_expression(void) {
|
|
ENode *left;
|
|
ENode *right;
|
|
Conversion conv;
|
|
|
|
left = assignment_expression();
|
|
while (tk == ',') {
|
|
left = pointer_generation(left);
|
|
tk = lex();
|
|
right = pointer_generation(assignment_expression());
|
|
|
|
if (copts.cplusplus && CExpr_CheckOperator(',', left, right, &conv)) {
|
|
CError_ASSERT(7143, left = conv.x0);
|
|
} else {
|
|
CExpr_CheckUnusedExpression(left);
|
|
left = makecommaexpression(left, right);
|
|
left->rtype = right->rtype;
|
|
}
|
|
}
|
|
|
|
return left;
|
|
}
|
|
|
|
ENode *expression(void) {
|
|
return pointer_generation(s_expression());
|
|
}
|
|
|
|
CInt64 CExpr_IntegralConstExprType(Type **tint) {
|
|
ENode *expr;
|
|
|
|
expr = pointer_generation(conditional_expression());
|
|
if (ENODE_IS(expr, EINTCONST)) {
|
|
switch (expr->rtype->type) {
|
|
case TYPEINT:
|
|
*tint = expr->rtype;
|
|
return expr->data.intval;
|
|
case TYPEENUM:
|
|
*tint = TYPE_ENUM(expr->rtype)->enumtype;
|
|
return expr->data.intval;
|
|
}
|
|
}
|
|
|
|
CError_Error(CErrorStr124);
|
|
*tint = TYPE(&stchar);
|
|
return cint64_zero;
|
|
}
|
|
|
|
ENode *CExpr_IntegralConstOrDepExpr(void) {
|
|
ENode *expr;
|
|
|
|
expr = pointer_generation(conditional_expression());
|
|
if (ENODE_IS(expr, EINTCONST)) {
|
|
switch (expr->rtype->type) {
|
|
case TYPEINT:
|
|
return expr;
|
|
case TYPEENUM:
|
|
expr->rtype = TYPE_ENUM(expr->rtype)->enumtype;
|
|
return expr;
|
|
default:
|
|
CError_FATAL(7209);
|
|
}
|
|
}
|
|
|
|
if (CTemplTool_IsTemplateArgumentDependentExpression(expr))
|
|
return expr;
|
|
|
|
CError_Error(CErrorStr124);
|
|
expr = nullnode();
|
|
expr->rtype = TYPE(&stchar);
|
|
return expr;
|
|
}
|
|
|
|
CInt64 CExpr_IntegralConstExpr(void) {
|
|
Type *throwaway;
|
|
return CExpr_IntegralConstExprType(&throwaway);
|
|
}
|
|
|
|
void CExpr_CheckUnwantedAssignment(ENode *expr) {
|
|
if (copts.warn_possunwant) {
|
|
if (ENODE_IS(expr, EASS) && !(expr->flags & ENODE_FLAG_80))
|
|
CError_Warning(CErrorStr207);
|
|
}
|
|
}
|
|
|
|
Boolean CExpr_ParseAsmExpr(Object **objptr, CInt64 *valptr) {
|
|
ENode *expr;
|
|
|
|
if (objptr)
|
|
*objptr = NULL;
|
|
*valptr = cint64_zero;
|
|
|
|
expr = pointer_generation(assignment_expression());
|
|
if (ENODE_IS(expr, EINTCONST)) {
|
|
*valptr = expr->data.intval;
|
|
return 1;
|
|
}
|
|
|
|
if (objptr) {
|
|
switch (expr->type) {
|
|
case EINDIRECT:
|
|
if (CInit_RelocInitCheck(expr->data.monadic, objptr, valptr, 1))
|
|
return 1;
|
|
break;
|
|
case EOBJREF:
|
|
*objptr = expr->data.objref;
|
|
while ((*objptr)->datatype == DALIAS)
|
|
*objptr = (*objptr)->u.alias.object;
|
|
return 1;
|
|
case EMEMBER:
|
|
if (expr->data.emember->list->object->otype == OT_OBJECT) {
|
|
if (expr->data.emember->list->next && expr->data.emember->list->next->object->otype == OT_OBJECT)
|
|
CError_Error(CErrorStr199);
|
|
*objptr = OBJECT(expr->data.emember->list->object);
|
|
while ((*objptr)->datatype == DALIAS)
|
|
*objptr = (*objptr)->u.alias.object;
|
|
return 1;
|
|
}
|
|
break;
|
|
case EOBJLIST:
|
|
CError_Error(CErrorStr199);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
CError_Error(CErrorStr155);
|
|
return 0;
|
|
}
|