1 // 2 // Copyright (c) 2002-2013 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/InfoSink.h" 37 #include "compiler/intermediate.h" 38 39 // 40 // Symbol base class. (Can build functions or variables out of these...) 41 // 42 class TSymbol { 43 public: 44 POOL_ALLOCATOR_NEW_DELETE(); 45 TSymbol(const TString* n) : uniqueId(0), name(n) { } 46 virtual ~TSymbol() { /* don't delete name, it's from the pool */ } 47 48 const TString& getName() const { return *name; } 49 virtual const TString& getMangledName() const { return getName(); } 50 virtual bool isFunction() const { return false; } 51 virtual bool isVariable() const { return false; } 52 void setUniqueId(int id) { uniqueId = id; } 53 int getUniqueId() const { return uniqueId; } 54 virtual void dump(TInfoSink &infoSink) const = 0; 55 void relateToExtension(const TString& ext) { extension = ext; } 56 const TString& getExtension() const { return extension; } 57 58 private: 59 DISALLOW_COPY_AND_ASSIGN(TSymbol); 60 61 int uniqueId; // For real comparing during code generation 62 const TString *name; 63 TString extension; 64 }; 65 66 // 67 // Variable class, meaning a symbol that's not a function. 68 // 69 // There could be a separate class heirarchy for Constant variables; 70 // Only one of int, bool, or float, (or none) is correct for 71 // any particular use, but it's easy to do this way, and doesn't 72 // seem worth having separate classes, and "getConst" can't simply return 73 // different values for different types polymorphically, so this is 74 // just simple and pragmatic. 75 // 76 class TVariable : public TSymbol { 77 public: 78 TVariable(const TString *name, const TType& t, bool uT = false ) : TSymbol(name), type(t), userType(uT), unionArray(0) { } 79 virtual ~TVariable() { } 80 virtual bool isVariable() const { return true; } 81 TType& getType() { return type; } 82 const TType& getType() const { return type; } 83 bool isUserType() const { return userType; } 84 void setQualifier(TQualifier qualifier) { type.setQualifier(qualifier); } 85 86 virtual void dump(TInfoSink &infoSink) const; 87 88 ConstantUnion* getConstPointer() 89 { 90 if (!unionArray) 91 unionArray = new ConstantUnion[type.getObjectSize()]; 92 93 return unionArray; 94 } 95 96 ConstantUnion* getConstPointer() const { return unionArray; } 97 98 void shareConstPointer( ConstantUnion *constArray) 99 { 100 if (unionArray == constArray) 101 return; 102 103 delete[] unionArray; 104 unionArray = constArray; 105 } 106 107 private: 108 DISALLOW_COPY_AND_ASSIGN(TVariable); 109 110 TType type; 111 bool userType; 112 // we are assuming that Pool Allocator will free the memory allocated to unionArray 113 // when this object is destroyed 114 ConstantUnion *unionArray; 115 }; 116 117 // 118 // The function sub-class of symbols and the parser will need to 119 // share this definition of a function parameter. 120 // 121 struct TParameter { 122 TString *name; 123 TType* type; 124 }; 125 126 // 127 // The function sub-class of a symbol. 128 // 129 class TFunction : public TSymbol { 130 public: 131 TFunction(TOperator o) : 132 TSymbol(0), 133 returnType(TType(EbtVoid, EbpUndefined)), 134 op(o), 135 defined(false) { } 136 TFunction(const TString *name, TType& retType, TOperator tOp = EOpNull) : 137 TSymbol(name), 138 returnType(retType), 139 mangledName(TFunction::mangleName(*name)), 140 op(tOp), 141 defined(false) { } 142 virtual ~TFunction(); 143 virtual bool isFunction() const { return true; } 144 145 static TString mangleName(const TString& name) { return name + '('; } 146 static TString unmangleName(const TString& mangledName) 147 { 148 return TString(mangledName.c_str(), mangledName.find_first_of('(')); 149 } 150 151 void addParameter(TParameter& p) 152 { 153 parameters.push_back(p); 154 mangledName = mangledName + p.type->getMangledName(); 155 } 156 157 const TString& getMangledName() const { return mangledName; } 158 const TType& getReturnType() const { return returnType; } 159 160 void relateToOperator(TOperator o) { op = o; } 161 TOperator getBuiltInOp() const { return op; } 162 163 void setDefined() { defined = true; } 164 bool isDefined() { return defined; } 165 166 size_t getParamCount() const { return parameters.size(); } 167 const TParameter& getParam(size_t i) const { return parameters[i]; } 168 169 virtual void dump(TInfoSink &infoSink) const; 170 171 private: 172 DISALLOW_COPY_AND_ASSIGN(TFunction); 173 174 typedef TVector<TParameter> TParamList; 175 TParamList parameters; 176 TType returnType; 177 TString mangledName; 178 TOperator op; 179 bool defined; 180 }; 181 182 183 class TSymbolTableLevel { 184 public: 185 typedef TMap<TString, TSymbol*> tLevel; 186 typedef tLevel::const_iterator const_iterator; 187 typedef const tLevel::value_type tLevelPair; 188 typedef std::pair<tLevel::iterator, bool> tInsertResult; 189 190 TSymbolTableLevel() { } 191 ~TSymbolTableLevel(); 192 193 bool insert(const TString &name, TSymbol &symbol) 194 { 195 // 196 // returning true means symbol was added to the table 197 // 198 tInsertResult result = level.insert(tLevelPair(name, &symbol)); 199 200 return result.second; 201 } 202 203 bool insert(TSymbol &symbol) 204 { 205 return insert(symbol.getMangledName(), symbol); 206 } 207 208 TSymbol* find(const TString& name) const 209 { 210 tLevel::const_iterator it = level.find(name); 211 if (it == level.end()) 212 return 0; 213 else 214 return (*it).second; 215 } 216 217 const_iterator begin() const 218 { 219 return level.begin(); 220 } 221 222 const_iterator end() const 223 { 224 return level.end(); 225 } 226 227 void relateToOperator(const char* name, TOperator op); 228 void relateToExtension(const char* name, const TString& ext); 229 void dump(TInfoSink &infoSink) const; 230 231 protected: 232 tLevel level; 233 }; 234 235 class TSymbolTable { 236 public: 237 TSymbolTable() : uniqueId(0) 238 { 239 // 240 // The symbol table cannot be used until push() is called, but 241 // the lack of an initial call to push() can be used to detect 242 // that the symbol table has not been preloaded with built-ins. 243 // 244 } 245 ~TSymbolTable(); 246 247 // 248 // When the symbol table is initialized with the built-ins, there should 249 // 'push' calls, so that built-ins are at level 0 and the shader 250 // globals are at level 1. 251 // 252 bool isEmpty() { return table.size() == 0; } 253 bool atBuiltInLevel() { return table.size() == 1; } 254 bool atGlobalLevel() { return table.size() <= 2; } 255 void push() 256 { 257 table.push_back(new TSymbolTableLevel); 258 precisionStack.push_back(new PrecisionStackLevel); 259 } 260 261 void pop() 262 { 263 delete table.back(); 264 table.pop_back(); 265 266 delete precisionStack.back(); 267 precisionStack.pop_back(); 268 } 269 270 bool insert(TSymbol& symbol) 271 { 272 symbol.setUniqueId(++uniqueId); 273 return table[currentLevel()]->insert(symbol); 274 } 275 276 bool insertConstInt(const char *name, int value) 277 { 278 TVariable *constant = new TVariable(NewPoolTString(name), TType(EbtInt, EbpUndefined, EvqConst, 1)); 279 constant->getConstPointer()->setIConst(value); 280 return insert(*constant); 281 } 282 283 bool insertBuiltIn(TType *rvalue, const char *name, TType *ptype1, TType *ptype2 = 0, TType *ptype3 = 0) 284 { 285 TFunction *function = new TFunction(NewPoolTString(name), *rvalue); 286 287 TParameter param1 = {NULL, ptype1}; 288 function->addParameter(param1); 289 290 if(ptype2) 291 { 292 TParameter param2 = {NULL, ptype2}; 293 function->addParameter(param2); 294 } 295 296 if(ptype3) 297 { 298 TParameter param3 = {NULL, ptype3}; 299 function->addParameter(param3); 300 } 301 302 return insert(*function); 303 } 304 305 TSymbol* find(const TString& name, bool* builtIn = 0, bool *sameScope = 0) 306 { 307 int level = currentLevel(); 308 TSymbol* symbol; 309 do { 310 symbol = table[level]->find(name); 311 --level; 312 } while (symbol == 0 && level >= 0); 313 level++; 314 if (builtIn) 315 *builtIn = level == 0; 316 if (sameScope) 317 *sameScope = level == currentLevel(); 318 return symbol; 319 } 320 321 TSymbol* findBuiltIn(const TString &name) 322 { 323 return table[0]->find(name); 324 } 325 326 TSymbolTableLevel* getOuterLevel() { 327 assert(table.size() >= 2); 328 return table[currentLevel() - 1]; 329 } 330 331 void relateToOperator(const char* name, TOperator op) { 332 table[0]->relateToOperator(name, op); 333 } 334 void relateToExtension(const char* name, const TString& ext) { 335 table[0]->relateToExtension(name, ext); 336 } 337 void dump(TInfoSink &infoSink) const; 338 339 bool setDefaultPrecision(const TPublicType& type, TPrecision prec) { 340 if (!supportsPrecision(type.type)) 341 return false; 342 if (type.size != 1 || type.matrix || type.array) 343 return false; // Not allowed to set for aggregate types 344 int indexOfLastElement = static_cast<int>(precisionStack.size()) - 1; 345 (*precisionStack[indexOfLastElement])[type.type] = prec; // Uses map operator [], overwrites the current value 346 return true; 347 } 348 349 // Searches down the precisionStack for a precision qualifier for the specified TBasicType 350 TPrecision getDefaultPrecision(TBasicType type) { 351 if (!supportsPrecision(type)) 352 return EbpUndefined; 353 int level = static_cast<int>(precisionStack.size()) - 1; 354 assert(level >= 0); // Just to be safe. Should not happen. 355 PrecisionStackLevel::iterator it; 356 TPrecision prec = EbpUndefined; // If we dont find anything we return this. Should we error check this? 357 while (level >= 0) { 358 it = precisionStack[level]->find(type); 359 if (it != precisionStack[level]->end()) { 360 prec = (*it).second; 361 break; 362 } 363 level--; 364 } 365 return prec; 366 } 367 368 private: 369 int currentLevel() const { return static_cast<int>(table.size()) - 1; } 370 371 bool supportsPrecision(TBasicType type) { 372 // Only supports precision for int, float, and sampler types. 373 return type == EbtFloat || type == EbtInt || IsSampler(type); 374 } 375 376 int uniqueId; // for unique identification in code generation 377 std::vector<TSymbolTableLevel*> table; 378 typedef TMap<TBasicType, TPrecision> PrecisionStackLevel; 379 std::vector<PrecisionStackLevel*> precisionStack; 380 }; 381 382 #endif // _SYMBOL_TABLE_INCLUDED_ 383