MWCC/compiler_and_linker/unsorted/CExpr.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;
}