xkslang/hlsl/hlslScanContext.cpp

636 строки
24 KiB
C++
Executable File

//
//Copyright (C) 2016 Google, Inc.
//
//All rights reserved.
//
//Redistribution and use in source and binary forms, with or without
//modification, are permitted provided that the following conditions
//are met:
//
// Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
//
// Neither the name of Google, Inc., nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
//POSSIBILITY OF SUCH DAMAGE.
//
//
// HLSL scanning, leveraging the scanning done by the preprocessor.
//
#include <string.h>
#include <unordered_map>
#include <unordered_set>
#include "../glslang/Include/Types.h"
#include "../glslang/MachineIndependent/SymbolTable.h"
#include "../glslang/MachineIndependent/ParseHelper.h"
#include "hlslScanContext.h"
#include "hlslTokens.h"
//#include "Scan.h"
// preprocessor includes
#include "../glslang/MachineIndependent/preprocessor/PpContext.h"
#include "../glslang/MachineIndependent/preprocessor/PpTokens.h"
namespace {
struct str_eq
{
bool operator()(const char* lhs, const char* rhs) const
{
return strcmp(lhs, rhs) == 0;
}
};
struct str_hash
{
size_t operator()(const char* str) const
{
// djb2
unsigned long hash = 5381;
int c;
while ((c = *str++) != 0)
hash = ((hash << 5) + hash) + c;
return hash;
}
};
// A single global usable by all threads, by all versions, by all languages.
// After a single process-level initialization, this is read only and thread safe
std::unordered_map<const char*, glslang::EHlslTokenClass, str_hash, str_eq>* KeywordMap = nullptr;
std::unordered_set<const char*, str_hash, str_eq>* ReservedSet = nullptr;
};
namespace glslang {
void HlslScanContext::fillInKeywordMap()
{
if (KeywordMap != nullptr) {
// this is really an error, as this should called only once per process
// but, the only risk is if two threads called simultaneously
return;
}
KeywordMap = new std::unordered_map<const char*, EHlslTokenClass, str_hash, str_eq>;
(*KeywordMap)["static"] = EHTokStatic;
(*KeywordMap)["const"] = EHTokConst;
(*KeywordMap)["unorm"] = EHTokUnorm;
(*KeywordMap)["snorm"] = EHTokSNorm;
(*KeywordMap)["extern"] = EHTokExtern;
(*KeywordMap)["uniform"] = EHTokUniform;
(*KeywordMap)["volatile"] = EHTokVolatile;
(*KeywordMap)["precise"] = EHTokPrecise;
(*KeywordMap)["shared"] = EHTokShared;
(*KeywordMap)["groupshared"] = EHTokGroupShared;
(*KeywordMap)["linear"] = EHTokLinear;
(*KeywordMap)["centroid"] = EHTokCentroid;
(*KeywordMap)["nointerpolation"] = EHTokNointerpolation;
(*KeywordMap)["noperspective"] = EHTokNoperspective;
(*KeywordMap)["sample"] = EHTokSample;
(*KeywordMap)["row_major"] = EHTokRowMajor;
(*KeywordMap)["column_major"] = EHTokColumnMajor;
(*KeywordMap)["packoffset"] = EHTokPackOffset;
(*KeywordMap)["Buffer"] = EHTokBuffer;
(*KeywordMap)["vector"] = EHTokVector;
(*KeywordMap)["matrix"] = EHTokMatrix;
(*KeywordMap)["void"] = EHTokVoid;
(*KeywordMap)["bool"] = EHTokBool;
(*KeywordMap)["int"] = EHTokInt;
(*KeywordMap)["uint"] = EHTokUint;
(*KeywordMap)["dword"] = EHTokDword;
(*KeywordMap)["half"] = EHTokHalf;
(*KeywordMap)["float"] = EHTokFloat;
(*KeywordMap)["double"] = EHTokDouble;
(*KeywordMap)["min16float"] = EHTokMin16float;
(*KeywordMap)["min10float"] = EHTokMin10float;
(*KeywordMap)["min16int"] = EHTokMin16int;
(*KeywordMap)["min12int"] = EHTokMin12int;
(*KeywordMap)["min16uint"] = EHTokMin16int;
(*KeywordMap)["bool1"] = EHTokBool1;
(*KeywordMap)["bool2"] = EHTokBool2;
(*KeywordMap)["bool3"] = EHTokBool3;
(*KeywordMap)["bool4"] = EHTokBool4;
(*KeywordMap)["float1"] = EHTokFloat1;
(*KeywordMap)["float2"] = EHTokFloat2;
(*KeywordMap)["float3"] = EHTokFloat3;
(*KeywordMap)["float4"] = EHTokFloat4;
(*KeywordMap)["int1"] = EHTokInt1;
(*KeywordMap)["int2"] = EHTokInt2;
(*KeywordMap)["int3"] = EHTokInt3;
(*KeywordMap)["int4"] = EHTokInt4;
(*KeywordMap)["double1"] = EHTokDouble1;
(*KeywordMap)["double2"] = EHTokDouble2;
(*KeywordMap)["double3"] = EHTokDouble3;
(*KeywordMap)["double4"] = EHTokDouble4;
(*KeywordMap)["uint1"] = EHTokUint1;
(*KeywordMap)["uint2"] = EHTokUint2;
(*KeywordMap)["uint3"] = EHTokUint3;
(*KeywordMap)["uint4"] = EHTokUint4;
(*KeywordMap)["int1x1"] = EHTokInt1x1;
(*KeywordMap)["int1x2"] = EHTokInt1x2;
(*KeywordMap)["int1x3"] = EHTokInt1x3;
(*KeywordMap)["int1x4"] = EHTokInt1x4;
(*KeywordMap)["int2x1"] = EHTokInt2x1;
(*KeywordMap)["int2x2"] = EHTokInt2x2;
(*KeywordMap)["int2x3"] = EHTokInt2x3;
(*KeywordMap)["int2x4"] = EHTokInt2x4;
(*KeywordMap)["int3x1"] = EHTokInt3x1;
(*KeywordMap)["int3x2"] = EHTokInt3x2;
(*KeywordMap)["int3x3"] = EHTokInt3x3;
(*KeywordMap)["int3x4"] = EHTokInt3x4;
(*KeywordMap)["int4x1"] = EHTokInt4x1;
(*KeywordMap)["int4x2"] = EHTokInt4x2;
(*KeywordMap)["int4x3"] = EHTokInt4x3;
(*KeywordMap)["int4x4"] = EHTokInt4x4;
(*KeywordMap)["uint1x1"] = EHTokUint1x1;
(*KeywordMap)["uint1x2"] = EHTokUint1x2;
(*KeywordMap)["uint1x3"] = EHTokUint1x3;
(*KeywordMap)["uint1x4"] = EHTokUint1x4;
(*KeywordMap)["uint2x1"] = EHTokUint2x1;
(*KeywordMap)["uint2x2"] = EHTokUint2x2;
(*KeywordMap)["uint2x3"] = EHTokUint2x3;
(*KeywordMap)["uint2x4"] = EHTokUint2x4;
(*KeywordMap)["uint3x1"] = EHTokUint3x1;
(*KeywordMap)["uint3x2"] = EHTokUint3x2;
(*KeywordMap)["uint3x3"] = EHTokUint3x3;
(*KeywordMap)["uint3x4"] = EHTokUint3x4;
(*KeywordMap)["uint4x1"] = EHTokUint4x1;
(*KeywordMap)["uint4x2"] = EHTokUint4x2;
(*KeywordMap)["uint4x3"] = EHTokUint4x3;
(*KeywordMap)["uint4x4"] = EHTokUint4x4;
(*KeywordMap)["bool1x1"] = EHTokBool1x1;
(*KeywordMap)["bool1x2"] = EHTokBool1x2;
(*KeywordMap)["bool1x3"] = EHTokBool1x3;
(*KeywordMap)["bool1x4"] = EHTokBool1x4;
(*KeywordMap)["bool2x1"] = EHTokBool2x1;
(*KeywordMap)["bool2x2"] = EHTokBool2x2;
(*KeywordMap)["bool2x3"] = EHTokBool2x3;
(*KeywordMap)["bool2x4"] = EHTokBool2x4;
(*KeywordMap)["bool3x1"] = EHTokBool3x1;
(*KeywordMap)["bool3x2"] = EHTokBool3x2;
(*KeywordMap)["bool3x3"] = EHTokBool3x3;
(*KeywordMap)["bool3x4"] = EHTokBool3x4;
(*KeywordMap)["bool4x1"] = EHTokBool4x1;
(*KeywordMap)["bool4x2"] = EHTokBool4x2;
(*KeywordMap)["bool4x3"] = EHTokBool4x3;
(*KeywordMap)["bool4x4"] = EHTokBool4x4;
(*KeywordMap)["float1x1"] = EHTokFloat1x1;
(*KeywordMap)["float1x2"] = EHTokFloat1x2;
(*KeywordMap)["float1x3"] = EHTokFloat1x3;
(*KeywordMap)["float1x4"] = EHTokFloat1x4;
(*KeywordMap)["float2x1"] = EHTokFloat2x1;
(*KeywordMap)["float2x2"] = EHTokFloat2x2;
(*KeywordMap)["float2x3"] = EHTokFloat2x3;
(*KeywordMap)["float2x4"] = EHTokFloat2x4;
(*KeywordMap)["float3x1"] = EHTokFloat3x1;
(*KeywordMap)["float3x2"] = EHTokFloat3x2;
(*KeywordMap)["float3x3"] = EHTokFloat3x3;
(*KeywordMap)["float3x4"] = EHTokFloat3x4;
(*KeywordMap)["float4x1"] = EHTokFloat4x1;
(*KeywordMap)["float4x2"] = EHTokFloat4x2;
(*KeywordMap)["float4x3"] = EHTokFloat4x3;
(*KeywordMap)["float4x4"] = EHTokFloat4x4;
(*KeywordMap)["double1x1"] = EHTokDouble1x1;
(*KeywordMap)["double1x2"] = EHTokDouble1x2;
(*KeywordMap)["double1x3"] = EHTokDouble1x3;
(*KeywordMap)["double1x4"] = EHTokDouble1x4;
(*KeywordMap)["double2x1"] = EHTokDouble2x1;
(*KeywordMap)["double2x2"] = EHTokDouble2x2;
(*KeywordMap)["double2x3"] = EHTokDouble2x3;
(*KeywordMap)["double2x4"] = EHTokDouble2x4;
(*KeywordMap)["double3x1"] = EHTokDouble3x1;
(*KeywordMap)["double3x2"] = EHTokDouble3x2;
(*KeywordMap)["double3x3"] = EHTokDouble3x3;
(*KeywordMap)["double3x4"] = EHTokDouble3x4;
(*KeywordMap)["double4x1"] = EHTokDouble4x1;
(*KeywordMap)["double4x2"] = EHTokDouble4x2;
(*KeywordMap)["double4x3"] = EHTokDouble4x3;
(*KeywordMap)["double4x4"] = EHTokDouble4x4;
(*KeywordMap)["sampler"] = EHTokSampler;
(*KeywordMap)["sampler1D"] = EHTokSampler1d;
(*KeywordMap)["sampler2D"] = EHTokSampler2d;
(*KeywordMap)["sampler3D"] = EHTokSampler3d;
(*KeywordMap)["samplerCube"] = EHTokSamplerCube;
(*KeywordMap)["sampler_state"] = EHTokSamplerState;
(*KeywordMap)["SamplerState"] = EHTokSamplerState;
(*KeywordMap)["SamplerComparisonState"] = EHTokSamplerComparisonState;
(*KeywordMap)["texture"] = EHTokTexture;
(*KeywordMap)["Texture1D"] = EHTokTexture1d;
(*KeywordMap)["Texture1DArray"] = EHTokTexture1darray;
(*KeywordMap)["Texture2D"] = EHTokTexture2d;
(*KeywordMap)["Texture2DArray"] = EHTokTexture2darray;
(*KeywordMap)["Texture3D"] = EHTokTexture3d;
(*KeywordMap)["TextureCube"] = EHTokTextureCube;
(*KeywordMap)["struct"] = EHTokStruct;
(*KeywordMap)["typedef"] = EHTokTypedef;
(*KeywordMap)["true"] = EHTokBoolConstant;
(*KeywordMap)["false"] = EHTokBoolConstant;
(*KeywordMap)["for"] = EHTokFor;
(*KeywordMap)["do"] = EHTokDo;
(*KeywordMap)["while"] = EHTokWhile;
(*KeywordMap)["break"] = EHTokBreak;
(*KeywordMap)["continue"] = EHTokContinue;
(*KeywordMap)["if"] = EHTokIf;
(*KeywordMap)["else"] = EHTokElse;
(*KeywordMap)["discard"] = EHTokDiscard;
(*KeywordMap)["return"] = EHTokReturn;
(*KeywordMap)["switch"] = EHTokSwitch;
(*KeywordMap)["case"] = EHTokCase;
(*KeywordMap)["default"] = EHTokDefault;
// TODO: get correct set here
ReservedSet = new std::unordered_set<const char*, str_hash, str_eq>;
ReservedSet->insert("auto");
ReservedSet->insert("catch");
ReservedSet->insert("char");
ReservedSet->insert("class");
ReservedSet->insert("const_cast");
ReservedSet->insert("enum");
ReservedSet->insert("explicit");
ReservedSet->insert("friend");
ReservedSet->insert("goto");
ReservedSet->insert("long");
ReservedSet->insert("mutable");
ReservedSet->insert("new");
ReservedSet->insert("operator");
ReservedSet->insert("private");
ReservedSet->insert("protected");
ReservedSet->insert("public");
ReservedSet->insert("reinterpret_cast");
ReservedSet->insert("short");
ReservedSet->insert("signed");
ReservedSet->insert("sizeof");
ReservedSet->insert("static_cast");
ReservedSet->insert("template");
ReservedSet->insert("this");
ReservedSet->insert("throw");
ReservedSet->insert("try");
ReservedSet->insert("typename");
ReservedSet->insert("union");
ReservedSet->insert("unsigned");
ReservedSet->insert("using");
ReservedSet->insert("virtual");
}
void HlslScanContext::deleteKeywordMap()
{
delete KeywordMap;
KeywordMap = nullptr;
delete ReservedSet;
ReservedSet = nullptr;
}
// Wrapper for tokenizeClass()"] = to get everything inside the token.
void HlslScanContext::tokenize(HlslToken& token)
{
EHlslTokenClass tokenClass = tokenizeClass(token);
token.tokenClass = tokenClass;
}
//
// Fill in token information for the next token, except for the token class.
// Returns the enum value of the token class of the next token found.
// Return 0 (EndOfTokens) on end of input.
//
EHlslTokenClass HlslScanContext::tokenizeClass(HlslToken& token)
{
do {
parserToken = &token;
TPpToken ppToken;
tokenText = ppContext.tokenize(&ppToken);
if (tokenText == nullptr)
return EHTokNone;
loc = ppToken.loc;
parserToken->loc = loc;
switch (ppToken.token) {
case ';': return EHTokSemicolon;
case ',': return EHTokComma;
case ':': return EHTokColon;
case '=': return EHTokAssign;
case '(': return EHTokLeftParen;
case ')': return EHTokRightParen;
case '.': return EHTokDot;
case '!': return EHTokBang;
case '-': return EHTokDash;
case '~': return EHTokTilde;
case '+': return EHTokPlus;
case '*': return EHTokStar;
case '/': return EHTokSlash;
case '%': return EHTokPercent;
case '<': return EHTokLeftAngle;
case '>': return EHTokRightAngle;
case '|': return EHTokVerticalBar;
case '^': return EHTokCaret;
case '&': return EHTokAmpersand;
case '?': return EHTokQuestion;
case '[': return EHTokLeftBracket;
case ']': return EHTokRightBracket;
case '{': return EHTokLeftBrace;
case '}': return EHTokRightBrace;
case '\\':
parseContext.error(loc, "illegal use of escape character", "\\", "");
break;
case PpAtomAdd: return EHTokAddAssign;
case PpAtomSub: return EHTokSubAssign;
case PpAtomMul: return EHTokMulAssign;
case PpAtomDiv: return EHTokDivAssign;
case PpAtomMod: return EHTokModAssign;
case PpAtomRight: return EHTokRightOp;
case PpAtomLeft: return EHTokLeftOp;
case PpAtomRightAssign: return EHTokRightAssign;
case PpAtomLeftAssign: return EHTokLeftAssign;
case PpAtomAndAssign: return EHTokAndAssign;
case PpAtomOrAssign: return EHTokOrAssign;
case PpAtomXorAssign: return EHTokXorAssign;
case PpAtomAnd: return EHTokAndOp;
case PpAtomOr: return EHTokOrOp;
case PpAtomXor: return EHTokXorOp;
case PpAtomEQ: return EHTokEqOp;
case PpAtomGE: return EHTokGeOp;
case PpAtomNE: return EHTokNeOp;
case PpAtomLE: return EHTokLeOp;
case PpAtomDecrement: return EHTokDecOp;
case PpAtomIncrement: return EHTokIncOp;
case PpAtomConstInt: parserToken->i = ppToken.ival; return EHTokIntConstant;
case PpAtomConstUint: parserToken->i = ppToken.ival; return EHTokUintConstant;
case PpAtomConstFloat: parserToken->d = ppToken.dval; return EHTokFloatConstant;
case PpAtomConstDouble: parserToken->d = ppToken.dval; return EHTokDoubleConstant;
case PpAtomIdentifier:
{
EHlslTokenClass token = tokenizeIdentifier();
return token;
}
case EndOfInput: return EHTokNone;
default:
char buf[2];
buf[0] = (char)ppToken.token;
buf[1] = 0;
parseContext.error(loc, "unexpected token", buf, "");
break;
}
} while (true);
}
EHlslTokenClass HlslScanContext::tokenizeIdentifier()
{
if (ReservedSet->find(tokenText) != ReservedSet->end())
return reservedWord();
auto it = KeywordMap->find(tokenText);
if (it == KeywordMap->end()) {
// Should have an identifier of some sort
return identifierOrType();
}
keyword = it->second;
switch (keyword) {
// qualifiers
case EHTokStatic:
case EHTokConst:
case EHTokSNorm:
case EHTokUnorm:
case EHTokExtern:
case EHTokUniform:
case EHTokVolatile:
case EHTokShared:
case EHTokGroupShared:
case EHTokLinear:
case EHTokCentroid:
case EHTokNointerpolation:
case EHTokNoperspective:
case EHTokSample:
case EHTokRowMajor:
case EHTokColumnMajor:
case EHTokPackOffset:
return keyword;
// template types
case EHTokBuffer:
case EHTokVector:
case EHTokMatrix:
return keyword;
// scalar types
case EHTokVoid:
case EHTokBool:
case EHTokInt:
case EHTokUint:
case EHTokDword:
case EHTokHalf:
case EHTokFloat:
case EHTokDouble:
case EHTokMin16float:
case EHTokMin10float:
case EHTokMin16int:
case EHTokMin12int:
case EHTokMin16uint:
// vector types
case EHTokBool1:
case EHTokBool2:
case EHTokBool3:
case EHTokBool4:
case EHTokFloat1:
case EHTokFloat2:
case EHTokFloat3:
case EHTokFloat4:
case EHTokInt1:
case EHTokInt2:
case EHTokInt3:
case EHTokInt4:
case EHTokDouble1:
case EHTokDouble2:
case EHTokDouble3:
case EHTokDouble4:
case EHTokUint1:
case EHTokUint2:
case EHTokUint3:
case EHTokUint4:
// matrix types
case EHTokInt1x1:
case EHTokInt1x2:
case EHTokInt1x3:
case EHTokInt1x4:
case EHTokInt2x1:
case EHTokInt2x2:
case EHTokInt2x3:
case EHTokInt2x4:
case EHTokInt3x1:
case EHTokInt3x2:
case EHTokInt3x3:
case EHTokInt3x4:
case EHTokInt4x1:
case EHTokInt4x2:
case EHTokInt4x3:
case EHTokInt4x4:
case EHTokFloat1x1:
case EHTokFloat1x2:
case EHTokFloat1x3:
case EHTokFloat1x4:
case EHTokFloat2x1:
case EHTokFloat2x2:
case EHTokFloat2x3:
case EHTokFloat2x4:
case EHTokFloat3x1:
case EHTokFloat3x2:
case EHTokFloat3x3:
case EHTokFloat3x4:
case EHTokFloat4x1:
case EHTokFloat4x2:
case EHTokFloat4x3:
case EHTokFloat4x4:
case EHTokDouble1x1:
case EHTokDouble1x2:
case EHTokDouble1x3:
case EHTokDouble1x4:
case EHTokDouble2x1:
case EHTokDouble2x2:
case EHTokDouble2x3:
case EHTokDouble2x4:
case EHTokDouble3x1:
case EHTokDouble3x2:
case EHTokDouble3x3:
case EHTokDouble3x4:
case EHTokDouble4x1:
case EHTokDouble4x2:
case EHTokDouble4x3:
case EHTokDouble4x4:
return keyword;
// texturing types
case EHTokSampler:
case EHTokSampler1d:
case EHTokSampler2d:
case EHTokSampler3d:
case EHTokSamplerCube:
case EHTokSamplerState:
case EHTokSamplerComparisonState:
case EHTokTexture:
case EHTokTexture1d:
case EHTokTexture1darray:
case EHTokTexture2d:
case EHTokTexture2darray:
case EHTokTexture3d:
case EHTokTextureCube:
return keyword;
// variable, user type, ...
case EHTokStruct:
case EHTokTypedef:
case EHTokBoolConstant:
if (strcmp("true", tokenText) == 0)
parserToken->b = true;
else
parserToken->b = false;
return keyword;
// control flow
case EHTokFor:
case EHTokDo:
case EHTokWhile:
case EHTokBreak:
case EHTokContinue:
case EHTokIf:
case EHTokElse:
case EHTokDiscard:
case EHTokReturn:
case EHTokCase:
case EHTokSwitch:
case EHTokDefault:
return keyword;
default:
parseContext.infoSink.info.message(EPrefixInternalError, "Unknown glslang keyword", loc);
return EHTokNone;
}
}
EHlslTokenClass HlslScanContext::identifierOrType()
{
parserToken->string = NewPoolTString(tokenText);
return EHTokIdentifier;
}
// Give an error for use of a reserved symbol.
// However, allow built-in declarations to use reserved words, to allow
// extension support before the extension is enabled.
EHlslTokenClass HlslScanContext::reservedWord()
{
if (! parseContext.symbolTable.atBuiltInLevel())
parseContext.error(loc, "Reserved word.", tokenText, "", "");
return EHTokNone;
}
EHlslTokenClass HlslScanContext::identifierOrReserved(bool reserved)
{
if (reserved) {
reservedWord();
return EHTokNone;
}
if (parseContext.forwardCompatible)
parseContext.warn(loc, "using future reserved keyword", tokenText, "");
return identifierOrType();
}
// For a keyword that was never reserved, until it suddenly
// showed up.
EHlslTokenClass HlslScanContext::nonreservedKeyword(int version)
{
if (parseContext.version < version)
return identifierOrType();
return keyword;
}
} // end namespace glslang