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;
// 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
// 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))
// identifier
HlslToken idToken;
+ TIntermAggregate* initializers = nullptr;
while (acceptIdentifier(idToken)) {
TString* fnName = idToken.string;
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", "{", "");
// 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);
}
}
}
}
};
- // 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)) {
break;
// declaration
- TIntermNode* node;
+ TIntermNode* node = nullptr;
if (! acceptDeclaration(node)) {
expected("declaration in annotation");
return false;
// 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;
}
~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);