diff options
Diffstat (limited to 'compiler_and_linker/FrontEnd/C/CFunc.c')
-rw-r--r-- | compiler_and_linker/FrontEnd/C/CFunc.c | 3224 |
1 files changed, 3224 insertions, 0 deletions
diff --git a/compiler_and_linker/FrontEnd/C/CFunc.c b/compiler_and_linker/FrontEnd/C/CFunc.c new file mode 100644 index 0000000..38cfab3 --- /dev/null +++ b/compiler_and_linker/FrontEnd/C/CFunc.c @@ -0,0 +1,3224 @@ +#include "compiler/CFunc.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/CInit.h" +#include "compiler/CInline.h" +#include "compiler/CInt64.h" +#include "compiler/CMachine.h" +#include "compiler/CMangler.h" +#include "compiler/CParser.h" +#include "compiler/CPrepTokenizer.h" +#include "compiler/CSOM.h" +#include "compiler/CTemplateTools.h" +#include "compiler/CodeGen.h" +#include "compiler/CompilerTools.h" +#include "compiler/Exceptions.h" +#include "compiler/FuncLevelAsmPPC.h" +#include "compiler/InlineAsmPPC.h" +#include "compiler/ObjGenMachO.h" +#include "compiler/Switch.h" +#include "compiler/objects.h" +#include "compiler/scopes.h" +#include "compiler/types.h" + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +struct CFuncSave { + CScopeSave scope; + ObjectList *arguments; + ObjectList *locals; + CLabel *labels; + Statement *curstmt; + DeclBlock *firstblock; + DeclBlock *currentblock; + ExceptionAction *cexcept_dobjstack; + CLabel *sinit_label; + ENode *ainit_expr; + CtorChain *ctor_chain; + ParserTryBlock *trychain; + TempNodeCB cinit_tempnodefunc; + HashNameNode *tkidentifier; + Object *sinit_first_object; + FileOffsetInfo cparser_fileoffset; + TStreamElement symdecltoken; + SInt32 functionbodyoffset; + HashNameNode *functionbodypath; + SInt32 symdecloffset; + SInt32 symdeclend; + SInt32 sourceoffset; + HashNameNode *sourcefilepath; + SInt32 curstmtvalue; + NameObjCheckCB name_obj_check; + FuncArg *check_arglist; + short blockcount; + short localcount; + short tk; + AccessType global_access; + Boolean cexcept_hasdobjects; + Boolean ainit_only_one; + Boolean cfunc_is_extern_c; + Boolean temp_reference_init; +}; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +FuncArg elipsis; +FuncArg oldstyle; +ObjectList *arguments; +ObjectList *locals; +short localcount; +SInt32 curstmtvalue; +SInt32 sourceoffset; +HashNameNode *sourcefilepath; +SInt32 functionbodyoffset; +HashNameNode *functionbodypath; +InitExpr *init_expressions; +CLabel *Labels; +CtorChain *ctor_chain; +Statement *curstmt; +static short temp_destructor_object_regmem; +static short temp_destructor_objects; +static short temp_expression_has_conditionals; +static DeclBlock *firstblock; +static DeclBlock *currentblock; +static short blockcount; +static Object *sinit_first_object; +static CLabel *sinit_label; +static Boolean ainit_only_one; +static ENode *ainit_expr; +static FuncArg *check_arglist; +static Boolean cfunc_is_extern_c; +static short cfunc_staticvarcount; +static void *destroyobjects; +static Boolean cfunc_hasdtortemp; + +// forward decls +static void statement(DeclThing *thing); + +static void CFunc_LoopIncrement(void) { + if (curstmtvalue >= 0x1000) { + if (curstmtvalue >= 0xF000) + curstmtvalue++; + else + curstmtvalue += 0x1000; + } else { + curstmtvalue <<= 3; + } +} + +static void CFunc_LoopDecrement(void) { + if (curstmtvalue > 0x1000) { + if (curstmtvalue > 0xF000) + curstmtvalue--; + else + curstmtvalue -= 0x1000; + } else { + curstmtvalue >>= 3; + } + + if (curstmtvalue < 1) + curstmtvalue = 1; +} + +DeclBlock *CFunc_NewDeclBlock(void) { + DeclBlock *block; + NameSpace *nspace; + + block = lalloc(sizeof(DeclBlock)); + if (firstblock) { + currentblock->next = block; + currentblock = block; + } else { + firstblock = block; + currentblock = block; + } + + block->index = blockcount++; + block->parent_nspace = cscope_current; + block->dobjstack = cexcept_dobjstack; + + nspace = CScope_NewListNameSpace(NULL, 0); + nspace->parent = cscope_current; + cscope_current = nspace; + + return block; +} + +void CFunc_RestoreBlock(DeclBlock *block) { + if (curstmt && curstmt->dobjstack != cexcept_dobjstack) { + Statement *stmt = CFunc_AppendStatement(ST_EXPRESSION); + stmt->expr = nullnode(); + } + + cscope_current = block->parent_nspace; + cexcept_dobjstack = block->dobjstack; +} + +void CFunc_SetupLocalVarInfo(Object *obj) { + obj->u.var.info = CodeGen_GetNewVarInfo(); + obj->u.var.info->func = cscope_currentfunc; + + if (obj->sclass == TK_REGISTER) { + if (!copts.optimizesize) + obj->u.var.info->usage = 100; + else + obj->u.var.info->usage = 5; + } + + if (obj->type && is_volatile_object(obj)) + obj->u.var.info->noregister = 1; +} + +static void adjustargumenttype(DeclInfo *declinfo) { + switch (declinfo->thetype->type) { + case TYPECLASS: + if (TYPE_CLASS(declinfo->thetype)->sominfo) { + CError_Error(CErrorStr284); + declinfo->thetype = TYPE(&stsignedint); + } + break; + case TYPEFUNC: + makethetypepointer(declinfo, 0); + return; + case TYPEARRAY: + declinfo->thetype = CDecl_NewPointerType(TPTR_TARGET(declinfo->thetype)); + return; + case TYPETEMPLATE: + if (TYPE_TEMPLATE(declinfo->thetype)->dtype == TEMPLDEP_ARRAY) + declinfo->thetype = CDecl_NewPointerType(TYPE_TEMPLATE(declinfo->thetype)->u.array.type); + return; + } + + if (!CanCreateObject(declinfo->thetype)) + declinfo->thetype = TYPE(&stsignedint); +} + +static FuncArg *CFunc_IsInArgList(FuncArg *list, HashNameNode *name) { + while (list) { + if (name == list->name) + return list; + list = list->next; + } + + return NULL; +} + +static Object *CFunc_IsInObjList(ObjectList *list, HashNameNode *name) { + while (list) { + if (name == list->object->name) + return list->object; + list = list->next; + } + + return NULL; +} + +static void CFunc_AppendArg(FuncArg **list, FuncArg *arg) { + FuncArg *tail; + + if ((tail = *list)) { + while (tail->next) + tail = tail->next; + tail->next = arg; + } else { + *list = arg; + } +} + +static void identifier_list(DeclInfo *declinfo) { + FuncArg *arg; + + declinfo->x45 = 1; + + while (1) { + if (tk != TK_IDENTIFIER) { + CError_Error(CErrorStr121); + } else { + if (CFunc_IsInArgList(declinfo->x18, tkidentifier)) + CError_Error(CErrorStr122, tkidentifier->name); + + arg = CParser_NewFuncArg(); + arg->name = tkidentifier; + CFunc_AppendArg(&declinfo->x18, arg); + declinfo->x44 = 1; + } + + if ((tk = lex()) != ',') + break; + tk = lex(); + } +} + +static Boolean defarg_name_obj_check(HashNameNode *name, Object *obj) { + FuncArg *arg; + + if (name) { + for (arg = check_arglist; arg; arg = arg->next) { + if (arg->name == name) { + CError_Error(CErrorStr205); + return 0; + } + } + } + + if (obj && obj->datatype == DLOCAL) { + CError_Error(CErrorStr205); + return 0; + } + + return 1; +} + +ENode *CFunc_DefaultArg(Type *type, UInt32 qual, FuncArg *args) { + TStreamElement *element; + ENode *expr; + ENode *templdepexpr; + + name_obj_check = defarg_name_obj_check; + check_arglist = args; + expr = conv_assignment_expression(); + name_obj_check = NULL; + + if ( + !CTemplTool_IsTemplateArgumentDependentExpression(expr) && + !CTemplTool_IsTemplateArgumentDependentType(type) + ) + { + expr = argumentpromotion(expr, type, qual, 1); + } else { + element = CPrep_CurStreamElement(); + if (element && element->tokenfile) { + templdepexpr = CExpr_NewTemplDepENode(TDE_SOURCEREF); + templdepexpr->data.templdep.u.sourceref.expr = expr; + templdepexpr->data.templdep.u.sourceref.token = galloc(sizeof(TStreamElement)); + *templdepexpr->data.templdep.u.sourceref.token = *element; + expr = templdepexpr; + } + } + + return CInline_CopyExpression(expr, CopyMode1); +} + +static FuncArg *parameter_list(DeclInfo *declinfo) { + Boolean flag26; + FuncArg *args; + FuncArg *arg; + DeclInfo my_di; + Boolean isArray; + + args = NULL; + flag26 = 1; + + while (1) { + if (tk == TK_ELLIPSIS) { + if (flag26) { + if (!copts.cplusplus && copts.ANSIstrict) + CError_Warning(CErrorStr127); + args = &elipsis; + } else { + CFunc_AppendArg(&args, &elipsis); + } + + tk = lex(); + return args; + } + + memclrw(&my_di, sizeof(my_di)); + CParser_GetDeclSpecs(&my_di, 0); + if (my_di.x48) + CError_Error(CErrorStr127); + + if ( + my_di.storageclass && + my_di.storageclass != TK_REGISTER && + (!copts.cplusplus || my_di.storageclass != TK_AUTO) + ) + { + CError_Error(CErrorStr127); + my_di.storageclass = 0; + } + + my_di.name = NULL; + + scandeclarator(&my_di); + + if (flag26) { + flag26 = 0; + if (my_di.thetype == &stvoid) { + if (my_di.storageclass || my_di.qual || my_di.name) + CError_Error(CErrorStr127); + return NULL; + } + } + + isArray = IS_TYPE_ARRAY(my_di.thetype); + adjustargumenttype(&my_di); + + if (my_di.name) { + if (args && CFunc_IsInArgList(args, my_di.name)) + CError_Error(CErrorStr122, my_di.name->name); + } else { + my_di.name = no_name_node; + } + + if (my_di.thetype == &stvoid) + CError_Error(CErrorStr126); + + arg = CParser_NewFuncArg(); + arg->name = my_di.name; + arg->type = my_di.thetype; + arg->qual = my_di.qual; + arg->sclass = my_di.storageclass; + arg->is_array = isArray; + CFunc_AppendArg(&args, arg); + + if (copts.cplusplus && tk == '=') { + tk = lex(); + arg->dexpr = CFunc_DefaultArg(arg->type, arg->qual, args); + } + + if (tk != ',') { + if (tk != TK_ELLIPSIS || !copts.cplusplus) + return args; + } else { + tk = lex(); + } + } +} + +Boolean CFunc_ParseFakeArgList(Boolean flag) { + DeclInfo di; + + if (tk == TK_ELLIPSIS) + return 1; + + do { + memclrw(&di, sizeof(di)); + CParser_GetDeclSpecs(&di, 0); + + if (di.x48) + return 0; + + scandeclarator(&di); + + if (tk == '=') { + tk = lex(); + assignment_expression(); + } + + switch (tk) { + case TK_ELLIPSIS: + return 1; + case ',': + if (!flag) + tk = lex(); + else + return 1; + break; + default: + return 0; + } + } while (tk != TK_ELLIPSIS); + + return 1; +} + +FuncArg *parameter_type_list(DeclInfo *declinfo) { + FuncArg *args; + NameSpace *nspace; + Boolean save_in_func_arglist; + + declinfo->x44 = 0; + declinfo->x45 = 0; + declinfo->x1C = NULL; + + if (tk == TK_ELLIPSIS || isdeclaration(0, 0, 0, 0)) { + if (!copts.cplusplus) { + nspace = CScope_NewListNameSpace(NULL, 0); + nspace->parent = cscope_current; + cscope_current = nspace; + + save_in_func_arglist = in_func_arglist; + in_func_arglist = 1; + args = parameter_list(declinfo); + in_func_arglist = save_in_func_arglist; + + cscope_current = nspace->parent; + + if (!CScope_IsEmptyNameSpace(nspace)) + declinfo->x1C = nspace; + } else { + args = parameter_list(declinfo); + } + } else if (copts.cplusplus) { + args = NULL; + if (tk != ')') + CError_Error(CErrorStr127); + } else { + identifier_list(declinfo); + args = &oldstyle; + } + + return args; +} + +CLabel *findlabel(void) { + CLabel *scan; + + for (scan = Labels; scan; scan = scan->next) { + if (tkidentifier == scan->name) + return scan; + } + + return NULL; +} + +CLabel *newlabel(void) { + CLabel *label = lalloc(sizeof(CLabel)); + memclrw(label, sizeof(CLabel)); + + label->name = label->uniquename = CParser_GetUniqueName(); + return label; +} + +Statement *CFunc_AppendStatement(StatementType sttype) { + Statement *stmt = lalloc(sizeof(Statement)); + + stmt->next = NULL; + stmt->type = sttype; + stmt->value = curstmtvalue; + stmt->flags = 0; + stmt->sourceoffset = sourceoffset; + stmt->sourcefilepath = sourcefilepath; + stmt->dobjstack = cexcept_dobjstack; + + curstmt->next = stmt; + curstmt = stmt; + return stmt; +} + +Statement *CFunc_InsertStatement(StatementType sttype, Statement *after) { + Statement *stmt = lalloc(sizeof(Statement)); + + stmt->next = after->next; + after->next = stmt; + stmt->type = sttype; + stmt->value = after->value; + stmt->flags = 0; + stmt->sourceoffset = after->sourceoffset; + stmt->sourcefilepath = after->sourcefilepath; + stmt->dobjstack = after->dobjstack; + + return stmt; +} + +Statement *CFunc_InsertBeforeStatement(StatementType sttype, Statement *before) { + Statement *stmt = lalloc(sizeof(Statement)); + + *stmt = *before; + before->next = stmt; + before->type = sttype; + before->flags = 0; + + return before; +} + +void CheckCLabels(void) { + CLabel *scan; + + for (scan = Labels; scan; scan = scan->next) { + if (!scan->stmt) + CError_Error(CErrorStr159, scan->name->name); + } +} + +Object *create_temp_object(Type *type) { + Object *object = CParser_NewLocalDataObject(NULL, 1); + object->name = CParser_GetUniqueName(); + object->type = type; + CFunc_SetupLocalVarInfo(object); + return object; +} + +ENode *create_temp_node(Type *type) { + ENode *node; + + if (cinit_tempnodefunc) + return cinit_tempnodefunc(type, 0); + + node = CExpr_NewETEMPNode(type, 0); + if (IS_TYPE_CLASS(type) && CClass_Destructor(TYPE_CLASS(type))) + node->data.temp.needs_dtor = 1; + return node; +} + +ENode *create_temp_node2(Type *type) { + ENode *node; + + if (cinit_tempnodefunc) + return cinit_tempnodefunc(type, 1); + + node = CExpr_NewETEMPNode(type, 0); + node->data.temp.needs_dtor = 1; + return node; +} + +static ENode *CFunc_DestroyReverse(ENode *expr, DtorTemp *list) { + expr = makediadicnode(expr, CABI_DestroyObject(list->dtor, create_objectrefnode(list->object), CABIDestroy1, 1, 0), ECOMMA); + expr->rtype = &stvoid; + if (list->next) + expr = CFunc_DestroyReverse(expr, list->next); + return expr; +} + +static ENode *CFunc_TempTransDestroy(ENode *expr, DtorTemp *list, Boolean flag) { + Object *tempobj; + + if (flag) { + CError_ASSERT(738, !(IS_TYPE_CLASS(expr->rtype) && CClass_Destructor(TYPE_CLASS(expr->rtype)))); + tempobj = create_temp_object(expr->rtype); + expr = makediadicnode(create_objectnode(tempobj), expr, EASS); + } + + expr = CFunc_DestroyReverse(expr, list); + + if (flag) { + expr = makediadicnode(expr, create_objectnode(tempobj), ECOMMA); + expr->rtype = tempobj->type; + } + + return expr; +} + +void CFunc_WarnUnused(void) { + if (copts.warn_unusedvar) { + ObjectList *list; + for (list = locals; list; list = list->next) { + if ( + !(list->object->flags & OBJECT_USED) && + !IsTempName(list->object->name) && + !(list->object->qual & Q_INLINE_DATA) + ) + { + CError_SetErrorToken(&list->object->u.var.info->deftoken); + CError_Warning(CErrorStr182, &list->object->name->name); + } + } + } + + if (copts.warn_unusedarg) { + ObjectList *list; + for (list = arguments; list; list = list->next) { + if ( + !(list->object->flags & OBJECT_USED) && + !IsTempName(list->object->name) && + list->object->name != this_name_node && + list->object->name != self_name_node + ) + { + CError_SetErrorToken(&symdecltoken); + CError_Warning(CErrorStr182, &list->object->name->name); + } + } + } +} + +void CFunc_CodeCleanup(Statement *stmt) { + if (cscope_currentclass && cscope_currentclass->sominfo) + CSOM_InitSOMSelf(cscope_currentclass, stmt); + + CFunc_WarnUnused(); + CExcept_ExceptionTansform(stmt); +} + +static Boolean DestructorNeeded(ExceptionAction *ea, ExceptionAction *end) { + while (ea) { + if (CExcept_ActionNeedsDestruction(ea)) + return 1; + if (ea == end) + break; + ea = ea->prev; + } + + return 0; +} + +static Statement *DestructLocals(Statement *stmt, ExceptionAction *ea, ExceptionAction *end) { + while (ea) { + stmt = CExcept_ActionCleanup(ea, stmt); + if (ea == end) + break; + ea = ea->prev; + } + + return stmt; +} + +static Boolean NeedsDestruction(Statement *stmt1, Statement *stmt2) { + ExceptionAction *ea2; + ExceptionAction *ea1; + ExceptionAction *scan; + + ea1 = stmt1->dobjstack; + ea2 = stmt2->dobjstack; + + for (scan = ea2; scan; scan = scan->prev) { + if (scan == ea1) + return 0; + } + + while (ea1 && ea1 != ea2) { + if (CExcept_ActionNeedsDestruction(ea1)) + return 1; + ea1 = ea1->prev; + } + + return 0; +} + +static ExceptionAction *FindLastNonCommonStackObj(Statement *stmt1, Statement *stmt2) { + ExceptionAction *ea1; + ExceptionAction *ea2; + + for (ea2 = stmt2->dobjstack; ea2; ea2 = ea2->prev) { + for (ea1 = stmt1->dobjstack; ea1; ea1 = ea1->prev) { + if (ea1->prev == ea2) + return ea1; + } + } + + return NULL; +} + +static void DestructorReturnTransform(Statement *stmt1, Statement *stmt2) { + Statement *stmt; + Object *tempobj; + + if (stmt1->dobjstack != stmt2->dobjstack && NeedsDestruction(stmt1, stmt2)) + stmt1 = DestructLocals(stmt1, stmt1->dobjstack, FindLastNonCommonStackObj(stmt1, stmt2)); + + if (DestructorNeeded(stmt2->dobjstack, NULL)) { + if (CMach_GetFunctionResultClass(TYPE_FUNC(cscope_currentfunc->type)) != 1) { + tempobj = create_temp_object(stmt2->expr->rtype); + stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt1); + stmt->expr = makediadicnode(create_objectnode(tempobj), stmt2->expr, EASS); + stmt->sourceoffset = stmt2->sourceoffset; + stmt->sourcefilepath = stmt2->sourcefilepath; + DestructLocals(stmt, stmt2->dobjstack, NULL); + stmt2->expr = create_objectnode(tempobj); + } else { + stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt1); + stmt->expr = stmt2->expr; + stmt->sourceoffset = stmt2->sourceoffset; + stmt->sourcefilepath = stmt2->sourcefilepath; + DestructLocals(stmt, stmt2->dobjstack, NULL); + stmt2->expr = nullnode(); + } + } +} + +static Statement *DestructorIfTransform(Statement *stmt) { + CLabel *label; + Statement *newStmt; + + if (stmt->type == ST_IFGOTO) + stmt->type = ST_IFNGOTO; + else + stmt->type = ST_IFGOTO; + + label = newlabel(); + newStmt = DestructLocals(stmt, stmt->dobjstack, FindLastNonCommonStackObj(stmt, stmt->label->stmt)); + newStmt = CFunc_InsertStatement(ST_GOTO, newStmt); + newStmt->label = stmt->label; + newStmt = CFunc_InsertStatement(ST_LABEL, newStmt); + newStmt->label = label; + label->stmt = newStmt; + stmt->label = label; + newStmt->dobjstack = stmt->dobjstack; + return newStmt; +} + +static Boolean IsSubStack(ExceptionAction *exc1, ExceptionAction *exc2) { + if (!exc1) + return 1; + + while (exc2) { + if (exc2 == exc1) + return 1; + exc2 = exc2->prev; + } + + return 0; +} + +static void CFunc_CheckInitSkip(Statement *stmt, ExceptionAction *exc) { + if (stmt->dobjstack != exc && !IsSubStack(exc, stmt->dobjstack)) { + while (exc) { + if (CExcept_ActionNeedsDestruction(exc) && exc->type != EAT_ACTIVECATCHBLOCK) { + CError_Warning(CErrorStr211); + break; + } + exc = exc->prev; + } + } +} + +void CFunc_DestructorCleanup(Statement *stmt) { + Statement *scan; + Statement *next; + SwitchCase *swcase; + + if (copts.cplusplus) { + for (scan = stmt; scan; scan = scan->next) { + switch (scan->type) { + case ST_NOP: + case ST_LABEL: + case ST_EXPRESSION: + case ST_RETURN: + case ST_BEGINCATCH: + case ST_ENDCATCH: + case ST_ENDCATCHDTOR: + case ST_GOTOEXPR: + case ST_ASM: + break; + case ST_SWITCH: + CFunc_CheckInitSkip(scan, ((SwitchInfo *) scan->label)->defaultlabel->stmt->dobjstack); + for (swcase = ((SwitchInfo *) scan->label)->cases; swcase; swcase = swcase->next) { + CFunc_CheckInitSkip(scan, swcase->label->stmt->dobjstack); + } + break; + case ST_GOTO: + case ST_IFGOTO: + case ST_IFNGOTO: + CFunc_CheckInitSkip(scan, scan->label->stmt->dobjstack); + break; + default: + CError_FATAL(1045); + } + } + + if (cexcept_hasdobjects) { + while (1) { + next = stmt->next; + if (!next) { + if (stmt->type != ST_RETURN && stmt->dobjstack) + DestructLocals(stmt, stmt->dobjstack, NULL); + return; + } + + switch (next->type) { + case ST_GOTO: + if ( + stmt->dobjstack != next->label->stmt->dobjstack && + NeedsDestruction(stmt, next->label->stmt) + ) + { + DestructLocals(stmt, stmt->dobjstack, FindLastNonCommonStackObj(stmt, next->label->stmt)); + } + stmt = next; + continue; + + case ST_RETURN: + if (next->expr && DestructorNeeded(stmt->dobjstack, NULL)) { + DestructorReturnTransform(stmt, next); + } else if (stmt->dobjstack) { + DestructLocals(stmt, stmt->dobjstack, NULL); + } + stmt = next; + continue; + } + + switch (stmt->type) { + case ST_GOTO: + case ST_SWITCH: + case ST_RETURN: + case ST_GOTOEXPR: + break; + case ST_NOP: + case ST_LABEL: + case ST_EXPRESSION: + case ST_IFGOTO: + case ST_IFNGOTO: + case ST_BEGINCATCH: + case ST_ENDCATCH: + case ST_ENDCATCHDTOR: + case ST_ASM: + if ( + stmt->dobjstack != next->dobjstack && + NeedsDestruction(stmt, next) + ) + { + DestructLocals(stmt, stmt->dobjstack, FindLastNonCommonStackObj(stmt, next)); + } + break; + default: + CError_FATAL(1109); + } + + switch (next->type) { + case ST_NOP: + case ST_LABEL: + case ST_EXPRESSION: + case ST_SWITCH: + case ST_BEGINCATCH: + case ST_ENDCATCH: + case ST_ENDCATCHDTOR: + case ST_ASM: + stmt = next; + continue; + + case ST_IFGOTO: + case ST_IFNGOTO: + if ( + next->dobjstack != next->label->stmt->dobjstack && + NeedsDestruction(next, next->label->stmt) + ) + { + stmt = DestructorIfTransform(next); + } else { + stmt = next; + } + break; + + default: + CError_FATAL(1138); + } + } + } + } +} + +static void scancase(DeclThing *thing) { + SwitchCase *swcase; + Statement *stmt; + CInt64 min; + CInt64 max; + + if (!thing->switchinfo) { + CError_Error(CErrorStr169); + return; + } + + tk = lex(); + min = CExpr_IntConstConvert(thing->switchinfo->x8, thing->switchinfo->x8, CExpr_IntegralConstExpr()); + if (!copts.ANSIstrict && tk == TK_ELLIPSIS) { + tk = lex(); + max = CExpr_IntConstConvert(thing->switchinfo->x8, thing->switchinfo->x8, CExpr_IntegralConstExpr()); + if (CInt64_Greater(min, max)) + CError_Error(CErrorStr366); + if (thing->switchinfo->x8->size == stsignedlonglong.size) + CError_Error(CErrorStr368); + } else { + max = min; + } + + for (swcase = thing->switchinfo->cases; swcase; swcase = swcase->next) { + if (CInt64_GreaterEqual(swcase->min, min) && CInt64_LessEqual(swcase->min, max)) + CError_Error(CErrorStr172); + if (CInt64_GreaterEqual(swcase->max, min) && CInt64_LessEqual(swcase->max, max)) + CError_Error(CErrorStr172); + if (CInt64_Less(swcase->min, min) && CInt64_Greater(swcase->max, max)) + CError_Error(CErrorStr172); + } + + stmt = CFunc_AppendStatement(ST_LABEL); + stmt->label = newlabel(); + stmt->label->stmt = stmt; + + swcase = lalloc(sizeof(SwitchCase)); + swcase->min = min; + swcase->label = stmt->label; + swcase->next = thing->switchinfo->cases; + thing->switchinfo->cases = swcase; + swcase->max = max; + + if (tk != ':') + CError_ErrorSkip(CErrorStr170); + else + tk = lex(); + + statement(thing); +} + +static void CFunc_NameLocalStaticDataObject(Object *obj, char *str) { + char buf[64]; + HashNameNode *name; + + if (!(cscope_currentfunc && (cscope_currentfunc->qual & Q_INLINE)) || CParser_HasInternalLinkage(cscope_currentfunc)) { + obj->name = CParser_AppendUniqueName(str); + } else { + sprintf(buf, "$localstatic%" PRId32 "$", cfunc_staticvarcount++); + name = CMangler_GetLinkName(cscope_currentfunc); + name = CParser_NameConcat(buf, name->name); + name = CParser_NameConcat(str, name->name); + obj->name = name; + obj->qual |= Q_20000; + obj->sclass = 0; + } +} + +static void sinit_insert_expr(ENode *expr) { + Statement *stmt; + + if (!sinit_first_object) { + sinit_first_object = CParser_NewCompilerDefDataObject(); + sinit_first_object->type = TYPE(&stsignedchar); + sinit_first_object->sclass = TK_STATIC; + CFunc_NameLocalStaticDataObject(sinit_first_object, "init"); + CInit_DeclareData(sinit_first_object, NULL, NULL, sinit_first_object->type->size); + + sinit_label = newlabel(); + stmt = CFunc_AppendStatement(ST_IFGOTO); + stmt->expr = create_objectnode(sinit_first_object); + stmt->label = sinit_label; + } + + stmt = CFunc_AppendStatement(ST_EXPRESSION); + stmt->expr = expr; +} + +static void ainit_insert_expr(ENode *expr) { + Statement *stmt; + + if (ainit_only_one) { + if (ainit_expr) { + stmt = CFunc_AppendStatement(ST_EXPRESSION); + stmt->expr = ainit_expr; + } + ainit_expr = expr; + } else { + stmt = CFunc_AppendStatement(ST_EXPRESSION); + stmt->expr = expr; + } +} + +static ENode *ainit_register_object(Type *type, Object *local, SInt32 offset, Boolean flag) { + return CExcept_RegisterDestructorObject(local, offset, CClass_Destructor(TYPE_CLASS(type)), flag); +} + +static void CFunc_LocalDataDeclarator(DeclInfo *di, TStreamElement *deftoken, Boolean flag1, Boolean flag2) { + Object *object; + Object *aliasObject; + NameSpace *globalNS; + NameSpaceObjectList *nsol; + NameSpaceName *nsname; + Statement *stmt; + + if (di->nspace) + CError_Error(CErrorStr121); + + CDecl_CompleteType(di->thetype); + + object = NULL; + + if ((nsol = CScope_FindName(cscope_current, di->name))) { + switch (nsol->object->otype) { + case OT_OBJECT: + object = OBJECT(nsol->object); + break; + case OT_NAMESPACE: + CError_Error(CErrorStr321); + return; + case OT_ENUMCONST: + case OT_TYPE: + CError_Error(CErrorStr322); + break; + case OT_TYPETAG: + break; + default: + CError_FATAL(1344); + } + } + + if (object) + CError_Error(CErrorStr333, object); + + if (di->storageclass == TK_EXTERN) { + object = NULL; + globalNS = CScope_FindGlobalNS(cscope_current); + if ((nsol = CScope_FindName(globalNS, di->name))) { + switch (nsol->object->otype) { + case OT_OBJECT: + object = OBJECT(nsol->object); + break; + case OT_NAMESPACE: + CError_Error(CErrorStr321); + return; + case OT_ENUMCONST: + case OT_TYPE: + CError_Error(CErrorStr322); + break; + case OT_TYPETAG: + break; + default: + CError_FATAL(1381); + } + } + + if (object) { + if ( + !is_typesame(di->thetype, object->type) || + (di->qual & (Q_CONST | Q_VOLATILE | Q_PASCAL | Q_20000 | Q_WEAK | Q_ALIGNED_MASK)) != (object->qual & (Q_CONST | Q_VOLATILE | Q_PASCAL | Q_20000 | Q_WEAK | Q_ALIGNED_MASK)) + ) + { + CError_Error(CErrorStr249, di->name->name, object->type, object->qual, di->thetype, di->qual); + } + } else { + object = CParser_NewGlobalDataObject(di); + object->nspace = globalNS; + } + + CParser_NewAliasObject(object, 0); + return; + } + + if (di->storageclass != TK_STATIC) + object = CParser_NewObject(di); + else + object = CParser_NewGlobalDataObject(di); + + object->name = di->name; + object->type = di->thetype; + object->qual = di->qual; + object->sclass = di->storageclass; + + switch (di->storageclass) { + case TK_STATIC: + if (flag1) { + CError_Error(CErrorStr177); + return; + } + if (flag2) + CError_Error(CErrorStr174); + + if (CanCreateObject(di->thetype)) { + CError_QualifierCheck(di->qual & ~(Q_CONST | Q_VOLATILE | Q_PASCAL | Q_20000 | Q_WEAK | Q_ALIGNED_MASK)); + CParser_NewAliasObject(object, 0); + object->nspace = cscope_root; + object->datatype = DDATA; + CFunc_NameLocalStaticDataObject(object, object->name->name); + + if (copts.cplusplus) { + sinit_first_object = NULL; + CInit_InitializeStaticData(object, sinit_insert_expr); + if (sinit_first_object) { + stmt = CFunc_AppendStatement(ST_EXPRESSION); + stmt->expr = makediadicnode( + create_objectnode(sinit_first_object), + intconstnode(TYPE(&stsignedchar), 1), + EASS); + stmt = CFunc_AppendStatement(ST_LABEL); + stmt->label = sinit_label; + sinit_label->stmt = stmt; + } + } else { + CInit_InitializeData(object); + } + } + break; + + case 0: + case TK_AUTO: + case TK_REGISTER: + if (CanCreateObject(di->thetype)) { + CError_QualifierCheck(di->qual & ~(Q_CONST | Q_VOLATILE | Q_PASCAL | Q_ALIGNED_MASK)); + object->datatype = DLOCAL; + CFunc_SetupLocalVarInfo(object); + + object->u.var.info->deftoken = *deftoken; + if (object->sclass == TK_REGISTER && flag1) + object->u.var.info->usage = 100; + + CScope_AddObject(cscope_current, object->name, OBJ_BASE(object)); + + if (!flag1) { + if (IS_TYPE_SOM_CLASS(di->thetype)) { + CSOM_InitAutoClass(object); + } else { + CInit_InitializeAutoData(object, ainit_insert_expr, ainit_register_object); + if (object->type != di->thetype && (IS_TYPE_STRUCT(object->type) || IS_TYPE_CLASS(object->type))) { + CError_ASSERT(1478, !cscope_current->is_hash); + CError_ASSERT(1479, nsname = CScope_FindNameSpaceName(cscope_current, object->name)); + CError_ASSERT(1480, nsname->first.object == OBJ_BASE(object)); + CError_ASSERT(1481, !nsname->first.next); + nsname->name = CParser_AppendUniqueName(object->name->name); + + aliasObject = CParser_NewAliasObject(object, 0); + aliasObject->type = di->thetype; + } + } + } + + if (object->datatype == DLOCAL) { + ObjectList *list = lalloc(sizeof(ObjectList)); + list->object = object; + list->next = locals; + locals = list; + } + + IsCompleteType(di->thetype); + } + break; + + default: + CError_FATAL(1504); + } +} + +static ENode *CFunc_ParseLocalDeclarationList(Boolean flag1, Boolean flag2, Boolean flag3, Boolean flag4) { + Type *type; + UInt32 qual; + DeclInfo di; + TStreamElement deftoken; + + ainit_expr = NULL; + ainit_only_one = flag2; + + while (flag2 || isdeclaration(copts.cplusplus, 0, 0, 0)) { + CPrep_GetFileOffsetInfo2(&cparser_fileoffset, &sourceoffset, &sourcefilepath); + + memclrw(&di, sizeof(di)); + di.is_extern_c = cfunc_is_extern_c; + CParser_GetDeclSpecs(&di, 0); + + if (IS_TYPE_TEMPLATE(di.thetype)) { + CError_Error(CErrorStr146); + di.thetype = TYPE(&stsignedint); + } + + type = di.thetype; + qual = di.qual; + + if (tk != ';') { + while (1) { + deftoken = *CPrep_CurStreamElement(); + di.name = NULL; + scandeclarator(&di); + + if (di.name) { + if (di.storageclass != TK_TYPEDEF) { + if (IS_TYPE_FUNC(di.thetype)) { + if (!CDecl_FunctionDeclarator(&di, CScope_FindGlobalNS(cscope_current), 0, 0)) + break; + } else { + CFunc_LocalDataDeclarator(&di, &deftoken, flag1, flag2); + } + } else { + CDecl_TypedefDeclarator(&di); + } + } else { + CError_Error(CErrorStr134); + } + + if (tk == ';') + break; + + if (tk != ',') { + if (!flag2) + CError_Error(CErrorStr123); + break; + } + + di.nspace = NULL; + di.thetype = type; + di.qual = qual; + tk = lex(); + } + } else { + CParser_CheckAnonymousUnion(&di, 1); + } + + if (flag2) + break; + if (flag4) + break; + tk = lex(); + } + + if (flag2) { + if (!ainit_expr) { + if (!flag3) { + CError_Error(CErrorStr141); + ainit_expr = nullnode(); + } + } else { + ainit_expr = checkreference(ainit_expr); + } + } + + return ainit_expr; +} + +static void makeifstatement(ENode *expr, CLabel *label1, CLabel *label2, Boolean flag1, Boolean flag2) { + Statement *stmt; + CLabel *tmplabel; + + if (!expr) { + if (flag1) { + stmt = CFunc_AppendStatement(ST_GOTO); + stmt->label = label1; + return; + } + return; + } + + if ( + ENODE_IS(expr, ETYPCON) && + IS_TYPE_INT(expr->rtype) && + IS_TYPE_INT(expr->data.monadic->rtype) && + expr->rtype->size >= expr->data.monadic->rtype->size + ) + expr = expr->data.monadic; + + if (isnotzero(expr)) { + if (flag1) { + stmt = CFunc_AppendStatement(ST_GOTO); + stmt->label = label1; + return; + } + return; + } + + if (iszero(expr)) { + if (!flag1) { + stmt = CFunc_AppendStatement(ST_GOTO); + stmt->label = label1; + return; + } + return; + } + + if (ENODE_IS(expr, ELOGNOT)) { + makeifstatement(expr->data.monadic, label1, label2, !flag1, flag2); + return; + } + + if (ENODE_IS(expr, ELOR)) { + tmplabel = newlabel(); + if (flag1) { + makeifstatement(expr->data.diadic.left, label1, tmplabel, 1, flag2); + tmplabel->stmt = CFunc_AppendStatement(ST_LABEL); + tmplabel->stmt->label = tmplabel; + makeifstatement(expr->data.diadic.right, label1, label2, 1, flag2); + return; + } else { + makeifstatement(expr->data.diadic.left, label2, tmplabel, 1, flag2); + tmplabel->stmt = CFunc_AppendStatement(ST_LABEL); + tmplabel->stmt->label = tmplabel; + makeifstatement(expr->data.diadic.right, label1, label2, 0, flag2); + return; + } + } + + if (ENODE_IS(expr, ELAND)) { + tmplabel = newlabel(); + if (flag1) { + makeifstatement(expr->data.diadic.left, label2, tmplabel, 0, flag2); + tmplabel->stmt = CFunc_AppendStatement(ST_LABEL); + tmplabel->stmt->label = tmplabel; + makeifstatement(expr->data.diadic.right, label1, label2, 1, flag2); + return; + } else { + makeifstatement(expr->data.diadic.left, label1, tmplabel, 0, flag2); + tmplabel->stmt = CFunc_AppendStatement(ST_LABEL); + tmplabel->stmt->label = tmplabel; + makeifstatement(expr->data.diadic.right, label1, label2, 0, flag2); + return; + } + } + + stmt = CFunc_AppendStatement(ST_IFGOTO); + stmt->label = label1; + stmt->expr = expr; + if (!flag1) + stmt->type = ST_IFNGOTO; + if (flag2) + stmt->flags = stmt->flags | StmtFlag_4; +} + +static void CFunc_HasDtorTempCallBack(ENode *expr) { + if (expr->data.temp.needs_dtor || expr->data.temp.uniqueid) + cfunc_hasdtortemp = 1; +} + +static void ifstatement(Boolean flag1, ENode *expr, CLabel *label, Boolean flag2) { + Statement *stmt; + CLabel *tmplabel; + + if (expr && copts.cplusplus && copts.exceptions) { + cfunc_hasdtortemp = 0; + CExpr_SearchExprTree(expr, CFunc_HasDtorTempCallBack, 1, ETEMP); + if (cfunc_hasdtortemp) { + stmt = CFunc_AppendStatement(flag1 ? ST_IFGOTO : ST_IFNGOTO); + stmt->label = label; + stmt->expr = expr; + if (flag2) + stmt->flags = stmt->flags | StmtFlag_4; + return; + } + } + + tmplabel = newlabel(); + makeifstatement(expr, label, tmplabel, flag1, flag2); + tmplabel->stmt = CFunc_AppendStatement(ST_LABEL); + tmplabel->stmt->label = tmplabel; +} + +Statement *CFunc_GenerateLoop(Statement *stmt, Type *type, ENode *lowerBound, ENode *upperBound, ENode *increment1, ENode *increment2, ENode *(*callback)(ENode *, ENode *)) { + ENode *var1; + ENode *var2; + CLabel *label; + ENode *ind; + ENode *ind2; + Statement *s; + + var1 = CExpr_NewETEMPNode(type, 1); + ind = lalloc(sizeof(ENode)); + *ind = *var1; + ind = makemonadicnode(ind, EINDIRECT); + ind->rtype = type; + + // initialise var1 to lowerBound + if (stmt) { + stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt); + s = stmt; + } else { + s = CFunc_AppendStatement(ST_EXPRESSION); + } + s->expr = makediadicnode(ind, lowerBound, EASS); + + if (increment2) { + var2 = CExpr_NewETEMPNode(type, 1); + ind = lalloc(sizeof(ENode)); + *ind = *var2; + ind = makemonadicnode(ind, EINDIRECT); + ind->rtype = type; + + // initialise var2 to upperBound + if (stmt) { + stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt); + s = stmt; + } else { + s = CFunc_AppendStatement(ST_EXPRESSION); + } + s->expr = makediadicnode(ind, upperBound, EASS); + } + + // label for loop body + label = newlabel(); + if (stmt) { + stmt = CFunc_InsertStatement(ST_LABEL, stmt); + s = stmt; + } else { + s = CFunc_AppendStatement(ST_LABEL); + } + s->label = label; + label->stmt = s; + + if (callback) { + ind = lalloc(sizeof(ENode)); + *ind = *var1; + ind = makemonadicnode(ind, EINDIRECT); + ind->rtype = type; + + if (increment2) { + ind2 = lalloc(sizeof(ENode)); + *ind2 = *var2; + ind2 = makemonadicnode(ind2, EINDIRECT); + ind2->rtype = type; + } else { + ind2 = NULL; + } + + // generate a loop body + if ((ind = callback(ind, ind2))) { + if (stmt) { + stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt); + s = stmt; + } else { + s = CFunc_AppendStatement(ST_EXPRESSION); + } + s->expr = ind; + } + } + + if (increment1) { + ind = lalloc(sizeof(ENode)); + *ind = *var1; + ind = makemonadicnode(ind, EINDIRECT); + ind->rtype = type; + + // add increment1 to var1 + if (stmt) { + stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt); + s = stmt; + } else { + s = CFunc_AppendStatement(ST_EXPRESSION); + } + s->expr = makediadicnode(ind, increment1, EADDASS); + + if (increment2) { + ind = lalloc(sizeof(ENode)); + *ind = *var2; + ind = makemonadicnode(ind, EINDIRECT); + ind->rtype = type; + + // add increment2 to var2 + if (stmt) { + stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt); + s = stmt; + } else { + s = CFunc_AppendStatement(ST_EXPRESSION); + } + s->expr = makediadicnode(ind, increment2, EADDASS); + } + } + + ind = lalloc(sizeof(ENode)); + *ind = *var1; + ind = makemonadicnode(ind, EINDIRECT); + ind->rtype = type; + + // loop if var1 < upperBound + if (stmt) { + stmt = CFunc_InsertStatement(ST_IFGOTO, stmt); + s = stmt; + } else { + s = CFunc_AppendStatement(ST_IFGOTO); + } + s->expr = makediadicnode(ind, upperBound, ELESS); + s->expr->rtype = TYPE(&stbool); + s->label = label; + s->flags = StmtFlag_4; + + return stmt; +} + +static Boolean checklabel(void) { + HashNameNode *savename; + short savesize; + short token; + + savename = tkidentifier; + savesize = tksize; + token = lookahead(); + tkidentifier = savename; + tksize = savesize; + + return token == ':'; +} + +static ENode *returnstatementadjust(ENode *expr, Type *type, UInt32 qual) { + Object *object; + ENode *expr2; + ENode *objexpr; + ObjectList *list; + ENodeList *exprlist; + + for (list = arguments; list; list = list->next) { + if (list->object->name == temp_argument_name) + break; + } + + CError_ASSERT(1907, list); + + object = list->object; + if ((expr2 = CExpr_IsTempConstruction(expr, type, &objexpr)) && ENODE_IS(objexpr, ETEMP)) { + *objexpr = *create_objectnode(object); + return expr2; + } + + if (IS_TYPE_CLASS(type)) { + expr2 = create_objectnode(object); + exprlist = lalloc(sizeof(ENodeList)); + exprlist->next = NULL; + exprlist->node = expr; + return CExpr_ConstructObject(TYPE_CLASS(type), expr2, exprlist, 1, 1, 0, 1, 0); + } + + expr2 = create_objectnode(object); + expr2 = makemonadicnode(expr2, EINDIRECT); + expr2->rtype = type; + + return makediadicnode(expr2, CExpr_AssignmentPromotion(expr, type, qual, 1), EASS); +} + +static void CFunc_AutoResultCheck(ENode *expr) { + while (1) { + while (ENODE_IS(expr, ECOMMA)) + expr = expr->data.diadic.right; + + switch (expr->type) { + case EOBJREF: + if (expr->data.objref->datatype != DLOCAL) + break; + case ETEMP: + CError_Warning(CErrorStr326); + break; + case EADD: + case ESUB: + CFunc_AutoResultCheck(expr->data.diadic.left); + expr = expr->data.diadic.right; + continue; + default: + break; + } + break; + } +} + +static void statement(DeclThing *thing) { + Statement *stmt; + Statement *stmt2; + CLabel *label; + DeclBlock *block; + ENode *expr; + HashNameNode *name; + DeclThing subthing; + + CPrep_GetFileOffsetInfo2(&cparser_fileoffset, &sourceoffset, &sourcefilepath); + + switch (tk) { + case TK_RETURN: + tk = lex(); + if ( + (thing->thetype == &stvoid && !copts.cplusplus) || + CClass_IsConstructor(cscope_currentfunc) || + CClass_IsDestructor(cscope_currentfunc) + ) + { + if (tk != ';') { + CError_Error(CErrorStr315); + expression(); + } + + stmt = CFunc_AppendStatement(ST_RETURN); + stmt->expr = NULL; + CError_ResetErrorSkip(); + tk = lex(); + return; + } + + if (tk == ';') { + if (thing->thetype != &stvoid && (copts.pedantic || copts.cplusplus)) + CError_Warning(CErrorStr184); + + stmt = CFunc_AppendStatement(ST_RETURN); + stmt->expr = NULL; + CError_ResetErrorSkip(); + tk = lex(); + return; + } + + if (copts.old_argmatch) + expr = expression(); + else + expr = s_expression(); + + if (thing->thetype == &stvoid) { + if (expr->rtype != &stvoid) + CError_Error(CErrorStr315); + + stmt = CFunc_AppendStatement(ST_EXPRESSION); + stmt->expr = expr; + + stmt = CFunc_AppendStatement(ST_RETURN); + stmt->expr = NULL; + } else { + if (CMach_GetFunctionResultClass(TYPE_FUNC(cscope_currentfunc->type)) == 1) + expr = returnstatementadjust(expr, thing->thetype, thing->qual); + else + expr = CExpr_AssignmentPromotion(expr, thing->thetype, thing->qual, 1); + + stmt = CFunc_AppendStatement(ST_RETURN); + stmt->expr = expr; + + if (IS_TYPE_POINTER_ONLY(thing->thetype)) + CFunc_AutoResultCheck(expr); + } + + break; + + case TK_CASE: + scancase(thing); + return; + + case TK_DEFAULT: + if (!thing->switchinfo) { + CError_Error(CErrorStr169); + return; + } + + if (lex() != ':') + CError_ErrorSkip(CErrorStr170); + else + tk = lex(); + + if (thing->switchinfo->defaultlabel) + CError_ErrorSkip(CErrorStr173); + + stmt = CFunc_AppendStatement(ST_LABEL); + stmt->label = newlabel(); + stmt->label->stmt = stmt; + thing->switchinfo->defaultlabel = stmt->label; + statement(thing); + return; + + case TK_SWITCH: + if (lex() != '(') + CError_ErrorSkip(CErrorStr114); + else + tk = lex(); + + if (copts.cplusplus && !copts.ARMscoping && isdeclaration(1, 0, 0, '=')) { + block = CFunc_NewDeclBlock(); + expr = CFunc_ParseLocalDeclarationList(0, 1, 0, 0); + if (CScope_IsEmptyNameSpace(cscope_current)) { + CFunc_RestoreBlock(block); + block = NULL; + } + } else { + expr = expression(); + block = NULL; + } + + stmt = CFunc_AppendStatement(ST_SWITCH); + stmt->expr = CExpr_ConvertToIntegral(expr); + + if (tk != ')') + CError_ErrorSkip(CErrorStr115); + else + tk = lex(); + + stmt->label = (CLabel *) lalloc(sizeof(SwitchInfo)); + ((SwitchInfo *) stmt->label)->defaultlabel = NULL; + ((SwitchInfo *) stmt->label)->cases = NULL; + ((SwitchInfo *) stmt->label)->x8 = stmt->expr->rtype; + + label = newlabel(); + subthing = *thing; + subthing.loopBreak = label; + subthing.switchinfo = (SwitchInfo *) stmt->label; + CFunc_CompoundStatement(&subthing); + + if (!subthing.switchinfo->defaultlabel) + subthing.switchinfo->defaultlabel = label; + + if (!subthing.switchinfo->cases) { + stmt->type = ST_EXPRESSION; + stmt2 = lalloc(sizeof(Statement)); + *stmt2 = *stmt; + stmt->next = stmt2; + stmt2->type = ST_GOTO; + stmt2->label = subthing.switchinfo->defaultlabel; + stmt2->dobjstack = cexcept_dobjstack; + } + + stmt = CFunc_AppendStatement(ST_LABEL); + stmt->label = label; + label->stmt = stmt; + + if (block) + CFunc_RestoreBlock(block); + return; + + case TK_GOTO: + if ((tk = lex()) != TK_IDENTIFIER) { + if (tk == '*' && !copts.ANSIstrict) { + tk = lex(); + stmt = CFunc_AppendStatement(ST_GOTOEXPR); + stmt->expr = expression(); + if (!IS_TYPE_POINTER_ONLY(stmt->expr->rtype)) { + CError_Error(CErrorStr146); + stmt->expr = nullnode(); + stmt->expr->rtype = TYPE(&void_ptr); + } + } else { + CError_Error(CErrorStr107); + return; + } + } else { + stmt = CFunc_AppendStatement(ST_GOTO); + if (!(stmt->label = findlabel())) { + stmt->label = newlabel(); + stmt->label->next = Labels; + Labels = stmt->label; + stmt->label->name = tkidentifier; + } + tk = lex(); + } + break; + + case TK_BREAK: + if (thing->loopBreak) { + stmt = CFunc_AppendStatement(ST_GOTO); + stmt->label = thing->loopBreak; + } else { + CError_Error(CErrorStr169); + } + tk = lex(); + break; + + case TK_CONTINUE: + if (thing->loopContinue) { + stmt = CFunc_AppendStatement(ST_GOTO); + stmt->label = thing->loopContinue; + } else { + CError_Error(CErrorStr169); + } + tk = lex(); + break; + + case TK_FOR: { + CLabel *forLabel1; + CLabel *forLabel2; + CLabel *forLabel3; + ENode *forCond; + ENode *forInc; + + if (lex() != '(') + CError_ErrorSkip(CErrorStr114); + else + tk = lex(); + + block = NULL; + if (tk != ';') { + if (!copts.cplusplus || !isdeclaration(1, 0, 0, 0)) { + expr = expression(); + CExpr_CheckUnusedExpression(expr); + } else { + if (!copts.ARMscoping) + block = CFunc_NewDeclBlock(); + expr = CFunc_ParseLocalDeclarationList(0, 1, 1, 0); + if (block && CScope_IsEmptyNameSpace(cscope_current)) { + CFunc_RestoreBlock(block); + block = NULL; + } + } + + if (expr) { + stmt = CFunc_AppendStatement(ST_EXPRESSION); + stmt->expr = expr; + } + + if (tk == ';') + CError_ResetErrorSkip(); + else + CError_Error(CErrorStr123); + } else { + CError_ResetErrorSkip(); + } + + if ((tk = lex()) != ';') { + if (copts.cplusplus && !copts.ARMscoping && isdeclaration(1, 0, 0, '=')) { + if (!block) + block = CFunc_NewDeclBlock(); + expr = CFunc_ParseLocalDeclarationList(0, 1, 0, 0); + if (CScope_IsEmptyNameSpace(cscope_current)) { + CFunc_RestoreBlock(block); + block = NULL; + } + } else { + expr = expression(); + CExpr_CheckUnwantedAssignment(expr); + } + + forCond = CExpr_ConvertToCondition(expr); + + if (tk == ';') + CError_ResetErrorSkip(); + else + CError_Error(CErrorStr123); + } else { + CError_ResetErrorSkip(); + forCond = NULL; + } + + if ((tk = lex()) != ')') { + forInc = expression(); + CExpr_CheckUnusedExpression(forInc); + if (tk == ')') + CError_ResetErrorSkip(); + else + CError_Error(CErrorStr115); + } else { + CError_ResetErrorSkip(); + forInc = NULL; + } + + if (copts.warn_possunwant) { + spaceskip = 0; + if ((tk = lex()) == ';' && !spaceskip) + CError_Warning(CErrorStr206); + } else { + tk = lex(); + } + + if (forCond) { + stmt = CFunc_AppendStatement(ST_GOTO); + label = newlabel(); + stmt->label = label; + } else { + label = newlabel(); + } + + CFunc_LoopIncrement(); + + stmt = CFunc_AppendStatement(ST_LABEL); + forLabel1 = stmt->label = newlabel(); + forLabel1->stmt = stmt; + + forLabel2 = newlabel(); + forLabel3 = newlabel(); + + subthing = *thing; + subthing.loopContinue = forLabel3; + subthing.loopBreak = forLabel2; + + if (tk != '{') { + DeclBlock *b = CFunc_NewDeclBlock(); + CFunc_CompoundStatement(&subthing); + CFunc_RestoreBlock(b); + } else { + CFunc_CompoundStatement(&subthing); + } + + stmt = CFunc_AppendStatement(ST_LABEL); + stmt->label = forLabel3; + forLabel3->stmt = stmt; + + if (forInc) { + stmt = CFunc_AppendStatement(ST_EXPRESSION); + stmt->expr = forInc; + } + + stmt = CFunc_AppendStatement(ST_LABEL); + stmt->label = label; + label->stmt = stmt; + + ifstatement(1, forCond, forLabel1, 1); + CFunc_LoopDecrement(); + + stmt = CFunc_AppendStatement(ST_LABEL); + stmt->label = forLabel2; + forLabel2->stmt = stmt; + + if (block) + CFunc_RestoreBlock(block); + + return; + } + + case TK_DO: { + CLabel *label1; + CLabel *label2; + CLabel *label3; + + CFunc_LoopIncrement(); + stmt = CFunc_AppendStatement(ST_LABEL); + label1 = stmt->label = newlabel(); + label1->stmt = stmt; + + label2 = newlabel(); + label3 = newlabel(); + + subthing = *thing; + subthing.loopContinue = label2; + subthing.loopBreak = label3; + + tk = lex(); + CFunc_CompoundStatement(&subthing); + + stmt = CFunc_AppendStatement(ST_LABEL); + stmt->label = label2; + label2->stmt = stmt; + + if (tk != TK_WHILE) + CError_Error(CErrorStr105); + + if (lex() != '(') + CError_ErrorSkip(CErrorStr114); + else + tk = lex(); + + expr = CExpr_ConvertToCondition(expression()); + CExpr_CheckUnwantedAssignment(expr); + + if (tk != ')') + CError_ErrorSkip(CErrorStr115); + else + tk = lex(); + + ifstatement(1, expr, label1, 1); + + CFunc_LoopDecrement(); + + stmt = CFunc_AppendStatement(ST_LABEL); + stmt->label = label3; + label3->stmt = stmt; + break; + } + + case TK_WHILE: { + CLabel *label1; + CLabel *label2; + CLabel *label3; + + if ((tk = lex()) != '(') + CError_ErrorSkip(CErrorStr114); + else + tk = lex(); + + if (copts.cplusplus && !copts.ARMscoping && isdeclaration(1, 0, 0, '=')) { + block = CFunc_NewDeclBlock(); + expr = CFunc_ParseLocalDeclarationList(0, 1, 0, 0); + if (CScope_IsEmptyNameSpace(cscope_current)) { + CFunc_RestoreBlock(block); + block = NULL; + } + } else { + expr = expression(); + block = NULL; + CExpr_CheckUnwantedAssignment(expr); + } + expr = CExpr_ConvertToCondition(expr); + + if (tk != ')') { + CError_ErrorSkip(CErrorStr115); + } else { + if (copts.warn_possunwant) { + spaceskip = 0; + if ((tk = lex()) == ';' && !spaceskip) + CError_Warning(CErrorStr206); + } else { + tk = lex(); + } + } + + stmt = CFunc_AppendStatement(ST_GOTO); + label1 = newlabel(); + stmt->label = label1; + + CFunc_LoopIncrement(); + + stmt = CFunc_AppendStatement(ST_LABEL); + label2 = stmt->label = newlabel(); + label2->stmt = stmt; + + label3 = newlabel(); + + subthing = *thing; + subthing.loopContinue = label1; + subthing.loopBreak = label3; + + CFunc_CompoundStatement(&subthing); + + stmt = CFunc_AppendStatement(ST_LABEL); + stmt->label = label1; + label1->stmt = stmt; + + ifstatement(1, expr, label2, 1); + + CFunc_LoopDecrement(); + + stmt = CFunc_AppendStatement(ST_LABEL); + stmt->label = label3; + label3->stmt = stmt; + + if (block) + CFunc_RestoreBlock(block); + return; + } + + case TK_IF: { + CLabel *label1; + if ((tk = lex()) != '(') + CError_ErrorSkip(CErrorStr114); + else + tk = lex(); + + if (copts.cplusplus && !copts.ARMscoping && isdeclaration(1, 0, 0, '=')) { + block = CFunc_NewDeclBlock(); + expr = CFunc_ParseLocalDeclarationList(0, 1, 0, 0); + if (CScope_IsEmptyNameSpace(cscope_current)) { + CFunc_RestoreBlock(block); + block = NULL; + } + } else { + expr = expression(); + block = NULL; + CExpr_CheckUnwantedAssignment(expr); + } + + expr = CExpr_ConvertToCondition(expr); + + label1 = newlabel(); + ifstatement(0, expr, label1, 0); + + if (tk != ')') { + CError_ErrorSkip(CErrorStr115); + } else { + if (copts.warn_possunwant) { + spaceskip = 0; + if ((tk = lex()) == ';' && !spaceskip) + CError_Warning(CErrorStr206); + } else { + tk = lex(); + } + } + + CFunc_CompoundStatement(thing); + + if (tk == TK_ELSE) { + if (copts.warn_possunwant) { + spaceskip = 0; + if ((tk = lex()) == ';' && !spaceskip) + CError_Warning(CErrorStr206); + } else { + tk = lex(); + } + + stmt = CFunc_AppendStatement(ST_GOTO); + label = stmt->label = newlabel(); + + stmt = CFunc_AppendStatement(ST_LABEL); + stmt->label = label1; + label1->stmt = stmt; + + CFunc_CompoundStatement(thing); + + label1 = label; + } + + stmt = CFunc_AppendStatement(ST_LABEL); + stmt->label = label1; + label1->stmt = stmt; + + if (block) + CFunc_RestoreBlock(block); + + return; + } + + case '{': + CFunc_CompoundStatement(thing); + return; + + case TK_ASM: + if (copts.cplusplus || !copts.ANSIstrict) { + tk = lex(); + volatileasm = 0; + + if (tk == TK_VOLATILE || (tk == TK_IDENTIFIER && !strcmp(tkidentifier->name, "__volatile__"))) { + tk = lex(); + volatileasm = 1; + } + + if (tk == '(') { + InlineAsm_Assemble(); + if (tk == ')') { + tk = lex(); + break; + } else { + CError_Error(CErrorStr115); + return; + } + } + + if (tk == '{') { + InlineAsm_Assemble(); + if (tk != '}') { + CError_Error(CErrorStr130); + return; + } + if ((tk = lex()) == ';') + tk = lex(); + CError_ResetErrorSkip(); + return; + } + + CError_Error(CErrorStr114); + } else { + CError_Error(CErrorStr121); + } + return; + + case TK_TRY: + tk = lex(); + CExcept_ScanTryBlock(thing, 0); + return; + + case TK_USING: + if ((tk = lex()) == TK_NAMESPACE) { + tk = lex(); + CScope_ParseUsingDirective(cscope_current); + } else { + CScope_ParseUsingDeclaration(cscope_current, 0, 0); + } + return; + + case TK_NAMESPACE: + if ((tk = lex()) != TK_IDENTIFIER) { + CError_Error(CErrorStr107); + return; + } + name = tkidentifier; + if ((tk = lex()) != '=') { + CError_Error(CErrorStr121); + return; + } + + CScope_ParseNameSpaceAlias(name); + break; + + case ';': + break; + + case TK_IDENTIFIER: + if (checklabel()) { + stmt = CFunc_AppendStatement(ST_LABEL); + if ((stmt->label = findlabel())) { + if (stmt->label->stmt) + CError_Error(CErrorStr171, tkidentifier->name); + } else { + stmt->label = newlabel(); + stmt->label->next = Labels; + Labels = stmt->label; + stmt->label->name = tkidentifier; + } + + stmt->label->stmt = stmt; + tk = lex(); + tk = lex(); + statement(thing); + return; + } + tk = TK_IDENTIFIER; + + default: + if (copts.cplusplus && isdeclaration(1, 0, 0, 0)) { + CFunc_ParseLocalDeclarationList(0, 0, 0, 1); + tk = lex(); + return; + } + + stmt = CFunc_AppendStatement(ST_EXPRESSION); + stmt->expr = expression(); + CExpr_CheckUnusedExpression(stmt->expr); + } + + if (tk == ';') { + CPrep_TokenStreamFlush(); + tk = lex(); + CError_ResetErrorSkip(); + } else { + CError_ErrorSkip(CErrorStr123); + } +} + +void CFunc_CompoundStatement(DeclThing *thing) { + DeclBlock *block; + + block = CFunc_NewDeclBlock(); + + if (tk == '{') { + tk = lex(); + if (!copts.cplusplus && isdeclaration(0, 0, 0, 0)) + CFunc_ParseLocalDeclarationList(0, 0, 0, 0); + + while (tk != '}') + statement(thing); + + CPrep_GetFileOffsetInfo2(&cparser_fileoffset, &sourceoffset, &sourcefilepath); + tk = lex(); + } else { + statement(thing); + } + + CFunc_RestoreBlock(block); +} + +static void CFunc_InsertArgumentCopyConversion(Object *obj, Type *type1, Type *type2, Boolean flag) { + Object *newobj; + Statement *stmt; + ENode *expr; + NameSpaceObjectList *nsol; + ObjectList *list; + + newobj = lalloc(sizeof(Object)); + *newobj = *obj; + newobj->type = type2; + + CFunc_SetupLocalVarInfo(newobj); + + obj->name = CParser_GetUniqueName(); + if (flag) + obj->type = CDecl_NewPointerType(type1); + else + obj->type = type1; + + CError_ASSERT(2527, (nsol = CScope_FindName(cscope_current, newobj->name)) && nsol->object == OBJ_BASE(obj)); + nsol->object = OBJ_BASE(newobj); + + list = lalloc(sizeof(ObjectList)); + list->object = newobj; + list->next = locals; + locals = list; + + stmt = CFunc_AppendStatement(ST_EXPRESSION); + expr = create_objectnode(obj); + if (flag) { + expr->rtype = CDecl_NewPointerType(type1); + expr = makemonadicnode(expr, EINDIRECT); + } + expr->rtype = type1; + + if (type1 != type2) + expr = promote(expr, type2); + + stmt->expr = makediadicnode(create_objectnode(newobj), expr, EASS); +} + +static void CFunc_AdjustOldStyleArgs(void) { + ObjectList *list; + + for (list = arguments; list; list = list->next) { + if (IS_TYPE_FLOAT(list->object->type) && list->object->type->size < stdouble.size) + CFunc_InsertArgumentCopyConversion(list->object, TYPE(&stdouble), list->object->type, 0); + } +} + +void CFunc_SetupNewFuncArgs(Object *func, FuncArg *args) { + Object *obj; + ObjectList *newlist; + + arguments = NULL; + + if (args != &elipsis && args != &oldstyle) { + newlist = NULL; + + while (args && args != &elipsis) { + IsCompleteType(args->type); + + obj = CParser_NewLocalDataObject(NULL, 0); + obj->name = !args->name ? no_name_node : args->name; + obj->type = args->type; + obj->qual = args->qual; + obj->sclass = args->sclass; + + CFunc_SetupLocalVarInfo(obj); + + if (IS_TYPE_CLASS(obj->type) && CClass_ReferenceArgument(TYPE_CLASS(obj->type))) { + obj->type = CDecl_NewPointerType(obj->type); + TPTR_QUAL(obj->type) = Q_REFERENCE | Q_RESTRICT; + } + + if (obj->name == no_name_node && copts.ANSIstrict && !copts.cplusplus && !(func->qual & Q_MANGLE_NAME)) + CError_Error(CErrorStr127); + + if (newlist) { + newlist->next = lalloc(sizeof(ObjectList)); + newlist = newlist->next; + } else { + newlist = lalloc(sizeof(ObjectList)); + arguments = newlist; + } + + newlist->next = NULL; + newlist->object = obj; + + args = args->next; + } + } +} + +static ObjectList *CFunc_CopyObjectList(const FuncArg *args) { + Object *obj; + ObjectList *list; + ObjectList *last; + + list = NULL; + + while (args) { + if (list) { + last->next = lalloc(sizeof(ObjectList)); + last = last->next; + } else { + last = lalloc(sizeof(ObjectList)); + list = last; + } + + obj = CParser_NewLocalDataObject(NULL, 0); + obj->name = args->name; + obj->type = args->type; + obj->qual = args->qual; + obj->sclass = args->sclass; + CFunc_SetupLocalVarInfo(obj); + + last->object = obj; + last->next = NULL; + + args = args->next; + } + + return list; +} + +static void SetupFunctionArguments(Object *func, DeclInfo *di, Statement *firstStmt) { + ObjectList *list; + Object *resultobj; + Object *obj; + Type *type; + DeclInfo my_di; + + if (TYPE_FUNC(func->type)->args) { + if (di->x45) { + arguments = CFunc_CopyObjectList(di->x18); + while (1) { + if (tk == '{') + break; + + memclrw(&my_di, sizeof(my_di)); + CParser_GetDeclSpecs(&my_di, 0); + + type = my_di.thetype; + if (my_di.storageclass && my_di.storageclass != TK_REGISTER) + CError_Error(CErrorStr127); + + while (1) { + my_di.thetype = type; + my_di.name = NULL; + scandeclarator(&my_di); + if (!my_di.name) { + CError_Error(CErrorStr107); + break; + } + + adjustargumenttype(&my_di); + IsCompleteType(my_di.thetype); + + if ((obj = CFunc_IsInObjList(arguments, my_di.name))) { + if (obj->type) + CError_Error(CErrorStr333, obj); + obj->type = my_di.thetype; + obj->sclass = my_di.storageclass; + obj->qual = my_di.qual; + } else { + CError_Error(CErrorStr127); + } + + if (tk != ',') + break; + tk = lex(); + } + + if (tk != ';') + CError_ErrorSkip(CErrorStr123); + else + tk = lex(); + } + + for (list = arguments; list; list = list->next) { + if (!list->object->type) + list->object->type = TYPE(&stsignedint); + } + } else { + CFunc_SetupNewFuncArgs(func, TYPE_FUNC(func->type)->args); + } + } + + if (CMach_GetFunctionResultClass(TYPE_FUNC(func->type)) == 1) { + resultobj = CParser_NewLocalDataObject(NULL, 0); + resultobj->name = temp_argument_name; + resultobj->type = CDecl_NewPointerType(TYPE_FUNC(func->type)->functype); + CFunc_SetupLocalVarInfo(resultobj); + + list = lalloc(sizeof(ObjectList)); + list->object = resultobj; + if (CABI_GetStructResultArgumentIndex(TYPE_FUNC(func->type))) { + CError_ASSERT(2797, arguments); + list->next = arguments->next; + arguments->next = list; + } else { + list->next = arguments; + arguments = list; + } + } + + for (list = arguments; list; list = list->next) { + NameSpaceObjectList *nsol = CScope_InsertName(cscope_current, list->object->name); + nsol->object = OBJ_BASE(list->object); + } +} + +NameSpace *CFunc_FuncGenSetup(Statement *stmt, Object *func) { + NameSpace *nspace; + DeclBlock *block; + + nspace = CScope_NewListNameSpace(NULL, 0); + nspace->parent = cscope_current; + cscope_current = nspace; + + arguments = NULL; + locals = NULL; + Labels = NULL; + + localcount = 0; + cfunc_staticvarcount = 0; + + CExcept_Setup(); + + memclrw(stmt, sizeof(Statement)); + curstmt = stmt; + stmt->type = ST_NOP; + curstmtvalue = 1; + stmt->value = 1; + + blockcount = 0; + block = lalloc(sizeof(DeclBlock)); + memclrw(block, sizeof(DeclBlock)); + block->index = blockcount++; + block->parent_nspace = cscope_current; + + firstblock = block; + currentblock = block; + + return nspace; +} + +CFuncSave *CFunc_GetGlobalCompilerState(void) { + CFuncSave *state; + + if (!cscope_currentfunc && !cscope_currentclass && cscope_current == cscope_root) + return NULL; + + locklheap(); + state = lalloc(sizeof(CFuncSave)); + + CScope_SetNameSpaceScope(cscope_root, &state->scope); + + state->arguments = arguments; + arguments = NULL; + + state->locals = locals; + locals = NULL; + + state->labels = Labels; + Labels = NULL; + + state->curstmt = curstmt; + curstmt = NULL; + + state->firstblock = firstblock; + firstblock = NULL; + + state->currentblock = currentblock; + currentblock = NULL; + + state->cexcept_dobjstack = cexcept_dobjstack; + cexcept_dobjstack = NULL; + + state->sinit_label = sinit_label; + sinit_label = NULL; + + state->ainit_expr = ainit_expr; + ainit_expr = NULL; + + state->ctor_chain = ctor_chain; + ctor_chain = NULL; + + state->cinit_tempnodefunc = cinit_tempnodefunc; + cinit_tempnodefunc = NULL; + + state->trychain = trychain; + trychain = NULL; + + state->cparser_fileoffset = cparser_fileoffset; + state->symdecltoken = symdecltoken; + + state->functionbodyoffset = functionbodyoffset; + functionbodyoffset = 0; + + state->functionbodypath = functionbodypath; + functionbodypath = NULL; + + state->symdecloffset = symdecloffset; + symdecloffset = 0; + + state->symdeclend = symdeclend; + + state->sourceoffset = sourceoffset; + sourceoffset = 0; + + state->sourcefilepath = sourcefilepath; + sourcefilepath = NULL; + + state->curstmtvalue = curstmtvalue; + curstmtvalue = 0; + + state->name_obj_check = name_obj_check; + name_obj_check = NULL; + + state->check_arglist = check_arglist; + check_arglist = NULL; + + state->blockcount = blockcount; + blockcount = 0; + + state->localcount = localcount; + localcount = 0; + + state->tk = tk; + state->tkidentifier = tkidentifier; + + state->global_access = global_access; + + state->cexcept_hasdobjects = cexcept_hasdobjects; + cexcept_hasdobjects = 0; + + state->sinit_first_object = sinit_first_object; + sinit_first_object = NULL; + + state->ainit_only_one = ainit_only_one; + ainit_only_one = 0; + + state->cfunc_is_extern_c = cfunc_is_extern_c; + cfunc_is_extern_c = 0; + + state->temp_reference_init = temp_reference_init; + + return state; +} + +void CFunc_SetGlobalCompilerState(CFuncSave *state) { + if (state) { + CScope_RestoreScope(&state->scope); + + arguments = state->arguments; + locals = state->locals; + Labels = state->labels; + curstmt = state->curstmt; + firstblock = state->firstblock; + currentblock = state->currentblock; + cexcept_dobjstack = state->cexcept_dobjstack; + sinit_label = state->sinit_label; + ainit_expr = state->ainit_expr; + ctor_chain = state->ctor_chain; + cinit_tempnodefunc = state->cinit_tempnodefunc; + trychain = state->trychain; + name_obj_check = state->name_obj_check; + check_arglist = state->check_arglist; + curstmtvalue = state->curstmtvalue; + cparser_fileoffset = state->cparser_fileoffset; + symdecltoken = state->symdecltoken; + functionbodyoffset = state->functionbodyoffset; + functionbodypath = state->functionbodypath; + symdecloffset = state->symdecloffset; + symdeclend = state->symdeclend; + sourceoffset = state->sourceoffset; + sourcefilepath = state->sourcefilepath; + blockcount = state->blockcount; + tk = state->tk; + tkidentifier = state->tkidentifier; + global_access = state->global_access; + localcount = state->localcount; + cexcept_hasdobjects = state->cexcept_hasdobjects; + sinit_first_object = state->sinit_first_object; + ainit_only_one = state->ainit_only_one; + cfunc_is_extern_c = state->cfunc_is_extern_c; + temp_reference_init = state->temp_reference_init; + + unlocklheap(); + } +} + +void CFunc_Gen(Statement *stmt, Object *func, UInt8 unk) { + Boolean flag; + CI_FuncData packed; + + if ((TYPE_FUNC(func->type)->flags & FUNC_FLAGS_400000) && !anyerrors) { + CInline_PackIFunctionData(&packed, stmt, func); + flag = 1; + } else { + flag = 0; + } + + CInline_GenFunc(stmt, func, unk); + + if (flag) + CClass_DefineCovariantFuncs(func, &packed); +} + +static void CFunc_CheckCtorInitializer(TypeClass *tclass, CtorChain *chain) { + ObjMemberVar *ivar; + CtorChain *scan; + + if (tclass->mode != CLASS_MODE_UNION) { + for (ivar = tclass->ivars; ivar; ivar = ivar->next) { + if (IS_TYPE_REFERENCE(ivar->type)) { + for (scan = chain; scan; scan = scan->next) { + if (scan->what == CtorChain_MemberVar && scan->u.membervar == ivar) + break; + } + + if (!scan) + CError_Error(CErrorStr256, ivar->name->name); + } else if (CParser_IsConst(ivar->type, ivar->qual)) { + for (scan = chain; scan; scan = scan->next) { + if (scan->what == CtorChain_MemberVar && scan->u.membervar == ivar) + break; + } + + if (!scan && !IS_TYPE_CLASS(ivar->type)) + CError_Error(CErrorStr255, ivar->name->name); + } + } + } +} + +void CFunc_CheckClassCtors(TypeClass *tclass) { + CFunc_CheckCtorInitializer(tclass, NULL); +} + +static void CFunc_ParseCtorInitializer(void) { + CtorChain *chain; + ENodeList *args; + TypeClass *tclass; + ObjMemberVar *ivar; + ClassList *base; + VClassList *vbase; + ENode *expr; + Type *origtype; + + ctor_chain = NULL; + + if (tk == ':') { + do { + tclass = NULL; + switch ((tk = lex())) { + case TK_IDENTIFIER: + for (ivar = cscope_currentclass->ivars; ivar; ivar = ivar->next) { + if (ivar->name == tkidentifier && lookahead() == '(') + goto do_ivar; + } + for (base = cscope_currentclass->bases; base; base = base->next) { + if (base->base->classname == tkidentifier) { + if (lookahead() == '(') { + tclass = base->base; + tk = lex(); + } else { + tkidentifier = base->base->classname; + } + break; + } + } + break; + + case TK_COLON_COLON: + break; + + default: + CError_Error(CErrorStr212); + return; + } + + if (!tclass) + tclass = CClass_GetQualifiedClass(); + + if (tclass) { + for (vbase = cscope_currentclass->vbases; vbase; vbase = vbase->next) { + if (vbase->base == tclass) + break; + } + + if (vbase) { + for (chain = ctor_chain; chain; chain = chain->next) { + if (chain->what == CtorChain_VBase && chain->u.vbase == vbase) { + CError_Error(CErrorStr212); + return; + } + } + + chain = lalloc(sizeof(CtorChain)); + chain->what = CtorChain_VBase; + chain->u.vbase = vbase; + } else { + for (base = cscope_currentclass->bases; base; base = base->next) { + if (base->base == tclass) + break; + } + + if (base) { + for (chain = ctor_chain; chain; chain = chain->next) { + if (chain->what == CtorChain_Base && chain->u.base == base) { + CError_Error(CErrorStr212); + return; + } + } + + chain = lalloc(sizeof(CtorChain)); + chain->what = CtorChain_Base; + chain->u.base = base; + } else { + CError_Error(CErrorStr212); + return; + } + } + } else { + for (ivar = cscope_currentclass->ivars; ivar; ivar = ivar->next) { + if (ivar->name == tkidentifier) + break; + } + + if (ivar) { + do_ivar: + for (chain = ctor_chain; chain; chain = chain->next) { + if (chain->what == CtorChain_MemberVar && chain->u.membervar == ivar) + CError_Error(CErrorStr212); + } + + chain = lalloc(sizeof(CtorChain)); + chain->what = CtorChain_MemberVar; + chain->u.membervar = ivar; + } else { + CError_Error(CErrorStr212); + return; + } + + tk = lex(); + } + + if (tk != '(') { + CError_Error(CErrorStr114); + return; + } + + tk = lex(); + args = CExpr_ScanExpressionList(1); + + if (tk != ')') { + CError_Error(CErrorStr115); + return; + } + + switch (chain->what) { + case CtorChain_Base: + expr = CABI_MakeThisExpr(NULL, chain->u.base->offset); + chain->objexpr = CExpr_ConstructObject(chain->u.base->base, expr, args, 1, 0, 0, 0, 1); + break; + case CtorChain_VBase: + expr = CABI_MakeThisExpr(chain->u.vbase->base, chain->u.vbase->offset); + chain->objexpr = CExpr_ConstructObject(chain->u.vbase->base, expr, args, 1, 0, 0, 0, 1); + break; + case CtorChain_MemberVar: + expr = CABI_MakeThisExpr(cscope_currentclass, chain->u.membervar->offset); + expr->flags = chain->u.membervar->qual & ENODE_FLAG_QUALS; + switch (chain->u.membervar->type->type) { + case TYPECLASS: + chain->objexpr = CExpr_ConstructObject(TYPE_CLASS(chain->u.membervar->type), expr, args, 1, 1, 0, 1, 1); + break; + case TYPEARRAY: + if (args) { + CError_Error(CErrorStr212); + continue; + } + chain->objexpr = NULL; + break; + default: + if (!args) { + args = lalloc(sizeof(ENodeList)); + args->next = NULL; + args->node = CExpr_DoExplicitConversion(chain->u.membervar->type, chain->u.membervar->qual, NULL); + } + if (args->next) { + CError_Error(CErrorStr212); + return; + } + expr = makemonadicnode(expr, EINDIRECT); + expr->rtype = chain->u.membervar->type; + if (IS_TYPE_BITFIELD(origtype = expr->rtype)) { + expr->data.monadic = makemonadicnode(expr->data.monadic, EBITFIELD); + expr->data.monadic->rtype = origtype; + expr->rtype = TYPE_BITFIELD(origtype)->bitfieldtype; + } + + chain->objexpr = makediadicnode(expr, CExpr_AssignmentPromotion(args->node, expr->rtype, expr->flags, 1), EASS); + } + break; + default: + CError_FATAL(3286); + } + + chain->next = ctor_chain; + ctor_chain = chain; + } while ((tk = lex()) == ','); + } +} + +static void CFunc_FunctionRedefinedCheck(Object *func) { + if (TYPE_FUNC(func->type)->flags & FUNC_AUTO_GENERATED) + CError_Error(CErrorStr333, func); + + if ((TYPE_FUNC(func->type)->flags & FUNC_DEFINED) && func->datatype != DINLINEFUNC) + CError_Error(CErrorStr333, func); + + TYPE_FUNC(func->type)->flags |= FUNC_DEFINED; +} + +static Object *CFunc_DeclareFuncName(char *str, HashNameNode *name) { + Object *obj; + Object *aliasobj; + DeclInfo di; + + memclrw(&di, sizeof(di)); + di.name = name; + di.storageclass = TK_STATIC; + di.qual = Q_CONST; + di.thetype = CDecl_NewArrayType(TYPE(&stchar), strlen(str) + 1); + + obj = CParser_NewGlobalDataObject(&di); + aliasobj = CParser_NewAliasObject(obj, 0); + obj->nspace = cscope_root; + obj->datatype = DDATA; + CFunc_NameLocalStaticDataObject(obj, obj->name->name); + + return aliasobj; +} + +void CFunc_ParseFuncDef(Object *func, DeclInfo *di, TypeClass *tclass, Boolean is_method, Boolean is_static, NameSpace *nspace) { + Boolean has_try; + Object *nameobj_func; + Object *nameobj_FUNCTION; + Object *nameobj_pretty; + char *prettyname; + Statement *stmt18; + Statement *stmt16; + Statement firstStmt; + DeclThing thing; + CScopeSave scope; + + nameobj_func = NULL; + nameobj_FUNCTION = NULL; + nameobj_pretty = NULL; + prettyname = NULL; + + CError_ASSERT(3373, IS_TYPE_FUNC(func->type)); + + CFunc_FunctionRedefinedCheck(func); + CParser_UpdateObject(func, di); + + if (!is_method) { + CScope_SetFunctionScope(func, &scope); + if (tclass) + cscope_current = tclass->nspace; + } else { + CScope_SetMethodScope(func, tclass, is_static, &scope); + } + + if (nspace) + cscope_current = nspace; + + if (cscope_currentclass) + CClass_MemberDef(func, cscope_currentclass); + + cfunc_is_extern_c = di->is_extern_c; + + CError_ASSERT(3392, IS_TYPE_FUNC(func->type)); + if (di->x45 && (func->qual & Q_ASM)) + CError_Error(CErrorStr176); + + if (cparamblkptr->precompile == 1 && !(func->qual & Q_INLINE)) + CError_ErrorTerm(CErrorStr180); + + if (di->x49) + CError_Error(CErrorStr127); + + CFunc_FuncGenSetup(&firstStmt, func); + if (!IS_TYPE_VOID(TYPE_FUNC(func->type)->functype)) + IsCompleteType(TYPE_FUNC(func->type)->functype); + + SetupFunctionArguments(func, di, &firstStmt); + + stmt18 = curstmt; + CPrep_GetFileOffsetInfo2(&cparser_fileoffset, &sourceoffset, &sourcefilepath); + functionbodyoffset = sourceoffset; + firstStmt.sourceoffset = sourceoffset; + functionbodypath = sourcefilepath; + firstStmt.sourcefilepath = sourcefilepath; + + if (di->x45) + CFunc_AdjustOldStyleArgs(); + + if (di->x1C) + CScope_MergeNameSpace(cscope_current, di->x1C); + + if (tk == TK_TRY) { + tk = lex(); + has_try = 1; + } else { + has_try = 0; + } + + if (CClass_IsConstructor(func)) { + CError_ASSERT(3445, cscope_currentclass); + CFunc_ParseCtorInitializer(); + CFunc_CheckCtorInitializer(cscope_currentclass, ctor_chain); + } + + CPrep_TokenStreamFlush(); + + if (!(func->qual & Q_ASM)) { + if (tk == '{') { + if (!has_try) + tk = lex(); + } else { + CError_ErrorSkip(CErrorStr135); + has_try = 0; + } + + if (func->name) { + nameobj_func = CFunc_DeclareFuncName(func->name->name, GetHashNameNode("__func__")); + nameobj_FUNCTION = CFunc_DeclareFuncName(func->name->name, GetHashNameNode("__FUNCTION__")); + prettyname = CError_GetObjectName(func); + nameobj_pretty = CFunc_DeclareFuncName(prettyname, GetHashNameNode("__PRETTY_FUNCTION__")); + } + + if (!copts.cplusplus) + CFunc_ParseLocalDeclarationList(0, 0, 0, 0); + + thing.switchinfo = NULL; + thing.loopContinue = NULL; + thing.loopBreak = NULL; + thing.thetype = TYPE_FUNC(func->type)->functype; + thing.qual = TYPE_FUNC(func->type)->qual; + + if (has_try) { + CExcept_ScanTryBlock(&thing, CClass_IsConstructor(func) || CClass_IsDestructor(func)); + if (tk != 0) + CPrep_UnLex(); + tk = '}'; + } else { + while (tk != '}') + statement(&thing); + } + + stmt16 = curstmt; + + if (stmt16->type != ST_RETURN && stmt16->type != ST_GOTO) { + CPrep_GetFileOffsetInfo2(&cparser_fileoffset, &sourceoffset, &sourcefilepath); + CFunc_AppendStatement(ST_RETURN); + + curstmt->dobjstack = NULL; + curstmt->expr = NULL; + + if ( + (copts.cplusplus || copts.c9x) && + !strcmp(func->name->name, "main") && + TYPE_FUNC(func->type)->functype == TYPE(&stsignedint) + ) + curstmt->expr = intconstnode(TYPE(&stsignedint), 0); + + if ( + stmt16->type == ST_EXPRESSION && + stmt16->expr->type == EFUNCCALL && + stmt16->expr->rtype == &stvoid && + (stmt16->expr->flags & ENODE_FLAG_VOLATILE) + ) + curstmt->flags = curstmt->flags | StmtFlag_8; + } + + CheckCLabels(); + + if (nameobj_func && (nameobj_func->flags & OBJECT_USED)) + CInit_DeclareData(nameobj_func->u.alias.object, func->name->name, NULL, strlen(func->name->name) + 1); + if (nameobj_FUNCTION && (nameobj_FUNCTION->flags & OBJECT_USED)) + CInit_DeclareData(nameobj_FUNCTION->u.alias.object, func->name->name, NULL, strlen(func->name->name) + 1); + if (nameobj_pretty && (nameobj_pretty->flags & OBJECT_USED)) + CInit_DeclareData(nameobj_pretty->u.alias.object, prettyname, NULL, strlen(prettyname) + 1); + + if (!fatalerrors) { + if (CClass_IsConstructor(func)) + CABI_TransConstructor(func, stmt18, cscope_currentclass, NULL, has_try); + if (CClass_IsDestructor(func)) + CABI_TransDestructor(func, func, &firstStmt, cscope_currentclass, 0); + + CFunc_DestructorCleanup(&firstStmt); + CFunc_CodeCleanup(&firstStmt); + symdeclend = CPrep_GetFileOffsetInfo(&cparser_fileoffset); + CFunc_Gen(&firstStmt, func, di->x45); + } + } else { + if (tk == '{') { + in_assembler = 1; + tk = lex(); + in_assembler = 0; + } else { + CError_ErrorSkip(CErrorStr135); + } + + CFunc_ParseLocalDeclarationList(1, 0, 0, 0); + Assembler(func); + } + + if (tk != '}') + CError_Error(CErrorStr130); + + CScope_RestoreScope(&scope); +} + +void InitExpr_Register(ENode *expr, Object *object) { + InitExpr *initexpr; + InitExpr *scan; + + if ( + cparamblkptr->precompile == 1 && + object->sclass != TK_STATIC && + !(object->qual & (Q_20000 | Q_WEAK)) + ) + { + CError_Error(CErrorStr180); + return; + } + + if (copts.suppress_init_code) + return; + + initexpr = galloc(sizeof(InitExpr)); + initexpr->next = NULL; + initexpr->object = object; + initexpr->expr = CInline_CopyExpression(expr, CopyMode1); + + if (init_expressions) { + scan = init_expressions; + while (scan->next) + scan = scan->next; + scan->next = initexpr; + } else { + init_expressions = initexpr; + } +} + +void CFunc_GenerateDummyFunction(Object *func) { + NameSpace *nspace; + Boolean saveDebugInfo; + Statement firstStmt; + + if (!anyerrors) { + nspace = CFunc_FuncGenSetup(&firstStmt, NULL); + + saveDebugInfo = copts.filesyminfo; + copts.filesyminfo = 0; + + CFunc_CodeCleanup(&firstStmt); + CFunc_Gen(&firstStmt, func, 0); + + cscope_current = nspace->parent; + copts.filesyminfo = saveDebugInfo; + } +} + +void CFunc_GenerateSingleExprFunc(Object *func, ENode *expr) { + NameSpace *nspace; + Boolean saveDebugInfo; + Statement firstStmt; + Statement *stmt; + + if (cparamblkptr->precompile == 1) { + CError_Error(CErrorStr180); + return; + } + + if (!anyerrors) { + nspace = CFunc_FuncGenSetup(&firstStmt, func); + + saveDebugInfo = copts.filesyminfo; + copts.filesyminfo = 0; + + stmt = CFunc_AppendStatement(ST_EXPRESSION); + stmt->expr = expr; + + CFunc_CodeCleanup(&firstStmt); + CInline_GenFunc(&firstStmt, func, 0); + + cscope_current = nspace->parent; + copts.filesyminfo = saveDebugInfo; + } +} + +void CFunc_GenerateDummyCtorFunc(Object *func, Object *real_ctor) { + ENode *expr; + NameSpace *nspace; + FuncArg *arg1; + FuncArg *arg0; + ENodeList *list; + Boolean saveDebugInfo; + Statement firstStmt; + Statement *stmt; + + if (cparamblkptr->precompile == 1) { + CError_Error(CErrorStr180); + return; + } + + if (!anyerrors) { + cscope_currentfunc = func; + + nspace = CFunc_FuncGenSetup(&firstStmt, func); + + saveDebugInfo = copts.filesyminfo; + copts.filesyminfo = 0; + + CFunc_SetupNewFuncArgs(func, TYPE_FUNC(func->type)->args); + + expr = CExpr_NewENode(EFUNCCALL); + expr->type = EFUNCCALL; + expr->cost = 200; + expr->rtype = TYPE(&void_ptr); + expr->data.funccall.funcref = CExpr_MakeObjRefNode(real_ctor, 0); + expr->data.funccall.functype = TYPE_FUNC(func->type); + + CError_ASSERT(3716, IS_TYPE_FUNC(real_ctor->type)); + CError_ASSERT(3717, TYPE_FUNC(real_ctor->type)->flags & FUNC_METHOD); + CError_ASSERT(3718, arg0 = TYPE_FUNC(real_ctor->type)->args); + CError_ASSERT(3720, arg1 = arg0->next); + CError_ASSERT(3721, arguments); + + list = lalloc(sizeof(ENodeList)); + expr->data.funccall.args = list; + list->node = create_objectnode(arguments->object); + + if (TYPE_METHOD(real_ctor->type)->theclass->flags & CLASS_HAS_VBASES) { + CError_ASSERT(3727, arg1 = arg1->next); + CError_ASSERT(3728, arguments->next); + list->next = lalloc(sizeof(ENodeList)); + list = list->next; + list->node = create_objectnode(arguments->next->object); + } + + while (arg1) { + CError_ASSERT(3737, arg1->dexpr); + list->next = lalloc(sizeof(ENodeList)); + list = list->next; + list->node = CExpr_GetDefaultArgument(expr->data.funccall.funcref, arg1); + arg1 = arg1->next; + } + + list->next = NULL; + + stmt = CFunc_AppendStatement(ST_RETURN); + stmt->expr = expr; + + CFunc_CodeCleanup(&firstStmt); + CInline_GenFunc(&firstStmt, func, 0); + + cscope_current = nspace->parent; + cscope_currentfunc = NULL; + copts.filesyminfo = saveDebugInfo; + } +} |