HLSL: Grammar: Generalize accepting a declaration to accept an aggregate of subtrees.

This is slightly cleaner today for entry-point wrapping, which sometimes made
two subtrees for a function definition instead of just one subtree.  It will be
critical though for recognizing a struct with multiple member functions.
This commit is contained in:
John Kessenich 2017-03-07 20:44:09 -07:00
parent 057df2935a
commit ca71d946d7
5 changed files with 49 additions and 44 deletions

View File

@ -2,5 +2,5 @@
// For the version, it uses the latest git tag followed by the number of commits. // For the version, it uses the latest git tag followed by the number of commits.
// For the date, it uses the current date (when then script is run). // For the date, it uses the current date (when then script is run).
#define GLSLANG_REVISION "Overload400-PrecQual.1881" #define GLSLANG_REVISION "Overload400-PrecQual.1882"
#define GLSLANG_DATE "06-Mar-2017" #define GLSLANG_DATE "07-Mar-2017"

View File

@ -1158,15 +1158,15 @@ TIntermAggregate* TIntermediate::growAggregate(TIntermNode* left, TIntermNode* r
return nullptr; return nullptr;
TIntermAggregate* aggNode = nullptr; TIntermAggregate* aggNode = nullptr;
if (left) if (left != nullptr)
aggNode = left->getAsAggregate(); aggNode = left->getAsAggregate();
if (! aggNode || aggNode->getOp() != EOpNull) { if (aggNode == nullptr || aggNode->getOp() != EOpNull) {
aggNode = new TIntermAggregate; aggNode = new TIntermAggregate;
if (left) if (left != nullptr)
aggNode->getSequence().push_back(left); aggNode->getSequence().push_back(left);
} }
if (right) if (right != nullptr)
aggNode->getSequence().push_back(right); aggNode->getSequence().push_back(right);
return aggNode; return aggNode;

View File

@ -131,18 +131,13 @@ bool HlslGrammar::acceptCompilationUnit()
continue; continue;
// externalDeclaration // externalDeclaration
TIntermNode* declarationNode1; if (! acceptDeclaration(unitNode))
TIntermNode* declarationNode2 = nullptr; // sometimes the grammar for a single declaration creates two
if (! acceptDeclaration(declarationNode1, declarationNode2))
return false; return false;
// hook it up
unitNode = intermediate.growAggregate(unitNode, declarationNode1);
if (declarationNode2 != nullptr)
unitNode = intermediate.growAggregate(unitNode, declarationNode2);
} }
// set root of AST // set root of AST
if (unitNode && !unitNode->getAsAggregate())
unitNode = intermediate.growAggregate(nullptr, unitNode);
intermediate.setTreeRoot(unitNode); intermediate.setTreeRoot(unitNode);
return true; return true;
@ -292,21 +287,17 @@ bool HlslGrammar::acceptSamplerDeclarationDX9(TType& /*type*/)
// as above. (The 'identifier' in the first item in init_declarator list is the // as above. (The 'identifier' in the first item in init_declarator list is the
// same as 'identifier' for function declarations.) // same as 'identifier' for function declarations.)
// //
// 'node' could get populated if the declaration creates code, like an initializer // This can generate more than one subtree, one per initializer or a function body.
// or a function body. // All initializer subtrees are put in their own aggregate node, making one top-level
// node for all the initializers. Each function created is a top-level node to grow
// into the passed-in nodeList.
// //
// 'node2' could get populated with a second decoration tree if a single source declaration // If 'nodeList' is passed in as non-null, it must an aggregate to extend for
// leads to two subtrees that need to be peers higher up. // each top-level node the declaration creates. Otherwise, if only one top-level
// node in generated here, that is want is returned in nodeList.
// //
bool HlslGrammar::acceptDeclaration(TIntermNode*& node) bool HlslGrammar::acceptDeclaration(TIntermNode*& nodeList)
{ {
TIntermNode* node2;
return acceptDeclaration(node, node2);
}
bool HlslGrammar::acceptDeclaration(TIntermNode*& node, TIntermNode*& node2)
{
node = nullptr;
node2 = nullptr;
bool list = false; bool list = false;
// attributes // attributes
@ -324,9 +315,8 @@ bool HlslGrammar::acceptDeclaration(TIntermNode*& node, TIntermNode*& node2)
// HLSL shaders, this will have to be a master level switch // HLSL shaders, this will have to be a master level switch
// As such, the sampler keyword in D3D10+ turns into an automatic sampler type, and is commonly used // As such, the sampler keyword in D3D10+ turns into an automatic sampler type, and is commonly used
// For that reason, this line is commented out // For that reason, this line is commented out
// if (acceptSamplerDeclarationDX9(declaredType))
// if (acceptSamplerDeclarationDX9(declaredType)) // return true;
// return true;
// fully_specified_type // fully_specified_type
if (! acceptFullySpecifiedType(declaredType)) if (! acceptFullySpecifiedType(declaredType))
@ -334,6 +324,7 @@ bool HlslGrammar::acceptDeclaration(TIntermNode*& node, TIntermNode*& node2)
// identifier // identifier
HlslToken idToken; HlslToken idToken;
TIntermAggregate* initializers = nullptr;
while (acceptIdentifier(idToken)) { while (acceptIdentifier(idToken)) {
TString* fnName = idToken.string; TString* fnName = idToken.string;
@ -352,7 +343,7 @@ bool HlslGrammar::acceptDeclaration(TIntermNode*& node, TIntermNode*& node2)
parseContext.error(idToken.loc, "function body can't be in a declarator list", "{", ""); parseContext.error(idToken.loc, "function body can't be in a declarator list", "{", "");
if (typedefDecl) if (typedefDecl)
parseContext.error(idToken.loc, "function body can't be in a typedef", "{", ""); parseContext.error(idToken.loc, "function body can't be in a typedef", "{", "");
return acceptFunctionDefinition(function, node, node2, attributes); return acceptFunctionDefinition(function, nodeList, attributes);
} else { } else {
if (typedefDecl) if (typedefDecl)
parseContext.error(idToken.loc, "function typedefs not implemented", "{", ""); parseContext.error(idToken.loc, "function typedefs not implemented", "{", "");
@ -421,10 +412,9 @@ bool HlslGrammar::acceptDeclaration(TIntermNode*& node, TIntermNode*& node2)
// Declare the variable and add any initializer code to the AST. // Declare the variable and add any initializer code to the AST.
// The top-level node is always made into an aggregate, as that's // The top-level node is always made into an aggregate, as that's
// historically how the AST has been. // historically how the AST has been.
node = intermediate.growAggregate(node, initializers = intermediate.growAggregate(initializers,
parseContext.declareVariable(idToken.loc, *idToken.string, variableType, parseContext.declareVariable(idToken.loc, *idToken.string, variableType, expressionNode),
expressionNode), idToken.loc);
idToken.loc);
} }
} }
} }
@ -436,9 +426,15 @@ bool HlslGrammar::acceptDeclaration(TIntermNode*& node, TIntermNode*& node2)
} }
}; };
// The top-level node is a sequence. // The top-level initializer node is a sequence.
if (node != nullptr) if (initializers != nullptr)
node->getAsAggregate()->setOperator(EOpSequence); initializers->setOperator(EOpSequence);
// Add the initializers' aggregate to the nodeList we were handed.
if (nodeList)
nodeList = intermediate.growAggregate(nodeList, initializers);
else
nodeList = initializers;
// SEMICOLON // SEMICOLON
if (! acceptTokenClass(EHTokSemicolon)) { if (! acceptTokenClass(EHTokSemicolon)) {
@ -989,7 +985,7 @@ bool HlslGrammar::acceptAnnotations(TQualifier&)
break; break;
// declaration // declaration
TIntermNode* node; TIntermNode* node = nullptr;
if (! acceptDeclaration(node)) { if (! acceptDeclaration(node)) {
expected("declaration in annotation"); expected("declaration in annotation");
return false; return false;
@ -2114,20 +2110,28 @@ bool HlslGrammar::acceptParameterDeclaration(TFunction& function)
// Do the work to create the function definition in addition to // Do the work to create the function definition in addition to
// parsing the body (compound_statement). // parsing the body (compound_statement).
bool HlslGrammar::acceptFunctionDefinition(TFunction& function, TIntermNode*& node, TIntermNode*& node2, const TAttributeMap& attributes) bool HlslGrammar::acceptFunctionDefinition(TFunction& function, TIntermNode*& nodeList, const TAttributeMap& attributes)
{ {
TFunction& functionDeclarator = parseContext.handleFunctionDeclarator(token.loc, function, false /* not prototype */); TFunction& functionDeclarator = parseContext.handleFunctionDeclarator(token.loc, function, false /* not prototype */);
TSourceLoc loc = token.loc; TSourceLoc loc = token.loc;
// we might get back and entry-point
TIntermNode* entryPointNode = nullptr;
// This does a pushScope() // This does a pushScope()
node = parseContext.handleFunctionDefinition(loc, functionDeclarator, attributes, node2); TIntermNode* functionNode = parseContext.handleFunctionDefinition(loc, functionDeclarator, attributes,
entryPointNode);
// compound_statement // compound_statement
TIntermNode* functionBody = nullptr; TIntermNode* functionBody = nullptr;
if (! acceptCompoundStatement(functionBody)) if (! acceptCompoundStatement(functionBody))
return false; return false;
parseContext.handleFunctionBody(loc, functionDeclarator, functionBody, node); parseContext.handleFunctionBody(loc, functionDeclarator, functionBody, functionNode);
// Hook up the 1 or 2 function definitions.
nodeList = intermediate.growAggregate(nodeList, functionNode);
nodeList = intermediate.growAggregate(nodeList, entryPointNode);
return true; return true;
} }
@ -2528,7 +2532,7 @@ bool HlslGrammar::acceptPostfixExpression(TIntermTyped*& node)
~tFinalize() { parseContext.finalizeFlattening(); } ~tFinalize() { parseContext.finalizeFlattening(); }
HlslParseContext& parseContext; HlslParseContext& parseContext;
private: private:
const tFinalize& operator=(const tFinalize& f) { return *this; } const tFinalize& operator=(const tFinalize&) { return *this; }
tFinalize(const tFinalize& f) : parseContext(f.parseContext) { } tFinalize(const tFinalize& f) : parseContext(f.parseContext) { }
} finalize(parseContext); } finalize(parseContext);

View File

@ -65,7 +65,6 @@ namespace glslang {
bool acceptIdentifier(HlslToken&); bool acceptIdentifier(HlslToken&);
bool acceptCompilationUnit(); bool acceptCompilationUnit();
bool acceptDeclaration(TIntermNode*&); bool acceptDeclaration(TIntermNode*&);
bool acceptDeclaration(TIntermNode*& node1, TIntermNode*& node2);
bool acceptControlDeclaration(TIntermNode*& node); bool acceptControlDeclaration(TIntermNode*& node);
bool acceptSamplerDeclarationDX9(TType&); bool acceptSamplerDeclarationDX9(TType&);
bool acceptSamplerState(); bool acceptSamplerState();
@ -88,7 +87,7 @@ namespace glslang {
bool acceptStructDeclarationList(TTypeList*&); bool acceptStructDeclarationList(TTypeList*&);
bool acceptFunctionParameters(TFunction&); bool acceptFunctionParameters(TFunction&);
bool acceptParameterDeclaration(TFunction&); bool acceptParameterDeclaration(TFunction&);
bool acceptFunctionDefinition(TFunction&, TIntermNode*& node1, TIntermNode*& node2, const TAttributeMap&); bool acceptFunctionDefinition(TFunction&, TIntermNode*& nodeList, const TAttributeMap&);
bool acceptParenExpression(TIntermTyped*&); bool acceptParenExpression(TIntermTyped*&);
bool acceptExpression(TIntermTyped*&); bool acceptExpression(TIntermTyped*&);
bool acceptInitializer(TIntermTyped*&); bool acceptInitializer(TIntermTyped*&);

View File

@ -1521,6 +1521,8 @@ void HlslParseContext::addInterstageIoToLinkage()
// Handle seeing the function prototype in front of a function definition in the grammar. // Handle seeing the function prototype in front of a function definition in the grammar.
// The body is handled after this function returns. // The body is handled after this function returns.
// //
// Returns an aggregate of parameter-symbol nodes.
//
TIntermAggregate* HlslParseContext::handleFunctionDefinition(const TSourceLoc& loc, TFunction& function, TIntermAggregate* HlslParseContext::handleFunctionDefinition(const TSourceLoc& loc, TFunction& function,
const TAttributeMap& attributes, TIntermNode*& entryPointTree) const TAttributeMap& attributes, TIntermNode*& entryPointTree)
{ {