blob: 9ab9f2c339b6923eb6c2f1cb6b3acf69b8176d22 [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
John Kessenich4678ca92016-05-13 09:33:42 -0600611 TIntermTyped* arguments = nullptr;
John Kessenichd016be12016-03-13 11:24:20 -0600612 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//
John Kessenich4678ca92016-05-13 09:33:42 -0600631bool HlslGrammar::acceptFunctionCall(HlslToken idToken, TIntermTyped*& node)
John Kessenich34fb0362016-05-03 23:17:20 -0600632{
John Kessenich4678ca92016-05-13 09:33:42 -0600633 // arguments
634 TFunction* function = new TFunction(idToken.string, TType(EbtVoid));
635 TIntermTyped* arguments = nullptr;
636 if (! acceptArguments(function, arguments))
637 return false;
638
639 node = parseContext.handleFunctionCall(idToken.loc, function, arguments);
640
641 return true;
John Kessenich34fb0362016-05-03 23:17:20 -0600642}
643
John Kessenich87142c72016-03-12 20:24:24 -0700644// arguments
John Kessenich078d7f22016-03-14 10:02:11 -0600645// : LEFT_PAREN expression COMMA expression COMMA ... RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -0700646//
John Kessenichd016be12016-03-13 11:24:20 -0600647// The arguments are pushed onto the 'function' argument list and
648// onto the 'arguments' aggregate.
649//
John Kessenich4678ca92016-05-13 09:33:42 -0600650bool HlslGrammar::acceptArguments(TFunction* function, TIntermTyped*& arguments)
John Kessenich87142c72016-03-12 20:24:24 -0700651{
John Kessenich078d7f22016-03-14 10:02:11 -0600652 // LEFT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -0700653 if (! acceptTokenClass(EHTokLeftParen))
654 return false;
655
656 do {
John Kessenichd016be12016-03-13 11:24:20 -0600657 // expression
John Kessenich87142c72016-03-12 20:24:24 -0700658 TIntermTyped* arg;
John Kessenich4678ca92016-05-13 09:33:42 -0600659 if (! acceptAssignmentExpression(arg))
John Kessenich87142c72016-03-12 20:24:24 -0700660 break;
John Kessenichd016be12016-03-13 11:24:20 -0600661
662 // hook it up
663 parseContext.handleFunctionArgument(function, arguments, arg);
664
John Kessenich078d7f22016-03-14 10:02:11 -0600665 // COMMA
John Kessenich87142c72016-03-12 20:24:24 -0700666 if (! acceptTokenClass(EHTokComma))
667 break;
668 } while (true);
669
John Kessenich078d7f22016-03-14 10:02:11 -0600670 // RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -0700671 if (! acceptTokenClass(EHTokRightParen)) {
672 expected("right parenthesis");
673 return false;
674 }
675
676 return true;
677}
678
679bool HlslGrammar::acceptLiteral(TIntermTyped*& node)
680{
681 switch (token.tokenClass) {
682 case EHTokIntConstant:
John Kessenich078d7f22016-03-14 10:02:11 -0600683 node = intermediate.addConstantUnion(token.i, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -0700684 break;
685 case EHTokFloatConstant:
John Kessenich078d7f22016-03-14 10:02:11 -0600686 node = intermediate.addConstantUnion(token.d, EbtFloat, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -0700687 break;
688 case EHTokDoubleConstant:
John Kessenich078d7f22016-03-14 10:02:11 -0600689 node = intermediate.addConstantUnion(token.d, EbtDouble, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -0700690 break;
691 case EHTokBoolConstant:
John Kessenich078d7f22016-03-14 10:02:11 -0600692 node = intermediate.addConstantUnion(token.b, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -0700693 break;
694
695 default:
696 return false;
697 }
698
699 advanceToken();
700
701 return true;
702}
703
John Kessenich5f934b02016-03-13 17:58:25 -0600704// compound_statement
John Kessenich34fb0362016-05-03 23:17:20 -0600705// : LEFT_CURLY statement statement ... RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -0600706//
707bool HlslGrammar::acceptCompoundStatement(TIntermAggregate*& compoundStatement)
John Kessenich87142c72016-03-12 20:24:24 -0700708{
John Kessenich34fb0362016-05-03 23:17:20 -0600709 // LEFT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -0600710 if (! acceptTokenClass(EHTokLeftBrace))
711 return false;
712
713 // statement statement ...
714 TIntermNode* statement = nullptr;
715 while (acceptStatement(statement)) {
716 // hook it up
John Kessenich078d7f22016-03-14 10:02:11 -0600717 compoundStatement = intermediate.growAggregate(compoundStatement, statement);
John Kessenich5f934b02016-03-13 17:58:25 -0600718 }
John Kessenich34fb0362016-05-03 23:17:20 -0600719 if (compoundStatement)
720 compoundStatement->setOperator(EOpSequence);
John Kessenich5f934b02016-03-13 17:58:25 -0600721
John Kessenich34fb0362016-05-03 23:17:20 -0600722 // RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -0600723 return acceptTokenClass(EHTokRightBrace);
724}
725
726// statement
727// : compound_statement
John Kessenich078d7f22016-03-14 10:02:11 -0600728// | return SEMICOLON
729// | return expression SEMICOLON
730// | expression SEMICOLON
John Kessenich5f934b02016-03-13 17:58:25 -0600731//
732bool HlslGrammar::acceptStatement(TIntermNode*& statement)
733{
734 // compound_statement
735 TIntermAggregate* compoundStatement = nullptr;
736 if (acceptCompoundStatement(compoundStatement)) {
737 statement = compoundStatement;
738 return true;
739 }
740
John Kessenich078d7f22016-03-14 10:02:11 -0600741 // RETURN
John Kessenich5f934b02016-03-13 17:58:25 -0600742 if (acceptTokenClass(EHTokReturn)) {
743 // expression
744 TIntermTyped* node;
745 if (acceptExpression(node)) {
746 // hook it up
John Kessenich078d7f22016-03-14 10:02:11 -0600747 statement = intermediate.addBranch(EOpReturn, node, token.loc);
John Kessenich5f934b02016-03-13 17:58:25 -0600748 } else
John Kessenich078d7f22016-03-14 10:02:11 -0600749 statement = intermediate.addBranch(EOpReturn, token.loc);
John Kessenich5f934b02016-03-13 17:58:25 -0600750
John Kessenich078d7f22016-03-14 10:02:11 -0600751 // SEMICOLON
John Kessenich5f934b02016-03-13 17:58:25 -0600752 if (! acceptTokenClass(EHTokSemicolon))
753 return false;
754
755 return true;
756 }
757
758 // expression
759 TIntermTyped* node;
760 if (acceptExpression(node))
761 statement = node;
762
John Kessenich078d7f22016-03-14 10:02:11 -0600763 // SEMICOLON
John Kessenich5f934b02016-03-13 17:58:25 -0600764 if (! acceptTokenClass(EHTokSemicolon))
765 return false;
766
767 return true;
John Kessenich87142c72016-03-12 20:24:24 -0700768}
769
John Kessenich078d7f22016-03-14 10:02:11 -0600770// COLON semantic
771bool HlslGrammar::acceptSemantic()
772{
773 // COLON
774 if (acceptTokenClass(EHTokColon)) {
775 // semantic
John Kessenichaecd4972016-03-14 10:46:34 -0600776 HlslToken idToken;
777 if (! acceptIdentifier(idToken)) {
John Kessenich078d7f22016-03-14 10:02:11 -0600778 expected("semantic");
779 return false;
780 }
781 }
782
783 return true;
784}
785
John Kesseniche01a9bc2016-03-12 20:11:22 -0700786} // end namespace glslang