blob: c1600e4daee872a990465e62009acc78cfefdd6b [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 Kessenich87142c72016-03-12 20:24:24 -0700216 case EHTokInt:
217 case EHTokInt1:
218 case EHTokDword:
219 new(&type) TType(EbtInt);
220 break;
221 case EHTokFloat:
John Kessenich8d72f1a2016-05-20 12:06:03 -0600222 new(&type) TType(EbtFloat);
223 break;
224
John Kessenich87142c72016-03-12 20:24:24 -0700225 case EHTokFloat1:
226 new(&type) TType(EbtFloat);
John Kessenich8d72f1a2016-05-20 12:06:03 -0600227 type.makeVector();
John Kessenich87142c72016-03-12 20:24:24 -0700228 break;
229
230 case EHTokFloat2:
231 new(&type) TType(EbtFloat, EvqTemporary, 2);
232 break;
233 case EHTokFloat3:
234 new(&type) TType(EbtFloat, EvqTemporary, 3);
235 break;
236 case EHTokFloat4:
237 new(&type) TType(EbtFloat, EvqTemporary, 4);
238 break;
239
240 case EHTokInt2:
241 new(&type) TType(EbtInt, EvqTemporary, 2);
242 break;
243 case EHTokInt3:
244 new(&type) TType(EbtInt, EvqTemporary, 3);
245 break;
246 case EHTokInt4:
247 new(&type) TType(EbtInt, EvqTemporary, 4);
248 break;
249
250 case EHTokBool2:
251 new(&type) TType(EbtBool, EvqTemporary, 2);
252 break;
253 case EHTokBool3:
254 new(&type) TType(EbtBool, EvqTemporary, 3);
255 break;
256 case EHTokBool4:
257 new(&type) TType(EbtBool, EvqTemporary, 4);
258 break;
259
John Kessenich0133c122016-05-20 12:17:26 -0600260 case EHTokInt1x1:
261 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 1);
262 break;
263 case EHTokInt1x2:
264 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 1);
265 break;
266 case EHTokInt1x3:
267 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 1);
268 break;
269 case EHTokInt1x4:
270 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 1);
271 break;
272 case EHTokInt2x1:
273 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 2);
274 break;
275 case EHTokInt2x2:
276 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 2);
277 break;
278 case EHTokInt2x3:
279 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 2);
280 break;
281 case EHTokInt2x4:
282 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 2);
283 break;
284 case EHTokInt3x1:
285 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 3);
286 break;
287 case EHTokInt3x2:
288 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 3);
289 break;
290 case EHTokInt3x3:
291 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 3);
292 break;
293 case EHTokInt3x4:
294 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 3);
295 break;
296 case EHTokInt4x1:
297 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 4);
298 break;
299 case EHTokInt4x2:
300 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 4);
301 break;
302 case EHTokInt4x3:
303 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 4);
304 break;
305 case EHTokInt4x4:
306 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 4);
307 break;
308
309 case EHTokFloat1x1:
310 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 1);
311 break;
312 case EHTokFloat1x2:
313 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 1);
314 break;
315 case EHTokFloat1x3:
316 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 1);
317 break;
318 case EHTokFloat1x4:
319 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 1);
320 break;
321 case EHTokFloat2x1:
322 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 2);
323 break;
John Kessenich87142c72016-03-12 20:24:24 -0700324 case EHTokFloat2x2:
325 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 2);
326 break;
327 case EHTokFloat2x3:
328 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 2);
329 break;
330 case EHTokFloat2x4:
331 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 2);
332 break;
John Kessenich0133c122016-05-20 12:17:26 -0600333 case EHTokFloat3x1:
334 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 3);
335 break;
John Kessenich87142c72016-03-12 20:24:24 -0700336 case EHTokFloat3x2:
337 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 3);
338 break;
339 case EHTokFloat3x3:
340 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 3);
341 break;
342 case EHTokFloat3x4:
343 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 3);
344 break;
John Kessenich0133c122016-05-20 12:17:26 -0600345 case EHTokFloat4x1:
346 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 4);
347 break;
John Kessenich87142c72016-03-12 20:24:24 -0700348 case EHTokFloat4x2:
349 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 4);
350 break;
351 case EHTokFloat4x3:
352 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 4);
353 break;
354 case EHTokFloat4x4:
355 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 4);
356 break;
357
John Kessenich0133c122016-05-20 12:17:26 -0600358 case EHTokDouble1x1:
359 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 1);
360 break;
361 case EHTokDouble1x2:
362 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 1);
363 break;
364 case EHTokDouble1x3:
365 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 1);
366 break;
367 case EHTokDouble1x4:
368 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 1);
369 break;
370 case EHTokDouble2x1:
371 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 2);
372 break;
373 case EHTokDouble2x2:
374 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 2);
375 break;
376 case EHTokDouble2x3:
377 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 2);
378 break;
379 case EHTokDouble2x4:
380 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 2);
381 break;
382 case EHTokDouble3x1:
383 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 3);
384 break;
385 case EHTokDouble3x2:
386 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 3);
387 break;
388 case EHTokDouble3x3:
389 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 3);
390 break;
391 case EHTokDouble3x4:
392 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 3);
393 break;
394 case EHTokDouble4x1:
395 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 4);
396 break;
397 case EHTokDouble4x2:
398 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 4);
399 break;
400 case EHTokDouble4x3:
401 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 4);
402 break;
403 case EHTokDouble4x4:
404 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 4);
405 break;
406
John Kessenich87142c72016-03-12 20:24:24 -0700407 default:
408 return false;
409 }
410
411 advanceToken();
412
413 return true;
414}
415
John Kessenich5f934b02016-03-13 17:58:25 -0600416// function_parameters
John Kessenich078d7f22016-03-14 10:02:11 -0600417// : LEFT_PAREN parameter_declaration COMMA parameter_declaration ... RIGHT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -0600418//
419bool HlslGrammar::acceptFunctionParameters(TFunction& function)
420{
John Kessenich078d7f22016-03-14 10:02:11 -0600421 // LEFT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -0600422 if (! acceptTokenClass(EHTokLeftParen))
423 return false;
424
425 do {
426 // parameter_declaration
427 if (! acceptParameterDeclaration(function))
428 break;
429
John Kessenich078d7f22016-03-14 10:02:11 -0600430 // COMMA
John Kessenich5f934b02016-03-13 17:58:25 -0600431 if (! acceptTokenClass(EHTokComma))
432 break;
433 } while (true);
434
John Kessenich078d7f22016-03-14 10:02:11 -0600435 // RIGHT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -0600436 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -0600437 expected(")");
John Kessenich5f934b02016-03-13 17:58:25 -0600438 return false;
439 }
440
441 return true;
442}
443
444// parameter_declaration
445// : fully_specified_type
446// | fully_specified_type identifier
447//
448bool HlslGrammar::acceptParameterDeclaration(TFunction& function)
449{
450 // fully_specified_type
451 TType* type = new TType;
452 if (! acceptFullySpecifiedType(*type))
453 return false;
454
455 // identifier
John Kessenichaecd4972016-03-14 10:46:34 -0600456 HlslToken idToken;
457 acceptIdentifier(idToken);
John Kessenich5f934b02016-03-13 17:58:25 -0600458
John Kessenichaecd4972016-03-14 10:46:34 -0600459 TParameter param = { idToken.string, type };
John Kessenich5f934b02016-03-13 17:58:25 -0600460 function.addParameter(param);
461
462 return true;
463}
464
465// Do the work to create the function definition in addition to
466// parsing the body (compound_statement).
467bool HlslGrammar::acceptFunctionDefinition(TFunction& function, TIntermNode*& node)
468{
469 TFunction* functionDeclarator = parseContext.handleFunctionDeclarator(token.loc, function, false /* not prototype */);
470
471 // This does a symbol table push
472 node = parseContext.handleFunctionDefinition(token.loc, *functionDeclarator);
473
474 // compound_statement
John Kessenich21472ae2016-06-04 11:46:33 -0600475 TIntermNode* functionBody = nullptr;
John Kessenich5f934b02016-03-13 17:58:25 -0600476 if (acceptCompoundStatement(functionBody)) {
John Kessenich078d7f22016-03-14 10:02:11 -0600477 node = intermediate.growAggregate(node, functionBody);
478 intermediate.setAggregateOperator(node, EOpFunction, functionDeclarator->getType(), token.loc);
John Kessenich5f934b02016-03-13 17:58:25 -0600479 node->getAsAggregate()->setName(functionDeclarator->getMangledName().c_str());
480 parseContext.symbolTable.pop(nullptr);
481
482 return true;
483 }
484
485 return false;
486}
487
John Kessenich0d2b6de2016-06-05 11:23:11 -0600488// Accept an expression with parenthesis around it, where
489// the parenthesis ARE NOT expression parenthesis, but the
490// syntactically required ones like in "if ( expression )"
491//
492// Note this one is not set up to be speculative; as it gives
493// errors if not found.
494//
495bool HlslGrammar::acceptParenExpression(TIntermTyped*& expression)
496{
497 // LEFT_PAREN
498 if (! acceptTokenClass(EHTokLeftParen))
499 expected("(");
500
501 if (! acceptExpression(expression)) {
502 expected("expression");
503 return false;
504 }
505
506 // RIGHT_PAREN
507 if (! acceptTokenClass(EHTokRightParen))
508 expected(")");
509
510 return true;
511}
512
John Kessenich34fb0362016-05-03 23:17:20 -0600513// The top-level full expression recognizer.
514//
John Kessenich87142c72016-03-12 20:24:24 -0700515// expression
John Kessenich34fb0362016-05-03 23:17:20 -0600516// : assignment_expression COMMA assignment_expression COMMA assignment_expression ...
John Kessenich87142c72016-03-12 20:24:24 -0700517//
518bool HlslGrammar::acceptExpression(TIntermTyped*& node)
519{
LoopDawgef764a22016-06-03 09:17:51 -0600520 node = nullptr;
521
John Kessenich34fb0362016-05-03 23:17:20 -0600522 // assignment_expression
523 if (! acceptAssignmentExpression(node))
524 return false;
John Kessenich5f934b02016-03-13 17:58:25 -0600525
John Kessenich34fb0362016-05-03 23:17:20 -0600526 if (! peekTokenClass(EHTokComma))
527 return true;
528
529 do {
530 // ... COMMA
John Kessenich5f934b02016-03-13 17:58:25 -0600531 TSourceLoc loc = token.loc;
John Kessenich34fb0362016-05-03 23:17:20 -0600532 advanceToken();
John Kessenich5f934b02016-03-13 17:58:25 -0600533
John Kessenich34fb0362016-05-03 23:17:20 -0600534 // ... assignment_expression
535 TIntermTyped* rightNode = nullptr;
536 if (! acceptAssignmentExpression(rightNode)) {
537 expected("assignment expression");
538 return false;
John Kessenich5f934b02016-03-13 17:58:25 -0600539 }
540
John Kessenich34fb0362016-05-03 23:17:20 -0600541 node = intermediate.addComma(node, rightNode, loc);
542
543 if (! peekTokenClass(EHTokComma))
544 return true;
545 } while (true);
546}
547
548// Accept an assignment expression, where assignment operations
549// associate right-to-left. This is, it is implicit, for example
550//
551// a op (b op (c op d))
552//
553// assigment_expression
554// : binary_expression op binary_expression op binary_expression ...
555//
556bool HlslGrammar::acceptAssignmentExpression(TIntermTyped*& node)
557{
558 if (! acceptBinaryExpression(node, PlLogicalOr))
559 return false;
560
561 TOperator assignOp = HlslOpMap::assignment(peek());
562 if (assignOp == EOpNull)
563 return true;
564
565 // ... op
566 TSourceLoc loc = token.loc;
567 advanceToken();
568
569 // ... binary_expression
570 // But, done by recursing this function, which automatically
571 // gets the right-to-left associativity.
572 TIntermTyped* rightNode = nullptr;
573 if (! acceptAssignmentExpression(rightNode)) {
574 expected("assignment expression");
John Kessenich5f934b02016-03-13 17:58:25 -0600575 return false;
John Kessenich87142c72016-03-12 20:24:24 -0700576 }
577
John Kessenich34fb0362016-05-03 23:17:20 -0600578 node = intermediate.addAssign(assignOp, node, rightNode, loc);
579
580 if (! peekTokenClass(EHTokComma))
581 return true;
582
583 return true;
584}
585
586// Accept a binary expression, for binary operations that
587// associate left-to-right. This is, it is implicit, for example
588//
589// ((a op b) op c) op d
590//
591// binary_expression
592// : expression op expression op expression ...
593//
594// where 'expression' is the next higher level in precedence.
595//
596bool HlslGrammar::acceptBinaryExpression(TIntermTyped*& node, PrecedenceLevel precedenceLevel)
597{
598 if (precedenceLevel > PlMul)
599 return acceptUnaryExpression(node);
600
601 // assignment_expression
602 if (! acceptBinaryExpression(node, (PrecedenceLevel)(precedenceLevel + 1)))
603 return false;
604
605 TOperator op = HlslOpMap::binary(peek());
606 PrecedenceLevel tokenLevel = HlslOpMap::precedenceLevel(op);
607 if (tokenLevel < precedenceLevel)
608 return true;
609
610 do {
611 // ... op
612 TSourceLoc loc = token.loc;
613 advanceToken();
614
615 // ... expression
616 TIntermTyped* rightNode = nullptr;
617 if (! acceptBinaryExpression(rightNode, (PrecedenceLevel)(precedenceLevel + 1))) {
618 expected("expression");
619 return false;
620 }
621
622 node = intermediate.addBinaryMath(op, node, rightNode, loc);
623
624 if (! peekTokenClass(EHTokComma))
625 return true;
626 } while (true);
627}
628
629// unary_expression
John Kessenich1cc1a282016-06-03 16:55:49 -0600630// : (type) unary_expression
631// | + unary_expression
John Kessenich34fb0362016-05-03 23:17:20 -0600632// | - unary_expression
633// | ! unary_expression
634// | ~ unary_expression
635// | ++ unary_expression
636// | -- unary_expression
637// | postfix_expression
638//
639bool HlslGrammar::acceptUnaryExpression(TIntermTyped*& node)
640{
John Kessenich1cc1a282016-06-03 16:55:49 -0600641 // (type) unary_expression
642 // Have to look two steps ahead, because this could be, e.g., a
643 // postfix_expression instead, since that also starts with at "(".
644 if (acceptTokenClass(EHTokLeftParen)) {
645 TType castType;
646 if (acceptType(castType)) {
647 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -0600648 expected(")");
John Kessenich1cc1a282016-06-03 16:55:49 -0600649 return false;
650 }
651
652 // We've matched "(type)" now, get the expression to cast
653 TSourceLoc loc = token.loc;
654 if (! acceptUnaryExpression(node))
655 return false;
656
657 // Hook it up like a constructor
658 TFunction* constructorFunction = parseContext.handleConstructorCall(loc, castType);
659 if (constructorFunction == nullptr) {
660 expected("type that can be constructed");
661 return false;
662 }
663 TIntermTyped* arguments = nullptr;
664 parseContext.handleFunctionArgument(constructorFunction, arguments, node);
665 node = parseContext.handleFunctionCall(loc, constructorFunction, arguments);
666
667 return true;
668 } else {
669 // This isn't a type cast, but it still started "(", so if it is a
670 // unary expression, it can only be a postfix_expression, so try that.
671 // Back it up first.
672 recedeToken();
673 return acceptPostfixExpression(node);
674 }
675 }
676
677 // peek for "op unary_expression"
John Kessenich34fb0362016-05-03 23:17:20 -0600678 TOperator unaryOp = HlslOpMap::preUnary(peek());
679
John Kessenich1cc1a282016-06-03 16:55:49 -0600680 // postfix_expression (if no unary operator)
John Kessenich34fb0362016-05-03 23:17:20 -0600681 if (unaryOp == EOpNull)
682 return acceptPostfixExpression(node);
683
684 // op unary_expression
685 TSourceLoc loc = token.loc;
686 advanceToken();
687 if (! acceptUnaryExpression(node))
688 return false;
689
690 // + is a no-op
691 if (unaryOp == EOpAdd)
692 return true;
693
694 node = intermediate.addUnaryMath(unaryOp, node, loc);
695
696 return node != nullptr;
697}
698
699// postfix_expression
700// : LEFT_PAREN expression RIGHT_PAREN
701// | literal
702// | constructor
703// | identifier
704// | function_call
705// | postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET
706// | postfix_expression DOT IDENTIFIER
707// | postfix_expression INC_OP
708// | postfix_expression DEC_OP
709//
710bool HlslGrammar::acceptPostfixExpression(TIntermTyped*& node)
711{
712 // Not implemented as self-recursive:
713 // The logical "right recursion" is done with an loop at the end
714
715 // idToken will pick up either a variable or a function name in a function call
716 HlslToken idToken;
717
John Kessenich21472ae2016-06-04 11:46:33 -0600718 // Find something before the postfix operations, as they can't operate
719 // on nothing. So, no "return true", they fall through, only "return false".
John Kessenich87142c72016-03-12 20:24:24 -0700720 if (acceptTokenClass(EHTokLeftParen)) {
John Kessenich21472ae2016-06-04 11:46:33 -0600721 // LEFT_PAREN expression RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -0700722 if (! acceptExpression(node)) {
723 expected("expression");
724 return false;
725 }
726 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -0600727 expected(")");
John Kessenich87142c72016-03-12 20:24:24 -0700728 return false;
729 }
John Kessenich34fb0362016-05-03 23:17:20 -0600730 } else if (acceptLiteral(node)) {
731 // literal (nothing else to do yet), go on to the
732 } else if (acceptConstructor(node)) {
733 // constructor (nothing else to do yet)
734 } else if (acceptIdentifier(idToken)) {
735 // identifier or function_call name
736 if (! peekTokenClass(EHTokLeftParen)) {
737 node = parseContext.handleVariable(idToken.loc, idToken.symbol, token.string);
738 } else if (acceptFunctionCall(idToken, node)) {
739 // function_call (nothing else to do yet)
740 } else {
741 expected("function call arguments");
742 return false;
743 }
John Kessenich21472ae2016-06-04 11:46:33 -0600744 } else {
745 // nothing found, can't post operate
746 return false;
John Kessenich87142c72016-03-12 20:24:24 -0700747 }
748
John Kessenich21472ae2016-06-04 11:46:33 -0600749 // Something was found, chain as many postfix operations as exist.
John Kessenich34fb0362016-05-03 23:17:20 -0600750 do {
751 TSourceLoc loc = token.loc;
752 TOperator postOp = HlslOpMap::postUnary(peek());
John Kessenich87142c72016-03-12 20:24:24 -0700753
John Kessenich34fb0362016-05-03 23:17:20 -0600754 // Consume only a valid post-unary operator, otherwise we are done.
755 switch (postOp) {
756 case EOpIndexDirectStruct:
757 case EOpIndexIndirect:
758 case EOpPostIncrement:
759 case EOpPostDecrement:
760 advanceToken();
761 break;
762 default:
763 return true;
764 }
John Kessenich87142c72016-03-12 20:24:24 -0700765
John Kessenich34fb0362016-05-03 23:17:20 -0600766 // We have a valid post-unary operator, process it.
767 switch (postOp) {
768 case EOpIndexDirectStruct:
769 // todo
770 break;
771 case EOpIndexIndirect:
772 {
773 TIntermTyped* indexNode = nullptr;
774 if (! acceptExpression(indexNode) ||
775 ! peekTokenClass(EHTokRightBracket)) {
776 expected("expression followed by ']'");
777 return false;
778 }
779 // todo: node = intermediate.addBinaryMath(
780 }
781 case EOpPostIncrement:
782 case EOpPostDecrement:
783 node = intermediate.addUnaryMath(postOp, node, loc);
784 break;
785 default:
786 assert(0);
787 break;
788 }
789 } while (true);
John Kessenich87142c72016-03-12 20:24:24 -0700790}
791
John Kessenichd016be12016-03-13 11:24:20 -0600792// constructor
John Kessenich078d7f22016-03-14 10:02:11 -0600793// : type argument_list
John Kessenichd016be12016-03-13 11:24:20 -0600794//
795bool HlslGrammar::acceptConstructor(TIntermTyped*& node)
796{
797 // type
798 TType type;
799 if (acceptType(type)) {
800 TFunction* constructorFunction = parseContext.handleConstructorCall(token.loc, type);
801 if (constructorFunction == nullptr)
802 return false;
803
804 // arguments
John Kessenich4678ca92016-05-13 09:33:42 -0600805 TIntermTyped* arguments = nullptr;
John Kessenichd016be12016-03-13 11:24:20 -0600806 if (! acceptArguments(constructorFunction, arguments)) {
807 expected("constructor arguments");
808 return false;
809 }
810
811 // hook it up
812 node = parseContext.handleFunctionCall(arguments->getLoc(), constructorFunction, arguments);
813
814 return true;
815 }
816
817 return false;
818}
819
John Kessenich34fb0362016-05-03 23:17:20 -0600820// The function_call identifier was already recognized, and passed in as idToken.
821//
822// function_call
823// : [idToken] arguments
824//
John Kessenich4678ca92016-05-13 09:33:42 -0600825bool HlslGrammar::acceptFunctionCall(HlslToken idToken, TIntermTyped*& node)
John Kessenich34fb0362016-05-03 23:17:20 -0600826{
John Kessenich4678ca92016-05-13 09:33:42 -0600827 // arguments
828 TFunction* function = new TFunction(idToken.string, TType(EbtVoid));
829 TIntermTyped* arguments = nullptr;
830 if (! acceptArguments(function, arguments))
831 return false;
832
833 node = parseContext.handleFunctionCall(idToken.loc, function, arguments);
834
835 return true;
John Kessenich34fb0362016-05-03 23:17:20 -0600836}
837
John Kessenich87142c72016-03-12 20:24:24 -0700838// arguments
John Kessenich078d7f22016-03-14 10:02:11 -0600839// : LEFT_PAREN expression COMMA expression COMMA ... RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -0700840//
John Kessenichd016be12016-03-13 11:24:20 -0600841// The arguments are pushed onto the 'function' argument list and
842// onto the 'arguments' aggregate.
843//
John Kessenich4678ca92016-05-13 09:33:42 -0600844bool HlslGrammar::acceptArguments(TFunction* function, TIntermTyped*& arguments)
John Kessenich87142c72016-03-12 20:24:24 -0700845{
John Kessenich078d7f22016-03-14 10:02:11 -0600846 // LEFT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -0700847 if (! acceptTokenClass(EHTokLeftParen))
848 return false;
849
850 do {
John Kessenichd016be12016-03-13 11:24:20 -0600851 // expression
John Kessenich87142c72016-03-12 20:24:24 -0700852 TIntermTyped* arg;
John Kessenich4678ca92016-05-13 09:33:42 -0600853 if (! acceptAssignmentExpression(arg))
John Kessenich87142c72016-03-12 20:24:24 -0700854 break;
John Kessenichd016be12016-03-13 11:24:20 -0600855
856 // hook it up
857 parseContext.handleFunctionArgument(function, arguments, arg);
858
John Kessenich078d7f22016-03-14 10:02:11 -0600859 // COMMA
John Kessenich87142c72016-03-12 20:24:24 -0700860 if (! acceptTokenClass(EHTokComma))
861 break;
862 } while (true);
863
John Kessenich078d7f22016-03-14 10:02:11 -0600864 // RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -0700865 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -0600866 expected(")");
John Kessenich87142c72016-03-12 20:24:24 -0700867 return false;
868 }
869
870 return true;
871}
872
873bool HlslGrammar::acceptLiteral(TIntermTyped*& node)
874{
875 switch (token.tokenClass) {
876 case EHTokIntConstant:
John Kessenich078d7f22016-03-14 10:02:11 -0600877 node = intermediate.addConstantUnion(token.i, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -0700878 break;
879 case EHTokFloatConstant:
John Kessenich078d7f22016-03-14 10:02:11 -0600880 node = intermediate.addConstantUnion(token.d, EbtFloat, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -0700881 break;
882 case EHTokDoubleConstant:
John Kessenich078d7f22016-03-14 10:02:11 -0600883 node = intermediate.addConstantUnion(token.d, EbtDouble, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -0700884 break;
885 case EHTokBoolConstant:
John Kessenich078d7f22016-03-14 10:02:11 -0600886 node = intermediate.addConstantUnion(token.b, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -0700887 break;
888
889 default:
890 return false;
891 }
892
893 advanceToken();
894
895 return true;
896}
897
John Kessenich5f934b02016-03-13 17:58:25 -0600898// compound_statement
John Kessenich34fb0362016-05-03 23:17:20 -0600899// : LEFT_CURLY statement statement ... RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -0600900//
John Kessenich21472ae2016-06-04 11:46:33 -0600901bool HlslGrammar::acceptCompoundStatement(TIntermNode*& retStatement)
John Kessenich87142c72016-03-12 20:24:24 -0700902{
John Kessenich21472ae2016-06-04 11:46:33 -0600903 TIntermAggregate* compoundStatement = nullptr;
904
John Kessenich34fb0362016-05-03 23:17:20 -0600905 // LEFT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -0600906 if (! acceptTokenClass(EHTokLeftBrace))
907 return false;
908
909 // statement statement ...
910 TIntermNode* statement = nullptr;
911 while (acceptStatement(statement)) {
912 // hook it up
John Kessenich078d7f22016-03-14 10:02:11 -0600913 compoundStatement = intermediate.growAggregate(compoundStatement, statement);
John Kessenich5f934b02016-03-13 17:58:25 -0600914 }
John Kessenich34fb0362016-05-03 23:17:20 -0600915 if (compoundStatement)
916 compoundStatement->setOperator(EOpSequence);
John Kessenich5f934b02016-03-13 17:58:25 -0600917
John Kessenich21472ae2016-06-04 11:46:33 -0600918 retStatement = compoundStatement;
919
John Kessenich34fb0362016-05-03 23:17:20 -0600920 // RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -0600921 return acceptTokenClass(EHTokRightBrace);
922}
923
John Kessenich0d2b6de2016-06-05 11:23:11 -0600924bool HlslGrammar::acceptScopedStatement(TIntermNode*& statement)
925{
926 parseContext.pushScope();
927 bool result = acceptNestedStatement(statement);
928 parseContext.popScope();
929
930 return result;
931}
932
933bool HlslGrammar::acceptNestedStatement(TIntermNode*& statement)
934{
935 parseContext.nestStatement();
936 bool result = acceptStatement(statement);
937 parseContext.unnestStatement();
938
939 return result;
940}
941
John Kessenich5f934b02016-03-13 17:58:25 -0600942// statement
John Kessenich21472ae2016-06-04 11:46:33 -0600943// : attributes attributed_statement
944//
945// attributed_statement
John Kessenich5f934b02016-03-13 17:58:25 -0600946// : compound_statement
John Kessenich21472ae2016-06-04 11:46:33 -0600947// | SEMICOLON
John Kessenich078d7f22016-03-14 10:02:11 -0600948// | expression SEMICOLON
John Kessenich21472ae2016-06-04 11:46:33 -0600949// | declaration_statement
950// | selection_statement
951// | switch_statement
952// | case_label
953// | iteration_statement
954// | jump_statement
John Kessenich5f934b02016-03-13 17:58:25 -0600955//
956bool HlslGrammar::acceptStatement(TIntermNode*& statement)
957{
John Kessenich21472ae2016-06-04 11:46:33 -0600958 statement = nullptr;
John Kessenich5f934b02016-03-13 17:58:25 -0600959
John Kessenich21472ae2016-06-04 11:46:33 -0600960 // attributes
961 acceptAttributes();
John Kessenich5f934b02016-03-13 17:58:25 -0600962
John Kessenich21472ae2016-06-04 11:46:33 -0600963 // attributed_statement
964 switch (peek()) {
965 case EHTokLeftBrace:
966 return acceptCompoundStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -0600967
John Kessenich21472ae2016-06-04 11:46:33 -0600968 case EHTokIf:
969 return acceptSelectionStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -0600970
John Kessenich21472ae2016-06-04 11:46:33 -0600971 case EHTokSwitch:
972 return acceptSwitchStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -0600973
John Kessenich21472ae2016-06-04 11:46:33 -0600974 case EHTokFor:
975 case EHTokDo:
976 case EHTokWhile:
977 return acceptIterationStatement(statement);
978
979 case EHTokContinue:
980 case EHTokBreak:
981 case EHTokDiscard:
982 case EHTokReturn:
983 return acceptJumpStatement(statement);
984
985 case EHTokCase:
986 return acceptCaseLabel(statement);
987
988 case EHTokSemicolon:
989 return acceptTokenClass(EHTokSemicolon);
990
991 case EHTokRightBrace:
992 // Performance: not strictly necessary, but stops a bunch of hunting early,
993 // and is how sequences of statements end.
John Kessenich5f934b02016-03-13 17:58:25 -0600994 return false;
995
John Kessenich21472ae2016-06-04 11:46:33 -0600996 default:
997 {
998 // declaration
999 if (acceptDeclaration(statement))
1000 return true;
1001
1002 // expression
1003 TIntermTyped* node;
1004 if (acceptExpression(node))
1005 statement = node;
1006 else
1007 return false;
1008
1009 // SEMICOLON (following an expression)
1010 if (! acceptTokenClass(EHTokSemicolon)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06001011 expected(";");
John Kessenich21472ae2016-06-04 11:46:33 -06001012 return false;
1013 }
1014 }
1015 }
1016
John Kessenich5f934b02016-03-13 17:58:25 -06001017 return true;
John Kessenich87142c72016-03-12 20:24:24 -07001018}
1019
John Kessenich21472ae2016-06-04 11:46:33 -06001020// attributes
1021// : list of zero or more of: LEFT_BRACKET attribute RIGHT_BRACKET
1022//
1023// attribute:
1024// : UNROLL
1025// | UNROLL LEFT_PAREN literal RIGHT_PAREN
1026// | FASTOPT
1027// | ALLOW_UAV_CONDITION
1028// | BRANCH
1029// | FLATTEN
1030// | FORCECASE
1031// | CALL
1032//
1033void HlslGrammar::acceptAttributes()
1034{
John Kessenich0d2b6de2016-06-05 11:23:11 -06001035 // For now, accept the [ XXX(X) ] syntax, but drop.
1036 // TODO: subset to correct set? Pass on?
1037 do {
1038 // LEFT_BRACKET?
1039 if (! acceptTokenClass(EHTokLeftBracket))
1040 return;
1041
1042 // attribute
1043 if (peekTokenClass(EHTokIdentifier)) {
1044 // 'token.string' is the attribute
1045 advanceToken();
1046 } else if (! peekTokenClass(EHTokRightBracket)) {
1047 expected("identifier");
1048 advanceToken();
1049 }
1050
1051 // (x)
1052 if (acceptTokenClass(EHTokLeftParen)) {
1053 TIntermTyped* node;
1054 if (! acceptLiteral(node))
1055 expected("literal");
1056 // 'node' has the literal in it
1057 if (! acceptTokenClass(EHTokRightParen))
1058 expected(")");
1059 }
1060
1061 // RIGHT_BRACKET
1062 if (acceptTokenClass(EHTokRightBracket))
1063 continue;
1064
1065 expected("]");
1066 return;
1067
1068 } while (true);
John Kessenich21472ae2016-06-04 11:46:33 -06001069}
1070
John Kessenich0d2b6de2016-06-05 11:23:11 -06001071// selection_statement
1072// : IF LEFT_PAREN expression RIGHT_PAREN statement
1073// : IF LEFT_PAREN expression RIGHT_PAREN statement ELSE statement
1074//
John Kessenich21472ae2016-06-04 11:46:33 -06001075bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement)
1076{
John Kessenich0d2b6de2016-06-05 11:23:11 -06001077 TSourceLoc loc = token.loc;
1078
1079 // IF
1080 if (! acceptTokenClass(EHTokIf))
1081 return false;
1082
1083 // so that something declared in the condition is scoped to the lifetimes
1084 // of the then-else statements
1085 parseContext.pushScope();
1086
1087 // LEFT_PAREN expression RIGHT_PAREN
1088 TIntermTyped* condition;
1089 if (! acceptParenExpression(condition))
1090 return false;
1091
1092 // create the child statements
1093 TIntermNodePair thenElse = { nullptr, nullptr };
1094
1095 // then statement
1096 if (! acceptScopedStatement(thenElse.node1)) {
1097 expected("then statement");
1098 return false;
1099 }
1100
1101 // ELSE
1102 if (acceptTokenClass(EHTokElse)) {
1103 // else statement
1104 if (! acceptScopedStatement(thenElse.node2)) {
1105 expected("else statement");
1106 return false;
1107 }
1108 }
1109
1110 // Put the pieces together
1111 statement = intermediate.addSelection(condition, thenElse, loc);
1112 parseContext.popScope();
1113
1114 return true;
John Kessenich21472ae2016-06-04 11:46:33 -06001115}
1116
1117bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement)
1118{
1119 return false;
1120}
1121
John Kessenich119f8f62016-06-05 15:44:07 -06001122// iteration_statement
1123// : WHILE LEFT_PAREN condition RIGHT_PAREN statement
1124// | DO LEFT_BRACE statement RIGHT_BRACE WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON
1125// | FOR LEFT_PAREN for_init_statement for_rest_statement RIGHT_PAREN statement
1126//
1127// Non-speculative, only call if it needs to be found; WHILE or DO or FOR already seen.
John Kessenich21472ae2016-06-04 11:46:33 -06001128bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement)
1129{
John Kessenich119f8f62016-06-05 15:44:07 -06001130 TSourceLoc loc = token.loc;
1131 TIntermTyped* condition = nullptr;
1132
1133 EHlslTokenClass loop = peek();
1134 assert(loop == EHTokDo || loop == EHTokFor || loop == EHTokWhile);
1135
1136 // WHILE or DO or FOR
1137 advanceToken();
1138
1139 switch (loop) {
1140 case EHTokWhile:
1141 // so that something declared in the condition is scoped to the lifetime
1142 // of the while sub-statement
1143 parseContext.pushScope();
1144 parseContext.nestLooping();
1145
1146 // LEFT_PAREN condition RIGHT_PAREN
1147 if (! acceptParenExpression(condition))
1148 return false;
1149
1150 // statement
1151 if (! acceptScopedStatement(statement)) {
1152 expected("while sub-statement");
1153 return false;
1154 }
1155
1156 parseContext.unnestLooping();
1157 parseContext.popScope();
1158
1159 statement = intermediate.addLoop(statement, condition, nullptr, true, loc);
1160
1161 return true;
1162
1163 case EHTokDo:
1164 parseContext.nestLooping();
1165
1166 if (! acceptTokenClass(EHTokLeftBrace))
1167 expected("{");
1168
1169 // statement
1170 if (! peekTokenClass(EHTokRightBrace) && ! acceptScopedStatement(statement)) {
1171 expected("do sub-statement");
1172 return false;
1173 }
1174
1175 if (! acceptTokenClass(EHTokRightBrace))
1176 expected("}");
1177
1178 // WHILE
1179 if (! acceptTokenClass(EHTokWhile)) {
1180 expected("while");
1181 return false;
1182 }
1183
1184 // LEFT_PAREN condition RIGHT_PAREN
1185 TIntermTyped* condition;
1186 if (! acceptParenExpression(condition))
1187 return false;
1188
1189 if (! acceptTokenClass(EHTokSemicolon))
1190 expected(";");
1191
1192 parseContext.unnestLooping();
1193
1194 statement = intermediate.addLoop(statement, condition, 0, false, loc);
1195
1196 return true;
1197
1198 case EHTokFor:
1199 {
1200 // LEFT_PAREN
1201 if (! acceptTokenClass(EHTokLeftParen))
1202 expected("(");
1203
1204 // so that something declared in the condition is scoped to the lifetime
1205 // of the for sub-statement
1206 parseContext.pushScope();
1207
1208 // initializer SEMI_COLON
1209 TIntermTyped* initializer = nullptr; // TODO, "for (initializer" needs to support decl. statement
1210 acceptExpression(initializer);
1211 if (! acceptTokenClass(EHTokSemicolon))
1212 expected(";");
1213
1214 parseContext.nestLooping();
1215
1216 // condition SEMI_COLON
1217 acceptExpression(condition);
1218 if (! acceptTokenClass(EHTokSemicolon))
1219 expected(";");
1220
1221 // iterator SEMI_COLON
1222 TIntermTyped* iterator = nullptr;
1223 acceptExpression(iterator);
1224 if (! acceptTokenClass(EHTokRightParen))
1225 expected(")");
1226
1227 // statement
1228 if (! acceptScopedStatement(statement)) {
1229 expected("for sub-statement");
1230 return false;
1231 }
1232
1233 statement = intermediate.addForLoop(statement, initializer, condition, iterator, true, loc);
1234
1235 parseContext.popScope();
1236 parseContext.unnestLooping();
1237
1238 return true;
1239 }
1240
1241 default:
1242 return false;
1243 }
John Kessenich21472ae2016-06-04 11:46:33 -06001244}
1245
1246// jump_statement
1247// : CONTINUE SEMICOLON
1248// | BREAK SEMICOLON
1249// | DISCARD SEMICOLON
1250// | RETURN SEMICOLON
1251// | RETURN expression SEMICOLON
1252//
1253bool HlslGrammar::acceptJumpStatement(TIntermNode*& statement)
1254{
1255 switch (peek()) {
1256 case EHTokContinue:
1257 case EHTokBreak:
1258 case EHTokDiscard:
1259 // TODO
1260 return false;
1261
1262 case EHTokReturn:
1263 // return
1264 if (acceptTokenClass(EHTokReturn)) {
1265 // expression
1266 TIntermTyped* node;
1267 if (acceptExpression(node)) {
1268 // hook it up
1269 statement = intermediate.addBranch(EOpReturn, node, token.loc);
1270 } else
1271 statement = intermediate.addBranch(EOpReturn, token.loc);
1272
1273 // SEMICOLON
1274 if (! acceptTokenClass(EHTokSemicolon)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06001275 expected(";");
John Kessenich21472ae2016-06-04 11:46:33 -06001276 return false;
1277 }
1278
1279 return true;
1280 }
1281
1282 default:
1283 return false;
1284 }
1285}
1286
1287
1288bool HlslGrammar::acceptCaseLabel(TIntermNode*& statement)
1289{
1290 return false;
1291}
1292
John Kessenich078d7f22016-03-14 10:02:11 -06001293// COLON semantic
1294bool HlslGrammar::acceptSemantic()
1295{
1296 // COLON
1297 if (acceptTokenClass(EHTokColon)) {
1298 // semantic
John Kessenichaecd4972016-03-14 10:46:34 -06001299 HlslToken idToken;
1300 if (! acceptIdentifier(idToken)) {
John Kessenich078d7f22016-03-14 10:02:11 -06001301 expected("semantic");
1302 return false;
1303 }
1304 }
1305
1306 return true;
1307}
1308
John Kesseniche01a9bc2016-03-12 20:11:22 -07001309} // end namespace glslang