blob: bbf3c999dad2b9ca7985b704cdecfa8eb678c522 [file] [log] [blame]
John Kesseniche01a9bc2016-03-12 20:11:22 -07001//
2//Copyright (C) 2016 Google, Inc.
3//
4//All rights reserved.
5//
6//Redistribution and use in source and binary forms, with or without
7//modification, are permitted provided that the following conditions
8//are met:
9//
10// Redistributions of source code must retain the above copyright
11// notice, this list of conditions and the following disclaimer.
12//
13// Redistributions in binary form must reproduce the above
14// copyright notice, this list of conditions and the following
15// disclaimer in the documentation and/or other materials provided
16// with the distribution.
17//
18// Neither the name of Google, Inc., nor the names of its
19// contributors may be used to endorse or promote products derived
20// from this software without specific prior written permission.
21//
22//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33//POSSIBILITY OF SUCH DAMAGE.
34//
35
36#include "hlslTokens.h"
37#include "hlslGrammar.h"
38
39namespace glslang {
40
41// Root entry point to this recursive decent parser.
42// Return true if compilation unit was successfully accepted.
43bool HlslGrammar::parse()
44{
45 advanceToken();
46 return acceptCompilationUnit();
47}
48
49void HlslGrammar::expected(const char* syntax)
50{
51 parseContext.error(token.loc, "Expected", syntax, "");
52}
53
54// Load 'token' with the next token in the stream of tokens.
55void HlslGrammar::advanceToken()
56{
57 scanContext.tokenize(token);
58}
59
60// Return true and advance to the next token if the current token is the
61// expected (passed in) token class.
62bool HlslGrammar::acceptTokenClass(EHlslTokenClass tokenClass)
63{
64 if (token.tokenClass == tokenClass) {
65 advanceToken();
66 return true;
67 }
68
69 return false;
70}
71
72// compilationUnit
73// : list of externalDeclaration
74//
75bool HlslGrammar::acceptCompilationUnit()
76{
77 while (token.tokenClass != EHTokNone) {
78 if (! acceptDeclaration())
79 return false;
80 }
81
82 return true;
83}
84
85// declaration
John Kessenich87142c72016-03-12 20:24:24 -070086// : SEMICOLON
87// : fully_specified_type ;
88// | fully_specified_type identifier ;
89// | fully_specified_type identifier = expression ;
90// | fully_specified_type identifier function_parameters ; // function prototype
91// | fully_specified_type function_parameters compound_statement // function definition
92//
John Kesseniche01a9bc2016-03-12 20:11:22 -070093bool HlslGrammar::acceptDeclaration()
94{
John Kessenich87142c72016-03-12 20:24:24 -070095 // fully_specified_type
96 TType type;
97 if (! acceptFullySpecifiedType(type))
98 return false;
99
100 // identifier
101 if (token.tokenClass == EHTokIdentifier) {
102 TSourceLoc declLoc = token.loc;
103 TString* declName = token.string;
104 advanceToken();
105
106 // = expression
107 TIntermTyped* expressionNode = nullptr;
108 if (acceptTokenClass(EHTokEqual)) {
109 if (! acceptExpression(expressionNode)) {
110 expected("initializer");
111 return false;
112 }
113 }
114
115 // ;
116 if (acceptTokenClass(EHTokSemicolon)) {
117 parseContext.declareVariable(declLoc, *declName, type, 0, expressionNode);
118 return true;
119 }
120 }
121
122 // no identifier, just ;
123 if (acceptTokenClass(EHTokSemicolon))
124 return true;
125
John Kesseniche01a9bc2016-03-12 20:11:22 -0700126 return true;
127}
128
John Kessenich87142c72016-03-12 20:24:24 -0700129// fully_specified_type
130// : type_specifier
131// | type_qualifier type_specifier
132//
133bool HlslGrammar::acceptFullySpecifiedType(TType& type)
134{
135 // type_qualifier
136 TQualifier qualifier;
137 qualifier.clear();
138 acceptQualifier(qualifier);
139
140 // type_specifier
141 if (! acceptType(type))
142 return false;
143 type.getQualifier() = qualifier;
144
145 return true;
146}
147
148// If token is a qualifier, return its token class and advance to the next
149// qualifier. Otherwise, return false, and don't advance.
150void HlslGrammar::acceptQualifier(TQualifier& qualifier)
151{
152 switch (token.tokenClass) {
153 case EHTokUniform:
154 qualifier.storage = EvqUniform;
155 break;
156 case EHTokConst:
157 qualifier.storage = EvqConst;
158 break;
159 default:
160 return;
161 }
162
163 advanceToken();
164}
165
166// If token is for a type, update 'type' with the type information,
167// and return true and advance.
168// Otherwise, return false, and don't advance
169bool HlslGrammar::acceptType(TType& type)
170{
171 if (! token.isType)
172 return false;
173
174 switch (token.tokenClass) {
175 case EHTokInt:
176 case EHTokInt1:
177 case EHTokDword:
178 new(&type) TType(EbtInt);
179 break;
180 case EHTokFloat:
181 case EHTokFloat1:
182 new(&type) TType(EbtFloat);
183 break;
184
185 case EHTokFloat2:
186 new(&type) TType(EbtFloat, EvqTemporary, 2);
187 break;
188 case EHTokFloat3:
189 new(&type) TType(EbtFloat, EvqTemporary, 3);
190 break;
191 case EHTokFloat4:
192 new(&type) TType(EbtFloat, EvqTemporary, 4);
193 break;
194
195 case EHTokInt2:
196 new(&type) TType(EbtInt, EvqTemporary, 2);
197 break;
198 case EHTokInt3:
199 new(&type) TType(EbtInt, EvqTemporary, 3);
200 break;
201 case EHTokInt4:
202 new(&type) TType(EbtInt, EvqTemporary, 4);
203 break;
204
205 case EHTokBool2:
206 new(&type) TType(EbtBool, EvqTemporary, 2);
207 break;
208 case EHTokBool3:
209 new(&type) TType(EbtBool, EvqTemporary, 3);
210 break;
211 case EHTokBool4:
212 new(&type) TType(EbtBool, EvqTemporary, 4);
213 break;
214
215 case EHTokFloat2x2:
216 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 2);
217 break;
218 case EHTokFloat2x3:
219 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 2);
220 break;
221 case EHTokFloat2x4:
222 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 2);
223 break;
224 case EHTokFloat3x2:
225 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 3);
226 break;
227 case EHTokFloat3x3:
228 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 3);
229 break;
230 case EHTokFloat3x4:
231 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 3);
232 break;
233 case EHTokFloat4x2:
234 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 4);
235 break;
236 case EHTokFloat4x3:
237 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 4);
238 break;
239 case EHTokFloat4x4:
240 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 4);
241 break;
242
243 default:
244 return false;
245 }
246
247 advanceToken();
248
249 return true;
250}
251
252// expression
253// : identifier
254// | ( expression )
255// | type(...) // constructor
256// | literal
257// | identifier + identifier
258//
259bool HlslGrammar::acceptExpression(TIntermTyped*& node)
260{
261 // identifier
262 if (token.tokenClass == EHTokIdentifier) {
263 node = parseContext.handleVariable(token.loc, token.symbol, token.string);
264 return true;
265 }
266
267 // ( expression )
268 if (acceptTokenClass(EHTokLeftParen)) {
269 if (! acceptExpression(node)) {
270 expected("expression");
271 return false;
272 }
273 if (! acceptTokenClass(EHTokRightParen)) {
274 expected("right parenthesis");
275 return false;
276 }
277
278 return true;
279 }
280
281 // literal
282 if (acceptLiteral(node))
283 return true;
284
285 // type(...) // constructor
286 TType type;
287 if (acceptType(type)) {
288 TIntermSequence* arguments;
289 if (! acceptArguments(arguments)) {
290 expected("constructor arguments");
291 return false;
292 }
293
294 return true;
295 }
296
297 // identifier + identifier
298 if (token.tokenClass == EHTokIdentifier) {
299 TIntermTyped* left = parseContext.handleVariable(token.loc, token.symbol, token.string);
300 advanceToken();
301
302 // operator
303 TOperator op;
304 if (! acceptOperator(op))
305 return false;
306 TSourceLoc loc = token.loc;
307
308 // right
309 if (token.tokenClass == EHTokIdentifier) {
310 TIntermTyped* right = parseContext.handleVariable(token.loc, token.symbol, token.string);
311 advanceToken();
312 node = parseContext.intermediate.addBinaryMath(op, left, right, loc);
313 } else
314 return false;
315 } else
316 return false;
317
318 return true;
319}
320
321// arguments
322// : ( expression , expression, ... )
323//
324bool HlslGrammar::acceptArguments(TIntermSequence*& arguments)
325{
326 if (! acceptTokenClass(EHTokLeftParen))
327 return false;
328
329 do {
330 TIntermTyped* arg;
331 if (! acceptExpression(arg))
332 break;
333 if (! acceptTokenClass(EHTokComma))
334 break;
335 } while (true);
336
337 if (! acceptTokenClass(EHTokRightParen)) {
338 expected("right parenthesis");
339 return false;
340 }
341
342 return true;
343}
344
345bool HlslGrammar::acceptLiteral(TIntermTyped*& node)
346{
347 switch (token.tokenClass) {
348 case EHTokIntConstant:
349 node = parseContext.intermediate.addConstantUnion(token.i, token.loc, true);
350 break;
351 case EHTokFloatConstant:
352 node = parseContext.intermediate.addConstantUnion(token.d, EbtFloat, token.loc, true);
353 break;
354 case EHTokDoubleConstant:
355 node = parseContext.intermediate.addConstantUnion(token.d, EbtDouble, token.loc, true);
356 break;
357 case EHTokBoolConstant:
358 node = parseContext.intermediate.addConstantUnion(token.b, token.loc, true);
359 break;
360
361 default:
362 return false;
363 }
364
365 advanceToken();
366
367 return true;
368}
369
370bool HlslGrammar::acceptOperator(TOperator& op)
371{
372 switch (token.tokenClass) {
373 case EHTokPlus:
374 op = EOpAdd;
375 break;
376 default:
377 return false;
378 }
379
380 advanceToken();
381
382 return true;
383}
384
385bool HlslGrammar::acceptCompoundStatement()
386{
387 return false;
388}
389
John Kesseniche01a9bc2016-03-12 20:11:22 -0700390} // end namespace glslang