text: //===--- HLSLRootSignature.cpp -- HLSL root signature parsing -------------===//
  ///////////////////////////////////////////////////////////////////////////////
  //                                                                           //
  // HLSLRootSignature.cpp                                                     //
  // Copyright (C) Microsoft Corporation. All rights reserved.                 //
  // This file is distributed under the University of Illinois Open Source     //
  // License. See LICENSE.TXT for details.                                     //
  //                                                                           //
  //  This file implements the parser for the root signature mini-language.    //
  //                                                                           //
  ///////////////////////////////////////////////////////////////////////////////
  
  #include "llvm/ADT/SmallVector.h"
  #include "llvm/Support/raw_ostream.h"
  #include "clang/Basic/Diagnostic.h"
  #include "clang/Parse/ParseHLSL.h"
  #include "clang/Parse/ParseDiagnostic.h"
  #include "dxc/Support/Global.h"
  #include "dxc/Support/WinIncludes.h"
  #include "dxc/Support/WinFunctions.h"
  #include "HLSLRootSignature.h"
  
  #include <float.h>
  
  using namespace llvm;
  using namespace hlsl;
  
  // Error codes. These could be useful for localization at some point.
  #define ERR_RS_UNEXPECTED_TOKEN             4612  
  #define ERR_RS_ROOTFLAGS_MORE_THAN_ONCE     4613  
  #define ERR_RS_CREATION_FAILED              4614  
  #define ERR_RS_BAD_SM                       4615  
  #define ERR_RS_UNDEFINED_REGISTER           4616  
  #define ERR_RS_INCORRECT_REGISTER_TYPE      4617  
  #define ERR_RS_NOT_ALLOWED_FOR_HS_PATCH_CONST 4618  
  #define ERR_RS_WRONG_ROOT_DESC_FLAG         4619  
  #define ERR_RS_WRONG_DESC_RANGE_FLAG        4620
  #define ERR_RS_LOCAL_FLAG_ON_GLOBAL         4621
  #define ERR_RS_BAD_FLOAT                    5000
  
  // Non-throwing new
  #define NEW new (std::nothrow)
  
  DEFINE_ENUM_FLAG_OPERATORS(DxilRootSignatureFlags)
  DEFINE_ENUM_FLAG_OPERATORS(DxilRootDescriptorFlags)
  DEFINE_ENUM_FLAG_OPERATORS(DxilDescriptorRangeFlags)
  DEFINE_ENUM_FLAG_OPERATORS(DxilRootSignatureCompilationFlags)
  
  RootSignatureTokenizer::RootSignatureTokenizer(const char *pStr, size_t len)
    : m_pStrPos(pStr)
    , m_pEndPos(pStr + len)
  {
      m_TokenBufferIdx = 0;
      ReadNextToken(m_TokenBufferIdx);
  }
  
  RootSignatureTokenizer::RootSignatureTokenizer(const char *pStr)
    : m_pStrPos(pStr)
    , m_pEndPos(pStr + strlen(pStr))
  {
    m_TokenBufferIdx = 0;
    ReadNextToken(m_TokenBufferIdx);
  }
  
  RootSignatureTokenizer::Token
  RootSignatureTokenizer::GetToken()
  {
      uint32_t CurBufferIdx = m_TokenBufferIdx;
      m_TokenBufferIdx = (m_TokenBufferIdx + 1) % kNumBuffers;
      ReadNextToken(m_TokenBufferIdx);
      return m_Tokens[CurBufferIdx];
  }
  
  RootSignatureTokenizer::Token
  RootSignatureTokenizer::PeekToken()
  {
      return m_Tokens[m_TokenBufferIdx];
  }
  
  bool RootSignatureTokenizer::IsDone() const
  {
      return m_pStrPos == m_pEndPos;
  }
  
  void RootSignatureTokenizer::ReadNextToken(uint32_t BufferIdx)
  {
      char *pBuffer = m_TokenStrings[BufferIdx];
      Token &T = m_Tokens[BufferIdx];
      bool bFloat = false;
      bool bKW = false;
      char c = 0;
  
      EatSpace();
  
      // Identify token
      uint32_t TokLen = 0;
      char ch;
      // Any time m_pStrPos moves, update ch; no null termination assumptions made.
      // Test ch, not m_StrPos[0], which may be at end.
  #define STRPOS_MOVED() ch = m_pStrPos == m_pEndPos ? '\0' : m_pStrPos[0];
      STRPOS_MOVED();
      if(IsSeparator(ch))
      {
          pBuffer[TokLen++] = *m_pStrPos++;
      }
      else if(IsDigit(ch) || ch == '+' || ch == '-' || ch == '.')
      {
          if(ch == '+' || ch == '-')
          {
              pBuffer[TokLen++] = *m_pStrPos++;
              STRPOS_MOVED();
          }
  
          bool bSeenDigit = false;
          while(IsDigit(ch) && TokLen < kMaxTokenLength)
          {
              pBuffer[TokLen++] = *m_pStrPos++;
              STRPOS_MOVED();
              bSeenDigit = true;
          }
              
          if(ch == '.')
          {
              bFloat = true;
              pBuffer[TokLen++] = *m_pStrPos++;
              STRPOS_MOVED();
              if(!bSeenDigit && !IsDigit(ch))
              {
                  goto lUnknownToken;
              }
              while(IsDigit(ch) && TokLen < kMaxTokenLength)
              {
                  pBuffer[TokLen++] = *m_pStrPos++;
                  STRPOS_MOVED();
                  bSeenDigit = true;
              }
          }
  
          if(!bSeenDigit)
          {
              goto lUnknownToken;
          }
  
          if(ch == 'e' || ch == 'E')
          {
              bFloat = true;
              pBuffer[TokLen++] = *m_pStrPos++;
              STRPOS_MOVED()
              if(ch == '+' || ch == '-')
              {
                  pBuffer[TokLen++] = *m_pStrPos++;
                  STRPOS_MOVED();
              }
              if(!IsDigit(ch))
              {
                  goto lUnknownToken;
              }
              while(IsDigit(ch) && TokLen < kMaxTokenLength)
              {
                  pBuffer[TokLen++] = *m_pStrPos++;
                  STRPOS_MOVED();
              }
          }
  
          if(ch == 'f' || ch == 'F')
          {
              bFloat = true;
              pBuffer[TokLen++] = *m_pStrPos++;
              STRPOS_MOVED();
          }
      }
      else if(IsAlpha(ch) || ch == '_')
      {
          while((IsAlpha(ch) || ch == '_' || IsDigit(ch)) && TokLen < kMaxTokenLength)
          {
              pBuffer[TokLen++] = *m_pStrPos++;
              STRPOS_MOVED();
          }
      }
      else
      {
          while(m_pStrPos < m_pEndPos && TokLen < kMaxTokenLength)
          {
              pBuffer[TokLen++] = *m_pStrPos++;
              STRPOS_MOVED(); // not really needed, but good for consistency
          }
      }
      pBuffer[TokLen] = '\0';
  #undef STRPOS_MOVED
  
      //
      // Classify token
      //
      c = pBuffer[0];
  
      // Delimiters
      switch(c)
      {
      case '\0':  T = Token(Token::Type::EOL,    pBuffer);    return;
      case ',':   T = Token(Token::Type::Comma,  pBuffer);    return;
      case '(':   T = Token(Token::Type::LParen, pBuffer);    return;
      case ')':   T = Token(Token::Type::RParen, pBuffer);    return;
      case '=':   T = Token(Token::Type::EQ,     pBuffer);    return;
      case '|':   T = Token(Token::Type::OR,     pBuffer);    return;
      }
  
      // Number
      if(IsDigit(c) || c == '+' || c == '-' || c == '.')
      {
          if(bFloat)
          {
              float v = 0.f;
              if(ToFloat(pBuffer, v))
              {
                  T = Token(Token::Type::NumberFloat, pBuffer, v);
                  return;
              }
          }
          else
          {
              if(c == '-')
              {
                  int n = 0;
                  if(ToI32(pBuffer, n))
                  {
                      T = Token(Token::Type::NumberI32, pBuffer, (uint32_t)n);
                      return;
                  }
              }
              else
              {
                  uint32_t n = 0;
                  if(ToU32(pBuffer, n))
                  {
                      T = Token(Token::Type::NumberU32, pBuffer, n);
                      return;
                  }
              }
          }
          
          goto lUnknownToken;
      }
  
      // Register
      if(IsDigit(pBuffer[1])  &&  (c == 't' || c == 's' || c == 'u' || c == 'b'))
      {
          if(ToRegister(pBuffer, T))
              return;
      }
  
      // Keyword
  #define KW(__name)  ToKeyword(pBuffer, T, #__name, Token::Type::__name)
  
      // Case-incensitive
      switch(toupper(c))
      {
      case 'A':
          bKW = KW(ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT) ||
                KW(ALLOW_STREAM_OUTPUT) ||
                KW(addressU) || 
                KW(addressV) || 
                KW(addressW);
          break;
  
      case 'B':
          bKW = KW(borderColor);
          break;
  
      case 'C':
          bKW = KW(CBV) ||
                KW(comparisonFunc) ||
                KW(COMPARISON_NEVER) ||
                KW(COMPARISON_LESS) ||
                KW(COMPARISON_EQUAL) ||
                KW(COMPARISON_LESS_EQUAL) ||
                KW(COMPARISON_GREATER) ||
                KW(COMPARISON_NOT_EQUAL) ||
                KW(COMPARISON_GREATER_EQUAL) ||
                KW(COMPARISON_ALWAYS);
          break;
  
      case 'D':
          bKW = KW(DescriptorTable) || 
                KW(DESCRIPTOR_RANGE_OFFSET_APPEND) ||
                KW(DENY_VERTEX_SHADER_ROOT_ACCESS) || 
                KW(DENY_HULL_SHADER_ROOT_ACCESS) || 
                KW(DENY_DOMAIN_SHADER_ROOT_ACCESS) || 
                KW(DENY_GEOMETRY_SHADER_ROOT_ACCESS) || 
                KW(DENY_PIXEL_SHADER_ROOT_ACCESS) ||
                KW(DESCRIPTORS_VOLATILE) ||
                KW(DATA_VOLATILE) ||
                KW(DATA_STATIC) ||
                KW(DATA_STATIC_WHILE_SET_AT_EXECUTE) ||
                KW(DESCRIPTORS_STATIC_KEEPING_BUFFER_BOUNDS_CHECKS);
            break;
  
      case 'F':
          bKW = KW(flags) ||
                KW(filter) || 
                KW(FILTER_MIN_MAG_MIP_POINT) || 
                KW(FILTER_MIN_MAG_POINT_MIP_LINEAR) || 
                KW(FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT) || 
                KW(FILTER_MIN_POINT_MAG_MIP_LINEAR) || 
                KW(FILTER_MIN_LINEAR_MAG_MIP_POINT) || 
                KW(FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR) || 
                KW(FILTER_MIN_MAG_LINEAR_MIP_POINT) || 
                KW(FILTER_MIN_MAG_MIP_LINEAR) || 
                KW(FILTER_ANISOTROPIC) || 
                KW(FILTER_COMPARISON_MIN_MAG_MIP_POINT) || 
                KW(FILTER_COMPARISON_MIN_MAG_POINT_MIP_LINEAR) || 
                KW(FILTER_COMPARISON_MIN_POINT_MAG_LINEAR_MIP_POINT) || 
                KW(FILTER_COMPARISON_MIN_POINT_MAG_MIP_LINEAR) || 
                KW(FILTER_COMPARISON_MIN_LINEAR_MAG_MIP_POINT) || 
                KW(FILTER_COMPARISON_MIN_LINEAR_MAG_POINT_MIP_LINEAR) || 
                KW(FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT) || 
                KW(FILTER_COMPARISON_MIN_MAG_MIP_LINEAR) || 
                KW(FILTER_COMPARISON_ANISOTROPIC) || 
                KW(FILTER_MINIMUM_MIN_MAG_MIP_POINT) || 
                KW(FILTER_MINIMUM_MIN_MAG_POINT_MIP_LINEAR) || 
                KW(FILTER_MINIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT) || 
                KW(FILTER_MINIMUM_MIN_POINT_MAG_MIP_LINEAR) || 
                KW(FILTER_MINIMUM_MIN_LINEAR_MAG_MIP_POINT) || 
                KW(FILTER_MINIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR) || 
                KW(FILTER_MINIMUM_MIN_MAG_LINEAR_MIP_POINT) || 
                KW(FILTER_MINIMUM_MIN_MAG_MIP_LINEAR) || 
                KW(FILTER_MINIMUM_ANISOTROPIC) || 
                KW(FILTER_MAXIMUM_MIN_MAG_MIP_POINT) || 
                KW(FILTER_MAXIMUM_MIN_MAG_POINT_MIP_LINEAR) || 
                KW(FILTER_MAXIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT) || 
                KW(FILTER_MAXIMUM_MIN_POINT_MAG_MIP_LINEAR) || 
                KW(FILTER_MAXIMUM_MIN_LINEAR_MAG_MIP_POINT) || 
                KW(FILTER_MAXIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR) || 
                KW(FILTER_MAXIMUM_MIN_MAG_LINEAR_MIP_POINT) || 
                KW(FILTER_MAXIMUM_MIN_MAG_MIP_LINEAR) || 
                KW(FILTER_MAXIMUM_ANISOTROPIC);
          break;
  
      case 'L':
          bKW = KW(LOCAL_ROOT_SIGNATURE);
          break;
  
      case 'M':
          bKW = KW(maxAnisotropy) || KW(mipLODBias) || KW(minLOD) || KW(maxLOD);
          break;
  
      case 'N':
          bKW = KW(numDescriptors) || KW(num32BitConstants);
          break;
  
      case 'O':
          bKW = KW(offset);
          break;
  
      case 'R':
          bKW = KW(RootFlags) || KW(RootConstants);
          break;
  
      case 'S':
          bKW = KW(space) || KW(Sampler) || KW(StaticSampler) || KW(SRV) ||
                KW(SHADER_VISIBILITY_ALL)      ||  KW(SHADER_VISIBILITY_VERTEX) || 
                KW(SHADER_VISIBILITY_HULL)     || KW(SHADER_VISIBILITY_DOMAIN)  ||
                KW(SHADER_VISIBILITY_GEOMETRY) || KW(SHADER_VISIBILITY_PIXEL) ||
                KW(STATIC_BORDER_COLOR_TRANSPARENT_BLACK) ||
                KW(STATIC_BORDER_COLOR_OPAQUE_BLACK) ||
                KW(STATIC_BORDER_COLOR_OPAQUE_WHITE);
          break;
  
      case 'T':
          bKW = KW(TEXTURE_ADDRESS_WRAP) || 
                KW(TEXTURE_ADDRESS_MIRROR) ||
                KW(TEXTURE_ADDRESS_CLAMP) ||
                KW(TEXTURE_ADDRESS_BORDER) ||
                KW(TEXTURE_ADDRESS_MIRROR_ONCE);
          break;
  
      case 'U':
          bKW = KW(unbounded) || KW(UAV);
          break;
  
      case 'V':
          bKW = KW(visibility);
          break;
      }
  #undef KW
  
      if(!bKW) goto lUnknownToken;
  
      return;
  
  lUnknownToken:
      T = Token(Token::Type::Unknown, pBuffer);
  }
  
  void RootSignatureTokenizer::EatSpace()
  {
      while(m_pStrPos < m_pEndPos && *m_pStrPos == ' ')
          m_pStrPos++;
  }
  
  bool RootSignatureTokenizer::ToI32(LPCSTR pBuf, int & n)
  {
      if(pBuf[0] == '\0') return false;
  
      long long N = _atoi64(pBuf);
      if(N > INT_MAX || N < INT_MIN) return false;
  
      n = static_cast<int>(N);
      return true;
  }
  
  bool RootSignatureTokenizer::ToU32(LPCSTR pBuf, uint32_t & n)
  {
      if(pBuf[0] == '\0') return false;
  
      long long N = _atoi64(pBuf);
      if(N > UINT32_MAX || N < 0) return false;
  
      n = static_cast<uint32_t>(N);
      return true;
  }
  
  bool RootSignatureTokenizer::ToFloat(LPCSTR pBuf, float & n)
  {
      if(pBuf[0] == '\0') return false;
  
      errno = 0;
      double N = strtod(pBuf, NULL);
      if (errno == ERANGE || (N > FLT_MAX || N < -FLT_MAX)) {
        return false;
      }
  
      n = static_cast<float>(N);
      return true;
  }
  
  
  bool RootSignatureTokenizer::ToRegister(LPCSTR pBuf, Token & T)
  {
      uint32_t n;
      if(ToU32(&pBuf[1], n))
      {
          switch(pBuf[0])
          {
          case 't':   T = Token(Token::Type::TReg, pBuf, n);  return true;
          case 's':   T = Token(Token::Type::SReg, pBuf, n);  return true;
          case 'u':   T = Token(Token::Type::UReg, pBuf, n);  return true;
          case 'b':   T = Token(Token::Type::BReg, pBuf, n);  return true;
          }
      }
  
      return false;
  }
  
  bool RootSignatureTokenizer::ToKeyword(LPCSTR pBuf, Token & T, const char *pKeyword, Token::Type Type)
  {
      // Tokens are case-insencitive to allow more flexibility for programmers
      if(_stricmp(pBuf, pKeyword) == 0)
      {
          T = Token(Type, pBuf);
          return true;
      }
      else
      {
          T = Token(Token::Type::Unknown, pBuf);
          return false;
      }
  }
  
  bool RootSignatureTokenizer::IsSeparator(char c) const
  {
      return (c == ',' || c == '=' || c == '|' || c == '('  || c == ')' || c == ' ' || c == '\t' || c == '\n');
  }
  
  bool RootSignatureTokenizer::IsDigit(char c) const
  {
      return isdigit(c) > 0;
  }
  
  bool RootSignatureTokenizer::IsAlpha(char c) const
  {
      return isalpha(c) > 0;
  }
  
  RootSignatureParser::RootSignatureParser(
      RootSignatureTokenizer *pTokenizer, DxilRootSignatureVersion DefaultVersion,
      DxilRootSignatureCompilationFlags CompilationFlags, llvm::raw_ostream &OS)
      : m_pTokenizer(pTokenizer), m_Version(DefaultVersion), m_CompilationFlags(CompilationFlags), m_OS(OS) {}
  
  HRESULT RootSignatureParser::Parse(DxilVersionedRootSignatureDesc **ppRootSignature)
  {
      HRESULT hr = S_OK;
      DxilVersionedRootSignatureDesc *pRS = NULL;
  
      DXASSERT(!((bool)(m_CompilationFlags & DxilRootSignatureCompilationFlags::GlobalRootSignature) && 
                 (bool)(m_CompilationFlags & DxilRootSignatureCompilationFlags::LocalRootSignature)),
               "global and local cannot be both set");
  
      if(ppRootSignature != NULL)
      {
          IFC(ParseRootSignature(&pRS));
          *ppRootSignature = pRS;
      }
  
  Cleanup:
      return hr;
  }
  
  HRESULT RootSignatureParser::GetAndMatchToken(TokenType & Token, TokenType::Type Type)
  {
      HRESULT hr = S_OK;
      Token = m_pTokenizer->GetToken();
      if(Token.GetType() != Type)
          IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Unexpected token '%s'", Token.GetStr()));
  
  Cleanup:
      return hr;
  }
  
  HRESULT RootSignatureParser::Error(uint32_t uErrorNum, LPCSTR pError, ...)
  {
      va_list Args;
      char msg[512];
      va_start(Args, pError);
      vsprintf_s(msg, pError, Args);
      va_end(Args);
      try {
        m_OS << msg;
      }
      CATCH_CPP_RETURN_HRESULT();
      return E_FAIL;
  }
  
  HRESULT RootSignatureParser::ParseRootSignature(DxilVersionedRootSignatureDesc **ppRootSignature)
  {
      HRESULT hr = S_OK;
      TokenType Token;
      bool bSeenFlags = false;
      SmallVector<DxilRootParameter1, 8> RSParameters;
      DxilRootParameter1 *pRSParams = NULL;
      SmallVector<DxilStaticSamplerDesc, 8> StaticSamplers;
      DxilStaticSamplerDesc *pStaticSamplers = NULL;
      DxilVersionedRootSignatureDesc *pRS = NULL;
  
      *ppRootSignature = NULL;
      IFCOOM(pRS = NEW DxilVersionedRootSignatureDesc);
      // Always parse root signature string to the latest version.
      pRS->Version = DxilRootSignatureVersion::Version_1_1;
      memset(&pRS->Desc_1_1, 0, sizeof(pRS->Desc_1_1));
  
      Token = m_pTokenizer->PeekToken();
      while(Token.GetType() != TokenType::EOL)
      {
          switch(Token.GetType())
          {
          case TokenType::RootFlags:
              if(!bSeenFlags)
              {
                  IFC(ParseRootSignatureFlags(pRS->Desc_1_1.Flags));
                  bSeenFlags = true;
              }
              else
              {
                  IFC(Error(ERR_RS_ROOTFLAGS_MORE_THAN_ONCE, "RootFlags cannot be specified more than once"));
              }
              break;
  
          case TokenType::RootConstants:
          {
              DxilRootParameter1 P;
              IFC(ParseRootConstants(P));
              RSParameters.push_back(P);
              break;
          }
  
          case TokenType::CBV:
          {
              DxilRootParameter1 P;
              IFC(ParseRootShaderResource(Token.GetType(), TokenType::BReg, DxilRootParameterType::CBV, P));
              RSParameters.push_back(P);
              break;
          }
  
          case TokenType::SRV:
          {
              DxilRootParameter1 P;
              IFC(ParseRootShaderResource(Token.GetType(), TokenType::TReg, DxilRootParameterType::SRV, P));
              RSParameters.push_back(P);
              break;
          }
  
          case TokenType::UAV:
          {
              DxilRootParameter1 P;
              IFC(ParseRootShaderResource(Token.GetType(), TokenType::UReg, DxilRootParameterType::UAV, P));
              RSParameters.push_back(P);
              break;
          }
  
          case TokenType::DescriptorTable:
          {
              DxilRootParameter1 P;
              IFC(ParseRootDescriptorTable(P));
              RSParameters.push_back(P);
              break;
          }
  
          case TokenType::StaticSampler:
          {
              DxilStaticSamplerDesc P;
              IFC(ParseStaticSampler(P));
              StaticSamplers.push_back(P);
              break;
          }
  
          default:
              IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Unexpected token '%s' when parsing root signature", Token.GetStr()));
          }
  
          Token = m_pTokenizer->GetToken();
          if(Token.GetType() == TokenType::EOL)
              break;
  
          // Consume ','
          if(Token.GetType() != TokenType::Comma)
              IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Expected ',', found: '%s'", Token.GetStr()));
  
          Token = m_pTokenizer->PeekToken();
      }
      
      if(RSParameters.size() > 0)
      {
          IFCOOM(pRSParams = NEW DxilRootParameter1[RSParameters.size()]);
          pRS->Desc_1_1.NumParameters = RSParameters.size();
          memcpy(pRSParams, RSParameters.data(), pRS->Desc_1_1.NumParameters*sizeof(DxilRootParameter1));
          pRS->Desc_1_1.pParameters = pRSParams;
      }
      if(StaticSamplers.size() > 0)
      {
          IFCOOM(pStaticSamplers = NEW DxilStaticSamplerDesc[StaticSamplers.size()]);
          pRS->Desc_1_1.NumStaticSamplers = StaticSamplers.size();
          memcpy(pStaticSamplers, StaticSamplers.data(), pRS->Desc_1_1.NumStaticSamplers*sizeof(DxilStaticSamplerDesc));
          pRS->Desc_1_1.pStaticSamplers = pStaticSamplers;
      }
  
      // Set local signature flag if not already on
      if ((bool)(m_CompilationFlags & DxilRootSignatureCompilationFlags::LocalRootSignature))
        pRS->Desc_1_1.Flags |= DxilRootSignatureFlags::LocalRootSignature;
  
      // Down-convert root signature to the right version, if needed.
      if(pRS->Version != m_Version)
      {
          DxilVersionedRootSignatureDesc *pRS1 = NULL;
          try {
            hlsl::ConvertRootSignature(pRS, m_Version, (const DxilVersionedRootSignatureDesc **)&pRS1);
          }
          CATCH_CPP_ASSIGN_HRESULT();
          IFC(hr);
          hlsl::DeleteRootSignature(pRS);
          pRS = pRS1;
      }
  
      *ppRootSignature = pRS;
  
  Cleanup:
      if(FAILED(hr))
      {
          hlsl::DeleteRootSignature(pRS);
      }
      return hr;
  }
  
  HRESULT RootSignatureParser::ParseRootSignatureFlags(DxilRootSignatureFlags & Flags)
  {
      //RootFlags(ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | DENY_VERTEX_SHADER_ROOT_ACCESS)
      //  ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT
      //  DENY_VERTEX_SHADER_ROOT_ACCESS
      //  DENY_HULL_SHADER_ROOT_ACCESS
      //  DENY_DOMAIN_SHADER_ROOT_ACCESS
      //  DENY_GEOMETRY_SHADER_ROOT_ACCESS
      //  DENY_PIXEL_SHADER_ROOT_ACCESS
      //  ALLOW_STREAM_OUTPUT
      //  LOCAL_ROOT_SIGNATURE
  
      HRESULT hr = S_OK;
      TokenType Token;
  
      IFC(GetAndMatchToken(Token, TokenType::RootFlags));
      IFC(GetAndMatchToken(Token, TokenType::LParen));
  
      Flags = DxilRootSignatureFlags::None;
  
      Token = m_pTokenizer->PeekToken();
      if(Token.GetType() == TokenType::NumberU32)
      {
          IFC(GetAndMatchToken(Token, TokenType::NumberU32));
          uint32_t n = Token.GetU32Value();
          if(n != 0)
          {
              IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Root signature flag values can only be 0 or flag enum values, found: '%s'", Token.GetStr()));
          }
      }
      else
      {
          for(;;)
          {
              Token = m_pTokenizer->GetToken();
              switch(Token.GetType())
              {
              case TokenType::ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT:
                  Flags |= DxilRootSignatureFlags::AllowInputAssemblerInputLayout;
                  break;
              case TokenType::DENY_VERTEX_SHADER_ROOT_ACCESS:
                  Flags |= DxilRootSignatureFlags::DenyVertexShaderRootAccess;
                  break;
              case TokenType::DENY_HULL_SHADER_ROOT_ACCESS:
                  Flags |= DxilRootSignatureFlags::DenyHullShaderRootAccess;
                  break;
              case TokenType::DENY_DOMAIN_SHADER_ROOT_ACCESS:
                  Flags |= DxilRootSignatureFlags::DenyDomainShaderRootAccess;
                  break;
              case TokenType::DENY_GEOMETRY_SHADER_ROOT_ACCESS:
                  Flags |= DxilRootSignatureFlags::DenyGeometryShaderRootAccess;
                  break;
              case TokenType::DENY_PIXEL_SHADER_ROOT_ACCESS:
                  Flags |= DxilRootSignatureFlags::DenyPixelShaderRootAccess;
                  break;
              case TokenType::ALLOW_STREAM_OUTPUT:
                  Flags |= DxilRootSignatureFlags::AllowStreamOutput;
                  break;
              case TokenType::LOCAL_ROOT_SIGNATURE:
                  if ((bool)(m_CompilationFlags & DxilRootSignatureCompilationFlags::GlobalRootSignature))
                    IFC(Error(ERR_RS_LOCAL_FLAG_ON_GLOBAL, "LOCAL_ROOT_SIGNATURE flag used in global root signature"));
                  Flags |= DxilRootSignatureFlags::LocalRootSignature;
                  break;
              default:
                  IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Expected a root signature flag value, found: '%s'", Token.GetStr()));
              }
  
              Token = m_pTokenizer->PeekToken();
              if(Token.GetType() == TokenType::RParen)
                  break;
  
              IFC(GetAndMatchToken(Token, TokenType::OR));
          }
      }
  
      IFC(GetAndMatchToken(Token, TokenType::RParen));
  
  Cleanup:
      return hr;
  }
  
  HRESULT RootSignatureParser::ParseRootConstants(DxilRootParameter1 &P)
  {
      //"RootConstants(num32BitConstants=3, b2 [, space=1, visibility=SHADER_VISIBILITY_ALL ] ), "
      HRESULT hr = S_OK;
      TokenType Token;
      memset(&P, 0, sizeof(P));
      DXASSERT(P.ShaderVisibility == DxilShaderVisibility::All, "else default isn't zero");
      P.ParameterType = DxilRootParameterType::Constants32Bit;
      bool bSeenNum32BitConstants = false;
      bool bSeenBReg = false;
      bool bSeenSpace = false;
      bool bSeenVisibility = false;
  
      IFC(GetAndMatchToken(Token, TokenType::RootConstants));
      IFC(GetAndMatchToken(Token, TokenType::LParen));
  
      for(;;)
      {
          Token = m_pTokenizer->PeekToken();
  
          switch(Token.GetType())
          {
          case TokenType::num32BitConstants:
              IFC(MarkParameter(bSeenNum32BitConstants, "num32BitConstants"));
              IFC(ParseNum32BitConstants(P.Constants.Num32BitValues));
              break;
          case TokenType::BReg:
              IFC(MarkParameter(bSeenBReg, "cbuffer register b#"));
              IFC(ParseRegister(TokenType::BReg, P.Constants.ShaderRegister));
              break;
          case TokenType::space:
              IFC(MarkParameter(bSeenSpace, "space"));
              IFC(ParseSpace(P.Constants.RegisterSpace));
              break;
          case TokenType::visibility:
              IFC(MarkParameter(bSeenVisibility, "visibility"));
              IFC(ParseVisibility(P.ShaderVisibility));
              break;
          default:
              IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Unexpected token '%s'", Token.GetStr()));
              break;
          }
  
          Token = m_pTokenizer->GetToken();
          if(Token.GetType() == TokenType::RParen)
              break;
          else if(Token.GetType() != TokenType::Comma)
              IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Unexpected token '%s'", Token.GetStr()));
      }
  
      if(!bSeenNum32BitConstants)
      {
          IFC(Error(ERR_RS_UNDEFINED_REGISTER, "num32BitConstants must be defined for each RootConstants"));
      }
      if(!bSeenBReg)
      {
          IFC(Error(ERR_RS_UNDEFINED_REGISTER, "Constant buffer register b# must be defined for each RootConstants"));
      }
  
  Cleanup:
      return hr;
  }
  
  HRESULT RootSignatureParser::ParseRootShaderResource(TokenType::Type TokType, 
                                                       TokenType::Type RegType,
                                                       DxilRootParameterType ResType,
                                                       DxilRootParameter1 &P)
  {
      // CBV(b0 [, space=3, flags=0, visibility=VISIBILITY_ALL] )
      HRESULT hr = S_OK;
      TokenType Token;
      P.ParameterType = ResType;
      P.ShaderVisibility = DxilShaderVisibility::All;
      P.Descriptor.ShaderRegister = 0;
      P.Descriptor.RegisterSpace = 0;
      P.Descriptor.Flags = DxilRootDescriptorFlags::None;
      bool bSeenReg           = false;
      bool bSeenFlags         = false;
      bool bSeenSpace         = false;
      bool bSeenVisibility    = false;
  
      IFC(GetAndMatchToken(Token, TokType));
      IFC(GetAndMatchToken(Token, TokenType::LParen));
  
      for(;;)
      {
          Token = m_pTokenizer->PeekToken();
  
          switch(Token.GetType())
          {
          case TokenType::BReg:
          case TokenType::TReg:
          case TokenType::UReg:
              IFC(MarkParameter(bSeenReg, "shader register"));
              IFC(ParseRegister(RegType, P.Descriptor.ShaderRegister));
              break;
          case TokenType::flags:
              IFC(MarkParameter(bSeenFlags, "flags"));
              IFC(ParseRootDescFlags(P.Descriptor.Flags));
              break;
          case TokenType::space:
              IFC(MarkParameter(bSeenSpace, "space"));
              IFC(ParseSpace(P.Descriptor.RegisterSpace));
              break;
          case TokenType::visibility:
              IFC(MarkParameter(bSeenVisibility, "visibility"));
              IFC(ParseVisibility(P.ShaderVisibility));
              break;
          default:
              IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Unexpected token '%s'", Token.GetStr()));
              break;
          }
  
          Token = m_pTokenizer->GetToken();
          if(Token.GetType() == TokenType::RParen)
              break;
          else if(Token.GetType() != TokenType::Comma)
              IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Unexpected token '%s'", Token.GetStr()));
      }
  
      if(!bSeenReg)
      {
          IFC(Error(ERR_RS_UNDEFINED_REGISTER, "shader register must be defined for each CBV/SRV/UAV"));
      }
  
  Cleanup:
      return hr;
  }
  
  HRESULT RootSignatureParser::ParseRootDescriptorTable(DxilRootParameter1 &P)
  {
      //DescriptorTable( SRV(t2, numDescriptors = 6), UAV(u0, numDescriptors = 4) [, visibility = SHADER_VISIBILITY_ALL ] )
      HRESULT hr = S_OK;
      TokenType Token;
      memset(&P, 0, sizeof(P));
      DXASSERT(P.ShaderVisibility == DxilShaderVisibility::All, "else default isn't zero");
      P.ParameterType = DxilRootParameterType::DescriptorTable;
      bool bSeenVisibility = false;
      DxilDescriptorRange1 * pDescs = NULL;
      SmallVector<DxilDescriptorRange1, 4> Ranges;
  
      IFC(GetAndMatchToken(Token, TokenType::DescriptorTable));
      IFC(GetAndMatchToken(Token, TokenType::LParen));
  
      for(;;)
      {
          Token = m_pTokenizer->PeekToken();
  
          switch(Token.GetType())
          {
          case TokenType::CBV:
          {
              DxilDescriptorRange1 R;
              IFC(ParseDescTableResource(Token.GetType(), TokenType::BReg, DxilDescriptorRangeType::CBV, R));
              Ranges.push_back(R);
              break;
          }
          case TokenType::SRV:
          {
              DxilDescriptorRange1 R;
              IFC(ParseDescTableResource(Token.GetType(), TokenType::TReg, DxilDescriptorRangeType::SRV, R));
              Ranges.push_back(R);
              break;
          }
          case TokenType::UAV:
          {
              DxilDescriptorRange1 R;
              IFC(ParseDescTableResource(Token.GetType(), TokenType::UReg, DxilDescriptorRangeType::UAV, R));
              Ranges.push_back(R);
              break;
          }
          case TokenType::Sampler:
          {
              DxilDescriptorRange1 R;
              IFC(ParseDescTableResource(Token.GetType(), TokenType::SReg, DxilDescriptorRangeType::Sampler, R));
              Ranges.push_back(R);
              break;
          }
          case TokenType::visibility:
              IFC(MarkParameter(bSeenVisibility, "visibility"));
              IFC(ParseVisibility(P.ShaderVisibility));
              break;
          default:
              IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Unexpected token '%s'", Token.GetStr()));
              break;
          }
  
          Token = m_pTokenizer->GetToken();
          if(Token.GetType() == TokenType::RParen)
              break;
          else if(Token.GetType() != TokenType::Comma)
              IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Unexpected token '%s'", Token.GetStr()));
      }
  
      if(Ranges.size() > 0)
      {
          IFCOOM(pDescs = NEW DxilDescriptorRange1[Ranges.size()]);
          for(uint32_t i = 0; i < Ranges.size(); i++)
          {
              pDescs[i] = Ranges[i];
          }
          P.DescriptorTable.pDescriptorRanges = pDescs;
          P.DescriptorTable.NumDescriptorRanges = Ranges.size();
      }
  
  Cleanup:
      if(FAILED(hr))
      {
          delete[] pDescs;
      }
      return hr;
  }
  
  HRESULT RootSignatureParser::ParseDescTableResource(TokenType::Type TokType, 
                                                      TokenType::Type RegType, 
                                                      DxilDescriptorRangeType RangeType, 
                                                      DxilDescriptorRange1 &R)
  {
      HRESULT hr = S_OK;
      TokenType Token;
      // CBV(b0 [, numDescriptors = 1, space=0, flags=0, offset = DESCRIPTOR_RANGE_OFFSET_APPEND] )
  
      R.RangeType = RangeType;
      R.NumDescriptors = 1;
      R.BaseShaderRegister = 0;
      R.RegisterSpace = 0;
      R.Flags = DxilDescriptorRangeFlags::None;
      R.OffsetInDescriptorsFromTableStart = DxilDescriptorRangeOffsetAppend;
      bool bSeenReg               = false;
      bool bSeenNumDescriptors    = false;
      bool bSeenSpace             = false;
      bool bSeenFlags             = false;
      bool bSeenOffset            = false;
  
      IFC(GetAndMatchToken(Token, TokType));
      IFC(GetAndMatchToken(Token, TokenType::LParen));
  
      for(;;)
      {
          Token = m_pTokenizer->PeekToken();
  
          switch(Token.GetType())
          {
          case TokenType::BReg:
          case TokenType::TReg:
          case TokenType::UReg:
          case TokenType::SReg:
              IFC(MarkParameter(bSeenReg, "shader register"));
              IFC(ParseRegister(RegType, R.BaseShaderRegister));
              break;
          case TokenType::numDescriptors:
              IFC(MarkParameter(bSeenNumDescriptors, "numDescriptors"));
              IFC(ParseNumDescriptors(R.NumDescriptors));
              break;
          case TokenType::space:
              IFC(MarkParameter(bSeenSpace, "space"));
              IFC(ParseSpace(R.RegisterSpace));
              break;
          case TokenType::flags:
              IFC(MarkParameter(bSeenFlags, "flags"));
              IFC(ParseDescRangeFlags(RangeType, R.Flags));
              break;
          case TokenType::offset:
              IFC(MarkParameter(bSeenOffset, "offset"));
              IFC(ParseOffset(R.OffsetInDescriptorsFromTableStart));
              break;
          default:
              IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Unexpected token '%s'", Token.GetStr()));
              break;
          }
  
          Token = m_pTokenizer->GetToken();
          if(Token.GetType() == TokenType::RParen)
              break;
          else if(Token.GetType() != TokenType::Comma)
              IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Unexpected token '%s'", Token.GetStr()));
      }
  
      if(!bSeenReg)
      {
          IFC(Error(ERR_RS_UNDEFINED_REGISTER, "shader register must be defined for each CBV/SRV/UAV"));
      }
  
  Cleanup:
      return hr;
  }
  
  HRESULT RootSignatureParser::ParseRegister(TokenType::Type RegType, uint32_t & Reg)
  {
      HRESULT hr = S_OK;
      TokenType Token = m_pTokenizer->PeekToken();
  
      switch(Token.GetType())
      {
      case TokenType::BReg:
          IFC(GetAndMatchToken(Token, TokenType::BReg));
          break;
      case TokenType::TReg:
          IFC(GetAndMatchToken(Token, TokenType::TReg));
          break;
      case TokenType::UReg:
          IFC(GetAndMatchToken(Token, TokenType::UReg));
          break;
      case TokenType::SReg:
          IFC(GetAndMatchToken(Token, TokenType::SReg));
          break;
      default:
          IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Expected a register token (CBV, SRV, UAV, Sampler), found: '%s'", Token.GetStr()));
      }
  
      if(Token.GetType() != RegType)
      {
          switch(RegType)
          {
          case TokenType::BReg:
              IFC(Error(ERR_RS_INCORRECT_REGISTER_TYPE, "Incorrect register type '%s' in CBV (expected b#)", Token.GetStr()));
              break;
          case TokenType::TReg:
              IFC(Error(ERR_RS_INCORRECT_REGISTER_TYPE, "Incorrect register type '%s' in SRV (expected t#)", Token.GetStr()));
              break;
          case TokenType::UReg:
              IFC(Error(ERR_RS_INCORRECT_REGISTER_TYPE, "Incorrect register type '%s' in UAV (expected u#)", Token.GetStr()));
              break;
          case TokenType::SReg:
              IFC(Error(ERR_RS_INCORRECT_REGISTER_TYPE, "Incorrect register type '%s' in Sampler/StaticSampler (expected s#)", Token.GetStr()));
              break;
          default:
            // Only Register types are relevant.
  	  break;
          }
      }
  
      Reg = Token.GetU32Value();
  
  Cleanup:
      return hr;
  }
  
  HRESULT RootSignatureParser::ParseSpace(uint32_t & Space)
  {
      HRESULT hr = S_OK;
      TokenType Token;
  
      IFC(GetAndMatchToken(Token, TokenType::space));
      IFC(GetAndMatchToken(Token, TokenType::EQ));
      IFC(GetAndMatchToken(Token, TokenType::NumberU32));
      Space = Token.GetU32Value();
  
  Cleanup:
      return hr;
  }
  
  HRESULT RootSignatureParser::ParseNumDescriptors(uint32_t & NumDescriptors)
  {
      HRESULT hr = S_OK;
      TokenType Token;
  
      IFC(GetAndMatchToken(Token, TokenType::numDescriptors));
      IFC(GetAndMatchToken(Token, TokenType::EQ));
      Token = m_pTokenizer->PeekToken();
      if(Token.GetType() == TokenType::unbounded)
      {
          IFC(GetAndMatchToken(Token, TokenType::unbounded));
          NumDescriptors = UINT32_MAX;
      }
      else
      {
          IFC(GetAndMatchToken(Token, TokenType::NumberU32));
          NumDescriptors = Token.GetU32Value();
      }
  
  Cleanup:
      return hr;
  }
  
  HRESULT RootSignatureParser::ParseRootDescFlags(DxilRootDescriptorFlags &Flags)
  {
      // flags=DATA_VOLATILE | DATA_STATIC | DATA_STATIC_WHILE_SET_AT_EXECUTE
  
      HRESULT hr = S_OK;
      TokenType Token;
  
      if (m_Version == DxilRootSignatureVersion::Version_1_0)
      {
          IFC(Error(ERR_RS_WRONG_ROOT_DESC_FLAG, "Root descriptor flags cannot be specified for root_sig_1_0"));
      }
  
      IFC(GetAndMatchToken(Token, TokenType::flags));
      IFC(GetAndMatchToken(Token, TokenType::EQ));
  
      Flags = DxilRootDescriptorFlags::None;
  
      Token = m_pTokenizer->PeekToken();
      if(Token.GetType() == TokenType::NumberU32)
      {
          IFC(GetAndMatchToken(Token, TokenType::NumberU32));
          uint32_t n = Token.GetU32Value();
          if(n != 0)
          {
              IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Root descriptor flag values can only be 0 or flag enum values, found: '%s'", Token.GetStr()));
          }
      }
      else
      {
          for(;;)
          {
              Token = m_pTokenizer->GetToken();
              switch(Token.GetType())
              {
              case TokenType::DATA_VOLATILE:
                  Flags |= DxilRootDescriptorFlags::DataVolatile;
                  break;
              case TokenType::DATA_STATIC:
                  Flags |= DxilRootDescriptorFlags::DataStatic;
                  break;
              case TokenType::DATA_STATIC_WHILE_SET_AT_EXECUTE:
                  Flags |= DxilRootDescriptorFlags::DataStaticWhileSetAtExecute;
                  break;
              default:
                  IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Expected a root descriptor flag value, found: '%s'", Token.GetStr()));
              }
  
              Token = m_pTokenizer->PeekToken();
              if(Token.GetType() == TokenType::RParen || Token.GetType() == TokenType::Comma)
                  break;
  
              IFC(GetAndMatchToken(Token, TokenType::OR));
          }
      }
  
  Cleanup:
      return hr;
  }
  
  HRESULT RootSignatureParser::ParseDescRangeFlags(DxilDescriptorRangeType,
                                                   DxilDescriptorRangeFlags & Flags)
  {
      // flags=DESCRIPTORS_VOLATILE | DATA_VOLATILE | DATA_STATIC | DATA_STATIC_WHILE_SET_AT_EXECUTE | DESCRIPTORS_STATIC_KEEPING_BUFFER_BOUNDS_CHECKS
  
      HRESULT hr = S_OK;
      TokenType Token;
  
      if (m_Version == DxilRootSignatureVersion::Version_1_0)
      {
          IFC(Error(ERR_RS_WRONG_DESC_RANGE_FLAG, "Descriptor range flags cannot be specified for root_sig_1_0"));
      }
  
      IFC(GetAndMatchToken(Token, TokenType::flags));
      IFC(GetAndMatchToken(Token, TokenType::EQ));
  
      Flags = DxilDescriptorRangeFlags::None;
  
      Token = m_pTokenizer->PeekToken();
      if(Token.GetType() == TokenType::NumberU32)
      {
          IFC(GetAndMatchToken(Token, TokenType::NumberU32));
          uint32_t n = Token.GetU32Value();
          if(n != 0)
          {
              IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Descriptor range flag values can only be 0 or flag enum values, found: '%s'", Token.GetStr()));
          }
      }
      else
      {
          for(;;)
          {
              Token = m_pTokenizer->GetToken();
              switch(Token.GetType())
              {
              case TokenType::DESCRIPTORS_VOLATILE:
                  Flags |= DxilDescriptorRangeFlags::DescriptorsVolatile;
                  break;
              case TokenType::DATA_VOLATILE:
                  Flags |= DxilDescriptorRangeFlags::DataVolatile;
                  break;
              case TokenType::DATA_STATIC:
                  Flags |= DxilDescriptorRangeFlags::DataStatic;
                  break;
              case TokenType::DATA_STATIC_WHILE_SET_AT_EXECUTE:
                  Flags |= DxilDescriptorRangeFlags::DataStaticWhileSetAtExecute;
                  break;
              case TokenType::DESCRIPTORS_STATIC_KEEPING_BUFFER_BOUNDS_CHECKS:
                  Flags |= DxilDescriptorRangeFlags::DescriptorsStaticKeepingBufferBoundsChecks;
                  break;
              default:
                  IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Expected a descriptor range flag value, found: '%s'", Token.GetStr()));
              }
  
              Token = m_pTokenizer->PeekToken();
              if(Token.GetType() == TokenType::RParen || Token.GetType() == TokenType::Comma)
                  break;
  
              IFC(GetAndMatchToken(Token, TokenType::OR));
          }
      }
  
  Cleanup:
      return hr;
  }
  
  HRESULT RootSignatureParser::ParseOffset(uint32_t & Offset)
  {
      HRESULT hr = S_OK;
      TokenType Token;
  
      IFC(GetAndMatchToken(Token, TokenType::offset));
      IFC(GetAndMatchToken(Token, TokenType::EQ));
      Token = m_pTokenizer->PeekToken();
      if(Token.GetType() == TokenType::DESCRIPTOR_RANGE_OFFSET_APPEND)
      {
          IFC(GetAndMatchToken(Token, TokenType::DESCRIPTOR_RANGE_OFFSET_APPEND));
          Offset = DxilDescriptorRangeOffsetAppend;
      }
      else
      {
          IFC(GetAndMatchToken(Token, TokenType::NumberU32));
          Offset = Token.GetU32Value();
      }
  
  Cleanup:
      return hr;
  }
  
  HRESULT RootSignatureParser::ParseVisibility(DxilShaderVisibility & Vis)
  {
      HRESULT hr = S_OK;
      TokenType Token;
  
      IFC(GetAndMatchToken(Token, TokenType::visibility));
      IFC(GetAndMatchToken(Token, TokenType::EQ));
      Token = m_pTokenizer->GetToken();
  
      switch(Token.GetType())
      {
      case TokenType::SHADER_VISIBILITY_ALL:      Vis = DxilShaderVisibility::All;      break;
      case TokenType::SHADER_VISIBILITY_VERTEX:   Vis = DxilShaderVisibility::Vertex;   break;
      case TokenType::SHADER_VISIBILITY_HULL:     Vis = DxilShaderVisibility::Hull;     break;
      case TokenType::SHADER_VISIBILITY_DOMAIN:   Vis = DxilShaderVisibility::Domain;   break;
      case TokenType::SHADER_VISIBILITY_GEOMETRY: Vis = DxilShaderVisibility::Geometry; break;
      case TokenType::SHADER_VISIBILITY_PIXEL:    Vis = DxilShaderVisibility::Pixel;    break;
      default:
          IFC(Error(ERR_RS_UNEXPECTED_TOKEN, 
                   "Unexpected visibility value: '%s'.", Token.GetStr()));
      }
  
  Cleanup:
      return hr;
  }
  
  HRESULT RootSignatureParser::ParseNum32BitConstants(uint32_t & NumConst)
  {
      HRESULT hr = S_OK;
      TokenType Token;
  
      IFC(GetAndMatchToken(Token, TokenType::num32BitConstants));
      IFC(GetAndMatchToken(Token, TokenType::EQ));
      IFC(GetAndMatchToken(Token, TokenType::NumberU32));
      NumConst = Token.GetU32Value();
  
  Cleanup:
      return hr;
  }
  
  HRESULT RootSignatureParser::ParseStaticSampler(DxilStaticSamplerDesc &P)
  {
      // StaticSampler( s0,
      //                [ Filter = FILTER_ANISOTROPIC, 
      //                  AddressU = TEXTURE_ADDRESS_WRAP,
      //                  AddressV = TEXTURE_ADDRESS_WRAP,
      //                  AddressW = TEXTURE_ADDRESS_WRAP,
      //                  MipLODBias = 0,
      //                  MaxAnisotropy = 16,
      //                  ComparisonFunc = COMPARISON_LESS_EQUAL,
      //                  BorderColor = STATIC_BORDER_COLOR_OPAQUE_WHITE,
      //                  MinLOD = 0.f,
      //                  MaxLOD = 3.402823466e+38f
      //                  space = 0, 
      //                  visibility = SHADER_VISIBILITY_ALL ] )
      HRESULT hr = S_OK;
      TokenType Token;
      memset(&P, 0, sizeof(P));
      P.Filter = DxilFilter::ANISOTROPIC;
      P.AddressU = P.AddressV = P.AddressW = DxilTextureAddressMode::Wrap;
      P.MaxAnisotropy = 16;
      P.ComparisonFunc = DxilComparisonFunc::LessEqual;
      P.BorderColor = DxilStaticBorderColor::OpaqueWhite;
      P.MaxLOD = DxilFloat32Max;
      bool bSeenFilter            = false;
      bool bSeenAddressU          = false;
      bool bSeenAddressV          = false;
      bool bSeenAddressW          = false;
      bool bSeenMipLODBias        = false;
      bool bSeenMaxAnisotropy     = false;
      bool bSeenComparisonFunc    = false;
      bool bSeenBorderColor       = false;
      bool bSeenMinLOD            = false;
      bool bSeenMaxLOD            = false;
      bool bSeenSReg              = false;
      bool bSeenSpace             = false;
      bool bSeenVisibility        = false;
  
      IFC(GetAndMatchToken(Token, TokenType::StaticSampler));
      IFC(GetAndMatchToken(Token, TokenType::LParen));
  
      for(;;)
      {
          Token = m_pTokenizer->PeekToken();
  
          switch(Token.GetType())
          {
          case TokenType::filter:
              IFC(MarkParameter(bSeenFilter, "filter"));
              IFC(ParseFilter(P.Filter));
              break;
          case TokenType::addressU:
              IFC(MarkParameter(bSeenAddressU, "addressU"));
              IFC(ParseTextureAddressMode(P.AddressU));
              break;
          case TokenType::addressV:
              IFC(MarkParameter(bSeenAddressV, "addressV"));
              IFC(ParseTextureAddressMode(P.AddressV));
              break;
          case TokenType::addressW:
              IFC(MarkParameter(bSeenAddressW, "addressW"));
              IFC(ParseTextureAddressMode(P.AddressW));
              break;
          case TokenType::mipLODBias:
              IFC(MarkParameter(bSeenMipLODBias, "mipLODBias"));
              IFC(ParseMipLODBias(P.MipLODBias));
              break;
          case TokenType::maxAnisotropy:
              IFC(MarkParameter(bSeenMaxAnisotropy, "maxAnisotropy"));
              IFC(ParseMaxAnisotropy(P.MaxAnisotropy));
              break;
          case TokenType::comparisonFunc:
              IFC(MarkParameter(bSeenComparisonFunc, "comparisonFunc"));
              IFC(ParseComparisonFunction(P.ComparisonFunc));
              break;
          case TokenType::borderColor:
              IFC(MarkParameter(bSeenBorderColor, "borderColor"));
              IFC(ParseBorderColor(P.BorderColor));
              break;
          case TokenType::minLOD:
              IFC(MarkParameter(bSeenMinLOD, "minLOD"));
              IFC(ParseMinLOD(P.MinLOD));
              break;
          case TokenType::maxLOD:
              IFC(MarkParameter(bSeenMaxLOD, "maxLOD"));
              IFC(ParseMaxLOD(P.MaxLOD));
              break;
          case TokenType::SReg:
              IFC(MarkParameter(bSeenSReg, "sampler register s#"));
              IFC(ParseRegister(TokenType::SReg, P.ShaderRegister));
              break;
          case TokenType::space:
              IFC(MarkParameter(bSeenSpace, "space"));
              IFC(ParseSpace(P.RegisterSpace));
              break;
          case TokenType::visibility:
              IFC(MarkParameter(bSeenVisibility, "visibility"));
              IFC(ParseVisibility(P.ShaderVisibility));
              break;
          default:
              IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Unexpected token '%s'", Token.GetStr()));
              break;
          }
  
          Token = m_pTokenizer->GetToken();
          if(Token.GetType() == TokenType::RParen)
              break;
          else if(Token.GetType() != TokenType::Comma)
              IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Unexpected token '%s'", Token.GetStr()));
      }
  
      if(!bSeenSReg)
      {
          IFC(Error(ERR_RS_UNDEFINED_REGISTER, "Sampler register s# must be defined for each static sampler"));
      }
  
  Cleanup:
      return hr;
  }
  
  HRESULT RootSignatureParser::ParseFilter(DxilFilter & Filter)
  {
      HRESULT hr = S_OK;
      TokenType Token;
  
      IFC(GetAndMatchToken(Token, TokenType::filter));
      IFC(GetAndMatchToken(Token, TokenType::EQ));
      Token = m_pTokenizer->GetToken();
  
      switch(Token.GetType())
      {
      case TokenType::FILTER_MIN_MAG_MIP_POINT:                           Filter = DxilFilter::MIN_MAG_MIP_POINT;                            break;
      case TokenType::FILTER_MIN_MAG_POINT_MIP_LINEAR:                    Filter = DxilFilter::MIN_MAG_POINT_MIP_LINEAR;                     break;
      case TokenType::FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT:              Filter = DxilFilter::MIN_POINT_MAG_LINEAR_MIP_POINT;               break;
      case TokenType::FILTER_MIN_POINT_MAG_MIP_LINEAR:                    Filter = DxilFilter::MIN_POINT_MAG_MIP_LINEAR;                     break;
      case TokenType::FILTER_MIN_LINEAR_MAG_MIP_POINT:                    Filter = DxilFilter::MIN_LINEAR_MAG_MIP_POINT;                     break;
      case TokenType::FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR:             Filter = DxilFilter::MIN_LINEAR_MAG_POINT_MIP_LINEAR;              break;
      case TokenType::FILTER_MIN_MAG_LINEAR_MIP_POINT:                    Filter = DxilFilter::MIN_MAG_LINEAR_MIP_POINT;                     break;
      case TokenType::FILTER_MIN_MAG_MIP_LINEAR:                          Filter = DxilFilter::MIN_MAG_MIP_LINEAR;                           break;
      case TokenType::FILTER_ANISOTROPIC:                                 Filter = DxilFilter::ANISOTROPIC;                                  break;
      case TokenType::FILTER_COMPARISON_MIN_MAG_MIP_POINT:                Filter = DxilFilter::COMPARISON_MIN_MAG_MIP_POINT;                 break;
      case TokenType::FILTER_COMPARISON_MIN_MAG_POINT_MIP_LINEAR:         Filter = DxilFilter::COMPARISON_MIN_MAG_POINT_MIP_LINEAR;          break;
      case TokenType::FILTER_COMPARISON_MIN_POINT_MAG_LINEAR_MIP_POINT:   Filter = DxilFilter::COMPARISON_MIN_POINT_MAG_LINEAR_MIP_POINT;    break;
      case TokenType::FILTER_COMPARISON_MIN_POINT_MAG_MIP_LINEAR:         Filter = DxilFilter::COMPARISON_MIN_POINT_MAG_MIP_LINEAR;          break;
      case TokenType::FILTER_COMPARISON_MIN_LINEAR_MAG_MIP_POINT:         Filter = DxilFilter::COMPARISON_MIN_LINEAR_MAG_MIP_POINT;          break;
      case TokenType::FILTER_COMPARISON_MIN_LINEAR_MAG_POINT_MIP_LINEAR:  Filter = DxilFilter::COMPARISON_MIN_LINEAR_MAG_POINT_MIP_LINEAR;   break;
      case TokenType::FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT:         Filter = DxilFilter::COMPARISON_MIN_MAG_LINEAR_MIP_POINT;          break;
      case TokenType::FILTER_COMPARISON_MIN_MAG_MIP_LINEAR:               Filter = DxilFilter::COMPARISON_MIN_MAG_MIP_LINEAR;                break;
      case TokenType::FILTER_COMPARISON_ANISOTROPIC:                      Filter = DxilFilter::COMPARISON_ANISOTROPIC;                       break;
      case TokenType::FILTER_MINIMUM_MIN_MAG_MIP_POINT:                   Filter = DxilFilter::MINIMUM_MIN_MAG_MIP_POINT;                    break;
      case TokenType::FILTER_MINIMUM_MIN_MAG_POINT_MIP_LINEAR:            Filter = DxilFilter::MINIMUM_MIN_MAG_POINT_MIP_LINEAR;             break;
      case TokenType::FILTER_MINIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT:      Filter = DxilFilter::MINIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT;       break;
      case TokenType::FILTER_MINIMUM_MIN_POINT_MAG_MIP_LINEAR:            Filter = DxilFilter::MINIMUM_MIN_POINT_MAG_MIP_LINEAR;             break;
      case TokenType::FILTER_MINIMUM_MIN_LINEAR_MAG_MIP_POINT:            Filter = DxilFilter::MINIMUM_MIN_LINEAR_MAG_MIP_POINT;             break;
      case TokenType::FILTER_MINIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR:     Filter = DxilFilter::MINIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR;      break;
      case TokenType::FILTER_MINIMUM_MIN_MAG_LINEAR_MIP_POINT:            Filter = DxilFilter::MINIMUM_MIN_MAG_LINEAR_MIP_POINT;             break;
      case TokenType::FILTER_MINIMUM_MIN_MAG_MIP_LINEAR:                  Filter = DxilFilter::MINIMUM_MIN_MAG_MIP_LINEAR;                   break;
      case TokenType::FILTER_MINIMUM_ANISOTROPIC:                         Filter = DxilFilter::MINIMUM_ANISOTROPIC;                          break;
      case TokenType::FILTER_MAXIMUM_MIN_MAG_MIP_POINT:                   Filter = DxilFilter::MAXIMUM_MIN_MAG_MIP_POINT;                    break;
      case TokenType::FILTER_MAXIMUM_MIN_MAG_POINT_MIP_LINEAR:            Filter = DxilFilter::MAXIMUM_MIN_MAG_POINT_MIP_LINEAR;             break;
      case TokenType::FILTER_MAXIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT:      Filter = DxilFilter::MAXIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT;       break;
      case TokenType::FILTER_MAXIMUM_MIN_POINT_MAG_MIP_LINEAR:            Filter = DxilFilter::MAXIMUM_MIN_POINT_MAG_MIP_LINEAR;             break;
      case TokenType::FILTER_MAXIMUM_MIN_LINEAR_MAG_MIP_POINT:            Filter = DxilFilter::MAXIMUM_MIN_LINEAR_MAG_MIP_POINT;             break;
      case TokenType::FILTER_MAXIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR:     Filter = DxilFilter::MAXIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR;      break;
      case TokenType::FILTER_MAXIMUM_MIN_MAG_LINEAR_MIP_POINT:            Filter = DxilFilter::MAXIMUM_MIN_MAG_LINEAR_MIP_POINT;             break;
      case TokenType::FILTER_MAXIMUM_MIN_MAG_MIP_LINEAR:                  Filter = DxilFilter::MAXIMUM_MIN_MAG_MIP_LINEAR;                   break;
      case TokenType::FILTER_MAXIMUM_ANISOTROPIC:                         Filter = DxilFilter::MAXIMUM_ANISOTROPIC;                          break;
      default:
          IFC(Error(ERR_RS_UNEXPECTED_TOKEN, 
                   "Unexpected filter value: '%s'.", Token.GetStr()));
      }
  
  Cleanup:
      return hr;
  }
  
  HRESULT RootSignatureParser::ParseTextureAddressMode(DxilTextureAddressMode & AddressMode)
  {
      HRESULT hr = S_OK;
      TokenType Token = m_pTokenizer->GetToken();
      DXASSERT_NOMSG(Token.GetType() == TokenType::addressU || 
                     Token.GetType() == TokenType::addressV || 
                     Token.GetType() == TokenType::addressW);
      IFC(GetAndMatchToken(Token, TokenType::EQ));
      Token = m_pTokenizer->GetToken();
  
      switch(Token.GetType())
      {
      case TokenType::TEXTURE_ADDRESS_WRAP:           AddressMode = DxilTextureAddressMode::Wrap;       break;
      case TokenType::TEXTURE_ADDRESS_MIRROR:         AddressMode = DxilTextureAddressMode::Mirror;     break;
      case TokenType::TEXTURE_ADDRESS_CLAMP:          AddressMode = DxilTextureAddressMode::Clamp;      break;
      case TokenType::TEXTURE_ADDRESS_BORDER:         AddressMode = DxilTextureAddressMode::Border;     break;
      case TokenType::TEXTURE_ADDRESS_MIRROR_ONCE:    AddressMode = DxilTextureAddressMode::MirrorOnce; break;
      default:
          IFC(Error(ERR_RS_UNEXPECTED_TOKEN, 
                   "Unexpected texture address mode value: '%s'.", Token.GetStr()));
      }
  
  Cleanup:
      return hr;
  }
  
  HRESULT RootSignatureParser::ParseMipLODBias(float & MipLODBias)
  {
      HRESULT hr = S_OK;
      TokenType Token;
  
      IFC(GetAndMatchToken(Token, TokenType::mipLODBias));
      IFC(GetAndMatchToken(Token, TokenType::EQ));
      IFC(ParseFloat(MipLODBias));
  
  Cleanup:
      return hr;
  }
  
  HRESULT RootSignatureParser::ParseMaxAnisotropy(uint32_t & MaxAnisotropy)
  {
      HRESULT hr = S_OK;
      TokenType Token;
  
      IFC(GetAndMatchToken(Token, TokenType::maxAnisotropy));
      IFC(GetAndMatchToken(Token, TokenType::EQ));
      IFC(GetAndMatchToken(Token, TokenType::NumberU32));
      MaxAnisotropy = Token.GetU32Value();
  
  Cleanup:
      return hr;
  }
  
  HRESULT RootSignatureParser::ParseComparisonFunction(DxilComparisonFunc & ComparisonFunc)
  {
      HRESULT hr = S_OK;
      TokenType Token;
  
      IFC(GetAndMatchToken(Token, TokenType::comparisonFunc));
      IFC(GetAndMatchToken(Token, TokenType::EQ));
      Token = m_pTokenizer->GetToken();
  
      switch(Token.GetType())
      {
      case TokenType::COMPARISON_NEVER:           ComparisonFunc = DxilComparisonFunc::Never;        break;
      case TokenType::COMPARISON_LESS:            ComparisonFunc = DxilComparisonFunc::Less;         break;
      case TokenType::COMPARISON_EQUAL:           ComparisonFunc = DxilComparisonFunc::Equal;        break;
      case TokenType::COMPARISON_LESS_EQUAL:      ComparisonFunc = DxilComparisonFunc::LessEqual;    break;
      case TokenType::COMPARISON_GREATER:         ComparisonFunc = DxilComparisonFunc::Greater;      break;
      case TokenType::COMPARISON_NOT_EQUAL:       ComparisonFunc = DxilComparisonFunc::NotEqual;     break;
      case TokenType::COMPARISON_GREATER_EQUAL:   ComparisonFunc = DxilComparisonFunc::GreaterEqual; break;
      case TokenType::COMPARISON_ALWAYS:          ComparisonFunc = DxilComparisonFunc::Always;       break;
      default:
          IFC(Error(ERR_RS_UNEXPECTED_TOKEN, 
                   "Unexpected texture address mode value: '%s'.", Token.GetStr()));
      }
  
  Cleanup:
      return hr;
  }
  
  HRESULT RootSignatureParser::ParseBorderColor(DxilStaticBorderColor & BorderColor)
  {
      HRESULT hr = S_OK;
      TokenType Token;
  
      IFC(GetAndMatchToken(Token, TokenType::borderColor));
      IFC(GetAndMatchToken(Token, TokenType::EQ));
      Token = m_pTokenizer->GetToken();
  
      switch(Token.GetType())
      {
      case TokenType::STATIC_BORDER_COLOR_TRANSPARENT_BLACK:  BorderColor = DxilStaticBorderColor::TransparentBlack;  break;
      case TokenType::STATIC_BORDER_COLOR_OPAQUE_BLACK:       BorderColor = DxilStaticBorderColor::OpaqueBlack;       break;
      case TokenType::STATIC_BORDER_COLOR_OPAQUE_WHITE:       BorderColor = DxilStaticBorderColor::OpaqueWhite;       break;
      default:
          IFC(Error(ERR_RS_UNEXPECTED_TOKEN, 
                   "Unexpected texture address mode value: '%s'.", Token.GetStr()));
      }
  
  Cleanup:
      return hr;
  }
  
  HRESULT RootSignatureParser::ParseMinLOD(float & MinLOD)
  {
      HRESULT hr = S_OK;
      TokenType Token;
  
      IFC(GetAndMatchToken(Token, TokenType::minLOD));
      IFC(GetAndMatchToken(Token, TokenType::EQ));
      IFC(ParseFloat(MinLOD));
  
  Cleanup:
      return hr;
  }
  
  HRESULT RootSignatureParser::ParseMaxLOD(float & MaxLOD)
  {
      HRESULT hr = S_OK;
      TokenType Token;
  
      IFC(GetAndMatchToken(Token, TokenType::maxLOD));
      IFC(GetAndMatchToken(Token, TokenType::EQ));
      IFC(ParseFloat(MaxLOD));
  
  Cleanup:
      return hr;
  }
  
  HRESULT RootSignatureParser::ParseFloat(float & v)
  {
      HRESULT hr = S_OK;
      TokenType Token = m_pTokenizer->GetToken();
      if(Token.GetType() == TokenType::NumberU32)
      {
          v = (float)Token.GetU32Value();
      }
      else if(Token.GetType() == TokenType::NumberI32)
      {
          v = (float)Token.GetI32Value();
      }
      else if(Token.GetType() == TokenType::NumberFloat)
      {
          v = Token.GetFloatValue();
      }
      else
      {
          IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Expected float, found token '%s'", Token.GetStr()));
      }
  
  Cleanup:
      return hr;
  }
  
  HRESULT RootSignatureParser::MarkParameter(bool & bSeen, LPCSTR pName)
  {
      HRESULT hr = S_OK;
  
      if(bSeen)
      {
          IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Parameter '%s' can be specified only once", pName));
      }
  
      bSeen = true;
  
  Cleanup:
      return hr;
  }
  
  _Use_decl_annotations_
  bool clang::ParseHLSLRootSignature(
      const char *pData, unsigned Len, hlsl::DxilRootSignatureVersion Ver,
      hlsl::DxilRootSignatureCompilationFlags Flags, hlsl::DxilVersionedRootSignatureDesc **ppDesc, 
      SourceLocation Loc, clang::DiagnosticsEngine &Diags) {
    *ppDesc = nullptr;
    std::string OSStr;
    llvm::raw_string_ostream OS(OSStr);
    hlsl::RootSignatureTokenizer RST(pData, Len);
    hlsl::RootSignatureParser RSP(&RST, Ver, Flags, OS);
    hlsl::DxilVersionedRootSignatureDesc *D = nullptr;
    if (SUCCEEDED(RSP.Parse(&D))) {
      *ppDesc = D;
      return true;
    }
    else {
      // Create diagnostic error message.
      OS.flush();
      if (OSStr.empty()) {
        Diags.Report(Loc, clang::diag::err_hlsl_rootsig) << "unexpected";
      }
      else {
        Diags.Report(Loc, clang::diag::err_hlsl_rootsig) << OSStr.c_str();
      }
      return false;
    }
  }
  
  _Use_decl_annotations_
  void clang::ReportHLSLRootSigError(clang::DiagnosticsEngine &Diags,
                              clang::SourceLocation Loc, const char *pData,
                              unsigned Len) {
    Diags.Report(Loc, clang::diag::err_hlsl_rootsig) << StringRef(pData, Len);
    return;
  }
  