Add template algorithm sort
This commit is contained in:
parent
ae2fbb6256
commit
50cc2afb52
|
@ -0,0 +1,37 @@
|
|||
#ifndef OPP_ALGORITHM_H
|
||||
#define OPP_ALGORITHM_H
|
||||
|
||||
template <class T>
|
||||
inline void swap(T & x, T & y)
|
||||
{
|
||||
T t(x); x = y; y = t;
|
||||
}
|
||||
|
||||
template<class T, class LT>
|
||||
void sort(T s, T e)
|
||||
{
|
||||
while (s != e)
|
||||
{
|
||||
auto p = s;
|
||||
auto q = s;
|
||||
|
||||
q++;
|
||||
while (q != e)
|
||||
{
|
||||
if (LT(*q, *p))
|
||||
{
|
||||
swap(*q, *p);
|
||||
p++;
|
||||
swap(*q, *p);
|
||||
}
|
||||
q++;
|
||||
}
|
||||
|
||||
sort<T, LT>(s, p);
|
||||
p++;
|
||||
s = p;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -16,6 +16,11 @@ static inline char sstrlen(const char * sp)
|
|||
return n;
|
||||
}
|
||||
|
||||
inline void swap(string & u, string & v)
|
||||
{
|
||||
char * p = u.cstr; u.cstr = v.cstr; v.cstr = p;
|
||||
}
|
||||
|
||||
string::string(void) : cstr(nullptr)
|
||||
{}
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@ class string
|
|||
private:
|
||||
char * cstr;
|
||||
|
||||
friend void swap(string & u, string & v);
|
||||
|
||||
public:
|
||||
string(void);
|
||||
string(const string & s);
|
||||
|
@ -70,6 +72,8 @@ protected:
|
|||
string(char l, char * b);
|
||||
};
|
||||
|
||||
void swap(string & u, string & v);
|
||||
|
||||
#pragma compile("string.cpp")
|
||||
|
||||
#endif
|
||||
|
|
|
@ -70,6 +70,36 @@ public:
|
|||
return _data[at];
|
||||
}
|
||||
|
||||
T * begin(void)
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
|
||||
const T * begin(void) const
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
|
||||
const T * cbegin(void) const
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
|
||||
T * end(void)
|
||||
{
|
||||
return _data + _size;
|
||||
}
|
||||
|
||||
const T * end(void) const
|
||||
{
|
||||
return _data + _size;
|
||||
}
|
||||
|
||||
const T * cend(void) const
|
||||
{
|
||||
return _data + _size;
|
||||
}
|
||||
|
||||
T & front(void)
|
||||
{
|
||||
return _data[0];
|
||||
|
|
|
@ -842,7 +842,7 @@ Declaration::Declaration(const Location& loc, DecType type)
|
|||
mDefaultConstructor(nullptr), mDestructor(nullptr), mCopyConstructor(nullptr), mCopyAssignment(nullptr),
|
||||
mVectorConstructor(nullptr), mVectorDestructor(nullptr), mVectorCopyConstructor(nullptr), mVectorCopyAssignment(nullptr),
|
||||
mVTable(nullptr), mTemplate(nullptr),
|
||||
mVarIndex(-1), mLinkerObject(nullptr), mCallers(nullptr), mCalled(nullptr), mAlignment(1),
|
||||
mVarIndex(-1), mLinkerObject(nullptr), mCallers(nullptr), mCalled(nullptr), mAlignment(1), mFriends(nullptr),
|
||||
mInteger(0), mNumber(0), mMinValue(-0x80000000LL), mMaxValue(0x7fffffffLL), mFastCallBase(0), mFastCallSize(0), mStride(0), mStripe(1),
|
||||
mCompilerOptions(0), mUseCount(0), mTokens(nullptr), mParser(nullptr)
|
||||
{}
|
||||
|
@ -947,6 +947,10 @@ const Ident* Declaration::MangleIdent(void)
|
|||
sprintf_s(buffer, "%d", (int)mInteger);
|
||||
mMangleIdent = Ident::Unique(buffer);
|
||||
}
|
||||
else if (mType == DT_CONST_FUNCTION)
|
||||
{
|
||||
mMangleIdent = mQualIdent;
|
||||
}
|
||||
else if (mType == DT_TYPE_INTEGER)
|
||||
{
|
||||
char buffer[20];
|
||||
|
@ -1532,7 +1536,7 @@ bool Declaration::IsTemplateSameParams(const Declaration* dec, const Declaration
|
|||
|
||||
bool Declaration::IsSameParams(const Declaration* dec) const
|
||||
{
|
||||
if (mType == DT_TYPE_FUNCTION && dec->mType == DT_TYPE_FUNCTION || mType == DT_TEMPLATE && dec->mType == DT_TEMPLATE)
|
||||
if (mType == DT_TYPE_FUNCTION && dec->mType == DT_TYPE_FUNCTION)
|
||||
{
|
||||
Declaration* ld = mParams, * rd = dec->mParams;
|
||||
while (ld && rd)
|
||||
|
@ -1545,6 +1549,24 @@ bool Declaration::IsSameParams(const Declaration* dec) const
|
|||
|
||||
return !ld && !rd;
|
||||
}
|
||||
else if (mType == DT_TEMPLATE && dec->mType == DT_TEMPLATE)
|
||||
{
|
||||
Declaration* ld = mParams, * rd = dec->mParams;
|
||||
while (ld && rd)
|
||||
{
|
||||
if (ld->mType == DT_CONST_FUNCTION && rd->mType == DT_CONST_FUNCTION)
|
||||
{
|
||||
if (ld->mValue != rd->mValue)
|
||||
return false;
|
||||
}
|
||||
else if (!ld->mBase->IsSame(rd->mBase))
|
||||
return false;
|
||||
ld = ld->mNext;
|
||||
rd = rd->mNext;
|
||||
}
|
||||
|
||||
return !ld && !rd;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -272,7 +272,7 @@ public:
|
|||
TokenSequence * mTokens;
|
||||
Parser * mParser;
|
||||
|
||||
GrowingArray<Declaration*> mCallers, mCalled;
|
||||
GrowingArray<Declaration*> mCallers, mCalled, mFriends;
|
||||
|
||||
bool CanAssign(const Declaration* fromType) const;
|
||||
bool IsSame(const Declaration* dec) const;
|
||||
|
|
|
@ -162,6 +162,28 @@ InterCodeGenerator::ExValue InterCodeGenerator::CoerceType(InterCodeProcedure* p
|
|||
{
|
||||
mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_TYPES, "Cannot assign numeric value to pointer");
|
||||
}
|
||||
else if( type->mType == DT_TYPE_BOOL && v.mType->mType == DT_TYPE_POINTER)
|
||||
{
|
||||
InterInstruction* zins = new InterInstruction(exp->mLocation, IC_CONSTANT);
|
||||
zins->mDst.mType = IT_POINTER;
|
||||
zins->mDst.mTemp = proc->AddTemporary(IT_POINTER);
|
||||
zins->mConst.mType = IT_POINTER;
|
||||
zins->mConst.mMemory = IM_ABSOLUTE;
|
||||
zins->mConst.mIntConst = 0;
|
||||
block->Append(zins);
|
||||
|
||||
InterInstruction* cins = new InterInstruction(exp->mLocation, IC_RELATIONAL_OPERATOR);
|
||||
cins->mOperator = IA_CMPNE;
|
||||
cins->mSrc[0].mType = IT_POINTER;
|
||||
cins->mSrc[0].mTemp = v.mTemp;
|
||||
cins->mSrc[1].mType = IT_POINTER;
|
||||
cins->mSrc[1].mTemp = zins->mDst.mTemp;
|
||||
cins->mDst.mType = IT_BOOL;
|
||||
cins->mDst.mTemp = proc->AddTemporary(IT_BOOL);
|
||||
block->Append(cins);
|
||||
v.mTemp = cins->mDst.mTemp;
|
||||
v.mType = type;
|
||||
}
|
||||
else if (v.mType->mSize < type->mSize)
|
||||
{
|
||||
if (v.mType->mSize == 1 && type->mSize == 2)
|
||||
|
@ -3697,6 +3719,8 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration*
|
|||
|
||||
if (!procType->mBase || procType->mBase->mType == DT_TYPE_VOID)
|
||||
mErrors->Error(exp->mLocation, EERR_INVALID_RETURN, "Function has void return type");
|
||||
else if (procType->mBase->mType == DT_TYPE_BOOL && (vr.mType->IsIntegerType() || vr.mType->mType == DT_TYPE_POINTER))
|
||||
;
|
||||
else if (!procType->mBase->CanAssign(vr.mType))
|
||||
mErrors->Error(exp->mLocation, EERR_INVALID_RETURN, "Cannot return incompatible type");
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ Parser::Parser(Errors* errors, Scanner* scanner, CompilationUnits* compilationUn
|
|||
mInlineCall = false;
|
||||
mCompilerOptionSP = 0;
|
||||
mThisPointer = nullptr;
|
||||
mFunction = nullptr;
|
||||
|
||||
for (int i = 0; i < 256; i++)
|
||||
mCharMap[i] = i;
|
||||
|
@ -248,6 +249,13 @@ Declaration* Parser::ParseStructDeclaration(uint64 flags, DecType dt)
|
|||
flags |= DTF_PRIVATE | DTF_PROTECTED;
|
||||
ConsumeToken(TK_COLON);
|
||||
}
|
||||
else if (ConsumeTokenIf(TK_FRIEND))
|
||||
{
|
||||
mScope = oscope;
|
||||
Declaration* fdec = ParseDeclaration(nullptr, true, false);
|
||||
dec->mFriends.Push(fdec);
|
||||
mScope = dec->mScope;
|
||||
}
|
||||
else if (ConsumeTokenIf(TK_CLOSE_BRACE))
|
||||
{
|
||||
break;
|
||||
|
@ -3210,7 +3218,7 @@ void Parser::ParseVariableInit(Declaration* ndec)
|
|||
mErrors->Error(pexp->mLocation, EERR_INCOMPATIBLE_TYPES, "Can not initialize variable with expression", ndec->mIdent);
|
||||
}
|
||||
|
||||
Declaration* Parser::ParseDeclaration(Declaration * pdec, bool variable, bool expression, Declaration* pthis)
|
||||
Declaration* Parser::ParseDeclaration(Declaration * pdec, bool variable, bool expression, Declaration* pthis, Declaration* ptempl)
|
||||
{
|
||||
bool definingType = false, destructor = false;
|
||||
uint64 storageFlags = 0, typeFlags = 0;
|
||||
|
@ -3734,14 +3742,30 @@ Declaration* Parser::ParseDeclaration(Declaration * pdec, bool variable, bool ex
|
|||
}
|
||||
else
|
||||
{
|
||||
if (ndec->mBase->mType == DT_TYPE_FUNCTION && pthis)
|
||||
if (ptempl)
|
||||
ptempl->mBase = ndec;
|
||||
|
||||
if (ptempl && mTemplateScope && ndec->mIdent)
|
||||
{
|
||||
if (ConsumeTokenIf(TK_CONST))
|
||||
PrependThisArgument(ndec->mBase, pthis->mBase->ToConstType()->BuildConstPointer(ndec->mLocation));
|
||||
else
|
||||
PrependThisArgument(ndec->mBase, pthis);
|
||||
if (!strstr(ndec->mQualIdent->mString, mTemplateScope->mName->mString))
|
||||
{
|
||||
ndec->mIdent = ndec->mIdent->Mangle(mTemplateScope->mName->mString);
|
||||
ndec->mQualIdent = ndec->mQualIdent->Mangle(mTemplateScope->mName->mString);
|
||||
}
|
||||
}
|
||||
|
||||
if (ndec->mBase->mType == DT_TYPE_FUNCTION)
|
||||
{
|
||||
if (pthis)
|
||||
{
|
||||
if (ConsumeTokenIf(TK_CONST))
|
||||
PrependThisArgument(ndec->mBase, pthis->mBase->ToConstType()->BuildConstPointer(ndec->mLocation));
|
||||
else
|
||||
PrependThisArgument(ndec->mBase, pthis);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (variable)
|
||||
{
|
||||
ndec->mFlags |= storageFlags;
|
||||
|
@ -3776,11 +3800,15 @@ Declaration* Parser::ParseDeclaration(Declaration * pdec, bool variable, bool ex
|
|||
if (ndec->mIdent == ndec->mQualIdent)
|
||||
{
|
||||
Declaration* ldec = mScope->Insert(ndec->mIdent, pdec ? pdec : ndec);
|
||||
#if 0
|
||||
if (ldec && ldec->mTemplate && mTemplateScope)
|
||||
{
|
||||
ndec->mQualIdent = ndec->mQualIdent->Mangle(mTemplateScope->mName->mString);
|
||||
}
|
||||
else if (ldec && ldec != pdec)
|
||||
else
|
||||
#endif
|
||||
|
||||
if (ldec && ldec != pdec)
|
||||
mErrors->Error(ndec->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate definition");
|
||||
}
|
||||
else if (!pdec)
|
||||
|
@ -4085,14 +4113,16 @@ Declaration* Parser::ParseDeclaration(Declaration * pdec, bool variable, bool ex
|
|||
if (ndec->mBase->mType == DT_TYPE_FUNCTION)
|
||||
{
|
||||
if (ndec->mFlags & DTF_DEFINED)
|
||||
mErrors->Error(mScanner->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate function definition");
|
||||
mErrors->Error(mScanner->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate function definition", ndec->mQualIdent);
|
||||
|
||||
ndec->mCompilerOptions = mCompilerOptions;
|
||||
ndec->mBase->mCompilerOptions = mCompilerOptions;
|
||||
|
||||
ndec->mVarIndex = -1;
|
||||
|
||||
mFunction = ndec;
|
||||
ndec->mValue = ParseFunction(ndec->mBase);
|
||||
mFunction = nullptr;
|
||||
|
||||
if (pthis)
|
||||
ndec->mFlags |= DTF_REQUEST_INLINE;
|
||||
|
@ -4309,6 +4339,10 @@ Expression* Parser::ParseSimpleExpression(bool lhs)
|
|||
exp = new Expression(mScanner->mLocation, EX_TYPE);
|
||||
exp->mDecValue = nullptr;
|
||||
exp->mDecType = ParseBaseTypeDeclaration(0, true);
|
||||
while (ConsumeTokenIf(TK_MUL))
|
||||
exp->mDecType = exp->mDecType->BuildPointer(mScanner->mLocation);
|
||||
while (ConsumeTokenIf(TK_BINARY_AND))
|
||||
exp->mDecType = exp->mDecType->BuildReference(mScanner->mLocation);
|
||||
}
|
||||
break;
|
||||
case TK_CONST:
|
||||
|
@ -4555,6 +4589,10 @@ Expression* Parser::ParseSimpleExpression(bool lhs)
|
|||
exp = new Expression(mScanner->mLocation, EX_TYPE);
|
||||
exp->mDecValue = nullptr;
|
||||
exp->mDecType = dec;
|
||||
while (ConsumeTokenIf(TK_MUL))
|
||||
exp->mDecType = exp->mDecType->BuildPointer(mScanner->mLocation);
|
||||
while (ConsumeTokenIf(TK_BINARY_AND))
|
||||
exp->mDecType = exp->mDecType->BuildReference(mScanner->mLocation);
|
||||
}
|
||||
}
|
||||
else if (dec->mType == DT_ELEMENT)
|
||||
|
@ -4737,7 +4775,12 @@ Expression* Parser::ParseQualify(Expression* exp)
|
|||
if (tp && tp->mType == DT_ARGUMENT)
|
||||
tp = tp->mBase;
|
||||
if (!(tp && tp->mBase->IsConstSame(dtype)))
|
||||
mErrors->Error(mScanner->mLocation, EERR_OBJECT_NOT_FOUND, "Struct member identifier not visible", ident);
|
||||
{
|
||||
if (dtype->mFriends.Contains(mFunction))
|
||||
;
|
||||
else
|
||||
mErrors->Error(mScanner->mLocation, EERR_OBJECT_NOT_FOUND, "Struct member identifier not visible", ident);
|
||||
}
|
||||
}
|
||||
|
||||
mScanner->NextToken();
|
||||
|
@ -4952,7 +4995,13 @@ int Parser::OverloadDistance(Declaration* fdec, Expression* pexp)
|
|||
else if (ptype->IsSame(ex->mDecType))
|
||||
;
|
||||
else if (CanCoerceExpression(ex, ptype))
|
||||
{
|
||||
dist += 512;
|
||||
if (ptype->mType == DT_TYPE_REFERENCE)
|
||||
dist += 4;
|
||||
else if (ptype->mType == DT_TYPE_RVALUEREF)
|
||||
dist += 2;
|
||||
}
|
||||
else if (ptype->mType == DT_TYPE_REFERENCE && ptype->mBase->mType == DT_TYPE_STRUCT && etype->mType == DT_TYPE_STRUCT)
|
||||
{
|
||||
if (ex->IsLValue())
|
||||
|
@ -5247,7 +5296,9 @@ Expression * Parser::ResolveOverloadCall(Expression* exp, Expression* exp2)
|
|||
while (fdec)
|
||||
{
|
||||
int d = OverloadDistance(fdec, exp->mRight);
|
||||
if (d < ibest)
|
||||
if (d == NOOVERLOAD)
|
||||
;
|
||||
else if (d < ibest)
|
||||
{
|
||||
dbest = fdec;
|
||||
pbest = exp->mRight;
|
||||
|
@ -5262,7 +5313,9 @@ Expression * Parser::ResolveOverloadCall(Expression* exp, Expression* exp2)
|
|||
while (fdec2)
|
||||
{
|
||||
int d = OverloadDistance(fdec2, exp2->mRight);
|
||||
if (d < ibest)
|
||||
if (d == NOOVERLOAD)
|
||||
;
|
||||
else if (d < ibest)
|
||||
{
|
||||
dbest = fdec2;
|
||||
pbest = exp2->mRight;
|
||||
|
@ -6244,6 +6297,9 @@ Expression* Parser::CheckOperatorOverload(Expression* exp)
|
|||
if (exp->mType == EX_ASSIGNMENT)
|
||||
{
|
||||
Declaration* tdec = exp->mLeft->mDecType;
|
||||
while (tdec->mType == DT_TYPE_REFERENCE || tdec->mType == DT_TYPE_RVALUEREF)
|
||||
tdec = tdec->mBase;
|
||||
|
||||
if (tdec->mType == DT_TYPE_STRUCT)
|
||||
{
|
||||
const Ident* opident = nullptr;
|
||||
|
@ -6320,7 +6376,7 @@ Expression* Parser::CheckOperatorOverload(Expression* exp)
|
|||
texp->mLeft = exp->mLeft;
|
||||
texp->mDecType = new Declaration(nexp->mLocation, DT_TYPE_POINTER);
|
||||
texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED;
|
||||
texp->mDecType->mBase = exp->mDecType;
|
||||
texp->mDecType->mBase = tdec;
|
||||
texp->mDecType->mSize = 2;
|
||||
|
||||
Expression* lexp = new Expression(nexp->mLocation, EX_LIST);
|
||||
|
@ -7138,7 +7194,10 @@ Expression* Parser::ParseStatement(void)
|
|||
exp = new Expression(mScanner->mLocation, EX_RETURN);
|
||||
if (mScanner->mToken != TK_SEMICOLON)
|
||||
{
|
||||
exp->mLeft = CleanupExpression(ParseRExpression());
|
||||
exp->mLeft = ParseRExpression();
|
||||
if (mReturnType)
|
||||
exp->mLeft = CoerceExpression(exp->mLeft, mReturnType);
|
||||
exp->mLeft = CleanupExpression(exp->mLeft);
|
||||
if (exp->mLeft->mType == EX_CONSTRUCT && mReturnType && mReturnType->mType == DT_TYPE_STRUCT)
|
||||
{
|
||||
Expression* cexp = exp->mLeft->mLeft->mLeft;
|
||||
|
@ -7325,8 +7384,13 @@ Declaration* Parser::ParseTemplateExpansion(Declaration* tmpld, Declaration* exp
|
|||
{
|
||||
if (exp->mType == EX_TYPE)
|
||||
epdec->mBase = exp->mDecType;
|
||||
else if (exp->mType == EX_CONSTANT && exp->mDecValue->mType == DT_CONST_FUNCTION)
|
||||
epdec->mBase = exp->mDecValue;
|
||||
else
|
||||
{
|
||||
mErrors->Error(exp->mLocation, EERR_TEMPLATE_PARAMS, "Type parameter expected", pdec->mIdent);
|
||||
epdec->mBase = TheVoidTypeDeclaration;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -7367,14 +7431,13 @@ Declaration* Parser::ParseTemplateExpansion(Declaration* tmpld, Declaration* exp
|
|||
p->mScanner->Replay(tmpld->mTokens);
|
||||
|
||||
tdec->mScope->mName = tdec->MangleIdent();
|
||||
|
||||
p->mTemplateScope = tdec->mScope;
|
||||
tdec->mBase = p->ParseDeclaration(nullptr, true, false);
|
||||
p->mTemplateScope = nullptr;
|
||||
|
||||
tdec->mNext = tmpld->mNext;
|
||||
tmpld->mNext = tdec;
|
||||
|
||||
p->mTemplateScope = tdec->mScope;
|
||||
tdec->mBase = p->ParseDeclaration(nullptr, true, false, nullptr, tdec);
|
||||
p->mTemplateScope = nullptr;
|
||||
|
||||
if (tdec->mBase->mType == DT_ANON)
|
||||
{
|
||||
tdec->mBase = tdec->mBase->mBase;
|
||||
|
@ -7533,6 +7596,8 @@ void Parser::ParseTemplateDeclaration(void)
|
|||
// Function template
|
||||
mTemplateScope = tdec->mScope;
|
||||
|
||||
ConsumeTokenIf(TK_INLINE);
|
||||
|
||||
Declaration* bdec = ParseBaseTypeDeclaration(0, false);
|
||||
Declaration* adec = ParsePostfixDeclaration();
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ public:
|
|||
DeclarationScope * mGlobals, * mScope, * mTemplateScope;
|
||||
int mLocalIndex;
|
||||
CompilationUnits * mCompilationUnits;
|
||||
Declaration * mThisPointer, * mReturnType;
|
||||
Declaration * mThisPointer, * mReturnType, * mFunction;
|
||||
|
||||
LinkerSection * mCodeSection, * mDataSection, * mBSSection;
|
||||
|
||||
|
@ -58,7 +58,7 @@ protected:
|
|||
Expression* CleanupExpression(Expression* exp);
|
||||
|
||||
Declaration* ParseBaseTypeDeclaration(uint64 flags, bool qualified);
|
||||
Declaration* ParseDeclaration(Declaration* pdec, bool variable, bool expression, Declaration * pthis = nullptr);
|
||||
Declaration* ParseDeclaration(Declaration* pdec, bool variable, bool expression, Declaration * pthis = nullptr, Declaration * ptempl = nullptr);
|
||||
Declaration* ParseStructDeclaration(uint64 flags, DecType dt);
|
||||
|
||||
Declaration* CopyConstantInitializer(int offset, Declaration* dtype, Expression* exp);
|
||||
|
|
|
@ -163,6 +163,7 @@ const char* TokenNames[] =
|
|||
"'virtual'",
|
||||
"'operator'",
|
||||
"'template'",
|
||||
"'friend'",
|
||||
};
|
||||
|
||||
|
||||
|
@ -1511,6 +1512,8 @@ void Scanner::NextRawToken(void)
|
|||
mToken = TK_VIRTUAL;
|
||||
else if ((mCompilerOptions & COPT_CPLUSPLUS) && !strcmp(tkident, "template"))
|
||||
mToken = TK_TEMPLATE;
|
||||
else if ((mCompilerOptions & COPT_CPLUSPLUS) && !strcmp(tkident, "friend"))
|
||||
mToken = TK_FRIEND;
|
||||
else if ((mCompilerOptions & COPT_CPLUSPLUS) && !strcmp(tkident, "operator"))
|
||||
{
|
||||
NextRawToken();
|
||||
|
|
|
@ -162,6 +162,7 @@ enum Token
|
|||
TK_VIRTUAL,
|
||||
TK_OPERATOR,
|
||||
TK_TEMPLATE,
|
||||
TK_FRIEND,
|
||||
|
||||
NUM_TOKENS
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue