1 // 2 // Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style license that can be 4 // found in the LICENSE file. 5 // 6 7 #ifndef _SYMBOL_TABLE_INCLUDED_ 8 #define _SYMBOL_TABLE_INCLUDED_ 9 10 // 11 // Symbol table for parsing. Has these design characteristics: 12 // 13 // * Same symbol table can be used to compile many shaders, to preserve 14 // effort of creating and loading with the large numbers of built-in 15 // symbols. 16 // 17 // * Name mangling will be used to give each function a unique name 18 // so that symbol table lookups are never ambiguous. This allows 19 // a simpler symbol table structure. 20 // 21 // * Pushing and popping of scope, so symbol table will really be a stack 22 // of symbol tables. Searched from the top, with new inserts going into 23 // the top. 24 // 25 // * Constants: Compile time constant symbols will keep their values 26 // in the symbol table. The parser can substitute constants at parse 27 // time, including doing constant folding and constant propagation. 28 // 29 // * No temporaries: Temporaries made from operations (+, --, .xy, etc.) 30 // are tracked in the intermediate representation, not the symbol table. 31 // 32 33 #include <assert.h> 34 35 #include "common/angleutils.h" 36 #include "compiler/translator/InfoSink.h" 37 #include "compiler/translator/intermediate.h" 38 39 // Symbol base class. (Can build functions or variables out of these...) 40 class TSymbol 41 { 42 public: 43 POOL_ALLOCATOR_NEW_DELETE(); TSymbol(const TString * n)44 TSymbol(const TString *n) 45 : uniqueId(0), 46 name(n) 47 { 48 } ~TSymbol()49 virtual ~TSymbol() 50 { 51 // don't delete name, it's from the pool 52 } 53 getName()54 const TString &getName() const 55 { 56 return *name; 57 } getMangledName()58 virtual const TString &getMangledName() const 59 { 60 return getName(); 61 } isFunction()62 virtual bool isFunction() const 63 { 64 return false; 65 } isVariable()66 virtual bool isVariable() const 67 { 68 return false; 69 } setUniqueId(int id)70 void setUniqueId(int id) 71 { 72 uniqueId = id; 73 } getUniqueId()74 int getUniqueId() const 75 { 76 return uniqueId; 77 } relateToExtension(const TString & ext)78 void relateToExtension(const TString &ext) 79 { 80 extension = ext; 81 } getExtension()82 const TString &getExtension() const 83 { 84 return extension; 85 } 86 87 private: 88 DISALLOW_COPY_AND_ASSIGN(TSymbol); 89 90 int uniqueId; // For real comparing during code generation 91 const TString *name; 92 TString extension; 93 }; 94 95 // Variable class, meaning a symbol that's not a function. 96 // 97 // There could be a separate class heirarchy for Constant variables; 98 // Only one of int, bool, or float, (or none) is correct for 99 // any particular use, but it's easy to do this way, and doesn't 100 // seem worth having separate classes, and "getConst" can't simply return 101 // different values for different types polymorphically, so this is 102 // just simple and pragmatic. 103 class TVariable : public TSymbol 104 { 105 public: 106 TVariable(const TString *name, const TType &t, bool uT = false) TSymbol(name)107 : TSymbol(name), 108 type(t), 109 userType(uT), 110 unionArray(0) 111 { 112 } ~TVariable()113 virtual ~TVariable() 114 { 115 } isVariable()116 virtual bool isVariable() const 117 { 118 return true; 119 } getType()120 TType &getType() 121 { 122 return type; 123 } getType()124 const TType &getType() const 125 { 126 return type; 127 } isUserType()128 bool isUserType() const 129 { 130 return userType; 131 } setQualifier(TQualifier qualifier)132 void setQualifier(TQualifier qualifier) 133 { 134 type.setQualifier(qualifier); 135 } 136 getConstPointer()137 ConstantUnion *getConstPointer() 138 { 139 if (!unionArray) 140 unionArray = new ConstantUnion[type.getObjectSize()]; 141 142 return unionArray; 143 } 144 getConstPointer()145 ConstantUnion *getConstPointer() const 146 { 147 return unionArray; 148 } 149 shareConstPointer(ConstantUnion * constArray)150 void shareConstPointer(ConstantUnion *constArray) 151 { 152 if (unionArray == constArray) 153 return; 154 155 delete[] unionArray; 156 unionArray = constArray; 157 } 158 159 private: 160 DISALLOW_COPY_AND_ASSIGN(TVariable); 161 162 TType type; 163 bool userType; 164 // we are assuming that Pool Allocator will free the memory 165 // allocated to unionArray when this object is destroyed. 166 ConstantUnion *unionArray; 167 }; 168 169 // The function sub-class of symbols and the parser will need to 170 // share this definition of a function parameter. 171 struct TParameter 172 { 173 TString *name; 174 TType *type; 175 }; 176 177 // The function sub-class of a symbol. 178 class TFunction : public TSymbol 179 { 180 public: TFunction(TOperator o)181 TFunction(TOperator o) 182 : TSymbol(0), 183 returnType(TType(EbtVoid, EbpUndefined)), 184 op(o), 185 defined(false) 186 { 187 } 188 TFunction(const TString *name, TType &retType, TOperator tOp = EOpNull) TSymbol(name)189 : TSymbol(name), 190 returnType(retType), 191 mangledName(TFunction::mangleName(*name)), 192 op(tOp), 193 defined(false) 194 { 195 } 196 virtual ~TFunction(); isFunction()197 virtual bool isFunction() const 198 { 199 return true; 200 } 201 mangleName(const TString & name)202 static TString mangleName(const TString &name) 203 { 204 return name + '('; 205 } unmangleName(const TString & mangledName)206 static TString unmangleName(const TString &mangledName) 207 { 208 return TString(mangledName.c_str(), mangledName.find_first_of('(')); 209 } 210 addParameter(TParameter & p)211 void addParameter(TParameter &p) 212 { 213 parameters.push_back(p); 214 mangledName = mangledName + p.type->getMangledName(); 215 } 216 getMangledName()217 const TString &getMangledName() const 218 { 219 return mangledName; 220 } getReturnType()221 const TType &getReturnType() const 222 { 223 return returnType; 224 } 225 relateToOperator(TOperator o)226 void relateToOperator(TOperator o) 227 { 228 op = o; 229 } getBuiltInOp()230 TOperator getBuiltInOp() const 231 { 232 return op; 233 } 234 setDefined()235 void setDefined() 236 { 237 defined = true; 238 } isDefined()239 bool isDefined() 240 { 241 return defined; 242 } 243 getParamCount()244 size_t getParamCount() const 245 { 246 return parameters.size(); 247 } getParam(size_t i)248 const TParameter &getParam(size_t i) const 249 { 250 return parameters[i]; 251 } 252 253 private: 254 DISALLOW_COPY_AND_ASSIGN(TFunction); 255 256 typedef TVector<TParameter> TParamList; 257 TParamList parameters; 258 TType returnType; 259 TString mangledName; 260 TOperator op; 261 bool defined; 262 }; 263 264 // Interface block name sub-symbol 265 class TInterfaceBlockName : public TSymbol 266 { 267 public: TInterfaceBlockName(const TString * name)268 TInterfaceBlockName(const TString *name) 269 : TSymbol(name) 270 { 271 } 272 ~TInterfaceBlockName()273 virtual ~TInterfaceBlockName() 274 { 275 } 276 }; 277 278 class TSymbolTableLevel 279 { 280 public: 281 typedef TMap<TString, TSymbol *> tLevel; 282 typedef tLevel::const_iterator const_iterator; 283 typedef const tLevel::value_type tLevelPair; 284 typedef std::pair<tLevel::iterator, bool> tInsertResult; 285 TSymbolTableLevel()286 TSymbolTableLevel() 287 { 288 } 289 ~TSymbolTableLevel(); 290 291 bool insert(const TString &name, TSymbol &symbol); 292 bool insert(TSymbol &symbol); 293 294 TSymbol *find(const TString &name) const; 295 296 void relateToOperator(const char *name, TOperator op); 297 void relateToExtension(const char *name, const TString &ext); 298 299 protected: 300 tLevel level; 301 static int uniqueId; // for unique identification in code generation 302 }; 303 304 enum ESymbolLevel 305 { 306 COMMON_BUILTINS = 0, 307 ESSL1_BUILTINS = 1, 308 ESSL3_BUILTINS = 2, 309 LAST_BUILTIN_LEVEL = ESSL3_BUILTINS, 310 GLOBAL_LEVEL = 3 311 }; 312 313 class TSymbolTable 314 { 315 public: TSymbolTable()316 TSymbolTable() 317 { 318 // The symbol table cannot be used until push() is called, but 319 // the lack of an initial call to push() can be used to detect 320 // that the symbol table has not been preloaded with built-ins. 321 } 322 323 ~TSymbolTable(); 324 325 // When the symbol table is initialized with the built-ins, there should 326 // 'push' calls, so that built-ins are at level 0 and the shader 327 // globals are at level 1. isEmpty()328 bool isEmpty() 329 { 330 return table.empty(); 331 } atBuiltInLevel()332 bool atBuiltInLevel() 333 { 334 return currentLevel() <= LAST_BUILTIN_LEVEL; 335 } atGlobalLevel()336 bool atGlobalLevel() 337 { 338 return currentLevel() <= GLOBAL_LEVEL; 339 } push()340 void push() 341 { 342 table.push_back(new TSymbolTableLevel); 343 precisionStack.push_back(new PrecisionStackLevel); 344 } 345 pop()346 void pop() 347 { 348 delete table.back(); 349 table.pop_back(); 350 351 delete precisionStack.back(); 352 precisionStack.pop_back(); 353 } 354 declare(TSymbol & symbol)355 bool declare(TSymbol &symbol) 356 { 357 return insert(currentLevel(), symbol); 358 } 359 insert(ESymbolLevel level,TSymbol & symbol)360 bool insert(ESymbolLevel level, TSymbol &symbol) 361 { 362 return table[level]->insert(symbol); 363 } 364 insertConstInt(ESymbolLevel level,const char * name,int value)365 bool insertConstInt(ESymbolLevel level, const char *name, int value) 366 { 367 TVariable *constant = new TVariable( 368 NewPoolTString(name), TType(EbtInt, EbpUndefined, EvqConst, 1)); 369 constant->getConstPointer()->setIConst(value); 370 return insert(level, *constant); 371 } 372 373 void insertBuiltIn(ESymbolLevel level, TType *rvalue, const char *name, 374 TType *ptype1, TType *ptype2 = 0, TType *ptype3 = 0, 375 TType *ptype4 = 0, TType *ptype5 = 0); 376 377 TSymbol *find(const TString &name, int shaderVersion, 378 bool *builtIn = NULL, bool *sameScope = NULL); 379 TSymbol *findBuiltIn(const TString &name, int shaderVersion); 380 getOuterLevel()381 TSymbolTableLevel *getOuterLevel() 382 { 383 assert(currentLevel() >= 1); 384 return table[currentLevel() - 1]; 385 } 386 relateToOperator(ESymbolLevel level,const char * name,TOperator op)387 void relateToOperator(ESymbolLevel level, const char *name, TOperator op) 388 { 389 table[level]->relateToOperator(name, op); 390 } relateToExtension(ESymbolLevel level,const char * name,const TString & ext)391 void relateToExtension(ESymbolLevel level, const char *name, const TString &ext) 392 { 393 table[level]->relateToExtension(name, ext); 394 } 395 void dump(TInfoSink &infoSink) const; 396 setDefaultPrecision(const TPublicType & type,TPrecision prec)397 bool setDefaultPrecision(const TPublicType &type, TPrecision prec) 398 { 399 if (!SupportsPrecision(type.type)) 400 return false; 401 if (type.isAggregate()) 402 return false; // Not allowed to set for aggregate types 403 int indexOfLastElement = static_cast<int>(precisionStack.size()) - 1; 404 // Uses map operator [], overwrites the current value 405 (*precisionStack[indexOfLastElement])[type.type] = prec; 406 return true; 407 } 408 409 // Searches down the precisionStack for a precision qualifier 410 // for the specified TBasicType 411 TPrecision getDefaultPrecision(TBasicType type); 412 nextUniqueId()413 static int nextUniqueId() 414 { 415 return ++uniqueIdCounter; 416 } 417 418 private: currentLevel()419 ESymbolLevel currentLevel() const 420 { 421 return static_cast<ESymbolLevel>(table.size() - 1); 422 } 423 424 std::vector<TSymbolTableLevel *> table; 425 typedef TMap<TBasicType, TPrecision> PrecisionStackLevel; 426 std::vector< PrecisionStackLevel *> precisionStack; 427 428 static int uniqueIdCounter; 429 }; 430 431 #endif // _SYMBOL_TABLE_INCLUDED_ 432