blob: c3825f835648f402a1712a2153c65d51c5522a28 [file] [log] [blame]
John Kesseniche01a9bc2016-03-12 20:11:22 -07001//
2//Copyright (C) 2016 Google, Inc.
LoopDawg6daaa4f2016-06-23 19:13:48 -06003//Copyright (C) 2016 LunarG, Inc.
John Kesseniche01a9bc2016-03-12 20:11:22 -07004//
5//All rights reserved.
6//
7//Redistribution and use in source and binary forms, with or without
8//modification, are permitted provided that the following conditions
9//are met:
10//
11// Redistributions of source code must retain the above copyright
12// notice, this list of conditions and the following disclaimer.
13//
14// Redistributions in binary form must reproduce the above
15// copyright notice, this list of conditions and the following
16// disclaimer in the documentation and/or other materials provided
17// with the distribution.
18//
19// Neither the name of Google, Inc., nor the names of its
20// contributors may be used to endorse or promote products derived
21// from this software without specific prior written permission.
22//
23//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34//POSSIBILITY OF SUCH DAMAGE.
35//
36
John Kessenichd016be12016-03-13 11:24:20 -060037//
38// This is a set of mutually recursive methods implementing the HLSL grammar.
39// Generally, each returns
40// - through an argument: a type specifically appropriate to which rule it
41// recognized
42// - through the return value: true/false to indicate whether or not it
43// recognized its rule
44//
45// As much as possible, only grammar recognition should happen in this file,
John Kessenich078d7f22016-03-14 10:02:11 -060046// with all other work being farmed out to hlslParseHelper.cpp, which in turn
John Kessenichd016be12016-03-13 11:24:20 -060047// will build the AST.
48//
49// The next token, yet to be "accepted" is always sitting in 'token'.
50// When a method says it accepts a rule, that means all tokens involved
51// in the rule will have been consumed, and none left in 'token'.
52//
53
John Kesseniche01a9bc2016-03-12 20:11:22 -070054#include "hlslTokens.h"
55#include "hlslGrammar.h"
56
57namespace glslang {
58
59// Root entry point to this recursive decent parser.
60// Return true if compilation unit was successfully accepted.
61bool HlslGrammar::parse()
62{
63 advanceToken();
64 return acceptCompilationUnit();
65}
66
67void HlslGrammar::expected(const char* syntax)
68{
69 parseContext.error(token.loc, "Expected", syntax, "");
70}
71
LoopDawg4886f692016-06-29 10:58:58 -060072void HlslGrammar::unimplemented(const char* error)
73{
74 parseContext.error(token.loc, "Unimplemented", error, "");
75}
76
John Kessenichaecd4972016-03-14 10:46:34 -060077// Only process the next token if it is an identifier.
78// Return true if it was an identifier.
79bool HlslGrammar::acceptIdentifier(HlslToken& idToken)
80{
81 if (peekTokenClass(EHTokIdentifier)) {
82 idToken = token;
83 advanceToken();
84 return true;
85 }
86
87 return false;
88}
89
John Kesseniche01a9bc2016-03-12 20:11:22 -070090// compilationUnit
91// : list of externalDeclaration
92//
93bool HlslGrammar::acceptCompilationUnit()
94{
John Kessenichd016be12016-03-13 11:24:20 -060095 TIntermNode* unitNode = nullptr;
96
John Kessenich9c86c6a2016-05-03 22:49:24 -060097 while (! peekTokenClass(EHTokNone)) {
John Kessenichd016be12016-03-13 11:24:20 -060098 // externalDeclaration
99 TIntermNode* declarationNode;
100 if (! acceptDeclaration(declarationNode))
John Kesseniche01a9bc2016-03-12 20:11:22 -0700101 return false;
John Kessenichd016be12016-03-13 11:24:20 -0600102
103 // hook it up
John Kessenich078d7f22016-03-14 10:02:11 -0600104 unitNode = intermediate.growAggregate(unitNode, declarationNode);
John Kesseniche01a9bc2016-03-12 20:11:22 -0700105 }
106
John Kessenichd016be12016-03-13 11:24:20 -0600107 // set root of AST
John Kessenich078d7f22016-03-14 10:02:11 -0600108 intermediate.setTreeRoot(unitNode);
John Kessenichd016be12016-03-13 11:24:20 -0600109
John Kesseniche01a9bc2016-03-12 20:11:22 -0700110 return true;
111}
112
LoopDawg4886f692016-06-29 10:58:58 -0600113// sampler_state
114// : LEFT_BRACE [sampler_state_assignment ... ] RIGHT_BRACE
115//
116// sampler_state_assignment
117// : sampler_state_identifier EQUAL value SEMICOLON
118//
119// sampler_state_identifier
120// : ADDRESSU
121// | ADDRESSV
122// | ADDRESSW
123// | BORDERCOLOR
124// | FILTER
125// | MAXANISOTROPY
126// | MAXLOD
127// | MINLOD
128// | MIPLODBIAS
129//
130bool HlslGrammar::acceptSamplerState()
131{
132 // TODO: this should be genericized to accept a list of valid tokens and
133 // return token/value pairs. Presently it is specific to texture values.
134
135 if (! acceptTokenClass(EHTokLeftBrace))
136 return true;
137
138 parseContext.warn(token.loc, "unimplemented", "immediate sampler state", "");
139
140 do {
141 // read state name
142 HlslToken state;
143 if (! acceptIdentifier(state))
144 break; // end of list
145
146 // FXC accepts any case
147 TString stateName = *state.string;
148 std::transform(stateName.begin(), stateName.end(), stateName.begin(), ::tolower);
149
150 if (! acceptTokenClass(EHTokAssign)) {
151 expected("assign");
152 return false;
153 }
154
155 if (stateName == "minlod" || stateName == "maxlod") {
156 if (! peekTokenClass(EHTokIntConstant)) {
157 expected("integer");
158 return false;
159 }
160
161 TIntermTyped* lod = nullptr;
162 if (! acceptLiteral(lod)) // should never fail, since we just looked for an integer
163 return false;
164 } else if (stateName == "maxanisotropy") {
165 if (! peekTokenClass(EHTokIntConstant)) {
166 expected("integer");
167 return false;
168 }
169
170 TIntermTyped* maxAnisotropy = nullptr;
171 if (! acceptLiteral(maxAnisotropy)) // should never fail, since we just looked for an integer
172 return false;
173 } else if (stateName == "filter") {
174 HlslToken filterMode;
175 if (! acceptIdentifier(filterMode)) {
176 expected("filter mode");
177 return false;
178 }
179 } else if (stateName == "addressu" || stateName == "addressv" || stateName == "addressw") {
180 HlslToken addrMode;
181 if (! acceptIdentifier(addrMode)) {
182 expected("texture address mode");
183 return false;
184 }
185 } else if (stateName == "miplodbias") {
186 TIntermTyped* lodBias = nullptr;
187 if (! acceptLiteral(lodBias)) {
188 expected("lod bias");
189 return false;
190 }
191 } else if (stateName == "bordercolor") {
192 return false;
193 } else {
194 expected("texture state");
195 return false;
196 }
197
198 // SEMICOLON
199 if (! acceptTokenClass(EHTokSemicolon)) {
200 expected("semicolon");
201 return false;
202 }
203 } while (true);
204
205 if (! acceptTokenClass(EHTokRightBrace))
206 return false;
207
208 return true;
209}
210
211// sampler_declaration_dx9
212// : SAMPLER identifier EQUAL sampler_type sampler_state
213//
John Kesseniche4821e42016-07-16 10:19:43 -0600214bool HlslGrammar::acceptSamplerDeclarationDX9(TType& /*type*/)
LoopDawg4886f692016-06-29 10:58:58 -0600215{
216 if (! acceptTokenClass(EHTokSampler))
217 return false;
218
219 // TODO: remove this when DX9 style declarations are implemented.
220 unimplemented("Direct3D 9 sampler declaration");
221
222 // read sampler name
223 HlslToken name;
224 if (! acceptIdentifier(name)) {
225 expected("sampler name");
226 return false;
227 }
228
229 if (! acceptTokenClass(EHTokAssign)) {
230 expected("=");
231 return false;
232 }
233
234 return false;
235}
236
237
John Kesseniche01a9bc2016-03-12 20:11:22 -0700238// declaration
LoopDawg4886f692016-06-29 10:58:58 -0600239// : sampler_declaration_dx9 post_decls SEMICOLON
240// | fully_specified_type declarator_list SEMICOLON
John Kessenich630dd7d2016-06-12 23:52:12 -0600241// | fully_specified_type identifier function_parameters post_decls compound_statement // function definition
LoopDawg4886f692016-06-29 10:58:58 -0600242// | fully_specified_type identifier sampler_state post_decls compound_statement // sampler definition
John Kessenich5e69ec62016-07-05 00:02:40 -0600243// | typedef declaration
John Kessenich87142c72016-03-12 20:24:24 -0700244//
John Kessenichd5ed0b62016-07-04 17:32:45 -0600245// declarator_list
246// : declarator COMMA declarator COMMA declarator... // zero or more declarators
John Kessenich532543c2016-07-01 19:06:44 -0600247//
John Kessenichd5ed0b62016-07-04 17:32:45 -0600248// declarator
John Kessenich532543c2016-07-01 19:06:44 -0600249// : identifier array_specifier post_decls
250// | identifier array_specifier post_decls EQUAL assignment_expression
John Kessenichd5ed0b62016-07-04 17:32:45 -0600251// | identifier function_parameters post_decls // function prototype
John Kessenich532543c2016-07-01 19:06:44 -0600252//
John Kessenichd5ed0b62016-07-04 17:32:45 -0600253// Parsing has to go pretty far in to know whether it's a variable, prototype, or
254// function definition, so the implementation below doesn't perfectly divide up the grammar
John Kessenich532543c2016-07-01 19:06:44 -0600255// as above. (The 'identifier' in the first item in init_declarator list is the
256// same as 'identifier' for function declarations.)
257//
258// 'node' could get populated if the declaration creates code, like an initializer
John Kessenichd016be12016-03-13 11:24:20 -0600259// or a function body.
260//
261bool HlslGrammar::acceptDeclaration(TIntermNode*& node)
John Kesseniche01a9bc2016-03-12 20:11:22 -0700262{
John Kessenichd016be12016-03-13 11:24:20 -0600263 node = nullptr;
John Kessenichd5ed0b62016-07-04 17:32:45 -0600264 bool list = false;
John Kessenichd016be12016-03-13 11:24:20 -0600265
John Kessenich5e69ec62016-07-05 00:02:40 -0600266 // typedef
267 bool typedefDecl = acceptTokenClass(EHTokTypedef);
268
John Kessenich87142c72016-03-12 20:24:24 -0700269 TType type;
LoopDawg4886f692016-06-29 10:58:58 -0600270
271 // DX9 sampler declaration use a different syntax
272 if (acceptSamplerDeclarationDX9(type))
273 return true;
274
275 // fully_specified_type
John Kessenich87142c72016-03-12 20:24:24 -0700276 if (! acceptFullySpecifiedType(type))
277 return false;
LoopDawg4886f692016-06-29 10:58:58 -0600278
279 if (type.getQualifier().storage == EvqTemporary && parseContext.symbolTable.atGlobalLevel()) {
280 if (type.getBasicType() == EbtSampler) {
281 // Sampler/textures are uniform by default (if no explicit qualifier is present) in
282 // HLSL. This line silently converts samplers *explicitly* declared static to uniform,
283 // which is incorrect but harmless.
284 type.getQualifier().storage = EvqUniform;
285 } else {
286 type.getQualifier().storage = EvqGlobal;
287 }
288 }
John Kessenich87142c72016-03-12 20:24:24 -0700289
290 // identifier
John Kessenichaecd4972016-03-14 10:46:34 -0600291 HlslToken idToken;
John Kessenichd5ed0b62016-07-04 17:32:45 -0600292 while (acceptIdentifier(idToken)) {
John Kessenich5f934b02016-03-13 17:58:25 -0600293 // function_parameters
John Kessenichaecd4972016-03-14 10:46:34 -0600294 TFunction* function = new TFunction(idToken.string, type);
John Kessenich5f934b02016-03-13 17:58:25 -0600295 if (acceptFunctionParameters(*function)) {
John Kessenich630dd7d2016-06-12 23:52:12 -0600296 // post_decls
297 acceptPostDecls(type);
John Kessenich078d7f22016-03-14 10:02:11 -0600298
John Kessenichd5ed0b62016-07-04 17:32:45 -0600299 // compound_statement (function body definition) or just a prototype?
300 if (peekTokenClass(EHTokLeftBrace)) {
301 if (list)
302 parseContext.error(idToken.loc, "function body can't be in a declarator list", "{", "");
John Kessenich5e69ec62016-07-05 00:02:40 -0600303 if (typedefDecl)
304 parseContext.error(idToken.loc, "function body can't be in a typedef", "{", "");
John Kessenich5f934b02016-03-13 17:58:25 -0600305 return acceptFunctionDefinition(*function, node);
John Kessenich5e69ec62016-07-05 00:02:40 -0600306 } else {
307 if (typedefDecl)
308 parseContext.error(idToken.loc, "function typedefs not implemented", "{", "");
John Kessenichd5ed0b62016-07-04 17:32:45 -0600309 parseContext.handleFunctionDeclarator(idToken.loc, *function, true);
John Kessenich5e69ec62016-07-05 00:02:40 -0600310 }
John Kessenichd5ed0b62016-07-04 17:32:45 -0600311 } else {
312 // a variable declaration
John Kessenich5f934b02016-03-13 17:58:25 -0600313
John Kessenichd5ed0b62016-07-04 17:32:45 -0600314 // array_specifier
315 TArraySizes* arraySizes = nullptr;
316 acceptArraySpecifier(arraySizes);
John Kessenich5f934b02016-03-13 17:58:25 -0600317
LoopDawg4886f692016-06-29 10:58:58 -0600318 // samplers accept immediate sampler state
319 if (type.getBasicType() == EbtSampler) {
320 if (! acceptSamplerState())
321 return false;
322 }
323
John Kessenichd5ed0b62016-07-04 17:32:45 -0600324 // post_decls
325 acceptPostDecls(type);
326
327 // EQUAL assignment_expression
328 TIntermTyped* expressionNode = nullptr;
329 if (acceptTokenClass(EHTokAssign)) {
John Kessenich5e69ec62016-07-05 00:02:40 -0600330 if (typedefDecl)
331 parseContext.error(idToken.loc, "can't have an initializer", "typedef", "");
John Kessenichd5ed0b62016-07-04 17:32:45 -0600332 if (! acceptAssignmentExpression(expressionNode)) {
333 expected("initializer");
334 return false;
335 }
336 }
337
John Kessenich5e69ec62016-07-05 00:02:40 -0600338 if (typedefDecl)
339 parseContext.declareTypedef(idToken.loc, *idToken.string, type, arraySizes);
John Kessenich3d157c52016-07-25 16:05:33 -0600340 else if (type.getBasicType() == EbtBlock)
341 parseContext.declareBlock(idToken.loc, type, idToken.string);
John Kessenich5e69ec62016-07-05 00:02:40 -0600342 else {
343 // Declare the variable and add any initializer code to the AST.
344 // The top-level node is always made into an aggregate, as that's
345 // historically how the AST has been.
346 node = intermediate.growAggregate(node,
347 parseContext.declareVariable(idToken.loc, *idToken.string, type,
348 arraySizes, expressionNode),
349 idToken.loc);
350 }
John Kessenich5f934b02016-03-13 17:58:25 -0600351 }
John Kessenichd5ed0b62016-07-04 17:32:45 -0600352
353 if (acceptTokenClass(EHTokComma)) {
354 list = true;
355 continue;
356 }
357 };
358
359 // The top-level node is a sequence.
360 if (node != nullptr)
361 node->getAsAggregate()->setOperator(EOpSequence);
John Kessenich87142c72016-03-12 20:24:24 -0700362
John Kessenich078d7f22016-03-14 10:02:11 -0600363 // SEMICOLON
John Kessenichd5ed0b62016-07-04 17:32:45 -0600364 if (! acceptTokenClass(EHTokSemicolon)) {
365 expected(";");
366 return false;
367 }
368
John Kesseniche01a9bc2016-03-12 20:11:22 -0700369 return true;
370}
371
John Kessenich5bc4d9a2016-06-20 01:22:38 -0600372// control_declaration
373// : fully_specified_type identifier EQUAL expression
374//
375bool HlslGrammar::acceptControlDeclaration(TIntermNode*& node)
376{
377 node = nullptr;
378
379 // fully_specified_type
380 TType type;
381 if (! acceptFullySpecifiedType(type))
382 return false;
383
384 // identifier
385 HlslToken idToken;
386 if (! acceptIdentifier(idToken)) {
387 expected("identifier");
388 return false;
389 }
390
391 // EQUAL
392 TIntermTyped* expressionNode = nullptr;
393 if (! acceptTokenClass(EHTokAssign)) {
394 expected("=");
395 return false;
396 }
397
398 // expression
399 if (! acceptExpression(expressionNode)) {
400 expected("initializer");
401 return false;
402 }
403
404 node = parseContext.declareVariable(idToken.loc, *idToken.string, type, 0, expressionNode);
405
406 return true;
407}
408
John Kessenich87142c72016-03-12 20:24:24 -0700409// fully_specified_type
410// : type_specifier
411// | type_qualifier type_specifier
412//
413bool HlslGrammar::acceptFullySpecifiedType(TType& type)
414{
415 // type_qualifier
416 TQualifier qualifier;
417 qualifier.clear();
418 acceptQualifier(qualifier);
John Kessenich3d157c52016-07-25 16:05:33 -0600419 TSourceLoc loc = token.loc;
John Kessenich87142c72016-03-12 20:24:24 -0700420
421 // type_specifier
422 if (! acceptType(type))
423 return false;
John Kessenich3d157c52016-07-25 16:05:33 -0600424 if (type.getBasicType() == EbtBlock) {
425 // the type was a block, which set some parts of the qualifier
426 parseContext.mergeQualifiers(loc, type.getQualifier(), qualifier, true);
427 // further, it can create an anonymous instance of the block
428 if (peekTokenClass(EHTokSemicolon))
429 parseContext.declareBlock(loc, type);
430 } else
431 type.getQualifier() = qualifier;
John Kessenich87142c72016-03-12 20:24:24 -0700432
433 return true;
434}
435
John Kessenich630dd7d2016-06-12 23:52:12 -0600436// type_qualifier
437// : qualifier qualifier ...
438//
439// Zero or more of these, so this can't return false.
440//
John Kessenich87142c72016-03-12 20:24:24 -0700441void HlslGrammar::acceptQualifier(TQualifier& qualifier)
442{
John Kessenich630dd7d2016-06-12 23:52:12 -0600443 do {
444 switch (peek()) {
445 case EHTokStatic:
446 // normal glslang default
447 break;
448 case EHTokExtern:
449 // TODO: no meaning in glslang?
450 break;
451 case EHTokShared:
452 // TODO: hint
453 break;
454 case EHTokGroupShared:
455 qualifier.storage = EvqShared;
456 break;
457 case EHTokUniform:
458 qualifier.storage = EvqUniform;
459 break;
460 case EHTokConst:
461 qualifier.storage = EvqConst;
462 break;
463 case EHTokVolatile:
464 qualifier.volatil = true;
465 break;
466 case EHTokLinear:
467 qualifier.storage = EvqVaryingIn;
468 qualifier.smooth = true;
469 break;
470 case EHTokCentroid:
471 qualifier.centroid = true;
472 break;
473 case EHTokNointerpolation:
474 qualifier.flat = true;
475 break;
476 case EHTokNoperspective:
477 qualifier.nopersp = true;
478 break;
479 case EHTokSample:
480 qualifier.sample = true;
481 break;
482 case EHTokRowMajor:
483 qualifier.layoutMatrix = ElmRowMajor;
484 break;
485 case EHTokColumnMajor:
486 qualifier.layoutMatrix = ElmColumnMajor;
487 break;
488 case EHTokPrecise:
489 qualifier.noContraction = true;
490 break;
LoopDawg9249c702016-07-12 20:44:32 -0600491 case EHTokIn:
492 qualifier.storage = EvqIn;
493 break;
494 case EHTokOut:
495 qualifier.storage = EvqOut;
496 break;
497 case EHTokInOut:
498 qualifier.storage = EvqInOut;
499 break;
John Kessenich630dd7d2016-06-12 23:52:12 -0600500 default:
501 return;
502 }
503 advanceToken();
504 } while (true);
John Kessenich87142c72016-03-12 20:24:24 -0700505}
506
LoopDawg6daaa4f2016-06-23 19:13:48 -0600507// template_type
508// : FLOAT
509// | DOUBLE
510// | INT
511// | DWORD
512// | UINT
513// | BOOL
514//
515bool HlslGrammar::acceptTemplateType(TBasicType& basicType)
516{
517 switch (peek()) {
518 case EHTokFloat:
519 basicType = EbtFloat;
520 break;
521 case EHTokDouble:
522 basicType = EbtDouble;
523 break;
524 case EHTokInt:
525 case EHTokDword:
526 basicType = EbtInt;
527 break;
528 case EHTokUint:
529 basicType = EbtUint;
530 break;
531 case EHTokBool:
532 basicType = EbtBool;
533 break;
534 default:
535 return false;
536 }
537
538 advanceToken();
539
540 return true;
541}
542
543// vector_template_type
544// : VECTOR
545// | VECTOR LEFT_ANGLE template_type COMMA integer_literal RIGHT_ANGLE
546//
547bool HlslGrammar::acceptVectorTemplateType(TType& type)
548{
549 if (! acceptTokenClass(EHTokVector))
550 return false;
551
552 if (! acceptTokenClass(EHTokLeftAngle)) {
553 // in HLSL, 'vector' alone means float4.
554 new(&type) TType(EbtFloat, EvqTemporary, 4);
555 return true;
556 }
557
558 TBasicType basicType;
559 if (! acceptTemplateType(basicType)) {
560 expected("scalar type");
561 return false;
562 }
563
564 // COMMA
565 if (! acceptTokenClass(EHTokComma)) {
566 expected(",");
567 return false;
568 }
569
570 // integer
571 if (! peekTokenClass(EHTokIntConstant)) {
572 expected("literal integer");
573 return false;
574 }
575
576 TIntermTyped* vecSize;
577 if (! acceptLiteral(vecSize))
578 return false;
579
580 const int vecSizeI = vecSize->getAsConstantUnion()->getConstArray()[0].getIConst();
581
582 new(&type) TType(basicType, EvqTemporary, vecSizeI);
583
584 if (vecSizeI == 1)
585 type.makeVector();
586
587 if (!acceptTokenClass(EHTokRightAngle)) {
588 expected("right angle bracket");
589 return false;
590 }
591
592 return true;
593}
594
595// matrix_template_type
596// : MATRIX
597// | MATRIX LEFT_ANGLE template_type COMMA integer_literal COMMA integer_literal RIGHT_ANGLE
598//
599bool HlslGrammar::acceptMatrixTemplateType(TType& type)
600{
601 if (! acceptTokenClass(EHTokMatrix))
602 return false;
603
604 if (! acceptTokenClass(EHTokLeftAngle)) {
605 // in HLSL, 'matrix' alone means float4x4.
606 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 4);
607 return true;
608 }
609
610 TBasicType basicType;
611 if (! acceptTemplateType(basicType)) {
612 expected("scalar type");
613 return false;
614 }
615
616 // COMMA
617 if (! acceptTokenClass(EHTokComma)) {
618 expected(",");
619 return false;
620 }
621
622 // integer rows
623 if (! peekTokenClass(EHTokIntConstant)) {
624 expected("literal integer");
625 return false;
626 }
627
628 TIntermTyped* rows;
629 if (! acceptLiteral(rows))
630 return false;
631
632 // COMMA
633 if (! acceptTokenClass(EHTokComma)) {
634 expected(",");
635 return false;
636 }
637
638 // integer cols
639 if (! peekTokenClass(EHTokIntConstant)) {
640 expected("literal integer");
641 return false;
642 }
643
644 TIntermTyped* cols;
645 if (! acceptLiteral(cols))
646 return false;
647
648 new(&type) TType(basicType, EvqTemporary, 0,
649 cols->getAsConstantUnion()->getConstArray()[0].getIConst(),
650 rows->getAsConstantUnion()->getConstArray()[0].getIConst());
651
652 if (!acceptTokenClass(EHTokRightAngle)) {
653 expected("right angle bracket");
654 return false;
655 }
656
657 return true;
658}
659
660
LoopDawg4886f692016-06-29 10:58:58 -0600661// sampler_type
662// : SAMPLER
663// | SAMPLER1D
664// | SAMPLER2D
665// | SAMPLER3D
666// | SAMPLERCUBE
667// | SAMPLERSTATE
668// | SAMPLERCOMPARISONSTATE
669bool HlslGrammar::acceptSamplerType(TType& type)
670{
671 // read sampler type
672 const EHlslTokenClass samplerType = peek();
673
LoopDawga78b0292016-07-19 14:28:05 -0600674 // TODO: for DX9
LoopDawg5d58fae2016-07-15 11:22:24 -0600675 // TSamplerDim dim = EsdNone;
LoopDawg4886f692016-06-29 10:58:58 -0600676
LoopDawga78b0292016-07-19 14:28:05 -0600677 bool isShadow = false;
678
LoopDawg4886f692016-06-29 10:58:58 -0600679 switch (samplerType) {
680 case EHTokSampler: break;
LoopDawg5d58fae2016-07-15 11:22:24 -0600681 case EHTokSampler1d: /*dim = Esd1D*/; break;
682 case EHTokSampler2d: /*dim = Esd2D*/; break;
683 case EHTokSampler3d: /*dim = Esd3D*/; break;
684 case EHTokSamplerCube: /*dim = EsdCube*/; break;
LoopDawg4886f692016-06-29 10:58:58 -0600685 case EHTokSamplerState: break;
LoopDawga78b0292016-07-19 14:28:05 -0600686 case EHTokSamplerComparisonState: isShadow = true; break;
LoopDawg4886f692016-06-29 10:58:58 -0600687 default:
688 return false; // not a sampler declaration
689 }
690
691 advanceToken(); // consume the sampler type keyword
692
693 TArraySizes* arraySizes = nullptr; // TODO: array
LoopDawg4886f692016-06-29 10:58:58 -0600694
695 TSampler sampler;
LoopDawga78b0292016-07-19 14:28:05 -0600696 sampler.setPureSampler(isShadow);
LoopDawg4886f692016-06-29 10:58:58 -0600697
698 type.shallowCopy(TType(sampler, EvqUniform, arraySizes));
699
700 return true;
701}
702
703// texture_type
704// | BUFFER
705// | TEXTURE1D
706// | TEXTURE1DARRAY
707// | TEXTURE2D
708// | TEXTURE2DARRAY
709// | TEXTURE3D
710// | TEXTURECUBE
711// | TEXTURECUBEARRAY
712// | TEXTURE2DMS
713// | TEXTURE2DMSARRAY
714bool HlslGrammar::acceptTextureType(TType& type)
715{
716 const EHlslTokenClass textureType = peek();
717
718 TSamplerDim dim = EsdNone;
719 bool array = false;
720 bool ms = false;
721
722 switch (textureType) {
723 case EHTokBuffer: dim = EsdBuffer; break;
724 case EHTokTexture1d: dim = Esd1D; break;
725 case EHTokTexture1darray: dim = Esd1D; array = true; break;
726 case EHTokTexture2d: dim = Esd2D; break;
727 case EHTokTexture2darray: dim = Esd2D; array = true; break;
728 case EHTokTexture3d: dim = Esd3D; break;
729 case EHTokTextureCube: dim = EsdCube; break;
730 case EHTokTextureCubearray: dim = EsdCube; array = true; break;
731 case EHTokTexture2DMS: dim = Esd2D; ms = true; break;
732 case EHTokTexture2DMSarray: dim = Esd2D; array = true; ms = true; break;
733 default:
734 return false; // not a texture declaration
735 }
736
737 advanceToken(); // consume the texture object keyword
738
739 TType txType(EbtFloat, EvqUniform, 4); // default type is float4
740
741 TIntermTyped* msCount = nullptr;
742
743 // texture type: required for multisample types!
744 if (acceptTokenClass(EHTokLeftAngle)) {
745 if (! acceptType(txType)) {
746 expected("scalar or vector type");
747 return false;
748 }
749
750 const TBasicType basicRetType = txType.getBasicType() ;
751
752 if (basicRetType != EbtFloat && basicRetType != EbtUint && basicRetType != EbtInt) {
753 unimplemented("basic type in texture");
754 return false;
755 }
756
steve-lunargd53f7172016-07-27 15:46:48 -0600757 // Buffers can handle small mats if they fit in 4 components
758 if (dim == EsdBuffer && txType.isMatrix()) {
759 if ((txType.getMatrixCols() * txType.getMatrixRows()) > 4) {
760 expected("components < 4 in matrix buffer type");
761 return false;
762 }
763
764 // TODO: except we don't handle it yet...
765 unimplemented("matrix type in buffer");
766 return false;
767 }
768
LoopDawg4886f692016-06-29 10:58:58 -0600769 if (!txType.isScalar() && !txType.isVector()) {
770 expected("scalar or vector type");
771 return false;
772 }
773
774 if (txType.getVectorSize() != 1 && txType.getVectorSize() != 4) {
775 // TODO: handle vec2/3 types
776 expected("vector size not yet supported in texture type");
777 return false;
778 }
779
780 if (ms && acceptTokenClass(EHTokComma)) {
781 // read sample count for multisample types, if given
782 if (! peekTokenClass(EHTokIntConstant)) {
783 expected("multisample count");
784 return false;
785 }
786
787 if (! acceptLiteral(msCount)) // should never fail, since we just found an integer
788 return false;
789 }
790
791 if (! acceptTokenClass(EHTokRightAngle)) {
792 expected("right angle bracket");
793 return false;
794 }
795 } else if (ms) {
796 expected("texture type for multisample");
797 return false;
798 }
799
800 TArraySizes* arraySizes = nullptr;
801 const bool shadow = txType.isScalar() || (txType.isVector() && txType.getVectorSize() == 1);
802
803 TSampler sampler;
steve-lunargd53f7172016-07-27 15:46:48 -0600804
805 // Buffers are combined.
806 if (dim == EsdBuffer) {
807 sampler.set(txType.getBasicType(), dim, array);
808 } else {
809 // DX10 textures are separated. TODO: DX9.
810 sampler.setTexture(txType.getBasicType(), dim, array, shadow, ms);
811 }
LoopDawg4886f692016-06-29 10:58:58 -0600812
813 type.shallowCopy(TType(sampler, EvqUniform, arraySizes));
814
815 return true;
816}
817
818
John Kessenich87142c72016-03-12 20:24:24 -0700819// If token is for a type, update 'type' with the type information,
820// and return true and advance.
821// Otherwise, return false, and don't advance
822bool HlslGrammar::acceptType(TType& type)
823{
John Kessenich9c86c6a2016-05-03 22:49:24 -0600824 switch (peek()) {
LoopDawg6daaa4f2016-06-23 19:13:48 -0600825 case EHTokVector:
826 return acceptVectorTemplateType(type);
827 break;
828
829 case EHTokMatrix:
830 return acceptMatrixTemplateType(type);
831 break;
832
LoopDawg4886f692016-06-29 10:58:58 -0600833 case EHTokSampler: // fall through
834 case EHTokSampler1d: // ...
835 case EHTokSampler2d: // ...
836 case EHTokSampler3d: // ...
837 case EHTokSamplerCube: // ...
838 case EHTokSamplerState: // ...
839 case EHTokSamplerComparisonState: // ...
840 return acceptSamplerType(type);
841 break;
842
843 case EHTokBuffer: // fall through
844 case EHTokTexture1d: // ...
845 case EHTokTexture1darray: // ...
846 case EHTokTexture2d: // ...
847 case EHTokTexture2darray: // ...
848 case EHTokTexture3d: // ...
849 case EHTokTextureCube: // ...
850 case EHTokTextureCubearray: // ...
851 case EHTokTexture2DMS: // ...
852 case EHTokTexture2DMSarray: // ...
853 return acceptTextureType(type);
854 break;
855
John Kesseniche6e74942016-06-11 16:43:14 -0600856 case EHTokStruct:
John Kessenich3d157c52016-07-25 16:05:33 -0600857 case EHTokCBuffer:
858 case EHTokTBuffer:
John Kesseniche6e74942016-06-11 16:43:14 -0600859 return acceptStruct(type);
860 break;
861
862 case EHTokIdentifier:
863 // An identifier could be for a user-defined type.
864 // Note we cache the symbol table lookup, to save for a later rule
865 // when this is not a type.
866 token.symbol = parseContext.symbolTable.find(*token.string);
867 if (token.symbol && token.symbol->getAsVariable() && token.symbol->getAsVariable()->isUserType()) {
868 type.shallowCopy(token.symbol->getType());
869 advanceToken();
870 return true;
871 } else
872 return false;
873
John Kessenich71351de2016-06-08 12:50:56 -0600874 case EHTokVoid:
875 new(&type) TType(EbtVoid);
John Kessenich87142c72016-03-12 20:24:24 -0700876 break;
John Kessenich71351de2016-06-08 12:50:56 -0600877
John Kessenich87142c72016-03-12 20:24:24 -0700878 case EHTokFloat:
John Kessenich8d72f1a2016-05-20 12:06:03 -0600879 new(&type) TType(EbtFloat);
880 break;
John Kessenich87142c72016-03-12 20:24:24 -0700881 case EHTokFloat1:
882 new(&type) TType(EbtFloat);
John Kessenich8d72f1a2016-05-20 12:06:03 -0600883 type.makeVector();
John Kessenich87142c72016-03-12 20:24:24 -0700884 break;
John Kessenich87142c72016-03-12 20:24:24 -0700885 case EHTokFloat2:
886 new(&type) TType(EbtFloat, EvqTemporary, 2);
887 break;
888 case EHTokFloat3:
889 new(&type) TType(EbtFloat, EvqTemporary, 3);
890 break;
891 case EHTokFloat4:
892 new(&type) TType(EbtFloat, EvqTemporary, 4);
893 break;
894
John Kessenich71351de2016-06-08 12:50:56 -0600895 case EHTokDouble:
896 new(&type) TType(EbtDouble);
897 break;
898 case EHTokDouble1:
899 new(&type) TType(EbtDouble);
900 type.makeVector();
901 break;
902 case EHTokDouble2:
903 new(&type) TType(EbtDouble, EvqTemporary, 2);
904 break;
905 case EHTokDouble3:
906 new(&type) TType(EbtDouble, EvqTemporary, 3);
907 break;
908 case EHTokDouble4:
909 new(&type) TType(EbtDouble, EvqTemporary, 4);
910 break;
911
912 case EHTokInt:
913 case EHTokDword:
914 new(&type) TType(EbtInt);
915 break;
916 case EHTokInt1:
917 new(&type) TType(EbtInt);
918 type.makeVector();
919 break;
John Kessenich87142c72016-03-12 20:24:24 -0700920 case EHTokInt2:
921 new(&type) TType(EbtInt, EvqTemporary, 2);
922 break;
923 case EHTokInt3:
924 new(&type) TType(EbtInt, EvqTemporary, 3);
925 break;
926 case EHTokInt4:
927 new(&type) TType(EbtInt, EvqTemporary, 4);
928 break;
929
John Kessenich71351de2016-06-08 12:50:56 -0600930 case EHTokUint:
931 new(&type) TType(EbtUint);
932 break;
933 case EHTokUint1:
934 new(&type) TType(EbtUint);
935 type.makeVector();
936 break;
937 case EHTokUint2:
938 new(&type) TType(EbtUint, EvqTemporary, 2);
939 break;
940 case EHTokUint3:
941 new(&type) TType(EbtUint, EvqTemporary, 3);
942 break;
943 case EHTokUint4:
944 new(&type) TType(EbtUint, EvqTemporary, 4);
945 break;
946
LoopDawg6daaa4f2016-06-23 19:13:48 -0600947
John Kessenich71351de2016-06-08 12:50:56 -0600948 case EHTokBool:
949 new(&type) TType(EbtBool);
950 break;
951 case EHTokBool1:
952 new(&type) TType(EbtBool);
953 type.makeVector();
954 break;
John Kessenich87142c72016-03-12 20:24:24 -0700955 case EHTokBool2:
956 new(&type) TType(EbtBool, EvqTemporary, 2);
957 break;
958 case EHTokBool3:
959 new(&type) TType(EbtBool, EvqTemporary, 3);
960 break;
961 case EHTokBool4:
962 new(&type) TType(EbtBool, EvqTemporary, 4);
963 break;
964
John Kessenich0133c122016-05-20 12:17:26 -0600965 case EHTokInt1x1:
966 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 1);
967 break;
968 case EHTokInt1x2:
969 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 1);
970 break;
971 case EHTokInt1x3:
972 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 1);
973 break;
974 case EHTokInt1x4:
975 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 1);
976 break;
977 case EHTokInt2x1:
978 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 2);
979 break;
980 case EHTokInt2x2:
981 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 2);
982 break;
983 case EHTokInt2x3:
984 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 2);
985 break;
986 case EHTokInt2x4:
987 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 2);
988 break;
989 case EHTokInt3x1:
990 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 3);
991 break;
992 case EHTokInt3x2:
993 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 3);
994 break;
995 case EHTokInt3x3:
996 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 3);
997 break;
998 case EHTokInt3x4:
999 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 3);
1000 break;
1001 case EHTokInt4x1:
1002 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 4);
1003 break;
1004 case EHTokInt4x2:
1005 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 4);
1006 break;
1007 case EHTokInt4x3:
1008 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 4);
1009 break;
1010 case EHTokInt4x4:
1011 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 4);
1012 break;
1013
John Kessenich71351de2016-06-08 12:50:56 -06001014 case EHTokUint1x1:
1015 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 1);
1016 break;
1017 case EHTokUint1x2:
1018 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 1);
1019 break;
1020 case EHTokUint1x3:
1021 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 1);
1022 break;
1023 case EHTokUint1x4:
1024 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 1);
1025 break;
1026 case EHTokUint2x1:
1027 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 2);
1028 break;
1029 case EHTokUint2x2:
1030 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 2);
1031 break;
1032 case EHTokUint2x3:
1033 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 2);
1034 break;
1035 case EHTokUint2x4:
1036 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 2);
1037 break;
1038 case EHTokUint3x1:
1039 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 3);
1040 break;
1041 case EHTokUint3x2:
1042 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 3);
1043 break;
1044 case EHTokUint3x3:
1045 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 3);
1046 break;
1047 case EHTokUint3x4:
1048 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 3);
1049 break;
1050 case EHTokUint4x1:
1051 new(&type) TType(EbtUint, EvqTemporary, 0, 1, 4);
1052 break;
1053 case EHTokUint4x2:
1054 new(&type) TType(EbtUint, EvqTemporary, 0, 2, 4);
1055 break;
1056 case EHTokUint4x3:
1057 new(&type) TType(EbtUint, EvqTemporary, 0, 3, 4);
1058 break;
1059 case EHTokUint4x4:
1060 new(&type) TType(EbtUint, EvqTemporary, 0, 4, 4);
1061 break;
1062
1063 case EHTokBool1x1:
1064 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 1);
1065 break;
1066 case EHTokBool1x2:
1067 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 1);
1068 break;
1069 case EHTokBool1x3:
1070 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 1);
1071 break;
1072 case EHTokBool1x4:
1073 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 1);
1074 break;
1075 case EHTokBool2x1:
1076 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 2);
1077 break;
1078 case EHTokBool2x2:
1079 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 2);
1080 break;
1081 case EHTokBool2x3:
1082 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 2);
1083 break;
1084 case EHTokBool2x4:
1085 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 2);
1086 break;
1087 case EHTokBool3x1:
1088 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 3);
1089 break;
1090 case EHTokBool3x2:
1091 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 3);
1092 break;
1093 case EHTokBool3x3:
1094 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 3);
1095 break;
1096 case EHTokBool3x4:
1097 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 3);
1098 break;
1099 case EHTokBool4x1:
1100 new(&type) TType(EbtBool, EvqTemporary, 0, 1, 4);
1101 break;
1102 case EHTokBool4x2:
1103 new(&type) TType(EbtBool, EvqTemporary, 0, 2, 4);
1104 break;
1105 case EHTokBool4x3:
1106 new(&type) TType(EbtBool, EvqTemporary, 0, 3, 4);
1107 break;
1108 case EHTokBool4x4:
1109 new(&type) TType(EbtBool, EvqTemporary, 0, 4, 4);
1110 break;
1111
John Kessenich0133c122016-05-20 12:17:26 -06001112 case EHTokFloat1x1:
1113 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 1);
1114 break;
1115 case EHTokFloat1x2:
1116 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 1);
1117 break;
1118 case EHTokFloat1x3:
1119 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 1);
1120 break;
1121 case EHTokFloat1x4:
1122 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 1);
1123 break;
1124 case EHTokFloat2x1:
1125 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 2);
1126 break;
John Kessenich87142c72016-03-12 20:24:24 -07001127 case EHTokFloat2x2:
1128 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 2);
1129 break;
1130 case EHTokFloat2x3:
1131 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 2);
1132 break;
1133 case EHTokFloat2x4:
1134 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 2);
1135 break;
John Kessenich0133c122016-05-20 12:17:26 -06001136 case EHTokFloat3x1:
1137 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 3);
1138 break;
John Kessenich87142c72016-03-12 20:24:24 -07001139 case EHTokFloat3x2:
1140 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 3);
1141 break;
1142 case EHTokFloat3x3:
1143 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 3);
1144 break;
1145 case EHTokFloat3x4:
1146 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 3);
1147 break;
John Kessenich0133c122016-05-20 12:17:26 -06001148 case EHTokFloat4x1:
1149 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 4);
1150 break;
John Kessenich87142c72016-03-12 20:24:24 -07001151 case EHTokFloat4x2:
1152 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 4);
1153 break;
1154 case EHTokFloat4x3:
1155 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 4);
1156 break;
1157 case EHTokFloat4x4:
1158 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 4);
1159 break;
1160
John Kessenich0133c122016-05-20 12:17:26 -06001161 case EHTokDouble1x1:
1162 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 1);
1163 break;
1164 case EHTokDouble1x2:
1165 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 1);
1166 break;
1167 case EHTokDouble1x3:
1168 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 1);
1169 break;
1170 case EHTokDouble1x4:
1171 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 1);
1172 break;
1173 case EHTokDouble2x1:
1174 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 2);
1175 break;
1176 case EHTokDouble2x2:
1177 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 2);
1178 break;
1179 case EHTokDouble2x3:
1180 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 2);
1181 break;
1182 case EHTokDouble2x4:
1183 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 2);
1184 break;
1185 case EHTokDouble3x1:
1186 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 3);
1187 break;
1188 case EHTokDouble3x2:
1189 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 3);
1190 break;
1191 case EHTokDouble3x3:
1192 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 3);
1193 break;
1194 case EHTokDouble3x4:
1195 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 3);
1196 break;
1197 case EHTokDouble4x1:
1198 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 4);
1199 break;
1200 case EHTokDouble4x2:
1201 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 4);
1202 break;
1203 case EHTokDouble4x3:
1204 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 4);
1205 break;
1206 case EHTokDouble4x4:
1207 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 4);
1208 break;
1209
John Kessenich87142c72016-03-12 20:24:24 -07001210 default:
1211 return false;
1212 }
1213
1214 advanceToken();
1215
1216 return true;
1217}
1218
John Kesseniche6e74942016-06-11 16:43:14 -06001219// struct
John Kessenich3d157c52016-07-25 16:05:33 -06001220// : struct_type IDENTIFIER post_decls LEFT_BRACE struct_declaration_list RIGHT_BRACE
1221// | struct_type post_decls LEFT_BRACE struct_declaration_list RIGHT_BRACE
1222//
1223// struct_type
1224// : STRUCT
1225// | CBUFFER
1226// | TBUFFER
John Kesseniche6e74942016-06-11 16:43:14 -06001227//
1228bool HlslGrammar::acceptStruct(TType& type)
1229{
John Kessenich3d157c52016-07-25 16:05:33 -06001230 // This qualifier.storage will tell us whether it's an AST block or
1231 // just a struct.
1232 TQualifier qualifier;
1233 qualifier.clear();
1234
1235 // CBUFFER
1236 if (acceptTokenClass(EHTokCBuffer))
1237 qualifier.storage = EvqUniform;
1238 // TBUFFER
1239 else if (acceptTokenClass(EHTokTBuffer))
1240 qualifier.storage = EvqBuffer;
John Kesseniche6e74942016-06-11 16:43:14 -06001241 // STRUCT
John Kessenich3d157c52016-07-25 16:05:33 -06001242 else if (! acceptTokenClass(EHTokStruct))
John Kesseniche6e74942016-06-11 16:43:14 -06001243 return false;
1244
1245 // IDENTIFIER
1246 TString structName = "";
1247 if (peekTokenClass(EHTokIdentifier)) {
1248 structName = *token.string;
1249 advanceToken();
1250 }
1251
John Kessenich3d157c52016-07-25 16:05:33 -06001252 // post_decls
1253 acceptPostDecls(type);
1254
John Kesseniche6e74942016-06-11 16:43:14 -06001255 // LEFT_BRACE
1256 if (! acceptTokenClass(EHTokLeftBrace)) {
1257 expected("{");
1258 return false;
1259 }
1260
1261 // struct_declaration_list
1262 TTypeList* typeList;
1263 if (! acceptStructDeclarationList(typeList)) {
1264 expected("struct member declarations");
1265 return false;
1266 }
1267
1268 // RIGHT_BRACE
1269 if (! acceptTokenClass(EHTokRightBrace)) {
1270 expected("}");
1271 return false;
1272 }
1273
1274 // create the user-defined type
John Kessenich3d157c52016-07-25 16:05:33 -06001275 if (qualifier.storage == EvqTemporary)
1276 new(&type) TType(typeList, structName);
1277 else
1278 new(&type) TType(typeList, structName, qualifier); // sets EbtBlock
John Kesseniche6e74942016-06-11 16:43:14 -06001279
John Kessenich3d157c52016-07-25 16:05:33 -06001280 // If it was named, which means the type can be reused later, add
1281 // it to the symbol table. (Unless it's a block, in which
1282 // case the name is not a type.)
1283 if (type.getBasicType() != EbtBlock && structName.size() > 0) {
John Kesseniche6e74942016-06-11 16:43:14 -06001284 TVariable* userTypeDef = new TVariable(&structName, type, true);
1285 if (! parseContext.symbolTable.insert(*userTypeDef))
1286 parseContext.error(token.loc, "redefinition", structName.c_str(), "struct");
1287 }
1288
1289 return true;
1290}
1291
1292// struct_declaration_list
1293// : struct_declaration SEMI_COLON struct_declaration SEMI_COLON ...
1294//
1295// struct_declaration
1296// : fully_specified_type struct_declarator COMMA struct_declarator ...
1297//
1298// struct_declarator
John Kessenich630dd7d2016-06-12 23:52:12 -06001299// : IDENTIFIER post_decls
1300// | IDENTIFIER array_specifier post_decls
John Kesseniche6e74942016-06-11 16:43:14 -06001301//
1302bool HlslGrammar::acceptStructDeclarationList(TTypeList*& typeList)
1303{
1304 typeList = new TTypeList();
1305
1306 do {
1307 // success on seeing the RIGHT_BRACE coming up
1308 if (peekTokenClass(EHTokRightBrace))
1309 return true;
1310
1311 // struct_declaration
1312
1313 // fully_specified_type
1314 TType memberType;
1315 if (! acceptFullySpecifiedType(memberType)) {
1316 expected("member type");
1317 return false;
1318 }
1319
1320 // struct_declarator COMMA struct_declarator ...
1321 do {
1322 // peek IDENTIFIER
1323 if (! peekTokenClass(EHTokIdentifier)) {
1324 expected("member name");
1325 return false;
1326 }
1327
1328 // add it to the list of members
1329 TTypeLoc member = { new TType(EbtVoid), token.loc };
1330 member.type->shallowCopy(memberType);
1331 member.type->setFieldName(*token.string);
1332 typeList->push_back(member);
1333
1334 // accept IDENTIFIER
1335 advanceToken();
1336
1337 // array_specifier
John Kessenich19b92ff2016-06-19 11:50:34 -06001338 TArraySizes* arraySizes = nullptr;
1339 acceptArraySpecifier(arraySizes);
1340 if (arraySizes)
1341 typeList->back().type->newArraySizes(*arraySizes);
John Kesseniche6e74942016-06-11 16:43:14 -06001342
John Kessenich630dd7d2016-06-12 23:52:12 -06001343 acceptPostDecls(*member.type);
1344
John Kesseniche6e74942016-06-11 16:43:14 -06001345 // success on seeing the SEMICOLON coming up
1346 if (peekTokenClass(EHTokSemicolon))
1347 break;
1348
1349 // COMMA
1350 if (! acceptTokenClass(EHTokComma)) {
1351 expected(",");
1352 return false;
1353 }
1354
1355 } while (true);
1356
1357 // SEMI_COLON
1358 if (! acceptTokenClass(EHTokSemicolon)) {
1359 expected(";");
1360 return false;
1361 }
1362
1363 } while (true);
1364}
1365
John Kessenich5f934b02016-03-13 17:58:25 -06001366// function_parameters
John Kessenich078d7f22016-03-14 10:02:11 -06001367// : LEFT_PAREN parameter_declaration COMMA parameter_declaration ... RIGHT_PAREN
John Kessenich71351de2016-06-08 12:50:56 -06001368// | LEFT_PAREN VOID RIGHT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -06001369//
1370bool HlslGrammar::acceptFunctionParameters(TFunction& function)
1371{
John Kessenich078d7f22016-03-14 10:02:11 -06001372 // LEFT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -06001373 if (! acceptTokenClass(EHTokLeftParen))
1374 return false;
1375
John Kessenich71351de2016-06-08 12:50:56 -06001376 // VOID RIGHT_PAREN
1377 if (! acceptTokenClass(EHTokVoid)) {
1378 do {
1379 // parameter_declaration
1380 if (! acceptParameterDeclaration(function))
1381 break;
John Kessenich5f934b02016-03-13 17:58:25 -06001382
John Kessenich71351de2016-06-08 12:50:56 -06001383 // COMMA
1384 if (! acceptTokenClass(EHTokComma))
1385 break;
1386 } while (true);
1387 }
John Kessenich5f934b02016-03-13 17:58:25 -06001388
John Kessenich078d7f22016-03-14 10:02:11 -06001389 // RIGHT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -06001390 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06001391 expected(")");
John Kessenich5f934b02016-03-13 17:58:25 -06001392 return false;
1393 }
1394
1395 return true;
1396}
1397
1398// parameter_declaration
John Kessenichc3387d32016-06-17 14:21:02 -06001399// : fully_specified_type post_decls
John Kessenich19b92ff2016-06-19 11:50:34 -06001400// | fully_specified_type identifier array_specifier post_decls
John Kessenich5f934b02016-03-13 17:58:25 -06001401//
1402bool HlslGrammar::acceptParameterDeclaration(TFunction& function)
1403{
1404 // fully_specified_type
1405 TType* type = new TType;
1406 if (! acceptFullySpecifiedType(*type))
1407 return false;
1408
1409 // identifier
John Kessenichaecd4972016-03-14 10:46:34 -06001410 HlslToken idToken;
1411 acceptIdentifier(idToken);
John Kessenich5f934b02016-03-13 17:58:25 -06001412
John Kessenich19b92ff2016-06-19 11:50:34 -06001413 // array_specifier
1414 TArraySizes* arraySizes = nullptr;
1415 acceptArraySpecifier(arraySizes);
1416 if (arraySizes)
1417 type->newArraySizes(*arraySizes);
1418
1419 // post_decls
John Kessenichc3387d32016-06-17 14:21:02 -06001420 acceptPostDecls(*type);
1421
John Kessenich5aa59e22016-06-17 15:50:47 -06001422 parseContext.paramFix(*type);
1423
John Kessenichaecd4972016-03-14 10:46:34 -06001424 TParameter param = { idToken.string, type };
John Kessenich5f934b02016-03-13 17:58:25 -06001425 function.addParameter(param);
1426
1427 return true;
1428}
1429
1430// Do the work to create the function definition in addition to
1431// parsing the body (compound_statement).
1432bool HlslGrammar::acceptFunctionDefinition(TFunction& function, TIntermNode*& node)
1433{
1434 TFunction* functionDeclarator = parseContext.handleFunctionDeclarator(token.loc, function, false /* not prototype */);
1435
John Kessenich077e0522016-06-09 02:02:17 -06001436 // This does a pushScope()
John Kessenich5f934b02016-03-13 17:58:25 -06001437 node = parseContext.handleFunctionDefinition(token.loc, *functionDeclarator);
1438
1439 // compound_statement
John Kessenich21472ae2016-06-04 11:46:33 -06001440 TIntermNode* functionBody = nullptr;
John Kessenich5f934b02016-03-13 17:58:25 -06001441 if (acceptCompoundStatement(functionBody)) {
John Kessenich078d7f22016-03-14 10:02:11 -06001442 node = intermediate.growAggregate(node, functionBody);
1443 intermediate.setAggregateOperator(node, EOpFunction, functionDeclarator->getType(), token.loc);
John Kessenich5f934b02016-03-13 17:58:25 -06001444 node->getAsAggregate()->setName(functionDeclarator->getMangledName().c_str());
John Kessenich077e0522016-06-09 02:02:17 -06001445 parseContext.popScope();
John Kessenich5f934b02016-03-13 17:58:25 -06001446
1447 return true;
1448 }
1449
1450 return false;
1451}
1452
John Kessenich0d2b6de2016-06-05 11:23:11 -06001453// Accept an expression with parenthesis around it, where
1454// the parenthesis ARE NOT expression parenthesis, but the
John Kessenich5bc4d9a2016-06-20 01:22:38 -06001455// syntactically required ones like in "if ( expression )".
1456//
1457// Also accepts a declaration expression; "if (int a = expression)".
John Kessenich0d2b6de2016-06-05 11:23:11 -06001458//
1459// Note this one is not set up to be speculative; as it gives
1460// errors if not found.
1461//
1462bool HlslGrammar::acceptParenExpression(TIntermTyped*& expression)
1463{
1464 // LEFT_PAREN
1465 if (! acceptTokenClass(EHTokLeftParen))
1466 expected("(");
1467
John Kessenich5bc4d9a2016-06-20 01:22:38 -06001468 bool decl = false;
1469 TIntermNode* declNode = nullptr;
1470 decl = acceptControlDeclaration(declNode);
1471 if (decl) {
1472 if (declNode == nullptr || declNode->getAsTyped() == nullptr) {
1473 expected("initialized declaration");
1474 return false;
1475 } else
1476 expression = declNode->getAsTyped();
1477 } else {
1478 // no declaration
1479 if (! acceptExpression(expression)) {
1480 expected("expression");
1481 return false;
1482 }
John Kessenich0d2b6de2016-06-05 11:23:11 -06001483 }
1484
1485 // RIGHT_PAREN
1486 if (! acceptTokenClass(EHTokRightParen))
1487 expected(")");
1488
1489 return true;
1490}
1491
John Kessenich34fb0362016-05-03 23:17:20 -06001492// The top-level full expression recognizer.
1493//
John Kessenich87142c72016-03-12 20:24:24 -07001494// expression
John Kessenich34fb0362016-05-03 23:17:20 -06001495// : assignment_expression COMMA assignment_expression COMMA assignment_expression ...
John Kessenich87142c72016-03-12 20:24:24 -07001496//
1497bool HlslGrammar::acceptExpression(TIntermTyped*& node)
1498{
LoopDawgef764a22016-06-03 09:17:51 -06001499 node = nullptr;
1500
John Kessenich34fb0362016-05-03 23:17:20 -06001501 // assignment_expression
1502 if (! acceptAssignmentExpression(node))
1503 return false;
John Kessenich5f934b02016-03-13 17:58:25 -06001504
John Kessenich34fb0362016-05-03 23:17:20 -06001505 if (! peekTokenClass(EHTokComma))
1506 return true;
1507
1508 do {
1509 // ... COMMA
John Kessenich5f934b02016-03-13 17:58:25 -06001510 TSourceLoc loc = token.loc;
John Kessenich34fb0362016-05-03 23:17:20 -06001511 advanceToken();
John Kessenich5f934b02016-03-13 17:58:25 -06001512
John Kessenich34fb0362016-05-03 23:17:20 -06001513 // ... assignment_expression
1514 TIntermTyped* rightNode = nullptr;
1515 if (! acceptAssignmentExpression(rightNode)) {
1516 expected("assignment expression");
1517 return false;
John Kessenich5f934b02016-03-13 17:58:25 -06001518 }
1519
John Kessenich34fb0362016-05-03 23:17:20 -06001520 node = intermediate.addComma(node, rightNode, loc);
1521
1522 if (! peekTokenClass(EHTokComma))
1523 return true;
1524 } while (true);
1525}
1526
John Kessenich07354242016-07-01 19:58:06 -06001527// initializer
1528// : LEFT_BRACE initializer_list RIGHT_BRACE
1529//
1530// initializer_list
1531// : assignment_expression COMMA assignment_expression COMMA ...
1532//
1533bool HlslGrammar::acceptInitializer(TIntermTyped*& node)
1534{
1535 // LEFT_BRACE
1536 if (! acceptTokenClass(EHTokLeftBrace))
1537 return false;
1538
1539 // initializer_list
1540 TSourceLoc loc = token.loc;
1541 node = nullptr;
1542 do {
1543 // assignment_expression
1544 TIntermTyped* expr;
1545 if (! acceptAssignmentExpression(expr)) {
1546 expected("assignment expression in initializer list");
1547 return false;
1548 }
1549 node = intermediate.growAggregate(node, expr, loc);
1550
1551 // COMMA
1552 if (acceptTokenClass(EHTokComma))
1553 continue;
1554
1555 // RIGHT_BRACE
1556 if (acceptTokenClass(EHTokRightBrace))
1557 return true;
1558
1559 expected(", or }");
1560 return false;
1561 } while (true);
1562}
1563
John Kessenich34fb0362016-05-03 23:17:20 -06001564// Accept an assignment expression, where assignment operations
John Kessenich07354242016-07-01 19:58:06 -06001565// associate right-to-left. That is, it is implicit, for example
John Kessenich34fb0362016-05-03 23:17:20 -06001566//
1567// a op (b op (c op d))
1568//
1569// assigment_expression
John Kessenich00957f82016-07-27 10:39:57 -06001570// : initializer
1571// | conditional_expression
1572// | conditional_expression assign_op conditional_expression assign_op conditional_expression ...
John Kessenich34fb0362016-05-03 23:17:20 -06001573//
1574bool HlslGrammar::acceptAssignmentExpression(TIntermTyped*& node)
1575{
John Kessenich07354242016-07-01 19:58:06 -06001576 // initializer
1577 if (peekTokenClass(EHTokLeftBrace)) {
1578 if (acceptInitializer(node))
1579 return true;
1580
1581 expected("initializer");
1582 return false;
1583 }
1584
John Kessenich00957f82016-07-27 10:39:57 -06001585 // conditional_expression
1586 if (! acceptConditionalExpression(node))
John Kessenich34fb0362016-05-03 23:17:20 -06001587 return false;
1588
John Kessenich07354242016-07-01 19:58:06 -06001589 // assignment operation?
John Kessenich34fb0362016-05-03 23:17:20 -06001590 TOperator assignOp = HlslOpMap::assignment(peek());
1591 if (assignOp == EOpNull)
1592 return true;
1593
John Kessenich00957f82016-07-27 10:39:57 -06001594 // assign_op
John Kessenich34fb0362016-05-03 23:17:20 -06001595 TSourceLoc loc = token.loc;
1596 advanceToken();
1597
John Kessenich00957f82016-07-27 10:39:57 -06001598 // conditional_expression assign_op conditional_expression ...
1599 // Done by recursing this function, which automatically
John Kessenich34fb0362016-05-03 23:17:20 -06001600 // gets the right-to-left associativity.
1601 TIntermTyped* rightNode = nullptr;
1602 if (! acceptAssignmentExpression(rightNode)) {
1603 expected("assignment expression");
John Kessenich5f934b02016-03-13 17:58:25 -06001604 return false;
John Kessenich87142c72016-03-12 20:24:24 -07001605 }
1606
John Kessenich34fb0362016-05-03 23:17:20 -06001607 node = intermediate.addAssign(assignOp, node, rightNode, loc);
John Kessenichfea226b2016-07-28 17:53:56 -06001608 if (node == nullptr) {
1609 parseContext.error(loc, "could not create assignment", "", "");
1610 return false;
1611 }
John Kessenich34fb0362016-05-03 23:17:20 -06001612
1613 if (! peekTokenClass(EHTokComma))
1614 return true;
1615
1616 return true;
1617}
1618
John Kessenich00957f82016-07-27 10:39:57 -06001619// Accept a conditional expression, which associates right-to-left,
1620// accomplished by the "true" expression calling down to lower
1621// precedence levels than this level.
1622//
1623// conditional_expression
1624// : binary_expression
1625// | binary_expression QUESTION expression COLON assignment_expression
1626//
1627bool HlslGrammar::acceptConditionalExpression(TIntermTyped*& node)
1628{
1629 // binary_expression
1630 if (! acceptBinaryExpression(node, PlLogicalOr))
1631 return false;
1632
1633 if (! acceptTokenClass(EHTokQuestion))
1634 return true;
1635
1636 TIntermTyped* trueNode = nullptr;
1637 if (! acceptExpression(trueNode)) {
1638 expected("expression after ?");
1639 return false;
1640 }
1641 TSourceLoc loc = token.loc;
1642
1643 if (! acceptTokenClass(EHTokColon)) {
1644 expected(":");
1645 return false;
1646 }
1647
1648 TIntermTyped* falseNode = nullptr;
1649 if (! acceptAssignmentExpression(falseNode)) {
1650 expected("expression after :");
1651 return false;
1652 }
1653
1654 node = intermediate.addSelection(node, trueNode, falseNode, loc);
1655
1656 return true;
1657}
1658
John Kessenich34fb0362016-05-03 23:17:20 -06001659// Accept a binary expression, for binary operations that
1660// associate left-to-right. This is, it is implicit, for example
1661//
1662// ((a op b) op c) op d
1663//
1664// binary_expression
1665// : expression op expression op expression ...
1666//
1667// where 'expression' is the next higher level in precedence.
1668//
1669bool HlslGrammar::acceptBinaryExpression(TIntermTyped*& node, PrecedenceLevel precedenceLevel)
1670{
1671 if (precedenceLevel > PlMul)
1672 return acceptUnaryExpression(node);
1673
1674 // assignment_expression
1675 if (! acceptBinaryExpression(node, (PrecedenceLevel)(precedenceLevel + 1)))
1676 return false;
1677
John Kessenich34fb0362016-05-03 23:17:20 -06001678 do {
John Kessenich64076ed2016-07-28 21:43:17 -06001679 TOperator op = HlslOpMap::binary(peek());
1680 PrecedenceLevel tokenLevel = HlslOpMap::precedenceLevel(op);
1681 if (tokenLevel < precedenceLevel)
1682 return true;
1683
John Kessenich34fb0362016-05-03 23:17:20 -06001684 // ... op
1685 TSourceLoc loc = token.loc;
1686 advanceToken();
1687
1688 // ... expression
1689 TIntermTyped* rightNode = nullptr;
1690 if (! acceptBinaryExpression(rightNode, (PrecedenceLevel)(precedenceLevel + 1))) {
1691 expected("expression");
1692 return false;
1693 }
1694
1695 node = intermediate.addBinaryMath(op, node, rightNode, loc);
John Kessenichfea226b2016-07-28 17:53:56 -06001696 if (node == nullptr) {
1697 parseContext.error(loc, "Could not perform requested binary operation", "", "");
1698 return false;
1699 }
John Kessenich34fb0362016-05-03 23:17:20 -06001700 } while (true);
1701}
1702
1703// unary_expression
John Kessenich1cc1a282016-06-03 16:55:49 -06001704// : (type) unary_expression
1705// | + unary_expression
John Kessenich34fb0362016-05-03 23:17:20 -06001706// | - unary_expression
1707// | ! unary_expression
1708// | ~ unary_expression
1709// | ++ unary_expression
1710// | -- unary_expression
1711// | postfix_expression
1712//
1713bool HlslGrammar::acceptUnaryExpression(TIntermTyped*& node)
1714{
John Kessenich1cc1a282016-06-03 16:55:49 -06001715 // (type) unary_expression
1716 // Have to look two steps ahead, because this could be, e.g., a
1717 // postfix_expression instead, since that also starts with at "(".
1718 if (acceptTokenClass(EHTokLeftParen)) {
1719 TType castType;
1720 if (acceptType(castType)) {
1721 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06001722 expected(")");
John Kessenich1cc1a282016-06-03 16:55:49 -06001723 return false;
1724 }
1725
1726 // We've matched "(type)" now, get the expression to cast
1727 TSourceLoc loc = token.loc;
1728 if (! acceptUnaryExpression(node))
1729 return false;
1730
1731 // Hook it up like a constructor
1732 TFunction* constructorFunction = parseContext.handleConstructorCall(loc, castType);
1733 if (constructorFunction == nullptr) {
1734 expected("type that can be constructed");
1735 return false;
1736 }
1737 TIntermTyped* arguments = nullptr;
1738 parseContext.handleFunctionArgument(constructorFunction, arguments, node);
1739 node = parseContext.handleFunctionCall(loc, constructorFunction, arguments);
1740
1741 return true;
1742 } else {
1743 // This isn't a type cast, but it still started "(", so if it is a
1744 // unary expression, it can only be a postfix_expression, so try that.
1745 // Back it up first.
1746 recedeToken();
1747 return acceptPostfixExpression(node);
1748 }
1749 }
1750
1751 // peek for "op unary_expression"
John Kessenich34fb0362016-05-03 23:17:20 -06001752 TOperator unaryOp = HlslOpMap::preUnary(peek());
1753
John Kessenich1cc1a282016-06-03 16:55:49 -06001754 // postfix_expression (if no unary operator)
John Kessenich34fb0362016-05-03 23:17:20 -06001755 if (unaryOp == EOpNull)
1756 return acceptPostfixExpression(node);
1757
1758 // op unary_expression
1759 TSourceLoc loc = token.loc;
1760 advanceToken();
1761 if (! acceptUnaryExpression(node))
1762 return false;
1763
1764 // + is a no-op
1765 if (unaryOp == EOpAdd)
1766 return true;
1767
1768 node = intermediate.addUnaryMath(unaryOp, node, loc);
1769
1770 return node != nullptr;
1771}
1772
1773// postfix_expression
1774// : LEFT_PAREN expression RIGHT_PAREN
1775// | literal
1776// | constructor
1777// | identifier
1778// | function_call
1779// | postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET
1780// | postfix_expression DOT IDENTIFIER
1781// | postfix_expression INC_OP
1782// | postfix_expression DEC_OP
1783//
1784bool HlslGrammar::acceptPostfixExpression(TIntermTyped*& node)
1785{
1786 // Not implemented as self-recursive:
1787 // The logical "right recursion" is done with an loop at the end
1788
1789 // idToken will pick up either a variable or a function name in a function call
1790 HlslToken idToken;
1791
John Kessenich21472ae2016-06-04 11:46:33 -06001792 // Find something before the postfix operations, as they can't operate
1793 // on nothing. So, no "return true", they fall through, only "return false".
John Kessenich87142c72016-03-12 20:24:24 -07001794 if (acceptTokenClass(EHTokLeftParen)) {
John Kessenich21472ae2016-06-04 11:46:33 -06001795 // LEFT_PAREN expression RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07001796 if (! acceptExpression(node)) {
1797 expected("expression");
1798 return false;
1799 }
1800 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06001801 expected(")");
John Kessenich87142c72016-03-12 20:24:24 -07001802 return false;
1803 }
John Kessenich34fb0362016-05-03 23:17:20 -06001804 } else if (acceptLiteral(node)) {
1805 // literal (nothing else to do yet), go on to the
1806 } else if (acceptConstructor(node)) {
1807 // constructor (nothing else to do yet)
1808 } else if (acceptIdentifier(idToken)) {
1809 // identifier or function_call name
1810 if (! peekTokenClass(EHTokLeftParen)) {
John Kesseniche6e74942016-06-11 16:43:14 -06001811 node = parseContext.handleVariable(idToken.loc, idToken.symbol, token.string);
John Kessenich34fb0362016-05-03 23:17:20 -06001812 } else if (acceptFunctionCall(idToken, node)) {
1813 // function_call (nothing else to do yet)
1814 } else {
1815 expected("function call arguments");
1816 return false;
1817 }
John Kessenich21472ae2016-06-04 11:46:33 -06001818 } else {
1819 // nothing found, can't post operate
1820 return false;
John Kessenich87142c72016-03-12 20:24:24 -07001821 }
1822
John Kessenich21472ae2016-06-04 11:46:33 -06001823 // Something was found, chain as many postfix operations as exist.
John Kessenich34fb0362016-05-03 23:17:20 -06001824 do {
1825 TSourceLoc loc = token.loc;
1826 TOperator postOp = HlslOpMap::postUnary(peek());
John Kessenich87142c72016-03-12 20:24:24 -07001827
John Kessenich34fb0362016-05-03 23:17:20 -06001828 // Consume only a valid post-unary operator, otherwise we are done.
1829 switch (postOp) {
1830 case EOpIndexDirectStruct:
1831 case EOpIndexIndirect:
1832 case EOpPostIncrement:
1833 case EOpPostDecrement:
1834 advanceToken();
1835 break;
1836 default:
1837 return true;
1838 }
John Kessenich87142c72016-03-12 20:24:24 -07001839
John Kessenich34fb0362016-05-03 23:17:20 -06001840 // We have a valid post-unary operator, process it.
1841 switch (postOp) {
1842 case EOpIndexDirectStruct:
John Kessenich93a162a2016-06-17 17:16:27 -06001843 {
John Kessenich19b92ff2016-06-19 11:50:34 -06001844 // DOT IDENTIFIER
1845 // includes swizzles and struct members
John Kessenich93a162a2016-06-17 17:16:27 -06001846 HlslToken field;
1847 if (! acceptIdentifier(field)) {
1848 expected("swizzle or member");
1849 return false;
1850 }
LoopDawg4886f692016-06-29 10:58:58 -06001851
1852 TIntermTyped* base = node; // preserve for method function calls
John Kessenich93a162a2016-06-17 17:16:27 -06001853 node = parseContext.handleDotDereference(field.loc, node, *field.string);
LoopDawg4886f692016-06-29 10:58:58 -06001854
1855 // In the event of a method node, we look for an open paren and accept the function call.
1856 if (node->getAsMethodNode() != nullptr && peekTokenClass(EHTokLeftParen)) {
1857 if (! acceptFunctionCall(field, node, base)) {
1858 expected("function parameters");
1859 return false;
1860 }
1861 }
1862
John Kessenich34fb0362016-05-03 23:17:20 -06001863 break;
John Kessenich93a162a2016-06-17 17:16:27 -06001864 }
John Kessenich34fb0362016-05-03 23:17:20 -06001865 case EOpIndexIndirect:
1866 {
John Kessenich19b92ff2016-06-19 11:50:34 -06001867 // LEFT_BRACKET integer_expression RIGHT_BRACKET
John Kessenich34fb0362016-05-03 23:17:20 -06001868 TIntermTyped* indexNode = nullptr;
1869 if (! acceptExpression(indexNode) ||
1870 ! peekTokenClass(EHTokRightBracket)) {
1871 expected("expression followed by ']'");
1872 return false;
1873 }
John Kessenich19b92ff2016-06-19 11:50:34 -06001874 advanceToken();
1875 node = parseContext.handleBracketDereference(indexNode->getLoc(), node, indexNode);
1876 break;
John Kessenich34fb0362016-05-03 23:17:20 -06001877 }
1878 case EOpPostIncrement:
John Kessenich19b92ff2016-06-19 11:50:34 -06001879 // INC_OP
1880 // fall through
John Kessenich34fb0362016-05-03 23:17:20 -06001881 case EOpPostDecrement:
John Kessenich19b92ff2016-06-19 11:50:34 -06001882 // DEC_OP
John Kessenich34fb0362016-05-03 23:17:20 -06001883 node = intermediate.addUnaryMath(postOp, node, loc);
1884 break;
1885 default:
1886 assert(0);
1887 break;
1888 }
1889 } while (true);
John Kessenich87142c72016-03-12 20:24:24 -07001890}
1891
John Kessenichd016be12016-03-13 11:24:20 -06001892// constructor
John Kessenich078d7f22016-03-14 10:02:11 -06001893// : type argument_list
John Kessenichd016be12016-03-13 11:24:20 -06001894//
1895bool HlslGrammar::acceptConstructor(TIntermTyped*& node)
1896{
1897 // type
1898 TType type;
1899 if (acceptType(type)) {
1900 TFunction* constructorFunction = parseContext.handleConstructorCall(token.loc, type);
1901 if (constructorFunction == nullptr)
1902 return false;
1903
1904 // arguments
John Kessenich4678ca92016-05-13 09:33:42 -06001905 TIntermTyped* arguments = nullptr;
John Kessenichd016be12016-03-13 11:24:20 -06001906 if (! acceptArguments(constructorFunction, arguments)) {
1907 expected("constructor arguments");
1908 return false;
1909 }
1910
1911 // hook it up
1912 node = parseContext.handleFunctionCall(arguments->getLoc(), constructorFunction, arguments);
1913
1914 return true;
1915 }
1916
1917 return false;
1918}
1919
John Kessenich34fb0362016-05-03 23:17:20 -06001920// The function_call identifier was already recognized, and passed in as idToken.
1921//
1922// function_call
1923// : [idToken] arguments
1924//
LoopDawg4886f692016-06-29 10:58:58 -06001925bool HlslGrammar::acceptFunctionCall(HlslToken idToken, TIntermTyped*& node, TIntermTyped* base)
John Kessenich34fb0362016-05-03 23:17:20 -06001926{
John Kessenich4678ca92016-05-13 09:33:42 -06001927 // arguments
1928 TFunction* function = new TFunction(idToken.string, TType(EbtVoid));
1929 TIntermTyped* arguments = nullptr;
LoopDawg4886f692016-06-29 10:58:58 -06001930
1931 // methods have an implicit first argument of the calling object.
1932 if (base != nullptr)
1933 parseContext.handleFunctionArgument(function, arguments, base);
1934
John Kessenich4678ca92016-05-13 09:33:42 -06001935 if (! acceptArguments(function, arguments))
1936 return false;
1937
1938 node = parseContext.handleFunctionCall(idToken.loc, function, arguments);
1939
1940 return true;
John Kessenich34fb0362016-05-03 23:17:20 -06001941}
1942
John Kessenich87142c72016-03-12 20:24:24 -07001943// arguments
John Kessenich078d7f22016-03-14 10:02:11 -06001944// : LEFT_PAREN expression COMMA expression COMMA ... RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07001945//
John Kessenichd016be12016-03-13 11:24:20 -06001946// The arguments are pushed onto the 'function' argument list and
1947// onto the 'arguments' aggregate.
1948//
John Kessenich4678ca92016-05-13 09:33:42 -06001949bool HlslGrammar::acceptArguments(TFunction* function, TIntermTyped*& arguments)
John Kessenich87142c72016-03-12 20:24:24 -07001950{
John Kessenich078d7f22016-03-14 10:02:11 -06001951 // LEFT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07001952 if (! acceptTokenClass(EHTokLeftParen))
1953 return false;
1954
1955 do {
John Kessenichd016be12016-03-13 11:24:20 -06001956 // expression
John Kessenich87142c72016-03-12 20:24:24 -07001957 TIntermTyped* arg;
John Kessenich4678ca92016-05-13 09:33:42 -06001958 if (! acceptAssignmentExpression(arg))
John Kessenich87142c72016-03-12 20:24:24 -07001959 break;
John Kessenichd016be12016-03-13 11:24:20 -06001960
1961 // hook it up
1962 parseContext.handleFunctionArgument(function, arguments, arg);
1963
John Kessenich078d7f22016-03-14 10:02:11 -06001964 // COMMA
John Kessenich87142c72016-03-12 20:24:24 -07001965 if (! acceptTokenClass(EHTokComma))
1966 break;
1967 } while (true);
1968
John Kessenich078d7f22016-03-14 10:02:11 -06001969 // RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -07001970 if (! acceptTokenClass(EHTokRightParen)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06001971 expected(")");
John Kessenich87142c72016-03-12 20:24:24 -07001972 return false;
1973 }
1974
1975 return true;
1976}
1977
1978bool HlslGrammar::acceptLiteral(TIntermTyped*& node)
1979{
1980 switch (token.tokenClass) {
1981 case EHTokIntConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06001982 node = intermediate.addConstantUnion(token.i, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07001983 break;
steve-lunarg2de32912016-07-28 14:49:48 -06001984 case EHTokUintConstant:
1985 node = intermediate.addConstantUnion(token.u, token.loc, true);
1986 break;
John Kessenich87142c72016-03-12 20:24:24 -07001987 case EHTokFloatConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06001988 node = intermediate.addConstantUnion(token.d, EbtFloat, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07001989 break;
1990 case EHTokDoubleConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06001991 node = intermediate.addConstantUnion(token.d, EbtDouble, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07001992 break;
1993 case EHTokBoolConstant:
John Kessenich078d7f22016-03-14 10:02:11 -06001994 node = intermediate.addConstantUnion(token.b, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -07001995 break;
1996
1997 default:
1998 return false;
1999 }
2000
2001 advanceToken();
2002
2003 return true;
2004}
2005
John Kessenich5f934b02016-03-13 17:58:25 -06002006// compound_statement
John Kessenich34fb0362016-05-03 23:17:20 -06002007// : LEFT_CURLY statement statement ... RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06002008//
John Kessenich21472ae2016-06-04 11:46:33 -06002009bool HlslGrammar::acceptCompoundStatement(TIntermNode*& retStatement)
John Kessenich87142c72016-03-12 20:24:24 -07002010{
John Kessenich21472ae2016-06-04 11:46:33 -06002011 TIntermAggregate* compoundStatement = nullptr;
2012
John Kessenich34fb0362016-05-03 23:17:20 -06002013 // LEFT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06002014 if (! acceptTokenClass(EHTokLeftBrace))
2015 return false;
2016
2017 // statement statement ...
2018 TIntermNode* statement = nullptr;
2019 while (acceptStatement(statement)) {
John Kessenichd02dc5d2016-07-01 00:04:11 -06002020 TIntermBranch* branch = statement ? statement->getAsBranchNode() : nullptr;
2021 if (branch != nullptr && (branch->getFlowOp() == EOpCase ||
2022 branch->getFlowOp() == EOpDefault)) {
2023 // hook up individual subsequences within a switch statement
2024 parseContext.wrapupSwitchSubsequence(compoundStatement, statement);
2025 compoundStatement = nullptr;
2026 } else {
2027 // hook it up to the growing compound statement
2028 compoundStatement = intermediate.growAggregate(compoundStatement, statement);
2029 }
John Kessenich5f934b02016-03-13 17:58:25 -06002030 }
John Kessenich34fb0362016-05-03 23:17:20 -06002031 if (compoundStatement)
2032 compoundStatement->setOperator(EOpSequence);
John Kessenich5f934b02016-03-13 17:58:25 -06002033
John Kessenich21472ae2016-06-04 11:46:33 -06002034 retStatement = compoundStatement;
2035
John Kessenich34fb0362016-05-03 23:17:20 -06002036 // RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -06002037 return acceptTokenClass(EHTokRightBrace);
2038}
2039
John Kessenich0d2b6de2016-06-05 11:23:11 -06002040bool HlslGrammar::acceptScopedStatement(TIntermNode*& statement)
2041{
2042 parseContext.pushScope();
John Kessenich077e0522016-06-09 02:02:17 -06002043 bool result = acceptStatement(statement);
John Kessenich0d2b6de2016-06-05 11:23:11 -06002044 parseContext.popScope();
2045
2046 return result;
2047}
2048
John Kessenich077e0522016-06-09 02:02:17 -06002049bool HlslGrammar::acceptScopedCompoundStatement(TIntermNode*& statement)
John Kessenich0d2b6de2016-06-05 11:23:11 -06002050{
John Kessenich077e0522016-06-09 02:02:17 -06002051 parseContext.pushScope();
2052 bool result = acceptCompoundStatement(statement);
2053 parseContext.popScope();
John Kessenich0d2b6de2016-06-05 11:23:11 -06002054
2055 return result;
2056}
2057
John Kessenich5f934b02016-03-13 17:58:25 -06002058// statement
John Kessenich21472ae2016-06-04 11:46:33 -06002059// : attributes attributed_statement
2060//
2061// attributed_statement
John Kessenich5f934b02016-03-13 17:58:25 -06002062// : compound_statement
John Kessenich21472ae2016-06-04 11:46:33 -06002063// | SEMICOLON
John Kessenich078d7f22016-03-14 10:02:11 -06002064// | expression SEMICOLON
John Kessenich21472ae2016-06-04 11:46:33 -06002065// | declaration_statement
2066// | selection_statement
2067// | switch_statement
2068// | case_label
2069// | iteration_statement
2070// | jump_statement
John Kessenich5f934b02016-03-13 17:58:25 -06002071//
2072bool HlslGrammar::acceptStatement(TIntermNode*& statement)
2073{
John Kessenich21472ae2016-06-04 11:46:33 -06002074 statement = nullptr;
John Kessenich5f934b02016-03-13 17:58:25 -06002075
John Kessenich21472ae2016-06-04 11:46:33 -06002076 // attributes
2077 acceptAttributes();
John Kessenich5f934b02016-03-13 17:58:25 -06002078
John Kessenich21472ae2016-06-04 11:46:33 -06002079 // attributed_statement
2080 switch (peek()) {
2081 case EHTokLeftBrace:
John Kessenich077e0522016-06-09 02:02:17 -06002082 return acceptScopedCompoundStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06002083
John Kessenich21472ae2016-06-04 11:46:33 -06002084 case EHTokIf:
2085 return acceptSelectionStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06002086
John Kessenich21472ae2016-06-04 11:46:33 -06002087 case EHTokSwitch:
2088 return acceptSwitchStatement(statement);
John Kessenich5f934b02016-03-13 17:58:25 -06002089
John Kessenich21472ae2016-06-04 11:46:33 -06002090 case EHTokFor:
2091 case EHTokDo:
2092 case EHTokWhile:
2093 return acceptIterationStatement(statement);
2094
2095 case EHTokContinue:
2096 case EHTokBreak:
2097 case EHTokDiscard:
2098 case EHTokReturn:
2099 return acceptJumpStatement(statement);
2100
2101 case EHTokCase:
2102 return acceptCaseLabel(statement);
John Kessenichd02dc5d2016-07-01 00:04:11 -06002103 case EHTokDefault:
2104 return acceptDefaultLabel(statement);
John Kessenich21472ae2016-06-04 11:46:33 -06002105
2106 case EHTokSemicolon:
2107 return acceptTokenClass(EHTokSemicolon);
2108
2109 case EHTokRightBrace:
2110 // Performance: not strictly necessary, but stops a bunch of hunting early,
2111 // and is how sequences of statements end.
John Kessenich5f934b02016-03-13 17:58:25 -06002112 return false;
2113
John Kessenich21472ae2016-06-04 11:46:33 -06002114 default:
2115 {
2116 // declaration
2117 if (acceptDeclaration(statement))
2118 return true;
2119
2120 // expression
2121 TIntermTyped* node;
2122 if (acceptExpression(node))
2123 statement = node;
2124 else
2125 return false;
2126
2127 // SEMICOLON (following an expression)
2128 if (! acceptTokenClass(EHTokSemicolon)) {
John Kessenich0d2b6de2016-06-05 11:23:11 -06002129 expected(";");
John Kessenich21472ae2016-06-04 11:46:33 -06002130 return false;
2131 }
2132 }
2133 }
2134
John Kessenich5f934b02016-03-13 17:58:25 -06002135 return true;
John Kessenich87142c72016-03-12 20:24:24 -07002136}
2137
John Kessenich21472ae2016-06-04 11:46:33 -06002138// attributes
2139// : list of zero or more of: LEFT_BRACKET attribute RIGHT_BRACKET
2140//
2141// attribute:
2142// : UNROLL
2143// | UNROLL LEFT_PAREN literal RIGHT_PAREN
2144// | FASTOPT
2145// | ALLOW_UAV_CONDITION
2146// | BRANCH
2147// | FLATTEN
2148// | FORCECASE
2149// | CALL
2150//
2151void HlslGrammar::acceptAttributes()
2152{
John Kessenich0d2b6de2016-06-05 11:23:11 -06002153 // For now, accept the [ XXX(X) ] syntax, but drop.
2154 // TODO: subset to correct set? Pass on?
2155 do {
2156 // LEFT_BRACKET?
2157 if (! acceptTokenClass(EHTokLeftBracket))
2158 return;
2159
2160 // attribute
2161 if (peekTokenClass(EHTokIdentifier)) {
2162 // 'token.string' is the attribute
2163 advanceToken();
2164 } else if (! peekTokenClass(EHTokRightBracket)) {
2165 expected("identifier");
2166 advanceToken();
2167 }
2168
2169 // (x)
2170 if (acceptTokenClass(EHTokLeftParen)) {
2171 TIntermTyped* node;
2172 if (! acceptLiteral(node))
2173 expected("literal");
2174 // 'node' has the literal in it
2175 if (! acceptTokenClass(EHTokRightParen))
2176 expected(")");
2177 }
2178
2179 // RIGHT_BRACKET
2180 if (acceptTokenClass(EHTokRightBracket))
2181 continue;
2182
2183 expected("]");
2184 return;
2185
2186 } while (true);
John Kessenich21472ae2016-06-04 11:46:33 -06002187}
2188
John Kessenich0d2b6de2016-06-05 11:23:11 -06002189// selection_statement
2190// : IF LEFT_PAREN expression RIGHT_PAREN statement
2191// : IF LEFT_PAREN expression RIGHT_PAREN statement ELSE statement
2192//
John Kessenich21472ae2016-06-04 11:46:33 -06002193bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement)
2194{
John Kessenich0d2b6de2016-06-05 11:23:11 -06002195 TSourceLoc loc = token.loc;
2196
2197 // IF
2198 if (! acceptTokenClass(EHTokIf))
2199 return false;
2200
2201 // so that something declared in the condition is scoped to the lifetimes
2202 // of the then-else statements
2203 parseContext.pushScope();
2204
2205 // LEFT_PAREN expression RIGHT_PAREN
2206 TIntermTyped* condition;
2207 if (! acceptParenExpression(condition))
2208 return false;
2209
2210 // create the child statements
2211 TIntermNodePair thenElse = { nullptr, nullptr };
2212
2213 // then statement
2214 if (! acceptScopedStatement(thenElse.node1)) {
2215 expected("then statement");
2216 return false;
2217 }
2218
2219 // ELSE
2220 if (acceptTokenClass(EHTokElse)) {
2221 // else statement
2222 if (! acceptScopedStatement(thenElse.node2)) {
2223 expected("else statement");
2224 return false;
2225 }
2226 }
2227
2228 // Put the pieces together
2229 statement = intermediate.addSelection(condition, thenElse, loc);
2230 parseContext.popScope();
2231
2232 return true;
John Kessenich21472ae2016-06-04 11:46:33 -06002233}
2234
John Kessenichd02dc5d2016-07-01 00:04:11 -06002235// switch_statement
2236// : SWITCH LEFT_PAREN expression RIGHT_PAREN compound_statement
2237//
John Kessenich21472ae2016-06-04 11:46:33 -06002238bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement)
2239{
John Kessenichd02dc5d2016-07-01 00:04:11 -06002240 // SWITCH
2241 TSourceLoc loc = token.loc;
2242 if (! acceptTokenClass(EHTokSwitch))
2243 return false;
2244
2245 // LEFT_PAREN expression RIGHT_PAREN
2246 parseContext.pushScope();
2247 TIntermTyped* switchExpression;
2248 if (! acceptParenExpression(switchExpression)) {
2249 parseContext.popScope();
2250 return false;
2251 }
2252
2253 // compound_statement
2254 parseContext.pushSwitchSequence(new TIntermSequence);
2255 bool statementOkay = acceptCompoundStatement(statement);
2256 if (statementOkay)
2257 statement = parseContext.addSwitch(loc, switchExpression, statement ? statement->getAsAggregate() : nullptr);
2258
2259 parseContext.popSwitchSequence();
2260 parseContext.popScope();
2261
2262 return statementOkay;
John Kessenich21472ae2016-06-04 11:46:33 -06002263}
2264
John Kessenich119f8f62016-06-05 15:44:07 -06002265// iteration_statement
2266// : WHILE LEFT_PAREN condition RIGHT_PAREN statement
2267// | DO LEFT_BRACE statement RIGHT_BRACE WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON
2268// | FOR LEFT_PAREN for_init_statement for_rest_statement RIGHT_PAREN statement
2269//
2270// Non-speculative, only call if it needs to be found; WHILE or DO or FOR already seen.
John Kessenich21472ae2016-06-04 11:46:33 -06002271bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement)
2272{
John Kessenich119f8f62016-06-05 15:44:07 -06002273 TSourceLoc loc = token.loc;
2274 TIntermTyped* condition = nullptr;
2275
2276 EHlslTokenClass loop = peek();
2277 assert(loop == EHTokDo || loop == EHTokFor || loop == EHTokWhile);
2278
2279 // WHILE or DO or FOR
2280 advanceToken();
2281
2282 switch (loop) {
2283 case EHTokWhile:
2284 // so that something declared in the condition is scoped to the lifetime
2285 // of the while sub-statement
2286 parseContext.pushScope();
2287 parseContext.nestLooping();
2288
2289 // LEFT_PAREN condition RIGHT_PAREN
2290 if (! acceptParenExpression(condition))
2291 return false;
2292
2293 // statement
2294 if (! acceptScopedStatement(statement)) {
2295 expected("while sub-statement");
2296 return false;
2297 }
2298
2299 parseContext.unnestLooping();
2300 parseContext.popScope();
2301
2302 statement = intermediate.addLoop(statement, condition, nullptr, true, loc);
2303
2304 return true;
2305
2306 case EHTokDo:
2307 parseContext.nestLooping();
2308
2309 if (! acceptTokenClass(EHTokLeftBrace))
2310 expected("{");
2311
2312 // statement
2313 if (! peekTokenClass(EHTokRightBrace) && ! acceptScopedStatement(statement)) {
2314 expected("do sub-statement");
2315 return false;
2316 }
2317
2318 if (! acceptTokenClass(EHTokRightBrace))
2319 expected("}");
2320
2321 // WHILE
2322 if (! acceptTokenClass(EHTokWhile)) {
2323 expected("while");
2324 return false;
2325 }
2326
2327 // LEFT_PAREN condition RIGHT_PAREN
2328 TIntermTyped* condition;
2329 if (! acceptParenExpression(condition))
2330 return false;
2331
2332 if (! acceptTokenClass(EHTokSemicolon))
2333 expected(";");
2334
2335 parseContext.unnestLooping();
2336
2337 statement = intermediate.addLoop(statement, condition, 0, false, loc);
2338
2339 return true;
2340
2341 case EHTokFor:
2342 {
2343 // LEFT_PAREN
2344 if (! acceptTokenClass(EHTokLeftParen))
2345 expected("(");
2346
2347 // so that something declared in the condition is scoped to the lifetime
2348 // of the for sub-statement
2349 parseContext.pushScope();
2350
John Kessenich5bc4d9a2016-06-20 01:22:38 -06002351 // initializer
2352 TIntermNode* initNode = nullptr;
2353 if (! acceptControlDeclaration(initNode)) {
2354 TIntermTyped* initExpr = nullptr;
2355 acceptExpression(initExpr);
2356 initNode = initExpr;
2357 }
2358 // SEMI_COLON
John Kessenich119f8f62016-06-05 15:44:07 -06002359 if (! acceptTokenClass(EHTokSemicolon))
2360 expected(";");
2361
2362 parseContext.nestLooping();
2363
2364 // condition SEMI_COLON
2365 acceptExpression(condition);
2366 if (! acceptTokenClass(EHTokSemicolon))
2367 expected(";");
2368
2369 // iterator SEMI_COLON
2370 TIntermTyped* iterator = nullptr;
2371 acceptExpression(iterator);
2372 if (! acceptTokenClass(EHTokRightParen))
2373 expected(")");
2374
2375 // statement
2376 if (! acceptScopedStatement(statement)) {
2377 expected("for sub-statement");
2378 return false;
2379 }
2380
John Kessenich5bc4d9a2016-06-20 01:22:38 -06002381 statement = intermediate.addForLoop(statement, initNode, condition, iterator, true, loc);
John Kessenich119f8f62016-06-05 15:44:07 -06002382
2383 parseContext.popScope();
2384 parseContext.unnestLooping();
2385
2386 return true;
2387 }
2388
2389 default:
2390 return false;
2391 }
John Kessenich21472ae2016-06-04 11:46:33 -06002392}
2393
2394// jump_statement
2395// : CONTINUE SEMICOLON
2396// | BREAK SEMICOLON
2397// | DISCARD SEMICOLON
2398// | RETURN SEMICOLON
2399// | RETURN expression SEMICOLON
2400//
2401bool HlslGrammar::acceptJumpStatement(TIntermNode*& statement)
2402{
John Kessenich5bc4d9a2016-06-20 01:22:38 -06002403 EHlslTokenClass jump = peek();
2404 switch (jump) {
John Kessenich21472ae2016-06-04 11:46:33 -06002405 case EHTokContinue:
2406 case EHTokBreak:
2407 case EHTokDiscard:
John Kessenich21472ae2016-06-04 11:46:33 -06002408 case EHTokReturn:
John Kessenich5bc4d9a2016-06-20 01:22:38 -06002409 advanceToken();
2410 break;
John Kessenich21472ae2016-06-04 11:46:33 -06002411 default:
John Kessenich5bc4d9a2016-06-20 01:22:38 -06002412 // not something we handle in this function
John Kessenich21472ae2016-06-04 11:46:33 -06002413 return false;
2414 }
John Kessenich21472ae2016-06-04 11:46:33 -06002415
John Kessenich5bc4d9a2016-06-20 01:22:38 -06002416 switch (jump) {
2417 case EHTokContinue:
2418 statement = intermediate.addBranch(EOpContinue, token.loc);
2419 break;
2420 case EHTokBreak:
2421 statement = intermediate.addBranch(EOpBreak, token.loc);
2422 break;
2423 case EHTokDiscard:
2424 statement = intermediate.addBranch(EOpKill, token.loc);
2425 break;
2426
2427 case EHTokReturn:
2428 {
2429 // expression
2430 TIntermTyped* node;
2431 if (acceptExpression(node)) {
2432 // hook it up
2433 statement = intermediate.addBranch(EOpReturn, node, token.loc);
2434 } else
2435 statement = intermediate.addBranch(EOpReturn, token.loc);
2436 break;
2437 }
2438
2439 default:
2440 assert(0);
2441 return false;
2442 }
2443
2444 // SEMICOLON
2445 if (! acceptTokenClass(EHTokSemicolon))
2446 expected(";");
2447
2448 return true;
2449}
John Kessenich21472ae2016-06-04 11:46:33 -06002450
John Kessenichd02dc5d2016-07-01 00:04:11 -06002451// case_label
2452// : CASE expression COLON
2453//
John Kessenich21472ae2016-06-04 11:46:33 -06002454bool HlslGrammar::acceptCaseLabel(TIntermNode*& statement)
2455{
John Kessenichd02dc5d2016-07-01 00:04:11 -06002456 TSourceLoc loc = token.loc;
2457 if (! acceptTokenClass(EHTokCase))
2458 return false;
2459
2460 TIntermTyped* expression;
2461 if (! acceptExpression(expression)) {
2462 expected("case expression");
2463 return false;
2464 }
2465
2466 if (! acceptTokenClass(EHTokColon)) {
2467 expected(":");
2468 return false;
2469 }
2470
2471 statement = parseContext.intermediate.addBranch(EOpCase, expression, loc);
2472
2473 return true;
2474}
2475
2476// default_label
2477// : DEFAULT COLON
2478//
2479bool HlslGrammar::acceptDefaultLabel(TIntermNode*& statement)
2480{
2481 TSourceLoc loc = token.loc;
2482 if (! acceptTokenClass(EHTokDefault))
2483 return false;
2484
2485 if (! acceptTokenClass(EHTokColon)) {
2486 expected(":");
2487 return false;
2488 }
2489
2490 statement = parseContext.intermediate.addBranch(EOpDefault, loc);
2491
2492 return true;
John Kessenich21472ae2016-06-04 11:46:33 -06002493}
2494
John Kessenich19b92ff2016-06-19 11:50:34 -06002495// array_specifier
2496// : LEFT_BRACKET integer_expression RGHT_BRACKET post_decls // optional
2497//
2498void HlslGrammar::acceptArraySpecifier(TArraySizes*& arraySizes)
2499{
2500 arraySizes = nullptr;
2501
2502 if (! acceptTokenClass(EHTokLeftBracket))
2503 return;
2504
2505 TSourceLoc loc = token.loc;
2506 TIntermTyped* sizeExpr;
2507 if (! acceptAssignmentExpression(sizeExpr)) {
2508 expected("array-sizing expression");
2509 return;
2510 }
2511
2512 if (! acceptTokenClass(EHTokRightBracket)) {
2513 expected("]");
2514 return;
2515 }
2516
2517 TArraySize arraySize;
2518 parseContext.arraySizeCheck(loc, sizeExpr, arraySize);
2519 arraySizes = new TArraySizes;
2520 arraySizes->addInnerSize(arraySize);
2521}
2522
John Kessenich630dd7d2016-06-12 23:52:12 -06002523// post_decls
2524// : COLON semantic // optional
2525// COLON PACKOFFSET LEFT_PAREN ... RIGHT_PAREN // optional
2526// COLON REGISTER // optional
2527// annotations // optional
2528//
2529void HlslGrammar::acceptPostDecls(TType& type)
John Kessenich078d7f22016-03-14 10:02:11 -06002530{
John Kessenich630dd7d2016-06-12 23:52:12 -06002531 do {
2532 // COLON
2533 if (acceptTokenClass(EHTokColon)) {
2534 HlslToken idToken;
2535 if (acceptTokenClass(EHTokPackOffset)) {
2536 if (! acceptTokenClass(EHTokLeftParen)) {
2537 expected("(");
2538 return;
2539 }
2540 acceptTokenClass(EHTokIdentifier);
2541 acceptTokenClass(EHTokDot);
2542 acceptTokenClass(EHTokIdentifier);
2543 if (! acceptTokenClass(EHTokRightParen)) {
2544 expected(")");
2545 break;
2546 }
2547 // TODO: process the packoffset information
John Kessenich3d157c52016-07-25 16:05:33 -06002548 // c1.y means component y of location slot 1
John Kessenich630dd7d2016-06-12 23:52:12 -06002549 } else if (! acceptIdentifier(idToken)) {
2550 expected("semantic or packoffset or register");
2551 return;
2552 } else if (*idToken.string == "register") {
2553 if (! acceptTokenClass(EHTokLeftParen)) {
2554 expected("(");
2555 return;
2556 }
2557 acceptTokenClass(EHTokIdentifier);
2558 acceptTokenClass(EHTokComma);
2559 acceptTokenClass(EHTokIdentifier);
2560 acceptTokenClass(EHTokLeftBracket);
2561 if (peekTokenClass(EHTokIntConstant))
2562 advanceToken();
2563 acceptTokenClass(EHTokRightBracket);
2564 if (! acceptTokenClass(EHTokRightParen)) {
2565 expected(")");
2566 break;
2567 }
2568 // TODO: process the register information
John Kessenich3d157c52016-07-25 16:05:33 -06002569 // b2 means buffer 2
John Kessenich630dd7d2016-06-12 23:52:12 -06002570 } else {
2571 // semantic, in idToken.string
2572 parseContext.handleSemantic(type, *idToken.string);
2573 }
2574 } else if (acceptTokenClass(EHTokLeftAngle)) {
2575 // TODO: process annotations, just accepting them for now
2576 do {
2577 if (peekTokenClass(EHTokNone))
2578 return;
2579 if (acceptTokenClass(EHTokRightAngle))
2580 break;
2581 advanceToken();
2582 } while (true);
2583 } else
2584 break;
John Kessenich078d7f22016-03-14 10:02:11 -06002585
John Kessenich630dd7d2016-06-12 23:52:12 -06002586 } while (true);
John Kessenich078d7f22016-03-14 10:02:11 -06002587}
2588
John Kesseniche01a9bc2016-03-12 20:11:22 -07002589} // end namespace glslang