blob: 31e67d3607713aa2ab785ba93891697a31ba004f [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)) {
437 expected("right parenthesis");
438 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 Kessenich34fb0362016-05-03 23:17:20 -0600488// The top-level full expression recognizer.
489//
John Kessenich87142c72016-03-12 20:24:24 -0700490// expression
John Kessenich34fb0362016-05-03 23:17:20 -0600491// : assignment_expression COMMA assignment_expression COMMA assignment_expression ...
John Kessenich87142c72016-03-12 20:24:24 -0700492//
493bool HlslGrammar::acceptExpression(TIntermTyped*& node)
494{
LoopDawgef764a22016-06-03 09:17:51 -0600495 node = nullptr;
496
John Kessenich34fb0362016-05-03 23:17:20 -0600497 // assignment_expression
498 if (! acceptAssignmentExpression(node))
499 return false;
John Kessenich5f934b02016-03-13 17:58:25 -0600500
John Kessenich34fb0362016-05-03 23:17:20 -0600501 if (! peekTokenClass(EHTokComma))
502 return true;
503
504 do {
505 // ... COMMA
John Kessenich5f934b02016-03-13 17:58:25 -0600506 TSourceLoc loc = token.loc;
John Kessenich34fb0362016-05-03 23:17:20 -0600507 advanceToken();
John Kessenich5f934b02016-03-13 17:58:25 -0600508
John Kessenich34fb0362016-05-03 23:17:20 -0600509 // ... assignment_expression
510 TIntermTyped* rightNode = nullptr;
511 if (! acceptAssignmentExpression(rightNode)) {
512 expected("assignment expression");
513 return false;
John Kessenich5f934b02016-03-13 17:58:25 -0600514 }
515
John Kessenich34fb0362016-05-03 23:17:20 -0600516 node = intermediate.addComma(node, rightNode, loc);
517
518 if (! peekTokenClass(EHTokComma))
519 return true;
520 } while (true);
521}
522
523// Accept an assignment expression, where assignment operations
524// associate right-to-left. This is, it is implicit, for example
525//
526// a op (b op (c op d))
527//
528// assigment_expression
529// : binary_expression op binary_expression op binary_expression ...
530//
531bool HlslGrammar::acceptAssignmentExpression(TIntermTyped*& node)
532{
533 if (! acceptBinaryExpression(node, PlLogicalOr))
534 return false;
535
536 TOperator assignOp = HlslOpMap::assignment(peek());
537 if (assignOp == EOpNull)
538 return true;
539
540 // ... op
541 TSourceLoc loc = token.loc;
542 advanceToken();
543
544 // ... binary_expression
545 // But, done by recursing this function, which automatically
546 // gets the right-to-left associativity.
547 TIntermTyped* rightNode = nullptr;
548 if (! acceptAssignmentExpression(rightNode)) {
549 expected("assignment expression");
John Kessenich5f934b02016-03-13 17:58:25 -0600550 return false;
John Kessenich87142c72016-03-12 20:24:24 -0700551 }
552
John Kessenich34fb0362016-05-03 23:17:20 -0600553 node = intermediate.addAssign(assignOp, node, rightNode, loc);
554
555 if (! peekTokenClass(EHTokComma))
556 return true;
557
558 return true;
559}
560
561// Accept a binary expression, for binary operations that
562// associate left-to-right. This is, it is implicit, for example
563//
564// ((a op b) op c) op d
565//
566// binary_expression
567// : expression op expression op expression ...
568//
569// where 'expression' is the next higher level in precedence.
570//
571bool HlslGrammar::acceptBinaryExpression(TIntermTyped*& node, PrecedenceLevel precedenceLevel)
572{
573 if (precedenceLevel > PlMul)
574 return acceptUnaryExpression(node);
575
576 // assignment_expression
577 if (! acceptBinaryExpression(node, (PrecedenceLevel)(precedenceLevel + 1)))
578 return false;
579
580 TOperator op = HlslOpMap::binary(peek());
581 PrecedenceLevel tokenLevel = HlslOpMap::precedenceLevel(op);
582 if (tokenLevel < precedenceLevel)
583 return true;
584
585 do {
586 // ... op
587 TSourceLoc loc = token.loc;
588 advanceToken();
589
590 // ... expression
591 TIntermTyped* rightNode = nullptr;
592 if (! acceptBinaryExpression(rightNode, (PrecedenceLevel)(precedenceLevel + 1))) {
593 expected("expression");
594 return false;
595 }
596
597 node = intermediate.addBinaryMath(op, node, rightNode, loc);
598
599 if (! peekTokenClass(EHTokComma))
600 return true;
601 } while (true);
602}
603
604// unary_expression
John Kessenich1cc1a282016-06-03 16:55:49 -0600605// : (type) unary_expression
606// | + unary_expression
John Kessenich34fb0362016-05-03 23:17:20 -0600607// | - unary_expression
608// | ! unary_expression
609// | ~ unary_expression
610// | ++ unary_expression
611// | -- unary_expression
612// | postfix_expression
613//
614bool HlslGrammar::acceptUnaryExpression(TIntermTyped*& node)
615{
John Kessenich1cc1a282016-06-03 16:55:49 -0600616 // (type) unary_expression
617 // Have to look two steps ahead, because this could be, e.g., a
618 // postfix_expression instead, since that also starts with at "(".
619 if (acceptTokenClass(EHTokLeftParen)) {
620 TType castType;
621 if (acceptType(castType)) {
622 if (! acceptTokenClass(EHTokRightParen)) {
623 expected("right parenthesis");
624 return false;
625 }
626
627 // We've matched "(type)" now, get the expression to cast
628 TSourceLoc loc = token.loc;
629 if (! acceptUnaryExpression(node))
630 return false;
631
632 // Hook it up like a constructor
633 TFunction* constructorFunction = parseContext.handleConstructorCall(loc, castType);
634 if (constructorFunction == nullptr) {
635 expected("type that can be constructed");
636 return false;
637 }
638 TIntermTyped* arguments = nullptr;
639 parseContext.handleFunctionArgument(constructorFunction, arguments, node);
640 node = parseContext.handleFunctionCall(loc, constructorFunction, arguments);
641
642 return true;
643 } else {
644 // This isn't a type cast, but it still started "(", so if it is a
645 // unary expression, it can only be a postfix_expression, so try that.
646 // Back it up first.
647 recedeToken();
648 return acceptPostfixExpression(node);
649 }
650 }
651
652 // peek for "op unary_expression"
John Kessenich34fb0362016-05-03 23:17:20 -0600653 TOperator unaryOp = HlslOpMap::preUnary(peek());
654
John Kessenich1cc1a282016-06-03 16:55:49 -0600655 // postfix_expression (if no unary operator)
John Kessenich34fb0362016-05-03 23:17:20 -0600656 if (unaryOp == EOpNull)
657 return acceptPostfixExpression(node);
658
659 // op unary_expression
660 TSourceLoc loc = token.loc;
661 advanceToken();
662 if (! acceptUnaryExpression(node))
663 return false;
664
665 // + is a no-op
666 if (unaryOp == EOpAdd)
667 return true;
668
669 node = intermediate.addUnaryMath(unaryOp, node, loc);
670
671 return node != nullptr;
672}
673
674// postfix_expression
675// : LEFT_PAREN expression RIGHT_PAREN
676// | literal
677// | constructor
678// | identifier
679// | function_call
680// | postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET
681// | postfix_expression DOT IDENTIFIER
682// | postfix_expression INC_OP
683// | postfix_expression DEC_OP
684//
685bool HlslGrammar::acceptPostfixExpression(TIntermTyped*& node)
686{
687 // Not implemented as self-recursive:
688 // The logical "right recursion" is done with an loop at the end
689
690 // idToken will pick up either a variable or a function name in a function call
691 HlslToken idToken;
692
John Kessenich21472ae2016-06-04 11:46:33 -0600693 // Find something before the postfix operations, as they can't operate
694 // on nothing. So, no "return true", they fall through, only "return false".
John Kessenich87142c72016-03-12 20:24:24 -0700695 if (acceptTokenClass(EHTokLeftParen)) {
John Kessenich21472ae2016-06-04 11:46:33 -0600696 // LEFT_PAREN expression RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -0700697 if (! acceptExpression(node)) {
698 expected("expression");
699 return false;
700 }
701 if (! acceptTokenClass(EHTokRightParen)) {
702 expected("right parenthesis");
703 return false;
704 }
John Kessenich34fb0362016-05-03 23:17:20 -0600705 } else if (acceptLiteral(node)) {
706 // literal (nothing else to do yet), go on to the
707 } else if (acceptConstructor(node)) {
708 // constructor (nothing else to do yet)
709 } else if (acceptIdentifier(idToken)) {
710 // identifier or function_call name
711 if (! peekTokenClass(EHTokLeftParen)) {
712 node = parseContext.handleVariable(idToken.loc, idToken.symbol, token.string);
713 } else if (acceptFunctionCall(idToken, node)) {
714 // function_call (nothing else to do yet)
715 } else {
716 expected("function call arguments");
717 return false;
718 }
John Kessenich21472ae2016-06-04 11:46:33 -0600719 } else {
720 // nothing found, can't post operate
721 return false;
John Kessenich87142c72016-03-12 20:24:24 -0700722 }
723
John Kessenich21472ae2016-06-04 11:46:33 -0600724 // Something was found, chain as many postfix operations as exist.
John Kessenich34fb0362016-05-03 23:17:20 -0600725 do {
726 TSourceLoc loc = token.loc;
727 TOperator postOp = HlslOpMap::postUnary(peek());
John Kessenich87142c72016-03-12 20:24:24 -0700728
John Kessenich34fb0362016-05-03 23:17:20 -0600729 // Consume only a valid post-unary operator, otherwise we are done.
730 switch (postOp) {
731 case EOpIndexDirectStruct:
732 case EOpIndexIndirect:
733 case EOpPostIncrement:
734 case EOpPostDecrement:
735 advanceToken();
736 break;
737 default:
738 return true;
739 }
John Kessenich87142c72016-03-12 20:24:24 -0700740
John Kessenich34fb0362016-05-03 23:17:20 -0600741 // We have a valid post-unary operator, process it.
742 switch (postOp) {
743 case EOpIndexDirectStruct:
744 // todo
745 break;
746 case EOpIndexIndirect:
747 {
748 TIntermTyped* indexNode = nullptr;
749 if (! acceptExpression(indexNode) ||
750 ! peekTokenClass(EHTokRightBracket)) {
751 expected("expression followed by ']'");
752 return false;
753 }
754 // todo: node = intermediate.addBinaryMath(
755 }
756 case EOpPostIncrement:
757 case EOpPostDecrement:
758 node = intermediate.addUnaryMath(postOp, node, loc);
759 break;
760 default:
761 assert(0);
762 break;
763 }
764 } while (true);
John Kessenich87142c72016-03-12 20:24:24 -0700765}
766
John Kessenichd016be12016-03-13 11:24:20 -0600767// constructor
John Kessenich078d7f22016-03-14 10:02:11 -0600768// : type argument_list
John Kessenichd016be12016-03-13 11:24:20 -0600769//
770bool HlslGrammar::acceptConstructor(TIntermTyped*& node)
771{
772 // type
773 TType type;
774 if (acceptType(type)) {
775 TFunction* constructorFunction = parseContext.handleConstructorCall(token.loc, type);
776 if (constructorFunction == nullptr)
777 return false;
778
779 // arguments
John Kessenich4678ca92016-05-13 09:33:42 -0600780 TIntermTyped* arguments = nullptr;
John Kessenichd016be12016-03-13 11:24:20 -0600781 if (! acceptArguments(constructorFunction, arguments)) {
782 expected("constructor arguments");
783 return false;
784 }
785
786 // hook it up
787 node = parseContext.handleFunctionCall(arguments->getLoc(), constructorFunction, arguments);
788
789 return true;
790 }
791
792 return false;
793}
794
John Kessenich34fb0362016-05-03 23:17:20 -0600795// The function_call identifier was already recognized, and passed in as idToken.
796//
797// function_call
798// : [idToken] arguments
799//
John Kessenich4678ca92016-05-13 09:33:42 -0600800bool HlslGrammar::acceptFunctionCall(HlslToken idToken, TIntermTyped*& node)
John Kessenich34fb0362016-05-03 23:17:20 -0600801{
John Kessenich4678ca92016-05-13 09:33:42 -0600802 // arguments
803 TFunction* function = new TFunction(idToken.string, TType(EbtVoid));
804 TIntermTyped* arguments = nullptr;
805 if (! acceptArguments(function, arguments))
806 return false;
807
808 node = parseContext.handleFunctionCall(idToken.loc, function, arguments);
809
810 return true;
John Kessenich34fb0362016-05-03 23:17:20 -0600811}
812
John Kessenich87142c72016-03-12 20:24:24 -0700813// arguments
John Kessenich078d7f22016-03-14 10:02:11 -0600814// : LEFT_PAREN expression COMMA expression COMMA ... RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -0700815//
John Kessenichd016be12016-03-13 11:24:20 -0600816// The arguments are pushed onto the 'function' argument list and
817// onto the 'arguments' aggregate.
818//
John Kessenich4678ca92016-05-13 09:33:42 -0600819bool HlslGrammar::acceptArguments(TFunction* function, TIntermTyped*& arguments)
John Kessenich87142c72016-03-12 20:24:24 -0700820{
John Kessenich078d7f22016-03-14 10:02:11 -0600821 // LEFT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -0700822 if (! acceptTokenClass(EHTokLeftParen))
823 return false;
824
825 do {
John Kessenichd016be12016-03-13 11:24:20 -0600826 // expression
John Kessenich87142c72016-03-12 20:24:24 -0700827 TIntermTyped* arg;
John Kessenich4678ca92016-05-13 09:33:42 -0600828 if (! acceptAssignmentExpression(arg))
John Kessenich87142c72016-03-12 20:24:24 -0700829 break;
John Kessenichd016be12016-03-13 11:24:20 -0600830
831 // hook it up
832 parseContext.handleFunctionArgument(function, arguments, arg);
833
John Kessenich078d7f22016-03-14 10:02:11 -0600834 // COMMA
John Kessenich87142c72016-03-12 20:24:24 -0700835 if (! acceptTokenClass(EHTokComma))
836 break;
837 } while (true);
838
John Kessenich078d7f22016-03-14 10:02:11 -0600839 // RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -0700840 if (! acceptTokenClass(EHTokRightParen)) {
841 expected("right parenthesis");
842 return false;
843 }
844
845 return true;
846}
847
848bool HlslGrammar::acceptLiteral(TIntermTyped*& node)
849{
850 switch (token.tokenClass) {
851 case EHTokIntConstant:
John Kessenich078d7f22016-03-14 10:02:11 -0600852 node = intermediate.addConstantUnion(token.i, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -0700853 break;
854 case EHTokFloatConstant:
John Kessenich078d7f22016-03-14 10:02:11 -0600855 node = intermediate.addConstantUnion(token.d, EbtFloat, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -0700856 break;
857 case EHTokDoubleConstant:
John Kessenich078d7f22016-03-14 10:02:11 -0600858 node = intermediate.addConstantUnion(token.d, EbtDouble, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -0700859 break;
860 case EHTokBoolConstant:
John Kessenich078d7f22016-03-14 10:02:11 -0600861 node = intermediate.addConstantUnion(token.b, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -0700862 break;
863
864 default:
865 return false;
866 }
867
868 advanceToken();
869
870 return true;
871}
872
John Kessenich5f934b02016-03-13 17:58:25 -0600873// compound_statement
John Kessenich34fb0362016-05-03 23:17:20 -0600874// : LEFT_CURLY statement statement ... RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -0600875//
John Kessenich21472ae2016-06-04 11:46:33 -0600876bool HlslGrammar::acceptCompoundStatement(TIntermNode*& retStatement)
John Kessenich87142c72016-03-12 20:24:24 -0700877{
John Kessenich21472ae2016-06-04 11:46:33 -0600878 TIntermAggregate* compoundStatement = nullptr;
879
John Kessenich34fb0362016-05-03 23:17:20 -0600880 // LEFT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -0600881 if (! acceptTokenClass(EHTokLeftBrace))
882 return false;
883
884 // statement statement ...
885 TIntermNode* statement = nullptr;
886 while (acceptStatement(statement)) {
887 // hook it up
John Kessenich078d7f22016-03-14 10:02:11 -0600888 compoundStatement = intermediate.growAggregate(compoundStatement, statement);
John Kessenich5f934b02016-03-13 17:58:25 -0600889 }
John Kessenich34fb0362016-05-03 23:17:20 -0600890 if (compoundStatement)
891 compoundStatement->setOperator(EOpSequence);
John Kessenich5f934b02016-03-13 17:58:25 -0600892
John Kessenich21472ae2016-06-04 11:46:33 -0600893 retStatement = compoundStatement;
894
John Kessenich34fb0362016-05-03 23:17:20 -0600895 // RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -0600896 return acceptTokenClass(EHTokRightBrace);
897}
898
899// statement
John Kessenich21472ae2016-06-04 11:46:33 -0600900// : attributes attributed_statement
901//
902// attributed_statement
John Kessenich5f934b02016-03-13 17:58:25 -0600903// : compound_statement
John Kessenich21472ae2016-06-04 11:46:33 -0600904// | SEMICOLON
John Kessenich078d7f22016-03-14 10:02:11 -0600905// | expression SEMICOLON
John Kessenich21472ae2016-06-04 11:46:33 -0600906// | declaration_statement
907// | selection_statement
908// | switch_statement
909// | case_label
910// | iteration_statement
911// | jump_statement
John Kessenich5f934b02016-03-13 17:58:25 -0600912//
913bool HlslGrammar::acceptStatement(TIntermNode*& statement)
914{
John Kessenich21472ae2016-06-04 11:46:33 -0600915 statement = nullptr;
John Kessenich5f934b02016-03-13 17:58:25 -0600916
John Kessenich21472ae2016-06-04 11:46:33 -0600917 // attributes
918 acceptAttributes();
John Kessenich5f934b02016-03-13 17:58:25 -0600919
John Kessenich21472ae2016-06-04 11:46:33 -0600920 // attributed_statement
921 switch (peek()) {
922 case EHTokLeftBrace:
923 return acceptCompoundStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -0600924
John Kessenich21472ae2016-06-04 11:46:33 -0600925 case EHTokIf:
926 return acceptSelectionStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -0600927
John Kessenich21472ae2016-06-04 11:46:33 -0600928 case EHTokSwitch:
929 return acceptSwitchStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -0600930
John Kessenich21472ae2016-06-04 11:46:33 -0600931 case EHTokFor:
932 case EHTokDo:
933 case EHTokWhile:
934 return acceptIterationStatement(statement);
935
936 case EHTokContinue:
937 case EHTokBreak:
938 case EHTokDiscard:
939 case EHTokReturn:
940 return acceptJumpStatement(statement);
941
942 case EHTokCase:
943 return acceptCaseLabel(statement);
944
945 case EHTokSemicolon:
946 return acceptTokenClass(EHTokSemicolon);
947
948 case EHTokRightBrace:
949 // Performance: not strictly necessary, but stops a bunch of hunting early,
950 // and is how sequences of statements end.
John Kessenich5f934b02016-03-13 17:58:25 -0600951 return false;
952
John Kessenich21472ae2016-06-04 11:46:33 -0600953 default:
954 {
955 // declaration
956 if (acceptDeclaration(statement))
957 return true;
958
959 // expression
960 TIntermTyped* node;
961 if (acceptExpression(node))
962 statement = node;
963 else
964 return false;
965
966 // SEMICOLON (following an expression)
967 if (! acceptTokenClass(EHTokSemicolon)) {
968 expected("semicolon");
969 return false;
970 }
971 }
972 }
973
John Kessenich5f934b02016-03-13 17:58:25 -0600974 return true;
John Kessenich87142c72016-03-12 20:24:24 -0700975}
976
John Kessenich21472ae2016-06-04 11:46:33 -0600977// attributes
978// : list of zero or more of: LEFT_BRACKET attribute RIGHT_BRACKET
979//
980// attribute:
981// : UNROLL
982// | UNROLL LEFT_PAREN literal RIGHT_PAREN
983// | FASTOPT
984// | ALLOW_UAV_CONDITION
985// | BRANCH
986// | FLATTEN
987// | FORCECASE
988// | CALL
989//
990void HlslGrammar::acceptAttributes()
991{
992 // TODO
993}
994
995bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement)
996{
997 return false;
998}
999
1000bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement)
1001{
1002 return false;
1003}
1004
1005bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement)
1006{
1007 return false;
1008}
1009
1010// jump_statement
1011// : CONTINUE SEMICOLON
1012// | BREAK SEMICOLON
1013// | DISCARD SEMICOLON
1014// | RETURN SEMICOLON
1015// | RETURN expression SEMICOLON
1016//
1017bool HlslGrammar::acceptJumpStatement(TIntermNode*& statement)
1018{
1019 switch (peek()) {
1020 case EHTokContinue:
1021 case EHTokBreak:
1022 case EHTokDiscard:
1023 // TODO
1024 return false;
1025
1026 case EHTokReturn:
1027 // return
1028 if (acceptTokenClass(EHTokReturn)) {
1029 // expression
1030 TIntermTyped* node;
1031 if (acceptExpression(node)) {
1032 // hook it up
1033 statement = intermediate.addBranch(EOpReturn, node, token.loc);
1034 } else
1035 statement = intermediate.addBranch(EOpReturn, token.loc);
1036
1037 // SEMICOLON
1038 if (! acceptTokenClass(EHTokSemicolon)) {
1039 expected("semicolon");
1040 return false;
1041 }
1042
1043 return true;
1044 }
1045
1046 default:
1047 return false;
1048 }
1049}
1050
1051
1052bool HlslGrammar::acceptCaseLabel(TIntermNode*& statement)
1053{
1054 return false;
1055}
1056
John Kessenich078d7f22016-03-14 10:02:11 -06001057// COLON semantic
1058bool HlslGrammar::acceptSemantic()
1059{
1060 // COLON
1061 if (acceptTokenClass(EHTokColon)) {
1062 // semantic
John Kessenichaecd4972016-03-14 10:46:34 -06001063 HlslToken idToken;
1064 if (! acceptIdentifier(idToken)) {
John Kessenich078d7f22016-03-14 10:02:11 -06001065 expected("semantic");
1066 return false;
1067 }
1068 }
1069
1070 return true;
1071}
1072
John Kesseniche01a9bc2016-03-12 20:11:22 -07001073} // end namespace glslang