mirror of https://git.wuffs.org/MWCC
3481 lines
111 KiB
C
3481 lines
111 KiB
C
#include "compiler/CParser.h"
|
|
#include "compiler/CABI.h"
|
|
#include "compiler/CClass.h"
|
|
#include "compiler/CDecl.h"
|
|
#include "compiler/CError.h"
|
|
#include "compiler/CExpr.h"
|
|
#include "compiler/CFunc.h"
|
|
#include "compiler/CInit.h"
|
|
#include "compiler/CInline.h"
|
|
#include "compiler/CInt64.h"
|
|
#include "compiler/CIRTransform.h"
|
|
#include "compiler/CMachine.h"
|
|
#include "compiler/CMangler.h"
|
|
#include "compiler/CObjC.h"
|
|
#include "compiler/CPrep.h"
|
|
#include "compiler/CPrepTokenizer.h"
|
|
#include "compiler/CScope.h"
|
|
#include "compiler/CSOM.h"
|
|
#include "compiler/CTemplateNew.h"
|
|
#include "compiler/CTemplateTools.h"
|
|
#include "compiler/CodeGen.h"
|
|
#include "compiler/CompilerTools.h"
|
|
#include "compiler/IrOptimizer.h"
|
|
#include "compiler/IroPointerAnalysis.h"
|
|
#include "compiler/ObjGenMachO.h"
|
|
#include "compiler/objects.h"
|
|
#include "compiler/scopes.h"
|
|
#include "compiler/templates.h"
|
|
#include "cos.h"
|
|
|
|
FileOffsetInfo cparser_fileoffset;
|
|
TStreamElement symdecltoken;
|
|
ParserTryBlock *trychain;
|
|
Boolean inassembler;
|
|
Boolean dont_set_references;
|
|
TypeStruct ptmstruct;
|
|
TypeStruct catchinfostruct;
|
|
Boolean in_assembler;
|
|
Boolean illegalimplicitconversion;
|
|
Boolean in_func_arglist;
|
|
NameSpaceName *newp_fobj;
|
|
NameSpaceName *newa_fobj;
|
|
NameSpaceName *delp_fobj;
|
|
NameSpaceName *dela_fobj;
|
|
Object *newh_func;
|
|
Object *delh_func;
|
|
Object *copy_func;
|
|
Object *clear_func;
|
|
Object *Rgtid_func;
|
|
Object *Rdync_func;
|
|
Object *rt_ptmf_cast;
|
|
Object *rt_ptmf_cmpr;
|
|
Object *rt_ptmf_test;
|
|
Object *rt_ptmf_call;
|
|
Object *rt_ptmf_scall;
|
|
Object *rt_ptmf_call4;
|
|
Object *rt_ptmf_scall4;
|
|
Object *rt_ptmf_null;
|
|
Object *rt_som_new;
|
|
Object *rt_som_newcheck;
|
|
Object *rt_som_check;
|
|
Object *rt_som_glue1;
|
|
Object *rt_som_glue2;
|
|
Object *rt_som_glue3;
|
|
Object *carr_func;
|
|
Object *cnar_func;
|
|
Object *darr_func;
|
|
Object *dnar_func;
|
|
Object *dnar3_func;
|
|
Object *Xgreg_func;
|
|
Object *Xthrw_func;
|
|
Object *Xicth_func;
|
|
Object *Xecth_func;
|
|
Object *Xunex_func;
|
|
COpts copts;
|
|
GList name_mangle_list;
|
|
HashNameNode *no_name_node;
|
|
HashNameNode *temp_argument_name;
|
|
HashNameNode *this_name_node;
|
|
HashNameNode *self_name_node;
|
|
HashNameNode *vptr_name_node;
|
|
CallbackAction *callbackactions;
|
|
Boolean fatalerrors;
|
|
Boolean anyerrors;
|
|
jmp_buf errorreturn;
|
|
static HashNameNode *uniquenamespacename;
|
|
static SInt32 uniqueid;
|
|
|
|
struct ClassAction {
|
|
struct ClassAction *next;
|
|
TypeClass *tclass;
|
|
};
|
|
static struct ClassAction *cparser_classactions;
|
|
|
|
struct ParentCleanup {
|
|
struct ParentCleanup *next;
|
|
TypeClass *tclass;
|
|
};
|
|
static struct ParentCleanup *cparser_parentcleanup;
|
|
|
|
struct SFuncList {
|
|
struct SFuncList *next;
|
|
Object *func;
|
|
Object *obj;
|
|
ENode *expr;
|
|
};
|
|
static struct SFuncList *cparser_sfunclist;
|
|
|
|
char string[256];
|
|
SInt32 compilererrornum;
|
|
SInt32 compilererrfile;
|
|
SInt32 compilererrline;
|
|
|
|
Type sttemplexpr = {TYPETEMPLDEPEXPR, 0};
|
|
Type stillegal = {TYPEILLEGAL, 1};
|
|
Type stvoid = {TYPEVOID, 0};
|
|
TypePointer void_ptr = {TYPEPOINTER, 0, &stvoid, 0};
|
|
TypeFunc rt_func = {TYPEFUNC, 0, NULL, NULL, &stvoid, 0, 0};
|
|
|
|
// forward declarations
|
|
static void CParser_ParseDeclaration(DeclInfo *di);
|
|
|
|
Object *CParser_NewRTFunc(Type *rettype, HashNameNode *name, Boolean flag, int argcount, ...) {
|
|
Object *obj;
|
|
FuncArg *args;
|
|
FuncArg *arg;
|
|
TypeFunc *tfunc;
|
|
va_list va;
|
|
|
|
args = NULL;
|
|
if (argcount) {
|
|
va_start(va, argcount);
|
|
while (--argcount >= 0) {
|
|
if (args) {
|
|
arg->next = CParser_NewFuncArg();
|
|
arg = arg->next;
|
|
} else {
|
|
arg = CParser_NewFuncArg();
|
|
args = arg;
|
|
}
|
|
arg->type = va_arg(va, Type *);
|
|
}
|
|
va_end(va);
|
|
}
|
|
|
|
obj = CParser_NewFunctionObject(NULL);
|
|
|
|
tfunc = galloc(sizeof(TypeFunc));
|
|
memclrw(tfunc, sizeof(TypeFunc));
|
|
tfunc->type = TYPEFUNC;
|
|
tfunc->functype = rettype;
|
|
tfunc->args = args;
|
|
CDecl_SetFuncFlags(tfunc, 0);
|
|
|
|
obj->name = name;
|
|
obj->type = TYPE(tfunc);
|
|
if (flag == 1)
|
|
obj->qual = Q_80000;
|
|
|
|
return obj;
|
|
}
|
|
|
|
Boolean CParser_IsPublicRuntimeObject(Object *obj) {
|
|
if (newp_fobj->first.object == OBJ_BASE(obj) && !newp_fobj->first.next)
|
|
return 1;
|
|
if (newa_fobj->first.object == OBJ_BASE(obj) && !newa_fobj->first.next)
|
|
return 1;
|
|
if (delp_fobj->first.object == OBJ_BASE(obj) && !delp_fobj->first.next)
|
|
return 1;
|
|
if (dela_fobj->first.object == OBJ_BASE(obj) && !dela_fobj->first.next)
|
|
return 1;
|
|
return CodeGen_IsPublicRuntimeObject(obj);
|
|
}
|
|
|
|
Object *CParser_FindPublicRuntimeObject(HashNameNode *name) {
|
|
NameSpaceObjectList *list = CScope_FindName(cscope_root, name);
|
|
if (list && list->object->otype == OT_OBJECT && (!list->next || list->next->object->otype == OT_TYPETAG))
|
|
return OBJECT(list->object);
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
Boolean CParser_ReInitRuntimeObjects(Boolean is_precompiler) {
|
|
if (!(newp_fobj = CScope_FindNameSpaceName(cscope_root, CMangler_OperatorName(TK_NEW))))
|
|
return 0;
|
|
if (!(newa_fobj = CScope_FindNameSpaceName(cscope_root, CMangler_OperatorName(TK_NEW_ARRAY))))
|
|
return 0;
|
|
if (!(delp_fobj = CScope_FindNameSpaceName(cscope_root, CMangler_OperatorName(TK_DELETE))))
|
|
return 0;
|
|
if (!(dela_fobj = CScope_FindNameSpaceName(cscope_root, CMangler_OperatorName(TK_DELETE_ARRAY))))
|
|
return 0;
|
|
|
|
newh_func->name = GetHashNameNodeExport("__new_hdl");
|
|
delh_func->name = GetHashNameNodeExport("__del_hdl");
|
|
copy_func->name = GetHashNameNodeExport("__copy");
|
|
clear_func->name = GetHashNameNodeExport("__clear");
|
|
Rgtid_func->name = GetHashNameNodeExport("__get_typeid");
|
|
Rdync_func->name = GetHashNameNodeExport("__dynamic_cast");
|
|
rt_ptmf_cast->name = GetHashNameNodeExport("__ptmf_cast");
|
|
rt_ptmf_cmpr->name = GetHashNameNodeExport("__ptmf_cmpr");
|
|
rt_ptmf_test->name = GetHashNameNodeExport("__ptmf_test");
|
|
rt_ptmf_call->name = GetHashNameNodeExport("__ptmf_call");
|
|
rt_ptmf_scall->name = GetHashNameNodeExport("__ptmf_scall");
|
|
rt_ptmf_call4->name = GetHashNameNodeExport("__ptmf_call4");
|
|
rt_ptmf_scall4->name = GetHashNameNodeExport("__ptmf_scall4");
|
|
rt_ptmf_null->name = GetHashNameNodeExport("__ptmf_null");
|
|
rt_som_new->name = GetHashNameNodeExport("__som_new");
|
|
rt_som_newcheck->name = GetHashNameNodeExport("__som_check_new");
|
|
rt_som_check->name = GetHashNameNodeExport("__som_check_ev");
|
|
rt_som_glue1->name = GetHashNameNodeExport("_som_ptrgl4");
|
|
rt_som_glue2->name = GetHashNameNodeExport("_som_ptrgl5");
|
|
rt_som_glue3->name = GetHashNameNodeExport("_som_ptrgl_");
|
|
carr_func->name = GetHashNameNodeExport("__construct_array");
|
|
cnar_func->name = GetHashNameNodeExport("__construct_new_array");
|
|
darr_func->name = GetHashNameNodeExport("__destroy_arr");
|
|
dnar_func->name = GetHashNameNodeExport("__destroy_new_array");
|
|
dnar3_func->name = GetHashNameNodeExport("__destroy_new_array3");
|
|
Xgreg_func->name = GetHashNameNodeExport("__register_global_object");
|
|
Xthrw_func->name = GetHashNameNodeExport("__throw");
|
|
Xicth_func->name = GetHashNameNodeExport("__init__catch");
|
|
Xecth_func->name = GetHashNameNodeExport("__end__catch");
|
|
Xunex_func->name = GetHashNameNodeExport("__unexpected");
|
|
|
|
CMangler_Setup();
|
|
|
|
no_name_node = GetHashNameNodeExport("@no_name@");
|
|
temp_argument_name = GetHashNameNodeExport("@temp_ptr@");
|
|
this_name_node = GetHashNameNodeExport("this");
|
|
self_name_node = GetHashNameNodeExport("self");
|
|
vptr_name_node = GetHashNameNodeExport("__vptr$");
|
|
|
|
CSOM_Setup(is_precompiler);
|
|
return CodeGen_ReInitRuntimeObjects(is_precompiler);
|
|
}
|
|
|
|
static void CParser_SetupRuntimeObjects(void) {
|
|
ExceptSpecList *exspecs;
|
|
Type *sizet;
|
|
Object *func;
|
|
|
|
exspecs = galloc(sizeof(ExceptSpecList));
|
|
memclrw(exspecs, sizeof(ExceptSpecList));
|
|
|
|
sizet = CABI_GetSizeTType();
|
|
|
|
func = CParser_NewRTFunc(
|
|
TYPE(&void_ptr), CMangler_OperatorName(TK_NEW), 1,
|
|
1, sizet);
|
|
CScope_AddGlobalObject(func);
|
|
|
|
func = CParser_NewRTFunc(
|
|
TYPE(&void_ptr), CMangler_OperatorName(TK_NEW_ARRAY), 1,
|
|
1, sizet);
|
|
CScope_AddGlobalObject(func);
|
|
|
|
func = CParser_NewRTFunc(
|
|
TYPE(&stvoid), CMangler_OperatorName(TK_DELETE), 1,
|
|
1, &void_ptr);
|
|
CError_ASSERT(379, IS_TYPE_FUNC(func->type));
|
|
TYPE_FUNC(func->type)->exspecs = exspecs;
|
|
CScope_AddGlobalObject(func);
|
|
|
|
func = CParser_NewRTFunc(
|
|
TYPE(&stvoid), CMangler_OperatorName(TK_DELETE_ARRAY), 1,
|
|
1, &void_ptr);
|
|
CError_ASSERT(387, IS_TYPE_FUNC(func->type));
|
|
TYPE_FUNC(func->type)->exspecs = exspecs;
|
|
CScope_AddGlobalObject(func);
|
|
|
|
newh_func = CParser_NewRTFunc(
|
|
TYPE(&void_ptr), NULL, 0,
|
|
1, sizet);
|
|
delh_func = CParser_NewRTFunc(
|
|
TYPE(&stvoid), NULL, 0,
|
|
1, &void_ptr);
|
|
|
|
Rgtid_func = CParser_NewRTFunc(
|
|
TYPE(&void_ptr), NULL, 0,
|
|
2, &void_ptr, &stsignedlong);
|
|
Rdync_func = CParser_NewRTFunc(
|
|
TYPE(&void_ptr), NULL, 0,
|
|
5, &void_ptr, &stsignedlong, &void_ptr, &void_ptr, &stsignedshort);
|
|
|
|
copy_func = CParser_NewRTFunc(
|
|
TYPE(&void_ptr), NULL, 2,
|
|
3, &void_ptr, &void_ptr, sizet);
|
|
clear_func = CParser_NewRTFunc(
|
|
TYPE(&void_ptr), NULL, 2,
|
|
2, &void_ptr, sizet);
|
|
|
|
rt_ptmf_cast = CParser_NewRTFunc(
|
|
TYPE(&void_ptr), NULL, 2,
|
|
3, &stsignedlong, &void_ptr, &void_ptr);
|
|
rt_ptmf_cmpr = CParser_NewRTFunc(
|
|
TYPE(&stsignedlong), NULL, 2,
|
|
2, &void_ptr, &void_ptr);
|
|
rt_ptmf_test = CParser_NewRTFunc(
|
|
TYPE(&stsignedlong), NULL, 2,
|
|
1, &void_ptr);
|
|
|
|
rt_ptmf_call = CParser_NewRTFunc(TYPE(&stvoid), NULL, 2, 0);
|
|
rt_ptmf_scall = CParser_NewRTFunc(TYPE(&stvoid), NULL, 2, 0);
|
|
rt_ptmf_call4 = CParser_NewRTFunc(TYPE(&stvoid), NULL, 2, 0);
|
|
rt_ptmf_scall4 = CParser_NewRTFunc(TYPE(&stvoid), NULL, 2, 0);
|
|
|
|
rt_ptmf_null = CParser_NewGlobalDataObject(NULL);
|
|
rt_ptmf_null->type = &stvoid;
|
|
|
|
rt_som_new = CParser_NewRTFunc(
|
|
TYPE(&void_ptr), NULL, 2,
|
|
3, &void_ptr, &stsignedlong, &stsignedlong);
|
|
rt_som_newcheck = CParser_NewRTFunc(
|
|
TYPE(&stvoid), NULL, 0,
|
|
1, &void_ptr);
|
|
rt_som_check = CParser_NewRTFunc(
|
|
TYPE(&stvoid), NULL, 0,
|
|
1, &void_ptr);
|
|
rt_som_glue1 = CParser_NewRTFunc(TYPE(&stvoid), NULL, 2, 0);
|
|
rt_som_glue2 = CParser_NewRTFunc(TYPE(&stvoid), NULL, 2, 0);
|
|
rt_som_glue3 = CParser_NewRTFunc(TYPE(&stvoid), NULL, 2, 0);
|
|
|
|
carr_func = CParser_NewRTFunc(
|
|
TYPE(&stvoid), NULL, 0,
|
|
5, &void_ptr, &void_ptr, &void_ptr, sizet, sizet);
|
|
cnar_func = CParser_NewRTFunc(
|
|
TYPE(&void_ptr), NULL, 0,
|
|
5, &void_ptr, &void_ptr, &void_ptr, sizet, sizet);
|
|
darr_func = CParser_NewRTFunc(
|
|
TYPE(&stvoid), NULL, 0,
|
|
4, &void_ptr, &void_ptr, sizet, sizet);
|
|
dnar_func = CParser_NewRTFunc(
|
|
TYPE(&stvoid), NULL, 0,
|
|
2, &void_ptr, &void_ptr);
|
|
dnar3_func = CParser_NewRTFunc(
|
|
TYPE(&stvoid), NULL, 0,
|
|
4, &void_ptr, &void_ptr, &void_ptr, &stsignedshort);
|
|
|
|
Xgreg_func = CParser_NewRTFunc(
|
|
TYPE(&void_ptr), NULL, 0,
|
|
3, &void_ptr, &void_ptr, &void_ptr);
|
|
Xthrw_func = CParser_NewRTFunc(
|
|
TYPE(&stvoid), NULL, 0,
|
|
3, &void_ptr, &void_ptr, &void_ptr);
|
|
Xicth_func = CParser_NewRTFunc(
|
|
TYPE(&stvoid), NULL, 0,
|
|
1, &void_ptr);
|
|
Xecth_func = CParser_NewRTFunc(
|
|
TYPE(&stvoid), NULL, 0,
|
|
1, &void_ptr);
|
|
Xunex_func = CParser_NewRTFunc(
|
|
TYPE(&stvoid), NULL, 0,
|
|
1, &void_ptr);
|
|
|
|
CodeGen_SetupRuntimeObjects();
|
|
CError_ASSERT(534, CParser_ReInitRuntimeObjects(0));
|
|
}
|
|
|
|
void CParser_Setup(void) {
|
|
CScope_Setup();
|
|
|
|
name_mangle_list.data = NULL;
|
|
if (InitGList(&name_mangle_list, 256))
|
|
CError_NoMem();
|
|
|
|
void_ptr.size = 4;
|
|
CError_Init();
|
|
CInit_Init();
|
|
CClass_Init();
|
|
CIRTrans_Setup();
|
|
CObjC_Setup();
|
|
CInline_Init();
|
|
|
|
in_assembler = 0;
|
|
in_func_arglist = 0;
|
|
CParser_SetUniqueID(1);
|
|
dont_set_references = 0;
|
|
|
|
copts.side_effects = 1;
|
|
cparser_classactions = NULL;
|
|
name_obj_check = NULL;
|
|
callbackactions = NULL;
|
|
init_expressions = NULL;
|
|
cparser_sfunclist = NULL;
|
|
trychain = NULL;
|
|
cparser_parentcleanup = NULL;
|
|
|
|
memclrw(&cparser_fileoffset, sizeof(FileOffsetInfo));
|
|
|
|
memclrw(&catchinfostruct, sizeof(TypeStruct));
|
|
catchinfostruct.type = TYPESTRUCT;
|
|
catchinfostruct.size = 24;
|
|
catchinfostruct.stype = STRUCT_TYPE_STRUCT;
|
|
catchinfostruct.align = 4;
|
|
|
|
memclrw(&ptmstruct, sizeof(TypeStruct));
|
|
ptmstruct.type = TYPESTRUCT;
|
|
ptmstruct.size = 12;
|
|
ptmstruct.stype = STRUCT_TYPE_STRUCT;
|
|
ptmstruct.align = 4;
|
|
|
|
CMach_Configure();
|
|
CTempl_Setup();
|
|
|
|
uniquenamespacename = NULL;
|
|
disallowgreaterthan = 0;
|
|
|
|
CParser_SetupRuntimeObjects();
|
|
}
|
|
|
|
void CParser_Cleanup(void) {
|
|
CTempl_Cleanup();
|
|
CIRTrans_Cleanup();
|
|
CObjC_Cleanup();
|
|
CScope_Cleanup();
|
|
FreeGList(&name_mangle_list);
|
|
}
|
|
|
|
short GetPrec(short token) {
|
|
switch (token) {
|
|
case '%':
|
|
case '*':
|
|
case '/':
|
|
return 11;
|
|
case '+':
|
|
case '-':
|
|
return 10;
|
|
case TK_SHL:
|
|
case TK_SHR:
|
|
return 9;
|
|
case '<':
|
|
case '>':
|
|
case TK_LESS_EQUAL:
|
|
case TK_GREATER_EQUAL:
|
|
return 8;
|
|
case TK_LOGICAL_EQ:
|
|
case TK_LOGICAL_NE:
|
|
return 7;
|
|
case '&':
|
|
return 6;
|
|
case '^':
|
|
return 5;
|
|
case '|':
|
|
return 4;
|
|
case TK_LOGICAL_AND:
|
|
return 3;
|
|
case TK_LOGICAL_OR:
|
|
return 2;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
Boolean CParser_ParseOperatorName(short *token, Boolean flag1, Boolean flag2) {
|
|
HashNameNode *name;
|
|
|
|
switch ((tk = lex())) {
|
|
case TK_NEW:
|
|
case TK_DELETE:
|
|
if (lookahead() == '[') {
|
|
lex();
|
|
if (lex() != ']')
|
|
CError_Error(CErrorStr125);
|
|
//if (tk == TK_NEW)
|
|
// tk = TK_NEW_ARRAY;
|
|
//else
|
|
// tk = TK_DELETE_ARRAY;
|
|
tk = (tk == TK_NEW) ? TK_NEW_ARRAY : TK_DELETE_ARRAY;
|
|
}
|
|
break;
|
|
case '(':
|
|
if ((tk = lex()) != ')') {
|
|
CError_Error(CErrorStr204);
|
|
return 0;
|
|
}
|
|
tk = '(';
|
|
break;
|
|
case '[':
|
|
if ((tk = lex()) != ']') {
|
|
CError_Error(CErrorStr204);
|
|
return 0;
|
|
}
|
|
tk = '[';
|
|
break;
|
|
}
|
|
|
|
if ((name = CMangler_OperatorName(tk))) {
|
|
if (token)
|
|
*token = tk;
|
|
tk = lex();
|
|
tkidentifier = name;
|
|
return 1;
|
|
}
|
|
|
|
if (flag1) {
|
|
if (flag2) {
|
|
DeclInfo declinfo;
|
|
memclrw(&declinfo, sizeof(DeclInfo));
|
|
conversion_type_name(&declinfo);
|
|
tkidentifier = CMangler_ConversionFuncName(declinfo.thetype, declinfo.qual);
|
|
}
|
|
if (token)
|
|
*token = 0;
|
|
return 1;
|
|
} else {
|
|
CError_Error(CErrorStr204);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
SInt32 CParser_GetUniqueID(void) {
|
|
return uniqueid++;
|
|
}
|
|
|
|
void CParser_PrintUniqueID(char *buf) {
|
|
SInt32 id;
|
|
char mybuf[16];
|
|
char *ptr;
|
|
|
|
ptr = mybuf;
|
|
id = CParser_GetUniqueID();
|
|
while (id) {
|
|
*ptr = '0' + (id - ((id / 10) * 10));
|
|
id = id / 10;
|
|
ptr++;
|
|
}
|
|
|
|
while (ptr > mybuf)
|
|
*(buf++) = *(--ptr);
|
|
|
|
*buf = 0;
|
|
}
|
|
|
|
void CParser_SetUniqueID(SInt32 id) {
|
|
uniqueid = id;
|
|
}
|
|
|
|
HashNameNode *CParser_GetUniqueName(void) {
|
|
char buf[20];
|
|
buf[0] = '@';
|
|
CParser_PrintUniqueID(buf + 1);
|
|
return GetHashNameNodeExport(buf);
|
|
}
|
|
|
|
HashNameNode *CParser_NameConcat(char *a, char *b) {
|
|
char mybuf[256];
|
|
char *buf;
|
|
char *dst;
|
|
int len;
|
|
|
|
len = strlen(a) + strlen(b);
|
|
if (len > (sizeof(mybuf) - 1)) {
|
|
buf = lalloc(len + 1);
|
|
dst = buf;
|
|
} else {
|
|
buf = mybuf;
|
|
dst = buf;
|
|
}
|
|
|
|
while (*a)
|
|
*(dst++) = *(a++);
|
|
while (*b)
|
|
*(dst++) = *(b++);
|
|
*dst = 0;
|
|
|
|
return GetHashNameNodeExport(buf);
|
|
}
|
|
|
|
HashNameNode *CParser_AppendUniqueName(char *prefix) {
|
|
char buf[256];
|
|
char *dst;
|
|
int i;
|
|
|
|
dst = buf;
|
|
for (i = 0; *prefix && i < 240; i++) {
|
|
*(dst++) = *(prefix++);
|
|
}
|
|
*(dst++) = '$';
|
|
|
|
CParser_PrintUniqueID(dst);
|
|
return GetHashNameNodeExport(buf);
|
|
}
|
|
|
|
HashNameNode *CParser_AppendUniqueNameFile(char *prefix) {
|
|
Str255 filename;
|
|
char buf[256];
|
|
char *src;
|
|
char *dst;
|
|
char c;
|
|
int i;
|
|
int j;
|
|
int len;
|
|
|
|
dst = buf;
|
|
for (i = 0; *prefix && i < 200; i++) {
|
|
*(dst++) = *(prefix++);
|
|
}
|
|
*(dst++) = '$';
|
|
|
|
CParser_PrintUniqueID(dst);
|
|
|
|
while (*dst) {
|
|
dst++;
|
|
i++;
|
|
}
|
|
|
|
COS_FileGetFSSpecInfo(&cparamblkptr->mainFileSpec, NULL, NULL, filename);
|
|
src = (char *) &filename[1];
|
|
len = filename[0];
|
|
for (j = 0; j < len && i < 255; j++, i++) {
|
|
c = *(src++);
|
|
if (!(c >= 'a' && c <= 'z') && !(c >= 'A' && c <= 'Z') && !(c >= '0' && c <= '9'))
|
|
c = '_';
|
|
*(dst++) = c;
|
|
}
|
|
|
|
dst[0] = 0;
|
|
return GetHashNameNodeExport(buf);
|
|
}
|
|
|
|
static HashNameNode *CParser_GetUnnamedNameSpaceName(void) {
|
|
Str255 filename;
|
|
char buf[256];
|
|
char *src;
|
|
char *dst;
|
|
char c;
|
|
int i;
|
|
int len;
|
|
|
|
if (!uniquenamespacename) {
|
|
strcpy(buf, "@unnamed@");
|
|
dst = buf + strlen(buf);
|
|
|
|
COS_FileGetFSSpecInfo(&cparamblkptr->mainFileSpec, NULL, NULL, filename);
|
|
src = (char *) &filename[1];
|
|
len = filename[0];
|
|
for (i = 0; i < len && dst < &buf[254]; i++) {
|
|
c = *(src++);
|
|
if (!(c >= 'a' && c <= 'z') && !(c >= 'A' && c <= 'Z') && !(c >= '0' && c <= '9'))
|
|
c = '_';
|
|
*(dst++) = c;
|
|
}
|
|
|
|
dst[0] = '@';
|
|
dst[1] = 0;
|
|
uniquenamespacename = GetHashNameNodeExport(buf);
|
|
}
|
|
|
|
return uniquenamespacename;
|
|
}
|
|
|
|
Boolean IsTempName(HashNameNode *name) {
|
|
return !name || (name->name[0] == '@') || (name->name[0] == '$');
|
|
}
|
|
|
|
static void CParser_SetCFMFlags(Object *object, DeclInfo *declinfo) {
|
|
if (declinfo && declinfo->exportflags)
|
|
object->flags |= declinfo->exportflags;
|
|
|
|
if (object->datatype == DDATA) {
|
|
if (copts.export)
|
|
object->flags |= OBJECT_FLAGS_40;
|
|
if (copts.internal)
|
|
object->flags |= OBJECT_FLAGS_10;
|
|
} else if (copts.internal) {
|
|
object->flags |= OBJECT_FLAGS_10;
|
|
} else {
|
|
if (copts.import)
|
|
object->flags |= OBJECT_FLAGS_20;
|
|
if (copts.export)
|
|
object->flags |= OBJECT_FLAGS_40;
|
|
if (copts.lib_export)
|
|
object->flags |= OBJECT_FLAGS_20 | OBJECT_FLAGS_40;
|
|
}
|
|
}
|
|
|
|
void CParser_UpdateObject(Object *object, DeclInfo *declinfo) {
|
|
if (declinfo && declinfo->section)
|
|
object->section = declinfo->section;
|
|
|
|
CParser_SetCFMFlags(object, declinfo);
|
|
CodeGen_UpdateObject(object);
|
|
}
|
|
|
|
Object *CParser_NewObject(DeclInfo *declinfo) {
|
|
Object *object = galloc(sizeof(Object));
|
|
memclrw(object, sizeof(Object));
|
|
CParser_SetCFMFlags(object, declinfo);
|
|
object->otype = OT_OBJECT;
|
|
object->access = ACCESSPUBLIC;
|
|
object->section = SECT_DEFAULT;
|
|
return object;
|
|
}
|
|
|
|
Object *CParser_NewLocalDataObject(DeclInfo *declinfo, Boolean add_to_locals) {
|
|
Object *object = lalloc(sizeof(Object));
|
|
memclrw(object, sizeof(Object));
|
|
object->otype = OT_OBJECT;
|
|
object->access = ACCESSPUBLIC;
|
|
object->datatype = DLOCAL;
|
|
|
|
if (declinfo) {
|
|
object->type = declinfo->thetype;
|
|
object->name = declinfo->name;
|
|
object->qual = declinfo->qual;
|
|
object->sclass = declinfo->storageclass;
|
|
}
|
|
|
|
if (add_to_locals) {
|
|
ObjectList *list = lalloc(sizeof(ObjectList));
|
|
list->object = object;
|
|
list->next = locals;
|
|
locals = list;
|
|
}
|
|
|
|
return object;
|
|
}
|
|
|
|
Object *CParser_NewGlobalDataObject(DeclInfo *declinfo) {
|
|
Object *object = galloc(sizeof(Object));
|
|
memclrw(object, sizeof(Object));
|
|
object->otype = OT_OBJECT;
|
|
object->access = ACCESSPUBLIC;
|
|
object->section = SECT_DEFAULT;
|
|
object->datatype = DDATA;
|
|
object->nspace = cscope_current;
|
|
|
|
if (declinfo) {
|
|
object->type = declinfo->thetype;
|
|
object->name = declinfo->name;
|
|
object->qual = declinfo->qual;
|
|
object->sclass = declinfo->storageclass;
|
|
if (copts.cplusplus && !declinfo->x4E)
|
|
object->qual |= Q_80000;
|
|
}
|
|
|
|
CParser_UpdateObject(object, declinfo);
|
|
return object;
|
|
}
|
|
|
|
Object *CParser_NewCompilerDefDataObject(void) {
|
|
Object *object = galloc(sizeof(Object));
|
|
memclrw(object, sizeof(Object));
|
|
object->otype = OT_OBJECT;
|
|
object->access = ACCESSPUBLIC;
|
|
object->section = SECT_DEFAULT;
|
|
object->datatype = DDATA;
|
|
object->nspace = cscope_root;
|
|
|
|
return object;
|
|
}
|
|
|
|
Object *CParser_NewFunctionObject(DeclInfo *declinfo) {
|
|
Object *object = galloc(sizeof(Object));
|
|
memclrw(object, sizeof(Object));
|
|
object->otype = OT_OBJECT;
|
|
object->access = ACCESSPUBLIC;
|
|
object->section = SECT_DEFAULT;
|
|
object->datatype = DFUNC;
|
|
object->nspace = cscope_current;
|
|
|
|
if (declinfo) {
|
|
object->type = declinfo->thetype;
|
|
object->name = declinfo->name;
|
|
object->qual = declinfo->qual;
|
|
object->sclass = declinfo->storageclass;
|
|
if (copts.cplusplus && !declinfo->x4E)
|
|
object->qual |= Q_80000;
|
|
}
|
|
|
|
CParser_UpdateObject(object, declinfo);
|
|
return object;
|
|
}
|
|
|
|
Object *CParser_NewCompilerDefFunctionObject(void) {
|
|
Object *object = galloc(sizeof(Object));
|
|
memclrw(object, sizeof(Object));
|
|
object->otype = OT_OBJECT;
|
|
object->access = ACCESSPUBLIC;
|
|
object->section = SECT_DEFAULT;
|
|
object->datatype = DFUNC;
|
|
object->nspace = cscope_root;
|
|
return object;
|
|
}
|
|
|
|
Object *CParser_NewAliasObject(Object *object, SInt32 offset) {
|
|
Object *alias = galloc(sizeof(Object));
|
|
*alias = *object;
|
|
alias->datatype = DALIAS;
|
|
alias->u.alias.object = object;
|
|
alias->u.alias.member = NULL;
|
|
alias->u.alias.offset = offset;
|
|
CScope_AddObject(cscope_current, alias->name, OBJ_BASE(alias));
|
|
return alias;
|
|
}
|
|
|
|
FuncArg *CParser_NewFuncArg(void) {
|
|
FuncArg *arg = galloc(sizeof(FuncArg));
|
|
memclrw(arg, sizeof(FuncArg));
|
|
return arg;
|
|
}
|
|
|
|
Type *atomtype(void) {
|
|
switch (tksize) {
|
|
default:
|
|
CError_FATAL(1145);
|
|
case ATOM_VOID: return &stvoid;
|
|
case ATOM_CHAR: return TYPE(&stchar);
|
|
case ATOM_WCHAR: return TYPE(&stwchar);
|
|
case ATOM_UCHAR: return TYPE(&stunsignedchar);
|
|
case ATOM_SHORT: return TYPE(&stsignedshort);
|
|
case ATOM_USHORT: return TYPE(&stunsignedshort);
|
|
case ATOM_INT: return TYPE(&stsignedint);
|
|
case ATOM_UINT: return TYPE(&stunsignedint);
|
|
case ATOM_LONG: return TYPE(&stsignedlong);
|
|
case ATOM_ULONG: return TYPE(&stunsignedlong);
|
|
case ATOM_LONGLONG: return TYPE(&stsignedlonglong);
|
|
case ATOM_ULONGLONG: return TYPE(&stunsignedlonglong);
|
|
case ATOM_FLOAT: return TYPE(&stfloat);
|
|
case ATOM_SHORTDOUBLE: return TYPE(&stshortdouble);
|
|
case ATOM_DOUBLE: return TYPE(&stdouble);
|
|
case ATOM_LONGDOUBLE: return TYPE(&stlongdouble);
|
|
}
|
|
}
|
|
|
|
Object *CParser_FindDeallocationObject(Type *type, FuncArg *args, Boolean flag1, Boolean flag2, Boolean *outflag) {
|
|
NameSpaceObjectList *list;
|
|
NameSpaceObjectList *scan;
|
|
NameSpaceObjectList mylist;
|
|
CScopeParseResult pr;
|
|
Boolean first_time;
|
|
Boolean retry_flag;
|
|
Object *obj;
|
|
Type *sizet;
|
|
|
|
list = NULL;
|
|
*outflag = 0;
|
|
if (IS_TYPE_CLASS(type) && !flag2) {
|
|
HashNameNode *name;
|
|
name = (flag1 && copts.array_new_delete) ? dela_fobj->name : delp_fobj->name;
|
|
if (CScope_FindClassMemberObject(TYPE_CLASS(type), &pr, name)) {
|
|
if (pr.obj_10) {
|
|
mylist.next = NULL;
|
|
mylist.object = pr.obj_10;
|
|
list = &mylist;
|
|
} else {
|
|
CError_ASSERT(1202, pr.nsol_14);
|
|
list = pr.nsol_14;
|
|
}
|
|
} else if (TYPE_CLASS(type)->flags & CLASS_FLAGS_1) {
|
|
CError_ASSERT(1210, !args && !flag1);
|
|
return delh_func;
|
|
}
|
|
}
|
|
|
|
first_time = 1;
|
|
retry_flag = flag1;
|
|
while (1) {
|
|
if (!args) {
|
|
for (scan = list; scan; scan = scan->next) {
|
|
obj = OBJECT(scan->object);
|
|
if (
|
|
obj->otype == OT_OBJECT &&
|
|
IS_TYPE_FUNC(obj->type) &&
|
|
TYPE_FUNC(obj->type)->args &&
|
|
!TYPE_FUNC(obj->type)->args->next &&
|
|
is_typesame(TYPE_FUNC(obj->type)->args->type, TYPE(&void_ptr))
|
|
)
|
|
return obj;
|
|
}
|
|
|
|
CError_ASSERT(1231, first_time);
|
|
|
|
sizet = CABI_GetSizeTType();
|
|
for (scan = list; scan; scan = scan->next) {
|
|
obj = OBJECT(scan->object);
|
|
if (
|
|
obj->otype == OT_OBJECT &&
|
|
IS_TYPE_FUNC(obj->type) &&
|
|
TYPE_FUNC(obj->type)->args &&
|
|
TYPE_FUNC(obj->type)->args->next &&
|
|
!TYPE_FUNC(obj->type)->args->next->next &&
|
|
is_typesame(TYPE_FUNC(obj->type)->args->type, TYPE(&void_ptr)) &&
|
|
TYPE_FUNC(obj->type)->args->next->type == sizet
|
|
) {
|
|
*outflag = 1;
|
|
return obj;
|
|
}
|
|
}
|
|
} else {
|
|
for (scan = list; scan; scan = scan->next) {
|
|
obj = OBJECT(scan->object);
|
|
if (
|
|
obj->otype == OT_OBJECT &&
|
|
IS_TYPE_FUNC(obj->type) &&
|
|
TYPE_FUNC(obj->type)->args &&
|
|
TYPE_FUNC(obj->type)->args->next &&
|
|
is_arglistsame(TYPE_FUNC(obj->type)->args->next, args)
|
|
) {
|
|
*outflag = 1;
|
|
return obj;
|
|
}
|
|
}
|
|
|
|
if (!first_time)
|
|
return NULL;
|
|
}
|
|
|
|
if (list)
|
|
CError_Warning(CErrorStr375, type, 0);
|
|
|
|
list = (retry_flag && copts.array_new_delete) ? &dela_fobj->first : &delp_fobj->first;
|
|
first_time = 0;
|
|
}
|
|
}
|
|
|
|
static Boolean oldstylecompatible(FuncArg *arg) {
|
|
if (copts.ignore_oldstyle)
|
|
return 1;
|
|
|
|
while (arg) {
|
|
if (arg == &elipsis)
|
|
return 0;
|
|
switch (arg->type->type) {
|
|
case TYPEINT:
|
|
if (TYPE_INTEGRAL(arg->type)->integral < IT_INT)
|
|
return 0;
|
|
break;
|
|
case TYPEFLOAT:
|
|
if (TYPE_INTEGRAL(arg->type)->integral < IT_DOUBLE)
|
|
return 0;
|
|
break;
|
|
}
|
|
arg = arg->next;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static Boolean is_arglistequal(FuncArg *a, FuncArg *b) {
|
|
if (a == &oldstyle) {
|
|
if (b == &oldstyle)
|
|
return 1;
|
|
else
|
|
return oldstylecompatible(b);
|
|
} else {
|
|
if (b == &oldstyle)
|
|
return oldstylecompatible(a);
|
|
}
|
|
|
|
while (1) {
|
|
if (a == &elipsis || b == &elipsis)
|
|
return 1;
|
|
|
|
if (!a)
|
|
return !b;
|
|
if (!b)
|
|
return 0;
|
|
|
|
if (copts.mpwc_relax && !copts.cplusplus) {
|
|
if (!is_typeequal(a->type, b->type))
|
|
return 0;
|
|
} else {
|
|
if (!is_typesame(a->type, b->type))
|
|
return 0;
|
|
}
|
|
|
|
if (a->type->type == TYPEPOINTER && a->qual != b->qual)
|
|
return 0;
|
|
|
|
a = a->next;
|
|
b = b->next;
|
|
}
|
|
}
|
|
|
|
short is_memberpointerequal(Type *a, Type *b) {
|
|
FuncArg *arg_a;
|
|
FuncArg *arg_b;
|
|
|
|
if (a->type != b->type)
|
|
return 0;
|
|
if (!IS_TYPE_FUNC(a))
|
|
return is_typeequal(a, b);
|
|
|
|
if (!is_typesame(TYPE_FUNC(a)->functype, TYPE_FUNC(b)->functype))
|
|
return 0;
|
|
|
|
if ((TYPE_FUNC(a)->flags & (FUNC_FLAGS_F0000000 | FUNC_FLAGS_PASCAL)) != (TYPE_FUNC(b)->flags & (FUNC_FLAGS_F0000000 | FUNC_FLAGS_PASCAL)))
|
|
return 0;
|
|
|
|
CError_ASSERT(1345, arg_a = TYPE_FUNC(a)->args);
|
|
CError_ASSERT(1346, arg_b = TYPE_FUNC(b)->args);
|
|
|
|
if (TYPE_FUNC(a)->flags & FUNC_FLAGS_80)
|
|
CError_ASSERT(1351, arg_a = arg_a->next);
|
|
|
|
if (TYPE_FUNC(b)->flags & FUNC_FLAGS_80)
|
|
CError_ASSERT(1355, arg_b = arg_b->next);
|
|
|
|
if (arg_a->qual != arg_b->qual)
|
|
return 0;
|
|
|
|
return is_arglistsame(arg_a->next, arg_b->next);
|
|
}
|
|
|
|
short is_typeequal(Type *a, Type *b) {
|
|
restart:
|
|
if (a->type != b->type)
|
|
return 0;
|
|
switch (a->type) {
|
|
case TYPEVOID:
|
|
return 1;
|
|
case TYPEINT:
|
|
case TYPEFLOAT:
|
|
case TYPEENUM:
|
|
case TYPECLASS:
|
|
return a == b;
|
|
case TYPESTRUCT:
|
|
return a == b;
|
|
case TYPEPOINTER:
|
|
if (TYPE_POINTER(a)->target == &stvoid || TYPE_POINTER(b)->target == &stvoid)
|
|
return 1;
|
|
a = TYPE_POINTER(a)->target;
|
|
b = TYPE_POINTER(b)->target;
|
|
if (copts.mpwc_relax && !copts.cplusplus)
|
|
return 1;
|
|
goto restart;
|
|
case TYPEMEMBERPOINTER:
|
|
if (TYPE_MEMBER_POINTER(a)->ty2 != TYPE_MEMBER_POINTER(b)->ty2)
|
|
return 0;
|
|
return is_memberpointerequal(TYPE_MEMBER_POINTER(a)->ty1, TYPE_MEMBER_POINTER(b)->ty1);
|
|
case TYPEARRAY:
|
|
if (a->size && b->size && a->size != b->size)
|
|
return 0;
|
|
a = TYPE_POINTER(a)->target;
|
|
b = TYPE_POINTER(b)->target;
|
|
goto restart;
|
|
case TYPEFUNC:
|
|
if (copts.cplusplus || !copts.cpp_extensions) {
|
|
if (copts.mpwc_relax && !copts.cplusplus) {
|
|
if (!is_typeequal(TYPE_FUNC(a)->functype, TYPE_FUNC(b)->functype))
|
|
return 0;
|
|
} else {
|
|
if (!is_typesame(TYPE_FUNC(a)->functype, TYPE_FUNC(b)->functype))
|
|
return 0;
|
|
}
|
|
if ((TYPE_FUNC(a)->flags & (FUNC_FLAGS_F0000000 | FUNC_FLAGS_PASCAL)) != (TYPE_FUNC(b)->flags & (FUNC_FLAGS_F0000000 | FUNC_FLAGS_PASCAL)))
|
|
return 0;
|
|
}
|
|
return is_arglistequal(TYPE_FUNC(a)->args, TYPE_FUNC(b)->args);
|
|
case TYPETEMPLATE:
|
|
return CTemplTool_TemplDepTypeCompare(TYPE_TEMPLATE(a), TYPE_TEMPLATE(b));
|
|
default:
|
|
CError_FATAL(1441);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
short iscpp_typeequal(Type *a, Type *b) {
|
|
restart:
|
|
if (a->type != b->type)
|
|
return 0;
|
|
switch (a->type) {
|
|
case TYPEVOID:
|
|
return 1;
|
|
case TYPEINT:
|
|
case TYPEFLOAT:
|
|
case TYPEENUM:
|
|
case TYPECLASS:
|
|
return a == b;
|
|
case TYPESTRUCT:
|
|
return a == b;
|
|
case TYPEPOINTER:
|
|
if (TYPE_POINTER(b)->target == &stvoid) {
|
|
if (TYPE_POINTER(a)->target == &stvoid)
|
|
return 1;
|
|
else
|
|
return -1;
|
|
}
|
|
if (TYPE_POINTER(a)->target == &stvoid) {
|
|
illegalimplicitconversion = 1;
|
|
return 0;
|
|
}
|
|
a = TYPE_POINTER(a)->target;
|
|
b = TYPE_POINTER(b)->target;
|
|
goto restart;
|
|
case TYPEMEMBERPOINTER:
|
|
if (TYPE_MEMBER_POINTER(a)->ty2 != TYPE_MEMBER_POINTER(b)->ty2)
|
|
return 0;
|
|
return is_memberpointerequal(TYPE_MEMBER_POINTER(a)->ty1, TYPE_MEMBER_POINTER(b)->ty1);
|
|
case TYPEARRAY:
|
|
if (a->size && b->size && a->size != b->size)
|
|
return 0;
|
|
a = TYPE_POINTER(a)->target;
|
|
b = TYPE_POINTER(b)->target;
|
|
goto restart;
|
|
case TYPEFUNC:
|
|
if (!is_typesame(TYPE_FUNC(a)->functype, TYPE_FUNC(b)->functype))
|
|
return 0;
|
|
if ((TYPE_FUNC(a)->flags & (FUNC_FLAGS_F0000000 | FUNC_FLAGS_PASCAL)) != (TYPE_FUNC(b)->flags & (FUNC_FLAGS_F0000000 | FUNC_FLAGS_PASCAL)))
|
|
return 0;
|
|
return is_arglistequal(TYPE_FUNC(a)->args, TYPE_FUNC(b)->args);
|
|
case TYPETEMPLATE:
|
|
return CTemplTool_TemplDepTypeCompare(TYPE_TEMPLATE(a), TYPE_TEMPLATE(b));
|
|
default:
|
|
CError_FATAL(1500);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
short CParser_CompareArgLists(FuncArg *a, FuncArg *b) {
|
|
Boolean r30;
|
|
|
|
r30 = 0;
|
|
if (a == &oldstyle) {
|
|
if (b == &oldstyle)
|
|
return 1;
|
|
else
|
|
return 2;
|
|
}
|
|
if (b == &oldstyle)
|
|
return 2;
|
|
|
|
while (1) {
|
|
if (a == &elipsis) {
|
|
if (b != &elipsis)
|
|
return 0;
|
|
break;
|
|
}
|
|
if (b == &elipsis)
|
|
return 0;
|
|
|
|
if (a == NULL) {
|
|
if (b)
|
|
return 0;
|
|
break;
|
|
}
|
|
if (b == NULL)
|
|
return 0;
|
|
|
|
if (a->type->type == TYPEPOINTER) {
|
|
if (IS_TYPEPOINTER_REFERENCE(TYPE_POINTER(a->type))) {
|
|
if (IS_TYPE_REFERENCE(b->type)) {
|
|
if (!is_typesame(TYPE_POINTER(a->type)->target, TYPE_POINTER(b->type)->target))
|
|
return 0;
|
|
if ((a->qual & (Q_CONST | Q_VOLATILE)) != (b->qual & (Q_CONST | Q_VOLATILE)))
|
|
return 0;
|
|
} else {
|
|
if (!copts.old_argmatch)
|
|
return 0;
|
|
if (!is_typesame(TYPE_POINTER(a->type)->target, b->type))
|
|
return 0;
|
|
if (b->type->type == TYPEPOINTER && (a->qual & (Q_CONST | Q_VOLATILE)) != (b->qual & (Q_CONST | Q_VOLATILE)))
|
|
return 0;
|
|
r30 = 1;
|
|
}
|
|
} else {
|
|
if (b->type->type == TYPEPOINTER) {
|
|
if (IS_TYPEPOINTER_REFERENCE(TYPE_POINTER(b->type))) {
|
|
if (!copts.old_argmatch)
|
|
return 0;
|
|
if (!is_typesame(a->type, TYPE_POINTER(b->type)->target))
|
|
return 0;
|
|
if (a->type->type == TYPEPOINTER && (a->qual & (Q_CONST | Q_VOLATILE)) != (b->qual & (Q_CONST | Q_VOLATILE)))
|
|
return 0;
|
|
r30 = 1;
|
|
} else {
|
|
if (!is_typesame(TYPE_POINTER(a->type)->target, TYPE_POINTER(b->type)->target))
|
|
return 0;
|
|
if ((a->qual & (Q_CONST | Q_VOLATILE)) != (b->qual & (Q_CONST | Q_VOLATILE)))
|
|
return 0;
|
|
}
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
} else {
|
|
if (b->type->type == TYPEPOINTER) {
|
|
if (IS_TYPEPOINTER_REFERENCE(TYPE_POINTER(b->type))) {
|
|
if (!copts.old_argmatch)
|
|
return 0;
|
|
if (!is_typesame(a->type, TYPE_POINTER(b->type)->target))
|
|
return 0;
|
|
r30 = 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
} else {
|
|
if (!is_typesame(a->type, b->type))
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
a = a->next;
|
|
b = b->next;
|
|
}
|
|
|
|
if (r30)
|
|
return 2;
|
|
return 1;
|
|
}
|
|
|
|
Boolean is_arglistsame(FuncArg *a, FuncArg *b) {
|
|
if (a == &oldstyle) {
|
|
if (b == &oldstyle)
|
|
return 1;
|
|
else
|
|
return oldstylecompatible(b);
|
|
} else {
|
|
if (b == &oldstyle)
|
|
return oldstylecompatible(a);
|
|
}
|
|
|
|
while (1) {
|
|
if (!a || !b || a == &elipsis || b == &elipsis)
|
|
return a == b;
|
|
|
|
if (a->type->type == TYPEPOINTER) {
|
|
if (b->type->type != TYPEPOINTER ||
|
|
(a->qual & (Q_CONST | Q_VOLATILE)) != (b->qual & (Q_CONST | Q_VOLATILE)) ||
|
|
!is_typesame(TYPE_POINTER(a->type)->target, TYPE_POINTER(b->type)->target) ||
|
|
IS_TYPEPOINTER_REFERENCE(TYPE_POINTER(a->type)) != IS_TYPEPOINTER_REFERENCE(TYPE_POINTER(b->type)))
|
|
return 0;
|
|
} else {
|
|
if (!is_typesame(a->type, b->type))
|
|
return 0;
|
|
}
|
|
|
|
a = a->next;
|
|
b = b->next;
|
|
}
|
|
}
|
|
|
|
short is_typesame(Type *a, Type *b) {
|
|
restart:
|
|
if (a->type != b->type) {
|
|
if (IS_TYPE_TEMPLATE(a) && IS_TYPE_CLASS(b) && (TYPE_CLASS(b)->flags & CLASS_FLAGS_100))
|
|
return CTemplTool_IsSameTemplateType(b, a);
|
|
if (IS_TYPE_TEMPLATE(b) && IS_TYPE_CLASS(a) && (TYPE_CLASS(a)->flags & CLASS_FLAGS_100))
|
|
return CTemplTool_IsSameTemplateType(a, b);
|
|
return 0;
|
|
}
|
|
|
|
switch (a->type) {
|
|
case TYPEVOID:
|
|
return 1;
|
|
case TYPEINT:
|
|
case TYPEFLOAT:
|
|
case TYPEENUM:
|
|
case TYPECLASS:
|
|
return a == b;
|
|
case TYPETEMPLATE:
|
|
return CTemplTool_TemplDepTypeCompare(TYPE_TEMPLATE(a), TYPE_TEMPLATE(b));
|
|
case TYPESTRUCT:
|
|
return a == b;
|
|
case TYPEPOINTER:
|
|
if ((TYPE_POINTER(a)->qual & (Q_RESTRICT | Q_REFERENCE | Q_CONST | Q_VOLATILE)) != (TYPE_POINTER(b)->qual & (Q_RESTRICT | Q_REFERENCE | Q_CONST | Q_VOLATILE)))
|
|
return 0;
|
|
a = TYPE_POINTER(a)->target;
|
|
b = TYPE_POINTER(b)->target;
|
|
goto restart;
|
|
case TYPEMEMBERPOINTER:
|
|
if (!is_typesame(TYPE_MEMBER_POINTER(a)->ty2, TYPE_MEMBER_POINTER(b)->ty2))
|
|
return 0;
|
|
if ((TYPE_MEMBER_POINTER(a)->qual & (Q_RESTRICT | Q_REFERENCE | Q_CONST | Q_VOLATILE)) != (TYPE_MEMBER_POINTER(b)->qual & (Q_RESTRICT | Q_REFERENCE | Q_CONST | Q_VOLATILE)))
|
|
return 0;
|
|
return is_memberpointerequal(TYPE_MEMBER_POINTER(a)->ty1, TYPE_MEMBER_POINTER(b)->ty1);
|
|
case TYPEARRAY:
|
|
if (a->size != b->size)
|
|
return 0;
|
|
a = TYPE_POINTER(a)->target;
|
|
b = TYPE_POINTER(b)->target;
|
|
goto restart;
|
|
case TYPEFUNC:
|
|
if (!is_typesame(TYPE_FUNC(a)->functype, TYPE_FUNC(b)->functype))
|
|
return 0;
|
|
if (TYPE_FUNC(a)->qual != TYPE_FUNC(b)->qual)
|
|
return 0;
|
|
if ((TYPE_FUNC(a)->flags & (FUNC_FLAGS_F0000000 | FUNC_FLAGS_PASCAL)) != (TYPE_FUNC(b)->flags & (FUNC_FLAGS_F0000000 | FUNC_FLAGS_PASCAL)))
|
|
return 0;
|
|
return is_arglistsame(TYPE_FUNC(a)->args, TYPE_FUNC(b)->args);
|
|
default:
|
|
CError_FATAL(1709);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
Type *CParser_GetBoolType(void) {
|
|
if (copts.cplusplus && copts.booltruefalse)
|
|
return TYPE(&stbool);
|
|
else
|
|
return TYPE(&stsignedint);
|
|
}
|
|
|
|
Type *CParser_GetWCharType(void) {
|
|
if (copts.cplusplus && copts.wchar_type)
|
|
return TYPE(&stwchar);
|
|
else
|
|
return TYPE(&stsignedint);
|
|
}
|
|
|
|
short CParser_GetOperator(ENodeType t) {
|
|
switch (t) {
|
|
default:
|
|
CError_FATAL(1748);
|
|
case EMONMIN: return '-';
|
|
case EBINNOT: return '~';
|
|
case ELOGNOT: return '!';
|
|
case EADD: return '+';
|
|
case ESUB: return '-';
|
|
case EMUL: return '*';
|
|
case EDIV: return '/';
|
|
case EMODULO: return '%';
|
|
case EAND: return '&';
|
|
case EXOR: return '^';
|
|
case EOR: return '|';
|
|
case ESHL: return TK_SHL;
|
|
case ESHR: return TK_SHR;
|
|
case ELESS: return '<';
|
|
case EGREATER: return '>';
|
|
case ELESSEQU: return TK_LESS_EQUAL;
|
|
case EGREATEREQU: return TK_GREATER_EQUAL;
|
|
case EEQU: return TK_LOGICAL_EQ;
|
|
case ENOTEQU: return TK_LOGICAL_NE;
|
|
}
|
|
}
|
|
|
|
Boolean CParser_IsMoreCVQualified(UInt32 a, UInt32 b) {
|
|
if ((a & Q_CONST) && !(b & Q_CONST)) {
|
|
return ((a & Q_VOLATILE) || !(b & Q_VOLATILE));
|
|
} else if ((a & Q_VOLATILE) && !(b & Q_VOLATILE)) {
|
|
return ((a & Q_CONST) || !(b & Q_CONST));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
Boolean CParser_IsSameOrMoreCVQualified(UInt32 a, UInt32 b) {
|
|
if ((a & (Q_CONST | Q_VOLATILE)) == (b & (Q_CONST | Q_VOLATILE)))
|
|
return 1;
|
|
|
|
if ((a & Q_CONST) && !(b & Q_CONST)) {
|
|
return ((a & Q_VOLATILE) || !(b & Q_VOLATILE));
|
|
} else if ((a & Q_VOLATILE) && !(b & Q_VOLATILE)) {
|
|
return ((a & Q_CONST) || !(b & Q_CONST));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
Boolean is_unsigned(Type *type) {
|
|
if (IS_TYPE_ENUM(type))
|
|
type = TYPE_ENUM(type)->enumtype;
|
|
|
|
if (
|
|
(type == TYPE(&stunsignedchar)) ||
|
|
(type == TYPE(&stunsignedshort)) ||
|
|
(type == TYPE(&stunsignedint)) ||
|
|
(type == TYPE(&stunsignedlong)) ||
|
|
(type == TYPE(&stunsignedlonglong)) ||
|
|
(type == TYPE(&stbool)) ||
|
|
(copts.unsignedchars && (type == TYPE(&stchar))) ||
|
|
(type->type == TYPEPOINTER))
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
StructMember *ismember(TypeStruct *tstruct, HashNameNode *name) {
|
|
StructMember *member;
|
|
|
|
for (member = tstruct->members; member; member = member->next) {
|
|
if (member->name == name)
|
|
return member;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void appendmember(TypeStruct *tstruct, StructMember *member) {
|
|
StructMember *last;
|
|
|
|
if (!tstruct->members) {
|
|
tstruct->members = member;
|
|
return;
|
|
}
|
|
|
|
for (last = tstruct->members; last->next; last = last->next) {}
|
|
last->next = member;
|
|
}
|
|
|
|
static void CParser_InsertTryBlock(ParserTryBlock *block) {
|
|
block->cscope_current = cscope_current;
|
|
block->cscope_currentclass = cscope_currentclass;
|
|
block->cscope_currentfunc = cscope_currentfunc;
|
|
block->ctempl_curinstance = ctempl_curinstance;
|
|
block->cerror_locktoken = cerror_locktoken;
|
|
block->cscope_is_member_func = cscope_is_member_func;
|
|
block->next = trychain;
|
|
trychain = block;
|
|
}
|
|
|
|
static void CParser_RemoveTryBlock(ParserTryBlock *block) {
|
|
cscope_current = block->cscope_current;
|
|
cscope_currentclass = block->cscope_currentclass;
|
|
cscope_currentfunc = block->cscope_currentfunc;
|
|
ctempl_curinstance = block->ctempl_curinstance;
|
|
cerror_locktoken = block->cerror_locktoken;
|
|
cscope_is_member_func = block->cscope_is_member_func;
|
|
trychain = block->next;
|
|
}
|
|
|
|
static Boolean TryIsDeclaration(Boolean flag1, Boolean flag2, Boolean flag3, short token) {
|
|
Boolean result;
|
|
DeclInfo declinfo;
|
|
struct ParserTryBlock tryblock;
|
|
|
|
switch (tk) {
|
|
case TK_IDENTIFIER:
|
|
case TK_COLON_COLON:
|
|
break;
|
|
case TK_VOID:
|
|
case TK_CHAR:
|
|
case TK_SHORT:
|
|
case TK_INT:
|
|
case TK_LONG:
|
|
case TK_FLOAT:
|
|
case TK_DOUBLE:
|
|
case TK_SIGNED:
|
|
case TK_UNSIGNED:
|
|
case TK_UNK_113:
|
|
case TK_UNK_114:
|
|
case TK_UNK_115:
|
|
case TK_UNK_116:
|
|
case TK_UNK_117:
|
|
case TK_UNK_118:
|
|
case TK_UNK_119:
|
|
case TK_UNK_11A:
|
|
case TK_BOOL:
|
|
case TK_WCHAR_T:
|
|
if (lookahead() != '(')
|
|
return 1;
|
|
break;
|
|
default:
|
|
return 1;
|
|
}
|
|
|
|
result = 0;
|
|
CParser_InsertTryBlock(&tryblock);
|
|
if (setjmp(tryblock.jmpbuf) == 0) {
|
|
memclrw(&declinfo, sizeof(DeclInfo));
|
|
CParser_GetDeclSpecs(&declinfo, 0);
|
|
if (!(IS_TYPE_TEMPLATE(declinfo.thetype) && TYPE_TEMPLATE(declinfo.thetype)->dtype == TEMPLDEP_QUALNAME && !declinfo.x53 && !declinfo.x49)) {
|
|
if (flag1) {
|
|
declinfo.x46 = flag3;
|
|
scandeclarator(&declinfo);
|
|
if (!(flag2 && declinfo.name)) {
|
|
if (!token) {
|
|
if (tk == ';' || tk == ',' || tk == '=' || tk == '(' || tk == ')' || tk == '>')
|
|
result = 1;
|
|
} else {
|
|
result = (tk == token);
|
|
}
|
|
}
|
|
} else {
|
|
result = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
CParser_RemoveTryBlock(&tryblock);
|
|
return result;
|
|
}
|
|
|
|
Boolean isdeclaration(UInt8 flag1, UInt8 flag2, UInt8 flag3, short token) {
|
|
SInt32 state;
|
|
|
|
if (!(tk >= TK_AUTO && tk <= TK_BYREF) && tk != TK_COLON_COLON && !(tk == TK_IDENTIFIER && CScope_PossibleTypeName(tkidentifier))) {
|
|
if (!(tk == TK_IDENTIFIER && copts.altivec_model && !strcmp(tkidentifier->name, "vector")))
|
|
return 0;
|
|
} else {
|
|
if (!copts.cplusplus)
|
|
return 1;
|
|
}
|
|
|
|
CPrep_TokenStreamGetState(&state);
|
|
if (TryIsDeclaration(flag1, flag2, flag3, token)) {
|
|
CPrep_TokenStreamSetCurState(&state);
|
|
return 1;
|
|
} else {
|
|
CPrep_TokenStreamSetCurState(&state);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
Boolean islookaheaddeclaration(void) {
|
|
SInt32 state;
|
|
|
|
CPrep_TokenStreamGetState(&state);
|
|
tk = lex();
|
|
if (!(tk >= TK_AUTO && tk <= TK_BYREF) && tk != TK_COLON_COLON && !(tk == TK_IDENTIFIER && CScope_PossibleTypeName(tkidentifier))) {
|
|
if (!(tk == TK_IDENTIFIER && copts.altivec_model && !strcmp(tkidentifier->name, "vector"))) {
|
|
CPrep_TokenStreamSetCurState(&state);
|
|
return 0;
|
|
}
|
|
} else {
|
|
if (!copts.cplusplus) {
|
|
CPrep_TokenStreamSetCurState(&state);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
if (TryIsDeclaration(1, 1, 0, ')')) {
|
|
CPrep_TokenStreamSetCurState(&state);
|
|
return 1;
|
|
} else {
|
|
CPrep_TokenStreamSetCurState(&state);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
Type *CParser_ParseTypeID(UInt32 *qual, Boolean *flag) {
|
|
SInt32 state;
|
|
DeclInfo di;
|
|
struct ParserTryBlock tryblock;
|
|
|
|
memclrw(&di, sizeof(DeclInfo));
|
|
CPrep_TokenStreamGetState(&state);
|
|
CParser_InsertTryBlock(&tryblock);
|
|
|
|
if (setjmp(tryblock.jmpbuf) == 0) {
|
|
if (copts.cplusplus)
|
|
di.x55 = 1;
|
|
|
|
if (flag) {
|
|
di.x56 = 1;
|
|
*flag = 0;
|
|
}
|
|
|
|
CParser_GetDeclSpecs(&di, 0);
|
|
if (di.x57 && IS_TYPE_CLASS(di.thetype) && (TYPE_CLASS(di.thetype)->flags & CLASS_FLAGS_100)) {
|
|
CParser_RemoveTryBlock(&tryblock);
|
|
*qual = di.qual;
|
|
*flag = 1;
|
|
return di.thetype;
|
|
}
|
|
|
|
if (flag && IS_TYPE_TEMPLATE(di.thetype) && TYPE_TEMPLATE(di.thetype)->dtype == TEMPLDEP_ARGUMENT &&
|
|
TYPE_TEMPLATE(di.thetype)->u.pid.type == TPT_TEMPLATE) {
|
|
CParser_RemoveTryBlock(&tryblock);
|
|
*qual = di.qual;
|
|
*flag = 1;
|
|
return di.thetype;
|
|
}
|
|
|
|
scandeclarator(&di);
|
|
if (!di.name) {
|
|
CParser_RemoveTryBlock(&tryblock);
|
|
*qual = di.qual;
|
|
return di.thetype;
|
|
}
|
|
}
|
|
|
|
CPrep_TokenStreamSetCurState(&state);
|
|
CParser_RemoveTryBlock(&tryblock);
|
|
return 0;
|
|
}
|
|
|
|
Boolean CParser_TryFuncDecl(void) {
|
|
Boolean result;
|
|
SInt32 state;
|
|
DeclInfo di;
|
|
struct ParserTryBlock tryblock;
|
|
|
|
result = 0;
|
|
CPrep_TokenStreamGetState(&state);
|
|
CParser_InsertTryBlock(&tryblock);
|
|
|
|
if (setjmp(tryblock.jmpbuf) == 0) {
|
|
memclrw(&di, sizeof(DeclInfo));
|
|
di.thetype = &stvoid;
|
|
scandeclarator(&di);
|
|
|
|
if (IS_TYPE_FUNC(di.thetype))
|
|
result = 1;
|
|
}
|
|
|
|
CParser_RemoveTryBlock(&tryblock);
|
|
CPrep_TokenStreamSetCurState(&state);
|
|
return result;
|
|
}
|
|
|
|
Boolean CParser_TryParamList(Boolean flag) {
|
|
Boolean result;
|
|
SInt32 state;
|
|
struct ParserTryBlock tryblock;
|
|
|
|
result = 0;
|
|
CPrep_TokenStreamGetState(&state);
|
|
|
|
switch ((tk = lex())) {
|
|
case ')':
|
|
case TK_ELLIPSIS:
|
|
result = 1;
|
|
break;
|
|
default:
|
|
CParser_InsertTryBlock(&tryblock);
|
|
if (setjmp(tryblock.jmpbuf) == 0) {
|
|
if (CFunc_ParseFakeArgList(flag) || tk == ')')
|
|
result = 1;
|
|
}
|
|
CParser_RemoveTryBlock(&tryblock);
|
|
break;
|
|
}
|
|
|
|
CPrep_TokenStreamSetCurState(&state);
|
|
return result;
|
|
}
|
|
|
|
Type *CParser_RemoveTopMostQualifiers(Type *type, UInt32 *qual) {
|
|
switch (type->type) {
|
|
case TYPEARRAY:
|
|
TYPE_POINTER(type)->target = CParser_RemoveTopMostQualifiers(TYPE_POINTER(type)->target, qual);
|
|
return type;
|
|
case TYPEPOINTER:
|
|
if (TYPE_POINTER(type)->qual & Q_CONST) {
|
|
TypePointer *newtype = galloc(sizeof(TypePointer));
|
|
*newtype = *TYPE_POINTER(type);
|
|
newtype->qual = 0;
|
|
return TYPE(newtype);
|
|
}
|
|
return type;
|
|
case TYPEMEMBERPOINTER:
|
|
if (TYPE_MEMBER_POINTER(type)->qual & Q_CONST) {
|
|
TypeMemberPointer *newtype = galloc(sizeof(TypeMemberPointer));
|
|
*newtype = *TYPE_MEMBER_POINTER(type);
|
|
newtype->qual = 0;
|
|
return TYPE(newtype);
|
|
}
|
|
return type;
|
|
default:
|
|
*qual = 0;
|
|
return type;
|
|
}
|
|
}
|
|
|
|
UInt32 CParser_GetTypeQualifiers(Type *type, UInt32 qual) {
|
|
while (IS_TYPE_ARRAY(type))
|
|
type = TYPE_POINTER(type)->target;
|
|
|
|
switch (type->type) {
|
|
case TYPEPOINTER:
|
|
qual = TYPE_POINTER(type)->qual;
|
|
break;
|
|
case TYPEMEMBERPOINTER:
|
|
qual = TYPE_MEMBER_POINTER(type)->qual;
|
|
break;
|
|
}
|
|
|
|
return qual;
|
|
}
|
|
|
|
UInt32 CParser_GetCVTypeQualifiers(Type *type, UInt32 qual) {
|
|
while (IS_TYPE_ARRAY(type))
|
|
type = TYPE_POINTER(type)->target;
|
|
|
|
switch (type->type) {
|
|
case TYPEPOINTER:
|
|
qual = TYPE_POINTER(type)->qual;
|
|
break;
|
|
case TYPEMEMBERPOINTER:
|
|
qual = TYPE_MEMBER_POINTER(type)->qual;
|
|
break;
|
|
}
|
|
|
|
return qual & (Q_CONST | Q_VOLATILE);
|
|
}
|
|
|
|
Boolean CParser_IsConst(Type *type, UInt32 qual) {
|
|
while (IS_TYPE_ARRAY(type))
|
|
type = TYPE_POINTER(type)->target;
|
|
|
|
switch (type->type) {
|
|
case TYPEPOINTER:
|
|
qual = TYPE_POINTER(type)->qual;
|
|
break;
|
|
case TYPEMEMBERPOINTER:
|
|
qual = TYPE_MEMBER_POINTER(type)->qual;
|
|
break;
|
|
}
|
|
|
|
return qual & Q_CONST;
|
|
}
|
|
|
|
Boolean CParser_IsVolatile(Type *type, UInt32 qual) {
|
|
while (IS_TYPE_ARRAY(type))
|
|
type = TYPE_POINTER(type)->target;
|
|
|
|
switch (type->type) {
|
|
case TYPEPOINTER:
|
|
qual = TYPE_POINTER(type)->qual;
|
|
break;
|
|
case TYPEMEMBERPOINTER:
|
|
qual = TYPE_MEMBER_POINTER(type)->qual;
|
|
break;
|
|
}
|
|
|
|
return (qual & Q_VOLATILE) ? 1 : 0;
|
|
}
|
|
|
|
Boolean is_const_object(Object *obj) {
|
|
return CParser_IsConst(obj->type, obj->qual);
|
|
}
|
|
|
|
Boolean is_volatile_object(Object *obj) {
|
|
return CParser_IsVolatile(obj->type, obj->qual);
|
|
}
|
|
|
|
Boolean CParserIsConstExpr(ENode *expr) {
|
|
return CParser_IsConst(expr->rtype, expr->flags & ENODE_FLAG_QUALS);
|
|
}
|
|
|
|
Boolean CParserIsVolatileExpr(ENode *expr) {
|
|
return CParser_IsVolatile(expr->rtype, expr->flags & ENODE_FLAG_QUALS);
|
|
}
|
|
|
|
Boolean CParser_HasInternalLinkage(const Object *obj) {
|
|
NameSpace *nspace;
|
|
|
|
for (nspace = obj->nspace; nspace; nspace = nspace->parent) {
|
|
if (nspace->is_unnamed)
|
|
return 1;
|
|
}
|
|
|
|
if (obj->datatype == DLOCAL)
|
|
return 1;
|
|
if (obj->qual & (Q_20000 | Q_OVERLOAD))
|
|
return 0;
|
|
if (obj->sclass == TK_STATIC)
|
|
return 1;
|
|
|
|
// this feels *wrong* but it's the only way to match this function that I can see
|
|
if (obj->qual & Q_INLINE)
|
|
((Object *) obj)->qual |= Q_20000;
|
|
return 0;
|
|
}
|
|
|
|
Boolean CParser_HasInternalLinkage2(const Object *obj) {
|
|
if (obj->datatype == DLOCAL)
|
|
return 1;
|
|
if (obj->qual & (Q_20000 | Q_OVERLOAD))
|
|
return 0;
|
|
if (obj->sclass == TK_STATIC)
|
|
return 1;
|
|
|
|
// this feels *wrong* but it's the only way to match this function that I can see
|
|
if (obj->qual & Q_INLINE)
|
|
((Object *) obj)->qual |= Q_20000;
|
|
return 0;
|
|
}
|
|
|
|
Boolean CParser_IsVirtualFunction(Object *obj, TypeClass **tclass, SInt32 *index) {
|
|
if (obj->datatype == DVFUNC) {
|
|
*tclass = TYPE_METHOD(obj->type)->theclass;
|
|
*index = TYPE_METHOD(obj->type)->x1E;
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
Boolean is_pascal_object(Object *obj) {
|
|
return IS_TYPE_FUNC(obj->type) && (TYPE_FUNC(obj->type)->flags & FUNC_FLAGS_PASCAL);
|
|
}
|
|
|
|
Boolean is_cfm_type(Type *type) {
|
|
return 0;
|
|
}
|
|
|
|
Boolean CParser_IsVTableObject(Object *obj) {
|
|
return
|
|
obj->datatype == DDATA &&
|
|
obj->nspace &&
|
|
obj->nspace->theclass &&
|
|
obj->nspace->theclass->vtable &&
|
|
obj->nspace->theclass->vtable->object == obj;
|
|
}
|
|
|
|
static Type *getthetype(short token, short size, short signedness) {
|
|
switch (token) {
|
|
case 0:
|
|
case TK_INT:
|
|
if (signedness == 1) {
|
|
switch (size) {
|
|
case 1: return TYPE(&stunsignedshort);
|
|
case 2: return TYPE(&stunsignedlong);
|
|
case 3: return TYPE(&stunsignedlonglong);
|
|
default: return TYPE(&stunsignedint);
|
|
}
|
|
} else {
|
|
switch (size) {
|
|
case 1: return TYPE(&stsignedshort);
|
|
case 2: return TYPE(&stsignedlong);
|
|
case 3: return TYPE(&stsignedlonglong);
|
|
default: return TYPE(&stsignedint);
|
|
}
|
|
}
|
|
case TK_BOOL:
|
|
return TYPE(&stbool);
|
|
case TK_WCHAR_T:
|
|
return TYPE(&stwchar);
|
|
case TK_CHAR:
|
|
switch (signedness) {
|
|
case 1: return TYPE(&stunsignedchar);
|
|
default: return TYPE(&stchar);
|
|
case -1: return TYPE(&stsignedchar);
|
|
}
|
|
case TK_DOUBLE:
|
|
switch (size) {
|
|
case 1: return TYPE(&stshortdouble);
|
|
case 2: return TYPE(&stlongdouble);
|
|
default: return TYPE(&stdouble);
|
|
}
|
|
case TK_FLOAT:
|
|
return TYPE(&stfloat);
|
|
case TK_VOID:
|
|
return TYPE(&stvoid);
|
|
default:
|
|
CError_Error(CErrorStr121);
|
|
return TYPE(&stvoid);
|
|
}
|
|
}
|
|
|
|
void TypedefDeclInfo(DeclInfo *declinfo, Type *type, UInt32 qual) {
|
|
if (type->type == TYPEPOINTER) {
|
|
if (IS_TYPEPOINTER_REFERENCE(TYPE_POINTER(type))) {
|
|
declinfo->thetype = type;
|
|
declinfo->qual &= ~(Q_RESTRICT | Q_REFERENCE | Q_VOLATILE | Q_CONST);
|
|
declinfo->qual |= qual;
|
|
return;
|
|
}
|
|
|
|
declinfo->thetype = galloc(sizeof(TypePointer));
|
|
*TYPE_POINTER(declinfo->thetype) = *TYPE_POINTER(type);
|
|
TYPE_POINTER(declinfo->thetype)->qual |= declinfo->qual & (Q_RESTRICT | Q_REFERENCE | Q_VOLATILE | Q_CONST);
|
|
declinfo->qual &= ~(Q_RESTRICT | Q_REFERENCE | Q_VOLATILE | Q_CONST);
|
|
declinfo->qual |= qual & (Q_ALIGNED_MASK | Q_REFERENCE | Q_PASCAL | Q_VOLATILE | Q_CONST);
|
|
} else if (type->type == TYPEMEMBERPOINTER) {
|
|
declinfo->thetype = galloc(sizeof(TypeMemberPointer));
|
|
*TYPE_MEMBER_POINTER(declinfo->thetype) = *TYPE_MEMBER_POINTER(type);
|
|
TYPE_MEMBER_POINTER(declinfo->thetype)->qual |= declinfo->qual & (Q_RESTRICT | Q_REFERENCE | Q_VOLATILE | Q_CONST);
|
|
declinfo->qual &= ~(Q_RESTRICT | Q_REFERENCE | Q_VOLATILE | Q_CONST);
|
|
declinfo->qual |= qual & (Q_ALIGNED_MASK | Q_REFERENCE | Q_PASCAL | Q_VOLATILE | Q_CONST);
|
|
} else {
|
|
declinfo->thetype = type;
|
|
declinfo->qual |= qual & (Q_ALIGNED_MASK | Q_REFERENCE | Q_PASCAL | Q_VOLATILE | Q_CONST);
|
|
if (IS_TYPE_ARRAY(declinfo->thetype) && !declinfo->thetype->size) {
|
|
declinfo->thetype = galloc(sizeof(TypePointer));
|
|
*TYPE_POINTER(declinfo->thetype) = *TYPE_POINTER(type);
|
|
}
|
|
}
|
|
declinfo->x49 = 1;
|
|
}
|
|
|
|
static void CParser_ParseAttributeFunctionSummary(DeclInfo *declinfo) {
|
|
Boolean flag;
|
|
|
|
if ((tk = lex()) != '(') {
|
|
CError_Error(CErrorStr114);
|
|
return;
|
|
}
|
|
|
|
flag = 1;
|
|
tk = lookahead();
|
|
while (tk == TK_IDENTIFIER) {
|
|
if (flag && !strcmp(tkidentifier->name, "entry_points_to")) {
|
|
PointerAnalysis_ParseEntryPointsToSpecifier(declinfo);
|
|
} else if (!strcmp(tkidentifier->name, "exit_points_to")) {
|
|
PointerAnalysis_ParseExitPointsToSpecifier(declinfo);
|
|
flag = 0;
|
|
} else if (!strcmp(tkidentifier->name, "function_modifies")) {
|
|
PointerAnalysis_ParseFunctionModifiesSpecifier(declinfo);
|
|
flag = 0;
|
|
} else {
|
|
lex();
|
|
CError_Error(CErrorStr121);
|
|
return;
|
|
}
|
|
|
|
tk = lookahead();
|
|
if (tk == ',') {
|
|
lex();
|
|
tk = lookahead();
|
|
}
|
|
}
|
|
|
|
lex();
|
|
if (tk != ')')
|
|
CError_Error(CErrorStr121);
|
|
}
|
|
|
|
void CParser_ParseAttribute(Type *type, DeclInfo *declinfo) {
|
|
CInt64 val64;
|
|
SInt32 val;
|
|
|
|
do {
|
|
if ((tk = lex()) != '(') {
|
|
CError_Error(CErrorStr121);
|
|
return;
|
|
}
|
|
if ((tk = lex()) != '(') {
|
|
CError_Error(CErrorStr121);
|
|
return;
|
|
}
|
|
if ((tk = lex()) != TK_IDENTIFIER && tk != TK_CONST) {
|
|
CError_Error(CErrorStr121);
|
|
return;
|
|
}
|
|
|
|
if (!strcmp(tkidentifier->name, "aligned") || !strcmp(tkidentifier->name, "__aligned__")) {
|
|
if ((tk = lex()) != '(') {
|
|
CError_Error(CErrorStr121);
|
|
return;
|
|
}
|
|
|
|
tk = lex();
|
|
val64 = CExpr_IntegralConstExpr();
|
|
switch ((val = CInt64_GetULong(&val64))) {
|
|
case 1:
|
|
case 2:
|
|
case 4:
|
|
case 8:
|
|
case 0x10:
|
|
case 0x20:
|
|
case 0x40:
|
|
case 0x80:
|
|
case 0x100:
|
|
case 0x200:
|
|
case 0x400:
|
|
case 0x800:
|
|
case 0x1000:
|
|
case 0x2000:
|
|
break;
|
|
default:
|
|
CError_Error(CErrorStr124);
|
|
return;
|
|
}
|
|
if (type) {
|
|
if (IS_TYPE_STRUCT(type)) {
|
|
if (val > TYPE_STRUCT(type)->align) {
|
|
TYPE_STRUCT(type)->align = val;
|
|
type->size += CABI_StructSizeAlignValue(type, type->size);
|
|
}
|
|
} else if (IS_TYPE_CLASS(type)) {
|
|
if (val > TYPE_CLASS(type)->align) {
|
|
TYPE_CLASS(type)->align = val;
|
|
type->size += CABI_StructSizeAlignValue(type, type->size);
|
|
}
|
|
} else {
|
|
CError_Error(CErrorStr149);
|
|
}
|
|
} else if (declinfo) {
|
|
declinfo->qual &= ~Q_ALIGNED_MASK;
|
|
switch (val) {
|
|
case 1:
|
|
declinfo->qual |= Q_ALIGNED_1;
|
|
break;
|
|
case 2:
|
|
declinfo->qual |= Q_ALIGNED_2;
|
|
break;
|
|
case 4:
|
|
declinfo->qual |= Q_ALIGNED_4;
|
|
break;
|
|
case 8:
|
|
declinfo->qual |= Q_ALIGNED_8;
|
|
break;
|
|
case 16:
|
|
declinfo->qual |= Q_ALIGNED_16;
|
|
break;
|
|
case 32:
|
|
declinfo->qual |= Q_ALIGNED_32;
|
|
break;
|
|
case 64:
|
|
declinfo->qual |= Q_ALIGNED_64;
|
|
break;
|
|
case 128:
|
|
declinfo->qual |= Q_ALIGNED_128;
|
|
break;
|
|
case 256:
|
|
declinfo->qual |= Q_ALIGNED_256;
|
|
break;
|
|
case 512:
|
|
declinfo->qual |= Q_ALIGNED_512;
|
|
break;
|
|
case 1024:
|
|
declinfo->qual |= Q_ALIGNED_1024;
|
|
break;
|
|
case 2048:
|
|
declinfo->qual |= Q_ALIGNED_2048;
|
|
break;
|
|
case 4096:
|
|
declinfo->qual |= Q_ALIGNED_4096;
|
|
break;
|
|
case 8192:
|
|
declinfo->qual |= Q_ALIGNED_8192;
|
|
break;
|
|
default:
|
|
CError_FATAL(2779);
|
|
break;
|
|
}
|
|
} else {
|
|
CError_Error(CErrorStr359);
|
|
}
|
|
|
|
if (tk != ')') {
|
|
CError_Error(CErrorStr121);
|
|
return;
|
|
}
|
|
} else if (!strcmp(tkidentifier->name, "nothrow") || !strcmp(tkidentifier->name, "__nothrow__")) {
|
|
if (declinfo && declinfo->thetype && IS_TYPE_FUNC(declinfo->thetype))
|
|
TYPE_FUNC(declinfo->thetype)->flags |= FUNC_FLAGS_NOTHROW;
|
|
else
|
|
CError_Error(CErrorStr359);
|
|
} else if (!strcmp("function_summary", tkidentifier->name)) {
|
|
CParser_ParseAttributeFunctionSummary(declinfo);
|
|
} else if (!strcmp(tkidentifier->name, "packed") || !strcmp(tkidentifier->name, "__packed__")) {
|
|
CError_Error(CErrorStr359);
|
|
} else if (!strcmp(tkidentifier->name, "unused") || !strcmp(tkidentifier->name, "__unused__")) {
|
|
} else if (!strcmp(tkidentifier->name, "noreturn") || !strcmp(tkidentifier->name, "__noreturn__")) {
|
|
} else if (tk == TK_CONST || !strcmp(tkidentifier->name, "__const__")) {
|
|
} else if (!strcmp(tkidentifier->name, "format") || !strcmp(tkidentifier->name, "__format__")) {
|
|
CError_Warning(CErrorStr359);
|
|
if ((tk = lex()) != '(') {
|
|
CError_Warning(CErrorStr114);
|
|
return;
|
|
}
|
|
tk = lex();
|
|
if ((tk = lex()) != ',') {
|
|
CError_Warning(CErrorStr116);
|
|
return;
|
|
}
|
|
tk = lex();
|
|
if ((tk = lex()) != ',') {
|
|
CError_Warning(CErrorStr116);
|
|
return;
|
|
}
|
|
tk = lex();
|
|
if ((tk = lex()) != ')') {
|
|
CError_Warning(CErrorStr115);
|
|
return;
|
|
}
|
|
} else if (!strcmp(tkidentifier->name, "mode") || !strcmp(tkidentifier->name, "__mode__")) {
|
|
CError_Warning(CErrorStr359);
|
|
if ((tk = lex()) != '(') {
|
|
CError_Warning(CErrorStr114);
|
|
return;
|
|
}
|
|
tk = lex();
|
|
if ((tk = lex()) != ')') {
|
|
CError_Warning(CErrorStr115);
|
|
return;
|
|
}
|
|
} else {
|
|
CError_Error(CErrorStr359);
|
|
}
|
|
|
|
if ((tk = lex()) != ')') {
|
|
CError_Error(CErrorStr121);
|
|
return;
|
|
}
|
|
if ((tk = lex()) != ')') {
|
|
CError_Error(CErrorStr121);
|
|
return;
|
|
}
|
|
tk = lex();
|
|
} while (tk == TK_UU_ATTRIBUTE_UU);
|
|
}
|
|
|
|
static void CParser_ParseTypeOf(DeclInfo *declinfo) {
|
|
DeclInfo subdi;
|
|
ENode *expr;
|
|
|
|
if ((tk = lex()) == '(' && islookaheaddeclaration()) {
|
|
tk = lex();
|
|
|
|
memclrw(&subdi, sizeof(DeclInfo));
|
|
CParser_GetDeclSpecs(&subdi, 0);
|
|
scandeclarator(&subdi);
|
|
if (subdi.name)
|
|
CError_Error(CErrorStr121);
|
|
|
|
if (tk != ')')
|
|
CError_ErrorSkip(CErrorStr115);
|
|
else
|
|
tk = lex();
|
|
|
|
TypedefDeclInfo(declinfo, subdi.thetype, subdi.qual);
|
|
} else {
|
|
expr = unary_expression();
|
|
if (ENODE_IS(expr, EINDIRECT) && ENODE_IS(expr->data.monadic, EBITFIELD))
|
|
CError_Error(CErrorStr144);
|
|
TypedefDeclInfo(declinfo, expr->rtype, expr->flags & ENODE_FLAG_QUALS);
|
|
}
|
|
}
|
|
|
|
void CParser_ParseDeclSpec(DeclInfo *declinfo, Boolean flag) {
|
|
if ((tk = lex()) != TK_IDENTIFIER) {
|
|
if (tk != TK_EXPORT)
|
|
CError_Error(CErrorStr107);
|
|
else
|
|
declinfo->exportflags |= EXPORT_FLAGS_EXPORT;
|
|
} else if (!strcmp("internal", tkidentifier->name)) {
|
|
declinfo->exportflags |= EXPORT_FLAGS_INTERNAL;
|
|
} else if (!strcmp("import", tkidentifier->name) || !strcmp("dllimport", tkidentifier->name)) {
|
|
declinfo->exportflags |= EXPORT_FLAGS_IMPORT;
|
|
} else if (!strcmp("export", tkidentifier->name) || !strcmp("dllexport", tkidentifier->name)) {
|
|
declinfo->exportflags |= EXPORT_FLAGS_EXPORT;
|
|
} else if (!strcmp("lib_export", tkidentifier->name)) {
|
|
declinfo->exportflags |= EXPORT_FLAGS_IMPORT | EXPORT_FLAGS_EXPORT;
|
|
} else if (!strcmp("weak", tkidentifier->name)) {
|
|
declinfo->qual |= Q_OVERLOAD;
|
|
} else {
|
|
CodeGen_ParseDeclSpec(tkidentifier, declinfo);
|
|
}
|
|
}
|
|
|
|
static int CParser_GetVectorDeclSpec(Type **type) {
|
|
tk = lex();
|
|
switch (tk) {
|
|
case TK_CHAR:
|
|
tk = lex();
|
|
switch (tk) {
|
|
case TK_BOOL:
|
|
*type = TYPE(&stvectorboolchar);
|
|
tk = lex();
|
|
return 1;
|
|
case TK_UNSIGNED:
|
|
*type = TYPE(&stvectorunsignedchar);
|
|
tk = lex();
|
|
return 1;
|
|
case TK_SIGNED:
|
|
*type = TYPE(&stvectorsignedchar);
|
|
tk = lex();
|
|
return 1;
|
|
case TK_IDENTIFIER:
|
|
if (tkidentifier == GetHashNameNode("bool")) {
|
|
*type = TYPE(&stvectorboolchar);
|
|
tk = lex();
|
|
return 1;
|
|
}
|
|
default:
|
|
CError_Error(CErrorStr121);
|
|
}
|
|
break;
|
|
case TK_SIGNED:
|
|
tk = lex();
|
|
switch (tk) {
|
|
case TK_CHAR:
|
|
*type = TYPE(&stvectorsignedchar);
|
|
tk = lex();
|
|
return 1;
|
|
case TK_SHORT:
|
|
*type = TYPE(&stvectorsignedshort);
|
|
tk = lex();
|
|
if (tk == TK_INT)
|
|
tk = lex();
|
|
return 1;
|
|
case TK_LONG:
|
|
*type = TYPE(&stvectorsignedlong);
|
|
tk = lex();
|
|
if (tk == TK_INT)
|
|
tk = lex();
|
|
return 1;
|
|
case TK_INT:
|
|
tk = lex();
|
|
switch (tk) {
|
|
case TK_SHORT:
|
|
*type = TYPE(&stvectorsignedshort);
|
|
tk = lex();
|
|
return 1;
|
|
case TK_LONG:
|
|
*type = TYPE(&stvectorsignedlong);
|
|
tk = lex();
|
|
return 1;
|
|
default:
|
|
*type = TYPE(&stvectorsignedlong);
|
|
return 1;
|
|
}
|
|
default:
|
|
CError_Error(CErrorStr121);
|
|
}
|
|
break;
|
|
case TK_UNSIGNED:
|
|
tk = lex();
|
|
switch (tk) {
|
|
case TK_CHAR:
|
|
*type = TYPE(&stvectorunsignedchar);
|
|
tk = lex();
|
|
return 1;
|
|
case TK_SHORT:
|
|
*type = TYPE(&stvectorunsignedshort);
|
|
tk = lex();
|
|
if (tk == TK_INT)
|
|
tk = lex();
|
|
return 1;
|
|
case TK_LONG:
|
|
*type = TYPE(&stvectorunsignedlong);
|
|
tk = lex();
|
|
if (tk == TK_INT)
|
|
tk = lex();
|
|
return 1;
|
|
case TK_INT:
|
|
tk = lex();
|
|
switch (tk) {
|
|
case TK_SHORT:
|
|
*type = TYPE(&stvectorunsignedshort);
|
|
tk = lex();
|
|
return 1;
|
|
case TK_LONG:
|
|
*type = TYPE(&stvectorunsignedlong);
|
|
tk = lex();
|
|
return 1;
|
|
default:
|
|
*type = TYPE(&stvectorunsignedlong);
|
|
return 1;
|
|
}
|
|
default:
|
|
CError_Error(CErrorStr121);
|
|
}
|
|
break;
|
|
case TK_BOOL:
|
|
tk = lex();
|
|
switch (tk) {
|
|
case TK_CHAR:
|
|
*type = TYPE(&stvectorboolchar);
|
|
tk = lex();
|
|
return 1;
|
|
case TK_SHORT:
|
|
*type = TYPE(&stvectorboolshort);
|
|
tk = lex();
|
|
if (tk == TK_INT)
|
|
tk = lex();
|
|
return 1;
|
|
case TK_LONG:
|
|
*type = TYPE(&stvectorboollong);
|
|
tk = lex();
|
|
if (tk == TK_INT)
|
|
tk = lex();
|
|
return 1;
|
|
case TK_INT:
|
|
tk = lex();
|
|
switch (tk) {
|
|
case TK_SHORT:
|
|
*type = TYPE(&stvectorboolshort);
|
|
tk = lex();
|
|
return 1;
|
|
case TK_LONG:
|
|
*type = TYPE(&stvectorboollong);
|
|
tk = lex();
|
|
return 1;
|
|
default:
|
|
*type = TYPE(&stvectorboollong);
|
|
return 1;
|
|
}
|
|
default:
|
|
CError_Error(CErrorStr121);
|
|
}
|
|
break;
|
|
case TK_SHORT:
|
|
tk = lex();
|
|
switch (tk) {
|
|
case TK_BOOL:
|
|
*type = TYPE(&stvectorboolshort);
|
|
tk = lex();
|
|
if (tk == TK_INT)
|
|
tk = lex();
|
|
return 1;
|
|
case TK_SIGNED:
|
|
*type = TYPE(&stvectorsignedshort);
|
|
tk = lex();
|
|
if (tk == TK_INT)
|
|
tk = lex();
|
|
return 1;
|
|
case TK_UNSIGNED:
|
|
*type = TYPE(&stvectorunsignedshort);
|
|
tk = lex();
|
|
if (tk == TK_INT)
|
|
tk = lex();
|
|
return 1;
|
|
case TK_INT:
|
|
tk = lex();
|
|
switch (tk) {
|
|
case TK_BOOL:
|
|
*type = TYPE(&stvectorboolshort);
|
|
tk = lex();
|
|
if (tk == TK_INT)
|
|
tk = lex();
|
|
return 1;
|
|
case TK_SIGNED:
|
|
*type = TYPE(&stvectorsignedshort);
|
|
tk = lex();
|
|
return 1;
|
|
case TK_UNSIGNED:
|
|
*type = TYPE(&stvectorunsignedshort);
|
|
tk = lex();
|
|
return 1;
|
|
case TK_IDENTIFIER:
|
|
if (tkidentifier == GetHashNameNode("bool")) {
|
|
*type = TYPE(&stvectorboolshort);
|
|
tk = lex();
|
|
if (tk == TK_INT)
|
|
tk = lex();
|
|
return 1;
|
|
}
|
|
default:
|
|
CError_Error(CErrorStr121);
|
|
}
|
|
break;
|
|
case TK_IDENTIFIER:
|
|
if (tkidentifier == GetHashNameNode("bool")) {
|
|
*type = TYPE(&stvectorboolshort);
|
|
tk = lex();
|
|
if (tk == TK_INT)
|
|
tk = lex();
|
|
return 1;
|
|
}
|
|
default:
|
|
CError_Error(CErrorStr121);
|
|
}
|
|
break;
|
|
case TK_LONG:
|
|
tk = lex();
|
|
switch (tk) {
|
|
case TK_BOOL:
|
|
*type = TYPE(&stvectorboollong);
|
|
tk = lex();
|
|
if (tk == TK_INT)
|
|
tk = lex();
|
|
return 1;
|
|
case TK_SIGNED:
|
|
*type = TYPE(&stvectorsignedlong);
|
|
tk = lex();
|
|
if (tk == TK_INT)
|
|
tk = lex();
|
|
return 1;
|
|
case TK_UNSIGNED:
|
|
*type = TYPE(&stvectorunsignedlong);
|
|
tk = lex();
|
|
if (tk == TK_INT)
|
|
tk = lex();
|
|
return 1;
|
|
case TK_INT:
|
|
tk = lex();
|
|
switch (tk) {
|
|
case TK_BOOL:
|
|
*type = TYPE(&stvectorboollong);
|
|
tk = lex();
|
|
return 1;
|
|
case TK_SIGNED:
|
|
*type = TYPE(&stvectorsignedlong);
|
|
tk = lex();
|
|
return 1;
|
|
case TK_UNSIGNED:
|
|
*type = TYPE(&stvectorunsignedlong);
|
|
tk = lex();
|
|
return 1;
|
|
case TK_IDENTIFIER:
|
|
if (tkidentifier == GetHashNameNode("bool")) {
|
|
*type = TYPE(&stvectorboollong);
|
|
tk = lex();
|
|
return 1;
|
|
}
|
|
default:
|
|
CError_Error(CErrorStr121);
|
|
}
|
|
break;
|
|
case TK_IDENTIFIER:
|
|
if (tkidentifier == GetHashNameNode("bool")) {
|
|
*type = TYPE(&stvectorboollong);
|
|
tk = lex();
|
|
if (tk == TK_INT)
|
|
tk = lex();
|
|
return 1;
|
|
}
|
|
default:
|
|
CError_Error(CErrorStr121);
|
|
}
|
|
break;
|
|
case TK_INT:
|
|
tk = lex();
|
|
switch (tk) {
|
|
case TK_BOOL:
|
|
tk = lex();
|
|
switch (tk) {
|
|
case TK_SHORT:
|
|
*type = TYPE(&stvectorboolshort);
|
|
tk = lex();
|
|
return 1;
|
|
case TK_LONG:
|
|
*type = TYPE(&stvectorboollong);
|
|
tk = lex();
|
|
return 1;
|
|
default:
|
|
*type = TYPE(&stvectorboollong);
|
|
return 1;
|
|
}
|
|
case TK_SIGNED:
|
|
tk = lex();
|
|
switch (tk) {
|
|
case TK_SHORT:
|
|
*type = TYPE(&stvectorsignedshort);
|
|
tk = lex();
|
|
return 1;
|
|
case TK_LONG:
|
|
*type = TYPE(&stvectorsignedlong);
|
|
tk = lex();
|
|
return 1;
|
|
default:
|
|
*type = TYPE(&stvectorsignedlong);
|
|
return 1;
|
|
}
|
|
case TK_UNSIGNED:
|
|
tk = lex();
|
|
switch (tk) {
|
|
case TK_SHORT:
|
|
*type = TYPE(&stvectorunsignedshort);
|
|
tk = lex();
|
|
return 1;
|
|
case TK_LONG:
|
|
*type = TYPE(&stvectorunsignedlong);
|
|
tk = lex();
|
|
return 1;
|
|
default:
|
|
*type = TYPE(&stvectorunsignedlong);
|
|
return 1;
|
|
}
|
|
case TK_SHORT:
|
|
tk = lex();
|
|
switch (tk) {
|
|
case TK_BOOL:
|
|
*type = TYPE(&stvectorboolshort);
|
|
tk = lex();
|
|
return 1;
|
|
case TK_SIGNED:
|
|
*type = TYPE(&stvectorsignedshort);
|
|
tk = lex();
|
|
return 1;
|
|
case TK_UNSIGNED:
|
|
*type = TYPE(&stvectorunsignedshort);
|
|
tk = lex();
|
|
return 1;
|
|
case TK_IDENTIFIER:
|
|
if (tkidentifier == GetHashNameNode("bool")) {
|
|
*type = TYPE(&stvectorboolshort);
|
|
tk = lex();
|
|
return 1;
|
|
}
|
|
default:
|
|
CError_Error(CErrorStr121);
|
|
}
|
|
break;
|
|
case TK_LONG:
|
|
tk = lex();
|
|
switch (tk) {
|
|
case TK_BOOL:
|
|
*type = TYPE(&stvectorboollong);
|
|
tk = lex();
|
|
return 1;
|
|
case TK_SIGNED:
|
|
*type = TYPE(&stvectorsignedlong);
|
|
tk = lex();
|
|
return 1;
|
|
case TK_UNSIGNED:
|
|
*type = TYPE(&stvectorunsignedlong);
|
|
tk = lex();
|
|
return 1;
|
|
case TK_IDENTIFIER:
|
|
if (tkidentifier == GetHashNameNode("bool")) {
|
|
*type = TYPE(&stvectorboollong);
|
|
tk = lex();
|
|
return 1;
|
|
}
|
|
}
|
|
case TK_IDENTIFIER:
|
|
if (tkidentifier == GetHashNameNode("bool")) {
|
|
tk = lex();
|
|
switch (tk) {
|
|
case TK_LONG:
|
|
*type = TYPE(&stvectorboollong);
|
|
tk = lex();
|
|
return 1;
|
|
case TK_SHORT:
|
|
*type = TYPE(&stvectorboolshort);
|
|
tk = lex();
|
|
return 1;
|
|
default:
|
|
*type = TYPE(&stvectorboolshort);
|
|
return 1;
|
|
}
|
|
}
|
|
default:
|
|
CError_Error(CErrorStr121);
|
|
}
|
|
break;
|
|
case TK_FLOAT:
|
|
*type = TYPE(&stvectorfloat);
|
|
tk = lex();
|
|
return 1;
|
|
case TK_IDENTIFIER:
|
|
if (tkidentifier == GetHashNameNode("pixel") || tkidentifier == GetHashNameNode("__pixel")) {
|
|
*type = TYPE(&stvectorpixel);
|
|
tk = lex();
|
|
return 1;
|
|
}
|
|
if (tkidentifier == GetHashNameNode("bool")) {
|
|
tk = lex();
|
|
switch (tk) {
|
|
case TK_CHAR:
|
|
*type = TYPE(&stvectorboolchar);
|
|
tk = lex();
|
|
return 1;
|
|
case TK_SHORT:
|
|
*type = TYPE(&stvectorboolshort);
|
|
tk = lex();
|
|
if (tk == TK_INT)
|
|
tk = lex();
|
|
return 1;
|
|
case TK_LONG:
|
|
*type = TYPE(&stvectorboollong);
|
|
tk = lex();
|
|
if (tk == TK_INT)
|
|
tk = lex();
|
|
return 1;
|
|
case TK_INT:
|
|
tk = lex();
|
|
switch (tk) {
|
|
case TK_SHORT:
|
|
*type = TYPE(&stvectorboolshort);
|
|
tk = lex();
|
|
return 1;
|
|
case TK_LONG:
|
|
*type = TYPE(&stvectorboollong);
|
|
tk = lex();
|
|
return 1;
|
|
default:
|
|
*type = TYPE(&stvectorboollong);
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
default:
|
|
CError_Error(CErrorStr121);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
Boolean CParser_CheckTemplateClassUsage(TemplClass *tmclass, Boolean flag) {
|
|
NameSpace *nspace;
|
|
|
|
if (tmclass->templ__params) {
|
|
nspace = cscope_current;
|
|
while (1) {
|
|
if (!nspace) {
|
|
if (flag)
|
|
CError_Error(CErrorStr230);
|
|
return 0;
|
|
}
|
|
if (nspace->theclass == TYPE_CLASS(tmclass))
|
|
break;
|
|
nspace = nspace->parent;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static Boolean CParser_IsAltiVecPrefix(void) {
|
|
HashNameNode *save = tkidentifier;
|
|
|
|
switch (lookahead()) {
|
|
case TK_CHAR:
|
|
case TK_SHORT:
|
|
case TK_INT:
|
|
case TK_LONG:
|
|
case TK_FLOAT:
|
|
case TK_SIGNED:
|
|
case TK_UNSIGNED:
|
|
case TK_BOOL:
|
|
return 1;
|
|
case TK_IDENTIFIER:
|
|
if (!strcmp(tkidentifier->name, "bool") || !strcmp(tkidentifier->name, "pixel") || !strcmp(tkidentifier->name, "__pixel"))
|
|
return 1;
|
|
}
|
|
|
|
tkidentifier = save;
|
|
return 0;
|
|
}
|
|
|
|
void CParser_GetDeclSpecs(DeclInfo *di, Boolean flag) {
|
|
short typesize;
|
|
short signedness;
|
|
short typetoken;
|
|
Boolean r24;
|
|
Boolean r23;
|
|
SInt32 state;
|
|
CScopeParseResult pr;
|
|
|
|
di->file = CPrep_BrowserCurrentFile();
|
|
CPrep_BrowserFilePosition(
|
|
(CPrepFileInfo **) &di->file2,
|
|
&di->x60);
|
|
|
|
r24 = 1;
|
|
r23 = copts.cplusplus;
|
|
typetoken = 0;
|
|
signedness = 0;
|
|
typesize = 0;
|
|
|
|
restart:
|
|
switch (tk) {
|
|
case TK_AUTO:
|
|
case TK_REGISTER:
|
|
case TK_STATIC:
|
|
case TK_EXTERN:
|
|
case TK_TYPEDEF:
|
|
case TK_MUTABLE:
|
|
if (di->storageclass)
|
|
CError_Error(CErrorStr121);
|
|
di->storageclass = tk;
|
|
break;
|
|
case TK_CONST:
|
|
if (di->thetype) {
|
|
if (di->thetype->type == TYPEPOINTER) {
|
|
if (TYPE_POINTER(di->thetype)->qual & Q_CONST)
|
|
CError_QualifierCheck(Q_CONST);
|
|
TYPE_POINTER(di->thetype)->qual |= Q_CONST;
|
|
break;
|
|
} else if (di->thetype->type == TYPEMEMBERPOINTER) {
|
|
if (TYPE_MEMBER_POINTER(di->thetype)->qual & Q_CONST)
|
|
CError_QualifierCheck(Q_CONST);
|
|
TYPE_MEMBER_POINTER(di->thetype)->qual |= Q_CONST;
|
|
break;
|
|
}
|
|
}
|
|
if (di->qual & Q_CONST)
|
|
CError_QualifierCheck(Q_CONST);
|
|
di->qual |= Q_CONST;
|
|
break;
|
|
case TK_VOLATILE:
|
|
if (di->thetype) {
|
|
if (di->thetype->type == TYPEPOINTER) {
|
|
if (TYPE_POINTER(di->thetype)->qual & Q_VOLATILE)
|
|
CError_QualifierCheck(Q_VOLATILE);
|
|
TYPE_POINTER(di->thetype)->qual |= Q_VOLATILE;
|
|
break;
|
|
} else if (di->thetype->type == TYPEMEMBERPOINTER) {
|
|
if (TYPE_MEMBER_POINTER(di->thetype)->qual & Q_VOLATILE)
|
|
CError_QualifierCheck(Q_VOLATILE);
|
|
TYPE_MEMBER_POINTER(di->thetype)->qual |= Q_VOLATILE;
|
|
break;
|
|
}
|
|
}
|
|
if (di->qual & Q_VOLATILE)
|
|
CError_QualifierCheck(Q_VOLATILE);
|
|
di->qual |= Q_VOLATILE;
|
|
break;
|
|
case TK_PASCAL:
|
|
if (di->qual & Q_PASCAL)
|
|
CError_QualifierCheck(Q_PASCAL);
|
|
di->qual |= Q_PASCAL;
|
|
break;
|
|
case TK_EXPLICIT:
|
|
CError_QualifierCheck(di->qual & Q_EXPLICIT);
|
|
di->qual |= Q_EXPLICIT;
|
|
break;
|
|
case TK_VIRTUAL:
|
|
CError_QualifierCheck(di->qual & Q_VIRTUAL);
|
|
di->qual |= Q_VIRTUAL;
|
|
break;
|
|
case TK_IN:
|
|
CError_QualifierCheck(di->qual & Q_IN);
|
|
di->qual |= Q_IN;
|
|
break;
|
|
case TK_OUT:
|
|
CError_QualifierCheck(di->qual & Q_OUT);
|
|
di->qual |= Q_OUT;
|
|
break;
|
|
case TK_INOUT:
|
|
CError_QualifierCheck(di->qual & Q_INOUT);
|
|
di->qual |= Q_INOUT;
|
|
break;
|
|
case TK_BYCOPY:
|
|
CError_QualifierCheck(di->qual & Q_BYCOPY);
|
|
di->qual |= Q_BYCOPY;
|
|
break;
|
|
case TK_BYREF:
|
|
CError_QualifierCheck(di->qual & Q_BYREF);
|
|
di->qual |= Q_BYREF;
|
|
break;
|
|
case TK_ONEWAY:
|
|
CError_QualifierCheck(di->qual & Q_ONEWAY);
|
|
di->qual |= Q_ONEWAY;
|
|
break;
|
|
case TK_UU_DECLSPEC:
|
|
if ((tk = lex()) != '(')
|
|
CError_Error(CErrorStr114);
|
|
CParser_ParseDeclSpec(di, 0);
|
|
if ((tk = lex()) != ')')
|
|
CError_Error(CErrorStr115);
|
|
break;
|
|
case TK_ASM:
|
|
if (di->qual & Q_ASM)
|
|
CError_QualifierCheck(Q_ASM);
|
|
di->qual |= Q_ASM;
|
|
break;
|
|
case TK_INLINE:
|
|
if (di->qual & Q_INLINE)
|
|
CError_QualifierCheck(Q_INLINE);
|
|
di->qual |= Q_INLINE;
|
|
break;
|
|
case TK_SHORT:
|
|
if (typesize || (typetoken && typetoken != TK_INT && typetoken != TK_DOUBLE))
|
|
CError_Error(CErrorStr121);
|
|
typesize = 1;
|
|
break;
|
|
case TK_LONG:
|
|
if (copts.longlong) {
|
|
if (typetoken && typetoken != TK_INT && typetoken != TK_DOUBLE)
|
|
CError_Error(CErrorStr121);
|
|
if (typesize) {
|
|
if (typesize != 2 || typetoken == TK_DOUBLE)
|
|
CError_Error(CErrorStr121);
|
|
typesize = 3;
|
|
} else {
|
|
typesize = 2;
|
|
}
|
|
} else {
|
|
if (typesize || (typetoken && typetoken != TK_INT && typetoken != TK_DOUBLE))
|
|
CError_Error(CErrorStr121);
|
|
typesize = 2;
|
|
}
|
|
break;
|
|
case TK_SIGNED:
|
|
if (signedness || (typetoken && typetoken != TK_INT && typetoken != TK_CHAR))
|
|
CError_Error(CErrorStr121);
|
|
signedness = -1;
|
|
break;
|
|
case TK_UNSIGNED:
|
|
if (signedness || (typetoken && typetoken != TK_INT && typetoken != TK_CHAR))
|
|
CError_Error(CErrorStr121);
|
|
signedness = 1;
|
|
break;
|
|
case TK_VOID:
|
|
if (typetoken || typesize || signedness)
|
|
CError_Error(CErrorStr121);
|
|
typetoken = TK_VOID;
|
|
break;
|
|
case TK_FLOAT:
|
|
if (typetoken || typesize || signedness)
|
|
CError_Error(CErrorStr121);
|
|
typetoken = TK_FLOAT;
|
|
break;
|
|
case TK_BOOL:
|
|
if (typetoken || typesize)
|
|
CError_Error(CErrorStr121);
|
|
typetoken = TK_BOOL;
|
|
break;
|
|
case TK_CHAR:
|
|
if (typetoken || typesize)
|
|
CError_Error(CErrorStr121);
|
|
typetoken = TK_CHAR;
|
|
break;
|
|
case TK_WCHAR_T:
|
|
if (typetoken || typesize || signedness)
|
|
CError_Error(CErrorStr121);
|
|
typetoken = TK_WCHAR_T;
|
|
break;
|
|
case TK_INT:
|
|
if (typetoken)
|
|
CError_Error(CErrorStr121);
|
|
typetoken = TK_INT;
|
|
break;
|
|
case TK_DOUBLE:
|
|
if (typetoken || signedness)
|
|
CError_Error(CErrorStr121);
|
|
typetoken = TK_DOUBLE;
|
|
break;
|
|
case TK_STRUCT:
|
|
if (typetoken || signedness || typesize)
|
|
CError_Error(CErrorStr121);
|
|
tk = lex();
|
|
scanstruct(di, STRUCT_TYPE_STRUCT);
|
|
if (tk == TK_UU_ATTRIBUTE_UU)
|
|
CParser_ParseAttribute(di->thetype, NULL);
|
|
if (!(tk != TK_CONST && tk != TK_VOLATILE && tk != TK_UU_FAR && tk != TK_UU_DECLSPEC)) {
|
|
typetoken = -1;
|
|
goto restart;
|
|
}
|
|
return;
|
|
case TK_CLASS:
|
|
if (typetoken || signedness || typesize)
|
|
CError_Error(CErrorStr121);
|
|
tk = lex();
|
|
CDecl_ParseClass(di, CLASS_MODE_2, 1, 0);
|
|
if (tk == TK_UU_ATTRIBUTE_UU)
|
|
CParser_ParseAttribute(di->thetype, NULL);
|
|
if (!(tk != TK_CONST && tk != TK_VOLATILE && tk != TK_UU_FAR && tk != TK_UU_DECLSPEC)) {
|
|
typetoken = -1;
|
|
goto restart;
|
|
}
|
|
return;
|
|
case TK_UNION:
|
|
if (typetoken || signedness || typesize)
|
|
CError_Error(CErrorStr121);
|
|
tk = lex();
|
|
scanstruct(di, STRUCT_TYPE_UNION);
|
|
if (tk == TK_UU_ATTRIBUTE_UU)
|
|
CParser_ParseAttribute(di->thetype, NULL);
|
|
if (!(tk != TK_CONST && tk != TK_VOLATILE && tk != TK_UU_FAR && tk != TK_UU_DECLSPEC)) {
|
|
typetoken = -1;
|
|
goto restart;
|
|
}
|
|
return;
|
|
case TK_ENUM:
|
|
if (typetoken || signedness || typesize)
|
|
CError_Error(CErrorStr121);
|
|
tk = lex();
|
|
scanenum(di);
|
|
if (tk == TK_UU_ATTRIBUTE_UU)
|
|
CParser_ParseAttribute(di->thetype, NULL);
|
|
if (!(tk != TK_CONST && tk != TK_VOLATILE && tk != TK_UU_FAR && tk != TK_UU_DECLSPEC)) {
|
|
typetoken = -1;
|
|
goto restart;
|
|
}
|
|
return;
|
|
case TK_TYPENAME:
|
|
if (typetoken || signedness || typesize || di->x53)
|
|
CError_Error(CErrorStr121);
|
|
di->x53 = 1;
|
|
tk = lex();
|
|
if (tk != TK_COLON_COLON && tk != TK_IDENTIFIER) {
|
|
CError_Error(CErrorStr121);
|
|
break;
|
|
}
|
|
goto some_shared_label;
|
|
case TK_COLON_COLON:
|
|
if (typetoken || signedness || typesize)
|
|
goto switchDefault;
|
|
goto some_shared_label;
|
|
case TK_UU_VECTOR:
|
|
if (typetoken || signedness || typesize)
|
|
CError_Error(CErrorStr121);
|
|
handle_vector:
|
|
if (CParser_GetVectorDeclSpec(&di->thetype)) {
|
|
if (tk == TK_CONST) {
|
|
if (di->qual == 0) {
|
|
di->qual |= Q_CONST;
|
|
tk = lex();
|
|
} else {
|
|
CError_Error(CErrorStr121);
|
|
}
|
|
}
|
|
if (tk == TK_VOLATILE) {
|
|
if (di->qual == 0) {
|
|
di->qual |= Q_VOLATILE;
|
|
tk = lex();
|
|
} else {
|
|
CError_Error(CErrorStr121);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
break;
|
|
case TK_UU_TYPEOF_UU:
|
|
if (typetoken || signedness || typesize)
|
|
CError_Error(CErrorStr121);
|
|
CParser_ParseTypeOf(di);
|
|
typetoken = -1;
|
|
goto bailOut;
|
|
case TK_IDENTIFIER:
|
|
if (copts.altivec_model && !typetoken && !signedness && !typesize && !strcmp(tkidentifier->name, "vector")) {
|
|
if (CParser_IsAltiVecPrefix())
|
|
goto handle_vector;
|
|
}
|
|
if (!typetoken && !signedness && !typesize) {
|
|
if (copts.objective_c && !strcmp(tkidentifier->name, "id")) {
|
|
di->thetype = CObjC_ParseID();
|
|
typetoken = -1;
|
|
goto bailOut;
|
|
}
|
|
some_shared_label:
|
|
CPrep_TokenStreamGetState(&state);
|
|
if (CScope_ParseDeclName(&pr)) {
|
|
if (pr.x8) {
|
|
if (IS_TYPE_TEMPLATE(pr.x8)) {
|
|
switch (TYPE_TEMPLATE(pr.x8)->dtype) {
|
|
case TEMPLDEP_ARGUMENT:
|
|
switch (TYPE_TEMPLATE(pr.x8)->u.pid.type) {
|
|
case TPT_TYPE:
|
|
break;
|
|
case TPT_NONTYPE:
|
|
CError_Error(CErrorStr348);
|
|
pr.x8 = TYPE(&stsignedint);
|
|
break;
|
|
case TPT_TEMPLATE:
|
|
CError_Error(CErrorStr230);
|
|
pr.x8 = TYPE(&stsignedint);
|
|
break;
|
|
default:
|
|
CError_FATAL(4109);
|
|
}
|
|
break;
|
|
case TEMPLDEP_QUALNAME:
|
|
if (!di->x53 && !pr.x20 && di->x55)
|
|
CError_Error(CErrorStr355);
|
|
break;
|
|
case TEMPLDEP_TEMPLATE:
|
|
case TEMPLDEP_ARRAY:
|
|
case TEMPLDEP_QUALTEMPL:
|
|
case TEMPLDEP_BITFIELD:
|
|
break;
|
|
default:
|
|
CError_FATAL(4136);
|
|
}
|
|
}
|
|
|
|
if (IS_TYPE_CLASS(pr.x8) && (TYPE_CLASS(pr.x8)->flags & CLASS_FLAGS_100)) {
|
|
if (!CParser_CheckTemplateClassUsage(TEMPL_CLASS(pr.x8), 0)) {
|
|
if (di->x56) {
|
|
if (di->qual)
|
|
CError_Error(CErrorStr121);
|
|
di->thetype = pr.x8;
|
|
di->x57 = 1;
|
|
tk = lex();
|
|
return;
|
|
} else {
|
|
CError_Error(CErrorStr230);
|
|
pr.x8 = TYPE(&stsignedint);
|
|
}
|
|
}
|
|
}
|
|
|
|
TypedefDeclInfo(di, pr.x8, pr.xC);
|
|
di->x49 = pr.x20;
|
|
typetoken = -1;
|
|
tk = lex();
|
|
if (tk == '<' && copts.objective_c && IS_TYPE_CLASS(di->thetype) && TYPE_CLASS(di->thetype)->objcinfo)
|
|
di->thetype = CObjC_ParseTypeProtocol(TYPE_CLASS(di->thetype));
|
|
goto bailOut;
|
|
} else if (pr.nsol_14) {
|
|
if (pr.x1D) {
|
|
if (flag && (OBJECT(pr.nsol_14->object)->nspace == pr.nspace_0 || di->x4C)) {
|
|
di->x14 = pr.nsol_14;
|
|
if (IS_TYPE_FUNC(OBJECT(di->x14->object)->type) && ((TYPE_FUNC(OBJECT(di->x14->object)->type)->flags & FUNC_FLAGS_1000) | FUNC_FLAGS_2000))
|
|
r23 = 0;
|
|
} else {
|
|
CError_Error(CErrorStr121);
|
|
}
|
|
}
|
|
} else if (pr.obj_10) {
|
|
switch (pr.obj_10->otype) {
|
|
case OT_OBJECT:
|
|
if (pr.x1D) {
|
|
if (flag && (OBJECT(pr.obj_10)->nspace == pr.nspace_0 || di->x4C)) {
|
|
di->x10 = OBJECT(pr.obj_10);
|
|
if (IS_TYPE_FUNC(di->x10->type) && ((TYPE_FUNC(di->x10->type)->flags & FUNC_FLAGS_1000) | FUNC_FLAGS_2000))
|
|
r23 = 0;
|
|
} else {
|
|
CError_Error(CErrorStr121);
|
|
}
|
|
}
|
|
break;
|
|
case OT_ENUMCONST:
|
|
case OT_MEMBERVAR:
|
|
CError_Error(CErrorStr121);
|
|
break;
|
|
default:
|
|
CError_FATAL(4217);
|
|
}
|
|
} else if (pr.name_4) {
|
|
if (copts.cplusplus)
|
|
CError_Error(CErrorStr121);
|
|
} else if (pr.x21) {
|
|
CPrep_TokenStreamSetState(&state);
|
|
CPrep_UnLex();
|
|
tk = lex();
|
|
r23 = 0;
|
|
} else {
|
|
CError_FATAL(4234);
|
|
}
|
|
}
|
|
}
|
|
default:
|
|
switchDefault:
|
|
if (!typetoken && !signedness && !typesize) {
|
|
di->x4A = 1;
|
|
if (r23) {
|
|
if (!di->storageclass && !di->qual && !di->exportflags)
|
|
CError_Error(CErrorStr121);
|
|
else
|
|
CError_Warning(CErrorStr349);
|
|
}
|
|
}
|
|
if (typetoken >= 0)
|
|
di->thetype = getthetype(typetoken, typesize, signedness);
|
|
if (r24)
|
|
di->x48 = 1;
|
|
if (tk == TK_UU_ATTRIBUTE_UU)
|
|
CParser_ParseAttribute(NULL, di);
|
|
return;
|
|
case ';':
|
|
if (!typetoken && !signedness && !typesize && copts.warn_emptydecl)
|
|
CError_Warning(CErrorStr216);
|
|
if (typetoken >= 0)
|
|
di->thetype = getthetype(typetoken, typesize, signedness);
|
|
return;
|
|
}
|
|
|
|
tk = lex();
|
|
bailOut:
|
|
r24 = 0;
|
|
goto restart;
|
|
}
|
|
|
|
void CParser_RegisterNonGlobalClass(TypeClass *tclass) {
|
|
struct ParentCleanup *p = lalloc(sizeof(struct ParentCleanup));
|
|
p->next = cparser_parentcleanup;
|
|
p->tclass = tclass;
|
|
cparser_parentcleanup = p;
|
|
}
|
|
|
|
void CParser_RegisterSingleExprFunction(Object *func, ENode *expr) {
|
|
struct SFuncList *p = lalloc(sizeof(struct SFuncList));
|
|
p->next = cparser_sfunclist;
|
|
p->func = func;
|
|
p->obj = NULL;
|
|
p->expr = expr;
|
|
cparser_sfunclist = p;
|
|
}
|
|
|
|
void CParser_RegisterDummyCtorFunction(Object *func, Object *obj) {
|
|
struct SFuncList *p = lalloc(sizeof(struct SFuncList));
|
|
p->next = cparser_sfunclist;
|
|
p->func = func;
|
|
p->obj = obj;
|
|
p->expr = NULL;
|
|
cparser_sfunclist = p;
|
|
}
|
|
|
|
static void CParser_FreeLocalHeap(void) {
|
|
struct SFuncList *s;
|
|
struct ParentCleanup *p;
|
|
|
|
while ((s = cparser_sfunclist)) {
|
|
cparser_sfunclist = s->next;
|
|
if (s->expr)
|
|
CFunc_GenerateSingleExprFunc(s->func, s->expr);
|
|
else
|
|
CFunc_GenerateDummyCtorFunc(s->func, s->obj);
|
|
}
|
|
|
|
if (cparser_parentcleanup) {
|
|
if (!CInline_CanFreeLHeap())
|
|
return;
|
|
|
|
for (p = cparser_parentcleanup; p; p = p->next) {
|
|
while (!p->tclass->nspace->parent->is_global)
|
|
p->tclass->nspace->parent = p->tclass->nspace->parent->parent;
|
|
}
|
|
|
|
cparser_parentcleanup = NULL;
|
|
}
|
|
|
|
freelheap();
|
|
}
|
|
|
|
static void CParser_GlobalCleanup(Boolean flag) {
|
|
Boolean working;
|
|
|
|
do {
|
|
CParser_FreeLocalHeap();
|
|
working = 0;
|
|
|
|
if (flag) {
|
|
if (cparser_classactions) {
|
|
CClass_ClassAction(cparser_classactions->tclass);
|
|
cparser_classactions = cparser_classactions->next;
|
|
working = 1;
|
|
} else if (CTempl_Instantiate()) {
|
|
working = 1;
|
|
}
|
|
}
|
|
|
|
while (CInline_GenerateDeferredFuncs()) {
|
|
CParser_FreeLocalHeap();
|
|
working = 1;
|
|
}
|
|
} while (working);
|
|
}
|
|
|
|
Boolean CParser_IsAnonymousUnion(DeclInfo *di, Boolean flag) {
|
|
return IS_TYPE_CLASS(di->thetype) &&
|
|
((TYPE_CLASS(di->thetype)->mode == CLASS_MODE_1 || (flag && copts.cpp_extensions))) &&
|
|
IsTempName(TYPE_CLASS(di->thetype)->classname);
|
|
}
|
|
|
|
void CParser_CheckAnonymousUnion(DeclInfo *di, Boolean flag) {
|
|
ObjMemberVar *ivar;
|
|
Object *obj;
|
|
Object *ivar_obj;
|
|
|
|
if (!CParser_IsAnonymousUnion(di, 0)) {
|
|
if (copts.warn_emptydecl) {
|
|
switch (di->thetype->type) {
|
|
case TYPEENUM:
|
|
case TYPESTRUCT:
|
|
case TYPECLASS:
|
|
if (!di->storageclass && !di->qual)
|
|
return;
|
|
}
|
|
CError_Warning(CErrorStr216);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (!flag && di->storageclass != TK_STATIC)
|
|
CError_Error(CErrorStr177);
|
|
|
|
if (flag && di->storageclass != TK_STATIC) {
|
|
obj = CParser_NewLocalDataObject(di, 1);
|
|
obj->name = CParser_GetUniqueName();
|
|
CFunc_SetupLocalVarInfo(obj);
|
|
obj->u.var.info->noregister = 1;
|
|
} else {
|
|
obj = CParser_NewGlobalDataObject(di);
|
|
obj->name = CParser_GetUniqueName();
|
|
obj->nspace = cscope_root;
|
|
obj->sclass = TK_STATIC;
|
|
CInit_DeclareData(obj, NULL, NULL, obj->type->size);
|
|
}
|
|
|
|
for (ivar = TYPE_CLASS(di->thetype)->ivars; ivar; ivar = ivar->next) {
|
|
ivar_obj = galloc(sizeof(Object));
|
|
*ivar_obj = *obj;
|
|
ivar_obj->name = ivar->name;
|
|
ivar_obj->type = ivar->type;
|
|
ivar_obj->qual = ivar->qual;
|
|
ivar_obj->datatype = DALIAS;
|
|
ivar_obj->u.alias.object = obj;
|
|
ivar_obj->u.alias.offset = ivar->offset;
|
|
ivar_obj->u.alias.member = NULL;
|
|
CScope_AddObject(cscope_current, ivar_obj->name, OBJ_BASE(ivar_obj));
|
|
}
|
|
}
|
|
|
|
void CParser_NewCallBackAction(Object *obj, TypeClass *tclass) {
|
|
CallbackAction *act = galloc(sizeof(CallbackAction));
|
|
act->next = callbackactions;
|
|
act->obj = obj;
|
|
act->tclass = tclass;
|
|
callbackactions = act;
|
|
obj->flags |= OBJECT_FLAGS_8;
|
|
}
|
|
|
|
void CParser_NewClassAction(TypeClass *tclass) {
|
|
struct ClassAction *act = galloc(sizeof(struct ClassAction));
|
|
act->next = cparser_classactions;
|
|
act->tclass = tclass;
|
|
cparser_classactions = act;
|
|
}
|
|
|
|
void CParser_CallBackAction(Object *obj) {
|
|
CallbackAction *act;
|
|
|
|
for (act = callbackactions; act; act = act->next) {
|
|
if (act->obj == obj) {
|
|
CParser_NewClassAction(act->tclass);
|
|
return;
|
|
}
|
|
}
|
|
|
|
CError_FATAL(4551);
|
|
}
|
|
|
|
static Object *CParser_FindOverloadFunc(NameSpaceObjectList *list, TypeFunc *tfunc) {
|
|
while (list) {
|
|
if (list->object->otype == OT_OBJECT && IS_TYPE_FUNC(OBJECT(list->object)->type))
|
|
if (CParser_CompareArgLists(tfunc->args, TYPE_FUNC(OBJECT(list->object)->type)->args) == 1)
|
|
return OBJECT(list->object);
|
|
list = list->next;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
Object *CParser_ParseObject(void) {
|
|
DeclInfo di;
|
|
CScopeParseResult pr;
|
|
NameSpaceObjectList *list;
|
|
Object *obj;
|
|
|
|
memclrw(&di, sizeof(DeclInfo));
|
|
CParser_GetDeclSpecs(&di, 1);
|
|
scandeclarator(&di);
|
|
|
|
if (di.name && (list = CScope_FindObjectList(&pr, di.name))) {
|
|
if (list->object->otype == OT_OBJECT) {
|
|
if (IS_TYPE_FUNC(di.thetype))
|
|
return CParser_FindOverloadFunc(list, TYPE_FUNC(di.thetype));
|
|
|
|
if (is_typesame(di.thetype, OBJECT(list->object)->type) && OBJECT(list->object)->qual == di.qual)
|
|
return OBJECT(list->object);
|
|
|
|
obj = OBJECT(list->object);
|
|
CError_Error(CErrorStr249, CError_GetObjectName(obj), obj->type, obj->qual, di.thetype, di.qual);
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void CParser_ParseGlobalDeclaration(void) {
|
|
DeclInfo di;
|
|
|
|
if (tk) {
|
|
CPrep_NewFileOffsetInfo(&cparser_fileoffset, NULL);
|
|
symdecloffset = cparser_fileoffset.tokenline;
|
|
symdecltoken = *CPrep_CurStreamElement();
|
|
|
|
memclrw(&di, sizeof(DeclInfo));
|
|
CParser_GetDeclSpecs(&di, 1);
|
|
if (di.storageclass == TK_REGISTER || di.storageclass == TK_AUTO) {
|
|
CError_Error(CErrorStr177);
|
|
di.storageclass = 0;
|
|
}
|
|
|
|
if (tk != ';')
|
|
scandeclaratorlist(&di);
|
|
else
|
|
CParser_CheckAnonymousUnion(&di, 0);
|
|
|
|
tk = lex();
|
|
} else {
|
|
CError_Error(CErrorStr102);
|
|
}
|
|
}
|
|
|
|
static void CParser_ParseLinkageSpecification(DeclInfo *di) {
|
|
UInt32 r29;
|
|
UInt8 r28;
|
|
|
|
if (!strcmp(tkstring, "C") || !strcmp(tkstring, "Objective C")) {
|
|
r29 = 0;
|
|
r28 = 1;
|
|
} else if (!strcmp(tkstring, "C++")) {
|
|
r29 = 0;
|
|
r28 = 0;
|
|
} else if (!strcmp(tkstring, "Pascal")) {
|
|
r29 = 8;
|
|
r28 = 1;
|
|
} else {
|
|
CError_Error(CErrorStr121);
|
|
r29 = 0;
|
|
r28 = 1;
|
|
}
|
|
|
|
if ((tk = lex()) == '{') {
|
|
while (1) {
|
|
if ((tk = lex()) == 0) {
|
|
CError_Error(CErrorStr130);
|
|
return;
|
|
}
|
|
|
|
if (tk == '}')
|
|
break;
|
|
|
|
CPrep_NewFileOffsetInfo(&cparser_fileoffset, NULL);
|
|
symdecloffset = cparser_fileoffset.tokenline;
|
|
symdecltoken = *CPrep_CurStreamElement();
|
|
|
|
memclrw(di, sizeof(DeclInfo));
|
|
di->x4E = r28;
|
|
di->qual = r29;
|
|
CParser_ParseDeclaration(di);
|
|
}
|
|
} else if (tk == TK_EXTERN && copts.cpp_extensions && lookahead() == TK_STRING) {
|
|
tk = lex();
|
|
CParser_ParseLinkageSpecification(di);
|
|
} else {
|
|
memclrw(di, sizeof(DeclInfo));
|
|
di->x4E = r28;
|
|
di->qual = r29;
|
|
CParser_GetDeclSpecs(di, 1);
|
|
|
|
if (di->storageclass != TK_TYPEDEF) {
|
|
if (di->storageclass && copts.pedantic)
|
|
CError_Warning(CErrorStr177);
|
|
if (!di->storageclass)
|
|
di->storageclass = TK_EXTERN;
|
|
}
|
|
if (copts.cpp_extensions)
|
|
di->x48 = 0;
|
|
if (tk != ';')
|
|
scandeclaratorlist(di);
|
|
}
|
|
}
|
|
|
|
static void CParser_ParseNameSpace(DeclInfo *di) {
|
|
NameSpace *nspace;
|
|
ObjNameSpace *objns;
|
|
HashNameNode *name;
|
|
Boolean flag;
|
|
CScopeSave save;
|
|
NameSpaceObjectList *list;
|
|
NameSpaceList *nsl;
|
|
|
|
if ((tk = lex()) == TK_IDENTIFIER) {
|
|
name = tkidentifier;
|
|
flag = 0;
|
|
if ((tk = lex()) == '=') {
|
|
CScope_ParseNameSpaceAlias(name);
|
|
return;
|
|
}
|
|
} else {
|
|
if (tk != '{') {
|
|
CError_Error(CErrorStr107);
|
|
return;
|
|
}
|
|
name = CParser_GetUnnamedNameSpaceName();
|
|
flag = 1;
|
|
}
|
|
|
|
nspace = cscope_current;
|
|
if (!(list = CScope_FindName(nspace, name))) {
|
|
objns = galloc(sizeof(ObjNameSpace));
|
|
memclrw(objns, sizeof(ObjNameSpace));
|
|
objns->otype = OT_NAMESPACE;
|
|
objns->access = ACCESSPUBLIC;
|
|
if (flag) {
|
|
nspace = CScope_NewListNameSpace(name, 1);
|
|
nspace->is_unnamed = 1;
|
|
nsl = galloc(sizeof(NameSpaceList));
|
|
nsl->next = cscope_current->usings;
|
|
nsl->nspace = nspace;
|
|
cscope_current->usings = nsl;
|
|
} else {
|
|
nspace = CScope_NewHashNameSpace(name);
|
|
if (cscope_current->is_unnamed)
|
|
nspace->is_unnamed = 1;
|
|
}
|
|
|
|
nspace->parent = cscope_current;
|
|
objns->nspace = nspace;
|
|
CScope_AddObject(cscope_current, name, OBJ_BASE(objns));
|
|
} else {
|
|
if (list->object->otype != OT_NAMESPACE)
|
|
CError_Error(CErrorStr320);
|
|
else
|
|
nspace = OBJ_NAMESPACE(list->object)->nspace;
|
|
}
|
|
|
|
if (tk != '{') {
|
|
CError_Error(CErrorStr135);
|
|
return;
|
|
}
|
|
|
|
CScope_SetNameSpaceScope(nspace, &save);
|
|
while (1) {
|
|
if ((tk = lex()) == 0) {
|
|
CError_Error(CErrorStr130);
|
|
break;
|
|
}
|
|
|
|
if (tk == '}')
|
|
break;
|
|
|
|
CPrep_NewFileOffsetInfo(&cparser_fileoffset, NULL);
|
|
symdecloffset = cparser_fileoffset.tokenline;
|
|
symdecltoken = *CPrep_CurStreamElement();
|
|
|
|
memclrw(di, sizeof(DeclInfo));
|
|
CParser_ParseDeclaration(di);
|
|
}
|
|
CScope_RestoreScope(&save);
|
|
}
|
|
|
|
static void CParser_ParseDeclaration(DeclInfo *di) {
|
|
switch (tk) {
|
|
case TK_AT_INTERFACE:
|
|
CObjC_ParseInterface();
|
|
break;
|
|
case TK_AT_IMPLEMENTATION:
|
|
CObjC_ParseImplementation();
|
|
break;
|
|
case TK_AT_PROTOCOL:
|
|
CObjC_ParseProtocol();
|
|
break;
|
|
case TK_AT_CLASS:
|
|
CObjC_ParseClassDeclaration();
|
|
break;
|
|
case TK_NAMESPACE:
|
|
CParser_ParseNameSpace(di);
|
|
break;
|
|
case TK_EXPORT:
|
|
CError_Error(CErrorStr190);
|
|
if ((tk = lex()) != TK_TEMPLATE) {
|
|
CError_Error(CErrorStr121);
|
|
return;
|
|
}
|
|
case TK_TEMPLATE:
|
|
CTempl_Parse(NULL, 0);
|
|
break;
|
|
case TK_USING:
|
|
if ((tk = lex()) == TK_NAMESPACE) {
|
|
tk = lex();
|
|
CScope_ParseUsingDirective(cscope_current);
|
|
} else {
|
|
CScope_ParseUsingDeclaration(cscope_current, 0, 0);
|
|
}
|
|
break;
|
|
case TK_EXTERN:
|
|
if (copts.cplusplus) {
|
|
di->storageclass = TK_EXTERN;
|
|
if ((tk = lex()) == TK_STRING) {
|
|
CParser_ParseLinkageSpecification(di);
|
|
break;
|
|
}
|
|
}
|
|
default:
|
|
CParser_GetDeclSpecs(di, 1);
|
|
if ((di->storageclass == TK_REGISTER || di->storageclass == TK_AUTO) != 0) {
|
|
CError_Error(CErrorStr177);
|
|
di->storageclass = 0;
|
|
}
|
|
if (tk != ';')
|
|
scandeclaratorlist(di);
|
|
else
|
|
CParser_CheckAnonymousUnion(di, 0);
|
|
CParser_GlobalCleanup(0);
|
|
}
|
|
}
|
|
|
|
void cparser(void) {
|
|
DeclInfo di;
|
|
|
|
if (copts.crippled && copts.optimizationlevel > 1) {
|
|
CError_Warning(CErrorStr385);
|
|
copts.optimizationlevel = 1;
|
|
CodeGen_UpdateOptimizerOptions();
|
|
CodeGen_UpdateBackEndOptions();
|
|
}
|
|
|
|
if ((tk = lex())) {
|
|
do {
|
|
CPrep_NewFileOffsetInfo(&cparser_fileoffset, NULL);
|
|
symdecloffset = cparser_fileoffset.tokenline;
|
|
symdecltoken = *CPrep_CurStreamElement();
|
|
|
|
memclrw(&di, sizeof(DeclInfo));
|
|
CParser_ParseDeclaration(&di);
|
|
} while (tk && (tk = lex()));
|
|
} else {
|
|
if (!copts.cplusplus && copts.ANSI_strict)
|
|
CError_Error(CErrorStr102);
|
|
}
|
|
|
|
CInit_DefineTentativeData();
|
|
copts.defer_codegen = 0;
|
|
CParser_GlobalCleanup(1);
|
|
|
|
if (cparamblkptr->isPrecompiling != 1) {
|
|
CInline_Finish();
|
|
CParser_GlobalCleanup(1);
|
|
}
|
|
|
|
CClass_GenThunks();
|
|
if (cparamblkptr->isPrecompiling != 1)
|
|
CObjC_GenerateModule();
|
|
|
|
CSOM_Cleanup();
|
|
CInit_DefineTentativeData();
|
|
}
|