From b3dc3acd5933fd83568923a1b3b2a8f64563afde Mon Sep 17 00:00:00 2001 From: John Kessenich Date: Sat, 12 Mar 2016 19:08:55 -0700 Subject: [PATCH] Refactor TParseContext into 3 level inheritance. Adds parseVersions.h as the base TParseVersions for versioning, and splits the remainder between TParseContextBase (sharable across parsers) and TParseContext (now the GLSL-specific part). --- glslang/CMakeLists.txt | 1 + glslang/MachineIndependent/ParseHelper.cpp | 45 ++---- glslang/MachineIndependent/ParseHelper.h | 178 +++++++++++---------- glslang/MachineIndependent/ScanContext.h | 4 +- glslang/MachineIndependent/ShaderLang.cpp | 10 +- glslang/MachineIndependent/Versions.cpp | 53 +++--- glslang/MachineIndependent/parseVersions.h | 134 ++++++++++++++++ .../MachineIndependent/preprocessor/PpContext.cpp | 2 +- .../MachineIndependent/preprocessor/PpContext.h | 4 +- 9 files changed, 272 insertions(+), 159 deletions(-) create mode 100755 glslang/MachineIndependent/parseVersions.h diff --git a/glslang/CMakeLists.txt b/glslang/CMakeLists.txt index 28f4742..b6c70c4 100644 --- a/glslang/CMakeLists.txt +++ b/glslang/CMakeLists.txt @@ -63,6 +63,7 @@ set(HEADERS MachineIndependent/ScanContext.h MachineIndependent/SymbolTable.h MachineIndependent/Versions.h + MachineIndependent/parseVersions.h MachineIndependent/preprocessor/PpContext.h MachineIndependent/preprocessor/PpTokens.h) diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp index a43df95..f005da4 100644 --- a/glslang/MachineIndependent/ParseHelper.cpp +++ b/glslang/MachineIndependent/ParseHelper.cpp @@ -48,14 +48,14 @@ extern int yyparse(glslang::TParseContext*); namespace glslang { -TParseContext::TParseContext(TSymbolTable& symt, TIntermediate& interm, bool pb, int v, EProfile p, int spv, int vulkan, EShLanguage L, TInfoSink& is, - bool fc, EShMessages m) : - intermediate(interm), symbolTable(symt), infoSink(is), language(L), - version(v), profile(p), spv(spv), vulkan(vulkan), forwardCompatible(fc), +TParseContext::TParseContext(TSymbolTable& symbolTable, TIntermediate& interm, bool parsingBuiltins, + int version, EProfile profile, int spv, int vulkan, EShLanguage language, + TInfoSink& infoSink, bool forwardCompatible, EShMessages messages) : + TParseContextBase(symbolTable, interm, version, profile, spv, vulkan, language, infoSink, forwardCompatible, messages), contextPragma(true, false), loopNestingLevel(0), structNestingLevel(0), controlFlowNestingLevel(0), statementNestingLevel(0), - postMainReturn(false), - tokensBeforeEOF(false), limits(resources.limits), messages(m), currentScanner(nullptr), - numErrors(0), parsingBuiltins(pb), afterEOF(false), + inMain(false), postMainReturn(false), currentFunctionType(nullptr), blockName(nullptr), + limits(resources.limits), parsingBuiltins(parsingBuiltins), + afterEOF(false), atomicUintOffsets(nullptr), anyIndexLimits(false) { // ensure we always have a linkage node, even if empty, to simplify tree topology algorithms @@ -3133,7 +3133,8 @@ void TParseContext::updateImplicitArraySize(const TSourceLoc& loc, TIntermNode * // Desktop, version 3.30 and later, and ES: "After processing this directive // (including its new-line), the implementation will behave as if it is compiling at line number line and // source string number source-string-number. -bool TParseContext::lineDirectiveShouldSetNextLine() const { +bool TParseContext::lineDirectiveShouldSetNextLine() const +{ return profile == EEsProfile || version >= 330; } @@ -5941,32 +5942,4 @@ TIntermNode* TParseContext::addSwitch(const TSourceLoc& loc, TIntermTyped* expre return switchNode; } -void TParseContext::notifyVersion(int line, int version, const char* type_string) -{ - if (versionCallback) { - versionCallback(line, version, type_string); - } -} - -void TParseContext::notifyErrorDirective(int line, const char* error_message) -{ - if (errorCallback) { - errorCallback(line, error_message); - } -} - -void TParseContext::notifyLineDirective(int curLineNo, int newLineNo, bool hasSource, int sourceNum, const char* sourceName) -{ - if (lineCallback) { - lineCallback(curLineNo, newLineNo, hasSource, sourceNum, sourceName); - } -} - -void TParseContext::notifyExtensionDirective(int line, const char* extension, const char* behavior) -{ - if (extensionCallback) { - extensionCallback(line, extension, behavior); - } -} - } // end namespace glslang diff --git a/glslang/MachineIndependent/ParseHelper.h b/glslang/MachineIndependent/ParseHelper.h index ac1932d..ea5d0ba 100644 --- a/glslang/MachineIndependent/ParseHelper.h +++ b/glslang/MachineIndependent/ParseHelper.h @@ -33,10 +33,18 @@ //ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE //POSSIBILITY OF SUCH DAMAGE. // + +// +// This header defines a two-level parse-helper hierarchy, derived from +// TParseVersions: +// - TParseContextBase: sharable across multiple parsers +// - TParseContext: GLSL specific helper +// + #ifndef _PARSER_HELPER_INCLUDED_ #define _PARSER_HELPER_INCLUDED_ -#include "Versions.h" +#include "parseVersions.h" #include "../Include/ShHandle.h" #include "SymbolTable.h" #include "localintermediate.h" @@ -60,10 +68,88 @@ class TPpContext; typedef std::set TIdSetType; // -// The following are extra variables needed during parsing, grouped together so -// they can be passed to the parser without needing a global. +// Sharable code (as well as what's in TParseVersions) across +// parse helpers. +// +class TParseContextBase : public TParseVersions { +public: + TParseContextBase(TSymbolTable& symbolTable, TIntermediate& interm, int version, + EProfile profile, int spv, int vulkan, EShLanguage language, + TInfoSink& infoSink, bool forwardCompatible, EShMessages messages) + : TParseVersions(interm, version, profile, spv, vulkan, language, infoSink, forwardCompatible, messages), + symbolTable(symbolTable), tokensBeforeEOF(false), + linkage(nullptr), scanContext(nullptr), ppContext(nullptr) { } + virtual ~TParseContextBase() { } + + virtual void setLimits(const TBuiltInResource&) = 0; + + EShLanguage getLanguage() const { return language; } + TIntermAggregate*& getLinkage() { return linkage; } + void setScanContext(TScanContext* c) { scanContext = c; } + TScanContext* getScanContext() const { return scanContext; } + void setPpContext(TPpContext* c) { ppContext = c; } + TPpContext* getPpContext() const { return ppContext; } + + virtual void setLineCallback(const std::function& func) { lineCallback = func; } + virtual void setExtensionCallback(const std::function& func) { extensionCallback = func; } + virtual void setVersionCallback(const std::function& func) { versionCallback = func; } + virtual void setPragmaCallback(const std::function&)>& func) { pragmaCallback = func; } + virtual void setErrorCallback(const std::function& func) { errorCallback = func; } + + virtual void reservedPpErrorCheck(const TSourceLoc&, const char* name, const char* op) = 0; + virtual bool lineContinuationCheck(const TSourceLoc&, bool endOfComment) = 0; + virtual bool lineDirectiveShouldSetNextLine() const = 0; + virtual void handlePragma(const TSourceLoc&, const TVector&) = 0; + + virtual bool parseShaderStrings(TPpContext&, TInputScanner& input, bool versionWillBeError = false) = 0; + + virtual void notifyVersion(int line, int version, const char* type_string) + { + if (versionCallback) + versionCallback(line, version, type_string); + } + virtual void notifyErrorDirective(int line, const char* error_message) + { + if (errorCallback) + errorCallback(line, error_message); + } + virtual void notifyLineDirective(int curLineNo, int newLineNo, bool hasSource, int sourceNum, const char* sourceName) + { + if (lineCallback) + lineCallback(curLineNo, newLineNo, hasSource, sourceNum, sourceName); + } + virtual void notifyExtensionDirective(int line, const char* extension, const char* behavior) + { + if (extensionCallback) + extensionCallback(line, extension, behavior); + } + + TSymbolTable& symbolTable; // symbol table that goes with the current language, version, and profile + bool tokensBeforeEOF; + +protected: + TParseContextBase(TParseContextBase&); + TParseContextBase& operator=(TParseContextBase&); + + TIntermAggregate* linkage; // aggregate node of objects the linker may need, if not referenced by the rest of the AST + TScanContext* scanContext; + TPpContext* ppContext; + + // 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&)> pragmaCallback; + std::function versionCallback; + std::function extensionCallback; + std::function errorCallback; +}; + +// +// GLSL-specific parse helper. Should have GLSL in the name, but that's +// too big of a change for comparing branches at the moment, and perhaps +// impacts downstream consumers as well. // -class TParseContext { +class TParseContext : public TParseContextBase { public: TParseContext(TSymbolTable&, TIntermediate&, bool parsingBuiltins, int version, EProfile, int spv, int vulkan, EShLanguage, TInfoSink&, bool forwardCompatible = false, EShMessages messages = EShMsgDefault); @@ -72,7 +158,6 @@ public: void setLimits(const TBuiltInResource&); bool parseShaderStrings(TPpContext&, TInputScanner& input, bool versionWillBeError = false); void parserError(const char* s); // for bison's yyerror - const char* getPreamble(); void C_DECL error(const TSourceLoc&, const char* szReason, const char* szToken, const char* szExtraInfoFormat, ...); @@ -83,12 +168,10 @@ public: void C_DECL ppWarn(const TSourceLoc&, const char* szReason, const char* szToken, const char* szExtraInfoFormat, ...); - bool relaxedErrors() const { return (messages & EShMsgRelaxedErrors) != 0; } - bool suppressWarnings() const { return (messages & EShMsgSuppressWarnings) != 0; } - void reservedErrorCheck(const TSourceLoc&, const TString&); void reservedPpErrorCheck(const TSourceLoc&, const char* name, const char* op); bool lineContinuationCheck(const TSourceLoc&, bool endOfComment); + bool lineDirectiveShouldSetNextLine() const; bool builtInName(const TString&); void handlePragma(const TSourceLoc&, const TVector&); @@ -210,55 +293,6 @@ public: void updateImplicitArraySize(const TSourceLoc&, TIntermNode*, int index); - void setScanContext(TScanContext* c) { scanContext = c; } - TScanContext* getScanContext() const { return scanContext; } - void setPpContext(TPpContext* c) { ppContext = c; } - TPpContext* getPpContext() const { return ppContext; } - void addError() { ++numErrors; } - 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; - - 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, 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 - void initializeExtensionBehavior(); - void requireProfile(const TSourceLoc&, int queryProfiles, const char* featureDesc); - void profileRequires(const TSourceLoc&, int queryProfiles, int minVersion, int numExtensions, const char* const extensions[], const char* featureDesc); - void profileRequires(const TSourceLoc&, int queryProfiles, int minVersion, const char* const extension, const char* featureDesc); - void requireStage(const TSourceLoc&, EShLanguageMask, const char* featureDesc); - void requireStage(const TSourceLoc&, EShLanguage, const char* featureDesc); - 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[]); - void updateExtensionBehavior(int line, const char* const extension, const char* behavior); - void fullIntegerCheck(const TSourceLoc&, const char* op); - void doubleCheck(const TSourceLoc&, const char* op); - void spvRemoved(const TSourceLoc&, const char* op); - void vulkanRemoved(const TSourceLoc&, const char* op); - void requireVulkan(const TSourceLoc&, const char* op); - void requireSpv(const TSourceLoc&, const char* op); - - 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 setExtensionCallback(const std::function& func) { extensionCallback = func; } - void setErrorCallback(const std::function& func) { errorCallback = func; } - protected: void nonInitConstCheck(const TSourceLoc&, TString& identifier, TType& type); void inheritGlobalDefaults(TQualifier& dst) const; @@ -268,8 +302,6 @@ protected: 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, const char* szExtraInfoFormat, TPrefixType prefix, @@ -280,18 +312,6 @@ public: // Generally, bison productions, the scanner, and the PP need read/write access to these; just give them direct access // - TIntermediate& intermediate; // helper for making and hooking up pieces of the parse tree - TSymbolTable& symbolTable; // symbol table that goes with the current language, version, and profile - TInfoSink& infoSink; - - // compilation mode - EShLanguage language; // vertex or fragment language - int version; // version, updated by #version in the shader - EProfile profile; // the declared profile in the shader (core by default) - int spv; // SPIR-V version; 0 means not SPIR-V - int vulkan; // Vulkan version; 0 means not vulkan - bool forwardCompatible; // true if errors are to be given for use of deprecated features - // Current state of parsing struct TPragma contextPragma; int loopNestingLevel; // 0 if outside all loops @@ -306,9 +326,7 @@ public: bool functionReturnsValue; // true if a non-void function has a return const TString* blockName; TQualifier currentBlockQualifier; - TIntermAggregate *linkage; // aggregate node of objects the linker may need, if not referenced by the rest of the AST TPrecisionQualifier defaultPrecision[EbtNumTypes]; - bool tokensBeforeEOF; TBuiltInResource resources; TLimits& limits; @@ -316,13 +334,7 @@ protected: TParseContext(TParseContext&); TParseContext& operator=(TParseContext&); - EShMessages messages; // errors/warnings/rule-sets - TScanContext* scanContext; - TPpContext* ppContext; - TInputScanner* currentScanner; - int numErrors; // number of compile-time errors encountered bool parsingBuiltins; // true if parsing built-in symbols/functions - TMap extensionBehavior; // for each extension string, what its current behavior is set to static const int maxSamplerIndex = EsdNumDims * (EbtNumTypes * (2 * 2 * 2)); // see computeSamplerTypeIndex() TPrecisionQualifier defaultSamplerPrecision[maxSamplerIndex]; bool afterEOF; @@ -369,14 +381,6 @@ protected: // array-sizing declarations // TVector ioArraySymbolResizeList; - - // 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&)> pragmaCallback; - std::function versionCallback; - std::function extensionCallback; - std::function errorCallback; }; } // end namespace glslang diff --git a/glslang/MachineIndependent/ScanContext.h b/glslang/MachineIndependent/ScanContext.h index 5f1ffb5..f237bee 100644 --- a/glslang/MachineIndependent/ScanContext.h +++ b/glslang/MachineIndependent/ScanContext.h @@ -48,7 +48,7 @@ class TParserToken; class TScanContext { public: - explicit TScanContext(TParseContext& pc) : parseContext(pc), afterType(false), field(false) { } + explicit TScanContext(TParseContextBase& pc) : parseContext(pc), afterType(false), field(false) { } virtual ~TScanContext() { } static void fillInKeywordMap(); @@ -72,7 +72,7 @@ protected: int firstGenerationImage(bool inEs310); int secondGenerationImage(); - TParseContext& parseContext; + TParseContextBase& parseContext; bool afterType; // true if we've recognized a type, so can only be looking for an identifier bool field; // true if we're on a field, right after a '.' TSourceLoc loc; diff --git a/glslang/MachineIndependent/ShaderLang.cpp b/glslang/MachineIndependent/ShaderLang.cpp index 230929a..27bfc69 100644 --- a/glslang/MachineIndependent/ShaderLang.cpp +++ b/glslang/MachineIndependent/ShaderLang.cpp @@ -464,7 +464,7 @@ bool DeduceVersionProfile(TInfoSink& infoSink, EShLanguage stage, bool versionNo // This is the common setup and cleanup code for PreprocessDeferred and // CompileDeferred. // It takes any callable with a signature of -// bool (TParseContext& parseContext, TPpContext& ppContext, +// bool (TParseContextBase& parseContext, TPpContext& ppContext, // TInputScanner& input, bool versionWillBeError, // TSymbolTable& , TIntermediate& , // EShOptimizationLevel , EShMessages ); @@ -717,7 +717,7 @@ private: // It places the result in the "string" argument to its constructor. struct DoPreprocessing { explicit DoPreprocessing(std::string* string): outputString(string) {} - bool operator()(TParseContext& parseContext, TPpContext& ppContext, + bool operator()(TParseContextBase& parseContext, TPpContext& ppContext, TInputScanner& input, bool versionWillBeError, TSymbolTable& , TIntermediate& , EShOptimizationLevel , EShMessages ) @@ -828,7 +828,7 @@ struct DoPreprocessing { // DoFullParse is a valid ProcessingConext template argument for fully // parsing the shader. It populates the "intermediate" with the AST. struct DoFullParse{ - bool operator()(TParseContext& parseContext, TPpContext& ppContext, + bool operator()(TParseContextBase& parseContext, TPpContext& ppContext, TInputScanner& fullInput, bool versionWillBeError, TSymbolTable& symbolTable, TIntermediate& intermediate, EShOptimizationLevel optLevel, EShMessages messages) @@ -837,13 +837,13 @@ struct DoFullParse{ // Parse the full shader. if (! parseContext.parseShaderStrings(ppContext, fullInput, versionWillBeError)) success = false; - intermediate.addSymbolLinkageNodes(parseContext.linkage, parseContext.language, symbolTable); + intermediate.addSymbolLinkageNodes(parseContext.getLinkage(), parseContext.getLanguage(), symbolTable); if (success && intermediate.getTreeRoot()) { if (optLevel == EShOptNoGeneration) parseContext.infoSink.info.message(EPrefixNone, "No errors. No code generation or linking was requested."); else - success = intermediate.postProcess(intermediate.getTreeRoot(), parseContext.language); + success = intermediate.postProcess(intermediate.getTreeRoot(), parseContext.getLanguage()); } else if (! success) { parseContext.infoSink.info.prefix(EPrefixError); parseContext.infoSink.info << parseContext.getNumErrors() << " compilation errors. No code generated.\n\n"; diff --git a/glslang/MachineIndependent/Versions.cpp b/glslang/MachineIndependent/Versions.cpp index 676f4fd..af2f7f2 100644 --- a/glslang/MachineIndependent/Versions.cpp +++ b/glslang/MachineIndependent/Versions.cpp @@ -74,12 +74,12 @@ // // const char* const XXX_extension_X = "XXX_extension_X"; // -// 2) Add extension initialization to TParseContext::initializeExtensionBehavior(), +// 2) Add extension initialization to TParseVersions::initializeExtensionBehavior(), // the first function below: // // extensionBehavior[XXX_extension_X] = EBhDisable; // -// 3) Add any preprocessor directives etc. in the next function, TParseContext::getPreamble(): +// 3) Add any preprocessor directives etc. in the next function, TParseVersions::getPreamble(): // // "#define XXX_extension_X 1\n" // @@ -138,7 +138,8 @@ // table. (There is a different symbol table for each version.) // -#include "ParseHelper.h" +#include "parseVersions.h" +#include "localintermediate.h" namespace glslang { @@ -147,7 +148,7 @@ namespace glslang { // are incorporated into a core version, their features are supported through allowing that // core version, not through a pseudo-enablement of the extension. // -void TParseContext::initializeExtensionBehavior() +void TParseVersions::initializeExtensionBehavior() { extensionBehavior[E_GL_OES_texture_3D] = EBhDisable; extensionBehavior[E_GL_OES_standard_derivatives] = EBhDisable; @@ -213,7 +214,7 @@ void TParseContext::initializeExtensionBehavior() // Get code that is not part of a shared symbol table, is specific to this shader, // or needed by the preprocessor (which does not use a shared symbol table). -const char* TParseContext::getPreamble() +const char* TParseVersions::getPreamble() { if (profile == EEsProfile) { return @@ -297,7 +298,7 @@ const char* TParseContext::getPreamble() // Operation: If the current profile is not one of the profileMask, // give an error message. // -void TParseContext::requireProfile(const TSourceLoc& loc, int profileMask, const char* featureDesc) +void TParseVersions::requireProfile(const TSourceLoc& loc, int profileMask, const char* featureDesc) { if (! (profile & profileMask)) error(loc, "not supported with this profile:", featureDesc, ProfileName(profile)); @@ -336,7 +337,7 @@ const char* StageName(EShLanguage stage) // // entry point that takes multiple extensions -void TParseContext::profileRequires(const TSourceLoc& loc, int profileMask, int minVersion, int numExtensions, const char* const extensions[], const char* featureDesc) +void TParseVersions::profileRequires(const TSourceLoc& loc, int profileMask, int minVersion, int numExtensions, const char* const extensions[], const char* featureDesc) { if (profile & profileMask) { bool okay = false; @@ -361,7 +362,7 @@ void TParseContext::profileRequires(const TSourceLoc& loc, int profileMask, int } // entry point for the above that takes a single extension -void TParseContext::profileRequires(const TSourceLoc& loc, int profileMask, int minVersion, const char* extension, const char* featureDesc) +void TParseVersions::profileRequires(const TSourceLoc& loc, int profileMask, int minVersion, const char* extension, const char* featureDesc) { profileRequires(loc, profileMask, minVersion, extension ? 1 : 0, &extension, featureDesc); } @@ -373,7 +374,7 @@ void TParseContext::profileRequires(const TSourceLoc& loc, int profileMask, int // // Operation: If the current stage is not present, give an error message. // -void TParseContext::requireStage(const TSourceLoc& loc, EShLanguageMask languageMask, const char* featureDesc) +void TParseVersions::requireStage(const TSourceLoc& loc, EShLanguageMask languageMask, const char* featureDesc) { if (((1 << language) & languageMask) == 0) error(loc, "not supported in this stage:", featureDesc, StageName(language)); @@ -381,7 +382,7 @@ void TParseContext::requireStage(const TSourceLoc& loc, EShLanguageMask language // If only one stage supports a feature, this can be called. But, all supporting stages // must be specified with one call. -void TParseContext::requireStage(const TSourceLoc& loc, EShLanguage stage, const char* featureDesc) +void TParseVersions::requireStage(const TSourceLoc& loc, EShLanguage stage, const char* featureDesc) { requireStage(loc, static_cast(1 << stage), featureDesc); } @@ -390,7 +391,7 @@ void TParseContext::requireStage(const TSourceLoc& loc, EShLanguage stage, const // Within a set of profiles, see if a feature is deprecated and give an error or warning based on whether // a future compatibility context is being use. // -void TParseContext::checkDeprecated(const TSourceLoc& loc, int profileMask, int depVersion, const char* featureDesc) +void TParseVersions::checkDeprecated(const TSourceLoc& loc, int profileMask, int depVersion, const char* featureDesc) { if (profile & profileMask) { if (version >= depVersion) { @@ -407,7 +408,7 @@ void TParseContext::checkDeprecated(const TSourceLoc& loc, int profileMask, int // Within a set of profiles, see if a feature has now been removed and if so, give an error. // The version argument is the first version no longer having the feature. // -void TParseContext::requireNotRemoved(const TSourceLoc& loc, int profileMask, int removedVersion, const char* featureDesc) +void TParseVersions::requireNotRemoved(const TSourceLoc& loc, int profileMask, int removedVersion, const char* featureDesc) { if (profile & profileMask) { if (version >= removedVersion) { @@ -421,7 +422,7 @@ void TParseContext::requireNotRemoved(const TSourceLoc& loc, int profileMask, in // 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) +bool TParseVersions::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) { @@ -452,7 +453,7 @@ bool TParseContext::checkExtensionsRequested(const TSourceLoc& loc, int numExten // 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) +void TParseVersions::requireExtensions(const TSourceLoc& loc, int numExtensions, const char* const extensions[], const char* featureDesc) { if (checkExtensionsRequested(loc, numExtensions, extensions, featureDesc)) return; @@ -470,7 +471,7 @@ 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) +void TParseVersions::ppRequireExtensions(const TSourceLoc& loc, int numExtensions, const char* const extensions[], const char* featureDesc) { if (checkExtensionsRequested(loc, numExtensions, extensions, featureDesc)) return; @@ -484,7 +485,7 @@ void TParseContext::ppRequireExtensions(const TSourceLoc& loc, int numExtensions } } -TExtensionBehavior TParseContext::getExtensionBehavior(const char* extension) +TExtensionBehavior TParseVersions::getExtensionBehavior(const char* extension) { auto iter = extensionBehavior.find(TString(extension)); if (iter == extensionBehavior.end()) @@ -494,7 +495,7 @@ TExtensionBehavior TParseContext::getExtensionBehavior(const char* extension) } // Returns true if the given extension is set to enable, require, or warn. -bool TParseContext::extensionTurnedOn(const char* const extension) +bool TParseVersions::extensionTurnedOn(const char* const extension) { switch (getExtensionBehavior(extension)) { case EBhEnable: @@ -507,7 +508,7 @@ bool TParseContext::extensionTurnedOn(const char* const extension) return false; } // See if any of the extensions are set to enable, require, or warn. -bool TParseContext::extensionsTurnedOn(int numExtensions, const char* const extensions[]) +bool TParseVersions::extensionsTurnedOn(int numExtensions, const char* const extensions[]) { for (int i = 0; i < numExtensions; ++i) { if (extensionTurnedOn(extensions[i])) return true; @@ -518,7 +519,7 @@ bool TParseContext::extensionsTurnedOn(int numExtensions, const char* const exte // // Change the current state of an extension's behavior. // -void TParseContext::updateExtensionBehavior(int line, const char* extension, const char* behaviorString) +void TParseVersions::updateExtensionBehavior(int line, const char* extension, const char* behaviorString) { // Translate from text string of extension's behavior to an enum. TExtensionBehavior behavior = EBhDisable; @@ -571,7 +572,7 @@ void TParseContext::updateExtensionBehavior(int line, const char* extension, con spv = 100; } -void TParseContext::updateExtensionBehavior(const char* extension, TExtensionBehavior behavior) +void TParseVersions::updateExtensionBehavior(const char* extension, TExtensionBehavior behavior) { // Update the current behavior if (strcmp(extension, "all") == 0) { @@ -612,14 +613,14 @@ void TParseContext::updateExtensionBehavior(const char* extension, TExtensionBeh } // Call for any operation needing full GLSL integer data-type support. -void TParseContext::fullIntegerCheck(const TSourceLoc& loc, const char* op) +void TParseVersions::fullIntegerCheck(const TSourceLoc& loc, const char* op) { profileRequires(loc, ENoProfile, 130, nullptr, op); profileRequires(loc, EEsProfile, 300, nullptr, op); } // Call for any operation needing GLSL double data-type support. -void TParseContext::doubleCheck(const TSourceLoc& loc, const char* op) +void TParseVersions::doubleCheck(const TSourceLoc& loc, const char* op) { requireProfile(loc, ECoreProfile | ECompatibilityProfile, op); profileRequires(loc, ECoreProfile, 400, nullptr, op); @@ -627,28 +628,28 @@ void TParseContext::doubleCheck(const TSourceLoc& loc, const char* op) } // Call for any operation removed because SPIR-V is in use. -void TParseContext::spvRemoved(const TSourceLoc& loc, const char* op) +void TParseVersions::spvRemoved(const TSourceLoc& loc, const char* op) { if (spv > 0) error(loc, "not allowed when generating SPIR-V", op, ""); } // Call for any operation removed because Vulkan SPIR-V is being generated. -void TParseContext::vulkanRemoved(const TSourceLoc& loc, const char* op) +void TParseVersions::vulkanRemoved(const TSourceLoc& loc, const char* op) { if (vulkan > 0) error(loc, "not allowed when using GLSL for Vulkan", op, ""); } // Call for any operation that requires Vulkan. -void TParseContext::requireVulkan(const TSourceLoc& loc, const char* op) +void TParseVersions::requireVulkan(const TSourceLoc& loc, const char* op) { if (vulkan == 0) error(loc, "only allowed when using GLSL for Vulkan", op, ""); } // Call for any operation that requires SPIR-V. -void TParseContext::requireSpv(const TSourceLoc& loc, const char* op) +void TParseVersions::requireSpv(const TSourceLoc& loc, const char* op) { if (spv == 0) error(loc, "only allowed when generating SPIR-V", op, ""); diff --git a/glslang/MachineIndependent/parseVersions.h b/glslang/MachineIndependent/parseVersions.h new file mode 100755 index 0000000..c9dfdc9 --- /dev/null +++ b/glslang/MachineIndependent/parseVersions.h @@ -0,0 +1,134 @@ +// +//Copyright (C) 2016 Google, Inc. +// +//All rights reserved. +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions +//are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +//POSSIBILITY OF SUCH DAMAGE. +// + +// This is implemented in Versions.cpp + +#ifndef _PARSE_VERSIONS_INCLUDED_ +#define _PARSE_VERSIONS_INCLUDED_ + +#include "../Public/ShaderLang.h" +#include "../Include/InfoSink.h" +#include "Scan.h" + +#include + +namespace glslang { + +// +// Base class for parse helpers. +// This just has version-related information and checking. +// This class should be sufficient for preprocessing. +// +class TParseVersions { +public: + TParseVersions(TIntermediate& interm, int version, EProfile profile, + int spv, int vulkan, EShLanguage language, TInfoSink& infoSink, + bool forwardCompatible, EShMessages messages) + : infoSink(infoSink), version(version), profile(profile), language(language), + spv(spv), vulkan(vulkan), forwardCompatible(forwardCompatible), + intermediate(interm), messages(messages), numErrors(0), currentScanner(0) { } + virtual ~TParseVersions() { } + virtual void initializeExtensionBehavior(); + virtual void requireProfile(const TSourceLoc&, int queryProfiles, const char* featureDesc); + virtual void profileRequires(const TSourceLoc&, int queryProfiles, int minVersion, int numExtensions, const char* const extensions[], const char* featureDesc); + virtual void profileRequires(const TSourceLoc&, int queryProfiles, int minVersion, const char* const extension, const char* featureDesc); + virtual void requireStage(const TSourceLoc&, EShLanguageMask, const char* featureDesc); + virtual void requireStage(const TSourceLoc&, EShLanguage, const char* featureDesc); + virtual void checkDeprecated(const TSourceLoc&, int queryProfiles, int depVersion, const char* featureDesc); + virtual void requireNotRemoved(const TSourceLoc&, int queryProfiles, int removedVersion, const char* featureDesc); + virtual void requireExtensions(const TSourceLoc&, int numExtensions, const char* const extensions[], const char* featureDesc); + virtual void ppRequireExtensions(const TSourceLoc&, int numExtensions, const char* const extensions[], const char* featureDesc); + virtual TExtensionBehavior getExtensionBehavior(const char*); + virtual bool extensionTurnedOn(const char* const extension); + virtual bool extensionsTurnedOn(int numExtensions, const char* const extensions[]); + virtual void updateExtensionBehavior(int line, const char* const extension, const char* behavior); + virtual void fullIntegerCheck(const TSourceLoc&, const char* op); + virtual void doubleCheck(const TSourceLoc&, const char* op); + virtual void spvRemoved(const TSourceLoc&, const char* op); + virtual void vulkanRemoved(const TSourceLoc&, const char* op); + virtual void requireVulkan(const TSourceLoc&, const char* op); + virtual void requireSpv(const TSourceLoc&, const char* op); + virtual bool checkExtensionsRequested(const TSourceLoc&, int numExtensions, const char* const extensions[], const char* featureDesc); + virtual void updateExtensionBehavior(const char* const extension, TExtensionBehavior); + + virtual void C_DECL error(const TSourceLoc&, const char* szReason, const char* szToken, + const char* szExtraInfoFormat, ...) = 0; + virtual void C_DECL warn(const TSourceLoc&, const char* szReason, const char* szToken, + const char* szExtraInfoFormat, ...) = 0; + virtual void C_DECL ppError(const TSourceLoc&, const char* szReason, const char* szToken, + const char* szExtraInfoFormat, ...) = 0; + virtual void C_DECL ppWarn(const TSourceLoc&, const char* szReason, const char* szToken, + const char* szExtraInfoFormat, ...) = 0; + + void addError() { ++numErrors; } + int getNumErrors() const { return numErrors; } + + void setScanner(TInputScanner* scanner) { currentScanner = scanner; } + TInputScanner* getScanner() const { return currentScanner; } + 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); } + + const char* getPreamble(); + bool relaxedErrors() const { return (messages & EShMsgRelaxedErrors) != 0; } + bool suppressWarnings() const { return (messages & EShMsgSuppressWarnings) != 0; } + + TInfoSink& infoSink; + + // compilation mode + int version; // version, updated by #version in the shader + EProfile profile; // the declared profile in the shader (core by default) + EShLanguage language; // really the stage + int spv; // SPIR-V version; 0 means not SPIR-V + int vulkan; // Vulkan version; 0 means not vulkan + bool forwardCompatible; // true if errors are to be given for use of deprecated features + TIntermediate& intermediate; // helper for making and hooking up pieces of the parse tree + +protected: + EShMessages messages; // errors/warnings/rule-sets + int numErrors; // number of compile-time errors encountered + TInputScanner* currentScanner; + +private: + TMap extensionBehavior; // for each extension string, what its current behavior is set to + explicit TParseVersions(const TParseVersions&); + TParseVersions& operator=(const TParseVersions&); +}; + +} // end namespace glslang + +#endif // _PARSE_VERSIONS_INCLUDED_ diff --git a/glslang/MachineIndependent/preprocessor/PpContext.cpp b/glslang/MachineIndependent/preprocessor/PpContext.cpp index b8d2c73..b18ba4f 100644 --- a/glslang/MachineIndependent/preprocessor/PpContext.cpp +++ b/glslang/MachineIndependent/preprocessor/PpContext.cpp @@ -83,7 +83,7 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace glslang { -TPpContext::TPpContext(TParseContext& pc, const TShader::Includer& inclr) : +TPpContext::TPpContext(TParseContextBase& pc, const TShader::Includer& inclr) : preamble(0), strings(0), parseContext(pc), includer(inclr), inComment(false) { InitAtomTable(); diff --git a/glslang/MachineIndependent/preprocessor/PpContext.h b/glslang/MachineIndependent/preprocessor/PpContext.h index f1d5469..6716c7e 100644 --- a/glslang/MachineIndependent/preprocessor/PpContext.h +++ b/glslang/MachineIndependent/preprocessor/PpContext.h @@ -121,7 +121,7 @@ class TInputScanner; // Don't expect too much in terms of OO design. class TPpContext { public: - TPpContext(TParseContext&, const TShader::Includer&); + TPpContext(TParseContextBase&, const TShader::Includer&); virtual ~TPpContext(); void setPreamble(const char* preamble, size_t length); @@ -213,7 +213,7 @@ protected: // Scanner data: int previous_token; - TParseContext& parseContext; + TParseContextBase& parseContext; // Get the next token from *stack* of input sources, popping input sources // that are out of tokens, down until an input sources is found that has a token. -- 2.7.4