blob: 2339c2d4fe35e606abff280483ca73b6e04f4c92 [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:
222 case EHTokFloat1:
223 new(&type) TType(EbtFloat);
224 break;
225
226 case EHTokFloat2:
227 new(&type) TType(EbtFloat, EvqTemporary, 2);
228 break;
229 case EHTokFloat3:
230 new(&type) TType(EbtFloat, EvqTemporary, 3);
231 break;
232 case EHTokFloat4:
233 new(&type) TType(EbtFloat, EvqTemporary, 4);
234 break;
235
236 case EHTokInt2:
237 new(&type) TType(EbtInt, EvqTemporary, 2);
238 break;
239 case EHTokInt3:
240 new(&type) TType(EbtInt, EvqTemporary, 3);
241 break;
242 case EHTokInt4:
243 new(&type) TType(EbtInt, EvqTemporary, 4);
244 break;
245
246 case EHTokBool2:
247 new(&type) TType(EbtBool, EvqTemporary, 2);
248 break;
249 case EHTokBool3:
250 new(&type) TType(EbtBool, EvqTemporary, 3);
251 break;
252 case EHTokBool4:
253 new(&type) TType(EbtBool, EvqTemporary, 4);
254 break;
255
256 case EHTokFloat2x2:
257 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 2);
258 break;
259 case EHTokFloat2x3:
260 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 2);
261 break;
262 case EHTokFloat2x4:
263 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 2);
264 break;
265 case EHTokFloat3x2:
266 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 3);
267 break;
268 case EHTokFloat3x3:
269 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 3);
270 break;
271 case EHTokFloat3x4:
272 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 3);
273 break;
274 case EHTokFloat4x2:
275 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 4);
276 break;
277 case EHTokFloat4x3:
278 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 4);
279 break;
280 case EHTokFloat4x4:
281 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 4);
282 break;
283
284 default:
285 return false;
286 }
287
288 advanceToken();
289
290 return true;
291}
292
John Kessenich5f934b02016-03-13 17:58:25 -0600293// function_parameters
John Kessenich078d7f22016-03-14 10:02:11 -0600294// : LEFT_PAREN parameter_declaration COMMA parameter_declaration ... RIGHT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -0600295//
296bool HlslGrammar::acceptFunctionParameters(TFunction& function)
297{
John Kessenich078d7f22016-03-14 10:02:11 -0600298 // LEFT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -0600299 if (! acceptTokenClass(EHTokLeftParen))
300 return false;
301
302 do {
303 // parameter_declaration
304 if (! acceptParameterDeclaration(function))
305 break;
306
John Kessenich078d7f22016-03-14 10:02:11 -0600307 // COMMA
John Kessenich5f934b02016-03-13 17:58:25 -0600308 if (! acceptTokenClass(EHTokComma))
309 break;
310 } while (true);
311
John Kessenich078d7f22016-03-14 10:02:11 -0600312 // RIGHT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -0600313 if (! acceptTokenClass(EHTokRightParen)) {
314 expected("right parenthesis");
315 return false;
316 }
317
318 return true;
319}
320
321// parameter_declaration
322// : fully_specified_type
323// | fully_specified_type identifier
324//
325bool HlslGrammar::acceptParameterDeclaration(TFunction& function)
326{
327 // fully_specified_type
328 TType* type = new TType;
329 if (! acceptFullySpecifiedType(*type))
330 return false;
331
332 // identifier
John Kessenichaecd4972016-03-14 10:46:34 -0600333 HlslToken idToken;
334 acceptIdentifier(idToken);
John Kessenich5f934b02016-03-13 17:58:25 -0600335
John Kessenichaecd4972016-03-14 10:46:34 -0600336 TParameter param = { idToken.string, type };
John Kessenich5f934b02016-03-13 17:58:25 -0600337 function.addParameter(param);
338
339 return true;
340}
341
342// Do the work to create the function definition in addition to
343// parsing the body (compound_statement).
344bool HlslGrammar::acceptFunctionDefinition(TFunction& function, TIntermNode*& node)
345{
346 TFunction* functionDeclarator = parseContext.handleFunctionDeclarator(token.loc, function, false /* not prototype */);
347
348 // This does a symbol table push
349 node = parseContext.handleFunctionDefinition(token.loc, *functionDeclarator);
350
351 // compound_statement
352 TIntermAggregate* functionBody = nullptr;
353 if (acceptCompoundStatement(functionBody)) {
John Kessenich078d7f22016-03-14 10:02:11 -0600354 node = intermediate.growAggregate(node, functionBody);
355 intermediate.setAggregateOperator(node, EOpFunction, functionDeclarator->getType(), token.loc);
John Kessenich5f934b02016-03-13 17:58:25 -0600356 node->getAsAggregate()->setName(functionDeclarator->getMangledName().c_str());
357 parseContext.symbolTable.pop(nullptr);
358
359 return true;
360 }
361
362 return false;
363}
364
John Kessenich34fb0362016-05-03 23:17:20 -0600365// The top-level full expression recognizer.
366//
John Kessenich87142c72016-03-12 20:24:24 -0700367// expression
John Kessenich34fb0362016-05-03 23:17:20 -0600368// : assignment_expression COMMA assignment_expression COMMA assignment_expression ...
John Kessenich87142c72016-03-12 20:24:24 -0700369//
370bool HlslGrammar::acceptExpression(TIntermTyped*& node)
371{
John Kessenich34fb0362016-05-03 23:17:20 -0600372 // assignment_expression
373 if (! acceptAssignmentExpression(node))
374 return false;
John Kessenich5f934b02016-03-13 17:58:25 -0600375
John Kessenich34fb0362016-05-03 23:17:20 -0600376 if (! peekTokenClass(EHTokComma))
377 return true;
378
379 do {
380 // ... COMMA
John Kessenich5f934b02016-03-13 17:58:25 -0600381 TSourceLoc loc = token.loc;
John Kessenich34fb0362016-05-03 23:17:20 -0600382 advanceToken();
John Kessenich5f934b02016-03-13 17:58:25 -0600383
John Kessenich34fb0362016-05-03 23:17:20 -0600384 // ... assignment_expression
385 TIntermTyped* rightNode = nullptr;
386 if (! acceptAssignmentExpression(rightNode)) {
387 expected("assignment expression");
388 return false;
John Kessenich5f934b02016-03-13 17:58:25 -0600389 }
390
John Kessenich34fb0362016-05-03 23:17:20 -0600391 node = intermediate.addComma(node, rightNode, loc);
392
393 if (! peekTokenClass(EHTokComma))
394 return true;
395 } while (true);
396}
397
398// Accept an assignment expression, where assignment operations
399// associate right-to-left. This is, it is implicit, for example
400//
401// a op (b op (c op d))
402//
403// assigment_expression
404// : binary_expression op binary_expression op binary_expression ...
405//
406bool HlslGrammar::acceptAssignmentExpression(TIntermTyped*& node)
407{
408 if (! acceptBinaryExpression(node, PlLogicalOr))
409 return false;
410
411 TOperator assignOp = HlslOpMap::assignment(peek());
412 if (assignOp == EOpNull)
413 return true;
414
415 // ... op
416 TSourceLoc loc = token.loc;
417 advanceToken();
418
419 // ... binary_expression
420 // But, done by recursing this function, which automatically
421 // gets the right-to-left associativity.
422 TIntermTyped* rightNode = nullptr;
423 if (! acceptAssignmentExpression(rightNode)) {
424 expected("assignment expression");
John Kessenich5f934b02016-03-13 17:58:25 -0600425 return false;
John Kessenich87142c72016-03-12 20:24:24 -0700426 }
427
John Kessenich34fb0362016-05-03 23:17:20 -0600428 node = intermediate.addAssign(assignOp, node, rightNode, loc);
429
430 if (! peekTokenClass(EHTokComma))
431 return true;
432
433 return true;
434}
435
436// Accept a binary expression, for binary operations that
437// associate left-to-right. This is, it is implicit, for example
438//
439// ((a op b) op c) op d
440//
441// binary_expression
442// : expression op expression op expression ...
443//
444// where 'expression' is the next higher level in precedence.
445//
446bool HlslGrammar::acceptBinaryExpression(TIntermTyped*& node, PrecedenceLevel precedenceLevel)
447{
448 if (precedenceLevel > PlMul)
449 return acceptUnaryExpression(node);
450
451 // assignment_expression
452 if (! acceptBinaryExpression(node, (PrecedenceLevel)(precedenceLevel + 1)))
453 return false;
454
455 TOperator op = HlslOpMap::binary(peek());
456 PrecedenceLevel tokenLevel = HlslOpMap::precedenceLevel(op);
457 if (tokenLevel < precedenceLevel)
458 return true;
459
460 do {
461 // ... op
462 TSourceLoc loc = token.loc;
463 advanceToken();
464
465 // ... expression
466 TIntermTyped* rightNode = nullptr;
467 if (! acceptBinaryExpression(rightNode, (PrecedenceLevel)(precedenceLevel + 1))) {
468 expected("expression");
469 return false;
470 }
471
472 node = intermediate.addBinaryMath(op, node, rightNode, loc);
473
474 if (! peekTokenClass(EHTokComma))
475 return true;
476 } while (true);
477}
478
479// unary_expression
480// : + unary_expression
481// | - unary_expression
482// | ! unary_expression
483// | ~ unary_expression
484// | ++ unary_expression
485// | -- unary_expression
486// | postfix_expression
487//
488bool HlslGrammar::acceptUnaryExpression(TIntermTyped*& node)
489{
490 TOperator unaryOp = HlslOpMap::preUnary(peek());
491
492 // postfix_expression
493 if (unaryOp == EOpNull)
494 return acceptPostfixExpression(node);
495
496 // op unary_expression
497 TSourceLoc loc = token.loc;
498 advanceToken();
499 if (! acceptUnaryExpression(node))
500 return false;
501
502 // + is a no-op
503 if (unaryOp == EOpAdd)
504 return true;
505
506 node = intermediate.addUnaryMath(unaryOp, node, loc);
507
508 return node != nullptr;
509}
510
511// postfix_expression
512// : LEFT_PAREN expression RIGHT_PAREN
513// | literal
514// | constructor
515// | identifier
516// | function_call
517// | postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET
518// | postfix_expression DOT IDENTIFIER
519// | postfix_expression INC_OP
520// | postfix_expression DEC_OP
521//
522bool HlslGrammar::acceptPostfixExpression(TIntermTyped*& node)
523{
524 // Not implemented as self-recursive:
525 // The logical "right recursion" is done with an loop at the end
526
527 // idToken will pick up either a variable or a function name in a function call
528 HlslToken idToken;
529
John Kessenich078d7f22016-03-14 10:02:11 -0600530 // LEFT_PAREN expression RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -0700531 if (acceptTokenClass(EHTokLeftParen)) {
532 if (! acceptExpression(node)) {
533 expected("expression");
534 return false;
535 }
536 if (! acceptTokenClass(EHTokRightParen)) {
537 expected("right parenthesis");
538 return false;
539 }
John Kessenich34fb0362016-05-03 23:17:20 -0600540 } else if (acceptLiteral(node)) {
541 // literal (nothing else to do yet), go on to the
542 } else if (acceptConstructor(node)) {
543 // constructor (nothing else to do yet)
544 } else if (acceptIdentifier(idToken)) {
545 // identifier or function_call name
546 if (! peekTokenClass(EHTokLeftParen)) {
547 node = parseContext.handleVariable(idToken.loc, idToken.symbol, token.string);
548 } else if (acceptFunctionCall(idToken, node)) {
549 // function_call (nothing else to do yet)
550 } else {
551 expected("function call arguments");
552 return false;
553 }
John Kessenich87142c72016-03-12 20:24:24 -0700554 }
555
John Kessenich34fb0362016-05-03 23:17:20 -0600556 do {
557 TSourceLoc loc = token.loc;
558 TOperator postOp = HlslOpMap::postUnary(peek());
John Kessenich87142c72016-03-12 20:24:24 -0700559
John Kessenich34fb0362016-05-03 23:17:20 -0600560 // Consume only a valid post-unary operator, otherwise we are done.
561 switch (postOp) {
562 case EOpIndexDirectStruct:
563 case EOpIndexIndirect:
564 case EOpPostIncrement:
565 case EOpPostDecrement:
566 advanceToken();
567 break;
568 default:
569 return true;
570 }
John Kessenich87142c72016-03-12 20:24:24 -0700571
John Kessenich34fb0362016-05-03 23:17:20 -0600572 // We have a valid post-unary operator, process it.
573 switch (postOp) {
574 case EOpIndexDirectStruct:
575 // todo
576 break;
577 case EOpIndexIndirect:
578 {
579 TIntermTyped* indexNode = nullptr;
580 if (! acceptExpression(indexNode) ||
581 ! peekTokenClass(EHTokRightBracket)) {
582 expected("expression followed by ']'");
583 return false;
584 }
585 // todo: node = intermediate.addBinaryMath(
586 }
587 case EOpPostIncrement:
588 case EOpPostDecrement:
589 node = intermediate.addUnaryMath(postOp, node, loc);
590 break;
591 default:
592 assert(0);
593 break;
594 }
595 } while (true);
John Kessenich87142c72016-03-12 20:24:24 -0700596}
597
John Kessenichd016be12016-03-13 11:24:20 -0600598// constructor
John Kessenich078d7f22016-03-14 10:02:11 -0600599// : type argument_list
John Kessenichd016be12016-03-13 11:24:20 -0600600//
601bool HlslGrammar::acceptConstructor(TIntermTyped*& node)
602{
603 // type
604 TType type;
605 if (acceptType(type)) {
606 TFunction* constructorFunction = parseContext.handleConstructorCall(token.loc, type);
607 if (constructorFunction == nullptr)
608 return false;
609
610 // arguments
611 TIntermAggregate* arguments = nullptr;
612 if (! acceptArguments(constructorFunction, arguments)) {
613 expected("constructor arguments");
614 return false;
615 }
616
617 // hook it up
618 node = parseContext.handleFunctionCall(arguments->getLoc(), constructorFunction, arguments);
619
620 return true;
621 }
622
623 return false;
624}
625
John Kessenich34fb0362016-05-03 23:17:20 -0600626// The function_call identifier was already recognized, and passed in as idToken.
627//
628// function_call
629// : [idToken] arguments
630//
631bool HlslGrammar::acceptFunctionCall(HlslToken idToken, TIntermTyped*&)
632{
633 // todo
634 return false;
635}
636
John Kessenich87142c72016-03-12 20:24:24 -0700637// arguments
John Kessenich078d7f22016-03-14 10:02:11 -0600638// : LEFT_PAREN expression COMMA expression COMMA ... RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -0700639//
John Kessenichd016be12016-03-13 11:24:20 -0600640// The arguments are pushed onto the 'function' argument list and
641// onto the 'arguments' aggregate.
642//
643bool HlslGrammar::acceptArguments(TFunction* function, TIntermAggregate*& arguments)
John Kessenich87142c72016-03-12 20:24:24 -0700644{
John Kessenich078d7f22016-03-14 10:02:11 -0600645 // LEFT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -0700646 if (! acceptTokenClass(EHTokLeftParen))
647 return false;
648
649 do {
John Kessenichd016be12016-03-13 11:24:20 -0600650 // expression
John Kessenich87142c72016-03-12 20:24:24 -0700651 TIntermTyped* arg;
652 if (! acceptExpression(arg))
653 break;
John Kessenichd016be12016-03-13 11:24:20 -0600654
655 // hook it up
656 parseContext.handleFunctionArgument(function, arguments, arg);
657
John Kessenich078d7f22016-03-14 10:02:11 -0600658 // COMMA
John Kessenich87142c72016-03-12 20:24:24 -0700659 if (! acceptTokenClass(EHTokComma))
660 break;
661 } while (true);
662
John Kessenich078d7f22016-03-14 10:02:11 -0600663 // RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -0700664 if (! acceptTokenClass(EHTokRightParen)) {
665 expected("right parenthesis");
666 return false;
667 }
668
669 return true;
670}
671
672bool HlslGrammar::acceptLiteral(TIntermTyped*& node)
673{
674 switch (token.tokenClass) {
675 case EHTokIntConstant:
John Kessenich078d7f22016-03-14 10:02:11 -0600676 node = intermediate.addConstantUnion(token.i, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -0700677 break;
678 case EHTokFloatConstant:
John Kessenich078d7f22016-03-14 10:02:11 -0600679 node = intermediate.addConstantUnion(token.d, EbtFloat, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -0700680 break;
681 case EHTokDoubleConstant:
John Kessenich078d7f22016-03-14 10:02:11 -0600682 node = intermediate.addConstantUnion(token.d, EbtDouble, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -0700683 break;
684 case EHTokBoolConstant:
John Kessenich078d7f22016-03-14 10:02:11 -0600685 node = intermediate.addConstantUnion(token.b, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -0700686 break;
687
688 default:
689 return false;
690 }
691
692 advanceToken();
693
694 return true;
695}
696
John Kessenich5f934b02016-03-13 17:58:25 -0600697// compound_statement
John Kessenich34fb0362016-05-03 23:17:20 -0600698// : LEFT_CURLY statement statement ... RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -0600699//
700bool HlslGrammar::acceptCompoundStatement(TIntermAggregate*& compoundStatement)
John Kessenich87142c72016-03-12 20:24:24 -0700701{
John Kessenich34fb0362016-05-03 23:17:20 -0600702 // LEFT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -0600703 if (! acceptTokenClass(EHTokLeftBrace))
704 return false;
705
706 // statement statement ...
707 TIntermNode* statement = nullptr;
708 while (acceptStatement(statement)) {
709 // hook it up
John Kessenich078d7f22016-03-14 10:02:11 -0600710 compoundStatement = intermediate.growAggregate(compoundStatement, statement);
John Kessenich5f934b02016-03-13 17:58:25 -0600711 }
John Kessenich34fb0362016-05-03 23:17:20 -0600712 if (compoundStatement)
713 compoundStatement->setOperator(EOpSequence);
John Kessenich5f934b02016-03-13 17:58:25 -0600714
John Kessenich34fb0362016-05-03 23:17:20 -0600715 // RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -0600716 return acceptTokenClass(EHTokRightBrace);
717}
718
719// statement
720// : compound_statement
John Kessenich078d7f22016-03-14 10:02:11 -0600721// | return SEMICOLON
722// | return expression SEMICOLON
723// | expression SEMICOLON
John Kessenich5f934b02016-03-13 17:58:25 -0600724//
725bool HlslGrammar::acceptStatement(TIntermNode*& statement)
726{
727 // compound_statement
728 TIntermAggregate* compoundStatement = nullptr;
729 if (acceptCompoundStatement(compoundStatement)) {
730 statement = compoundStatement;
731 return true;
732 }
733
John Kessenich078d7f22016-03-14 10:02:11 -0600734 // RETURN
John Kessenich5f934b02016-03-13 17:58:25 -0600735 if (acceptTokenClass(EHTokReturn)) {
736 // expression
737 TIntermTyped* node;
738 if (acceptExpression(node)) {
739 // hook it up
John Kessenich078d7f22016-03-14 10:02:11 -0600740 statement = intermediate.addBranch(EOpReturn, node, token.loc);
John Kessenich5f934b02016-03-13 17:58:25 -0600741 } else
John Kessenich078d7f22016-03-14 10:02:11 -0600742 statement = intermediate.addBranch(EOpReturn, token.loc);
John Kessenich5f934b02016-03-13 17:58:25 -0600743
John Kessenich078d7f22016-03-14 10:02:11 -0600744 // SEMICOLON
John Kessenich5f934b02016-03-13 17:58:25 -0600745 if (! acceptTokenClass(EHTokSemicolon))
746 return false;
747
748 return true;
749 }
750
751 // expression
752 TIntermTyped* node;
753 if (acceptExpression(node))
754 statement = node;
755
John Kessenich078d7f22016-03-14 10:02:11 -0600756 // SEMICOLON
John Kessenich5f934b02016-03-13 17:58:25 -0600757 if (! acceptTokenClass(EHTokSemicolon))
758 return false;
759
760 return true;
John Kessenich87142c72016-03-12 20:24:24 -0700761}
762
John Kessenich078d7f22016-03-14 10:02:11 -0600763// COLON semantic
764bool HlslGrammar::acceptSemantic()
765{
766 // COLON
767 if (acceptTokenClass(EHTokColon)) {
768 // semantic
John Kessenichaecd4972016-03-14 10:46:34 -0600769 HlslToken idToken;
770 if (! acceptIdentifier(idToken)) {
John Kessenich078d7f22016-03-14 10:02:11 -0600771 expected("semantic");
772 return false;
773 }
774 }
775
776 return true;
777}
778
John Kesseniche01a9bc2016-03-12 20:11:22 -0700779} // end namespace glslang