Create a new class to keep track of line number in preprocessor.

SourceLineSynchronizer is added for keeping track of the last
line number and output newlines appropriately if we switch to
a new line in the preprocessor.
This commit is contained in:
Lei Zhang 2015-07-15 11:41:20 -04:00
parent 62aa5bdfca
commit d67e15e9b4

View File

@ -599,6 +599,36 @@ bool ProcessDeferred(
return success; return success;
} }
// Responsible for keeping track of the most recent line in the preprocessor
// and outputting newlines appropriately if the line changes.
class SourceLineSynchronizer {
public:
SourceLineSynchronizer(std::stringstream* output) : output(output) {}
SourceLineSynchronizer(const SourceLineSynchronizer&) = delete;
SourceLineSynchronizer& operator=(const SourceLineSynchronizer&) = delete;
// If we switched to a new line, returns true and inserts newlines
// appropriately. Otherwise, returns false and outputs nothing.
bool syncToLine(int tokenLine) {
const bool newLineStarted = lastLine < tokenLine;
for (; lastLine < tokenLine; ++lastLine) {
if (lastLine > 0) *output << std::endl;
}
return newLineStarted;
}
// Sets the line number of the most recent line to newLineNum.
void setLineNum(int newLineNum) { lastLine = newLineNum; }
private:
// output stream for newlines.
std::stringstream* output;
// lastLine is the line number (starting from 1) of the last token processed.
// It is tracked in order for newlines to be inserted when a token appears
// on a new line. 0 means we haven't started processing any line in the
// current source string.
int lastLine = 0;
};
// DoPreprocessing is a valid ProcessingContext template argument, // DoPreprocessing is a valid ProcessingContext template argument,
// which only performs the preprocessing step of compilation. // which only performs the preprocessing step of compilation.
@ -615,99 +645,75 @@ struct DoPreprocessing {
static const std::string noSpaceBeforeTokens = ","; static const std::string noSpaceBeforeTokens = ",";
glslang::TPpToken token; glslang::TPpToken token;
std::stringstream outputStream;
int lastLine = -1; // lastLine is the line number of the last token
// processed. It is tracked in order for new-lines to be inserted when
// a token appears on a new line.
int lastToken = -1;
parseContext.setScanner(&input); parseContext.setScanner(&input);
ppContext.setInput(input, versionWillBeError); ppContext.setInput(input, versionWillBeError);
// Inserts newlines and incremnets lastLine until std::stringstream outputStream;
// lastLine >= line. SourceLineSynchronizer lineSync(&outputStream);
auto adjustLine = [&lastLine, &outputStream](int line) {
int tokenLine = line - 1;
while(lastLine < tokenLine) {
if (lastLine >= 0) {
outputStream << std::endl;
}
++lastLine;
}
};
parseContext.setExtensionCallback([&adjustLine, &outputStream]( parseContext.setExtensionCallback([&lineSync, &outputStream](
int line, const char* extension, const char* behavior) { int line, const char* extension, const char* behavior) {
adjustLine(line); lineSync.syncToLine(line);
outputStream << "#extension " << extension << " : " << behavior; outputStream << "#extension " << extension << " : " << behavior;
}); });
parseContext.setLineCallback([&adjustLine, &lastLine, &outputStream, &parseContext]( parseContext.setLineCallback([&lineSync, &outputStream, &parseContext](
int curLineNo, int newLineNo, bool hasSource, int sourceNum) { int curLineNum, int newLineNum, bool hasSource, int sourceNum) {
// SourceNum is the number of the source-string that is being parsed. // SourceNum is the number of the source-string that is being parsed.
adjustLine(curLineNo); lineSync.syncToLine(curLineNum);
outputStream << "#line " << newLineNo; outputStream << "#line " << newLineNum;
if (hasSource) { if (hasSource) {
outputStream << " " << sourceNum; outputStream << " " << sourceNum;
} }
if (parseContext.lineDirectiveShouldSetNextLine()) { if (parseContext.lineDirectiveShouldSetNextLine()) {
// newLineNo is the new line number for the line following the #line // newLineNum is the new line number for the line following the #line
// directive. So the new line number for the current line is // directive. So the new line number for the current line is
newLineNo -= 1; newLineNum -= 1;
} }
outputStream << std::endl; outputStream << std::endl;
// Line number starts from 1. And we are at the next line of the #line // And we are at the next line of the #line directive now.
// directive now. So lastLine (from 0) should be (newLineNo - 1) + 1. lineSync.setLineNum(newLineNum + 1);
lastLine = newLineNo;
}); });
parseContext.setVersionCallback( parseContext.setVersionCallback(
[&adjustLine, &outputStream](int line, int version, const char* str) { [&lineSync, &outputStream](int line, int version, const char* str) {
adjustLine(line); lineSync.syncToLine(line);
outputStream << "#version " << version; outputStream << "#version " << version;
if (str) { if (str) {
outputStream << " " << str; outputStream << " " << str;
} }
}); });
parseContext.setPragmaCallback([&adjustLine, &outputStream]( parseContext.setPragmaCallback([&lineSync, &outputStream](
int line, const glslang::TVector<glslang::TString>& ops) { int line, const glslang::TVector<glslang::TString>& ops) {
adjustLine(line); lineSync.syncToLine(line);
outputStream << "#pragma "; outputStream << "#pragma ";
for(size_t i = 0; i < ops.size(); ++i) { for(size_t i = 0; i < ops.size(); ++i) {
outputStream << ops[i]; outputStream << ops[i];
} }
}); });
parseContext.setErrorCallback([&adjustLine, &outputStream]( parseContext.setErrorCallback([&lineSync, &outputStream](
int line, const char* errorMessage) { int line, const char* errorMessage) {
adjustLine(line); lineSync.syncToLine(line);
outputStream << "#error " << errorMessage; outputStream << "#error " << errorMessage;
}); });
int lastToken = EOF; // lastToken records the last token processed.
while (const char* tok = ppContext.tokenize(&token)) { while (const char* tok = ppContext.tokenize(&token)) {
int tokenLine = token.loc.line - 1; // start at 0; bool isNewLine = lineSync.syncToLine(token.loc.line);
bool newLine = false;
while (lastLine < tokenLine) { if (isNewLine) {
if (lastLine > -1) { // Don't emit whitespace onto empty lines.
outputStream << std::endl; // Copy any whitespace characters at the start of a line
newLine = true; // from the input to the output.
} outputStream << std::string(token.loc.column - 1, ' ');
++lastLine;
if (lastLine == tokenLine) {
// Don't emit whitespace onto empty lines.
// Copy any whitespace characters at the start of a line
// from the input to the output.
for(int i = 0; i < token.loc.column - 1; ++i) {
outputStream << " ";
}
}
} }
// Output a space in between tokens, but not at the start of a line, // Output a space in between tokens, but not at the start of a line,
// and also not around special tokens. This helps with readability // and also not around special tokens. This helps with readability
// and consistency. // and consistency.
if (!newLine && if (!isNewLine && lastToken != -1 &&
lastToken != -1 &&
(unNeededSpaceTokens.find((char)token.token) == std::string::npos) && (unNeededSpaceTokens.find((char)token.token) == std::string::npos) &&
(unNeededSpaceTokens.find((char)lastToken) == std::string::npos) && (unNeededSpaceTokens.find((char)lastToken) == std::string::npos) &&
(noSpaceBeforeTokens.find((char)token.token) == std::string::npos)) { (noSpaceBeforeTokens.find((char)token.token) == std::string::npos)) {