summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/glslang/src/hlsl/hlslGrammar.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/glslang/src/hlsl/hlslGrammar.cpp')
-rwxr-xr-xchromium/third_party/glslang/src/hlsl/hlslGrammar.cpp1684
1 files changed, 1684 insertions, 0 deletions
diff --git a/chromium/third_party/glslang/src/hlsl/hlslGrammar.cpp b/chromium/third_party/glslang/src/hlsl/hlslGrammar.cpp
new file mode 100755
index 00000000000..c0d4f285734
--- /dev/null
+++ b/chromium/third_party/glslang/src/hlsl/hlslGrammar.cpp
@@ -0,0 +1,1684 @@
+//
+//Copyright (C) 2016 Google, Inc.
+//
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without
+//modification, are permitted provided that the following conditions
+//are met:
+//
+// Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+//
+// Neither the name of Google, Inc., nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+//POSSIBILITY OF SUCH DAMAGE.
+//
+
+//
+// This is a set of mutually recursive methods implementing the HLSL grammar.
+// Generally, each returns
+// - through an argument: a type specifically appropriate to which rule it
+// recognized
+// - through the return value: true/false to indicate whether or not it
+// recognized its rule
+//
+// As much as possible, only grammar recognition should happen in this file,
+// with all other work being farmed out to hlslParseHelper.cpp, which in turn
+// will build the AST.
+//
+// The next token, yet to be "accepted" is always sitting in 'token'.
+// When a method says it accepts a rule, that means all tokens involved
+// in the rule will have been consumed, and none left in 'token'.
+//
+
+#include "hlslTokens.h"
+#include "hlslGrammar.h"
+
+namespace glslang {
+
+// Root entry point to this recursive decent parser.
+// Return true if compilation unit was successfully accepted.
+bool HlslGrammar::parse()
+{
+ advanceToken();
+ return acceptCompilationUnit();
+}
+
+void HlslGrammar::expected(const char* syntax)
+{
+ parseContext.error(token.loc, "Expected", syntax, "");
+}
+
+// Only process the next token if it is an identifier.
+// Return true if it was an identifier.
+bool HlslGrammar::acceptIdentifier(HlslToken& idToken)
+{
+ if (peekTokenClass(EHTokIdentifier)) {
+ idToken = token;
+ advanceToken();
+ return true;
+ }
+
+ return false;
+}
+
+// compilationUnit
+// : list of externalDeclaration
+//
+bool HlslGrammar::acceptCompilationUnit()
+{
+ TIntermNode* unitNode = nullptr;
+
+ while (! peekTokenClass(EHTokNone)) {
+ // externalDeclaration
+ TIntermNode* declarationNode;
+ if (! acceptDeclaration(declarationNode))
+ return false;
+
+ // hook it up
+ unitNode = intermediate.growAggregate(unitNode, declarationNode);
+ }
+
+ // set root of AST
+ intermediate.setTreeRoot(unitNode);
+
+ return true;
+}
+
+// declaration
+// : SEMICOLON
+// : fully_specified_type SEMICOLON
+// | fully_specified_type identifier post_decls SEMICOLON
+// | fully_specified_type identifier post_decls = expression SEMICOLON
+// | fully_specified_type identifier function_parameters post_decls SEMICOLON // function prototype
+// | fully_specified_type identifier function_parameters post_decls compound_statement // function definition
+//
+// 'node' could get created if the declaration creates code, like an initializer
+// or a function body.
+//
+bool HlslGrammar::acceptDeclaration(TIntermNode*& node)
+{
+ node = nullptr;
+
+ // fully_specified_type
+ TType type;
+ if (! acceptFullySpecifiedType(type))
+ return false;
+
+ // identifier
+ HlslToken idToken;
+ if (acceptIdentifier(idToken)) {
+ acceptPostDecls(type);
+ // = expression
+ TIntermTyped* expressionNode = nullptr;
+ if (acceptTokenClass(EHTokAssign)) {
+ if (! acceptExpression(expressionNode)) {
+ expected("initializer");
+ return false;
+ }
+ }
+
+ // SEMICOLON
+ if (acceptTokenClass(EHTokSemicolon)) {
+ node = parseContext.declareVariable(idToken.loc, *idToken.string, type, 0, expressionNode);
+ return true;
+ }
+
+ // function_parameters
+ TFunction* function = new TFunction(idToken.string, type);
+ if (acceptFunctionParameters(*function)) {
+ // post_decls
+ acceptPostDecls(type);
+
+ // compound_statement
+ if (peekTokenClass(EHTokLeftBrace))
+ return acceptFunctionDefinition(*function, node);
+
+ // SEMICOLON
+ if (acceptTokenClass(EHTokSemicolon))
+ return true;
+
+ return false;
+ }
+ }
+
+ // SEMICOLON
+ if (acceptTokenClass(EHTokSemicolon))
+ return true;
+
+ return true;
+}
+
+// fully_specified_type
+// : type_specifier
+// | type_qualifier type_specifier
+//
+bool HlslGrammar::acceptFullySpecifiedType(TType& type)
+{
+ // type_qualifier
+ TQualifier qualifier;
+ qualifier.clear();
+ acceptQualifier(qualifier);
+
+ // type_specifier
+ if (! acceptType(type))
+ return false;
+ type.getQualifier() = qualifier;
+
+ return true;
+}
+
+// type_qualifier
+// : qualifier qualifier ...
+//
+// Zero or more of these, so this can't return false.
+//
+void HlslGrammar::acceptQualifier(TQualifier& qualifier)
+{
+ do {
+ switch (peek()) {
+ case EHTokStatic:
+ // normal glslang default
+ break;
+ case EHTokExtern:
+ // TODO: no meaning in glslang?
+ break;
+ case EHTokShared:
+ // TODO: hint
+ break;
+ case EHTokGroupShared:
+ qualifier.storage = EvqShared;
+ break;
+ case EHTokUniform:
+ qualifier.storage = EvqUniform;
+ break;
+ case EHTokConst:
+ qualifier.storage = EvqConst;
+ break;
+ case EHTokVolatile:
+ qualifier.volatil = true;
+ break;
+ case EHTokLinear:
+ qualifier.storage = EvqVaryingIn;
+ qualifier.smooth = true;
+ break;
+ case EHTokCentroid:
+ qualifier.centroid = true;
+ break;
+ case EHTokNointerpolation:
+ qualifier.flat = true;
+ break;
+ case EHTokNoperspective:
+ qualifier.nopersp = true;
+ break;
+ case EHTokSample:
+ qualifier.sample = true;
+ break;
+ case EHTokRowMajor:
+ qualifier.layoutMatrix = ElmRowMajor;
+ break;
+ case EHTokColumnMajor:
+ qualifier.layoutMatrix = ElmColumnMajor;
+ break;
+ case EHTokPrecise:
+ qualifier.noContraction = true;
+ break;
+ default:
+ return;
+ }
+ advanceToken();
+ } while (true);
+}
+
+// If token is for a type, update 'type' with the type information,
+// and return true and advance.
+// Otherwise, return false, and don't advance
+bool HlslGrammar::acceptType(TType& type)
+{
+ switch (peek()) {
+ case EHTokStruct:
+ return acceptStruct(type);
+ break;
+
+ case EHTokIdentifier:
+ // An identifier could be for a user-defined type.
+ // Note we cache the symbol table lookup, to save for a later rule
+ // when this is not a type.
+ token.symbol = parseContext.symbolTable.find(*token.string);
+ if (token.symbol && token.symbol->getAsVariable() && token.symbol->getAsVariable()->isUserType()) {
+ type.shallowCopy(token.symbol->getType());
+ advanceToken();
+ return true;
+ } else
+ return false;
+
+ case EHTokVoid:
+ new(&type) TType(EbtVoid);
+ break;
+
+ case EHTokFloat:
+ new(&type) TType(EbtFloat);
+ break;
+ case EHTokFloat1:
+ new(&type) TType(EbtFloat);
+ type.makeVector();
+ break;
+ case EHTokFloat2:
+ new(&type) TType(EbtFloat, EvqTemporary, 2);
+ break;
+ case EHTokFloat3:
+ new(&type) TType(EbtFloat, EvqTemporary, 3);
+ break;
+ case EHTokFloat4:
+ new(&type) TType(EbtFloat, EvqTemporary, 4);
+ break;
+
+ case EHTokDouble:
+ new(&type) TType(EbtDouble);
+ break;
+ case EHTokDouble1:
+ new(&type) TType(EbtDouble);
+ type.makeVector();
+ break;
+ case EHTokDouble2:
+ new(&type) TType(EbtDouble, EvqTemporary, 2);
+ break;
+ case EHTokDouble3:
+ new(&type) TType(EbtDouble, EvqTemporary, 3);
+ break;
+ case EHTokDouble4:
+ new(&type) TType(EbtDouble, EvqTemporary, 4);
+ break;
+
+ case EHTokInt:
+ case EHTokDword:
+ new(&type) TType(EbtInt);
+ break;
+ case EHTokInt1:
+ new(&type) TType(EbtInt);
+ type.makeVector();
+ break;
+ case EHTokInt2:
+ new(&type) TType(EbtInt, EvqTemporary, 2);
+ break;
+ case EHTokInt3:
+ new(&type) TType(EbtInt, EvqTemporary, 3);
+ break;
+ case EHTokInt4:
+ new(&type) TType(EbtInt, EvqTemporary, 4);
+ break;
+
+ case EHTokUint:
+ new(&type) TType(EbtUint);
+ break;
+ case EHTokUint1:
+ new(&type) TType(EbtUint);
+ type.makeVector();
+ break;
+ case EHTokUint2:
+ new(&type) TType(EbtUint, EvqTemporary, 2);
+ break;
+ case EHTokUint3:
+ new(&type) TType(EbtUint, EvqTemporary, 3);
+ break;
+ case EHTokUint4:
+ new(&type) TType(EbtUint, EvqTemporary, 4);
+ break;
+
+ case EHTokBool:
+ new(&type) TType(EbtBool);
+ break;
+ case EHTokBool1:
+ new(&type) TType(EbtBool);
+ type.makeVector();
+ break;
+ case EHTokBool2:
+ new(&type) TType(EbtBool, EvqTemporary, 2);
+ break;
+ case EHTokBool3:
+ new(&type) TType(EbtBool, EvqTemporary, 3);
+ break;
+ case EHTokBool4:
+ new(&type) TType(EbtBool, EvqTemporary, 4);
+ break;
+
+ case EHTokInt1x1:
+ new(&type) TType(EbtInt, EvqTemporary, 0, 1, 1);
+ break;
+ case EHTokInt1x2:
+ new(&type) TType(EbtInt, EvqTemporary, 0, 2, 1);
+ break;
+ case EHTokInt1x3:
+ new(&type) TType(EbtInt, EvqTemporary, 0, 3, 1);
+ break;
+ case EHTokInt1x4:
+ new(&type) TType(EbtInt, EvqTemporary, 0, 4, 1);
+ break;
+ case EHTokInt2x1:
+ new(&type) TType(EbtInt, EvqTemporary, 0, 1, 2);
+ break;
+ case EHTokInt2x2:
+ new(&type) TType(EbtInt, EvqTemporary, 0, 2, 2);
+ break;
+ case EHTokInt2x3:
+ new(&type) TType(EbtInt, EvqTemporary, 0, 3, 2);
+ break;
+ case EHTokInt2x4:
+ new(&type) TType(EbtInt, EvqTemporary, 0, 4, 2);
+ break;
+ case EHTokInt3x1:
+ new(&type) TType(EbtInt, EvqTemporary, 0, 1, 3);
+ break;
+ case EHTokInt3x2:
+ new(&type) TType(EbtInt, EvqTemporary, 0, 2, 3);
+ break;
+ case EHTokInt3x3:
+ new(&type) TType(EbtInt, EvqTemporary, 0, 3, 3);
+ break;
+ case EHTokInt3x4:
+ new(&type) TType(EbtInt, EvqTemporary, 0, 4, 3);
+ break;
+ case EHTokInt4x1:
+ new(&type) TType(EbtInt, EvqTemporary, 0, 1, 4);
+ break;
+ case EHTokInt4x2:
+ new(&type) TType(EbtInt, EvqTemporary, 0, 2, 4);
+ break;
+ case EHTokInt4x3:
+ new(&type) TType(EbtInt, EvqTemporary, 0, 3, 4);
+ break;
+ case EHTokInt4x4:
+ new(&type) TType(EbtInt, EvqTemporary, 0, 4, 4);
+ break;
+
+ case EHTokUint1x1:
+ new(&type) TType(EbtUint, EvqTemporary, 0, 1, 1);
+ break;
+ case EHTokUint1x2:
+ new(&type) TType(EbtUint, EvqTemporary, 0, 2, 1);
+ break;
+ case EHTokUint1x3:
+ new(&type) TType(EbtUint, EvqTemporary, 0, 3, 1);
+ break;
+ case EHTokUint1x4:
+ new(&type) TType(EbtUint, EvqTemporary, 0, 4, 1);
+ break;
+ case EHTokUint2x1:
+ new(&type) TType(EbtUint, EvqTemporary, 0, 1, 2);
+ break;
+ case EHTokUint2x2:
+ new(&type) TType(EbtUint, EvqTemporary, 0, 2, 2);
+ break;
+ case EHTokUint2x3:
+ new(&type) TType(EbtUint, EvqTemporary, 0, 3, 2);
+ break;
+ case EHTokUint2x4:
+ new(&type) TType(EbtUint, EvqTemporary, 0, 4, 2);
+ break;
+ case EHTokUint3x1:
+ new(&type) TType(EbtUint, EvqTemporary, 0, 1, 3);
+ break;
+ case EHTokUint3x2:
+ new(&type) TType(EbtUint, EvqTemporary, 0, 2, 3);
+ break;
+ case EHTokUint3x3:
+ new(&type) TType(EbtUint, EvqTemporary, 0, 3, 3);
+ break;
+ case EHTokUint3x4:
+ new(&type) TType(EbtUint, EvqTemporary, 0, 4, 3);
+ break;
+ case EHTokUint4x1:
+ new(&type) TType(EbtUint, EvqTemporary, 0, 1, 4);
+ break;
+ case EHTokUint4x2:
+ new(&type) TType(EbtUint, EvqTemporary, 0, 2, 4);
+ break;
+ case EHTokUint4x3:
+ new(&type) TType(EbtUint, EvqTemporary, 0, 3, 4);
+ break;
+ case EHTokUint4x4:
+ new(&type) TType(EbtUint, EvqTemporary, 0, 4, 4);
+ break;
+
+ case EHTokBool1x1:
+ new(&type) TType(EbtBool, EvqTemporary, 0, 1, 1);
+ break;
+ case EHTokBool1x2:
+ new(&type) TType(EbtBool, EvqTemporary, 0, 2, 1);
+ break;
+ case EHTokBool1x3:
+ new(&type) TType(EbtBool, EvqTemporary, 0, 3, 1);
+ break;
+ case EHTokBool1x4:
+ new(&type) TType(EbtBool, EvqTemporary, 0, 4, 1);
+ break;
+ case EHTokBool2x1:
+ new(&type) TType(EbtBool, EvqTemporary, 0, 1, 2);
+ break;
+ case EHTokBool2x2:
+ new(&type) TType(EbtBool, EvqTemporary, 0, 2, 2);
+ break;
+ case EHTokBool2x3:
+ new(&type) TType(EbtBool, EvqTemporary, 0, 3, 2);
+ break;
+ case EHTokBool2x4:
+ new(&type) TType(EbtBool, EvqTemporary, 0, 4, 2);
+ break;
+ case EHTokBool3x1:
+ new(&type) TType(EbtBool, EvqTemporary, 0, 1, 3);
+ break;
+ case EHTokBool3x2:
+ new(&type) TType(EbtBool, EvqTemporary, 0, 2, 3);
+ break;
+ case EHTokBool3x3:
+ new(&type) TType(EbtBool, EvqTemporary, 0, 3, 3);
+ break;
+ case EHTokBool3x4:
+ new(&type) TType(EbtBool, EvqTemporary, 0, 4, 3);
+ break;
+ case EHTokBool4x1:
+ new(&type) TType(EbtBool, EvqTemporary, 0, 1, 4);
+ break;
+ case EHTokBool4x2:
+ new(&type) TType(EbtBool, EvqTemporary, 0, 2, 4);
+ break;
+ case EHTokBool4x3:
+ new(&type) TType(EbtBool, EvqTemporary, 0, 3, 4);
+ break;
+ case EHTokBool4x4:
+ new(&type) TType(EbtBool, EvqTemporary, 0, 4, 4);
+ break;
+
+ case EHTokFloat1x1:
+ new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 1);
+ break;
+ case EHTokFloat1x2:
+ new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 1);
+ break;
+ case EHTokFloat1x3:
+ new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 1);
+ break;
+ case EHTokFloat1x4:
+ new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 1);
+ break;
+ case EHTokFloat2x1:
+ new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 2);
+ break;
+ case EHTokFloat2x2:
+ new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 2);
+ break;
+ case EHTokFloat2x3:
+ new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 2);
+ break;
+ case EHTokFloat2x4:
+ new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 2);
+ break;
+ case EHTokFloat3x1:
+ new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 3);
+ break;
+ case EHTokFloat3x2:
+ new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 3);
+ break;
+ case EHTokFloat3x3:
+ new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 3);
+ break;
+ case EHTokFloat3x4:
+ new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 3);
+ break;
+ case EHTokFloat4x1:
+ new(&type) TType(EbtFloat, EvqTemporary, 0, 1, 4);
+ break;
+ case EHTokFloat4x2:
+ new(&type) TType(EbtFloat, EvqTemporary, 0, 2, 4);
+ break;
+ case EHTokFloat4x3:
+ new(&type) TType(EbtFloat, EvqTemporary, 0, 3, 4);
+ break;
+ case EHTokFloat4x4:
+ new(&type) TType(EbtFloat, EvqTemporary, 0, 4, 4);
+ break;
+
+ case EHTokDouble1x1:
+ new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 1);
+ break;
+ case EHTokDouble1x2:
+ new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 1);
+ break;
+ case EHTokDouble1x3:
+ new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 1);
+ break;
+ case EHTokDouble1x4:
+ new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 1);
+ break;
+ case EHTokDouble2x1:
+ new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 2);
+ break;
+ case EHTokDouble2x2:
+ new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 2);
+ break;
+ case EHTokDouble2x3:
+ new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 2);
+ break;
+ case EHTokDouble2x4:
+ new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 2);
+ break;
+ case EHTokDouble3x1:
+ new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 3);
+ break;
+ case EHTokDouble3x2:
+ new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 3);
+ break;
+ case EHTokDouble3x3:
+ new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 3);
+ break;
+ case EHTokDouble3x4:
+ new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 3);
+ break;
+ case EHTokDouble4x1:
+ new(&type) TType(EbtDouble, EvqTemporary, 0, 1, 4);
+ break;
+ case EHTokDouble4x2:
+ new(&type) TType(EbtDouble, EvqTemporary, 0, 2, 4);
+ break;
+ case EHTokDouble4x3:
+ new(&type) TType(EbtDouble, EvqTemporary, 0, 3, 4);
+ break;
+ case EHTokDouble4x4:
+ new(&type) TType(EbtDouble, EvqTemporary, 0, 4, 4);
+ break;
+
+ default:
+ return false;
+ }
+
+ advanceToken();
+
+ return true;
+}
+
+// struct
+// : STRUCT IDENTIFIER LEFT_BRACE struct_declaration_list RIGHT_BRACE
+// | STRUCT LEFT_BRACE struct_declaration_list RIGHT_BRACE
+//
+bool HlslGrammar::acceptStruct(TType& type)
+{
+ // STRUCT
+ if (! acceptTokenClass(EHTokStruct))
+ return false;
+
+ // IDENTIFIER
+ TString structName = "";
+ if (peekTokenClass(EHTokIdentifier)) {
+ structName = *token.string;
+ advanceToken();
+ }
+
+ // LEFT_BRACE
+ if (! acceptTokenClass(EHTokLeftBrace)) {
+ expected("{");
+ return false;
+ }
+
+ // struct_declaration_list
+ TTypeList* typeList;
+ if (! acceptStructDeclarationList(typeList)) {
+ expected("struct member declarations");
+ return false;
+ }
+
+ // RIGHT_BRACE
+ if (! acceptTokenClass(EHTokRightBrace)) {
+ expected("}");
+ return false;
+ }
+
+ // create the user-defined type
+ new(&type) TType(typeList, structName);
+
+ // If it was named, which means it can be reused later, add
+ // it to the symbol table.
+ if (structName.size() > 0) {
+ TVariable* userTypeDef = new TVariable(&structName, type, true);
+ if (! parseContext.symbolTable.insert(*userTypeDef))
+ parseContext.error(token.loc, "redefinition", structName.c_str(), "struct");
+ }
+
+ return true;
+}
+
+// struct_declaration_list
+// : struct_declaration SEMI_COLON struct_declaration SEMI_COLON ...
+//
+// struct_declaration
+// : fully_specified_type struct_declarator COMMA struct_declarator ...
+//
+// struct_declarator
+// : IDENTIFIER post_decls
+// | IDENTIFIER array_specifier post_decls
+//
+bool HlslGrammar::acceptStructDeclarationList(TTypeList*& typeList)
+{
+ typeList = new TTypeList();
+
+ do {
+ // success on seeing the RIGHT_BRACE coming up
+ if (peekTokenClass(EHTokRightBrace))
+ return true;
+
+ // struct_declaration
+
+ // fully_specified_type
+ TType memberType;
+ if (! acceptFullySpecifiedType(memberType)) {
+ expected("member type");
+ return false;
+ }
+
+ // struct_declarator COMMA struct_declarator ...
+ do {
+ // peek IDENTIFIER
+ if (! peekTokenClass(EHTokIdentifier)) {
+ expected("member name");
+ return false;
+ }
+
+ // add it to the list of members
+ TTypeLoc member = { new TType(EbtVoid), token.loc };
+ member.type->shallowCopy(memberType);
+ member.type->setFieldName(*token.string);
+ typeList->push_back(member);
+
+ // accept IDENTIFIER
+ advanceToken();
+
+ // array_specifier
+ // TODO
+
+ acceptPostDecls(*member.type);
+
+ // success on seeing the SEMICOLON coming up
+ if (peekTokenClass(EHTokSemicolon))
+ break;
+
+ // COMMA
+ if (! acceptTokenClass(EHTokComma)) {
+ expected(",");
+ return false;
+ }
+
+ } while (true);
+
+ // SEMI_COLON
+ if (! acceptTokenClass(EHTokSemicolon)) {
+ expected(";");
+ return false;
+ }
+
+ } while (true);
+}
+
+// function_parameters
+// : LEFT_PAREN parameter_declaration COMMA parameter_declaration ... RIGHT_PAREN
+// | LEFT_PAREN VOID RIGHT_PAREN
+//
+bool HlslGrammar::acceptFunctionParameters(TFunction& function)
+{
+ // LEFT_PAREN
+ if (! acceptTokenClass(EHTokLeftParen))
+ return false;
+
+ // VOID RIGHT_PAREN
+ if (! acceptTokenClass(EHTokVoid)) {
+ do {
+ // parameter_declaration
+ if (! acceptParameterDeclaration(function))
+ break;
+
+ // COMMA
+ if (! acceptTokenClass(EHTokComma))
+ break;
+ } while (true);
+ }
+
+ // RIGHT_PAREN
+ if (! acceptTokenClass(EHTokRightParen)) {
+ expected(")");
+ return false;
+ }
+
+ return true;
+}
+
+// parameter_declaration
+// : fully_specified_type
+// | fully_specified_type identifier
+//
+bool HlslGrammar::acceptParameterDeclaration(TFunction& function)
+{
+ // fully_specified_type
+ TType* type = new TType;
+ if (! acceptFullySpecifiedType(*type))
+ return false;
+
+ // identifier
+ HlslToken idToken;
+ acceptIdentifier(idToken);
+
+ TParameter param = { idToken.string, type };
+ function.addParameter(param);
+
+ return true;
+}
+
+// Do the work to create the function definition in addition to
+// parsing the body (compound_statement).
+bool HlslGrammar::acceptFunctionDefinition(TFunction& function, TIntermNode*& node)
+{
+ TFunction* functionDeclarator = parseContext.handleFunctionDeclarator(token.loc, function, false /* not prototype */);
+
+ // This does a pushScope()
+ node = parseContext.handleFunctionDefinition(token.loc, *functionDeclarator);
+
+ // compound_statement
+ TIntermNode* functionBody = nullptr;
+ if (acceptCompoundStatement(functionBody)) {
+ node = intermediate.growAggregate(node, functionBody);
+ intermediate.setAggregateOperator(node, EOpFunction, functionDeclarator->getType(), token.loc);
+ node->getAsAggregate()->setName(functionDeclarator->getMangledName().c_str());
+ parseContext.popScope();
+
+ return true;
+ }
+
+ return false;
+}
+
+// Accept an expression with parenthesis around it, where
+// the parenthesis ARE NOT expression parenthesis, but the
+// syntactically required ones like in "if ( expression )"
+//
+// Note this one is not set up to be speculative; as it gives
+// errors if not found.
+//
+bool HlslGrammar::acceptParenExpression(TIntermTyped*& expression)
+{
+ // LEFT_PAREN
+ if (! acceptTokenClass(EHTokLeftParen))
+ expected("(");
+
+ if (! acceptExpression(expression)) {
+ expected("expression");
+ return false;
+ }
+
+ // RIGHT_PAREN
+ if (! acceptTokenClass(EHTokRightParen))
+ expected(")");
+
+ return true;
+}
+
+// The top-level full expression recognizer.
+//
+// expression
+// : assignment_expression COMMA assignment_expression COMMA assignment_expression ...
+//
+bool HlslGrammar::acceptExpression(TIntermTyped*& node)
+{
+ node = nullptr;
+
+ // assignment_expression
+ if (! acceptAssignmentExpression(node))
+ return false;
+
+ if (! peekTokenClass(EHTokComma))
+ return true;
+
+ do {
+ // ... COMMA
+ TSourceLoc loc = token.loc;
+ advanceToken();
+
+ // ... assignment_expression
+ TIntermTyped* rightNode = nullptr;
+ if (! acceptAssignmentExpression(rightNode)) {
+ expected("assignment expression");
+ return false;
+ }
+
+ node = intermediate.addComma(node, rightNode, loc);
+
+ if (! peekTokenClass(EHTokComma))
+ return true;
+ } while (true);
+}
+
+// Accept an assignment expression, where assignment operations
+// associate right-to-left. This is, it is implicit, for example
+//
+// a op (b op (c op d))
+//
+// assigment_expression
+// : binary_expression op binary_expression op binary_expression ...
+//
+bool HlslGrammar::acceptAssignmentExpression(TIntermTyped*& node)
+{
+ if (! acceptBinaryExpression(node, PlLogicalOr))
+ return false;
+
+ TOperator assignOp = HlslOpMap::assignment(peek());
+ if (assignOp == EOpNull)
+ return true;
+
+ // ... op
+ TSourceLoc loc = token.loc;
+ advanceToken();
+
+ // ... binary_expression
+ // But, done by recursing this function, which automatically
+ // gets the right-to-left associativity.
+ TIntermTyped* rightNode = nullptr;
+ if (! acceptAssignmentExpression(rightNode)) {
+ expected("assignment expression");
+ return false;
+ }
+
+ node = intermediate.addAssign(assignOp, node, rightNode, loc);
+
+ if (! peekTokenClass(EHTokComma))
+ return true;
+
+ return true;
+}
+
+// Accept a binary expression, for binary operations that
+// associate left-to-right. This is, it is implicit, for example
+//
+// ((a op b) op c) op d
+//
+// binary_expression
+// : expression op expression op expression ...
+//
+// where 'expression' is the next higher level in precedence.
+//
+bool HlslGrammar::acceptBinaryExpression(TIntermTyped*& node, PrecedenceLevel precedenceLevel)
+{
+ if (precedenceLevel > PlMul)
+ return acceptUnaryExpression(node);
+
+ // assignment_expression
+ if (! acceptBinaryExpression(node, (PrecedenceLevel)(precedenceLevel + 1)))
+ return false;
+
+ TOperator op = HlslOpMap::binary(peek());
+ PrecedenceLevel tokenLevel = HlslOpMap::precedenceLevel(op);
+ if (tokenLevel < precedenceLevel)
+ return true;
+
+ do {
+ // ... op
+ TSourceLoc loc = token.loc;
+ advanceToken();
+
+ // ... expression
+ TIntermTyped* rightNode = nullptr;
+ if (! acceptBinaryExpression(rightNode, (PrecedenceLevel)(precedenceLevel + 1))) {
+ expected("expression");
+ return false;
+ }
+
+ node = intermediate.addBinaryMath(op, node, rightNode, loc);
+
+ if (! peekTokenClass(EHTokComma))
+ return true;
+ } while (true);
+}
+
+// unary_expression
+// : (type) unary_expression
+// | + unary_expression
+// | - unary_expression
+// | ! unary_expression
+// | ~ unary_expression
+// | ++ unary_expression
+// | -- unary_expression
+// | postfix_expression
+//
+bool HlslGrammar::acceptUnaryExpression(TIntermTyped*& node)
+{
+ // (type) unary_expression
+ // Have to look two steps ahead, because this could be, e.g., a
+ // postfix_expression instead, since that also starts with at "(".
+ if (acceptTokenClass(EHTokLeftParen)) {
+ TType castType;
+ if (acceptType(castType)) {
+ if (! acceptTokenClass(EHTokRightParen)) {
+ expected(")");
+ return false;
+ }
+
+ // We've matched "(type)" now, get the expression to cast
+ TSourceLoc loc = token.loc;
+ if (! acceptUnaryExpression(node))
+ return false;
+
+ // Hook it up like a constructor
+ TFunction* constructorFunction = parseContext.handleConstructorCall(loc, castType);
+ if (constructorFunction == nullptr) {
+ expected("type that can be constructed");
+ return false;
+ }
+ TIntermTyped* arguments = nullptr;
+ parseContext.handleFunctionArgument(constructorFunction, arguments, node);
+ node = parseContext.handleFunctionCall(loc, constructorFunction, arguments);
+
+ return true;
+ } else {
+ // This isn't a type cast, but it still started "(", so if it is a
+ // unary expression, it can only be a postfix_expression, so try that.
+ // Back it up first.
+ recedeToken();
+ return acceptPostfixExpression(node);
+ }
+ }
+
+ // peek for "op unary_expression"
+ TOperator unaryOp = HlslOpMap::preUnary(peek());
+
+ // postfix_expression (if no unary operator)
+ if (unaryOp == EOpNull)
+ return acceptPostfixExpression(node);
+
+ // op unary_expression
+ TSourceLoc loc = token.loc;
+ advanceToken();
+ if (! acceptUnaryExpression(node))
+ return false;
+
+ // + is a no-op
+ if (unaryOp == EOpAdd)
+ return true;
+
+ node = intermediate.addUnaryMath(unaryOp, node, loc);
+
+ return node != nullptr;
+}
+
+// postfix_expression
+// : LEFT_PAREN expression RIGHT_PAREN
+// | literal
+// | constructor
+// | identifier
+// | function_call
+// | postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET
+// | postfix_expression DOT IDENTIFIER
+// | postfix_expression INC_OP
+// | postfix_expression DEC_OP
+//
+bool HlslGrammar::acceptPostfixExpression(TIntermTyped*& node)
+{
+ // Not implemented as self-recursive:
+ // The logical "right recursion" is done with an loop at the end
+
+ // idToken will pick up either a variable or a function name in a function call
+ HlslToken idToken;
+
+ // Find something before the postfix operations, as they can't operate
+ // on nothing. So, no "return true", they fall through, only "return false".
+ if (acceptTokenClass(EHTokLeftParen)) {
+ // LEFT_PAREN expression RIGHT_PAREN
+ if (! acceptExpression(node)) {
+ expected("expression");
+ return false;
+ }
+ if (! acceptTokenClass(EHTokRightParen)) {
+ expected(")");
+ return false;
+ }
+ } else if (acceptLiteral(node)) {
+ // literal (nothing else to do yet), go on to the
+ } else if (acceptConstructor(node)) {
+ // constructor (nothing else to do yet)
+ } else if (acceptIdentifier(idToken)) {
+ // identifier or function_call name
+ if (! peekTokenClass(EHTokLeftParen)) {
+ node = parseContext.handleVariable(idToken.loc, idToken.symbol, token.string);
+ } else if (acceptFunctionCall(idToken, node)) {
+ // function_call (nothing else to do yet)
+ } else {
+ expected("function call arguments");
+ return false;
+ }
+ } else {
+ // nothing found, can't post operate
+ return false;
+ }
+
+ // Something was found, chain as many postfix operations as exist.
+ do {
+ TSourceLoc loc = token.loc;
+ TOperator postOp = HlslOpMap::postUnary(peek());
+
+ // Consume only a valid post-unary operator, otherwise we are done.
+ switch (postOp) {
+ case EOpIndexDirectStruct:
+ case EOpIndexIndirect:
+ case EOpPostIncrement:
+ case EOpPostDecrement:
+ advanceToken();
+ break;
+ default:
+ return true;
+ }
+
+ // We have a valid post-unary operator, process it.
+ switch (postOp) {
+ case EOpIndexDirectStruct:
+ // todo
+ break;
+ case EOpIndexIndirect:
+ {
+ TIntermTyped* indexNode = nullptr;
+ if (! acceptExpression(indexNode) ||
+ ! peekTokenClass(EHTokRightBracket)) {
+ expected("expression followed by ']'");
+ return false;
+ }
+ // todo: node = intermediate.addBinaryMath(
+ }
+ case EOpPostIncrement:
+ case EOpPostDecrement:
+ node = intermediate.addUnaryMath(postOp, node, loc);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ } while (true);
+}
+
+// constructor
+// : type argument_list
+//
+bool HlslGrammar::acceptConstructor(TIntermTyped*& node)
+{
+ // type
+ TType type;
+ if (acceptType(type)) {
+ TFunction* constructorFunction = parseContext.handleConstructorCall(token.loc, type);
+ if (constructorFunction == nullptr)
+ return false;
+
+ // arguments
+ TIntermTyped* arguments = nullptr;
+ if (! acceptArguments(constructorFunction, arguments)) {
+ expected("constructor arguments");
+ return false;
+ }
+
+ // hook it up
+ node = parseContext.handleFunctionCall(arguments->getLoc(), constructorFunction, arguments);
+
+ return true;
+ }
+
+ return false;
+}
+
+// The function_call identifier was already recognized, and passed in as idToken.
+//
+// function_call
+// : [idToken] arguments
+//
+bool HlslGrammar::acceptFunctionCall(HlslToken idToken, TIntermTyped*& node)
+{
+ // arguments
+ TFunction* function = new TFunction(idToken.string, TType(EbtVoid));
+ TIntermTyped* arguments = nullptr;
+ if (! acceptArguments(function, arguments))
+ return false;
+
+ node = parseContext.handleFunctionCall(idToken.loc, function, arguments);
+
+ return true;
+}
+
+// arguments
+// : LEFT_PAREN expression COMMA expression COMMA ... RIGHT_PAREN
+//
+// The arguments are pushed onto the 'function' argument list and
+// onto the 'arguments' aggregate.
+//
+bool HlslGrammar::acceptArguments(TFunction* function, TIntermTyped*& arguments)
+{
+ // LEFT_PAREN
+ if (! acceptTokenClass(EHTokLeftParen))
+ return false;
+
+ do {
+ // expression
+ TIntermTyped* arg;
+ if (! acceptAssignmentExpression(arg))
+ break;
+
+ // hook it up
+ parseContext.handleFunctionArgument(function, arguments, arg);
+
+ // COMMA
+ if (! acceptTokenClass(EHTokComma))
+ break;
+ } while (true);
+
+ // RIGHT_PAREN
+ if (! acceptTokenClass(EHTokRightParen)) {
+ expected(")");
+ return false;
+ }
+
+ return true;
+}
+
+bool HlslGrammar::acceptLiteral(TIntermTyped*& node)
+{
+ switch (token.tokenClass) {
+ case EHTokIntConstant:
+ node = intermediate.addConstantUnion(token.i, token.loc, true);
+ break;
+ case EHTokFloatConstant:
+ node = intermediate.addConstantUnion(token.d, EbtFloat, token.loc, true);
+ break;
+ case EHTokDoubleConstant:
+ node = intermediate.addConstantUnion(token.d, EbtDouble, token.loc, true);
+ break;
+ case EHTokBoolConstant:
+ node = intermediate.addConstantUnion(token.b, token.loc, true);
+ break;
+
+ default:
+ return false;
+ }
+
+ advanceToken();
+
+ return true;
+}
+
+// compound_statement
+// : LEFT_CURLY statement statement ... RIGHT_CURLY
+//
+bool HlslGrammar::acceptCompoundStatement(TIntermNode*& retStatement)
+{
+ TIntermAggregate* compoundStatement = nullptr;
+
+ // LEFT_CURLY
+ if (! acceptTokenClass(EHTokLeftBrace))
+ return false;
+
+ // statement statement ...
+ TIntermNode* statement = nullptr;
+ while (acceptStatement(statement)) {
+ // hook it up
+ compoundStatement = intermediate.growAggregate(compoundStatement, statement);
+ }
+ if (compoundStatement)
+ compoundStatement->setOperator(EOpSequence);
+
+ retStatement = compoundStatement;
+
+ // RIGHT_CURLY
+ return acceptTokenClass(EHTokRightBrace);
+}
+
+bool HlslGrammar::acceptScopedStatement(TIntermNode*& statement)
+{
+ parseContext.pushScope();
+ bool result = acceptStatement(statement);
+ parseContext.popScope();
+
+ return result;
+}
+
+bool HlslGrammar::acceptScopedCompoundStatement(TIntermNode*& statement)
+{
+ parseContext.pushScope();
+ bool result = acceptCompoundStatement(statement);
+ parseContext.popScope();
+
+ return result;
+}
+
+// statement
+// : attributes attributed_statement
+//
+// attributed_statement
+// : compound_statement
+// | SEMICOLON
+// | expression SEMICOLON
+// | declaration_statement
+// | selection_statement
+// | switch_statement
+// | case_label
+// | iteration_statement
+// | jump_statement
+//
+bool HlslGrammar::acceptStatement(TIntermNode*& statement)
+{
+ statement = nullptr;
+
+ // attributes
+ acceptAttributes();
+
+ // attributed_statement
+ switch (peek()) {
+ case EHTokLeftBrace:
+ return acceptScopedCompoundStatement(statement);
+
+ case EHTokIf:
+ return acceptSelectionStatement(statement);
+
+ case EHTokSwitch:
+ return acceptSwitchStatement(statement);
+
+ case EHTokFor:
+ case EHTokDo:
+ case EHTokWhile:
+ return acceptIterationStatement(statement);
+
+ case EHTokContinue:
+ case EHTokBreak:
+ case EHTokDiscard:
+ case EHTokReturn:
+ return acceptJumpStatement(statement);
+
+ case EHTokCase:
+ return acceptCaseLabel(statement);
+
+ case EHTokSemicolon:
+ return acceptTokenClass(EHTokSemicolon);
+
+ case EHTokRightBrace:
+ // Performance: not strictly necessary, but stops a bunch of hunting early,
+ // and is how sequences of statements end.
+ return false;
+
+ default:
+ {
+ // declaration
+ if (acceptDeclaration(statement))
+ return true;
+
+ // expression
+ TIntermTyped* node;
+ if (acceptExpression(node))
+ statement = node;
+ else
+ return false;
+
+ // SEMICOLON (following an expression)
+ if (! acceptTokenClass(EHTokSemicolon)) {
+ expected(";");
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+// attributes
+// : list of zero or more of: LEFT_BRACKET attribute RIGHT_BRACKET
+//
+// attribute:
+// : UNROLL
+// | UNROLL LEFT_PAREN literal RIGHT_PAREN
+// | FASTOPT
+// | ALLOW_UAV_CONDITION
+// | BRANCH
+// | FLATTEN
+// | FORCECASE
+// | CALL
+//
+void HlslGrammar::acceptAttributes()
+{
+ // For now, accept the [ XXX(X) ] syntax, but drop.
+ // TODO: subset to correct set? Pass on?
+ do {
+ // LEFT_BRACKET?
+ if (! acceptTokenClass(EHTokLeftBracket))
+ return;
+
+ // attribute
+ if (peekTokenClass(EHTokIdentifier)) {
+ // 'token.string' is the attribute
+ advanceToken();
+ } else if (! peekTokenClass(EHTokRightBracket)) {
+ expected("identifier");
+ advanceToken();
+ }
+
+ // (x)
+ if (acceptTokenClass(EHTokLeftParen)) {
+ TIntermTyped* node;
+ if (! acceptLiteral(node))
+ expected("literal");
+ // 'node' has the literal in it
+ if (! acceptTokenClass(EHTokRightParen))
+ expected(")");
+ }
+
+ // RIGHT_BRACKET
+ if (acceptTokenClass(EHTokRightBracket))
+ continue;
+
+ expected("]");
+ return;
+
+ } while (true);
+}
+
+// selection_statement
+// : IF LEFT_PAREN expression RIGHT_PAREN statement
+// : IF LEFT_PAREN expression RIGHT_PAREN statement ELSE statement
+//
+bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement)
+{
+ TSourceLoc loc = token.loc;
+
+ // IF
+ if (! acceptTokenClass(EHTokIf))
+ return false;
+
+ // so that something declared in the condition is scoped to the lifetimes
+ // of the then-else statements
+ parseContext.pushScope();
+
+ // LEFT_PAREN expression RIGHT_PAREN
+ TIntermTyped* condition;
+ if (! acceptParenExpression(condition))
+ return false;
+
+ // create the child statements
+ TIntermNodePair thenElse = { nullptr, nullptr };
+
+ // then statement
+ if (! acceptScopedStatement(thenElse.node1)) {
+ expected("then statement");
+ return false;
+ }
+
+ // ELSE
+ if (acceptTokenClass(EHTokElse)) {
+ // else statement
+ if (! acceptScopedStatement(thenElse.node2)) {
+ expected("else statement");
+ return false;
+ }
+ }
+
+ // Put the pieces together
+ statement = intermediate.addSelection(condition, thenElse, loc);
+ parseContext.popScope();
+
+ return true;
+}
+
+bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement)
+{
+ return false;
+}
+
+// iteration_statement
+// : WHILE LEFT_PAREN condition RIGHT_PAREN statement
+// | DO LEFT_BRACE statement RIGHT_BRACE WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON
+// | FOR LEFT_PAREN for_init_statement for_rest_statement RIGHT_PAREN statement
+//
+// Non-speculative, only call if it needs to be found; WHILE or DO or FOR already seen.
+bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement)
+{
+ TSourceLoc loc = token.loc;
+ TIntermTyped* condition = nullptr;
+
+ EHlslTokenClass loop = peek();
+ assert(loop == EHTokDo || loop == EHTokFor || loop == EHTokWhile);
+
+ // WHILE or DO or FOR
+ advanceToken();
+
+ switch (loop) {
+ case EHTokWhile:
+ // so that something declared in the condition is scoped to the lifetime
+ // of the while sub-statement
+ parseContext.pushScope();
+ parseContext.nestLooping();
+
+ // LEFT_PAREN condition RIGHT_PAREN
+ if (! acceptParenExpression(condition))
+ return false;
+
+ // statement
+ if (! acceptScopedStatement(statement)) {
+ expected("while sub-statement");
+ return false;
+ }
+
+ parseContext.unnestLooping();
+ parseContext.popScope();
+
+ statement = intermediate.addLoop(statement, condition, nullptr, true, loc);
+
+ return true;
+
+ case EHTokDo:
+ parseContext.nestLooping();
+
+ if (! acceptTokenClass(EHTokLeftBrace))
+ expected("{");
+
+ // statement
+ if (! peekTokenClass(EHTokRightBrace) && ! acceptScopedStatement(statement)) {
+ expected("do sub-statement");
+ return false;
+ }
+
+ if (! acceptTokenClass(EHTokRightBrace))
+ expected("}");
+
+ // WHILE
+ if (! acceptTokenClass(EHTokWhile)) {
+ expected("while");
+ return false;
+ }
+
+ // LEFT_PAREN condition RIGHT_PAREN
+ TIntermTyped* condition;
+ if (! acceptParenExpression(condition))
+ return false;
+
+ if (! acceptTokenClass(EHTokSemicolon))
+ expected(";");
+
+ parseContext.unnestLooping();
+
+ statement = intermediate.addLoop(statement, condition, 0, false, loc);
+
+ return true;
+
+ case EHTokFor:
+ {
+ // LEFT_PAREN
+ if (! acceptTokenClass(EHTokLeftParen))
+ expected("(");
+
+ // so that something declared in the condition is scoped to the lifetime
+ // of the for sub-statement
+ parseContext.pushScope();
+
+ // initializer SEMI_COLON
+ TIntermTyped* initializer = nullptr; // TODO, "for (initializer" needs to support decl. statement
+ acceptExpression(initializer);
+ if (! acceptTokenClass(EHTokSemicolon))
+ expected(";");
+
+ parseContext.nestLooping();
+
+ // condition SEMI_COLON
+ acceptExpression(condition);
+ if (! acceptTokenClass(EHTokSemicolon))
+ expected(";");
+
+ // iterator SEMI_COLON
+ TIntermTyped* iterator = nullptr;
+ acceptExpression(iterator);
+ if (! acceptTokenClass(EHTokRightParen))
+ expected(")");
+
+ // statement
+ if (! acceptScopedStatement(statement)) {
+ expected("for sub-statement");
+ return false;
+ }
+
+ statement = intermediate.addForLoop(statement, initializer, condition, iterator, true, loc);
+
+ parseContext.popScope();
+ parseContext.unnestLooping();
+
+ return true;
+ }
+
+ default:
+ return false;
+ }
+}
+
+// jump_statement
+// : CONTINUE SEMICOLON
+// | BREAK SEMICOLON
+// | DISCARD SEMICOLON
+// | RETURN SEMICOLON
+// | RETURN expression SEMICOLON
+//
+bool HlslGrammar::acceptJumpStatement(TIntermNode*& statement)
+{
+ switch (peek()) {
+ case EHTokContinue:
+ case EHTokBreak:
+ case EHTokDiscard:
+ // TODO
+ return false;
+
+ case EHTokReturn:
+ // return
+ if (acceptTokenClass(EHTokReturn)) {
+ // expression
+ TIntermTyped* node;
+ if (acceptExpression(node)) {
+ // hook it up
+ statement = intermediate.addBranch(EOpReturn, node, token.loc);
+ } else
+ statement = intermediate.addBranch(EOpReturn, token.loc);
+
+ // SEMICOLON
+ if (! acceptTokenClass(EHTokSemicolon)) {
+ expected(";");
+ return false;
+ }
+
+ return true;
+ }
+
+ default:
+ return false;
+ }
+}
+
+
+bool HlslGrammar::acceptCaseLabel(TIntermNode*& statement)
+{
+ return false;
+}
+
+// post_decls
+// : COLON semantic // optional
+// COLON PACKOFFSET LEFT_PAREN ... RIGHT_PAREN // optional
+// COLON REGISTER // optional
+// annotations // optional
+//
+void HlslGrammar::acceptPostDecls(TType& type)
+{
+ do {
+ // COLON
+ if (acceptTokenClass(EHTokColon)) {
+ HlslToken idToken;
+ if (acceptTokenClass(EHTokPackOffset)) {
+ if (! acceptTokenClass(EHTokLeftParen)) {
+ expected("(");
+ return;
+ }
+ acceptTokenClass(EHTokIdentifier);
+ acceptTokenClass(EHTokDot);
+ acceptTokenClass(EHTokIdentifier);
+ if (! acceptTokenClass(EHTokRightParen)) {
+ expected(")");
+ break;
+ }
+ // TODO: process the packoffset information
+ } else if (! acceptIdentifier(idToken)) {
+ expected("semantic or packoffset or register");
+ return;
+ } else if (*idToken.string == "register") {
+ if (! acceptTokenClass(EHTokLeftParen)) {
+ expected("(");
+ return;
+ }
+ acceptTokenClass(EHTokIdentifier);
+ acceptTokenClass(EHTokComma);
+ acceptTokenClass(EHTokIdentifier);
+ acceptTokenClass(EHTokLeftBracket);
+ if (peekTokenClass(EHTokIntConstant))
+ advanceToken();
+ acceptTokenClass(EHTokRightBracket);
+ if (! acceptTokenClass(EHTokRightParen)) {
+ expected(")");
+ break;
+ }
+ // TODO: process the register information
+ } else {
+ // semantic, in idToken.string
+ parseContext.handleSemantic(type, *idToken.string);
+ }
+ } else if (acceptTokenClass(EHTokLeftAngle)) {
+ // TODO: process annotations, just accepting them for now
+ do {
+ if (peekTokenClass(EHTokNone))
+ return;
+ if (acceptTokenClass(EHTokRightAngle))
+ break;
+ advanceToken();
+ } while (true);
+ } else
+ break;
+
+ } while (true);
+}
+
+} // end namespace glslang