diff options
Diffstat (limited to 'compiler_and_linker/FrontEnd/C/CInit.c')
-rw-r--r-- | compiler_and_linker/FrontEnd/C/CInit.c | 3082 |
1 files changed, 3082 insertions, 0 deletions
diff --git a/compiler_and_linker/FrontEnd/C/CInit.c b/compiler_and_linker/FrontEnd/C/CInit.c new file mode 100644 index 0000000..c2d2299 --- /dev/null +++ b/compiler_and_linker/FrontEnd/C/CInit.c @@ -0,0 +1,3082 @@ +#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.is_extern_c = 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->offset; + step = 1; + } else { + pos = tbitfield->bitlength + tbitfield->offset - 1; + step = -1; + } + for (i = 0; i < tbitfield->bitlength; i++, pos += step) { + 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); + } +} + +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_WEAK)); + + 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_VECTOR_UCHAR: + case STRUCT_VECTOR_SCHAR: + case STRUCT_VECTOR_BCHAR: + 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_VECTOR_USHORT: + case STRUCT_VECTOR_SSHORT: + case STRUCT_VECTOR_BSHORT: + case STRUCT_VECTOR_PIXEL: + 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_VECTOR_UINT: + case STRUCT_VECTOR_SINT: + case STRUCT_VECTOR_BINT: + case STRUCT_VECTOR_FLOAT: + 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)->offset != TYPE_BITFIELD(ivar->type)->offset) + 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_UNION && 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_WEAK)); + + 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; + copy->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 & Q_CV; + else + cv = cinit_initinfo->obj1C->qual & Q_CV; + + 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_INLINE_DATA; + 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_DEFINED) + 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_DEFINED) + CError_Error(CErrorStr329, obj); + obj->flags = obj->flags | OBJECT_DEFINED; + + 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_DEFINED) + 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 = obj->flags | OBJECT_DEFINED; + 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_DEFINED)) + CInit_DeclareData(list->object, NULL, NULL, list->object->type->size); + } + + cinit_tentative = NULL; +} |