blob: b7cb84230ad9c820b8048adff02de8f78fa15c6c [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{
212 if (! token.isType)
213 return false;
214
John Kessenich9c86c6a2016-05-03 22:49:24 -0600215 switch (peek()) {
John Kessenich71351de2016-06-08 12:50:56 -0600216 case EHTokVoid:
217 new(&type) TType(EbtVoid);
John Kessenich87142c72016-03-12 20:24:24 -0700218 break;
John Kessenich71351de2016-06-08 12:50:56 -0600219
John Kessenich87142c72016-03-12 20:24:24 -0700220 case EHTokFloat:
John Kessenich8d72f1a2016-05-20 12:06:03 -0600221 new(&type) TType(EbtFloat);
222 break;
John Kessenich87142c72016-03-12 20:24:24 -0700223 case EHTokFloat1:
224 new(&type) TType(EbtFloat);
John Kessenich8d72f1a2016-05-20 12:06:03 -0600225 type.makeVector();
John Kessenich87142c72016-03-12 20:24:24 -0700226 break;
John Kessenich87142c72016-03-12 20:24:24 -0700227 case EHTokFloat2:
228 new(&type) TType(EbtFloat, EvqTemporary, 2);
229 break;
230 case EHTokFloat3:
231 new(&type) TType(EbtFloat, EvqTemporary, 3);
232 break;
233 case EHTokFloat4:
234 new(&type) TType(EbtFloat, EvqTemporary, 4);
235 break;
236
John Kessenich71351de2016-06-08 12:50:56 -0600237 case EHTokDouble:
238 new(&type) TType(EbtDouble);
239 break;
240 case EHTokDouble1:
241 new(&type) TType(EbtDouble);
242 type.makeVector();
243 break;
244 case EHTokDouble2:
245 new(&type) TType(EbtDouble, EvqTemporary, 2);
246 break;
247 case EHTokDouble3:
248 new(&type) TType(EbtDouble, EvqTemporary, 3);
249 break;
250 case EHTokDouble4:
251 new(&type) TType(EbtDouble, EvqTemporary, 4);
252 break;
253
254 case EHTokInt:
255 case EHTokDword:
256 new(&type) TType(EbtInt);
257 break;
258 case EHTokInt1:
259 new(&type) TType(EbtInt);
260 type.makeVector();
261 break;
John Kessenich87142c72016-03-12 20:24:24 -0700262 case EHTokInt2:
263 new(&type) TType(EbtInt, EvqTemporary, 2);
264 break;
265 case EHTokInt3:
266 new(&type) TType(EbtInt, EvqTemporary, 3);
267 break;
268 case EHTokInt4:
269 new(&type) TType(EbtInt, EvqTemporary, 4);
270 break;
271
John Kessenich71351de2016-06-08 12:50:56 -0600272 case EHTokUint:
273 new(&type) TType(EbtUint);
274 break;
275 case EHTokUint1:
276 new(&type) TType(EbtUint);
277 type.makeVector();
278 break;
279 case EHTokUint2:
280 new(&type) TType(EbtUint, EvqTemporary, 2);
281 break;
282 case EHTokUint3:
283 new(&type) TType(EbtUint, EvqTemporary, 3);
284 break;
285 case EHTokUint4:
286 new(&type) TType(EbtUint, EvqTemporary, 4);
287 break;
288
289 case EHTokBool:
290 new(&type) TType(EbtBool);
291 break;
292 case EHTokBool1:
293 new(&type) TType(EbtBool);
294 type.makeVector();
295 break;
John Kessenich87142c72016-03-12 20:24:24 -0700296 case EHTokBool2:
297 new(&type) TType(EbtBool, EvqTemporary, 2);
298 break;
299 case EHTokBool3:
300 new(&type) TType(EbtBool, EvqTemporary, 3);
301 break;
302 case EHTokBool4:
303 new(&type) TType(EbtBool, EvqTemporary, 4);
304 break;
305
John Kessenich0133c122016-05-20 12:17:26 -0600306 case EHTokInt1x1:
307 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 1);
308 break;
309 case EHTokInt1x2:
310 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 1);
311 break;
312 case EHTokInt1x3:
313 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 1);
314 break;
315 case EHTokInt1x4:
316 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 1);
317 break;
318 case EHTokInt2x1:
319 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 2);
320 break;
321 case EHTokInt2x2:
322 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 2);
323 break;
324 case EHTokInt2x3:
325 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 2);
326 break;
327 case EHTokInt2x4:
328 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 2);
329 break;
330 case EHTokInt3x1:
331 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 3);
332 break;
333 case EHTokInt3x2:
334 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 3);
335 break;
336 case EHTokInt3x3:
337 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 3);
338 break;
339 case EHTokInt3x4:
340 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 3);
341 break;
342 case EHTokInt4x1:
343 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 4);
344 break;
345 case EHTokInt4x2:
346 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 4);
347 break;
348 case EHTokInt4x3:
349 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 4);
350 break;
351 case EHTokInt4x4:
352 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 4);
353 break;
354
John Kessenich71351de2016-06-08 12:50:56 -0600355 case EHTokUint1x1:
356 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 1);
357 break;
358 case EHTokUint1x2:
359 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 1);
360 break;
361 case EHTokUint1x3:
362 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 1);
363 break;
364 case EHTokUint1x4:
365 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 1);
366 break;
367 case EHTokUint2x1:
368 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 2);
369 break;
370 case EHTokUint2x2:
371 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 2);
372 break;
373 case EHTokUint2x3:
374 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 2);
375 break;
376 case EHTokUint2x4:
377 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 2);
378 break;
379 case EHTokUint3x1:
380 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 3);
381 break;
382 case EHTokUint3x2:
383 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 3);
384 break;
385 case EHTokUint3x3:
386 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 3);
387 break;
388 case EHTokUint3x4:
389 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 3);
390 break;
391 case EHTokUint4x1:
392 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 4);
393 break;
394 case EHTokUint4x2:
395 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 4);
396 break;
397 case EHTokUint4x3:
398 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 4);
399 break;
400 case EHTokUint4x4:
401 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 4);
402 break;
403
404 case EHTokBool1x1:
405 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 1);
406 break;
407 case EHTokBool1x2:
408 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 1);
409 break;
410 case EHTokBool1x3:
411 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 1);
412 break;
413 case EHTokBool1x4:
414 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 1);
415 break;
416 case EHTokBool2x1:
417 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 2);
418 break;
419 case EHTokBool2x2:
420 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 2);
421 break;
422 case EHTokBool2x3:
423 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 2);
424 break;
425 case EHTokBool2x4:
426 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 2);
427 break;
428 case EHTokBool3x1:
429 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 3);
430 break;
431 case EHTokBool3x2:
432 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 3);
433 break;
434 case EHTokBool3x3:
435 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 3);
436 break;
437 case EHTokBool3x4:
438 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 3);
439 break;
440 case EHTokBool4x1:
441 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 4);
442 break;
443 case EHTokBool4x2:
444 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 4);
445 break;
446 case EHTokBool4x3:
447 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 4);
448 break;
449 case EHTokBool4x4:
450 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 4);
451 break;
452
John Kessenich0133c122016-05-20 12:17:26 -0600453 case EHTokFloat1x1:
454 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 1);
455 break;
456 case EHTokFloat1x2:
457 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 1);
458 break;
459 case EHTokFloat1x3:
460 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 1);
461 break;
462 case EHTokFloat1x4:
463 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 1);
464 break;
465 case EHTokFloat2x1:
466 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 2);
467 break;
John Kessenich87142c72016-03-12 20:24:24 -0700468 case EHTokFloat2x2:
469 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 2);
470 break;
471 case EHTokFloat2x3:
472 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 2);
473 break;
474 case EHTokFloat2x4:
475 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 2);
476 break;
John Kessenich0133c122016-05-20 12:17:26 -0600477 case EHTokFloat3x1:
478 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 3);
479 break;
John Kessenich87142c72016-03-12 20:24:24 -0700480 case EHTokFloat3x2:
481 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 3);
482 break;
483 case EHTokFloat3x3:
484 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 3);
485 break;
486 case EHTokFloat3x4:
487 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 3);
488 break;
John Kessenich0133c122016-05-20 12:17:26 -0600489 case EHTokFloat4x1:
490 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 4);
491 break;
John Kessenich87142c72016-03-12 20:24:24 -0700492 case EHTokFloat4x2:
493 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 4);
494 break;
495 case EHTokFloat4x3:
496 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 4);
497 break;
498 case EHTokFloat4x4:
499 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 4);
500 break;
501
John Kessenich0133c122016-05-20 12:17:26 -0600502 case EHTokDouble1x1:
503 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 1);
504 break;
505 case EHTokDouble1x2:
506 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 1);
507 break;
508 case EHTokDouble1x3:
509 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 1);
510 break;
511 case EHTokDouble1x4:
512 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 1);
513 break;
514 case EHTokDouble2x1:
515 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 2);
516 break;
517 case EHTokDouble2x2:
518 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 2);
519 break;
520 case EHTokDouble2x3:
521 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 2);
522 break;
523 case EHTokDouble2x4:
524 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 2);
525 break;
526 case EHTokDouble3x1:
527 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 3);
528 break;
529 case EHTokDouble3x2:
530 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 3);
531 break;
532 case EHTokDouble3x3:
533 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 3);
534 break;
535 case EHTokDouble3x4:
536 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 3);
537 break;
538 case EHTokDouble4x1:
539 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 4);
540 break;
541 case EHTokDouble4x2:
542 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 4);
543 break;
544 case EHTokDouble4x3:
545 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 4);
546 break;
547 case EHTokDouble4x4:
548 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 4);
549 break;
550
John Kessenich87142c72016-03-12 20:24:24 -0700551 default:
552 return false;
553 }
554
555 advanceToken();
556
557 return true;
558}
559
John Kessenich5f934b02016-03-13 17:58:25 -0600560// function_parameters
John Kessenich078d7f22016-03-14 10:02:11 -0600561// : LEFT_PAREN parameter_declaration COMMA parameter_declaration ... RIGHT_PAREN
John Kessenich71351de2016-06-08 12:50:56 -0600562// | LEFT_PAREN VOID RIGHT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -0600563//
564bool HlslGrammar::acceptFunctionParameters(TFunction& function)
565{
John Kessenich078d7f22016-03-14 10:02:11 -0600566 // LEFT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -0600567 if (! acceptTokenClass(EHTokLeftParen))
568 return false;
569
John Kessenich71351de2016-06-08 12:50:56 -0600570 // VOID RIGHT_PAREN
571 if (! acceptTokenClass(EHTokVoid)) {
572 do {
573 // parameter_declaration
574 if (! acceptParameterDeclaration(function))
575 break;
John Kessenich5f934b02016-03-13 17:58:25 -0600576
John Kessenich71351de2016-06-08 12:50:56 -0600577 // COMMA
578 if (! acceptTokenClass(EHTokComma))
579 break;
580 } while (true);
581 }
John Kessenich5f934b02016-03-13 17:58:25 -0600582
John Kessenich078d7f22016-03-14 10:02:11 -0600583 // RIGHT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -0600584 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -0600585 expected(")");
John Kessenich5f934b02016-03-13 17:58:25 -0600586 return false;
587 }
588
589 return true;
590}
591
592// parameter_declaration
593// : fully_specified_type
594// | fully_specified_type identifier
595//
596bool HlslGrammar::acceptParameterDeclaration(TFunction& function)
597{
598 // fully_specified_type
599 TType* type = new TType;
600 if (! acceptFullySpecifiedType(*type))
601 return false;
602
603 // identifier
John Kessenichaecd4972016-03-14 10:46:34 -0600604 HlslToken idToken;
605 acceptIdentifier(idToken);
John Kessenich5f934b02016-03-13 17:58:25 -0600606
John Kessenichaecd4972016-03-14 10:46:34 -0600607 TParameter param = { idToken.string, type };
John Kessenich5f934b02016-03-13 17:58:25 -0600608 function.addParameter(param);
609
610 return true;
611}
612
613// Do the work to create the function definition in addition to
614// parsing the body (compound_statement).
615bool HlslGrammar::acceptFunctionDefinition(TFunction& function, TIntermNode*& node)
616{
617 TFunction* functionDeclarator = parseContext.handleFunctionDeclarator(token.loc, function, false /* not prototype */);
618
619 // This does a symbol table push
620 node = parseContext.handleFunctionDefinition(token.loc, *functionDeclarator);
621
622 // compound_statement
John Kessenich21472ae2016-06-04 11:46:33 -0600623 TIntermNode* functionBody = nullptr;
John Kessenich5f934b02016-03-13 17:58:25 -0600624 if (acceptCompoundStatement(functionBody)) {
John Kessenich078d7f22016-03-14 10:02:11 -0600625 node = intermediate.growAggregate(node, functionBody);
626 intermediate.setAggregateOperator(node, EOpFunction, functionDeclarator->getType(), token.loc);
John Kessenich5f934b02016-03-13 17:58:25 -0600627 node->getAsAggregate()->setName(functionDeclarator->getMangledName().c_str());
628 parseContext.symbolTable.pop(nullptr);
629
630 return true;
631 }
632
633 return false;
634}
635
John Kessenich0d2b6de2016-06-05 11:23:11 -0600636// Accept an expression with parenthesis around it, where
637// the parenthesis ARE NOT expression parenthesis, but the
638// syntactically required ones like in "if ( expression )"
639//
640// Note this one is not set up to be speculative; as it gives
641// errors if not found.
642//
643bool HlslGrammar::acceptParenExpression(TIntermTyped*& expression)
644{
645 // LEFT_PAREN
646 if (! acceptTokenClass(EHTokLeftParen))
647 expected("(");
648
649 if (! acceptExpression(expression)) {
650 expected("expression");
651 return false;
652 }
653
654 // RIGHT_PAREN
655 if (! acceptTokenClass(EHTokRightParen))
656 expected(")");
657
658 return true;
659}
660
John Kessenich34fb0362016-05-03 23:17:20 -0600661// The top-level full expression recognizer.
662//
John Kessenich87142c72016-03-12 20:24:24 -0700663// expression
John Kessenich34fb0362016-05-03 23:17:20 -0600664// : assignment_expression COMMA assignment_expression COMMA assignment_expression ...
John Kessenich87142c72016-03-12 20:24:24 -0700665//
666bool HlslGrammar::acceptExpression(TIntermTyped*& node)
667{
LoopDawgef764a22016-06-03 09:17:51 -0600668 node = nullptr;
669
John Kessenich34fb0362016-05-03 23:17:20 -0600670 // assignment_expression
671 if (! acceptAssignmentExpression(node))
672 return false;
John Kessenich5f934b02016-03-13 17:58:25 -0600673
John Kessenich34fb0362016-05-03 23:17:20 -0600674 if (! peekTokenClass(EHTokComma))
675 return true;
676
677 do {
678 // ... COMMA
John Kessenich5f934b02016-03-13 17:58:25 -0600679 TSourceLoc loc = token.loc;
John Kessenich34fb0362016-05-03 23:17:20 -0600680 advanceToken();
John Kessenich5f934b02016-03-13 17:58:25 -0600681
John Kessenich34fb0362016-05-03 23:17:20 -0600682 // ... assignment_expression
683 TIntermTyped* rightNode = nullptr;
684 if (! acceptAssignmentExpression(rightNode)) {
685 expected("assignment expression");
686 return false;
John Kessenich5f934b02016-03-13 17:58:25 -0600687 }
688
John Kessenich34fb0362016-05-03 23:17:20 -0600689 node = intermediate.addComma(node, rightNode, loc);
690
691 if (! peekTokenClass(EHTokComma))
692 return true;
693 } while (true);
694}
695
696// Accept an assignment expression, where assignment operations
697// associate right-to-left. This is, it is implicit, for example
698//
699// a op (b op (c op d))
700//
701// assigment_expression
702// : binary_expression op binary_expression op binary_expression ...
703//
704bool HlslGrammar::acceptAssignmentExpression(TIntermTyped*& node)
705{
706 if (! acceptBinaryExpression(node, PlLogicalOr))
707 return false;
708
709 TOperator assignOp = HlslOpMap::assignment(peek());
710 if (assignOp == EOpNull)
711 return true;
712
713 // ... op
714 TSourceLoc loc = token.loc;
715 advanceToken();
716
717 // ... binary_expression
718 // But, done by recursing this function, which automatically
719 // gets the right-to-left associativity.
720 TIntermTyped* rightNode = nullptr;
721 if (! acceptAssignmentExpression(rightNode)) {
722 expected("assignment expression");
John Kessenich5f934b02016-03-13 17:58:25 -0600723 return false;
John Kessenich87142c72016-03-12 20:24:24 -0700724 }
725
John Kessenich34fb0362016-05-03 23:17:20 -0600726 node = intermediate.addAssign(assignOp, node, rightNode, loc);
727
728 if (! peekTokenClass(EHTokComma))
729 return true;
730
731 return true;
732}
733
734// Accept a binary expression, for binary operations that
735// associate left-to-right. This is, it is implicit, for example
736//
737// ((a op b) op c) op d
738//
739// binary_expression
740// : expression op expression op expression ...
741//
742// where 'expression' is the next higher level in precedence.
743//
744bool HlslGrammar::acceptBinaryExpression(TIntermTyped*& node, PrecedenceLevel precedenceLevel)
745{
746 if (precedenceLevel > PlMul)
747 return acceptUnaryExpression(node);
748
749 // assignment_expression
750 if (! acceptBinaryExpression(node, (PrecedenceLevel)(precedenceLevel + 1)))
751 return false;
752
753 TOperator op = HlslOpMap::binary(peek());
754 PrecedenceLevel tokenLevel = HlslOpMap::precedenceLevel(op);
755 if (tokenLevel < precedenceLevel)
756 return true;
757
758 do {
759 // ... op
760 TSourceLoc loc = token.loc;
761 advanceToken();
762
763 // ... expression
764 TIntermTyped* rightNode = nullptr;
765 if (! acceptBinaryExpression(rightNode, (PrecedenceLevel)(precedenceLevel + 1))) {
766 expected("expression");
767 return false;
768 }
769
770 node = intermediate.addBinaryMath(op, node, rightNode, loc);
771
772 if (! peekTokenClass(EHTokComma))
773 return true;
774 } while (true);
775}
776
777// unary_expression
John Kessenich1cc1a282016-06-03 16:55:49 -0600778// : (type) unary_expression
779// | + unary_expression
John Kessenich34fb0362016-05-03 23:17:20 -0600780// | - unary_expression
781// | ! unary_expression
782// | ~ unary_expression
783// | ++ unary_expression
784// | -- unary_expression
785// | postfix_expression
786//
787bool HlslGrammar::acceptUnaryExpression(TIntermTyped*& node)
788{
John Kessenich1cc1a282016-06-03 16:55:49 -0600789 // (type) unary_expression
790 // Have to look two steps ahead, because this could be, e.g., a
791 // postfix_expression instead, since that also starts with at "(".
792 if (acceptTokenClass(EHTokLeftParen)) {
793 TType castType;
794 if (acceptType(castType)) {
795 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -0600796 expected(")");
John Kessenich1cc1a282016-06-03 16:55:49 -0600797 return false;
798 }
799
800 // We've matched "(type)" now, get the expression to cast
801 TSourceLoc loc = token.loc;
802 if (! acceptUnaryExpression(node))
803 return false;
804
805 // Hook it up like a constructor
806 TFunction* constructorFunction = parseContext.handleConstructorCall(loc, castType);
807 if (constructorFunction == nullptr) {
808 expected("type that can be constructed");
809 return false;
810 }
811 TIntermTyped* arguments = nullptr;
812 parseContext.handleFunctionArgument(constructorFunction, arguments, node);
813 node = parseContext.handleFunctionCall(loc, constructorFunction, arguments);
814
815 return true;
816 } else {
817 // This isn't a type cast, but it still started "(", so if it is a
818 // unary expression, it can only be a postfix_expression, so try that.
819 // Back it up first.
820 recedeToken();
821 return acceptPostfixExpression(node);
822 }
823 }
824
825 // peek for "op unary_expression"
John Kessenich34fb0362016-05-03 23:17:20 -0600826 TOperator unaryOp = HlslOpMap::preUnary(peek());
827
John Kessenich1cc1a282016-06-03 16:55:49 -0600828 // postfix_expression (if no unary operator)
John Kessenich34fb0362016-05-03 23:17:20 -0600829 if (unaryOp == EOpNull)
830 return acceptPostfixExpression(node);
831
832 // op unary_expression
833 TSourceLoc loc = token.loc;
834 advanceToken();
835 if (! acceptUnaryExpression(node))
836 return false;
837
838 // + is a no-op
839 if (unaryOp == EOpAdd)
840 return true;
841
842 node = intermediate.addUnaryMath(unaryOp, node, loc);
843
844 return node != nullptr;
845}
846
847// postfix_expression
848// : LEFT_PAREN expression RIGHT_PAREN
849// | literal
850// | constructor
851// | identifier
852// | function_call
853// | postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET
854// | postfix_expression DOT IDENTIFIER
855// | postfix_expression INC_OP
856// | postfix_expression DEC_OP
857//
858bool HlslGrammar::acceptPostfixExpression(TIntermTyped*& node)
859{
860 // Not implemented as self-recursive:
861 // The logical "right recursion" is done with an loop at the end
862
863 // idToken will pick up either a variable or a function name in a function call
864 HlslToken idToken;
865
John Kessenich21472ae2016-06-04 11:46:33 -0600866 // Find something before the postfix operations, as they can't operate
867 // on nothing. So, no "return true", they fall through, only "return false".
John Kessenich87142c72016-03-12 20:24:24 -0700868 if (acceptTokenClass(EHTokLeftParen)) {
John Kessenich21472ae2016-06-04 11:46:33 -0600869 // LEFT_PAREN expression RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -0700870 if (! acceptExpression(node)) {
871 expected("expression");
872 return false;
873 }
874 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -0600875 expected(")");
John Kessenich87142c72016-03-12 20:24:24 -0700876 return false;
877 }
John Kessenich34fb0362016-05-03 23:17:20 -0600878 } else if (acceptLiteral(node)) {
879 // literal (nothing else to do yet), go on to the
880 } else if (acceptConstructor(node)) {
881 // constructor (nothing else to do yet)
882 } else if (acceptIdentifier(idToken)) {
883 // identifier or function_call name
884 if (! peekTokenClass(EHTokLeftParen)) {
885 node = parseContext.handleVariable(idToken.loc, idToken.symbol, token.string);
886 } else if (acceptFunctionCall(idToken, node)) {
887 // function_call (nothing else to do yet)
888 } else {
889 expected("function call arguments");
890 return false;
891 }
John Kessenich21472ae2016-06-04 11:46:33 -0600892 } else {
893 // nothing found, can't post operate
894 return false;
John Kessenich87142c72016-03-12 20:24:24 -0700895 }
896
John Kessenich21472ae2016-06-04 11:46:33 -0600897 // Something was found, chain as many postfix operations as exist.
John Kessenich34fb0362016-05-03 23:17:20 -0600898 do {
899 TSourceLoc loc = token.loc;
900 TOperator postOp = HlslOpMap::postUnary(peek());
John Kessenich87142c72016-03-12 20:24:24 -0700901
John Kessenich34fb0362016-05-03 23:17:20 -0600902 // Consume only a valid post-unary operator, otherwise we are done.
903 switch (postOp) {
904 case EOpIndexDirectStruct:
905 case EOpIndexIndirect:
906 case EOpPostIncrement:
907 case EOpPostDecrement:
908 advanceToken();
909 break;
910 default:
911 return true;
912 }
John Kessenich87142c72016-03-12 20:24:24 -0700913
John Kessenich34fb0362016-05-03 23:17:20 -0600914 // We have a valid post-unary operator, process it.
915 switch (postOp) {
916 case EOpIndexDirectStruct:
917 // todo
918 break;
919 case EOpIndexIndirect:
920 {
921 TIntermTyped* indexNode = nullptr;
922 if (! acceptExpression(indexNode) ||
923 ! peekTokenClass(EHTokRightBracket)) {
924 expected("expression followed by ']'");
925 return false;
926 }
927 // todo: node = intermediate.addBinaryMath(
928 }
929 case EOpPostIncrement:
930 case EOpPostDecrement:
931 node = intermediate.addUnaryMath(postOp, node, loc);
932 break;
933 default:
934 assert(0);
935 break;
936 }
937 } while (true);
John Kessenich87142c72016-03-12 20:24:24 -0700938}
939
John Kessenichd016be12016-03-13 11:24:20 -0600940// constructor
John Kessenich078d7f22016-03-14 10:02:11 -0600941// : type argument_list
John Kessenichd016be12016-03-13 11:24:20 -0600942//
943bool HlslGrammar::acceptConstructor(TIntermTyped*& node)
944{
945 // type
946 TType type;
947 if (acceptType(type)) {
948 TFunction* constructorFunction = parseContext.handleConstructorCall(token.loc, type);
949 if (constructorFunction == nullptr)
950 return false;
951
952 // arguments
John Kessenich4678ca92016-05-13 09:33:42 -0600953 TIntermTyped* arguments = nullptr;
John Kessenichd016be12016-03-13 11:24:20 -0600954 if (! acceptArguments(constructorFunction, arguments)) {
955 expected("constructor arguments");
956 return false;
957 }
958
959 // hook it up
960 node = parseContext.handleFunctionCall(arguments->getLoc(), constructorFunction, arguments);
961
962 return true;
963 }
964
965 return false;
966}
967
John Kessenich34fb0362016-05-03 23:17:20 -0600968// The function_call identifier was already recognized, and passed in as idToken.
969//
970// function_call
971// : [idToken] arguments
972//
John Kessenich4678ca92016-05-13 09:33:42 -0600973bool HlslGrammar::acceptFunctionCall(HlslToken idToken, TIntermTyped*& node)
John Kessenich34fb0362016-05-03 23:17:20 -0600974{
John Kessenich4678ca92016-05-13 09:33:42 -0600975 // arguments
976 TFunction* function = new TFunction(idToken.string, TType(EbtVoid));
977 TIntermTyped* arguments = nullptr;
978 if (! acceptArguments(function, arguments))
979 return false;
980
981 node = parseContext.handleFunctionCall(idToken.loc, function, arguments);
982
983 return true;
John Kessenich34fb0362016-05-03 23:17:20 -0600984}
985
John Kessenich87142c72016-03-12 20:24:24 -0700986// arguments
John Kessenich078d7f22016-03-14 10:02:11 -0600987// : LEFT_PAREN expression COMMA expression COMMA ... RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -0700988//
John Kessenichd016be12016-03-13 11:24:20 -0600989// The arguments are pushed onto the 'function' argument list and
990// onto the 'arguments' aggregate.
991//
John Kessenich4678ca92016-05-13 09:33:42 -0600992bool HlslGrammar::acceptArguments(TFunction* function, TIntermTyped*& arguments)
John Kessenich87142c72016-03-12 20:24:24 -0700993{
John Kessenich078d7f22016-03-14 10:02:11 -0600994 // LEFT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -0700995 if (! acceptTokenClass(EHTokLeftParen))
996 return false;
997
998 do {
John Kessenichd016be12016-03-13 11:24:20 -0600999 // expression
John Kessenich87142c72016-03-12 20:24:24 -07001000 TIntermTyped* arg;
John Kessenich4678ca92016-05-13 09:33:42 -06001001 if (! acceptAssignmentExpression(arg))
John Kessenich87142c72016-03-12 20:24:24 -07001002 break;
John Kessenichd016be12016-03-13 11:24:20 -06001003
1004 // hook it up
1005 parseContext.handleFunctionArgument(function, arguments, arg);
1006
John Kessenich078d7f22016-03-14 10:02:11 -06001007 // COMMA
John Kessenich87142c72016-03-12 20:24:24 -07001008 if (! acceptTokenClass(EHTokComma))
1009 break;
1010 } while (true);
1011
John Kessenich078d7f22016-03-14 10:02:11 -06001012 // RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07001013 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06001014 expected(")");
John Kessenich87142c72016-03-12 20:24:24 -07001015 return false;
1016 }
1017
1018 return true;
1019}
1020
1021bool HlslGrammar::acceptLiteral(TIntermTyped*& node)
1022{
1023 switch (token.tokenClass) {
1024 case EHTokIntConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06001025 node = intermediate.addConstantUnion(token.i, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07001026 break;
1027 case EHTokFloatConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06001028 node = intermediate.addConstantUnion(token.d, EbtFloat, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07001029 break;
1030 case EHTokDoubleConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06001031 node = intermediate.addConstantUnion(token.d, EbtDouble, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07001032 break;
1033 case EHTokBoolConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06001034 node = intermediate.addConstantUnion(token.b, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07001035 break;
1036
1037 default:
1038 return false;
1039 }
1040
1041 advanceToken();
1042
1043 return true;
1044}
1045
John Kessenich5f934b02016-03-13 17:58:25 -06001046// compound_statement
John Kessenich34fb0362016-05-03 23:17:20 -06001047// : LEFT_CURLY statement statement ... RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06001048//
John Kessenich21472ae2016-06-04 11:46:33 -06001049bool HlslGrammar::acceptCompoundStatement(TIntermNode*& retStatement)
John Kessenich87142c72016-03-12 20:24:24 -07001050{
John Kessenich21472ae2016-06-04 11:46:33 -06001051 TIntermAggregate* compoundStatement = nullptr;
1052
John Kessenich34fb0362016-05-03 23:17:20 -06001053 // LEFT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06001054 if (! acceptTokenClass(EHTokLeftBrace))
1055 return false;
1056
1057 // statement statement ...
1058 TIntermNode* statement = nullptr;
1059 while (acceptStatement(statement)) {
1060 // hook it up
John Kessenich078d7f22016-03-14 10:02:11 -06001061 compoundStatement = intermediate.growAggregate(compoundStatement, statement);
John Kessenich5f934b02016-03-13 17:58:25 -06001062 }
John Kessenich34fb0362016-05-03 23:17:20 -06001063 if (compoundStatement)
1064 compoundStatement->setOperator(EOpSequence);
John Kessenich5f934b02016-03-13 17:58:25 -06001065
John Kessenich21472ae2016-06-04 11:46:33 -06001066 retStatement = compoundStatement;
1067
John Kessenich34fb0362016-05-03 23:17:20 -06001068 // RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06001069 return acceptTokenClass(EHTokRightBrace);
1070}
1071
John Kessenich0d2b6de2016-06-05 11:23:11 -06001072bool HlslGrammar::acceptScopedStatement(TIntermNode*& statement)
1073{
1074 parseContext.pushScope();
1075 bool result = acceptNestedStatement(statement);
1076 parseContext.popScope();
1077
1078 return result;
1079}
1080
1081bool HlslGrammar::acceptNestedStatement(TIntermNode*& statement)
1082{
1083 parseContext.nestStatement();
1084 bool result = acceptStatement(statement);
1085 parseContext.unnestStatement();
1086
1087 return result;
1088}
1089
John Kessenich5f934b02016-03-13 17:58:25 -06001090// statement
John Kessenich21472ae2016-06-04 11:46:33 -06001091// : attributes attributed_statement
1092//
1093// attributed_statement
John Kessenich5f934b02016-03-13 17:58:25 -06001094// : compound_statement
John Kessenich21472ae2016-06-04 11:46:33 -06001095// | SEMICOLON
John Kessenich078d7f22016-03-14 10:02:11 -06001096// | expression SEMICOLON
John Kessenich21472ae2016-06-04 11:46:33 -06001097// | declaration_statement
1098// | selection_statement
1099// | switch_statement
1100// | case_label
1101// | iteration_statement
1102// | jump_statement
John Kessenich5f934b02016-03-13 17:58:25 -06001103//
1104bool HlslGrammar::acceptStatement(TIntermNode*& statement)
1105{
John Kessenich21472ae2016-06-04 11:46:33 -06001106 statement = nullptr;
John Kessenich5f934b02016-03-13 17:58:25 -06001107
John Kessenich21472ae2016-06-04 11:46:33 -06001108 // attributes
1109 acceptAttributes();
John Kessenich5f934b02016-03-13 17:58:25 -06001110
John Kessenich21472ae2016-06-04 11:46:33 -06001111 // attributed_statement
1112 switch (peek()) {
1113 case EHTokLeftBrace:
1114 return acceptCompoundStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06001115
John Kessenich21472ae2016-06-04 11:46:33 -06001116 case EHTokIf:
1117 return acceptSelectionStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06001118
John Kessenich21472ae2016-06-04 11:46:33 -06001119 case EHTokSwitch:
1120 return acceptSwitchStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06001121
John Kessenich21472ae2016-06-04 11:46:33 -06001122 case EHTokFor:
1123 case EHTokDo:
1124 case EHTokWhile:
1125 return acceptIterationStatement(statement);
1126
1127 case EHTokContinue:
1128 case EHTokBreak:
1129 case EHTokDiscard:
1130 case EHTokReturn:
1131 return acceptJumpStatement(statement);
1132
1133 case EHTokCase:
1134 return acceptCaseLabel(statement);
1135
1136 case EHTokSemicolon:
1137 return acceptTokenClass(EHTokSemicolon);
1138
1139 case EHTokRightBrace:
1140 // Performance: not strictly necessary, but stops a bunch of hunting early,
1141 // and is how sequences of statements end.
John Kessenich5f934b02016-03-13 17:58:25 -06001142 return false;
1143
John Kessenich21472ae2016-06-04 11:46:33 -06001144 default:
1145 {
1146 // declaration
1147 if (acceptDeclaration(statement))
1148 return true;
1149
1150 // expression
1151 TIntermTyped* node;
1152 if (acceptExpression(node))
1153 statement = node;
1154 else
1155 return false;
1156
1157 // SEMICOLON (following an expression)
1158 if (! acceptTokenClass(EHTokSemicolon)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06001159 expected(";");
John Kessenich21472ae2016-06-04 11:46:33 -06001160 return false;
1161 }
1162 }
1163 }
1164
John Kessenich5f934b02016-03-13 17:58:25 -06001165 return true;
John Kessenich87142c72016-03-12 20:24:24 -07001166}
1167
John Kessenich21472ae2016-06-04 11:46:33 -06001168// attributes
1169// : list of zero or more of: LEFT_BRACKET attribute RIGHT_BRACKET
1170//
1171// attribute:
1172// : UNROLL
1173// | UNROLL LEFT_PAREN literal RIGHT_PAREN
1174// | FASTOPT
1175// | ALLOW_UAV_CONDITION
1176// | BRANCH
1177// | FLATTEN
1178// | FORCECASE
1179// | CALL
1180//
1181void HlslGrammar::acceptAttributes()
1182{
John Kessenich0d2b6de2016-06-05 11:23:11 -06001183 // For now, accept the [ XXX(X) ] syntax, but drop.
1184 // TODO: subset to correct set? Pass on?
1185 do {
1186 // LEFT_BRACKET?
1187 if (! acceptTokenClass(EHTokLeftBracket))
1188 return;
1189
1190 // attribute
1191 if (peekTokenClass(EHTokIdentifier)) {
1192 // 'token.string' is the attribute
1193 advanceToken();
1194 } else if (! peekTokenClass(EHTokRightBracket)) {
1195 expected("identifier");
1196 advanceToken();
1197 }
1198
1199 // (x)
1200 if (acceptTokenClass(EHTokLeftParen)) {
1201 TIntermTyped* node;
1202 if (! acceptLiteral(node))
1203 expected("literal");
1204 // 'node' has the literal in it
1205 if (! acceptTokenClass(EHTokRightParen))
1206 expected(")");
1207 }
1208
1209 // RIGHT_BRACKET
1210 if (acceptTokenClass(EHTokRightBracket))
1211 continue;
1212
1213 expected("]");
1214 return;
1215
1216 } while (true);
John Kessenich21472ae2016-06-04 11:46:33 -06001217}
1218
John Kessenich0d2b6de2016-06-05 11:23:11 -06001219// selection_statement
1220// : IF LEFT_PAREN expression RIGHT_PAREN statement
1221// : IF LEFT_PAREN expression RIGHT_PAREN statement ELSE statement
1222//
John Kessenich21472ae2016-06-04 11:46:33 -06001223bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement)
1224{
John Kessenich0d2b6de2016-06-05 11:23:11 -06001225 TSourceLoc loc = token.loc;
1226
1227 // IF
1228 if (! acceptTokenClass(EHTokIf))
1229 return false;
1230
1231 // so that something declared in the condition is scoped to the lifetimes
1232 // of the then-else statements
1233 parseContext.pushScope();
1234
1235 // LEFT_PAREN expression RIGHT_PAREN
1236 TIntermTyped* condition;
1237 if (! acceptParenExpression(condition))
1238 return false;
1239
1240 // create the child statements
1241 TIntermNodePair thenElse = { nullptr, nullptr };
1242
1243 // then statement
1244 if (! acceptScopedStatement(thenElse.node1)) {
1245 expected("then statement");
1246 return false;
1247 }
1248
1249 // ELSE
1250 if (acceptTokenClass(EHTokElse)) {
1251 // else statement
1252 if (! acceptScopedStatement(thenElse.node2)) {
1253 expected("else statement");
1254 return false;
1255 }
1256 }
1257
1258 // Put the pieces together
1259 statement = intermediate.addSelection(condition, thenElse, loc);
1260 parseContext.popScope();
1261
1262 return true;
John Kessenich21472ae2016-06-04 11:46:33 -06001263}
1264
1265bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement)
1266{
1267 return false;
1268}
1269
John Kessenich119f8f62016-06-05 15:44:07 -06001270// iteration_statement
1271// : WHILE LEFT_PAREN condition RIGHT_PAREN statement
1272// | DO LEFT_BRACE statement RIGHT_BRACE WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON
1273// | FOR LEFT_PAREN for_init_statement for_rest_statement RIGHT_PAREN statement
1274//
1275// Non-speculative, only call if it needs to be found; WHILE or DO or FOR already seen.
John Kessenich21472ae2016-06-04 11:46:33 -06001276bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement)
1277{
John Kessenich119f8f62016-06-05 15:44:07 -06001278 TSourceLoc loc = token.loc;
1279 TIntermTyped* condition = nullptr;
1280
1281 EHlslTokenClass loop = peek();
1282 assert(loop == EHTokDo || loop == EHTokFor || loop == EHTokWhile);
1283
1284 // WHILE or DO or FOR
1285 advanceToken();
1286
1287 switch (loop) {
1288 case EHTokWhile:
1289 // so that something declared in the condition is scoped to the lifetime
1290 // of the while sub-statement
1291 parseContext.pushScope();
1292 parseContext.nestLooping();
1293
1294 // LEFT_PAREN condition RIGHT_PAREN
1295 if (! acceptParenExpression(condition))
1296 return false;
1297
1298 // statement
1299 if (! acceptScopedStatement(statement)) {
1300 expected("while sub-statement");
1301 return false;
1302 }
1303
1304 parseContext.unnestLooping();
1305 parseContext.popScope();
1306
1307 statement = intermediate.addLoop(statement, condition, nullptr, true, loc);
1308
1309 return true;
1310
1311 case EHTokDo:
1312 parseContext.nestLooping();
1313
1314 if (! acceptTokenClass(EHTokLeftBrace))
1315 expected("{");
1316
1317 // statement
1318 if (! peekTokenClass(EHTokRightBrace) && ! acceptScopedStatement(statement)) {
1319 expected("do sub-statement");
1320 return false;
1321 }
1322
1323 if (! acceptTokenClass(EHTokRightBrace))
1324 expected("}");
1325
1326 // WHILE
1327 if (! acceptTokenClass(EHTokWhile)) {
1328 expected("while");
1329 return false;
1330 }
1331
1332 // LEFT_PAREN condition RIGHT_PAREN
1333 TIntermTyped* condition;
1334 if (! acceptParenExpression(condition))
1335 return false;
1336
1337 if (! acceptTokenClass(EHTokSemicolon))
1338 expected(";");
1339
1340 parseContext.unnestLooping();
1341
1342 statement = intermediate.addLoop(statement, condition, 0, false, loc);
1343
1344 return true;
1345
1346 case EHTokFor:
1347 {
1348 // LEFT_PAREN
1349 if (! acceptTokenClass(EHTokLeftParen))
1350 expected("(");
1351
1352 // so that something declared in the condition is scoped to the lifetime
1353 // of the for sub-statement
1354 parseContext.pushScope();
1355
1356 // initializer SEMI_COLON
1357 TIntermTyped* initializer = nullptr; // TODO, "for (initializer" needs to support decl. statement
1358 acceptExpression(initializer);
1359 if (! acceptTokenClass(EHTokSemicolon))
1360 expected(";");
1361
1362 parseContext.nestLooping();
1363
1364 // condition SEMI_COLON
1365 acceptExpression(condition);
1366 if (! acceptTokenClass(EHTokSemicolon))
1367 expected(";");
1368
1369 // iterator SEMI_COLON
1370 TIntermTyped* iterator = nullptr;
1371 acceptExpression(iterator);
1372 if (! acceptTokenClass(EHTokRightParen))
1373 expected(")");
1374
1375 // statement
1376 if (! acceptScopedStatement(statement)) {
1377 expected("for sub-statement");
1378 return false;
1379 }
1380
1381 statement = intermediate.addForLoop(statement, initializer, condition, iterator, true, loc);
1382
1383 parseContext.popScope();
1384 parseContext.unnestLooping();
1385
1386 return true;
1387 }
1388
1389 default:
1390 return false;
1391 }
John Kessenich21472ae2016-06-04 11:46:33 -06001392}
1393
1394// jump_statement
1395// : CONTINUE SEMICOLON
1396// | BREAK SEMICOLON
1397// | DISCARD SEMICOLON
1398// | RETURN SEMICOLON
1399// | RETURN expression SEMICOLON
1400//
1401bool HlslGrammar::acceptJumpStatement(TIntermNode*& statement)
1402{
1403 switch (peek()) {
1404 case EHTokContinue:
1405 case EHTokBreak:
1406 case EHTokDiscard:
1407 // TODO
1408 return false;
1409
1410 case EHTokReturn:
1411 // return
1412 if (acceptTokenClass(EHTokReturn)) {
1413 // expression
1414 TIntermTyped* node;
1415 if (acceptExpression(node)) {
1416 // hook it up
1417 statement = intermediate.addBranch(EOpReturn, node, token.loc);
1418 } else
1419 statement = intermediate.addBranch(EOpReturn, token.loc);
1420
1421 // SEMICOLON
1422 if (! acceptTokenClass(EHTokSemicolon)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06001423 expected(";");
John Kessenich21472ae2016-06-04 11:46:33 -06001424 return false;
1425 }
1426
1427 return true;
1428 }
1429
1430 default:
1431 return false;
1432 }
1433}
1434
1435
1436bool HlslGrammar::acceptCaseLabel(TIntermNode*& statement)
1437{
1438 return false;
1439}
1440
John Kessenich078d7f22016-03-14 10:02:11 -06001441// COLON semantic
1442bool HlslGrammar::acceptSemantic()
1443{
1444 // COLON
1445 if (acceptTokenClass(EHTokColon)) {
1446 // semantic
John Kessenichaecd4972016-03-14 10:46:34 -06001447 HlslToken idToken;
1448 if (! acceptIdentifier(idToken)) {
John Kessenich078d7f22016-03-14 10:02:11 -06001449 expected("semantic");
1450 return false;
1451 }
1452 }
1453
1454 return true;
1455}
1456
John Kesseniche01a9bc2016-03-12 20:11:22 -07001457} // end namespace glslang