From b7630450f17a05ba678355ef82c00ee3597c4bc5 Mon Sep 17 00:00:00 2001 From: drmortalwombat <90205530+drmortalwombat@users.noreply.github.com> Date: Tue, 8 Aug 2023 14:19:08 +0200 Subject: [PATCH] Improve C++ compliance --- oscar64/Declaration.h | 2 + oscar64/Emulator.cpp | 6 + oscar64/Errors.h | 1 + oscar64/InterCode.cpp | 16 ++- oscar64/InterCodeGenerator.cpp | 3 + oscar64/Parser.cpp | 252 +++++++++++++++++++++++++++++++-- oscar64/Parser.h | 3 + oscar64/Scanner.cpp | 65 +++++++++ oscar64/Scanner.h | 27 +++- 9 files changed, 358 insertions(+), 17 deletions(-) diff --git a/oscar64/Declaration.h b/oscar64/Declaration.h index 89075ca..2788596 100644 --- a/oscar64/Declaration.h +++ b/oscar64/Declaration.h @@ -51,6 +51,8 @@ enum DecType DT_NAMESPACE, DT_BASECLASS, + DT_TEMPLATE, + DT_VTABLE }; diff --git a/oscar64/Emulator.cpp b/oscar64/Emulator.cpp index c7f1bdf..7bc4421 100644 --- a/oscar64/Emulator.cpp +++ b/oscar64/Emulator.cpp @@ -545,6 +545,12 @@ int Emulator::Emulate(int startIP, int trace) mIP = mMemory[0x101 + mRegS] + 256 * mMemory[0x102 + mRegS] + 1; mRegS += 2; } + else if (mIP == 0xff81) + { + printf("------------------ CLEAR ---------------\n"); + mIP = mMemory[0x101 + mRegS] + 256 * mMemory[0x102 + mRegS] + 1; + mRegS += 2; + } uint8 opcode = mMemory[mIP]; AsmInsData d = DecInsData[opcode]; diff --git a/oscar64/Errors.h b/oscar64/Errors.h index 1813cfc..157de78 100644 --- a/oscar64/Errors.h +++ b/oscar64/Errors.h @@ -80,6 +80,7 @@ enum ErrorID EERR_INVALID_OPERATOR, EERR_MISSING_TEMP, EERR_NON_STATIC_MEMBER, + EERR_TEMPLATE_PARAMS, ERRR_STACK_OVERFLOW, ERRR_INVALID_NUMBER, diff --git a/oscar64/InterCode.cpp b/oscar64/InterCode.cpp index 31222ad..06b6ed9 100644 --- a/oscar64/InterCode.cpp +++ b/oscar64/InterCode.cpp @@ -13420,6 +13420,18 @@ void InterCodeBasicBlock::SingleBlockLoopOptimisation(const NumberSet& aliasedPa sins->mSrc[0].mFinal = false; assert(nins->mSrc[0].mTemp >= 0); + // Propagate all loads to move temps + + for (int t = j + 1; t < mInstructions.Size(); t++) + { + InterInstruction* ti = mInstructions[t]; + if (ti->mCode == IC_LOAD && SameMem(ti->mSrc[0], ins->mSrc[0])) + { + ti->mCode = IC_LOAD_TEMPORARY; + ti->mSrc[0].mTemp = ins->mDst.mTemp; + } + } + // Move store behind loop tailBlock->mInstructions.Insert(0, sins); mInstructions.Remove(j); @@ -16724,7 +16736,7 @@ void InterCodeProcedure::Close(void) { GrowingTypeArray tstack(IT_NONE); - CheckFunc = !strcmp(mIdent->mString, "playSong"); + CheckFunc = !strcmp(mIdent->mString, "MenuItem::+MenuItem"); mEntryBlock = mBlocks[0]; @@ -16899,6 +16911,8 @@ void InterCodeProcedure::Close(void) TempForwarding(); RemoveUnusedInstructions(); + DisassembleDebug("pre single block loop opt"); + ResetVisited(); mEntryBlock->SingleBlockLoopOptimisation(mParamAliasedSet, mModule->mGlobalVars); diff --git a/oscar64/InterCodeGenerator.cpp b/oscar64/InterCodeGenerator.cpp index 3b61f44..7663feb 100644 --- a/oscar64/InterCodeGenerator.cpp +++ b/oscar64/InterCodeGenerator.cpp @@ -4111,6 +4111,9 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* vr = Dereference(proc, exp, block, vr); return CoerceType(proc, exp, block, vr, exp->mDecType); } + else if (exp->mDecType->mType == DT_TYPE_VOID) + { + } else { vr = Dereference(proc, exp, block, vr); diff --git a/oscar64/Parser.cpp b/oscar64/Parser.cpp index 8688095..e424e98 100644 --- a/oscar64/Parser.cpp +++ b/oscar64/Parser.cpp @@ -284,6 +284,15 @@ Declaration* Parser::ParseStructDeclaration(uint64 flags, DecType dt) if (dec->mScope->Insert(mdec->mIdent, mdec)) mErrors->Error(mdec->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate struct member declaration", mdec->mIdent); + if (dec->mConst) + { + Declaration* cmdec = mdec->Clone(); + cmdec->mBase = mdec->mBase->ToConstType(); + + dec->mConst->mScope->Insert(cmdec->mIdent, cmdec); + dec->mConst->mSize = dec->mSize; + } + if (mlast) mlast->mNext = mdec; else @@ -442,6 +451,7 @@ Declaration* Parser::ParseStructDeclaration(uint64 flags, DecType dt) Declaration* Parser::ParseBaseTypeDeclaration(uint64 flags, bool qualified) { Declaration* dec = nullptr; + const Ident* pident = nullptr; switch (mScanner->mToken) { @@ -551,6 +561,7 @@ Declaration* Parser::ParseBaseTypeDeclaration(uint64 flags, bool qualified) break; case TK_IDENT: + pident = mScanner->mTokenIdent; dec = mScope->Lookup(mScanner->mTokenIdent); if (dec && dec->mType == DT_CONST_FUNCTION && mScope->mLevel == SLEVEL_CLASS) dec = mScope->mParent->Lookup(mScanner->mTokenIdent); @@ -560,6 +571,7 @@ Declaration* Parser::ParseBaseTypeDeclaration(uint64 flags, bool qualified) { if (ExpectToken(TK_IDENT)) { + pident = mScanner->mTokenIdent; dec = dec->mScope->Lookup(mScanner->mTokenIdent); mScanner->NextToken(); } @@ -594,15 +606,9 @@ Declaration* Parser::ParseBaseTypeDeclaration(uint64 flags, bool qualified) } } else if (!dec) - { - mErrors->Error(mScanner->mLocation, EERR_OBJECT_NOT_FOUND, "Identifier not defined", mScanner->mTokenIdent); - mScanner->NextToken(); - } + mErrors->Error(mScanner->mLocation, EERR_OBJECT_NOT_FOUND, "Identifier not defined", pident); else - { - mErrors->Error(mScanner->mLocation, EERR_NOT_A_TYPE, "Identifier is no type", mScanner->mTokenIdent); - mScanner->NextToken(); - } + mErrors->Error(mScanner->mLocation, EERR_NOT_A_TYPE, "Identifier is no type", dec->mQualIdent); break; case TK_ENUM: @@ -3424,6 +3430,21 @@ Declaration* Parser::ParseDeclaration(Declaration * pdec, bool variable, bool ex if (mScanner->mToken == TK_OPEN_BRACE) { + // + // Take parameter names from new declaration + // + Declaration* npdec = ctdec->mParams, * ppdec = cdec->mBase->mParams; + while (npdec && ppdec) + { + if (npdec->mIdent) + { + ppdec->mIdent = npdec->mIdent; + ppdec->mQualIdent = npdec->mQualIdent; + } + npdec = npdec->mNext; + ppdec = ppdec->mNext; + } + if (cdec->mFlags & DTF_DEFINED) mErrors->Error(cdec->mLocation, EERR_DUPLICATE_DEFINITION, "Function already has a body"); @@ -4001,7 +4022,7 @@ Expression* Parser::ParseDeclarationExpression(Declaration * pdec) texp->mLeft = vexp; texp->mDecType = new Declaration(mScanner->mLocation, DT_TYPE_POINTER); texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED; - texp->mDecType->mBase = pdec->mBase; + texp->mDecType->mBase = dec->mBase; texp->mDecType->mSize = 2; Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT); @@ -4014,12 +4035,13 @@ Expression* Parser::ParseDeclarationExpression(Declaration * pdec) Expression* aexp; - if (dec->mBase->mCopyConstructor && !(dec->mValue->mType == EX_CALL && dec->mValue->mDecType->mType == DT_TYPE_STRUCT)) + Declaration* fcons = dec->mBase->mScope->Lookup(dec->mBase->mIdent->PreMangle("+")); + + if (fcons && !(dec->mValue->mType == EX_CALL && dec->mValue->mDecType->mType == DT_TYPE_STRUCT)) { - Declaration* mdec = dec->mBase->mCopyConstructor; Expression* cexp = new Expression(dec->mLocation, EX_CONSTANT); - cexp->mDecValue = mdec; + cexp->mDecValue = fcons; cexp->mDecType = cexp->mDecValue->mBase; aexp = new Expression(mScanner->mLocation, EX_CALL); @@ -4027,6 +4049,8 @@ Expression* Parser::ParseDeclarationExpression(Declaration * pdec) aexp->mRight = new Expression(dec->mLocation, EX_LIST); aexp->mRight->mLeft = texp; aexp->mRight->mRight = dec->mValue; + + ResolveOverloadCall(aexp); } else { @@ -4710,6 +4734,8 @@ int Parser::OverloadDistance(Declaration* fdec, Expression* pexp) dist += 4; else if (ptype->IsSame(ex->mDecType)) ; + else if (CanCoerceExpression(ex, ptype)) + dist += 512; else if (ptype->mType == DT_TYPE_REFERENCE && ptype->mBase->mType == DT_TYPE_STRUCT && etype->mType == DT_TYPE_STRUCT) { int ncast = 0; @@ -4771,12 +4797,52 @@ int Parser::OverloadDistance(Declaration* fdec, Expression* pexp) return dist; } +bool Parser::CanCoerceExpression(Expression* exp, Declaration* type) +{ + Declaration* tdec = exp->mDecType; + while (tdec->mType == DT_TYPE_REFERENCE) + tdec = tdec->mBase; + while (type->mType == DT_TYPE_REFERENCE) + type = type->mBase; + + if (tdec->mType == DT_TYPE_STRUCT) + { + Declaration* fexp = tdec->mScope->Lookup(Ident::Unique("(cast)")); + if (fexp) + { + while (fexp && !fexp->mBase->mBase->IsSame(type)) + fexp = fexp->mNext; + if (fexp) + return true; + } + } + + if (type->mType == DT_TYPE_STRUCT) + { + if (!type->IsConstSame(tdec)) + { + Declaration* fcons = type->mScope->Lookup(type->mIdent->PreMangle("+")); + if (fcons) + { + while (fcons && !(fcons->mBase->mParams && fcons->mBase->mParams->mNext && !fcons->mBase->mParams->mNext->mNext && fcons->mBase->mParams->mNext->mBase->CanAssign(tdec))) + fcons = fcons->mNext; + + if (fcons) + return true; + } + } + } + + return false; +} + Expression* Parser::CoerceExpression(Expression* exp, Declaration* type) { Declaration* tdec = exp->mDecType; while (tdec->mType == DT_TYPE_REFERENCE) tdec = tdec->mBase; - + while (type->mType == DT_TYPE_REFERENCE) + type = type->mBase; if (tdec->mType == DT_TYPE_STRUCT) { @@ -4802,6 +4868,78 @@ Expression* Parser::CoerceExpression(Expression* exp, Declaration* type) } } } + + if (type->mType == DT_TYPE_STRUCT) + { + if (!type->IsConstSame(tdec)) + { + Declaration* fcons = type->mScope->Lookup(type->mIdent->PreMangle("+")); + if (fcons) + { + while (fcons && !(fcons->mBase->mParams && fcons->mBase->mParams->mNext && !fcons->mBase->mParams->mNext->mNext && fcons->mBase->mParams->mNext->mBase->CanAssign(tdec))) + fcons = fcons->mNext; + + if (fcons) + { + Declaration* vdec = new Declaration(mScanner->mLocation, DT_VARIABLE); + + vdec->mBase = type->ToMutableType(); + vdec->mVarIndex = mLocalIndex++; + vdec->mSize = type->mSize; + vdec->mFlags |= DTF_DEFINED; + + Expression* vexp = new Expression(mScanner->mLocation, EX_VARIABLE); + vexp->mDecType = vdec->mBase; + vexp->mDecValue = vdec; + + Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT); + cexp->mDecValue = fcons; + cexp->mDecType = cexp->mDecValue->mBase; + + Expression* fexp = new Expression(mScanner->mLocation, EX_CALL); + fexp->mLeft = cexp; + + fexp->mRight = exp; + + Expression* texp = new Expression(mScanner->mLocation, EX_PREFIX); + texp->mToken = TK_BINARY_AND; + texp->mLeft = vexp; + texp->mDecType = new Declaration(mScanner->mLocation, DT_TYPE_POINTER); + texp->mDecType->mFlags |= DTF_CONST | DTF_DEFINED; + texp->mDecType->mBase = vdec->mBase; + texp->mDecType->mSize = 2; + + Expression* lexp = new Expression(mScanner->mLocation, EX_LIST); + lexp->mLeft = texp; + lexp->mRight = fexp->mRight; + fexp->mRight = lexp; + + Expression* dexp = nullptr; + if (type->mDestructor) + { + Expression* cexp = new Expression(mScanner->mLocation, EX_CONSTANT); + cexp->mDecValue = type->mDestructor; + cexp->mDecType = cexp->mDecValue->mBase; + + dexp = new Expression(mScanner->mLocation, EX_CALL); + dexp->mLeft = cexp; + dexp->mRight = texp; + } + + Expression* nexp = new Expression(mScanner->mLocation, EX_CONSTRUCT); + + nexp->mLeft = new Expression(mScanner->mLocation, EX_LIST); + nexp->mLeft->mLeft = fexp; + nexp->mLeft->mRight = dexp; + + nexp->mRight = vexp; + nexp->mDecType = vexp->mDecType; + + return nexp; + } + } + } + } return exp; } @@ -4817,13 +4955,19 @@ void Parser::CompleteFunctionDefaultParams(Expression* exp) { if (pexp) { + Expression* exp = pexp; + if (pexp->mType == EX_LIST) { + pexp->mLeft = CoerceExpression(pexp->mLeft, pdec->mBase); lexp = pexp; pexp = pexp->mRight; } else + { + lexp->mRight = CoerceExpression(lexp->mRight, pdec->mBase); pexp = nullptr; + } } else if (pdec->mValue) { @@ -4887,9 +5031,14 @@ Expression * Parser::ResolveOverloadCall(Expression* exp, Expression* exp2) } if (ibest == NOOVERLOAD) - mErrors->Error(exp->mLocation, ERRO_NO_MATCHING_FUNCTION_CALL, "No matching function call"); + { +#if _DEBUG + int d = OverloadDistance(exp->mLeft->mDecValue->mBase, exp->mRight); +#endif + mErrors->Error(exp->mLocation, ERRO_NO_MATCHING_FUNCTION_CALL, "No matching function call", exp->mLeft->mDecValue->mQualIdent); + } else if (nbest > 1) - mErrors->Error(exp->mLocation, ERRO_AMBIGUOUS_FUNCTION_CALL, "Ambiguous function call"); + mErrors->Error(exp->mLocation, ERRO_AMBIGUOUS_FUNCTION_CALL, "Ambiguous function call", exp->mLeft->mDecValue->mQualIdent); else { exp->mLeft->mDecValue = dbest; @@ -6831,6 +6980,69 @@ Expression* Parser::ParseSwitchStatement(void) return sexp; } +void Parser::ParseTemplate(void) +{ + ConsumeToken(TK_LESS_THAN); + Declaration* tdec = new Declaration(mScanner->mLocation, DT_TEMPLATE); + Declaration* ppdec = nullptr; + + for (;;) + { + Declaration* pdec = nullptr; + + if (ConsumeTokenIf(TK_CLASS)) + { + if (mScanner->mToken == TK_IDENT) + { + Declaration* pdec = new Declaration(mScanner->mLocation, DT_ARGUMENT); + pdec->mIdent = mScanner->mTokenIdent; + pdec->mBase = TheVoidTypeDeclaration; + mScanner->NextToken(); + } + else + mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "Identifier expected"); + } + else if (ConsumeTokenIf(TK_INT)) + { + if (mScanner->mToken == TK_IDENT) + { + Declaration* pdec = new Declaration(mScanner->mLocation, DT_ARGUMENT); + pdec->mIdent = mScanner->mTokenIdent; + pdec->mBase = TheSignedIntTypeDeclaration; + mScanner->NextToken(); + } + else + mErrors->Error(mScanner->mLocation, EERR_SYNTAX, "Identifier expected"); + } + else + mErrors->Error(mScanner->mLocation, EERR_TEMPLATE_PARAMS, "'class' or 'int' expected as template parameter"); + + if (pdec) + { + if (ppdec) + ppdec->mNext = pdec; + else + tdec->mParams = pdec; + ppdec = pdec; + } + + if (!ConsumeTokenIf(TK_COMMA)) + break; + } + + ConsumeToken(TK_GREATER_THAN); + + if (mScanner->mToken == TK_CLASS) + { + // Class template + + } + else + { + // Function template + + } +} Expression* Parser::ParseAssemblerBaseOperand(Declaration* pcasm, int pcoffset) @@ -7541,6 +7753,11 @@ void Parser::ParsePragma(void) } ConsumeToken(TK_CLOSE_PARENTHESIS); } + else if (!strcmp(mScanner->mTokenIdent->mString, "once")) + { + mScanner->MarkSourceOnce(); + mScanner->NextToken(); + } else if (!strcmp(mScanner->mTokenIdent->mString, "compile")) { mScanner->NextToken(); @@ -8453,6 +8670,11 @@ void Parser::Parse(void) } else if (mScanner->mToken == TK_SEMICOLON) mScanner->NextToken(); + else if (mScanner->mToken == TK_TEMPLATE) + { + mScanner->NextToken(); + ParseTemplate(); + } else if (mScanner->mToken == TK_NAMESPACE) { mScanner->NextToken(); diff --git a/oscar64/Parser.h b/oscar64/Parser.h index 608a1c0..81fa74b 100644 --- a/oscar64/Parser.h +++ b/oscar64/Parser.h @@ -90,8 +90,11 @@ protected: int OverloadDistance(Declaration* pdec, Expression* pexp); Expression * ResolveOverloadCall(Expression* exp, Expression * exp2 = nullptr); Expression* CoerceExpression(Expression* exp, Declaration* type); + bool CanCoerceExpression(Expression* exp, Declaration* type); void CompleteFunctionDefaultParams(Expression* exp); + void ParseTemplate(void); + Expression* ParseSimpleExpression(bool lhs); Expression* ParsePrefixExpression(bool lhs); Expression* ParsePostfixExpression(bool lhs); diff --git a/oscar64/Scanner.cpp b/oscar64/Scanner.cpp index c1541d6..07f60f4 100644 --- a/oscar64/Scanner.cpp +++ b/oscar64/Scanner.cpp @@ -162,6 +162,7 @@ const char* TokenNames[] = "'delete'", "'virtual'", "'operator'", + "'template'", }; @@ -306,6 +307,25 @@ Macro* MacroDict::Lookup(const Ident* ident) } +TokenSequence::TokenSequence(Scanner* scanner) + : mNext(nullptr), mLocation(scanner->mLocation), mToken(scanner->mToken), + mTokenIdent(scanner->mTokenIdent), mTokenChar(scanner->mTokenChar), + mTokenInteger(scanner->mTokenInteger), mTokenNumber(scanner->mTokenNumber), + mTokenString(nullptr) +{ + if (mToken == TK_STRING) + { + int ssize = strlen(scanner->mTokenString); + char * str = new char[ssize + 1]; + strcpy_s(str, ssize + 1, scanner->mTokenString); + mTokenString = str; + } +} + +TokenSequence::~TokenSequence(void) +{ + delete[] mTokenString; +} Scanner::Scanner(Errors* errors, Preprocessor* preprocessor) : mErrors(errors), mPreprocessor(preprocessor) @@ -324,6 +344,9 @@ Scanner::Scanner(Errors* errors, Preprocessor* preprocessor) mDefineArguments = nullptr; mToken = TK_NONE; mUngetToken = TK_NONE; + mReplay = nullptr; + + mOnceDict = new MacroDict(); NextChar(); @@ -336,6 +359,18 @@ Scanner::~Scanner(void) } +TokenSequence* Scanner::Record(void) +{ + return new TokenSequence(this); +} + +const TokenSequence* Scanner::Replay(const TokenSequence* replay) +{ + const TokenSequence* seq = mReplay; + mReplay = replay; + return seq; +} + const char* Scanner::TokenName(Token token) const { return TokenNames[token]; @@ -412,8 +447,32 @@ void Scanner::AddMacro(const Ident* ident, const char* value) mDefines->Insert(macro); } +void Scanner::MarkSourceOnce(void) +{ + const Ident* fident = Ident::Unique(mPreprocessor->mSource->mFileName); + + Macro* macro = new Macro(fident, nullptr); + mOnceDict->Insert(macro); +} + void Scanner::NextToken(void) { + if (mReplay) + { + mLocation = mReplay->mLocation; + mToken = mReplay->mToken; + + mTokenIdent = mReplay->mTokenIdent; + mTokenChar = mReplay->mTokenChar; + mTokenNumber = mReplay->mTokenNumber; + mTokenInteger = mReplay->mTokenInteger; + if (mReplay->mTokenString) + strcpy_s(mTokenString, mReplay->mTokenString); + + mReplay = mReplay->mNext; + return; + } + for (;;) { NextRawToken(); @@ -503,6 +562,8 @@ void Scanner::NextToken(void) { if (!mPreprocessor->OpenSource("Including", mTokenString, true)) mErrors->Error(mLocation, EERR_FILE_NOT_FOUND, "Could not open source file", mTokenString); + else if (mOnceDict->Lookup(Ident::Unique(mPreprocessor->mSource->mFileName))) + mPreprocessor->CloseSource(); } else if (mToken == TK_LESS_THAN) { @@ -510,6 +571,8 @@ void Scanner::NextToken(void) StringToken('>', 'a'); if (!mPreprocessor->OpenSource("Including", mTokenString, false)) mErrors->Error(mLocation, EERR_FILE_NOT_FOUND, "Could not open source file", mTokenString); + else if (mOnceDict->Lookup(Ident::Unique(mPreprocessor->mSource->mFileName))) + mPreprocessor->CloseSource(); } } else if (mToken == TK_PREP_DEFINE) @@ -1426,6 +1489,8 @@ void Scanner::NextRawToken(void) mToken = TK_DELETE; else if ((mCompilerOptions & COPT_CPLUSPLUS) && !strcmp(tkident, "virtual")) mToken = TK_VIRTUAL; + else if ((mCompilerOptions & COPT_CPLUSPLUS) && !strcmp(tkident, "template")) + mToken = TK_TEMPLATE; else if ((mCompilerOptions & COPT_CPLUSPLUS) && !strcmp(tkident, "operator")) { NextRawToken(); diff --git a/oscar64/Scanner.h b/oscar64/Scanner.h index 2c61d7d..3d1691f 100644 --- a/oscar64/Scanner.h +++ b/oscar64/Scanner.h @@ -161,6 +161,7 @@ enum Token TK_DELETE, TK_VIRTUAL, TK_OPERATOR, + TK_TEMPLATE, NUM_TOKENS }; @@ -204,6 +205,24 @@ protected: MacroDict * mParent; }; +class Scanner; + +struct TokenSequence +{ + TokenSequence * mNext; + Location mLocation; + Token mToken; + + const Ident * mTokenIdent; + char mTokenChar; + const char * mTokenString; + double mTokenNumber; + int64 mTokenInteger; + + TokenSequence(Scanner* scanner); + ~TokenSequence(void); +}; + class Scanner { public: @@ -214,6 +233,9 @@ public: void NextToken(void); + TokenSequence* Record(void); + const TokenSequence* Replay(const TokenSequence * sequence); + void Warning(const char * error); void Error(const char * error); @@ -247,6 +269,7 @@ public: uint64 mCompilerOptions; void AddMacro(const Ident* ident, const char* value); + void MarkSourceOnce(void); protected: void NextRawToken(void); @@ -261,10 +284,12 @@ protected: int mMacroExpansionDepth; - MacroDict* mDefines, * mDefineArguments; + MacroDict* mDefines, * mDefineArguments, * mOnceDict; Token mUngetToken; + const TokenSequence* mReplay; + void StringToken(char terminator, char mode); void CharToken(char mode); bool NextChar(void);