From e6e7494e2af0096a046396f69db6f5792be80824 Mon Sep 17 00:00:00 2001 From: John Kessenich Date: Sat, 11 Jun 2016 16:43:14 -0600 Subject: [PATCH] HLSL: Implement basic "struct" grammar. --- Test/baseResults/hlsl.struct.frag.out | 81 +++++++++++++++ Test/hlsl.struct.frag | 26 +++++ gtests/Hlsl.FromFile.cpp | 1 + hlsl/hlslGrammar.cpp | 137 +++++++++++++++++++++++++- hlsl/hlslGrammar.h | 2 + hlsl/hlslParseHelper.cpp | 11 ++- hlsl/hlslParseHelper.h | 2 +- hlsl/hlslScanContext.h | 3 +- 8 files changed, 257 insertions(+), 6 deletions(-) create mode 100755 Test/baseResults/hlsl.struct.frag.out create mode 100644 Test/hlsl.struct.frag diff --git a/Test/baseResults/hlsl.struct.frag.out b/Test/baseResults/hlsl.struct.frag.out new file mode 100755 index 00000000..6e344891 --- /dev/null +++ b/Test/baseResults/hlsl.struct.frag.out @@ -0,0 +1,81 @@ +hlsl.struct.frag +Shader version: 450 +gl_FragCoord origin is upper left +0:? Sequence +0:26 Function Definition: PixelShaderFunction(vf4; (temp 4-component vector of float) +0:20 Function Parameters: +0:20 'input' (temp 4-component vector of float) +0:? Sequence +0:25 Compare Equal (temp bool) +0:25 's3' (temp structure{temp 3-component vector of bool b3}) +0:25 's3' (temp structure{temp 3-component vector of bool b3}) +0:? Linker Objects +0:? 's1' (temp structure{temp bool b, temp bool c, temp 4-component vector of float a, temp 4-component vector of float d}) +0:? 's2' (temp structure{temp 4-component vector of float i}) + + +Linked fragment stage: + + +Shader version: 450 +gl_FragCoord origin is upper left +0:? Sequence +0:26 Function Definition: PixelShaderFunction(vf4; (temp 4-component vector of float) +0:20 Function Parameters: +0:20 'input' (temp 4-component vector of float) +0:? Sequence +0:25 Compare Equal (temp bool) +0:25 's3' (temp structure{temp 3-component vector of bool b3}) +0:25 's3' (temp structure{temp 3-component vector of bool b3}) +0:? Linker Objects +0:? 's1' (temp structure{temp bool b, temp bool c, temp 4-component vector of float a, temp 4-component vector of float d}) +0:? 's2' (temp structure{temp 4-component vector of float i}) + +// Module Version 10000 +// Generated by (magic number): 80001 +// Id's are bound by 25 + + Capability Shader + 1: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint Fragment 4 "PixelShaderFunction" + ExecutionMode 4 OriginUpperLeft + Source HLSL 450 + Name 4 "PixelShaderFunction" + Name 8 "FS" + MemberName 8(FS) 0 "b3" + Name 10 "s3" + Name 19 "myS" + MemberName 19(myS) 0 "b" + MemberName 19(myS) 1 "c" + MemberName 19(myS) 2 "a" + MemberName 19(myS) 3 "d" + Name 21 "s1" + Name 22 "" + MemberName 22 0 "i" + Name 24 "s2" + 2: TypeVoid + 3: TypeFunction 2 + 6: TypeBool + 7: TypeVector 6(bool) 3 + 8(FS): TypeStruct 7(bvec3) + 9: TypePointer Function 8(FS) + 17: TypeFloat 32 + 18: TypeVector 17(float) 4 + 19(myS): TypeStruct 6(bool) 6(bool) 18(fvec4) 18(fvec4) + 20: TypePointer Function 19(myS) + 22: TypeStruct 18(fvec4) + 23: TypePointer Function 22(struct) +4(PixelShaderFunction): 2 Function None 3 + 5: Label + 10(s3): 9(ptr) Variable Function + 21(s1): 20(ptr) Variable Function + 24(s2): 23(ptr) Variable Function + 11: 8(FS) Load 10(s3) + 12: 8(FS) Load 10(s3) + 13: 7(bvec3) CompositeExtract 11 0 + 14: 7(bvec3) CompositeExtract 12 0 + 15: 7(bvec3) LogicalEqual 13 14 + 16: 6(bool) All 15 + Return + FunctionEnd diff --git a/Test/hlsl.struct.frag b/Test/hlsl.struct.frag new file mode 100644 index 00000000..4b5b2419 --- /dev/null +++ b/Test/hlsl.struct.frag @@ -0,0 +1,26 @@ +struct { +}; + +struct { + bool b; +}; + +struct myS { + bool b, c; + float4 a, d; +}; + +myS s1; + +struct { + float4 i; +} s2; + +float4 PixelShaderFunction(float4 input) : COLOR0 +{ + struct FS { + bool3 b3; + } s3; + + s3 == s3; +} \ No newline at end of file diff --git a/gtests/Hlsl.FromFile.cpp b/gtests/Hlsl.FromFile.cpp index fa3442cd..22425014 100644 --- a/gtests/Hlsl.FromFile.cpp +++ b/gtests/Hlsl.FromFile.cpp @@ -90,6 +90,7 @@ INSTANTIATE_TEST_CASE_P( {"hlsl.precedence2.frag", "PixelShaderFunction"}, {"hlsl.scope.frag", "PixelShaderFunction"}, {"hlsl.sin.frag", "PixelShaderFunction"}, + {"hlsl.struct.frag", "PixelShaderFunction"}, {"hlsl.whileLoop.frag", "PixelShaderFunction"}, {"hlsl.void.frag", "PixelShaderFunction"}, }), diff --git a/hlsl/hlslGrammar.cpp b/hlsl/hlslGrammar.cpp index 9ea14dae..1bd44165 100755 --- a/hlsl/hlslGrammar.cpp +++ b/hlsl/hlslGrammar.cpp @@ -210,6 +210,22 @@ void HlslGrammar::acceptQualifier(TQualifier& qualifier) 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; @@ -554,6 +570,125 @@ bool HlslGrammar::acceptType(TType& type) 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 +// | IDENTIFIER array_specifier +// +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 + + // 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 @@ -879,7 +1014,7 @@ bool HlslGrammar::acceptPostfixExpression(TIntermTyped*& node) } else if (acceptIdentifier(idToken)) { // identifier or function_call name if (! peekTokenClass(EHTokLeftParen)) { - node = parseContext.handleVariable(idToken.loc, token.string); + node = parseContext.handleVariable(idToken.loc, idToken.symbol, token.string); } else if (acceptFunctionCall(idToken, node)) { // function_call (nothing else to do yet) } else { diff --git a/hlsl/hlslGrammar.h b/hlsl/hlslGrammar.h index ba92c922..6cbcf2f0 100755 --- a/hlsl/hlslGrammar.h +++ b/hlsl/hlslGrammar.h @@ -61,6 +61,8 @@ namespace glslang { bool acceptFullySpecifiedType(TType&); void acceptQualifier(TQualifier&); bool acceptType(TType&); + bool acceptStruct(TType&); + bool acceptStructDeclarationList(TTypeList*&); bool acceptFunctionParameters(TFunction&); bool acceptParameterDeclaration(TFunction&); bool acceptFunctionDefinition(TFunction&, TIntermNode*&); diff --git a/hlsl/hlslParseHelper.cpp b/hlsl/hlslParseHelper.cpp index e5c15648..1d6ffd85 100755 --- a/hlsl/hlslParseHelper.cpp +++ b/hlsl/hlslParseHelper.cpp @@ -282,10 +282,14 @@ void C_DECL HlslParseContext::ppWarn(const TSourceLoc& loc, const char* szReason // // Handle seeing a variable identifier in the grammar. // -TIntermTyped* HlslParseContext::handleVariable(const TSourceLoc& loc, const TString* string) +TIntermTyped* HlslParseContext::handleVariable(const TSourceLoc& loc, TSymbol* symbol, const TString* string) { - TSymbol* symbol = symbolTable.find(*string); - TIntermTyped* node = nullptr; + if (symbol == nullptr) + symbol = symbolTable.find(*string); + if (symbol && symbol->getAsVariable() && symbol->getAsVariable()->isUserType()) { + error(loc, "expected symbol, not user-defined type", string->c_str(), ""); + return nullptr; + } // Error check for requiring specific extensions present. if (symbol && symbol->getNumExtensions()) @@ -306,6 +310,7 @@ TIntermTyped* HlslParseContext::handleVariable(const TSourceLoc& loc, const TStr const TVariable* variable; const TAnonMember* anon = symbol ? symbol->getAsAnonMember() : nullptr; + TIntermTyped* node = nullptr; if (anon) { // It was a member of an anonymous container. diff --git a/hlsl/hlslParseHelper.h b/hlsl/hlslParseHelper.h index e1fbbf85..7f1e1acb 100755 --- a/hlsl/hlslParseHelper.h +++ b/hlsl/hlslParseHelper.h @@ -65,7 +65,7 @@ public: bool builtInName(const TString&); void handlePragma(const TSourceLoc&, const TVector&); - TIntermTyped* handleVariable(const TSourceLoc&, const TString* string); + TIntermTyped* handleVariable(const TSourceLoc&, TSymbol* symbol, const TString* string); TIntermTyped* handleBracketDereference(const TSourceLoc&, TIntermTyped* base, TIntermTyped* index); void checkIndex(const TSourceLoc&, const TType&, int& index); diff --git a/hlsl/hlslScanContext.h b/hlsl/hlslScanContext.h index 75c01a9d..144a8534 100755 --- a/hlsl/hlslScanContext.h +++ b/hlsl/hlslScanContext.h @@ -54,7 +54,7 @@ class TPpToken; // Everything needed to fully describe a token. // struct HlslToken { - HlslToken() : string(nullptr) { loc.init(); } + HlslToken() : string(nullptr), symbol(nullptr) { loc.init(); } TSourceLoc loc; // location of token in the source EHlslTokenClass tokenClass; // what kind of token it is union { // what data the token holds @@ -64,6 +64,7 @@ struct HlslToken { bool b; double d; }; + glslang::TSymbol* symbol; // if a symbol-table lookup was done already, this is the result }; //