diff options
author | Ash Wolf <ninji@wuffs.org> | 2023-01-26 11:30:47 +0000 |
---|---|---|
committer | Ash Wolf <ninji@wuffs.org> | 2023-01-26 11:30:47 +0000 |
commit | 094b96ca1df4a035b5f93c351f773306c0241f3f (patch) | |
tree | 95ce05e3ebe816c7ee7996206bb37ea17d8ca33c /compiler_and_linker/FrontEnd/C/CExpr.c | |
parent | fc0c4c0df7b583b55a08317cf1ef6a71d27c0440 (diff) | |
download | MWCC-main.tar.gz MWCC-main.zip |
move lots of source files around to match their actual placement in the original treemain
Diffstat (limited to 'compiler_and_linker/FrontEnd/C/CExpr.c')
-rw-r--r-- | compiler_and_linker/FrontEnd/C/CExpr.c | 4971 |
1 files changed, 4971 insertions, 0 deletions
diff --git a/compiler_and_linker/FrontEnd/C/CExpr.c b/compiler_and_linker/FrontEnd/C/CExpr.c new file mode 100644 index 0000000..484f56d --- /dev/null +++ b/compiler_and_linker/FrontEnd/C/CExpr.c @@ -0,0 +1,4971 @@ +#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_INLINE_DATA) && 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_COMPLETED)) + 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(NameResult *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(NameResult *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_DEFINED; + + ptm->size = 12; + ptm->ty2 = TYPE(tmethod->theclass); + ptm->ty1 = TYPE(tmethod); + } + + return TYPE(ptm); +} + +static ENode *CExpr_ParseNameResultExpr(NameResult *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->type) { + if (copts.cplusplus) { + if (IS_TYPE_TEMPLATE(pr->type)) { + if (TYPE_TEMPLATE(pr->type)->dtype == TEMPLDEP_ARGUMENT && TYPE_TEMPLATE(pr->type)->u.pid.type == TPT_NONTYPE) { + result = CExpr_NewTemplDepENode(TDE_PARAM); + result->data.templdep.u.pid = TYPE_TEMPLATE(pr->type)->u.pid; + tk = lex(); + return result; + } + if (TYPE_TEMPLATE(pr->type)->dtype == TEMPLDEP_QUALNAME && !pr->x20) { + result = CExpr_NewTemplDepENode(TDE_QUALNAME); + result->data.templdep.u.qual.type = TYPE_TEMPLATE(pr->type)->u.qual.type; + result->data.templdep.u.qual.name = TYPE_TEMPLATE(pr->type)->u.qual.name; + tk = lex(); + return result; + } + } + tk = lex(); + return CExpr_ParseExplicitConversion(pr->type, pr->qual); + } + 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_IS_TEMPL)) { + 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_IS_TEMPL)) { + 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; + NameResult 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(PPCErrorStr104, "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) { + NameResult 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 = 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; + NameResult 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.type) && tk == TK_COLON_COLON) { + tk = lex(); + nspace = TYPE_CLASS(pr.type)->nspace; + goto loop; + } else { + if (!is_typesame(pr.type, 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.type, 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) { + NameResult 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_COMPLETED)) + 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 = 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_IS_TEMPL) + 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->vtbl_index; + 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; + short 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, qual & ENODE_FLAG_QUALS, 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 = 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) != 0) { + 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) != 0) { + 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; +} |