зеркало из https://github.com/stride3d/xkslang.git
Merge pull request #46 from google/include-directive
#include directive support
This commit is contained in:
Коммит
d618070ab0
|
@ -701,8 +701,8 @@ void CompileAndLinkShaders()
|
|||
shader->setStrings(shaderStrings, 1);
|
||||
if (Options & EOptionOutputPreprocessed) {
|
||||
std::string str;
|
||||
if (shader->preprocess(&Resources, defaultVersion, ENoProfile,
|
||||
false, false, messages, &str)) {
|
||||
if (shader->preprocess(&Resources, defaultVersion, ENoProfile, false, false,
|
||||
messages, &str, glslang::TShader::ForbidInclude())) {
|
||||
PutsIfNonEmpty(str.c_str());
|
||||
} else {
|
||||
CompileFailed = true;
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
ERROR: 0:8000: '#include' : required extension not requested: GL_GOOGLE_include_directive
|
||||
ERROR: 0:8000: '#include' : must be followed by a file designation
|
||||
ERROR: 0:8001: '#include' : required extension not requested: GL_GOOGLE_include_directive
|
||||
ERROR: 0:8001: '#include' : must be followed by a file designation
|
||||
ERROR: 0:8002: '#include' : required extension not requested: GL_GOOGLE_include_directive
|
||||
ERROR: 0:8002: '#include' : unexpected include directive
|
||||
ERROR: 0:8003: '#include' : required extension not requested: GL_GOOGLE_include_directive
|
||||
ERROR: 0:8003: '#include' : extra content after file designation
|
||||
ERROR: 0:8004: '#include' : required extension not requested: GL_GOOGLE_include_directive
|
||||
ERROR: 0:8004: '#include' : unexpected include directive
|
||||
ERROR: 10 compilation errors. No code generated.
|
||||
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
ERROR: 0:8000: '#include' : must be followed by a file designation
|
||||
ERROR: 0:8001: '#include' : must be followed by a file designation
|
||||
ERROR: 0:8002: '#include' : unexpected include directive
|
||||
ERROR: 0:8003: '#include' : extra content after file designation
|
||||
ERROR: 0:8004: '#include' : unexpected include directive
|
||||
ERROR: 5 compilation errors. No code generated.
|
||||
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
#line 8000
|
||||
#include
|
||||
#include 123
|
||||
#include "foo"
|
||||
#include "foo" garbage
|
||||
#include "no-eol"
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
#extension GL_GOOGLE_include_directive : enable
|
||||
#line 8000
|
||||
#include
|
||||
#include 123
|
||||
#include "foo"
|
||||
#include "foo" garbage
|
||||
#include "no-eol"
|
|
@ -4,6 +4,8 @@ preprocessor.edge_cases.vert
|
|||
preprocessor.errors.vert
|
||||
preprocessor.extensions.vert
|
||||
preprocessor.function_macro.vert
|
||||
preprocessor.include.enabled.vert
|
||||
preprocessor.include.disabled.vert
|
||||
preprocessor.line.vert
|
||||
preprocessor.line.frag
|
||||
preprocessor.pragma.vert
|
||||
|
|
|
@ -214,9 +214,11 @@ public:
|
|||
int getNumErrors() const { return numErrors; }
|
||||
const TSourceLoc& getCurrentLoc() const { return currentScanner->getSourceLoc(); }
|
||||
void setCurrentLine(int line) { currentScanner->setLine(line); }
|
||||
void setCurrentColumn(int col) { currentScanner->setColumn(col); }
|
||||
void setCurrentSourceName(const char* name) { currentScanner->setFile(name); }
|
||||
void setCurrentString(int string) { currentScanner->setString(string); }
|
||||
void setScanner(TInputScanner* scanner) { currentScanner = scanner; }
|
||||
TInputScanner* getScanner() const { return currentScanner; }
|
||||
|
||||
bool lineDirectiveShouldSetNextLine() const;
|
||||
|
||||
|
@ -235,6 +237,7 @@ public:
|
|||
void checkDeprecated(const TSourceLoc&, int queryProfiles, int depVersion, const char* featureDesc);
|
||||
void requireNotRemoved(const TSourceLoc&, int queryProfiles, int removedVersion, const char* featureDesc);
|
||||
void requireExtensions(const TSourceLoc&, int numExtensions, const char* const extensions[], const char* featureDesc);
|
||||
void ppRequireExtensions(const TSourceLoc&, int numExtensions, const char* const extensions[], const char* featureDesc);
|
||||
TExtensionBehavior getExtensionBehavior(const char*);
|
||||
bool extensionTurnedOn(const char* const extension);
|
||||
bool extensionsTurnedOn(int numExtensions, const char* const extensions[]);
|
||||
|
@ -250,13 +253,14 @@ public:
|
|||
|
||||
protected:
|
||||
void nonInitConstCheck(const TSourceLoc&, TString& identifier, TType& type);
|
||||
void inheritGlobalDefaults(TQualifier& dst) const;
|
||||
void inheritGlobalDefaults(TQualifier& dst) const;
|
||||
TVariable* makeInternalVariable(const char* name, const TType&) const;
|
||||
TVariable* declareNonArray(const TSourceLoc&, TString& identifier, TType&, bool& newDeclaration);
|
||||
void declareArray(const TSourceLoc&, TString& identifier, const TType&, TSymbol*&, bool& newDeclaration);
|
||||
TIntermNode* executeInitializer(const TSourceLoc&, TIntermTyped* initializer, TVariable* variable);
|
||||
TIntermTyped* convertInitializerList(const TSourceLoc&, const TType&, TIntermTyped* initializer);
|
||||
TOperator mapTypeToConstructorOp(const TType&) const;
|
||||
bool checkExtensionsRequested(const TSourceLoc&, int numExtensions, const char* const extensions[], const char* featureDesc);
|
||||
void updateExtensionBehavior(const char* const extension, TExtensionBehavior);
|
||||
void finalErrorCheck();
|
||||
void outputMessage(const TSourceLoc&, const char* szReason, const char* szToken,
|
||||
|
|
|
@ -154,6 +154,9 @@ public:
|
|||
loc[getLastValidSourceIndex()].name = nullptr;
|
||||
}
|
||||
|
||||
// for #include content indentation
|
||||
void setColumn(int col) { loc[getLastValidSourceIndex()].column = col; }
|
||||
|
||||
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.
|
||||
int getLastValidSourceIndex() const { return std::min(currentSource, numSources - 1); }
|
||||
|
|
|
@ -130,7 +130,7 @@ bool InitializeSymbolTable(const TString& builtIns, int version, EProfile profil
|
|||
TIntermediate intermediate(language, version, profile);
|
||||
|
||||
TParseContext parseContext(symbolTable, intermediate, true, version, profile, language, infoSink);
|
||||
TPpContext ppContext(parseContext);
|
||||
TPpContext ppContext(parseContext, TShader::ForbidInclude());
|
||||
TScanContext scanContext(parseContext);
|
||||
parseContext.setScanContext(&scanContext);
|
||||
parseContext.setPpContext(&ppContext);
|
||||
|
@ -463,7 +463,8 @@ bool ProcessDeferred(
|
|||
EShMessages messages, // warnings/errors/AST; things to print out
|
||||
TIntermediate& intermediate, // returned tree, etc.
|
||||
ProcessingContext& processingContext,
|
||||
bool requireNonempty
|
||||
bool requireNonempty,
|
||||
const TShader::Includer& includer
|
||||
)
|
||||
{
|
||||
if (! InitThread())
|
||||
|
@ -565,7 +566,7 @@ bool ProcessDeferred(
|
|||
|
||||
TParseContext parseContext(symbolTable, intermediate, false, version, profile, compiler->getLanguage(), compiler->infoSink, forwardCompatible, messages);
|
||||
glslang::TScanContext scanContext(parseContext);
|
||||
TPpContext ppContext(parseContext);
|
||||
TPpContext ppContext(parseContext, includer);
|
||||
parseContext.setScanContext(&scanContext);
|
||||
parseContext.setPpContext(&ppContext);
|
||||
parseContext.setLimits(*resources);
|
||||
|
@ -838,6 +839,7 @@ bool PreprocessDeferred(
|
|||
bool forceDefaultVersionAndProfile,
|
||||
bool forwardCompatible, // give errors for use of deprecated features
|
||||
EShMessages messages, // warnings/errors/AST; things to print out
|
||||
const TShader::Includer& includer,
|
||||
TIntermediate& intermediate, // returned tree, etc.
|
||||
std::string* outputString)
|
||||
{
|
||||
|
@ -845,7 +847,8 @@ bool PreprocessDeferred(
|
|||
return ProcessDeferred(compiler, shaderStrings, numStrings, inputLengths, stringNames,
|
||||
preamble, optLevel, resources, defaultVersion,
|
||||
defaultProfile, forceDefaultVersionAndProfile,
|
||||
forwardCompatible, messages, intermediate, parser, false);
|
||||
forwardCompatible, messages, intermediate, parser,
|
||||
false, includer);
|
||||
}
|
||||
|
||||
|
||||
|
@ -874,13 +877,15 @@ bool CompileDeferred(
|
|||
bool forceDefaultVersionAndProfile,
|
||||
bool forwardCompatible, // give errors for use of deprecated features
|
||||
EShMessages messages, // warnings/errors/AST; things to print out
|
||||
TIntermediate& intermediate) // returned tree, etc.
|
||||
TIntermediate& intermediate,// returned tree, etc.
|
||||
const TShader::Includer& includer)
|
||||
{
|
||||
DoFullParse parser;
|
||||
return ProcessDeferred(compiler, shaderStrings, numStrings, inputLengths, stringNames,
|
||||
preamble, optLevel, resources, defaultVersion,
|
||||
defaultProfile, forceDefaultVersionAndProfile,
|
||||
forwardCompatible, messages, intermediate, parser, true);
|
||||
forwardCompatible, messages, intermediate, parser,
|
||||
true, includer);
|
||||
}
|
||||
|
||||
} // end anonymous namespace for local functions
|
||||
|
@ -1024,7 +1029,7 @@ int ShCompile(
|
|||
TIntermediate intermediate(compiler->getLanguage());
|
||||
bool success = CompileDeferred(compiler, shaderStrings, numStrings, inputLengths, nullptr,
|
||||
"", optLevel, resources, defaultVersion, ENoProfile, false,
|
||||
forwardCompatible, messages, intermediate);
|
||||
forwardCompatible, messages, intermediate, TShader::ForbidInclude());
|
||||
|
||||
//
|
||||
// Call the machine dependent compiler
|
||||
|
@ -1327,7 +1332,7 @@ void TShader::setStringsWithLengthsAndNames(
|
|||
// Returns true for success.
|
||||
//
|
||||
bool TShader::parse(const TBuiltInResource* builtInResources, int defaultVersion, EProfile defaultProfile, bool forceDefaultVersionAndProfile,
|
||||
bool forwardCompatible, EShMessages messages)
|
||||
bool forwardCompatible, EShMessages messages, const Includer& includer)
|
||||
{
|
||||
if (! InitThread())
|
||||
return false;
|
||||
|
@ -1340,7 +1345,7 @@ bool TShader::parse(const TBuiltInResource* builtInResources, int defaultVersion
|
|||
return CompileDeferred(compiler, strings, numStrings, lengths, stringNames,
|
||||
preamble, EShOptNone, builtInResources, defaultVersion,
|
||||
defaultProfile, forceDefaultVersionAndProfile,
|
||||
forwardCompatible, messages, *intermediate);
|
||||
forwardCompatible, messages, *intermediate, includer);
|
||||
}
|
||||
|
||||
bool TShader::parse(const TBuiltInResource* builtInResources, int defaultVersion, bool forwardCompatible, EShMessages messages)
|
||||
|
@ -1351,9 +1356,11 @@ bool TShader::parse(const TBuiltInResource* builtInResources, int defaultVersion
|
|||
// Fill in a string with the result of preprocessing ShaderStrings
|
||||
// Returns true if all extensions, pragmas and version strings were valid.
|
||||
bool TShader::preprocess(const TBuiltInResource* builtInResources,
|
||||
int defaultVersion, EProfile defaultProfile, bool forceDefaultVersionAndProfile,
|
||||
bool forwardCompatible,
|
||||
EShMessages message, std::string* output_string)
|
||||
int defaultVersion, EProfile defaultProfile,
|
||||
bool forceDefaultVersionAndProfile,
|
||||
bool forwardCompatible, EShMessages message,
|
||||
std::string* output_string,
|
||||
const TShader::Includer& includer)
|
||||
{
|
||||
if (! InitThread())
|
||||
return false;
|
||||
|
@ -1366,7 +1373,7 @@ bool TShader::preprocess(const TBuiltInResource* builtInResources,
|
|||
return PreprocessDeferred(compiler, strings, numStrings, lengths, stringNames, preamble,
|
||||
EShOptNone, builtInResources, defaultVersion,
|
||||
defaultProfile, forceDefaultVersionAndProfile,
|
||||
forwardCompatible, message, *intermediate, output_string);
|
||||
forwardCompatible, message, includer, *intermediate, output_string);
|
||||
}
|
||||
|
||||
const char* TShader::getInfoLog()
|
||||
|
|
|
@ -174,7 +174,9 @@ void TParseContext::initializeExtensionBehavior()
|
|||
extensionBehavior[E_GL_ARB_viewport_array] = EBhDisable;
|
||||
// extensionBehavior[E_GL_ARB_cull_distance] = EBhDisable; // present for 4.5, but need extension control over block members
|
||||
|
||||
// #line and #include
|
||||
extensionBehavior[E_GL_GOOGLE_cpp_style_line_directive] = EBhDisable;
|
||||
extensionBehavior[E_GL_GOOGLE_include_directive] = EBhDisable;
|
||||
|
||||
// AEP
|
||||
extensionBehavior[E_GL_ANDROID_extension_pack_es31a] = EBhDisablePartial;
|
||||
|
@ -219,7 +221,9 @@ const char* TParseContext::getPreamble()
|
|||
"#define GL_OES_EGL_image_external 1\n"
|
||||
"#define GL_EXT_shader_texture_lod 1\n"
|
||||
|
||||
// #line and #include
|
||||
"#define GL_GOOGLE_cpp_style_line_directive 1\n"
|
||||
"#define GL_GOOGLE_include_directive 1\n"
|
||||
|
||||
// AEP
|
||||
"#define GL_ANDROID_extension_pack_es31a 1\n"
|
||||
|
@ -270,6 +274,7 @@ const char* TParseContext::getPreamble()
|
|||
"#define GL_ARB_viewport_array 1\n"
|
||||
|
||||
"#define GL_GOOGLE_cpp_style_line_directive 1\n"
|
||||
"#define GL_GOOGLE_include_directive 1\n"
|
||||
// "#define GL_ARB_cull_distance 1\n" // present for 4.5, but need extension control over block members
|
||||
;
|
||||
}
|
||||
|
@ -406,17 +411,15 @@ void TParseContext::requireNotRemoved(const TSourceLoc& loc, int profileMask, in
|
|||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Use when there are no profile/version to check, it's just an error if one of the
|
||||
// extensions is not present.
|
||||
//
|
||||
void TParseContext::requireExtensions(const TSourceLoc& loc, int numExtensions, const char* const extensions[], const char* featureDesc)
|
||||
// Returns true if at least one of the extensions in the extensions parameter is requested. Otherwise, returns false.
|
||||
// Warns appropriately if the requested behavior of an extension is "warn".
|
||||
bool TParseContext::checkExtensionsRequested(const TSourceLoc& loc, int numExtensions, const char* const extensions[], const char* featureDesc)
|
||||
{
|
||||
// First, see if any of the extensions are enabled
|
||||
for (int i = 0; i < numExtensions; ++i) {
|
||||
TExtensionBehavior behavior = getExtensionBehavior(extensions[i]);
|
||||
if (behavior == EBhEnable || behavior == EBhRequire)
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
// See if any extensions want to give a warning on use; give warnings for all such extensions
|
||||
|
@ -433,7 +436,17 @@ void TParseContext::requireExtensions(const TSourceLoc& loc, int numExtensions,
|
|||
}
|
||||
}
|
||||
if (warned)
|
||||
return;
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// Use when there are no profile/version to check, it's just an error if one of the
|
||||
// extensions is not present.
|
||||
//
|
||||
void TParseContext::requireExtensions(const TSourceLoc& loc, int numExtensions, const char* const extensions[], const char* featureDesc)
|
||||
{
|
||||
if (checkExtensionsRequested(loc, numExtensions, extensions, featureDesc)) return;
|
||||
|
||||
// If we get this far, give errors explaining what extensions are needed
|
||||
if (numExtensions == 1)
|
||||
|
@ -445,6 +458,24 @@ void TParseContext::requireExtensions(const TSourceLoc& loc, int numExtensions,
|
|||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Use by preprocessor when there are no profile/version to check, it's just an error if one of the
|
||||
// extensions is not present.
|
||||
//
|
||||
void TParseContext::ppRequireExtensions(const TSourceLoc& loc, int numExtensions, const char* const extensions[], const char* featureDesc)
|
||||
{
|
||||
if (checkExtensionsRequested(loc, numExtensions, extensions, featureDesc)) return;
|
||||
|
||||
// If we get this far, give errors explaining what extensions are needed
|
||||
if (numExtensions == 1)
|
||||
ppError(loc, "required extension not requested:", featureDesc, extensions[0]);
|
||||
else {
|
||||
ppError(loc, "required extension not requested:", featureDesc, "Possible extensions include:");
|
||||
for (int i = 0; i < numExtensions; ++i)
|
||||
infoSink.info.message(EPrefixNone, extensions[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TExtensionBehavior TParseContext::getExtensionBehavior(const char* extension)
|
||||
{
|
||||
auto iter = extensionBehavior.find(TString(extension));
|
||||
|
@ -525,6 +556,8 @@ void TParseContext::updateExtensionBehavior(int line, const char* extension, con
|
|||
updateExtensionBehavior(line, "GL_EXT_shader_io_blocks", behaviorString);
|
||||
else if (strcmp(extension, "GL_OES_tessellation_shader") == 0)
|
||||
updateExtensionBehavior(line, "GL_OES_shader_io_blocks", behaviorString);
|
||||
else if (strcmp(extension, "GL_GOOGLE_include_directive") == 0)
|
||||
updateExtensionBehavior(line, "GL_GOOGLE_cpp_style_line_directive", behaviorString);
|
||||
}
|
||||
|
||||
void TParseContext::updateExtensionBehavior(const char* extension, TExtensionBehavior behavior)
|
||||
|
|
|
@ -112,7 +112,9 @@ const char* const E_GL_ARB_shader_texture_image_samples = "GL_ARB_shader_texture
|
|||
const char* const E_GL_ARB_viewport_array = "GL_ARB_viewport_array";
|
||||
//const char* const E_GL_ARB_cull_distance = "GL_ARB_cull_distance"; // present for 4.5, but need extension control over block members
|
||||
|
||||
// #line and #include
|
||||
const char* const E_GL_GOOGLE_cpp_style_line_directive = "GL_GOOGLE_cpp_style_line_directive";
|
||||
const char* const E_GL_GOOGLE_include_directive = "GL_GOOGLE_include_directive";
|
||||
|
||||
// AEP
|
||||
const char* const E_GL_ANDROID_extension_pack_es31a = "GL_ANDROID_extension_pack_es31a";
|
||||
|
|
|
@ -83,6 +83,7 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <sstream>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
@ -596,6 +597,51 @@ int TPpContext::CPPifdef(int defined, TPpToken* ppToken)
|
|||
return token;
|
||||
}
|
||||
|
||||
// Handle #include
|
||||
int TPpContext::CPPinclude(TPpToken* ppToken)
|
||||
{
|
||||
const TSourceLoc directiveLoc = ppToken->loc;
|
||||
int token = scanToken(ppToken);
|
||||
if (token != PpAtomConstString) {
|
||||
// TODO: handle angle brackets.
|
||||
parseContext.ppError(directiveLoc, "must be followed by a file designation", "#include", "");
|
||||
} else {
|
||||
// Make a copy of the name because it will be overwritten by the next token scan.
|
||||
const std::string filename = ppToken->name;
|
||||
token = scanToken(ppToken);
|
||||
if (token != '\n' && token != EndOfInput) {
|
||||
parseContext.ppError(ppToken->loc, "extra content after file designation", "#include", "");
|
||||
} else {
|
||||
std::string sourceName;
|
||||
std::string replacement;
|
||||
std::tie(sourceName, replacement) = includer.include(filename.c_str());
|
||||
if (!sourceName.empty()) {
|
||||
if (!replacement.empty()) {
|
||||
const bool forNextLine = parseContext.lineDirectiveShouldSetNextLine();
|
||||
std::ostringstream content;
|
||||
content << "#line " << forNextLine << " " << "\"" << sourceName << "\"\n";
|
||||
content << replacement << (replacement.back() == '\n' ? "" : "\n");
|
||||
content << "#line " << directiveLoc.line + forNextLine << " ";
|
||||
if (directiveLoc.name != nullptr) {
|
||||
content << "\"" << directiveLoc.name << "\"";
|
||||
} else {
|
||||
content << directiveLoc.string;
|
||||
}
|
||||
content << "\n";
|
||||
pushInput(new TokenizableString(directiveLoc, content.str(), this));
|
||||
}
|
||||
// At EOF, there's no "current" location anymore.
|
||||
if (token != EndOfInput) parseContext.setCurrentColumn(0);
|
||||
// Don't accidentally return EndOfInput, which will end all preprocessing.
|
||||
return '\n';
|
||||
} else {
|
||||
parseContext.ppError(directiveLoc, replacement.c_str(), "#include", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
// Handle #line
|
||||
int TPpContext::CPPline(TPpToken* ppToken)
|
||||
{
|
||||
|
@ -629,7 +675,7 @@ int TPpContext::CPPline(TPpToken* ppToken)
|
|||
|
||||
if (token != '\n') {
|
||||
if (token == PpAtomConstString) {
|
||||
parseContext.requireExtensions(directiveLoc, 1, &E_GL_GOOGLE_cpp_style_line_directive, "filename-based #line");
|
||||
parseContext.ppRequireExtensions(directiveLoc, 1, &E_GL_GOOGLE_cpp_style_line_directive, "filename-based #line");
|
||||
// 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.
|
||||
|
@ -845,6 +891,10 @@ int TPpContext::readCPPline(TPpToken* ppToken)
|
|||
case PpAtomIfndef:
|
||||
token = CPPifdef(0, ppToken);
|
||||
break;
|
||||
case PpAtomInclude:
|
||||
parseContext.ppRequireExtensions(ppToken->loc, 1, &E_GL_GOOGLE_include_directive, "#include");
|
||||
token = CPPinclude(ppToken);
|
||||
break;
|
||||
case PpAtomLine:
|
||||
token = CPPline(ppToken);
|
||||
break;
|
||||
|
@ -967,7 +1017,7 @@ int TPpContext::MacroExpand(int atom, TPpToken* ppToken, bool expandUndef, bool
|
|||
|
||||
case PpAtomFileMacro: {
|
||||
if (const char* current_file = parseContext.getCurrentLoc().name) {
|
||||
parseContext.requireExtensions(ppToken->loc, 1, &E_GL_GOOGLE_cpp_style_line_directive, "filename-based __FILE__");
|
||||
parseContext.ppRequireExtensions(ppToken->loc, 1, &E_GL_GOOGLE_cpp_style_line_directive, "filename-based __FILE__");
|
||||
sprintf(ppToken->name, "\"%s\"", current_file);
|
||||
} else {
|
||||
ppToken->ival = parseContext.getCurrentLoc().string;
|
||||
|
|
|
@ -120,6 +120,9 @@ const struct {
|
|||
{ PpAtomLineMacro, "__LINE__" },
|
||||
{ PpAtomFileMacro, "__FILE__" },
|
||||
{ PpAtomVersionMacro, "__VERSION__" },
|
||||
|
||||
{ PpAtomInclude, "include" },
|
||||
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
|
|
@ -83,8 +83,8 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
namespace glslang {
|
||||
|
||||
TPpContext::TPpContext(TParseContext& pc) :
|
||||
preamble(0), strings(0), parseContext(pc), inComment(false)
|
||||
TPpContext::TPpContext(TParseContext& pc, const TShader::Includer& inclr) :
|
||||
preamble(0), strings(0), parseContext(pc), includer(inclr), inComment(false)
|
||||
{
|
||||
InitAtomTable();
|
||||
InitScanner();
|
||||
|
|
|
@ -118,7 +118,7 @@ class TInputScanner;
|
|||
// Don't expect too much in terms of OO design.
|
||||
class TPpContext {
|
||||
public:
|
||||
TPpContext(TParseContext&);
|
||||
TPpContext(TParseContext&, const TShader::Includer&);
|
||||
virtual ~TPpContext();
|
||||
|
||||
void setPreamble(const char* preamble, size_t length);
|
||||
|
@ -134,6 +134,10 @@ public:
|
|||
virtual int getch() = 0;
|
||||
virtual void ungetch() = 0;
|
||||
|
||||
// Will be called when we start reading tokens from this instance
|
||||
virtual void notifyActivated() {}
|
||||
// Will be called when we do not read tokens from this instance anymore
|
||||
virtual void notifyDeleted() {}
|
||||
protected:
|
||||
bool done;
|
||||
TPpContext* pp;
|
||||
|
@ -144,9 +148,11 @@ public:
|
|||
void pushInput(tInput* in)
|
||||
{
|
||||
inputStack.push_back(in);
|
||||
in->notifyActivated();
|
||||
}
|
||||
void popInput()
|
||||
{
|
||||
inputStack.back()->notifyDeleted();
|
||||
delete inputStack.back();
|
||||
inputStack.pop_back();
|
||||
}
|
||||
|
@ -281,6 +287,8 @@ protected:
|
|||
// from Pp.cpp
|
||||
//
|
||||
TSourceLoc ifloc; /* outermost #if */
|
||||
// Used to obtain #include content.
|
||||
const TShader::Includer& includer;
|
||||
|
||||
int InitCPP();
|
||||
int CPPdefine(TPpToken * ppToken);
|
||||
|
@ -291,6 +299,7 @@ protected:
|
|||
int evalToToken(int token, bool shortCircuit, int& res, bool& err, TPpToken * ppToken);
|
||||
int CPPif (TPpToken * ppToken);
|
||||
int CPPifdef(int defined, TPpToken * ppToken);
|
||||
int CPPinclude(TPpToken * ppToken);
|
||||
int CPPline(TPpToken * ppToken);
|
||||
int CPPerror(TPpToken * ppToken);
|
||||
int CPPpragma(TPpToken * ppToken);
|
||||
|
@ -419,6 +428,51 @@ protected:
|
|||
TInputScanner* input;
|
||||
};
|
||||
|
||||
// Holds a string that can be tokenized via the tInput interface.
|
||||
class TokenizableString : public tInput {
|
||||
public:
|
||||
// Copies str, which must be non-empty.
|
||||
TokenizableString(const TSourceLoc& startLoc, const std::string& str, TPpContext* pp)
|
||||
: tInput(pp),
|
||||
str_(str),
|
||||
strings(str_.data()),
|
||||
length(str_.size()),
|
||||
scanner(1, &strings, &length),
|
||||
prevScanner(nullptr),
|
||||
stringInput(pp, scanner) {
|
||||
scanner.setLine(startLoc.line);
|
||||
scanner.setString(startLoc.string);
|
||||
scanner.setFile(startLoc.name);
|
||||
}
|
||||
|
||||
// tInput methods:
|
||||
int scan(TPpToken* t) override { return stringInput.scan(t); }
|
||||
int getch() override { return stringInput.getch(); }
|
||||
void ungetch() override { stringInput.ungetch(); }
|
||||
|
||||
void notifyActivated() override
|
||||
{
|
||||
prevScanner = pp->parseContext.getScanner();
|
||||
pp->parseContext.setScanner(&scanner);
|
||||
}
|
||||
void notifyDeleted() override { pp->parseContext.setScanner(prevScanner); }
|
||||
|
||||
private:
|
||||
// Stores the titular string.
|
||||
const std::string str_;
|
||||
// Will point to str_[0] and be passed to scanner constructor.
|
||||
const char* const strings;
|
||||
// Length of str_, passed to scanner constructor.
|
||||
size_t length;
|
||||
// Scans over str_.
|
||||
TInputScanner scanner;
|
||||
// The previous effective scanner before the scanner in this instance
|
||||
// has been activated.
|
||||
TInputScanner* prevScanner;
|
||||
// Delegate object implementing the tInput interface.
|
||||
tStringInput stringInput;
|
||||
};
|
||||
|
||||
int InitScanner();
|
||||
int ScanFromString(char* s);
|
||||
void missingEndifCheck();
|
||||
|
|
|
@ -158,6 +158,9 @@ enum EFixedAtoms {
|
|||
PpAtomFileMacro,
|
||||
PpAtomVersionMacro,
|
||||
|
||||
// #include
|
||||
PpAtomInclude,
|
||||
|
||||
PpAtomLast,
|
||||
};
|
||||
|
||||
|
|
|
@ -249,6 +249,7 @@ SH_IMPORT_EXPORT int ShGetUniformLocation(const ShHandle uniformMap, const char*
|
|||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
class TCompiler;
|
||||
class TInfoSink;
|
||||
|
@ -288,14 +289,35 @@ public:
|
|||
void setStringsWithLengthsAndNames(
|
||||
const char* const* s, const int* l, const char* const* names, int n);
|
||||
void setPreamble(const char* s) { preamble = s; }
|
||||
bool parse(const TBuiltInResource*, int defaultVersion, EProfile defaultProfile, bool forceDefaultVersionAndProfile, bool forwardCompatible, EShMessages);
|
||||
|
||||
// Interface to #include handlers.
|
||||
class Includer {
|
||||
public:
|
||||
// On success, returns the full path and content of the file with the given
|
||||
// filename that replaces "#include filename". On failure, returns an empty
|
||||
// string and an error message.
|
||||
virtual std::pair<std::string, std::string> include(const char* filename) const = 0;
|
||||
};
|
||||
|
||||
// Returns an error message for any #include directive.
|
||||
class ForbidInclude : public Includer {
|
||||
public:
|
||||
std::pair<std::string, std::string> include(const char* filename) const override
|
||||
{
|
||||
return std::make_pair<std::string, std::string>("", "unexpected include directive");
|
||||
}
|
||||
};
|
||||
|
||||
bool parse(const TBuiltInResource*, int defaultVersion, EProfile defaultProfile, bool forceDefaultVersionAndProfile,
|
||||
bool forwardCompatible, EShMessages, const Includer& = ForbidInclude());
|
||||
|
||||
// Equivalent to parse() without a default profile and without forcing defaults.
|
||||
// Provided for backwards compatibility.
|
||||
bool parse(const TBuiltInResource*, int defaultVersion, bool forwardCompatible, EShMessages);
|
||||
bool preprocess(const TBuiltInResource* builtInResources,
|
||||
int defaultVersion, EProfile defaultProfile, bool forceDefaultVersionAndProfile,
|
||||
bool forwardCompatible,
|
||||
EShMessages message, std::string* outputString);
|
||||
bool forwardCompatible, EShMessages message, std::string* outputString,
|
||||
const TShader::Includer& includer);
|
||||
|
||||
const char* getInfoLog();
|
||||
const char* getInfoDebugLog();
|
||||
|
|
Загрузка…
Ссылка в новой задаче