mirror of https://git.wuffs.org/MWCC
3225 lines
94 KiB
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;
|
|
}
|
|
}
|