HLSL: cbuffer and tbuffer grammar and production.
This commit is contained in:
@@ -337,6 +337,8 @@ bool HlslGrammar::acceptDeclaration(TIntermNode*& node)
|
||||
|
||||
if (typedefDecl)
|
||||
parseContext.declareTypedef(idToken.loc, *idToken.string, type, arraySizes);
|
||||
else if (type.getBasicType() == EbtBlock)
|
||||
parseContext.declareBlock(idToken.loc, type, idToken.string);
|
||||
else {
|
||||
// Declare the variable and add any initializer code to the AST.
|
||||
// The top-level node is always made into an aggregate, as that's
|
||||
@@ -414,11 +416,19 @@ bool HlslGrammar::acceptFullySpecifiedType(TType& type)
|
||||
TQualifier qualifier;
|
||||
qualifier.clear();
|
||||
acceptQualifier(qualifier);
|
||||
TSourceLoc loc = token.loc;
|
||||
|
||||
// type_specifier
|
||||
if (! acceptType(type))
|
||||
return false;
|
||||
type.getQualifier() = qualifier;
|
||||
if (type.getBasicType() == EbtBlock) {
|
||||
// the type was a block, which set some parts of the qualifier
|
||||
parseContext.mergeQualifiers(loc, type.getQualifier(), qualifier, true);
|
||||
// further, it can create an anonymous instance of the block
|
||||
if (peekTokenClass(EHTokSemicolon))
|
||||
parseContext.declareBlock(loc, type);
|
||||
} else
|
||||
type.getQualifier() = qualifier;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -825,6 +835,8 @@ bool HlslGrammar::acceptType(TType& type)
|
||||
break;
|
||||
|
||||
case EHTokStruct:
|
||||
case EHTokCBuffer:
|
||||
case EHTokTBuffer:
|
||||
return acceptStruct(type);
|
||||
break;
|
||||
|
||||
@@ -1186,13 +1198,29 @@ bool HlslGrammar::acceptType(TType& type)
|
||||
}
|
||||
|
||||
// struct
|
||||
// : STRUCT IDENTIFIER LEFT_BRACE struct_declaration_list RIGHT_BRACE
|
||||
// | STRUCT LEFT_BRACE struct_declaration_list RIGHT_BRACE
|
||||
// : struct_type IDENTIFIER post_decls LEFT_BRACE struct_declaration_list RIGHT_BRACE
|
||||
// | struct_type post_decls LEFT_BRACE struct_declaration_list RIGHT_BRACE
|
||||
//
|
||||
// struct_type
|
||||
// : STRUCT
|
||||
// | CBUFFER
|
||||
// | TBUFFER
|
||||
//
|
||||
bool HlslGrammar::acceptStruct(TType& type)
|
||||
{
|
||||
// This qualifier.storage will tell us whether it's an AST block or
|
||||
// just a struct.
|
||||
TQualifier qualifier;
|
||||
qualifier.clear();
|
||||
|
||||
// CBUFFER
|
||||
if (acceptTokenClass(EHTokCBuffer))
|
||||
qualifier.storage = EvqUniform;
|
||||
// TBUFFER
|
||||
else if (acceptTokenClass(EHTokTBuffer))
|
||||
qualifier.storage = EvqBuffer;
|
||||
// STRUCT
|
||||
if (! acceptTokenClass(EHTokStruct))
|
||||
else if (! acceptTokenClass(EHTokStruct))
|
||||
return false;
|
||||
|
||||
// IDENTIFIER
|
||||
@@ -1202,6 +1230,9 @@ bool HlslGrammar::acceptStruct(TType& type)
|
||||
advanceToken();
|
||||
}
|
||||
|
||||
// post_decls
|
||||
acceptPostDecls(type);
|
||||
|
||||
// LEFT_BRACE
|
||||
if (! acceptTokenClass(EHTokLeftBrace)) {
|
||||
expected("{");
|
||||
@@ -1222,11 +1253,15 @@ bool HlslGrammar::acceptStruct(TType& type)
|
||||
}
|
||||
|
||||
// create the user-defined type
|
||||
new(&type) TType(typeList, structName);
|
||||
if (qualifier.storage == EvqTemporary)
|
||||
new(&type) TType(typeList, structName);
|
||||
else
|
||||
new(&type) TType(typeList, structName, qualifier); // sets EbtBlock
|
||||
|
||||
// If it was named, which means it can be reused later, add
|
||||
// it to the symbol table.
|
||||
if (structName.size() > 0) {
|
||||
// If it was named, which means the type can be reused later, add
|
||||
// it to the symbol table. (Unless it's a block, in which
|
||||
// case the name is not a type.)
|
||||
if (type.getBasicType() != EbtBlock && structName.size() > 0) {
|
||||
TVariable* userTypeDef = new TVariable(&structName, type, true);
|
||||
if (! parseContext.symbolTable.insert(*userTypeDef))
|
||||
parseContext.error(token.loc, "redefinition", structName.c_str(), "struct");
|
||||
@@ -2442,6 +2477,7 @@ void HlslGrammar::acceptPostDecls(TType& type)
|
||||
break;
|
||||
}
|
||||
// TODO: process the packoffset information
|
||||
// c1.y means component y of location slot 1
|
||||
} else if (! acceptIdentifier(idToken)) {
|
||||
expected("semantic or packoffset or register");
|
||||
return;
|
||||
@@ -2462,6 +2498,7 @@ void HlslGrammar::acceptPostDecls(TType& type)
|
||||
break;
|
||||
}
|
||||
// TODO: process the register information
|
||||
// b2 means buffer 2
|
||||
} else {
|
||||
// semantic, in idToken.string
|
||||
parseContext.handleSemantic(type, *idToken.string);
|
||||
|
||||
@@ -2533,10 +2533,10 @@ void HlslParseContext::mergeQualifiers(const TSourceLoc& loc, TQualifier& dst, c
|
||||
if (dst.storage == EvqTemporary || dst.storage == EvqGlobal)
|
||||
dst.storage = src.storage;
|
||||
else if ((dst.storage == EvqIn && src.storage == EvqOut) ||
|
||||
(dst.storage == EvqOut && src.storage == EvqIn))
|
||||
(dst.storage == EvqOut && src.storage == EvqIn))
|
||||
dst.storage = EvqInOut;
|
||||
else if ((dst.storage == EvqIn && src.storage == EvqConst) ||
|
||||
(dst.storage == EvqConst && src.storage == EvqIn))
|
||||
(dst.storage == EvqConst && src.storage == EvqIn))
|
||||
dst.storage = EvqConstReadOnly;
|
||||
else if (src.storage != EvqTemporary && src.storage != EvqGlobal)
|
||||
error(loc, "too many storage qualifiers", GetStorageQualifierString(src.storage), "");
|
||||
@@ -3898,28 +3898,31 @@ TIntermTyped* HlslParseContext::constructAggregate(TIntermNode* node, const TTyp
|
||||
//
|
||||
// Do everything needed to add an interface block.
|
||||
//
|
||||
void HlslParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, const TString* instanceName, TArraySizes* arraySizes)
|
||||
void HlslParseContext::declareBlock(const TSourceLoc& loc, TType& type, const TString* instanceName, TArraySizes* arraySizes)
|
||||
{
|
||||
assert(type.getWritableStruct() != nullptr);
|
||||
|
||||
TTypeList& typeList = *type.getWritableStruct();
|
||||
// fix and check for member storage qualifiers and types that don't belong within a block
|
||||
for (unsigned int member = 0; member < typeList.size(); ++member) {
|
||||
TType& memberType = *typeList[member].type;
|
||||
TQualifier& memberQualifier = memberType.getQualifier();
|
||||
const TSourceLoc& memberLoc = typeList[member].loc;
|
||||
globalQualifierFix(memberLoc, memberQualifier);
|
||||
memberQualifier.storage = currentBlockQualifier.storage;
|
||||
memberQualifier.storage = type.getQualifier().storage;
|
||||
}
|
||||
|
||||
// This might be a redeclaration of a built-in block. If so, redeclareBuiltinBlock() will
|
||||
// do all the rest.
|
||||
if (! symbolTable.atBuiltInLevel() && builtInName(*blockName)) {
|
||||
redeclareBuiltinBlock(loc, typeList, *blockName, instanceName, arraySizes);
|
||||
return;
|
||||
}
|
||||
//if (! symbolTable.atBuiltInLevel() && builtInName(*blockName)) {
|
||||
// redeclareBuiltinBlock(loc, typeList, *blockName, instanceName, arraySizes);
|
||||
// return;
|
||||
//}
|
||||
|
||||
// Make default block qualification, and adjust the member qualifications
|
||||
|
||||
TQualifier defaultQualification;
|
||||
switch (currentBlockQualifier.storage) {
|
||||
switch (type.getQualifier().storage) {
|
||||
case EvqUniform: defaultQualification = globalUniformDefaults; break;
|
||||
case EvqBuffer: defaultQualification = globalBufferDefaults; break;
|
||||
case EvqVaryingIn: defaultQualification = globalInputDefaults; break;
|
||||
@@ -3929,12 +3932,12 @@ void HlslParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList,
|
||||
|
||||
// Special case for "push_constant uniform", which has a default of std430,
|
||||
// contrary to normal uniform defaults, and can't have a default tracked for it.
|
||||
if (currentBlockQualifier.layoutPushConstant && ! currentBlockQualifier.hasPacking())
|
||||
currentBlockQualifier.layoutPacking = ElpStd430;
|
||||
if (type.getQualifier().layoutPushConstant && ! type.getQualifier().hasPacking())
|
||||
type.getQualifier().layoutPacking = ElpStd430;
|
||||
|
||||
// fix and check for member layout qualifiers
|
||||
|
||||
mergeObjectLayoutQualifiers(defaultQualification, currentBlockQualifier, true);
|
||||
mergeObjectLayoutQualifiers(defaultQualification, type.getQualifier(), true);
|
||||
|
||||
bool memberWithLocation = false;
|
||||
bool memberWithoutLocation = false;
|
||||
@@ -3958,7 +3961,7 @@ void HlslParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList,
|
||||
if (memberQualifier.hasPacking())
|
||||
error(memberLoc, "member of block cannot have a packing layout qualifier", typeList[member].type->getFieldName().c_str(), "");
|
||||
if (memberQualifier.hasLocation()) {
|
||||
switch (currentBlockQualifier.storage) {
|
||||
switch (type.getQualifier().storage) {
|
||||
case EvqVaryingIn:
|
||||
case EvqVaryingOut:
|
||||
memberWithLocation = true;
|
||||
@@ -3979,19 +3982,20 @@ void HlslParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList,
|
||||
}
|
||||
|
||||
// Process the members
|
||||
fixBlockLocations(loc, currentBlockQualifier, typeList, memberWithLocation, memberWithoutLocation);
|
||||
fixBlockXfbOffsets(currentBlockQualifier, typeList);
|
||||
fixBlockUniformOffsets(currentBlockQualifier, typeList);
|
||||
fixBlockLocations(loc, type.getQualifier(), typeList, memberWithLocation, memberWithoutLocation);
|
||||
fixBlockXfbOffsets(type.getQualifier(), typeList);
|
||||
fixBlockUniformOffsets(type.getQualifier(), typeList);
|
||||
|
||||
// reverse merge, so that currentBlockQualifier now has all layout information
|
||||
// (can't use defaultQualification directly, it's missing other non-layout-default-class qualifiers)
|
||||
mergeObjectLayoutQualifiers(currentBlockQualifier, defaultQualification, true);
|
||||
mergeObjectLayoutQualifiers(type.getQualifier(), defaultQualification, true);
|
||||
|
||||
//
|
||||
// Build and add the interface block as a new type named 'blockName'
|
||||
//
|
||||
|
||||
TType blockType(&typeList, *blockName, currentBlockQualifier);
|
||||
//?? need the block name to be a typename?
|
||||
TType blockType(&typeList, "" /* *blockName */, type.getQualifier());
|
||||
if (arraySizes)
|
||||
blockType.newArraySizes(*arraySizes);
|
||||
|
||||
@@ -4008,20 +4012,20 @@ void HlslParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList,
|
||||
// whose type is EbtBlock, but without all the structure; that will come from the type
|
||||
// the instances point to.
|
||||
//
|
||||
TType blockNameType(EbtBlock, blockType.getQualifier().storage);
|
||||
TVariable* blockNameVar = new TVariable(blockName, blockNameType);
|
||||
if (! symbolTable.insert(*blockNameVar)) {
|
||||
TSymbol* existingName = symbolTable.find(*blockName);
|
||||
if (existingName->getType().getBasicType() == EbtBlock) {
|
||||
if (existingName->getType().getQualifier().storage == blockType.getQualifier().storage) {
|
||||
error(loc, "Cannot reuse block name within the same interface:", blockName->c_str(), blockType.getStorageQualifierString());
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
error(loc, "block name cannot redefine a non-block name", blockName->c_str(), "");
|
||||
return;
|
||||
}
|
||||
}
|
||||
//??TType blockNameType(EbtBlock, blockType.getQualifier().storage);
|
||||
//??TVariable* blockNameVar = new TVariable(blockName, blockNameType);
|
||||
//if (! symbolTable.insert(*blockNameVar)) {
|
||||
// TSymbol* existingName = symbolTable.find(*blockName);
|
||||
// if (existingName->getType().getBasicType() == EbtBlock) {
|
||||
// if (existingName->getType().getQualifier().storage == blockType.getQualifier().storage) {
|
||||
// error(loc, "Cannot reuse block name within the same interface:", blockName->c_str(), blockType.getStorageQualifierString());
|
||||
// return;
|
||||
// }
|
||||
// } else {
|
||||
// error(loc, "block name cannot redefine a non-block name", blockName->c_str(), "");
|
||||
// return;
|
||||
// }
|
||||
//}
|
||||
|
||||
// Add the variable, as anonymous or named instanceName.
|
||||
// Make an anonymous variable if no name was provided.
|
||||
@@ -4031,7 +4035,7 @@ void HlslParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList,
|
||||
TVariable& variable = *new TVariable(instanceName, blockType);
|
||||
if (! symbolTable.insert(variable)) {
|
||||
if (*instanceName == "")
|
||||
error(loc, "nameless block contains a member that already has a name at global scope", blockName->c_str(), "");
|
||||
error(loc, "nameless block contains a member that already has a name at global scope", "" /* blockName->c_str() */, "");
|
||||
else
|
||||
error(loc, "block instance name redefinition", variable.getName().c_str(), "");
|
||||
|
||||
|
||||
@@ -133,7 +133,7 @@ public:
|
||||
TIntermTyped* addConstructor(const TSourceLoc&, TIntermNode*, const TType&, TOperator);
|
||||
TIntermTyped* constructAggregate(TIntermNode*, const TType&, int, const TSourceLoc&);
|
||||
TIntermTyped* constructBuiltIn(const TType&, TOperator, TIntermTyped*, const TSourceLoc&, bool subset);
|
||||
void declareBlock(const TSourceLoc&, TTypeList& typeList, const TString* instanceName = 0, TArraySizes* arraySizes = 0);
|
||||
void declareBlock(const TSourceLoc&, TType&, const TString* instanceName = 0, TArraySizes* arraySizes = 0);
|
||||
void fixBlockLocations(const TSourceLoc&, TQualifier&, TTypeList&, bool memberWithLocation, bool memberWithoutLocation);
|
||||
void fixBlockXfbOffsets(TQualifier&, TTypeList&);
|
||||
void fixBlockUniformOffsets(TQualifier&, TTypeList&);
|
||||
@@ -176,8 +176,6 @@ protected:
|
||||
bool postMainReturn; // if inside a function, true if the function is the entry point and this is after a return statement
|
||||
const TType* currentFunctionType; // the return type of the function that's currently being parsed
|
||||
bool functionReturnsValue; // true if a non-void function has a return
|
||||
const TString* blockName;
|
||||
TQualifier currentBlockQualifier;
|
||||
TBuiltInResource resources;
|
||||
TLimits& limits;
|
||||
|
||||
|
||||
@@ -258,6 +258,8 @@ void HlslScanContext::fillInKeywordMap()
|
||||
(*KeywordMap)["Texture2DMSArray"] = EHTokTexture2DMSarray;
|
||||
|
||||
(*KeywordMap)["struct"] = EHTokStruct;
|
||||
(*KeywordMap)["cbuffer"] = EHTokCBuffer;
|
||||
(*KeywordMap)["tbuffer"] = EHTokTBuffer;
|
||||
(*KeywordMap)["typedef"] = EHTokTypedef;
|
||||
|
||||
(*KeywordMap)["true"] = EHTokBoolConstant;
|
||||
@@ -574,6 +576,9 @@ EHlslTokenClass HlslScanContext::tokenizeIdentifier()
|
||||
// variable, user type, ...
|
||||
case EHTokStruct:
|
||||
case EHTokTypedef:
|
||||
case EHTokCBuffer:
|
||||
case EHTokTBuffer:
|
||||
return keyword;
|
||||
|
||||
case EHTokBoolConstant:
|
||||
if (strcmp("true", tokenText) == 0)
|
||||
|
||||
@@ -212,6 +212,8 @@ enum EHlslTokenClass {
|
||||
EHTokIdentifier,
|
||||
EHTokTypeName,
|
||||
EHTokStruct,
|
||||
EHTokCBuffer,
|
||||
EHTokTBuffer,
|
||||
EHTokTypedef,
|
||||
|
||||
// constant
|
||||
|
||||
Reference in New Issue
Block a user