blob: 1bd4416580ef587df3a7aeb1a19131b8ac7cb3ae [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
John Kessenichd016be12016-03-13 11:24:20 -060036//
37// This is a set of mutually recursive methods implementing the HLSL grammar.
38// Generally, each returns
39// - through an argument: a type specifically appropriate to which rule it
40// recognized
41// - through the return value: true/false to indicate whether or not it
42// recognized its rule
43//
44// As much as possible, only grammar recognition should happen in this file,
John Kessenich078d7f22016-03-14 10:02:11 -060045// with all other work being farmed out to hlslParseHelper.cpp, which in turn
John Kessenichd016be12016-03-13 11:24:20 -060046// will build the AST.
47//
48// The next token, yet to be "accepted" is always sitting in 'token'.
49// When a method says it accepts a rule, that means all tokens involved
50// in the rule will have been consumed, and none left in 'token'.
51//
52
John Kesseniche01a9bc2016-03-12 20:11:22 -070053#include "hlslTokens.h"
54#include "hlslGrammar.h"
55
56namespace glslang {
57
58// Root entry point to this recursive decent parser.
59// Return true if compilation unit was successfully accepted.
60bool HlslGrammar::parse()
61{
62 advanceToken();
63 return acceptCompilationUnit();
64}
65
66void HlslGrammar::expected(const char* syntax)
67{
68 parseContext.error(token.loc, "Expected", syntax, "");
69}
70
John Kessenichaecd4972016-03-14 10:46:34 -060071// Only process the next token if it is an identifier.
72// Return true if it was an identifier.
73bool HlslGrammar::acceptIdentifier(HlslToken& idToken)
74{
75 if (peekTokenClass(EHTokIdentifier)) {
76 idToken = token;
77 advanceToken();
78 return true;
79 }
80
81 return false;
82}
83
John Kesseniche01a9bc2016-03-12 20:11:22 -070084// compilationUnit
85// : list of externalDeclaration
86//
87bool HlslGrammar::acceptCompilationUnit()
88{
John Kessenichd016be12016-03-13 11:24:20 -060089 TIntermNode* unitNode = nullptr;
90
John Kessenich9c86c6a2016-05-03 22:49:24 -060091 while (! peekTokenClass(EHTokNone)) {
John Kessenichd016be12016-03-13 11:24:20 -060092 // externalDeclaration
93 TIntermNode* declarationNode;
94 if (! acceptDeclaration(declarationNode))
John Kesseniche01a9bc2016-03-12 20:11:22 -070095 return false;
John Kessenichd016be12016-03-13 11:24:20 -060096
97 // hook it up
John Kessenich078d7f22016-03-14 10:02:11 -060098 unitNode = intermediate.growAggregate(unitNode, declarationNode);
John Kesseniche01a9bc2016-03-12 20:11:22 -070099 }
100
John Kessenichd016be12016-03-13 11:24:20 -0600101 // set root of AST
John Kessenich078d7f22016-03-14 10:02:11 -0600102 intermediate.setTreeRoot(unitNode);
John Kessenichd016be12016-03-13 11:24:20 -0600103
John Kesseniche01a9bc2016-03-12 20:11:22 -0700104 return true;
105}
106
107// declaration
John Kessenich078d7f22016-03-14 10:02:11 -0600108// : SEMICOLON
109// : fully_specified_type SEMICOLON
110// | fully_specified_type identifier SEMICOLON
111// | fully_specified_type identifier = expression SEMICOLON
112// | fully_specified_type identifier function_parameters SEMICOLON // function prototype
113// | fully_specified_type identifier function_parameters COLON semantic compound_statement // function definition
John Kessenich87142c72016-03-12 20:24:24 -0700114//
John Kessenichd016be12016-03-13 11:24:20 -0600115// 'node' could get created if the declaration creates code, like an initializer
116// or a function body.
117//
118bool HlslGrammar::acceptDeclaration(TIntermNode*& node)
John Kesseniche01a9bc2016-03-12 20:11:22 -0700119{
John Kessenichd016be12016-03-13 11:24:20 -0600120 node = nullptr;
121
John Kessenich87142c72016-03-12 20:24:24 -0700122 // fully_specified_type
123 TType type;
124 if (! acceptFullySpecifiedType(type))
125 return false;
126
127 // identifier
John Kessenichaecd4972016-03-14 10:46:34 -0600128 HlslToken idToken;
129 if (acceptIdentifier(idToken)) {
John Kessenich87142c72016-03-12 20:24:24 -0700130 // = expression
131 TIntermTyped* expressionNode = nullptr;
John Kessenich34fb0362016-05-03 23:17:20 -0600132 if (acceptTokenClass(EHTokAssign)) {
John Kessenich87142c72016-03-12 20:24:24 -0700133 if (! acceptExpression(expressionNode)) {
134 expected("initializer");
135 return false;
136 }
137 }
138
John Kessenich078d7f22016-03-14 10:02:11 -0600139 // SEMICOLON
John Kessenich87142c72016-03-12 20:24:24 -0700140 if (acceptTokenClass(EHTokSemicolon)) {
John Kessenichaecd4972016-03-14 10:46:34 -0600141 node = parseContext.declareVariable(idToken.loc, *idToken.string, type, 0, expressionNode);
John Kessenich87142c72016-03-12 20:24:24 -0700142 return true;
143 }
John Kessenich5f934b02016-03-13 17:58:25 -0600144
145 // function_parameters
John Kessenichaecd4972016-03-14 10:46:34 -0600146 TFunction* function = new TFunction(idToken.string, type);
John Kessenich5f934b02016-03-13 17:58:25 -0600147 if (acceptFunctionParameters(*function)) {
John Kessenich078d7f22016-03-14 10:02:11 -0600148 // COLON semantic
149 acceptSemantic();
150
John Kessenich5f934b02016-03-13 17:58:25 -0600151 // compound_statement
John Kessenich078d7f22016-03-14 10:02:11 -0600152 if (peekTokenClass(EHTokLeftBrace))
John Kessenich5f934b02016-03-13 17:58:25 -0600153 return acceptFunctionDefinition(*function, node);
154
John Kessenich078d7f22016-03-14 10:02:11 -0600155 // SEMICOLON
John Kessenich5f934b02016-03-13 17:58:25 -0600156 if (acceptTokenClass(EHTokSemicolon))
157 return true;
158
159 return false;
160 }
John Kessenich87142c72016-03-12 20:24:24 -0700161 }
162
John Kessenich078d7f22016-03-14 10:02:11 -0600163 // SEMICOLON
John Kessenich87142c72016-03-12 20:24:24 -0700164 if (acceptTokenClass(EHTokSemicolon))
165 return true;
166
John Kesseniche01a9bc2016-03-12 20:11:22 -0700167 return true;
168}
169
John Kessenich87142c72016-03-12 20:24:24 -0700170// fully_specified_type
171// : type_specifier
172// | type_qualifier type_specifier
173//
174bool HlslGrammar::acceptFullySpecifiedType(TType& type)
175{
176 // type_qualifier
177 TQualifier qualifier;
178 qualifier.clear();
179 acceptQualifier(qualifier);
180
181 // type_specifier
182 if (! acceptType(type))
183 return false;
184 type.getQualifier() = qualifier;
185
186 return true;
187}
188
189// If token is a qualifier, return its token class and advance to the next
190// qualifier. Otherwise, return false, and don't advance.
191void HlslGrammar::acceptQualifier(TQualifier& qualifier)
192{
John Kessenich9c86c6a2016-05-03 22:49:24 -0600193 switch (peek()) {
John Kessenich87142c72016-03-12 20:24:24 -0700194 case EHTokUniform:
195 qualifier.storage = EvqUniform;
196 break;
197 case EHTokConst:
198 qualifier.storage = EvqConst;
199 break;
200 default:
201 return;
202 }
203
204 advanceToken();
205}
206
207// If token is for a type, update 'type' with the type information,
208// and return true and advance.
209// Otherwise, return false, and don't advance
210bool HlslGrammar::acceptType(TType& type)
211{
John Kessenich9c86c6a2016-05-03 22:49:24 -0600212 switch (peek()) {
John Kesseniche6e74942016-06-11 16:43:14 -0600213 case EHTokStruct:
214 return acceptStruct(type);
215 break;
216
217 case EHTokIdentifier:
218 // An identifier could be for a user-defined type.
219 // Note we cache the symbol table lookup, to save for a later rule
220 // when this is not a type.
221 token.symbol = parseContext.symbolTable.find(*token.string);
222 if (token.symbol && token.symbol->getAsVariable() && token.symbol->getAsVariable()->isUserType()) {
223 type.shallowCopy(token.symbol->getType());
224 advanceToken();
225 return true;
226 } else
227 return false;
228
John Kessenich71351de2016-06-08 12:50:56 -0600229 case EHTokVoid:
230 new(&type) TType(EbtVoid);
John Kessenich87142c72016-03-12 20:24:24 -0700231 break;
John Kessenich71351de2016-06-08 12:50:56 -0600232
John Kessenich87142c72016-03-12 20:24:24 -0700233 case EHTokFloat:
John Kessenich8d72f1a2016-05-20 12:06:03 -0600234 new(&type) TType(EbtFloat);
235 break;
John Kessenich87142c72016-03-12 20:24:24 -0700236 case EHTokFloat1:
237 new(&type) TType(EbtFloat);
John Kessenich8d72f1a2016-05-20 12:06:03 -0600238 type.makeVector();
John Kessenich87142c72016-03-12 20:24:24 -0700239 break;
John Kessenich87142c72016-03-12 20:24:24 -0700240 case EHTokFloat2:
241 new(&type) TType(EbtFloat, EvqTemporary, 2);
242 break;
243 case EHTokFloat3:
244 new(&type) TType(EbtFloat, EvqTemporary, 3);
245 break;
246 case EHTokFloat4:
247 new(&type) TType(EbtFloat, EvqTemporary, 4);
248 break;
249
John Kessenich71351de2016-06-08 12:50:56 -0600250 case EHTokDouble:
251 new(&type) TType(EbtDouble);
252 break;
253 case EHTokDouble1:
254 new(&type) TType(EbtDouble);
255 type.makeVector();
256 break;
257 case EHTokDouble2:
258 new(&type) TType(EbtDouble, EvqTemporary, 2);
259 break;
260 case EHTokDouble3:
261 new(&type) TType(EbtDouble, EvqTemporary, 3);
262 break;
263 case EHTokDouble4:
264 new(&type) TType(EbtDouble, EvqTemporary, 4);
265 break;
266
267 case EHTokInt:
268 case EHTokDword:
269 new(&type) TType(EbtInt);
270 break;
271 case EHTokInt1:
272 new(&type) TType(EbtInt);
273 type.makeVector();
274 break;
John Kessenich87142c72016-03-12 20:24:24 -0700275 case EHTokInt2:
276 new(&type) TType(EbtInt, EvqTemporary, 2);
277 break;
278 case EHTokInt3:
279 new(&type) TType(EbtInt, EvqTemporary, 3);
280 break;
281 case EHTokInt4:
282 new(&type) TType(EbtInt, EvqTemporary, 4);
283 break;
284
John Kessenich71351de2016-06-08 12:50:56 -0600285 case EHTokUint:
286 new(&type) TType(EbtUint);
287 break;
288 case EHTokUint1:
289 new(&type) TType(EbtUint);
290 type.makeVector();
291 break;
292 case EHTokUint2:
293 new(&type) TType(EbtUint, EvqTemporary, 2);
294 break;
295 case EHTokUint3:
296 new(&type) TType(EbtUint, EvqTemporary, 3);
297 break;
298 case EHTokUint4:
299 new(&type) TType(EbtUint, EvqTemporary, 4);
300 break;
301
302 case EHTokBool:
303 new(&type) TType(EbtBool);
304 break;
305 case EHTokBool1:
306 new(&type) TType(EbtBool);
307 type.makeVector();
308 break;
John Kessenich87142c72016-03-12 20:24:24 -0700309 case EHTokBool2:
310 new(&type) TType(EbtBool, EvqTemporary, 2);
311 break;
312 case EHTokBool3:
313 new(&type) TType(EbtBool, EvqTemporary, 3);
314 break;
315 case EHTokBool4:
316 new(&type) TType(EbtBool, EvqTemporary, 4);
317 break;
318
John Kessenich0133c122016-05-20 12:17:26 -0600319 case EHTokInt1x1:
320 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 1);
321 break;
322 case EHTokInt1x2:
323 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 1);
324 break;
325 case EHTokInt1x3:
326 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 1);
327 break;
328 case EHTokInt1x4:
329 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 1);
330 break;
331 case EHTokInt2x1:
332 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 2);
333 break;
334 case EHTokInt2x2:
335 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 2);
336 break;
337 case EHTokInt2x3:
338 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 2);
339 break;
340 case EHTokInt2x4:
341 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 2);
342 break;
343 case EHTokInt3x1:
344 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 3);
345 break;
346 case EHTokInt3x2:
347 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 3);
348 break;
349 case EHTokInt3x3:
350 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 3);
351 break;
352 case EHTokInt3x4:
353 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 3);
354 break;
355 case EHTokInt4x1:
356 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 4);
357 break;
358 case EHTokInt4x2:
359 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 4);
360 break;
361 case EHTokInt4x3:
362 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 4);
363 break;
364 case EHTokInt4x4:
365 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 4);
366 break;
367
John Kessenich71351de2016-06-08 12:50:56 -0600368 case EHTokUint1x1:
369 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 1);
370 break;
371 case EHTokUint1x2:
372 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 1);
373 break;
374 case EHTokUint1x3:
375 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 1);
376 break;
377 case EHTokUint1x4:
378 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 1);
379 break;
380 case EHTokUint2x1:
381 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 2);
382 break;
383 case EHTokUint2x2:
384 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 2);
385 break;
386 case EHTokUint2x3:
387 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 2);
388 break;
389 case EHTokUint2x4:
390 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 2);
391 break;
392 case EHTokUint3x1:
393 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 3);
394 break;
395 case EHTokUint3x2:
396 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 3);
397 break;
398 case EHTokUint3x3:
399 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 3);
400 break;
401 case EHTokUint3x4:
402 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 3);
403 break;
404 case EHTokUint4x1:
405 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 4);
406 break;
407 case EHTokUint4x2:
408 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 4);
409 break;
410 case EHTokUint4x3:
411 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 4);
412 break;
413 case EHTokUint4x4:
414 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 4);
415 break;
416
417 case EHTokBool1x1:
418 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 1);
419 break;
420 case EHTokBool1x2:
421 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 1);
422 break;
423 case EHTokBool1x3:
424 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 1);
425 break;
426 case EHTokBool1x4:
427 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 1);
428 break;
429 case EHTokBool2x1:
430 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 2);
431 break;
432 case EHTokBool2x2:
433 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 2);
434 break;
435 case EHTokBool2x3:
436 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 2);
437 break;
438 case EHTokBool2x4:
439 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 2);
440 break;
441 case EHTokBool3x1:
442 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 3);
443 break;
444 case EHTokBool3x2:
445 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 3);
446 break;
447 case EHTokBool3x3:
448 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 3);
449 break;
450 case EHTokBool3x4:
451 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 3);
452 break;
453 case EHTokBool4x1:
454 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 4);
455 break;
456 case EHTokBool4x2:
457 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 4);
458 break;
459 case EHTokBool4x3:
460 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 4);
461 break;
462 case EHTokBool4x4:
463 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 4);
464 break;
465
John Kessenich0133c122016-05-20 12:17:26 -0600466 case EHTokFloat1x1:
467 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 1);
468 break;
469 case EHTokFloat1x2:
470 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 1);
471 break;
472 case EHTokFloat1x3:
473 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 1);
474 break;
475 case EHTokFloat1x4:
476 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 1);
477 break;
478 case EHTokFloat2x1:
479 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 2);
480 break;
John Kessenich87142c72016-03-12 20:24:24 -0700481 case EHTokFloat2x2:
482 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 2);
483 break;
484 case EHTokFloat2x3:
485 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 2);
486 break;
487 case EHTokFloat2x4:
488 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 2);
489 break;
John Kessenich0133c122016-05-20 12:17:26 -0600490 case EHTokFloat3x1:
491 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 3);
492 break;
John Kessenich87142c72016-03-12 20:24:24 -0700493 case EHTokFloat3x2:
494 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 3);
495 break;
496 case EHTokFloat3x3:
497 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 3);
498 break;
499 case EHTokFloat3x4:
500 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 3);
501 break;
John Kessenich0133c122016-05-20 12:17:26 -0600502 case EHTokFloat4x1:
503 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 4);
504 break;
John Kessenich87142c72016-03-12 20:24:24 -0700505 case EHTokFloat4x2:
506 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 4);
507 break;
508 case EHTokFloat4x3:
509 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 4);
510 break;
511 case EHTokFloat4x4:
512 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 4);
513 break;
514
John Kessenich0133c122016-05-20 12:17:26 -0600515 case EHTokDouble1x1:
516 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 1);
517 break;
518 case EHTokDouble1x2:
519 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 1);
520 break;
521 case EHTokDouble1x3:
522 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 1);
523 break;
524 case EHTokDouble1x4:
525 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 1);
526 break;
527 case EHTokDouble2x1:
528 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 2);
529 break;
530 case EHTokDouble2x2:
531 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 2);
532 break;
533 case EHTokDouble2x3:
534 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 2);
535 break;
536 case EHTokDouble2x4:
537 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 2);
538 break;
539 case EHTokDouble3x1:
540 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 3);
541 break;
542 case EHTokDouble3x2:
543 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 3);
544 break;
545 case EHTokDouble3x3:
546 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 3);
547 break;
548 case EHTokDouble3x4:
549 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 3);
550 break;
551 case EHTokDouble4x1:
552 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 4);
553 break;
554 case EHTokDouble4x2:
555 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 4);
556 break;
557 case EHTokDouble4x3:
558 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 4);
559 break;
560 case EHTokDouble4x4:
561 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 4);
562 break;
563
John Kessenich87142c72016-03-12 20:24:24 -0700564 default:
565 return false;
566 }
567
568 advanceToken();
569
570 return true;
571}
572
John Kesseniche6e74942016-06-11 16:43:14 -0600573// struct
574// : STRUCT IDENTIFIER LEFT_BRACE struct_declaration_list RIGHT_BRACE
575// | STRUCT LEFT_BRACE struct_declaration_list RIGHT_BRACE
576//
577bool HlslGrammar::acceptStruct(TType& type)
578{
579 // STRUCT
580 if (! acceptTokenClass(EHTokStruct))
581 return false;
582
583 // IDENTIFIER
584 TString structName = "";
585 if (peekTokenClass(EHTokIdentifier)) {
586 structName = *token.string;
587 advanceToken();
588 }
589
590 // LEFT_BRACE
591 if (! acceptTokenClass(EHTokLeftBrace)) {
592 expected("{");
593 return false;
594 }
595
596 // struct_declaration_list
597 TTypeList* typeList;
598 if (! acceptStructDeclarationList(typeList)) {
599 expected("struct member declarations");
600 return false;
601 }
602
603 // RIGHT_BRACE
604 if (! acceptTokenClass(EHTokRightBrace)) {
605 expected("}");
606 return false;
607 }
608
609 // create the user-defined type
610 new(&type) TType(typeList, structName);
611
612 // If it was named, which means it can be reused later, add
613 // it to the symbol table.
614 if (structName.size() > 0) {
615 TVariable* userTypeDef = new TVariable(&structName, type, true);
616 if (! parseContext.symbolTable.insert(*userTypeDef))
617 parseContext.error(token.loc, "redefinition", structName.c_str(), "struct");
618 }
619
620 return true;
621}
622
623// struct_declaration_list
624// : struct_declaration SEMI_COLON struct_declaration SEMI_COLON ...
625//
626// struct_declaration
627// : fully_specified_type struct_declarator COMMA struct_declarator ...
628//
629// struct_declarator
630// : IDENTIFIER
631// | IDENTIFIER array_specifier
632//
633bool HlslGrammar::acceptStructDeclarationList(TTypeList*& typeList)
634{
635 typeList = new TTypeList();
636
637 do {
638 // success on seeing the RIGHT_BRACE coming up
639 if (peekTokenClass(EHTokRightBrace))
640 return true;
641
642 // struct_declaration
643
644 // fully_specified_type
645 TType memberType;
646 if (! acceptFullySpecifiedType(memberType)) {
647 expected("member type");
648 return false;
649 }
650
651 // struct_declarator COMMA struct_declarator ...
652 do {
653 // peek IDENTIFIER
654 if (! peekTokenClass(EHTokIdentifier)) {
655 expected("member name");
656 return false;
657 }
658
659 // add it to the list of members
660 TTypeLoc member = { new TType(EbtVoid), token.loc };
661 member.type->shallowCopy(memberType);
662 member.type->setFieldName(*token.string);
663 typeList->push_back(member);
664
665 // accept IDENTIFIER
666 advanceToken();
667
668 // array_specifier
669 // TODO
670
671 // success on seeing the SEMICOLON coming up
672 if (peekTokenClass(EHTokSemicolon))
673 break;
674
675 // COMMA
676 if (! acceptTokenClass(EHTokComma)) {
677 expected(",");
678 return false;
679 }
680
681 } while (true);
682
683 // SEMI_COLON
684 if (! acceptTokenClass(EHTokSemicolon)) {
685 expected(";");
686 return false;
687 }
688
689 } while (true);
690}
691
John Kessenich5f934b02016-03-13 17:58:25 -0600692// function_parameters
John Kessenich078d7f22016-03-14 10:02:11 -0600693// : LEFT_PAREN parameter_declaration COMMA parameter_declaration ... RIGHT_PAREN
John Kessenich71351de2016-06-08 12:50:56 -0600694// | LEFT_PAREN VOID RIGHT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -0600695//
696bool HlslGrammar::acceptFunctionParameters(TFunction& function)
697{
John Kessenich078d7f22016-03-14 10:02:11 -0600698 // LEFT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -0600699 if (! acceptTokenClass(EHTokLeftParen))
700 return false;
701
John Kessenich71351de2016-06-08 12:50:56 -0600702 // VOID RIGHT_PAREN
703 if (! acceptTokenClass(EHTokVoid)) {
704 do {
705 // parameter_declaration
706 if (! acceptParameterDeclaration(function))
707 break;
John Kessenich5f934b02016-03-13 17:58:25 -0600708
John Kessenich71351de2016-06-08 12:50:56 -0600709 // COMMA
710 if (! acceptTokenClass(EHTokComma))
711 break;
712 } while (true);
713 }
John Kessenich5f934b02016-03-13 17:58:25 -0600714
John Kessenich078d7f22016-03-14 10:02:11 -0600715 // RIGHT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -0600716 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -0600717 expected(")");
John Kessenich5f934b02016-03-13 17:58:25 -0600718 return false;
719 }
720
721 return true;
722}
723
724// parameter_declaration
725// : fully_specified_type
726// | fully_specified_type identifier
727//
728bool HlslGrammar::acceptParameterDeclaration(TFunction& function)
729{
730 // fully_specified_type
731 TType* type = new TType;
732 if (! acceptFullySpecifiedType(*type))
733 return false;
734
735 // identifier
John Kessenichaecd4972016-03-14 10:46:34 -0600736 HlslToken idToken;
737 acceptIdentifier(idToken);
John Kessenich5f934b02016-03-13 17:58:25 -0600738
John Kessenichaecd4972016-03-14 10:46:34 -0600739 TParameter param = { idToken.string, type };
John Kessenich5f934b02016-03-13 17:58:25 -0600740 function.addParameter(param);
741
742 return true;
743}
744
745// Do the work to create the function definition in addition to
746// parsing the body (compound_statement).
747bool HlslGrammar::acceptFunctionDefinition(TFunction& function, TIntermNode*& node)
748{
749 TFunction* functionDeclarator = parseContext.handleFunctionDeclarator(token.loc, function, false /* not prototype */);
750
John Kessenich077e0522016-06-09 02:02:17 -0600751 // This does a pushScope()
John Kessenich5f934b02016-03-13 17:58:25 -0600752 node = parseContext.handleFunctionDefinition(token.loc, *functionDeclarator);
753
754 // compound_statement
John Kessenich21472ae2016-06-04 11:46:33 -0600755 TIntermNode* functionBody = nullptr;
John Kessenich5f934b02016-03-13 17:58:25 -0600756 if (acceptCompoundStatement(functionBody)) {
John Kessenich078d7f22016-03-14 10:02:11 -0600757 node = intermediate.growAggregate(node, functionBody);
758 intermediate.setAggregateOperator(node, EOpFunction, functionDeclarator->getType(), token.loc);
John Kessenich5f934b02016-03-13 17:58:25 -0600759 node->getAsAggregate()->setName(functionDeclarator->getMangledName().c_str());
John Kessenich077e0522016-06-09 02:02:17 -0600760 parseContext.popScope();
John Kessenich5f934b02016-03-13 17:58:25 -0600761
762 return true;
763 }
764
765 return false;
766}
767
John Kessenich0d2b6de2016-06-05 11:23:11 -0600768// Accept an expression with parenthesis around it, where
769// the parenthesis ARE NOT expression parenthesis, but the
770// syntactically required ones like in "if ( expression )"
771//
772// Note this one is not set up to be speculative; as it gives
773// errors if not found.
774//
775bool HlslGrammar::acceptParenExpression(TIntermTyped*& expression)
776{
777 // LEFT_PAREN
778 if (! acceptTokenClass(EHTokLeftParen))
779 expected("(");
780
781 if (! acceptExpression(expression)) {
782 expected("expression");
783 return false;
784 }
785
786 // RIGHT_PAREN
787 if (! acceptTokenClass(EHTokRightParen))
788 expected(")");
789
790 return true;
791}
792
John Kessenich34fb0362016-05-03 23:17:20 -0600793// The top-level full expression recognizer.
794//
John Kessenich87142c72016-03-12 20:24:24 -0700795// expression
John Kessenich34fb0362016-05-03 23:17:20 -0600796// : assignment_expression COMMA assignment_expression COMMA assignment_expression ...
John Kessenich87142c72016-03-12 20:24:24 -0700797//
798bool HlslGrammar::acceptExpression(TIntermTyped*& node)
799{
LoopDawgef764a22016-06-03 09:17:51 -0600800 node = nullptr;
801
John Kessenich34fb0362016-05-03 23:17:20 -0600802 // assignment_expression
803 if (! acceptAssignmentExpression(node))
804 return false;
John Kessenich5f934b02016-03-13 17:58:25 -0600805
John Kessenich34fb0362016-05-03 23:17:20 -0600806 if (! peekTokenClass(EHTokComma))
807 return true;
808
809 do {
810 // ... COMMA
John Kessenich5f934b02016-03-13 17:58:25 -0600811 TSourceLoc loc = token.loc;
John Kessenich34fb0362016-05-03 23:17:20 -0600812 advanceToken();
John Kessenich5f934b02016-03-13 17:58:25 -0600813
John Kessenich34fb0362016-05-03 23:17:20 -0600814 // ... assignment_expression
815 TIntermTyped* rightNode = nullptr;
816 if (! acceptAssignmentExpression(rightNode)) {
817 expected("assignment expression");
818 return false;
John Kessenich5f934b02016-03-13 17:58:25 -0600819 }
820
John Kessenich34fb0362016-05-03 23:17:20 -0600821 node = intermediate.addComma(node, rightNode, loc);
822
823 if (! peekTokenClass(EHTokComma))
824 return true;
825 } while (true);
826}
827
828// Accept an assignment expression, where assignment operations
829// associate right-to-left. This is, it is implicit, for example
830//
831// a op (b op (c op d))
832//
833// assigment_expression
834// : binary_expression op binary_expression op binary_expression ...
835//
836bool HlslGrammar::acceptAssignmentExpression(TIntermTyped*& node)
837{
838 if (! acceptBinaryExpression(node, PlLogicalOr))
839 return false;
840
841 TOperator assignOp = HlslOpMap::assignment(peek());
842 if (assignOp == EOpNull)
843 return true;
844
845 // ... op
846 TSourceLoc loc = token.loc;
847 advanceToken();
848
849 // ... binary_expression
850 // But, done by recursing this function, which automatically
851 // gets the right-to-left associativity.
852 TIntermTyped* rightNode = nullptr;
853 if (! acceptAssignmentExpression(rightNode)) {
854 expected("assignment expression");
John Kessenich5f934b02016-03-13 17:58:25 -0600855 return false;
John Kessenich87142c72016-03-12 20:24:24 -0700856 }
857
John Kessenich34fb0362016-05-03 23:17:20 -0600858 node = intermediate.addAssign(assignOp, node, rightNode, loc);
859
860 if (! peekTokenClass(EHTokComma))
861 return true;
862
863 return true;
864}
865
866// Accept a binary expression, for binary operations that
867// associate left-to-right. This is, it is implicit, for example
868//
869// ((a op b) op c) op d
870//
871// binary_expression
872// : expression op expression op expression ...
873//
874// where 'expression' is the next higher level in precedence.
875//
876bool HlslGrammar::acceptBinaryExpression(TIntermTyped*& node, PrecedenceLevel precedenceLevel)
877{
878 if (precedenceLevel > PlMul)
879 return acceptUnaryExpression(node);
880
881 // assignment_expression
882 if (! acceptBinaryExpression(node, (PrecedenceLevel)(precedenceLevel + 1)))
883 return false;
884
885 TOperator op = HlslOpMap::binary(peek());
886 PrecedenceLevel tokenLevel = HlslOpMap::precedenceLevel(op);
887 if (tokenLevel < precedenceLevel)
888 return true;
889
890 do {
891 // ... op
892 TSourceLoc loc = token.loc;
893 advanceToken();
894
895 // ... expression
896 TIntermTyped* rightNode = nullptr;
897 if (! acceptBinaryExpression(rightNode, (PrecedenceLevel)(precedenceLevel + 1))) {
898 expected("expression");
899 return false;
900 }
901
902 node = intermediate.addBinaryMath(op, node, rightNode, loc);
903
904 if (! peekTokenClass(EHTokComma))
905 return true;
906 } while (true);
907}
908
909// unary_expression
John Kessenich1cc1a282016-06-03 16:55:49 -0600910// : (type) unary_expression
911// | + unary_expression
John Kessenich34fb0362016-05-03 23:17:20 -0600912// | - unary_expression
913// | ! unary_expression
914// | ~ unary_expression
915// | ++ unary_expression
916// | -- unary_expression
917// | postfix_expression
918//
919bool HlslGrammar::acceptUnaryExpression(TIntermTyped*& node)
920{
John Kessenich1cc1a282016-06-03 16:55:49 -0600921 // (type) unary_expression
922 // Have to look two steps ahead, because this could be, e.g., a
923 // postfix_expression instead, since that also starts with at "(".
924 if (acceptTokenClass(EHTokLeftParen)) {
925 TType castType;
926 if (acceptType(castType)) {
927 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -0600928 expected(")");
John Kessenich1cc1a282016-06-03 16:55:49 -0600929 return false;
930 }
931
932 // We've matched "(type)" now, get the expression to cast
933 TSourceLoc loc = token.loc;
934 if (! acceptUnaryExpression(node))
935 return false;
936
937 // Hook it up like a constructor
938 TFunction* constructorFunction = parseContext.handleConstructorCall(loc, castType);
939 if (constructorFunction == nullptr) {
940 expected("type that can be constructed");
941 return false;
942 }
943 TIntermTyped* arguments = nullptr;
944 parseContext.handleFunctionArgument(constructorFunction, arguments, node);
945 node = parseContext.handleFunctionCall(loc, constructorFunction, arguments);
946
947 return true;
948 } else {
949 // This isn't a type cast, but it still started "(", so if it is a
950 // unary expression, it can only be a postfix_expression, so try that.
951 // Back it up first.
952 recedeToken();
953 return acceptPostfixExpression(node);
954 }
955 }
956
957 // peek for "op unary_expression"
John Kessenich34fb0362016-05-03 23:17:20 -0600958 TOperator unaryOp = HlslOpMap::preUnary(peek());
959
John Kessenich1cc1a282016-06-03 16:55:49 -0600960 // postfix_expression (if no unary operator)
John Kessenich34fb0362016-05-03 23:17:20 -0600961 if (unaryOp == EOpNull)
962 return acceptPostfixExpression(node);
963
964 // op unary_expression
965 TSourceLoc loc = token.loc;
966 advanceToken();
967 if (! acceptUnaryExpression(node))
968 return false;
969
970 // + is a no-op
971 if (unaryOp == EOpAdd)
972 return true;
973
974 node = intermediate.addUnaryMath(unaryOp, node, loc);
975
976 return node != nullptr;
977}
978
979// postfix_expression
980// : LEFT_PAREN expression RIGHT_PAREN
981// | literal
982// | constructor
983// | identifier
984// | function_call
985// | postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET
986// | postfix_expression DOT IDENTIFIER
987// | postfix_expression INC_OP
988// | postfix_expression DEC_OP
989//
990bool HlslGrammar::acceptPostfixExpression(TIntermTyped*& node)
991{
992 // Not implemented as self-recursive:
993 // The logical "right recursion" is done with an loop at the end
994
995 // idToken will pick up either a variable or a function name in a function call
996 HlslToken idToken;
997
John Kessenich21472ae2016-06-04 11:46:33 -0600998 // Find something before the postfix operations, as they can't operate
999 // on nothing. So, no "return true", they fall through, only "return false".
John Kessenich87142c72016-03-12 20:24:24 -07001000 if (acceptTokenClass(EHTokLeftParen)) {
John Kessenich21472ae2016-06-04 11:46:33 -06001001 // LEFT_PAREN expression RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07001002 if (! acceptExpression(node)) {
1003 expected("expression");
1004 return false;
1005 }
1006 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06001007 expected(")");
John Kessenich87142c72016-03-12 20:24:24 -07001008 return false;
1009 }
John Kessenich34fb0362016-05-03 23:17:20 -06001010 } else if (acceptLiteral(node)) {
1011 // literal (nothing else to do yet), go on to the
1012 } else if (acceptConstructor(node)) {
1013 // constructor (nothing else to do yet)
1014 } else if (acceptIdentifier(idToken)) {
1015 // identifier or function_call name
1016 if (! peekTokenClass(EHTokLeftParen)) {
John Kesseniche6e74942016-06-11 16:43:14 -06001017 node = parseContext.handleVariable(idToken.loc, idToken.symbol, token.string);
John Kessenich34fb0362016-05-03 23:17:20 -06001018 } else if (acceptFunctionCall(idToken, node)) {
1019 // function_call (nothing else to do yet)
1020 } else {
1021 expected("function call arguments");
1022 return false;
1023 }
John Kessenich21472ae2016-06-04 11:46:33 -06001024 } else {
1025 // nothing found, can't post operate
1026 return false;
John Kessenich87142c72016-03-12 20:24:24 -07001027 }
1028
John Kessenich21472ae2016-06-04 11:46:33 -06001029 // Something was found, chain as many postfix operations as exist.
John Kessenich34fb0362016-05-03 23:17:20 -06001030 do {
1031 TSourceLoc loc = token.loc;
1032 TOperator postOp = HlslOpMap::postUnary(peek());
John Kessenich87142c72016-03-12 20:24:24 -07001033
John Kessenich34fb0362016-05-03 23:17:20 -06001034 // Consume only a valid post-unary operator, otherwise we are done.
1035 switch (postOp) {
1036 case EOpIndexDirectStruct:
1037 case EOpIndexIndirect:
1038 case EOpPostIncrement:
1039 case EOpPostDecrement:
1040 advanceToken();
1041 break;
1042 default:
1043 return true;
1044 }
John Kessenich87142c72016-03-12 20:24:24 -07001045
John Kessenich34fb0362016-05-03 23:17:20 -06001046 // We have a valid post-unary operator, process it.
1047 switch (postOp) {
1048 case EOpIndexDirectStruct:
1049 // todo
1050 break;
1051 case EOpIndexIndirect:
1052 {
1053 TIntermTyped* indexNode = nullptr;
1054 if (! acceptExpression(indexNode) ||
1055 ! peekTokenClass(EHTokRightBracket)) {
1056 expected("expression followed by ']'");
1057 return false;
1058 }
1059 // todo: node = intermediate.addBinaryMath(
1060 }
1061 case EOpPostIncrement:
1062 case EOpPostDecrement:
1063 node = intermediate.addUnaryMath(postOp, node, loc);
1064 break;
1065 default:
1066 assert(0);
1067 break;
1068 }
1069 } while (true);
John Kessenich87142c72016-03-12 20:24:24 -07001070}
1071
John Kessenichd016be12016-03-13 11:24:20 -06001072// constructor
John Kessenich078d7f22016-03-14 10:02:11 -06001073// : type argument_list
John Kessenichd016be12016-03-13 11:24:20 -06001074//
1075bool HlslGrammar::acceptConstructor(TIntermTyped*& node)
1076{
1077 // type
1078 TType type;
1079 if (acceptType(type)) {
1080 TFunction* constructorFunction = parseContext.handleConstructorCall(token.loc, type);
1081 if (constructorFunction == nullptr)
1082 return false;
1083
1084 // arguments
John Kessenich4678ca92016-05-13 09:33:42 -06001085 TIntermTyped* arguments = nullptr;
John Kessenichd016be12016-03-13 11:24:20 -06001086 if (! acceptArguments(constructorFunction, arguments)) {
1087 expected("constructor arguments");
1088 return false;
1089 }
1090
1091 // hook it up
1092 node = parseContext.handleFunctionCall(arguments->getLoc(), constructorFunction, arguments);
1093
1094 return true;
1095 }
1096
1097 return false;
1098}
1099
John Kessenich34fb0362016-05-03 23:17:20 -06001100// The function_call identifier was already recognized, and passed in as idToken.
1101//
1102// function_call
1103// : [idToken] arguments
1104//
John Kessenich4678ca92016-05-13 09:33:42 -06001105bool HlslGrammar::acceptFunctionCall(HlslToken idToken, TIntermTyped*& node)
John Kessenich34fb0362016-05-03 23:17:20 -06001106{
John Kessenich4678ca92016-05-13 09:33:42 -06001107 // arguments
1108 TFunction* function = new TFunction(idToken.string, TType(EbtVoid));
1109 TIntermTyped* arguments = nullptr;
1110 if (! acceptArguments(function, arguments))
1111 return false;
1112
1113 node = parseContext.handleFunctionCall(idToken.loc, function, arguments);
1114
1115 return true;
John Kessenich34fb0362016-05-03 23:17:20 -06001116}
1117
John Kessenich87142c72016-03-12 20:24:24 -07001118// arguments
John Kessenich078d7f22016-03-14 10:02:11 -06001119// : LEFT_PAREN expression COMMA expression COMMA ... RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07001120//
John Kessenichd016be12016-03-13 11:24:20 -06001121// The arguments are pushed onto the 'function' argument list and
1122// onto the 'arguments' aggregate.
1123//
John Kessenich4678ca92016-05-13 09:33:42 -06001124bool HlslGrammar::acceptArguments(TFunction* function, TIntermTyped*& arguments)
John Kessenich87142c72016-03-12 20:24:24 -07001125{
John Kessenich078d7f22016-03-14 10:02:11 -06001126 // LEFT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07001127 if (! acceptTokenClass(EHTokLeftParen))
1128 return false;
1129
1130 do {
John Kessenichd016be12016-03-13 11:24:20 -06001131 // expression
John Kessenich87142c72016-03-12 20:24:24 -07001132 TIntermTyped* arg;
John Kessenich4678ca92016-05-13 09:33:42 -06001133 if (! acceptAssignmentExpression(arg))
John Kessenich87142c72016-03-12 20:24:24 -07001134 break;
John Kessenichd016be12016-03-13 11:24:20 -06001135
1136 // hook it up
1137 parseContext.handleFunctionArgument(function, arguments, arg);
1138
John Kessenich078d7f22016-03-14 10:02:11 -06001139 // COMMA
John Kessenich87142c72016-03-12 20:24:24 -07001140 if (! acceptTokenClass(EHTokComma))
1141 break;
1142 } while (true);
1143
John Kessenich078d7f22016-03-14 10:02:11 -06001144 // RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07001145 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06001146 expected(")");
John Kessenich87142c72016-03-12 20:24:24 -07001147 return false;
1148 }
1149
1150 return true;
1151}
1152
1153bool HlslGrammar::acceptLiteral(TIntermTyped*& node)
1154{
1155 switch (token.tokenClass) {
1156 case EHTokIntConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06001157 node = intermediate.addConstantUnion(token.i, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07001158 break;
1159 case EHTokFloatConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06001160 node = intermediate.addConstantUnion(token.d, EbtFloat, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07001161 break;
1162 case EHTokDoubleConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06001163 node = intermediate.addConstantUnion(token.d, EbtDouble, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07001164 break;
1165 case EHTokBoolConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06001166 node = intermediate.addConstantUnion(token.b, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07001167 break;
1168
1169 default:
1170 return false;
1171 }
1172
1173 advanceToken();
1174
1175 return true;
1176}
1177
John Kessenich5f934b02016-03-13 17:58:25 -06001178// compound_statement
John Kessenich34fb0362016-05-03 23:17:20 -06001179// : LEFT_CURLY statement statement ... RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06001180//
John Kessenich21472ae2016-06-04 11:46:33 -06001181bool HlslGrammar::acceptCompoundStatement(TIntermNode*& retStatement)
John Kessenich87142c72016-03-12 20:24:24 -07001182{
John Kessenich21472ae2016-06-04 11:46:33 -06001183 TIntermAggregate* compoundStatement = nullptr;
1184
John Kessenich34fb0362016-05-03 23:17:20 -06001185 // LEFT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06001186 if (! acceptTokenClass(EHTokLeftBrace))
1187 return false;
1188
1189 // statement statement ...
1190 TIntermNode* statement = nullptr;
1191 while (acceptStatement(statement)) {
1192 // hook it up
John Kessenich078d7f22016-03-14 10:02:11 -06001193 compoundStatement = intermediate.growAggregate(compoundStatement, statement);
John Kessenich5f934b02016-03-13 17:58:25 -06001194 }
John Kessenich34fb0362016-05-03 23:17:20 -06001195 if (compoundStatement)
1196 compoundStatement->setOperator(EOpSequence);
John Kessenich5f934b02016-03-13 17:58:25 -06001197
John Kessenich21472ae2016-06-04 11:46:33 -06001198 retStatement = compoundStatement;
1199
John Kessenich34fb0362016-05-03 23:17:20 -06001200 // RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06001201 return acceptTokenClass(EHTokRightBrace);
1202}
1203
John Kessenich0d2b6de2016-06-05 11:23:11 -06001204bool HlslGrammar::acceptScopedStatement(TIntermNode*& statement)
1205{
1206 parseContext.pushScope();
John Kessenich077e0522016-06-09 02:02:17 -06001207 bool result = acceptStatement(statement);
John Kessenich0d2b6de2016-06-05 11:23:11 -06001208 parseContext.popScope();
1209
1210 return result;
1211}
1212
John Kessenich077e0522016-06-09 02:02:17 -06001213bool HlslGrammar::acceptScopedCompoundStatement(TIntermNode*& statement)
John Kessenich0d2b6de2016-06-05 11:23:11 -06001214{
John Kessenich077e0522016-06-09 02:02:17 -06001215 parseContext.pushScope();
1216 bool result = acceptCompoundStatement(statement);
1217 parseContext.popScope();
John Kessenich0d2b6de2016-06-05 11:23:11 -06001218
1219 return result;
1220}
1221
John Kessenich5f934b02016-03-13 17:58:25 -06001222// statement
John Kessenich21472ae2016-06-04 11:46:33 -06001223// : attributes attributed_statement
1224//
1225// attributed_statement
John Kessenich5f934b02016-03-13 17:58:25 -06001226// : compound_statement
John Kessenich21472ae2016-06-04 11:46:33 -06001227// | SEMICOLON
John Kessenich078d7f22016-03-14 10:02:11 -06001228// | expression SEMICOLON
John Kessenich21472ae2016-06-04 11:46:33 -06001229// | declaration_statement
1230// | selection_statement
1231// | switch_statement
1232// | case_label
1233// | iteration_statement
1234// | jump_statement
John Kessenich5f934b02016-03-13 17:58:25 -06001235//
1236bool HlslGrammar::acceptStatement(TIntermNode*& statement)
1237{
John Kessenich21472ae2016-06-04 11:46:33 -06001238 statement = nullptr;
John Kessenich5f934b02016-03-13 17:58:25 -06001239
John Kessenich21472ae2016-06-04 11:46:33 -06001240 // attributes
1241 acceptAttributes();
John Kessenich5f934b02016-03-13 17:58:25 -06001242
John Kessenich21472ae2016-06-04 11:46:33 -06001243 // attributed_statement
1244 switch (peek()) {
1245 case EHTokLeftBrace:
John Kessenich077e0522016-06-09 02:02:17 -06001246 return acceptScopedCompoundStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06001247
John Kessenich21472ae2016-06-04 11:46:33 -06001248 case EHTokIf:
1249 return acceptSelectionStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06001250
John Kessenich21472ae2016-06-04 11:46:33 -06001251 case EHTokSwitch:
1252 return acceptSwitchStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06001253
John Kessenich21472ae2016-06-04 11:46:33 -06001254 case EHTokFor:
1255 case EHTokDo:
1256 case EHTokWhile:
1257 return acceptIterationStatement(statement);
1258
1259 case EHTokContinue:
1260 case EHTokBreak:
1261 case EHTokDiscard:
1262 case EHTokReturn:
1263 return acceptJumpStatement(statement);
1264
1265 case EHTokCase:
1266 return acceptCaseLabel(statement);
1267
1268 case EHTokSemicolon:
1269 return acceptTokenClass(EHTokSemicolon);
1270
1271 case EHTokRightBrace:
1272 // Performance: not strictly necessary, but stops a bunch of hunting early,
1273 // and is how sequences of statements end.
John Kessenich5f934b02016-03-13 17:58:25 -06001274 return false;
1275
John Kessenich21472ae2016-06-04 11:46:33 -06001276 default:
1277 {
1278 // declaration
1279 if (acceptDeclaration(statement))
1280 return true;
1281
1282 // expression
1283 TIntermTyped* node;
1284 if (acceptExpression(node))
1285 statement = node;
1286 else
1287 return false;
1288
1289 // SEMICOLON (following an expression)
1290 if (! acceptTokenClass(EHTokSemicolon)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06001291 expected(";");
John Kessenich21472ae2016-06-04 11:46:33 -06001292 return false;
1293 }
1294 }
1295 }
1296
John Kessenich5f934b02016-03-13 17:58:25 -06001297 return true;
John Kessenich87142c72016-03-12 20:24:24 -07001298}
1299
John Kessenich21472ae2016-06-04 11:46:33 -06001300// attributes
1301// : list of zero or more of: LEFT_BRACKET attribute RIGHT_BRACKET
1302//
1303// attribute:
1304// : UNROLL
1305// | UNROLL LEFT_PAREN literal RIGHT_PAREN
1306// | FASTOPT
1307// | ALLOW_UAV_CONDITION
1308// | BRANCH
1309// | FLATTEN
1310// | FORCECASE
1311// | CALL
1312//
1313void HlslGrammar::acceptAttributes()
1314{
John Kessenich0d2b6de2016-06-05 11:23:11 -06001315 // For now, accept the [ XXX(X) ] syntax, but drop.
1316 // TODO: subset to correct set? Pass on?
1317 do {
1318 // LEFT_BRACKET?
1319 if (! acceptTokenClass(EHTokLeftBracket))
1320 return;
1321
1322 // attribute
1323 if (peekTokenClass(EHTokIdentifier)) {
1324 // 'token.string' is the attribute
1325 advanceToken();
1326 } else if (! peekTokenClass(EHTokRightBracket)) {
1327 expected("identifier");
1328 advanceToken();
1329 }
1330
1331 // (x)
1332 if (acceptTokenClass(EHTokLeftParen)) {
1333 TIntermTyped* node;
1334 if (! acceptLiteral(node))
1335 expected("literal");
1336 // 'node' has the literal in it
1337 if (! acceptTokenClass(EHTokRightParen))
1338 expected(")");
1339 }
1340
1341 // RIGHT_BRACKET
1342 if (acceptTokenClass(EHTokRightBracket))
1343 continue;
1344
1345 expected("]");
1346 return;
1347
1348 } while (true);
John Kessenich21472ae2016-06-04 11:46:33 -06001349}
1350
John Kessenich0d2b6de2016-06-05 11:23:11 -06001351// selection_statement
1352// : IF LEFT_PAREN expression RIGHT_PAREN statement
1353// : IF LEFT_PAREN expression RIGHT_PAREN statement ELSE statement
1354//
John Kessenich21472ae2016-06-04 11:46:33 -06001355bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement)
1356{
John Kessenich0d2b6de2016-06-05 11:23:11 -06001357 TSourceLoc loc = token.loc;
1358
1359 // IF
1360 if (! acceptTokenClass(EHTokIf))
1361 return false;
1362
1363 // so that something declared in the condition is scoped to the lifetimes
1364 // of the then-else statements
1365 parseContext.pushScope();
1366
1367 // LEFT_PAREN expression RIGHT_PAREN
1368 TIntermTyped* condition;
1369 if (! acceptParenExpression(condition))
1370 return false;
1371
1372 // create the child statements
1373 TIntermNodePair thenElse = { nullptr, nullptr };
1374
1375 // then statement
1376 if (! acceptScopedStatement(thenElse.node1)) {
1377 expected("then statement");
1378 return false;
1379 }
1380
1381 // ELSE
1382 if (acceptTokenClass(EHTokElse)) {
1383 // else statement
1384 if (! acceptScopedStatement(thenElse.node2)) {
1385 expected("else statement");
1386 return false;
1387 }
1388 }
1389
1390 // Put the pieces together
1391 statement = intermediate.addSelection(condition, thenElse, loc);
1392 parseContext.popScope();
1393
1394 return true;
John Kessenich21472ae2016-06-04 11:46:33 -06001395}
1396
1397bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement)
1398{
1399 return false;
1400}
1401
John Kessenich119f8f62016-06-05 15:44:07 -06001402// iteration_statement
1403// : WHILE LEFT_PAREN condition RIGHT_PAREN statement
1404// | DO LEFT_BRACE statement RIGHT_BRACE WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON
1405// | FOR LEFT_PAREN for_init_statement for_rest_statement RIGHT_PAREN statement
1406//
1407// Non-speculative, only call if it needs to be found; WHILE or DO or FOR already seen.
John Kessenich21472ae2016-06-04 11:46:33 -06001408bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement)
1409{
John Kessenich119f8f62016-06-05 15:44:07 -06001410 TSourceLoc loc = token.loc;
1411 TIntermTyped* condition = nullptr;
1412
1413 EHlslTokenClass loop = peek();
1414 assert(loop == EHTokDo || loop == EHTokFor || loop == EHTokWhile);
1415
1416 // WHILE or DO or FOR
1417 advanceToken();
1418
1419 switch (loop) {
1420 case EHTokWhile:
1421 // so that something declared in the condition is scoped to the lifetime
1422 // of the while sub-statement
1423 parseContext.pushScope();
1424 parseContext.nestLooping();
1425
1426 // LEFT_PAREN condition RIGHT_PAREN
1427 if (! acceptParenExpression(condition))
1428 return false;
1429
1430 // statement
1431 if (! acceptScopedStatement(statement)) {
1432 expected("while sub-statement");
1433 return false;
1434 }
1435
1436 parseContext.unnestLooping();
1437 parseContext.popScope();
1438
1439 statement = intermediate.addLoop(statement, condition, nullptr, true, loc);
1440
1441 return true;
1442
1443 case EHTokDo:
1444 parseContext.nestLooping();
1445
1446 if (! acceptTokenClass(EHTokLeftBrace))
1447 expected("{");
1448
1449 // statement
1450 if (! peekTokenClass(EHTokRightBrace) && ! acceptScopedStatement(statement)) {
1451 expected("do sub-statement");
1452 return false;
1453 }
1454
1455 if (! acceptTokenClass(EHTokRightBrace))
1456 expected("}");
1457
1458 // WHILE
1459 if (! acceptTokenClass(EHTokWhile)) {
1460 expected("while");
1461 return false;
1462 }
1463
1464 // LEFT_PAREN condition RIGHT_PAREN
1465 TIntermTyped* condition;
1466 if (! acceptParenExpression(condition))
1467 return false;
1468
1469 if (! acceptTokenClass(EHTokSemicolon))
1470 expected(";");
1471
1472 parseContext.unnestLooping();
1473
1474 statement = intermediate.addLoop(statement, condition, 0, false, loc);
1475
1476 return true;
1477
1478 case EHTokFor:
1479 {
1480 // LEFT_PAREN
1481 if (! acceptTokenClass(EHTokLeftParen))
1482 expected("(");
1483
1484 // so that something declared in the condition is scoped to the lifetime
1485 // of the for sub-statement
1486 parseContext.pushScope();
1487
1488 // initializer SEMI_COLON
1489 TIntermTyped* initializer = nullptr; // TODO, "for (initializer" needs to support decl. statement
1490 acceptExpression(initializer);
1491 if (! acceptTokenClass(EHTokSemicolon))
1492 expected(";");
1493
1494 parseContext.nestLooping();
1495
1496 // condition SEMI_COLON
1497 acceptExpression(condition);
1498 if (! acceptTokenClass(EHTokSemicolon))
1499 expected(";");
1500
1501 // iterator SEMI_COLON
1502 TIntermTyped* iterator = nullptr;
1503 acceptExpression(iterator);
1504 if (! acceptTokenClass(EHTokRightParen))
1505 expected(")");
1506
1507 // statement
1508 if (! acceptScopedStatement(statement)) {
1509 expected("for sub-statement");
1510 return false;
1511 }
1512
1513 statement = intermediate.addForLoop(statement, initializer, condition, iterator, true, loc);
1514
1515 parseContext.popScope();
1516 parseContext.unnestLooping();
1517
1518 return true;
1519 }
1520
1521 default:
1522 return false;
1523 }
John Kessenich21472ae2016-06-04 11:46:33 -06001524}
1525
1526// jump_statement
1527// : CONTINUE SEMICOLON
1528// | BREAK SEMICOLON
1529// | DISCARD SEMICOLON
1530// | RETURN SEMICOLON
1531// | RETURN expression SEMICOLON
1532//
1533bool HlslGrammar::acceptJumpStatement(TIntermNode*& statement)
1534{
1535 switch (peek()) {
1536 case EHTokContinue:
1537 case EHTokBreak:
1538 case EHTokDiscard:
1539 // TODO
1540 return false;
1541
1542 case EHTokReturn:
1543 // return
1544 if (acceptTokenClass(EHTokReturn)) {
1545 // expression
1546 TIntermTyped* node;
1547 if (acceptExpression(node)) {
1548 // hook it up
1549 statement = intermediate.addBranch(EOpReturn, node, token.loc);
1550 } else
1551 statement = intermediate.addBranch(EOpReturn, token.loc);
1552
1553 // SEMICOLON
1554 if (! acceptTokenClass(EHTokSemicolon)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06001555 expected(";");
John Kessenich21472ae2016-06-04 11:46:33 -06001556 return false;
1557 }
1558
1559 return true;
1560 }
1561
1562 default:
1563 return false;
1564 }
1565}
1566
1567
1568bool HlslGrammar::acceptCaseLabel(TIntermNode*& statement)
1569{
1570 return false;
1571}
1572
John Kessenich078d7f22016-03-14 10:02:11 -06001573// COLON semantic
1574bool HlslGrammar::acceptSemantic()
1575{
1576 // COLON
1577 if (acceptTokenClass(EHTokColon)) {
1578 // semantic
John Kessenichaecd4972016-03-14 10:46:34 -06001579 HlslToken idToken;
1580 if (! acceptIdentifier(idToken)) {
John Kessenich078d7f22016-03-14 10:02:11 -06001581 expected("semantic");
1582 return false;
1583 }
1584 }
1585
1586 return true;
1587}
1588
John Kesseniche01a9bc2016-03-12 20:11:22 -07001589} // end namespace glslang