From 5011fbebc3e83d695f6ba9ae12b813a0089d9538 Mon Sep 17 00:00:00 2001 From: Lei Zhang Date: Thu, 25 Jun 2015 17:53:54 -0400 Subject: [PATCH] Extend the syntax of #line and __FILE__ to support filename strings. According to the GLSL spec, the second parameter to #line should be an integer source string number and __FILE__ will be substituted with the integer source string number currently processed. This patch extends the syntax of #line and __FILE__. Now #line accepts as the second parameter a filename string quoted by double quotation marks. And if such a #line is set, __FILE__ will be substituted with the currently set filename string. The implementation is done via introducing a new extension GL_GOOGLE_cpp_style_line_directive using the extension framework. The purpose is to support cpp-style #line directives, which is required by #include. --- .../preprocessor.cpp_style___FILE__.vert.err | 0 .../preprocessor.cpp_style___FILE__.vert.out | 26 ++++++++++++++ ...rocessor.cpp_style_line_directive.vert.err | 15 ++++++++ ...rocessor.cpp_style_line_directive.vert.out | 0 Test/preprocessor.cpp_style___FILE__.vert | 36 +++++++++++++++++++ ...preprocessor.cpp_style_line_directive.vert | 36 +++++++++++++++++++ Test/test-preprocessor-list | 1 + glslang/Include/Common.h | 3 +- glslang/Include/InfoSink.h | 9 +++-- glslang/MachineIndependent/ParseHelper.cpp | 4 +-- glslang/MachineIndependent/ParseHelper.h | 7 ++-- glslang/MachineIndependent/Scan.h | 10 +++++- glslang/MachineIndependent/ShaderLang.cpp | 9 +++-- glslang/MachineIndependent/Versions.cpp | 3 ++ glslang/MachineIndependent/Versions.h | 2 ++ .../MachineIndependent/preprocessor/Pp.cpp | 34 +++++++++++++----- 16 files changed, 176 insertions(+), 19 deletions(-) create mode 100644 Test/baseResults/preprocessor.cpp_style___FILE__.vert.err create mode 100644 Test/baseResults/preprocessor.cpp_style___FILE__.vert.out create mode 100644 Test/baseResults/preprocessor.cpp_style_line_directive.vert.err create mode 100644 Test/baseResults/preprocessor.cpp_style_line_directive.vert.out create mode 100644 Test/preprocessor.cpp_style___FILE__.vert create mode 100644 Test/preprocessor.cpp_style_line_directive.vert diff --git a/Test/baseResults/preprocessor.cpp_style___FILE__.vert.err b/Test/baseResults/preprocessor.cpp_style___FILE__.vert.err new file mode 100644 index 000000000..e69de29bb diff --git a/Test/baseResults/preprocessor.cpp_style___FILE__.vert.out b/Test/baseResults/preprocessor.cpp_style___FILE__.vert.out new file mode 100644 index 000000000..5487ac38f --- /dev/null +++ b/Test/baseResults/preprocessor.cpp_style___FILE__.vert.out @@ -0,0 +1,26 @@ +#extension GL_GOOGLE_cpp_style_line_directive : enable + +0 +#line 150 a.h + "a.h" +#line 24 + "a.h" +#line 42 + "a.h" +#line 30 b.cc + "b.cc" +#line 10 3 + 3 +#line 48 + 3 +#line 4 + 3 +#line 55 100 + 100 +#line 1000 c + "c" +#line 42 1 + 1 +#line 42 this-is-a-quite-long-name-maybe-i-should-shorten-it + "this-is-a-quite-long-name-maybe-i-should-shorten-it" + diff --git a/Test/baseResults/preprocessor.cpp_style_line_directive.vert.err b/Test/baseResults/preprocessor.cpp_style_line_directive.vert.err new file mode 100644 index 000000000..dbfc50660 --- /dev/null +++ b/Test/baseResults/preprocessor.cpp_style_line_directive.vert.err @@ -0,0 +1,15 @@ +ERROR: 0:3: '#error' : at 0:3 +ERROR: a.h:150: '#error' : at a.h:150 +ERROR: a.h:24: '#error' : at a.h:24 +ERROR: a.h:42: '#error' : at a.h:42 +ERROR: b.cc:30: '#error' : at b.cc:30 +ERROR: 3:10: '#error' : at 3:10 +ERROR: 3:48: '#error' : at 3:48 +ERROR: 3:4: '#error' : at 3:4 +ERROR: 100:55: '#error' : at 100:55 +ERROR: c:1000: '#error' : at c:1000 +ERROR: 1:42: '#error' : at 1:42 +ERROR: this-is-a-quite-long-name-maybe-i-should-shorten-it:42: '#error' : at this-is-a-quite-long-name-maybe-i-should-shorten-it:42 +ERROR: 12 compilation errors. No code generated. + + diff --git a/Test/baseResults/preprocessor.cpp_style_line_directive.vert.out b/Test/baseResults/preprocessor.cpp_style_line_directive.vert.out new file mode 100644 index 000000000..e69de29bb diff --git a/Test/preprocessor.cpp_style___FILE__.vert b/Test/preprocessor.cpp_style___FILE__.vert new file mode 100644 index 000000000..6d2bc1d81 --- /dev/null +++ b/Test/preprocessor.cpp_style___FILE__.vert @@ -0,0 +1,36 @@ +#extension GL_GOOGLE_cpp_style_line_directive : enable + +__FILE__ + +#line 150 "a.h" +__FILE__ + +#line 24 +__FILE__ + +#line 42 +__FILE__ + +#line 30 "b.cc" +__FILE__ + +#line 10 3 +__FILE__ + +#line 48 +__FILE__ + +#line 4 +__FILE__ + +#line 55 100 +__FILE__ + +#line 1000 "c" +__FILE__ + +#line 42 1 +__FILE__ + +#line 42 "this-is-a-quite-long-name-maybe-i-should-shorten-it" +__FILE__ diff --git a/Test/preprocessor.cpp_style_line_directive.vert b/Test/preprocessor.cpp_style_line_directive.vert new file mode 100644 index 000000000..90fb2614d --- /dev/null +++ b/Test/preprocessor.cpp_style_line_directive.vert @@ -0,0 +1,36 @@ +#extension GL_GOOGLE_cpp_style_line_directive : enable + +#error at "0:3" + +#line 150 "a.h" +#error at "a.h:150" + +#line 24 +#error at "a.h:24" + +#line 42 +#error at "a.h:42" + +#line 30 "b.cc" +#error at "b.cc:30" + +#line 10 3 +#error at "3:10" + +#line 48 +#error at "3:48" + +#line 4 +#error at "3:4" + +#line 55 100 +#error at "100:55" + +#line 1000 "c" +#error at "c:1000" + +#line 42 1 +#error at "1:42" + +#line 42 "this-is-a-quite-long-name-maybe-i-should-shorten-it" +#error at "this-is-a-quite-long-name-maybe-i-should-shorten-it:42" diff --git a/Test/test-preprocessor-list b/Test/test-preprocessor-list index 2816d4095..5ecc57fdc 100644 --- a/Test/test-preprocessor-list +++ b/Test/test-preprocessor-list @@ -1,3 +1,4 @@ +preprocessor.cpp_style_line_directive.vert preprocessor.edge_cases.vert preprocessor.errors.vert preprocessor.extensions.vert diff --git a/glslang/Include/Common.h b/glslang/Include/Common.h index 244ec3dd1..4c59a37c6 100644 --- a/glslang/Include/Common.h +++ b/glslang/Include/Common.h @@ -189,7 +189,8 @@ inline const TString String(const int i, const int base = 10) } struct TSourceLoc { - void init() { string = 0; line = 0; column = 0; } + void init() { name = nullptr; string = 0; line = 0; column = 0; } + const char* name; // descriptive name for this string int string; int line; int column; diff --git a/glslang/Include/InfoSink.h b/glslang/Include/InfoSink.h index c27727afb..92704739a 100644 --- a/glslang/Include/InfoSink.h +++ b/glslang/Include/InfoSink.h @@ -96,9 +96,14 @@ public: } } void location(TSourceLoc loc) { - const int maxSize = 24; + const int maxSize = 24; char locText[maxSize]; - snprintf(locText, maxSize, "%d:%d", loc.string, loc.line); + if (loc.name != nullptr) { + append(loc.name); + snprintf(locText, maxSize, ":%d", loc.line); + } else { + snprintf(locText, maxSize, "%d:%d", loc.string, loc.line); + } append(locText); append(": "); } diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp index d88db56f9..5b90f8edc 100644 --- a/glslang/MachineIndependent/ParseHelper.cpp +++ b/glslang/MachineIndependent/ParseHelper.cpp @@ -5346,10 +5346,10 @@ void TParseContext::notifyErrorDirective(int line, const char* error_message) } } -void TParseContext::notifyLineDirective(int curLineNo, int newLineNo, bool hasSource, int sourceNum) +void TParseContext::notifyLineDirective(int curLineNo, int newLineNo, bool hasSource, int sourceNum, const char* sourceName) { if (lineCallback) { - lineCallback(curLineNo, newLineNo, hasSource, sourceNum); + lineCallback(curLineNo, newLineNo, hasSource, sourceNum, sourceName); } } diff --git a/glslang/MachineIndependent/ParseHelper.h b/glslang/MachineIndependent/ParseHelper.h index 3e74af2ff..4a6d58aee 100644 --- a/glslang/MachineIndependent/ParseHelper.h +++ b/glslang/MachineIndependent/ParseHelper.h @@ -214,6 +214,7 @@ public: int getNumErrors() const { return numErrors; } const TSourceLoc& getCurrentLoc() const { return currentScanner->getSourceLoc(); } void setCurrentLine(int line) { currentScanner->setLine(line); } + void setCurrentSourceName(const char* name) { currentScanner->setFile(name); } void setCurrentString(int string) { currentScanner->setString(string); } void setScanner(TInputScanner* scanner) { currentScanner = scanner; } @@ -221,7 +222,7 @@ public: void notifyVersion(int line, int version, const char* type_string); void notifyErrorDirective(int line, const char* error_message); - void notifyLineDirective(int curLineNo, int newLineNo, bool hasSource, int sourceNum); + void notifyLineDirective(int curLineNo, int newLineNo, bool hasSource, int sourceNum, const char* sourceName); void notifyExtensionDirective(int line, const char* extension, const char* behavior); // The following are implemented in Versions.cpp to localize version/profile/stage/extensions control @@ -243,7 +244,7 @@ public: void setVersionCallback(const std::function& func) { versionCallback = func; } void setPragmaCallback(const std::function&)>& func) { pragmaCallback = func; } - void setLineCallback(const std::function& func) { lineCallback = func; } + void setLineCallback(const std::function& func) { lineCallback = func; } void setExtensionCallback(const std::function& func) { extensionCallback = func; } void setErrorCallback(const std::function& func) { errorCallback = func; } @@ -357,7 +358,7 @@ protected: // These, if set, will be called when a line, pragma ... is preprocessed. // They will be called with any parameters to the original directive. - std::function lineCallback; + std::function lineCallback; std::function&)> pragmaCallback; std::function versionCallback; std::function extensionCallback; diff --git a/glslang/MachineIndependent/Scan.h b/glslang/MachineIndependent/Scan.h index 86de5183e..a6eb80919 100644 --- a/glslang/MachineIndependent/Scan.h +++ b/glslang/MachineIndependent/Scan.h @@ -57,6 +57,9 @@ public: lengths(L), currentSource(0), currentChar(0), stringBias(b), finale(f) { loc = new TSourceLoc[numSources]; + for (int i = 0; i < numSources; ++i) { + loc[i].init(); + } loc[currentSource].string = -stringBias; loc[currentSource].line = 1; loc[currentSource].column = 0; @@ -140,7 +143,12 @@ public: // for #line override void setLine(int newLine) { loc[getLastValidSourceIndex()].line = newLine; } - void setString(int newString) { loc[getLastValidSourceIndex()].string = newString; } + void setFile(const char* filename) { loc[getLastValidSourceIndex()].name = filename; } + void setString(int newString) + { + loc[getLastValidSourceIndex()].string = newString; + loc[getLastValidSourceIndex()].name = nullptr; + } const TSourceLoc& getSourceLoc() const { return loc[std::max(0, std::min(currentSource, numSources - finale - 1))]; } // Returns the index (starting from 0) of the most recent valid source string we are reading from. diff --git a/glslang/MachineIndependent/ShaderLang.cpp b/glslang/MachineIndependent/ShaderLang.cpp index 067a336ab..3955c0b10 100644 --- a/glslang/MachineIndependent/ShaderLang.cpp +++ b/glslang/MachineIndependent/ShaderLang.cpp @@ -690,12 +690,17 @@ struct DoPreprocessing { }); parseContext.setLineCallback([&lineSync, &outputStream, &parseContext]( - int curLineNum, int newLineNum, bool hasSource, int sourceNum) { + int curLineNum, int newLineNum, bool hasSource, int sourceNum, const char* sourceName) { // SourceNum is the number of the source-string that is being parsed. lineSync.syncToLine(curLineNum); outputStream << "#line " << newLineNum; if (hasSource) { - outputStream << " " << sourceNum; + outputStream << " "; + if (sourceName != nullptr) { + outputStream << "\"" << sourceName << "\""; + } else { + outputStream << sourceNum; + } } if (parseContext.lineDirectiveShouldSetNextLine()) { // newLineNum is the new line number for the line following the #line diff --git a/glslang/MachineIndependent/Versions.cpp b/glslang/MachineIndependent/Versions.cpp index 53007d5e2..3b41a9b24 100644 --- a/glslang/MachineIndependent/Versions.cpp +++ b/glslang/MachineIndependent/Versions.cpp @@ -190,6 +190,7 @@ void TParseContext::initializeExtensionBehavior() extensionBehavior[E_GL_EXT_tessellation_point_size] = EBhDisable; extensionBehavior[E_GL_EXT_texture_buffer] = EBhDisablePartial; extensionBehavior[E_GL_EXT_texture_cube_map_array] = EBhDisablePartial; + extensionBehavior[E_GL_GOOGLE_cpp_style_line_directive] = EBhDisable; // OES matching AEP extensionBehavior[E_GL_OES_geometry_shader] = EBhDisable; @@ -233,6 +234,7 @@ const char* TParseContext::getPreamble() "#define GL_EXT_tessellation_point_size 1\n" "#define GL_EXT_texture_buffer 1\n" "#define GL_EXT_texture_cube_map_array 1\n" + "#define GL_GOOGLE_cpp_style_line_directive 1\n" // OES matching AEP "#define GL_OES_geometry_shader 1\n" @@ -264,6 +266,7 @@ const char* TParseContext::getPreamble() "#define GL_ARB_derivative_control 1\n" "#define GL_ARB_shader_texture_image_samples 1\n" "#define GL_ARB_viewport_array 1\n" + "#define GL_GOOGLE_cpp_style_line_directive 1\n" // "#define GL_ARB_cull_distance 1\n" // present for 4.5, but need extension control over block members ; } diff --git a/glslang/MachineIndependent/Versions.h b/glslang/MachineIndependent/Versions.h index 189be377f..527dbc6db 100644 --- a/glslang/MachineIndependent/Versions.h +++ b/glslang/MachineIndependent/Versions.h @@ -129,6 +129,8 @@ const char* const E_GL_EXT_tessellation_point_size = "GL_EXT_tessel const char* const E_GL_EXT_texture_buffer = "GL_EXT_texture_buffer"; const char* const E_GL_EXT_texture_cube_map_array = "GL_EXT_texture_cube_map_array"; +const char* const E_GL_GOOGLE_cpp_style_line_directive = "GL_GOOGLE_cpp_style_line_directive"; + // OES matching AEP const char* const E_GL_OES_geometry_shader = "GL_OES_geometry_shader"; const char* const E_GL_OES_geometry_point_size = "GL_OES_geometry_point_size"; diff --git a/glslang/MachineIndependent/preprocessor/Pp.cpp b/glslang/MachineIndependent/preprocessor/Pp.cpp index b7f8d4899..486b4f80d 100644 --- a/glslang/MachineIndependent/preprocessor/Pp.cpp +++ b/glslang/MachineIndependent/preprocessor/Pp.cpp @@ -612,8 +612,9 @@ int TPpContext::CPPline(TPpToken* ppToken) int lineRes = 0; // Line number after macro expansion. int lineToken = 0; - int fileRes = 0; // Source file number after macro expansion. bool hasFile = false; + int fileRes = 0; // Source file number after macro expansion. + const char* sourceName = nullptr; // Optional source file name. bool lineErr = false; bool fileErr = false; token = eval(token, MIN_PRECEDENCE, false, lineRes, lineErr, ppToken); @@ -627,14 +628,25 @@ int TPpContext::CPPline(TPpToken* ppToken) parseContext.setCurrentLine(lineRes); if (token != '\n') { - token = eval(token, MIN_PRECEDENCE, false, fileRes, fileErr, ppToken); - if (! fileErr) - parseContext.setCurrentString(fileRes); + if (parseContext.extensionTurnedOn(E_GL_GOOGLE_cpp_style_line_directive) && token == PpAtomConstString) { + // We need to save a copy of the string instead of pointing + // to the name field of the token since the name field + // will likely be overwritten by the next token scan. + sourceName = GetAtomString(LookUpAddString(ppToken->name)); + parseContext.setCurrentSourceName(sourceName); hasFile = true; + token = scanToken(ppToken); + } else { + token = eval(token, MIN_PRECEDENCE, false, fileRes, fileErr, ppToken); + if (! fileErr) { + parseContext.setCurrentString(fileRes); + hasFile = true; + } + } } } if (!fileErr && !lineErr) { - parseContext.notifyLineDirective(directiveLoc, lineToken, hasFile, fileRes); + parseContext.notifyLineDirective(directiveLoc, lineToken, hasFile, fileRes, sourceName); } token = extraTokenCheck(PpAtomLine, ppToken, token); @@ -952,11 +964,17 @@ int TPpContext::MacroExpand(int atom, TPpToken* ppToken, bool expandUndef, bool UngetToken(PpAtomConstInt, ppToken); return 1; - case PpAtomFileMacro: - ppToken->ival = parseContext.getCurrentLoc().string; - sprintf(ppToken->name, "%d", ppToken->ival); + case PpAtomFileMacro: { + const char* current_file = parseContext.getCurrentLoc().name; + if (parseContext.extensionTurnedOn(E_GL_GOOGLE_cpp_style_line_directive) && current_file != nullptr) { + sprintf(ppToken->name, "\"%s\"", current_file); + } else { + ppToken->ival = parseContext.getCurrentLoc().string; + sprintf(ppToken->name, "%d", ppToken->ival); + } UngetToken(PpAtomConstInt, ppToken); return 1; + } case PpAtomVersionMacro: ppToken->ival = parseContext.version;