1 // 2 //Copyright (C) 2002-2005 3Dlabs Inc. Ltd. 3 //Copyright (C) 2012-2013 LunarG, Inc. 4 // 5 //All rights reserved. 6 // 7 //Redistribution and use in source and binary forms, with or without 8 //modification, are permitted provided that the following conditions 9 //are met: 10 // 11 // Redistributions of source code must retain the above copyright 12 // notice, this list of conditions and the following disclaimer. 13 // 14 // Redistributions in binary form must reproduce the above 15 // copyright notice, this list of conditions and the following 16 // disclaimer in the documentation and/or other materials provided 17 // with the distribution. 18 // 19 // Neither the name of 3Dlabs Inc. Ltd. nor the names of its 20 // contributors may be used to endorse or promote products derived 21 // from this software without specific prior written permission. 22 // 23 //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 //"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 //LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 //FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 27 //COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 28 //INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 29 //BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30 //LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 31 //CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 //LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 33 //ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34 //POSSIBILITY OF SUCH DAMAGE. 35 // 36 37 // 38 // This header defines a two-level parse-helper hierarchy, derived from 39 // TParseVersions: 40 // - TParseContextBase: sharable across multiple parsers 41 // - TParseContext: GLSL specific helper 42 // 43 44 #ifndef _PARSER_HELPER_INCLUDED_ 45 #define _PARSER_HELPER_INCLUDED_ 46 47 #include "parseVersions.h" 48 #include "../Include/ShHandle.h" 49 #include "SymbolTable.h" 50 #include "localintermediate.h" 51 #include "Scan.h" 52 #include <functional> 53 54 #include <functional> 55 56 namespace glslang { 57 58 struct TPragma { 59 TPragma(bool o, bool d) : optimize(o), debug(d) { } 60 bool optimize; 61 bool debug; 62 TPragmaTable pragmaTable; 63 }; 64 65 class TScanContext; 66 class TPpContext; 67 68 typedef std::set<int> TIdSetType; 69 70 // 71 // Sharable code (as well as what's in TParseVersions) across 72 // parse helpers. 73 // 74 class TParseContextBase : public TParseVersions { 75 public: 76 TParseContextBase(TSymbolTable& symbolTable, TIntermediate& interm, int version, 77 EProfile profile, const SpvVersion& spvVersion, EShLanguage language, 78 TInfoSink& infoSink, bool forwardCompatible, EShMessages messages) 79 : TParseVersions(interm, version, profile, spvVersion, language, infoSink, forwardCompatible, messages), 80 symbolTable(symbolTable), tokensBeforeEOF(false), 81 linkage(nullptr), scanContext(nullptr), ppContext(nullptr) { } 82 virtual ~TParseContextBase() { } 83 84 virtual void setLimits(const TBuiltInResource&) = 0; 85 86 EShLanguage getLanguage() const { return language; } 87 TIntermAggregate*& getLinkage() { return linkage; } 88 void setScanContext(TScanContext* c) { scanContext = c; } 89 TScanContext* getScanContext() const { return scanContext; } 90 void setPpContext(TPpContext* c) { ppContext = c; } 91 TPpContext* getPpContext() const { return ppContext; } 92 93 virtual void setLineCallback(const std::function<void(int, int, bool, int, const char*)>& func) { lineCallback = func; } 94 virtual void setExtensionCallback(const std::function<void(int, const char*, const char*)>& func) { extensionCallback = func; } 95 virtual void setVersionCallback(const std::function<void(int, int, const char*)>& func) { versionCallback = func; } 96 virtual void setPragmaCallback(const std::function<void(int, const TVector<TString>&)>& func) { pragmaCallback = func; } 97 virtual void setErrorCallback(const std::function<void(int, const char*)>& func) { errorCallback = func; } 98 99 virtual void reservedPpErrorCheck(const TSourceLoc&, const char* name, const char* op) = 0; 100 virtual bool lineContinuationCheck(const TSourceLoc&, bool endOfComment) = 0; 101 virtual bool lineDirectiveShouldSetNextLine() const = 0; 102 virtual void handlePragma(const TSourceLoc&, const TVector<TString>&) = 0; 103 104 virtual bool parseShaderStrings(TPpContext&, TInputScanner& input, bool versionWillBeError = false) = 0; 105 106 virtual void notifyVersion(int line, int version, const char* type_string) 107 { 108 if (versionCallback) 109 versionCallback(line, version, type_string); 110 } 111 virtual void notifyErrorDirective(int line, const char* error_message) 112 { 113 if (errorCallback) 114 errorCallback(line, error_message); 115 } 116 virtual void notifyLineDirective(int curLineNo, int newLineNo, bool hasSource, int sourceNum, const char* sourceName) 117 { 118 if (lineCallback) 119 lineCallback(curLineNo, newLineNo, hasSource, sourceNum, sourceName); 120 } 121 virtual void notifyExtensionDirective(int line, const char* extension, const char* behavior) 122 { 123 if (extensionCallback) 124 extensionCallback(line, extension, behavior); 125 } 126 127 TSymbolTable& symbolTable; // symbol table that goes with the current language, version, and profile 128 bool tokensBeforeEOF; 129 130 protected: 131 TParseContextBase(TParseContextBase&); 132 TParseContextBase& operator=(TParseContextBase&); 133 134 TIntermAggregate* linkage; // aggregate node of objects the linker may need, if not referenced by the rest of the AST 135 TScanContext* scanContext; 136 TPpContext* ppContext; 137 138 // These, if set, will be called when a line, pragma ... is preprocessed. 139 // They will be called with any parameters to the original directive. 140 std::function<void(int, int, bool, int, const char*)> lineCallback; 141 std::function<void(int, const TVector<TString>&)> pragmaCallback; 142 std::function<void(int, int, const char*)> versionCallback; 143 std::function<void(int, const char*, const char*)> extensionCallback; 144 std::function<void(int, const char*)> errorCallback; 145 }; 146 147 // 148 // GLSL-specific parse helper. Should have GLSL in the name, but that's 149 // too big of a change for comparing branches at the moment, and perhaps 150 // impacts downstream consumers as well. 151 // 152 class TParseContext : public TParseContextBase { 153 public: 154 TParseContext(TSymbolTable&, TIntermediate&, bool parsingBuiltins, int version, EProfile, const SpvVersion& spvVersion, EShLanguage, TInfoSink&, 155 bool forwardCompatible = false, EShMessages messages = EShMsgDefault); 156 virtual ~TParseContext(); 157 158 void setLimits(const TBuiltInResource&); 159 bool parseShaderStrings(TPpContext&, TInputScanner& input, bool versionWillBeError = false); 160 void parserError(const char* s); // for bison's yyerror 161 162 void C_DECL error(const TSourceLoc&, const char* szReason, const char* szToken, 163 const char* szExtraInfoFormat, ...); 164 void C_DECL warn(const TSourceLoc&, const char* szReason, const char* szToken, 165 const char* szExtraInfoFormat, ...); 166 void C_DECL ppError(const TSourceLoc&, const char* szReason, const char* szToken, 167 const char* szExtraInfoFormat, ...); 168 void C_DECL ppWarn(const TSourceLoc&, const char* szReason, const char* szToken, 169 const char* szExtraInfoFormat, ...); 170 171 void reservedErrorCheck(const TSourceLoc&, const TString&); 172 void reservedPpErrorCheck(const TSourceLoc&, const char* name, const char* op); 173 bool lineContinuationCheck(const TSourceLoc&, bool endOfComment); 174 bool lineDirectiveShouldSetNextLine() const; 175 bool builtInName(const TString&); 176 177 void handlePragma(const TSourceLoc&, const TVector<TString>&); 178 TIntermTyped* handleVariable(const TSourceLoc&, TSymbol* symbol, const TString* string); 179 TIntermTyped* handleBracketDereference(const TSourceLoc&, TIntermTyped* base, TIntermTyped* index); 180 void checkIndex(const TSourceLoc&, const TType&, int& index); 181 void handleIndexLimits(const TSourceLoc&, TIntermTyped* base, TIntermTyped* index); 182 183 void makeEditable(TSymbol*&); 184 TVariable* getEditableVariable(const char* name); 185 bool isIoResizeArray(const TType&) const; 186 void fixIoArraySize(const TSourceLoc&, TType&); 187 void ioArrayCheck(const TSourceLoc&, const TType&, const TString& identifier); 188 void handleIoResizeArrayAccess(const TSourceLoc&, TIntermTyped* base); 189 void checkIoArraysConsistency(const TSourceLoc&, bool tailOnly = false); 190 int getIoArrayImplicitSize() const; 191 void checkIoArrayConsistency(const TSourceLoc&, int requiredSize, const char* feature, TType&, const TString&); 192 193 TIntermTyped* handleBinaryMath(const TSourceLoc&, const char* str, TOperator op, TIntermTyped* left, TIntermTyped* right); 194 TIntermTyped* handleUnaryMath(const TSourceLoc&, const char* str, TOperator op, TIntermTyped* childNode); 195 TIntermTyped* handleDotDereference(const TSourceLoc&, TIntermTyped* base, const TString& field); 196 void blockMemberExtensionCheck(const TSourceLoc&, const TIntermTyped* base, const TString& field); 197 TFunction* handleFunctionDeclarator(const TSourceLoc&, TFunction& function, bool prototype); 198 TIntermAggregate* handleFunctionDefinition(const TSourceLoc&, TFunction&); 199 TIntermTyped* handleFunctionCall(const TSourceLoc&, TFunction*, TIntermNode*); 200 TIntermNode* handleReturnValue(const TSourceLoc&, TIntermTyped*); 201 void checkLocation(const TSourceLoc&, TOperator); 202 TIntermTyped* handleLengthMethod(const TSourceLoc&, TFunction*, TIntermNode*); 203 void addInputArgumentConversions(const TFunction&, TIntermNode*&) const; 204 TIntermTyped* addOutputArgumentConversions(const TFunction&, TIntermAggregate&) const; 205 void builtInOpCheck(const TSourceLoc&, const TFunction&, TIntermOperator&); 206 void nonOpBuiltInCheck(const TSourceLoc&, const TFunction&, TIntermAggregate&); 207 TFunction* handleConstructorCall(const TSourceLoc&, const TPublicType&); 208 209 bool parseVectorFields(const TSourceLoc&, const TString&, int vecSize, TVectorFields&); 210 void assignError(const TSourceLoc&, const char* op, TString left, TString right); 211 void unaryOpError(const TSourceLoc&, const char* op, TString operand); 212 void binaryOpError(const TSourceLoc&, const char* op, TString left, TString right); 213 void variableCheck(TIntermTyped*& nodePtr); 214 bool lValueErrorCheck(const TSourceLoc&, const char* op, TIntermTyped*); 215 void rValueErrorCheck(const TSourceLoc&, const char* op, TIntermTyped*); 216 void constantValueCheck(TIntermTyped* node, const char* token); 217 void integerCheck(const TIntermTyped* node, const char* token); 218 void globalCheck(const TSourceLoc&, const char* token); 219 bool constructorError(const TSourceLoc&, TIntermNode*, TFunction&, TOperator, TType&); 220 bool constructorTextureSamplerError(const TSourceLoc&, const TFunction&); 221 void arraySizeCheck(const TSourceLoc&, TIntermTyped* expr, TArraySize&); 222 bool arrayQualifierError(const TSourceLoc&, const TQualifier&); 223 bool arrayError(const TSourceLoc&, const TType&); 224 void arraySizeRequiredCheck(const TSourceLoc&, const TArraySizes&); 225 void structArrayCheck(const TSourceLoc&, const TType& structure); 226 void arrayUnsizedCheck(const TSourceLoc&, const TQualifier&, const TArraySizes*, bool initializer, bool lastMember); 227 void arrayOfArrayVersionCheck(const TSourceLoc&); 228 void arrayDimCheck(const TSourceLoc&, const TArraySizes* sizes1, const TArraySizes* sizes2); 229 void arrayDimCheck(const TSourceLoc&, const TType*, const TArraySizes*); 230 void arrayDimMerge(TType& type, const TArraySizes* sizes); 231 bool voidErrorCheck(const TSourceLoc&, const TString&, TBasicType); 232 void boolCheck(const TSourceLoc&, const TIntermTyped*); 233 void boolCheck(const TSourceLoc&, const TPublicType&); 234 void samplerCheck(const TSourceLoc&, const TType&, const TString& identifier, TIntermTyped* initializer); 235 void atomicUintCheck(const TSourceLoc&, const TType&, const TString& identifier); 236 void transparentCheck(const TSourceLoc&, const TType&, const TString& identifier); 237 void globalQualifierFixCheck(const TSourceLoc&, TQualifier&); 238 void globalQualifierTypeCheck(const TSourceLoc&, const TQualifier&, const TPublicType&); 239 bool structQualifierErrorCheck(const TSourceLoc&, const TPublicType& pType); 240 void mergeQualifiers(const TSourceLoc&, TQualifier& dst, const TQualifier& src, bool force); 241 void setDefaultPrecision(const TSourceLoc&, TPublicType&, TPrecisionQualifier); 242 int computeSamplerTypeIndex(TSampler&); 243 TPrecisionQualifier getDefaultPrecision(TPublicType&); 244 void precisionQualifierCheck(const TSourceLoc&, TBasicType, TQualifier&); 245 void parameterTypeCheck(const TSourceLoc&, TStorageQualifier qualifier, const TType& type); 246 bool containsFieldWithBasicType(const TType& type ,TBasicType basicType); 247 TSymbol* redeclareBuiltinVariable(const TSourceLoc&, const TString&, const TQualifier&, const TShaderQualifiers&, bool& newDeclaration); 248 void redeclareBuiltinBlock(const TSourceLoc&, TTypeList& typeList, const TString& blockName, const TString* instanceName, TArraySizes* arraySizes); 249 void paramCheckFix(const TSourceLoc&, const TStorageQualifier&, TType& type); 250 void paramCheckFix(const TSourceLoc&, const TQualifier&, TType& type); 251 void nestedBlockCheck(const TSourceLoc&); 252 void nestedStructCheck(const TSourceLoc&); 253 void arrayObjectCheck(const TSourceLoc&, const TType&, const char* op); 254 void opaqueCheck(const TSourceLoc&, const TType&, const char* op); 255 void specializationCheck(const TSourceLoc&, const TType&, const char* op); 256 void structTypeCheck(const TSourceLoc&, TPublicType&); 257 void inductiveLoopCheck(const TSourceLoc&, TIntermNode* init, TIntermLoop* loop); 258 void arrayLimitCheck(const TSourceLoc&, const TString&, int size); 259 void limitCheck(const TSourceLoc&, int value, const char* limit, const char* feature); 260 261 void inductiveLoopBodyCheck(TIntermNode*, int loopIndexId, TSymbolTable&); 262 void constantIndexExpressionCheck(TIntermNode*); 263 264 void setLayoutQualifier(const TSourceLoc&, TPublicType&, TString&); 265 void setLayoutQualifier(const TSourceLoc&, TPublicType&, TString&, const TIntermTyped*); 266 void mergeObjectLayoutQualifiers(TQualifier& dest, const TQualifier& src, bool inheritOnly); 267 void layoutObjectCheck(const TSourceLoc&, const TSymbol&); 268 void layoutTypeCheck(const TSourceLoc&, const TType&); 269 void layoutQualifierCheck(const TSourceLoc&, const TQualifier&); 270 void checkNoShaderLayouts(const TSourceLoc&, const TShaderQualifiers&); 271 void fixOffset(const TSourceLoc&, TSymbol&); 272 273 const TFunction* findFunction(const TSourceLoc& loc, const TFunction& call, bool& builtIn); 274 const TFunction* findFunctionExact(const TSourceLoc& loc, const TFunction& call, bool& builtIn); 275 const TFunction* findFunction120(const TSourceLoc& loc, const TFunction& call, bool& builtIn); 276 const TFunction* findFunction400(const TSourceLoc& loc, const TFunction& call, bool& builtIn); 277 void declareTypeDefaults(const TSourceLoc&, const TPublicType&); 278 TIntermNode* declareVariable(const TSourceLoc&, TString& identifier, const TPublicType&, TArraySizes* typeArray = 0, TIntermTyped* initializer = 0); 279 TIntermTyped* addConstructor(const TSourceLoc&, TIntermNode*, const TType&, TOperator); 280 TIntermTyped* constructAggregate(TIntermNode*, const TType&, int, const TSourceLoc&); 281 TIntermTyped* constructBuiltIn(const TType&, TOperator, TIntermTyped*, const TSourceLoc&, bool subset); 282 void declareBlock(const TSourceLoc&, TTypeList& typeList, const TString* instanceName = 0, TArraySizes* arraySizes = 0); 283 void blockStageIoCheck(const TSourceLoc&, const TQualifier&); 284 void blockQualifierCheck(const TSourceLoc&, const TQualifier&, bool instanceName); 285 void fixBlockLocations(const TSourceLoc&, TQualifier&, TTypeList&, bool memberWithLocation, bool memberWithoutLocation); 286 void fixBlockXfbOffsets(TQualifier&, TTypeList&); 287 void fixBlockUniformOffsets(TQualifier&, TTypeList&); 288 void addQualifierToExisting(const TSourceLoc&, TQualifier, const TString& identifier); 289 void addQualifierToExisting(const TSourceLoc&, TQualifier, TIdentifierList&); 290 void invariantCheck(const TSourceLoc&, const TQualifier&); 291 void updateStandaloneQualifierDefaults(const TSourceLoc&, const TPublicType&); 292 void wrapupSwitchSubsequence(TIntermAggregate* statements, TIntermNode* branchNode); 293 TIntermNode* addSwitch(const TSourceLoc&, TIntermTyped* expression, TIntermAggregate* body); 294 295 void updateImplicitArraySize(const TSourceLoc&, TIntermNode*, int index); 296 297 protected: 298 void nonInitConstCheck(const TSourceLoc&, TString& identifier, TType& type); 299 void inheritGlobalDefaults(TQualifier& dst) const; 300 TVariable* makeInternalVariable(const char* name, const TType&) const; 301 TVariable* declareNonArray(const TSourceLoc&, TString& identifier, TType&, bool& newDeclaration); 302 void declareArray(const TSourceLoc&, TString& identifier, const TType&, TSymbol*&, bool& newDeclaration); 303 TIntermNode* executeInitializer(const TSourceLoc&, TIntermTyped* initializer, TVariable* variable); 304 TIntermTyped* convertInitializerList(const TSourceLoc&, const TType&, TIntermTyped* initializer); 305 TOperator mapTypeToConstructorOp(const TType&) const; 306 void finalErrorCheck(); 307 void outputMessage(const TSourceLoc&, const char* szReason, const char* szToken, 308 const char* szExtraInfoFormat, TPrefixType prefix, 309 va_list args); 310 311 public: 312 // 313 // Generally, bison productions, the scanner, and the PP need read/write access to these; just give them direct access 314 // 315 316 // Current state of parsing 317 struct TPragma contextPragma; 318 int loopNestingLevel; // 0 if outside all loops 319 int structNestingLevel; // 0 if outside blocks and structures 320 int controlFlowNestingLevel; // 0 if outside all flow control 321 int statementNestingLevel; // 0 if outside all flow control or compound statements 322 TList<TIntermSequence*> switchSequenceStack; // case, node, case, case, node, ...; ensure only one node between cases; stack of them for nesting 323 TList<int> switchLevel; // the statementNestingLevel the current switch statement is at, which must match the level of its case statements 324 bool inMain; // if inside a function, true if the function is main 325 bool postMainReturn; // if inside a function, true if the function is main and this is after a return statement 326 const TType* currentFunctionType; // the return type of the function that's currently being parsed 327 bool functionReturnsValue; // true if a non-void function has a return 328 const TString* blockName; 329 TQualifier currentBlockQualifier; 330 TPrecisionQualifier defaultPrecision[EbtNumTypes]; 331 TBuiltInResource resources; 332 TLimits& limits; 333 334 protected: 335 TParseContext(TParseContext&); 336 TParseContext& operator=(TParseContext&); 337 338 const bool parsingBuiltins; // true if parsing built-in symbols/functions 339 static const int maxSamplerIndex = EsdNumDims * (EbtNumTypes * (2 * 2 * 2 * 2 * 2)); // see computeSamplerTypeIndex() 340 TPrecisionQualifier defaultSamplerPrecision[maxSamplerIndex]; 341 bool afterEOF; 342 TQualifier globalBufferDefaults; 343 TQualifier globalUniformDefaults; 344 TQualifier globalInputDefaults; 345 TQualifier globalOutputDefaults; 346 int* atomicUintOffsets; // to become an array of the right size to hold an offset per binding point 347 TString currentCaller; // name of last function body entered (not valid when at global scope) 348 TIdSetType inductiveLoopIds; 349 bool anyIndexLimits; 350 TVector<TIntermTyped*> needsIndexLimitationChecking; 351 352 // 353 // Geometry shader input arrays: 354 // - array sizing is based on input primitive and/or explicit size 355 // 356 // Tessellation control output arrays: 357 // - array sizing is based on output layout(vertices=...) and/or explicit size 358 // 359 // Both: 360 // - array sizing is retroactive 361 // - built-in block redeclarations interact with this 362 // 363 // Design: 364 // - use a per-context "resize-list", a list of symbols whose array sizes 365 // can be fixed 366 // 367 // - the resize-list starts empty at beginning of user-shader compilation, it does 368 // not have built-ins in it 369 // 370 // - on built-in array use: copyUp() symbol and add it to the resize-list 371 // 372 // - on user array declaration: add it to the resize-list 373 // 374 // - on block redeclaration: copyUp() symbol and add it to the resize-list 375 // * note, that appropriately gives an error if redeclaring a block that 376 // was already used and hence already copied-up 377 // 378 // - on seeing a layout declaration that sizes the array, fix everything in the 379 // resize-list, giving errors for mismatch 380 // 381 // - on seeing an array size declaration, give errors on mismatch between it and previous 382 // array-sizing declarations 383 // 384 TVector<TSymbol*> ioArraySymbolResizeList; 385 }; 386 387 } // end namespace glslang 388 389 #endif // _PARSER_HELPER_INCLUDED_ 390