#include "Engine.h"
#include "HLSLParser.h"
#include "HLSLTree.h"
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <ctype.h>
#include <iostream>
#include <stack>
#include <string.h>
#if defined _WIN32 && !defined alloca
#include <malloc.h>
#endif
namespace M4
{
enum CompareFunctionsResult
{
FunctionsEqual,
Function1Better,
Function2Better
};
struct Intrinsic
{
explicit Intrinsic(const char* name, HLSLBaseType returnType)
{
function.name = name;
function.returnType.baseType = returnType;
function.numArguments = 0;
}
explicit Intrinsic(const char* name, HLSLBaseType returnType, HLSLBaseType arg1)
{
function.name = name;
function.returnType.baseType = returnType;
function.numArguments = 1;
function.argument = argument + 0;
argument[0].type.baseType = arg1;
argument[0].type.flags = HLSLTypeFlag_Const;
}
explicit Intrinsic(const char* name, HLSLBaseType returnType, HLSLBaseType arg1, HLSLBaseType arg2)
{
function.name = name;
function.returnType.baseType = returnType;
function.argument = argument + 0;
function.numArguments = 2;
argument[0].type.baseType = arg1;
argument[0].type.flags = HLSLTypeFlag_Const;
argument[0].nextArgument = argument + 1;
argument[1].type.baseType = arg2;
argument[1].type.flags = HLSLTypeFlag_Const;
}
explicit Intrinsic(const char* name, HLSLBaseType returnType, HLSLBaseType arg1, HLSLBaseType arg2, HLSLBaseType arg3)
{
function.name = name;
function.returnType.baseType = returnType;
function.argument = argument + 0;
function.numArguments = 3;
argument[0].type.baseType = arg1;
argument[0].type.flags = HLSLTypeFlag_Const;
argument[0].nextArgument = argument + 1;
argument[1].type.baseType = arg2;
argument[1].type.flags = HLSLTypeFlag_Const;
argument[1].nextArgument = argument + 2;
argument[2].type.baseType = arg3;
argument[2].type.flags = HLSLTypeFlag_Const;
}
explicit Intrinsic(const char* name, HLSLBaseType returnType, HLSLBaseType arg1, HLSLBaseType arg2, HLSLBaseType arg3, HLSLBaseType arg4)
{
function.name = name;
function.returnType.baseType = returnType;
function.argument = argument + 0;
function.numArguments = 4;
argument[0].type.baseType = arg1;
argument[0].type.flags = HLSLTypeFlag_Const;
argument[0].nextArgument = argument + 1;
argument[1].type.baseType = arg2;
argument[1].type.flags = HLSLTypeFlag_Const;
argument[1].nextArgument = argument + 2;
argument[2].type.baseType = arg3;
argument[2].type.flags = HLSLTypeFlag_Const;
argument[2].nextArgument = argument + 3;
argument[3].type.baseType = arg4;
argument[3].type.flags = HLSLTypeFlag_Const;
}
HLSLFunction function;
HLSLArgument argument[4];
};
Intrinsic SamplerIntrinsic(const char* name, HLSLBaseType returnType, HLSLBaseType arg1, HLSLBaseType samplerType, HLSLBaseType arg2)
{
Intrinsic i(name, returnType, arg1, arg2);
i.argument[0].type.samplerType = samplerType;
return i;
}
static const int _numberTypeRank[NumericType_Count][NumericType_Count] =
{
{ 0, 4, 4, 4 }, { 5, 0, 5, 5 }, { 2, 4, 0, 1 }, { 2, 4, 1, 0 } };
struct EffectStateValue
{
const char * name;
int value;
};
static const EffectStateValue textureFilteringValues[] = {
{"None", 0},
{"Point", 1},
{"Linear", 2},
{"Anisotropic", 3},
{NULL, 0}
};
static const EffectStateValue textureAddressingValues[] = {
{"Wrap", 1},
{"Mirror", 2},
{"Clamp", 3},
{"Border", 4},
{"MirrorOnce", 5},
{NULL, 0}
};
static const EffectStateValue booleanValues[] = {
{"False", 0},
{"True", 1},
{NULL, 0}
};
static const EffectStateValue cullValues[] = {
{"None", 1},
{"CW", 2},
{"CCW", 3},
{NULL, 0}
};
static const EffectStateValue cmpValues[] = {
{"Never", 1},
{"Less", 2},
{"Equal", 3},
{"LessEqual", 4},
{"Greater", 5},
{"NotEqual", 6},
{"GreaterEqual", 7},
{"Always", 8},
{NULL, 0}
};
static const EffectStateValue blendValues[] = {
{"Zero", 1},
{"One", 2},
{"SrcColor", 3},
{"InvSrcColor", 4},
{"SrcAlpha", 5},
{"InvSrcAlpha", 6},
{"DestAlpha", 7},
{"InvDestAlpha", 8},
{"DestColor", 9},
{"InvDestColor", 10},
{"SrcAlphaSat", 11},
{"BothSrcAlpha", 12},
{"BothInvSrcAlpha", 13},
{"BlendFactor", 14},
{"InvBlendFactor", 15},
{"SrcColor2", 16}, {"InvSrcColor2", 17},
{NULL, 0}
};
static const EffectStateValue blendOpValues[] = {
{"Add", 1},
{"Subtract", 2},
{"RevSubtract", 3},
{"Min", 4},
{"Max", 5},
{NULL, 0}
};
static const EffectStateValue fillModeValues[] = {
{"Point", 1},
{"Wireframe", 2},
{"Solid", 3},
{NULL, 0}
};
static const EffectStateValue stencilOpValues[] = {
{"Keep", 1},
{"Zero", 2},
{"Replace", 3},
{"IncrSat", 4},
{"DecrSat", 5},
{"Invert", 6},
{"Incr", 7},
{"Decr", 8},
{NULL, 0}
};
static const EffectStateValue colorMaskValues[] = {
{"False", 0},
{"Red", 1<<0},
{"Green", 1<<1},
{"Blue", 1<<2},
{"Alpha", 1<<3},
{"X", 1<<0},
{"Y", 1<<1},
{"Z", 1<<2},
{"W", 1<<3},
{NULL, 0}
};
static const EffectStateValue integerValues[] = {
{NULL, 0}
};
static const EffectStateValue floatValues[] = {
{NULL, 0}
};
struct EffectState
{
const char * name;
int d3drs;
const EffectStateValue * values;
};
static const EffectState samplerStates[] = {
{"AddressU", 1, textureAddressingValues},
{"AddressV", 2, textureAddressingValues},
{"AddressW", 3, textureAddressingValues},
{"MagFilter", 5, textureFilteringValues},
{"MinFilter", 6, textureFilteringValues},
{"MipFilter", 7, textureFilteringValues},
{"MipMapLodBias", 8, floatValues},
{"MaxMipLevel", 9, integerValues},
{"MaxAnisotropy", 10, integerValues},
{"sRGBTexture", 11, booleanValues},
};
static const EffectState effectStates[] = {
{"VertexShader", 0, NULL},
{"PixelShader", 0, NULL},
{"AlphaBlendEnable", 27, booleanValues},
{"SrcBlend", 19, blendValues},
{"DestBlend", 20, blendValues},
{"BlendOp", 171, blendOpValues},
{"SeparateAlphaBlendEanble", 206, booleanValues},
{"SrcBlendAlpha", 207, blendValues},
{"DestBlendAlpha", 208, blendValues},
{"BlendOpAlpha", 209, blendOpValues},
{"AlphaTestEnable", 15, booleanValues},
{"AlphaRef", 24, integerValues},
{"AlphaFunc", 25, cmpValues},
{"CullMode", 22, cullValues},
{"ZEnable", 7, booleanValues},
{"ZWriteEnable", 14, booleanValues},
{"ZFunc", 23, cmpValues},
{"StencilEnable", 52, booleanValues},
{"StencilFail", 53, stencilOpValues},
{"StencilZFail", 54, stencilOpValues},
{"StencilPass", 55, stencilOpValues},
{"StencilFunc", 56, cmpValues},
{"StencilRef", 57, integerValues},
{"StencilMask", 58, integerValues},
{"StencilWriteMask", 59, integerValues},
{"TwoSidedStencilMode", 185, booleanValues},
{"CCW_StencilFail", 186, stencilOpValues},
{"CCW_StencilZFail", 187, stencilOpValues},
{"CCW_StencilPass", 188, stencilOpValues},
{"CCW_StencilFunc", 189, cmpValues},
{"ColorWriteEnable", 168, colorMaskValues},
{"FillMode", 8, fillModeValues},
{"MultisampleAlias", 161, booleanValues},
{"MultisampleMask", 162, integerValues},
{"ScissorTestEnable", 174, booleanValues},
{"SlopeScaleDepthBias", 175, floatValues},
{"DepthBias", 195, floatValues}
};
static const EffectStateValue witnessCullModeValues[] = {
{"None", 0},
{"Back", 1},
{"Front", 2},
{NULL, 0}
};
static const EffectStateValue witnessFillModeValues[] = {
{"Solid", 0},
{"Wireframe", 1},
{NULL, 0}
};
static const EffectStateValue witnessBlendModeValues[] = {
{"Disabled", 0},
{"AlphaBlend", 1}, {"Add", 2}, {"Mixed", 3}, {"Multiply", 4}, {"Multiply2", 5}, {NULL, 0}
};
static const EffectStateValue witnessDepthFuncValues[] = {
{"LessEqual", 0},
{"Less", 1},
{"Equal", 2},
{"Greater", 3},
{"Always", 4},
{NULL, 0}
};
static const EffectStateValue witnessStencilModeValues[] = {
{"Disabled", 0},
{"Set", 1},
{"Test", 2},
{NULL, 0}
};
static const EffectState pipelineStates[] = {
{"VertexShader", 0, NULL},
{"PixelShader", 0, NULL},
{"DepthWrite", 0, booleanValues},
{"DepthEnable", 0, booleanValues},
{"DepthFunc", 0, witnessDepthFuncValues},
{"StencilMode", 0, witnessStencilModeValues},
{"CullMode", 0, witnessCullModeValues},
{"FillMode", 0, witnessFillModeValues},
{"MultisampleEnable", 0, booleanValues},
{"PolygonOffset", 0, booleanValues},
{"BlendMode", 0, witnessBlendModeValues},
{"ColorWrite", 0, booleanValues},
{"AlphaWrite", 0, booleanValues},
{"AlphaTest", 0, booleanValues}, };
#define INTRINSIC_FLOAT1_FUNCTION(name) \
Intrinsic( name, HLSLBaseType_Float, HLSLBaseType_Float ), \
Intrinsic( name, HLSLBaseType_Float2, HLSLBaseType_Float2 ), \
Intrinsic( name, HLSLBaseType_Float3, HLSLBaseType_Float3 ), \
Intrinsic( name, HLSLBaseType_Float4, HLSLBaseType_Float4 )
#define INTRINSIC_FLOAT2_FUNCTION(name) \
Intrinsic( name, HLSLBaseType_Float, HLSLBaseType_Float, HLSLBaseType_Float ), \
Intrinsic( name, HLSLBaseType_Float2, HLSLBaseType_Float2, HLSLBaseType_Float2 ), \
Intrinsic( name, HLSLBaseType_Float3, HLSLBaseType_Float3, HLSLBaseType_Float3 ), \
Intrinsic( name, HLSLBaseType_Float4, HLSLBaseType_Float4, HLSLBaseType_Float4 )
#define INTRINSIC_FLOAT3_FUNCTION(name) \
Intrinsic( name, HLSLBaseType_Float, HLSLBaseType_Float, HLSLBaseType_Float, HLSLBaseType_Float ), \
Intrinsic( name, HLSLBaseType_Float2, HLSLBaseType_Float2, HLSLBaseType_Float2, HLSLBaseType_Float2 ), \
Intrinsic( name, HLSLBaseType_Float3, HLSLBaseType_Float3, HLSLBaseType_Float3, HLSLBaseType_Float3 ), \
Intrinsic( name, HLSLBaseType_Float4, HLSLBaseType_Float4, HLSLBaseType_Float4, HLSLBaseType_Float4 )
#if 0#else
#define SAMPLER_INTRINSIC_FUNCTION(name, sampler, arg1) \
Intrinsic( name, HLSLBaseType_Float4, sampler, arg1)
#endif
const Intrinsic _intrinsic[] =
{
INTRINSIC_FLOAT1_FUNCTION( "abs" ),
INTRINSIC_FLOAT1_FUNCTION( "acos" ),
Intrinsic( "any", HLSLBaseType_Bool, HLSLBaseType_Float ),
Intrinsic( "any", HLSLBaseType_Bool, HLSLBaseType_Float2 ),
Intrinsic( "any", HLSLBaseType_Bool, HLSLBaseType_Float3 ),
Intrinsic( "any", HLSLBaseType_Bool, HLSLBaseType_Float4 ),
Intrinsic( "any", HLSLBaseType_Bool, HLSLBaseType_Float2x4 ),
Intrinsic( "any", HLSLBaseType_Bool, HLSLBaseType_Float2x3 ),
Intrinsic( "any", HLSLBaseType_Bool, HLSLBaseType_Float2x2 ),
Intrinsic( "any", HLSLBaseType_Bool, HLSLBaseType_Float3x4 ),
Intrinsic( "any", HLSLBaseType_Bool, HLSLBaseType_Float3x3 ),
Intrinsic( "any", HLSLBaseType_Bool, HLSLBaseType_Float3x2 ),
Intrinsic( "any", HLSLBaseType_Bool, HLSLBaseType_Float4x4 ),
Intrinsic( "any", HLSLBaseType_Bool, HLSLBaseType_Float4x3 ),
Intrinsic( "any", HLSLBaseType_Bool, HLSLBaseType_Float4x2 ),
Intrinsic( "any", HLSLBaseType_Bool, HLSLBaseType_Bool ),
Intrinsic( "any", HLSLBaseType_Bool, HLSLBaseType_Int ),
Intrinsic( "any", HLSLBaseType_Bool, HLSLBaseType_Int2 ),
Intrinsic( "any", HLSLBaseType_Bool, HLSLBaseType_Int3 ),
Intrinsic( "any", HLSLBaseType_Bool, HLSLBaseType_Int4 ),
Intrinsic( "any", HLSLBaseType_Bool, HLSLBaseType_Uint ),
Intrinsic( "any", HLSLBaseType_Bool, HLSLBaseType_Uint2 ),
Intrinsic( "any", HLSLBaseType_Bool, HLSLBaseType_Uint3 ),
Intrinsic( "any", HLSLBaseType_Bool, HLSLBaseType_Uint4 ),
INTRINSIC_FLOAT1_FUNCTION( "asin" ),
INTRINSIC_FLOAT1_FUNCTION( "atan" ),
INTRINSIC_FLOAT2_FUNCTION( "atan2" ),
INTRINSIC_FLOAT3_FUNCTION( "clamp" ),
INTRINSIC_FLOAT1_FUNCTION( "cos" ),
INTRINSIC_FLOAT1_FUNCTION( "tan" ),
INTRINSIC_FLOAT3_FUNCTION( "lerp" ),
INTRINSIC_FLOAT3_FUNCTION( "smoothstep" ),
INTRINSIC_FLOAT1_FUNCTION( "floor" ),
INTRINSIC_FLOAT1_FUNCTION( "ceil" ),
INTRINSIC_FLOAT1_FUNCTION( "round" ),
INTRINSIC_FLOAT1_FUNCTION( "frac" ),
INTRINSIC_FLOAT2_FUNCTION( "fmod" ),
Intrinsic( "clip", HLSLBaseType_Void, HLSLBaseType_Float ),
Intrinsic( "clip", HLSLBaseType_Void, HLSLBaseType_Float2 ),
Intrinsic( "clip", HLSLBaseType_Void, HLSLBaseType_Float3 ),
Intrinsic( "clip", HLSLBaseType_Void, HLSLBaseType_Float4 ),
Intrinsic( "dot", HLSLBaseType_Float, HLSLBaseType_Float, HLSLBaseType_Float ),
Intrinsic( "dot", HLSLBaseType_Float, HLSLBaseType_Float2, HLSLBaseType_Float2 ),
Intrinsic( "dot", HLSLBaseType_Float, HLSLBaseType_Float3, HLSLBaseType_Float3 ),
Intrinsic( "dot", HLSLBaseType_Float, HLSLBaseType_Float4, HLSLBaseType_Float4 ),
Intrinsic( "cross", HLSLBaseType_Float3, HLSLBaseType_Float3, HLSLBaseType_Float3 ),
Intrinsic( "length", HLSLBaseType_Float, HLSLBaseType_Float ),
Intrinsic( "length", HLSLBaseType_Float, HLSLBaseType_Float2 ),
Intrinsic( "length", HLSLBaseType_Float, HLSLBaseType_Float3 ),
Intrinsic( "length", HLSLBaseType_Float, HLSLBaseType_Float4 ),
INTRINSIC_FLOAT2_FUNCTION( "max" ),
INTRINSIC_FLOAT2_FUNCTION( "min" ),
Intrinsic( "mul", HLSLBaseType_Float, HLSLBaseType_Float, HLSLBaseType_Float),
Intrinsic( "mul", HLSLBaseType_Float4, HLSLBaseType_Float, HLSLBaseType_Float4),
Intrinsic( "mul", HLSLBaseType_Float3, HLSLBaseType_Float, HLSLBaseType_Float3),
Intrinsic( "mul", HLSLBaseType_Float2, HLSLBaseType_Float, HLSLBaseType_Float2),
Intrinsic( "mul", HLSLBaseType_Float4x4, HLSLBaseType_Float, HLSLBaseType_Float4x4),
Intrinsic( "mul", HLSLBaseType_Float4x3, HLSLBaseType_Float, HLSLBaseType_Float4x3),
Intrinsic( "mul", HLSLBaseType_Float4x2, HLSLBaseType_Float, HLSLBaseType_Float4x2),
Intrinsic( "mul", HLSLBaseType_Float3x4, HLSLBaseType_Float, HLSLBaseType_Float3x4),
Intrinsic( "mul", HLSLBaseType_Float3x3, HLSLBaseType_Float, HLSLBaseType_Float3x3),
Intrinsic( "mul", HLSLBaseType_Float3x2, HLSLBaseType_Float, HLSLBaseType_Float3x2),
Intrinsic( "mul", HLSLBaseType_Float2x4, HLSLBaseType_Float, HLSLBaseType_Float2x4),
Intrinsic( "mul", HLSLBaseType_Float2x3, HLSLBaseType_Float, HLSLBaseType_Float2x3),
Intrinsic( "mul", HLSLBaseType_Float2x2, HLSLBaseType_Float, HLSLBaseType_Float2x2),
Intrinsic( "mul", HLSLBaseType_Float4, HLSLBaseType_Float4, HLSLBaseType_Float),
Intrinsic( "mul", HLSLBaseType_Float3, HLSLBaseType_Float3, HLSLBaseType_Float),
Intrinsic( "mul", HLSLBaseType_Float2, HLSLBaseType_Float2, HLSLBaseType_Float),
Intrinsic( "mul", HLSLBaseType_Float, HLSLBaseType_Float4, HLSLBaseType_Float4),
Intrinsic( "mul", HLSLBaseType_Float, HLSLBaseType_Float3, HLSLBaseType_Float3),
Intrinsic( "mul", HLSLBaseType_Float, HLSLBaseType_Float2, HLSLBaseType_Float2),
Intrinsic( "mul", HLSLBaseType_Float4, HLSLBaseType_Float4, HLSLBaseType_Float4x4),
Intrinsic( "mul", HLSLBaseType_Float3, HLSLBaseType_Float4, HLSLBaseType_Float4x3),
Intrinsic( "mul", HLSLBaseType_Float2, HLSLBaseType_Float4, HLSLBaseType_Float4x2),
Intrinsic( "mul", HLSLBaseType_Float4, HLSLBaseType_Float3, HLSLBaseType_Float3x4),
Intrinsic( "mul", HLSLBaseType_Float3, HLSLBaseType_Float3, HLSLBaseType_Float3x3),
Intrinsic( "mul", HLSLBaseType_Float2, HLSLBaseType_Float3, HLSLBaseType_Float3x2),
Intrinsic( "mul", HLSLBaseType_Float4, HLSLBaseType_Float2, HLSLBaseType_Float2x4),
Intrinsic( "mul", HLSLBaseType_Float3, HLSLBaseType_Float2, HLSLBaseType_Float2x3),
Intrinsic( "mul", HLSLBaseType_Float2, HLSLBaseType_Float2, HLSLBaseType_Float2x2),
Intrinsic( "mul", HLSLBaseType_Float4x4, HLSLBaseType_Float4x4, HLSLBaseType_Float),
Intrinsic( "mul", HLSLBaseType_Float3x4, HLSLBaseType_Float3x4, HLSLBaseType_Float),
Intrinsic( "mul", HLSLBaseType_Float2x4, HLSLBaseType_Float2x4, HLSLBaseType_Float),
Intrinsic( "mul", HLSLBaseType_Float4x3, HLSLBaseType_Float4x3, HLSLBaseType_Float),
Intrinsic( "mul", HLSLBaseType_Float3x3, HLSLBaseType_Float3x3, HLSLBaseType_Float),
Intrinsic( "mul", HLSLBaseType_Float2x3, HLSLBaseType_Float2x3, HLSLBaseType_Float),
Intrinsic( "mul", HLSLBaseType_Float4x2, HLSLBaseType_Float4x2, HLSLBaseType_Float),
Intrinsic( "mul", HLSLBaseType_Float3x2, HLSLBaseType_Float3x2, HLSLBaseType_Float),
Intrinsic( "mul", HLSLBaseType_Float2x2, HLSLBaseType_Float2x2, HLSLBaseType_Float),
Intrinsic( "mul", HLSLBaseType_Float4, HLSLBaseType_Float4x4, HLSLBaseType_Float4),
Intrinsic( "mul", HLSLBaseType_Float3, HLSLBaseType_Float3x4, HLSLBaseType_Float4),
Intrinsic( "mul", HLSLBaseType_Float2, HLSLBaseType_Float2x4, HLSLBaseType_Float4),
Intrinsic( "mul", HLSLBaseType_Float4, HLSLBaseType_Float4x3, HLSLBaseType_Float3),
Intrinsic( "mul", HLSLBaseType_Float3, HLSLBaseType_Float3x3, HLSLBaseType_Float3),
Intrinsic( "mul", HLSLBaseType_Float2, HLSLBaseType_Float2x3, HLSLBaseType_Float3),
Intrinsic( "mul", HLSLBaseType_Float4, HLSLBaseType_Float4x2, HLSLBaseType_Float2),
Intrinsic( "mul", HLSLBaseType_Float3, HLSLBaseType_Float3x2, HLSLBaseType_Float2),
Intrinsic( "mul", HLSLBaseType_Float2, HLSLBaseType_Float2x2, HLSLBaseType_Float2),
Intrinsic( "mul", HLSLBaseType_Float4x4, HLSLBaseType_Float4x4, HLSLBaseType_Float4x4 ),
Intrinsic( "mul", HLSLBaseType_Float4x3, HLSLBaseType_Float4x4, HLSLBaseType_Float4x3 ),
Intrinsic( "mul", HLSLBaseType_Float4x2, HLSLBaseType_Float4x4, HLSLBaseType_Float4x2 ),
Intrinsic( "mul", HLSLBaseType_Float3x4, HLSLBaseType_Float3x4, HLSLBaseType_Float4x4 ),
Intrinsic( "mul", HLSLBaseType_Float3x3, HLSLBaseType_Float3x4, HLSLBaseType_Float4x3 ),
Intrinsic( "mul", HLSLBaseType_Float3x2, HLSLBaseType_Float3x4, HLSLBaseType_Float4x2 ),
Intrinsic( "mul", HLSLBaseType_Float2x4, HLSLBaseType_Float2x4, HLSLBaseType_Float4x4 ),
Intrinsic( "mul", HLSLBaseType_Float2x3, HLSLBaseType_Float2x4, HLSLBaseType_Float4x3 ),
Intrinsic( "mul", HLSLBaseType_Float2x2, HLSLBaseType_Float2x4, HLSLBaseType_Float4x2 ),
Intrinsic( "mul", HLSLBaseType_Float4x4, HLSLBaseType_Float4x3, HLSLBaseType_Float3x4 ),
Intrinsic( "mul", HLSLBaseType_Float4x3, HLSLBaseType_Float4x3, HLSLBaseType_Float3x3 ),
Intrinsic( "mul", HLSLBaseType_Float4x2, HLSLBaseType_Float4x3, HLSLBaseType_Float3x2 ),
Intrinsic( "mul", HLSLBaseType_Float3x4, HLSLBaseType_Float3x3, HLSLBaseType_Float3x4 ),
Intrinsic( "mul", HLSLBaseType_Float3x3, HLSLBaseType_Float3x3, HLSLBaseType_Float3x3 ),
Intrinsic( "mul", HLSLBaseType_Float3x2, HLSLBaseType_Float3x3, HLSLBaseType_Float3x2 ),
Intrinsic( "mul", HLSLBaseType_Float2x4, HLSLBaseType_Float2x3, HLSLBaseType_Float3x4 ),
Intrinsic( "mul", HLSLBaseType_Float2x3, HLSLBaseType_Float2x3, HLSLBaseType_Float3x3 ),
Intrinsic( "mul", HLSLBaseType_Float2x2, HLSLBaseType_Float2x3, HLSLBaseType_Float3x2 ),
Intrinsic( "mul", HLSLBaseType_Float4x4, HLSLBaseType_Float4x2, HLSLBaseType_Float2x4 ),
Intrinsic( "mul", HLSLBaseType_Float4x3, HLSLBaseType_Float4x2, HLSLBaseType_Float2x3 ),
Intrinsic( "mul", HLSLBaseType_Float4x2, HLSLBaseType_Float4x2, HLSLBaseType_Float2x2 ),
Intrinsic( "mul", HLSLBaseType_Float3x4, HLSLBaseType_Float3x2, HLSLBaseType_Float2x4 ),
Intrinsic( "mul", HLSLBaseType_Float3x3, HLSLBaseType_Float3x2, HLSLBaseType_Float2x3 ),
Intrinsic( "mul", HLSLBaseType_Float3x2, HLSLBaseType_Float3x2, HLSLBaseType_Float2x2 ),
Intrinsic( "mul", HLSLBaseType_Float2x4, HLSLBaseType_Float2x2, HLSLBaseType_Float2x4 ),
Intrinsic( "mul", HLSLBaseType_Float2x3, HLSLBaseType_Float2x2, HLSLBaseType_Float2x3 ),
Intrinsic( "mul", HLSLBaseType_Float2x2, HLSLBaseType_Float2x2, HLSLBaseType_Float2x2 ),
Intrinsic( "transpose", HLSLBaseType_Float2x2, HLSLBaseType_Float2x2 ),
Intrinsic( "transpose", HLSLBaseType_Float3x3, HLSLBaseType_Float3x3 ),
Intrinsic( "transpose", HLSLBaseType_Float4x4, HLSLBaseType_Float4x4 ),
INTRINSIC_FLOAT2_FUNCTION( "modf" ),
INTRINSIC_FLOAT1_FUNCTION( "normalize" ),
INTRINSIC_FLOAT2_FUNCTION( "pow" ),
INTRINSIC_FLOAT1_FUNCTION( "saturate" ),
INTRINSIC_FLOAT1_FUNCTION( "sin" ),
INTRINSIC_FLOAT1_FUNCTION( "sqrt" ),
INTRINSIC_FLOAT1_FUNCTION( "rsqrt" ),
INTRINSIC_FLOAT1_FUNCTION( "rcp" ),
INTRINSIC_FLOAT1_FUNCTION( "exp" ),
INTRINSIC_FLOAT1_FUNCTION( "exp2" ),
INTRINSIC_FLOAT1_FUNCTION( "log" ),
INTRINSIC_FLOAT1_FUNCTION( "log2" ),
INTRINSIC_FLOAT1_FUNCTION( "log10" ),
INTRINSIC_FLOAT1_FUNCTION( "ddx" ),
INTRINSIC_FLOAT1_FUNCTION( "ddy" ),
INTRINSIC_FLOAT1_FUNCTION( "sign" ),
INTRINSIC_FLOAT2_FUNCTION( "step" ),
INTRINSIC_FLOAT2_FUNCTION( "reflect" ),
Intrinsic("ldexp", HLSLBaseType_Float, HLSLBaseType_Float, HLSLBaseType_Float),
Intrinsic("ldexp", HLSLBaseType_Float2, HLSLBaseType_Float2, HLSLBaseType_Float2),
Intrinsic("ldexp", HLSLBaseType_Float3, HLSLBaseType_Float3, HLSLBaseType_Float3),
Intrinsic("ldexp", HLSLBaseType_Float4, HLSLBaseType_Float4, HLSLBaseType_Float4),
Intrinsic("ldexp", HLSLBaseType_Float2x2, HLSLBaseType_Float2x2, HLSLBaseType_Float2x2),
Intrinsic("ldexp", HLSLBaseType_Float2x3, HLSLBaseType_Float2x3, HLSLBaseType_Float2x3),
Intrinsic("ldexp", HLSLBaseType_Float2x4, HLSLBaseType_Float2x4, HLSLBaseType_Float2x4),
Intrinsic("ldexp", HLSLBaseType_Float3x2, HLSLBaseType_Float3x2, HLSLBaseType_Float3x2),
Intrinsic("ldexp", HLSLBaseType_Float3x3, HLSLBaseType_Float3x3, HLSLBaseType_Float3x3),
Intrinsic("ldexp", HLSLBaseType_Float3x4, HLSLBaseType_Float3x4, HLSLBaseType_Float3x4),
Intrinsic("ldexp", HLSLBaseType_Float4x2, HLSLBaseType_Float4x2, HLSLBaseType_Float4x2),
Intrinsic("ldexp", HLSLBaseType_Float4x3, HLSLBaseType_Float4x3, HLSLBaseType_Float4x3),
Intrinsic("ldexp", HLSLBaseType_Float4x4, HLSLBaseType_Float4x4, HLSLBaseType_Float4x4),
Intrinsic("refract", HLSLBaseType_Float2, HLSLBaseType_Float2, HLSLBaseType_Float2, HLSLBaseType_Float),
Intrinsic("refract", HLSLBaseType_Float3, HLSLBaseType_Float3, HLSLBaseType_Float3, HLSLBaseType_Float),
Intrinsic("refract", HLSLBaseType_Float4, HLSLBaseType_Float4, HLSLBaseType_Float4, HLSLBaseType_Float),
Intrinsic("faceforward", HLSLBaseType_Float, HLSLBaseType_Float, HLSLBaseType_Float, HLSLBaseType_Float),
Intrinsic("faceforward", HLSLBaseType_Float2, HLSLBaseType_Float2, HLSLBaseType_Float2, HLSLBaseType_Float2),
Intrinsic("faceforward", HLSLBaseType_Float3, HLSLBaseType_Float3, HLSLBaseType_Float3, HLSLBaseType_Float3),
Intrinsic("faceforward", HLSLBaseType_Float4, HLSLBaseType_Float4, HLSLBaseType_Float4, HLSLBaseType_Float4),
Intrinsic("isnan", HLSLBaseType_Bool, HLSLBaseType_Float),
Intrinsic("isinf", HLSLBaseType_Bool, HLSLBaseType_Float),
Intrinsic("asuint", HLSLBaseType_Uint, HLSLBaseType_Float),
SAMPLER_INTRINSIC_FUNCTION("tex2D", HLSLBaseType_Sampler2D, HLSLBaseType_Float2),
Intrinsic("tex2Dproj", HLSLBaseType_Float4, HLSLBaseType_Sampler2D, HLSLBaseType_Float4),
SAMPLER_INTRINSIC_FUNCTION("tex2Dlod", HLSLBaseType_Sampler2D, HLSLBaseType_Float4),
Intrinsic("tex2Dlod", HLSLBaseType_Float4, HLSLBaseType_Sampler2D, HLSLBaseType_Float4, HLSLBaseType_Int2),
SAMPLER_INTRINSIC_FUNCTION("tex2Dbias", HLSLBaseType_Sampler2D, HLSLBaseType_Float4),
Intrinsic("tex2Dgrad", HLSLBaseType_Float4, HLSLBaseType_Sampler2D, HLSLBaseType_Float2, HLSLBaseType_Float2, HLSLBaseType_Float2),
Intrinsic("tex2Dgather", HLSLBaseType_Float4, HLSLBaseType_Sampler2D, HLSLBaseType_Float2, HLSLBaseType_Int),
Intrinsic("tex2Dgather", HLSLBaseType_Float4, HLSLBaseType_Sampler2D, HLSLBaseType_Float2, HLSLBaseType_Int2, HLSLBaseType_Int), Intrinsic("tex2Dsize", HLSLBaseType_Int2, HLSLBaseType_Sampler2D),
Intrinsic("tex2Dfetch", HLSLBaseType_Float4, HLSLBaseType_Sampler2D, HLSLBaseType_Int3),
Intrinsic("tex2Dcmp", HLSLBaseType_Float4, HLSLBaseType_Sampler2DShadow, HLSLBaseType_Float4),
Intrinsic("tex2DMSfetch", HLSLBaseType_Float4, HLSLBaseType_Sampler2DMS, HLSLBaseType_Int2, HLSLBaseType_Int),
Intrinsic("tex2DMSsize", HLSLBaseType_Int3, HLSLBaseType_Sampler2DMS),
Intrinsic("tex2DArray", HLSLBaseType_Float4, HLSLBaseType_Sampler2DArray, HLSLBaseType_Float3),
Intrinsic("tex3D", HLSLBaseType_Float4, HLSLBaseType_Sampler3D, HLSLBaseType_Float3),
Intrinsic("tex3Dlod", HLSLBaseType_Float4, HLSLBaseType_Sampler3D, HLSLBaseType_Float4),
Intrinsic("tex3Dbias", HLSLBaseType_Float4, HLSLBaseType_Sampler3D, HLSLBaseType_Float4),
Intrinsic("tex3Dsize", HLSLBaseType_Int3, HLSLBaseType_Sampler3D),
Intrinsic("texCUBE", HLSLBaseType_Float4, HLSLBaseType_SamplerCube, HLSLBaseType_Float3),
Intrinsic("texCUBElod", HLSLBaseType_Float4, HLSLBaseType_SamplerCube, HLSLBaseType_Float4),
Intrinsic("texCUBEbias", HLSLBaseType_Float4, HLSLBaseType_SamplerCube, HLSLBaseType_Float4),
Intrinsic("texCUBEsize", HLSLBaseType_Int, HLSLBaseType_SamplerCube),
Intrinsic( "sincos", HLSLBaseType_Void, HLSLBaseType_Float, HLSLBaseType_Float, HLSLBaseType_Float ),
Intrinsic( "sincos", HLSLBaseType_Void, HLSLBaseType_Float2, HLSLBaseType_Float, HLSLBaseType_Float2 ),
Intrinsic( "sincos", HLSLBaseType_Void, HLSLBaseType_Float3, HLSLBaseType_Float, HLSLBaseType_Float3 ),
Intrinsic( "sincos", HLSLBaseType_Void, HLSLBaseType_Float4, HLSLBaseType_Float, HLSLBaseType_Float4 ),
Intrinsic( "mad", HLSLBaseType_Float, HLSLBaseType_Float, HLSLBaseType_Float, HLSLBaseType_Float ),
Intrinsic( "mad", HLSLBaseType_Float2, HLSLBaseType_Float2, HLSLBaseType_Float2, HLSLBaseType_Float2 ),
Intrinsic( "mad", HLSLBaseType_Float3, HLSLBaseType_Float3, HLSLBaseType_Float3, HLSLBaseType_Float3 ),
Intrinsic( "mad", HLSLBaseType_Float4, HLSLBaseType_Float4, HLSLBaseType_Float4, HLSLBaseType_Float4 ),
};
const int _numIntrinsics = sizeof(_intrinsic) / sizeof(Intrinsic);
const int _binaryOpPriority[] =
{
2, 1, 8, 8, 9, 9, 7, 7, 7, 7, 6, 6, 5, 3, 4, };
HLSLBaseType _binaryOpTypeLookup[HLSLBaseType_NumericCount][HLSLBaseType_NumericCount] =
{
{ HLSLBaseType_Float, HLSLBaseType_Float2, HLSLBaseType_Float3, HLSLBaseType_Float4,
HLSLBaseType_Float2x4, HLSLBaseType_Float2x3, HLSLBaseType_Float2x2,
HLSLBaseType_Float3x4, HLSLBaseType_Float3x3, HLSLBaseType_Float3x2,
HLSLBaseType_Float4x4, HLSLBaseType_Float4x3, HLSLBaseType_Float4x2,
HLSLBaseType_Float, HLSLBaseType_Float2, HLSLBaseType_Float3, HLSLBaseType_Float4,
HLSLBaseType_Float, HLSLBaseType_Float2, HLSLBaseType_Float3, HLSLBaseType_Float4,
HLSLBaseType_Float, HLSLBaseType_Float2, HLSLBaseType_Float3, HLSLBaseType_Float4
},
{ HLSLBaseType_Float2, HLSLBaseType_Float2, HLSLBaseType_Float2, HLSLBaseType_Float2,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Float2, HLSLBaseType_Float2, HLSLBaseType_Float2, HLSLBaseType_Float2,
HLSLBaseType_Float2, HLSLBaseType_Float2, HLSLBaseType_Float2, HLSLBaseType_Float2,
HLSLBaseType_Float2, HLSLBaseType_Float2, HLSLBaseType_Float2, HLSLBaseType_Float2
},
{ HLSLBaseType_Float3, HLSLBaseType_Float2, HLSLBaseType_Float3, HLSLBaseType_Float3,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Float3, HLSLBaseType_Float2, HLSLBaseType_Float3, HLSLBaseType_Float3,
HLSLBaseType_Float3, HLSLBaseType_Float2, HLSLBaseType_Float3, HLSLBaseType_Float3,
HLSLBaseType_Float3, HLSLBaseType_Float2, HLSLBaseType_Float3, HLSLBaseType_Float3
},
{ HLSLBaseType_Float4, HLSLBaseType_Float2, HLSLBaseType_Float3, HLSLBaseType_Float4,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Float4, HLSLBaseType_Float2, HLSLBaseType_Float3, HLSLBaseType_Float4,
HLSLBaseType_Float4, HLSLBaseType_Float2, HLSLBaseType_Float3, HLSLBaseType_Float4,
HLSLBaseType_Float4, HLSLBaseType_Float2, HLSLBaseType_Float3, HLSLBaseType_Float4
},
{ HLSLBaseType_Float2x4, HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Float2x4, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Float2x4, HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Float2x4, HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Float2x4, HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown
},
{ HLSLBaseType_Float2x3, HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Unknown, HLSLBaseType_Float2x3, HLSLBaseType_Unknown,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Float2x3, HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Float2x3, HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Float2x3, HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown
},
{ HLSLBaseType_Float2x2, HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Float2x2,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Float2x2, HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Float2x2, HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Float2x2, HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown
},
{ HLSLBaseType_Float3x4, HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Float3x4, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Float3x4, HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Float3x4, HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Float3x4, HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown
},
{ HLSLBaseType_Float3x3, HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Unknown, HLSLBaseType_Float3x3, HLSLBaseType_Unknown,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Float3x3, HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Float3x3, HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Float3x3, HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown
},
{ HLSLBaseType_Float3x2, HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Float3x2,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Float3x2, HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Float3x2, HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Float3x2, HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown
},
{ HLSLBaseType_Float4x4, HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Float4x4, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Float4x4, HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Float4x4, HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Float4x4, HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown
},
{ HLSLBaseType_Float4x3, HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Unknown, HLSLBaseType_Float4x3, HLSLBaseType_Unknown,
HLSLBaseType_Float4x3, HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Float4x3, HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Float4x3, HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown
},
{ HLSLBaseType_Float4x2, HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Float4x2,
HLSLBaseType_Float4x2, HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Float4x2, HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Float4x2, HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown
},
{ HLSLBaseType_Float, HLSLBaseType_Float2, HLSLBaseType_Float3, HLSLBaseType_Float4,
HLSLBaseType_Float2x4, HLSLBaseType_Float2x3, HLSLBaseType_Float2x2,
HLSLBaseType_Float3x4, HLSLBaseType_Float3x3, HLSLBaseType_Float3x2,
HLSLBaseType_Float4x4, HLSLBaseType_Float4x3, HLSLBaseType_Float4x2,
HLSLBaseType_Int, HLSLBaseType_Int2, HLSLBaseType_Int3, HLSLBaseType_Int4,
HLSLBaseType_Int, HLSLBaseType_Int2, HLSLBaseType_Int3, HLSLBaseType_Int4,
HLSLBaseType_Uint, HLSLBaseType_Uint2, HLSLBaseType_Uint3, HLSLBaseType_Uint4
},
{ HLSLBaseType_Float2, HLSLBaseType_Float2, HLSLBaseType_Float3, HLSLBaseType_Float4,
HLSLBaseType_Float2x4, HLSLBaseType_Float2x3, HLSLBaseType_Float2x2,
HLSLBaseType_Float3x4, HLSLBaseType_Float3x3, HLSLBaseType_Float3x2,
HLSLBaseType_Float4x4, HLSLBaseType_Float4x3, HLSLBaseType_Float4x2,
HLSLBaseType_Int2, HLSLBaseType_Int2, HLSLBaseType_Int3, HLSLBaseType_Int4,
HLSLBaseType_Int2, HLSLBaseType_Int2, HLSLBaseType_Int3, HLSLBaseType_Int4,
HLSLBaseType_Uint2, HLSLBaseType_Uint2, HLSLBaseType_Uint3, HLSLBaseType_Uint4
},
{ HLSLBaseType_Float3, HLSLBaseType_Float3, HLSLBaseType_Float3, HLSLBaseType_Float4,
HLSLBaseType_Float2x4, HLSLBaseType_Float2x3, HLSLBaseType_Float2x2,
HLSLBaseType_Float3x4, HLSLBaseType_Float3x3, HLSLBaseType_Float3x2,
HLSLBaseType_Float4x4, HLSLBaseType_Float4x3, HLSLBaseType_Float4x2,
HLSLBaseType_Int3, HLSLBaseType_Int2, HLSLBaseType_Int3, HLSLBaseType_Int4,
HLSLBaseType_Int3, HLSLBaseType_Int2, HLSLBaseType_Int3, HLSLBaseType_Int4,
HLSLBaseType_Uint3, HLSLBaseType_Uint2, HLSLBaseType_Uint3, HLSLBaseType_Uint4
},
{ HLSLBaseType_Float, HLSLBaseType_Float2, HLSLBaseType_Float3, HLSLBaseType_Float4,
HLSLBaseType_Float2x4, HLSLBaseType_Float2x3, HLSLBaseType_Float2x2,
HLSLBaseType_Float3x4, HLSLBaseType_Float3x3, HLSLBaseType_Float3x2,
HLSLBaseType_Float4x4, HLSLBaseType_Float4x3, HLSLBaseType_Float4x2,
HLSLBaseType_Int, HLSLBaseType_Int2, HLSLBaseType_Int3, HLSLBaseType_Int4,
HLSLBaseType_Int, HLSLBaseType_Int2, HLSLBaseType_Int3, HLSLBaseType_Int4,
HLSLBaseType_Uint, HLSLBaseType_Uint2, HLSLBaseType_Uint3, HLSLBaseType_Uint4
},
{ HLSLBaseType_Float, HLSLBaseType_Float2, HLSLBaseType_Float3, HLSLBaseType_Float4,
HLSLBaseType_Float2x4, HLSLBaseType_Float2x3, HLSLBaseType_Float2x2,
HLSLBaseType_Float3x4, HLSLBaseType_Float3x3, HLSLBaseType_Float3x2,
HLSLBaseType_Float4x4, HLSLBaseType_Float4x3, HLSLBaseType_Float4x2,
HLSLBaseType_Int, HLSLBaseType_Int2, HLSLBaseType_Int2, HLSLBaseType_Int2,
HLSLBaseType_Int, HLSLBaseType_Int2, HLSLBaseType_Int3, HLSLBaseType_Int4,
HLSLBaseType_Uint, HLSLBaseType_Uint2, HLSLBaseType_Uint3, HLSLBaseType_Uint4
},
{ HLSLBaseType_Float2, HLSLBaseType_Float2, HLSLBaseType_Float2, HLSLBaseType_Float2,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Int2, HLSLBaseType_Int2, HLSLBaseType_Int2, HLSLBaseType_Int2,
HLSLBaseType_Int2, HLSLBaseType_Int2, HLSLBaseType_Int2, HLSLBaseType_Int2,
HLSLBaseType_Uint2, HLSLBaseType_Uint2, HLSLBaseType_Uint2, HLSLBaseType_Uint2
},
{ HLSLBaseType_Float3, HLSLBaseType_Float2, HLSLBaseType_Float3, HLSLBaseType_Float3,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Int3, HLSLBaseType_Int2, HLSLBaseType_Int3, HLSLBaseType_Int3,
HLSLBaseType_Int3, HLSLBaseType_Int2, HLSLBaseType_Int3, HLSLBaseType_Int3,
HLSLBaseType_Uint3, HLSLBaseType_Uint2, HLSLBaseType_Uint3, HLSLBaseType_Uint3
},
{ HLSLBaseType_Float4, HLSLBaseType_Float2, HLSLBaseType_Float3, HLSLBaseType_Float4,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Int4, HLSLBaseType_Int2, HLSLBaseType_Int3, HLSLBaseType_Int4,
HLSLBaseType_Int4, HLSLBaseType_Int2, HLSLBaseType_Int3, HLSLBaseType_Int4,
HLSLBaseType_Uint4, HLSLBaseType_Uint2, HLSLBaseType_Uint3, HLSLBaseType_Uint4
},
{ HLSLBaseType_Float, HLSLBaseType_Float2, HLSLBaseType_Float3, HLSLBaseType_Float4,
HLSLBaseType_Float2x4, HLSLBaseType_Float2x3, HLSLBaseType_Float2x2,
HLSLBaseType_Float3x4, HLSLBaseType_Float3x3, HLSLBaseType_Float3x2,
HLSLBaseType_Float4x4, HLSLBaseType_Float4x3, HLSLBaseType_Float4x2,
HLSLBaseType_Uint, HLSLBaseType_Uint2, HLSLBaseType_Uint3, HLSLBaseType_Uint4,
HLSLBaseType_Uint, HLSLBaseType_Uint2, HLSLBaseType_Uint3, HLSLBaseType_Uint4,
HLSLBaseType_Uint, HLSLBaseType_Uint2, HLSLBaseType_Uint3, HLSLBaseType_Uint4
},
{ HLSLBaseType_Float2, HLSLBaseType_Float2, HLSLBaseType_Float2, HLSLBaseType_Float2,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Uint2, HLSLBaseType_Uint2, HLSLBaseType_Uint2, HLSLBaseType_Uint2,
HLSLBaseType_Uint2, HLSLBaseType_Uint2, HLSLBaseType_Uint2, HLSLBaseType_Uint2,
HLSLBaseType_Uint2, HLSLBaseType_Uint2, HLSLBaseType_Uint2, HLSLBaseType_Uint2
},
{ HLSLBaseType_Float3, HLSLBaseType_Float2, HLSLBaseType_Float3, HLSLBaseType_Float3,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Uint3, HLSLBaseType_Uint2, HLSLBaseType_Uint3, HLSLBaseType_Uint3,
HLSLBaseType_Uint3, HLSLBaseType_Uint2, HLSLBaseType_Uint3, HLSLBaseType_Uint3,
HLSLBaseType_Uint3, HLSLBaseType_Uint2, HLSLBaseType_Uint3, HLSLBaseType_Uint3
},
{ HLSLBaseType_Float4, HLSLBaseType_Float2, HLSLBaseType_Float3, HLSLBaseType_Float4,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Unknown, HLSLBaseType_Unknown, HLSLBaseType_Unknown,
HLSLBaseType_Uint4, HLSLBaseType_Uint2, HLSLBaseType_Uint3, HLSLBaseType_Uint4,
HLSLBaseType_Uint4, HLSLBaseType_Uint2, HLSLBaseType_Uint3, HLSLBaseType_Uint4,
HLSLBaseType_Uint4, HLSLBaseType_Uint2, HLSLBaseType_Uint3, HLSLBaseType_Uint4
},
};
const int _conditionalOpPriority = 1;
static const char* GetTypeName(const HLSLType& type)
{
if (type.baseType == HLSLBaseType_UserDefined)
{
return type.typeName;
}
else
{
return baseTypeDescriptions[type.baseType].typeName;
}
}
static const char* GetBinaryOpName(HLSLBinaryOp binaryOp)
{
switch (binaryOp)
{
case HLSLBinaryOp_And: return "&&";
case HLSLBinaryOp_Or: return "||";
case HLSLBinaryOp_Add: return "+";
case HLSLBinaryOp_Sub: return "-";
case HLSLBinaryOp_Mul: return "*";
case HLSLBinaryOp_Div: return "/";
case HLSLBinaryOp_Mod: return "%";
case HLSLBinaryOp_Less: return "<";
case HLSLBinaryOp_Greater: return ">";
case HLSLBinaryOp_LessEqual: return "<=";
case HLSLBinaryOp_GreaterEqual: return ">=";
case HLSLBinaryOp_Equal: return "==";
case HLSLBinaryOp_NotEqual: return "!=";
case HLSLBinaryOp_BitAnd: return "&";
case HLSLBinaryOp_BitOr: return "|";
case HLSLBinaryOp_BitXor: return "^";
case HLSLBinaryOp_Assign: return "=";
case HLSLBinaryOp_AddAssign: return "+=";
case HLSLBinaryOp_SubAssign: return "-=";
case HLSLBinaryOp_MulAssign: return "*=";
case HLSLBinaryOp_DivAssign: return "/=";
default:
ASSERT(0);
return "???";
}
}
static int GetTypeCastRank(HLSLTree * tree, const HLSLType& srcType, const HLSLType& dstType)
{
if (srcType.array != dstType.array)
{
return -1;
}
if (srcType.array == true)
{
ASSERT(dstType.array == true);
int srcArraySize = -1;
int dstArraySize = -1;
tree->GetExpressionValue(srcType.arraySize, srcArraySize);
tree->GetExpressionValue(dstType.arraySize, dstArraySize);
if (srcArraySize != dstArraySize) {
return -1;
}
}
if (srcType.baseType == HLSLBaseType_UserDefined && dstType.baseType == HLSLBaseType_UserDefined)
{
return strcmp(srcType.typeName, dstType.typeName) == 0 ? 0 : -1;
}
if (srcType.baseType == dstType.baseType)
{
if (IsSamplerType(srcType.baseType))
{
return srcType.samplerType == dstType.samplerType ? 0 : -1;
}
return 0;
}
const BaseTypeDescription& srcDesc = baseTypeDescriptions[srcType.baseType];
const BaseTypeDescription& dstDesc = baseTypeDescriptions[dstType.baseType];
if (srcDesc.numericType == NumericType_NaN || dstDesc.numericType == NumericType_NaN)
{
return -1;
}
int result = _numberTypeRank[srcDesc.numericType][dstDesc.numericType] << 3;
if (srcDesc.numDimensions == 0 && dstDesc.numDimensions > 0)
{
result |= (1 << 2);
}
else if ((srcDesc.numDimensions == dstDesc.numDimensions && (srcDesc.numComponents > dstDesc.numComponents || srcDesc.height > dstDesc.height)) ||
(srcDesc.numDimensions > 0 && dstDesc.numDimensions == 0))
{
result |= (1 << 6);
}
else if (srcDesc.numDimensions != dstDesc.numDimensions)
{
return -1;
}
else if (srcDesc.height != dstDesc.height)
{
result |= (1 << 1);
}
else if (srcDesc.numComponents != dstDesc.numComponents)
{
result |= (1 << 0);
}
return result;
}
static bool GetFunctionCallCastRanks(HLSLTree* tree, const HLSLFunctionCall* call, const HLSLFunction* function, int* rankBuffer)
{
if (function == NULL || function->numArguments < call->numArguments)
{
return false;
}
const HLSLExpression* expression = call->argument;
const HLSLArgument* argument = function->argument;
for (int i = 0; i < call->numArguments; ++i)
{
int rank = GetTypeCastRank(tree, expression->expressionType, argument->type);
if (rank == -1)
{
return false;
}
rankBuffer[i] = rank;
argument = argument->nextArgument;
expression = expression->nextExpression;
}
for (int i = call->numArguments; i < function->numArguments; ++i)
{
if (argument->defaultValue == NULL)
{
return false;
}
}
return true;
}
struct CompareRanks
{
bool operator() (const int& rank1, const int& rank2) { return rank1 > rank2; }
};
static CompareFunctionsResult CompareFunctions(HLSLTree* tree, const HLSLFunctionCall* call, const HLSLFunction* function1, const HLSLFunction* function2)
{
#if defined _WIN32 && !defined alloca
int* function1Ranks = static_cast<int*>(_alloca(sizeof(int) * call->numArguments));
int* function2Ranks = static_cast<int*>(_alloca(sizeof(int) * call->numArguments));
#else
int* function1Ranks = static_cast<int*>(alloca(sizeof(int) * call->numArguments));
int* function2Ranks = static_cast<int*>(alloca(sizeof(int) * call->numArguments));
#endif
const bool function1Viable = GetFunctionCallCastRanks(tree, call, function1, function1Ranks);
const bool function2Viable = GetFunctionCallCastRanks(tree, call, function2, function2Ranks);
if (!(function1Viable && function2Viable))
{
if (function1Viable)
{
return Function1Better;
}
else if (function2Viable)
{
return Function2Better;
}
else
{
return FunctionsEqual;
}
}
std::sort(function1Ranks, function1Ranks + call->numArguments, CompareRanks());
std::sort(function2Ranks, function2Ranks + call->numArguments, CompareRanks());
for (int i = 0; i < call->numArguments; ++i)
{
if (function1Ranks[i] < function2Ranks[i])
{
return Function1Better;
}
else if (function2Ranks[i] < function1Ranks[i])
{
return Function2Better;
}
}
return FunctionsEqual;
}
static bool GetBinaryOpResultType(HLSLBinaryOp binaryOp, const HLSLType& type1, const HLSLType& type2, HLSLType& result)
{
if (type1.baseType < HLSLBaseType_FirstNumeric || type1.baseType > HLSLBaseType_LastNumeric || type1.array ||
type2.baseType < HLSLBaseType_FirstNumeric || type2.baseType > HLSLBaseType_LastNumeric || type2.array)
{
return false;
}
if (binaryOp == HLSLBinaryOp_BitAnd || binaryOp == HLSLBinaryOp_BitOr || binaryOp == HLSLBinaryOp_BitXor)
{
if (type1.baseType < HLSLBaseType_FirstInteger || type1.baseType > HLSLBaseType_LastInteger)
{
return false;
}
}
switch (binaryOp)
{
case HLSLBinaryOp_And:
case HLSLBinaryOp_Or:
case HLSLBinaryOp_Less:
case HLSLBinaryOp_Greater:
case HLSLBinaryOp_LessEqual:
case HLSLBinaryOp_GreaterEqual:
case HLSLBinaryOp_Equal:
case HLSLBinaryOp_NotEqual:
{
int numComponents = std::max( baseTypeDescriptions[ type1.baseType ].numComponents, baseTypeDescriptions[ type2.baseType ].numComponents );
result.baseType = HLSLBaseType( HLSLBaseType_Bool + numComponents - 1 );
break;
}
case HLSLBinaryOp_Mod:
result.baseType = HLSLBaseType_Int;
break;
default:
result.baseType = _binaryOpTypeLookup[type1.baseType - HLSLBaseType_FirstNumeric][type2.baseType - HLSLBaseType_FirstNumeric];
break;
}
result.typeName = NULL;
result.array = false;
result.arraySize = NULL;
result.flags = (type1.flags & type2.flags) & HLSLTypeFlag_Const;
return result.baseType != HLSLBaseType_Unknown;
}
HLSLParser::HLSLParser(Allocator* allocator, HLSLTree* tree) :
m_userTypes(allocator),
m_variables(allocator),
m_functions(allocator),
m_macros(allocator)
{
m_numGlobals = 0;
m_tree = tree;
}
bool HLSLParser::Accept(int token)
{
if (m_tokenizer.GetToken() == token)
{
m_tokenizer.Next();
return true;
}
return false;
}
bool HLSLParser::Accept(const char* token)
{
if (m_tokenizer.GetToken() == HLSLToken_Identifier && String_Equal( token, m_tokenizer.GetIdentifier() ) )
{
m_tokenizer.Next();
return true;
}
return false;
}
bool HLSLParser::Expect(int token)
{
if (!Accept(token))
{
char want[HLSLTokenizer::s_maxIdentifier];
m_tokenizer.GetTokenName(token, want);
char near[HLSLTokenizer::s_maxIdentifier];
m_tokenizer.GetTokenName(near);
m_tokenizer.Error("Syntax error: expected '%s' near '%s'", want, near);
return false;
}
return true;
}
bool HLSLParser::Expect(const char * token)
{
if (!Accept(token))
{
const char * want = token;
char near[HLSLTokenizer::s_maxIdentifier];
m_tokenizer.GetTokenName(near);
m_tokenizer.Error("Syntax error: expected '%s' near '%s'", want, near);
return false;
}
return true;
}
bool HLSLParser::AcceptIdentifier(const char*& identifier)
{
if (m_tokenizer.GetToken() == HLSLToken_Identifier)
{
identifier = m_tree->AddString( m_tokenizer.GetIdentifier() );
m_tokenizer.Next();
return true;
}
return false;
}
bool HLSLParser::ExpectIdentifier(const char*& identifier)
{
if (!AcceptIdentifier(identifier))
{
char near[HLSLTokenizer::s_maxIdentifier];
m_tokenizer.GetTokenName(near);
m_tokenizer.Error("Syntax error: expected identifier near '%s'", near);
identifier = "";
return false;
}
return true;
}
bool HLSLParser::AcceptFloat(float& value)
{
if (m_tokenizer.GetToken() == HLSLToken_FloatLiteral)
{
value = m_tokenizer.GetFloat();
m_tokenizer.Next();
return true;
}
return false;
}
bool HLSLParser::AcceptInt(int& value)
{
if (m_tokenizer.GetToken() == HLSLToken_IntLiteral)
{
value = m_tokenizer.GetInt();
m_tokenizer.Next();
return true;
}
return false;
}
bool HLSLParser::ParseTopLevel(HLSLStatement*& statement)
{
HLSLAttribute * attributes = NULL;
ParseAttributeBlock(attributes);
int line = GetLineNumber();
const char* fileName = GetFileName();
HLSLType type;
bool doesNotExpectSemicolon = false;
if (Accept(HLSLToken_Struct))
{
const char* structName = NULL;
if (!ExpectIdentifier(structName))
{
return false;
}
if (FindUserDefinedType(structName) != NULL)
{
m_tokenizer.Error("struct %s already defined", structName);
return false;
}
if (!Expect('{'))
{
return false;
}
HLSLStruct* structure = m_tree->AddNode<HLSLStruct>(fileName, line);
structure->name = structName;
m_userTypes.PushBack(structure);
HLSLStructField* lastField = NULL;
while (!Accept('}'))
{
if (CheckForUnexpectedEndOfStream('}'))
{
return false;
}
HLSLStructField* field = NULL;
if (!ParseFieldDeclaration(field))
{
return false;
}
ASSERT(field != NULL);
if (lastField == NULL)
{
structure->field = field;
}
else
{
lastField->nextField = field;
}
lastField = field;
}
statement = structure;
}
else if (Accept(HLSLToken_CBuffer) || Accept(HLSLToken_TBuffer))
{
HLSLBuffer* buffer = m_tree->AddNode<HLSLBuffer>(fileName, line);
AcceptIdentifier(buffer->name);
if (Accept(':'))
{
if (!Expect(HLSLToken_Register) || !Expect('(') || !ExpectIdentifier(buffer->registerName) || !Expect(')'))
{
return false;
}
}
if (!Expect('{'))
{
return false;
}
HLSLDeclaration* lastField = NULL;
while (!Accept('}'))
{
if (CheckForUnexpectedEndOfStream('}'))
{
return false;
}
HLSLDeclaration* field = NULL;
if (!ParseDeclaration(field))
{
m_tokenizer.Error("Expected variable declaration");
return false;
}
DeclareVariable( field->name, field->type );
field->buffer = buffer;
if (buffer->field == NULL)
{
buffer->field = field;
}
else
{
lastField->nextStatement = field;
}
lastField = field;
if (!Expect(';')) {
return false;
}
}
statement = buffer;
}
else if (AcceptType(true, type))
{
const char* globalName = NULL;
if (!ExpectIdentifier(globalName))
{
return false;
}
if (Accept('('))
{
HLSLFunction* function = m_tree->AddNode<HLSLFunction>(fileName, line);
function->name = globalName;
function->returnType.baseType = type.baseType;
function->returnType.typeName = type.typeName;
function->attributes = attributes;
BeginScope();
if (!ParseArgumentList(function->argument, function->numArguments, function->numOutputArguments))
{
return false;
}
const HLSLFunction* declaration = FindFunction(function);
if (Accept(';'))
{
if (!declaration)
{
m_functions.PushBack( function );
statement = function;
}
EndScope();
return true;
}
if (Accept(':') && !ExpectIdentifier(function->semantic))
{
return false;
}
if (declaration)
{
if (declaration->forward || declaration->statement)
{
m_tokenizer.Error("Duplicate function definition");
return false;
}
const_cast<HLSLFunction*>(declaration)->forward = function;
}
else
{
m_functions.PushBack( function );
}
if (!Expect('{') || !ParseBlock(function->statement, function->returnType))
{
return false;
}
EndScope();
statement = function;
return true;
}
else
{
HLSLDeclaration * firstDeclaration = NULL;
HLSLDeclaration * lastDeclaration = NULL;
do {
if (firstDeclaration != NULL) {
if (!ExpectIdentifier(globalName))
{
return false;
}
}
HLSLDeclaration* declaration = m_tree->AddNode<HLSLDeclaration>(fileName, line);
declaration->name = globalName;
declaration->type = type;
if (Accept('['))
{
if (!Accept(']'))
{
if (!ParseExpression(declaration->type.arraySize) || !Expect(']'))
{
return false;
}
}
declaration->type.array = true;
}
if (Accept(':'))
{
if (AcceptIdentifier(declaration->semantic)) {
}
else if (!Expect(HLSLToken_Register) || !Expect('(') || !ExpectIdentifier(declaration->registerName) || !Expect(')'))
{
return false;
}
}
DeclareVariable( globalName, declaration->type );
if (!ParseDeclarationAssignment(declaration))
{
return false;
}
if (firstDeclaration == NULL) firstDeclaration = declaration;
if (lastDeclaration != NULL) lastDeclaration->nextDeclaration = declaration;
lastDeclaration = declaration;
} while(Accept(','));
statement = firstDeclaration;
}
}
else if (ParseTechnique(statement)) {
doesNotExpectSemicolon = true;
}
else if (ParsePipeline(statement)) {
doesNotExpectSemicolon = true;
}
else if (ParseStage(statement)) {
doesNotExpectSemicolon = true;
}
if (statement != NULL) {
statement->attributes = attributes;
}
return doesNotExpectSemicolon || Expect(';');
}
bool HLSLParser::ParseStatementOrBlock(HLSLStatement*& firstStatement, const HLSLType& returnType, bool scoped)
{
if (scoped)
{
BeginScope();
}
if (Accept('{'))
{
if (!ParseBlock(firstStatement, returnType))
{
return false;
}
}
else
{
if (!ParseStatement(firstStatement, returnType))
{
return false;
}
}
if (scoped)
{
EndScope();
}
return true;
}
bool HLSLParser::ParseBlock(HLSLStatement*& firstStatement, const HLSLType& returnType)
{
HLSLStatement* lastStatement = NULL;
while (!Accept('}'))
{
if (CheckForUnexpectedEndOfStream('}'))
{
return false;
}
HLSLStatement* statement = NULL;
if (!ParseStatement(statement, returnType))
{
return false;
}
if (statement != NULL)
{
if (firstStatement == NULL)
{
firstStatement = statement;
}
else
{
lastStatement->nextStatement = statement;
}
lastStatement = statement;
while (lastStatement->nextStatement) lastStatement = lastStatement->nextStatement;
}
}
return true;
}
bool HLSLParser::ParseStatement(HLSLStatement*& statement, const HLSLType& returnType)
{
const char* fileName = GetFileName();
int line = GetLineNumber();
if (Accept(';'))
{
return true;
}
HLSLAttribute * attributes = NULL;
ParseAttributeBlock(attributes);
#if 0#endif
if (Accept(HLSLToken_If))
{
HLSLIfStatement* ifStatement = m_tree->AddNode<HLSLIfStatement>(fileName, line);
ifStatement->attributes = attributes;
if (!Expect('(') || !ParseExpression(ifStatement->condition) || !Expect(')'))
{
return false;
}
statement = ifStatement;
if (!ParseStatementOrBlock(ifStatement->statement, returnType))
{
return false;
}
if (Accept(HLSLToken_Else))
{
return ParseStatementOrBlock(ifStatement->elseStatement, returnType);
}
return true;
}
if (Accept(HLSLToken_For))
{
HLSLForStatement* forStatement = m_tree->AddNode<HLSLForStatement>(fileName, line);
forStatement->attributes = attributes;
if (!Expect('('))
{
return false;
}
BeginScope();
if (!ParseDeclaration(forStatement->initialization) && !ParseExpression(forStatement->initializationWithoutType))
{
return false;
}
if (!Expect(';'))
{
return false;
}
ParseExpression(forStatement->condition);
if (!Expect(';'))
{
return false;
}
ParseExpression(forStatement->increment);
if (!Expect(')'))
{
return false;
}
statement = forStatement;
if (!ParseStatementOrBlock(forStatement->statement, returnType))
{
return false;
}
EndScope();
return true;
}
if (Accept(HLSLToken_While))
{
HLSLWhileStatement* whileStatement = m_tree->AddNode<HLSLWhileStatement>(fileName, line);
whileStatement->attributes = attributes;
if (!Expect('(') || !ParseExpression(whileStatement->condition) || !Expect(')'))
{
return false;
}
statement = whileStatement;
if (!ParseStatementOrBlock(whileStatement->statement, returnType))
{
return false;
}
return true;
}
if (attributes != NULL)
{
}
if (Accept('{'))
{
HLSLBlockStatement* blockStatement = m_tree->AddNode<HLSLBlockStatement>(fileName, line);
statement = blockStatement;
BeginScope();
bool success = ParseBlock(blockStatement->statement, returnType);
EndScope();
return success;
}
if (Accept(HLSLToken_Discard))
{
HLSLDiscardStatement* discardStatement = m_tree->AddNode<HLSLDiscardStatement>(fileName, line);
statement = discardStatement;
return Expect(';');
}
if (Accept(HLSLToken_Break))
{
HLSLBreakStatement* breakStatement = m_tree->AddNode<HLSLBreakStatement>(fileName, line);
statement = breakStatement;
return Expect(';');
}
if (Accept(HLSLToken_Continue))
{
HLSLContinueStatement* continueStatement = m_tree->AddNode<HLSLContinueStatement>(fileName, line);
statement = continueStatement;
return Expect(';');
}
if (Accept(HLSLToken_Return))
{
HLSLReturnStatement* returnStatement = m_tree->AddNode<HLSLReturnStatement>(fileName, line);
if (!Accept(';') && !ParseExpression(returnStatement->expression))
{
return false;
}
HLSLType voidType(HLSLBaseType_Void);
if (!CheckTypeCast(returnStatement->expression ? returnStatement->expression->expressionType : voidType, returnType))
{
return false;
}
statement = returnStatement;
return Expect(';');
}
HLSLDeclaration* declaration = NULL;
HLSLExpression* expression = NULL;
if (ParseDeclaration(declaration))
{
statement = declaration;
}
else if (ParseExpression(expression))
{
HLSLExpressionStatement* expressionStatement;
expressionStatement = m_tree->AddNode<HLSLExpressionStatement>(fileName, line);
expressionStatement->expression = expression;
statement = expressionStatement;
}
if (Accept(',')) {
return true;
}
return Expect(';');
}
bool HLSLParser::ParseDeclaration(HLSLDeclaration*& declaration)
{
const char* fileName = GetFileName();
int line = GetLineNumber();
HLSLType type;
if (!AcceptType(false, type))
{
return false;
}
bool allowUnsizedArray = true;
HLSLDeclaration * firstDeclaration = NULL;
HLSLDeclaration * lastDeclaration = NULL;
do {
const char* name;
if (!ExpectIdentifier(name))
{
return false;
}
if (Accept('['))
{
type.array = true;
if (Accept(']') && allowUnsizedArray)
{
return true;
}
if (!ParseExpression(type.arraySize) || !Expect(']'))
{
return false;
}
}
HLSLDeclaration * declaration2 = m_tree->AddNode<HLSLDeclaration>(fileName, line);
declaration2->type = type;
declaration2->name = name;
DeclareVariable( declaration2->name, declaration2->type );
if (!ParseDeclarationAssignment( declaration2 )) {
return false;
}
if (firstDeclaration == NULL) firstDeclaration = declaration2;
if (lastDeclaration != NULL) lastDeclaration->nextDeclaration = declaration2;
lastDeclaration = declaration2;
} while(Accept(','));
declaration = firstDeclaration;
return true;
}
bool HLSLParser::ParseDeclarationAssignment(HLSLDeclaration* declaration)
{
if (Accept('='))
{
if (declaration->type.array)
{
int numValues = 0;
if (!Expect('{') || !ParseExpressionList('}', true, declaration->assignment, numValues))
{
return false;
}
}
else if (IsSamplerType(declaration->type.baseType))
{
if (!ParseSamplerState(declaration->assignment))
{
return false;
}
}
else if (!ParseExpression(declaration->assignment))
{
return false;
}
}
return true;
}
bool HLSLParser::ParseFieldDeclaration(HLSLStructField*& field)
{
field = m_tree->AddNode<HLSLStructField>( GetFileName(), GetLineNumber() );
if (!ExpectDeclaration(false, field->type, field->name))
{
return false;
}
if (Accept(':'))
{
if (!ExpectIdentifier(field->semantic))
{
return false;
}
}
return Expect(';');
}
bool HLSLParser::CheckTypeCast(const HLSLType& srcType, const HLSLType& dstType)
{
if (GetTypeCastRank(m_tree, srcType, dstType) == -1)
{
const char* srcTypeName = GetTypeName(srcType);
const char* dstTypeName = GetTypeName(dstType);
m_tokenizer.Error("Cannot implicitly convert from '%s' to '%s'", srcTypeName, dstTypeName);
return false;
}
return true;
}
bool HLSLParser::ParseExpression(HLSLExpression*& expression)
{
if (!ParseBinaryExpression(0, expression))
{
return false;
}
HLSLBinaryOp assignOp;
if (AcceptAssign(assignOp))
{
HLSLExpression* expression2 = NULL;
if (!ParseExpression(expression2))
{
return false;
}
HLSLBinaryExpression* binaryExpression = m_tree->AddNode<HLSLBinaryExpression>(expression->fileName, expression->line);
binaryExpression->binaryOp = assignOp;
binaryExpression->expression1 = expression;
binaryExpression->expression2 = expression2;
binaryExpression->expressionType = expression->expressionType;
if (!CheckTypeCast(expression2->expressionType, expression->expressionType))
{
const char* srcTypeName = GetTypeName(expression2->expressionType);
const char* dstTypeName = GetTypeName(expression->expressionType);
m_tokenizer.Error("Cannot implicitly convert from '%s' to '%s'", srcTypeName, dstTypeName);
return false;
}
expression = binaryExpression;
}
return true;
}
bool HLSLParser::AcceptBinaryOperator(int priority, HLSLBinaryOp& binaryOp)
{
int token = m_tokenizer.GetToken();
switch (token)
{
case HLSLToken_AndAnd: binaryOp = HLSLBinaryOp_And; break;
case HLSLToken_BarBar: binaryOp = HLSLBinaryOp_Or; break;
case '+': binaryOp = HLSLBinaryOp_Add; break;
case '-': binaryOp = HLSLBinaryOp_Sub; break;
case '*': binaryOp = HLSLBinaryOp_Mul; break;
case '/': binaryOp = HLSLBinaryOp_Div; break;
case '%': binaryOp = HLSLBinaryOp_Mod; break;
case '<': binaryOp = HLSLBinaryOp_Less; break;
case '>': binaryOp = HLSLBinaryOp_Greater; break;
case HLSLToken_LessEqual: binaryOp = HLSLBinaryOp_LessEqual; break;
case HLSLToken_GreaterEqual: binaryOp = HLSLBinaryOp_GreaterEqual; break;
case HLSLToken_EqualEqual: binaryOp = HLSLBinaryOp_Equal; break;
case HLSLToken_NotEqual: binaryOp = HLSLBinaryOp_NotEqual; break;
case '&': binaryOp = HLSLBinaryOp_BitAnd; break;
case '|': binaryOp = HLSLBinaryOp_BitOr; break;
case '^': binaryOp = HLSLBinaryOp_BitXor; break;
default:
return false;
}
if (_binaryOpPriority[binaryOp] > priority)
{
m_tokenizer.Next();
return true;
}
return false;
}
bool HLSLParser::AcceptUnaryOperator(bool pre, HLSLUnaryOp& unaryOp)
{
int token = m_tokenizer.GetToken();
if (token == HLSLToken_PlusPlus)
{
unaryOp = pre ? HLSLUnaryOp_PreIncrement : HLSLUnaryOp_PostIncrement;
}
else if (token == HLSLToken_MinusMinus)
{
unaryOp = pre ? HLSLUnaryOp_PreDecrement : HLSLUnaryOp_PostDecrement;
}
else if (pre && token == '-')
{
unaryOp = HLSLUnaryOp_Negative;
}
else if (pre && token == '+')
{
unaryOp = HLSLUnaryOp_Positive;
}
else if (pre && token == '!')
{
unaryOp = HLSLUnaryOp_Not;
}
else if (pre && token == '~')
{
unaryOp = HLSLUnaryOp_Not;
}
else
{
return false;
}
m_tokenizer.Next();
return true;
}
bool HLSLParser::AcceptAssign(HLSLBinaryOp& binaryOp)
{
if (Accept('='))
{
binaryOp = HLSLBinaryOp_Assign;
}
else if (Accept(HLSLToken_PlusEqual))
{
binaryOp = HLSLBinaryOp_AddAssign;
}
else if (Accept(HLSLToken_MinusEqual))
{
binaryOp = HLSLBinaryOp_SubAssign;
}
else if (Accept(HLSLToken_TimesEqual))
{
binaryOp = HLSLBinaryOp_MulAssign;
}
else if (Accept(HLSLToken_DivideEqual))
{
binaryOp = HLSLBinaryOp_DivAssign;
}
else
{
return false;
}
return true;
}
bool HLSLParser::ParseBinaryExpression(int priority, HLSLExpression*& expression)
{
const char* fileName = GetFileName();
int line = GetLineNumber();
char needsExpressionEndChar;
if (!ParseTerminalExpression(expression, needsExpressionEndChar))
{
return false;
}
if( needsExpressionEndChar != 0 )
priority = 0;
bool acceptBinaryOp = false;
HLSLBinaryOp binaryOp;
while (1)
{
if (acceptBinaryOp || AcceptBinaryOperator(priority, binaryOp))
{
acceptBinaryOp = false;
HLSLExpression* expression2 = NULL;
ASSERT( binaryOp < sizeof(_binaryOpPriority) / sizeof(int) );
if (!ParseBinaryExpression(_binaryOpPriority[binaryOp], expression2))
{
return false;
}
HLSLBinaryExpression* binaryExpression = m_tree->AddNode<HLSLBinaryExpression>(fileName, line);
binaryExpression->binaryOp = binaryOp;
binaryExpression->expression1 = expression;
binaryExpression->expression2 = expression2;
if (!GetBinaryOpResultType( binaryOp, expression->expressionType, expression2->expressionType, binaryExpression->expressionType ))
{
const char* typeName1 = GetTypeName( binaryExpression->expression1->expressionType );
const char* typeName2 = GetTypeName( binaryExpression->expression2->expressionType );
m_tokenizer.Error("binary '%s' : no global operator found which takes types '%s' and '%s' (or there is no acceptable conversion)",
GetBinaryOpName(binaryOp), typeName1, typeName2);
return false;
}
binaryExpression->expressionType.flags = (expression->expressionType.flags | expression2->expressionType.flags) & HLSLTypeFlag_Const;
expression = binaryExpression;
}
else if (_conditionalOpPriority > priority && Accept('?'))
{
HLSLConditionalExpression* conditionalExpression = m_tree->AddNode<HLSLConditionalExpression>(fileName, line);
conditionalExpression->condition = expression;
HLSLExpression* expression1 = NULL;
HLSLExpression* expression2 = NULL;
if (!ParseBinaryExpression(_conditionalOpPriority, expression1) || !Expect(':') || !ParseBinaryExpression(_conditionalOpPriority, expression2))
{
return false;
}
if (GetTypeCastRank(m_tree, expression1->expressionType, expression2->expressionType) == -1)
{
const char* srcTypeName = GetTypeName(expression2->expressionType);
const char* dstTypeName = GetTypeName(expression1->expressionType);
m_tokenizer.Error("':' no possible conversion from '%s' to '%s'", srcTypeName, dstTypeName);
return false;
}
conditionalExpression->trueExpression = expression1;
conditionalExpression->falseExpression = expression2;
conditionalExpression->expressionType = expression1->expressionType;
expression = conditionalExpression;
}
else
{
break;
}
if (AcceptBinaryOperator(priority, binaryOp))
{
acceptBinaryOp = true;
continue;
}
if( needsExpressionEndChar != 0 )
{
if( !Expect(needsExpressionEndChar) )
return false;
needsExpressionEndChar = 0;
}
}
return needsExpressionEndChar == 0 || Expect(needsExpressionEndChar);
}
bool HLSLParser::ParsePartialConstructor(HLSLExpression*& expression, HLSLBaseType type, const char* typeName)
{
const char* fileName = GetFileName();
int line = GetLineNumber();
HLSLConstructorExpression* constructorExpression = m_tree->AddNode<HLSLConstructorExpression>(fileName, line);
constructorExpression->type.baseType = type;
constructorExpression->type.typeName = typeName;
int numArguments = 0;
if (!ParseExpressionList(')', false, constructorExpression->argument, numArguments))
{
return false;
}
constructorExpression->expressionType = constructorExpression->type;
constructorExpression->expressionType.flags = HLSLTypeFlag_Const;
expression = constructorExpression;
return true;
}
bool HLSLParser::ParseTerminalExpression(HLSLExpression*& expression, char& needsExpressionEndChar)
{
const char* fileName = GetFileName();
int line = GetLineNumber();
needsExpressionEndChar = 0;
HLSLUnaryOp unaryOp;
if (AcceptUnaryOperator(true, unaryOp))
{
HLSLUnaryExpression* unaryExpression = m_tree->AddNode<HLSLUnaryExpression>(fileName, line);
unaryExpression->unaryOp = unaryOp;
if (!ParseTerminalExpression(unaryExpression->expression, needsExpressionEndChar))
{
return false;
}
if (unaryOp == HLSLUnaryOp_BitNot)
{
if (unaryExpression->expression->expressionType.baseType < HLSLBaseType_FirstInteger ||
unaryExpression->expression->expressionType.baseType > HLSLBaseType_LastInteger)
{
const char * typeName = GetTypeName(unaryExpression->expression->expressionType);
m_tokenizer.Error("unary '~' : no global operator found which takes type '%s' (or there is no acceptable conversion)", typeName);
return false;
}
}
if (unaryOp == HLSLUnaryOp_Not)
{
if (unaryExpression->expression->expressionType.baseType != HLSLBaseType_Bool)
{
HLSLCastingExpression* castingExpression = m_tree->AddNode<HLSLCastingExpression>(fileName, line);
castingExpression->type.baseType = HLSLBaseType_Bool;
castingExpression->expression = unaryExpression->expression;
castingExpression->expressionType.baseType = HLSLBaseType_Bool;
unaryExpression->expression = castingExpression;
expression = unaryExpression;
}
unaryExpression->expressionType = HLSLType(HLSLBaseType_Bool);
unaryExpression->expressionType.flags = unaryExpression->expression->expressionType.flags & HLSLTypeFlag_Const;
}
if (unaryOp == HLSLUnaryOp_Negative || unaryOp == HLSLUnaryOp_Positive)
{
if (unaryExpression->expression->expressionType.baseType <= HLSLBaseType_Bool4 &&
unaryExpression->expression->expressionType.baseType >= HLSLBaseType_Bool)
{
int numComponents = baseTypeDescriptions[ unaryExpression->expression->expressionType.baseType ].numComponents;
HLSLBaseType baseType = HLSLBaseType( HLSLBaseType_Int + numComponents - 1 );
unaryExpression->expressionType = unaryExpression->expression->expressionType;
HLSLCastingExpression* castingExpression = m_tree->AddNode<HLSLCastingExpression>(fileName, line);
castingExpression->type.baseType = baseType;
castingExpression->expression = unaryExpression->expression;
castingExpression->expressionType.baseType = baseType;
unaryExpression->expression = castingExpression;
expression = unaryExpression;
}
else
{
unaryExpression->expressionType = unaryExpression->expression->expressionType;
}
}
else
{
unaryExpression->expressionType = unaryExpression->expression->expressionType;
}
expression = unaryExpression;
return true;
}
char expressionEndChar = 0;
if (Accept('('))
{
expressionEndChar = ')';
}
else if (Accept('{'))
{
expressionEndChar = '}';
}
if (expressionEndChar != 0)
{
HLSLType type;
if (AcceptType(false, type))
{
if (Accept('('))
{
needsExpressionEndChar = expressionEndChar;
return ParsePartialConstructor(expression, type.baseType, type.typeName);
}
HLSLCastingExpression* castingExpression = m_tree->AddNode<HLSLCastingExpression>(fileName, line);
castingExpression->type = type;
expression = castingExpression;
castingExpression->expressionType = type;
return Expect(')') && ParseExpression(castingExpression->expression);
}
int numArguments = 0;
if (!ParseExpressionList(expressionEndChar, false, expression, numArguments))
{
return false;
}
if (expressionEndChar == ')')
{
HLSLExpression* lastExpression = expression;
while(lastExpression->nextExpression != NULL) {
lastExpression = lastExpression->nextExpression;
}
}
}
else
{
float fValue = 0.0f;
int iValue = 0;
if (AcceptFloat(fValue))
{
HLSLLiteralExpression* literalExpression = m_tree->AddNode<HLSLLiteralExpression>(fileName, line);
literalExpression->type = HLSLBaseType_Float;
literalExpression->fValue = fValue;
literalExpression->expressionType.baseType = literalExpression->type;
literalExpression->expressionType.flags = HLSLTypeFlag_Const;
expression = literalExpression;
return true;
}
else if (AcceptInt(iValue))
{
HLSLLiteralExpression* literalExpression = m_tree->AddNode<HLSLLiteralExpression>(fileName, line);
literalExpression->type = HLSLBaseType_Int;
literalExpression->iValue = iValue;
literalExpression->expressionType.baseType = literalExpression->type;
literalExpression->expressionType.flags = HLSLTypeFlag_Const;
expression = literalExpression;
return true;
}
else if (Accept(HLSLToken_True))
{
HLSLLiteralExpression* literalExpression = m_tree->AddNode<HLSLLiteralExpression>(fileName, line);
literalExpression->type = HLSLBaseType_Bool;
literalExpression->bValue = true;
literalExpression->expressionType.baseType = literalExpression->type;
literalExpression->expressionType.flags = HLSLTypeFlag_Const;
expression = literalExpression;
return true;
}
else if (Accept(HLSLToken_False))
{
HLSLLiteralExpression* literalExpression = m_tree->AddNode<HLSLLiteralExpression>(fileName, line);
literalExpression->type = HLSLBaseType_Bool;
literalExpression->bValue = false;
literalExpression->expressionType.baseType = literalExpression->type;
literalExpression->expressionType.flags = HLSLTypeFlag_Const;
expression = literalExpression;
return true;
}
HLSLType type;
if (AcceptType(false, type))
{
Expect('(');
if (!ParsePartialConstructor(expression, type.baseType, type.typeName))
{
return false;
}
}
else
{
HLSLIdentifierExpression* identifierExpression = m_tree->AddNode<HLSLIdentifierExpression>(fileName, line);
if (!ExpectIdentifier(identifierExpression->name))
{
return false;
}
bool undeclaredIdentifier = false;
const HLSLType* identifierType = FindVariable(identifierExpression->name, identifierExpression->global);
if (identifierType != NULL)
{
identifierExpression->expressionType = *identifierType;
}
else
{
if (GetIsFunction(identifierExpression->name))
{
identifierExpression->global = true;
}
else
{
undeclaredIdentifier = true;
}
}
if (undeclaredIdentifier)
{
if (m_allowUndeclaredIdentifiers)
{
HLSLLiteralExpression* literalExpression = m_tree->AddNode<HLSLLiteralExpression>(fileName, line);
literalExpression->bValue = false;
literalExpression->type = HLSLBaseType_Bool;
literalExpression->expressionType.baseType = literalExpression->type;
literalExpression->expressionType.flags = HLSLTypeFlag_Const;
expression = literalExpression;
}
else
{
m_tokenizer.Error("Undeclared identifier '%s'", identifierExpression->name);
return false;
}
}
else {
expression = identifierExpression;
}
}
}
bool done = false;
while (!done)
{
done = true;
HLSLUnaryOp unaryOp2;
while (AcceptUnaryOperator(false, unaryOp2))
{
HLSLUnaryExpression* unaryExpression = m_tree->AddNode<HLSLUnaryExpression>(fileName, line);
unaryExpression->unaryOp = unaryOp2;
unaryExpression->expression = expression;
unaryExpression->expressionType = unaryExpression->expression->expressionType;
expression = unaryExpression;
done = false;
}
while (Accept('.'))
{
HLSLMemberAccess* memberAccess = m_tree->AddNode<HLSLMemberAccess>(fileName, line);
memberAccess->object = expression;
if (!ExpectIdentifier(memberAccess->field))
{
return false;
}
if (!GetMemberType( expression->expressionType, memberAccess))
{
m_tokenizer.Error("Couldn't access '%s'", memberAccess->field);
return false;
}
expression = memberAccess;
done = false;
}
while (Accept('['))
{
HLSLArrayAccess* arrayAccess = m_tree->AddNode<HLSLArrayAccess>(fileName, line);
arrayAccess->array = expression;
if (!ParseExpression(arrayAccess->index) || !Expect(']'))
{
return false;
}
if (expression->expressionType.array)
{
arrayAccess->expressionType = expression->expressionType;
arrayAccess->expressionType.array = false;
arrayAccess->expressionType.arraySize = NULL;
}
else
{
switch (expression->expressionType.baseType)
{
case HLSLBaseType_Float2:
case HLSLBaseType_Float3:
case HLSLBaseType_Float4:
arrayAccess->expressionType.baseType = HLSLBaseType_Float;
break;
case HLSLBaseType_Float4x4:
case HLSLBaseType_Float3x4:
case HLSLBaseType_Float2x4:
arrayAccess->expressionType.baseType = HLSLBaseType_Float4;
break;
case HLSLBaseType_Float4x3:
case HLSLBaseType_Float3x3:
case HLSLBaseType_Float2x3:
arrayAccess->expressionType.baseType = HLSLBaseType_Float3;
break;
case HLSLBaseType_Float4x2:
case HLSLBaseType_Float3x2:
case HLSLBaseType_Float2x2:
arrayAccess->expressionType.baseType = HLSLBaseType_Float2;
break;
case HLSLBaseType_Bool2:
case HLSLBaseType_Bool3:
case HLSLBaseType_Bool4:
arrayAccess->expressionType.baseType = HLSLBaseType_Bool;
break;
case HLSLBaseType_Int2:
case HLSLBaseType_Int3:
case HLSLBaseType_Int4:
arrayAccess->expressionType.baseType = HLSLBaseType_Int;
break;
case HLSLBaseType_Uint2:
case HLSLBaseType_Uint3:
case HLSLBaseType_Uint4:
arrayAccess->expressionType.baseType = HLSLBaseType_Uint;
break;
default:
m_tokenizer.Error("array, matrix, vector, or indexable object type expected in index expression");
return false;
}
}
expression = arrayAccess;
done = false;
}
if (Accept('('))
{
HLSLFunctionCall* functionCall = m_tree->AddNode<HLSLFunctionCall>(fileName, line);
done = false;
if (!ParseExpressionList(')', false, functionCall->argument, functionCall->numArguments))
{
return false;
}
if (expression->nodeType != HLSLNodeType_IdentifierExpression)
{
m_tokenizer.Error("Expected function identifier");
return false;
}
const HLSLIdentifierExpression* identifierExpression = static_cast<const HLSLIdentifierExpression*>(expression);
const HLSLFunction* function = MatchFunctionCall( functionCall, identifierExpression->name );
if (function == NULL)
{
return false;
}
functionCall->function = function;
functionCall->expressionType = function->returnType;
expression = functionCall;
}
}
return true;
}
bool HLSLParser::ParseExpressionList(int endToken, bool allowEmptyEnd, HLSLExpression*& firstExpression, int& numExpressions)
{
numExpressions = 0;
HLSLExpression* lastExpression = NULL;
while (!Accept(endToken))
{
if (CheckForUnexpectedEndOfStream(endToken))
{
return false;
}
if (numExpressions > 0 && !Expect(','))
{
return false;
}
if (allowEmptyEnd && Accept(endToken))
{
break;
}
HLSLExpression* expression = NULL;
if (!ParseExpression(expression))
{
return false;
}
if (firstExpression == NULL)
{
firstExpression = expression;
}
else
{
lastExpression->nextExpression = expression;
}
lastExpression = expression;
++numExpressions;
}
return true;
}
bool HLSLParser::ParseArgumentList(HLSLArgument*& firstArgument, int& numArguments, int& numOutputArguments)
{
const char* fileName = GetFileName();
int line = GetLineNumber();
HLSLArgument* lastArgument = NULL;
numArguments = 0;
while (!Accept(')'))
{
if (CheckForUnexpectedEndOfStream(')'))
{
return false;
}
if (numArguments > 0 && !Expect(','))
{
return false;
}
HLSLArgument* argument = m_tree->AddNode<HLSLArgument>(fileName, line);
if (Accept(HLSLToken_Uniform)) { argument->modifier = HLSLArgumentModifier_Uniform; }
else if (Accept(HLSLToken_In)) { argument->modifier = HLSLArgumentModifier_In; }
else if (Accept(HLSLToken_Out)) { argument->modifier = HLSLArgumentModifier_Out; }
else if (Accept(HLSLToken_InOut)) { argument->modifier = HLSLArgumentModifier_Inout; }
else if (Accept(HLSLToken_Const)) { argument->modifier = HLSLArgumentModifier_Const; }
if (!ExpectDeclaration(true, argument->type, argument->name))
{
return false;
}
DeclareVariable( argument->name, argument->type );
if (Accept(':') && !ExpectIdentifier(argument->semantic))
{
return false;
}
if (Accept('=') && !ParseExpression(argument->defaultValue))
{
return false;
}
if (lastArgument != NULL)
{
lastArgument->nextArgument = argument;
}
else
{
firstArgument = argument;
}
lastArgument = argument;
++numArguments;
if (argument->modifier == HLSLArgumentModifier_Out || argument->modifier == HLSLArgumentModifier_Inout)
{
++numOutputArguments;
}
}
return true;
}
bool HLSLParser::ParseSamplerState(HLSLExpression*& expression)
{
if (!Expect(HLSLToken_SamplerState))
{
return false;
}
const char* fileName = GetFileName();
int line = GetLineNumber();
HLSLSamplerState* samplerState = m_tree->AddNode<HLSLSamplerState>(fileName, line);
if (!Expect('{'))
{
return false;
}
HLSLStateAssignment* lastStateAssignment = NULL;
while (!Accept('}'))
{
if (CheckForUnexpectedEndOfStream('}'))
{
return false;
}
HLSLStateAssignment* stateAssignment = NULL;
if (!ParseStateAssignment(stateAssignment, true, false))
{
return false;
}
ASSERT(stateAssignment != NULL);
if (lastStateAssignment == NULL)
{
samplerState->stateAssignments = stateAssignment;
}
else
{
lastStateAssignment->nextStateAssignment = stateAssignment;
}
lastStateAssignment = stateAssignment;
samplerState->numStateAssignments++;
}
expression = samplerState;
return true;
}
bool HLSLParser::ParseTechnique(HLSLStatement*& statement)
{
if (!Accept(HLSLToken_Technique)) {
return false;
}
const char* techniqueName = NULL;
if (!ExpectIdentifier(techniqueName))
{
return false;
}
if (!Expect('{'))
{
return false;
}
HLSLTechnique* technique = m_tree->AddNode<HLSLTechnique>(GetFileName(), GetLineNumber());
technique->name = techniqueName;
HLSLPass* lastPass = NULL;
while (!Accept('}'))
{
if (CheckForUnexpectedEndOfStream('}'))
{
return false;
}
HLSLPass* pass = NULL;
if (!ParsePass(pass))
{
return false;
}
ASSERT(pass != NULL);
if (lastPass == NULL)
{
technique->passes = pass;
}
else
{
lastPass->nextPass = pass;
}
lastPass = pass;
technique->numPasses++;
}
statement = technique;
return true;
}
bool HLSLParser::ParsePass(HLSLPass*& pass)
{
if (!Accept(HLSLToken_Pass)) {
return false;
}
const char* passName = NULL;
AcceptIdentifier(passName);
if (!Expect('{'))
{
return false;
}
const char* fileName = GetFileName();
int line = GetLineNumber();
pass = m_tree->AddNode<HLSLPass>(fileName, line);
pass->name = passName;
HLSLStateAssignment* lastStateAssignment = NULL;
while (!Accept('}'))
{
if (CheckForUnexpectedEndOfStream('}'))
{
return false;
}
HLSLStateAssignment* stateAssignment = NULL;
if (!ParseStateAssignment(stateAssignment, false, false))
{
return false;
}
ASSERT(stateAssignment != NULL);
if (lastStateAssignment == NULL)
{
pass->stateAssignments = stateAssignment;
}
else
{
lastStateAssignment->nextStateAssignment = stateAssignment;
}
lastStateAssignment = stateAssignment;
pass->numStateAssignments++;
}
return true;
}
bool HLSLParser::ParsePipeline(HLSLStatement*& statement)
{
if (!Accept("pipeline")) {
return false;
}
const char* pipelineName = NULL;
AcceptIdentifier(pipelineName);
if (!Expect('{'))
{
return false;
}
HLSLPipeline* pipeline = m_tree->AddNode<HLSLPipeline>(GetFileName(), GetLineNumber());
pipeline->name = pipelineName;
HLSLStateAssignment* lastStateAssignment = NULL;
while (!Accept('}'))
{
if (CheckForUnexpectedEndOfStream('}'))
{
return false;
}
HLSLStateAssignment* stateAssignment = NULL;
if (!ParseStateAssignment(stateAssignment, false, true))
{
return false;
}
ASSERT(stateAssignment != NULL);
if (lastStateAssignment == NULL)
{
pipeline->stateAssignments = stateAssignment;
}
else
{
lastStateAssignment->nextStateAssignment = stateAssignment;
}
lastStateAssignment = stateAssignment;
pipeline->numStateAssignments++;
}
statement = pipeline;
return true;
}
const EffectState* GetEffectState(const char* name, bool isSamplerState, bool isPipeline)
{
const EffectState* validStates = effectStates;
int count = sizeof(effectStates)/sizeof(effectStates[0]);
if (isPipeline)
{
validStates = pipelineStates;
count = sizeof(pipelineStates) / sizeof(pipelineStates[0]);
}
if (isSamplerState)
{
validStates = samplerStates;
count = sizeof(samplerStates)/sizeof(samplerStates[0]);
}
for (int i = 0; i < count; i++)
{
if (String_EqualNoCase(name, validStates[i].name))
{
return &validStates[i];
}
}
return NULL;
}
static const EffectStateValue* GetStateValue(const char* name, const EffectState* state)
{
for (int i = 0; ; i++)
{
const EffectStateValue & value = state->values[i];
if (value.name == NULL) break;
if (String_EqualNoCase(name, value.name))
{
return &value;
}
}
return NULL;
}
bool HLSLParser::ParseStateName(bool isSamplerState, bool isPipelineState, const char*& name, const EffectState *& state)
{
if (m_tokenizer.GetToken() != HLSLToken_Identifier)
{
char near[HLSLTokenizer::s_maxIdentifier];
m_tokenizer.GetTokenName(near);
m_tokenizer.Error("Syntax error: expected identifier near '%s'", near);
return false;
}
state = GetEffectState(m_tokenizer.GetIdentifier(), isSamplerState, isPipelineState);
if (state == NULL)
{
m_tokenizer.Error("Syntax error: unexpected identifier '%s'", m_tokenizer.GetIdentifier());
return false;
}
m_tokenizer.Next();
return true;
}
bool HLSLParser::ParseColorMask(int& mask)
{
mask = 0;
do {
if (m_tokenizer.GetToken() == HLSLToken_IntLiteral) {
mask |= m_tokenizer.GetInt();
}
else if (m_tokenizer.GetToken() == HLSLToken_Identifier) {
const char * ident = m_tokenizer.GetIdentifier();
const EffectStateValue * stateValue = colorMaskValues;
while (stateValue->name != NULL) {
if (String_EqualNoCase(stateValue->name, ident)) {
mask |= stateValue->value;
break;
}
++stateValue;
}
}
else {
return false;
}
m_tokenizer.Next();
} while (Accept('|'));
return true;
}
bool HLSLParser::ParseStateValue(const EffectState * state, HLSLStateAssignment* stateAssignment)
{
const bool expectsExpression = state->values == colorMaskValues;
const bool expectsInteger = state->values == integerValues;
const bool expectsFloat = state->values == floatValues;
const bool expectsBoolean = state->values == booleanValues;
if (!expectsExpression && !expectsInteger && !expectsFloat && !expectsBoolean)
{
if (m_tokenizer.GetToken() != HLSLToken_Identifier)
{
char near[HLSLTokenizer::s_maxIdentifier];
m_tokenizer.GetTokenName(near);
m_tokenizer.Error("Syntax error: expected identifier near '%s'", near);
stateAssignment->iValue = 0;
return false;
}
}
if (state->values == NULL)
{
if (strcmp(m_tokenizer.GetIdentifier(), "compile") != 0)
{
m_tokenizer.Error("Syntax error: unexpected identifier '%s' expected compile statement", m_tokenizer.GetIdentifier());
stateAssignment->iValue = 0;
return false;
}
while(m_tokenizer.GetToken() != ';')
{
m_tokenizer.Next();
}
}
else {
if (expectsInteger)
{
if (!AcceptInt(stateAssignment->iValue))
{
m_tokenizer.Error("Syntax error: expected integer near '%s'", m_tokenizer.GetIdentifier());
stateAssignment->iValue = 0;
return false;
}
}
else if (expectsFloat)
{
if (!AcceptFloat(stateAssignment->fValue))
{
m_tokenizer.Error("Syntax error: expected float near '%s'", m_tokenizer.GetIdentifier());
stateAssignment->iValue = 0;
return false;
}
}
else if (expectsBoolean)
{
const EffectStateValue * stateValue = GetStateValue(m_tokenizer.GetIdentifier(), state);
if (stateValue != NULL)
{
stateAssignment->iValue = stateValue->value;
m_tokenizer.Next();
}
else if (AcceptInt(stateAssignment->iValue))
{
stateAssignment->iValue = (stateAssignment->iValue != 0);
}
else {
m_tokenizer.Error("Syntax error: expected bool near '%s'", m_tokenizer.GetIdentifier());
stateAssignment->iValue = 0;
return false;
}
}
else if (expectsExpression)
{
if (!ParseColorMask(stateAssignment->iValue))
{
m_tokenizer.Error("Syntax error: expected color mask near '%s'", m_tokenizer.GetIdentifier());
stateAssignment->iValue = 0;
return false;
}
}
else
{
const EffectStateValue * stateValue = GetStateValue(m_tokenizer.GetIdentifier(), state);
if (stateValue == NULL)
{
m_tokenizer.Error("Syntax error: unexpected value '%s' for state '%s'", m_tokenizer.GetIdentifier(), state->name);
stateAssignment->iValue = 0;
return false;
}
stateAssignment->iValue = stateValue->value;
m_tokenizer.Next();
}
}
return true;
}
bool HLSLParser::ParseStateAssignment(HLSLStateAssignment*& stateAssignment, bool isSamplerState, bool isPipelineState)
{
const char* fileName = GetFileName();
int line = GetLineNumber();
stateAssignment = m_tree->AddNode<HLSLStateAssignment>(fileName, line);
const EffectState * state;
if (!ParseStateName(isSamplerState, isPipelineState, stateAssignment->stateName, state)) {
return false;
}
stateAssignment->stateName = state->name;
stateAssignment->d3dRenderState = state->d3drs;
if (!Expect('=')) {
return false;
}
if (!ParseStateValue(state, stateAssignment)) {
return false;
}
if (!Expect(';')) {
return false;
}
return true;
}
bool HLSLParser::ParseAttributeList(HLSLAttribute*& firstAttribute)
{
const char* fileName = GetFileName();
int line = GetLineNumber();
HLSLAttribute * lastAttribute = firstAttribute;
do {
const char * identifier = NULL;
if (!ExpectIdentifier(identifier)) {
return false;
}
HLSLAttribute * attribute = m_tree->AddNode<HLSLAttribute>(fileName, line);
if (strcmp(identifier, "unroll") == 0) attribute->attributeType = HLSLAttributeType_Unroll;
else if (strcmp(identifier, "flatten") == 0) attribute->attributeType = HLSLAttributeType_Flatten;
else if (strcmp(identifier, "branch") == 0) attribute->attributeType = HLSLAttributeType_Branch;
else if (strcmp(identifier, "nofastmath") == 0) attribute->attributeType = HLSLAttributeType_NoFastMath;
if (firstAttribute == NULL)
{
firstAttribute = attribute;
}
else
{
lastAttribute->nextAttribute = attribute;
}
lastAttribute = attribute;
} while(Accept(','));
return true;
}
bool HLSLParser::ParseAttributeBlock(HLSLAttribute*& attribute)
{
HLSLAttribute ** lastAttribute = &attribute;
while (*lastAttribute != NULL) { lastAttribute = &(*lastAttribute)->nextAttribute; }
if (!Accept('['))
{
return false;
}
ParseAttributeList(*lastAttribute);
if (!Expect(']'))
{
return false;
}
ParseAttributeBlock(*lastAttribute);
return true;
}
bool HLSLParser::ParseStage(HLSLStatement*& statement)
{
if (!Accept("stage"))
{
return false;
}
const char* stageName = NULL;
if (!ExpectIdentifier(stageName))
{
return false;
}
if (!Expect('{'))
{
return false;
}
HLSLStage* stage = m_tree->AddNode<HLSLStage>(GetFileName(), GetLineNumber());
stage->name = stageName;
BeginScope();
HLSLType voidType(HLSLBaseType_Void);
if (!Expect('{') || !ParseBlock(stage->statement, voidType))
{
return false;
}
EndScope();
statement = stage;
return true;
}
bool HLSLParser::Parse(const char* fileName, const char* buffer, size_t length)
{
HLSLRoot* root = m_tree->GetRoot();
HLSLStatement* lastStatement = NULL;
m_tokenizer = HLSLTokenizer(fileName, buffer, length);
while (!Accept(HLSLToken_EndOfStream))
{
HLSLStatement* statement = NULL;
if (!ParseTopLevel(statement))
{
return false;
}
if (statement != NULL)
{
if (lastStatement == NULL)
{
root->statement = statement;
}
else
{
lastStatement->nextStatement = statement;
}
lastStatement = statement;
while (lastStatement->nextStatement) lastStatement = lastStatement->nextStatement;
}
}
return true;
}
bool HLSLParser::ParsePreprocessorDefine()
{
int line = GetLineNumber();
const char* fileName = GetFileName();
const char* macroName = NULL;
m_tokenizer.Next();
if (m_tokenizer.GetToken() == HLSLToken_Identifier)
{
macroName = m_tree->AddString( m_tokenizer.GetIdentifier() );
}
else
{
char near[HLSLTokenizer::s_maxIdentifier];
m_tokenizer.GetTokenName(near);
m_tokenizer.Error("Syntax error: expected identifier near '%s'", near);
return false;
}
bool macroWithArguments = !m_tokenizer.NextIsWhitespace();
HLSLMacro* macro = m_tree->AddNode<HLSLMacro>(fileName, line);
macro->name = macroName;
m_macros.PushBack(macro);
m_tokenizer.Next();
std::string value;
if (macroWithArguments)
{
if (Accept('('))
{
unsigned int numArguments = 0;
HLSLArgument* lastArgument = NULL;
while (!Accept(')'))
{
if (CheckForUnexpectedEndOfStream(')'))
{
return false;
}
if (numArguments > 0 && !Expect(','))
{
return false;
}
HLSLArgument* argument = m_tree->AddNode<HLSLArgument>(fileName, line);
if (!ExpectIdentifier(argument->name))
{
return false;
}
if (lastArgument != NULL)
{
lastArgument->nextArgument = argument;
}
else
{
macro->argument = argument;
}
lastArgument = argument;
++numArguments;
}
macro->numArguments = numArguments;
}
while(m_tokenizer.GetToken() != HLSLToken_EndOfLine)
{
bool addOriginalSource = true;
if (m_tokenizer.GetToken() == HLSLToken_Identifier)
{
HLSLArgument* argument = macro->argument;
unsigned argNum = 0;
while(argument != NULL)
{
if (String_Equal(argument->name, m_tokenizer.GetIdentifier()))
{
value.append("#" + std::to_string(argNum) + "#");
addOriginalSource = false;
break;
}
argument = argument->nextArgument;
argNum++;
}
}
if (addOriginalSource)
{
value.append(m_tokenizer.getLastPos(true),
m_tokenizer.getCurrentPos() - m_tokenizer.getLastPos(true));
}
m_tokenizer.Next(false);
}
}
else
{
while(m_tokenizer.GetToken() != HLSLToken_EndOfLine)
{
const char * start = m_tokenizer.getLastPos(true);
std::string valueAdd(start, m_tokenizer.getCurrentPos() - start);
value.append(valueAdd);
m_tokenizer.Next(false);
}
}
if (value[0] == '(')
{
value.erase(value.length()-1, 1);
value.erase(0, 1);
}
macro->value = m_tree->AddString(value.c_str());
return true;
}
bool HLSLParser::ApplyPreprocessor(const char* fileName, const char* buffer, size_t length,
std::string & sourcePreprocessed) {
m_tokenizer = HLSLTokenizer(fileName, buffer, length);
while (m_tokenizer.GetToken() != HLSLToken_EndOfStream)
{
if (m_tokenizer.GetToken() == HLSLToken_PreprocessorDefine)
{
ParsePreprocessorDefine();
}
m_tokenizer.Next();
}
int index = 0;
while (index < m_macros.GetSize())
{
HLSLMacro * macro = m_macros[index];
m_tokenizer = HLSLTokenizer(fileName, macro->value, strlen(macro->value));
std::string valueProcessed;
while (m_tokenizer.GetToken() != HLSLToken_EndOfStream)
{
bool addOriginalSource = true;
if (m_tokenizer.GetToken() == HLSLToken_Identifier)
{
HLSLMacro * matchedMacro = ProcessMacroFromIdentifier(valueProcessed, addOriginalSource);
if (matchedMacro != NULL)
{
if (macro->value == matchedMacro->name)
{
macro->macroAliased = matchedMacro;
}
}
}
if (addOriginalSource)
{
valueProcessed.append(m_tokenizer.getLastPos(true),
m_tokenizer.getCurrentPos() - m_tokenizer.getLastPos(true));
}
m_tokenizer.Next();
}
if (valueProcessed == "main")
{
valueProcessed = "sampler_fw_main";
}
if (valueProcessed != macro->value)
{
macro->value = m_tree->AddString(valueProcessed.c_str());
}
else
{
index++;
}
}
index = 0;
while (index < m_macros.GetSize())
{
HLSLMacro * macro = m_macros[index];
if (macro->macroAliased != NULL)
{
macro->argument = macro->macroAliased->argument;
macro->numArguments = macro->macroAliased->numArguments;
macro->value = macro->macroAliased->value;
}
index++;
}
std::stack<bool> isCodeActive;
isCodeActive.push(true);
m_tokenizer = HLSLTokenizer(fileName, buffer, length);
sourcePreprocessed.clear();
while (m_tokenizer.GetToken() != HLSLToken_EndOfStream)
{
bool addOriginalSource = true;
if (m_tokenizer.GetToken() == HLSLToken_PreprocessorIf)
{
while (m_tokenizer.GetToken() != HLSLToken_IntLiteral && m_tokenizer.GetToken() != HLSLToken_EndOfLine)
{
m_tokenizer.Next(false);
}
if (m_tokenizer.GetToken() == HLSLToken_IntLiteral)
{
isCodeActive.push(m_tokenizer.GetInt() != 0);
}
else
{
m_tokenizer.Error("#if evaluation failed: not an integer");
return false;
}
addOriginalSource = false;
}
else if (m_tokenizer.GetToken() == HLSLToken_PreprocessorElse)
{
bool state = isCodeActive.top();
isCodeActive.pop();
isCodeActive.push(!state);
addOriginalSource = false;
}
else if (m_tokenizer.GetToken() == HLSLToken_PreprocessorEndif)
{
isCodeActive.pop();
addOriginalSource = false;
}
else if (m_tokenizer.GetToken() == HLSLToken_PreprocessorDefine)
{
while(m_tokenizer.GetToken() != HLSLToken_EndOfLine)
{
m_tokenizer.Next(false);
}
addOriginalSource = false;
}
else if (m_tokenizer.GetToken() == HLSLToken_Identifier && isCodeActive.top())
{
ProcessMacroFromIdentifier(sourcePreprocessed, addOriginalSource);
}
else if (!isCodeActive.top())
{
addOriginalSource = false;
}
if (addOriginalSource)
{
sourcePreprocessed.append(m_tokenizer.getLastPos(false),
m_tokenizer.getCurrentPos() - m_tokenizer.getLastPos(false));
}
m_tokenizer.Next();
}
return isCodeActive.size() == 1;
}
HLSLMacro * HLSLParser::ProcessMacroFromIdentifier(std::string & sourcePreprocessed, bool & addOriginalSource)
{
for (int i = m_macros.GetSize() - 1; i >= 0; --i)
{
if (String_Equal(m_macros[i]->name, m_tokenizer.GetIdentifier()))
{
if (m_macros[i]->argument == NULL)
{
sourcePreprocessed.append("(");
sourcePreprocessed.append(m_macros[i]->value);
sourcePreprocessed.append(")");
addOriginalSource = false;
}
else
{
const char * savePos = m_tokenizer.getLastPos(false);
m_tokenizer.Next();
if (ProcessMacroArguments(m_macros[i], sourcePreprocessed))
{
addOriginalSource = false;
}
else
{
sourcePreprocessed.append(savePos,
m_tokenizer.getLastPos(false) - savePos);
m_tokenizer.ReturnToPos(m_tokenizer.getLastPos(false));
addOriginalSource = true;
}
}
return m_macros[i];
}
}
return NULL;
}
bool HLSLParser::ProcessMacroArguments(HLSLMacro* macro, std::string & sourcePreprocessed)
{
unsigned scopeLevel = 0;
std::vector<std::string> argumentsValues;
std::string argValue;
bool firstToken = true;
while(m_tokenizer.GetToken() != HLSLToken_EndOfStream) {
bool addToValue = true;
if (firstToken && m_tokenizer.GetToken() != '(')
{
break;
}
else if (m_tokenizer.GetToken() == '(')
{
scopeLevel++;
if (scopeLevel == 1)
{
addToValue = false;
}
}
else if (m_tokenizer.GetToken() == ')')
{
scopeLevel--;
if (scopeLevel == 0)
{
argumentsValues.push_back(argValue);
break;
}
}
else if (m_tokenizer.GetToken() == ',')
{
if (scopeLevel == 1)
{
argumentsValues.push_back(argValue);
argValue.clear();
addToValue = false;
}
}
else if (m_tokenizer.GetToken() == HLSLToken_Identifier)
{
ProcessMacroFromIdentifier(argValue, addToValue);
}
if (addToValue)
{
argValue.append(m_tokenizer.getLastPos(false),
m_tokenizer.getCurrentPos() - m_tokenizer.getLastPos(false));
}
m_tokenizer.Next();
firstToken = false;
}
if (argumentsValues.size() != macro->numArguments) {
return false;
}
sourcePreprocessed.append("(");
unsigned index = 0;
std::string arg;
bool argFound = false;
while(index < strlen(macro->value))
{
if (macro->value[index] == '#' && !argFound)
{
argFound = true;
arg.clear();
}
else if (macro->value[index] == '#' && argFound)
{
unsigned indexArg = std::stoi(arg);
if (indexArg < argumentsValues.size())
{
sourcePreprocessed.append(argumentsValues[indexArg]);
}
argFound = false;
}
else if (argFound)
{
arg += macro->value[index];
}
else
{
sourcePreprocessed += macro->value[index];
}
index++;
}
sourcePreprocessed.append(")");
return true;
}
bool HLSLParser::AcceptTypeModifier(int& flags)
{
if (Accept(HLSLToken_Const))
{
flags |= HLSLTypeFlag_Const;
return true;
}
else if (Accept(HLSLToken_Static))
{
flags |= HLSLTypeFlag_Static;
return true;
}
else if (Accept(HLSLToken_Uniform))
{
flags |= HLSLTypeFlag_Uniform;
return true;
}
else if (Accept(HLSLToken_Inline))
{
return true;
}
return false;
}
bool HLSLParser::AcceptInterpolationModifier(int& flags)
{
if (Accept("linear"))
{
flags |= HLSLTypeFlag_Linear;
return true;
}
else if (Accept("centroid"))
{
flags |= HLSLTypeFlag_Centroid;
return true;
}
else if (Accept("nointerpolation"))
{
flags |= HLSLTypeFlag_NoInterpolation;
return true;
}
else if (Accept("noperspective"))
{
flags |= HLSLTypeFlag_NoPerspective;
return true;
}
else if (Accept("sample"))
{
flags |= HLSLTypeFlag_Sample;
return true;
}
return false;
}
bool HLSLParser::AcceptType(bool allowVoid, HLSLType& type)
{
{
type.flags = 0;
while(AcceptTypeModifier(type.flags) || AcceptInterpolationModifier(type.flags)) {}
}
int token = m_tokenizer.GetToken();
type.baseType = HLSLBaseType_Void;
switch (token)
{
case HLSLToken_Float:
case HLSLToken_Float1:
case HLSLToken_Float1x1:
case HLSLToken_Half:
case HLSLToken_Half1:
case HLSLToken_Half1x1:
case HLSLToken_Double:
case HLSLToken_Double1:
case HLSLToken_Double1x1:
type.baseType = HLSLBaseType_Float;
break;
case HLSLToken_Float2:
case HLSLToken_Float2x1:
case HLSLToken_Half2:
case HLSLToken_Half2x1:
case HLSLToken_Double2:
case HLSLToken_Double2x1:
type.baseType = HLSLBaseType_Float2;
break;
case HLSLToken_Float3:
case HLSLToken_Float3x1:
case HLSLToken_Half3:
case HLSLToken_Half3x1:
case HLSLToken_Double3:
case HLSLToken_Double3x1:
type.baseType = HLSLBaseType_Float3;
break;
case HLSLToken_Float4:
case HLSLToken_Float4x1:
case HLSLToken_Half4:
case HLSLToken_Half4x1:
case HLSLToken_Double4:
case HLSLToken_Double4x1:
type.baseType = HLSLBaseType_Float4;
break;
case HLSLToken_Float2x4:
case HLSLToken_Half2x4:
case HLSLToken_Double2x4:
type.baseType = HLSLBaseType_Float2x4;
break;
case HLSLToken_Float2x3:
case HLSLToken_Half2x3:
case HLSLToken_Double2x3:
type.baseType = HLSLBaseType_Float2x3;
break;
case HLSLToken_Float2x2:
case HLSLToken_Half2x2:
case HLSLToken_Double2x2:
type.baseType = HLSLBaseType_Float2x2;
break;
case HLSLToken_Float3x4:
case HLSLToken_Half3x4:
case HLSLToken_Double3x4:
type.baseType = HLSLBaseType_Float3x4;
break;
case HLSLToken_Float3x3:
case HLSLToken_Half3x3:
case HLSLToken_Double3x3:
type.baseType = HLSLBaseType_Float3x3;
break;
case HLSLToken_Float3x2:
case HLSLToken_Half3x2:
case HLSLToken_Double3x2:
type.baseType = HLSLBaseType_Float3x2;
break;
case HLSLToken_Float4x4:
case HLSLToken_Half4x4:
case HLSLToken_Double4x4:
type.baseType = HLSLBaseType_Float4x4;
break;
case HLSLToken_Float4x3:
case HLSLToken_Half4x3:
case HLSLToken_Double4x3:
type.baseType = HLSLBaseType_Float4x3;
break;
case HLSLToken_Float4x2:
case HLSLToken_Half4x2:
case HLSLToken_Double4x2:
type.baseType = HLSLBaseType_Float4x2;
break;
case HLSLToken_Bool:
type.baseType = HLSLBaseType_Bool;
break;
case HLSLToken_Bool2:
type.baseType = HLSLBaseType_Bool2;
break;
case HLSLToken_Bool3:
type.baseType = HLSLBaseType_Bool3;
break;
case HLSLToken_Bool4:
type.baseType = HLSLBaseType_Bool4;
break;
case HLSLToken_Int:
type.baseType = HLSLBaseType_Int;
break;
case HLSLToken_Int2:
type.baseType = HLSLBaseType_Int2;
break;
case HLSLToken_Int3:
type.baseType = HLSLBaseType_Int3;
break;
case HLSLToken_Int4:
type.baseType = HLSLBaseType_Int4;
break;
case HLSLToken_Uint:
type.baseType = HLSLBaseType_Uint;
break;
case HLSLToken_Uint2:
type.baseType = HLSLBaseType_Uint2;
break;
case HLSLToken_Uint3:
type.baseType = HLSLBaseType_Uint3;
break;
case HLSLToken_Uint4:
type.baseType = HLSLBaseType_Uint4;
break;
case HLSLToken_Texture:
type.baseType = HLSLBaseType_Texture;
break;
case HLSLToken_Sampler:
type.baseType = HLSLBaseType_Sampler2D; break;
case HLSLToken_Sampler2D:
type.baseType = HLSLBaseType_Sampler2D;
break;
case HLSLToken_Sampler3D:
type.baseType = HLSLBaseType_Sampler3D;
break;
case HLSLToken_SamplerCube:
type.baseType = HLSLBaseType_SamplerCube;
break;
case HLSLToken_Sampler2DShadow:
type.baseType = HLSLBaseType_Sampler2DShadow;
break;
case HLSLToken_Sampler2DMS:
type.baseType = HLSLBaseType_Sampler2DMS;
break;
case HLSLToken_Sampler2DArray:
type.baseType = HLSLBaseType_Sampler2DArray;
break;
}
if (type.baseType != HLSLBaseType_Void)
{
m_tokenizer.Next();
if (IsSamplerType(type.baseType))
{
if (Accept('<'))
{
int token2 = m_tokenizer.GetToken();
if (token2 == HLSLToken_Float || token2 == HLSLToken_Float1)
{
type.samplerType = HLSLBaseType_Float;
}
else
{
m_tokenizer.Error("Expected half or float.");
return false;
}
m_tokenizer.Next();
if (!Expect('>'))
{
m_tokenizer.Error("Syntax error: '>' expected for sampler type");
return false;
}
}
}
return true;
}
if (allowVoid && Accept(HLSLToken_Void))
{
type.baseType = HLSLBaseType_Void;
return true;
}
if (token == HLSLToken_Identifier)
{
const char* identifier = m_tree->AddString( m_tokenizer.GetIdentifier() );
if (FindUserDefinedType(identifier) != NULL)
{
m_tokenizer.Next();
type.baseType = HLSLBaseType_UserDefined;
type.typeName = identifier;
return true;
}
}
return false;
}
bool HLSLParser::ExpectType(bool allowVoid, HLSLType& type)
{
if (!AcceptType(allowVoid, type))
{
m_tokenizer.Error("Expected type");
return false;
}
return true;
}
bool HLSLParser::AcceptDeclaration(bool allowUnsizedArray, HLSLType& type, const char*& name)
{
if (!AcceptType(false, type))
{
return false;
}
if (!ExpectIdentifier(name))
{
return false;
}
if (Accept('['))
{
type.array = true;
if (Accept(']') && allowUnsizedArray)
{
return true;
}
if (!ParseExpression(type.arraySize) || !Expect(']'))
{
return false;
}
}
return true;
}
bool HLSLParser::ExpectDeclaration(bool allowUnsizedArray, HLSLType& type, const char*& name)
{
if (!AcceptDeclaration(allowUnsizedArray, type, name))
{
m_tokenizer.Error("Expected declaration");
return false;
}
return true;
}
const HLSLStruct* HLSLParser::FindUserDefinedType(const char* name) const
{
for (int i = 0; i < m_userTypes.GetSize(); ++i)
{
if (m_userTypes[i]->name == name)
{
return m_userTypes[i];
}
}
return NULL;
}
bool HLSLParser::CheckForUnexpectedEndOfStream(int endToken)
{
if (Accept(HLSLToken_EndOfStream))
{
char what[HLSLTokenizer::s_maxIdentifier];
m_tokenizer.GetTokenName(endToken, what);
m_tokenizer.Error("Unexpected end of file while looking for '%s'", what);
return true;
}
return false;
}
int HLSLParser::GetLineNumber() const
{
return m_tokenizer.GetLineNumber();
}
const char* HLSLParser::GetFileName()
{
return m_tree->AddString( m_tokenizer.GetFileName() );
}
void HLSLParser::BeginScope()
{
Variable& variable = m_variables.PushBackNew();
variable.name = NULL;
}
void HLSLParser::EndScope()
{
int numVariables = m_variables.GetSize() - 1;
while (m_variables[numVariables].name != NULL)
{
--numVariables;
ASSERT(numVariables >= 0);
}
m_variables.Resize(numVariables);
}
const HLSLType* HLSLParser::FindVariable(const char* name, bool& global) const
{
for (int i = m_variables.GetSize() - 1; i >= 0; --i)
{
if (m_variables[i].name == name)
{
global = (i < m_numGlobals);
return &m_variables[i].type;
}
}
return NULL;
}
const HLSLFunction* HLSLParser::FindFunction(const char* name) const
{
for (int i = 0; i < m_functions.GetSize(); ++i)
{
if (m_functions[i]->name == name)
{
return m_functions[i];
}
}
return NULL;
}
static bool AreTypesEqual(HLSLTree* tree, const HLSLType& lhs, const HLSLType& rhs)
{
return GetTypeCastRank(tree, lhs, rhs) == 0;
}
static bool AreArgumentListsEqual(HLSLTree* tree, HLSLArgument* lhs, HLSLArgument* rhs)
{
while (lhs && rhs)
{
if (!AreTypesEqual(tree, lhs->type, rhs->type))
return false;
if (lhs->modifier != rhs->modifier)
return false;
if (lhs->semantic != rhs->semantic || lhs->sv_semantic != rhs->sv_semantic)
return false;
lhs = lhs->nextArgument;
rhs = rhs->nextArgument;
}
return lhs == NULL && rhs == NULL;
}
const HLSLFunction* HLSLParser::FindFunction(const HLSLFunction* fun) const
{
for (int i = 0; i < m_functions.GetSize(); ++i)
{
if (m_functions[i]->name == fun->name &&
AreTypesEqual(m_tree, m_functions[i]->returnType, fun->returnType) &&
AreArgumentListsEqual(m_tree, m_functions[i]->argument, fun->argument))
{
return m_functions[i];
}
}
return NULL;
}
void HLSLParser::DeclareVariable(const char* name, const HLSLType& type)
{
if (m_variables.GetSize() == m_numGlobals)
{
++m_numGlobals;
}
Variable& variable = m_variables.PushBackNew();
variable.name = name;
variable.type = type;
}
bool HLSLParser::GetIsFunction(const char* name) const
{
for (int i = 0; i < m_functions.GetSize(); ++i)
{
if (m_functions[i]->name == name)
{
return true;
}
}
for (int i = 0; i < _numIntrinsics; ++i)
{
if (String_Equal(name, _intrinsic[i].function.name))
{
return true;
}
}
return false;
}
const HLSLFunction* HLSLParser::MatchFunctionCall(const HLSLFunctionCall* functionCall, const char* name)
{
const HLSLFunction* matchedFunction = NULL;
int numMatchedOverloads = 0;
bool nameMatches = false;
for (int i = 0; i < m_functions.GetSize(); ++i)
{
const HLSLFunction* function = m_functions[i];
if (function->name == name)
{
nameMatches = true;
CompareFunctionsResult result = CompareFunctions( m_tree, functionCall, function, matchedFunction );
if (result == Function1Better)
{
matchedFunction = function;
numMatchedOverloads = 1;
}
else if (result == FunctionsEqual)
{
++numMatchedOverloads;
}
}
}
for (int i = 0; i < _numIntrinsics; ++i)
{
const HLSLFunction* function = &_intrinsic[i].function;
if (String_Equal(function->name, name))
{
nameMatches = true;
CompareFunctionsResult result = CompareFunctions( m_tree, functionCall, function, matchedFunction );
if (result == Function1Better)
{
matchedFunction = function;
numMatchedOverloads = 1;
}
else if (result == FunctionsEqual)
{
++numMatchedOverloads;
}
}
}
if (matchedFunction != NULL && numMatchedOverloads > 1)
{
m_tokenizer.Error("'%s' %d overloads have similar conversions", name, numMatchedOverloads);
return NULL;
}
else if (matchedFunction == NULL)
{
if (nameMatches)
{
m_tokenizer.Error("'%s' no overloaded function matched all of the arguments", name);
}
else
{
m_tokenizer.Error("Undeclared identifier '%s'", name);
}
}
return matchedFunction;
}
bool HLSLParser::GetMemberType(const HLSLType& objectType, HLSLMemberAccess * memberAccess)
{
const char* fieldName = memberAccess->field;
if (objectType.baseType == HLSLBaseType_UserDefined)
{
const HLSLStruct* structure = FindUserDefinedType( objectType.typeName );
ASSERT(structure != NULL);
const HLSLStructField* field = structure->field;
while (field != NULL)
{
if (field->name == fieldName)
{
memberAccess->expressionType = field->type;
return true;
}
field = field->nextField;
}
return false;
}
if (baseTypeDescriptions[objectType.baseType].numericType == NumericType_NaN)
{
return false;
}
int swizzleLength = 0;
if (baseTypeDescriptions[objectType.baseType].numDimensions <= 1)
{
for (int i = 0; fieldName[i] != 0; ++i)
{
if (fieldName[i] != 'x' && fieldName[i] != 'y' && fieldName[i] != 'z' && fieldName[i] != 'w' &&
fieldName[i] != 'r' && fieldName[i] != 'g' && fieldName[i] != 'b' && fieldName[i] != 'a')
{
m_tokenizer.Error("Invalid swizzle '%s'", fieldName);
return false;
}
++swizzleLength;
}
ASSERT(swizzleLength > 0);
}
else
{
const char* n = fieldName;
while (n[0] == '_')
{
++n;
int base = 1;
if (n[0] == 'm')
{
base = 0;
++n;
}
if (!isdigit(n[0]) || !isdigit(n[1]))
{
return false;
}
int r = (n[0] - '0') - base;
int c = (n[1] - '0') - base;
if (r >= baseTypeDescriptions[objectType.baseType].height ||
c >= baseTypeDescriptions[objectType.baseType].numComponents)
{
return false;
}
++swizzleLength;
n += 2;
}
if (n[0] != 0)
{
return false;
}
}
if (swizzleLength > 4)
{
m_tokenizer.Error("Invalid swizzle '%s'", fieldName);
return false;
}
static const HLSLBaseType floatType[] = { HLSLBaseType_Float, HLSLBaseType_Float2, HLSLBaseType_Float3, HLSLBaseType_Float4 };
static const HLSLBaseType intType[] = { HLSLBaseType_Int, HLSLBaseType_Int2, HLSLBaseType_Int3, HLSLBaseType_Int4 };
static const HLSLBaseType uintType[] = { HLSLBaseType_Uint, HLSLBaseType_Uint2, HLSLBaseType_Uint3, HLSLBaseType_Uint4 };
static const HLSLBaseType boolType[] = { HLSLBaseType_Bool, HLSLBaseType_Bool2, HLSLBaseType_Bool3, HLSLBaseType_Bool4 };
switch (baseTypeDescriptions[objectType.baseType].numericType)
{
case NumericType_Float:
memberAccess->expressionType.baseType = floatType[swizzleLength - 1];
break;
case NumericType_Int:
memberAccess->expressionType.baseType = intType[swizzleLength - 1];
break;
case NumericType_Uint:
memberAccess->expressionType.baseType = uintType[swizzleLength - 1];
break;
case NumericType_Bool:
memberAccess->expressionType.baseType = boolType[swizzleLength - 1];
break;
default:
ASSERT(0);
}
memberAccess->swizzle = true;
return true;
}
}