#include "compiler/CInit.h" #include "compiler/CABI.h" #include "compiler/CClass.h" #include "compiler/CDecl.h" #include "compiler/CError.h" #include "compiler/CException.h" #include "compiler/CExpr.h" #include "compiler/CInline.h" #include "compiler/CInt64.h" #include "compiler/CMachine.h" #include "compiler/CParser.h" #include "compiler/CPrec.h" #include "compiler/CPrep.h" #include "compiler/CPrepTokenizer.h" #include "compiler/CScope.h" #include "compiler/CompilerTools.h" #include "compiler/ObjGenMachO.h" #include "compiler/objects.h" #include "compiler/types.h" TempNodeCB cinit_tempnodefunc; InitInfo *cinit_initinfo; static PooledString *cinit_stringlist; static PooledString *cinit_pooledstringlist; static PooledString *cinit_pooledwstringlist; static ObjectList *cinit_tentative; static TypeClass *cinit_loop_class; static ENodeList *cinit_fdtnode; static Boolean cinit_fdtambig; #ifdef __MWERKS__ #pragma options align=mac68k #endif typedef struct CInit_1C { struct CInit_1C *next; Type *type; ENode *expr; SInt32 offset; } CInit_1C; typedef struct CInit_Stuff { struct CInit_Stuff *x0; struct CInit_Stuff *x4; char *buffer; SInt32 xC; SInt32 size; SInt32 bufferSize; SInt32 x18; CInit_1C *x1C; OLinkList *list; Boolean flag; } CInit_Stuff; typedef enum { Stage0, Stage1, Stage2, Stage3, Stage4 } Stage; typedef struct CInit_Stuff2 { ENode *expr; ENode myexpr; Stage stage; Boolean x23; SInt32 x24; Type *type; } CInit_Stuff2; #ifdef __MWERKS__ #pragma options align=reset #endif // forward decls static void CInit_InitType(CInit_Stuff *s, CInit_Stuff2 *s2, Type *type, UInt32 qual, Boolean flag); static void CInit_Type(Type *type, UInt32 qual, Boolean flag); void CInit_Init(void) { cinit_tempnodefunc = NULL; cinit_initinfo = NULL; cinit_stringlist = NULL; cinit_pooledstringlist = NULL; cinit_pooledwstringlist = NULL; cinit_tentative = NULL; } static void CInit_SetupInitInfo(InitInfo *info, Object *obj) { memclrw(info, sizeof(InitInfo)); info->obj = obj; info->next = cinit_initinfo; cinit_initinfo = info; } static void CInit_CleanupInitInfo(InitInfo *info) { cinit_initinfo = info->next; } static void CInit_SetupInitInfoBuffer(Type *type) { SInt32 size = type->size; cinit_initinfo->size = size; if (!size) size = 512; else if (size & 1) size++; cinit_initinfo->buffer = lalloc(size); cinit_initinfo->bufferSize = size; memclrw(cinit_initinfo->buffer, size); } static void CInit_SetData(void *data, SInt32 offset, SInt32 size) { SInt32 end; char *buffer; end = offset + size; if (end > cinit_initinfo->size) cinit_initinfo->size = end; if (end > cinit_initinfo->bufferSize) { if (cinit_initinfo->obj->type->size == 0) { if (end < 8000) end += 0x400; else end += 0x4000; } if (end & 1) end++; buffer = lalloc(end); memclrw(buffer, end); memcpy(buffer, cinit_initinfo->buffer, cinit_initinfo->bufferSize); cinit_initinfo->buffer = buffer; cinit_initinfo->bufferSize = end; } if (data) memcpy(cinit_initinfo->buffer + offset, data, size); } typedef struct CInit_Initializer { struct CInit_Initializer *next; struct CInit_Initializer *sublist; ENode *expr; TStreamElement element; } CInit_Initializer; static CInit_Initializer *CInit_ParseInitializerList(void) { CInit_Initializer *r30; CInit_Initializer *r29; CInit_Initializer *tmp; if ((tk = lex()) == '}') return NULL; r30 = NULL; do { if (r30) { tmp = lalloc(sizeof(CInit_Initializer)); r29->next = tmp; r29 = tmp; } if (!r30) { r30 = r29 = lalloc(sizeof(CInit_Initializer)); } r29->next = NULL; if (tk == '{') { r29->element = *CPrep_CurStreamElement(); r29->sublist = CInit_ParseInitializerList(); r29->expr = NULL; tk = lex(); } else { r29->sublist = NULL; r29->expr = conv_assignment_expression(); r29->element = *CPrep_CurStreamElement(); } if (tk == '}') return r30; if (tk != ',') { CError_Error(CErrorStr116); return r30; } } while ((tk = lex()) != '}'); return r30; } static CInit_Initializer *CInit_ParseInitializerClause(void) { CInit_Initializer *init; init = lalloc(sizeof(CInit_Initializer)); init->next = NULL; if (tk != '{') { init->sublist = NULL; init->expr = conv_assignment_expression(); init->element = *CPrep_CurStreamElement(); } else { init->element = *CPrep_CurStreamElement(); init->expr = NULL; init->sublist = CInit_ParseInitializerList(); tk = lex(); } return init; } static ENode *CInit_ParseInitializer(ENode *expr) { CInt64 save_int; Float save_float; SInt32 save_size; short t; switch (tk) { case TK_INTCONST: case TK_FLOATCONST: save_int = tkintconst; save_float = tkfloatconst; save_size = tksize; t = lookahead(); tkintconst = save_int; tkfloatconst = save_float; tksize = save_size; switch (t) { case ',': case ';': case '}': memclrw(expr, sizeof(ENode)); switch (tk) { case TK_INTCONST: expr->type = EINTCONST; expr->rtype = atomtype(); expr->data.intval = tkintconst; break; case TK_FLOATCONST: expr->type = EFLOATCONST; expr->rtype = atomtype(); expr->data.floatval = tkfloatconst; break; } tk = lex(); CPrep_TokenStreamFlush(); return expr; } } expr = assignment_expression(); CPrep_TokenStreamFlush(); return expr; } static Stage CInit_ParseNextInit(CInit_Stuff2 *s) { DeclInfo di; short t; s->expr = NULL; if (tk == ';') { s->stage = Stage4; return Stage4; } switch (s->stage) { case Stage0: if (s->x23) { if (tk == '(') { tk = lex(); CParser_GetDeclSpecs(&di, 1); s->type = di.thetype; if (tk == ')') tk = lex(); else CError_Error(CErrorStr115); if (tk == '(') tk = lex(); else CError_Error(CErrorStr114); s->x24++; t = lookahead(); if (t == TK_UU_VECTOR || (t == TK_IDENTIFIER && !strcmp("vector", tkidentifier->name))) CInit_ParseNextInit(s); s->stage = Stage1; return Stage1; } } else { if (tk == '{') { tk = lex(); s->x24 = 0; s->stage = Stage1; return Stage1; } } s->expr = CInit_ParseInitializer(&s->myexpr); s->stage = Stage2; return Stage2; case Stage1: break; case Stage2: case Stage3: if (tk == ',') { tk = lex(); break; } if (s->x24) { if (tk != ')') CError_Error(CErrorStr174); if (s->x24 > 1) { s->x24--; tk = lex(); CInit_ParseNextInit(s); } } else { if (tk != '}') CError_Error(CErrorStr174); } s->stage = Stage3; return Stage3; default: CError_FATAL(389); } switch (tk) { case '{': tk = lex(); s->stage = Stage1; return Stage1; case '}': s->stage = Stage3; return Stage3; case '(': if (s->x23) { tk = lex(); s->stage = Stage1; return Stage1; } case ')': if (s->x23 && s->x24) { if (s->x24 > 1) { s->x24--; tk = lex(); CInit_ParseNextInit(s); } s->stage = Stage3; return Stage3; } default: s->expr = CInit_ParseInitializer(&s->myexpr); s->stage = Stage2; return Stage2; } } static void CInit_CloseInitList(void) { if (tk == ',' && copts.cplusplus) tk = lex(); if (tk != '}') CError_ErrorSkip(CErrorStr130); else tk = lex(); } static Boolean CInit_IsAllZero(char *buf, SInt32 size) { SInt32 i; if (copts.explicit_zero_data) return 0; for (i = 0; i < size; i++) if (buf[i]) return 0; return 1; } static Boolean CInit_ClassNeedsConstruction(TypeClass *tclass) { return CClass_Constructor(tclass) || CClass_Destructor(tclass); } static Boolean CInit_IsSimpleStructArrayInit(Type *type) { switch (type->type) { case TYPESTRUCT: return 1; case TYPEARRAY: while (IS_TYPE_ARRAY(type)) type = TYPE_POINTER(type)->target; if (!IS_TYPE_CLASS(type)) return 1; case TYPECLASS: return !CInit_ClassNeedsConstruction(TYPE_CLASS(type)); default: return 0; } } static Boolean CInit_IsSimpleInit(Type *type) { switch (type->type) { case TYPEPOINTER: return (TYPE_POINTER(type)->qual & Q_REFERENCE) == 0; case TYPEARRAY: while (IS_TYPE_ARRAY(type)) type = TYPE_POINTER(type)->target; if (!IS_TYPE_CLASS(type)) return 1; case TYPECLASS: return !CInit_ClassNeedsConstruction(TYPE_CLASS(type)); default: return 1; } } static Object *CInit_GetInitObject(Object *obj) { if (obj->datatype == DALIAS) { CError_ASSERT(521, !obj->u.alias.offset); obj = obj->u.alias.object; } return obj; } static Object *CInit_CreateStaticDataObject(Type *type, UInt32 qual, HashNameNode *name) { Object *obj; DeclInfo di; memclrw(&di, sizeof(DeclInfo)); di.thetype = type; di.name = name ? name : CParser_GetUniqueName(); di.qual = qual; di.storageclass = TK_STATIC; di.x4E = 1; obj = CParser_NewGlobalDataObject(&di); obj->nspace = cscope_root; return obj; } static Type *CInit_GetRegMemType(void) { return CDecl_NewStructType(void_ptr.size * 3, CMach_GetTypeAlign((Type *) &void_ptr)); } static Object *CInit_CreateStaticData(Type *type) { Object *obj = CInit_CreateStaticDataObject(type, 0, NULL); CInit_DeclareData(obj, NULL, NULL, obj->type->size); return obj; } static void CInit_InitNonConst(CInit_Stuff *s, Type *type, ENode *expr) { CInit_1C *entry; CInit_1C *scan; MWVector128 *vec; if (s->x4->flag || IS_TYPE_VECTOR(type)) { if (IS_TYPE_VECTOR(type) && ENODE_IS(expr, EVECTOR128CONST)) { vec = (MWVector128 *) (s->buffer + s->size); *vec = expr->data.vector128val; CMach_InitVectorMem(type, *vec, vec, 1); } entry = lalloc(sizeof(CInit_1C)); memclrw(entry, sizeof(CInit_1C)); entry->next = NULL; entry->type = type; entry->expr = expr; entry->offset = s->xC + s->size; if ((scan = s->x4->x1C)) { while (scan->next) scan = scan->next; scan->next = entry; } else { s->x4->x1C = entry; } } else { CError_Error(CErrorStr124); } } static CInit_Stuff *CInit_GrowBuffer(CInit_Stuff *s, SInt32 size) { CInit_Stuff *newbuf; newbuf = lalloc(sizeof(CInit_Stuff)); memclrw(newbuf, sizeof(CInit_Stuff)); newbuf->x4 = s->x4; newbuf->buffer = lalloc(size); newbuf->xC = s->xC + s->size; newbuf->bufferSize = size; s->x0 = newbuf; memset(newbuf->buffer, 0, newbuf->bufferSize); return newbuf; } Boolean CInit_RelocInitCheck(ENode *expr, Object **objptr, CInt64 *valptr, Boolean flag) { Object *objcheck1; Object *objcheck2; CInt64 valcheck1; CInt64 valcheck2; *objptr = NULL; valptr->lo = 0; valptr->hi = 0; while (1) { switch (expr->type) { case EINTCONST: *valptr = expr->data.intval; return 1; case EOBJREF: objcheck1 = CInit_GetInitObject(expr->data.objref); if (objcheck1->datatype == DLOCAL && !flag) return 0; *objptr = objcheck1; return 1; case ESTRINGCONST: CInit_RewriteString(expr, 0); continue; case ETYPCON: do { if (expr->rtype->size != expr->data.monadic->rtype->size) return 0; expr = expr->data.monadic; if (!IS_TYPE_POINTER_ONLY(expr->rtype) && !IS_TYPE_INT(expr->rtype)) return 0; } while (ENODE_IS(expr, ETYPCON)); continue; case EADD: if (!CInit_RelocInitCheck(expr->data.diadic.left, &objcheck1, &valcheck1, flag)) return 0; if (!CInit_RelocInitCheck(expr->data.diadic.right, &objcheck2, &valcheck2, flag)) return 0; if (objcheck1) { if (objcheck2) return 0; *objptr = objcheck1; } else { *objptr = objcheck1; } *valptr = CMach_CalcIntDiadic(TYPE(&stunsignedlong), valcheck1, '+', valcheck2); return 1; case ESUB: if (!CInit_RelocInitCheck(expr->data.diadic.left, &objcheck1, &valcheck1, flag)) return 0; if (!CInit_RelocInitCheck(expr->data.diadic.right, &objcheck2, &valcheck2, flag)) return 0; if (objcheck2) return 0; *objptr = objcheck1; *valptr = CMach_CalcIntDiadic(TYPE(&stunsignedlong), valcheck1, '-', valcheck2); return 1; default: return 0; } } } static void CInit_InitTypePointer(CInit_Stuff *s, ENode *expr, TypePointer *tptr, UInt32 qual) { Object *obj; CInt64 val; OLinkList *list; expr = CExpr_AssignmentPromotion(expr, TYPE(tptr), qual & (Q_CONST | Q_VOLATILE), 1); if (IS_TYPE_POINTER_ONLY(expr->rtype) || ENODE_IS(expr, EINTCONST)) { if (CInit_RelocInitCheck(expr, &obj, &val, 0)) { if (obj) { list = lalloc(sizeof(OLinkList)); list->next = s->x4->list; list->obj = obj; list->somevalue = CInt64_GetULong(&val); list->offset = s->xC + s->size; s->x4->list = list; } else { CMach_InitIntMem(TYPE(&stunsignedlong), val, s->buffer + s->size); } } else { CInit_InitNonConst(s, TYPE(tptr), expr); } } else { CError_Error(CErrorStr174); } } static void CInit_InitTypeInt(CInit_Stuff *s, ENode *expr, TypeIntegral *tint, UInt32 qual) { expr = CExpr_AssignmentPromotion(expr, TYPE(tint), qual & (Q_CONST | Q_VOLATILE), 1); if (IS_TYPE_INT(expr->rtype)) { if (ENODE_IS(expr, EINTCONST)) { CMach_InitIntMem(TYPE(tint), expr->data.intval, s->buffer + s->size); } else if (ENODE_IS(expr, ETYPCON) && IS_TYPE_POINTER_ONLY(expr->data.monadic->rtype) && expr->rtype->size == 4 && (copts.cplusplus || !copts.ANSIstrict)) { CInit_InitTypePointer(s, expr->data.monadic, TYPE_POINTER(expr->data.monadic->rtype), qual); } else { CInit_InitNonConst(s, TYPE(tint), expr); } } else { CError_Error(CErrorStr174); } } static void CInit_InitTypeFloat(CInit_Stuff *s, ENode *expr, TypeIntegral *tint, UInt32 qual) { expr = CExpr_AssignmentPromotion(expr, TYPE(tint), qual & (Q_CONST | Q_VOLATILE), 1); if (IS_TYPE_FLOAT(expr->rtype)) { if (ENODE_IS(expr, EFLOATCONST)) { CMach_InitFloatMem(TYPE(tint), expr->data.floatval, s->buffer + s->size); } else { CInit_InitNonConst(s, TYPE(tint), expr); } } else { CError_Error(CErrorStr174); } } static void CInit_InitTypeEnum(CInit_Stuff *s, ENode *expr, TypeEnum *tenum, UInt32 qual) { expr = CExpr_AssignmentPromotion(expr, TYPE(tenum), qual & (Q_CONST | Q_VOLATILE), 1); if (IS_TYPE_ENUM(expr->rtype)) { if (ENODE_IS(expr, EINTCONST)) { CMach_InitIntMem(tenum->enumtype, expr->data.intval, s->buffer + s->size); } else { CInit_InitNonConst(s, TYPE(tenum), expr); } } else { CError_Error(CErrorStr174); } } static void CInit_InitTypeMemberPointer(CInit_Stuff *s, ENode *expr, TypeMemberPointer *tmptr, UInt32 qual) { expr = CExpr_AssignmentPromotion(expr, TYPE(tmptr), qual & (Q_CONST | Q_VOLATILE), 1); if (ENODE_IS(expr, EINTCONST)) { CMach_InitIntMem(TYPE(&stsignedlong), expr->data.intval, s->buffer + s->size); } else { CInit_InitNonConst(s, TYPE(tmptr), expr); } } static void CInit_SetBitfield(TypeBitfield *tbitfield, UInt8 *buffer, CInt64 val) { int i; int pos; int step; if (copts.littleendian) { pos = tbitfield->unkA; step = 1; } else { pos = tbitfield->unkB + tbitfield->unkA - 1; step = -1; } for (i = 0; i < tbitfield->unkB; i++) { if (CInt64_GetULong(&val) & 1) { if (copts.littleendian) { buffer[pos >> 3] |= 1 << (pos & 7); } else { buffer[pos >> 3] |= 0x80 >> (pos & 7); } } val = CInt64_ShrU(val, cint64_one); pos += step; } } static void CInit_InitTypeBitfield(CInit_Stuff *s, ENode *expr, TypeBitfield *tbitfield, UInt32 qual) { Type *inner; inner = tbitfield->bitfieldtype; if (IS_TYPE_ENUM(inner)) inner = TYPE_ENUM(inner)->enumtype; expr = CExpr_AssignmentPromotion(expr, inner, qual & (Q_CONST | Q_VOLATILE), 1); if (IS_TYPE_INT(expr->rtype)) { if (ENODE_IS(expr, EINTCONST)) { CInit_SetBitfield(tbitfield, (UInt8 *) s->buffer + s->size, expr->data.intval); } else { CInit_InitNonConst(s, TYPE(tbitfield), expr); } } else { CError_Error(CErrorStr174); } } static void CInit_InitTypeArray(CInit_Stuff *s, CInit_Stuff2 *s2, TypePointer *tptr, UInt32 qual, Boolean errorflag) { SInt32 targetsize; SInt32 start; SInt32 i; Boolean flag; Boolean is_zero_size; SInt32 size; SInt32 tmp; Boolean is_char_ptr; Boolean is_wchar_ptr; is_zero_size = tptr->size == 0; targetsize = tptr->target->size; if (!targetsize) { CError_Error(CErrorStr145); return; } is_char_ptr = IS_TYPE_INT(tptr->target) && (targetsize == 1); is_wchar_ptr = IS_TYPE_INT(tptr->target) && (targetsize == stwchar.size); switch (s2->stage) { case Stage1: flag = 1; if (CInit_ParseNextInit(s2) == Stage3) { if (is_zero_size) CError_Error(CErrorStr174); tk = lex(); return; } break; case Stage2: flag = 0; break; } switch (s2->stage) { case Stage1: case Stage2: break; default: CError_Error(CErrorStr174); return; } if (s2->stage == Stage2) s2->expr = pointer_generation(s2->expr); if (s2->stage == Stage2 && ENODE_IS(s2->expr, ESTRINGCONST) && (is_char_ptr || is_wchar_ptr)) { if (IS_TYPE_POINTER_ONLY(s2->expr->rtype) && tptr->target->size != TYPE_POINTER(s2->expr->rtype)->target->size) CError_Warning(CErrorStr174); size = tmp = s2->expr->data.string.size; if (is_zero_size) { tptr->size = s2->expr->data.string.size; if (s->bufferSize < tmp) s = CInit_GrowBuffer(s, tmp); memcpy(s->buffer, s2->expr->data.string.data, size); s->size = size; } else { if (s2->expr->data.string.size > tptr->size) { if (copts.cplusplus || (s2->expr->data.string.size - 1) > tptr->size) CError_Error(CErrorStr147); s2->expr->data.string.size = tptr->size; size = tptr->size; } memcpy(s->buffer + s->size, s2->expr->data.string.data, size); } } else { if (!flag && errorflag) { CError_Error(CErrorStr174); return; } start = s->size; i = 0; while (1) { if (is_zero_size) { size = (i + 1) * targetsize; s->size = start + size - targetsize - s->xC; if (s->size + targetsize > s->bufferSize) s = CInit_GrowBuffer(s, targetsize * 16); CInit_InitType(s, s2, tptr->target, qual, 0); tptr->size = size; s->size = start + size - s->xC; } else { if (tptr->size <= i * targetsize) { i--; CError_Error(CErrorStr147); } s->size = start + i * targetsize; CInit_InitType(s, s2, tptr->target, qual, 0); if (!flag && tptr->size <= (i + 1) * targetsize) break; } switch (CInit_ParseNextInit(s2)) { case Stage1: case Stage2: break; case Stage3: if (flag) tk = lex(); return; default: CError_Error(CErrorStr130); return; } i++; } } if (flag) { switch (CInit_ParseNextInit(s2)) { case Stage3: tk = lex(); return; case Stage2: CError_Error(CErrorStr147); return; default: CError_Error(CErrorStr130); } } } static void CInit_InitTypeStruct(CInit_Stuff *s, CInit_Stuff2 *s2, const TypeStruct *tstruct, UInt32 qual, Boolean errorflag) { StructMember *member; SInt32 start; Boolean flag; SInt32 count; TypePointer arraytype; MWVector128 *vecp; int i; count = 0; if (s2->type) tstruct = TYPE_STRUCT(s2->type); if (!(member = tstruct->members)) { CError_Error(CErrorStr145); return; } switch (s2->stage) { case Stage1: flag = 1; if (CInit_ParseNextInit(s2) == Stage3) { tk = lex(); return; } break; case Stage2: flag = 0; break; } switch (s2->stage) { case Stage1: case Stage2: break; default: CError_Error(CErrorStr174); return; } if (!flag && s2->stage == Stage2 && (errorflag || s2->expr->rtype == TYPE(tstruct))) { s2->expr = CExpr_AssignmentPromotion(s2->expr, TYPE(tstruct), qual, 1); if (IS_TYPE_STRUCT(s2->expr->rtype)) CInit_InitNonConst(s, TYPE(tstruct), s2->expr); return; } start = s->size; while (1) { s->size = start + member->offset; if (!member->type->size) { if (!errorflag || !IS_TYPE_ARRAY(member->type)) { CError_Error(CErrorStr147); if (!IS_TYPE_ARRAY(member->type)) return; } arraytype = *TYPE_POINTER(member->type); CInit_InitTypeArray(s, s2, &arraytype, member->qual, 1); s->x18 = arraytype.size; } else { CInit_InitType(s, s2, member->type, member->qual, 0); } count++; if (IS_TYPESTRUCT_VECTOR(tstruct) && s2->expr) CError_ASSERT(1218, !ENODE_IS(s2->expr, EVECTOR128CONST)); do { member = member->next; } while (member && (member->qual & Q_OVERLOAD)); if (!member || tstruct->stype == STRUCT_TYPE_UNION) { if (flag) { switch (CInit_ParseNextInit(s2)) { case Stage3: if (IS_TYPESTRUCT_VECTOR(tstruct)) { vecp = (MWVector128 *) (s->buffer + start); CMach_InitVectorMem(TYPE(tstruct), *vecp, vecp, 0); } tk = lex(); return; case Stage2: CError_Error(CErrorStr147); return; default: CError_Error(CErrorStr130); return; } } return; } else { switch (CInit_ParseNextInit(s2)) { case Stage1: case Stage2: continue; case Stage3: if (flag) tk = lex(); if (IS_TYPESTRUCT_VECTOR(tstruct)) { switch (TYPE_STRUCT(tstruct)->stype) { case STRUCT_TYPE_4: case STRUCT_TYPE_5: case STRUCT_TYPE_6: if (count != 16) { if (count == 1) { UInt8 val, *p; p = (UInt8 *) s->buffer; val = p[0]; for (i = 1; i < 16; i++) p[i] = val; } else { CError_Error(CErrorStr174); } } break; case STRUCT_TYPE_7: case STRUCT_TYPE_8: case STRUCT_TYPE_9: case STRUCT_TYPE_E: if (count != 8) { if (count == 1) { SInt16 val, *p; p = (SInt16 *) s->buffer; val = p[0]; for (i = 1; i < 8; i++) p[i] = val; } else { CError_Error(CErrorStr174); } } break; case STRUCT_TYPE_A: case STRUCT_TYPE_B: case STRUCT_TYPE_C: case STRUCT_TYPE_D: if (count != 4) { if (count == 1) { UInt32 val, *p; p = (UInt32 *) s->buffer; val = p[0]; for (i = 1; i < 4; i++) p[i] = val; } else { CError_Error(CErrorStr174); } } break; } } return; default: CError_Error(CErrorStr174); return; } } } } static ObjMemberVar *CInit_FindNextMember(ObjMemberVar *ivar) { ObjMemberVar *scan = ivar; while (1) { scan = scan->next; if (!scan) return NULL; if (!scan->anonunion) return scan; if (scan->offset > ivar->offset) return scan; if (IS_TYPE_BITFIELD(scan->type) && IS_TYPE_BITFIELD(ivar->type) && TYPE_BITFIELD(scan->type)->unkA != TYPE_BITFIELD(ivar->type)->unkA) return scan; } } static void CInit_InitTypeClass(CInit_Stuff *s, CInit_Stuff2 *s2, TypeClass *tclass, UInt32 qual, Boolean errorflag) { ObjMemberVar *ivar; SInt32 start; Boolean flag; SInt32 last_offset; TypePointer arraytype; if (tclass->bases || tclass->vtable) { CError_Error(CErrorStr174); return; } switch (s2->stage) { case Stage1: flag = 1; if (CInit_ParseNextInit(s2) == Stage3) { tk = lex(); return; } break; case Stage2: flag = 0; break; } switch (s2->stage) { case Stage1: case Stage2: break; default: CError_Error(CErrorStr174); return; } if (!flag && s2->stage == Stage2 && (errorflag || s2->expr->rtype == TYPE(tclass) || CExpr_CanImplicitlyConvert(s2->expr, TYPE(tclass), 0))) { s2->expr = CExpr_AssignmentPromotion(s2->expr, TYPE(tclass), qual, 1); if (IS_TYPE_CLASS(s2->expr->rtype)) CInit_InitNonConst(s, TYPE(tclass), s2->expr); return; } for (ivar = tclass->ivars; ivar; ivar = ivar->next) { if (ivar->access != ACCESSPUBLIC) { CError_Error(CErrorStr174); break; } } if (!(ivar = tclass->ivars)) { CError_Error(CErrorStr147); return; } start = s->size; while (1) { s->size = start + ivar->offset; if (!ivar->type->size) { if (!errorflag || !IS_TYPE_ARRAY(ivar->type)) { CError_Error(CErrorStr147); if (!IS_TYPE_ARRAY(ivar->type)) return; } arraytype = *TYPE_POINTER(ivar->type); CInit_InitTypeArray(s, s2, &arraytype, ivar->qual, 1); s->x18 = arraytype.size; } else { CInit_InitType(s, s2, ivar->type, ivar->qual, 0); } last_offset = ivar->offset; if (!(ivar = CInit_FindNextMember(ivar)) || (tclass->mode == CLASS_MODE_1 && ivar->offset == last_offset)) { if (flag) { switch (CInit_ParseNextInit(s2)) { case Stage3: tk = lex(); return; case Stage2: CError_Error(CErrorStr147); return; default: CError_Error(CErrorStr130); return; } } return; } else { switch (CInit_ParseNextInit(s2)) { case Stage1: case Stage2: continue; case Stage3: if (flag) tk = lex(); break; default: CError_Error(CErrorStr174); } return; } } } static void CInit_InitType(CInit_Stuff *s, CInit_Stuff2 *s2, Type *type, UInt32 qual, Boolean errorflag) { Boolean flag; switch (type->type) { case TYPEVOID: CError_Error(CErrorStr174); break; case TYPEINT: case TYPEFLOAT: case TYPEENUM: case TYPEBITFIELD: case TYPEMEMBERPOINTER: case TYPEPOINTER: switch (s2->stage) { case Stage1: flag = 1; CInit_ParseNextInit(s2); break; case Stage2: flag = 0; break; } if (s2->stage != Stage2) { CError_Error(CErrorStr174); return; } switch (type->type) { case TYPEINT: CInit_InitTypeInt(s, s2->expr, TYPE_INTEGRAL(type), qual); break; case TYPEFLOAT: CInit_InitTypeFloat(s, s2->expr, TYPE_INTEGRAL(type), qual); break; case TYPEENUM: CInit_InitTypeEnum(s, s2->expr, TYPE_ENUM(type), qual); break; case TYPEPOINTER: CInit_InitTypePointer(s, s2->expr, TYPE_POINTER(type), qual); break; case TYPEMEMBERPOINTER: CInit_InitTypeMemberPointer(s, s2->expr, TYPE_MEMBER_POINTER(type), qual); break; case TYPEBITFIELD: CInit_InitTypeBitfield(s, s2->expr, TYPE_BITFIELD(type), qual); break; default: CError_FATAL(1542); } if (flag) { switch (CInit_ParseNextInit(s2)) { case Stage3: tk = lex(); break; case Stage2: CError_Error(CErrorStr147); break; default: CError_Error(CErrorStr130); } } break; case TYPESTRUCT: CInit_InitTypeStruct(s, s2, TYPE_STRUCT(type), qual, errorflag); break; case TYPEARRAY: CInit_InitTypeArray(s, s2, TYPE_POINTER(type), qual, errorflag); break; case TYPECLASS: CInit_InitTypeClass(s, s2, TYPE_CLASS(type), qual, errorflag); break; default: CError_FATAL(1573); } } static void CInit_InitData(CInit_Stuff *s, Type *type, UInt32 qual, Boolean flag) { CInit_Stuff2 s2; SInt32 size; CInit_Stuff *tmp; char *buffer; locklheap(); memclrw(s, sizeof(CInit_Stuff)); s->x4 = s; if (type->size == 0) { if (IS_TYPE_ARRAY(type)) s->bufferSize = 16 * TYPE_POINTER(type)->target->size; else CError_Error(CErrorStr145); } else { s->bufferSize = type->size; } s->buffer = lalloc(s->bufferSize); memset(s->buffer, 0, s->bufferSize); s->flag = flag; s2.stage = Stage0; s2.x23 = 0; if (IS_TYPE_VECTOR(type)) { s2.x23 = 1; s->flag = 1; } if (IS_TYPE_ARRAY(type) && IS_TYPE_VECTOR(TYPE_POINTER(type)->target)) { s->flag = 1; } s2.type = NULL; s2.x24 = 0; CInit_ParseNextInit(&s2); CInit_InitType(s, &s2, type, qual, 1); if ((size = type->size + s->x18)) { if (s->x0) { buffer = lalloc(size); for (tmp = s; tmp; tmp = tmp->x0) { CError_ASSERT(1647, (tmp->xC + tmp->size) <= size); memcpy(buffer + tmp->xC, tmp->buffer, tmp->size); } s->buffer = buffer; } } else { CError_Error(CErrorStr174); } s->size = size; s->x0 = NULL; unlocklheap(); } static ENode *CInit_InitConcat(ENode *a1, ENode *a2, SInt32 offset, Type *type, ENode *a5) { ENode *r30; ENode *r28; ENode *tmp; r28 = lalloc(sizeof(ENode)); *r28 = *a2; if (offset) r28 = makediadicnode(r28, intconstnode(TYPE(&stunsignedlong), offset), EADD); if (IS_TYPE_BITFIELD(type)) { tmp = makemonadicnode(r28, EBITFIELD); tmp->rtype = type; tmp = makemonadicnode(tmp, EINDIRECT); tmp->rtype = TYPE_BITFIELD(type)->bitfieldtype; } else { tmp = makemonadicnode(r28, EINDIRECT); tmp->rtype = type; } r30 = makediadicnode(tmp, a5, EASS); if (!a1) { return r30; } else { tmp = makediadicnode(a1, r30, ECOMMA); tmp->rtype = r30->rtype; return tmp; } } static ENode *CInit_RegisterDtorObject(Type *type, Object *dtor, ENode *objexpr) { ENode *expr; if (copts.no_static_dtors) return objexpr; expr = lalloc(sizeof(ENode)); expr->type = EFUNCCALL; expr->cost = 4; expr->flags = 0; expr->rtype = CDecl_NewPointerType(type); expr->data.funccall.funcref = create_objectrefnode(Xgreg_func); expr->data.funccall.functype = TYPE_FUNC(Xgreg_func->type); expr->data.funccall.args = lalloc(sizeof(ENodeList)); expr->data.funccall.args->node = objexpr; expr->data.funccall.args->next = lalloc(sizeof(ENodeList)); expr->data.funccall.args->next->node = create_objectrefnode(CABI_GetDestructorObject(dtor, CABIDestroy1)); expr->data.funccall.args->next->next = lalloc(sizeof(ENodeList)); expr->data.funccall.args->next->next->node = create_objectrefnode(CInit_CreateStaticData(CInit_GetRegMemType())); expr->data.funccall.args->next->next->next = NULL; return expr; } static Boolean CInit_ConstructGlobalObject(Object *obj, TypeClass *tclass, ENode *valueexpr, SInt32 offset, Boolean flag) { NameSpaceObjectList *ctor; Object *dtor; ENodeList *list; ENode *expr; Boolean ctorflag; ctor = CClass_Constructor(tclass); dtor = CClass_Destructor(tclass); if (!ctor && !dtor) return 0; if (flag && !ctor && tk == '=' && lookahead() == '{') return 0; if (flag && tk == '(') { tk = lex(); list = CExpr_ScanExpressionList(1); if (tk == ')') tk = lex(); else CError_Error(CErrorStr115); } else if (valueexpr) { list = lalloc(sizeof(ENodeList)); list->node = valueexpr; list->next = NULL; } else { list = NULL; } expr = create_objectrefnode(obj); if (offset) expr = makediadicnode(expr, intconstnode(TYPE(&stunsignedlong), offset), EADD); if (ctor) { ctorflag = 1; if (tk == '=') { ctorflag = 0; if (list) CError_Error(CErrorStr174); list = lalloc(sizeof(ENodeList)); list->next = NULL; tk = lex(); list->node = conv_assignment_expression(); } expr = CExpr_ConstructObject(tclass, expr, list, 0, 1, 0, 1, ctorflag); if (expr->rtype->type != TYPEPOINTER) { CError_Error(CErrorStr174); return 1; } } else { if (list) CError_Error(CErrorStr174); } if (dtor) expr = CInit_RegisterDtorObject(TYPE(tclass), dtor, expr); if (cinit_initinfo->x16) cinit_initinfo->init_expr_register_cb(expr); else InitExpr_Register(expr, obj); return 1; } static Boolean CInit_ConstructAutoObject(TypeClass *tclass, ENode *expr, SInt32 offset, Boolean flag) { ENodeList *r30; ENode *r29; NameSpaceObjectList *ctor; Object *dtor; Boolean r24; ctor = CClass_Constructor(tclass); dtor = CClass_Destructor(tclass); if (!ctor && !dtor) return 0; if (dtor) CClass_CheckStaticAccess(NULL, tclass, dtor->access); if (flag && !ctor && tk == '=' && lookahead() == '{') return 0; if (flag && tk == '(') { tk = lex(); r30 = CExpr_ScanExpressionList(1); if (tk == ')') tk = lex(); else CError_Error(CErrorStr115); } else if (expr) { r30 = lalloc(sizeof(ENodeList)); r30->node = expr; r30->next = NULL; } else { r30 = NULL; } if (ctor) { r24 = 1; if (tk == '=') { if (r30) CError_Error(CErrorStr174); r30 = lalloc(sizeof(ENodeList)); r30->next = NULL; tk = lex(); r30->node = conv_assignment_expression(); r24 = 0; } if (!dtor) { r29 = create_objectrefnode(cinit_initinfo->obj1C); if (offset) r29 = makediadicnode(r29, intconstnode(TYPE(&stunsignedlong), offset), EADD); } else { r29 = cinit_initinfo->register_object_cb(TYPE(tclass), cinit_initinfo->obj1C, offset, 0); } r29 = CExpr_ConstructObject(tclass, r29, r30, 0, 1, 0, 1, r24); if (!IS_TYPE_POINTER_ONLY(r29->rtype)) { CError_Error(CErrorStr174); return 1; } r29 = makemonadicnode(r29, EINDIRECT); r29->rtype = TYPE_POINTER(r29->rtype)->target; cinit_initinfo->insert_expr_cb(r29); } else { if (r30) CError_Error(CErrorStr174); if (dtor) r29 = cinit_initinfo->register_object_cb(TYPE(tclass), cinit_initinfo->obj1C, offset, 0); cinit_initinfo->insert_expr_cb(r29); } return 1; } static void CInit_ExprPointer(TypePointer *tptr, ENode *expr) { Object *obj; CInt64 val; OLinkList *list; if (CInit_RelocInitCheck(expr, &obj, &val, 0)) { if (obj) { list = lalloc(sizeof(OLinkList)); list->next = cinit_initinfo->list; list->obj = obj; list->somevalue = CInt64_GetULong(&val); list->offset = cinit_initinfo->expr_offset; cinit_initinfo->list = list; } else { CMach_InitIntMem(TYPE(&stunsignedlong), val, cinit_initinfo->buffer + cinit_initinfo->expr_offset); } } else if (cinit_initinfo->expr_cb) { cinit_initinfo->expr_cb(TYPE(tptr), expr, 0); cinit_initinfo->expr_cb_called = 1; } else { CError_Error(CErrorStr124); } cinit_initinfo->expr_offset += 4; } static void CInit_ExprInt(TypeIntegral *tint, ENode *expr) { if (ENODE_IS(expr, EINTCONST)) { CMach_InitIntMem(TYPE(tint), expr->data.intval, cinit_initinfo->buffer + cinit_initinfo->expr_offset); } else if (ENODE_IS(expr, ETYPCON) && IS_TYPE_POINTER_ONLY(expr->data.monadic->rtype) && expr->rtype->size == 4 && (copts.cplusplus || !copts.ANSIstrict)) { CInit_ExprPointer(TYPE_POINTER(expr->data.monadic->rtype), expr->data.monadic); } else if (cinit_initinfo->expr_cb) { cinit_initinfo->expr_cb(TYPE(tint), expr, 0); cinit_initinfo->expr_cb_called = 1; } else { CError_Error(CErrorStr124); } cinit_initinfo->expr_offset += tint->size; } static void CInit_ExprFloat(TypeIntegral *tint, ENode *expr) { if (ENODE_IS(expr, EFLOATCONST)) { CMach_InitFloatMem(TYPE(tint), expr->data.floatval, cinit_initinfo->buffer + cinit_initinfo->expr_offset); } else if (cinit_initinfo->expr_cb) { cinit_initinfo->expr_cb(TYPE(tint), expr, 0); cinit_initinfo->expr_cb_called = 1; } else { CError_Error(CErrorStr124); } cinit_initinfo->expr_offset += tint->size; } static void CInit_ExprEnum(TypeEnum *tenum, ENode *expr) { if (ENODE_IS(expr, EINTCONST)) { CMach_InitIntMem(tenum->enumtype, expr->data.intval, cinit_initinfo->buffer + cinit_initinfo->expr_offset); } else if (cinit_initinfo->expr_cb) { cinit_initinfo->expr_cb(TYPE(tenum), expr, 0); cinit_initinfo->expr_cb_called = 1; } else { CError_Error(CErrorStr124); } cinit_initinfo->expr_offset += tenum->size; } static void CInit_ExprMemberPointer(TypeMemberPointer *tmptr, ENode *expr) { if (ENODE_IS(expr, EINTCONST)) { CMach_InitIntMem(TYPE(&stsignedlong), expr->data.intval, cinit_initinfo->buffer + cinit_initinfo->expr_offset); } else if (cinit_initinfo->expr_cb) { cinit_initinfo->expr_cb(TYPE(tmptr), expr, 0); cinit_initinfo->expr_cb_called = 1; } else { CError_Error(CErrorStr124); } cinit_initinfo->expr_offset += tmptr->size; } static void CInit_TypeExpr(Type *type, ENode *expr) { switch (type->type) { case TYPEINT: CInit_ExprInt(TYPE_INTEGRAL(type), expr); break; case TYPEFLOAT: CInit_ExprFloat(TYPE_INTEGRAL(type), expr); break; case TYPEENUM: CInit_ExprEnum(TYPE_ENUM(type), expr); break; case TYPEPOINTER: CInit_ExprPointer(TYPE_POINTER(type), expr); break; case TYPEMEMBERPOINTER: CInit_ExprMemberPointer(TYPE_MEMBER_POINTER(type), expr); break; case TYPESTRUCT: case TYPECLASS: if (cinit_initinfo->expr_cb) { cinit_initinfo->expr_cb(type, expr, 0); cinit_initinfo->expr_cb_called = 1; } else { CError_Error(CErrorStr124); } break; case TYPEARRAY: CError_Error(CErrorStr174); break; default: CError_FATAL(2082); } } static void CInit_Bitfield(TypeBitfield *tbitfield) { Boolean r30; ENode *expr; ENode myexpr; r30 = tk == '{'; if (r30) tk = lex(); expr = CInit_ParseInitializer(&myexpr); expr = CExpr_AssignmentPromotion( expr, IS_TYPE_ENUM(tbitfield->bitfieldtype) ? TYPE_ENUM(tbitfield->bitfieldtype)->enumtype : tbitfield->bitfieldtype, 0, 1); if (ENODE_IS(expr, EINTCONST)) CInit_SetBitfield(tbitfield, (UInt8 *) cinit_initinfo->buffer + cinit_initinfo->expr_offset, expr->data.intval); else CError_Error(CErrorStr124); if (r30) CInit_CloseInitList(); } static void CInit_Array(TypePointer *tptr, UInt32 qual, Boolean flag) { SInt32 start; SInt32 i; SInt32 targetsize1; SInt32 targetsize2; Boolean in_block; Boolean is_char_ptr; Boolean needs_construction; Boolean is_wchar_ptr; targetsize1 = tptr->target->size; targetsize2 = tptr->target->size; if (!tptr->target->size) { if (!IS_TYPE_ARRAY(tptr->target)) { CError_Error(CErrorStr145); return; } targetsize1 = tptr->target->size; targetsize2 = tptr->target->size; if (!tptr->target->size) { CError_Error(CErrorStr145); return; } } is_char_ptr = IS_TYPE_INT(tptr->target) && (tptr->target->size == 1); is_wchar_ptr = IS_TYPE_INT(tptr->target) && (tptr->target->size == stwchar.size); in_block = 1; if (flag && !(tk == TK_STRING && is_char_ptr) && !(tk == TK_STRING_WIDE && is_wchar_ptr)) { if (tk != '{') { CError_ErrorSkip(CErrorStr135); return; } tk = lex(); } else { if (tk == '{') tk = lex(); else in_block = 0; } if ((tk == TK_STRING && is_char_ptr) || (tk == TK_STRING_WIDE && is_wchar_ptr)) { if (tptr->size) { if (tksize > tptr->size) { if (copts.cplusplus || (tksize - (is_wchar_ptr ? stwchar.size : 1)) > tptr->size) CError_Error(CErrorStr147); tksize = tptr->size; } memcpy(cinit_initinfo->buffer + cinit_initinfo->expr_offset, tkstring, tksize); } else { tptr->size = tksize; CInit_SetData(tkstring, cinit_initinfo->expr_offset, tptr->size); } cinit_initinfo->expr_offset += tptr->size; tk = lex(); if (in_block) CInit_CloseInitList(); return; } if (IS_TYPE_CLASS(tptr->target) && CInit_ClassNeedsConstruction(TYPE_CLASS(tptr->target))) needs_construction = 1; else needs_construction = 0; start = cinit_initinfo->expr_offset; i = 0; while (1) { if (tk == '}') { innerloop: if (tptr->size) { if (needs_construction) { while (tptr->size > (i * targetsize1)) { cinit_initinfo->expr_offset = start + i * targetsize2; if (cinit_initinfo->expr_cb) { cinit_initinfo->expr_cb(tptr->target, NULL, 1); cinit_initinfo->expr_cb_called = 1; } else { CError_Error(CErrorStr174); } i++; } } } else { tptr->size = i * targetsize1; } cinit_initinfo->expr_offset = start + tptr->size; if (in_block) tk = lex(); return; } if (!tptr->size) { cinit_initinfo->expr_offset = start + i * targetsize2; CInit_SetData(NULL, cinit_initinfo->expr_offset, targetsize2); if (needs_construction) { if (cinit_initinfo->expr_cb) { cinit_initinfo->expr_cb(tptr->target, conv_assignment_expression(), 1); cinit_initinfo->expr_cb_called = 1; } else { CError_Error(CErrorStr174); } } else { CInit_Type(tptr->target, qual, 0); } } else { if (tptr->size <= i * targetsize1) { i--; CError_Error(CErrorStr147); } cinit_initinfo->expr_offset = start + i * targetsize2; if (needs_construction) { if (cinit_initinfo->expr_cb) { cinit_initinfo->expr_cb(tptr->target, conv_assignment_expression(), 1); cinit_initinfo->expr_cb_called = 1; } else { CError_Error(CErrorStr174); } } else { CInit_Type(tptr->target, qual, 0); } if (!in_block) { if (tptr->size <= (i + 1) * targetsize1) return; } } if (tk != '}') { if (tk != ',') { CError_ErrorSkip(CErrorStr121); in_block = 0; i++; goto innerloop; } tk = lex(); } i++; } } static void CInit_Struct(TypeStruct *tstruct, Boolean flag) { StructMember *member; SInt32 start; Boolean in_block; if (!(member = tstruct->members)) { CError_Error(CErrorStr145); return; } if (tstruct->stype == STRUCT_TYPE_UNION) { if (tk == '{') { tk = lex(); CInit_Type(member->type, member->qual, 0); if (tk == '}') tk = lex(); } else { CInit_Type(member->type, member->qual, 0); } return; } if (IS_TYPE_VECTOR(tstruct) && tk != '{') { CInit_TypeExpr(TYPE(tstruct), CExpr_AssignmentPromotion(conv_assignment_expression(), TYPE(tstruct), 0, 1)); return; } if (tk != '{') { if (flag) CError_ErrorSkip(CErrorStr135); in_block = 0; } else { in_block = 1; tk = lex(); } start = cinit_initinfo->expr_offset; while (1) { if (tk == '}') break; cinit_initinfo->expr_offset = start + member->offset; if (!member->type->size && IS_TYPE_ARRAY(member->type)) { CError_Error(CErrorStr147); break; } CInit_Type(member->type, member->qual, 0); if (tk == '}') break; if (tk != ',') { CError_Error(CErrorStr121); break; } do { member = member->next; } while (member && (member->qual & Q_OVERLOAD)); if (!member) { if (!in_block) break; if ((tk = lex()) != '}') { CError_Error(CErrorStr147); break; } } else { tk = lex(); } } cinit_initinfo->expr_offset = start + tstruct->size; if (tk == '}' && in_block) tk = lex(); } static void CInit_Class(TypeClass *tclass, Boolean flag) { ObjMemberVar *ivar; SInt32 start; Boolean in_block; if (tk == '{') { in_block = 1; tk = lex(); } else { in_block = 0; } if (tclass->bases || tclass->vtable) { CError_Error(CErrorStr174); return; } for (ivar = tclass->ivars; ivar; ivar = ivar->next) { if (ivar->access != ACCESSPUBLIC) break; } if (!ivar && !CClass_Constructor(tclass) && (!CClass_Destructor(tclass) || in_block)) { if ((ivar = tclass->ivars)) { start = cinit_initinfo->expr_offset; while (1) { if (tk == '}') break; if (!ivar->type->size && IS_TYPE_ARRAY(ivar->type)) { CError_Error(CErrorStr147); break; } cinit_initinfo->expr_offset = start + ivar->offset; CInit_Type(ivar->type, ivar->qual, 0); if (tk == '}') break; if (tk != ',') { CError_Error(CErrorStr121); break; } do { ivar = ivar->next; } while (ivar && ivar->anonunion); if (!ivar) { if (!in_block) break; if ((tk = lex()) != '}') { CError_Error(CErrorStr147); break; } } else { tk = lex(); } } } else { if (in_block && tk != '}') CError_Error(CErrorStr147); } } else { if (in_block) CError_Error(CErrorStr174); CInit_TypeExpr(TYPE(tclass), CExpr_AssignmentPromotion(conv_assignment_expression(), TYPE(tclass), 0, 1)); } cinit_initinfo->expr_offset = start + tclass->size; if (tk == '}' && in_block) tk = lex(); } static void CInit_Type(Type *type, UInt32 qual, Boolean flag) { ENode *expr; ENode myexpr; switch (type->type) { case TYPEVOID: CError_Error(CErrorStr174); break; case TYPEINT: case TYPEFLOAT: case TYPEENUM: case TYPEPOINTER: case TYPEMEMBERPOINTER: if (tk == '{') { tk = lex(); expr = CInit_ParseInitializer(&myexpr); expr = CExpr_AssignmentPromotion(expr, type, qual & (Q_CONST | Q_VOLATILE), 1); CInit_CloseInitList(); } else { expr = CInit_ParseInitializer(&myexpr); expr = CExpr_AssignmentPromotion(expr, type, qual & (Q_CONST | Q_VOLATILE), 1); } CInit_TypeExpr(type, expr); break; case TYPEBITFIELD: CInit_Bitfield(TYPE_BITFIELD(type)); break; case TYPEARRAY: CInit_Array(TYPE_POINTER(type), qual, flag); break; case TYPESTRUCT: CInit_Struct(TYPE_STRUCT(type), flag); break; case TYPECLASS: CInit_Class(TYPE_CLASS(type), flag); break; default: CError_FATAL(2482); } } static void CInit_GlobalStaticInit(Type *type, ENode *valueexpr, Boolean flag) { ENode *expr; ENode *tmp; cinit_initinfo->x15 = 1; if (flag) { CInit_ConstructGlobalObject(cinit_initinfo->obj, TYPE_CLASS(type), valueexpr, cinit_initinfo->expr_offset, 0); } else { expr = create_objectrefnode(cinit_initinfo->obj); if (!IS_TYPE_POINTER_ONLY(expr->rtype)) { CError_Error(CErrorStr174); return; } TYPE_POINTER(expr->rtype)->target = type; if (cinit_initinfo->expr_offset) expr = makediadicnode(expr, intconstnode(TYPE(&stunsignedlong), cinit_initinfo->expr_offset), EADD); tmp = makemonadicnode(expr, EINDIRECT); tmp->rtype = type; expr = makediadicnode(tmp, valueexpr, EASS); if (cinit_initinfo->x16) cinit_initinfo->init_expr_register_cb(expr); else InitExpr_Register(expr, cinit_initinfo->obj); } } static void CInit_AutoInit(Type *type, ENode *valueexpr, Boolean flag) { ENode *expr; ENode *tmp; Type *copy; SInt32 size; if (flag) { CInit_ConstructAutoObject(TYPE_CLASS(type), valueexpr, cinit_initinfo->expr_offset, 0); } else { if (IS_TYPE_ARRAY(type) && (type->size & 1)) { copy = galloc(sizeof(TypePointer)); *TYPE_POINTER(copy) = *TYPE_POINTER(type); type = copy; type->size++; } expr = create_objectrefnode(cinit_initinfo->obj1C); if (!IS_TYPE_POINTER_ONLY(expr->rtype)) { CError_Error(CErrorStr174); return; } TYPE_POINTER(expr->rtype)->target = type; if (cinit_initinfo->expr_offset) expr = makediadicnode(expr, intconstnode(TYPE(&stunsignedlong), cinit_initinfo->expr_offset), EADD); tmp = makemonadicnode(expr, EINDIRECT); tmp->rtype = type; expr = makediadicnode(tmp, valueexpr, EASS); if (!copts.cplusplus) CError_Error(CErrorStr124); cinit_initinfo->insert_expr_cb(expr); } } static SInt32 CInit_AdjustObjectDataSize(Object *obj) { if (obj->type->size <= 1) return obj->type->size; if (obj->type->size & 1) return obj->type->size + 1; else return obj->type->size; } static ENode *CInit_GenericData(Object *obj, Type *type, UInt32 qual, ExprCB expr_cb, Boolean flag) { Object *r31; ENode *expr; ENode *tmpexpr; Type *inner; Type *copy; SInt32 size; Boolean lastflag; SInt16 cv; cinit_initinfo->expr_cb = expr_cb; expr = NULL; if (tk == '(') { if (IS_TYPE_ARRAY(type)) CError_Error(CErrorStr174); tk = lex(); expr = CExpr_AssignmentPromotion(assignment_expression(), type, qual, 1); if (tk != ')') CError_ErrorSkip(CErrorStr115); else tk = lex(); goto jump_ahead; } tk = lex(); switch (type->type) { case TYPECLASS: if (tk == '{' && CClass_Constructor(TYPE_CLASS(type))) CError_Error(CErrorStr174); case TYPESTRUCT: if (tk != '{') goto generic_type; case TYPEARRAY: if (!obj) { if (IS_TYPE_ARRAY(type)) { inner = type; while (IS_TYPE_ARRAY(inner)) inner = TYPE_POINTER(inner)->target; if (IS_TYPE_CLASS(inner) && CInit_ClassNeedsConstruction(TYPE_CLASS(inner))) { CInit_SetupInitInfoBuffer(type); cinit_initinfo->obj = cinit_initinfo->obj1C; CInit_Type(type, cinit_initinfo->obj->qual, 1); return 0; } if (type->size & 1) { copy = galloc(sizeof(TypePointer)); *TYPE_POINTER(copy) = *TYPE_POINTER(type); type = copy; type->size++; } } obj = CInit_CreateStaticDataObject(type, qual, NULL); cinit_initinfo->obj = obj; expr = create_objectnode(obj); cinit_initinfo->obj1C = obj; } CInit_SetupInitInfoBuffer(type); CInit_Type(type, obj->qual, 1); CError_ASSERT(2639, obj->type->size == (size = cinit_initinfo->size)); if (cinit_initinfo->list || !CInit_IsAllZero(cinit_initinfo->buffer, size)) { CInit_AdjustObjectDataSize(obj); CInit_DeclareData(obj, cinit_initinfo->buffer, cinit_initinfo->list, obj->type->size); } else { CInit_AdjustObjectDataSize(obj); CInit_DeclareData(obj, NULL, NULL, obj->type->size); } return expr; case TYPEINT: case TYPEFLOAT: case TYPEENUM: case TYPEPOINTER: case TYPEMEMBERPOINTER: generic_type: if (obj) { cv = obj->qual; cv &= Q_CONST | Q_VOLATILE; } else { cv = cinit_initinfo->obj1C->qual; cv &= Q_CONST | Q_VOLATILE; } if (tk == '{') { tk = lex(); expr = assignment_expression(); CInit_CloseInitList(); } else { expr = assignment_expression(); } expr = CExpr_AssignmentPromotion(expr, type, cv, 1); jump_ahead: if (obj == NULL) r31 = cinit_initinfo->obj1C; else r31 = obj; if (is_const_object(r31)) { switch (r31->type->type) { case TYPEINT: case TYPEENUM: if (ENODE_IS(expr, EINTCONST)) { r31->u.data.u.intconst = expr->data.intval; goto common_8068C; } break; case TYPEFLOAT: if (ENODE_IS(expr, EFLOATCONST)) { Float fl; r31->u.data.u.floatconst = galloc(sizeof(Float)); fl = CMach_CalcFloatConvert(r31->type, expr->data.floatval); *r31->u.data.u.floatconst = fl; goto common_8068C; } break; case TYPEPOINTER: tmpexpr = expr; while (ENODE_IS(tmpexpr, ETYPCON)) tmpexpr = tmpexpr->data.monadic; if (!ENODE_IS(tmpexpr, EINTCONST)) break; r31->u.data.u.intconst = tmpexpr->data.intval; common_8068C: r31->qual |= Q_10000; if (!obj) { r31->sclass = TK_STATIC; r31->datatype = DDATA; r31->u.data.linkname = CParser_AppendUniqueName(r31->name->name); } else if (r31->sclass != TK_STATIC || (r31->flags & OBJECT_FLAGS_2)) { CInit_ExportConst(r31); } return NULL; } } if (!obj || (flag && copts.cplusplus)) { if (obj) { IsCompleteType(obj->type); CError_ASSERT(2747, obj->type->size == type->size); CInit_DeclareData(obj, NULL, NULL, obj->type->size); } return expr; } CInit_SetupInitInfoBuffer(type); CInit_TypeExpr(type, expr); CError_ASSERT(2756, obj->type->size == cinit_initinfo->size); IsCompleteType(obj->type); CInit_AdjustObjectDataSize(obj); lastflag = !cinit_initinfo->x15 && is_const_object(r31); if (cinit_initinfo->list || !CInit_IsAllZero(cinit_initinfo->buffer, obj->type->size)) { if (lastflag) CInit_DeclareReadOnlyData(obj, cinit_initinfo->buffer, cinit_initinfo->list, obj->type->size); else CInit_DeclareData(obj, cinit_initinfo->buffer, cinit_initinfo->list, obj->type->size); } else { if (lastflag) CInit_DeclareReadOnlyData(obj, NULL, NULL, obj->type->size); else CInit_DeclareData(obj, NULL, NULL, obj->type->size); } break; default: CError_FATAL(2776); } return NULL; } void CInit_ExportConst(Object *obj) { char buffer[64]; if (obj->flags & OBJECT_FLAGS_4) return; switch (obj->type->type) { case TYPEINT: CMach_InitIntMem(obj->type, obj->u.data.u.intconst, buffer); break; case TYPEENUM: CMach_InitIntMem(TYPE_ENUM(obj->type)->enumtype, obj->u.data.u.intconst, buffer); break; case TYPEPOINTER: CMach_InitIntMem(TYPE(&stunsignedlong), obj->u.data.u.intconst, buffer); break; case TYPEFLOAT: CMach_InitFloatMem(obj->type, *obj->u.data.u.floatconst, buffer); break; default: CError_FATAL(2807); } if (is_const_object(obj)) CInit_DeclareReadOnlyData(obj, buffer, NULL, obj->type->size); else CInit_DeclareData(obj, buffer, NULL, obj->type->size); } static ENode *CInit_ClassInitLoopCallBack(ENode *expr) { return CExpr_ConstructObject(cinit_loop_class, expr, NULL, 0, 1, 0, 1, 1); } Statement *CInit_ConstructClassArray(Statement *stmt, TypeClass *tclass, Object *ctor, Object *dtor, ENode *firstarg, SInt32 count) { ENode *dtor_expr; if (stmt) stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt); else stmt = CFunc_AppendStatement(ST_EXPRESSION); if (dtor) dtor_expr = create_objectrefnode(CABI_GetDestructorObject(dtor, CABIDestroy1)); else dtor_expr = nullnode(); stmt->expr = CExpr_FuncCallSix( carr_func, firstarg, create_objectrefnode(ctor), dtor_expr, intconstnode(TYPE(&stunsignedlong), tclass->size), intconstnode(TYPE(&stunsignedlong), count), NULL ); return stmt; } static void CInit_InitializeClassArray(Object *obj, TypeClass *tclass, Boolean flag) { Object *ctor; Object *dtor; SInt32 count; SInt32 i; ENode *expr; SInt32 offset; ENode *dtor_expr; Statement *stmt; TypeFunc *tfunc; Object *funcobj; dtor = CClass_Destructor(tclass); count = obj->type->size / tclass->size; if (CClass_Constructor(tclass)) { ctor = CClass_DefaultConstructor(tclass); if (!ctor) { ctor = CClass_DummyDefaultConstructor(tclass); if (!ctor) { CError_Error(CErrorStr203); return; } } } else { ctor = NULL; } if (count <= 1 || (!flag && count <= 8)) { if (flag) { for (i = 0; i < count; i++) { CInit_ConstructGlobalObject(obj, tclass, NULL, i * tclass->size, 0); } } else { for (i = 0; i < count; i++) { offset = i * tclass->size; expr = create_objectrefnode(obj); if (offset) expr = makediadicnode(expr, intconstnode(TYPE(&stunsignedlong), offset), EADD); if (ctor) expr = CExpr_ConstructObject(tclass, expr, NULL, 0, 1, 0, 1, 1); cinit_initinfo->insert_expr_cb(expr); if (dtor) CExcept_RegisterDestructorObject(obj, offset, dtor, 1); } if (dtor) { stmt = CFunc_AppendStatement(ST_EXPRESSION); stmt->expr = nullnode(); } } } else { if (ctor) { if (!flag && !dtor) { CInit_ConstructClassArray(NULL, tclass, ctor, dtor, create_objectrefnode(obj), count); expr = nullnode(); } else { if (dtor) dtor_expr = create_objectrefnode(CABI_GetDestructorObject(dtor, CABIDestroy1)); else dtor_expr = nullnode(); expr = CExpr_FuncCallSix( carr_func, create_objectrefnode(obj), create_objectrefnode(ctor), dtor_expr, intconstnode(TYPE(&stunsignedlong), tclass->size), intconstnode(TYPE(&stunsignedlong), count), NULL ); } } else { expr = nullnode(); } if (flag) { if (dtor && !copts.no_static_dtors) { tfunc = galloc(sizeof(TypeFunc)); memclrw(tfunc, sizeof(TypeFunc)); tfunc->type = TYPEFUNC; tfunc->functype = &stvoid; CDecl_SetFuncFlags(tfunc, 1); funcobj = CParser_NewCompilerDefFunctionObject(); funcobj->name = CParser_AppendUniqueName("__arraydtor"); funcobj->type = TYPE(tfunc); funcobj->sclass = TK_STATIC; funcobj->qual = Q_INLINE; CParser_RegisterSingleExprFunction(funcobj, funccallexpr( darr_func, create_objectrefnode(obj), create_objectrefnode(CABI_GetDestructorObject(dtor, CABIDestroy1)), intconstnode(TYPE(&stsignedlong), tclass->size), intconstnode(TYPE(&stsignedlong), count) )); expr = makediadicnode(expr, nullnode(), ECOMMA); expr->rtype = TYPE(&void_ptr); expr = funccallexpr( Xgreg_func, expr, create_objectrefnode(funcobj), create_objectrefnode(CInit_CreateStaticData(CInit_GetRegMemType())), NULL ); } if (cinit_initinfo->x16) cinit_initinfo->init_expr_register_cb(expr); else InitExpr_Register(expr, obj); } else { stmt = CFunc_AppendStatement(ST_EXPRESSION); stmt->expr = expr; if (dtor) { CExcept_RegisterLocalArray(stmt, obj, dtor, count, tclass->size); stmt = CFunc_AppendStatement(ST_EXPRESSION); stmt->expr = nullnode(); } } } } static ENode *CInit_AutoTempNode(Type *type, Boolean flag) { ENode *node; node = CExpr_NewETEMPNode(type, 0); if (IS_TYPE_CLASS(type) && CClass_Destructor(TYPE_CLASS(type))) node->data.temp.needs_dtor = 1; return node; } static ENode *CInit_GlobalTempNode(Type *type, Boolean flag) { Object *dtor; ENode *node; ENode *funcnode; node = create_objectrefnode(CInit_CreateStaticData(type)); if (IS_TYPE_CLASS(type) && (dtor = CClass_Destructor(TYPE_CLASS(type))) && !copts.no_static_dtors) { if (flag) CError_Error(CErrorStr190); funcnode = galloc(sizeof(ENode)); funcnode->type = EFUNCCALL; funcnode->cost = 200; funcnode->flags = 0; funcnode->rtype = CDecl_NewPointerType(type); funcnode->data.funccall.funcref = create_objectrefnode(Xgreg_func); funcnode->data.funccall.functype = TYPE_FUNC(Xgreg_func->type); funcnode->data.funccall.args = lalloc(sizeof(ENodeList)); funcnode->data.funccall.args->node = node; funcnode->data.funccall.args->next = lalloc(sizeof(ENodeList)); funcnode->data.funccall.args->next->node = create_objectrefnode(CABI_GetDestructorObject(dtor, CABIDestroy1)); funcnode->data.funccall.args->next->next = lalloc(sizeof(ENodeList)); funcnode->data.funccall.args->next->next->node = create_objectrefnode(CInit_CreateStaticData(CInit_GetRegMemType()));; funcnode->data.funccall.args->next->next->next = NULL; node = funcnode; } return node; } static void CInit_RefInit(Type *type, ENode *expr, Boolean flag) { ENode *objexpr; objexpr = create_objectrefnode(cinit_initinfo->obj); if (!IS_TYPE_POINTER_ONLY(objexpr->rtype)) { CError_Error(CErrorStr174); return; } TYPE_POINTER(objexpr->rtype)->target = type; if (cinit_initinfo->expr_offset) objexpr = makediadicnode(objexpr, intconstnode(TYPE(&stunsignedlong), cinit_initinfo->expr_offset), EADD); objexpr = makemonadicnode(objexpr, EINDIRECT); objexpr->rtype = type; expr = makediadicnode(objexpr, expr, EASS); if (cinit_initinfo->x16) cinit_initinfo->init_expr_register_cb(expr); else InitExpr_Register(expr, cinit_initinfo->obj); } static Boolean CInit_IsDtorTemp(ENode *expr) { return ENODE_IS(expr, ETEMP) && expr->data.temp.needs_dtor; } static void CInit_FindDtorTemp(ENode *expr) { ENodeList *list; while (ENODE_IS(expr, ECOMMA)) expr = expr->data.diadic.right; if (IS_TYPE_POINTER_ONLY(expr->rtype) && IS_TYPE_CLASS(TYPE_POINTER(expr->rtype)->target)) { switch (expr->type) { case ETYPCON: CInit_FindDtorTemp(expr->data.monadic); break; case EADD: case ESUB: CInit_FindDtorTemp(expr->data.diadic.left); CInit_FindDtorTemp(expr->data.diadic.right); break; case EFUNCCALL: case EFUNCCALLP: if ((list = expr->data.funccall.args)) { if (CInit_IsDtorTemp(list->node) || ((list = list->next) && CInit_IsDtorTemp(list->node))) { if (!cinit_fdtnode) cinit_fdtnode = list; else cinit_fdtambig = 1; } } break; } } } static void CInit_RefTempTransform(Type *type, ENode *expr) { Object *obj; CError_ASSERT(3164, IS_TYPE_POINTER_ONLY(type)); if (IS_TYPE_CLASS(TYPE_POINTER(type)->target)) { cinit_fdtnode = NULL; cinit_fdtambig = 0; CInit_FindDtorTemp(expr); if (cinit_fdtnode) { CError_ASSERT(3172, !cinit_fdtambig); obj = create_temp_object(cinit_fdtnode->node->data.temp.type); cinit_initinfo->register_object_cb(cinit_fdtnode->node->data.temp.type, obj, 0, 0); cinit_fdtnode->node = create_objectrefnode(obj); } } } static Boolean CInit_InitReference(Object *obj, Boolean flag) { ENode *expr; if (tk == '=') { cinit_tempnodefunc = flag ? CInit_AutoTempNode : CInit_GlobalTempNode; tk = lex(); expr = CExpr_AssignmentPromotion(assignment_expression(), obj->type, obj->qual & (Q_CONST | Q_VOLATILE), 1); cinit_tempnodefunc = NULL; if (flag) { CInit_RefTempTransform(obj->type, expr); expr = makediadicnode(create_objectnode2(obj), expr, EASS); cinit_initinfo->insert_expr_cb(expr); } else { cinit_initinfo->expr_cb = CInit_RefInit; CInit_SetupInitInfoBuffer(obj->type); CInit_ExprPointer(TYPE_POINTER(obj->type), expr); CError_ASSERT(3213, obj->type->size == cinit_initinfo->size); if (cinit_initinfo->list || !CInit_IsAllZero(cinit_initinfo->buffer, obj->type->size)) { IsCompleteType(obj->type); CInit_AdjustObjectDataSize(obj); CInit_DeclareData(obj, cinit_initinfo->buffer, cinit_initinfo->list, obj->type->size); } else { IsCompleteType(obj->type); CInit_AdjustObjectDataSize(obj); CInit_DeclareData(obj, NULL, NULL, obj->type->size); } } return 1; } return 0; } ENode *CInit_AutoObject(Object *obj, Type *type, UInt32 qual) { CInit_Stuff s; CInit_1C *entry; ENode *expr; ENode *indirect_expr; ENode *obj_expr; ENode *const_expr; Type *newtype; Object *newobj; CInit_InitData(&s, type, qual, copts.cplusplus || copts.gcc_extensions || copts.c9x || !obj); if (!obj && !cscope_currentfunc) { obj = CParser_NewCompilerDefDataObject(); obj->name = CParser_GetUniqueName(); obj->type = type; obj->qual = qual; obj->sclass = TK_STATIC; CScope_AddGlobalObject(obj); } if (IS_TYPE_VECTOR(type) && !s.x1C) { if (obj) obj_expr = create_objectrefnode(obj); else obj_expr = CExpr_NewETEMPNode(type, 1); const_expr = CExpr_NewENode(EVECTOR128CONST); const_expr->rtype = type; const_expr->data.vector128val = *((MWVector128 *) s.buffer); indirect_expr = makemonadicnode(obj_expr, EINDIRECT); indirect_expr->rtype = type; expr = makediadicnode(indirect_expr, const_expr, EASS); if (!obj) { ENode *tmp = lalloc(sizeof(ENode)); *tmp = *obj_expr; tmp = makemonadicnode(tmp, EINDIRECT); tmp->rtype = type; tmp->flags = qual & ENODE_FLAG_QUALS; expr = makecommaexpression(expr, tmp); } return expr; } if (s.x18) { type = CDecl_NewStructType(type->size + s.x18, CMach_GetTypeAlign(type)); if (obj) obj->type = type; } if (obj) obj_expr = create_objectrefnode(obj); else obj_expr = CExpr_NewETEMPNode(type, 1); newtype = type; if (IS_TYPE_ARRAY(type)) newtype = CDecl_NewStructType(type->size, CMach_GetTypeAlign(type)); newobj = CInit_CreateStaticDataObject(newtype, 0, NULL); if (s.list || !CInit_IsAllZero(s.buffer, s.size)) CInit_DeclareReadOnlyData(newobj, s.buffer, s.list, s.size); else CInit_DeclareReadOnlyData(newobj, NULL, NULL, s.size); indirect_expr = makemonadicnode(obj_expr, EINDIRECT); indirect_expr->rtype = newtype; expr = makediadicnode(indirect_expr, create_objectnode(newobj), EASS); for (entry = s.x1C; entry; entry = entry->next) { expr = CInit_InitConcat(expr, obj_expr, entry->offset, entry->type, entry->expr); } if (!obj) { ENode *tmp = lalloc(sizeof(ENode)); *tmp = *obj_expr; tmp = makemonadicnode(tmp, EINDIRECT); tmp->rtype = type; tmp->flags = qual & ENODE_FLAG_QUALS; expr = makecommaexpression(expr, tmp); } else if (IS_TYPE_ARRAY(type)) { expr = makecommaexpression(expr, create_objectnode(obj)); } return expr; } static void CInit_GlobalObject(Object *obj) { CInit_Stuff s; CInit_1C *entry; ENode *obj_expr; ENode *expr; CInit_InitData(&s, obj->type, obj->qual, copts.cplusplus); obj_expr = create_objectrefnode(obj); IsCompleteType(obj->type); if (!s.x1C && is_const_object(obj)) CInit_DeclareReadOnlyData(obj, s.buffer, s.list, s.size); else CInit_DeclareData(obj, s.buffer, s.list, s.size); if (s.x1C) { entry = s.x1C; expr = NULL; while (entry) { if (!ENODE_IS(entry->expr, EVECTOR128CONST)) expr = CInit_InitConcat(expr, obj_expr, entry->offset, entry->type, entry->expr); entry = entry->next; } if (expr) InitExpr_Register(expr, obj); } } void CInit_InitializeAutoData(Object *obj, InsertExprCB insert_cb, RegisterObjectCB register_cb) { ENode *expr; Type *type; InitInfo initinfo; if (CInit_IsSimpleStructArrayInit(obj->type)) { if (tk == '=' || (tk == '(' && copts.cplusplus)) { if (tk == '(') { tk = lex(); expr = conv_assignment_expression(); if (tk != ')') CError_Error(CErrorStr115); tk = lex(); } else if (tk == '=' && ((tk = lex()) == '{' || IS_TYPE_ARRAY(obj->type))) { insert_cb(CInit_AutoObject(obj, obj->type, obj->qual)); return; } else { expr = conv_assignment_expression(); } expr = CExpr_AssignmentPromotion(expr, obj->type, obj->qual & (Q_CONST | Q_VOLATILE), 1); insert_cb(makediadicnode(create_objectnode2(obj), expr, EASS)); } else if (copts.cplusplus && is_const_object(obj)) { CError_Error(CErrorStr224); } return; } CInit_SetupInitInfo(&initinfo, obj); initinfo.obj1C = obj; initinfo.insert_expr_cb = insert_cb; initinfo.register_object_cb = register_cb; if (IS_TYPE_CLASS(obj->type) && CInit_ConstructAutoObject(TYPE_CLASS(obj->type), NULL, 0, 1)) { CInit_CleanupInitInfo(&initinfo); return; } if (IS_TYPE_REFERENCE(obj->type) && CInit_InitReference(obj, 1)) { CInit_CleanupInitInfo(&initinfo); return; } if (tk != '=' && (tk != '(' || !copts.cplusplus)) { if (IS_TYPE_ARRAY(obj->type)) { type = obj->type; while (IS_TYPE_ARRAY(type)) type = TYPE_POINTER(type)->target; if (IS_TYPE_CLASS(type)) { if (CInit_ClassNeedsConstruction(TYPE_CLASS(type))) { CInit_InitializeClassArray(obj, TYPE_CLASS(type), 0); CInit_CleanupInitInfo(&initinfo); return; } CFunc_CheckClassCtors(TYPE_CLASS(type)); } } if (IS_TYPE_CLASS(obj->type)) CFunc_CheckClassCtors(TYPE_CLASS(obj->type)); if ((IS_TYPE_REFERENCE(obj->type) || is_const_object(obj)) && copts.cplusplus) CError_Error(CErrorStr224); } else { if (obj->type->size || IS_TYPE_ARRAY(obj->type)) { if ((expr = CInit_GenericData(NULL, obj->type, obj->qual, CInit_AutoInit, 0))) insert_cb(makediadicnode(create_objectnode2(obj), expr, EASS)); } else { CError_Error(CErrorStr145); } } if (IS_TYPE_CLASS(obj->type) && CClass_Destructor(TYPE_CLASS(obj->type))) register_cb(obj->type, obj, 0, 0); CInit_CleanupInitInfo(&initinfo); } void CInit_InitializeStaticData(Object *obj, InitExprRegisterCB cb) { ENode *expr; Type *type; InitInfo initinfo; CInit_Stuff s; CInit_1C *entry; ENode *obj_expr; if (CInit_IsSimpleStructArrayInit(obj->type)) { if (tk == '=' || (tk == '(' && copts.cplusplus)) { if (tk == '=') tk = lex(); CInit_InitData(&s, obj->type, obj->qual, copts.cplusplus); IsCompleteType(obj->type); if (!s.x1C && is_const_object(obj)) CInit_DeclareReadOnlyData(obj, s.buffer, s.list, s.size); else CInit_DeclareData(obj, s.buffer, s.list, s.size); if (s.x1C) { obj_expr = create_objectrefnode(obj); entry = s.x1C; expr = NULL; while (entry) { expr = CInit_InitConcat(expr, obj_expr, entry->offset, entry->type, entry->expr); entry = entry->next; } cb(expr); } } else { if (copts.cplusplus && is_const_object(obj)) CError_Error(CErrorStr224); if (is_const_object(obj)) CInit_DeclareReadOnlyData(obj, NULL, NULL, obj->type->size); else CInit_DeclareData(obj, NULL, NULL, obj->type->size); } return; } CInit_SetupInitInfo(&initinfo, obj); initinfo.x16 = 1; initinfo.init_expr_register_cb = cb; if (IS_TYPE_CLASS(obj->type) && CInit_ConstructGlobalObject(obj, TYPE_CLASS(obj->type), NULL, 0, 1)) { IsCompleteType(obj->type); CInit_DeclareData(obj, NULL, NULL, obj->type->size); CInit_CleanupInitInfo(&initinfo); return; } if (IS_TYPE_REFERENCE(obj->type) && CInit_InitReference(obj, 0)) { CInit_CleanupInitInfo(&initinfo); return; } if (tk != '=' && (tk != '(' || !copts.cplusplus)) { if (IsCompleteType(obj->type)) CInit_DeclareData(obj, NULL, NULL, obj->type->size); if (IS_TYPE_ARRAY(obj->type)) { type = obj->type; while (IS_TYPE_ARRAY(type)) type = TYPE_POINTER(type)->target; if (IS_TYPE_CLASS(type)) { if (CInit_ClassNeedsConstruction(TYPE_CLASS(type))) { CInit_InitializeClassArray(obj, TYPE_CLASS(type), 1); CInit_CleanupInitInfo(&initinfo); return; } CFunc_CheckClassCtors(TYPE_CLASS(type)); } } if (IS_TYPE_CLASS(obj->type)) CFunc_CheckClassCtors(TYPE_CLASS(obj->type)); if ((IS_TYPE_REFERENCE(obj->type) || is_const_object(obj)) && copts.cplusplus) CError_Error(CErrorStr224); } else { if (obj->type->size || IS_TYPE_ARRAY(obj->type)) { if ((expr = CInit_GenericData(obj, obj->type, obj->qual, CInit_GlobalStaticInit, 1))) cb(makediadicnode(create_objectnode2(obj), expr, EASS)); } else { CError_Error(CErrorStr145); } } CInit_CleanupInitInfo(&initinfo); } void CInit_InitializeData(Object *obj) { Object *dtor; ObjectList *list; CInt64 val; InitInfo initinfo; Boolean needs_construction; Type *type; if (tk == ':') { tk = lex(); obj->datatype = DABSOLUTE; val = CExpr_IntegralConstExpr(); obj->u.address = CInt64_GetULong(&val); return; } if (tk != '=' && (tk != '(' || !copts.cplusplus)) { if (obj->sclass != TK_EXTERN) { if (!copts.cplusplus) { if (IsCompleteType(obj->type)) { for (list = cinit_tentative; list; list = list->next) { if (list->object == obj) break; } if (!list) { list = galloc(sizeof(ObjectList)); list->object = obj; list->next = cinit_tentative; cinit_tentative = list; obj->qual |= Q_1000000; } } } else { if (obj->flags & OBJECT_FLAGS_4) CError_Error(CErrorStr329, obj); obj->flags |= OBJECT_FLAGS_4; needs_construction = 0; if (IS_TYPE_ARRAY(obj->type)) { type = obj->type; while (IS_TYPE_ARRAY(type)) type = TYPE_POINTER(type)->target; if (IS_TYPE_CLASS(type)) { if (CInit_ClassNeedsConstruction(TYPE_CLASS(type))) { CInit_SetupInitInfo(&initinfo, obj); CInit_InitializeClassArray(obj, TYPE_CLASS(type), 1); CInit_CleanupInitInfo(&initinfo); needs_construction = 1; } else { CFunc_CheckClassCtors(TYPE_CLASS(type)); } } } else { if (IS_TYPE_CLASS(obj->type)) { if (CInit_ClassNeedsConstruction(TYPE_CLASS(obj->type))) { CInit_SetupInitInfo(&initinfo, obj); CInit_ConstructGlobalObject(obj, TYPE_CLASS(obj->type), NULL, 0, 0); CInit_CleanupInitInfo(&initinfo); needs_construction = 1; } else { CFunc_CheckClassCtors(TYPE_CLASS(obj->type)); } } } if (!needs_construction && copts.cplusplus) { if (IS_TYPE_REFERENCE(obj->type) || is_const_object(obj)) CError_Error(CErrorStr224); } if (IsCompleteType(obj->type)) CInit_DeclareData(obj, NULL, NULL, obj->type->size); } } return; } if (obj->flags & OBJECT_FLAGS_4) CError_Error(CErrorStr329, obj); if (CInit_IsSimpleStructArrayInit(obj->type)) { if (tk == '=') tk = lex(); else CError_Error(CErrorStr121); CInit_GlobalObject(obj); return; } CInit_SetupInitInfo(&initinfo, obj); if (IS_TYPE_CLASS(obj->type) && CInit_ConstructGlobalObject(obj, TYPE_CLASS(obj->type), NULL, 0, 1)) { IsCompleteType(obj->type); CInit_DeclareData(obj, NULL, NULL, obj->type->size); CInit_CleanupInitInfo(&initinfo); return; } if (IS_TYPE_REFERENCE(obj->type) && CInit_InitReference(obj, 0)) { CInit_CleanupInitInfo(&initinfo); return; } if (obj->type->size == 0 && !IS_TYPE_ARRAY(obj->type)) { CError_Error(CErrorStr145); CInit_CleanupInitInfo(&initinfo); return; } if (copts.cplusplus) CInit_GenericData(obj, obj->type, obj->qual, &CInit_GlobalStaticInit, 0); else CInit_GenericData(obj, obj->type, obj->qual, NULL, 0); if (IS_TYPE_CLASS(obj->type) && (dtor = CClass_Destructor(TYPE_CLASS(obj->type)))) InitExpr_Register(CInit_RegisterDtorObject(obj->type, dtor, create_objectrefnode(obj)), obj); CInit_CleanupInitInfo(&initinfo); } Object *CInit_DeclareString(char *data, SInt32 size, Boolean ispascal, Boolean iswide) { PooledString *str; Object *obj; PooledString *scan; if (!copts.dont_reuse_strings) { for (scan = cinit_stringlist; scan; scan = scan->next) { if (scan->size == size && scan->ispascal == ispascal && scan->iswide == iswide && !memcmp(scan->data, data, size)) return scan->obj; } } obj = CParser_NewCompilerDefDataObject(); obj->name = CParser_GetUniqueName(); if (iswide) { obj->type = CDecl_NewArrayType(CParser_GetWCharType(), size); } else { obj->type = CDecl_NewArrayType(ispascal ? TYPE(&stunsignedchar) : TYPE(&stchar), size); } obj->sclass = TK_STATIC; CScope_AddGlobalObject(obj); if (!iswide && !ispascal && size == (strlen(data) + 1)) obj->section = SECT_TEXT_CSTRING; else obj->section = SECT_CONST; if (copts.readonly_strings) CInit_DeclareReadOnlyData(obj, data, NULL, obj->type->size); else CInit_DeclareData(obj, data, NULL, obj->type->size); str = galloc(sizeof(PooledString)); str->next = cinit_stringlist; cinit_stringlist = str; str->obj = obj; str->offset = 0; str->size = size; str->ispascal = ispascal; str->iswide = iswide; str->data = galloc(size); memcpy(str->data, data, size); return obj; } PooledString *CInit_DeclarePooledString(char *data, SInt32 size, Boolean ispascal) { PooledString *str; Object *obj; PooledString *scan; SInt32 offset; if (!copts.dont_reuse_strings) { for (scan = cinit_pooledstringlist; scan; scan = scan->next) { if (scan->size == size && scan->ispascal == ispascal && !memcmp(scan->data, data, size)) return scan; } } if (cinit_pooledstringlist) { obj = cinit_pooledstringlist->obj; offset = cinit_pooledstringlist->offset + cinit_pooledstringlist->size; } else { obj = CInit_CreateStaticDataObject( CDecl_NewArrayType(ispascal ? TYPE(&stunsignedchar) : TYPE(&stchar), size), 0, GetHashNameNodeExport("@stringBase0")); obj->section = SECT_CONST; offset = 0; } str = galloc(sizeof(PooledString)); str->next = cinit_pooledstringlist; cinit_pooledstringlist = str; str->obj = obj; str->offset = offset; str->size = size; str->ispascal = ispascal; str->data = galloc(size); memcpy(str->data, data, size); return str; } PooledString *CInit_DeclarePooledWString(char *data, SInt32 size) { PooledString *str; Object *obj; PooledString *scan; SInt32 offset; if (!copts.dont_reuse_strings) { for (scan = cinit_pooledwstringlist; scan; scan = scan->next) { if (scan->size == size && !memcmp(scan->data, data, size)) return scan; } } if (cinit_pooledwstringlist) { obj = cinit_pooledwstringlist->obj; offset = cinit_pooledwstringlist->offset + cinit_pooledwstringlist->size; } else { obj = CInit_CreateStaticDataObject( CDecl_NewArrayType(CParser_GetWCharType(), size), 0, GetHashNameNodeExport("@wstringBase0")); obj->section = SECT_CONST; offset = 0; } str = galloc(sizeof(PooledString)); str->next = cinit_pooledwstringlist; cinit_pooledwstringlist = str; str->obj = obj; str->offset = offset; str->size = size; str->ispascal = 0; str->data = galloc(size); memcpy(str->data, data, size); return str; } void CInit_RewriteString(ENode *expr, Boolean flag) { PooledString *str; Boolean is_wide; if (cparamblkptr->precompile == 1) CError_Error(CErrorStr180); CError_ASSERT(4220, expr->rtype->type == TYPEPOINTER); is_wide = TYPE_POINTER(expr->rtype)->target->size != 1; if (copts.poolstrings) { if (is_wide) str = CInit_DeclarePooledWString(expr->data.string.data, expr->data.string.size); else str = CInit_DeclarePooledString(expr->data.string.data, expr->data.string.size, expr->data.string.ispascal); if (str->offset) { expr->type = EADD; expr->data.diadic.right = intconstnode(TYPE(&stunsignedlong), str->offset); expr->data.diadic.left = create_objectrefnode(str->obj); expr->cost = 1; } else { expr->type = EOBJREF; expr->data.objref = str->obj; } } else { expr->type = EOBJREF; expr->data.objref = CInit_DeclareString(expr->data.string.data, expr->data.string.size, expr->data.string.ispascal, is_wide); } } void CInit_DeclarePooledStrings(void) { SInt32 size; char *buffer; PooledString *str; size = 0; for (str = cinit_pooledstringlist; str; str = str->next) size += str->size; if (size) { cinit_pooledstringlist->obj->type = CDecl_NewArrayType(TYPE(&stchar), size); buffer = galloc(size); for (str = cinit_pooledstringlist; str; str = str->next) memcpy(buffer + str->offset, str->data, str->size); if (copts.readonly_strings) CInit_DeclareReadOnlyData(cinit_pooledstringlist->obj, buffer, NULL, size); else CInit_DeclareData(cinit_pooledstringlist->obj, buffer, NULL, size); } size = 0; for (str = cinit_pooledwstringlist; str; str = str->next) size += str->size; if (size) { cinit_pooledwstringlist->obj->type = CDecl_NewArrayType(CParser_GetWCharType(), size); buffer = galloc(size); for (str = cinit_pooledwstringlist; str; str = str->next) memcpy(buffer + str->offset, str->data, str->size); if (copts.readonly_strings) CInit_DeclareReadOnlyData(cinit_pooledwstringlist->obj, buffer, NULL, size); else CInit_DeclareData(cinit_pooledwstringlist->obj, buffer, NULL, size); } } static void declaredata(Object *obj, void *data, OLinkList *list, SInt32 size, Boolean is_readonly) { OLinkList *scan; UInt32 qual; qual = obj->qual; if (cparamblkptr->precompile == 1) { PreComp_StaticData(obj, data, list, size); } else { obj->flags |= OBJECT_FLAGS_4; if (!fatalerrors) { for (scan = list; scan; scan = scan->next) CInline_ObjectAddrRef(scan->obj); if (copts.filesyminfo) CPrep_SetSourceFile(&cparser_fileoffset); if (is_readonly) ObjGen_DeclareReadOnlyData(obj, data, list, size); else ObjGen_DeclareData(obj, data, list, size); obj->qual = qual; } } } void CInit_DeclareData(Object *obj, void *data, OLinkList *list, SInt32 size) { declaredata(obj, data, list, size, 0); } void CInit_DeclareReadOnlyData(Object *obj, void *data, OLinkList *list, SInt32 size) { declaredata(obj, data, list, size, 1); } void CInit_DefineTentativeData(void) { ObjectList *list; for (list = cinit_tentative; list; list = list->next) { if (!(list->object->flags & OBJECT_FLAGS_4)) CInit_DeclareData(list->object, NULL, NULL, list->object->type->size); } cinit_tentative = NULL; }