From 5964c64b2acd90e7403d61cc35303853fc60116c Mon Sep 17 00:00:00 2001 From: steve-lunarg Date: Sat, 30 Jul 2016 07:38:55 -0600 Subject: [PATCH] HLSL: Fix a grammar error related to constructors in parenthetical expressions --- Test/baseResults/hlsl.constructexpr.frag.out | 129 +++++++++++++++++++ Test/hlsl.constructexpr.frag | 17 +++ Test/hlsl.init2.frag | 23 ++++ gtests/Hlsl.FromFile.cpp | 1 + hlsl/hlslGrammar.cpp | 42 +++--- hlsl/hlslTokenStream.cpp | 18 +-- hlsl/hlslTokenStream.h | 16 ++- 7 files changed, 212 insertions(+), 34 deletions(-) create mode 100644 Test/baseResults/hlsl.constructexpr.frag.out create mode 100644 Test/hlsl.constructexpr.frag create mode 100644 Test/hlsl.init2.frag diff --git a/Test/baseResults/hlsl.constructexpr.frag.out b/Test/baseResults/hlsl.constructexpr.frag.out new file mode 100644 index 000000000..2eef7c0dc --- /dev/null +++ b/Test/baseResults/hlsl.constructexpr.frag.out @@ -0,0 +1,129 @@ +hlsl.constructexpr.frag +Shader version: 450 +gl_FragCoord origin is upper left +0:? Sequence +0:18 Function Definition: main( (global structure{temp 4-component vector of float color}) +0:4 Function Parameters: +0:? Sequence +0:6 Constant: +0:6 3 (const int) +0:7 Constant: +0:7 4 (const int) +0:8 Constant: +0:8 5 (const int) +0:9 Constant: +0:9 6 (const int) +0:10 Constant: +0:10 7 (const int) +0:11 Constant: +0:11 8 (const int) +0:12 Comma (temp 2-component vector of float) +0:? Constant: +0:? 9.000000 +0:? 10.000000 +0:? Constant: +0:? 11.000000 +0:? 12.000000 +0:15 move second child to first child (temp 4-component vector of float) +0:15 color: direct index for structure (temp 4-component vector of float) +0:15 'ps_output' (temp structure{temp 4-component vector of float color}) +0:15 Constant: +0:15 0 (const int) +0:15 Constant: +0:15 1.000000 +0:15 1.000000 +0:15 1.000000 +0:15 1.000000 +0:16 Branch: Return with expression +0:16 'ps_output' (temp structure{temp 4-component vector of float color}) +0:? Linker Objects + + +Linked fragment stage: + + +Shader version: 450 +gl_FragCoord origin is upper left +0:? Sequence +0:18 Function Definition: main( (global structure{temp 4-component vector of float color}) +0:4 Function Parameters: +0:? Sequence +0:6 Constant: +0:6 3 (const int) +0:7 Constant: +0:7 4 (const int) +0:8 Constant: +0:8 5 (const int) +0:9 Constant: +0:9 6 (const int) +0:10 Constant: +0:10 7 (const int) +0:11 Constant: +0:11 8 (const int) +0:12 Comma (temp 2-component vector of float) +0:? Constant: +0:? 9.000000 +0:? 10.000000 +0:? Constant: +0:? 11.000000 +0:? 12.000000 +0:15 move second child to first child (temp 4-component vector of float) +0:15 color: direct index for structure (temp 4-component vector of float) +0:15 'ps_output' (temp structure{temp 4-component vector of float color}) +0:15 Constant: +0:15 0 (const int) +0:15 Constant: +0:15 1.000000 +0:15 1.000000 +0:15 1.000000 +0:15 1.000000 +0:16 Branch: Return with expression +0:16 'ps_output' (temp structure{temp 4-component vector of float color}) +0:? Linker Objects + +// Module Version 10000 +// Generated by (magic number): 80001 +// Id's are bound by 32 + + Capability Shader + 1: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint Fragment 4 "main" + ExecutionMode 4 OriginUpperLeft + Source HLSL 450 + Name 4 "main" + Name 22 "PS_OUTPUT" + MemberName 22(PS_OUTPUT) 0 "color" + Name 24 "ps_output" + 2: TypeVoid + 3: TypeFunction 2 + 6: TypeInt 32 1 + 7: 6(int) Constant 3 + 8: 6(int) Constant 4 + 9: 6(int) Constant 5 + 10: 6(int) Constant 6 + 11: 6(int) Constant 7 + 12: 6(int) Constant 8 + 13: TypeFloat 32 + 14: TypeVector 13(float) 2 + 15: 13(float) Constant 1091567616 + 16: 13(float) Constant 1092616192 + 17: 14(fvec2) ConstantComposite 15 16 + 18: 13(float) Constant 1093664768 + 19: 13(float) Constant 1094713344 + 20: 14(fvec2) ConstantComposite 18 19 + 21: TypeVector 13(float) 4 + 22(PS_OUTPUT): TypeStruct 21(fvec4) + 23: TypePointer Function 22(PS_OUTPUT) + 25: 6(int) Constant 0 + 26: 13(float) Constant 1065353216 + 27: 21(fvec4) ConstantComposite 26 26 26 26 + 28: TypePointer Function 21(fvec4) + 4(main): 2 Function None 3 + 5: Label + 24(ps_output): 23(ptr) Variable Function + 29: 28(ptr) AccessChain 24(ps_output) 25 + Store 29 27 + 30:22(PS_OUTPUT) Load 24(ps_output) + ReturnValue 30 + FunctionEnd diff --git a/Test/hlsl.constructexpr.frag b/Test/hlsl.constructexpr.frag new file mode 100644 index 000000000..7048f62cd --- /dev/null +++ b/Test/hlsl.constructexpr.frag @@ -0,0 +1,17 @@ +struct PS_OUTPUT { float4 color : SV_Target0; }; + +PS_OUTPUT main() +{ + // Evaluates to a sequence: 3, 4, 5, 6, 7, 8, and a float2(9,10), float2(11,12) sequence + (int(3)); + (int(3) + int(1)); + (int(3) + int(1) + int(1)); + (((int(6)))); + (int(7.0)); + ((int((2)) ? 8 : 8)); + (float2(9, 10), float2(11, 12)); + + PS_OUTPUT ps_output; + ps_output.color = 1.0; + return ps_output; +} diff --git a/Test/hlsl.init2.frag b/Test/hlsl.init2.frag new file mode 100644 index 000000000..94be5ffeb --- /dev/null +++ b/Test/hlsl.init2.frag @@ -0,0 +1,23 @@ + +void Test1() +{ + struct mystruct { float2 a; }; + mystruct test1 = { + { 1, 2, }, // test trailing commas + }; + + mystruct test2 = { + { { 1, 2, } }, // test unneeded levels + }; + + float test3 = { 1 } ; // test scalar initialization +} + +struct PS_OUTPUT { float4 color : SV_Target0; }; + +PS_OUTPUT main() +{ + PS_OUTPUT ps_output; + ps_output.color = 1.0; + return ps_output; +} diff --git a/gtests/Hlsl.FromFile.cpp b/gtests/Hlsl.FromFile.cpp index d14be6772..91aa9df2d 100644 --- a/gtests/Hlsl.FromFile.cpp +++ b/gtests/Hlsl.FromFile.cpp @@ -80,6 +80,7 @@ INSTANTIATE_TEST_CASE_P( {"hlsl.calculatelodunclamped.dx10.frag", "main"}, {"hlsl.cast.frag", "PixelShaderFunction"}, {"hlsl.conditional.frag", "PixelShaderFunction"}, + {"hlsl.constructexpr.frag", "main"}, {"hlsl.discard.frag", "PixelShaderFunction"}, {"hlsl.doLoop.frag", "PixelShaderFunction"}, {"hlsl.float1.frag", "PixelShaderFunction"}, diff --git a/hlsl/hlslGrammar.cpp b/hlsl/hlslGrammar.cpp index e3e5df736..11b6dc152 100755 --- a/hlsl/hlslGrammar.cpp +++ b/hlsl/hlslGrammar.cpp @@ -1718,27 +1718,29 @@ bool HlslGrammar::acceptUnaryExpression(TIntermTyped*& node) if (acceptTokenClass(EHTokLeftParen)) { TType castType; if (acceptType(castType)) { - if (! acceptTokenClass(EHTokRightParen)) { - expected(")"); - return false; + if (acceptTokenClass(EHTokRightParen)) { + // We've matched "(type)" now, get the expression to cast + TSourceLoc loc = token.loc; + if (! acceptUnaryExpression(node)) + return false; + + // Hook it up like a constructor + TFunction* constructorFunction = parseContext.handleConstructorCall(loc, castType); + if (constructorFunction == nullptr) { + expected("type that can be constructed"); + return false; + } + TIntermTyped* arguments = nullptr; + parseContext.handleFunctionArgument(constructorFunction, arguments, node); + node = parseContext.handleFunctionCall(loc, constructorFunction, arguments); + + return true; + } else { + // This could be a parenthesized constructor, ala (int(3)), and we just accepted + // the '(int' part. We must back up twice. + recedeToken(); + recedeToken(); } - - // We've matched "(type)" now, get the expression to cast - TSourceLoc loc = token.loc; - if (! acceptUnaryExpression(node)) - return false; - - // Hook it up like a constructor - TFunction* constructorFunction = parseContext.handleConstructorCall(loc, castType); - if (constructorFunction == nullptr) { - expected("type that can be constructed"); - return false; - } - TIntermTyped* arguments = nullptr; - parseContext.handleFunctionArgument(constructorFunction, arguments, node); - node = parseContext.handleFunctionCall(loc, constructorFunction, arguments); - - return true; } else { // This isn't a type cast, but it still started "(", so if it is a // unary expression, it can only be a postfix_expression, so try that. diff --git a/hlsl/hlslTokenStream.cpp b/hlsl/hlslTokenStream.cpp index 47f779a81..c915e0b59 100755 --- a/hlsl/hlslTokenStream.cpp +++ b/hlsl/hlslTokenStream.cpp @@ -39,27 +39,29 @@ namespace glslang { void HlslTokenStream::pushPreToken(const HlslToken& tok) { - assert(preTokenStackSize == 0); - preTokenStack = tok; - ++preTokenStackSize; + assert(preTokenStackSize < tokenBufferSize); + preTokenStack[preTokenStackSize++] = tok; } HlslToken HlslTokenStream::popPreToken() { - assert(preTokenStackSize == 1); - --preTokenStackSize; + assert(preTokenStackSize > 0); - return preTokenStack; + return preTokenStack[--preTokenStackSize]; } void HlslTokenStream::pushTokenBuffer(const HlslToken& tok) { - tokenBuffer = tok; + tokenBuffer[tokenBufferPos] = tok; + tokenBufferPos = (tokenBufferPos+1) % tokenBufferSize; } HlslToken HlslTokenStream::popTokenBuffer() { - return tokenBuffer; + // Back up + tokenBufferPos = (tokenBufferPos+tokenBufferSize-1) % tokenBufferSize; + + return tokenBuffer[tokenBufferPos]; } // Load 'token' with the next token in the stream of tokens. diff --git a/hlsl/hlslTokenStream.h b/hlsl/hlslTokenStream.h index 12c2a2a02..ec4288943 100755 --- a/hlsl/hlslTokenStream.h +++ b/hlsl/hlslTokenStream.h @@ -43,7 +43,7 @@ namespace glslang { class HlslTokenStream { public: explicit HlslTokenStream(HlslScanContext& scanner) - : scanner(scanner), preTokenStackSize(0) { } + : scanner(scanner), preTokenStackSize(0), tokenBufferPos(0) { } virtual ~HlslTokenStream() { } public: @@ -62,20 +62,24 @@ namespace glslang { HlslScanContext& scanner; // lexical scanner, to get next token + // This is the number of tokens we can recedeToken() over. + static const int tokenBufferSize = 2; + // Previously scanned tokens, returned for future advances, // so logically in front of the token stream. // Is logically a stack; needs last in last out semantics. - // Currently implemented as a stack of size 1. - HlslToken preTokenStack; + // Currently implemented as a stack of size 2. + HlslToken preTokenStack[tokenBufferSize]; int preTokenStackSize; void pushPreToken(const HlslToken&); HlslToken popPreToken(); - // Previously scanned tokens, not yet return for future advances, + // Previously scanned tokens, not yet returned for future advances, // but available for that. // Is logically a fifo for normal advances, and a stack for recession. - // Currently implemented with an intrinsic size of 1. - HlslToken tokenBuffer; + // Currently implemented with an intrinsic size of 2. + HlslToken tokenBuffer[tokenBufferSize]; + int tokenBufferPos; void pushTokenBuffer(const HlslToken&); HlslToken popTokenBuffer(); };