Create a base GLSL front-end from the 3Dlabs glslang front-end from 20-Sep-2005.
[platform/upstream/glslang.git] / glslang / MachineIndependent / SymbolTable.h
1 //
2 //Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
3 //All rights reserved.
4 //
5 //Redistribution and use in source and binary forms, with or without
6 //modification, are permitted provided that the following conditions
7 //are met:
8 //
9 //    Redistributions of source code must retain the above copyright
10 //    notice, this list of conditions and the following disclaimer.
11 //
12 //    Redistributions in binary form must reproduce the above
13 //    copyright notice, this list of conditions and the following
14 //    disclaimer in the documentation and/or other materials provided
15 //    with the distribution.
16 //
17 //    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
18 //    contributors may be used to endorse or promote products derived
19 //    from this software without specific prior written permission.
20 //
21 //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 //"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 //LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 //FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 //COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 //INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 //BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 //LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 //CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 //LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 //ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 //POSSIBILITY OF SUCH DAMAGE.
33 //
34
35 #ifndef _SYMBOL_TABLE_INCLUDED_
36 #define _SYMBOL_TABLE_INCLUDED_
37
38 //
39 // Symbol table for parsing.  Has these design characteristics:
40 //
41 // * Same symbol table can be used to compile many shaders, to preserve
42 //   effort of creating and loading with the large numbers of built-in
43 //   symbols.
44 //
45 // * Name mangling will be used to give each function a unique name
46 //   so that symbol table lookups are never ambiguous.  This allows
47 //   a simpler symbol table structure.
48 //
49 // * Pushing and popping of scope, so symbol table will really be a stack 
50 //   of symbol tables.  Searched from the top, with new inserts going into
51 //   the top.
52 //
53 // * Constants:  Compile time constant symbols will keep their values
54 //   in the symbol table.  The parser can substitute constants at parse
55 //   time, including doing constant folding and constant propagation.
56 //
57 // * No temporaries:  Temporaries made from operations (+, --, .xy, etc.)
58 //   are tracked in the intermediate representation, not the symbol table.
59 //
60
61 #include "Include/Common.h"
62 #include "Include/intermediate.h"
63 #include "Include/InfoSink.h"
64  
65 //
66 // Symbol base class.  (Can build functions or variables out of these...)
67 //
68 class TSymbol {    
69 public:
70     POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator)
71     TSymbol(const TString *n) :  name(n) { }
72     virtual ~TSymbol() { /* don't delete name, it's from the pool */ }
73     const TString& getName() const { return *name; }
74     virtual const TString& getMangledName() const { return getName(); }
75     virtual bool isFunction() const { return false; }
76     virtual bool isVariable() const { return false; }
77     void setUniqueId(int id) { uniqueId = id; }
78     int getUniqueId() const { return uniqueId; }
79     virtual void dump(TInfoSink &infoSink) const = 0;   
80         TSymbol(const TSymbol&);
81         virtual TSymbol* clone(TStructureMap& remapper) = 0;
82
83 protected:
84     const TString *name;
85     unsigned int uniqueId;      // For real comparing during code generation
86 };
87
88 //
89 // Variable class, meaning a symbol that's not a function.
90 // 
91 // There could be a separate class heirarchy for Constant variables;
92 // Only one of int, bool, or float, (or none) is correct for
93 // any particular use, but it's easy to do this way, and doesn't
94 // seem worth having separate classes, and "getConst" can't simply return
95 // different values for different types polymorphically, so this is 
96 // just simple and pragmatic.
97 //
98 class TVariable : public TSymbol {
99 public:
100     TVariable(const TString *name, const TType& t, bool uT = false ) : TSymbol(name), type(t), userType(uT), unionArray(0), arrayInformationType(0) { }
101     virtual ~TVariable() { }
102     virtual bool isVariable() const { return true; }    
103     TType& getType() { return type; }    
104     const TType& getType() const { return type; }
105     bool isUserType() const { return userType; }
106     void changeQualifier(TQualifier qualifier) { type.changeQualifier(qualifier); }
107     void updateArrayInformationType(TType *t) { arrayInformationType = t; }
108     TType* getArrayInformationType() { return arrayInformationType; }
109
110     virtual void dump(TInfoSink &infoSink) const;
111
112     constUnion* getConstPointer() { 
113         if (!unionArray)
114             unionArray = new constUnion[type.getObjectSize()];
115
116         return unionArray;
117     }
118
119     constUnion* getConstPointer() const { return unionArray; }
120
121     void shareConstPointer( constUnion *constArray)
122     {
123         delete unionArray;
124         unionArray = constArray;  
125     }
126         TVariable(const TVariable&, TStructureMap& remapper); // copy constructor
127         virtual TVariable* clone(TStructureMap& remapper);
128       
129 protected:
130     TType type;
131     bool userType;
132     // we are assuming that Pool Allocator will free the memory allocated to unionArray
133     // when this object is destroyed
134     constUnion *unionArray;
135     TType *arrayInformationType;  // this is used for updating maxArraySize in all the references to a given symbol
136 };
137
138 //
139 // The function sub-class of symbols and the parser will need to
140 // share this definition of a function parameter.
141 //
142 struct TParameter {
143     TString *name;
144     TType* type;
145         void copyParam(const TParameter& param, TStructureMap& remapper) {
146                 name = NewPoolTString(param.name->c_str());
147                 type = param.type->clone(remapper);
148         }
149 };
150
151 //
152 // The function sub-class of a symbol.  
153 //
154 class TFunction : public TSymbol {
155 public:
156     TFunction(TOperator o) :
157         TSymbol(0),
158         returnType(TType(EbtVoid)),
159         op(o),
160         defined(false) { }
161     TFunction(const TString *name, TType& retType, TOperator tOp = EOpNull) : 
162         TSymbol(name), 
163         returnType(retType),
164         mangledName(*name + '('),
165         op(tOp),
166         defined(false) { }
167         virtual ~TFunction();
168     virtual bool isFunction() const { return true; }    
169     
170     void addParameter(TParameter& p) 
171     { 
172         parameters.push_back(p);
173         mangledName = mangledName + p.type->getMangledName();
174     }
175     
176     const TString& getMangledName() const { return mangledName; }
177     const TType& getReturnType() const { return returnType; }
178     void relateToOperator(TOperator o) { op = o; }
179     TOperator getBuiltInOp() const { return op; }
180     void setDefined() { defined = true; }
181     bool isDefined() { return defined; }
182
183     int getParamCount() const { return static_cast<int>(parameters.size()); }    
184           TParameter& operator [](int i)       { return parameters[i]; }
185     const TParameter& operator [](int i) const { return parameters[i]; }
186     
187     virtual void dump(TInfoSink &infoSink) const;
188         TFunction(const TFunction&, TStructureMap& remapper);
189         virtual TFunction* clone(TStructureMap& remapper);
190     
191 protected:
192     typedef TVector<TParameter> TParamList;
193         TParamList parameters;
194     TType returnType;
195     TString mangledName;
196     TOperator op;
197     bool defined;
198 };
199
200
201 class TSymbolTableLevel {
202 public:
203     POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator)
204     TSymbolTableLevel() { }
205         ~TSymbolTableLevel();
206     
207     bool insert(TSymbol& symbol) 
208     {
209         //
210         // returning true means symbol was added to the table
211         //
212         tInsertResult result;
213         result = level.insert(tLevelPair(symbol.getMangledName(), &symbol));
214         
215         return result.second;
216     }
217
218     TSymbol* find(const TString& name) const
219     {
220         tLevel::const_iterator it = level.find(name);
221         if (it == level.end())
222             return 0;
223         else
224             return (*it).second;
225     }
226
227
228     void relateToOperator(const char* name, TOperator op);
229     void dump(TInfoSink &infoSink) const;
230         TSymbolTableLevel* clone(TStructureMap& remapper);
231     
232 protected:
233     typedef std::map<TString, TSymbol*, std::less<TString>, pool_allocator<std::pair<const TString, TSymbol*> > > tLevel;
234     typedef const tLevel::value_type tLevelPair;
235     typedef std::pair<tLevel::iterator, bool> tInsertResult;
236
237     tLevel level;
238 };
239
240 class TSymbolTable {
241 public:
242     TSymbolTable() : uniqueId(0)
243     {
244         //
245         // The symbol table cannot be used until push() is called, but
246         // the lack of an initial call to push() can be used to detect
247         // that the symbol table has not been preloaded with built-ins.
248         //
249     }
250
251     TSymbolTable(TSymbolTable& symTable)
252     {
253         table.push_back(symTable.table[0]);
254         uniqueId = symTable.uniqueId;
255     }
256
257     ~TSymbolTable()
258     {
259         // level 0 is always built In symbols, so we never pop that out
260         while (table.size() > 1)
261             pop();
262     }
263
264     //
265     // When the symbol table is initialized with the built-ins, there should
266     // 'push' calls, so that built-ins are at level 0 and the shader
267     // globals are at level 1.
268     //
269     bool isEmpty() { return table.size() == 0; }
270     bool atBuiltInLevel() { return atSharedBuiltInLevel() || atDynamicBuiltInLevel(); }
271     bool atSharedBuiltInLevel() { return table.size() == 1; }   
272     bool atGlobalLevel() { return table.size() <= 3; }
273     void push() { 
274         table.push_back(new TSymbolTableLevel);
275     }
276
277     void pop() { 
278         delete table[currentLevel()]; 
279         table.pop_back(); 
280     }
281
282     bool insert(TSymbol& symbol)
283     {
284         symbol.setUniqueId(++uniqueId);
285         return table[currentLevel()]->insert(symbol);
286     }
287     
288     TSymbol* find(const TString& name, bool* builtIn = 0, bool *sameScope = 0) 
289     {
290         int level = currentLevel();
291         TSymbol* symbol;
292         do {
293             symbol = table[level]->find(name);
294             --level;
295         } while (symbol == 0 && level >= 0);
296         level++;
297         if (builtIn)
298             *builtIn = level == 0;
299         if (sameScope)
300             *sameScope = level == currentLevel();
301         return symbol;
302     }
303
304     TSymbolTableLevel* getGlobalLevel() { assert(table.size() >= 3); return table[2]; }
305     void relateToOperator(const char* name, TOperator op) { table[0]->relateToOperator(name, op); }
306     int getMaxSymbolId() { return uniqueId; }
307     void dump(TInfoSink &infoSink) const;
308         void copyTable(const TSymbolTable& copyOf);
309
310 protected:    
311     int currentLevel() const { return static_cast<int>(table.size()) - 1; }
312     bool atDynamicBuiltInLevel() { return table.size() == 2; }
313
314     std::vector<TSymbolTableLevel*> table;
315     int uniqueId;     // for unique identification in code generation
316 };
317
318 #endif // _SYMBOL_TABLE_INCLUDED_