blob: 75f9818ddb901bc6ca2f57609dacdac9d5f51e13 [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
260 case EHTokFloat2x2:
261 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 2);
262 break;
263 case EHTokFloat2x3:
264 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 2);
265 break;
266 case EHTokFloat2x4:
267 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 2);
268 break;
269 case EHTokFloat3x2:
270 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 3);
271 break;
272 case EHTokFloat3x3:
273 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 3);
274 break;
275 case EHTokFloat3x4:
276 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 3);
277 break;
278 case EHTokFloat4x2:
279 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 4);
280 break;
281 case EHTokFloat4x3:
282 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 4);
283 break;
284 case EHTokFloat4x4:
285 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 4);
286 break;
287
288 default:
289 return false;
290 }
291
292 advanceToken();
293
294 return true;
295}
296
John Kessenich5f934b02016-03-13 17:58:25 -0600297// function_parameters
John Kessenich078d7f22016-03-14 10:02:11 -0600298// : LEFT_PAREN parameter_declaration COMMA parameter_declaration ... RIGHT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -0600299//
300bool HlslGrammar::acceptFunctionParameters(TFunction& function)
301{
John Kessenich078d7f22016-03-14 10:02:11 -0600302 // LEFT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -0600303 if (! acceptTokenClass(EHTokLeftParen))
304 return false;
305
306 do {
307 // parameter_declaration
308 if (! acceptParameterDeclaration(function))
309 break;
310
John Kessenich078d7f22016-03-14 10:02:11 -0600311 // COMMA
John Kessenich5f934b02016-03-13 17:58:25 -0600312 if (! acceptTokenClass(EHTokComma))
313 break;
314 } while (true);
315
John Kessenich078d7f22016-03-14 10:02:11 -0600316 // RIGHT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -0600317 if (! acceptTokenClass(EHTokRightParen)) {
318 expected("right parenthesis");
319 return false;
320 }
321
322 return true;
323}
324
325// parameter_declaration
326// : fully_specified_type
327// | fully_specified_type identifier
328//
329bool HlslGrammar::acceptParameterDeclaration(TFunction& function)
330{
331 // fully_specified_type
332 TType* type = new TType;
333 if (! acceptFullySpecifiedType(*type))
334 return false;
335
336 // identifier
John Kessenichaecd4972016-03-14 10:46:34 -0600337 HlslToken idToken;
338 acceptIdentifier(idToken);
John Kessenich5f934b02016-03-13 17:58:25 -0600339
John Kessenichaecd4972016-03-14 10:46:34 -0600340 TParameter param = { idToken.string, type };
John Kessenich5f934b02016-03-13 17:58:25 -0600341 function.addParameter(param);
342
343 return true;
344}
345
346// Do the work to create the function definition in addition to
347// parsing the body (compound_statement).
348bool HlslGrammar::acceptFunctionDefinition(TFunction& function, TIntermNode*& node)
349{
350 TFunction* functionDeclarator = parseContext.handleFunctionDeclarator(token.loc, function, false /* not prototype */);
351
352 // This does a symbol table push
353 node = parseContext.handleFunctionDefinition(token.loc, *functionDeclarator);
354
355 // compound_statement
356 TIntermAggregate* functionBody = nullptr;
357 if (acceptCompoundStatement(functionBody)) {
John Kessenich078d7f22016-03-14 10:02:11 -0600358 node = intermediate.growAggregate(node, functionBody);
359 intermediate.setAggregateOperator(node, EOpFunction, functionDeclarator->getType(), token.loc);
John Kessenich5f934b02016-03-13 17:58:25 -0600360 node->getAsAggregate()->setName(functionDeclarator->getMangledName().c_str());
361 parseContext.symbolTable.pop(nullptr);
362
363 return true;
364 }
365
366 return false;
367}
368
John Kessenich34fb0362016-05-03 23:17:20 -0600369// The top-level full expression recognizer.
370//
John Kessenich87142c72016-03-12 20:24:24 -0700371// expression
John Kessenich34fb0362016-05-03 23:17:20 -0600372// : assignment_expression COMMA assignment_expression COMMA assignment_expression ...
John Kessenich87142c72016-03-12 20:24:24 -0700373//
374bool HlslGrammar::acceptExpression(TIntermTyped*& node)
375{
John Kessenich34fb0362016-05-03 23:17:20 -0600376 // assignment_expression
377 if (! acceptAssignmentExpression(node))
378 return false;
John Kessenich5f934b02016-03-13 17:58:25 -0600379
John Kessenich34fb0362016-05-03 23:17:20 -0600380 if (! peekTokenClass(EHTokComma))
381 return true;
382
383 do {
384 // ... COMMA
John Kessenich5f934b02016-03-13 17:58:25 -0600385 TSourceLoc loc = token.loc;
John Kessenich34fb0362016-05-03 23:17:20 -0600386 advanceToken();
John Kessenich5f934b02016-03-13 17:58:25 -0600387
John Kessenich34fb0362016-05-03 23:17:20 -0600388 // ... assignment_expression
389 TIntermTyped* rightNode = nullptr;
390 if (! acceptAssignmentExpression(rightNode)) {
391 expected("assignment expression");
392 return false;
John Kessenich5f934b02016-03-13 17:58:25 -0600393 }
394
John Kessenich34fb0362016-05-03 23:17:20 -0600395 node = intermediate.addComma(node, rightNode, loc);
396
397 if (! peekTokenClass(EHTokComma))
398 return true;
399 } while (true);
400}
401
402// Accept an assignment expression, where assignment operations
403// associate right-to-left. This is, it is implicit, for example
404//
405// a op (b op (c op d))
406//
407// assigment_expression
408// : binary_expression op binary_expression op binary_expression ...
409//
410bool HlslGrammar::acceptAssignmentExpression(TIntermTyped*& node)
411{
412 if (! acceptBinaryExpression(node, PlLogicalOr))
413 return false;
414
415 TOperator assignOp = HlslOpMap::assignment(peek());
416 if (assignOp == EOpNull)
417 return true;
418
419 // ... op
420 TSourceLoc loc = token.loc;
421 advanceToken();
422
423 // ... binary_expression
424 // But, done by recursing this function, which automatically
425 // gets the right-to-left associativity.
426 TIntermTyped* rightNode = nullptr;
427 if (! acceptAssignmentExpression(rightNode)) {
428 expected("assignment expression");
John Kessenich5f934b02016-03-13 17:58:25 -0600429 return false;
John Kessenich87142c72016-03-12 20:24:24 -0700430 }
431
John Kessenich34fb0362016-05-03 23:17:20 -0600432 node = intermediate.addAssign(assignOp, node, rightNode, loc);
433
434 if (! peekTokenClass(EHTokComma))
435 return true;
436
437 return true;
438}
439
440// Accept a binary expression, for binary operations that
441// associate left-to-right. This is, it is implicit, for example
442//
443// ((a op b) op c) op d
444//
445// binary_expression
446// : expression op expression op expression ...
447//
448// where 'expression' is the next higher level in precedence.
449//
450bool HlslGrammar::acceptBinaryExpression(TIntermTyped*& node, PrecedenceLevel precedenceLevel)
451{
452 if (precedenceLevel > PlMul)
453 return acceptUnaryExpression(node);
454
455 // assignment_expression
456 if (! acceptBinaryExpression(node, (PrecedenceLevel)(precedenceLevel + 1)))
457 return false;
458
459 TOperator op = HlslOpMap::binary(peek());
460 PrecedenceLevel tokenLevel = HlslOpMap::precedenceLevel(op);
461 if (tokenLevel < precedenceLevel)
462 return true;
463
464 do {
465 // ... op
466 TSourceLoc loc = token.loc;
467 advanceToken();
468
469 // ... expression
470 TIntermTyped* rightNode = nullptr;
471 if (! acceptBinaryExpression(rightNode, (PrecedenceLevel)(precedenceLevel + 1))) {
472 expected("expression");
473 return false;
474 }
475
476 node = intermediate.addBinaryMath(op, node, rightNode, loc);
477
478 if (! peekTokenClass(EHTokComma))
479 return true;
480 } while (true);
481}
482
483// unary_expression
484// : + unary_expression
485// | - unary_expression
486// | ! unary_expression
487// | ~ unary_expression
488// | ++ unary_expression
489// | -- unary_expression
490// | postfix_expression
491//
492bool HlslGrammar::acceptUnaryExpression(TIntermTyped*& node)
493{
494 TOperator unaryOp = HlslOpMap::preUnary(peek());
495
496 // postfix_expression
497 if (unaryOp == EOpNull)
498 return acceptPostfixExpression(node);
499
500 // op unary_expression
501 TSourceLoc loc = token.loc;
502 advanceToken();
503 if (! acceptUnaryExpression(node))
504 return false;
505
506 // + is a no-op
507 if (unaryOp == EOpAdd)
508 return true;
509
510 node = intermediate.addUnaryMath(unaryOp, node, loc);
511
512 return node != nullptr;
513}
514
515// postfix_expression
516// : LEFT_PAREN expression RIGHT_PAREN
517// | literal
518// | constructor
519// | identifier
520// | function_call
521// | postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET
522// | postfix_expression DOT IDENTIFIER
523// | postfix_expression INC_OP
524// | postfix_expression DEC_OP
525//
526bool HlslGrammar::acceptPostfixExpression(TIntermTyped*& node)
527{
528 // Not implemented as self-recursive:
529 // The logical "right recursion" is done with an loop at the end
530
531 // idToken will pick up either a variable or a function name in a function call
532 HlslToken idToken;
533
John Kessenich078d7f22016-03-14 10:02:11 -0600534 // LEFT_PAREN expression RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -0700535 if (acceptTokenClass(EHTokLeftParen)) {
536 if (! acceptExpression(node)) {
537 expected("expression");
538 return false;
539 }
540 if (! acceptTokenClass(EHTokRightParen)) {
541 expected("right parenthesis");
542 return false;
543 }
John Kessenich34fb0362016-05-03 23:17:20 -0600544 } else if (acceptLiteral(node)) {
545 // literal (nothing else to do yet), go on to the
546 } else if (acceptConstructor(node)) {
547 // constructor (nothing else to do yet)
548 } else if (acceptIdentifier(idToken)) {
549 // identifier or function_call name
550 if (! peekTokenClass(EHTokLeftParen)) {
551 node = parseContext.handleVariable(idToken.loc, idToken.symbol, token.string);
552 } else if (acceptFunctionCall(idToken, node)) {
553 // function_call (nothing else to do yet)
554 } else {
555 expected("function call arguments");
556 return false;
557 }
John Kessenich87142c72016-03-12 20:24:24 -0700558 }
559
John Kessenich34fb0362016-05-03 23:17:20 -0600560 do {
561 TSourceLoc loc = token.loc;
562 TOperator postOp = HlslOpMap::postUnary(peek());
John Kessenich87142c72016-03-12 20:24:24 -0700563
John Kessenich34fb0362016-05-03 23:17:20 -0600564 // Consume only a valid post-unary operator, otherwise we are done.
565 switch (postOp) {
566 case EOpIndexDirectStruct:
567 case EOpIndexIndirect:
568 case EOpPostIncrement:
569 case EOpPostDecrement:
570 advanceToken();
571 break;
572 default:
573 return true;
574 }
John Kessenich87142c72016-03-12 20:24:24 -0700575
John Kessenich34fb0362016-05-03 23:17:20 -0600576 // We have a valid post-unary operator, process it.
577 switch (postOp) {
578 case EOpIndexDirectStruct:
579 // todo
580 break;
581 case EOpIndexIndirect:
582 {
583 TIntermTyped* indexNode = nullptr;
584 if (! acceptExpression(indexNode) ||
585 ! peekTokenClass(EHTokRightBracket)) {
586 expected("expression followed by ']'");
587 return false;
588 }
589 // todo: node = intermediate.addBinaryMath(
590 }
591 case EOpPostIncrement:
592 case EOpPostDecrement:
593 node = intermediate.addUnaryMath(postOp, node, loc);
594 break;
595 default:
596 assert(0);
597 break;
598 }
599 } while (true);
John Kessenich87142c72016-03-12 20:24:24 -0700600}
601
John Kessenichd016be12016-03-13 11:24:20 -0600602// constructor
John Kessenich078d7f22016-03-14 10:02:11 -0600603// : type argument_list
John Kessenichd016be12016-03-13 11:24:20 -0600604//
605bool HlslGrammar::acceptConstructor(TIntermTyped*& node)
606{
607 // type
608 TType type;
609 if (acceptType(type)) {
610 TFunction* constructorFunction = parseContext.handleConstructorCall(token.loc, type);
611 if (constructorFunction == nullptr)
612 return false;
613
614 // arguments
John Kessenich4678ca92016-05-13 09:33:42 -0600615 TIntermTyped* arguments = nullptr;
John Kessenichd016be12016-03-13 11:24:20 -0600616 if (! acceptArguments(constructorFunction, arguments)) {
617 expected("constructor arguments");
618 return false;
619 }
620
621 // hook it up
622 node = parseContext.handleFunctionCall(arguments->getLoc(), constructorFunction, arguments);
623
624 return true;
625 }
626
627 return false;
628}
629
John Kessenich34fb0362016-05-03 23:17:20 -0600630// The function_call identifier was already recognized, and passed in as idToken.
631//
632// function_call
633// : [idToken] arguments
634//
John Kessenich4678ca92016-05-13 09:33:42 -0600635bool HlslGrammar::acceptFunctionCall(HlslToken idToken, TIntermTyped*& node)
John Kessenich34fb0362016-05-03 23:17:20 -0600636{
John Kessenich4678ca92016-05-13 09:33:42 -0600637 // arguments
638 TFunction* function = new TFunction(idToken.string, TType(EbtVoid));
639 TIntermTyped* arguments = nullptr;
640 if (! acceptArguments(function, arguments))
641 return false;
642
643 node = parseContext.handleFunctionCall(idToken.loc, function, arguments);
644
645 return true;
John Kessenich34fb0362016-05-03 23:17:20 -0600646}
647
John Kessenich87142c72016-03-12 20:24:24 -0700648// arguments
John Kessenich078d7f22016-03-14 10:02:11 -0600649// : LEFT_PAREN expression COMMA expression COMMA ... RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -0700650//
John Kessenichd016be12016-03-13 11:24:20 -0600651// The arguments are pushed onto the 'function' argument list and
652// onto the 'arguments' aggregate.
653//
John Kessenich4678ca92016-05-13 09:33:42 -0600654bool HlslGrammar::acceptArguments(TFunction* function, TIntermTyped*& arguments)
John Kessenich87142c72016-03-12 20:24:24 -0700655{
John Kessenich078d7f22016-03-14 10:02:11 -0600656 // LEFT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -0700657 if (! acceptTokenClass(EHTokLeftParen))
658 return false;
659
660 do {
John Kessenichd016be12016-03-13 11:24:20 -0600661 // expression
John Kessenich87142c72016-03-12 20:24:24 -0700662 TIntermTyped* arg;
John Kessenich4678ca92016-05-13 09:33:42 -0600663 if (! acceptAssignmentExpression(arg))
John Kessenich87142c72016-03-12 20:24:24 -0700664 break;
John Kessenichd016be12016-03-13 11:24:20 -0600665
666 // hook it up
667 parseContext.handleFunctionArgument(function, arguments, arg);
668
John Kessenich078d7f22016-03-14 10:02:11 -0600669 // COMMA
John Kessenich87142c72016-03-12 20:24:24 -0700670 if (! acceptTokenClass(EHTokComma))
671 break;
672 } while (true);
673
John Kessenich078d7f22016-03-14 10:02:11 -0600674 // RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -0700675 if (! acceptTokenClass(EHTokRightParen)) {
676 expected("right parenthesis");
677 return false;
678 }
679
680 return true;
681}
682
683bool HlslGrammar::acceptLiteral(TIntermTyped*& node)
684{
685 switch (token.tokenClass) {
686 case EHTokIntConstant:
John Kessenich078d7f22016-03-14 10:02:11 -0600687 node = intermediate.addConstantUnion(token.i, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -0700688 break;
689 case EHTokFloatConstant:
John Kessenich078d7f22016-03-14 10:02:11 -0600690 node = intermediate.addConstantUnion(token.d, EbtFloat, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -0700691 break;
692 case EHTokDoubleConstant:
John Kessenich078d7f22016-03-14 10:02:11 -0600693 node = intermediate.addConstantUnion(token.d, EbtDouble, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -0700694 break;
695 case EHTokBoolConstant:
John Kessenich078d7f22016-03-14 10:02:11 -0600696 node = intermediate.addConstantUnion(token.b, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -0700697 break;
698
699 default:
700 return false;
701 }
702
703 advanceToken();
704
705 return true;
706}
707
John Kessenich5f934b02016-03-13 17:58:25 -0600708// compound_statement
John Kessenich34fb0362016-05-03 23:17:20 -0600709// : LEFT_CURLY statement statement ... RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -0600710//
711bool HlslGrammar::acceptCompoundStatement(TIntermAggregate*& compoundStatement)
John Kessenich87142c72016-03-12 20:24:24 -0700712{
John Kessenich34fb0362016-05-03 23:17:20 -0600713 // LEFT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -0600714 if (! acceptTokenClass(EHTokLeftBrace))
715 return false;
716
717 // statement statement ...
718 TIntermNode* statement = nullptr;
719 while (acceptStatement(statement)) {
720 // hook it up
John Kessenich078d7f22016-03-14 10:02:11 -0600721 compoundStatement = intermediate.growAggregate(compoundStatement, statement);
John Kessenich5f934b02016-03-13 17:58:25 -0600722 }
John Kessenich34fb0362016-05-03 23:17:20 -0600723 if (compoundStatement)
724 compoundStatement->setOperator(EOpSequence);
John Kessenich5f934b02016-03-13 17:58:25 -0600725
John Kessenich34fb0362016-05-03 23:17:20 -0600726 // RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -0600727 return acceptTokenClass(EHTokRightBrace);
728}
729
730// statement
731// : compound_statement
John Kessenich078d7f22016-03-14 10:02:11 -0600732// | return SEMICOLON
733// | return expression SEMICOLON
734// | expression SEMICOLON
John Kessenich5f934b02016-03-13 17:58:25 -0600735//
736bool HlslGrammar::acceptStatement(TIntermNode*& statement)
737{
738 // compound_statement
739 TIntermAggregate* compoundStatement = nullptr;
740 if (acceptCompoundStatement(compoundStatement)) {
741 statement = compoundStatement;
742 return true;
743 }
744
John Kessenich078d7f22016-03-14 10:02:11 -0600745 // RETURN
John Kessenich5f934b02016-03-13 17:58:25 -0600746 if (acceptTokenClass(EHTokReturn)) {
747 // expression
748 TIntermTyped* node;
749 if (acceptExpression(node)) {
750 // hook it up
John Kessenich078d7f22016-03-14 10:02:11 -0600751 statement = intermediate.addBranch(EOpReturn, node, token.loc);
John Kessenich5f934b02016-03-13 17:58:25 -0600752 } else
John Kessenich078d7f22016-03-14 10:02:11 -0600753 statement = intermediate.addBranch(EOpReturn, token.loc);
John Kessenich5f934b02016-03-13 17:58:25 -0600754
John Kessenich078d7f22016-03-14 10:02:11 -0600755 // SEMICOLON
John Kessenich5f934b02016-03-13 17:58:25 -0600756 if (! acceptTokenClass(EHTokSemicolon))
757 return false;
758
759 return true;
760 }
761
762 // expression
763 TIntermTyped* node;
764 if (acceptExpression(node))
765 statement = node;
766
John Kessenich078d7f22016-03-14 10:02:11 -0600767 // SEMICOLON
John Kessenich5f934b02016-03-13 17:58:25 -0600768 if (! acceptTokenClass(EHTokSemicolon))
769 return false;
770
771 return true;
John Kessenich87142c72016-03-12 20:24:24 -0700772}
773
John Kessenich078d7f22016-03-14 10:02:11 -0600774// COLON semantic
775bool HlslGrammar::acceptSemantic()
776{
777 // COLON
778 if (acceptTokenClass(EHTokColon)) {
779 // semantic
John Kessenichaecd4972016-03-14 10:46:34 -0600780 HlslToken idToken;
781 if (! acceptIdentifier(idToken)) {
John Kessenich078d7f22016-03-14 10:02:11 -0600782 expected("semantic");
783 return false;
784 }
785 }
786
787 return true;
788}
789
John Kesseniche01a9bc2016-03-12 20:11:22 -0700790} // end namespace glslang