blob: 443db4ba6f3bf32d1df89deed573d7baf4c74503 [file] [log] [blame]
John Kesseniche01a9bc2016-03-12 20:11:22 -07001//
2//Copyright (C) 2016 Google, Inc.
3//
4//All rights reserved.
5//
6//Redistribution and use in source and binary forms, with or without
7//modification, are permitted provided that the following conditions
8//are met:
9//
10// Redistributions of source code must retain the above copyright
11// notice, this list of conditions and the following disclaimer.
12//
13// Redistributions in binary form must reproduce the above
14// copyright notice, this list of conditions and the following
15// disclaimer in the documentation and/or other materials provided
16// with the distribution.
17//
18// Neither the name of Google, Inc., nor the names of its
19// contributors may be used to endorse or promote products derived
20// from this software without specific prior written permission.
21//
22//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33//POSSIBILITY OF SUCH DAMAGE.
34//
35
John Kessenichd016be12016-03-13 11:24:20 -060036//
37// This is a set of mutually recursive methods implementing the HLSL grammar.
38// Generally, each returns
39// - through an argument: a type specifically appropriate to which rule it
40// recognized
41// - through the return value: true/false to indicate whether or not it
42// recognized its rule
43//
44// As much as possible, only grammar recognition should happen in this file,
John Kessenich078d7f22016-03-14 10:02:11 -060045// with all other work being farmed out to hlslParseHelper.cpp, which in turn
John Kessenichd016be12016-03-13 11:24:20 -060046// will build the AST.
47//
48// The next token, yet to be "accepted" is always sitting in 'token'.
49// When a method says it accepts a rule, that means all tokens involved
50// in the rule will have been consumed, and none left in 'token'.
51//
52
John Kesseniche01a9bc2016-03-12 20:11:22 -070053#include "hlslTokens.h"
54#include "hlslGrammar.h"
55
56namespace glslang {
57
58// Root entry point to this recursive decent parser.
59// Return true if compilation unit was successfully accepted.
60bool HlslGrammar::parse()
61{
62 advanceToken();
63 return acceptCompilationUnit();
64}
65
66void HlslGrammar::expected(const char* syntax)
67{
68 parseContext.error(token.loc, "Expected", syntax, "");
69}
70
John Kessenichaecd4972016-03-14 10:46:34 -060071// Only process the next token if it is an identifier.
72// Return true if it was an identifier.
73bool HlslGrammar::acceptIdentifier(HlslToken& idToken)
74{
75 if (peekTokenClass(EHTokIdentifier)) {
76 idToken = token;
77 advanceToken();
78 return true;
79 }
80
81 return false;
82}
83
John Kesseniche01a9bc2016-03-12 20:11:22 -070084// compilationUnit
85// : list of externalDeclaration
86//
87bool HlslGrammar::acceptCompilationUnit()
88{
John Kessenichd016be12016-03-13 11:24:20 -060089 TIntermNode* unitNode = nullptr;
90
John Kessenich9c86c6a2016-05-03 22:49:24 -060091 while (! peekTokenClass(EHTokNone)) {
John Kessenichd016be12016-03-13 11:24:20 -060092 // externalDeclaration
93 TIntermNode* declarationNode;
94 if (! acceptDeclaration(declarationNode))
John Kesseniche01a9bc2016-03-12 20:11:22 -070095 return false;
John Kessenichd016be12016-03-13 11:24:20 -060096
97 // hook it up
John Kessenich078d7f22016-03-14 10:02:11 -060098 unitNode = intermediate.growAggregate(unitNode, declarationNode);
John Kesseniche01a9bc2016-03-12 20:11:22 -070099 }
100
John Kessenichd016be12016-03-13 11:24:20 -0600101 // set root of AST
John Kessenich078d7f22016-03-14 10:02:11 -0600102 intermediate.setTreeRoot(unitNode);
John Kessenichd016be12016-03-13 11:24:20 -0600103
John Kesseniche01a9bc2016-03-12 20:11:22 -0700104 return true;
105}
106
107// declaration
John Kessenich078d7f22016-03-14 10:02:11 -0600108// : SEMICOLON
109// : fully_specified_type SEMICOLON
110// | fully_specified_type identifier SEMICOLON
111// | fully_specified_type identifier = expression SEMICOLON
112// | fully_specified_type identifier function_parameters SEMICOLON // function prototype
113// | fully_specified_type identifier function_parameters COLON semantic compound_statement // function definition
John Kessenich87142c72016-03-12 20:24:24 -0700114//
John Kessenichd016be12016-03-13 11:24:20 -0600115// 'node' could get created if the declaration creates code, like an initializer
116// or a function body.
117//
118bool HlslGrammar::acceptDeclaration(TIntermNode*& node)
John Kesseniche01a9bc2016-03-12 20:11:22 -0700119{
John Kessenichd016be12016-03-13 11:24:20 -0600120 node = nullptr;
121
John Kessenich87142c72016-03-12 20:24:24 -0700122 // fully_specified_type
123 TType type;
124 if (! acceptFullySpecifiedType(type))
125 return false;
126
127 // identifier
John Kessenichaecd4972016-03-14 10:46:34 -0600128 HlslToken idToken;
129 if (acceptIdentifier(idToken)) {
John Kessenich87142c72016-03-12 20:24:24 -0700130 // = expression
131 TIntermTyped* expressionNode = nullptr;
John Kessenich34fb0362016-05-03 23:17:20 -0600132 if (acceptTokenClass(EHTokAssign)) {
John Kessenich87142c72016-03-12 20:24:24 -0700133 if (! acceptExpression(expressionNode)) {
134 expected("initializer");
135 return false;
136 }
137 }
138
John Kessenich078d7f22016-03-14 10:02:11 -0600139 // SEMICOLON
John Kessenich87142c72016-03-12 20:24:24 -0700140 if (acceptTokenClass(EHTokSemicolon)) {
John Kessenichaecd4972016-03-14 10:46:34 -0600141 node = parseContext.declareVariable(idToken.loc, *idToken.string, type, 0, expressionNode);
John Kessenich87142c72016-03-12 20:24:24 -0700142 return true;
143 }
John Kessenich5f934b02016-03-13 17:58:25 -0600144
145 // function_parameters
John Kessenichaecd4972016-03-14 10:46:34 -0600146 TFunction* function = new TFunction(idToken.string, type);
John Kessenich5f934b02016-03-13 17:58:25 -0600147 if (acceptFunctionParameters(*function)) {
John Kessenich078d7f22016-03-14 10:02:11 -0600148 // COLON semantic
149 acceptSemantic();
150
John Kessenich5f934b02016-03-13 17:58:25 -0600151 // compound_statement
John Kessenich078d7f22016-03-14 10:02:11 -0600152 if (peekTokenClass(EHTokLeftBrace))
John Kessenich5f934b02016-03-13 17:58:25 -0600153 return acceptFunctionDefinition(*function, node);
154
John Kessenich078d7f22016-03-14 10:02:11 -0600155 // SEMICOLON
John Kessenich5f934b02016-03-13 17:58:25 -0600156 if (acceptTokenClass(EHTokSemicolon))
157 return true;
158
159 return false;
160 }
John Kessenich87142c72016-03-12 20:24:24 -0700161 }
162
John Kessenich078d7f22016-03-14 10:02:11 -0600163 // SEMICOLON
John Kessenich87142c72016-03-12 20:24:24 -0700164 if (acceptTokenClass(EHTokSemicolon))
165 return true;
166
John Kesseniche01a9bc2016-03-12 20:11:22 -0700167 return true;
168}
169
John Kessenich87142c72016-03-12 20:24:24 -0700170// fully_specified_type
171// : type_specifier
172// | type_qualifier type_specifier
173//
174bool HlslGrammar::acceptFullySpecifiedType(TType& type)
175{
176 // type_qualifier
177 TQualifier qualifier;
178 qualifier.clear();
179 acceptQualifier(qualifier);
180
181 // type_specifier
182 if (! acceptType(type))
183 return false;
184 type.getQualifier() = qualifier;
185
186 return true;
187}
188
189// If token is a qualifier, return its token class and advance to the next
190// qualifier. Otherwise, return false, and don't advance.
191void HlslGrammar::acceptQualifier(TQualifier& qualifier)
192{
John Kessenich9c86c6a2016-05-03 22:49:24 -0600193 switch (peek()) {
John Kessenich87142c72016-03-12 20:24:24 -0700194 case EHTokUniform:
195 qualifier.storage = EvqUniform;
196 break;
197 case EHTokConst:
198 qualifier.storage = EvqConst;
199 break;
200 default:
201 return;
202 }
203
204 advanceToken();
205}
206
207// If token is for a type, update 'type' with the type information,
208// and return true and advance.
209// Otherwise, return false, and don't advance
210bool HlslGrammar::acceptType(TType& type)
211{
212 if (! token.isType)
213 return false;
214
John Kessenich9c86c6a2016-05-03 22:49:24 -0600215 switch (peek()) {
John Kessenich87142c72016-03-12 20:24:24 -0700216 case EHTokInt:
217 case EHTokInt1:
218 case EHTokDword:
219 new(&type) TType(EbtInt);
220 break;
221 case EHTokFloat:
John Kessenich8d72f1a2016-05-20 12:06:03 -0600222 new(&type) TType(EbtFloat);
223 break;
224
John Kessenich87142c72016-03-12 20:24:24 -0700225 case EHTokFloat1:
226 new(&type) TType(EbtFloat);
John Kessenich8d72f1a2016-05-20 12:06:03 -0600227 type.makeVector();
John Kessenich87142c72016-03-12 20:24:24 -0700228 break;
229
230 case EHTokFloat2:
231 new(&type) TType(EbtFloat, EvqTemporary, 2);
232 break;
233 case EHTokFloat3:
234 new(&type) TType(EbtFloat, EvqTemporary, 3);
235 break;
236 case EHTokFloat4:
237 new(&type) TType(EbtFloat, EvqTemporary, 4);
238 break;
239
240 case EHTokInt2:
241 new(&type) TType(EbtInt, EvqTemporary, 2);
242 break;
243 case EHTokInt3:
244 new(&type) TType(EbtInt, EvqTemporary, 3);
245 break;
246 case EHTokInt4:
247 new(&type) TType(EbtInt, EvqTemporary, 4);
248 break;
249
250 case EHTokBool2:
251 new(&type) TType(EbtBool, EvqTemporary, 2);
252 break;
253 case EHTokBool3:
254 new(&type) TType(EbtBool, EvqTemporary, 3);
255 break;
256 case EHTokBool4:
257 new(&type) TType(EbtBool, EvqTemporary, 4);
258 break;
259
John Kessenich0133c122016-05-20 12:17:26 -0600260 case EHTokInt1x1:
261 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 1);
262 break;
263 case EHTokInt1x2:
264 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 1);
265 break;
266 case EHTokInt1x3:
267 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 1);
268 break;
269 case EHTokInt1x4:
270 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 1);
271 break;
272 case EHTokInt2x1:
273 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 2);
274 break;
275 case EHTokInt2x2:
276 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 2);
277 break;
278 case EHTokInt2x3:
279 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 2);
280 break;
281 case EHTokInt2x4:
282 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 2);
283 break;
284 case EHTokInt3x1:
285 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 3);
286 break;
287 case EHTokInt3x2:
288 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 3);
289 break;
290 case EHTokInt3x3:
291 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 3);
292 break;
293 case EHTokInt3x4:
294 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 3);
295 break;
296 case EHTokInt4x1:
297 new(&type) TType(EbtInt, EvqTemporary, 0, 1, 4);
298 break;
299 case EHTokInt4x2:
300 new(&type) TType(EbtInt, EvqTemporary, 0, 2, 4);
301 break;
302 case EHTokInt4x3:
303 new(&type) TType(EbtInt, EvqTemporary, 0, 3, 4);
304 break;
305 case EHTokInt4x4:
306 new(&type) TType(EbtInt, EvqTemporary, 0, 4, 4);
307 break;
308
309 case EHTokFloat1x1:
310 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 1);
311 break;
312 case EHTokFloat1x2:
313 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 1);
314 break;
315 case EHTokFloat1x3:
316 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 1);
317 break;
318 case EHTokFloat1x4:
319 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 1);
320 break;
321 case EHTokFloat2x1:
322 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 2);
323 break;
John Kessenich87142c72016-03-12 20:24:24 -0700324 case EHTokFloat2x2:
325 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 2);
326 break;
327 case EHTokFloat2x3:
328 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 2);
329 break;
330 case EHTokFloat2x4:
331 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 2);
332 break;
John Kessenich0133c122016-05-20 12:17:26 -0600333 case EHTokFloat3x1:
334 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 3);
335 break;
John Kessenich87142c72016-03-12 20:24:24 -0700336 case EHTokFloat3x2:
337 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 3);
338 break;
339 case EHTokFloat3x3:
340 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 3);
341 break;
342 case EHTokFloat3x4:
343 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 3);
344 break;
John Kessenich0133c122016-05-20 12:17:26 -0600345 case EHTokFloat4x1:
346 new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 4);
347 break;
John Kessenich87142c72016-03-12 20:24:24 -0700348 case EHTokFloat4x2:
349 new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 4);
350 break;
351 case EHTokFloat4x3:
352 new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 4);
353 break;
354 case EHTokFloat4x4:
355 new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 4);
356 break;
357
John Kessenich0133c122016-05-20 12:17:26 -0600358 case EHTokDouble1x1:
359 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 1);
360 break;
361 case EHTokDouble1x2:
362 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 1);
363 break;
364 case EHTokDouble1x3:
365 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 1);
366 break;
367 case EHTokDouble1x4:
368 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 1);
369 break;
370 case EHTokDouble2x1:
371 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 2);
372 break;
373 case EHTokDouble2x2:
374 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 2);
375 break;
376 case EHTokDouble2x3:
377 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 2);
378 break;
379 case EHTokDouble2x4:
380 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 2);
381 break;
382 case EHTokDouble3x1:
383 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 3);
384 break;
385 case EHTokDouble3x2:
386 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 3);
387 break;
388 case EHTokDouble3x3:
389 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 3);
390 break;
391 case EHTokDouble3x4:
392 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 3);
393 break;
394 case EHTokDouble4x1:
395 new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 4);
396 break;
397 case EHTokDouble4x2:
398 new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 4);
399 break;
400 case EHTokDouble4x3:
401 new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 4);
402 break;
403 case EHTokDouble4x4:
404 new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 4);
405 break;
406
John Kessenich87142c72016-03-12 20:24:24 -0700407 default:
408 return false;
409 }
410
411 advanceToken();
412
413 return true;
414}
415
John Kessenich5f934b02016-03-13 17:58:25 -0600416// function_parameters
John Kessenich078d7f22016-03-14 10:02:11 -0600417// : LEFT_PAREN parameter_declaration COMMA parameter_declaration ... RIGHT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -0600418//
419bool HlslGrammar::acceptFunctionParameters(TFunction& function)
420{
John Kessenich078d7f22016-03-14 10:02:11 -0600421 // LEFT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -0600422 if (! acceptTokenClass(EHTokLeftParen))
423 return false;
424
425 do {
426 // parameter_declaration
427 if (! acceptParameterDeclaration(function))
428 break;
429
John Kessenich078d7f22016-03-14 10:02:11 -0600430 // COMMA
John Kessenich5f934b02016-03-13 17:58:25 -0600431 if (! acceptTokenClass(EHTokComma))
432 break;
433 } while (true);
434
John Kessenich078d7f22016-03-14 10:02:11 -0600435 // RIGHT_PAREN
John Kessenich5f934b02016-03-13 17:58:25 -0600436 if (! acceptTokenClass(EHTokRightParen)) {
437 expected("right parenthesis");
438 return false;
439 }
440
441 return true;
442}
443
444// parameter_declaration
445// : fully_specified_type
446// | fully_specified_type identifier
447//
448bool HlslGrammar::acceptParameterDeclaration(TFunction& function)
449{
450 // fully_specified_type
451 TType* type = new TType;
452 if (! acceptFullySpecifiedType(*type))
453 return false;
454
455 // identifier
John Kessenichaecd4972016-03-14 10:46:34 -0600456 HlslToken idToken;
457 acceptIdentifier(idToken);
John Kessenich5f934b02016-03-13 17:58:25 -0600458
John Kessenichaecd4972016-03-14 10:46:34 -0600459 TParameter param = { idToken.string, type };
John Kessenich5f934b02016-03-13 17:58:25 -0600460 function.addParameter(param);
461
462 return true;
463}
464
465// Do the work to create the function definition in addition to
466// parsing the body (compound_statement).
467bool HlslGrammar::acceptFunctionDefinition(TFunction& function, TIntermNode*& node)
468{
469 TFunction* functionDeclarator = parseContext.handleFunctionDeclarator(token.loc, function, false /* not prototype */);
470
471 // This does a symbol table push
472 node = parseContext.handleFunctionDefinition(token.loc, *functionDeclarator);
473
474 // compound_statement
475 TIntermAggregate* functionBody = nullptr;
476 if (acceptCompoundStatement(functionBody)) {
John Kessenich078d7f22016-03-14 10:02:11 -0600477 node = intermediate.growAggregate(node, functionBody);
478 intermediate.setAggregateOperator(node, EOpFunction, functionDeclarator->getType(), token.loc);
John Kessenich5f934b02016-03-13 17:58:25 -0600479 node->getAsAggregate()->setName(functionDeclarator->getMangledName().c_str());
480 parseContext.symbolTable.pop(nullptr);
481
482 return true;
483 }
484
485 return false;
486}
487
John Kessenich34fb0362016-05-03 23:17:20 -0600488// The top-level full expression recognizer.
489//
John Kessenich87142c72016-03-12 20:24:24 -0700490// expression
John Kessenich34fb0362016-05-03 23:17:20 -0600491// : assignment_expression COMMA assignment_expression COMMA assignment_expression ...
John Kessenich87142c72016-03-12 20:24:24 -0700492//
493bool HlslGrammar::acceptExpression(TIntermTyped*& node)
494{
John Kessenich34fb0362016-05-03 23:17:20 -0600495 // assignment_expression
496 if (! acceptAssignmentExpression(node))
497 return false;
John Kessenich5f934b02016-03-13 17:58:25 -0600498
John Kessenich34fb0362016-05-03 23:17:20 -0600499 if (! peekTokenClass(EHTokComma))
500 return true;
501
502 do {
503 // ... COMMA
John Kessenich5f934b02016-03-13 17:58:25 -0600504 TSourceLoc loc = token.loc;
John Kessenich34fb0362016-05-03 23:17:20 -0600505 advanceToken();
John Kessenich5f934b02016-03-13 17:58:25 -0600506
John Kessenich34fb0362016-05-03 23:17:20 -0600507 // ... assignment_expression
508 TIntermTyped* rightNode = nullptr;
509 if (! acceptAssignmentExpression(rightNode)) {
510 expected("assignment expression");
511 return false;
John Kessenich5f934b02016-03-13 17:58:25 -0600512 }
513
John Kessenich34fb0362016-05-03 23:17:20 -0600514 node = intermediate.addComma(node, rightNode, loc);
515
516 if (! peekTokenClass(EHTokComma))
517 return true;
518 } while (true);
519}
520
521// Accept an assignment expression, where assignment operations
522// associate right-to-left. This is, it is implicit, for example
523//
524// a op (b op (c op d))
525//
526// assigment_expression
527// : binary_expression op binary_expression op binary_expression ...
528//
529bool HlslGrammar::acceptAssignmentExpression(TIntermTyped*& node)
530{
531 if (! acceptBinaryExpression(node, PlLogicalOr))
532 return false;
533
534 TOperator assignOp = HlslOpMap::assignment(peek());
535 if (assignOp == EOpNull)
536 return true;
537
538 // ... op
539 TSourceLoc loc = token.loc;
540 advanceToken();
541
542 // ... binary_expression
543 // But, done by recursing this function, which automatically
544 // gets the right-to-left associativity.
545 TIntermTyped* rightNode = nullptr;
546 if (! acceptAssignmentExpression(rightNode)) {
547 expected("assignment expression");
John Kessenich5f934b02016-03-13 17:58:25 -0600548 return false;
John Kessenich87142c72016-03-12 20:24:24 -0700549 }
550
John Kessenich34fb0362016-05-03 23:17:20 -0600551 node = intermediate.addAssign(assignOp, node, rightNode, loc);
552
553 if (! peekTokenClass(EHTokComma))
554 return true;
555
556 return true;
557}
558
559// Accept a binary expression, for binary operations that
560// associate left-to-right. This is, it is implicit, for example
561//
562// ((a op b) op c) op d
563//
564// binary_expression
565// : expression op expression op expression ...
566//
567// where 'expression' is the next higher level in precedence.
568//
569bool HlslGrammar::acceptBinaryExpression(TIntermTyped*& node, PrecedenceLevel precedenceLevel)
570{
571 if (precedenceLevel > PlMul)
572 return acceptUnaryExpression(node);
573
574 // assignment_expression
575 if (! acceptBinaryExpression(node, (PrecedenceLevel)(precedenceLevel + 1)))
576 return false;
577
578 TOperator op = HlslOpMap::binary(peek());
579 PrecedenceLevel tokenLevel = HlslOpMap::precedenceLevel(op);
580 if (tokenLevel < precedenceLevel)
581 return true;
582
583 do {
584 // ... op
585 TSourceLoc loc = token.loc;
586 advanceToken();
587
588 // ... expression
589 TIntermTyped* rightNode = nullptr;
590 if (! acceptBinaryExpression(rightNode, (PrecedenceLevel)(precedenceLevel + 1))) {
591 expected("expression");
592 return false;
593 }
594
595 node = intermediate.addBinaryMath(op, node, rightNode, loc);
596
597 if (! peekTokenClass(EHTokComma))
598 return true;
599 } while (true);
600}
601
602// unary_expression
603// : + unary_expression
604// | - unary_expression
605// | ! unary_expression
606// | ~ unary_expression
607// | ++ unary_expression
608// | -- unary_expression
609// | postfix_expression
610//
611bool HlslGrammar::acceptUnaryExpression(TIntermTyped*& node)
612{
613 TOperator unaryOp = HlslOpMap::preUnary(peek());
614
615 // postfix_expression
616 if (unaryOp == EOpNull)
617 return acceptPostfixExpression(node);
618
619 // op unary_expression
620 TSourceLoc loc = token.loc;
621 advanceToken();
622 if (! acceptUnaryExpression(node))
623 return false;
624
625 // + is a no-op
626 if (unaryOp == EOpAdd)
627 return true;
628
629 node = intermediate.addUnaryMath(unaryOp, node, loc);
630
631 return node != nullptr;
632}
633
634// postfix_expression
635// : LEFT_PAREN expression RIGHT_PAREN
636// | literal
637// | constructor
638// | identifier
639// | function_call
640// | postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET
641// | postfix_expression DOT IDENTIFIER
642// | postfix_expression INC_OP
643// | postfix_expression DEC_OP
644//
645bool HlslGrammar::acceptPostfixExpression(TIntermTyped*& node)
646{
647 // Not implemented as self-recursive:
648 // The logical "right recursion" is done with an loop at the end
649
650 // idToken will pick up either a variable or a function name in a function call
651 HlslToken idToken;
652
John Kessenich078d7f22016-03-14 10:02:11 -0600653 // LEFT_PAREN expression RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -0700654 if (acceptTokenClass(EHTokLeftParen)) {
655 if (! acceptExpression(node)) {
656 expected("expression");
657 return false;
658 }
659 if (! acceptTokenClass(EHTokRightParen)) {
660 expected("right parenthesis");
661 return false;
662 }
John Kessenich34fb0362016-05-03 23:17:20 -0600663 } else if (acceptLiteral(node)) {
664 // literal (nothing else to do yet), go on to the
665 } else if (acceptConstructor(node)) {
666 // constructor (nothing else to do yet)
667 } else if (acceptIdentifier(idToken)) {
668 // identifier or function_call name
669 if (! peekTokenClass(EHTokLeftParen)) {
670 node = parseContext.handleVariable(idToken.loc, idToken.symbol, token.string);
671 } else if (acceptFunctionCall(idToken, node)) {
672 // function_call (nothing else to do yet)
673 } else {
674 expected("function call arguments");
675 return false;
676 }
John Kessenich87142c72016-03-12 20:24:24 -0700677 }
678
John Kessenich34fb0362016-05-03 23:17:20 -0600679 do {
680 TSourceLoc loc = token.loc;
681 TOperator postOp = HlslOpMap::postUnary(peek());
John Kessenich87142c72016-03-12 20:24:24 -0700682
John Kessenich34fb0362016-05-03 23:17:20 -0600683 // Consume only a valid post-unary operator, otherwise we are done.
684 switch (postOp) {
685 case EOpIndexDirectStruct:
686 case EOpIndexIndirect:
687 case EOpPostIncrement:
688 case EOpPostDecrement:
689 advanceToken();
690 break;
691 default:
692 return true;
693 }
John Kessenich87142c72016-03-12 20:24:24 -0700694
John Kessenich34fb0362016-05-03 23:17:20 -0600695 // We have a valid post-unary operator, process it.
696 switch (postOp) {
697 case EOpIndexDirectStruct:
698 // todo
699 break;
700 case EOpIndexIndirect:
701 {
702 TIntermTyped* indexNode = nullptr;
703 if (! acceptExpression(indexNode) ||
704 ! peekTokenClass(EHTokRightBracket)) {
705 expected("expression followed by ']'");
706 return false;
707 }
708 // todo: node = intermediate.addBinaryMath(
709 }
710 case EOpPostIncrement:
711 case EOpPostDecrement:
712 node = intermediate.addUnaryMath(postOp, node, loc);
713 break;
714 default:
715 assert(0);
716 break;
717 }
718 } while (true);
John Kessenich87142c72016-03-12 20:24:24 -0700719}
720
John Kessenichd016be12016-03-13 11:24:20 -0600721// constructor
John Kessenich078d7f22016-03-14 10:02:11 -0600722// : type argument_list
John Kessenichd016be12016-03-13 11:24:20 -0600723//
724bool HlslGrammar::acceptConstructor(TIntermTyped*& node)
725{
726 // type
727 TType type;
728 if (acceptType(type)) {
729 TFunction* constructorFunction = parseContext.handleConstructorCall(token.loc, type);
730 if (constructorFunction == nullptr)
731 return false;
732
733 // arguments
John Kessenich4678ca92016-05-13 09:33:42 -0600734 TIntermTyped* arguments = nullptr;
John Kessenichd016be12016-03-13 11:24:20 -0600735 if (! acceptArguments(constructorFunction, arguments)) {
736 expected("constructor arguments");
737 return false;
738 }
739
740 // hook it up
741 node = parseContext.handleFunctionCall(arguments->getLoc(), constructorFunction, arguments);
742
743 return true;
744 }
745
746 return false;
747}
748
John Kessenich34fb0362016-05-03 23:17:20 -0600749// The function_call identifier was already recognized, and passed in as idToken.
750//
751// function_call
752// : [idToken] arguments
753//
John Kessenich4678ca92016-05-13 09:33:42 -0600754bool HlslGrammar::acceptFunctionCall(HlslToken idToken, TIntermTyped*& node)
John Kessenich34fb0362016-05-03 23:17:20 -0600755{
John Kessenich4678ca92016-05-13 09:33:42 -0600756 // arguments
757 TFunction* function = new TFunction(idToken.string, TType(EbtVoid));
758 TIntermTyped* arguments = nullptr;
759 if (! acceptArguments(function, arguments))
760 return false;
761
762 node = parseContext.handleFunctionCall(idToken.loc, function, arguments);
763
764 return true;
John Kessenich34fb0362016-05-03 23:17:20 -0600765}
766
John Kessenich87142c72016-03-12 20:24:24 -0700767// arguments
John Kessenich078d7f22016-03-14 10:02:11 -0600768// : LEFT_PAREN expression COMMA expression COMMA ... RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -0700769//
John Kessenichd016be12016-03-13 11:24:20 -0600770// The arguments are pushed onto the 'function' argument list and
771// onto the 'arguments' aggregate.
772//
John Kessenich4678ca92016-05-13 09:33:42 -0600773bool HlslGrammar::acceptArguments(TFunction* function, TIntermTyped*& arguments)
John Kessenich87142c72016-03-12 20:24:24 -0700774{
John Kessenich078d7f22016-03-14 10:02:11 -0600775 // LEFT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -0700776 if (! acceptTokenClass(EHTokLeftParen))
777 return false;
778
779 do {
John Kessenichd016be12016-03-13 11:24:20 -0600780 // expression
John Kessenich87142c72016-03-12 20:24:24 -0700781 TIntermTyped* arg;
John Kessenich4678ca92016-05-13 09:33:42 -0600782 if (! acceptAssignmentExpression(arg))
John Kessenich87142c72016-03-12 20:24:24 -0700783 break;
John Kessenichd016be12016-03-13 11:24:20 -0600784
785 // hook it up
786 parseContext.handleFunctionArgument(function, arguments, arg);
787
John Kessenich078d7f22016-03-14 10:02:11 -0600788 // COMMA
John Kessenich87142c72016-03-12 20:24:24 -0700789 if (! acceptTokenClass(EHTokComma))
790 break;
791 } while (true);
792
John Kessenich078d7f22016-03-14 10:02:11 -0600793 // RIGHT_PAREN
John Kessenich87142c72016-03-12 20:24:24 -0700794 if (! acceptTokenClass(EHTokRightParen)) {
795 expected("right parenthesis");
796 return false;
797 }
798
799 return true;
800}
801
802bool HlslGrammar::acceptLiteral(TIntermTyped*& node)
803{
804 switch (token.tokenClass) {
805 case EHTokIntConstant:
John Kessenich078d7f22016-03-14 10:02:11 -0600806 node = intermediate.addConstantUnion(token.i, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -0700807 break;
808 case EHTokFloatConstant:
John Kessenich078d7f22016-03-14 10:02:11 -0600809 node = intermediate.addConstantUnion(token.d, EbtFloat, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -0700810 break;
811 case EHTokDoubleConstant:
John Kessenich078d7f22016-03-14 10:02:11 -0600812 node = intermediate.addConstantUnion(token.d, EbtDouble, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -0700813 break;
814 case EHTokBoolConstant:
John Kessenich078d7f22016-03-14 10:02:11 -0600815 node = intermediate.addConstantUnion(token.b, token.loc, true);
John Kessenich87142c72016-03-12 20:24:24 -0700816 break;
817
818 default:
819 return false;
820 }
821
822 advanceToken();
823
824 return true;
825}
826
John Kessenich5f934b02016-03-13 17:58:25 -0600827// compound_statement
John Kessenich34fb0362016-05-03 23:17:20 -0600828// : LEFT_CURLY statement statement ... RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -0600829//
830bool HlslGrammar::acceptCompoundStatement(TIntermAggregate*& compoundStatement)
John Kessenich87142c72016-03-12 20:24:24 -0700831{
John Kessenich34fb0362016-05-03 23:17:20 -0600832 // LEFT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -0600833 if (! acceptTokenClass(EHTokLeftBrace))
834 return false;
835
836 // statement statement ...
837 TIntermNode* statement = nullptr;
838 while (acceptStatement(statement)) {
839 // hook it up
John Kessenich078d7f22016-03-14 10:02:11 -0600840 compoundStatement = intermediate.growAggregate(compoundStatement, statement);
John Kessenich5f934b02016-03-13 17:58:25 -0600841 }
John Kessenich34fb0362016-05-03 23:17:20 -0600842 if (compoundStatement)
843 compoundStatement->setOperator(EOpSequence);
John Kessenich5f934b02016-03-13 17:58:25 -0600844
John Kessenich34fb0362016-05-03 23:17:20 -0600845 // RIGHT_CURLY
John Kessenich5f934b02016-03-13 17:58:25 -0600846 return acceptTokenClass(EHTokRightBrace);
847}
848
849// statement
850// : compound_statement
John Kessenich078d7f22016-03-14 10:02:11 -0600851// | return SEMICOLON
852// | return expression SEMICOLON
853// | expression SEMICOLON
John Kessenich5f934b02016-03-13 17:58:25 -0600854//
855bool HlslGrammar::acceptStatement(TIntermNode*& statement)
856{
857 // compound_statement
858 TIntermAggregate* compoundStatement = nullptr;
859 if (acceptCompoundStatement(compoundStatement)) {
860 statement = compoundStatement;
861 return true;
862 }
863
John Kessenich078d7f22016-03-14 10:02:11 -0600864 // RETURN
John Kessenich5f934b02016-03-13 17:58:25 -0600865 if (acceptTokenClass(EHTokReturn)) {
866 // expression
867 TIntermTyped* node;
868 if (acceptExpression(node)) {
869 // hook it up
John Kessenich078d7f22016-03-14 10:02:11 -0600870 statement = intermediate.addBranch(EOpReturn, node, token.loc);
John Kessenich5f934b02016-03-13 17:58:25 -0600871 } else
John Kessenich078d7f22016-03-14 10:02:11 -0600872 statement = intermediate.addBranch(EOpReturn, token.loc);
John Kessenich5f934b02016-03-13 17:58:25 -0600873
John Kessenich078d7f22016-03-14 10:02:11 -0600874 // SEMICOLON
John Kessenich5f934b02016-03-13 17:58:25 -0600875 if (! acceptTokenClass(EHTokSemicolon))
876 return false;
877
878 return true;
879 }
880
881 // expression
882 TIntermTyped* node;
883 if (acceptExpression(node))
884 statement = node;
885
John Kessenich078d7f22016-03-14 10:02:11 -0600886 // SEMICOLON
John Kessenich5f934b02016-03-13 17:58:25 -0600887 if (! acceptTokenClass(EHTokSemicolon))
888 return false;
889
890 return true;
John Kessenich87142c72016-03-12 20:24:24 -0700891}
892
John Kessenich078d7f22016-03-14 10:02:11 -0600893// COLON semantic
894bool HlslGrammar::acceptSemantic()
895{
896 // COLON
897 if (acceptTokenClass(EHTokColon)) {
898 // semantic
John Kessenichaecd4972016-03-14 10:46:34 -0600899 HlslToken idToken;
900 if (! acceptIdentifier(idToken)) {
John Kessenich078d7f22016-03-14 10:02:11 -0600901 expected("semantic");
902 return false;
903 }
904 }
905
906 return true;
907}
908
John Kesseniche01a9bc2016-03-12 20:11:22 -0700909} // end namespace glslang