MWCC/compiler_and_linker/unsorted/CFunc.c

3225 lines
94 KiB
C

#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;
}
}