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 date, it uses the current date (when then script is run).
#define GLSLANG_REVISION "Overload400-PrecQual.1881"
#define GLSLANG_DATE "06-Mar-2017"
#define GLSLANG_REVISION "Overload400-PrecQual.1882"
#define GLSLANG_DATE "07-Mar-2017"

View File

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

View File

@ -131,18 +131,13 @@ bool HlslGrammar::acceptCompilationUnit()
continue;
// externalDeclaration
TIntermNode* declarationNode1;
TIntermNode* declarationNode2 = nullptr; // sometimes the grammar for a single declaration creates two
if (! acceptDeclaration(declarationNode1, declarationNode2))
if (! acceptDeclaration(unitNode))
return false;
// hook it up
unitNode = intermediate.growAggregate(unitNode, declarationNode1);
if (declarationNode2 != nullptr)
unitNode = intermediate.growAggregate(unitNode, declarationNode2);
}
// set root of AST
if (unitNode && !unitNode->getAsAggregate())
unitNode = intermediate.growAggregate(nullptr, unitNode);
intermediate.setTreeRoot(unitNode);
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
// same as 'identifier' for function declarations.)
//
// 'node' could get populated if the declaration creates code, like an initializer
// or a function body.
// This can generate more than one subtree, one per initializer 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
// leads to two subtrees that need to be peers higher up.
// If 'nodeList' is passed in as non-null, it must an aggregate to extend for
// 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;
// attributes
@ -324,9 +315,8 @@ bool HlslGrammar::acceptDeclaration(TIntermNode*& node, TIntermNode*& node2)
// 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
// For that reason, this line is commented out
// if (acceptSamplerDeclarationDX9(declaredType))
// return true;
// if (acceptSamplerDeclarationDX9(declaredType))
// return true;
// fully_specified_type
if (! acceptFullySpecifiedType(declaredType))
@ -334,6 +324,7 @@ bool HlslGrammar::acceptDeclaration(TIntermNode*& node, TIntermNode*& node2)
// identifier
HlslToken idToken;
TIntermAggregate* initializers = nullptr;
while (acceptIdentifier(idToken)) {
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", "{", "");
if (typedefDecl)
parseContext.error(idToken.loc, "function body can't be in a typedef", "{", "");
return acceptFunctionDefinition(function, node, node2, attributes);
return acceptFunctionDefinition(function, nodeList, attributes);
} else {
if (typedefDecl)
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.
// The top-level node is always made into an aggregate, as that's
// historically how the AST has been.
node = intermediate.growAggregate(node,
parseContext.declareVariable(idToken.loc, *idToken.string, variableType,
expressionNode),
idToken.loc);
initializers = intermediate.growAggregate(initializers,
parseContext.declareVariable(idToken.loc, *idToken.string, variableType, expressionNode),
idToken.loc);
}
}
}
@ -436,9 +426,15 @@ bool HlslGrammar::acceptDeclaration(TIntermNode*& node, TIntermNode*& node2)
}
};
// The top-level node is a sequence.
if (node != nullptr)
node->getAsAggregate()->setOperator(EOpSequence);
// The top-level initializer node is a sequence.
if (initializers != nullptr)
initializers->setOperator(EOpSequence);
// Add the initializers' aggregate to the nodeList we were handed.
if (nodeList)
nodeList = intermediate.growAggregate(nodeList, initializers);
else
nodeList = initializers;
// SEMICOLON
if (! acceptTokenClass(EHTokSemicolon)) {
@ -989,7 +985,7 @@ bool HlslGrammar::acceptAnnotations(TQualifier&)
break;
// declaration
TIntermNode* node;
TIntermNode* node = nullptr;
if (! acceptDeclaration(node)) {
expected("declaration in annotation");
return false;
@ -2114,20 +2110,28 @@ bool HlslGrammar::acceptParameterDeclaration(TFunction& function)
// Do the work to create the function definition in addition to
// 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 */);
TSourceLoc loc = token.loc;
// we might get back and entry-point
TIntermNode* entryPointNode = nullptr;
// This does a pushScope()
node = parseContext.handleFunctionDefinition(loc, functionDeclarator, attributes, node2);
TIntermNode* functionNode = parseContext.handleFunctionDefinition(loc, functionDeclarator, attributes,
entryPointNode);
// compound_statement
TIntermNode* functionBody = nullptr;
if (! acceptCompoundStatement(functionBody))
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;
}
@ -2528,7 +2532,7 @@ bool HlslGrammar::acceptPostfixExpression(TIntermTyped*& node)
~tFinalize() { parseContext.finalizeFlattening(); }
HlslParseContext& parseContext;
private:
const tFinalize& operator=(const tFinalize& f) { return *this; }
const tFinalize& operator=(const tFinalize&) { return *this; }
tFinalize(const tFinalize& f) : parseContext(f.parseContext) { }
} finalize(parseContext);

View File

@ -65,7 +65,6 @@ namespace glslang {
bool acceptIdentifier(HlslToken&);
bool acceptCompilationUnit();
bool acceptDeclaration(TIntermNode*&);
bool acceptDeclaration(TIntermNode*& node1, TIntermNode*& node2);
bool acceptControlDeclaration(TIntermNode*& node);
bool acceptSamplerDeclarationDX9(TType&);
bool acceptSamplerState();
@ -88,7 +87,7 @@ namespace glslang {
bool acceptStructDeclarationList(TTypeList*&);
bool acceptFunctionParameters(TFunction&);
bool acceptParameterDeclaration(TFunction&);
bool acceptFunctionDefinition(TFunction&, TIntermNode*& node1, TIntermNode*& node2, const TAttributeMap&);
bool acceptFunctionDefinition(TFunction&, TIntermNode*& nodeList, const TAttributeMap&);
bool acceptParenExpression(TIntermTyped*&);
bool acceptExpression(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.
// The body is handled after this function returns.
//
// Returns an aggregate of parameter-symbol nodes.
//
TIntermAggregate* HlslParseContext::handleFunctionDefinition(const TSourceLoc& loc, TFunction& function,
const TAttributeMap& attributes, TIntermNode*& entryPointTree)
{