PP: Non-functional: Remove custom allocator and related improvements.
Removed the preprocesser memory pool. Removed extra copies and unnecessary allocations of objects related to the ones that were using the pool. Replaced some allocated pointers with objects instead, generally using more modern techiques. There end up being fewer memory allocations/deletions to get right. Overall combined effect of all changes is to use slightly less memory and run slightly faster (< 1% for both, but noticable). As part of simplifying the code base, this change makes it easier to see PP symbol tracking, which I suspect has an even bigger run-time simplification to make.
This commit is contained in:
parent
bfff871dad
commit
b8387c87d0
@ -91,18 +91,10 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
|
|
||||||
namespace glslang {
|
namespace glslang {
|
||||||
|
|
||||||
int TPpContext::InitCPP()
|
|
||||||
{
|
|
||||||
pool = mem_CreatePool(0, 0);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle #define
|
// Handle #define
|
||||||
int TPpContext::CPPdefine(TPpToken* ppToken)
|
int TPpContext::CPPdefine(TPpToken* ppToken)
|
||||||
{
|
{
|
||||||
MacroSymbol mac;
|
MacroSymbol mac;
|
||||||
Symbol *symb;
|
|
||||||
|
|
||||||
// get macro name
|
// get macro name
|
||||||
int token = scanToken(ppToken);
|
int token = scanToken(ppToken);
|
||||||
@ -121,32 +113,28 @@ int TPpContext::CPPdefine(TPpToken* ppToken)
|
|||||||
// gather parameters to the macro, between (...)
|
// gather parameters to the macro, between (...)
|
||||||
token = scanToken(ppToken);
|
token = scanToken(ppToken);
|
||||||
if (token == '(' && ! ppToken->space) {
|
if (token == '(' && ! ppToken->space) {
|
||||||
int argc = 0;
|
mac.emptyArgs = 1;
|
||||||
int args[maxMacroArgs];
|
|
||||||
do {
|
do {
|
||||||
token = scanToken(ppToken);
|
token = scanToken(ppToken);
|
||||||
if (argc == 0 && token == ')')
|
if (mac.args.size() == 0 && token == ')')
|
||||||
break;
|
break;
|
||||||
if (token != PpAtomIdentifier) {
|
if (token != PpAtomIdentifier) {
|
||||||
parseContext.ppError(ppToken->loc, "bad argument", "#define", "");
|
parseContext.ppError(ppToken->loc, "bad argument", "#define", "");
|
||||||
|
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
mac.emptyArgs = 0;
|
||||||
// check for duplication of parameter name
|
// check for duplication of parameter name
|
||||||
bool duplicate = false;
|
bool duplicate = false;
|
||||||
for (int a = 0; a < argc; ++a) {
|
for (size_t a = 0; a < mac.args.size(); ++a) {
|
||||||
if (args[a] == ppToken->atom) {
|
if (mac.args[a] == ppToken->atom) {
|
||||||
parseContext.ppError(ppToken->loc, "duplicate macro parameter", "#define", "");
|
parseContext.ppError(ppToken->loc, "duplicate macro parameter", "#define", "");
|
||||||
duplicate = true;
|
duplicate = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (! duplicate) {
|
if (! duplicate)
|
||||||
if (argc < maxMacroArgs)
|
mac.args.push_back(ppToken->atom);
|
||||||
args[argc++] = ppToken->atom;
|
|
||||||
else
|
|
||||||
parseContext.ppError(ppToken->loc, "too many macro parameters", "#define", "");
|
|
||||||
}
|
|
||||||
token = scanToken(ppToken);
|
token = scanToken(ppToken);
|
||||||
} while (token == ',');
|
} while (token == ',');
|
||||||
if (token != ')') {
|
if (token != ')') {
|
||||||
@ -154,15 +142,12 @@ int TPpContext::CPPdefine(TPpToken* ppToken)
|
|||||||
|
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
mac.argc = argc;
|
|
||||||
mac.args = (int*)mem_Alloc(pool, argc * sizeof(int));
|
|
||||||
memcpy(mac.args, args, argc * sizeof(int));
|
|
||||||
token = scanToken(ppToken);
|
token = scanToken(ppToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
// record the definition of the macro
|
// record the definition of the macro
|
||||||
TSourceLoc defineLoc = ppToken->loc; // because ppToken is going to go to the next line before we report errors
|
TSourceLoc defineLoc = ppToken->loc; // because ppToken is going to go to the next line before we report errors
|
||||||
mac.body = new TokenStream;
|
|
||||||
while (token != '\n' && token != EndOfInput) {
|
while (token != '\n' && token != EndOfInput) {
|
||||||
RecordToken(mac.body, token, ppToken);
|
RecordToken(mac.body, token, ppToken);
|
||||||
token = scanToken(ppToken);
|
token = scanToken(ppToken);
|
||||||
@ -171,27 +156,25 @@ int TPpContext::CPPdefine(TPpToken* ppToken)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check for duplicate definition
|
// check for duplicate definition
|
||||||
symb = LookUpSymbol(defAtom);
|
MacroSymbol* existing = lookupMacroDef(defAtom);
|
||||||
if (symb) {
|
if (existing != nullptr) {
|
||||||
if (! symb->mac.undef) {
|
if (! existing->undef) {
|
||||||
// Already defined -- need to make sure they are identical:
|
// Already defined -- need to make sure they are identical:
|
||||||
// "Two replacement lists are identical if and only if the preprocessing tokens in both have the same number,
|
// "Two replacement lists are identical if and only if the preprocessing tokens in both have the same number,
|
||||||
// ordering, spelling, and white-space separation, where all white-space separations are considered identical."
|
// ordering, spelling, and white-space separation, where all white-space separations are considered identical."
|
||||||
if (symb->mac.argc != mac.argc)
|
if (existing->args.size() != mac.args.size() || existing->emptyArgs != mac.emptyArgs)
|
||||||
parseContext.ppError(defineLoc, "Macro redefined; different number of arguments:", "#define", GetAtomString(defAtom));
|
parseContext.ppError(defineLoc, "Macro redefined; different number of arguments:", "#define", GetAtomString(defAtom));
|
||||||
else {
|
else {
|
||||||
for (int argc = 0; argc < mac.argc; argc++) {
|
if (existing->args != mac.args)
|
||||||
if (symb->mac.args[argc] != mac.args[argc])
|
|
||||||
parseContext.ppError(defineLoc, "Macro redefined; different argument names:", "#define", GetAtomString(defAtom));
|
parseContext.ppError(defineLoc, "Macro redefined; different argument names:", "#define", GetAtomString(defAtom));
|
||||||
}
|
RewindTokenStream(existing->body);
|
||||||
RewindTokenStream(symb->mac.body);
|
|
||||||
RewindTokenStream(mac.body);
|
RewindTokenStream(mac.body);
|
||||||
int newToken;
|
int newToken;
|
||||||
do {
|
do {
|
||||||
int oldToken;
|
int oldToken;
|
||||||
TPpToken oldPpToken;
|
TPpToken oldPpToken;
|
||||||
TPpToken newPpToken;
|
TPpToken newPpToken;
|
||||||
oldToken = ReadToken(symb->mac.body, &oldPpToken);
|
oldToken = ReadToken(existing->body, &oldPpToken);
|
||||||
newToken = ReadToken(mac.body, &newPpToken);
|
newToken = ReadToken(mac.body, &newPpToken);
|
||||||
if (oldToken != newToken || oldPpToken != newPpToken) {
|
if (oldToken != newToken || oldPpToken != newPpToken) {
|
||||||
parseContext.ppError(defineLoc, "Macro redefined; different substitutions:", "#define", GetAtomString(defAtom));
|
parseContext.ppError(defineLoc, "Macro redefined; different substitutions:", "#define", GetAtomString(defAtom));
|
||||||
@ -200,11 +183,9 @@ int TPpContext::CPPdefine(TPpToken* ppToken)
|
|||||||
} while (newToken > 0);
|
} while (newToken > 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*existing = mac;
|
||||||
} else
|
} else
|
||||||
symb = AddSymbol(defAtom);
|
addMacroDef(defAtom, mac);
|
||||||
|
|
||||||
delete symb->mac.body;
|
|
||||||
symb->mac = mac;
|
|
||||||
|
|
||||||
return '\n';
|
return '\n';
|
||||||
}
|
}
|
||||||
@ -213,7 +194,6 @@ int TPpContext::CPPdefine(TPpToken* ppToken)
|
|||||||
int TPpContext::CPPundef(TPpToken* ppToken)
|
int TPpContext::CPPundef(TPpToken* ppToken)
|
||||||
{
|
{
|
||||||
int token = scanToken(ppToken);
|
int token = scanToken(ppToken);
|
||||||
Symbol *symb;
|
|
||||||
if (token != PpAtomIdentifier) {
|
if (token != PpAtomIdentifier) {
|
||||||
parseContext.ppError(ppToken->loc, "must be followed by macro name", "#undef", "");
|
parseContext.ppError(ppToken->loc, "must be followed by macro name", "#undef", "");
|
||||||
|
|
||||||
@ -222,10 +202,9 @@ int TPpContext::CPPundef(TPpToken* ppToken)
|
|||||||
|
|
||||||
parseContext.reservedPpErrorCheck(ppToken->loc, ppToken->name, "#undef");
|
parseContext.reservedPpErrorCheck(ppToken->loc, ppToken->name, "#undef");
|
||||||
|
|
||||||
symb = LookUpSymbol(ppToken->atom);
|
MacroSymbol* macro = lookupMacroDef(ppToken->atom);
|
||||||
if (symb) {
|
if (macro != nullptr)
|
||||||
symb->mac.undef = 1;
|
macro->undef = 1;
|
||||||
}
|
|
||||||
token = scanToken(ppToken);
|
token = scanToken(ppToken);
|
||||||
if (token != '\n')
|
if (token != '\n')
|
||||||
parseContext.ppError(ppToken->loc, "can only be followed by a single macro name", "#undef", "");
|
parseContext.ppError(ppToken->loc, "can only be followed by a single macro name", "#undef", "");
|
||||||
@ -427,8 +406,9 @@ int TPpContext::eval(int token, int precedence, bool shortCircuit, int& res, boo
|
|||||||
|
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
Symbol* s = LookUpSymbol(ppToken->atom);
|
|
||||||
res = s ? ! s->mac.undef : 0;
|
MacroSymbol* macro = lookupMacroDef(ppToken->atom);
|
||||||
|
res = macro != nullptr ? !macro->undef : 0;
|
||||||
token = scanToken(ppToken);
|
token = scanToken(ppToken);
|
||||||
if (needclose) {
|
if (needclose) {
|
||||||
if (token != ')') {
|
if (token != ')') {
|
||||||
@ -568,7 +548,6 @@ int TPpContext::CPPif(TPpToken* ppToken)
|
|||||||
int TPpContext::CPPifdef(int defined, TPpToken* ppToken)
|
int TPpContext::CPPifdef(int defined, TPpToken* ppToken)
|
||||||
{
|
{
|
||||||
int token = scanToken(ppToken);
|
int token = scanToken(ppToken);
|
||||||
int name = ppToken->atom;
|
|
||||||
if (++ifdepth > maxIfNesting) {
|
if (++ifdepth > maxIfNesting) {
|
||||||
parseContext.ppError(ppToken->loc, "maximum nesting depth exceeded", "#ifdef", "");
|
parseContext.ppError(ppToken->loc, "maximum nesting depth exceeded", "#ifdef", "");
|
||||||
return 0;
|
return 0;
|
||||||
@ -580,14 +559,14 @@ int TPpContext::CPPifdef(int defined, TPpToken* ppToken)
|
|||||||
else
|
else
|
||||||
parseContext.ppError(ppToken->loc, "must be followed by macro name", "#ifndef", "");
|
parseContext.ppError(ppToken->loc, "must be followed by macro name", "#ifndef", "");
|
||||||
} else {
|
} else {
|
||||||
Symbol *s = LookUpSymbol(name);
|
MacroSymbol* macro = lookupMacroDef(ppToken->atom);
|
||||||
token = scanToken(ppToken);
|
token = scanToken(ppToken);
|
||||||
if (token != '\n') {
|
if (token != '\n') {
|
||||||
parseContext.ppError(ppToken->loc, "unexpected tokens following #ifdef directive - expected a newline", "#ifdef", "");
|
parseContext.ppError(ppToken->loc, "unexpected tokens following #ifdef directive - expected a newline", "#ifdef", "");
|
||||||
while (token != '\n' && token != EndOfInput)
|
while (token != '\n' && token != EndOfInput)
|
||||||
token = scanToken(ppToken);
|
token = scanToken(ppToken);
|
||||||
}
|
}
|
||||||
if (((s && !s->mac.undef) ? 1 : 0) != defined)
|
if (((macro != nullptr && !macro->undef) ? 1 : 0) != defined)
|
||||||
token = CPPelse(1, ppToken);
|
token = CPPelse(1, ppToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -936,13 +915,13 @@ int TPpContext::readCPPline(TPpToken* ppToken)
|
|||||||
// Macro-expand a macro argument 'arg' to create 'expandedArg'.
|
// Macro-expand a macro argument 'arg' to create 'expandedArg'.
|
||||||
// Does not replace 'arg'.
|
// Does not replace 'arg'.
|
||||||
// Returns nullptr if no expanded argument is created.
|
// Returns nullptr if no expanded argument is created.
|
||||||
TPpContext::TokenStream* TPpContext::PrescanMacroArg(TokenStream* arg, TPpToken* ppToken, bool newLineOkay)
|
TPpContext::TokenStream* TPpContext::PrescanMacroArg(TokenStream& arg, TPpToken* ppToken, bool newLineOkay)
|
||||||
{
|
{
|
||||||
int token;
|
int token;
|
||||||
RewindTokenStream(arg);
|
RewindTokenStream(arg);
|
||||||
do {
|
do {
|
||||||
token = ReadToken(arg, ppToken);
|
token = ReadToken(arg, ppToken);
|
||||||
if (token == PpAtomIdentifier && LookUpSymbol(ppToken->atom))
|
if (token == PpAtomIdentifier && lookupMacroDef(ppToken->atom) != nullptr)
|
||||||
break;
|
break;
|
||||||
} while (token != EndOfInput);
|
} while (token != EndOfInput);
|
||||||
|
|
||||||
@ -955,7 +934,7 @@ TPpContext::TokenStream* TPpContext::PrescanMacroArg(TokenStream* arg, TPpToken*
|
|||||||
while ((token = scanToken(ppToken)) != tMarkerInput::marker) {
|
while ((token = scanToken(ppToken)) != tMarkerInput::marker) {
|
||||||
if (token == PpAtomIdentifier && MacroExpand(ppToken->atom, ppToken, false, newLineOkay) != 0)
|
if (token == PpAtomIdentifier && MacroExpand(ppToken->atom, ppToken, false, newLineOkay) != 0)
|
||||||
continue;
|
continue;
|
||||||
RecordToken(expandedArg, token, ppToken);
|
RecordToken(*expandedArg, token, ppToken);
|
||||||
}
|
}
|
||||||
popInput();
|
popInput();
|
||||||
|
|
||||||
@ -1009,14 +988,14 @@ int TPpContext::tMacroInput::scan(TPpToken* ppToken)
|
|||||||
// TODO: preprocessor: properly handle whitespace (or lack of it) between tokens when expanding
|
// TODO: preprocessor: properly handle whitespace (or lack of it) between tokens when expanding
|
||||||
if (token == PpAtomIdentifier) {
|
if (token == PpAtomIdentifier) {
|
||||||
int i;
|
int i;
|
||||||
for (i = mac->argc - 1; i >= 0; i--)
|
for (i = mac->args.size() - 1; i >= 0; i--)
|
||||||
if (mac->args[i] == ppToken->atom)
|
if (mac->args[i] == ppToken->atom)
|
||||||
break;
|
break;
|
||||||
if (i >= 0) {
|
if (i >= 0) {
|
||||||
TokenStream* arg = expandedArgs[i];
|
TokenStream* arg = expandedArgs[i];
|
||||||
if (arg == nullptr || pasting)
|
if (arg == nullptr || pasting)
|
||||||
arg = args[i];
|
arg = args[i];
|
||||||
pp->pushTokenStreamInput(arg, prepaste);
|
pp->pushTokenStreamInput(*arg, prepaste);
|
||||||
|
|
||||||
return pp->scanToken(ppToken);
|
return pp->scanToken(ppToken);
|
||||||
}
|
}
|
||||||
@ -1032,7 +1011,7 @@ int TPpContext::tMacroInput::scan(TPpToken* ppToken)
|
|||||||
bool TPpContext::tMacroInput::peekMacPasting()
|
bool TPpContext::tMacroInput::peekMacPasting()
|
||||||
{
|
{
|
||||||
// don't return early, have to restore this
|
// don't return early, have to restore this
|
||||||
size_t savePos = mac->body->current;
|
size_t savePos = mac->body.current;
|
||||||
|
|
||||||
// skip white-space
|
// skip white-space
|
||||||
int ltoken;
|
int ltoken;
|
||||||
@ -1048,7 +1027,7 @@ bool TPpContext::tMacroInput::peekMacPasting()
|
|||||||
pasting = true;
|
pasting = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
mac->body->current = savePos;
|
mac->body.current = savePos;
|
||||||
|
|
||||||
return pasting;
|
return pasting;
|
||||||
}
|
}
|
||||||
@ -1104,20 +1083,20 @@ int TPpContext::MacroExpand(int atom, TPpToken* ppToken, bool expandUndef, bool
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Symbol *sym = LookUpSymbol(atom);
|
MacroSymbol* macro = lookupMacroDef(atom);
|
||||||
int token;
|
int token;
|
||||||
int depth = 0;
|
int depth = 0;
|
||||||
|
|
||||||
// no recursive expansions
|
// no recursive expansions
|
||||||
if (sym && sym->mac.busy)
|
if (macro != nullptr && macro->busy)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// not expanding undefined macros
|
// not expanding undefined macros
|
||||||
if ((! sym || sym->mac.undef) && ! expandUndef)
|
if ((macro == nullptr || macro->undef) && ! expandUndef)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// 0 is the value of an undefined macro
|
// 0 is the value of an undefined macro
|
||||||
if ((! sym || sym->mac.undef) && expandUndef) {
|
if ((macro == nullptr || macro->undef) && expandUndef) {
|
||||||
pushInput(new tZeroInput(this));
|
pushInput(new tZeroInput(this));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -1125,8 +1104,8 @@ int TPpContext::MacroExpand(int atom, TPpToken* ppToken, bool expandUndef, bool
|
|||||||
tMacroInput *in = new tMacroInput(this);
|
tMacroInput *in = new tMacroInput(this);
|
||||||
|
|
||||||
TSourceLoc loc = ppToken->loc; // in case we go to the next line before discovering the error
|
TSourceLoc loc = ppToken->loc; // in case we go to the next line before discovering the error
|
||||||
in->mac = &sym->mac;
|
in->mac = macro;
|
||||||
if (sym->mac.args) {
|
if (macro->args.size() > 0 || macro->emptyArgs) {
|
||||||
token = scanToken(ppToken);
|
token = scanToken(ppToken);
|
||||||
if (newLineOkay) {
|
if (newLineOkay) {
|
||||||
while (token == '\n')
|
while (token == '\n')
|
||||||
@ -1140,13 +1119,13 @@ int TPpContext::MacroExpand(int atom, TPpToken* ppToken, bool expandUndef, bool
|
|||||||
delete in;
|
delete in;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
in->args.resize(in->mac->argc);
|
in->args.resize(in->mac->args.size());
|
||||||
for (int i = 0; i < in->mac->argc; i++)
|
for (size_t i = 0; i < in->mac->args.size(); i++)
|
||||||
in->args[i] = new TokenStream;
|
in->args[i] = new TokenStream;
|
||||||
in->expandedArgs.resize(in->mac->argc);
|
in->expandedArgs.resize(in->mac->args.size());
|
||||||
for (int i = 0; i < in->mac->argc; i++)
|
for (size_t i = 0; i < in->mac->args.size(); i++)
|
||||||
in->expandedArgs[i] = nullptr;
|
in->expandedArgs[i] = nullptr;
|
||||||
int arg = 0;
|
size_t arg = 0;
|
||||||
bool tokenRecorded = false;
|
bool tokenRecorded = false;
|
||||||
do {
|
do {
|
||||||
depth = 0;
|
depth = 0;
|
||||||
@ -1170,7 +1149,7 @@ int TPpContext::MacroExpand(int atom, TPpToken* ppToken, bool expandUndef, bool
|
|||||||
delete in;
|
delete in;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (in->mac->argc == 0 && token != ')')
|
if (in->mac->args.size() == 0 && token != ')')
|
||||||
break;
|
break;
|
||||||
if (depth == 0 && (token == ',' || token == ')'))
|
if (depth == 0 && (token == ',' || token == ')'))
|
||||||
break;
|
break;
|
||||||
@ -1178,19 +1157,19 @@ int TPpContext::MacroExpand(int atom, TPpToken* ppToken, bool expandUndef, bool
|
|||||||
depth++;
|
depth++;
|
||||||
if (token == ')')
|
if (token == ')')
|
||||||
depth--;
|
depth--;
|
||||||
RecordToken(in->args[arg], token, ppToken);
|
RecordToken(*in->args[arg], token, ppToken);
|
||||||
tokenRecorded = true;
|
tokenRecorded = true;
|
||||||
}
|
}
|
||||||
if (token == ')') {
|
if (token == ')') {
|
||||||
if (in->mac->argc == 1 && tokenRecorded == 0)
|
if (in->mac->args.size() == 1 && tokenRecorded == 0)
|
||||||
break;
|
break;
|
||||||
arg++;
|
arg++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
arg++;
|
arg++;
|
||||||
} while (arg < in->mac->argc);
|
} while (arg < in->mac->args.size());
|
||||||
|
|
||||||
if (arg < in->mac->argc)
|
if (arg < in->mac->args.size())
|
||||||
parseContext.ppError(loc, "Too few args in Macro", "macro expansion", GetAtomString(atom));
|
parseContext.ppError(loc, "Too few args in Macro", "macro expansion", GetAtomString(atom));
|
||||||
else if (token != ')') {
|
else if (token != ')') {
|
||||||
depth=0;
|
depth=0;
|
||||||
@ -1212,13 +1191,13 @@ int TPpContext::MacroExpand(int atom, TPpToken* ppToken, bool expandUndef, bool
|
|||||||
|
|
||||||
// We need both expanded and non-expanded forms of the argument, for whether or
|
// We need both expanded and non-expanded forms of the argument, for whether or
|
||||||
// not token pasting is in play.
|
// not token pasting is in play.
|
||||||
for (int i = 0; i < in->mac->argc; i++)
|
for (size_t i = 0; i < in->mac->args.size(); i++)
|
||||||
in->expandedArgs[i] = PrescanMacroArg(in->args[i], ppToken, newLineOkay);
|
in->expandedArgs[i] = PrescanMacroArg(*in->args[i], ppToken, newLineOkay);
|
||||||
}
|
}
|
||||||
|
|
||||||
pushInput(in);
|
pushInput(in);
|
||||||
sym->mac.busy = 1;
|
macro->busy = 1;
|
||||||
RewindTokenStream(sym->mac.body);
|
RewindTokenStream(macro->body);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -83,12 +83,11 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
namespace glslang {
|
namespace glslang {
|
||||||
|
|
||||||
TPpContext::TPpContext(TParseContextBase& pc, const std::string& rootFileName, TShader::Includer& inclr) :
|
TPpContext::TPpContext(TParseContextBase& pc, const std::string& rootFileName, TShader::Includer& inclr) :
|
||||||
preamble(0), strings(0), parseContext(pc), includer(inclr), inComment(false),
|
preamble(0), strings(0), previous_token('\n'), parseContext(pc), includer(inclr), inComment(false),
|
||||||
rootFileName(rootFileName),
|
rootFileName(rootFileName),
|
||||||
currentSourceFile(rootFileName)
|
currentSourceFile(rootFileName)
|
||||||
{
|
{
|
||||||
InitAtomTable();
|
InitAtomTable();
|
||||||
InitScanner();
|
|
||||||
|
|
||||||
ifdepth = 0;
|
ifdepth = 0;
|
||||||
for (elsetracker = 0; elsetracker < maxIfNesting; elsetracker++)
|
for (elsetracker = 0; elsetracker < maxIfNesting; elsetracker++)
|
||||||
@ -98,9 +97,6 @@ TPpContext::TPpContext(TParseContextBase& pc, const std::string& rootFileName, T
|
|||||||
|
|
||||||
TPpContext::~TPpContext()
|
TPpContext::~TPpContext()
|
||||||
{
|
{
|
||||||
for (TSymbolMap::iterator it = symbols.begin(); it != symbols.end(); ++it)
|
|
||||||
delete it->second->mac.body;
|
|
||||||
mem_FreePool(pool);
|
|
||||||
delete [] preamble;
|
delete [] preamble;
|
||||||
|
|
||||||
// free up the inputStack
|
// free up the inputStack
|
||||||
|
|||||||
@ -172,39 +172,27 @@ public:
|
|||||||
size_t current;
|
size_t current;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MemoryPool {
|
|
||||||
struct chunk *next;
|
|
||||||
uintptr_t free, end;
|
|
||||||
size_t chunksize;
|
|
||||||
uintptr_t alignmask;
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// From Pp.cpp
|
// From Pp.cpp
|
||||||
//
|
//
|
||||||
|
|
||||||
struct MacroSymbol {
|
struct MacroSymbol {
|
||||||
MacroSymbol() : argc(0), args(0), body(0), busy(0), undef(0) { }
|
MacroSymbol() : emptyArgs(0), busy(0), undef(0) { }
|
||||||
int argc;
|
TVector<int> args;
|
||||||
int *args;
|
TokenStream body;
|
||||||
TokenStream *body;
|
unsigned emptyArgs : 1;
|
||||||
unsigned busy:1;
|
unsigned busy : 1;
|
||||||
unsigned undef:1;
|
unsigned undef : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Symbol {
|
typedef TMap<int, MacroSymbol> TSymbolMap;
|
||||||
int atom;
|
TSymbolMap macroDefs; // map atoms to macro definitions
|
||||||
MacroSymbol mac;
|
MacroSymbol* lookupMacroDef(int atom)
|
||||||
};
|
{
|
||||||
|
auto existingMacroIt = macroDefs.find(atom);
|
||||||
struct SymbolList {
|
return (existingMacroIt == macroDefs.end()) ? nullptr : &(existingMacroIt->second);
|
||||||
struct SymbolList_Rec *next;
|
}
|
||||||
Symbol *symb;
|
void addMacroDef(int atom, MacroSymbol& macroDef) { macroDefs[atom] = macroDef; }
|
||||||
};
|
|
||||||
|
|
||||||
MemoryPool *pool;
|
|
||||||
typedef TMap<int, Symbol*> TSymbolMap;
|
|
||||||
TSymbolMap symbols; // this has light use... just defined macros
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
TPpContext(TPpContext&);
|
TPpContext(TPpContext&);
|
||||||
@ -242,7 +230,6 @@ protected:
|
|||||||
bool peekPasting() { return !inputStack.empty() && inputStack.back()->peekPasting(); }
|
bool peekPasting() { return !inputStack.empty() && inputStack.back()->peekPasting(); }
|
||||||
bool endOfReplacementList() { return inputStack.empty() || inputStack.back()->endOfReplacementList(); }
|
bool endOfReplacementList() { return inputStack.empty() || inputStack.back()->endOfReplacementList(); }
|
||||||
|
|
||||||
static const int maxMacroArgs = 64;
|
|
||||||
static const int maxIfNesting = 64;
|
static const int maxIfNesting = 64;
|
||||||
|
|
||||||
int ifdepth; // current #if-#else-#endif nesting in the cpp.c file (pre-processor)
|
int ifdepth; // current #if-#else-#endif nesting in the cpp.c file (pre-processor)
|
||||||
@ -264,7 +251,7 @@ protected:
|
|||||||
virtual int getch() { assert(0); return EndOfInput; }
|
virtual int getch() { assert(0); return EndOfInput; }
|
||||||
virtual void ungetch() { assert(0); }
|
virtual void ungetch() { assert(0); }
|
||||||
bool peekPasting() override { return prepaste; }
|
bool peekPasting() override { return prepaste; }
|
||||||
bool endOfReplacementList() override { return mac->body->current >= mac->body->data.size(); }
|
bool endOfReplacementList() override { return mac->body.current >= mac->body.data.size(); }
|
||||||
|
|
||||||
MacroSymbol *mac;
|
MacroSymbol *mac;
|
||||||
TVector<TokenStream*> args;
|
TVector<TokenStream*> args;
|
||||||
@ -311,7 +298,6 @@ protected:
|
|||||||
// Used to obtain #include content.
|
// Used to obtain #include content.
|
||||||
TShader::Includer& includer;
|
TShader::Includer& includer;
|
||||||
|
|
||||||
int InitCPP();
|
|
||||||
int CPPdefine(TPpToken * ppToken);
|
int CPPdefine(TPpToken * ppToken);
|
||||||
int CPPundef(TPpToken * ppToken);
|
int CPPundef(TPpToken * ppToken);
|
||||||
int CPPelse(int matchelse, TPpToken * ppToken);
|
int CPPelse(int matchelse, TPpToken * ppToken);
|
||||||
@ -327,27 +313,20 @@ protected:
|
|||||||
int CPPversion(TPpToken * ppToken);
|
int CPPversion(TPpToken * ppToken);
|
||||||
int CPPextension(TPpToken * ppToken);
|
int CPPextension(TPpToken * ppToken);
|
||||||
int readCPPline(TPpToken * ppToken);
|
int readCPPline(TPpToken * ppToken);
|
||||||
TokenStream* PrescanMacroArg(TokenStream *a, TPpToken * ppToken, bool newLineOkay);
|
TokenStream* PrescanMacroArg(TokenStream&, TPpToken*, bool newLineOkay);
|
||||||
int MacroExpand(int atom, TPpToken* ppToken, bool expandUndef, bool newLineOkay);
|
int MacroExpand(int atom, TPpToken* ppToken, bool expandUndef, bool newLineOkay);
|
||||||
|
|
||||||
//
|
|
||||||
// from PpSymbols.cpp
|
|
||||||
//
|
|
||||||
Symbol *NewSymbol(int name);
|
|
||||||
Symbol *AddSymbol(int atom);
|
|
||||||
Symbol *LookUpSymbol(int atom);
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// From PpTokens.cpp
|
// From PpTokens.cpp
|
||||||
//
|
//
|
||||||
void lAddByte(TokenStream *fTok, unsigned char fVal);
|
void lAddByte(TokenStream&, unsigned char fVal);
|
||||||
int lReadByte(TokenStream *pTok);
|
int lReadByte(TokenStream&);
|
||||||
void lUnreadByte(TokenStream *pTok);
|
void lUnreadByte(TokenStream&);
|
||||||
void RecordToken(TokenStream* pTok, int token, TPpToken* ppToken);
|
void RecordToken(TokenStream&, int token, TPpToken* ppToken);
|
||||||
void RewindTokenStream(TokenStream *pTok);
|
void RewindTokenStream(TokenStream&);
|
||||||
int ReadToken(TokenStream* pTok, TPpToken* ppToken);
|
int ReadToken(TokenStream&, TPpToken*);
|
||||||
void pushTokenStreamInput(TokenStream *ts, bool pasting = false);
|
void pushTokenStreamInput(TokenStream&, bool pasting = false);
|
||||||
void UngetToken(int token, TPpToken* ppToken);
|
void UngetToken(int token, TPpToken*);
|
||||||
|
|
||||||
class tTokenInput : public tInput {
|
class tTokenInput : public tInput {
|
||||||
public:
|
public:
|
||||||
@ -357,7 +336,7 @@ protected:
|
|||||||
virtual void ungetch() { assert(0); }
|
virtual void ungetch() { assert(0); }
|
||||||
virtual bool peekPasting() override;
|
virtual bool peekPasting() override;
|
||||||
protected:
|
protected:
|
||||||
TokenStream *tokens;
|
TokenStream* tokens;
|
||||||
bool lastTokenPastes; // true if the last token in the input is to be pasted, rather than consumed as a token
|
bool lastTokenPastes; // true if the last token in the input is to be pasted, rather than consumed as a token
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -535,7 +514,6 @@ protected:
|
|||||||
tStringInput stringInput;
|
tStringInput stringInput;
|
||||||
};
|
};
|
||||||
|
|
||||||
int InitScanner();
|
|
||||||
int ScanFromString(char* s);
|
int ScanFromString(char* s);
|
||||||
void missingEndifCheck();
|
void missingEndifCheck();
|
||||||
int lFloatConst(int len, int ch, TPpToken* ppToken);
|
int lFloatConst(int len, int ch, TPpToken* ppToken);
|
||||||
@ -576,14 +554,6 @@ protected:
|
|||||||
void AddAtomFixed(const char* s, int atom);
|
void AddAtomFixed(const char* s, int atom);
|
||||||
int LookUpAddString(const char* s);
|
int LookUpAddString(const char* s);
|
||||||
const char* GetAtomString(int atom);
|
const char* GetAtomString(int atom);
|
||||||
|
|
||||||
//
|
|
||||||
// From PpMemory.cpp
|
|
||||||
//
|
|
||||||
MemoryPool *mem_CreatePool(size_t chunksize, unsigned align);
|
|
||||||
void mem_FreePool(MemoryPool*);
|
|
||||||
void *mem_Alloc(MemoryPool* p, size_t size);
|
|
||||||
int mem_AddCleanup(MemoryPool* p, void (*fn)(void *, void*), void* arg1, void* arg2);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace glslang
|
} // end namespace glslang
|
||||||
|
|||||||
@ -76,86 +76,6 @@ TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
|
|||||||
NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
\****************************************************************************/
|
\****************************************************************************/
|
||||||
|
|
||||||
#include <cstddef>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
#include "PpContext.h"
|
|
||||||
|
|
||||||
// default alignment and chunksize, if called with 0 arguments
|
|
||||||
#define CHUNKSIZE (64*1024)
|
|
||||||
#define ALIGN 8
|
|
||||||
|
|
||||||
namespace glslang {
|
namespace glslang {
|
||||||
|
|
||||||
struct chunk {
|
|
||||||
struct chunk *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
TPpContext::MemoryPool* TPpContext::mem_CreatePool(size_t chunksize, unsigned int align)
|
|
||||||
{
|
|
||||||
if (align == 0)
|
|
||||||
align = ALIGN;
|
|
||||||
if (chunksize == 0)
|
|
||||||
chunksize = CHUNKSIZE;
|
|
||||||
if (align & (align - 1))
|
|
||||||
return nullptr;
|
|
||||||
if (chunksize < sizeof(MemoryPool))
|
|
||||||
return nullptr;
|
|
||||||
if (chunksize & (align - 1))
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
MemoryPool *pool = (MemoryPool*)malloc(chunksize);
|
|
||||||
if (! pool)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
pool->next = 0;
|
|
||||||
pool->chunksize = chunksize;
|
|
||||||
pool->alignmask = (uintptr_t)(align) - 1;
|
|
||||||
pool->free = ((uintptr_t)(pool + 1) + pool->alignmask) & ~pool->alignmask;
|
|
||||||
pool->end = (uintptr_t)pool + chunksize;
|
|
||||||
|
|
||||||
return pool;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TPpContext::mem_FreePool(MemoryPool *pool)
|
|
||||||
{
|
|
||||||
struct chunk *p, *next;
|
|
||||||
|
|
||||||
for (p = (struct chunk *)pool; p; p = next) {
|
|
||||||
next = p->next;
|
|
||||||
free(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void* TPpContext::mem_Alloc(MemoryPool *pool, size_t size)
|
|
||||||
{
|
|
||||||
struct chunk *ch;
|
|
||||||
void *rv = (void *)pool->free;
|
|
||||||
size = (size + pool->alignmask) & ~pool->alignmask;
|
|
||||||
if (size <= 0) size = pool->alignmask;
|
|
||||||
pool->free += size;
|
|
||||||
if (pool->free > pool->end || pool->free < (uintptr_t)rv) {
|
|
||||||
size_t minreq = (size + sizeof(struct chunk) + pool->alignmask) & ~pool->alignmask;
|
|
||||||
pool->free = (uintptr_t)rv;
|
|
||||||
if (minreq >= pool->chunksize) {
|
|
||||||
// request size is too big for the chunksize, so allocate it as
|
|
||||||
// a single chunk of the right size
|
|
||||||
ch = (struct chunk*)malloc(minreq);
|
|
||||||
if (! ch)
|
|
||||||
return nullptr;
|
|
||||||
} else {
|
|
||||||
ch = (struct chunk*)malloc(pool->chunksize);
|
|
||||||
if (! ch)
|
|
||||||
return nullptr;
|
|
||||||
pool->free = (uintptr_t)ch + minreq;
|
|
||||||
pool->end = (uintptr_t)ch + pool->chunksize;
|
|
||||||
}
|
|
||||||
ch->next = pool->next;
|
|
||||||
pool->next = ch;
|
|
||||||
rv = (void *)(((uintptr_t)(ch+1) + pool->alignmask) & ~pool->alignmask);
|
|
||||||
}
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // end namespace glslang
|
} // end namespace glslang
|
||||||
|
|||||||
@ -90,17 +90,6 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
|
|
||||||
namespace glslang {
|
namespace glslang {
|
||||||
|
|
||||||
int TPpContext::InitScanner()
|
|
||||||
{
|
|
||||||
// Add various atoms needed by the CPP line scanner:
|
|
||||||
if (!InitCPP())
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
previous_token = '\n';
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
/////////////////////////////////// Floating point constants: /////////////////////////////////
|
/////////////////////////////////// Floating point constants: /////////////////////////////////
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
@ -91,44 +91,4 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
|
|
||||||
namespace glslang {
|
namespace glslang {
|
||||||
|
|
||||||
/*
|
|
||||||
* Allocate a new symbol node;
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
TPpContext::Symbol* TPpContext::NewSymbol(int atom)
|
|
||||||
{
|
|
||||||
Symbol* lSymb;
|
|
||||||
char* pch;
|
|
||||||
size_t ii;
|
|
||||||
|
|
||||||
lSymb = (Symbol *) mem_Alloc(pool, sizeof(Symbol));
|
|
||||||
lSymb->atom = atom;
|
|
||||||
|
|
||||||
// Clear macro
|
|
||||||
pch = (char*) &lSymb->mac;
|
|
||||||
for (ii = 0; ii < sizeof(lSymb->mac); ii++)
|
|
||||||
*pch++ = 0;
|
|
||||||
|
|
||||||
return lSymb;
|
|
||||||
}
|
|
||||||
|
|
||||||
TPpContext::Symbol* TPpContext::AddSymbol(int atom)
|
|
||||||
{
|
|
||||||
Symbol *lSymb;
|
|
||||||
|
|
||||||
lSymb = NewSymbol(atom);
|
|
||||||
symbols[lSymb->atom] = lSymb;
|
|
||||||
|
|
||||||
return lSymb;
|
|
||||||
}
|
|
||||||
|
|
||||||
TPpContext::Symbol* TPpContext::LookUpSymbol(int atom)
|
|
||||||
{
|
|
||||||
TSymbolMap::iterator it = symbols.find(atom);
|
|
||||||
if (it == symbols.end())
|
|
||||||
return nullptr;
|
|
||||||
else
|
|
||||||
return it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // end namespace glslang
|
} // end namespace glslang
|
||||||
|
|||||||
@ -95,32 +95,32 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
|
|
||||||
namespace glslang {
|
namespace glslang {
|
||||||
|
|
||||||
void TPpContext::lAddByte(TokenStream *fTok, unsigned char fVal)
|
void TPpContext::lAddByte(TokenStream& fTok, unsigned char fVal)
|
||||||
{
|
{
|
||||||
fTok->data.push_back(fVal);
|
fTok.data.push_back(fVal);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the next byte from a stream.
|
* Get the next byte from a stream.
|
||||||
*/
|
*/
|
||||||
int TPpContext::lReadByte(TokenStream *pTok)
|
int TPpContext::lReadByte(TokenStream& pTok)
|
||||||
{
|
{
|
||||||
if (pTok->current < pTok->data.size())
|
if (pTok.current < pTok.data.size())
|
||||||
return pTok->data[pTok->current++];
|
return pTok.data[pTok.current++];
|
||||||
else
|
else
|
||||||
return EndOfInput;
|
return EndOfInput;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TPpContext::lUnreadByte(TokenStream *pTok)
|
void TPpContext::lUnreadByte(TokenStream& pTok)
|
||||||
{
|
{
|
||||||
if (pTok->current > 0)
|
if (pTok.current > 0)
|
||||||
--pTok->current;
|
--pTok.current;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add a token to the end of a list for later playback.
|
* Add a token to the end of a list for later playback.
|
||||||
*/
|
*/
|
||||||
void TPpContext::RecordToken(TokenStream *pTok, int token, TPpToken* ppToken)
|
void TPpContext::RecordToken(TokenStream& pTok, int token, TPpToken* ppToken)
|
||||||
{
|
{
|
||||||
const char* s;
|
const char* s;
|
||||||
char* str = NULL;
|
char* str = NULL;
|
||||||
@ -162,15 +162,15 @@ void TPpContext::RecordToken(TokenStream *pTok, int token, TPpToken* ppToken)
|
|||||||
/*
|
/*
|
||||||
* Reset a token stream in preparation for reading.
|
* Reset a token stream in preparation for reading.
|
||||||
*/
|
*/
|
||||||
void TPpContext::RewindTokenStream(TokenStream *pTok)
|
void TPpContext::RewindTokenStream(TokenStream& pTok)
|
||||||
{
|
{
|
||||||
pTok->current = 0;
|
pTok.current = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read the next token from a token stream (not the source stream, but stream used to hold a tokenized macro).
|
* Read the next token from a token stream (not the source stream, but stream used to hold a tokenized macro).
|
||||||
*/
|
*/
|
||||||
int TPpContext::ReadToken(TokenStream *pTok, TPpToken *ppToken)
|
int TPpContext::ReadToken(TokenStream& pTok, TPpToken *ppToken)
|
||||||
{
|
{
|
||||||
char* tokenText = ppToken->name;
|
char* tokenText = ppToken->name;
|
||||||
int ltoken, len;
|
int ltoken, len;
|
||||||
@ -183,7 +183,7 @@ int TPpContext::ReadToken(TokenStream *pTok, TPpToken *ppToken)
|
|||||||
switch (ltoken) {
|
switch (ltoken) {
|
||||||
case '#':
|
case '#':
|
||||||
// Check for ##, unless the current # is the last character
|
// Check for ##, unless the current # is the last character
|
||||||
if (pTok->current < pTok->data.size()) {
|
if (pTok.current < pTok.data.size()) {
|
||||||
if (lReadByte(pTok) == '#') {
|
if (lReadByte(pTok) == '#') {
|
||||||
parseContext.requireProfile(ppToken->loc, ~EEsProfile, "token pasting (##)");
|
parseContext.requireProfile(ppToken->loc, ~EEsProfile, "token pasting (##)");
|
||||||
parseContext.profileRequires(ppToken->loc, ~EEsProfile, 130, 0, "token pasting (##)");
|
parseContext.profileRequires(ppToken->loc, ~EEsProfile, 130, 0, "token pasting (##)");
|
||||||
@ -274,7 +274,7 @@ int TPpContext::ReadToken(TokenStream *pTok, TPpToken *ppToken)
|
|||||||
|
|
||||||
int TPpContext::tTokenInput::scan(TPpToken* ppToken)
|
int TPpContext::tTokenInput::scan(TPpToken* ppToken)
|
||||||
{
|
{
|
||||||
return pp->ReadToken(tokens, ppToken);
|
return pp->ReadToken(*tokens, ppToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We are pasting if the entire macro is preceding a pasting operator
|
// We are pasting if the entire macro is preceding a pasting operator
|
||||||
@ -289,7 +289,7 @@ bool TPpContext::tTokenInput::peekPasting()
|
|||||||
size_t savePos = tokens->current;
|
size_t savePos = tokens->current;
|
||||||
bool moreTokens = false;
|
bool moreTokens = false;
|
||||||
do {
|
do {
|
||||||
int byte = pp->lReadByte(tokens);
|
int byte = pp->lReadByte(*tokens);
|
||||||
if (byte == EndOfInput)
|
if (byte == EndOfInput)
|
||||||
break;
|
break;
|
||||||
if (byte != ' ') {
|
if (byte != ' ') {
|
||||||
@ -302,9 +302,9 @@ bool TPpContext::tTokenInput::peekPasting()
|
|||||||
return !moreTokens;
|
return !moreTokens;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TPpContext::pushTokenStreamInput(TokenStream* ts, bool prepasting)
|
void TPpContext::pushTokenStreamInput(TokenStream& ts, bool prepasting)
|
||||||
{
|
{
|
||||||
pushInput(new tTokenInput(this, ts, prepasting));
|
pushInput(new tTokenInput(this, &ts, prepasting));
|
||||||
RewindTokenStream(ts);
|
RewindTokenStream(ts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user